permdock 0.0.0 → 0.2.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 +327 -1
- package/dist/a2a/index.d.ts +169 -0
- package/dist/a2a/index.js +232 -0
- package/dist/adapter-context-mlWsVGGg.js +23 -0
- package/dist/ai-sdk/index.d.ts +95 -0
- package/dist/ai-sdk/index.js +154 -0
- package/dist/approval-required-TzNB9oQA.js +6 -0
- package/dist/approvals/index.d.ts +3 -0
- package/dist/approvals/index.js +5 -0
- package/dist/approvals-DbYAuNkG.js +224 -0
- package/dist/approvers-DT4AVyIg.js +52 -0
- package/dist/arazzo-BAgw9ap6.js +70 -0
- package/dist/arazzo-cmvX2jDe.js +54 -0
- package/dist/authzen/index.d.ts +39 -0
- package/dist/authzen/index.js +302 -0
- package/dist/better-auth/index.d.ts +109 -0
- package/dist/better-auth/index.js +344 -0
- package/dist/better-supabase/index.d.ts +206 -0
- package/dist/better-supabase/index.js +620 -0
- package/dist/bind-CVy3Espv.d.ts +25 -0
- package/dist/bind-VnYn2HKq.js +97 -0
- package/dist/boundary-BM8a_P6E.js +13 -0
- package/dist/boundary-BmHxVH1J.d.ts +15 -0
- package/dist/budget-JqcRqyhK.d.ts +11 -0
- package/dist/budget-NbEtbJC_.js +11 -0
- package/dist/canonical-json-DemiK4Vp.js +26 -0
- package/dist/capability-4qPdO9gk.js +173 -0
- package/dist/capability-Dq43tT1u.d.ts +99 -0
- package/dist/catalog/index.d.ts +12 -0
- package/dist/catalog/index.js +2 -0
- package/dist/catalog-BjZSovXQ.js +2 -0
- package/dist/catalog-doc-Dsc9y7sd.js +309 -0
- package/dist/catalog-h2tlKFkq.js +48 -0
- package/dist/catalog-path-CnI0XTFK.js +12 -0
- package/dist/catalog-z8q6bi_r.js +55 -0
- package/dist/claude-agent/index.d.ts +72 -0
- package/dist/claude-agent/index.js +77 -0
- package/dist/clerk/index.d.ts +65 -0
- package/dist/clerk/index.js +301 -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/clients-C7zLFuWT.d.ts +12 -0
- package/dist/clients-DjU5ABMy.js +23 -0
- package/dist/cloud/index.d.ts +90 -0
- package/dist/cloud/index.js +404 -0
- package/dist/cloud-BGhHS-lY.js +50 -0
- package/dist/cloud-Bo3e9Ak3.js +118 -0
- package/dist/collect-DDDv_ESs.js +502 -0
- package/dist/collect-DLlujdHC.js +83 -0
- package/dist/collect-rG2IQ3t0.js +2 -0
- package/dist/commands-DWOrSQic.js +97 -0
- package/dist/compact-y6vfu2_f.js +19 -0
- package/dist/compare-pfyVnBjE.js +12 -0
- package/dist/compile/index.d.ts +3 -0
- package/dist/compile/index.js +2 -0
- package/dist/compile-Ba4blROR.js +613 -0
- package/dist/compile-CNnl6uIt.d.ts +94 -0
- package/dist/config-BJiM-xAm.js +157 -0
- package/dist/config-Bn00Z3ks.js +36 -0
- package/dist/config-report-Dw_JcUqT.js +44 -0
- package/dist/connection-CU8MQxRi.js +194 -0
- package/dist/context-Ttp0ekMT.js +82 -0
- package/dist/convex/index.d.ts +45 -0
- package/dist/convex/index.js +65 -0
- package/dist/create-BWyx3jua.d.ts +245 -0
- package/dist/create-CPhDL6qx.js +253 -0
- package/dist/credential-8P81ff4u.js +306 -0
- package/dist/delegation-D8pUEuce.js +103 -0
- package/dist/describe-B_gVZEVi.js +94 -0
- package/dist/describe-PdoqESvg.d.ts +36 -0
- package/dist/diff-B8Tunc3o.js +451 -0
- package/dist/diff-CzqLxZ77.js +48 -0
- package/dist/digest-B3kc_PgQ.d.ts +19 -0
- package/dist/digest-BI-6aa6d.js +27 -0
- package/dist/doctor-WpvG6p4k.js +1194 -0
- package/dist/doctor-collect-ByfYlNv1.js +664 -0
- package/dist/doctor-rOr-4ZfS.js +53 -0
- package/dist/drizzle/index.d.ts +73 -0
- package/dist/drizzle/index.js +160 -0
- package/dist/duration-xK2jGFVc.js +25 -0
- package/dist/elysia/index.d.ts +49 -0
- package/dist/elysia/index.js +59 -0
- package/dist/errors-CWfoNg9N.js +47 -0
- package/dist/errors-Cz5zn0mW.js +123 -0
- package/dist/errors-DAqevpNk.d.ts +125 -0
- package/dist/errors-DRnGZHzF.js +30 -0
- package/dist/evaluation-items-CfCCejQd.js +40 -0
- package/dist/evaluations-tz6D9A2G.js +461 -0
- package/dist/eve/index.d.ts +86 -0
- package/dist/eve/index.js +176 -0
- package/dist/expiry-BoBJ8Tvc.js +7 -0
- package/dist/express/index.d.ts +23 -0
- package/dist/express/index.js +78 -0
- package/dist/fastify/index.d.ts +33 -0
- package/dist/fastify/index.js +92 -0
- package/dist/fields-BMl1RxoX.js +26 -0
- package/dist/files-DWUN9PzI.js +125 -0
- package/dist/fixtures-ht28Cplr.js +67 -0
- package/dist/freeze-CrU8nQeX.js +60 -0
- package/dist/from-snapshot-C3sHpZNS.js +569 -0
- package/dist/generate-CH7ThJ14.js +173 -0
- package/dist/grantee-Cv5Sogfv.js +602 -0
- package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
- package/dist/headers-BZSDieNT.js +6 -0
- package/dist/headers-Cf-zWvsO.d.ts +6 -0
- package/dist/helpers-H_KARDVC.js +421 -0
- package/dist/hono/index.d.ts +48 -0
- package/dist/hono/index.js +99 -0
- package/dist/hosted-DJQw46hn.js +266 -0
- package/dist/http-BIhmLfCc.js +95 -0
- package/dist/http-DPuDaChb.d.ts +13 -0
- package/dist/http-SO7qGttf.js +44 -0
- package/dist/ids-DC4V4CFu.js +18 -0
- package/dist/index-A0YNL8jZ.d.ts +177 -0
- package/dist/index-CtE07CBF.d.ts +6 -0
- package/dist/index-D3vbkoSI.d.ts +483 -0
- package/dist/index-D6_cSa1z.d.ts +201 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +26 -0
- package/dist/instance-options-BK_rNOSC.d.ts +11 -0
- package/dist/instance-options-Dhhcnm3y.js +22 -0
- package/dist/json-schema-BsAflUGW.js +106 -0
- package/dist/jwt/index.d.ts +91 -0
- package/dist/jwt/index.js +590 -0
- package/dist/kernel-GSQnMz3O.js +208 -0
- package/dist/kysely/index.d.ts +78 -0
- package/dist/kysely/index.js +129 -0
- package/dist/live-options-H2eG8dfJ.js +60 -0
- package/dist/load-DhWEB9P1.js +75 -0
- package/dist/load-DwJUafYN.js +2 -0
- package/dist/load-jose-BL6LH4bL.js +11 -0
- package/dist/lru-8q4WZjBV.js +28 -0
- package/dist/manifest-iaoBXHKc.js +783 -0
- package/dist/manifest-uDS9y5de.d.ts +206 -0
- package/dist/map-AcxK9o_D.js +147 -0
- package/dist/map-claims-Z4QZOiFF.js +369 -0
- package/dist/map-error-pgUWNNtG.js +23 -0
- package/dist/markers-B0hYLvMD.js +60 -0
- package/dist/may-use-DndQ5tQ-.js +77 -0
- package/dist/mcp/index.d.ts +159 -0
- package/dist/mcp/index.js +603 -0
- package/dist/nest/index.d.ts +75 -0
- package/dist/nest/index.js +261 -0
- package/dist/next/client.d.ts +23 -0
- package/dist/next/client.js +33 -0
- package/dist/next/index.d.ts +93 -0
- package/dist/next/index.js +180 -0
- package/dist/next/plugin.d.ts +14 -0
- package/dist/next/plugin.js +33 -0
- package/dist/node/index.d.ts +24 -0
- package/dist/node/index.js +34 -0
- package/dist/openai/index.d.ts +62 -0
- package/dist/openai/index.js +92 -0
- package/dist/openapi/index.d.ts +176 -0
- package/dist/openapi/index.js +3 -0
- package/dist/openapi-Bbg4wGVL.js +164 -0
- package/dist/openapi-BqRBvAng.js +538 -0
- package/dist/openapi-CqqEbHsL.js +250 -0
- package/dist/openapi-import-cmwetbzw.js +5959 -0
- package/dist/openapi-schema--ARjyfQr.js +6902 -0
- package/dist/orpc/index.d.ts +51 -0
- package/dist/orpc/index.js +145 -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-BuyjxhZV.js +53 -0
- package/dist/parse-local-manifest-BkGQNzAh.d.ts +10 -0
- package/dist/parse-local-manifest-BrMozJCo.js +36 -0
- package/dist/pdp/index.d.ts +22 -0
- package/dist/pdp/index.js +682 -0
- package/dist/peer-BOr_kJE1.js +31 -0
- package/dist/permdock-CzqXjCpU.js +3471 -0
- package/dist/permissions-CDgvKG5L.d.ts +52 -0
- package/dist/permissions-CpZrivYv.js +142 -0
- package/dist/permissions-DVoF6dMt.js +662 -0
- package/dist/permissions-DttnqqxC.d.ts +214 -0
- package/dist/pins-8ILTftC9.js +12 -0
- package/dist/policy-CFZAr_Al.d.ts +2252 -0
- package/dist/policy-D8UFyERw.d.ts +20 -0
- package/dist/policy-xyWg7QdR.js +1122 -0
- package/dist/powersync-A8x_Yyvh.js +2 -0
- package/dist/powersync-C7kLglqX.js +540 -0
- package/dist/powersync-yW1UUFzp.js +62 -0
- package/dist/prisma/index.d.ts +136 -0
- package/dist/prisma/index.js +455 -0
- package/dist/problem-B43ztKIm.js +191 -0
- package/dist/problem-details-CkL50EEf.d.ts +7 -0
- package/dist/problem-details-_AMOYz-w.js +144 -0
- package/dist/prompt-CXYhLfsS.js +32 -0
- package/dist/protected-CNsMzrVd.d.ts +27 -0
- package/dist/protected-Cs6kTaHo.js +100 -0
- package/dist/protected-bZs6rbT1.d.ts +40 -0
- package/dist/provider-Cjr62YMV.d.ts +6 -0
- package/dist/provider-DLzpb2Xz.js +52 -0
- package/dist/provider-store-DNyC1y48.js +43 -0
- package/dist/react/index.d.ts +8 -0
- package/dist/react/index.js +7 -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 +198 -0
- package/dist/react-native/index.js +696 -0
- package/dist/refs-KYb4ntaz.js +91 -0
- package/dist/relations-cjOL01hZ.js +505 -0
- package/dist/replay-BsOyTrdV.js +28 -0
- package/dist/replay-sqBGMnNs.d.ts +5 -0
- package/dist/resource-ref-CaS9yVPi.js +20 -0
- package/dist/revocations-Bhr0aMIC.js +27 -0
- package/dist/revocations-Cy06JNx2.d.ts +21 -0
- package/dist/rls-BMNydpHk.js +2521 -0
- package/dist/rls-CEvs64Kj.js +238 -0
- package/dist/rls-fields-BMasREhR.js +3502 -0
- package/dist/rls-graph-pc9fuXYm.js +435 -0
- package/dist/rls-import-D8F7j35Q.js +943 -0
- package/dist/rls-migrate-7wikfrVI.js +367 -0
- package/dist/rls-ownership-B5Lkq62W.js +843 -0
- package/dist/rls-shared-aOQ4hGTO.js +493 -0
- package/dist/rls-verify-D8B7dOTh.js +745 -0
- package/dist/row-check-Dt35czLy.d.ts +40 -0
- package/dist/rpc-DOK54_CS.js +89 -0
- package/dist/run-YXCJDNYk.js +174 -0
- package/dist/runtime-CB8gQFvS.js +11 -0
- package/dist/saas-Bj_FFkjN.js +1203 -0
- package/dist/schema-D3MnDMxa.js +300 -0
- package/dist/scim/index.d.ts +2 -0
- package/dist/scim/index.js +2 -0
- package/dist/scim-BFGBBAqR.js +1445 -0
- package/dist/scopes-CVdPrWN-.js +239 -0
- package/dist/server/index.d.ts +134 -0
- package/dist/server/index.js +11 -0
- package/dist/server-DlZ28Oz5.js +268 -0
- package/dist/sha256-BO0swRXL.js +150 -0
- package/dist/shared-DRu8VFVM.js +123 -0
- package/dist/sink-Bd9PSyfq.js +141 -0
- package/dist/sink-Gs6TTVa-.d.ts +104 -0
- package/dist/skills-Biq5uup3.js +192 -0
- package/dist/skills-JaymNCdK.js +56 -0
- package/dist/snapshot-Enxd0n-s.js +975 -0
- package/dist/snapshot-cache-D6jLelln.js +44 -0
- package/dist/snapshot-cache-DwQH8ufx.d.ts +45 -0
- package/dist/solid/index.d.ts +93 -0
- package/dist/solid/index.js +188 -0
- package/dist/sources-B0UvrJ21.js +534 -0
- package/dist/sources-BcJgw0lt.d.ts +192 -0
- package/dist/sql-xdg5f4Fi.js +27 -0
- package/dist/src-CSbUiozF.js +568 -0
- package/dist/ssf/index.d.ts +4 -0
- package/dist/ssf/index.js +596 -0
- package/dist/store-DMAWwAJV.js +371 -0
- package/dist/store-D_pjn91-.d.ts +36 -0
- package/dist/store-options-yO0V6gRn.js +716 -0
- package/dist/stores-4_sqiOA1.js +87 -0
- package/dist/stores-DVR5NHLE.d.ts +52 -0
- package/dist/stream-DDpvynSB.js +66 -0
- package/dist/stream-DlvG2hs-.d.ts +12 -0
- package/dist/style-CTm1AXDT.js +22 -0
- package/dist/subject-C6dLxqHU.js +24 -0
- package/dist/subject-settings-BwBmCdTR.js +128 -0
- package/dist/supabase/index.d.ts +183 -0
- package/dist/supabase/index.js +5 -0
- package/dist/supabase/middleware.d.ts +82 -0
- package/dist/supabase/middleware.js +102 -0
- package/dist/supabase-CwafwxxF.js +83 -0
- package/dist/supabase-DTBaC20O.js +774 -0
- package/dist/supabase-config-Bs44dare.js +472 -0
- package/dist/supabase-hook-BuxLQLpU.js +1814 -0
- package/dist/supabase-hook-D5qVd_D8.js +2 -0
- package/dist/supautils-DYZnzRWV.js +91 -0
- package/dist/svelte/PermissionBoundary.svelte +37 -0
- package/dist/svelte/Protected.svelte +40 -0
- package/dist/svelte/index.d.ts +13 -0
- package/dist/svelte/index.js +107 -0
- package/dist/svelte/runtime.d.ts +7 -0
- package/dist/svelte/runtime.js +4 -0
- package/dist/svelte/source.d.ts +13 -0
- package/dist/svelte/source.js +11 -0
- package/dist/terminal/index.d.ts +163 -0
- package/dist/terminal/index.js +833 -0
- package/dist/testing/index.d.ts +745 -0
- package/dist/testing/index.js +3672 -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/token-CIWxJOCh.js +50 -0
- package/dist/trpc/index.d.ts +61 -0
- package/dist/trpc/index.js +122 -0
- package/dist/types-9AWO9EGt.d.ts +197 -0
- package/dist/types-BPxgszlT.d.ts +550 -0
- package/dist/types-BVyImy5I.d.ts +120 -0
- package/dist/types-Bvc4oWT6.d.ts +9 -0
- package/dist/types-C3s9xVJG.d.ts +48 -0
- package/dist/types-Dnemwd77.d.ts +183 -0
- package/dist/types-kxznc7cn.d.ts +52 -0
- package/dist/types-vKyAMtcX.d.ts +157 -0
- package/dist/types-vNSDF7Dq.d.ts +66 -0
- package/dist/types-yF5LmQVD.d.ts +306 -0
- package/dist/unplugin/index.d.ts +7 -0
- package/dist/unplugin/index.js +31 -0
- package/dist/usage-D07N9QJ3.js +42 -0
- package/dist/usage-D82l1CwK.js +2 -0
- package/dist/usage-DG1oeCca.js +693 -0
- package/dist/validation-error-CnjZ4t92.js +33 -0
- package/dist/validation-error-CtF23SrC.d.ts +26 -0
- package/dist/validity-uOp8UpYn.js +245 -0
- package/dist/verifier-BxBo6I44.js +466 -0
- package/dist/version-BvacVTZR.js +17 -0
- package/dist/views-Soe7bGSC.js +95 -0
- package/dist/vocabulary-DA8a8zif.d.ts +56 -0
- package/dist/vue/index.d.ts +79 -0
- package/dist/vue/index.js +196 -0
- package/dist/watch-Etoa_Mvr.js +2 -0
- package/dist/watch-UihESpsJ.js +128 -0
- package/dist/webmcp/index.d.ts +75 -0
- package/dist/webmcp/index.js +307 -0
- package/package.json +450 -5
- package/rulesets/permdock.yaml +29 -0
- package/schemas/approval-request-v1.json +175 -0
- package/schemas/catalog-v1.json +535 -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 +144 -0
- package/schemas/supabase-manifest-v1.json +361 -0
- package/skills/permdock/SKILL.md +66 -0
- package/skills/permdock-agents/SKILL.md +77 -0
- package/skills/permdock-agents/references/runtimes.md +213 -0
- package/skills/permdock-approvals/SKILL.md +80 -0
- package/skills/permdock-approvals/references/stores-and-resume.md +94 -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 +132 -0
- package/skills/permdock-data/SKILL.md +57 -0
- package/skills/permdock-data/references/queries-and-rls.md +62 -0
- package/skills/permdock-data/references/relationships.md +67 -0
- package/skills/permdock-tenancy/SKILL.md +80 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +89 -0
- package/skills/permdock-wire/SKILL.md +116 -0
- package/skills/permdock-wire/references/adapters.md +492 -0
- package/skills/permdock-wire/references/policy-options.md +45 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { n as PermDockValidationError, t as PROBLEM_BASE } from "./validation-error-CnjZ4t92.js";
|
|
3
|
+
import { i as stepUpOf, n as problemDetails, t as notFoundDetails } from "./problem-details-_AMOYz-w.js";
|
|
4
|
+
import { a as deniedMessage, i as approvalMessage } from "./errors-Cz5zn0mW.js";
|
|
5
|
+
//#region src/server/problem.ts
|
|
6
|
+
function quoted(value) {
|
|
7
|
+
return `"${value.replaceAll(/["\\]/gu, "")}"`;
|
|
8
|
+
}
|
|
9
|
+
const UTF8 = /* @__PURE__ */ new TextEncoder();
|
|
10
|
+
/**
|
|
11
|
+
* An RFC 9651 sf-string: `"` and `\` escaped, and anything outside printable
|
|
12
|
+
* ASCII percent-encoded, which the grammar does not allow.
|
|
13
|
+
*/
|
|
14
|
+
function sfString(value) {
|
|
15
|
+
return `"${value.replaceAll(/[\\"]/gu, (char) => `\\${char}`).replaceAll(/[^\u0020-\u007E]/gu, (char) => Array.from(UTF8.encode(char), (byte) => `%${byte.toString(16).toUpperCase().padStart(2, "0")}`).join(""))}"`;
|
|
16
|
+
}
|
|
17
|
+
/** An RFC 6750 `WWW-Authenticate: Bearer` value. */
|
|
18
|
+
function bearerChallenge(challenge) {
|
|
19
|
+
const parts = [`error=${quoted(challenge.error)}`];
|
|
20
|
+
if (challenge.description !== void 0) parts.push(`error_description=${quoted(challenge.description)}`);
|
|
21
|
+
if (challenge.scopes !== void 0 && challenge.scopes.length > 0) parts.push(`scope=${quoted([...new Set(challenge.scopes)].join(" "))}`);
|
|
22
|
+
if (challenge.acrValues !== void 0 && challenge.acrValues.length > 0) parts.push(`acr_values=${quoted(challenge.acrValues.join(" "))}`);
|
|
23
|
+
if (challenge.maxAge !== void 0) parts.push(`max_age=${quoted(String(challenge.maxAge))}`);
|
|
24
|
+
if (challenge.resourceMetadata !== void 0) parts.push(`resource_metadata=${quoted(challenge.resourceMetadata)}`);
|
|
25
|
+
return `Bearer ${parts.join(", ")}`;
|
|
26
|
+
}
|
|
27
|
+
/** The RFC 9728 well-known metadata URL for a resource identifier. */
|
|
28
|
+
function protectedResourceMetadataUrl(resource) {
|
|
29
|
+
const path = resource.pathname === "/" ? "" : resource.pathname;
|
|
30
|
+
return `${resource.origin}/.well-known/oauth-protected-resource${path}`;
|
|
31
|
+
}
|
|
32
|
+
/** The `error_description` of every `invalid_token` challenge (RFC 6750 section 3.1). */
|
|
33
|
+
const INVALID_TOKEN = "The access token is invalid";
|
|
34
|
+
function wwwAuthenticate(decision, permission, credentials = true) {
|
|
35
|
+
return challengeFor(decision, permission?.scope, credentials);
|
|
36
|
+
}
|
|
37
|
+
function challengeFor(decision, scope, credentials = true) {
|
|
38
|
+
if (decision.outcome !== "denied") return;
|
|
39
|
+
const reasons = new Set(decision.denials.map((denial) => denial.reason));
|
|
40
|
+
if (reasons.has("insufficient-user-authentication")) return bearerChallenge({
|
|
41
|
+
error: "insufficient_user_authentication",
|
|
42
|
+
...stepUpOf(decision)
|
|
43
|
+
});
|
|
44
|
+
if (reasons.has("anonymous")) return credentials ? bearerChallenge({
|
|
45
|
+
error: "invalid_token",
|
|
46
|
+
description: INVALID_TOKEN
|
|
47
|
+
}) : "Bearer";
|
|
48
|
+
if (reasons.has("not-delegated") || reasons.has("no-delegation")) return bearerChallenge(compact({
|
|
49
|
+
error: "insufficient_scope",
|
|
50
|
+
scopes: scope === void 0 ? void 0 : [scope]
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
function problemResponse(details, permission, decision, extra, credentials) {
|
|
54
|
+
const headers = new Headers({
|
|
55
|
+
...extra,
|
|
56
|
+
"content-type": "application/problem+json"
|
|
57
|
+
});
|
|
58
|
+
if (decision !== void 0) {
|
|
59
|
+
const challenge = wwwAuthenticate(decision, permission, credentials);
|
|
60
|
+
if (challenge !== void 0) headers.set("WWW-Authenticate", challenge);
|
|
61
|
+
}
|
|
62
|
+
return new Response(JSON.stringify(details), {
|
|
63
|
+
status: details.status,
|
|
64
|
+
headers
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/** RFC 9457 413 for a batch over `max` evaluations. */
|
|
68
|
+
function batchTooLarge(max) {
|
|
69
|
+
return problemResponse({
|
|
70
|
+
type: `${PROBLEM_BASE}/payload-too-large`,
|
|
71
|
+
title: "Payload too large",
|
|
72
|
+
status: 413,
|
|
73
|
+
detail: `evaluations batch exceeds ${String(max)}`
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function validationProblem(detail) {
|
|
77
|
+
return problemResponse(compact({
|
|
78
|
+
type: `${PROBLEM_BASE}/validation`,
|
|
79
|
+
title: "Invalid request",
|
|
80
|
+
status: 400,
|
|
81
|
+
detail
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
function resourceRef(permission) {
|
|
85
|
+
return { type: permission.resource };
|
|
86
|
+
}
|
|
87
|
+
function isLimitDetail(value) {
|
|
88
|
+
if (value === null || typeof value !== "object") return false;
|
|
89
|
+
const { count, window, resetsAt } = value;
|
|
90
|
+
return Number.isFinite(count) && Number.isFinite(window) && Number.isFinite(resetsAt);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `Retry-After` plus the `RateLimit` / `RateLimit-Policy` fields of
|
|
94
|
+
* draft-ietf-httpapi-ratelimit-headers-11, one policy per exhausted grant.
|
|
95
|
+
*/
|
|
96
|
+
function rateLimitHeaders(decision, now = Date.now() / 1e3) {
|
|
97
|
+
if (decision.outcome !== "denied") return {};
|
|
98
|
+
const policies = /* @__PURE__ */ new Map();
|
|
99
|
+
for (const denial of decision.denials) {
|
|
100
|
+
if (denial.reason !== "limit" || !isLimitDetail(denial.detail)) continue;
|
|
101
|
+
const name = denial.role ?? "default";
|
|
102
|
+
if (!policies.has(name)) policies.set(name, denial.detail);
|
|
103
|
+
}
|
|
104
|
+
if (policies.size === 0) return {};
|
|
105
|
+
const entries = [...policies].map(([name, detail]) => ({
|
|
106
|
+
name: sfString(name),
|
|
107
|
+
detail,
|
|
108
|
+
wait: Math.max(1, Math.ceil(detail.resetsAt - now))
|
|
109
|
+
}));
|
|
110
|
+
return {
|
|
111
|
+
"Retry-After": String(Math.min(...entries.map((entry) => entry.wait))),
|
|
112
|
+
RateLimit: entries.map((entry) => `${entry.name};r=0;t=${entry.wait}`).join(", "),
|
|
113
|
+
"RateLimit-Policy": entries.map((entry) => `${entry.name};q=${entry.detail.count};w=${entry.detail.window}`).join(", ")
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The response for a decision's Problem Details: `WWW-Authenticate` for a
|
|
118
|
+
* `401` or a missing delegation, and the rate-limit fields for a `429`. A
|
|
119
|
+
* hidden row's `404` carries neither, so it reads like a missing one.
|
|
120
|
+
*/
|
|
121
|
+
function decisionResponse(details, decision, options = {}) {
|
|
122
|
+
const headers = new Headers({
|
|
123
|
+
...details.status === 429 ? rateLimitHeaders(decision) : {},
|
|
124
|
+
"content-type": "application/problem+json"
|
|
125
|
+
});
|
|
126
|
+
const challenge = details.status === 404 ? void 0 : challengeFor(decision, options.scope, options.credentials);
|
|
127
|
+
if (challenge !== void 0) headers.set("WWW-Authenticate", challenge);
|
|
128
|
+
return new Response(JSON.stringify(details), {
|
|
129
|
+
status: details.status,
|
|
130
|
+
headers
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function problemFromDecision(decision, permission, subject, options = {}) {
|
|
134
|
+
if (decision.outcome === "granted") return new Response(null, { status: 204 });
|
|
135
|
+
const validation = decision.outcome === "denied" ? decision.denials[0]?.detail : void 0;
|
|
136
|
+
if (options.disclosure !== "hide" && validation instanceof PermDockValidationError) return problemResponse(validation.toProblemDetails(), options.scope === void 0 ? permission : {
|
|
137
|
+
...permission,
|
|
138
|
+
scope: options.scope
|
|
139
|
+
}, decision);
|
|
140
|
+
const details = problemDetails(compact({
|
|
141
|
+
decision,
|
|
142
|
+
detail: decision.outcome === "approval-required" ? approvalMessage(permission.key, decision.reason, decision.token) : deniedMessage(permission.key, subject?.principal?.id, decision.denials, decision.alternatives.map((leaf) => leaf.key), subject !== void 0),
|
|
143
|
+
instance: options.instance,
|
|
144
|
+
permission: permission.key,
|
|
145
|
+
scope: permission.scope,
|
|
146
|
+
resource: resourceRef(permission),
|
|
147
|
+
disclosure: options.disclosure
|
|
148
|
+
}));
|
|
149
|
+
const approval = decision.outcome !== "approval-required" || options.approval === void 0 || options.approval.at === void 0 && options.approval.hint === void 0 ? void 0 : compact({
|
|
150
|
+
at: options.approval.at,
|
|
151
|
+
hint: options.approval.hint
|
|
152
|
+
});
|
|
153
|
+
return decisionResponse(approval === void 0 ? details : {
|
|
154
|
+
...details,
|
|
155
|
+
approval
|
|
156
|
+
}, decision, compact({
|
|
157
|
+
scope: options.scope ?? permission.scope,
|
|
158
|
+
credentials: options.credentials
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
/** The `404` a missing row and a hidden one share, so the two read the same. */
|
|
162
|
+
function notFoundProblem(instance) {
|
|
163
|
+
return problemResponse(notFoundDetails(instance));
|
|
164
|
+
}
|
|
165
|
+
const ANONYMOUS = {
|
|
166
|
+
outcome: "denied",
|
|
167
|
+
denials: [{
|
|
168
|
+
role: null,
|
|
169
|
+
reason: "anonymous"
|
|
170
|
+
}],
|
|
171
|
+
alternatives: []
|
|
172
|
+
};
|
|
173
|
+
/** The `401` for a request with no subject, with the RFC 6750 challenge its credentials call for. */
|
|
174
|
+
function unauthenticatedProblem(credentials) {
|
|
175
|
+
return decisionResponse(problemDetails({
|
|
176
|
+
decision: ANONYMOUS,
|
|
177
|
+
detail: "anonymous"
|
|
178
|
+
}), ANONYMOUS, { credentials });
|
|
179
|
+
}
|
|
180
|
+
function methodNotAllowed(allow) {
|
|
181
|
+
const response = problemResponse({
|
|
182
|
+
type: `${PROBLEM_BASE}/method-not-allowed`,
|
|
183
|
+
title: "Method not allowed",
|
|
184
|
+
status: 405,
|
|
185
|
+
detail: `use ${allow}`
|
|
186
|
+
});
|
|
187
|
+
response.headers.set("Allow", allow);
|
|
188
|
+
return response;
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
export { notFoundProblem as a, protectedResourceMetadataUrl as c, wwwAuthenticate as d, methodNotAllowed as i, unauthenticatedProblem as l, bearerChallenge as n, problemFromDecision as o, decisionResponse as r, problemResponse as s, batchTooLarge as t, validationProblem as u };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Yn as Decision } from "./policy-CFZAr_Al.js";
|
|
2
|
+
//#region src/core/problem-details.d.ts
|
|
3
|
+
type Disclosure = "hide" | "reveal";
|
|
4
|
+
/** The plans a `not-entitled` denial asks for; empty unless every denial is `not-entitled`. */
|
|
5
|
+
declare function requiredPlans(decision: Decision): readonly string[];
|
|
6
|
+
//#endregion
|
|
7
|
+
export { requiredPlans as n, Disclosure as t };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { t as PROBLEM_BASE } from "./validation-error-CnjZ4t92.js";
|
|
3
|
+
//#region src/core/wire-denial.ts
|
|
4
|
+
const IN_PROCESS = /* @__PURE__ */ new Set(["closure-error", "validation"]);
|
|
5
|
+
function jsonDetail(value) {
|
|
6
|
+
if (value === void 0 || value === null || value instanceof Error) return;
|
|
7
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
8
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
|
|
9
|
+
if (typeof value !== "object") return;
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(JSON.stringify(value));
|
|
12
|
+
} catch {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function wireDenial(denial) {
|
|
17
|
+
return compact({
|
|
18
|
+
role: denial.role,
|
|
19
|
+
reason: denial.reason,
|
|
20
|
+
to: denial.to,
|
|
21
|
+
detail: IN_PROCESS.has(denial.reason) ? void 0 : jsonDetail(denial.detail)
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function wireDenials(denials) {
|
|
25
|
+
return denials.map(wireDenial);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/core/problem-details.ts
|
|
29
|
+
/** Reasons that only arise once a matching grant was found, so they reveal nothing hidden. */
|
|
30
|
+
const HOLDS_GRANT = /* @__PURE__ */ new Set([
|
|
31
|
+
"insufficient-user-authentication",
|
|
32
|
+
"limit",
|
|
33
|
+
"limit-unavailable"
|
|
34
|
+
]);
|
|
35
|
+
function granteesOf(to) {
|
|
36
|
+
if (to === void 0) return [];
|
|
37
|
+
return Array.isArray(to) ? to : [to];
|
|
38
|
+
}
|
|
39
|
+
/** The plans a `not-entitled` denial asks for; empty unless every denial is `not-entitled`. */
|
|
40
|
+
function requiredPlans(decision) {
|
|
41
|
+
if (decision.outcome !== "denied" || decision.denials.length === 0 || decision.denials.some((denial) => denial.reason !== "not-entitled")) return [];
|
|
42
|
+
const plans = /* @__PURE__ */ new Set();
|
|
43
|
+
for (const denial of decision.denials) for (const item of granteesOf(denial.to)) if (item.kind === "plan") plans.add(item.plan);
|
|
44
|
+
return [...plans];
|
|
45
|
+
}
|
|
46
|
+
/** The `acr` values and the tightest `maxAge` the failing assurance grants ask for. */
|
|
47
|
+
function stepUpOf(decision) {
|
|
48
|
+
if (decision.outcome !== "denied") return {};
|
|
49
|
+
const acr = /* @__PURE__ */ new Set();
|
|
50
|
+
let maxAge;
|
|
51
|
+
for (const denial of decision.denials) {
|
|
52
|
+
if (denial.reason !== "insufficient-user-authentication") continue;
|
|
53
|
+
for (const grantee of granteesOf(denial.to)) {
|
|
54
|
+
if (grantee.kind !== "assurance") continue;
|
|
55
|
+
for (const value of grantee.acr ?? []) acr.add(value);
|
|
56
|
+
if (grantee.maxAge !== void 0) maxAge = maxAge === void 0 ? grantee.maxAge : Math.min(maxAge, grantee.maxAge);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return compact({
|
|
60
|
+
acrValues: acr.size === 0 ? void 0 : [...acr],
|
|
61
|
+
maxAge
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** The `404` a missing row and a hidden one share, so the two read the same. */
|
|
65
|
+
function notFoundDetails(instance) {
|
|
66
|
+
return compact({
|
|
67
|
+
type: `${PROBLEM_BASE}/not-found`,
|
|
68
|
+
title: "Not found",
|
|
69
|
+
status: 404,
|
|
70
|
+
detail: "No such resource",
|
|
71
|
+
instance
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The RFC 9457 body for a decision that is not `granted`. One status matrix
|
|
76
|
+
* serves `protect`, a thrown `assert` and `problemFromError`: `401` for an
|
|
77
|
+
* anonymous subject or a step-up, `404` for a hidden row, `429` for an
|
|
78
|
+
* exhausted limit, `503` for an unavailable limit store, `403` otherwise.
|
|
79
|
+
*/
|
|
80
|
+
function problemDetails(input) {
|
|
81
|
+
const { decision } = input;
|
|
82
|
+
const base = compact({
|
|
83
|
+
instance: input.instance,
|
|
84
|
+
permission: input.permission,
|
|
85
|
+
scope: input.scope,
|
|
86
|
+
resource: input.resource
|
|
87
|
+
});
|
|
88
|
+
if (decision.outcome === "approval-required") return compact({
|
|
89
|
+
type: `${PROBLEM_BASE}/approval-required`,
|
|
90
|
+
title: "Approval required",
|
|
91
|
+
status: 403,
|
|
92
|
+
detail: input.detail,
|
|
93
|
+
...base,
|
|
94
|
+
reason: decision.reason,
|
|
95
|
+
token: decision.token
|
|
96
|
+
});
|
|
97
|
+
const reasons = new Set(decision.denials.map((denial) => denial.reason));
|
|
98
|
+
if (input.disclosure === "hide" && ![...reasons].every((reason) => HOLDS_GRANT.has(reason))) return notFoundDetails(input.instance);
|
|
99
|
+
if (reasons.has("anonymous")) return compact({
|
|
100
|
+
type: `${PROBLEM_BASE}/unauthenticated`,
|
|
101
|
+
title: "Authentication required",
|
|
102
|
+
status: 401,
|
|
103
|
+
detail: "Authenticate and repeat the request",
|
|
104
|
+
instance: input.instance,
|
|
105
|
+
permission: input.permission
|
|
106
|
+
});
|
|
107
|
+
const denied = compact({
|
|
108
|
+
type: `${PROBLEM_BASE}/denied`,
|
|
109
|
+
title: "Permission denied",
|
|
110
|
+
status: 403,
|
|
111
|
+
detail: input.detail,
|
|
112
|
+
...base,
|
|
113
|
+
denials: wireDenials(decision.denials),
|
|
114
|
+
alternatives: decision.alternatives.map((leaf) => leaf.key)
|
|
115
|
+
});
|
|
116
|
+
if (reasons.has("insufficient-user-authentication")) return {
|
|
117
|
+
...denied,
|
|
118
|
+
status: 401,
|
|
119
|
+
type: `${PROBLEM_BASE}/step-up-required`,
|
|
120
|
+
...stepUpOf(decision)
|
|
121
|
+
};
|
|
122
|
+
const plans = requiredPlans(decision);
|
|
123
|
+
if (plans.length > 0) return {
|
|
124
|
+
...denied,
|
|
125
|
+
type: `${PROBLEM_BASE}/not-entitled`,
|
|
126
|
+
title: "Plan upgrade required",
|
|
127
|
+
plans
|
|
128
|
+
};
|
|
129
|
+
if (reasons.size > 0 && [...reasons].every((reason) => reason === "limit")) return {
|
|
130
|
+
...denied,
|
|
131
|
+
status: 429,
|
|
132
|
+
type: `${PROBLEM_BASE}/rate-limited`,
|
|
133
|
+
title: "Rate limit exceeded"
|
|
134
|
+
};
|
|
135
|
+
if (reasons.has("limit-unavailable") && [...reasons].every((reason) => reason === "limit" || reason === "limit-unavailable")) return {
|
|
136
|
+
...denied,
|
|
137
|
+
status: 503,
|
|
138
|
+
type: `${PROBLEM_BASE}/limit-unavailable`,
|
|
139
|
+
title: "Rate limit unavailable"
|
|
140
|
+
};
|
|
141
|
+
return denied;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { wireDenials as a, stepUpOf as i, problemDetails as n, requiredPlans as r, notFoundDetails as t };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { cancel, confirm, isCancel, multiselect } from "@clack/prompts";
|
|
2
|
+
//#region src/cli/commands/prompt.ts
|
|
3
|
+
/** What a command reports when the person at the terminal cancels a prompt. */
|
|
4
|
+
const CANCELLED = {
|
|
5
|
+
code: 2,
|
|
6
|
+
output: "Cancelled."
|
|
7
|
+
};
|
|
8
|
+
/** A yes or no question; `undefined` when cancelled. */
|
|
9
|
+
async function ask(message) {
|
|
10
|
+
const answer = await confirm({ message });
|
|
11
|
+
if (isCancel(answer)) {
|
|
12
|
+
cancel();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
return answer;
|
|
16
|
+
}
|
|
17
|
+
/** Pick one or more of `options`, `initial` preselected; `undefined` when cancelled. */
|
|
18
|
+
async function pick(message, options, initial) {
|
|
19
|
+
const answer = await multiselect({
|
|
20
|
+
message,
|
|
21
|
+
options: options.map((option) => ({ ...option })),
|
|
22
|
+
initialValues: [...initial],
|
|
23
|
+
required: true
|
|
24
|
+
});
|
|
25
|
+
if (isCancel(answer)) {
|
|
26
|
+
cancel();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
return answer;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { ask as n, pick as r, CANCELLED as t };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { D as PolicyVocabulary, Mr as Membership, Yn as Decision } from "./policy-CFZAr_Al.js";
|
|
2
|
+
import { f as Permission } from "./permissions-DttnqqxC.js";
|
|
3
|
+
import { r as Role } from "./vocabulary-DA8a8zif.js";
|
|
4
|
+
import { a as FilterResult, c as SubjectView, l as TenantView, o as PermissionSet, r as ClientPermDock, s as PermissionState, t as ApprovalHandle, u as UseRolesOptions } from "./types-kxznc7cn.js";
|
|
5
|
+
import { n as ProtectedProps } from "./types-C3s9xVJG.js";
|
|
6
|
+
import { ReactNode } from "react";
|
|
7
|
+
//#region src/react/hooks.d.ts
|
|
8
|
+
declare function usePermDock<V extends PolicyVocabulary = PolicyVocabulary>(): ClientPermDock<V>;
|
|
9
|
+
declare function usePermission(permission: Permission, data?: unknown): PermissionState;
|
|
10
|
+
declare function usePermissions(permissions: readonly Permission[], data?: unknown): PermissionSet;
|
|
11
|
+
declare function useFilter<T>(permission: Permission<string, T, "instance">, rows: readonly T[]): FilterResult<T>;
|
|
12
|
+
declare function useTenant(): TenantView;
|
|
13
|
+
declare function useMemberships(): readonly Membership[];
|
|
14
|
+
declare function useRoles(options?: UseRolesOptions): {
|
|
15
|
+
readonly roles: readonly Role[];
|
|
16
|
+
};
|
|
17
|
+
declare function useAssignableRoles(): readonly Role[];
|
|
18
|
+
declare function useAssignablePermissions(options?: {
|
|
19
|
+
readonly tenant?: string;
|
|
20
|
+
}): readonly Permission[];
|
|
21
|
+
declare function useSubject(): SubjectView;
|
|
22
|
+
declare function useApproval(decision: Decision): ApprovalHandle;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/react/protected.d.ts
|
|
25
|
+
declare function Protected(props: ProtectedProps): ReactNode;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { useFilter as a, usePermission as c, useSubject as d, useTenant as f, useAssignableRoles as i, usePermissions as l, useApproval as n, useMemberships as o, useAssignablePermissions as r, usePermDock as s, Protected as t, useRoles as u };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { n as storeOf } from "./store-options-yO0V6gRn.js";
|
|
2
|
+
import { a as protectedView, c as subjectView, i as permissionSet, l as tenantView, n as filterResult, o as rolesView, s as scopedTenant, t as approvalHandle } from "./views-Soe7bGSC.js";
|
|
3
|
+
import { i as PermDockStoreContext, r as PermDockSnapshotPromiseContext } from "./live-options-H2eG8dfJ.js";
|
|
4
|
+
import { Suspense, use, useMemo, useSyncExternalStore } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/react/hooks.ts
|
|
7
|
+
function useStore() {
|
|
8
|
+
const store = use(PermDockStoreContext);
|
|
9
|
+
if (store === null) throw new Error("PermDock: hooks require <PermDockProvider>.");
|
|
10
|
+
const pending = use(PermDockSnapshotPromiseContext);
|
|
11
|
+
if (pending !== null) store.adopt(use(pending), pending);
|
|
12
|
+
return store;
|
|
13
|
+
}
|
|
14
|
+
function usePermDock() {
|
|
15
|
+
const store = useStore();
|
|
16
|
+
return useSyncExternalStore((listener) => store.subscribe(listener), () => store.get(), () => store.get());
|
|
17
|
+
}
|
|
18
|
+
function usePermission(permission, data) {
|
|
19
|
+
const permdock = usePermDock();
|
|
20
|
+
return useMemo(() => storeOf(permdock).permissionState(permission, data), [
|
|
21
|
+
permdock,
|
|
22
|
+
permission,
|
|
23
|
+
data
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
function usePermissions(permissions, data) {
|
|
27
|
+
const permdock = usePermDock();
|
|
28
|
+
return useMemo(() => permissionSet(storeOf(permdock), permissions, data), [
|
|
29
|
+
permdock,
|
|
30
|
+
permissions,
|
|
31
|
+
data
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
function useFilter(permission, rows) {
|
|
35
|
+
const permdock = usePermDock();
|
|
36
|
+
return useMemo(() => filterResult(permdock, permission, rows), [
|
|
37
|
+
permdock,
|
|
38
|
+
permission,
|
|
39
|
+
rows
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
function useTenant() {
|
|
43
|
+
const permdock = usePermDock();
|
|
44
|
+
return useMemo(() => tenantView(permdock), [permdock]);
|
|
45
|
+
}
|
|
46
|
+
function useMemberships() {
|
|
47
|
+
const permdock = usePermDock();
|
|
48
|
+
return useMemo(() => permdock.memberships(), [permdock]);
|
|
49
|
+
}
|
|
50
|
+
function useRoles(options = {}) {
|
|
51
|
+
const permdock = usePermDock();
|
|
52
|
+
const { tenant, team } = options;
|
|
53
|
+
return useMemo(() => rolesView(permdock, {
|
|
54
|
+
...tenant === void 0 ? {} : { tenant },
|
|
55
|
+
...team === void 0 ? {} : { team }
|
|
56
|
+
}), [
|
|
57
|
+
permdock,
|
|
58
|
+
tenant,
|
|
59
|
+
team
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
function useAssignableRoles() {
|
|
63
|
+
const permdock = usePermDock();
|
|
64
|
+
return useMemo(() => permdock.assignableRoles(), [permdock]);
|
|
65
|
+
}
|
|
66
|
+
function useAssignablePermissions(options = {}) {
|
|
67
|
+
const permdock = usePermDock();
|
|
68
|
+
const { tenant } = options;
|
|
69
|
+
return useMemo(() => permdock.assignablePermissions(tenant === void 0 ? {} : { tenant }), [permdock, tenant]);
|
|
70
|
+
}
|
|
71
|
+
function useSubject() {
|
|
72
|
+
const permdock = usePermDock();
|
|
73
|
+
return useMemo(() => subjectView(permdock), [permdock]);
|
|
74
|
+
}
|
|
75
|
+
function useApproval(decision) {
|
|
76
|
+
return approvalHandle(storeOf(usePermDock()), decision);
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/react/protected.tsx
|
|
80
|
+
function Protected(props) {
|
|
81
|
+
if (props.pending === void 0) return /* @__PURE__ */ jsx(Guard, { ...props });
|
|
82
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
83
|
+
fallback: props.pending,
|
|
84
|
+
children: /* @__PURE__ */ jsx(Guard, { ...props })
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function Guard(props) {
|
|
88
|
+
const root = usePermDock();
|
|
89
|
+
const local = usePermission(props.permission, props.data);
|
|
90
|
+
const scoped = useMemo(() => scopedTenant(root, props.tenant), [root, props.tenant]);
|
|
91
|
+
const view = protectedView(local, root, props.permission, props.data, scoped);
|
|
92
|
+
switch (view.slot) {
|
|
93
|
+
case "pending": return props.pending ?? null;
|
|
94
|
+
case "fallback": return typeof props.fallback === "function" ? props.fallback(view.decision) : props.fallback ?? null;
|
|
95
|
+
case "default": return typeof props.children === "function" ? props.children(view.decision) : props.children;
|
|
96
|
+
default: return view;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { useFilter as a, usePermission as c, useSubject as d, useTenant as f, useAssignableRoles as i, usePermissions as l, useApproval as n, useMemberships as o, useAssignablePermissions as r, usePermDock as s, Protected as t, useRoles as u };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Yn as Decision, er as GrantedDecision, ln as PermDock } from "./policy-CFZAr_Al.js";
|
|
2
|
+
import { f as Permission } from "./permissions-DttnqqxC.js";
|
|
3
|
+
import { t as PermissionBoundaryState } from "./boundary-BmHxVH1J.js";
|
|
4
|
+
import { s as PermissionState } from "./types-kxznc7cn.js";
|
|
5
|
+
import { t as ClientStore } from "./store-D_pjn91-.js";
|
|
6
|
+
import { Snippet } from "svelte";
|
|
7
|
+
//#region src/svelte/boundary.d.ts
|
|
8
|
+
type PermissionBoundaryProps = {
|
|
9
|
+
readonly children?: Snippet;
|
|
10
|
+
/** Rendered in place of the children when one throws `PermDockDeniedError`. */
|
|
11
|
+
readonly denied?: Snippet<[PermissionBoundaryState]>;
|
|
12
|
+
/** Rendered for `PermDockApprovalRequiredError`; defaults to `denied`. */
|
|
13
|
+
readonly approval?: Snippet<[PermissionBoundaryState]>;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/client/views.d.ts
|
|
17
|
+
/** What `Protected` renders: `pending` while an endpoint answer is in flight, `fallback` unless granted. */
|
|
18
|
+
type ProtectedView = (PermissionState & {
|
|
19
|
+
readonly slot: "pending" | "fallback";
|
|
20
|
+
}) | {
|
|
21
|
+
readonly allowed: true;
|
|
22
|
+
readonly status: PermissionState["status"];
|
|
23
|
+
readonly decision: GrantedDecision;
|
|
24
|
+
readonly slot: "default";
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/svelte/protected.d.ts
|
|
28
|
+
type ProtectedProps = {
|
|
29
|
+
readonly permission: Permission;
|
|
30
|
+
readonly data?: unknown;
|
|
31
|
+
readonly tenant?: string;
|
|
32
|
+
readonly children?: Snippet<[Decision]>;
|
|
33
|
+
readonly pending?: Snippet;
|
|
34
|
+
readonly fallback?: Snippet<[Decision]>;
|
|
35
|
+
};
|
|
36
|
+
/** The instance for `tenant`, built once per store change rather than once per check. */
|
|
37
|
+
declare function scopedFor(store: ClientStore, tenant: string | undefined, _generation?: number): PermDock | undefined;
|
|
38
|
+
declare function viewFor(store: ClientStore, reference: Permission, data: unknown, scoped: PermDock | undefined, _generation?: number): ProtectedView;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { PermissionBoundaryProps as i, scopedFor as n, viewFor as r, ProtectedProps as t };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { t as PermDockProviderProps } from "./types-C3s9xVJG.js";
|
|
2
|
+
import { ReactElement } from "react";
|
|
3
|
+
//#region src/react/provider.d.ts
|
|
4
|
+
declare function PermDockProvider(props: PermDockProviderProps): ReactElement;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { PermDockProvider as t };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { t as emptySnapshot } from "./from-snapshot-C3sHpZNS.js";
|
|
3
|
+
import { t as adapterStore } from "./store-options-yO0V6gRn.js";
|
|
4
|
+
import { i as PermDockStoreContext, n as useKeyed, r as PermDockSnapshotPromiseContext, t as useLiveOptions } from "./live-options-H2eG8dfJ.js";
|
|
5
|
+
import { useLayoutEffect } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
//#region src/react/provider.tsx
|
|
8
|
+
function PermDockProvider(props) {
|
|
9
|
+
const promise = props.snapshotPromise ?? null;
|
|
10
|
+
const suspend = props.suspend === true;
|
|
11
|
+
const awaiting = promise !== null && !suspend;
|
|
12
|
+
const live = useLiveOptions(props);
|
|
13
|
+
const store = useKeyed(() => adapterStore(compact({
|
|
14
|
+
endpoint: props.endpoint,
|
|
15
|
+
snapshotUrl: props.snapshotUrl,
|
|
16
|
+
approvals: props.approvals,
|
|
17
|
+
tenant: props.tenant,
|
|
18
|
+
fetch: live.fetch,
|
|
19
|
+
headers: live.headers,
|
|
20
|
+
maxAge: props.maxAge,
|
|
21
|
+
verifier: live.verifier,
|
|
22
|
+
awaiting,
|
|
23
|
+
passCache: true
|
|
24
|
+
}), props.snapshot ?? emptySnapshot()), [
|
|
25
|
+
props.snapshot,
|
|
26
|
+
props.endpoint,
|
|
27
|
+
props.snapshotUrl,
|
|
28
|
+
props.approvals,
|
|
29
|
+
props.tenant,
|
|
30
|
+
live.fetch,
|
|
31
|
+
live.headers,
|
|
32
|
+
props.maxAge,
|
|
33
|
+
live.verifier,
|
|
34
|
+
awaiting
|
|
35
|
+
]);
|
|
36
|
+
useLayoutEffect(() => {
|
|
37
|
+
if (promise !== null && !suspend) store.track(promise);
|
|
38
|
+
}, [
|
|
39
|
+
store,
|
|
40
|
+
promise,
|
|
41
|
+
suspend
|
|
42
|
+
]);
|
|
43
|
+
return /* @__PURE__ */ jsx(PermDockStoreContext, {
|
|
44
|
+
value: store,
|
|
45
|
+
children: /* @__PURE__ */ jsx(PermDockSnapshotPromiseContext, {
|
|
46
|
+
value: suspend ? promise : null,
|
|
47
|
+
children: props.children
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { PermDockProvider as t };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { t as emptySnapshot } from "./from-snapshot-C3sHpZNS.js";
|
|
3
|
+
import { i as isPromiseLike, t as adapterStore } from "./store-options-yO0V6gRn.js";
|
|
4
|
+
//#region src/client/provider-store.ts
|
|
5
|
+
/**
|
|
6
|
+
* Store options that read `read()` on every request, so a rotated token, a
|
|
7
|
+
* new `fetch` or a new verifier applies without rebuilding the store. A
|
|
8
|
+
* verifier is wired only when one is present at creation: it switches the
|
|
9
|
+
* store to signed snapshots.
|
|
10
|
+
*/
|
|
11
|
+
function liveOptions(read) {
|
|
12
|
+
return compact({
|
|
13
|
+
headers: () => read().headers,
|
|
14
|
+
fetch: (...args) => (read().fetch ?? fetch)(...args),
|
|
15
|
+
verifier: read().verifier === void 0 ? void 0 : { verify: (token, expectations) => {
|
|
16
|
+
const current = read().verifier;
|
|
17
|
+
return current === void 0 ? Promise.reject(/* @__PURE__ */ new Error("PermDock: the verifier option was removed.")) : current.verify(token, expectations);
|
|
18
|
+
} }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The store a Vue, Svelte or Solid provider owns. A promised snapshot keeps
|
|
23
|
+
* it `pending` until the promise settles; `undefined` starts empty.
|
|
24
|
+
*/
|
|
25
|
+
function providerStore(options, read, snapshot) {
|
|
26
|
+
const promised = isPromiseLike(snapshot);
|
|
27
|
+
const store = adapterStore(compact({
|
|
28
|
+
endpoint: options.endpoint,
|
|
29
|
+
snapshotUrl: options.snapshotUrl,
|
|
30
|
+
approvals: options.approvals,
|
|
31
|
+
tenant: options.tenant,
|
|
32
|
+
maxAge: options.maxAge,
|
|
33
|
+
...liveOptions(read)
|
|
34
|
+
}), promised || snapshot === void 0 ? emptySnapshot() : snapshot);
|
|
35
|
+
if (promised) store.follow(snapshot);
|
|
36
|
+
return store;
|
|
37
|
+
}
|
|
38
|
+
/** Refreshes for the tenant a reactive `tenant` option switched to; a failed refresh keeps the current answers. */
|
|
39
|
+
function switchTenant(store, tenant) {
|
|
40
|
+
if (tenant !== void 0) store.get().refresh({ tenant }).catch(() => void 0);
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { switchTenant as n, providerStore as t };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { n as requiredPlans } from "../problem-details-CkL50EEf.js";
|
|
2
|
+
import { i as describe } from "../describe-PdoqESvg.js";
|
|
3
|
+
import { t as approvalHeaders } from "../headers-Cf-zWvsO.js";
|
|
4
|
+
import { a as FilterResult, c as SubjectView, i as ClientStatus, l as TenantView, n as ApprovalState, o as PermissionSet, r as ClientPermDock, s as PermissionState, t as ApprovalHandle } from "../types-kxznc7cn.js";
|
|
5
|
+
import { n as ProtectedProps, t as PermDockProviderProps } from "../types-C3s9xVJG.js";
|
|
6
|
+
import { a as useFilter, c as usePermission, d as useSubject, f as useTenant, i as useAssignableRoles, l as usePermissions, n as useApproval, o as useMemberships, r as useAssignablePermissions, s as usePermDock, t as Protected, u as useRoles } from "../protected-CNsMzrVd.js";
|
|
7
|
+
import { t as PermDockProvider } from "../provider-Cjr62YMV.js";
|
|
8
|
+
export { type ApprovalHandle, type ApprovalState, type ClientPermDock, type ClientStatus, type FilterResult, PermDockProvider, type PermDockProviderProps, type PermissionSet, type PermissionState, Protected, type ProtectedProps, type SubjectView, type TenantView, approvalHeaders, describe, requiredPlans, useApproval, useAssignablePermissions, useAssignableRoles, useFilter, useMemberships, usePermDock, usePermission, usePermissions, useRoles, useSubject, useTenant };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { r as requiredPlans } from "../problem-details-_AMOYz-w.js";
|
|
3
|
+
import { t as describe } from "../describe-B_gVZEVi.js";
|
|
4
|
+
import { t as approvalHeaders } from "../headers-BZSDieNT.js";
|
|
5
|
+
import { a as useFilter, c as usePermission, d as useSubject, f as useTenant, i as useAssignableRoles, l as usePermissions, n as useApproval, o as useMemberships, r as useAssignablePermissions, s as usePermDock, t as Protected, u as useRoles } from "../protected-Cs6kTaHo.js";
|
|
6
|
+
import { t as PermDockProvider } from "../provider-DLzpb2Xz.js";
|
|
7
|
+
export { PermDockProvider, Protected, approvalHeaders, describe, requiredPlans, useApproval, useAssignablePermissions, useAssignableRoles, useFilter, useMemberships, usePermDock, usePermission, usePermissions, useRoles, useSubject, useTenant };
|