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,421 @@
|
|
|
1
|
+
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
+
import { n as freezeDeep } from "./freeze-CrU8nQeX.js";
|
|
3
|
+
import { i as findPermission, s as getRegistry } from "./permissions-DVoF6dMt.js";
|
|
4
|
+
import { r as approverLeaves } from "./approvers-DT4AVyIg.js";
|
|
5
|
+
import { t as describe } from "./describe-B_gVZEVi.js";
|
|
6
|
+
import { t as parseDuration } from "./duration-xK2jGFVc.js";
|
|
7
|
+
import { i as relationReader, n as pendingRelations, o as resolveRelated } from "./relations-cjOL01hZ.js";
|
|
8
|
+
import { t as ApprovalError } from "./errors-DRnGZHzF.js";
|
|
9
|
+
import { f as approverRelationKey, l as APPROVAL_HEADER, n as assertApprover, s as listAllApprovals } from "./store-DMAWwAJV.js";
|
|
10
|
+
//#region src/approvals/relations.ts
|
|
11
|
+
const DEFAULT_PARENT_DEPTH = 16;
|
|
12
|
+
/** Every approver a request names: `by`, each stage and its escalation, and `escalation.to`, inside `anyOf` groups too. */
|
|
13
|
+
function requestApprovers(approvers) {
|
|
14
|
+
return [
|
|
15
|
+
...approverLeaves(approvers.by),
|
|
16
|
+
...(approvers.stages ?? []).flatMap((stage) => approverLeaves(stage.by).concat(approverLeaves(stage.escalation?.to))),
|
|
17
|
+
...approverLeaves(approvers.escalation?.to)
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
/** Reads until nothing is in flight: each round loads one more layer of facts. */
|
|
21
|
+
async function settled(read, unread, cache) {
|
|
22
|
+
for (;;) {
|
|
23
|
+
const value = read();
|
|
24
|
+
if (!unread(value)) return value;
|
|
25
|
+
const pending = pendingRelations(cache);
|
|
26
|
+
if (pending.length === 0) return value;
|
|
27
|
+
await Promise.all(pending);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** The id of `item.resource` the walk starts from, after following `through` links. */
|
|
31
|
+
async function startOf(item, resource, id, reader, cache, registry) {
|
|
32
|
+
if (!Array.isArray(item.through)) return resource === item.resource ? id : void 0;
|
|
33
|
+
let current = resource;
|
|
34
|
+
let at = id;
|
|
35
|
+
for (const link of item.through) {
|
|
36
|
+
const node = registry.get(current);
|
|
37
|
+
const target = node !== void 0 && Object.hasOwn(node.links, link) ? node.links[link] : void 0;
|
|
38
|
+
if (target === void 0) return;
|
|
39
|
+
const query = {
|
|
40
|
+
resource: current,
|
|
41
|
+
id: at,
|
|
42
|
+
depth: 1,
|
|
43
|
+
through: link
|
|
44
|
+
};
|
|
45
|
+
const chain = await settled(() => reader.chain(query), (value) => value === "pending", cache);
|
|
46
|
+
const next = chain === "pending" || chain === "failed" ? void 0 : chain.ancestors[0]?.id;
|
|
47
|
+
if (next === void 0) return;
|
|
48
|
+
current = target.resource;
|
|
49
|
+
at = next;
|
|
50
|
+
}
|
|
51
|
+
return current === item.resource ? at : void 0;
|
|
52
|
+
}
|
|
53
|
+
function depthOf(item) {
|
|
54
|
+
if (item.through === "parent") return item.depth ?? DEFAULT_PARENT_DEPTH;
|
|
55
|
+
return item.depth ?? 0;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The relation approvers of `request` that `subject` holds on its resource,
|
|
59
|
+
* keyed by `approverRelationKey`, for `ApprovalVerdict.relations`. Reads go
|
|
60
|
+
* through `relations` by the request's resource id; a request without an id,
|
|
61
|
+
* a missing source or a read that fails holds nothing.
|
|
62
|
+
*/
|
|
63
|
+
async function approverRelations(request, subject, options) {
|
|
64
|
+
const approvers = request.approvers;
|
|
65
|
+
const id = request.resource.id;
|
|
66
|
+
if (approvers === void 0 || id === void 0 || options.relations === void 0 || options.permissions === void 0 || subject.principal === null) return [];
|
|
67
|
+
const items = /* @__PURE__ */ new Map();
|
|
68
|
+
for (const item of requestApprovers(approvers)) if (item.kind === "relation") items.set(approverRelationKey(item), item);
|
|
69
|
+
if (items.size === 0) return [];
|
|
70
|
+
const registry = getRegistry(options.permissions);
|
|
71
|
+
const cache = /* @__PURE__ */ new Map();
|
|
72
|
+
const reader = relationReader(options.relations, cache, registry);
|
|
73
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3;
|
|
74
|
+
const holds = async (item) => {
|
|
75
|
+
const start = await startOf(item, request.resource.type, id, reader, cache, registry);
|
|
76
|
+
if (start === void 0) return false;
|
|
77
|
+
const condition = {
|
|
78
|
+
op: "related",
|
|
79
|
+
resource: item.resource,
|
|
80
|
+
relation: item.relation,
|
|
81
|
+
field: "id",
|
|
82
|
+
depth: depthOf(item)
|
|
83
|
+
};
|
|
84
|
+
return await settled(() => resolveRelated(condition, { id: start }, subject, now, reader), (value) => value === "relation-unavailable", cache) === true;
|
|
85
|
+
};
|
|
86
|
+
const entries = [...items];
|
|
87
|
+
const verdicts = await Promise.all(entries.map(([, item]) => holds(item)));
|
|
88
|
+
return entries.flatMap(([key], index) => verdicts[index] === true ? [key] : []);
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/approvals/permissions.ts
|
|
92
|
+
/**
|
|
93
|
+
* The `holder(permission)` approvers of `request` that `approver` holds, for
|
|
94
|
+
* `ApprovalVerdict.permissions`: each permission key the approver's own
|
|
95
|
+
* instance grants without a row. `approver` must be an instance for the
|
|
96
|
+
* approving principal in the request's tenant; for any other tenant, or an
|
|
97
|
+
* anonymous instance, it holds nothing. A check that throws holds nothing.
|
|
98
|
+
*/
|
|
99
|
+
function approverPermissions(request, approver) {
|
|
100
|
+
const approvers = request.approvers;
|
|
101
|
+
const principal = approver.subject.principal;
|
|
102
|
+
const tenant = request.subject.principal?.tenant;
|
|
103
|
+
if (approvers === void 0 || principal === null || tenant !== void 0 && principal.tenant !== tenant) return [];
|
|
104
|
+
const keys = /* @__PURE__ */ new Set();
|
|
105
|
+
for (const item of requestApprovers(approvers)) if (item.kind === "permission") keys.add(item.permission);
|
|
106
|
+
return [...keys].filter((key) => {
|
|
107
|
+
const leaf = findPermission(approver.permissions, key);
|
|
108
|
+
if (leaf === void 0) return false;
|
|
109
|
+
try {
|
|
110
|
+
const decide = approver.decide;
|
|
111
|
+
return decide(leaf).outcome === "granted";
|
|
112
|
+
} catch {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/** The permission approvers `subject` holds on `request`, read through `permdockFor`. */
|
|
118
|
+
async function heldPermissions(request, subject, permdockFor) {
|
|
119
|
+
if (permdockFor === void 0 || request.approvers === void 0) return [];
|
|
120
|
+
try {
|
|
121
|
+
return approverPermissions(request, await permdockFor(subject, request));
|
|
122
|
+
} catch {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/approvals/helpers.ts
|
|
128
|
+
function permissionMeta(permission) {
|
|
129
|
+
return {
|
|
130
|
+
key: permission.key,
|
|
131
|
+
scope: permission.scope,
|
|
132
|
+
resource: permission.resource
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function summariseSubject(subject) {
|
|
136
|
+
const principal = subject.principal;
|
|
137
|
+
return compact({
|
|
138
|
+
principal: principal === null ? null : compact({
|
|
139
|
+
id: principal.id,
|
|
140
|
+
roles: principal.roles ?? [],
|
|
141
|
+
tenant: principal.tenant
|
|
142
|
+
}),
|
|
143
|
+
actor: subject.actor === void 0 ? void 0 : {
|
|
144
|
+
id: subject.actor.id,
|
|
145
|
+
kind: subject.actor.kind
|
|
146
|
+
},
|
|
147
|
+
session: subject.session,
|
|
148
|
+
delegation: subject.delegation === void 0 ? void 0 : compact({
|
|
149
|
+
scopes: subject.delegation.scopes,
|
|
150
|
+
authorizationDetails: subject.delegation.authorizationDetails
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The window (`meta.ttl`, else the store's `ttl`, else the default) capped by the grant's
|
|
156
|
+
* `approval.ttl`: a grant shortens how long a request stays open, never
|
|
157
|
+
* extends it.
|
|
158
|
+
*/
|
|
159
|
+
function approvalTtl(storeTtl, approval) {
|
|
160
|
+
if (storeTtl !== void 0 && (!Number.isSafeInteger(storeTtl) || storeTtl <= 0)) throw new RangeError(`PermDock: approval ttl must be a positive whole number of milliseconds, got ${String(storeTtl)}`);
|
|
161
|
+
const base = storeTtl ?? 36e5;
|
|
162
|
+
const grant = approval === void 0 || approval === "human" ? void 0 : parseDuration(approval.ttl);
|
|
163
|
+
return grant === void 0 ? base : Math.min(base, grant * 1e3);
|
|
164
|
+
}
|
|
165
|
+
async function requestApproval(store, decision, meta) {
|
|
166
|
+
const now = meta.now ?? /* @__PURE__ */ new Date();
|
|
167
|
+
const leaf = permissionMeta(meta.permission);
|
|
168
|
+
const approval = decision.grant.approval;
|
|
169
|
+
const approvers = approval === void 0 || approval === "human" ? void 0 : compact({
|
|
170
|
+
by: approval.by,
|
|
171
|
+
mode: approval.mode,
|
|
172
|
+
stages: approval.stages,
|
|
173
|
+
distinct: approval.distinct,
|
|
174
|
+
staleOn: approval.staleOn,
|
|
175
|
+
quorum: approval.quorum,
|
|
176
|
+
escalation: approval.escalation
|
|
177
|
+
});
|
|
178
|
+
const ttl = approvalTtl(meta.ttl ?? store.ttl, approval);
|
|
179
|
+
const request = freezeDeep(compact({
|
|
180
|
+
v: 1,
|
|
181
|
+
token: decision.token,
|
|
182
|
+
permission: leaf.key,
|
|
183
|
+
scope: leaf.scope,
|
|
184
|
+
resource: meta.resource ?? { type: leaf.resource },
|
|
185
|
+
subject: summariseSubject(meta.subject),
|
|
186
|
+
membership: meta.membership,
|
|
187
|
+
approvers,
|
|
188
|
+
detail: meta.detail ?? describe(decision).detail,
|
|
189
|
+
adapter: meta.adapter,
|
|
190
|
+
createdAt: now.toISOString(),
|
|
191
|
+
expiresAt: new Date(now.getTime() + ttl).toISOString(),
|
|
192
|
+
status: "pending"
|
|
193
|
+
}));
|
|
194
|
+
await store.create(request);
|
|
195
|
+
return request;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Checks `verdict.by` and resolves the request. Relation approvers are read
|
|
199
|
+
* through `options.relations` unless `verdict.relations` is already set.
|
|
200
|
+
*/
|
|
201
|
+
async function resolveApproval(store, token, verdict, options = {}) {
|
|
202
|
+
const current = await store.get(token);
|
|
203
|
+
if (current === null) throw new ApprovalError("approval-not-found", "approval was not found");
|
|
204
|
+
const relations = verdict.relations ?? await approverRelations(current, verdict.by, options);
|
|
205
|
+
const permissions = verdict.permissions ?? await heldPermissions(current, verdict.by, options.permdockFor);
|
|
206
|
+
assertApprover(current, verdict.by, options.requireDistinctApprover === true, options.now, relations, permissions);
|
|
207
|
+
return store.resolve(token, {
|
|
208
|
+
...verdict,
|
|
209
|
+
relations,
|
|
210
|
+
permissions
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async function vouchApproval(store, token, verdict) {
|
|
214
|
+
if (typeof verdict.rule !== "string" || verdict.rule === "") throw new TypeError("PermDock: vouchApproval needs the name of the rule that decided the verdict");
|
|
215
|
+
return await store.resolve(token, compact({
|
|
216
|
+
status: verdict.status,
|
|
217
|
+
by: verdict.by,
|
|
218
|
+
note: verdict.note,
|
|
219
|
+
vouched: verdict.rule
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
async function inspectApproval(store, token, now = /* @__PURE__ */ new Date()) {
|
|
223
|
+
await store.expire(now);
|
|
224
|
+
const request = await store.get(token);
|
|
225
|
+
if (request === null) return {
|
|
226
|
+
ok: false,
|
|
227
|
+
detail: "approval-not-found"
|
|
228
|
+
};
|
|
229
|
+
if (request.status === "pending") return {
|
|
230
|
+
ok: false,
|
|
231
|
+
detail: "approval-pending"
|
|
232
|
+
};
|
|
233
|
+
if (request.status === "rejected") return {
|
|
234
|
+
ok: false,
|
|
235
|
+
detail: "approval-rejected"
|
|
236
|
+
};
|
|
237
|
+
if (request.consumedAt !== void 0) return {
|
|
238
|
+
ok: false,
|
|
239
|
+
detail: "approval-consumed"
|
|
240
|
+
};
|
|
241
|
+
if (request.status === "expired" || Date.parse(request.expiresAt) <= now.getTime()) return {
|
|
242
|
+
ok: false,
|
|
243
|
+
detail: "approval-expired"
|
|
244
|
+
};
|
|
245
|
+
return {
|
|
246
|
+
ok: true,
|
|
247
|
+
request
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/** Inspects `token` and, when it is approved, consumes it so it resumes once. */
|
|
251
|
+
async function consumeApproval(store, token, now = /* @__PURE__ */ new Date()) {
|
|
252
|
+
const inspected = await inspectApproval(store, token, now);
|
|
253
|
+
if (!inspected.ok) return inspected;
|
|
254
|
+
if (typeof store.consume !== "function") return {
|
|
255
|
+
ok: false,
|
|
256
|
+
detail: "approval-not-found"
|
|
257
|
+
};
|
|
258
|
+
const consumed = await store.consume(token, now);
|
|
259
|
+
if (consumed === null) return {
|
|
260
|
+
ok: false,
|
|
261
|
+
detail: "approval-consumed"
|
|
262
|
+
};
|
|
263
|
+
return {
|
|
264
|
+
ok: true,
|
|
265
|
+
request: consumed
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function approvalDenied(detail) {
|
|
269
|
+
return {
|
|
270
|
+
outcome: "denied",
|
|
271
|
+
denials: [{
|
|
272
|
+
role: null,
|
|
273
|
+
reason: "approval",
|
|
274
|
+
detail
|
|
275
|
+
}],
|
|
276
|
+
alternatives: []
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function staleOnChange(decision) {
|
|
280
|
+
const approval = decision.grant.approval;
|
|
281
|
+
return approval !== void 0 && approval !== "human" && approval.staleOn === "resource-change";
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* True when `token` names a pending or approved request for this permission,
|
|
285
|
+
* resource and principal: the same request, issued while the row had another
|
|
286
|
+
* `version`.
|
|
287
|
+
*/
|
|
288
|
+
async function isStaleToken(store, token, input) {
|
|
289
|
+
const principal = input.subject.principal;
|
|
290
|
+
if (principal === null) return false;
|
|
291
|
+
let request;
|
|
292
|
+
try {
|
|
293
|
+
request = await store.get(token);
|
|
294
|
+
} catch {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
return request !== null && (request.status === "approved" || request.status === "pending") && request.permission === input.permission.key && request.resource.type === input.resource.type && request.resource.id === input.resource.id && request.subject.principal?.id === principal.id;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Applies a resume token to a decision. The token only matters when the
|
|
301
|
+
* decision is `approval-required` and the token is the one this call was
|
|
302
|
+
* issued; otherwise a new approval is requested. A matching token is consumed
|
|
303
|
+
* unless `consume` is `false`, so an approval resumes exactly one call. Under
|
|
304
|
+
* `staleOn: 'resource-change'`, a token issued for an earlier version of the
|
|
305
|
+
* same row denies with `stale-approval`; the next call without it asks again.
|
|
306
|
+
*/
|
|
307
|
+
async function resumeDecision(input) {
|
|
308
|
+
const { decision, store, token } = input;
|
|
309
|
+
if (decision.outcome !== "approval-required") return decision;
|
|
310
|
+
if (token === void 0 || token !== decision.token) {
|
|
311
|
+
if (store !== void 0 && token !== void 0 && staleOnChange(decision) && await isStaleToken(store, token, input)) return {
|
|
312
|
+
outcome: "denied",
|
|
313
|
+
denials: [{
|
|
314
|
+
role: null,
|
|
315
|
+
reason: "stale-approval"
|
|
316
|
+
}],
|
|
317
|
+
alternatives: []
|
|
318
|
+
};
|
|
319
|
+
if (store !== void 0) await requestApproval(store, decision, compact({
|
|
320
|
+
permission: input.permission,
|
|
321
|
+
resource: input.resource,
|
|
322
|
+
subject: input.subject,
|
|
323
|
+
adapter: input.adapter,
|
|
324
|
+
ttl: input.ttl
|
|
325
|
+
}));
|
|
326
|
+
return decision;
|
|
327
|
+
}
|
|
328
|
+
if (store === void 0) return approvalDenied("approval-not-found");
|
|
329
|
+
let inspected;
|
|
330
|
+
try {
|
|
331
|
+
inspected = await inspectApproval(store, token, input.now);
|
|
332
|
+
if (inspected.ok) {
|
|
333
|
+
const { request } = inspected;
|
|
334
|
+
if (request.permission !== input.permission.key || request.resource.id !== void 0 && request.resource.id !== input.resource.id) return approvalDenied("approval-mismatch");
|
|
335
|
+
if (input.consume !== false) inspected = await consumeApproval(store, token, input.now);
|
|
336
|
+
}
|
|
337
|
+
} catch {
|
|
338
|
+
return approvalDenied("approval-not-found");
|
|
339
|
+
}
|
|
340
|
+
if (!inspected.ok) return approvalDenied(inspected.detail);
|
|
341
|
+
const principal = input.subject.principal;
|
|
342
|
+
if (principal === null) return approvalDenied("approval-mismatch");
|
|
343
|
+
return {
|
|
344
|
+
outcome: "granted",
|
|
345
|
+
subject: {
|
|
346
|
+
...input.subject,
|
|
347
|
+
principal
|
|
348
|
+
},
|
|
349
|
+
matched: decision.grant,
|
|
350
|
+
token: decision.token
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const SYSTEM_KIND = "system";
|
|
354
|
+
async function cancelApprovals(store, filter, meta) {
|
|
355
|
+
if (store.cancel !== void 0) return store.cancel(filter, meta);
|
|
356
|
+
const pending = await listAllApprovals(store, {
|
|
357
|
+
...filter,
|
|
358
|
+
status: "pending"
|
|
359
|
+
});
|
|
360
|
+
const by = {
|
|
361
|
+
principal: {
|
|
362
|
+
id: `system:${meta.by}`,
|
|
363
|
+
kind: "service",
|
|
364
|
+
roles: []
|
|
365
|
+
},
|
|
366
|
+
actor: {
|
|
367
|
+
id: `system:${meta.by}`,
|
|
368
|
+
kind: SYSTEM_KIND
|
|
369
|
+
},
|
|
370
|
+
context: {}
|
|
371
|
+
};
|
|
372
|
+
return (await Promise.all(pending.map(async (request) => {
|
|
373
|
+
try {
|
|
374
|
+
await store.resolve(request.token, compact({
|
|
375
|
+
status: "rejected",
|
|
376
|
+
by,
|
|
377
|
+
note: meta.note
|
|
378
|
+
}));
|
|
379
|
+
return true;
|
|
380
|
+
} catch {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}))).filter(Boolean).length;
|
|
384
|
+
}
|
|
385
|
+
function readApprovalHeader(headers) {
|
|
386
|
+
const value = headers.get(APPROVAL_HEADER);
|
|
387
|
+
if (value === null || value.trim() === "") return;
|
|
388
|
+
return value.trim();
|
|
389
|
+
}
|
|
390
|
+
function resumeFromHeader(store, headers, now) {
|
|
391
|
+
const token = readApprovalHeader(headers);
|
|
392
|
+
if (token === void 0) return Promise.resolve({
|
|
393
|
+
ok: false,
|
|
394
|
+
detail: "approval-not-found"
|
|
395
|
+
});
|
|
396
|
+
return inspectApproval(store, token, now);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* The token to resume `decision` with when the caller carries none: the
|
|
400
|
+
* decision's own token when the store holds an approved or rejected request
|
|
401
|
+
* for it, so `resumeDecision` resumes (or denies) the call without the
|
|
402
|
+
* caller passing the token back. The token already binds permission,
|
|
403
|
+
* resource (or the call's data when there is no row id), subject and actor.
|
|
404
|
+
* A pending request counts only with `denyPending: true`, which makes the
|
|
405
|
+
* call deny with `approval-pending` instead of asking again. `undefined` when
|
|
406
|
+
* the decision needs no approval, there is no store, or the store has no
|
|
407
|
+
* unexpired request for the token; a store that throws counts as none.
|
|
408
|
+
*/
|
|
409
|
+
async function storedApprovalToken(store, decision, options = {}) {
|
|
410
|
+
if (store === void 0 || decision.outcome !== "approval-required") return;
|
|
411
|
+
const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
412
|
+
try {
|
|
413
|
+
const record = await store.get(decision.token);
|
|
414
|
+
if (record === null || record.status === "pending" && options.denyPending !== true || record.status === "expired" || Date.parse(record.expiresAt) <= now) return;
|
|
415
|
+
return decision.token;
|
|
416
|
+
} catch {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
//#endregion
|
|
421
|
+
export { requestApproval as a, resumeFromHeader as c, vouchApproval as d, approverPermissions as f, readApprovalHeader as i, storedApprovalToken as l, approverRelations as m, consumeApproval as n, resolveApproval as o, heldPermissions as p, inspectApproval as r, resumeDecision as s, cancelApprovals as t, summariseSubject as u };
|
|
@@ -0,0 +1,48 @@
|
|
|
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 { Context, Hono, MiddlewareHandler } from "hono";
|
|
7
|
+
import { SSEMessage, SSEStreamingApi } from "hono/streaming";
|
|
8
|
+
import { WSEvents } from "hono/ws";
|
|
9
|
+
//#region src/hono/create.d.ts
|
|
10
|
+
type HonoPermDockOptions<TUser = unknown> = ServerAdapterOptions<Context, TUser> & {
|
|
11
|
+
/** Ends or revalidates open sockets and streams. */
|
|
12
|
+
readonly revocations?: RevocationFeed;
|
|
13
|
+
};
|
|
14
|
+
/** The `Variables` both middlewares set; Hono merges them into the route's Env. */
|
|
15
|
+
type PermDockEnv<TData = unknown, V extends PolicyVocabulary = PolicyVocabulary> = {
|
|
16
|
+
readonly Variables: {
|
|
17
|
+
readonly permdock: PermDock<V>;
|
|
18
|
+
readonly permdockData: TData;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
type HonoPermDock<V extends PolicyVocabulary = PolicyVocabulary> = {
|
|
22
|
+
readonly permdock: () => MiddlewareHandler<PermDockEnv<unknown, V>>;
|
|
23
|
+
readonly protect: <TData = unknown>(permission: Permission | null, loadData?: (c: Context) => TData | Promise<TData>, protectOptions?: ProtectOptions) => MiddlewareHandler<PermDockEnv<NonNullable<TData>, V>>;
|
|
24
|
+
/** A long-lived connection for the request behind `c`. */
|
|
25
|
+
readonly connection: (c: Context, connectionOptions?: ConnectionOptions) => Promise<Connection>;
|
|
26
|
+
/** `upgradeWebSocket` events that close with `1008` when the connection aborts. */
|
|
27
|
+
readonly socket: <T = unknown>(connection: Connection, events: WSEvents<T>) => WSEvents<T>;
|
|
28
|
+
/**
|
|
29
|
+
* Writes `source` to a `streamSSE` stream, dropping items the subscriber
|
|
30
|
+
* cannot read, and resolves when it ends: after an `event: permdock` frame
|
|
31
|
+
* when the connection aborts, when the client disconnects, or when the
|
|
32
|
+
* source is done. Await it as the last statement of the callback.
|
|
33
|
+
*/
|
|
34
|
+
readonly sse: <T>(connection: Connection, stream: SSEStreamingApi, source: AsyncIterable<T>, options?: SseOptions<T>) => Promise<void>;
|
|
35
|
+
readonly permdockHandler: () => Hono;
|
|
36
|
+
readonly openapi: OpenApiHooks;
|
|
37
|
+
};
|
|
38
|
+
type SseOptions<T> = {
|
|
39
|
+
/** Items the subscriber cannot read under this permission are dropped. */
|
|
40
|
+
readonly items?: Permission<string, unknown, "instance">;
|
|
41
|
+
/** The row to check for an item, when the item wraps it. */
|
|
42
|
+
readonly unwrap?: (item: T) => unknown;
|
|
43
|
+
/** The frame for an item; defaults to `{ data: JSON.stringify(item) }`. */
|
|
44
|
+
readonly format?: (item: T) => SSEMessage;
|
|
45
|
+
};
|
|
46
|
+
export declare function createPermDock<TUser, TPrincipal extends Principal = Principal, V extends PolicyVocabulary = PolicyVocabulary>(policy: Policy<TUser, TPrincipal, V>, options: HonoPermDockOptions<TUser>): HonoPermDock<V>;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { type HonoPermDock, type HonoPermDockOptions, InvalidSignatureError, type PermDockEnv, type SseOptions, discoverViaSignatureAgent, verifyWebBotAuth };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { t as compact } from "../compact-y6vfu2_f.js";
|
|
2
|
+
import { r as PermDockRevokedError } from "../errors-Cz5zn0mW.js";
|
|
3
|
+
import { i as discoverViaSignatureAgent, r as InvalidSignatureError, s as verifyWebBotAuth } from "../evaluations-tz6D9A2G.js";
|
|
4
|
+
import { t as problemFromError } from "../map-error-pgUWNNtG.js";
|
|
5
|
+
import { r as bindKernel } from "../bind-VnYn2HKq.js";
|
|
6
|
+
import { i as onRevoked, n as guardIterable, t as POLICY_VIOLATION } from "../stream-DDpvynSB.js";
|
|
7
|
+
import { Hono } from "hono";
|
|
8
|
+
//#region src/hono/create.ts
|
|
9
|
+
function socket(connection, events) {
|
|
10
|
+
return {
|
|
11
|
+
...events,
|
|
12
|
+
onOpen: (evt, ws) => {
|
|
13
|
+
onRevoked(connection, (problem) => {
|
|
14
|
+
ws.close(POLICY_VIOLATION, problem.type);
|
|
15
|
+
});
|
|
16
|
+
if (!connection.signal.aborted) events.onOpen?.(evt, ws);
|
|
17
|
+
},
|
|
18
|
+
onClose: (evt, ws) => {
|
|
19
|
+
connection.close();
|
|
20
|
+
events.onClose?.(evt, ws);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function sse(connection, stream, source, options = {}) {
|
|
25
|
+
const disconnected = new Promise((resolve) => {
|
|
26
|
+
stream.onAbort(() => {
|
|
27
|
+
connection.close();
|
|
28
|
+
resolve({
|
|
29
|
+
done: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
const iterator = guardIterable(source, connection, compact({
|
|
35
|
+
items: options.items,
|
|
36
|
+
unwrap: options.unwrap,
|
|
37
|
+
onRevoked: (error) => error
|
|
38
|
+
}))[Symbol.asyncIterator]();
|
|
39
|
+
try {
|
|
40
|
+
for (;;) {
|
|
41
|
+
const next = await Promise.race([iterator.next(), disconnected]);
|
|
42
|
+
if (next.done === true || stream.aborted) return;
|
|
43
|
+
const item = next.value;
|
|
44
|
+
await stream.writeSSE(options.format?.(item) ?? { data: JSON.stringify(item) });
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (!(error instanceof PermDockRevokedError)) throw error;
|
|
48
|
+
if (!stream.aborted) await stream.writeSSE({
|
|
49
|
+
event: "permdock",
|
|
50
|
+
data: JSON.stringify(error.toProblemDetails())
|
|
51
|
+
});
|
|
52
|
+
} finally {
|
|
53
|
+
Promise.resolve(iterator.return(void 0)).catch(() => void 0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function mapDownstream(c) {
|
|
57
|
+
const mapped = c.error === void 0 ? void 0 : problemFromError(c.error, { credentials: c.req.header("authorization") !== void 0 });
|
|
58
|
+
if (mapped !== void 0) {
|
|
59
|
+
c.res = void 0;
|
|
60
|
+
c.res = mapped;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function createPermDock(policy, options) {
|
|
64
|
+
const { kernel, bind, scopeOf, handlerScope, attach } = bindKernel(policy, options, "hono", (c) => c.req.raw);
|
|
65
|
+
const permdock = () => async (c, next) => {
|
|
66
|
+
const attached = await attach(c);
|
|
67
|
+
if (!attached.ok) return attached.response;
|
|
68
|
+
c.set("permdock", attached.permdock);
|
|
69
|
+
await next();
|
|
70
|
+
mapDownstream(c);
|
|
71
|
+
};
|
|
72
|
+
const protect = (permission, loadData, protectOptions) => async (c, next) => {
|
|
73
|
+
const guard = await kernel.protect(permission, loadData === void 0 ? void 0 : () => loadData(c), protectOptions)(bind(c), await scopeOf(c));
|
|
74
|
+
if (!guard.ok) return guard.response;
|
|
75
|
+
c.set("permdock", guard.permdock);
|
|
76
|
+
c.set("permdockData", guard.data);
|
|
77
|
+
await next();
|
|
78
|
+
mapDownstream(c);
|
|
79
|
+
};
|
|
80
|
+
const connection = async (c, connectionOptions) => kernel.connection(bind(c), connectionOptions, await scopeOf(c));
|
|
81
|
+
const permdockHandler = () => {
|
|
82
|
+
const { POST, GET } = kernel.permdockHandler(handlerScope);
|
|
83
|
+
const app = new Hono();
|
|
84
|
+
app.post("/", (c) => POST(bind(c)));
|
|
85
|
+
app.get("/", (c) => GET(bind(c)));
|
|
86
|
+
return app;
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
permdock,
|
|
90
|
+
protect,
|
|
91
|
+
connection,
|
|
92
|
+
socket,
|
|
93
|
+
sse,
|
|
94
|
+
permdockHandler,
|
|
95
|
+
openapi: kernel.openapi
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { InvalidSignatureError, createPermDock, discoverViaSignatureAgent, verifyWebBotAuth };
|