permdock 0.7.0 → 0.9.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 +1 -3
- package/dist/a2a/index.d.ts +7 -7
- package/dist/a2a/index.js +8 -8
- package/dist/action-result-BcudBQOF.d.ts +19 -0
- package/dist/{adapter-context-CRhqyzCk.js → adapter-context-CIQpQxbE.js} +8 -2
- package/dist/{adoption-scan-D-feE7BE.js → adoption-scan-Ch07MdxN.js} +5 -5
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/ai-sdk/index.d.ts +19 -13
- package/dist/ai-sdk/index.js +6 -6
- package/dist/{app-data-MuyzVqX8.js → app-data-UNNm07jV.js} +10 -7
- package/dist/{approval-header-CJACtHkv.js → approval-header-8QV6MU4H.js} +6 -3
- package/dist/{approval-prompt-K0faOLFp.d.ts → approval-prompt-3BqWczTt.d.ts} +13 -11
- package/dist/{approval-prompt-Dg5LeAcT.js → approval-prompt-B8hQY69x.js} +5 -6
- package/dist/approvals/index.d.ts +4 -4
- package/dist/approvals/index.js +6 -6
- package/dist/{approvals-CMRfsbBh.js → approvals-DnIBTuXE.js} +66 -42
- package/dist/{approvers-CqPOLD-o.js → approvers-B4r0N_Uz.js} +8 -2
- package/dist/{arazzo-ClrF3PVb.js → arazzo-BpS7LnV0.js} +2 -2
- package/dist/{arazzo-rdeJ8n1J.js → arazzo-CmQaGPkM.js} +6 -6
- package/dist/{args-CC3OwyHW.js → args-0FrVs5EH.js} +14 -7
- package/dist/astro/index.d.ts +30 -12
- package/dist/astro/index.js +2 -2
- package/dist/{audience-BrMs8c4o.js → audience-DTjR8xet.js} +8 -8
- package/dist/{auth-CscUX8Sy.js → auth--yPyZNgr.js} +19 -7
- package/dist/authzen/index.d.ts +34 -28
- package/dist/authzen/index.js +23 -20
- package/dist/{automation-DOtAFWdy.d.ts → automation-C6Jg75xq.d.ts} +42 -32
- package/dist/{automation-ySsxp_Yp.js → automation-x3KEUusw.js} +22 -21
- package/dist/better-auth/index.d.ts +2 -2
- package/dist/better-auth/index.js +13 -7
- package/dist/better-supabase/index.d.ts +357 -227
- package/dist/better-supabase/index.js +219 -140
- package/dist/{bind-D1nO6fiC.js → bind-BNQA9JK9.js} +26 -10
- package/dist/{bind-JDuvxjuW.d.ts → bind-YYjvfpB9.d.ts} +32 -12
- package/dist/{body-CH5of8Ne.js → body-CJQwYVa8.js} +3 -3
- package/dist/{body-text-QcXok_SI.js → body-text-DQhcmqdY.js} +8 -4
- package/dist/{boundary-BM8a_P6E.js → boundary-BV3O1eud.js} +8 -2
- package/dist/{boundary-BmHxVH1J.d.ts → boundary-C9ck-3uK.d.ts} +13 -4
- package/dist/{budget-NbEtbJC_.js → budget-BELja5A9.js} +6 -3
- package/dist/{budget-JqcRqyhK.d.ts → budget-hYsPz_yE.d.ts} +6 -3
- package/dist/{build-instance-DxE7czo9.js → build-instance-BWXqwQYU.js} +3 -3
- package/dist/{capability-L7NnfhiE.js → capability-BqX94r07.js} +31 -25
- package/dist/{capability-D4UC9TTW.d.ts → capability-Di9tiUvi.d.ts} +41 -29
- package/dist/{casbin-BHijLuHY.js → casbin-B7_yS-oo.js} +2 -2
- package/dist/{casbin-BW9pS47J.js → casbin-bHyIxTNQ.js} +16 -8
- package/dist/{casl-CmJlgziS.js → casl-C4OINZHI.js} +2 -2
- package/dist/{casl-UbI8v-Wq.js → casl-CHHoCldP.js} +19 -10
- package/dist/catalog/index.d.ts +51 -30
- package/dist/catalog/index.js +18 -15
- package/dist/{catalog-D69WhFii.js → catalog-CGlSwU6j.js} +20 -19
- package/dist/catalog-D3oS2GH3.js +1 -0
- package/dist/{catalog-BaMQfQ6Y.js → catalog-amPDr0JQ.js} +3 -3
- package/dist/{catalog-doc-CV9s6B1S.js → catalog-doc-DjMKzJp9.js} +28 -14
- package/dist/{catalog-fingerprint-C144oW4M.js → catalog-fingerprint-e6aCWosn.js} +18 -14
- package/dist/catalog-operations-DeHTrJSV.js +60 -0
- package/dist/{challenge-nGWma08S.js → challenge-DImNcR7B.js} +48 -27
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +13 -10
- package/dist/chat-sdk/index.d.ts +44 -26
- package/dist/chat-sdk/index.js +17 -17
- package/dist/{checks-BC_0mPIq.js → checks-CGkP3Z7A.js} +4 -1
- package/dist/{claims-map-7oQ3ue4X.js → claims-map-CKkoAAYF.js} +5 -2
- package/dist/{claims-map-Ca-QX8C6.d.ts → claims-map-D1Pb5oRq.d.ts} +8 -5
- package/dist/claude-agent/index.d.ts +6 -6
- package/dist/claude-agent/index.js +6 -3
- package/dist/clerk/index.d.ts +11 -7
- package/dist/clerk/index.js +6 -6
- package/dist/cli/bin.js +4 -4
- package/dist/cli/index.d.ts +82 -7
- package/dist/cli/index.js +6 -6
- package/dist/{clients-C7zLFuWT.d.ts → clients-C_NOET3z.d.ts} +5 -5
- package/dist/{clients-DjU5ABMy.js → clients-DYr3U86j.js} +3 -3
- package/dist/cloud/index.d.ts +84 -52
- package/dist/cloud/index.js +53 -39
- package/dist/{cloud-CO8pYtwr.js → cloud-3kWfjnYy.js} +4 -5
- package/dist/{codemod-BP6n8N9L.js → codemod-Bv5i-Mzo.js} +523 -201
- package/dist/{codemod-i4N2BhDc.js → codemod-D9Aiii1r.js} +3 -4
- package/dist/{collect-DNm3oKOk.js → collect-B80GYEot.js} +4 -5
- package/dist/collect-D-eroIfV.js +1 -0
- package/dist/{collect-BaWeMjwV.js → collect-WCl8cJQV.js} +26 -63
- package/dist/{compare-pfyVnBjE.js → compare-DTfyUunF.js} +2 -2
- package/dist/compile/index.d.ts +2 -2
- package/dist/compile/index.js +1 -1
- package/dist/{compile-COM2VKuN.d.ts → compile-BEklRUYo.d.ts} +36 -12
- package/dist/{compile-BAEO5bOk.js → compile-EzEMB-7v.js} +77 -33
- package/dist/{completion-BNdVf7X2.js → completion-_bc0OUQ-.js} +17 -8
- package/dist/config-BwPBfN0t.js +108 -0
- package/dist/{config-DGZzMV1B.js → config-D5XrLWpk.js} +2 -2
- package/dist/{config-report-Cm7UITNA.js → config-report-BmWIskD7.js} +9 -6
- package/dist/config-shape-ykV0Vm2n.js +134 -0
- package/dist/{connection-DjhIJSs2.js → connection-B72dg5Q2.js} +23 -22
- package/dist/{connector-schema-_VCSsdtD.js → connector-schema-CYLQNMYq.js} +3 -2
- package/dist/{context--uM9V3Ui.js → context-BnIzxTNE.js} +4 -3
- package/dist/convex/index.d.ts +13 -7
- package/dist/convex/index.js +9 -6
- package/dist/{core-CQkE8Esr.d.ts → core-CFepFiDP.d.ts} +49 -22
- package/dist/{core-B5-w6Kw9.js → core-DzVINFbU.js} +26 -20
- package/dist/{create-Cb86Z8Im.js → create-6EwRQlig.js} +10 -7
- package/dist/{create-DJrlhEp9.js → create-BLPKnJKa.js} +35 -25
- package/dist/{create-UTnUVETj.d.ts → create-BPUopdfL.d.ts} +70 -37
- package/dist/{create-QHuuPw3q.d.ts → create-BamXmeob.d.ts} +37 -29
- package/dist/{create-B2-CQqCI.d.ts → create-DBvUsgzK.d.ts} +49 -28
- package/dist/{credential-CIM7wHwA.js → credential-CyyyvCsL.js} +41 -38
- package/dist/{credentials-BpuTwd7a.js → credentials-CdDxp7jN.js} +6 -6
- package/dist/{deciding-columns-DRo2QM6E.js → deciding-columns-NB4wcyBf.js} +2 -2
- package/dist/{delegation-C5rOdTp5.js → delegation-CDB6_keF.js} +31 -22
- package/dist/delivery/index.d.ts +4 -4
- package/dist/delivery/index.js +5 -5
- package/dist/{delivery-rwOKLWRm.js → delivery-BupfvJIV.js} +34 -22
- package/dist/{delivery-event-xX4obB8F.js → delivery-event-JioK5YbS.js} +6 -6
- package/dist/denied-text-DHldhVUv.d.ts +22 -0
- package/dist/{describe-DZlnEtLy.js → describe-Bb4hGK5d.js} +5 -5
- package/dist/{describe-O0SwYIK8.d.ts → describe-BbFPBSms.d.ts} +5 -5
- package/dist/{device-BARQ8eYG.js → device-BwbJNmb2.js} +11 -8
- package/dist/{diff-Btr1c1Ow.js → diff-BwR1JdP2.js} +2 -2
- package/dist/{diff-DzT-xD13.js → diff-CQegtBAo.js} +22 -13
- package/dist/{digest-B3kc_PgQ.d.ts → digest-8Yx2CchM.d.ts} +3 -3
- package/dist/{doctor-BU1szn63.js → doctor-ClRVAtXQ.js} +287 -135
- package/dist/{doctor-BoK_y0KO.js → doctor-LPMYjSqO.js} +4 -4
- package/dist/drizzle/index.d.ts +33 -19
- package/dist/drizzle/index.js +17 -9
- package/dist/elysia/index.d.ts +17 -11
- package/dist/elysia/index.js +5 -5
- package/dist/{errors-BKy0EfhN.js → errors-B6R_lg2a.js} +13 -4
- package/dist/{errors-B_Qg9D3e.d.ts → errors-BIM4MFsJ.d.ts} +22 -6
- package/dist/{errors-BWXBMaKK.d.ts → errors-CHwoRRpB.d.ts} +4 -1
- package/dist/{errors-DpP_U6Bf.js → errors-Vpu6rKHl.js} +13 -10
- package/dist/{evaluate-B_oqFbWC.js → evaluate-BAmf_AQd.js} +153 -82
- package/dist/{evaluations-BCddEOfO.d.ts → evaluations-DOWuBpWv.d.ts} +11 -5
- package/dist/{evaluations-DReoiVBw.js → evaluations-IBceAeKT.js} +40 -19
- package/dist/eve/index.d.ts +9 -6
- package/dist/eve/index.js +4 -4
- package/dist/{event-time-CsegxXxB.js → event-time-BGy48400.js} +8 -4
- package/dist/{expiry-D4_YKRKD.js → expiry-6XByK0dm.js} +8 -5
- package/dist/express/index.d.ts +9 -6
- package/dist/express/index.js +9 -6
- package/dist/fastify/index.d.ts +16 -10
- package/dist/fastify/index.js +8 -5
- package/dist/{fetch-adapter-CuhyYwC1.d.ts → fetch-adapter-BIbBAtPZ.d.ts} +9 -6
- package/dist/{fetch-adapter-De-u6vhJ.js → fetch-adapter-dPTgJVHd.js} +14 -11
- package/dist/fields-D0vUI6dq.js +498 -0
- package/dist/{files-acUbNwWt.js → files-B3AA05f1.js} +8 -5
- package/dist/{files-D_JIzUrP.js → files-BSjrtIHw.js} +11 -4
- package/dist/{fixtures-BTMW6zgU.js → fixtures-A1_sp_tR.js} +15 -6
- package/dist/{flags-aaeRAdiD.js → flags-DXjoTVbS.js} +2 -2
- package/dist/{freeze-CrU8nQeX.js → freeze-jjan0lCv.js} +4 -1
- package/dist/{from-snapshot-Bz469dIh.js → from-snapshot-DCakWRsr.js} +18 -15
- package/dist/gen-BFfzZSLH.js +58 -0
- package/dist/gen-BtfFWGbz.js +827 -0
- package/dist/{generate-3FNO5P5Q.js → generate-CRVV5V7l.js} +14 -8
- package/dist/generate-CezbCaTI.js +275 -0
- package/dist/{grantee-BrRANrpT.js → grantee-Dke-9rd1.js} +4 -4
- package/dist/{grantee-conditions-C6P1Tvol.js → grantee-conditions-BrYPe-w0.js} +12 -12
- package/dist/{grantee-match-0RtHWQDx.js → grantee-match-7RZZvoT_.js} +12 -6
- package/dist/{graph-sql-B-dsAT6j.d.ts → graph-sql-BwFC4Qjs.d.ts} +3 -3
- package/dist/h3/index.d.ts +10 -7
- package/dist/h3/index.js +3 -3
- package/dist/headers-B9jQxjtW.d.ts +10 -0
- package/dist/{helpers-DY3vXuGs.js → helpers-DJicaG6f.js} +40 -28
- package/dist/hono/index.d.ts +16 -10
- package/dist/hono/index.js +5 -5
- package/dist/{hosted-XBgU6RGT.js → hosted-D0IzESu_.js} +42 -21
- package/dist/{hosted-BmjzxQhp.d.ts → hosted-DVxlLZMe.d.ts} +33 -21
- package/dist/{http-ujKm0JXE.js → http-DH94eh6f.js} +4 -4
- package/dist/{http-BBoKefeS.js → http-DKLXrFGk.js} +13 -7
- package/dist/{http-Ca3Sr5x1.js → http-DOL33cO0.js} +11 -8
- package/dist/{import-DB2EG_iy.js → import-ACkOrv6g.js} +6 -6
- package/dist/{import-Bz0GefWg.js → import-CST57XLp.js} +64 -51
- package/dist/{index-CMiPH2Tv.d.ts → index-BinlXeU-.d.ts} +64 -37
- package/dist/{index-BSfRl0hZ.d.ts → index-CV-7DWeD.d.ts} +64 -52
- package/dist/{index-BE8y3moU.d.ts → index-DJwEgYzA.d.ts} +127 -82
- package/dist/{index-DH9DUDEM.d.ts → index-Dj2qF9VC.d.ts} +54 -30
- package/dist/{index-BTkwrK7v.d.ts → index-vYjMrXyK.d.ts} +336 -173
- package/dist/{index-DLwcuCN_.d.ts → index-ymept53A.d.ts} +51 -30
- package/dist/index.d.ts +22 -22
- package/dist/index.js +34 -34
- package/dist/{init-B-4t1NzC.js → init-BjuFDYT1.js} +10 -10
- package/dist/{init-5TXNji88.js → init-txYTuW9u.js} +5 -5
- package/dist/{instance-options-CU0YQCLH.d.ts → instance-options-CoHn-0e8.d.ts} +4 -4
- package/dist/{instance-snapshot-CjcwnEiV.js → instance-snapshot-DuWf1cT3.js} +86 -61
- package/dist/{instant-BluqDvyS.js → instant-DK3Iz83e.js} +2 -2
- package/dist/{internals-Dk8A8fX3.js → internals-B3IgHrvo.js} +6 -3
- package/dist/{json-schema-B-vAwlde.js → json-schema-BPGa-RjQ.js} +9 -3
- package/dist/{json-schema-CN_iLFH2.d.ts → json-schema-BfXgnRNT.d.ts} +4 -4
- package/dist/jwt/index.d.ts +57 -27
- package/dist/jwt/index.js +24 -21
- package/dist/{kernel-DVExUwkp.js → kernel-qv4cr9w8.js} +32 -23
- package/dist/kysely/index.d.ts +49 -33
- package/dist/kysely/index.js +9 -7
- package/dist/{live-options-BaAFCIiu.js → live-options-BBIT68le.js} +2 -2
- package/dist/{load-DxroEzH1.js → load-DjSU5KXO.js} +6 -6
- package/dist/load-Dm0pSYH3.js +1 -0
- package/dist/{login-ClSJh5t5.js → login-CfImTJGb.js} +4 -4
- package/dist/{login-WC9HPJpU.js → login-CgfCTO3F.js} +16 -9
- package/dist/{manifest-Dv6q4i5s.js → manifest-B2QPh19C.js} +49 -38
- package/dist/{manifest-BVhExYhw.d.ts → manifest-CzzWtnAb.d.ts} +126 -31
- package/dist/{manifest-schema-Cv492Qev.js → manifest-schema-2r37XRhD.js} +44 -3
- package/dist/{manifest-B79YuF2T.js → manifest-wg8WkkpD.js} +6 -6
- package/dist/{map-claims-etGIS_Dv.js → map-claims-C-nv08_n.js} +16 -9
- package/dist/{map-error-BQGyDm_M.js → map-error-pasIGqMT.js} +7 -7
- package/dist/{markers-C6joDI3o.js → markers-BeHZ4x9Q.js} +20 -5
- package/dist/mcp/index.d.ts +114 -61
- package/dist/mcp/index.js +70 -40
- package/dist/{migrate-Dodel0IJ.js → migrate-B7oP_sQU.js} +35 -17
- package/dist/module-values-BJTBdo6y.js +107 -0
- package/dist/nest/index.d.ts +23 -13
- package/dist/nest/index.js +18 -11
- package/dist/next/client.d.ts +5 -2
- package/dist/next/client.js +1 -1
- package/dist/next/index.d.ts +79 -26
- package/dist/next/index.js +121 -10
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +4 -3
- package/dist/node/index.d.ts +5 -5
- package/dist/node/index.js +3 -3
- package/dist/{ocsf-BFp-PZZA.js → ocsf-TcjRBgIs.js} +15 -5
- package/dist/openai/index.d.ts +13 -7
- package/dist/openai/index.js +3 -3
- package/dist/openapi/index.d.ts +51 -30
- package/dist/openapi/index.js +2 -2
- package/dist/{openapi-ztVaux6j.js → openapi-BGeuunWC.js} +23 -14
- package/dist/{openapi-DMocl1bh.js → openapi-BIpw3Mb7.js} +4 -5
- package/dist/{openapi-Ddb4628T.js → openapi-BOsx0xn9.js} +33 -18
- package/dist/{operation-findings-kRcEp8lE.js → operation-findings-CXtFzlKJ.js} +3 -3
- package/dist/{operations-BNLes61x.d.ts → operations-Ci_rT6Uo.d.ts} +10 -7
- package/dist/orpc/index.d.ts +68 -14
- package/dist/orpc/index.js +62 -13
- package/dist/otel/index.d.ts +7 -4
- package/dist/otel/index.js +8 -5
- package/dist/{output-DgSDLrta.js → output-DV5dwOTs.js} +9 -5
- package/dist/output-files-BHOIlrfD.js +1 -0
- package/dist/{output-files-CCMdcFWb.js → output-files-BIQ_9pIs.js} +29 -17
- package/dist/ownership-DA5YdYTm.js +1059 -0
- package/dist/{parse-Ddhz2xf4.js → parse-1_ZheTW5.js} +16 -13
- package/dist/parse-local-manifest-CCmbhnxP.d.ts +10 -0
- package/dist/{parse-local-manifest-T1Q8X3A2.js → parse-local-manifest-DEiCF4ah.js} +19 -7
- package/dist/{parse-request-D_tUXG6M.js → parse-request-CwCZpyjV.js} +7 -8
- package/dist/{paths-DXSHAMIa.js → paths-CUvURzHp.js} +4 -1
- package/dist/pdp/index.d.ts +9 -6
- package/dist/pdp/index.js +20 -13
- package/dist/{peer-DOzzMfZL.js → peer-C9LvBCcb.js} +1 -1
- package/dist/{peer-12Q5I_RH.js → peer-Q0fuZ6hx.js} +9 -3
- package/dist/{permdock-BfWEeMqk.js → permdock-BvjivVb9.js} +200 -140
- package/dist/{permdock-Dco6dyCK.d.ts → permdock-CprAPN3w.d.ts} +260 -129
- package/dist/{permission-registry-DpPtSKNZ.js → permission-registry-B8tYxPIt.js} +23 -10
- package/dist/{permission-types-DhNEmoRG.d.ts → permission-types-CAY-GU7e.d.ts} +127 -41
- package/dist/{permissions-CoqCOfJ3.d.ts → permissions-Bx6UI8n1.d.ts} +6 -3
- package/dist/{permissions-CyH2MV_B.js → permissions-CVXmRILq.js} +3 -3
- package/dist/{permissions-DArULThq.js → permissions-CYcHj_w7.js} +8 -5
- package/dist/pg-DQTqRrou.js +60 -0
- package/dist/{pins-8ILTftC9.js → pins-nqarl3oE.js} +4 -1
- package/dist/{pkce-5h8NgMQJ.js → pkce-CnmmYqUZ.js} +1 -1
- package/dist/{policy-B7dg_yzu.d.ts → policy-BycVKnXv.d.ts} +5 -5
- package/dist/{policy-DaJy4nK4.js → policy-CLQ8__GF.js} +43 -23
- package/dist/{policy-from-catalog-DFWYkNdu.js → policy-from-catalog-CU3An8uP.js} +28 -25
- package/dist/{policy-module-CTlwMvLI.js → policy-module-xym9fnSq.js} +12 -6
- package/dist/{policy-types-B-F-qAZk.d.ts → policy-types-DGIO_gxq.d.ts} +782 -357
- package/dist/{postgres-store-BL9M_CA1.js → postgres-store-DcyrPS-r.js} +43 -16
- package/dist/{postgrest-r5faDIzD.js → postgrest-5Dr3W64L.js} +84 -86
- package/dist/{postgrest-CYacM_u7.d.ts → postgrest-D5nUGm-c.d.ts} +55 -35
- package/dist/powersync-B701tvhE.js +1 -0
- package/dist/{powersync-13odBwiM.js → powersync-Bg8u-JcR.js} +3 -3
- package/dist/{powersync-53ryOZip.js → powersync-CJrT1DSc.js} +127 -69
- package/dist/preset/index.d.ts +38 -28
- package/dist/preset/index.js +1 -1
- package/dist/{preset-CHTbd-DQ.js → preset-BjLzeFpp.js} +56 -32
- package/dist/{principal-source-pHneukrx.js → principal-source-C6N60GtM.js} +10 -10
- package/dist/prisma/index.d.ts +69 -41
- package/dist/prisma/index.js +21 -17
- package/dist/{problem-CTviyH5L.js → problem-BVLHFK33.js} +41 -21
- package/dist/{problem-details-cn5X30gZ.js → problem-details-CLDgX1KV.js} +13 -4
- package/dist/{problem-types-CJ2325SZ.js → problem-types-DSsRfONQ.js} +4 -1
- package/dist/{prompt-DwtVemER.js → prompt-BYc6drYW.js} +4 -1
- package/dist/protected-action-D8x73IGm.d.ts +58 -0
- package/dist/protected-action-DUYqb-Ma.js +80 -0
- package/dist/{protected-DXE3cQYg.js → protected-action-QEA8arRB.js} +48 -14
- package/dist/{provider-BQsTYYy0.js → provider-C55OGXJ7.js} +5 -4
- package/dist/{provider-Csk-THAn.d.ts → provider-DfLeek9O.d.ts} +1 -1
- package/dist/{provider-store-IgqQipCO.js → provider-store-CaTv00tr.js} +13 -9
- package/dist/{pull-CN5OLxrF.js → pull-2nJr0qg_.js} +12 -11
- package/dist/pull-C3EEGzSw.js +1 -0
- package/dist/{push-tVdG8dUL.js → push-Bn-lMEmI.js} +19 -13
- package/dist/{pushed-policy-CmYeSQqq.js → pushed-policy-CDuOL2de.js} +10 -7
- package/dist/{pushed-policy-BbcY9r_4.d.ts → pushed-policy-CryQheKq.d.ts} +12 -6
- package/dist/react/index.d.ts +9 -8
- package/dist/react/index.js +7 -6
- package/dist/react/provider-client.d.ts +1 -1
- package/dist/react/provider-client.js +1 -1
- package/dist/react-native/index.d.ts +94 -55
- package/dist/react-native/index.js +200 -61
- package/dist/{refs-CNJBiTFo.js → refs-C8BKxc_e.js} +2 -2
- package/dist/{relation-walk-3OyDBF0S.js → relation-walk-DK_gkgL7.js} +12 -9
- package/dist/{relations-BnCWnJGI.js → relations-BxvRvDHK.js} +3 -3
- package/dist/{replay-Du1tJjG7.js → replay-BU09ad4L.js} +1 -1
- package/dist/{replay-DCDD_ZfL.d.ts → replay-Bs9Df2fQ.d.ts} +1 -1
- package/dist/{request-context-BykKLmyE.js → request-context-Duzdf0cd.js} +8 -8
- package/dist/{request-schema-CMreVuFM.js → request-schema-DhX7UbfQ.js} +4 -1
- package/dist/resend/index.d.ts +34 -28
- package/dist/resend/index.js +29 -29
- package/dist/resolve-names-ConCSj1y.js +201 -0
- package/dist/{resource-relations-D_jw0BFx.js → resource-relations-8-pCScBO.js} +18 -9
- package/dist/{retire-Wj6dkyDE.js → retire-B2xffQgY.js} +15 -6
- package/dist/{revocations-R07lFBnX.d.ts → revocations-BaUXHM1N.d.ts} +6 -3
- package/dist/{rls-Ck_PocSp.js → rls-Ba9wN0SP.js} +13 -6
- package/dist/{rls-CxBZb4rZ.js → rls-Cx0dtsB7.js} +310 -128
- package/dist/{role-builder-C1VJzvcr.js → role-builder-BK2-T6oD.js} +41 -20
- package/dist/{row-conditions-h2HythXQ.js → row-conditions-BAGHOmVq.js} +4 -3
- package/dist/{rpc-Bk1bE-ch.js → rpc-vHIwyXCp.js} +8 -5
- package/dist/run-Ck22anC2.js +1 -0
- package/dist/{run-uLD2aWuO.js → run-PbRlXTfh.js} +26 -23
- package/dist/{run-ticket-BpNi7BCi.d.ts → run-ticket-B2o2Kxz8.d.ts} +29 -14
- package/dist/{run-ticket-B5d_63Ma.js → run-ticket-Dv7aF7Dk.js} +9 -9
- package/dist/{runtime-Vif3_-zf.js → runtime-BGnrOkVH.js} +5 -2
- package/dist/{saas-Az_Kz-4D.js → saas-DK4V-3Is.js} +42 -29
- package/dist/{scan-DSljDE1Y.js → scan-CRTj6fke.js} +1 -1
- package/dist/{schema-B4v0Qrac.js → schema-BOJjqlWL.js} +3 -2
- package/dist/{schema-gIcCx7zM.js → schema-BTsE1WRT.js} +8 -4
- package/dist/scim/index.d.ts +2 -2
- package/dist/scim/index.js +2 -2
- package/dist/{scim-C7JYhySg.js → scim-D8YupzX1.js} +2 -2
- package/dist/{scim-YNieBO1U.js → scim-jJBJ7g1Z.js} +33 -15
- package/dist/{scopes-BHsc-wp-.js → scopes-0Up_UA2t.js} +41 -23
- package/dist/server/index.d.ts +11 -11
- package/dist/server/index.js +12 -12
- package/dist/{server-Bnga6I50.js → server-3cVlTLde.js} +31 -31
- package/dist/{server-types-C4gZUEZy.d.ts → server-types-CyRN0-Cd.d.ts} +88 -46
- package/dist/{sha256-D9ihqmvd.js → sha256-C-4WXKIu.js} +4 -3
- package/dist/{shared-fMKOv8hP.js → shared-Afctg7B0.js} +65 -32
- package/dist/{shared-C8LjUdVU.js → shared-l0oGGetg.js} +9 -6
- package/dist/{signals-D3NcTKUS.js → signals-B1vHR3fN.js} +2 -2
- package/dist/{sink-Cp_Eot9W.d.ts → sink-B5zoUW_O.d.ts} +44 -20
- package/dist/{sink-BEZSlMS_.js → sink-D9_vh372.js} +32 -21
- package/dist/{skills-g_3BS9NC.js → skills-C9uKfSF5.js} +3 -3
- package/dist/{skills-Dcjw9_1C.js → skills-CQQcuGBi.js} +12 -8
- package/dist/{snapshot-CbGmYiJx.js → snapshot-CXlzi69u.js} +21 -18
- package/dist/{snapshot-cache-Pahd3IYJ.d.ts → snapshot-cache-BjAWkchD.d.ts} +21 -12
- package/dist/{snapshot-cache-DT2Kx1F8.js → snapshot-cache-Bx_4xC_6.js} +14 -11
- package/dist/solid/index.d.ts +55 -16
- package/dist/solid/index.js +46 -12
- package/dist/solid-start/index.d.ts +30 -12
- package/dist/solid-start/index.js +3 -3
- package/dist/{sources-B-zYB4GS.js → sources-CMAM-2A3.js} +46 -27
- package/dist/{sources-DEEuGb8S.d.ts → sources-CWG32C0G.d.ts} +126 -53
- package/dist/{sql-B96movIM.js → sql-0WjxIp9g.js} +28 -7
- package/dist/{sql-CDEPCA0g.d.ts → sql-B80DFdpG.d.ts} +2 -2
- package/dist/{src-DLFrtrrC.js → src-C_pi2Rnh.js} +292 -101
- package/dist/ssf/index.d.ts +3 -3
- package/dist/ssf/index.js +47 -35
- package/dist/{standard-webhooks-DgFFD-Ga.js → standard-webhooks-D67a3nzk.js} +5 -5
- package/dist/{standard-webhooks-B_qRg0ws.d.ts → standard-webhooks-DOYEuOLx.d.ts} +7 -7
- package/dist/{store-DSP9oGvh.js → store-RNFvaJJv.js} +32 -26
- package/dist/{store-options-B_poyYvg.js → store-options-Dil3lraY.js} +105 -15
- package/dist/stores-DZJvxFIZ.d.ts +59 -0
- package/dist/{stores-BqEuHC05.js → stores-DxZWDXCs.js} +42 -5
- package/dist/{stream-2Vwhl7Er.d.ts → stream-9y9qw51m.d.ts} +4 -3
- package/dist/{stream-CvdUS9V1.js → stream-CDvF0sJm.js} +5 -5
- package/dist/{style-Ds1gNm77.js → style-DblOtSga.js} +1 -1
- package/dist/{style-Cqo7-73x.js → style-Ds11Hmk4.js} +2 -1
- package/dist/{subject-settings-CkEwrw3W.js → subject-settings-8sH5HlII.js} +8 -4
- package/dist/{row-check-Dt35czLy.d.ts → subject-settings-vNW8qmUH.d.ts} +30 -18
- package/dist/supabase/index.d.ts +48 -38
- package/dist/supabase/index.js +5 -5
- package/dist/supabase/middleware.d.ts +19 -13
- package/dist/supabase/middleware.js +7 -7
- package/dist/{supabase--0aJdLEd.js → supabase-DnMMg5Fn.js} +79 -35
- package/dist/{supabase-Bqp7iIY2.js → supabase-SBs3MYUE.js} +3 -3
- package/dist/supabase-hook-C0FyEACZ.js +1 -0
- package/dist/{supabase-hook-Dg0SrQWR.js → supabase-hook-CrgU06WH.js} +175 -196
- package/dist/{supautils-MESd81bF.js → supautils-ByezN3b8.js} +385 -219
- package/dist/{support-session-Cna49-3f.js → support-session-BsmPCbz8.js} +21 -21
- package/dist/svelte/PermissionBoundary.svelte +2 -6
- package/dist/svelte/Protected.svelte +2 -8
- package/dist/svelte/index.d.ts +9 -8
- package/dist/svelte/index.js +10 -9
- package/dist/svelte/runtime.d.ts +4 -4
- package/dist/svelte/runtime.js +4 -4
- package/dist/svelte/source.d.ts +9 -8
- package/dist/svelte/source.js +6 -5
- package/dist/sveltekit/index.d.ts +30 -12
- package/dist/sveltekit/index.js +2 -2
- package/dist/{ownership-Z2LpxsGa.js → tables-BqrxBCir.js} +641 -1104
- package/dist/tanstack-start/index.d.ts +22 -10
- package/dist/tanstack-start/index.js +2 -2
- package/dist/{target-Bw37TFNA.js → target-qdEAnnhU.js} +6 -6
- package/dist/{tenancy-CmeBQ6Nv.js → tenancy-5d1zVBvK.js} +25 -19
- package/dist/terminal/index.d.ts +23 -14
- package/dist/terminal/index.js +17 -20
- package/dist/testing/core.d.ts +1 -1
- package/dist/testing/core.js +1 -1
- package/dist/testing/fixtures/index.d.ts +8 -5
- package/dist/testing/fixtures/index.js +78 -17
- package/dist/testing/index.d.ts +225 -141
- package/dist/testing/index.js +352 -234
- package/dist/testing/saas/index.d.ts +43 -27
- 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/{text-diff-DhITNCnD.js → text-diff-BtfSmdUo.js} +2 -2
- package/dist/{thenable-yD7SabqG.js → thenable-BNSM1U2R.js} +12 -3
- package/dist/{time-DkWjdL98.js → time-nR1JesoH.js} +32 -8
- package/dist/{token-2qYDvXz2.js → token-DC9EQiet.js} +14 -12
- package/dist/{tool-refusal-reAhIzdl.js → tool-refusal-Qpjs_W6M.js} +5 -2
- package/dist/trpc/index.d.ts +11 -8
- package/dist/trpc/index.js +15 -9
- package/dist/type-helpers-c7Xo_2Cu.d.ts +50 -0
- package/dist/{types-CfiKC5aN.d.ts → types-B2efzoSX.d.ts} +14 -11
- package/dist/{types-CIeZcG8v.d.ts → types-B6ExllNo.d.ts} +2 -2
- package/dist/{types-DBHftjgS.d.ts → types-BB-zWDcR.d.ts} +45 -33
- package/dist/{types-BfVmNJO5.d.ts → types-BMVDHvI0.d.ts} +128 -50
- package/dist/{types-DXmwu78Z.d.ts → types-CEinc15V.d.ts} +31 -14
- package/dist/{types-g7Oy6Zg4.d.ts → types-CN0LsqbK.d.ts} +47 -24
- package/dist/{types-CeIscIKp.d.ts → types-CWBsAwqn.d.ts} +23 -12
- package/dist/{types-DqzsnlSA.js → types-CcUXciSj.js} +17 -5
- package/dist/{types-BWZybqs9.d.ts → types-CzOeVvcC.d.ts} +384 -203
- package/dist/{types-DC44-hqb.d.ts → types-DLvhVm1r.d.ts} +59 -32
- package/dist/{types-D3A19w4A.d.ts → types-DlelvQk4.d.ts} +22 -13
- package/dist/{types-cTos-H7p.d.ts → types-DsHGPtkR.d.ts} +68 -32
- package/dist/{types-BXMYB7BY.d.ts → types-ZzRGoViD.d.ts} +77 -24
- package/dist/{types-CQVEQawv.d.ts → types-rCRV4Ge-.d.ts} +24 -14
- package/dist/types-tQB2CEnY.d.ts +262 -0
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +2 -2
- package/dist/usage-0hjZPIRX.js +1 -0
- package/dist/{usage-Bybmck7f.js → usage-B9EtHWLa.js} +50 -26
- package/dist/{usage-CDaLXCfL.js → usage-CBzgwfIs.js} +2 -2
- package/dist/{validation-error-ZfUHbKvf.js → validation-error-CYg2kJEw.js} +4 -1
- package/dist/{validation-error-CQpoquwj.d.ts → validation-error-uvp-kyfO.d.ts} +5 -2
- package/dist/{validity-CZ7-y0Cj.js → validity-Buc7w8E9.js} +13 -10
- package/dist/{verifier-DHuh-okk.js → verifier-DUV6pLqZ.js} +10 -4
- package/dist/{verify-pe8rL_Qw.js → verify-DlUcTDBz.js} +148 -487
- package/dist/version-DMQ0dnN5.js +48 -0
- package/dist/version-DizhmD72.js +1 -0
- package/dist/{views-BB8E9dTP.js → views-CD8wuL4Z.js} +19 -6
- package/dist/{vocabulary-Bg3eeT2H.d.ts → vocabulary-DEJ5j4mR.d.ts} +7 -4
- package/dist/vue/index.d.ts +71 -22
- package/dist/vue/index.js +50 -13
- package/dist/{waiter-DwEyouan.d.ts → waiter-CqUKX6CY.d.ts} +13 -10
- package/dist/{waiter-BGUtGYoU.js → waiter-aBLM63_f.js} +1 -1
- package/dist/{watch-C-4VmFlL.js → watch-BFDKqmUa.js} +8 -8
- package/dist/watch-ClLuO2TL.js +1 -0
- package/dist/webmcp/index.d.ts +11 -11
- package/dist/webmcp/index.js +8 -5
- package/dist/{where-scope-wq2coopv.js → where-scope-DlCdCM_8.js} +24 -18
- package/dist/{who-can-BwNsI_Js.js → who-can-BoDJm0Nc.js} +23 -20
- package/dist/workflow/index.d.ts +3 -3
- package/dist/workflow/index.js +13 -13
- package/dist/workflow-sdk/index.d.ts +19 -13
- package/dist/workflow-sdk/index.js +6 -6
- package/dist/{wrap-CiSc_KCq.js → wrap-B2wziJI_.js} +4 -4
- package/dist/{wrap-B6R0cMRL.d.ts → wrap-DxXB54Wu.d.ts} +8 -5
- package/package.json +8 -8
- package/schemas/catalog-v1.json +3 -0
- package/schemas/supabase-manifest-v1.json +33 -1
- package/skills/permdock-credentials/references/tokens-keys-links.md +8 -6
- package/skills/permdock-data/references/queries-and-rls.md +2 -1
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +2 -2
- package/skills/permdock-wire/references/adapters.md +16 -23
- package/dist/catalog-BCCjSAdH.js +0 -1
- package/dist/collect-k_Dulxr5.js +0 -1
- package/dist/config-CoQHDrDi.js +0 -166
- package/dist/denied-text-D4qkEtFz.d.ts +0 -19
- package/dist/fields-ClcQLrVc.js +0 -238
- package/dist/generate-CNU1pIOo.js +0 -171
- package/dist/headers-BIjfMaoC.js +0 -8
- package/dist/headers-CIbDTUTK.d.ts +0 -7
- package/dist/load-DrMHXzgN.js +0 -1
- package/dist/output-files-DPAY7-GX.js +0 -1
- package/dist/package-root-Dk_ETdkp.js +0 -31
- package/dist/parse-local-manifest-e4mdwAKd.d.ts +0 -10
- package/dist/policies-B2lZIurj.js +0 -295
- package/dist/powersync-CExtTLyA.js +0 -1
- package/dist/problem-details-Tcfmj3bV.d.ts +0 -7
- package/dist/protected-BwZYL1X_.d.ts +0 -39
- package/dist/pull-Cty6Ovyu.js +0 -1
- package/dist/run-Bz7DXGEv.js +0 -1
- package/dist/stores-BAZwSYZA.d.ts +0 -31
- package/dist/supabase-hook-DJxC4PoP.js +0 -1
- package/dist/types-CKV71kKh.d.ts +0 -172
- package/dist/usage-y-kBNdqs.js +0 -1
- package/dist/version-CEbQ5UeM.js +0 -18
- package/dist/version-DXkYUISx.js +0 -1
- package/dist/watch-Bd9mx3rd.js +0 -1
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { c as listPermissions, u as renamedKeys } from "./permission-registry-
|
|
2
|
-
import { f as scopeList, s as resolveScope } from "./scopes-
|
|
3
|
-
import { o as flattenGrantee } from "./grantee-
|
|
4
|
-
import {
|
|
5
|
-
import { a as describeError, i as configError } from "./errors-
|
|
6
|
-
import { d as sqlTextArray, i as qualifySqlTable } from "./sql-
|
|
7
|
-
import "./budget-
|
|
8
|
-
import { l as roleColumn } from "./sources-
|
|
1
|
+
import { c as listPermissions, u as renamedKeys } from "./permission-registry-B8tYxPIt.js";
|
|
2
|
+
import { f as scopeList, s as resolveScope } from "./scopes-0Up_UA2t.js";
|
|
3
|
+
import { o as flattenGrantee } from "./grantee-Dke-9rd1.js";
|
|
4
|
+
import { l as policyLevels } from "./policy-CLQ8__GF.js";
|
|
5
|
+
import { a as describeError, i as configError } from "./errors-Vpu6rKHl.js";
|
|
6
|
+
import { d as sqlTextArray, i as qualifySqlTable } from "./sql-0WjxIp9g.js";
|
|
7
|
+
import "./budget-BELja5A9.js";
|
|
8
|
+
import { l as roleColumn } from "./sources-CMAM-2A3.js";
|
|
9
9
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
10
|
-
import { c as parseSplit } from "./output-files-
|
|
11
|
-
import {
|
|
12
|
-
import { A as quoteQualified, C as parseMembershipsFlag, D as qualified,
|
|
13
|
-
import {
|
|
10
|
+
import { c as parseSplit } from "./output-files-BIQ_9pIs.js";
|
|
11
|
+
import { b as resolveAuthorize } from "./supabase-hook-CrgU06WH.js";
|
|
12
|
+
import { A as quoteQualified, C as parseMembershipsFlag, D as qualified, F as firstScopeType, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, s as signedIn, t as CUSTOM_ROLES } from "./shared-Afctg7B0.js";
|
|
13
|
+
import { G as byKey, H as rolesTableScope, O as tokenScopesPlan, Q as graphSqlName, V as raiseSql, W as byCodeUnit, Y as apiKeysPlan, a as closureDepths, bt as checkSuspension, i as tablelessResources, o as graphPlan, r as tableNames, t as resolveVias, z as currentKeyExpr } from "./tables-BqrxBCir.js";
|
|
14
|
+
import { o as assignableRoles, r as unsatisfiedKinds, t as ownershipRules, u as roleNames } from "./ownership-DA5YdYTm.js";
|
|
14
15
|
import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
|
|
15
|
-
import { i as group, o as sqlStatements } from "./deciding-columns-
|
|
16
|
-
import {
|
|
17
|
-
import { d as
|
|
16
|
+
import { i as group, o as sqlStatements } from "./deciding-columns-NB4wcyBf.js";
|
|
17
|
+
import { t as resolveNames } from "./resolve-names-ConCSj1y.js";
|
|
18
|
+
import { d as orSql, h as branchClauses } from "./fields-D0vUI6dq.js";
|
|
19
|
+
import { m as tableFor } from "./verify-DlUcTDBz.js";
|
|
18
20
|
//#region src/cli/rls/custom-role-rebuild.ts
|
|
19
21
|
const PREFIX = "PermDock CLI";
|
|
20
22
|
/** A column of the roles-table row `r`. */
|
|
@@ -24,7 +26,10 @@ function col(name) {
|
|
|
24
26
|
function schemaOf(table) {
|
|
25
27
|
return table.includes(".") ? beforeFirst(table, ".") : "public";
|
|
26
28
|
}
|
|
27
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The roles-table column a reference joins on, after checking it points at
|
|
31
|
+
* `roles`.
|
|
32
|
+
*/
|
|
28
33
|
function roleRef(role, table, roles, label) {
|
|
29
34
|
const pairs = Object.entries(role.on);
|
|
30
35
|
const [pair] = pairs;
|
|
@@ -104,9 +109,9 @@ function rebuildPlan(ctx, from, migrate) {
|
|
|
104
109
|
const iRef = i === void 0 || iTable === void 0 ? void 0 : roleRef(i.role, i.table, roles, "rls.customRoles.from.includes.role");
|
|
105
110
|
const included = i === void 0 || iTable === void 0 ? void 0 : sourceSql(i.include, iTable, "rls.customRoles.from.includes.include");
|
|
106
111
|
const refs = [`${col(pRef.id)} as permissions_ref`, ...iRef === void 0 ? [] : [`${col(iRef.id)} as includes_ref`]].join(", ");
|
|
107
|
-
const includeBlock = i === void 0 || iTable === void 0 || iRef === void 0 || included === void 0 ? " v_include := null;" : ` with raw as (
|
|
112
|
+
const includeBlock = (rows) => i === void 0 || iTable === void 0 || iRef === void 0 || included === void 0 || rows === void 0 ? " v_include := null;" : ` with raw as (
|
|
108
113
|
select ${included} as role
|
|
109
|
-
from ${
|
|
114
|
+
from ${rows}
|
|
110
115
|
where x.${quoteIdent(iRef.ref)} = v.includes_ref
|
|
111
116
|
),
|
|
112
117
|
judged as (
|
|
@@ -125,9 +130,9 @@ function rebuildPlan(ctx, from, migrate) {
|
|
|
125
130
|
into v_include, v_lost
|
|
126
131
|
from judged j;
|
|
127
132
|
v_dropped := v_dropped || coalesce(v_lost, '{}'::text[]);`;
|
|
128
|
-
const
|
|
133
|
+
const permissionsBlock = (rows) => ` with raw as (
|
|
129
134
|
select ${legacy} as legacy, ${effect} as effect, ${level} as level
|
|
130
|
-
from ${
|
|
135
|
+
from ${rows}
|
|
131
136
|
where x.${quoteIdent(pRef.ref)} = v.permissions_ref
|
|
132
137
|
),
|
|
133
138
|
mapped as (
|
|
@@ -147,8 +152,9 @@ function rebuildPlan(ctx, from, migrate) {
|
|
|
147
152
|
array_agg(v.role || ': ' || coalesce(j.legacy, 'null') || ', ' || j.dropped) filter (where j.dropped is not null)
|
|
148
153
|
into v_allow, v_deny, v_lost
|
|
149
154
|
from judged j;
|
|
150
|
-
v_dropped := v_dropped || coalesce(v_lost, '{}'::text[])
|
|
151
|
-
|
|
155
|
+
v_dropped := v_dropped || coalesce(v_lost, '{}'::text[]);`;
|
|
156
|
+
const legacyRows = iTable === void 0 ? void 0 : `${quoteTable(iTable)} x`;
|
|
157
|
+
const newRow = "(select new.*) x";
|
|
152
158
|
return {
|
|
153
159
|
rolesTable,
|
|
154
160
|
identity: `select ${tenant} as tenant_id, ${scope} as scope, ${scopeId} as scope_id, ${col(roles.key)}::text as role, ${refs}`,
|
|
@@ -156,7 +162,15 @@ ${includeBlock}`;
|
|
|
156
162
|
permsRef: pRef,
|
|
157
163
|
includesRef: iRef,
|
|
158
164
|
scopes,
|
|
159
|
-
collect
|
|
165
|
+
collect: `${permissionsBlock(`${quoteTable(pTable)} x`)}
|
|
166
|
+
${includeBlock(legacyRows)}`,
|
|
167
|
+
collectNew: {
|
|
168
|
+
permissions: `${permissionsBlock(newRow)}
|
|
169
|
+
v_include := null;`,
|
|
170
|
+
includes: ` v_allow := null;
|
|
171
|
+
v_deny := null;
|
|
172
|
+
${includeBlock(newRow)}`
|
|
173
|
+
},
|
|
160
174
|
replace,
|
|
161
175
|
perms,
|
|
162
176
|
includes,
|
|
@@ -164,7 +178,10 @@ ${includeBlock}`;
|
|
|
164
178
|
roles
|
|
165
179
|
};
|
|
166
180
|
}
|
|
167
|
-
/**
|
|
181
|
+
/**
|
|
182
|
+
* `v_dropped` grouped per legacy role (`role: a, b; other: c`), capped at 50
|
|
183
|
+
* entries.
|
|
184
|
+
*/
|
|
168
185
|
const DROPPED_LIST = `(select string_agg(g.role || ': ' || g.items, '; ' order by g.role)
|
|
169
186
|
from (
|
|
170
187
|
select split_part(l.d, ': ', 1) as role, string_agg(substr(l.d, strpos(l.d, ': ') + 2), ', ' order by l.d) as items
|
|
@@ -176,14 +193,20 @@ const DROPPED_LIST = `(select string_agg(g.role || ': ' || g.items, '; ' order b
|
|
|
176
193
|
/**
|
|
177
194
|
* `rls.customRoles.from.sync: 'trigger'`: after-row triggers on the legacy
|
|
178
195
|
* permissions table, and on the includes table when mapped, rebuild each
|
|
179
|
-
* affected role through `permdock_trusted_replace_custom_role_grants`, with
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
196
|
+
* affected role through `permdock_trusted_replace_custom_role_grants`, with the
|
|
197
|
+
* same reads the backfill uses. An entry outside the ceiling is dropped with a
|
|
198
|
+
* warning rather than aborting the legacy write, and a tenant role whose name a
|
|
199
|
+
* shared role holds is skipped with a warning (`name-taken`). Before-row
|
|
200
|
+
* triggers hold a signed-in caller at trigger depth 1 to the checks of
|
|
201
|
+
* `permdock_replace_custom_role_grants`: `permdock_custom_role_guard` on each
|
|
202
|
+
* role the row names, then `permdock_custom_role_beyond` on the entry it adds;
|
|
203
|
+
* a refusal aborts the write.
|
|
183
204
|
*/
|
|
184
205
|
function customRoleSyncSql(ctx, from, migrate) {
|
|
185
206
|
const plan = rebuildPlan(ctx, from, migrate);
|
|
186
207
|
const shared = qualified(ctx, CUSTOM_ROLES.shared);
|
|
208
|
+
const guard = qualified(ctx, CUSTOM_ROLES.guard);
|
|
209
|
+
const beyond = qualified(ctx, CUSTOM_ROLES.beyond);
|
|
187
210
|
const keepIncludes = plan.includesRef === void 0 ? `
|
|
188
211
|
v_include := array(select c.include_role from ${plan.includes} c where c.tenant_id is not distinct from v.tenant_id and c.scope = v.scope and c.scope_id is not distinct from v.scope_id and c.role = v.role);` : "";
|
|
189
212
|
const one = (name, table, ref) => {
|
|
@@ -238,13 +261,317 @@ create trigger ${quoteIdent(trigger)}
|
|
|
238
261
|
after insert or update or delete on ${target}
|
|
239
262
|
for each row execute function ${fn}();`;
|
|
240
263
|
};
|
|
241
|
-
const
|
|
242
|
-
|
|
264
|
+
const guardOne = (name, table, ref) => {
|
|
265
|
+
const fn = qualified(ctx, `${CUSTOM_ROLES.syncGuard}_${name}`);
|
|
266
|
+
const target = quoteTable(qualifySqlTable(table));
|
|
267
|
+
const trigger = `${CUSTOM_ROLES.syncGuard}_${name}`;
|
|
268
|
+
return `create or replace function ${fn}()
|
|
269
|
+
returns trigger
|
|
270
|
+
language plpgsql
|
|
271
|
+
volatile
|
|
272
|
+
security definer
|
|
273
|
+
set search_path = ''
|
|
274
|
+
as $$
|
|
275
|
+
declare
|
|
276
|
+
v record;
|
|
277
|
+
v_allow text[];
|
|
278
|
+
v_deny text[];
|
|
279
|
+
v_include text[];
|
|
280
|
+
v_lost text[];
|
|
281
|
+
v_dropped text[];
|
|
282
|
+
v_beyond text;
|
|
283
|
+
v_refs text[] := array[
|
|
284
|
+
case when tg_op <> 'INSERT' then old.${quoteIdent(ref.ref)}::text end,
|
|
285
|
+
case when tg_op <> 'DELETE' then new.${quoteIdent(ref.ref)}::text end
|
|
286
|
+
];
|
|
287
|
+
begin
|
|
288
|
+
if not (${signedIn(ctx)} and pg_trigger_depth() = 1) then
|
|
289
|
+
return coalesce(new, old);
|
|
290
|
+
end if;
|
|
291
|
+
for v in
|
|
292
|
+
${plan.identity}
|
|
293
|
+
from ${plan.rolesTable} r
|
|
294
|
+
where ${plan.eligible} and r.${quoteIdent(ref.id)}::text = any(v_refs)
|
|
295
|
+
loop
|
|
296
|
+
if v.role is null or not (v.scope = 'global' or v.scope = any(${plan.scopes})) then
|
|
297
|
+
continue;
|
|
298
|
+
end if;
|
|
299
|
+
if v.tenant_id is not null and ${shared}(v.scope, v.role) then
|
|
300
|
+
continue;
|
|
301
|
+
end if;
|
|
302
|
+
perform ${guard}(v.tenant_id, v.scope, v.scope_id, v.role);
|
|
303
|
+
if tg_op = 'DELETE' then
|
|
304
|
+
continue;
|
|
305
|
+
end if;
|
|
306
|
+
v_dropped := '{}'::text[];
|
|
307
|
+
${plan.collectNew[name]}
|
|
308
|
+
select string_agg(b, ', ' order by b) into v_beyond
|
|
309
|
+
from ${beyond}(v.tenant_id, v.scope, v.scope_id, v_allow, v_deny, v_include) b;
|
|
310
|
+
if v_beyond is not null then
|
|
311
|
+
${raiseSql(" ", "42501", `'permdock: ' || v.role || ' would allow ' || v_beyond || ', which the caller may not hand out'`, "not-assignable-by")}
|
|
312
|
+
end if;
|
|
313
|
+
end loop;
|
|
314
|
+
return coalesce(new, old);
|
|
315
|
+
end;
|
|
316
|
+
$$;
|
|
317
|
+
revoke execute on function ${fn}() from public, anon, authenticated;
|
|
318
|
+
drop trigger if exists ${quoteIdent(trigger)} on ${target};
|
|
319
|
+
create trigger ${quoteIdent(trigger)}
|
|
320
|
+
before insert or update or delete on ${target}
|
|
321
|
+
for each row execute function ${fn}();`;
|
|
322
|
+
};
|
|
323
|
+
const chunks = [
|
|
324
|
+
`-- rls.customRoles.from.sync: a write to the application's role tables rebuilds the role's PermDock grants`,
|
|
325
|
+
one("permissions", from.permissions.table, plan.permsRef),
|
|
326
|
+
`-- a signed-in caller writes only what the guarded replace would accept`,
|
|
327
|
+
guardOne("permissions", from.permissions.table, plan.permsRef)
|
|
328
|
+
];
|
|
329
|
+
if (from.includes !== void 0 && plan.includesRef !== void 0) chunks.push(one("includes", from.includes.table, plan.includesRef), guardOne("includes", from.includes.table, plan.includesRef));
|
|
243
330
|
return `${chunks.join("\n\n")}\n`;
|
|
244
331
|
}
|
|
245
332
|
//#endregion
|
|
333
|
+
//#region src/cli/rls/rows.ts
|
|
334
|
+
/**
|
|
335
|
+
* `permitted_<resource>_rows(p_permission)`: the resource's row ids the subject
|
|
336
|
+
* may act on with one permission.
|
|
337
|
+
*/
|
|
338
|
+
function rowsHelper(resource) {
|
|
339
|
+
const name = graphSqlName(resource);
|
|
340
|
+
const helper = `permitted_${name ?? resource}_rows`;
|
|
341
|
+
if (name === void 0 || new TextEncoder().encode(`${helper}_for`).length > 63) throw configError(`PermDock CLI: rls.rowHelpers cannot name a helper for resource '${resource}'; use a SQL name of at most 45 bytes`);
|
|
342
|
+
return helper;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Every declared `<permission>@<level>` of an instance permission on a resource
|
|
346
|
+
* with levels.
|
|
347
|
+
*/
|
|
348
|
+
function levelKeys(policy) {
|
|
349
|
+
const out = [];
|
|
350
|
+
for (const leaf of listPermissions(policy.vocabulary.permissions)) {
|
|
351
|
+
if (leaf.kind !== "instance") continue;
|
|
352
|
+
for (const [level, condition] of policyLevels(policy, leaf.resource)) out.push({
|
|
353
|
+
key: `${leaf.key}@${level}`,
|
|
354
|
+
permission: leaf.key,
|
|
355
|
+
conditioned: !(condition.op === "and" && condition.conditions.length === 0),
|
|
356
|
+
rowHelper: `permitted_${graphSqlName(leaf.resource) ?? leaf.resource}_row`
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return out;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* The branches a row check of a permission reads: its allows and denies,
|
|
363
|
+
* inserts included, for signed-in callers.
|
|
364
|
+
*/
|
|
365
|
+
function rowBranchesOf(branches, resource) {
|
|
366
|
+
const out = /* @__PURE__ */ new Map();
|
|
367
|
+
for (const branch of branches) {
|
|
368
|
+
if (branch.resource !== resource || branch.coverage === true || !branch.roles.includes("authenticated")) continue;
|
|
369
|
+
out.set(branch.permissionKey, [...out.get(branch.permissionKey) ?? [], branch]);
|
|
370
|
+
}
|
|
371
|
+
return out;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* What a branch asks of a row: the `with check` of an insert, which sees the
|
|
375
|
+
* new row, the `using` of every other command.
|
|
376
|
+
*/
|
|
377
|
+
function clauseOf(branch) {
|
|
378
|
+
const clauses = branchClauses(branch);
|
|
379
|
+
return (branch.command === "insert" ? clauses.check : clauses.using) ?? "true";
|
|
380
|
+
}
|
|
381
|
+
function usingOf(branches) {
|
|
382
|
+
const parts = branches.map(clauseOf);
|
|
383
|
+
return parts.length === 0 ? void 0 : orSql(parts);
|
|
384
|
+
}
|
|
385
|
+
function permissionCase(key, branches) {
|
|
386
|
+
const allow = usingOf(branches.filter((branch) => branch.effect === "allow"));
|
|
387
|
+
if (allow === void 0) return;
|
|
388
|
+
const deny = usingOf(branches.filter((branch) => branch.effect === "deny"));
|
|
389
|
+
const granted = `coalesce((${allow}), false)`;
|
|
390
|
+
return ` when ${quoteLiteral(key)} then ${deny === void 0 ? granted : `${granted} and (${deny}) is not true`}`;
|
|
391
|
+
}
|
|
392
|
+
function forUserSql(ctx, fn, helper) {
|
|
393
|
+
const user = ctx.dialect === "supabase" ? "uuid" : "text";
|
|
394
|
+
const signature = `${user}, text, jsonb`;
|
|
395
|
+
const head = `create or replace function ${fn}(p_user ${user}, p_permission text, p_claims jsonb default '{}')
|
|
396
|
+
returns setof text
|
|
397
|
+
language plpgsql
|
|
398
|
+
volatile
|
|
399
|
+
security definer
|
|
400
|
+
set search_path = ''
|
|
401
|
+
as $$`;
|
|
402
|
+
const tail = `revoke execute on function ${fn}(${signature}) from public, anon, authenticated;`;
|
|
403
|
+
if (ctx.dialect === "supabase") return `${head}
|
|
404
|
+
declare
|
|
405
|
+
v_claims text := pg_catalog.current_setting('request.jwt.claims', true);
|
|
406
|
+
begin
|
|
407
|
+
perform pg_catalog.set_config(
|
|
408
|
+
'request.jwt.claims',
|
|
409
|
+
(coalesce(p_claims, '{}'::jsonb) || pg_catalog.jsonb_build_object('sub', p_user::text, 'role', 'authenticated'))::text,
|
|
410
|
+
true
|
|
411
|
+
);
|
|
412
|
+
return query select r.id from ${helper}(p_permission) r(id);
|
|
413
|
+
perform pg_catalog.set_config('request.jwt.claims', coalesce(v_claims, ''), true);
|
|
414
|
+
end
|
|
415
|
+
$$;
|
|
416
|
+
${tail}`;
|
|
417
|
+
const prefix = ctx.gucPrefix;
|
|
418
|
+
return `${head}
|
|
419
|
+
declare
|
|
420
|
+
v_saved jsonb := '{}'::jsonb;
|
|
421
|
+
v_key text;
|
|
422
|
+
v_value text;
|
|
423
|
+
begin
|
|
424
|
+
for v_key, v_value in
|
|
425
|
+
select 'user_id', p_user
|
|
426
|
+
union all
|
|
427
|
+
select c.key, c.value from pg_catalog.jsonb_each_text(coalesce(p_claims, '{}'::jsonb)) c where c.key <> 'user_id'
|
|
428
|
+
loop
|
|
429
|
+
v_saved := v_saved || pg_catalog.jsonb_build_object(v_key, coalesce(pg_catalog.current_setting(${quoteLiteral(`${prefix}.`)} || v_key, true), ''));
|
|
430
|
+
perform pg_catalog.set_config(${quoteLiteral(`${prefix}.`)} || v_key, v_value, true);
|
|
431
|
+
end loop;
|
|
432
|
+
return query select r.id from ${helper}(p_permission) r(id);
|
|
433
|
+
for v_key, v_value in select s.key, s.value from pg_catalog.jsonb_each_text(v_saved) s loop
|
|
434
|
+
perform pg_catalog.set_config(${quoteLiteral(`${prefix}.`)} || v_key, v_value, true);
|
|
435
|
+
end loop;
|
|
436
|
+
end
|
|
437
|
+
$$;
|
|
438
|
+
${tail}`;
|
|
439
|
+
}
|
|
440
|
+
function inheritTargets(policy) {
|
|
441
|
+
const out = /* @__PURE__ */ new Set();
|
|
442
|
+
for (const grant of policy.grants) for (const item of flattenGrantee(grant.to)) if (item.kind === "inherit") out.add(item.resource);
|
|
443
|
+
return [...out].toSorted();
|
|
444
|
+
}
|
|
445
|
+
const CANDIDATES = "permdock_candidates";
|
|
446
|
+
function stubSql(ctx, resource) {
|
|
447
|
+
const fn = qualified(ctx, rowsHelper(resource));
|
|
448
|
+
return ["p_permission text", "p_permission text, p_ids text[]"].map((parameters) => `create or replace function ${fn}(${parameters})
|
|
449
|
+
returns setof text
|
|
450
|
+
language sql
|
|
451
|
+
stable
|
|
452
|
+
security definer
|
|
453
|
+
set search_path = ''
|
|
454
|
+
as $$
|
|
455
|
+
select null::text where false
|
|
456
|
+
$$;`).join("\n");
|
|
457
|
+
}
|
|
458
|
+
function rowSql(ctx, rows, table, where) {
|
|
459
|
+
const fn = qualified(ctx, rows.replace(/_rows$/u, "_row"));
|
|
460
|
+
return `create or replace function ${fn}(p_row ${table}, p_permission text)
|
|
461
|
+
returns boolean
|
|
462
|
+
language sql
|
|
463
|
+
stable
|
|
464
|
+
security definer
|
|
465
|
+
set search_path = ''
|
|
466
|
+
as $$
|
|
467
|
+
with ${CANDIDATES} as (select (p_row).*)
|
|
468
|
+
select exists (select 1 from ${CANDIDATES} where ${where})
|
|
469
|
+
$$;
|
|
470
|
+
revoke execute on function ${fn}(${table}, text) from public, anon;
|
|
471
|
+
grant execute on function ${fn}(${table}, text) to authenticated;`;
|
|
472
|
+
}
|
|
473
|
+
function whereOf(branches) {
|
|
474
|
+
const cases = [...branches.keys()].toSorted().flatMap((key) => {
|
|
475
|
+
const sql = permissionCase(key, branches.get(key) ?? []);
|
|
476
|
+
return sql === void 0 ? [] : [sql];
|
|
477
|
+
});
|
|
478
|
+
return cases.length === 0 ? "false" : `case p_permission\n${cases.join("\n")}\n else false\n end`;
|
|
479
|
+
}
|
|
480
|
+
function candidatesSql(fn, table, id, where) {
|
|
481
|
+
const assign = (indent) => `${indent}v_row.${id} := v_id;\n${indent}v_rows := pg_catalog.array_append(v_rows, v_row);`;
|
|
482
|
+
return `create or replace function ${fn}(p_permission text, p_ids text[])
|
|
483
|
+
returns setof text
|
|
484
|
+
language plpgsql
|
|
485
|
+
stable
|
|
486
|
+
security definer
|
|
487
|
+
set search_path = ''
|
|
488
|
+
as $$
|
|
489
|
+
declare
|
|
490
|
+
v_row ${table};
|
|
491
|
+
v_rows ${table}[] := '{}';
|
|
492
|
+
v_id text;
|
|
493
|
+
begin
|
|
494
|
+
begin
|
|
495
|
+
foreach v_id in array coalesce(p_ids, '{}') loop
|
|
496
|
+
${assign(" ")}
|
|
497
|
+
end loop;
|
|
498
|
+
exception when data_exception then
|
|
499
|
+
v_rows := '{}';
|
|
500
|
+
foreach v_id in array p_ids loop
|
|
501
|
+
begin
|
|
502
|
+
${assign(" ")}
|
|
503
|
+
exception when data_exception then
|
|
504
|
+
null;
|
|
505
|
+
end;
|
|
506
|
+
end loop;
|
|
507
|
+
end;
|
|
508
|
+
return query
|
|
509
|
+
with ${CANDIDATES} as materialized (
|
|
510
|
+
select * from ${table} where ${id} = any (array(select (r).${id} from pg_catalog.unnest(v_rows) r))
|
|
511
|
+
)
|
|
512
|
+
select ${id}::text from ${CANDIDATES}
|
|
513
|
+
where ${where};
|
|
514
|
+
end
|
|
515
|
+
$$;
|
|
516
|
+
revoke execute on function ${fn}(text, text[]) from public, anon;
|
|
517
|
+
grant execute on function ${fn}(text, text[]) to authenticated;`;
|
|
518
|
+
}
|
|
519
|
+
function resourceSql(ctx, node, branches, narrowed, tables) {
|
|
520
|
+
const name = rowsHelper(node.name);
|
|
521
|
+
const fn = qualified(ctx, name);
|
|
522
|
+
const table = quoteQualified(tableFor(node.name, tables));
|
|
523
|
+
const where = whereOf(branches);
|
|
524
|
+
const near = whereOf(narrowed);
|
|
525
|
+
const rows = `-- ${node.name}: ids of the rows the caller may act on with p_permission, as the table's policies decide it
|
|
526
|
+
create or replace function ${fn}(p_permission text)
|
|
527
|
+
returns setof text
|
|
528
|
+
language sql
|
|
529
|
+
stable
|
|
530
|
+
security definer
|
|
531
|
+
set search_path = ''
|
|
532
|
+
as $$
|
|
533
|
+
select ${quoteIdent(node.id)}::text from ${table}
|
|
534
|
+
where ${where}
|
|
535
|
+
$$;
|
|
536
|
+
revoke execute on function ${fn}(text) from public, anon;
|
|
537
|
+
grant execute on function ${fn}(text) to authenticated;
|
|
538
|
+
${candidatesSql(fn, table, quoteIdent(node.id), near)}
|
|
539
|
+
${rowSql(ctx, name, table, near)}`;
|
|
540
|
+
if (ctx.dialect === "neon") return rows;
|
|
541
|
+
return `${rows}
|
|
542
|
+
-- the same rows for a user the caller names, with claims it supplies; no client role may execute it
|
|
543
|
+
${forUserSql(ctx, qualified(ctx, `${name}_for`), fn)}`;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* `permitted_<resource>_rows(p_permission)` for each resource `select` names
|
|
547
|
+
* (or every resource a grant reaches with `true`): the ids of its rows the
|
|
548
|
+
* caller may read, update or delete with that permission, from the same
|
|
549
|
+
* compiled allows and denies the table policies use, so closure walks, link
|
|
550
|
+
* hops, the restricted stop, `includes`, groups and `requires` all apply. A
|
|
551
|
+
* `security definer` helper, so hand-written policies and functions call it
|
|
552
|
+
* without restating the graph. Outside the `neon` dialect a
|
|
553
|
+
* `permitted_<resource>_rows_for(p_user, p_permission, p_claims)` form runs it
|
|
554
|
+
* as the named user, with the claims the caller supplies, for trusted SQL.
|
|
555
|
+
*/
|
|
556
|
+
function rowHelpersSql(ctx, policy, branches, select, tables, warnings, narrowed = branches) {
|
|
557
|
+
const names = select === true ? [...new Set(branches.flatMap((branch) => branch.resource === void 0 ? [] : [branch.resource]))].toSorted() : [...new Set(select)];
|
|
558
|
+
const called = inheritTargets(policy);
|
|
559
|
+
for (const name of called) if (!names.includes(name)) names.push(name);
|
|
560
|
+
const chunks = called.map((name) => stubSql(ctx, name));
|
|
561
|
+
for (const name of names) {
|
|
562
|
+
const node = policy.resources.get(name);
|
|
563
|
+
if (node === void 0) throw configError(`PermDock CLI: rls.rowHelpers names '${name}', which the policy does not declare`);
|
|
564
|
+
chunks.push(resourceSql(ctx, node, rowBranchesOf(branches, name), rowBranchesOf(narrowed, name), tables));
|
|
565
|
+
}
|
|
566
|
+
if (chunks.length > 0 && ctx.dialect === "neon") warnings.push("rls.rowHelpers: the neon dialect reads the subject from auth.session(), which SQL cannot set, so no permitted_<resource>_rows_for is written");
|
|
567
|
+
return chunks.length === 0 ? "" : `${chunks.join("\n\n")}\n`;
|
|
568
|
+
}
|
|
569
|
+
//#endregion
|
|
246
570
|
//#region src/cli/rls/generate-context.ts
|
|
247
|
-
/**
|
|
571
|
+
/**
|
|
572
|
+
* The scopes an `rls.migrate` `role` helper names, so `rls generate` writes
|
|
573
|
+
* their role-filtered member helper.
|
|
574
|
+
*/
|
|
248
575
|
function roleMemberScopesOf(migrate) {
|
|
249
576
|
const scopes = [...new Set(Object.values(migrate?.helpers ?? {}).flatMap((helper) => helper.form === "role" ? [helper.scope] : []))].toSorted();
|
|
250
577
|
return scopes.length === 0 ? {} : { roleMemberScopes: scopes };
|
|
@@ -285,7 +612,10 @@ function skippedOwnershipTriggers(triggers, scopes) {
|
|
|
285
612
|
return name;
|
|
286
613
|
});
|
|
287
614
|
}
|
|
288
|
-
/**
|
|
615
|
+
/**
|
|
616
|
+
* The SQL context every emitter reads, from the flags, `rls` config and the
|
|
617
|
+
* policy.
|
|
618
|
+
*/
|
|
289
619
|
function buildContext(input, policy, options) {
|
|
290
620
|
const rls = input.config.rls;
|
|
291
621
|
const memberships = parseMembershipsFlag(input.memberships) ?? rls?.memberships;
|
|
@@ -342,8 +672,7 @@ function buildContext(input, policy, options) {
|
|
|
342
672
|
schema,
|
|
343
673
|
authorize,
|
|
344
674
|
roleClaim: rls?.roleClaim ?? "user_role",
|
|
345
|
-
tenantType: input.tenantType ?? rls?.
|
|
346
|
-
...rls?.teamType === void 0 ? {} : { teamType: rls.teamType },
|
|
675
|
+
tenantType: input.tenantType ?? firstScopeType(rls?.scopeTypes, scopes),
|
|
347
676
|
...rls?.scopeTypes === void 0 ? {} : { scopeTypes: rls.scopeTypes },
|
|
348
677
|
...memberships === void 0 ? {} : { memberships },
|
|
349
678
|
...sources === void 0 || sources.length === 0 ? {} : { sources },
|
|
@@ -368,7 +697,7 @@ function buildContext(input, policy, options) {
|
|
|
368
697
|
} },
|
|
369
698
|
...options.fieldsMode === void 0 ? {} : { fields: options.fieldsMode },
|
|
370
699
|
...vias === void 0 ? {} : { vias },
|
|
371
|
-
...graph.size === 0 ? {} : { graph: {
|
|
700
|
+
...graph.size === 0 && inheritTargets(policy).length === 0 ? {} : { graph: {
|
|
372
701
|
closures: closureDepths(graph),
|
|
373
702
|
resources: policy.resources,
|
|
374
703
|
...rls?.tables === void 0 ? {} : { tables: tableNames(rls.tables) ?? {} }
|
|
@@ -388,8 +717,14 @@ function buildContext(input, policy, options) {
|
|
|
388
717
|
}
|
|
389
718
|
const [unsatisfied] = unsatisfiedKinds(ctx, policy);
|
|
390
719
|
if (unsatisfied !== void 0) return { refusal: `role ${unsatisfied.role} is for ${unsatisfied.for.join(", ")}, but its membership sources hold ${unsatisfied.sources.join(", ")}: no membership can hold it; set via on a source to one of those kinds` };
|
|
720
|
+
const names = resolveNames(policy, input.config, {
|
|
721
|
+
schema,
|
|
722
|
+
gucPrefix: ctx.gucPrefix,
|
|
723
|
+
tenantClaim: ctx.tenantClaim
|
|
724
|
+
});
|
|
391
725
|
return {
|
|
392
726
|
ctx,
|
|
727
|
+
names,
|
|
393
728
|
graph,
|
|
394
729
|
ownership,
|
|
395
730
|
schema,
|
|
@@ -413,192 +748,20 @@ function generateOptions(input) {
|
|
|
413
748
|
revokeColumns
|
|
414
749
|
};
|
|
415
750
|
}
|
|
416
|
-
/**
|
|
751
|
+
/**
|
|
752
|
+
* Whether `--split` names `part`, which then leaves the helpers or the
|
|
753
|
+
* warnings.
|
|
754
|
+
*/
|
|
417
755
|
function splitsPart(raw, part) {
|
|
418
756
|
const split = parseSplit(raw);
|
|
419
757
|
return typeof split !== "string" && split?.includes(part) === true;
|
|
420
758
|
}
|
|
421
759
|
//#endregion
|
|
422
|
-
//#region src/cli/
|
|
423
|
-
/** `permitted_<resource>_rows(p_permission)`: the resource's row ids the subject may act on with one permission. */
|
|
424
|
-
function rowsHelper(resource) {
|
|
425
|
-
const name = graphSqlName(resource);
|
|
426
|
-
const helper = `permitted_${name ?? resource}_rows`;
|
|
427
|
-
if (name === void 0 || new TextEncoder().encode(`${helper}_for`).length > 63) throw configError(`PermDock CLI: rls.rowHelpers cannot name a helper for resource '${resource}'; use a SQL name of at most 45 bytes`);
|
|
428
|
-
return helper;
|
|
429
|
-
}
|
|
430
|
-
/** Every declared `<permission>@<level>` of an instance permission on a resource with levels. */
|
|
431
|
-
function levelKeys(policy) {
|
|
432
|
-
const out = [];
|
|
433
|
-
for (const leaf of listPermissions(policy.vocabulary.permissions)) {
|
|
434
|
-
if (leaf.kind !== "instance") continue;
|
|
435
|
-
for (const [level, condition] of policyLevels(policy, leaf.resource)) out.push({
|
|
436
|
-
key: `${leaf.key}@${level}`,
|
|
437
|
-
permission: leaf.key,
|
|
438
|
-
conditioned: !(condition.op === "and" && condition.conditions.length === 0),
|
|
439
|
-
rowHelper: `permitted_${graphSqlName(leaf.resource) ?? leaf.resource}_row`
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
return out;
|
|
443
|
-
}
|
|
444
|
-
/** The branches a row check of a permission reads: its allows and denies, inserts included, for signed-in callers. */
|
|
445
|
-
function rowBranchesOf(branches, resource) {
|
|
446
|
-
const out = /* @__PURE__ */ new Map();
|
|
447
|
-
for (const branch of branches) {
|
|
448
|
-
if (branch.resource !== resource || branch.coverage === true || !branch.roles.includes("authenticated")) continue;
|
|
449
|
-
out.set(branch.permissionKey, [...out.get(branch.permissionKey) ?? [], branch]);
|
|
450
|
-
}
|
|
451
|
-
return out;
|
|
452
|
-
}
|
|
453
|
-
/** What a branch asks of a row: the `with check` of an insert, which sees the new row, the `using` of every other command. */
|
|
454
|
-
function clauseOf(branch) {
|
|
455
|
-
const clauses = branchClauses(branch);
|
|
456
|
-
return (branch.command === "insert" ? clauses.check : clauses.using) ?? "true";
|
|
457
|
-
}
|
|
458
|
-
function usingOf(branches) {
|
|
459
|
-
const parts = branches.map(clauseOf);
|
|
460
|
-
return parts.length === 0 ? void 0 : orSql(parts);
|
|
461
|
-
}
|
|
462
|
-
function permissionCase(key, branches) {
|
|
463
|
-
const allow = usingOf(branches.filter((branch) => branch.effect === "allow"));
|
|
464
|
-
if (allow === void 0) return;
|
|
465
|
-
const deny = usingOf(branches.filter((branch) => branch.effect === "deny"));
|
|
466
|
-
const granted = `coalesce((${allow}), false)`;
|
|
467
|
-
return ` when ${quoteLiteral(key)} then ${deny === void 0 ? granted : `${granted} and (${deny}) is not true`}`;
|
|
468
|
-
}
|
|
469
|
-
function forUserSql(ctx, fn, helper) {
|
|
470
|
-
const user = ctx.dialect === "supabase" ? "uuid" : "text";
|
|
471
|
-
const signature = `${user}, text, jsonb`;
|
|
472
|
-
const head = `create or replace function ${fn}(p_user ${user}, p_permission text, p_claims jsonb default '{}')
|
|
473
|
-
returns setof text
|
|
474
|
-
language plpgsql
|
|
475
|
-
volatile
|
|
476
|
-
security definer
|
|
477
|
-
set search_path = ''
|
|
478
|
-
as $$`;
|
|
479
|
-
const tail = `revoke execute on function ${fn}(${signature}) from public, anon, authenticated;`;
|
|
480
|
-
if (ctx.dialect === "supabase") return `${head}
|
|
481
|
-
declare
|
|
482
|
-
v_claims text := pg_catalog.current_setting('request.jwt.claims', true);
|
|
483
|
-
begin
|
|
484
|
-
perform pg_catalog.set_config(
|
|
485
|
-
'request.jwt.claims',
|
|
486
|
-
(coalesce(p_claims, '{}'::jsonb) || pg_catalog.jsonb_build_object('sub', p_user::text, 'role', 'authenticated'))::text,
|
|
487
|
-
true
|
|
488
|
-
);
|
|
489
|
-
return query select r.id from ${helper}(p_permission) r(id);
|
|
490
|
-
perform pg_catalog.set_config('request.jwt.claims', coalesce(v_claims, ''), true);
|
|
491
|
-
end
|
|
492
|
-
$$;
|
|
493
|
-
${tail}`;
|
|
494
|
-
const prefix = ctx.gucPrefix;
|
|
495
|
-
return `${head}
|
|
496
|
-
declare
|
|
497
|
-
v_saved jsonb := '{}'::jsonb;
|
|
498
|
-
v_key text;
|
|
499
|
-
v_value text;
|
|
500
|
-
begin
|
|
501
|
-
for v_key, v_value in
|
|
502
|
-
select 'user_id', p_user
|
|
503
|
-
union all
|
|
504
|
-
select c.key, c.value from pg_catalog.jsonb_each_text(coalesce(p_claims, '{}'::jsonb)) c where c.key <> 'user_id'
|
|
505
|
-
loop
|
|
506
|
-
v_saved := v_saved || pg_catalog.jsonb_build_object(v_key, coalesce(pg_catalog.current_setting(${quoteLiteral(`${prefix}.`)} || v_key, true), ''));
|
|
507
|
-
perform pg_catalog.set_config(${quoteLiteral(`${prefix}.`)} || v_key, v_value, true);
|
|
508
|
-
end loop;
|
|
509
|
-
return query select r.id from ${helper}(p_permission) r(id);
|
|
510
|
-
for v_key, v_value in select s.key, s.value from pg_catalog.jsonb_each_text(v_saved) s loop
|
|
511
|
-
perform pg_catalog.set_config(${quoteLiteral(`${prefix}.`)} || v_key, v_value, true);
|
|
512
|
-
end loop;
|
|
513
|
-
end
|
|
514
|
-
$$;
|
|
515
|
-
${tail}`;
|
|
516
|
-
}
|
|
517
|
-
function inheritTargets(policy) {
|
|
518
|
-
const out = /* @__PURE__ */ new Set();
|
|
519
|
-
for (const grant of policy.grants) for (const item of flattenGrantee(grant.to)) if (item.kind === "inherit") out.add(item.resource);
|
|
520
|
-
return [...out].toSorted();
|
|
521
|
-
}
|
|
522
|
-
function stubSql(ctx, resource) {
|
|
523
|
-
return `create or replace function ${qualified(ctx, rowsHelper(resource))}(p_permission text)
|
|
524
|
-
returns setof text
|
|
525
|
-
language sql
|
|
526
|
-
stable
|
|
527
|
-
security definer
|
|
528
|
-
set search_path = ''
|
|
529
|
-
as $$
|
|
530
|
-
select null::text where false
|
|
531
|
-
$$;`;
|
|
532
|
-
}
|
|
533
|
-
function rowSql(ctx, rows, table, where) {
|
|
534
|
-
const fn = qualified(ctx, rows.replace(/_rows$/u, "_row"));
|
|
535
|
-
return `create or replace function ${fn}(p_row ${table}, p_permission text)
|
|
536
|
-
returns boolean
|
|
537
|
-
language sql
|
|
538
|
-
stable
|
|
539
|
-
security definer
|
|
540
|
-
set search_path = ''
|
|
541
|
-
as $$
|
|
542
|
-
select exists (select 1 from (select (p_row).*) r where ${where})
|
|
543
|
-
$$;
|
|
544
|
-
revoke execute on function ${fn}(${table}, text) from public, anon;
|
|
545
|
-
grant execute on function ${fn}(${table}, text) to authenticated;`;
|
|
546
|
-
}
|
|
547
|
-
function resourceSql(ctx, node, branches, tables) {
|
|
548
|
-
const name = rowsHelper(node.name);
|
|
549
|
-
const fn = qualified(ctx, name);
|
|
550
|
-
const table = quoteQualified(tableFor(node.name, tables));
|
|
551
|
-
const cases = [...branches.keys()].toSorted().flatMap((key) => {
|
|
552
|
-
const sql = permissionCase(key, branches.get(key) ?? []);
|
|
553
|
-
return sql === void 0 ? [] : [sql];
|
|
554
|
-
});
|
|
555
|
-
const where = cases.length === 0 ? "false" : `case p_permission\n${cases.join("\n")}\n else false\n end`;
|
|
556
|
-
const rows = `-- ${node.name}: ids of the rows the caller may act on with p_permission, as the table's policies decide it
|
|
557
|
-
create or replace function ${fn}(p_permission text)
|
|
558
|
-
returns setof text
|
|
559
|
-
language sql
|
|
560
|
-
stable
|
|
561
|
-
security definer
|
|
562
|
-
set search_path = ''
|
|
563
|
-
as $$
|
|
564
|
-
select ${quoteIdent(node.id)}::text from ${table}
|
|
565
|
-
where ${where}
|
|
566
|
-
$$;
|
|
567
|
-
revoke execute on function ${fn}(text) from public, anon;
|
|
568
|
-
grant execute on function ${fn}(text) to authenticated;
|
|
569
|
-
${rowSql(ctx, name, table, where)}`;
|
|
570
|
-
if (ctx.dialect === "neon") return rows;
|
|
571
|
-
return `${rows}
|
|
572
|
-
-- the same rows for a user the caller names, with claims it supplies; no client role may execute it
|
|
573
|
-
${forUserSql(ctx, qualified(ctx, `${name}_for`), fn)}`;
|
|
574
|
-
}
|
|
760
|
+
//#region src/cli/sql/supautils.ts
|
|
575
761
|
/**
|
|
576
|
-
* `
|
|
577
|
-
*
|
|
578
|
-
* the caller may read, update or delete with that permission, from the same
|
|
579
|
-
* compiled allows and denies the table policies use, so closure walks, link
|
|
580
|
-
* hops, the restricted stop, `includes`, groups and `requires` all apply. A
|
|
581
|
-
* `security definer` helper, so hand-written policies and functions call it
|
|
582
|
-
* without restating the graph. Outside the `neon` dialect a
|
|
583
|
-
* `permitted_<resource>_rows_for(p_user, p_permission, p_claims)` form runs it
|
|
584
|
-
* as the named user, with the claims the caller supplies, for trusted SQL.
|
|
762
|
+
* `supautils.reserved_roles` of supabase/postgres 17.11.0.002 (supautils
|
|
763
|
+
* 3.4.4).
|
|
585
764
|
*/
|
|
586
|
-
function rowHelpersSql(ctx, policy, branches, select, tables, warnings) {
|
|
587
|
-
const names = select === true ? [...new Set(branches.flatMap((branch) => branch.resource === void 0 ? [] : [branch.resource]))].toSorted() : [...new Set(select)];
|
|
588
|
-
const called = inheritTargets(policy);
|
|
589
|
-
for (const name of called) if (!names.includes(name)) names.push(name);
|
|
590
|
-
const chunks = called.map((name) => stubSql(ctx, name));
|
|
591
|
-
for (const name of names) {
|
|
592
|
-
const node = policy.resources.get(name);
|
|
593
|
-
if (node === void 0) throw configError(`PermDock CLI: rls.rowHelpers names '${name}', which the policy does not declare`);
|
|
594
|
-
chunks.push(resourceSql(ctx, node, rowBranchesOf(branches, name), tables));
|
|
595
|
-
}
|
|
596
|
-
if (chunks.length > 0 && ctx.dialect === "neon") warnings.push("rls.rowHelpers: the neon dialect reads the subject from auth.session(), which SQL cannot set, so no permitted_<resource>_rows_for is written");
|
|
597
|
-
return chunks.length === 0 ? "" : `${chunks.join("\n\n")}\n`;
|
|
598
|
-
}
|
|
599
|
-
//#endregion
|
|
600
|
-
//#region src/cli/sql/supautils.ts
|
|
601
|
-
/** `supautils.reserved_roles` of supabase/postgres 17.11.0.002 (supautils 3.4.4). */
|
|
602
765
|
const RESERVED_ROLES = /* @__PURE__ */ new Set([
|
|
603
766
|
"supabase_admin",
|
|
604
767
|
"supabase_auth_admin",
|
|
@@ -615,7 +778,10 @@ const RESERVED_ROLES = /* @__PURE__ */ new Set([
|
|
|
615
778
|
"authenticated",
|
|
616
779
|
"anon"
|
|
617
780
|
]);
|
|
618
|
-
/**
|
|
781
|
+
/**
|
|
782
|
+
* The `*` entries of `reserved_roles`: `postgres` may still `set` or `reset`
|
|
783
|
+
* their settings.
|
|
784
|
+
*/
|
|
619
785
|
const CONFIGURABLE_ROLES = /* @__PURE__ */ new Set([
|
|
620
786
|
"service_role",
|
|
621
787
|
"authenticator",
|
|
@@ -672,9 +838,9 @@ function rejection(text) {
|
|
|
672
838
|
return role === void 0 ? void 0 : `grants membership in the reserved role ${role}`;
|
|
673
839
|
}
|
|
674
840
|
/**
|
|
675
|
-
* The statements of `sql` that supautils rejects for a non-superuser:
|
|
676
|
-
*
|
|
677
|
-
*
|
|
841
|
+
* The statements of `sql` that supautils rejects for a non-superuser: changing
|
|
842
|
+
* or dropping a reserved role, other than `set` or `reset` on the four API
|
|
843
|
+
* roles, and granting a reserved membership.
|
|
678
844
|
*/
|
|
679
845
|
function supautilsRejections(sql) {
|
|
680
846
|
return sqlStatements(sql).flatMap(({ line, text }) => {
|
|
@@ -686,4 +852,4 @@ function supautilsRejections(sql) {
|
|
|
686
852
|
});
|
|
687
853
|
}
|
|
688
854
|
//#endregion
|
|
689
|
-
export {
|
|
855
|
+
export { buildContext as a, levelKeys as c, rebuildPlan as d, splitsPart as i, rowHelpersSql as l, generateOptions as n, CANDIDATES as o, isRefusal as r, inheritTargets as s, supautilsRejections as t, DROPPED_LIST as u };
|