permdock 0.3.1 → 0.4.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/dist/a2a/index.d.ts +7 -5
- package/dist/a2a/index.js +14 -21
- package/dist/ai-sdk/index.d.ts +18 -6
- package/dist/ai-sdk/index.js +8 -5
- package/dist/app-data-CV8pqqMi.js +59 -0
- package/dist/approvals/index.d.ts +2 -2
- package/dist/approvals/index.js +3 -3
- package/dist/{approvals-DbYAuNkG.js → approvals-DZL76lKW.js} +35 -19
- package/dist/{approvers-DT4AVyIg.js → approvers-CqPOLD-o.js} +1 -1
- package/dist/{arazzo-BAgw9ap6.js → arazzo-C4BcskbX.js} +6 -5
- package/dist/{arazzo-C9chp3ST.js → arazzo-CD8d0WLb.js} +2 -2
- package/dist/authzen/index.d.ts +3 -3
- package/dist/authzen/index.js +161 -23
- package/dist/better-auth/index.d.ts +2 -2
- package/dist/better-auth/index.js +6 -19
- package/dist/better-supabase/index.d.ts +112 -87
- package/dist/better-supabase/index.js +257 -156
- package/dist/{bind-C_ob3LKa.d.ts → bind-BzqG8SMb.d.ts} +16 -5
- package/dist/{bind-CuzGytRf.js → bind-kk-uyCwH.js} +14 -6
- package/dist/build-instance-DIIV9DbC.js +51 -0
- package/dist/{canonical-json-DemiK4Vp.js → canonical-json-CFKyFOke.js} +1 -3
- package/dist/{capability-2kYTMWDv.d.ts → capability-CksyCWDH.d.ts} +2 -2
- package/dist/{capability-4qPdO9gk.js → capability-txATtKV4.js} +3 -2
- package/dist/catalog/index.d.ts +1 -1
- package/dist/catalog/index.js +1 -1
- package/dist/catalog-6yWAX6Ps.js +2 -0
- package/dist/{catalog-CYj-mX2O.js → catalog-WHG4kBq7.js} +2 -2
- package/dist/{catalog-doc-DdGm82XT.js → catalog-doc-DWtg0gGR.js} +17 -10
- package/dist/{catalog-DWF5cYqB.js → catalog-tZUyOfOv.js} +4 -4
- package/dist/claude-agent/index.d.ts +4 -4
- package/dist/claude-agent/index.js +4 -5
- package/dist/clerk/index.d.ts +3 -3
- package/dist/clerk/index.js +8 -33
- package/dist/cli/bin.js +1 -1
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +3 -3
- package/dist/cloud/index.d.ts +4 -4
- package/dist/cloud/index.js +9 -15
- package/dist/{cloud-CfwZ39Rl.js → cloud-C7bSDgX4.js} +2 -2
- package/dist/{cloud-DWLXO2af.js → cloud-PeBN3IEn.js} +5 -5
- package/dist/{collect-DSTE3ml9.js → collect-2SrB7lfk.js} +6 -8
- package/dist/collect-Bw2Jdq1q.js +2 -0
- package/dist/{collect-CHB22Sx4.js → collect-CQx4hX4N.js} +3 -3
- package/dist/{commands-BeaGNj_o.js → commands-Cpip4ULx.js} +13 -13
- package/dist/{compact-y6vfu2_f.js → compact-CAf557ZB.js} +11 -1
- package/dist/compile/index.d.ts +1 -1
- package/dist/compile/index.js +1 -1
- package/dist/{compile-Ba4blROR.js → compile-CcEu2ZQ1.js} +6 -5
- package/dist/{compile-BkRyBDBw.d.ts → compile-CtTP7eur.d.ts} +2 -2
- package/dist/{config-BJiM-xAm.js → config-BIjREpyE.js} +4 -4
- package/dist/{config-ir40y8m0.js → config-DLt6BvV7.js} +2 -2
- package/dist/{config-report-CdCgbRnV.js → config-report--Xb9APJS.js} +5 -6
- package/dist/{connection-CU8MQxRi.js → connection-DUsczpB5.js} +3 -2
- package/dist/constants-DcJABbLW.js +20 -0
- package/dist/{context-Bcy85rGi.js → context-DieZVJXu.js} +16 -5
- package/dist/convex/index.d.ts +4 -4
- package/dist/convex/index.js +14 -16
- package/dist/create-BBO24vj6.js +324 -0
- package/dist/{credential-8P81ff4u.js → credential-kue0qpbm.js} +4 -4
- package/dist/deciding-columns-Sq12mEA6.js +123 -0
- package/dist/delegation-input-FTxMK3ji.js +19 -0
- package/dist/denied-text-DfRk15uw.d.ts +19 -0
- package/dist/{describe-DMYiCjJV.d.ts → describe-C3ldA9os.d.ts} +11 -2
- package/dist/{describe-B_gVZEVi.js → describe-Cgkp7eP0.js} +5 -4
- package/dist/{diff-C9RDjjhs.js → diff-Cnghh_Ip.js} +2 -2
- package/dist/{diff-2VaeChzX.js → diff-rpqoe7Ag.js} +9 -9
- package/dist/{doctor-Djh6JDEk.js → doctor-CuVJvhV_.js} +2 -2
- package/dist/doctor-owlv6ddh.js +2166 -0
- package/dist/drizzle/index.d.ts +2 -2
- package/dist/drizzle/index.js +6 -14
- package/dist/elysia/index.d.ts +4 -4
- package/dist/elysia/index.js +7 -7
- package/dist/{errors-DPdqI50v.d.ts → errors-OD_4c__H.d.ts} +2 -2
- package/dist/{errors-Cz5zn0mW.js → errors-drnfxYtm.js} +3 -3
- package/dist/{evaluations-tz6D9A2G.js → evaluations-C9YJsv3H.js} +45 -7
- package/dist/eve/index.d.ts +5 -5
- package/dist/eve/index.js +5 -5
- package/dist/express/index.d.ts +4 -4
- package/dist/express/index.js +8 -7
- package/dist/fastify/index.d.ts +15 -5
- package/dist/fastify/index.js +9 -29
- package/dist/fields-fwfXN01n.js +1016 -0
- package/dist/{files-DWUN9PzI.js → files-D_JIzUrP.js} +12 -3
- package/dist/{fixtures-ht28Cplr.js → fixtures-h2eG2OZV.js} +5 -6
- package/dist/{from-snapshot-CTLijvdm.js → from-snapshot-7REQZe0H.js} +32 -22
- package/dist/{generate-CH7ThJ14.js → generate-CNU1pIOo.js} +1 -3
- package/dist/grantee-CXY-0C87.js +254 -0
- package/dist/grantee-conditions-MQs5NIuX.js +270 -0
- package/dist/grantee-match-fxYp9Nmt.js +141 -0
- package/dist/{helpers-H_KARDVC.js → helpers-C9YmyBIa.js} +7 -6
- package/dist/hono/index.d.ts +4 -4
- package/dist/hono/index.js +8 -8
- package/dist/hosted-CBHgkzDl.js +655 -0
- package/dist/{http-SO7qGttf.js → http-BBoKefeS.js} +35 -2
- package/dist/{http-BIhmLfCc.js → http-BEbdMZ05.js} +2 -24
- package/dist/{rls-import-4lLW_pbb.js → import-BFIlhetD.js} +86 -80
- package/dist/{openapi-import-cmwetbzw.js → import-UHk1N7vH.js} +6 -7
- package/dist/{index-C8z4RjQV.d.ts → index-BwMe94Xq.d.ts} +1 -1
- package/dist/{index-0nNqHspG.d.ts → index-DgM7w96K.d.ts} +2 -2
- package/dist/{index-C7Tw7MaW.d.ts → index-Dz7didpC.d.ts} +3 -3
- package/dist/{index-BNc7Wer_.d.ts → index-UdVQgq48.d.ts} +105 -38
- package/dist/index.d.ts +15 -13
- package/dist/index.js +22 -22
- package/dist/{instance-options-jARdwfPN.d.ts → instance-options-plkrsAog.d.ts} +1 -1
- package/dist/{json-schema-BsAflUGW.js → json-schema-DBkdUuCO.js} +1 -3
- package/dist/jwt/index.d.ts +4 -4
- package/dist/jwt/index.js +13 -13
- package/dist/{kernel-_RRHmnMY.js → kernel-CB3LrIJM.js} +81 -32
- package/dist/kysely/index.d.ts +2 -2
- package/dist/kysely/index.js +6 -14
- package/dist/{live-options-H2eG8dfJ.js → live-options-BaAFCIiu.js} +16 -3
- package/dist/load-B_shHrmd.js +2 -0
- package/dist/{load-DhWEB9P1.js → load-C3_oTHyO.js} +11 -3
- package/dist/{manifest-iaoBXHKc.js → manifest-BngWKryL.js} +5 -18
- package/dist/{map-claims-Z4QZOiFF.js → map-claims-AVlBaJoa.js} +7 -16
- package/dist/{map-error-pgUWNNtG.js → map-error-BE27PYkE.js} +5 -5
- package/dist/{markers-B0hYLvMD.js → markers-CiwAOZtO.js} +6 -2
- package/dist/{may-use-DndQ5tQ-.js → may-use-BOn_dR_w.js} +4 -3
- package/dist/mcp/index.d.ts +26 -9
- package/dist/mcp/index.js +456 -446
- package/dist/{rls-migrate-CN4TlJTO.js → migrate-BwlB5-Wk.js} +75 -15
- package/dist/nest/index.d.ts +4 -4
- package/dist/nest/index.js +11 -12
- package/dist/next/index.d.ts +31 -8
- package/dist/next/index.js +29 -33
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +1 -1
- package/dist/node/index.d.ts +4 -4
- package/dist/node/index.js +4 -4
- package/dist/ocsf-uYFXGVw2.js +115 -0
- package/dist/openai/index.d.ts +5 -5
- package/dist/openai/index.js +4 -4
- package/dist/openapi/index.d.ts +3 -3
- package/dist/openapi/index.js +1 -1
- package/dist/{openapi-CqqEbHsL.js → openapi-BJdBmYDG.js} +19 -23
- package/dist/{openapi-BqRBvAng.js → openapi-DBzHQbov.js} +2 -5
- package/dist/{openapi-CQTsgKoB.js → openapi-DcQ1Kg40.js} +3 -3
- package/dist/orpc/index.d.ts +5 -5
- package/dist/orpc/index.js +9 -11
- package/dist/otel/index.d.ts +2 -2
- package/dist/otel/index.js +26 -23
- package/dist/output-files-CgIsvdSa.js +140 -0
- package/dist/{rls-ownership-DcYlZ09B.js → ownership-BgnbOJFT.js} +387 -379
- package/dist/{package-root-zGkxO3oN.js → package-root-DtNnpmUd.js} +3 -2
- package/dist/{parse-BuyjxhZV.js → parse-CVFQHk6c.js} +3 -3
- package/dist/{parse-local-manifest-BrMozJCo.js → parse-local-manifest-C-q02Pal.js} +2 -4
- package/dist/{parse-local-manifest-JLnaBH0S.d.ts → parse-local-manifest-DvYUR0QL.d.ts} +1 -1
- package/dist/pdp/index.d.ts +2 -2
- package/dist/pdp/index.js +8 -9
- package/dist/{permdock-CbgvLnuo.js → permdock-L26udHSk.js} +1387 -1220
- package/dist/{rls-fields-CZOMlwHl.js → permission-keys-B26jeyUv.js} +1268 -2053
- package/dist/permission-registry-BsblpB-z.js +385 -0
- package/dist/{permissions-DttnqqxC.d.ts → permission-types-Dg39z9Kv.d.ts} +59 -31
- package/dist/{permissions-RJrovw98.js → permissions-CCJ6lmxB.js} +3 -3
- package/dist/{permissions-CDgvKG5L.d.ts → permissions-COH-KRgT.d.ts} +2 -2
- package/dist/{policy-IB6yxpC3.d.ts → policy-types-sp9P1iIV.d.ts} +661 -582
- package/dist/{policy-D2W7uv19.d.ts → policy-ur0BBK_e.d.ts} +2 -2
- package/dist/{powersync-DE19b9dT.js → powersync-BFSbSElQ.js} +2 -2
- package/dist/powersync-DCDgZgfZ.js +2 -0
- package/dist/{powersync-Dv1_aWF7.js → powersync-cZe4kzhL.js} +26 -27
- package/dist/prisma/index.d.ts +1 -1
- package/dist/prisma/index.js +6 -12
- package/dist/{problem-B43ztKIm.js → problem-CnWraVhC.js} +8 -7
- package/dist/{problem-details-_AMOYz-w.js → problem-details-DECUnXAn.js} +2 -2
- package/dist/{problem-details-DX075l9V.d.ts → problem-details-rIIo8B2C.d.ts} +1 -1
- package/dist/{protected-BdnIEFkY.d.ts → protected-B3_P7xuw.d.ts} +9 -6
- package/dist/{protected-utU-SLuy.js → protected-BN7BUdY1.js} +20 -8
- package/dist/{provider-CSQd7m92.js → provider-Bi-0HNL3.js} +23 -10
- package/dist/{provider-DZY281jO.d.ts → provider-kwHC9CZD.d.ts} +1 -1
- package/dist/{provider-store-Cfbvo4DE.js → provider-store-Ctt-81Ni.js} +6 -3
- package/dist/react/index.d.ts +7 -7
- package/dist/react/index.js +5 -5
- package/dist/react/provider-client.d.ts +1 -1
- package/dist/react/provider-client.js +1 -1
- package/dist/react-native/index.d.ts +20 -11
- package/dist/react-native/index.js +33 -17
- package/dist/{refs-KYb4ntaz.js → refs-f3imMjNW.js} +1 -1
- package/dist/relation-walk-BXnlLtg2.js +186 -0
- package/dist/relations-CvmSpG67.js +163 -0
- package/dist/{replay-CYyiLiwO.d.ts → replay-COpmZUfx.d.ts} +1 -1
- package/dist/request-context-BVM7aWNs.js +71 -0
- package/dist/request-context-C2_1lchh.d.ts +5 -0
- package/dist/resource-relations-D1Un3pcz.js +243 -0
- package/dist/retire-BFcxL6un.js +240 -0
- package/dist/{rls-P-BeBx0n.js → rls-55DQTuf5.js} +14 -2
- package/dist/{rls-DiinlRML.js → rls-BEktUaqg.js} +884 -484
- package/dist/{policy-xyWg7QdR.js → role-builder-B4GbKM-i.js} +235 -541
- package/dist/{rpc-DL9Sqvb1.js → rpc-nYC3cR_u.js} +15 -5
- package/dist/{run-BWc9qqvE.js → run-DMcNW_8T.js} +3 -3
- package/dist/{runtime-CB8gQFvS.js → runtime-D_tMXnsq.js} +1 -1
- package/dist/{saas-DhpJjnBA.js → saas-DtaA4JuW.js} +9 -8
- package/dist/{openapi-schema--ARjyfQr.js → schema-Bol6gqXA.js} +3 -5
- package/dist/{schema-D3MnDMxa.js → schema-DjQBcAP9.js} +4 -2
- package/dist/scim/index.d.ts +1 -1
- package/dist/scim/index.js +1 -1
- package/dist/{scim-BFGBBAqR.js → scim-vFR1O5oG.js} +6 -12
- package/dist/{scopes-CVdPrWN-.js → scopes-tvpa34ep.js} +10 -2
- package/dist/server/index.d.ts +18 -8
- package/dist/server/index.js +8 -8
- package/dist/{server-DlZ28Oz5.js → server-ZYEHtNHS.js} +4 -4
- package/dist/{create-B1d519XK.d.ts → server-types-DdqBwZN_.d.ts} +69 -33
- package/dist/shared-1uhI-e-b.js +294 -0
- package/dist/{shared-DRu8VFVM.js → shared-JhMeOsDF.js} +1 -1
- package/dist/{sink-Bd9PSyfq.js → sink-BTtmfPnE.js} +1 -1
- package/dist/{sink-B1fZzIMf.d.ts → sink-CPN4zLfs.d.ts} +1 -1
- package/dist/{skills-Biq5uup3.js → skills-BZdRQkxs.js} +4 -3
- package/dist/{skills-C5CbhhpG.js → skills-Dle4ZoLF.js} +2 -2
- package/dist/{snapshot-Enxd0n-s.js → snapshot-Dc9CHPME.js} +116 -13
- package/dist/{snapshot-cache-D6jLelln.js → snapshot-cache-Cod40D-X.js} +1 -1
- package/dist/{snapshot-cache-B-LxUahj.d.ts → snapshot-cache-J5T7t_vD.d.ts} +1 -1
- package/dist/solid/index.d.ts +22 -22
- package/dist/solid/index.js +40 -10
- package/dist/{sources-4p0-4xQm.js → sources-B1-b-R0t.js} +25 -26
- package/dist/{sources-BdOYLw9j.d.ts → sources-Dljy06zL.d.ts} +6 -2
- package/dist/{sql-xdg5f4Fi.js → sql-t8teWOfo.js} +19 -3
- package/dist/{src-BDwEZWrZ.js → src-Bb7no-hS.js} +194 -123
- package/dist/ssf/index.d.ts +3 -3
- package/dist/ssf/index.js +58 -61
- package/dist/store-9KO4BlkB.d.ts +147 -0
- package/dist/{store-DMAWwAJV.js → store-ILkLUj_o.js} +4 -4
- package/dist/{store-options-ByhZq1jV.js → store-options-CbUHDoSe.js} +16 -7
- package/dist/{stores-BT2pSCub.js → stores-BHXdSbw9.js} +7 -3
- package/dist/stores-Cxz_80g-.d.ts +31 -0
- package/dist/{stream-DDpvynSB.js → stream-BMui98KK.js} +2 -1
- package/dist/{stream-D1RXubw2.d.ts → stream-Dwsg6WwE.d.ts} +2 -2
- package/dist/{subject-settings-BwBmCdTR.js → subject-settings-CkEwrw3W.js} +23 -5
- package/dist/supabase/index.d.ts +4 -4
- package/dist/supabase/index.js +3 -3
- package/dist/supabase/middleware.d.ts +11 -5
- package/dist/supabase/middleware.js +10 -7
- package/dist/{supabase-C0qESOa-.js → supabase-C1TWlnYt.js} +36 -52
- package/dist/{supabase-s4o9s1O1.js → supabase-Dbqr141s.js} +2 -2
- package/dist/supabase-hook-BULg7Ut_.js +2 -0
- package/dist/{supabase-hook-ntETYCQu.js → supabase-hook-Cva3ikXz.js} +730 -781
- package/dist/{supautils-u8jXTGrt.js → supautils-B6HYL9eL.js} +2 -2
- package/dist/svelte/Protected.svelte +9 -2
- package/dist/svelte/index.d.ts +6 -6
- package/dist/svelte/index.js +25 -11
- package/dist/svelte/runtime.d.ts +10 -3
- package/dist/svelte/runtime.js +4 -3
- package/dist/svelte/source.d.ts +6 -6
- package/dist/svelte/source.js +4 -4
- package/dist/{validity-uOp8UpYn.js → tenancy-DshjqY0n.js} +3 -39
- package/dist/terminal/index.d.ts +5 -5
- package/dist/terminal/index.js +18 -34
- package/dist/testing/index.d.ts +89 -77
- package/dist/testing/index.js +1276 -1262
- package/dist/testing/saas/index.d.ts +4 -4
- package/dist/testing/saas/index.js +2 -2
- package/dist/testing/saas/permissions.d.ts +1 -1
- package/dist/testing/saas/permissions.js +1 -1
- package/dist/thenable-QSmvt-vZ.js +65 -0
- package/dist/{token-CIWxJOCh.js → token-Bx9qy30p.js} +1 -1
- package/dist/tool-refusal-CQ7OEia9.js +41 -0
- package/dist/trpc/index.d.ts +5 -5
- package/dist/trpc/index.js +7 -8
- package/dist/{types-DbjRN55U.d.ts → types-7rJVLWe5.d.ts} +82 -4
- package/dist/{types-aqOHTHcp.d.ts → types-Br9IXUBG.d.ts} +1 -1
- package/dist/types-ByUo56un.d.ts +88 -0
- package/dist/{types-Cq_H8N_X.d.ts → types-C0dee0Qf.d.ts} +2 -2
- package/dist/{types-DxiCGmmd.d.ts → types-CIlTojhq.d.ts} +2 -2
- package/dist/{types-QCuYJh4q.d.ts → types-CUcFZfpU.d.ts} +1 -1
- package/dist/{types-C97IskBw.d.ts → types-CqrjB9o6.d.ts} +1 -1
- package/dist/{types-BnIEz1sU.d.ts → types-DHrmBJLH.d.ts} +24 -6
- package/dist/{types-Dnemwd77.d.ts → types-DpWfQdSh.d.ts} +5 -1
- package/dist/{types-Bvc4oWT6.d.ts → types-DvupZE0w.d.ts} +1 -1
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +1 -1
- package/dist/{usage-B0YuTQRO.js → usage-4G6t643F.js} +2 -2
- package/dist/{usage-ItS7nLcl.js → usage-CG9nOYZw.js} +7 -7
- package/dist/usage-iFLJ0-rr.js +2 -0
- package/dist/{validation-error-Ba264OaJ.d.ts → validation-error-BSSw0l_8.d.ts} +1 -1
- package/dist/{validation-error-CnjZ4t92.js → validation-error-ZfUHbKvf.js} +1 -1
- package/dist/validity-dVrUEPJt.js +62 -0
- package/dist/{verifier-BxBo6I44.js → verifier-DMr_Zmb_.js} +51 -15
- package/dist/{rls-verify-CMv9H3wV.js → verify-BztUB3GX.js} +668 -239
- package/dist/{version-BvacVTZR.js → version-BEogC-rB.js} +1 -1
- package/dist/{views-Soe7bGSC.js → views-CJsrBS1f.js} +23 -1
- package/dist/{vocabulary-DA8a8zif.d.ts → vocabulary-hhEFLFoL.d.ts} +15 -6
- package/dist/vue/index.d.ts +24 -19
- package/dist/vue/index.js +24 -8
- package/dist/watch-C8TpsAl4.js +2 -0
- package/dist/{watch-DVBJ9cBq.js → watch-zeucB7eF.js} +6 -6
- package/dist/webmcp/index.d.ts +2 -2
- package/dist/webmcp/index.js +13 -37
- package/dist/wrap-Cr93qqdP.d.ts +14 -0
- package/dist/wrap-DWsU_5Bd.js +26 -0
- package/package.json +8 -8
- package/schemas/catalog-v1.json +6 -0
- package/skills/permdock-credentials/SKILL.md +1 -1
- package/skills/permdock-credentials/references/tokens-keys-links.md +7 -2
- package/skills/permdock-data/references/queries-and-rls.md +4 -0
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +1 -0
- package/skills/permdock-wire/SKILL.md +2 -2
- package/skills/permdock-wire/references/adapters.md +9 -1
- package/skills/permdock-wire/references/policy-options.md +10 -1
- package/dist/catalog-CRW5Mx_B.js +0 -2
- package/dist/collect-DSWOk19R.js +0 -2
- package/dist/create-CMwIl-w2.js +0 -253
- package/dist/delegation-D8pUEuce.js +0 -103
- package/dist/doctor-DvH0IQff.js +0 -1194
- package/dist/doctor-collect-CjdO0wQX.js +0 -665
- package/dist/evaluation-items-CfCCejQd.js +0 -40
- package/dist/fields-BMl1RxoX.js +0 -26
- package/dist/grantee-Cv5Sogfv.js +0 -602
- package/dist/hosted-DJQw46hn.js +0 -266
- package/dist/instance-options-Dhhcnm3y.js +0 -22
- package/dist/load-DwJUafYN.js +0 -2
- package/dist/map-AcxK9o_D.js +0 -147
- package/dist/permissions-DVoF6dMt.js +0 -662
- package/dist/powersync-CrBX8hY6.js +0 -2
- package/dist/protected-xAr24FEC.d.ts +0 -40
- package/dist/relations-cjOL01hZ.js +0 -505
- package/dist/rls-graph-CHwx0V8q.js +0 -435
- package/dist/rls-shared-Cewd_-zI.js +0 -495
- package/dist/store-jOBYpiXC.d.ts +0 -36
- package/dist/stores-C0IMQrGI.d.ts +0 -52
- package/dist/supabase-config-Bj3iDH2I.js +0 -472
- package/dist/supabase-hook-gd3s8bxB.js +0 -2
- package/dist/thenable-okc2xDsj.js +0 -10
- package/dist/types-CKNSyIf_.d.ts +0 -52
- package/dist/usage-DorAJiU_.js +0 -2
- package/dist/watch-BwxLTYMZ.js +0 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as describe } from "./describe-Cgkp7eP0.js";
|
|
1
2
|
//#region src/client/views.ts
|
|
2
3
|
function permissionSet(store, permissions, data) {
|
|
3
4
|
const granted = [];
|
|
@@ -64,6 +65,12 @@ function protectedView(local, root, permission, data, scoped) {
|
|
|
64
65
|
slot: "pending"
|
|
65
66
|
};
|
|
66
67
|
const decision = state.decision;
|
|
68
|
+
if (decision.outcome === "approval-required") return {
|
|
69
|
+
allowed: false,
|
|
70
|
+
status: state.status,
|
|
71
|
+
decision,
|
|
72
|
+
slot: "approval"
|
|
73
|
+
};
|
|
67
74
|
if (!state.allowed || decision.outcome !== "granted") return {
|
|
68
75
|
...state,
|
|
69
76
|
slot: "fallback"
|
|
@@ -91,5 +98,20 @@ function approvalHandle(store, decision) {
|
|
|
91
98
|
request: (note) => store.requestApproval(decision, note)
|
|
92
99
|
};
|
|
93
100
|
}
|
|
101
|
+
function slotContent(slot, own, defaults) {
|
|
102
|
+
switch (slot) {
|
|
103
|
+
case "pending": return own.pending ?? defaults?.pending;
|
|
104
|
+
case "fallback": return own.fallback ?? defaults?.fallback;
|
|
105
|
+
case "approval": return own.approval ?? own.fallback ?? defaults?.approval ?? defaults?.fallback;
|
|
106
|
+
default: return slot;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** `describe` with the provider's `messages`; a call's own `messages` win. */
|
|
110
|
+
function describeWith(messages) {
|
|
111
|
+
return (decision, options) => describe(decision, messages === void 0 || options?.messages !== void 0 ? options : {
|
|
112
|
+
...options,
|
|
113
|
+
messages
|
|
114
|
+
});
|
|
115
|
+
}
|
|
94
116
|
//#endregion
|
|
95
|
-
export {
|
|
117
|
+
export { permissionSet as a, scopedTenant as c, tenantView as d, livePermDock as i, slotContent as l, describeWith as n, protectedView as o, filterResult as r, rolesView as s, approvalHandle as t, subjectView as u };
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { n as ActionMeta } from "./
|
|
1
|
+
import { A as WithX, O as AppDataSchema, n as ActionMeta } from "./permission-types-Dg39z9Kv.js";
|
|
2
2
|
//#region src/core/vocabulary.d.ts
|
|
3
3
|
declare const ROLE_KIND: "role";
|
|
4
4
|
declare const PLAN_KIND: "plan";
|
|
5
|
+
/** `defineRoles` and `definePlans` options. */
|
|
6
|
+
type VocabularyOptions<X = never> = {
|
|
7
|
+
/**
|
|
8
|
+
* A Standard Schema for every leaf's `meta.x`, validated synchronously at
|
|
9
|
+
* definition time. On a role tree it also checks the `meta.x` of custom
|
|
10
|
+
* roles a `RoleSource` returns; an invalid one is dropped, not the role.
|
|
11
|
+
*/
|
|
12
|
+
readonly x?: AppDataSchema<X>;
|
|
13
|
+
};
|
|
5
14
|
/**
|
|
6
15
|
* A role's metadata. `audience` names the surface its holders use (`'staff'`,
|
|
7
16
|
* `'portal'`, `'platform'`); `permdock.audiences()` lists the distinct
|
|
@@ -43,14 +52,14 @@ type Vocabulary = {
|
|
|
43
52
|
readonly roles?: RoleTree;
|
|
44
53
|
readonly plans?: PlanTree;
|
|
45
54
|
};
|
|
46
|
-
type InferRoleTree<Input> = { readonly [K in keyof Input & string]: Role<K>; };
|
|
47
|
-
type InferPlanTree<Input> = { readonly [K in keyof Input & string]: Plan<K>; };
|
|
55
|
+
type InferRoleTree<Input, X = never> = { readonly [K in keyof Input & string]: WithX<Role<K>, X>; };
|
|
56
|
+
type InferPlanTree<Input, X = never> = { readonly [K in keyof Input & string]: WithX<Plan<K>, X>; };
|
|
48
57
|
declare function isRole(value: unknown): value is Role;
|
|
49
58
|
declare function isPlan(value: unknown): value is Plan;
|
|
50
|
-
declare function defineRoles<const Input extends Record<string, RoleInit
|
|
51
|
-
declare function definePlans<const Input extends Record<string, PlanInit
|
|
59
|
+
declare function defineRoles<const Input extends Record<string, RoleInit>, X = never>(input: Input, options?: VocabularyOptions<X>): InferRoleTree<Input, X>;
|
|
60
|
+
declare function definePlans<const Input extends Record<string, PlanInit>, X = never>(input: Input, options?: VocabularyOptions<X>): InferPlanTree<Input, X>;
|
|
52
61
|
declare function listRoles(tree: RoleTree | undefined): readonly Role[];
|
|
53
62
|
declare function listPlans(tree: PlanTree | undefined): readonly Plan[];
|
|
54
63
|
declare function findRole(tree: RoleTree | undefined, key: string): Role | undefined;
|
|
55
64
|
//#endregion
|
|
56
|
-
export { RoleTree as a,
|
|
65
|
+
export { RoleTree as a, definePlans as c, isPlan as d, isRole as f, RoleMeta as i, defineRoles as l, listRoles as m, PlanTree as n, Vocabulary as o, listPlans as p, Role as r, VocabularyOptions as s, Plan as t, findRole as u };
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -1,36 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as Role } from "../vocabulary-
|
|
4
|
-
import { n as requiredPlans } from "../problem-details-
|
|
5
|
-
import { i as describe } from "../describe-
|
|
1
|
+
import { Dr as Membership, an as Snapshot, ir as Decision, rr as ApprovalRequiredDecision, ut as TokenVerifier } from "../policy-types-sp9P1iIV.js";
|
|
2
|
+
import { d as Permission } from "../permission-types-Dg39z9Kv.js";
|
|
3
|
+
import { r as Role } from "../vocabulary-hhEFLFoL.js";
|
|
4
|
+
import { n as requiredPlans } from "../problem-details-rIIo8B2C.js";
|
|
5
|
+
import { i as describe, r as DescribeOptions, t as DecisionDescription } from "../describe-C3ldA9os.js";
|
|
6
6
|
import { t as PermissionBoundaryState } from "../boundary-BmHxVH1J.js";
|
|
7
7
|
import { t as approvalHeaders } from "../headers-Cf-zWvsO.js";
|
|
8
|
-
import { a as
|
|
9
|
-
import { ComputedRef, DefineComponent, MaybeRefOrGetter, Plugin } from "vue";
|
|
8
|
+
import { a as ClientPermDock, c as PermissionSet, d as SubjectView, f as TenantView, i as ApprovalState, l as PermissionState, o as ClientStatus, p as UseRolesOptions, r as ApprovalHandle, s as FilterResult, u as ProviderOptionsBase } from "../store-9KO4BlkB.js";
|
|
9
|
+
import { ComputedRef, DefineComponent, MaybeRefOrGetter, Plugin, VNode } from "vue";
|
|
10
10
|
//#region src/vue/types.d.ts
|
|
11
|
-
type PermDockPluginOptions = {
|
|
11
|
+
type PermDockPluginOptions = ProviderOptionsBase & {
|
|
12
12
|
/**
|
|
13
13
|
* A ref or getter re-hydrates the store when it changes; a promise keeps
|
|
14
14
|
* the store `pending` until it settles (await the same promise in an async
|
|
15
15
|
* `setup` under `<Suspense>`).
|
|
16
16
|
*/
|
|
17
17
|
readonly snapshot: MaybeRefOrGetter<Snapshot | string> | PromiseLike<Snapshot | string>;
|
|
18
|
-
/**
|
|
19
|
-
* The AuthZEN evaluations endpoint for checks the snapshot cannot answer.
|
|
20
|
-
* `false` never calls one: such a check is denied with reason `server-only`.
|
|
21
|
-
*/
|
|
22
|
-
readonly endpoint?: string | false;
|
|
23
|
-
/** Where `refresh()` fetches a fresh snapshot. Defaults to `endpoint`. */
|
|
24
|
-
readonly snapshotUrl?: string;
|
|
25
|
-
readonly approvals?: string;
|
|
26
18
|
/** A ref or getter switches the active tenant (`refresh({ tenant })`) when it changes. */
|
|
27
19
|
readonly tenant?: MaybeRefOrGetter<string | undefined>;
|
|
28
|
-
readonly fetch?: typeof fetch;
|
|
29
20
|
/** Read on every request: a ref or getter carries a rotated token without rebuilding the store. */
|
|
30
21
|
readonly headers?: MaybeRefOrGetter<Readonly<Record<string, string>> | undefined>;
|
|
31
|
-
readonly maxAge?: number;
|
|
32
22
|
/** Read on every verification; set it at install to verify signed snapshots. */
|
|
33
23
|
readonly verifier?: MaybeRefOrGetter<TokenVerifier | undefined>;
|
|
24
|
+
/** What every `<Protected>` renders for a slot it leaves out. */
|
|
25
|
+
readonly defaults?: PermDockDefaults;
|
|
26
|
+
};
|
|
27
|
+
type SlotOutput = VNode | VNode[] | string | null;
|
|
28
|
+
/** Render functions for the `<Protected>` slots a component leaves out; they get the slot props. */
|
|
29
|
+
type PermDockDefaults = {
|
|
30
|
+
readonly pending?: () => SlotOutput;
|
|
31
|
+
readonly fallback?: (props: {
|
|
32
|
+
readonly decision: Decision;
|
|
33
|
+
}) => SlotOutput;
|
|
34
|
+
readonly approval?: (props: {
|
|
35
|
+
readonly decision: ApprovalRequiredDecision;
|
|
36
|
+
}) => SlotOutput;
|
|
34
37
|
};
|
|
35
38
|
//#endregion
|
|
36
39
|
//#region src/vue/composables.d.ts
|
|
@@ -53,6 +56,8 @@ export declare function useAssignablePermissions(options?: MaybeRefOrGetter<{
|
|
|
53
56
|
}>): ComputedRef<readonly Permission[]>;
|
|
54
57
|
export declare function useSubject(): ComputedRef<SubjectView>;
|
|
55
58
|
export declare function useApproval(decision: MaybeRefOrGetter<Decision>): ComputedRef<ApprovalHandle>;
|
|
59
|
+
/** `describe` with the plugin's `messages`; a call's own `messages` win. */
|
|
60
|
+
export declare function useDescribe(): (decision: Decision, options?: DescribeOptions) => DecisionDescription;
|
|
56
61
|
//#endregion
|
|
57
62
|
//#region src/vue/boundary.d.ts
|
|
58
63
|
/**
|
|
@@ -76,4 +81,4 @@ type ProtectedProps = {
|
|
|
76
81
|
};
|
|
77
82
|
export declare const Protected: DefineComponent<ProtectedProps>;
|
|
78
83
|
//#endregion
|
|
79
|
-
export { type ApprovalHandle, type ApprovalState, type ClientPermDock, type ClientStatus, type FilterResult, type PermDockPluginOptions, type PermissionBoundaryState, type PermissionSet, type PermissionState, type ProtectedProps, type SubjectView, type TenantView, type UseRolesOptions, approvalHeaders, describe, requiredPlans };
|
|
84
|
+
export { type ApprovalHandle, type ApprovalState, type ClientPermDock, type ClientStatus, type FilterResult, type PermDockDefaults, type PermDockPluginOptions, type PermissionBoundaryState, type PermissionSet, type PermissionState, type ProtectedProps, type SubjectView, type TenantView, type UseRolesOptions, approvalHeaders, describe, requiredPlans };
|
package/dist/vue/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { r as requiredPlans } from "../problem-details-
|
|
2
|
-
import { t as describe } from "../describe-
|
|
1
|
+
import { r as requiredPlans } from "../problem-details-DECUnXAn.js";
|
|
2
|
+
import { t as describe } from "../describe-Cgkp7eP0.js";
|
|
3
3
|
import { t as approvalHeaders } from "../headers-BZSDieNT.js";
|
|
4
|
-
import { i as isPromiseLike } from "../store-options-
|
|
5
|
-
import { a as
|
|
4
|
+
import { i as isPromiseLike } from "../store-options-CbUHDoSe.js";
|
|
5
|
+
import { a as permissionSet, c as scopedTenant, d as tenantView, i as livePermDock, l as slotContent, n as describeWith, o as protectedView, r as filterResult, s as rolesView, t as approvalHandle, u as subjectView } from "../views-CJsrBS1f.js";
|
|
6
6
|
import { n as boundaryFallback, t as boundaryDigest } from "../boundary-BM8a_P6E.js";
|
|
7
|
-
import { n as switchTenant, t as providerStore } from "../provider-store-
|
|
7
|
+
import { n as switchTenant, t as providerStore } from "../provider-store-Ctt-81Ni.js";
|
|
8
8
|
import { computed, defineComponent, effectScope, getCurrentScope, inject, isRef, onErrorCaptured, onScopeDispose, provide, shallowRef, toValue, watch } from "vue";
|
|
9
9
|
//#region src/vue/context.ts
|
|
10
10
|
const permDockKey = Symbol("permdock");
|
|
11
|
+
const permDockUiKey = Symbol("permdock-ui");
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/vue/composables.ts
|
|
13
14
|
function useStore() {
|
|
@@ -87,6 +88,10 @@ function useApproval(decision) {
|
|
|
87
88
|
return approvalHandle(store, toValue(decision));
|
|
88
89
|
});
|
|
89
90
|
}
|
|
91
|
+
/** `describe` with the plugin's `messages`; a call's own `messages` win. */
|
|
92
|
+
function useDescribe() {
|
|
93
|
+
return describeWith(inject(permDockUiKey, {}).messages);
|
|
94
|
+
}
|
|
90
95
|
//#endregion
|
|
91
96
|
//#region src/vue/boundary.ts
|
|
92
97
|
const boundaryKey = Symbol("permdock-boundary");
|
|
@@ -154,6 +159,10 @@ const permdockPlugin = { install(app, options) {
|
|
|
154
159
|
store.dispose();
|
|
155
160
|
});
|
|
156
161
|
app.provide(permDockKey, store);
|
|
162
|
+
app.provide(permDockUiKey, {
|
|
163
|
+
defaults: options.defaults,
|
|
164
|
+
messages: options.messages
|
|
165
|
+
});
|
|
157
166
|
} };
|
|
158
167
|
//#endregion
|
|
159
168
|
//#region src/vue/protected.ts
|
|
@@ -176,6 +185,7 @@ const Protected = defineComponent({
|
|
|
176
185
|
setup(props, { slots }) {
|
|
177
186
|
const local = usePermission(() => props.permission, () => props.data);
|
|
178
187
|
const root = usePermDock();
|
|
188
|
+
const { defaults } = inject(permDockUiKey, {});
|
|
179
189
|
const scoped = computed(() => scopedTenant(root, props.tenant));
|
|
180
190
|
return () => {
|
|
181
191
|
const view = protectedView({
|
|
@@ -183,9 +193,15 @@ const Protected = defineComponent({
|
|
|
183
193
|
status: local.status.value,
|
|
184
194
|
decision: local.decision.value
|
|
185
195
|
}, root, props.permission, props.data, scoped.value);
|
|
196
|
+
const own = {
|
|
197
|
+
pending: slots["pending"],
|
|
198
|
+
fallback: slots["fallback"],
|
|
199
|
+
approval: slots["approval"]
|
|
200
|
+
};
|
|
186
201
|
switch (view.slot) {
|
|
187
|
-
case "pending": return
|
|
188
|
-
case "fallback": return
|
|
202
|
+
case "pending": return slotContent("pending", own, defaults)?.() ?? null;
|
|
203
|
+
case "fallback": return slotContent("fallback", own, defaults)?.({ decision: view.decision }) ?? null;
|
|
204
|
+
case "approval": return slotContent("approval", own, defaults)?.({ decision: view.decision }) ?? null;
|
|
189
205
|
case "default": return slots["default"]?.({ decision: view.decision }) ?? null;
|
|
190
206
|
default: return view;
|
|
191
207
|
}
|
|
@@ -193,4 +209,4 @@ const Protected = defineComponent({
|
|
|
193
209
|
}
|
|
194
210
|
});
|
|
195
211
|
//#endregion
|
|
196
|
-
export { PermissionBoundary, Protected, approvalHeaders, describe, permdockPlugin, requiredPlans, useApproval, useAssignablePermissions, useAssignableRoles, useFilter, useMemberships, usePermDock, usePermission, usePermissionBoundary, usePermissions, useRoles, useSubject, useTenant };
|
|
212
|
+
export { PermissionBoundary, Protected, approvalHeaders, describe, permdockPlugin, requiredPlans, useApproval, useAssignablePermissions, useAssignableRoles, useDescribe, useFilter, useMemberships, usePermDock, usePermission, usePermissionBoundary, usePermissions, useRoles, useSubject, useTenant };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as describeError } from "./errors-CWfoNg9N.js";
|
|
2
|
-
import { t as defaultSrcPath } from "./files-
|
|
3
|
-
import { r as runCollect } from "./collect-
|
|
4
|
-
import { n as isConfigFile, r as loadConfig } from "./config-
|
|
2
|
+
import { t as defaultSrcPath } from "./files-D_JIzUrP.js";
|
|
3
|
+
import { r as runCollect } from "./collect-2SrB7lfk.js";
|
|
4
|
+
import { n as isConfigFile, r as loadConfig } from "./config-BIjREpyE.js";
|
|
5
5
|
import { watch } from "node:fs";
|
|
6
6
|
import { basename, dirname, relative, resolve, sep } from "node:path";
|
|
7
7
|
//#region src/cli/watch.ts
|
|
@@ -19,7 +19,7 @@ function within(dirs, file) {
|
|
|
19
19
|
return path !== "" && !path.startsWith("..") && !path.startsWith(sep);
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
async function collectOnce(cwd, options, check, fresh, configFile) {
|
|
22
|
+
async function collectOnce(cwd, options, check, fresh, configFile, now = () => /* @__PURE__ */ new Date()) {
|
|
23
23
|
const config = await loadConfig(cwd, configFile, { fresh });
|
|
24
24
|
const collect = {
|
|
25
25
|
...config.collect,
|
|
@@ -30,7 +30,7 @@ async function collectOnce(cwd, options, check, fresh, configFile) {
|
|
|
30
30
|
config,
|
|
31
31
|
collect,
|
|
32
32
|
check,
|
|
33
|
-
now:
|
|
33
|
+
now: now(),
|
|
34
34
|
fresh
|
|
35
35
|
});
|
|
36
36
|
const inputs = [
|
|
@@ -67,7 +67,7 @@ function createCollectScheduler(cwd, options, settings) {
|
|
|
67
67
|
async function run(check) {
|
|
68
68
|
const fresh = loaded;
|
|
69
69
|
loaded = true;
|
|
70
|
-
const result = await collectOnce(cwd, options, check, fresh, settings?.configFile);
|
|
70
|
+
const result = await collectOnce(cwd, options, check, fresh, settings?.configFile, settings?.now);
|
|
71
71
|
ignored = new Set(result.written);
|
|
72
72
|
inputs = result.inputs;
|
|
73
73
|
sources = result.sources;
|
package/dist/webmcp/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { an as Snapshot, ir as Decision } from "../policy-types-sp9P1iIV.js";
|
|
2
|
+
import { d as Permission, p as PermissionTree } from "../permission-types-Dg39z9Kv.js";
|
|
3
3
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
4
|
//#region src/webmcp/types.d.ts
|
|
5
5
|
type WebMcpClientStatus = "ready" | "pending" | "stale" | "server-only";
|
package/dist/webmcp/index.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { t as compact } from "../compact-
|
|
2
|
-
import {
|
|
3
|
-
import { n as PermDockValidationError } from "../validation-error-
|
|
4
|
-
import {
|
|
5
|
-
import { t as describe } from "../describe-B_gVZEVi.js";
|
|
6
|
-
import { n as isThenable, t as ignoreRejection } from "../thenable-okc2xDsj.js";
|
|
1
|
+
import { r as isRecord, t as compact } from "../compact-CAf557ZB.js";
|
|
2
|
+
import { n as isThenable, t as ignoreRejection } from "../thenable-QSmvt-vZ.js";
|
|
3
|
+
import { n as PermDockValidationError } from "../validation-error-ZfUHbKvf.js";
|
|
4
|
+
import { c as listPermissions, f as resourceOfNode, i as getRegistry, m as annotationsFor, s as isRegistryTree } from "../permission-registry-BsblpB-z.js";
|
|
7
5
|
import { n as resourceRef } from "../resource-ref-CaS9yVPi.js";
|
|
6
|
+
import { n as deniedToolRefusal, r as toolErrorResult, t as approvalToolRefusal } from "../tool-refusal-CQ7OEia9.js";
|
|
8
7
|
//#region src/webmcp/register.ts
|
|
9
8
|
const MISSING_CONTEXT = "permdock/webmcp: document.modelContext is absent; registerTools is a no-op.";
|
|
10
|
-
function isRecord(value) {
|
|
11
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12
|
-
}
|
|
13
9
|
const CURRENT = Symbol.for("permdock.current");
|
|
14
10
|
function current(permdock) {
|
|
15
11
|
const latest = permdock[CURRENT];
|
|
@@ -100,43 +96,23 @@ function bindTenant(input, tenantKey, tenant) {
|
|
|
100
96
|
}
|
|
101
97
|
};
|
|
102
98
|
}
|
|
103
|
-
function alternativesOf(decision) {
|
|
104
|
-
return decision.alternatives.map((leaf) => leaf.key);
|
|
105
|
-
}
|
|
106
99
|
function deniedResult(decision, permission, data) {
|
|
107
|
-
|
|
108
|
-
const alternatives = alternativesOf(decision);
|
|
109
|
-
const suffix = alternatives.length === 0 ? "" : ` You may: ${alternatives.join(", ")}.`;
|
|
110
|
-
return {
|
|
111
|
-
isError: true,
|
|
112
|
-
content: [{
|
|
113
|
-
type: "text",
|
|
114
|
-
text: `Denied: ${permission.key}.${suffix}`
|
|
115
|
-
}],
|
|
116
|
-
structuredContent: compact({
|
|
117
|
-
outcome: "denied",
|
|
118
|
-
permission: permission.key,
|
|
119
|
-
resource: resourceRef(permission, permission.kind === "collection" ? void 0 : data),
|
|
120
|
-
denials: wireDenials(decision.denials),
|
|
121
|
-
alternatives,
|
|
122
|
-
detail: described.detail
|
|
123
|
-
})
|
|
124
|
-
};
|
|
100
|
+
return toolErrorResult(deniedToolRefusal(decision, permission, refOf(permission, data)));
|
|
125
101
|
}
|
|
126
102
|
function approvalResult(decision, permission, data) {
|
|
103
|
+
const refusal = approvalToolRefusal(decision, permission, refOf(permission, data));
|
|
127
104
|
return {
|
|
128
105
|
content: [{
|
|
129
106
|
type: "text",
|
|
130
|
-
text:
|
|
107
|
+
text: refusal.text
|
|
131
108
|
}],
|
|
132
|
-
structuredContent:
|
|
133
|
-
outcome: "approval-required",
|
|
134
|
-
permission: permission.key,
|
|
135
|
-
resource: resourceRef(permission, permission.kind === "collection" ? void 0 : data),
|
|
136
|
-
token: decision.token
|
|
137
|
-
}
|
|
109
|
+
structuredContent: refusal.structured
|
|
138
110
|
};
|
|
139
111
|
}
|
|
112
|
+
/** A collection permission names the resource type only, never an id from the input. */
|
|
113
|
+
function refOf(permission, data) {
|
|
114
|
+
return resourceRef(permission, permission.kind === "collection" ? void 0 : data);
|
|
115
|
+
}
|
|
140
116
|
function validationResult(error) {
|
|
141
117
|
return {
|
|
142
118
|
isError: true,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { j as PolicyVocabulary, jt as PermDock } from "./policy-types-sp9P1iIV.js";
|
|
2
|
+
//#region src/core/wrap.d.ts
|
|
3
|
+
/** A wrapper an adapter applies to each instance it builds, as `withOtel` does. */
|
|
4
|
+
type PermDockWrap = <V extends PolicyVocabulary>(permdock: PermDock<V>) => PermDock<V>;
|
|
5
|
+
/** The members `wrapPermDock` replaces; it re-wraps the derived instances itself. */
|
|
6
|
+
type PermDockOverrides<V extends PolicyVocabulary = PolicyVocabulary> = Partial<Omit<PermDock<V>, "tenant" | "team" | "derive">>;
|
|
7
|
+
/**
|
|
8
|
+
* A frozen copy of `permdock` with the members `overrides` returns replaced.
|
|
9
|
+
* `overrides` runs again for every instance `tenant()`, `team()` and
|
|
10
|
+
* `derive()` return, so a wrapper never falls off a derived instance.
|
|
11
|
+
*/
|
|
12
|
+
declare function wrapPermDock<V extends PolicyVocabulary = PolicyVocabulary>(permdock: PermDock<V>, overrides: (permdock: PermDock<V>) => PermDockOverrides<V>): PermDock<V>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { PermDockWrap as n, wrapPermDock as r, PermDockOverrides as t };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/core/wrap.ts
|
|
2
|
+
/**
|
|
3
|
+
* A frozen copy of `permdock` with the members `overrides` returns replaced.
|
|
4
|
+
* `overrides` runs again for every instance `tenant()`, `team()` and
|
|
5
|
+
* `derive()` return, so a wrapper never falls off a derived instance.
|
|
6
|
+
*/
|
|
7
|
+
function wrapPermDock(permdock, overrides) {
|
|
8
|
+
const wrap = (next) => wrapPermDock(next, overrides);
|
|
9
|
+
return Object.freeze({
|
|
10
|
+
...permdock,
|
|
11
|
+
...overrides(permdock),
|
|
12
|
+
tenant: (id) => wrap(permdock.tenant(id)),
|
|
13
|
+
team: (id) => wrap(permdock.team(id)),
|
|
14
|
+
derive: (options) => {
|
|
15
|
+
const derived = permdock.derive(options);
|
|
16
|
+
return derived instanceof Promise ? derived.then(wrap) : wrap(derived);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** `otel`, then `wrap`. */
|
|
21
|
+
function composeWraps(otel, wrap) {
|
|
22
|
+
if (otel === void 0 || wrap === void 0) return otel ?? wrap;
|
|
23
|
+
return (permdock) => wrap(otel(permdock));
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { wrapPermDock as n, composeWraps as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "permdock",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Typed permissions for TypeScript apps, APIs, databases, and AI agents, with the permdock CLI and test runners.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -263,7 +263,7 @@
|
|
|
263
263
|
"smol-toml": "1.9.0"
|
|
264
264
|
},
|
|
265
265
|
"devDependencies": {
|
|
266
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
266
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.289",
|
|
267
267
|
"@arethetypeswrong/cli": "0.18.5",
|
|
268
268
|
"@babel/core": "8.0.6",
|
|
269
269
|
"@modelcontextprotocol/client": "2.3.0",
|
|
@@ -272,9 +272,9 @@
|
|
|
272
272
|
"@nestjs/core": "12.1.2",
|
|
273
273
|
"@nestjs/platform-express": "12.1.2",
|
|
274
274
|
"@openai/agents": "0.18.0",
|
|
275
|
-
"@orpc/contract": "2.0.0-beta.
|
|
276
|
-
"@orpc/openapi": "2.0.0-beta.
|
|
277
|
-
"@orpc/server": "2.0.0-beta.
|
|
275
|
+
"@orpc/contract": "2.0.0-beta.42",
|
|
276
|
+
"@orpc/openapi": "2.0.0-beta.42",
|
|
277
|
+
"@orpc/server": "2.0.0-beta.42",
|
|
278
278
|
"@permdock/ox-config": "0.0.0",
|
|
279
279
|
"@permdock/typescript-config": "0.0.0",
|
|
280
280
|
"@supabase/middleware": "1.0.0",
|
|
@@ -290,14 +290,14 @@
|
|
|
290
290
|
"ai": "7.0.127",
|
|
291
291
|
"ajv": "8.20.0",
|
|
292
292
|
"babel-plugin-react-compiler": "1.0.0",
|
|
293
|
-
"better-supabase": "0.
|
|
293
|
+
"better-supabase": "0.8.0",
|
|
294
294
|
"drizzle-orm": "1.0.0-rc.5-5935859",
|
|
295
295
|
"elysia": "1.4.30",
|
|
296
296
|
"eve": "0.71.3",
|
|
297
297
|
"express": "5.2.1",
|
|
298
298
|
"fastify": "5.12.5",
|
|
299
299
|
"happy-dom": "20.14.5",
|
|
300
|
-
"hono": "4.13.
|
|
300
|
+
"hono": "4.13.13",
|
|
301
301
|
"jose": "6.2.12",
|
|
302
302
|
"kysely": "0.29.6",
|
|
303
303
|
"next": "16.3.8",
|
|
@@ -334,7 +334,7 @@
|
|
|
334
334
|
"@supabase/middleware": ">=1",
|
|
335
335
|
"@trpc/server": ">=11",
|
|
336
336
|
"ai": ">=5",
|
|
337
|
-
"better-supabase": ">=0.6.0 <0.
|
|
337
|
+
"better-supabase": ">=0.6.0 <0.9.0",
|
|
338
338
|
"drizzle-orm": ">=0.40 || >=1.0.0-rc.0",
|
|
339
339
|
"elysia": ">=1",
|
|
340
340
|
"eve": ">=0.40",
|
package/schemas/catalog-v1.json
CHANGED
|
@@ -30,7 +30,7 @@ Authentication is upstream: core never verifies a token. A `subjectFrom*` resolv
|
|
|
30
30
|
|
|
31
31
|
## Workflow
|
|
32
32
|
|
|
33
|
-
1. **Verify access tokens.**
|
|
33
|
+
1. **Verify access tokens.** Create one `createJwtSubjectResolver({ discovery, audience })` per issuer from `permdock/jwt` for the life of the process, because it caches Discovery and the JWKS; `subjectFromJwt(token, options)` caches nothing and suits a one-off check. Or use `subjectFromIntrospection` when the app already called introspection. -> [references/tokens-keys-links.md](references/tokens-keys-links.md)
|
|
34
34
|
✓ An ID token, a token for another audience and an expired token each resolve to the anonymous subject.
|
|
35
35
|
2. **Issue API keys, when the product has them.** Guard the creation endpoint with its own permission, call `decideCredential(permdock, request, { settings })`, store the hash with the returned `Credential`, and show the key once. -> [references/tokens-keys-links.md](references/tokens-keys-links.md#api-keys-and-service-accounts)
|
|
36
36
|
✓ A service key wider than its creator is denied with `exceeds-creator`.
|
|
@@ -5,14 +5,19 @@ Owning pages: [JWT adapter](https://permdock.com/docs/adapters/jwt), [authentica
|
|
|
5
5
|
## Access tokens — `permdock/jwt`
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
import {
|
|
8
|
+
import { createJwtSubjectResolver } from "permdock/jwt";
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// One resolver per issuer for the life of the process: it caches Discovery and the JWKS.
|
|
11
|
+
const resolve = createJwtSubjectResolver({
|
|
11
12
|
discovery: "https://issuer.example.com",
|
|
12
13
|
audience: "https://api.example.com",
|
|
13
14
|
});
|
|
15
|
+
|
|
16
|
+
const subject = await resolve(token, request);
|
|
14
17
|
```
|
|
15
18
|
|
|
19
|
+
`subjectFromJwt(token, options)` takes the same options but builds a new verifier per call, so each call fetches Discovery and the JWKS again. Use it for a one-off check such as a CLI or a test.
|
|
20
|
+
|
|
16
21
|
- Prefer `discovery: '<issuer>'` over a hand-copied `jwks` URL. Set `audience` to the resource identifier. Write algorithms as `Ed25519`, `ES256` or `PS256`; never `EdDSA`, `none` or `RSA1_5`.
|
|
17
22
|
- Keep the default `accept: 'access-token'`, so an ID token never authorises an API call.
|
|
18
23
|
- `jose` is an optional peer. A failure is the anonymous subject, never a throw; the cause is reported through `on('auth')`. A claimed `act` chain that does not nest is anonymous with cause `invalid-chain`.
|
|
@@ -57,6 +57,10 @@ When the database already holds the rules, skip `generate`. Map each helper in `
|
|
|
57
57
|
|
|
58
58
|
When hand-written policies call the app's own helpers (`org_ids_with_permission`, `has_org_permission`), map each under `rls.migrate.helpers` with its `form` (`ids`, `row`, `scoped`, `global`, `membership`) and the legacy keys under `rls.migrate.keys` or `prefixes`. Run `permdock rls migrate`, read the skipped calls, and apply with `--write`. Generate with `--helpers-only` while the policies stay hand-written. A `row-conditions` skip means that table's policy should be generated, not migrated.
|
|
59
59
|
|
|
60
|
+
When the old helpers read a permissions table that triggers keep in step (`user_permissions`), list it under `rls.migrate.tables`. `permdock rls migrate` then reports its refresh triggers and every policy, view or function that still reads it, and `permdock doctor` reports PD066 while the migrations still create it. Rewrite each reader, then run `permdock rls migrate --retire-out <migrations dir>/`, which exits `1` and writes nothing while a reader remains. Never hand-write the drop with `cascade` ([retire a materialised table](https://permdock.com/docs/cli/rls#retire-a-materialised-table)).
|
|
61
|
+
|
|
62
|
+
Triggers the app owns on generated tables (an audit trigger, a notification) go in `rls.triggers` or `rls.audit`, so they live in the generated files; never in a migration that patches the generated tables afterwards ([triggers and audit](https://permdock.com/docs/cli/rls#triggers-and-audit)).
|
|
63
|
+
|
|
60
64
|
## Attributes RLS cannot see
|
|
61
65
|
|
|
62
66
|
A grant condition on `context.*` cannot be enforced by the database (PD027). Compare with a server-set `principal.claims.*` claim instead, never one from `user_metadata`. On Supabase, `supabase.hook.attrs` lists only server-owned columns or `app_metadata.<key>` entries clients cannot update (PD028). A check that must refuse a sign-in (single sign-on enforcement, a locked account) goes in `supabase.hook.before` as a schema-qualified `(event jsonb) returns jsonb` function the generated hook calls first; never a second hook or a hand edit of the generated one. The hook, declarative schemas (`--split`) and `fromTable` / `fromJunction` membership sources are on the [Supabase adapter](https://permdock.com/docs/adapters/supabase) and [Supabase hook](https://permdock.com/docs/adapters/supabase-hook) pages.
|
|
@@ -87,3 +87,4 @@ type CustomRole = {
|
|
|
87
87
|
- A platform custom role (`scope: 'global'`, no `tenant`, `team` or `id`) is held through `principal.roles` and capped by the allows of declared global roles marked `assignable`. `RoleSource.globalRoles({ held })` returns them; `customRoleSource(reader, { read: 'held', policy })` skips that read while every held global role is declared.
|
|
88
88
|
- A stored grant under a key renamed with `definePermissions(..., { renamed })` still resolves; `validateCustomRole` lists it in `renamed` as `{ from, to }`, and `permdock doctor` PD055 prints the `update` that rewrites it.
|
|
89
89
|
- For generated RLS, add `--custom-roles` (or `rls.customRoles: true`) to `permdock rls generate`. Platform roles are rows with `scope = 'global'` and a null `tenant_id`, or the top-level `role_grants` claim in `jwt` mode. With levels, `custom_role_permissions` gains a `level` column and the claim writes `key@level`.
|
|
90
|
+
- To adopt custom roles the app already stores in its own tables, set `rls.customRoles.from` and `rls.customRoleWrites.roles`, then run `permdock rls generate --backfill-out <migrations dir>/`. The migration saves each role through the trusted replace function, drops entries outside the ceiling with a warning, and skips roles that already have rows; never write the copy by hand ([backfill](https://permdock.com/docs/cli/rls#backfill-from-existing-tables)).
|
|
@@ -110,7 +110,7 @@ Install each with `npx skills add ScaleDockHQ/PermDock --skill <name>` when the
|
|
|
110
110
|
|
|
111
111
|
## Reference index
|
|
112
112
|
|
|
113
|
-
- [references/adapters.md](references/adapters.md): factory shapes for Next.js, HTTP frameworks, RPC frameworks, UI frameworks, AuthZEN, OpenAPI, OpenTelemetry, SCIM, Cloud, Better Auth, Clerk, Supabase, the remote PDP
|
|
114
|
-
- [references/policy-options.md](references/policy-options.md): limits, disclosure, plans, validity windows, step-up, and CLI starting points (OpenAPI import, Arazzo, Cloud push).
|
|
113
|
+
- [references/adapters.md](references/adapters.md): factory shapes for Next.js, HTTP frameworks, RPC frameworks, UI frameworks, AuthZEN, OpenAPI, OpenTelemetry, SCIM, Cloud, Better Auth, Clerk, Supabase, the remote PDP, collect-only frameworks, and the `onDenied`, `context` and `wrap` adapter hooks.
|
|
114
|
+
- [references/policy-options.md](references/policy-options.md): limits, disclosure, plans, validity windows, step-up, app data and app obligations, and CLI starting points (OpenAPI import, Arazzo, Cloud push).
|
|
115
115
|
- The `permdock` skill: the mental model, `explain` for an unexpected denial, and the docs MCP.
|
|
116
116
|
- Docs: [policies](https://permdock.com/docs/concepts/policies), [conditions](https://permdock.com/docs/concepts/conditions), [decisions](https://permdock.com/docs/concepts/decisions), [adapters](https://permdock.com/docs/adapters).
|
|
@@ -313,6 +313,14 @@ instrument(permdock, {
|
|
|
313
313
|
|
|
314
314
|
HTTP adapters accept the same options as `otel`. `@opentelemetry/api` is optional; without it the adapter writes only through `logger`.
|
|
315
315
|
|
|
316
|
+
## Adapter hooks
|
|
317
|
+
|
|
318
|
+
Every HTTP adapter, `permdock/mcp` and `permdock/ai-sdk` take three hooks ([extend PermDock](https://permdock.com/docs/guides/extending)):
|
|
319
|
+
|
|
320
|
+
- `onDenied`: on HTTP, `({ decision, problem, request })` returns Problem Details with extra members, a `Response`, or `undefined`; a status below 300 or a throw keeps the default. On MCP and the AI SDK it returns replacement text only. On Next.js the factory `onDenied` also runs for `requireAccess`.
|
|
321
|
+
- `context`: returns plain JSON merged into `subject.context`. Return only server-derived values, never a header, body field or tool argument; it is visible in the snapshot.
|
|
322
|
+
- `wrap`: wraps each instance after `otel`; `permdock/next` takes it too. Build it with `wrapPermDock(permdock, (inner) => ({ … }))` so `tenant()`, `team()` and `derive()` stay wrapped.
|
|
323
|
+
|
|
316
324
|
## SCIM — `permdock/scim`
|
|
317
325
|
|
|
318
326
|
No factory. Mount `scimHandler` and pass `directoryMembershipSource(store)` as `memberships`:
|
|
@@ -402,7 +410,7 @@ const subject = subjectFromSupabase(claims, {
|
|
|
402
410
|
|
|
403
411
|
Write the claims with `permdock supabase hook generate`; `permdock supabase inspect --json` prints the manifest (helper names, tenant claim, budget, claims written) which `authorizationProvider` from `permdock/better-supabase` turns into better-supabase's `authorization` config. No `@supabase/supabase-js` peer. Pair with `permdock rls generate`, or keep SQL as authority and run `permdock rls verify --db` against `sqlFunction` twins ([database-first](https://permdock.com/docs/adapters/rls)); the generic RLS workflow is in the `permdock-data` skill.
|
|
404
412
|
|
|
405
|
-
With better-supabase, set `authorization: authorizationProvider({ manifest, catalog })` in `better-supabase.config.ts` (with `rls.customRoles` its `canAssign` and `canAssignFor` call `permdock_can_assign_any` and its `_for` form, so custom roles are assignable through better-supabase; regenerate the manifest after turning custom roles on), build bucket and topic `access` policies with `bucketPolicy` and `topicPolicy`, and map its session with `subjectFromBetterSupabase(session)` (all from `permdock/better-supabase`): the active tenant's `features` become `principal.plans`. Pass `plans: { keys }` when better-supabase's `entitlements.claim.keys` shortens feature keys, and `apiKeys: { permissions, manifest }` so an `apiKey` session maps to the key's credential subject instead of the anonymous one. For `createMcp` tools, put the permission in `meta` and spread `toolPolicy({ permdock })` into the options: tools without one are hidden and refused, and approval-required calls are refused because `createMcp` collects no approvals. Wrap a `CredentialProvider` with `credentialGuard(provider, { permdock, use, revoke? })` so PermDock decides each token use. `authorizationProvider({ ..., approver })` lets holders of that permission approve AI tool calls, never their own. better-supabase's `createAgentRuntime({ toolApproval })` takes `toolApproval` from `permdock/ai-sdk` as it is. Validate its claims with `betterSupabase.claims(supabaseClaims().extend(appSchema))` (`supabaseClaims` from `permdock/supabase`, any Standard Schema as `appSchema`) instead of a hand-written copy of the claim shape. A `supabase.hook.claims` function that needs the user's organizations calls `<schema>.member_organization_ids_for(user_id)` (generated by `rls generate`, executable by `supabase_auth_admin` only) instead of querying the membership tables itself. A token Supabase's OAuth server issued to a third-party app (`client_id`) becomes an `oauth-client` actor limited to its `scope`; `deny(permission, { to: actor('oauth-client') })` keeps such apps out, in the app and, through `rls generate`, in Postgres. A better-supabase support session (`act.kind: 'support'`) is actor kind `support` with `sessionId` and `readOnly`, and `actingAs` (`act.kind: 'impersonation'`) is kind `impersonation`; neither has a delegation, so they reach nothing until a policy delegation names `actor('support')` or `actor('impersonation')`, and `readOnly: true` (also when `read_only` is absent) narrows that to read-only permissions. Generated RLS reads memberships, not `act`, so a support token sent to the Data API writes as the user: add a restrictive `for update` (and `insert` / `delete`) policy per writable table that requires `act ->> 'read_only' = 'false'` when `act` is a support or session level ([support access](https://permdock.com/docs/guides/support-access)). With `rls.anonymousSignIns: 'deny'`, pass `anonymousSignIns: 'deny'` to the subject mapper too (doctor PD057). Check a deployed database against the generated policies with `permdock rls verify --introspect --db $DATABASE_URL`.
|
|
413
|
+
With better-supabase, set `authorization: authorizationProvider({ manifest, catalog })` in `better-supabase.config.ts` (with `rls.customRoles` its `canAssign` and `canAssignFor` call `permdock_can_assign_any` and its `_for` form, so custom roles are assignable through better-supabase; regenerate the manifest after turning custom roles on), on 0.8 pass `authorizer({ policy })` to the server (`createNext`, `createHono`, `createMcp`) so every `permission` a resource, action, route guard or tool declares is decided by PermDock from the verified claims (`operations` maps tables for `permissions: true`; a missing or anonymous claim denies), build bucket and topic `access` policies with `bucketPolicy` and `topicPolicy`, and map its session with `subjectFromBetterSupabase(session)` (all from `permdock/better-supabase`): the active tenant's `features` become `principal.plans`. Pass `plans: { keys }` when better-supabase's `entitlements.claim.keys` shortens feature keys, and `apiKeys: { permissions, manifest }` so an `apiKey` session maps to the key's credential subject instead of the anonymous one. For `createMcp` tools, put the permission in `meta` and spread `toolPolicy({ permdock })` into the options: tools without one are hidden and refused, and approval-required calls are refused because `createMcp` collects no approvals. Wrap a `CredentialProvider` with `credentialGuard(provider, { permdock, use, revoke? })` so PermDock decides each token use. `authorizationProvider({ ..., approver })` lets holders of that permission approve AI tool calls, never their own. better-supabase's `createAgentRuntime({ toolApproval })` takes `toolApproval` from `permdock/ai-sdk` as it is. Validate its claims with `betterSupabase.claims(supabaseClaims().extend(appSchema))` (`supabaseClaims` from `permdock/supabase`, any Standard Schema as `appSchema`) instead of a hand-written copy of the claim shape. A `supabase.hook.claims` function that needs the user's organizations calls `<schema>.member_organization_ids_for(user_id)` (generated by `rls generate`, executable by `supabase_auth_admin` only) instead of querying the membership tables itself. A token Supabase's OAuth server issued to a third-party app (`client_id`) becomes an `oauth-client` actor limited to its `scope`; `deny(permission, { to: actor('oauth-client') })` keeps such apps out, in the app and, through `rls generate`, in Postgres. A better-supabase support session (`act.kind: 'support'`) is actor kind `support` with `sessionId` and `readOnly`, and `actingAs` (`act.kind: 'impersonation'`) is kind `impersonation`; neither has a delegation, so they reach nothing until a policy delegation names `actor('support')` or `actor('impersonation')`, and `readOnly: true` (also when `read_only` is absent) narrows that to read-only permissions. Generated RLS reads memberships, not `act`, so a support token sent to the Data API writes as the user: add a restrictive `for update` (and `insert` / `delete`) policy per writable table that requires `act ->> 'read_only' = 'false'` when `act` is a support or session level ([support access](https://permdock.com/docs/guides/support-access)). With `rls.anonymousSignIns: 'deny'`, pass `anonymousSignIns: 'deny'` to the subject mapper too (doctor PD057). Check a deployed database against the generated policies with `permdock rls verify --introspect --db $DATABASE_URL`.
|
|
406
414
|
|
|
407
415
|
`claims` is whatever Supabase verified: `data.claims` from `supabase.auth.getClaims()` on an `@supabase/ssr` server client, or `jwtClaims` from `@supabase/server` (`ctx.jwtClaims` in `withSupabase` or a `pipeline`, and `c.var.jwtClaims` after a framework bridge such as `toHono([withClaims(), withPermDock()])`). `@supabase/server/adapters/*` and `c.var.supabaseContext` are deprecated and removed on 1 December 2026; do not write new code against them ([Hono, H3, Elysia and NestJS](https://permdock.com/docs/adapters/supabase#hono-h3-elysia-and-nestjs)). Pass `null` for anonymous callers; never `getSession().access_token` (unverified). An API-key auth mode (`secret`, `publishable`) has `jwtClaims: null` and is the anonymous subject, not a user.
|
|
408
416
|
|
|
@@ -33,10 +33,19 @@ Hardware-key step-up is `to: assurance({ amr: ['hwk'], maxAge: 300 })` and rende
|
|
|
33
33
|
Adopting PermDock in an app with its own keys, SQL helpers and tokens is a step-by-step guide ([existing apps](https://permdock.com/docs/getting-started/existing-apps)):
|
|
34
34
|
|
|
35
35
|
- Keep the app's keys. Map verbs such as `view` to SQL with `rls.actions`, and give colliding resources a distinct `name` on `resource()`.
|
|
36
|
-
- Put application-owned metadata in `meta.x`; PermDock carries it and never reads it.
|
|
36
|
+
- Put application-owned metadata in `meta.x`; PermDock carries it and never reads it (see App data below).
|
|
37
37
|
- Rename a key later with `definePermissions(tree, { renamed: { "old.key": "new.key" } })`. Remove the alias only when `permdock doctor` PD055 and PD056 are quiet; `permdock diff` reports the removal as the breaking `alias-removed`.
|
|
38
38
|
- Generate helpers beside legacy SQL with `permdock rls generate --helpers-only --shims`, then rewrite policies with `permdock rls migrate --write`.
|
|
39
39
|
|
|
40
|
+
## App data and app obligations
|
|
41
|
+
|
|
42
|
+
Owning page: [extend PermDock](https://permdock.com/docs/guides/extending).
|
|
43
|
+
|
|
44
|
+
- Type `x` with one Standard Schema per kind: `definePermissions(tree, { x: { permission, resource } })`, `defineRoles(tree, { x })`, `definePlans(tree, { x })`, `definePolicy(…, { x: { grant, membership } })`. Each schema validates synchronously. Invalid `x` in code throws; invalid `Membership.x` or custom-role `meta.x` from a source is dropped and the row stays.
|
|
45
|
+
- Describe a grant with `allow(p, { name, meta: { description, x } })`. It reaches `decision.matched`, decision events, snapshot grants and catalog grants, and stays out of the policy fingerprint.
|
|
46
|
+
- Steer code on a grant with `allow(p, { obligations: ['watermark', { name, detail }] })`, never on a deny. Read `{ kind: 'app', name, detail? }` from `decision.obligations` on a granted decision.
|
|
47
|
+
- Snapshots carry grant `meta`, membership `x` and every leaf's `meta` to the client: never put a secret in them.
|
|
48
|
+
|
|
40
49
|
## CLI starting points
|
|
41
50
|
|
|
42
51
|
- When the app already has an OpenAPI document and no definitions yet, start from `permdock openapi import --doc <doc> --out src/permissions.generated.ts --schema zod` and review each action's `meta.inferredFrom`.
|
package/dist/catalog-CRW5Mx_B.js
DELETED
package/dist/collect-DSWOk19R.js
DELETED