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,53 @@
|
|
|
1
|
+
import { a as listArg, i as globalArgs, t as COMMAND_DESCRIPTIONS } from "./commands-DWOrSQic.js";
|
|
2
|
+
import { n as ask, t as CANCELLED } from "./prompt-CXYhLfsS.js";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
//#region src/cli/commands/doctor.ts
|
|
5
|
+
function doctor(ctx) {
|
|
6
|
+
return defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "doctor",
|
|
9
|
+
description: COMMAND_DESCRIPTIONS.doctor
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
...globalArgs,
|
|
13
|
+
only: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Check codes or groups to run, repeatable",
|
|
16
|
+
valueHint: "codes"
|
|
17
|
+
},
|
|
18
|
+
fix: {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
description: "Apply safe fixes: install skills, regenerate the catalog"
|
|
21
|
+
},
|
|
22
|
+
strict: {
|
|
23
|
+
type: "boolean",
|
|
24
|
+
description: "Exit 1 on warnings too"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
async run({ args: parsed, rawArgs }) {
|
|
28
|
+
let fix = parsed.fix === true;
|
|
29
|
+
if (fix && ctx.interactive) {
|
|
30
|
+
const answer = await ask(`Install the Agent Skills and regenerate the catalog in ${ctx.cwd}?`);
|
|
31
|
+
if (answer === void 0) {
|
|
32
|
+
ctx.report(CANCELLED);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
fix = answer;
|
|
36
|
+
}
|
|
37
|
+
const result = await (await import("./doctor-WpvG6p4k.js")).runDoctor({
|
|
38
|
+
cwd: ctx.cwd,
|
|
39
|
+
config: ctx.config,
|
|
40
|
+
only: listArg(rawArgs, "only"),
|
|
41
|
+
json: ctx.json,
|
|
42
|
+
fix,
|
|
43
|
+
strict: parsed.strict === true,
|
|
44
|
+
color: ctx.color,
|
|
45
|
+
now: ctx.now,
|
|
46
|
+
io: ctx.io
|
|
47
|
+
});
|
|
48
|
+
ctx.report(result);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { doctor };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Ir as Condition, Pr as Subject, mn as WhereResult } from "../policy-CFZAr_Al.js";
|
|
2
|
+
import { r as RelationsMapping } from "../graph-sql-B-dsAT6j.js";
|
|
3
|
+
import { s as MembershipsMapping } from "../compile-CNnl6uIt.js";
|
|
4
|
+
import { n as WithSubjectOptions, t as RowCheck } from "../row-check-Dt35czLy.js";
|
|
5
|
+
import { SQL, Table } from "drizzle-orm";
|
|
6
|
+
//#region src/drizzle/types.d.ts
|
|
7
|
+
/** A column of the Drizzle table `T` or an `SQL` expression; anything for a structural stand-in. */
|
|
8
|
+
type DrizzleColumnOf<T> = T extends Table ? T["_"]["columns"][keyof T["_"]["columns"]] | SQL : unknown;
|
|
9
|
+
type DrizzleWhereOptions<T = unknown> = {
|
|
10
|
+
/** Condition field to column of the table passed to `toWhere`. */
|
|
11
|
+
readonly columns?: Readonly<Record<string, DrizzleColumnOf<T>>>;
|
|
12
|
+
readonly subject?: Subject;
|
|
13
|
+
readonly memberships?: MembershipsMapping;
|
|
14
|
+
/** Where the relation graph lives; graph grants compile to Postgres subqueries with it and are refused without. */
|
|
15
|
+
readonly relations?: RelationsMapping;
|
|
16
|
+
readonly now?: number;
|
|
17
|
+
readonly operators?: DrizzleOperators;
|
|
18
|
+
};
|
|
19
|
+
type DrizzleOperators = {
|
|
20
|
+
readonly and: (...args: unknown[]) => unknown;
|
|
21
|
+
readonly or: (...args: unknown[]) => unknown;
|
|
22
|
+
readonly not: (value: unknown) => unknown;
|
|
23
|
+
readonly eq: (column: unknown, value: unknown) => unknown;
|
|
24
|
+
readonly ne: (column: unknown, value: unknown) => unknown;
|
|
25
|
+
readonly gt: (column: unknown, value: unknown) => unknown;
|
|
26
|
+
readonly gte: (column: unknown, value: unknown) => unknown;
|
|
27
|
+
readonly lt: (column: unknown, value: unknown) => unknown;
|
|
28
|
+
readonly lte: (column: unknown, value: unknown) => unknown;
|
|
29
|
+
readonly inArray: (column: unknown, values: readonly unknown[]) => unknown;
|
|
30
|
+
readonly notInArray: (column: unknown, values: readonly unknown[]) => unknown;
|
|
31
|
+
readonly isNull: (column: unknown) => unknown;
|
|
32
|
+
readonly isNotNull: (column: unknown) => unknown;
|
|
33
|
+
readonly like: (column: unknown, value: unknown) => unknown;
|
|
34
|
+
readonly sql: (strings: TemplateStringsArray, ...values: unknown[]) => unknown;
|
|
35
|
+
};
|
|
36
|
+
type DrizzleWithSubjectOptions = WithSubjectOptions & {
|
|
37
|
+
/** `import * as operators from 'drizzle-orm'`, on runtimes without `require`. */
|
|
38
|
+
readonly operators?: DrizzleOperators;
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/drizzle/to-where.d.ts
|
|
42
|
+
/** Compiles a condition into a Drizzle `SQL` filter over `table`; no grant compiles to `false`. */
|
|
43
|
+
export declare function toWhere<T extends object>(input: Condition | WhereResult, table: T, options?: DrizzleWhereOptions<T>): SQL;
|
|
44
|
+
type DrizzleDatabase<Tx> = {
|
|
45
|
+
transaction<T>(fn: (tx: Tx) => Promise<T>): Promise<T>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Runs `fn` in a transaction whose role and claims are `permdock.subject`'s, so the generated
|
|
49
|
+
* RLS policies decide for the same subject as the in-process checks.
|
|
50
|
+
*/
|
|
51
|
+
export declare function withSubject<Tx extends {
|
|
52
|
+
execute(query: never): unknown;
|
|
53
|
+
}, T>(db: DrizzleDatabase<Tx>, permdock: {
|
|
54
|
+
readonly subject: Subject;
|
|
55
|
+
}, fn: (tx: Tx) => Promise<T>, options?: DrizzleWithSubjectOptions): Promise<T>;
|
|
56
|
+
type DrizzleSelectable = {
|
|
57
|
+
select(fields: Record<string, unknown>): {
|
|
58
|
+
from(table: never): {
|
|
59
|
+
where(where: unknown): {
|
|
60
|
+
limit(count: number): PromiseLike<readonly {
|
|
61
|
+
readonly granted?: unknown;
|
|
62
|
+
}[]>;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* One query for one row: `{ found: false }` when `key` matches nothing, otherwise whether the
|
|
69
|
+
* permission filter keeps the row. Throws when `key` matches more than one row.
|
|
70
|
+
*/
|
|
71
|
+
export declare function checkRow<T extends object>(db: DrizzleSelectable, table: T, input: Condition | WhereResult, key: SQL, options?: DrizzleWhereOptions<T>): Promise<RowCheck>;
|
|
72
|
+
//#endregion
|
|
73
|
+
export type { DrizzleOperators, DrizzleWhereOptions, DrizzleWithSubjectOptions, MembershipsMapping, RelationsMapping, RowCheck, WithSubjectOptions };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { t as compact } from "../compact-y6vfu2_f.js";
|
|
2
|
+
import { w as assertSafeKey } from "../permissions-DVoF6dMt.js";
|
|
3
|
+
import { n as escapeLike, t as compileWhere } from "../compile-Ba4blROR.js";
|
|
4
|
+
import { i as rowCheckFrom, r as subjectStatements, t as statementTemplate } from "../subject-settings-BwBmCdTR.js";
|
|
5
|
+
//#region src/drizzle/to-where.ts
|
|
6
|
+
function loadOperators(injected) {
|
|
7
|
+
if (injected !== void 0) return injected;
|
|
8
|
+
const loader = globalThis.process?.getBuiltinModule?.("node:module");
|
|
9
|
+
try {
|
|
10
|
+
if (loader === void 0) throw new Error("no module loader");
|
|
11
|
+
return loader.createRequire(import.meta.url)("drizzle-orm");
|
|
12
|
+
} catch {
|
|
13
|
+
throw new Error("PermDock: permdock/drizzle requires the drizzle-orm peer; pass `operators` on runtimes without require");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function ident(name) {
|
|
17
|
+
assertSafeKey(name, "sql identifier");
|
|
18
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(name)) throw new Error(`PermDock: unsafe SQL identifier '${name}'`);
|
|
19
|
+
return name;
|
|
20
|
+
}
|
|
21
|
+
function column(table, field, columns) {
|
|
22
|
+
assertSafeKey(field, "condition field");
|
|
23
|
+
const mapped = (columns !== void 0 && Object.hasOwn(columns, field) ? columns[field] : void 0) ?? (Object.hasOwn(table, field) ? table[field] : void 0);
|
|
24
|
+
if (mapped === void 0 || typeof mapped === "function") throw new Error(`PermDock: unknown column '${field}'`);
|
|
25
|
+
return mapped;
|
|
26
|
+
}
|
|
27
|
+
/** Drizzle's Postgres array columns (`text().array()`) report `dataType: 'array'`. */
|
|
28
|
+
function isArrayColumn(col) {
|
|
29
|
+
if (col === null || typeof col !== "object") return false;
|
|
30
|
+
const { dataType, dimensions } = col;
|
|
31
|
+
return dataType === "array" || typeof dimensions === "number" && dimensions > 0;
|
|
32
|
+
}
|
|
33
|
+
function tagged(parts, ops) {
|
|
34
|
+
const strings = [""];
|
|
35
|
+
const values = [];
|
|
36
|
+
for (const part of parts) if ("text" in part) strings[strings.length - 1] += part.text;
|
|
37
|
+
else {
|
|
38
|
+
values.push(part.value);
|
|
39
|
+
strings.push("");
|
|
40
|
+
}
|
|
41
|
+
const template = strings;
|
|
42
|
+
Object.defineProperty(template, "raw", { value: strings });
|
|
43
|
+
return ops.sql(template, ...values);
|
|
44
|
+
}
|
|
45
|
+
function existsSql(node, table, options, ops) {
|
|
46
|
+
const m = (name) => `m.${ident(name)}`;
|
|
47
|
+
const parts = [
|
|
48
|
+
{ text: `exists (select 1 from ${ident(node.table)} m where ${m(node.rowColumn)} = ` },
|
|
49
|
+
{ value: column(table, node.rowField, options.columns) },
|
|
50
|
+
{ text: ` and ${m(node.user)} = ` },
|
|
51
|
+
{ value: node.userValue }
|
|
52
|
+
];
|
|
53
|
+
if (node.roles.length > 0) {
|
|
54
|
+
parts.push({ text: ` and ${m(node.role)} in (` });
|
|
55
|
+
for (const [index, role] of node.roles.entries()) {
|
|
56
|
+
if (index > 0) parts.push({ text: ", " });
|
|
57
|
+
parts.push({ value: role });
|
|
58
|
+
}
|
|
59
|
+
parts.push({ text: ")" });
|
|
60
|
+
}
|
|
61
|
+
if (node.expiresAt !== void 0) {
|
|
62
|
+
const expires = m(node.expiresAt);
|
|
63
|
+
parts.push({ text: ` and (${expires} is null or ${expires} > ` }, { value: node.now }, { text: ")" });
|
|
64
|
+
}
|
|
65
|
+
if (node.tenantColumn !== void 0 && node.tenantValue !== void 0) {
|
|
66
|
+
const tenant = m(node.tenantColumn);
|
|
67
|
+
parts.push({ text: ` and (${tenant} is null or ${tenant} = ` }, { value: node.tenantValue }, { text: ")" });
|
|
68
|
+
}
|
|
69
|
+
if (node.resourceColumn !== void 0 && node.resourceValue !== void 0) parts.push({ text: ` and ${m(node.resourceColumn)} = ` }, { value: node.resourceValue });
|
|
70
|
+
parts.push({ text: ")" });
|
|
71
|
+
return tagged(parts, ops);
|
|
72
|
+
}
|
|
73
|
+
function containsSql(col, value, ops) {
|
|
74
|
+
if (isArrayColumn(col)) return tagged([
|
|
75
|
+
{ value },
|
|
76
|
+
{ text: " = any(" },
|
|
77
|
+
{ value: col },
|
|
78
|
+
{ text: ")" }
|
|
79
|
+
], ops);
|
|
80
|
+
if (typeof value === "string") return ops.like(col, `%${escapeLike(value)}%`);
|
|
81
|
+
return tagged([
|
|
82
|
+
{ value: col },
|
|
83
|
+
{ text: " @> " },
|
|
84
|
+
{ value }
|
|
85
|
+
], ops);
|
|
86
|
+
}
|
|
87
|
+
function render(node, table, options, ops) {
|
|
88
|
+
switch (node.kind) {
|
|
89
|
+
case "never": return ops.sql`false`;
|
|
90
|
+
case "always": return ops.sql`true`;
|
|
91
|
+
case "isNull": {
|
|
92
|
+
const col = column(table, node.field, options.columns);
|
|
93
|
+
return node.negated ? ops.isNotNull(col) : ops.isNull(col);
|
|
94
|
+
}
|
|
95
|
+
case "and": return ops.and(...node.items.map((item) => render(item, table, options, ops)));
|
|
96
|
+
case "or": return ops.or(...node.items.map((item) => render(item, table, options, ops)));
|
|
97
|
+
case "not": return ops.not(render(node.item, table, options, ops));
|
|
98
|
+
case "exists": return existsSql(node, table, options, ops);
|
|
99
|
+
case "sql": return tagged(node.parts.map((part) => {
|
|
100
|
+
if ("text" in part) return part;
|
|
101
|
+
if ("column" in part) return { value: column(table, part.column, options.columns) };
|
|
102
|
+
return { value: "subject" in part ? node.subject : part.value };
|
|
103
|
+
}), ops);
|
|
104
|
+
case "compare": {
|
|
105
|
+
const col = column(table, node.field, options.columns);
|
|
106
|
+
switch (node.op) {
|
|
107
|
+
case "eq": return ops.eq(col, node.value);
|
|
108
|
+
case "ne": return ops.ne(col, node.value);
|
|
109
|
+
case "gt": return ops.gt(col, node.value);
|
|
110
|
+
case "gte": return ops.gte(col, node.value);
|
|
111
|
+
case "lt": return ops.lt(col, node.value);
|
|
112
|
+
case "lte": return ops.lte(col, node.value);
|
|
113
|
+
case "in": return ops.inArray(col, node.value);
|
|
114
|
+
case "notIn": return ops.notInArray(col, node.value);
|
|
115
|
+
case "contains": return containsSql(col, node.value, ops);
|
|
116
|
+
/* v8 ignore next 4 */
|
|
117
|
+
default: {
|
|
118
|
+
const exhaustive = node.op;
|
|
119
|
+
throw new Error(`PermDock: unknown compare '${String(exhaustive)}'`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/* v8 ignore next 6 */
|
|
124
|
+
default: throw new Error(`PermDock: unknown compiled node '${String(node)}'`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Compiles a condition into a Drizzle `SQL` filter over `table`; no grant compiles to `false`. */
|
|
128
|
+
function toWhere(input, table, options = {}) {
|
|
129
|
+
return render(compileWhere(input, compact({
|
|
130
|
+
subject: options.subject,
|
|
131
|
+
memberships: options.memberships,
|
|
132
|
+
now: options.now,
|
|
133
|
+
relations: options.relations
|
|
134
|
+
})), table, options, loadOperators(options.operators));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Runs `fn` in a transaction whose role and claims are `permdock.subject`'s, so the generated
|
|
138
|
+
* RLS policies decide for the same subject as the in-process checks.
|
|
139
|
+
*/
|
|
140
|
+
function withSubject(db, permdock, fn, options = {}) {
|
|
141
|
+
const statements = subjectStatements(permdock, options);
|
|
142
|
+
const { sql } = loadOperators(options.operators);
|
|
143
|
+
return db.transaction(async (tx) => {
|
|
144
|
+
const execute = tx.execute.bind(tx);
|
|
145
|
+
for (const statement of statements) await execute(sql(statementTemplate(statement), ...statement.values));
|
|
146
|
+
return fn(tx);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* One query for one row: `{ found: false }` when `key` matches nothing, otherwise whether the
|
|
151
|
+
* permission filter keeps the row. Throws when `key` matches more than one row.
|
|
152
|
+
*/
|
|
153
|
+
async function checkRow(db, table, input, key, options = {}) {
|
|
154
|
+
const { sql } = loadOperators(options.operators);
|
|
155
|
+
const filter = toWhere(input, table, options);
|
|
156
|
+
const rows = await db.select({ granted: sql`coalesce((${filter}), false)` }).from(table).where(key).limit(2);
|
|
157
|
+
return rowCheckFrom(rows);
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
export { checkRow, toWhere, withSubject };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/core/duration.ts
|
|
2
|
+
/**
|
|
3
|
+
* Parses a duration string (`'30s'`, `'15m'`, `'4h'`, `'7d'`, `'2w'`) into
|
|
4
|
+
* whole seconds. Fail-closed: a malformed or non-positive duration is
|
|
5
|
+
* `undefined`, and every caller treats that as "no bound", never a default.
|
|
6
|
+
*/
|
|
7
|
+
const UNITS = {
|
|
8
|
+
s: 1,
|
|
9
|
+
m: 60,
|
|
10
|
+
h: 3600,
|
|
11
|
+
d: 86400,
|
|
12
|
+
w: 604800
|
|
13
|
+
};
|
|
14
|
+
function parseDuration(input) {
|
|
15
|
+
if (typeof input === "number") return Number.isFinite(input) && input > 0 ? Math.floor(input) : void 0;
|
|
16
|
+
if (typeof input !== "string") return;
|
|
17
|
+
const match = /^(\d+)(s|m|h|d|w)$/u.exec(input.trim());
|
|
18
|
+
if (match === null) return;
|
|
19
|
+
const amount = Number(match[1]);
|
|
20
|
+
const unit = UNITS[match[2] ?? ""];
|
|
21
|
+
if (unit === void 0 || !Number.isFinite(amount) || amount <= 0) return;
|
|
22
|
+
return amount * unit;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { parseDuration as t };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { C as Policy, D as PolicyVocabulary, Nr as Principal, ln as PermDock } from "../policy-CFZAr_Al.js";
|
|
2
|
+
import { f as Permission } from "../permissions-DttnqqxC.js";
|
|
3
|
+
import { n as RevocationFeed } from "../revocations-Cy06JNx2.js";
|
|
4
|
+
import { A as ConnectionOptions, O as Connection, h as InvalidSignatureError, i as ProtectOptions, n as OpenApiHooks, w as verifyWebBotAuth, x as discoverViaSignatureAgent } from "../create-BWyx3jua.js";
|
|
5
|
+
import { t as ServerAdapterOptions } from "../bind-CVy3Espv.js";
|
|
6
|
+
import { Elysia } from "elysia";
|
|
7
|
+
//#region src/elysia/create.d.ts
|
|
8
|
+
type ElysiaCtx = {
|
|
9
|
+
readonly request: Request;
|
|
10
|
+
readonly body?: unknown;
|
|
11
|
+
readonly params?: Readonly<Record<string, string | undefined>>;
|
|
12
|
+
};
|
|
13
|
+
type ElysiaPermDockOptions<TUser = unknown> = ServerAdapterOptions<ElysiaCtx, TUser> & {
|
|
14
|
+
/** Ends or revalidates open sockets. */
|
|
15
|
+
readonly revocations?: RevocationFeed;
|
|
16
|
+
};
|
|
17
|
+
/** The `ws` Elysia passes to `.ws` handlers; `data` is the upgrade context. */
|
|
18
|
+
type ElysiaSocket = {
|
|
19
|
+
readonly data: ElysiaCtx;
|
|
20
|
+
close(code?: number, reason?: string): unknown;
|
|
21
|
+
};
|
|
22
|
+
type ElysiaContext<V extends PolicyVocabulary = PolicyVocabulary> = ElysiaCtx & {
|
|
23
|
+
permdock: PermDock<V>;
|
|
24
|
+
permdockData?: unknown;
|
|
25
|
+
};
|
|
26
|
+
type ElysiaProtect = (permission: Permission | null, loadData?: (ctx: ElysiaCtx) => unknown, protectOptions?: ProtectOptions) => (ctx: ElysiaCtx) => Promise<Response | undefined>;
|
|
27
|
+
/** The `permdock()` plugin: its global derive types `permdock` in every later handler. */
|
|
28
|
+
type ElysiaPermDockPlugin<V extends PolicyVocabulary = PolicyVocabulary> = Elysia<"", {
|
|
29
|
+
decorator: Record<never, never>;
|
|
30
|
+
store: Record<never, never>;
|
|
31
|
+
derive: {
|
|
32
|
+
readonly permdock: PermDock<V>;
|
|
33
|
+
};
|
|
34
|
+
resolve: Record<never, never>;
|
|
35
|
+
}>;
|
|
36
|
+
type ElysiaPermDock<V extends PolicyVocabulary = PolicyVocabulary> = {
|
|
37
|
+
readonly permdock: () => ElysiaPermDockPlugin<V>;
|
|
38
|
+
readonly protect: ElysiaProtect;
|
|
39
|
+
/**
|
|
40
|
+
* One connection per socket: the same promise for every handler
|
|
41
|
+
* of that socket; closes it with `1008` when the connection aborts.
|
|
42
|
+
*/
|
|
43
|
+
readonly connection: (ws: ElysiaSocket, connectionOptions?: ConnectionOptions) => Promise<Connection>;
|
|
44
|
+
readonly permdockHandler: () => Elysia;
|
|
45
|
+
readonly openapi: OpenApiHooks;
|
|
46
|
+
};
|
|
47
|
+
export declare function createPermDock<TUser, TPrincipal extends Principal = Principal, V extends PolicyVocabulary = PolicyVocabulary>(policy: Policy<TUser, TPrincipal, V>, options: ElysiaPermDockOptions<TUser>): ElysiaPermDock<V>;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { type ElysiaContext, type ElysiaCtx, type ElysiaPermDock, type ElysiaPermDockOptions, type ElysiaProtect, type ElysiaSocket, InvalidSignatureError, discoverViaSignatureAgent, verifyWebBotAuth };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { i as parsedBody, n as hasCredentials } from "../http-SO7qGttf.js";
|
|
2
|
+
import { i as discoverViaSignatureAgent, r as InvalidSignatureError, s as verifyWebBotAuth } from "../evaluations-tz6D9A2G.js";
|
|
3
|
+
import { t as problemFromError } from "../map-error-pgUWNNtG.js";
|
|
4
|
+
import { a as socketConnection, i as decorate, r as bindKernel } from "../bind-VnYn2HKq.js";
|
|
5
|
+
import { i as onRevoked, t as POLICY_VIOLATION } from "../stream-DDpvynSB.js";
|
|
6
|
+
import { Elysia } from "elysia";
|
|
7
|
+
//#region src/elysia/create.ts
|
|
8
|
+
function createPermDock(policy, options) {
|
|
9
|
+
const seed = globalThis.crypto.randomUUID();
|
|
10
|
+
const { kernel, bind, scopeOf, handlerScope } = bindKernel(policy, options, "elysia", toRequest);
|
|
11
|
+
const permdock = () => new Elysia({
|
|
12
|
+
name: "permdock",
|
|
13
|
+
seed
|
|
14
|
+
}).derive({ as: "global" }, async (ctx) => {
|
|
15
|
+
const instance = await kernel.permdock(bind(ctx), await scopeOf(ctx));
|
|
16
|
+
decorate(ctx, instance);
|
|
17
|
+
return { permdock: instance };
|
|
18
|
+
}).onError({ as: "global" }, ({ error, request }) => problemFromError(error, { credentials: hasCredentials(request) }));
|
|
19
|
+
const protect = (permission, loadData, protectOptions) => async (ctx) => {
|
|
20
|
+
const guard = await kernel.protect(permission, loadData === void 0 ? void 0 : () => loadData(ctx), protectOptions)(bind(ctx), await scopeOf(ctx));
|
|
21
|
+
if (!guard.ok) return guard.response;
|
|
22
|
+
decorate(ctx, guard.permdock, guard.data);
|
|
23
|
+
};
|
|
24
|
+
const sockets = /* @__PURE__ */ new WeakMap();
|
|
25
|
+
const connection = (ws, connectionOptions) => socketConnection(sockets, ws.data, async () => {
|
|
26
|
+
const conn = await kernel.connection(bind(ws.data), connectionOptions, await scopeOf(ws.data));
|
|
27
|
+
onRevoked(conn, (problem) => {
|
|
28
|
+
ws.close(POLICY_VIOLATION, problem.type);
|
|
29
|
+
});
|
|
30
|
+
return conn;
|
|
31
|
+
});
|
|
32
|
+
const permdockHandler = () => {
|
|
33
|
+
const { POST, GET } = kernel.permdockHandler(handlerScope);
|
|
34
|
+
return new Elysia({
|
|
35
|
+
name: "permdock-handler",
|
|
36
|
+
seed
|
|
37
|
+
}).post("/", (ctx) => POST(bind(ctx))).get("/", (ctx) => GET(bind(ctx)));
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
permdock,
|
|
41
|
+
protect,
|
|
42
|
+
connection,
|
|
43
|
+
permdockHandler,
|
|
44
|
+
openapi: kernel.openapi
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function toRequest(ctx) {
|
|
48
|
+
const method = ctx.request.method;
|
|
49
|
+
if (method === "GET" || method === "HEAD" || ctx.body === void 0) return ctx.request;
|
|
50
|
+
const headers = new Headers(ctx.request.headers);
|
|
51
|
+
const body = parsedBody(ctx.body, headers) ?? null;
|
|
52
|
+
return new Request(ctx.request.url, {
|
|
53
|
+
method,
|
|
54
|
+
headers,
|
|
55
|
+
body
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { InvalidSignatureError, createPermDock, discoverViaSignatureAgent, verifyWebBotAuth };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
2
|
+
//#region src/cli/errors.ts
|
|
3
|
+
var CliError = class extends Error {
|
|
4
|
+
kind;
|
|
5
|
+
constructor(kind, message, options) {
|
|
6
|
+
super(message, options);
|
|
7
|
+
this.name = "CliError";
|
|
8
|
+
this.kind = kind;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const TITLES = {
|
|
12
|
+
usage: "Usage or configuration error",
|
|
13
|
+
unavailable: "A database or service the command needs did not answer",
|
|
14
|
+
failed: "The check the command ran found a problem"
|
|
15
|
+
};
|
|
16
|
+
function describeError(error) {
|
|
17
|
+
return error instanceof Error ? error.message : String(error);
|
|
18
|
+
}
|
|
19
|
+
/** An unclassified error is a usage error: a module that throws while loading is the project's to fix. */
|
|
20
|
+
function cliErrorKind(error) {
|
|
21
|
+
return error instanceof CliError ? error.kind : "usage";
|
|
22
|
+
}
|
|
23
|
+
function exitCodeOf(kind) {
|
|
24
|
+
return kind === "usage" ? 2 : 1;
|
|
25
|
+
}
|
|
26
|
+
function cliProblem(kind, message, command) {
|
|
27
|
+
return {
|
|
28
|
+
type: `https://permdock.com/problems/cli-${kind}`,
|
|
29
|
+
title: TITLES[kind],
|
|
30
|
+
detail: stripVTControlCharacters(message),
|
|
31
|
+
...command === void 0 ? {} : { command },
|
|
32
|
+
exitCode: exitCodeOf(kind)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The result a command reports for a usage error it caught. A `CliError`
|
|
37
|
+
* propagates instead, so `run()` prints it, as Problem Details under `--json`.
|
|
38
|
+
*/
|
|
39
|
+
function usageResult(error) {
|
|
40
|
+
if (error instanceof CliError) throw error;
|
|
41
|
+
return {
|
|
42
|
+
code: 2,
|
|
43
|
+
output: describeError(error)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { exitCodeOf as a, describeError as i, cliErrorKind as n, usageResult as o, cliProblem as r, CliError as t };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { t as PROBLEM_BASE } from "./validation-error-CnjZ4t92.js";
|
|
3
|
+
import { a as wireDenials, n as problemDetails } from "./problem-details-_AMOYz-w.js";
|
|
4
|
+
import { n as deniedDigest, t as approvalDigest } from "./digest-BI-6aa6d.js";
|
|
5
|
+
//#region src/core/errors.ts
|
|
6
|
+
var PermDockDeniedError = class extends Error {
|
|
7
|
+
name = "PermDockDeniedError";
|
|
8
|
+
decision;
|
|
9
|
+
permission;
|
|
10
|
+
scope;
|
|
11
|
+
resource;
|
|
12
|
+
subject;
|
|
13
|
+
/** The resource's `disclosure` when the denied check carried a row; `'hide'` answers as `404`. */
|
|
14
|
+
disclosure;
|
|
15
|
+
/** `PERMDOCK_DENIED;<permission>`; survives the Server Component boundary (`parsePermDockDigest`). */
|
|
16
|
+
digest;
|
|
17
|
+
constructor(input) {
|
|
18
|
+
super(input.message);
|
|
19
|
+
this.decision = input.decision;
|
|
20
|
+
this.permission = input.permission;
|
|
21
|
+
this.scope = input.scope;
|
|
22
|
+
this.resource = input.resource;
|
|
23
|
+
this.subject = input.subject;
|
|
24
|
+
if (input.disclosure !== void 0) this.disclosure = input.disclosure;
|
|
25
|
+
this.digest = deniedDigest(input.permission);
|
|
26
|
+
}
|
|
27
|
+
/** The same status matrix as `protect`: `401`, `404`, `429`, `503` or `403`. */
|
|
28
|
+
toProblemDetails(options) {
|
|
29
|
+
return problemDetails(compact({
|
|
30
|
+
decision: this.decision,
|
|
31
|
+
detail: this.message,
|
|
32
|
+
instance: options?.instance,
|
|
33
|
+
permission: this.permission,
|
|
34
|
+
scope: this.scope,
|
|
35
|
+
resource: this.resource,
|
|
36
|
+
disclosure: options?.disclosure ?? this.disclosure
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var PermDockApprovalRequiredError = class extends Error {
|
|
41
|
+
name = "PermDockApprovalRequiredError";
|
|
42
|
+
decision;
|
|
43
|
+
permission;
|
|
44
|
+
scope;
|
|
45
|
+
resource;
|
|
46
|
+
token;
|
|
47
|
+
reason;
|
|
48
|
+
/** `PERMDOCK_APPROVAL_REQUIRED;<permission>;<token>`; the token is already bound to this subject. */
|
|
49
|
+
digest;
|
|
50
|
+
constructor(input) {
|
|
51
|
+
super(input.message);
|
|
52
|
+
this.decision = input.decision;
|
|
53
|
+
this.permission = input.permission;
|
|
54
|
+
this.scope = input.scope;
|
|
55
|
+
this.resource = input.resource;
|
|
56
|
+
this.token = input.decision.token;
|
|
57
|
+
this.reason = input.decision.reason;
|
|
58
|
+
this.digest = approvalDigest(input.permission, input.decision.token);
|
|
59
|
+
}
|
|
60
|
+
toProblemDetails(options) {
|
|
61
|
+
return problemDetails(compact({
|
|
62
|
+
decision: this.decision,
|
|
63
|
+
detail: this.message,
|
|
64
|
+
instance: options?.instance,
|
|
65
|
+
permission: this.permission,
|
|
66
|
+
scope: this.scope,
|
|
67
|
+
resource: this.resource
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
/** The `name` of the deny grant a `deny` denial carries in `detail`, if any. */
|
|
72
|
+
function denyName(detail) {
|
|
73
|
+
if (detail === null || typeof detail !== "object" || !("name" in detail)) return;
|
|
74
|
+
return typeof detail.name === "string" ? detail.name : void 0;
|
|
75
|
+
}
|
|
76
|
+
function deniedMessage(permission, subjectId, denials, alternatives, named = true) {
|
|
77
|
+
const clauses = denials.map((denial) => {
|
|
78
|
+
const name = denial.reason === "deny" ? denyName(denial.detail) : void 0;
|
|
79
|
+
return name === void 0 ? `${denial.role ?? "none"} (${denial.reason})` : `${denial.role ?? "none"} (${denial.reason} '${name}')`;
|
|
80
|
+
}).join(", ");
|
|
81
|
+
const alt = alternatives.length === 0 ? "" : ` Alternatives: ${alternatives.join(", ")}.`;
|
|
82
|
+
return `${permission} denied${named ? ` for subject ${subjectId ?? "anonymous"}` : ""}: ${clauses}.${alt}`;
|
|
83
|
+
}
|
|
84
|
+
function approvalMessage(permission, reason, token) {
|
|
85
|
+
return `${permission} requires human approval (${reason}). Token: ${token}.`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The `reason` of a long-lived connection's aborted `signal`. `denied` carries
|
|
89
|
+
* the decision that re-denied the permission the connection was opened for.
|
|
90
|
+
*/
|
|
91
|
+
var PermDockRevokedError = class extends Error {
|
|
92
|
+
name = "PermDockRevokedError";
|
|
93
|
+
code;
|
|
94
|
+
permission;
|
|
95
|
+
decision;
|
|
96
|
+
constructor(input) {
|
|
97
|
+
super(`PermDock: connection ended (${input.code}).`);
|
|
98
|
+
this.code = input.code;
|
|
99
|
+
if (input.permission !== void 0) this.permission = input.permission;
|
|
100
|
+
if (input.decision !== void 0) this.decision = input.decision;
|
|
101
|
+
}
|
|
102
|
+
toProblemDetails(options) {
|
|
103
|
+
if (this.code === "denied") return compact({
|
|
104
|
+
type: `${PROBLEM_BASE}/denied`,
|
|
105
|
+
title: "Permission denied",
|
|
106
|
+
status: 403,
|
|
107
|
+
detail: this.code,
|
|
108
|
+
instance: options?.instance,
|
|
109
|
+
permission: this.permission,
|
|
110
|
+
denials: this.decision?.outcome === "denied" ? wireDenials(this.decision.denials) : void 0
|
|
111
|
+
});
|
|
112
|
+
return compact({
|
|
113
|
+
type: `${PROBLEM_BASE}/unauthenticated`,
|
|
114
|
+
title: "Authorization ended",
|
|
115
|
+
status: 401,
|
|
116
|
+
detail: this.code,
|
|
117
|
+
instance: options?.instance,
|
|
118
|
+
permission: this.permission
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
//#endregion
|
|
123
|
+
export { deniedMessage as a, approvalMessage as i, PermDockDeniedError as n, PermDockRevokedError as r, PermDockApprovalRequiredError as t };
|