permdock 0.16.0 → 0.18.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 +4 -4
- package/dist/a2a/index.js +3 -3
- package/dist/{adapter-context-CIQpQxbE.js → adapter-context-OHikyRqV.js} +1 -1
- package/dist/{adoption-scan-C2BCiUEG.js → adoption-scan-CxExBYSJ.js} +1 -1
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/ai-sdk/index.d.ts +3 -3
- package/dist/ai-sdk/index.js +3 -3
- package/dist/approval-normalize-CUjgSsOl.js +189 -0
- package/dist/approval-policies-oNnckT12.d.ts +138 -0
- package/dist/{approval-prompt-3BqWczTt.d.ts → approval-prompt-Bg7gDSqd.d.ts} +1 -1
- package/dist/approvals/index.d.ts +5 -4
- package/dist/approvals/index.js +7 -6
- package/dist/{approvals-DnIBTuXE.js → approvals-DGId_hgJ.js} +3 -3
- package/dist/{approvers-B4r0N_Uz.js → approvers-BaNwKYgd.js} +20 -1
- package/dist/{arazzo-ClYz2Z0W.js → arazzo--riLuGY0.js} +4 -4
- package/dist/{arazzo-CHoYnQXO.js → arazzo-CEDbb-uM.js} +2 -2
- package/dist/{args-0FrVs5EH.js → args-iafbHiXn.js} +2 -5
- package/dist/astro/index.d.ts +4 -4
- package/dist/astro/index.js +2 -2
- package/dist/{audience-DTjR8xet.js → audience-B4YR9UpV.js} +1 -1
- package/dist/{auth--yPyZNgr.js → auth-j3Eu-j4h.js} +1 -1
- package/dist/authz-topic-Dbc-HDOS.js +15 -0
- package/dist/authzen/index.d.ts +5 -5
- package/dist/authzen/index.js +2 -2
- package/dist/{automation-C6Jg75xq.d.ts → automation-Bfa_wD1h.d.ts} +1 -1
- package/dist/better-auth/index.d.ts +1 -1
- package/dist/better-auth/index.js +10 -8
- package/dist/better-supabase/index.d.ts +335 -38
- package/dist/better-supabase/index.js +778 -117
- package/dist/{better-supabase-Dirf_8Ec.js → better-supabase-BJtQ-kNf.js} +26 -10
- package/dist/{bind-BNQA9JK9.js → bind-B4pMH9bm.js} +6 -6
- package/dist/{bind-YYjvfpB9.d.ts → bind-DR6ku3A9.d.ts} +7 -7
- package/dist/{budget-BELja5A9.js → budget-BBCPDOGP.js} +1 -1
- package/dist/{budget-hYsPz_yE.d.ts → budget-CNLsV2SL.d.ts} +1 -1
- package/dist/{build-instance-BWXqwQYU.js → build-instance-BFMFQdE_.js} +3 -2
- package/dist/{capability-Di9tiUvi.d.ts → capability-BZ_veK9o.d.ts} +1 -1
- package/dist/{capability-BqX94r07.js → capability-zN6T9fxe.js} +2 -3
- package/dist/{casbin-D_rVQ31U.js → casbin-DCQHkkyj.js} +2 -2
- package/dist/{casbin-C9EvElBb.js → casbin-bKC1FpEx.js} +2 -2
- package/dist/{casl-C4OINZHI.js → casl-CjBVJj8R.js} +2 -2
- package/dist/{casl-CHHoCldP.js → casl-CkBssiB1.js} +1 -1
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +7 -7
- package/dist/catalog-Caqhbdix.js +1 -0
- package/dist/{catalog-CGlSwU6j.js → catalog-D1fw8qif.js} +5 -5
- package/dist/{catalog-doc-DjMKzJp9.js → catalog-doc-C4DGfJCO.js} +3 -3
- package/dist/{catalog-operations-DeHTrJSV.js → catalog-operations-BD22drQf.js} +4 -4
- package/dist/{catalog-amPDr0JQ.js → catalog-zzNuR3sY.js} +3 -3
- package/dist/{challenge-DImNcR7B.js → challenge-B2O2OLEk.js} +2 -2
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +2 -2
- package/dist/chat-sdk/index.d.ts +3 -3
- package/dist/{checks-CGkP3Z7A.js → checks-fyDOhcz0.js} +33 -1
- package/dist/claude-agent/index.d.ts +3 -3
- package/dist/claude-agent/index.js +2 -2
- package/dist/clerk/index.d.ts +2 -2
- package/dist/clerk/index.js +10 -7
- package/dist/cli/bin.js +1 -1
- package/dist/cli/index.d.ts +5 -5
- package/dist/cli/index.js +3 -3
- package/dist/client-CH7vzSAY.d.ts +32 -0
- package/dist/cloud/index.d.ts +8 -8
- package/dist/cloud/index.js +1 -1
- package/dist/{cloud-DdaJ7ILM.js → cloud-C0vXBmLG.js} +4 -4
- package/dist/{codemod-B1USJS7a.js → codemod-C-L0w-u7.js} +3 -3
- package/dist/{codemod-ammy6wv4.js → codemod-eYI1FbeJ.js} +395 -8
- package/dist/{collect-DnXL4B8c.js → collect-CU85z6Ta.js} +4 -4
- package/dist/{collect-WCl8cJQV.js → collect-D878zLDP.js} +4 -4
- package/dist/collect-KCtOigxx.js +1 -0
- package/dist/compile/index.d.ts +1 -1
- package/dist/compile/index.js +1 -1
- package/dist/{compile-EzEMB-7v.js → compile-B_oJqmIg.js} +4 -4
- package/dist/{compile-BEklRUYo.d.ts → compile-DBm0ub4p.d.ts} +2 -2
- package/dist/{completion--Y4YItFZ.js → completion-Dauc6pVT.js} +3 -3
- package/dist/{config-CcLlvEYW.js → config-COHmivz9.js} +4 -4
- package/dist/{config-BQ77xMZk.js → config-DWp2PucY.js} +2 -2
- package/dist/{config-report-DVMOLJ7F.js → config-report-DKpFm5ID.js} +2 -2
- package/dist/{context-BnIzxTNE.js → context-DeammvFl.js} +2 -2
- package/dist/convex/index.d.ts +4 -4
- package/dist/convex/index.js +3 -3
- package/dist/{core-lxoANyai.js → core-B8sLve3z.js} +7 -7
- package/dist/{core-CFepFiDP.d.ts → core-D87h2kpR.d.ts} +2 -2
- package/dist/{create-BLPKnJKa.js → create-3A7J9KRR.js} +6 -5
- package/dist/{create-CDd9c22W.d.ts → create-BrQXL-Wt.d.ts} +6 -6
- package/dist/{create-BPUopdfL.d.ts → create-BzwjZuRS.d.ts} +7 -7
- package/dist/{create-Coq5fIrq.js → create-C-tm3KIF.js} +5 -5
- package/dist/{create-DBvUsgzK.d.ts → create-CtoT1lIQ.d.ts} +4 -4
- package/dist/{credential-CyyyvCsL.js → credential-B3Hj4puZ.js} +4 -3
- package/dist/{credentials-CdDxp7jN.js → credentials-dkycUsY3.js} +1 -1
- package/dist/decision-CaG5_eNJ.js +21 -0
- package/dist/{delegation-CDB6_keF.js → delegation-aK4T_5WU.js} +3 -3
- package/dist/delivery/index.d.ts +4 -4
- package/dist/delivery/index.js +1 -1
- package/dist/{denied-text-DHldhVUv.d.ts → denied-text-DlIxt8fh.d.ts} +1 -1
- package/dist/{describe-BbFPBSms.d.ts → describe-BKtC_8PG.d.ts} +1 -1
- package/dist/{describe-Bb4hGK5d.js → describe-BZAlPHxT.js} +2 -1
- package/dist/{diff-DfmYaIhB.js → diff-BnNHqtHj.js} +8 -8
- package/dist/{diff-CxtbOi2l.js → diff-CBCzOTWM.js} +2 -2
- package/dist/{doctor-D1Xnmy6u.js → doctor-CkYKCuX7.js} +233 -30
- package/dist/{doctor-CwYc2lJb.js → doctor-xUpR5rXg.js} +3 -3
- package/dist/drizzle/index.d.ts +3 -3
- package/dist/drizzle/index.js +1 -1
- package/dist/elysia/index.d.ts +4 -4
- package/dist/elysia/index.js +3 -3
- package/dist/{errors-Vpu6rKHl.js → errors-BhRkoNS7.js} +0 -2
- package/dist/{errors-BIM4MFsJ.d.ts → errors-TpzkEKgJ.d.ts} +1 -1
- package/dist/{evaluate-BAmf_AQd.js → evaluate-Czbj7thS.js} +18 -15
- package/dist/{evaluations-DOWuBpWv.d.ts → evaluations-CisTTURl.d.ts} +3 -3
- package/dist/{evaluations-IBceAeKT.js → evaluations-h3KoJAPa.js} +3 -22
- package/dist/eve/index.d.ts +4 -4
- package/dist/eve/index.js +3 -3
- package/dist/express/index.d.ts +4 -4
- package/dist/express/index.js +3 -3
- package/dist/fastify/index.d.ts +4 -4
- package/dist/fastify/index.js +3 -3
- package/dist/{fetch-adapter-BIbBAtPZ.d.ts → fetch-adapter-BdmfnbJM.d.ts} +2 -2
- package/dist/{fetch-adapter-dPTgJVHd.js → fetch-adapter-DH-NJPbL.js} +2 -2
- package/dist/{fields-DI8s3cPl.js → fields-CrjL6A49.js} +3 -3
- package/dist/{files-B3AA05f1.js → files-CfiRtQ-m.js} +1 -1
- package/dist/{fixtures-Bm4_K1ke.js → fixtures-Cemqurt8.js} +10 -4
- package/dist/{flags-DXjoTVbS.js → flags-BlmpmXoY.js} +2 -2
- package/dist/{from-snapshot-DCakWRsr.js → from-snapshot-DMlSSo9b.js} +14 -12
- package/dist/{gen-DwgCSC6V.js → gen-BEIN-DRM.js} +2 -2
- package/dist/{gen-DuAhghDw.js → gen-mf-MRwVr.js} +9 -9
- package/dist/{generate-CRVV5V7l.js → generate-BqkZq8Dr.js} +2 -2
- package/dist/{grantee-conditions-BrYPe-w0.js → grantee-conditions-DX4K_gGI.js} +1 -1
- package/dist/{grantee-match-7RZZvoT_.js → grantee-match-BP-k4vRJ.js} +2 -2
- package/dist/h3/index.d.ts +4 -4
- package/dist/h3/index.js +3 -3
- package/dist/{helpers-DJicaG6f.js → helpers-DmqGy63f.js} +85 -13
- package/dist/hono/index.d.ts +4 -4
- package/dist/hono/index.js +3 -3
- package/dist/{hosted-DVxlLZMe.d.ts → hosted-BFNXwcjd.d.ts} +1 -1
- package/dist/{hosted-D0IzESu_.js → hosted-waouw2V-.js} +12 -10
- package/dist/{http-DOL33cO0.js → http-DhMWeB_h.js} +1 -1
- package/dist/{import-CNBF96hB.js → import-C1XXpG_m.js} +4 -4
- package/dist/{import-Dfe2unKO.js → import-DObwEota.js} +3 -3
- package/dist/{index-BinlXeU-.d.ts → index-BhnOOnp9.d.ts} +2 -2
- package/dist/{index-ymept53A.d.ts → index-CVGio3cH.d.ts} +4 -4
- package/dist/{index-DJwEgYzA.d.ts → index-CdMOd-GY.d.ts} +17 -11
- package/dist/{index-Cay5-Kvx.d.ts → index-CdUTE6qd.d.ts} +11 -10
- package/dist/{index-Dj2qF9VC.d.ts → index-Dfv9Toct.d.ts} +1 -1
- package/dist/{index-CV-7DWeD.d.ts → index-rFp6X_QP.d.ts} +4 -4
- package/dist/index.d.ts +18 -16
- package/dist/index.js +24 -20
- package/dist/{init-BUo2G-FI.js → init-CNJ8lLjo.js} +5 -5
- package/dist/{init-C6cWP3xW.js → init-DS3PEsCG.js} +5 -5
- package/dist/{instance-options-CoHn-0e8.d.ts → instance-options-2sFGSdsf.d.ts} +2 -2
- package/dist/{instance-snapshot-DuWf1cT3.js → instance-snapshot-BWa71my8.js} +15 -12
- package/dist/jwt/index.d.ts +4 -4
- package/dist/jwt/index.js +3 -3
- package/dist/{kernel-BD8QuMnv.js → kernel-30Z2zM_d.js} +10 -10
- package/dist/kysely/index.d.ts +3 -3
- package/dist/kysely/index.js +1 -1
- package/dist/{load-DjSU5KXO.js → load-BaEamml-.js} +1 -1
- package/dist/load-CjnlPxpL.js +1 -0
- package/dist/{login-D1MHOomI.js → login-BgK5Jloo.js} +4 -4
- package/dist/{login-DCKE5pVy.js → login-DUVzBLh7.js} +4 -4
- package/dist/{manifest-BXTbHNIV.js → manifest-BdzBobNK.js} +1 -1
- package/dist/{manifest-schema-DQkBK2Mr.js → manifest-schema-CsFsYLF-.js} +1 -1
- package/dist/{manifest-Cft51TLK.js → manifest-wclLWBVH.js} +37 -37
- package/dist/{map-claims-C-nv08_n.js → map-claims-PQwHynxV.js} +25 -11
- package/dist/{map-error-pasIGqMT.js → map-error-BH16Ah8P.js} +1 -1
- package/dist/mcp/index.d.ts +8 -8
- package/dist/mcp/index.js +9 -9
- package/dist/{migrate-BJHxQqT5.js → migrate-BbY5-Khy.js} +4 -4
- package/dist/{module-values-B1EVTkHP.js → module-values-B8tNIxdd.js} +2 -2
- package/dist/nest/index.d.ts +4 -4
- package/dist/nest/index.js +3 -3
- package/dist/next/index.d.ts +45 -13
- package/dist/next/index.js +68 -30
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +2 -2
- package/dist/node/index.d.ts +4 -4
- package/dist/node/index.js +2 -2
- package/dist/openai/index.d.ts +4 -4
- package/dist/openai/index.js +3 -3
- package/dist/openapi/index.d.ts +2 -2
- package/dist/{openapi-BwWkHxvW.js → openapi-C4gFqeRz.js} +4 -4
- package/dist/{openapi-DSzQN7Zu.js → openapi-zMEB9qxn.js} +5 -5
- package/dist/{operation-findings-CXtFzlKJ.js → operation-findings-CVwJHEu_.js} +1 -1
- package/dist/operation-risks-BKOcTv8J.js +13 -0
- package/dist/operations-Bm9HFecz.js +89 -0
- package/dist/orpc/index.d.ts +5 -5
- package/dist/orpc/index.js +3 -3
- package/dist/otel/index.d.ts +3 -3
- package/dist/otel/index.js +1 -1
- package/dist/{output-DlICTjBh.js → output-BFWLER4r.js} +1 -1
- package/dist/output-files-BYscrQl-.js +1 -0
- package/dist/{output-files-BIQ_9pIs.js → output-files-CM0BnH05.js} +1 -1
- package/dist/{ownership-qqBuGJXr.js → ownership-D-mIt-w0.js} +6 -6
- package/dist/{parse-1_ZheTW5.js → parse-UTC-sDrt.js} +2 -2
- package/dist/{parse-local-manifest-DEiCF4ah.js → parse-local-manifest-CxcSMQgl.js} +2 -2
- package/dist/{parse-local-manifest-CCmbhnxP.d.ts → parse-local-manifest-DvjTQNuO.d.ts} +1 -1
- package/dist/{parse-request-CwCZpyjV.js → parse-request-DOBVaeiQ.js} +1 -1
- package/dist/pdp/index.d.ts +3 -3
- package/dist/pdp/index.js +3 -3
- package/dist/{peer-Q0fuZ6hx.js → peer-BuK9F53f.js} +1 -1
- package/dist/{peer-C9LvBCcb.js → peer-n-swIV4H.js} +1 -1
- package/dist/{permdock-BvjivVb9.js → permdock-D-_WrdKu.js} +205 -102
- package/dist/{permdock-CprAPN3w.d.ts → permdock-ffY4CMd9.d.ts} +101 -131
- package/dist/{permissions-CYcHj_w7.js → permissions-B3ggI88M.js} +2 -2
- package/dist/{permissions-CVXmRILq.js → permissions-BaoLxy66.js} +1 -13
- package/dist/{pg-DQTqRrou.js → pg-Ddxsd5ZB.js} +2 -2
- package/dist/{policy-BycVKnXv.d.ts → policy-BtKSApSt.d.ts} +1 -1
- package/dist/{policy-CLQ8__GF.js → policy-cV_wwPb8.js} +5 -4
- package/dist/{policy-from-catalog-CU3An8uP.js → policy-from-catalog-B68hGC0S.js} +9 -8
- package/dist/{policy-types-DGIO_gxq.d.ts → policy-types-D-GwfQTc.d.ts} +72 -19
- package/dist/{postgrest-DAxFltvO.js → postgrest-BrjrckDG.js} +74 -19
- package/dist/{postgrest-D5nUGm-c.d.ts → postgrest-D84p5dbA.d.ts} +12 -7
- package/dist/{powersync-CBhTBhG2.js → powersync-9PYOE1wt.js} +158 -21
- package/dist/{powersync-DAfo0EL5.js → powersync-DStC_g0B.js} +3 -3
- package/dist/powersync-xNRlC4jN.js +1 -0
- package/dist/preset/index.js +1 -1
- package/dist/{preset-BjLzeFpp.js → preset-pPrVyGU5.js} +74 -7
- package/dist/prisma/index.d.ts +2 -2
- package/dist/prisma/index.js +1 -1
- package/dist/{protected-action-QEA8arRB.js → protected-action-B40tU3yP.js} +15 -5
- package/dist/{protected-action-D8x73IGm.d.ts → protected-action-Ds_EUY8B.d.ts} +14 -7
- package/dist/{protected-action-DUYqb-Ma.js → protected-action-OpOxtTsN.js} +1 -1
- package/dist/{provider-C55OGXJ7.js → provider-CY4TSSJo.js} +2 -2
- package/dist/{provider-DfLeek9O.d.ts → provider-OtnIiFWm.d.ts} +1 -1
- package/dist/{provider-store-CaTv00tr.js → provider-store-BQP_pp8s.js} +2 -2
- package/dist/{pull-CQCGy1gv.js → pull-DLP4I1Kl.js} +7 -7
- package/dist/pull-UBjDnf4b.js +1 -0
- package/dist/{push-Dq_ca4-j.js → push-BSb8j1EW.js} +8 -8
- package/dist/{pushed-policy-CDuOL2de.js → pushed-policy-BecMsTtM.js} +1 -1
- package/dist/{pushed-policy-CryQheKq.d.ts → pushed-policy-Ck3FZcoy.d.ts} +1 -1
- package/dist/react/index.d.ts +8 -8
- package/dist/react/index.js +6 -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 +104 -39
- package/dist/react-native/index.js +199 -40
- package/dist/refresh-on-L9UOwATg.d.ts +49 -0
- package/dist/{replay-Bs9Df2fQ.d.ts → replay-E5X9E1lC.d.ts} +1 -1
- package/dist/{request-context-Duzdf0cd.js → request-context-DM6_jY1n.js} +2 -2
- package/dist/{request-schema-DhX7UbfQ.js → request-schema-CMP8Cmxd.js} +5 -0
- package/dist/resend/index.d.ts +4 -4
- package/dist/{resolve-names-Y1Cb22cp.js → resolve-names-CBl4r4_r.js} +6 -6
- package/dist/{rls-tHu7N_Pe.js → rls-DGBL-jDY.js} +20 -20
- package/dist/{rls-C5ZGzR_B.js → rls-pAHGYgTb.js} +4 -4
- package/dist/{role-builder-BK2-T6oD.js → role-builder-CMW4wWzn.js} +3 -157
- package/dist/{rpc-vHIwyXCp.js → rpc-KwX_Jcxz.js} +2 -2
- package/dist/{run-DUq1xU4K.js → run-B7lv3NuK.js} +8 -40
- package/dist/run-UPbacxPg.js +1 -0
- package/dist/{run-ticket-DfnZCh-u.js → run-ticket-CjvXr6wj.js} +1 -1
- package/dist/{run-ticket-ylovhyFQ.d.ts → run-ticket-DPaD27_r.d.ts} +2 -2
- package/dist/{runtime-BGnrOkVH.js → runtime-rf0ZuyF3.js} +1 -1
- package/dist/{saas-DK4V-3Is.js → saas-B8H1MsQ3.js} +13 -10
- package/dist/{scan-C3HRH9Fs.js → scan-0r3OZqqK.js} +1 -1
- package/dist/{schema-DvXvxPhQ.js → schema-B_9tXrbG.js} +1 -1
- package/dist/{schema-BOJjqlWL.js → schema-CuX70xgH.js} +15 -2
- package/dist/scim/index.d.ts +1 -1
- package/dist/scim/index.js +1 -1
- package/dist/{scim-jJBJ7g1Z.js → scim-C30QBBoF.js} +2 -1
- package/dist/{scim-D8YupzX1.js → scim-CovliQUg.js} +2 -2
- package/dist/{scopes-0Up_UA2t.js → scopes-BSdYaGHs.js} +9 -40
- package/dist/server/index.d.ts +11 -11
- package/dist/server/index.js +8 -8
- package/dist/{server-3cVlTLde.js → server-D0PW6ZCw.js} +2 -2
- package/dist/{server-types-CyRN0-Cd.d.ts → server-types-3OnXjZ2D.d.ts} +8 -8
- package/dist/{shared-l0oGGetg.js → shared-BRmCJxDK.js} +2 -2
- package/dist/{shared-DrGLwM3s.js → shared-DyYVEjKC.js} +2 -2
- package/dist/{sink-B5zoUW_O.d.ts → sink-ogbVkyeo.d.ts} +2 -2
- package/dist/{skills-Celu2W6v.js → skills-B4MPRxQd.js} +2 -2
- package/dist/{skills-B2qTbaQa.js → skills-C9sTD70r.js} +2 -2
- package/dist/{snapshot-CXlzi69u.js → snapshot-DN_8J27z.js} +6 -2
- package/dist/{snapshot-cache-BjAWkchD.d.ts → snapshot-cache-B4YvlGG_.d.ts} +20 -6
- package/dist/{snapshot-cache-Bx_4xC_6.js → snapshot-cache-B66h7FBK.js} +25 -8
- package/dist/solid/index.d.ts +7 -7
- package/dist/solid/index.js +6 -6
- package/dist/solid-start/index.d.ts +4 -4
- package/dist/solid-start/index.js +3 -3
- package/dist/{sources-oB1Hg1Fm.d.ts → sources-xdQShLDU.d.ts} +1 -1
- package/dist/{src-C_pi2Rnh.js → src-Brzq_0in.js} +193 -128
- package/dist/ssf/index.d.ts +3 -3
- package/dist/ssf/index.js +1 -1
- package/dist/{standard-webhooks-DOYEuOLx.d.ts → standard-webhooks-BfPaZ6T1.d.ts} +2 -2
- package/dist/{types-tQB2CEnY.d.ts → store-DYeB-_U3.d.ts} +114 -113
- package/dist/{store-RNFvaJJv.js → store-DmVqy74I.js} +13 -7
- package/dist/{store-options-Dil3lraY.js → store-options--zWn48PK.js} +76 -7
- package/dist/{stores-DxZWDXCs.js → stores-BYFopOm1.js} +3 -3
- package/dist/{stores-DZJvxFIZ.d.ts → stores-EPul_8MN.d.ts} +5 -6
- package/dist/{stream-9y9qw51m.d.ts → stream-W2RuUYly.d.ts} +1 -1
- package/dist/{subject-BGoM5o8B.js → subject-C7RddW0G.js} +8 -1
- package/dist/supabase/client.d.ts +2 -0
- package/dist/supabase/client.js +21 -0
- package/dist/supabase/index.d.ts +37 -6
- package/dist/supabase/index.js +6 -5
- package/dist/supabase/middleware.d.ts +8 -7
- package/dist/supabase/middleware.js +6 -6
- package/dist/{supabase-CDHMsDD0.js → supabase-BiViJpQ4.js} +31 -8
- package/dist/{supabase-DYWnT800.js → supabase-CogTyJH2.js} +3 -3
- package/dist/supabase-hook-BN46IrVI.js +1 -0
- package/dist/{supabase-hook-HPgwYb9V.js → supabase-hook-DX38Hj8h.js} +393 -32
- package/dist/{supautils-SwE642N1.js → supautils-BGf6zRvM.js} +12 -12
- package/dist/svelte/index.d.ts +7 -7
- package/dist/svelte/index.js +8 -8
- package/dist/svelte/runtime.d.ts +3 -3
- package/dist/svelte/runtime.js +3 -3
- package/dist/svelte/source.d.ts +7 -7
- package/dist/svelte/source.js +5 -5
- package/dist/sveltekit/index.d.ts +4 -4
- package/dist/sveltekit/index.js +2 -2
- package/dist/{tables-DimBcVWY.js → tables-BfOk0ymL.js} +7 -7
- package/dist/tanstack-start/index.d.ts +4 -4
- package/dist/tanstack-start/index.js +2 -2
- package/dist/{tenancy-5d1zVBvK.js → tenancy-DvOHHk3-.js} +1 -1
- package/dist/terminal/index.d.ts +5 -5
- package/dist/terminal/index.js +6 -6
- package/dist/testing/core.d.ts +1 -1
- package/dist/testing/core.js +1 -1
- package/dist/testing/fixtures/index.d.ts +1 -1
- package/dist/testing/fixtures/index.js +2 -2
- package/dist/testing/index.d.ts +29 -22
- package/dist/testing/index.js +120 -48
- package/dist/testing/saas/index.d.ts +3 -3
- package/dist/testing/saas/index.js +2 -2
- package/dist/testing/saas/permissions.js +1 -1
- package/dist/token-D6pWn8Uj.d.ts +11 -0
- package/dist/{token-DC9EQiet.js → token-DaMnIU9O.js} +24 -8
- package/dist/{tool-refusal-Qpjs_W6M.js → tool-refusal-D4spOJ7I.js} +1 -1
- package/dist/trpc/index.d.ts +5 -5
- package/dist/trpc/index.js +3 -3
- package/dist/{type-helpers-c7Xo_2Cu.d.ts → type-helpers-i1EJ3Eb1.d.ts} +1 -1
- package/dist/{types-Cklw5hJo.d.ts → types-3Y8UpFkF.d.ts} +40 -1
- package/dist/{types-DlelvQk4.d.ts → types-B8qUkGja.d.ts} +2 -2
- package/dist/{types-CN0LsqbK.d.ts → types-CCEeSCMB.d.ts} +3 -3
- package/dist/{types-B2efzoSX.d.ts → types-CDVXR6YD.d.ts} +1 -1
- package/dist/{types-DsHGPtkR.d.ts → types-Ck1KOfug.d.ts} +2 -2
- package/dist/{types-DLvhVm1r.d.ts → types-CqcsNCaN.d.ts} +16 -7
- package/dist/{types-BB-zWDcR.d.ts → types-D-JO7lh8.d.ts} +5 -5
- package/dist/{types-CEinc15V.d.ts → types-D19MK4t-.d.ts} +3 -4
- package/dist/{types-B6ExllNo.d.ts → types-DGf_cpKF.d.ts} +2 -2
- package/dist/{types-rCRV4Ge-.d.ts → types-DmbfLu2p.d.ts} +4 -4
- package/dist/{types-ZzRGoViD.d.ts → types-NYoj8JBm.d.ts} +2 -2
- package/dist/{types-CWBsAwqn.d.ts → types-o1vu6Ks3.d.ts} +4 -4
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +2 -2
- package/dist/usage-Cl5eb-e1.js +1 -0
- package/dist/{usage-CPXeuAdT.js → usage-DC0UKe6C.js} +6 -6
- package/dist/{usage-CfZCQd0F.js → usage-DYtRVkcN.js} +2 -2
- package/dist/{validation-error-uvp-kyfO.d.ts → validation-error-Dx8PipbO.d.ts} +1 -1
- package/dist/{verify-DfT0QYNh.js → verify-Bpj0hauG.js} +19 -19
- package/dist/{version-cache-Df11C2Qp.d.ts → version-cache-DzNKWiI6.d.ts} +9 -3
- package/dist/{views-CD8wuL4Z.js → views-MWmJ6Y4P.js} +1 -1
- package/dist/vue/index.d.ts +7 -7
- package/dist/vue/index.js +6 -6
- package/dist/{waiter-CqUKX6CY.d.ts → waiter-NK_UuZbb.d.ts} +2 -2
- package/dist/{watch-DAkjm75Y.js → watch-CBHADqBH.js} +3 -3
- package/dist/watch-OYwAPCzx.js +1 -0
- package/dist/webmcp/index.d.ts +1 -1
- package/dist/webmcp/index.js +1 -1
- package/dist/{where-scope-DlCdCM_8.js → where-scope-BKrqUDVk.js} +5 -5
- package/dist/{who-can-BoDJm0Nc.js → who-can-KhVWMxtf.js} +4 -4
- package/dist/workflow/index.d.ts +3 -3
- package/dist/workflow/index.js +5 -4
- package/dist/workflow-sdk/index.d.ts +4 -4
- package/dist/{wrap-DxXB54Wu.d.ts → wrap-BHGA-SMM.d.ts} +2 -2
- package/dist/{wrap-B2wziJI_.js → wrap-C5PWzgkq.js} +1 -1
- package/package.json +8 -5
- package/schemas/approval-request-v1.json +5 -0
- package/schemas/catalog-v1.json +18 -2
- package/schemas/cli-result-v1.json +0 -2
- package/schemas/snapshot-v1.json +9 -0
- package/schemas/supabase-manifest-v1.json +1 -1
- package/skills/permdock-approvals/SKILL.md +8 -8
- package/skills/permdock-approvals/references/stores-and-resume.md +7 -3
- package/skills/permdock-audit/SKILL.md +1 -1
- package/skills/permdock-wire/references/adapters.md +3 -1
- package/dist/action-result-BcudBQOF.d.ts +0 -19
- package/dist/catalog-D3oS2GH3.js +0 -1
- package/dist/collect-D-eroIfV.js +0 -1
- package/dist/load-Dm0pSYH3.js +0 -1
- package/dist/output-files-BHOIlrfD.js +0 -1
- package/dist/powersync-0QVP_DuR.js +0 -1
- package/dist/pull-CCAChKuy.js +0 -1
- package/dist/renames-CGj7YwcQ.js +0 -175
- package/dist/run-C5P3x1EI.js +0 -1
- package/dist/supabase-hook-qsewAVZY.js +0 -1
- package/dist/usage-DmmO_xjJ.js +0 -1
- package/dist/watch-CuPz0D2M.js +0 -1
|
@@ -2,13 +2,13 @@ import { r as isRecord, t as compact } from "./compact-CAf557ZB.js";
|
|
|
2
2
|
import { d as isoNow, i as dateAt, p as nowSeconds, u as isoAt } from "./time-nR1JesoH.js";
|
|
3
3
|
import { t as canonicalJson } from "./canonical-json-DwilZ1iB.js";
|
|
4
4
|
import { s as ApprovalError } from "./types-CcUXciSj.js";
|
|
5
|
-
import { c as decodeApprovalCursor, l as encodeApprovalCursor, s as approvalPageSize, t as applyApprovalVerdict } from "./store-
|
|
6
|
-
import { a as parseCapability } from "./capability-
|
|
5
|
+
import { c as decodeApprovalCursor, l as encodeApprovalCursor, s as approvalPageSize, t as applyApprovalVerdict } from "./store-DmVqy74I.js";
|
|
6
|
+
import { a as parseCapability } from "./capability-zN6T9fxe.js";
|
|
7
7
|
import { t as loadJose } from "./load-jose-DZ4dnjri.js";
|
|
8
|
-
import "./budget-
|
|
8
|
+
import "./budget-BBCPDOGP.js";
|
|
9
9
|
import { a as quoteQualifiedTable, c as quoteSqlTable, d as sqlTextArray, i as qualifySqlTable, o as quoteSqlIdent, s as quoteSqlLiteral } from "./sql-0WjxIp9g.js";
|
|
10
10
|
import { d as keptKeys, l as roleColumn } from "./sources-C4vkzZJV.js";
|
|
11
|
-
import { t as callRpc } from "./postgrest-
|
|
11
|
+
import { t as callRpc } from "./postgrest-BrjrckDG.js";
|
|
12
12
|
//#region src/supabase/capability.ts
|
|
13
13
|
const DEFAULT_TTL = 300;
|
|
14
14
|
const MAX_TTL = 3600;
|
|
@@ -96,8 +96,6 @@ function checkMembership(item, path, issues) {
|
|
|
96
96
|
for (const key of [
|
|
97
97
|
"scope",
|
|
98
98
|
"id",
|
|
99
|
-
"tenant",
|
|
100
|
-
"team",
|
|
101
99
|
"via",
|
|
102
100
|
"granted_by",
|
|
103
101
|
"reason"
|
|
@@ -110,7 +108,7 @@ function checkMembership(item, path, issues) {
|
|
|
110
108
|
optional(item, "entitlements", path, issues, isStrings, "an array of strings");
|
|
111
109
|
optional(item, "keep", path, issues, isStrings, "an array of strings");
|
|
112
110
|
optional(item, "grants", path, issues, isRecord, "an object");
|
|
113
|
-
if (!(own(item, "scope") !== void 0 && own(item, "id") !== void 0 || own(item, "
|
|
111
|
+
if (!(own(item, "scope") !== void 0 && own(item, "id") !== void 0 || own(item, "on") !== void 0)) issue(issues, path, "Expected scope and id, or on");
|
|
114
112
|
}
|
|
115
113
|
function checkPermDockClaims(record, tenantClaim, path, issues) {
|
|
116
114
|
optional(record, "user_role", path, issues, (value) => value === null || typeof value === "string" || isStrings(value), "a string, an array of strings or null");
|
|
@@ -341,6 +339,31 @@ function supabaseApprovalStore(client, options = {}) {
|
|
|
341
339
|
};
|
|
342
340
|
}
|
|
343
341
|
//#endregion
|
|
342
|
+
//#region src/supabase/approval-policies.ts
|
|
343
|
+
function rowsOf$1(result) {
|
|
344
|
+
return Array.isArray(result) ? result : result.rows;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Approval policies from the table `rls.approvals.tenantPolicies` generates:
|
|
348
|
+
* the subject's tenants' enabled rows and every platform floor. A row whose
|
|
349
|
+
* body is not an object throws, and the evaluator checks every entry with
|
|
350
|
+
* `validateApprovalPolicy`, so a bad row denies every call an allow would grant
|
|
351
|
+
* until it is fixed.
|
|
352
|
+
*/
|
|
353
|
+
function tableApprovalPolicySource(options) {
|
|
354
|
+
const fn = quoteQualifiedTable(`${options.schema ?? "permdock"}.permdock_approval_policies_for`);
|
|
355
|
+
return {
|
|
356
|
+
name: "table",
|
|
357
|
+
async approvalPoliciesFor(query) {
|
|
358
|
+
return rowsOf$1(await options.query(`select p.body from ${fn}($1::text[]) p(body)`, [[...query.tenants]])).map((row) => {
|
|
359
|
+
const body = row["body"];
|
|
360
|
+
if (!isRecord(body)) throw new TypeError("PermDock: an approval_policies row has a body that is not an object");
|
|
361
|
+
return body;
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
//#endregion
|
|
344
367
|
//#region src/supabase/approval-delegations.ts
|
|
345
368
|
function rowsOf(result) {
|
|
346
369
|
return Array.isArray(result) ? result : result.rows;
|
|
@@ -697,4 +720,4 @@ grant execute on function ${signature} to authenticated;
|
|
|
697
720
|
`;
|
|
698
721
|
}
|
|
699
722
|
//#endregion
|
|
700
|
-
export {
|
|
723
|
+
export { supabaseApprovalStore as a, tableApprovalPolicySource as i, supabaseRls as n, supabaseClaims as o, tableApprovalDelegationSource as r, exchangeCapability as s, authorizeSql as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as defineLeaf } from "./command-L8EstFNm.js";
|
|
2
|
-
import { c as given, n as dbUrl, o as fileOut, r as dbUrlFlags, t as checkFlag } from "./flags-
|
|
2
|
+
import { c as given, n as dbUrl, o as fileOut, r as dbUrlFlags, t as checkFlag } from "./flags-BlmpmXoY.js";
|
|
3
3
|
//#region src/cli/commands/supabase.ts
|
|
4
4
|
const hookGenerate = defineLeaf({
|
|
5
5
|
flags: {
|
|
@@ -47,7 +47,7 @@ const hookGenerate = defineLeaf({
|
|
|
47
47
|
const budget = given(flags.budget);
|
|
48
48
|
const schema = given(flags.schema);
|
|
49
49
|
const grantsOut = given(flags["grants-out"]);
|
|
50
|
-
const { runSupabase } = await import("./supabase-hook-
|
|
50
|
+
const { runSupabase } = await import("./supabase-hook-BN46IrVI.js");
|
|
51
51
|
return runSupabase({
|
|
52
52
|
cwd: ctx.cwd,
|
|
53
53
|
config: ctx.config,
|
|
@@ -76,7 +76,7 @@ const inspect = defineLeaf({
|
|
|
76
76
|
},
|
|
77
77
|
async run(ctx, { flags }) {
|
|
78
78
|
const out = flags.out === "" ? true : flags.out === "-" ? void 0 : flags.out;
|
|
79
|
-
const { runSupabase } = await import("./supabase-hook-
|
|
79
|
+
const { runSupabase } = await import("./supabase-hook-BN46IrVI.js");
|
|
80
80
|
return runSupabase({
|
|
81
81
|
cwd: ctx.cwd,
|
|
82
82
|
config: ctx.config,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { i as runSupabase } from "./supabase-hook-DX38Hj8h.js";
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
import { r as isRecord } from "./compact-CAf557ZB.js";
|
|
2
2
|
import { o as hasConditionOp } from "./refs-C8BKxc_e.js";
|
|
3
|
-
import {
|
|
4
|
-
import { t as APPROVAL_REQUEST_SCHEMA } from "./request-schema-
|
|
5
|
-
import {
|
|
3
|
+
import { c as rootScope, d as scopeList, l as scopeChain, s as resolveScope } from "./scopes-BSdYaGHs.js";
|
|
4
|
+
import { t as APPROVAL_REQUEST_SCHEMA } from "./request-schema-CMP8Cmxd.js";
|
|
5
|
+
import { t as AUTHZ_EVENT } from "./authz-topic-Dbc-HDOS.js";
|
|
6
|
+
import { a as describeError, i as configError } from "./errors-BhRkoNS7.js";
|
|
6
7
|
import { i as readJsonFile, o as sqlFiles, s as writeFileEnsuringDir } from "./files-BSjrtIHw.js";
|
|
7
8
|
import { a as SUPABASE_MANIFEST_SCHEMA } from "./version-DMQ0dnN5.js";
|
|
8
|
-
import { c as requirePolicy } from "./load-
|
|
9
|
-
import "./budget-
|
|
9
|
+
import { c as requirePolicy } from "./load-BaEamml-.js";
|
|
10
|
+
import "./budget-BBCPDOGP.js";
|
|
10
11
|
import { i as qualifySqlTable } from "./sql-0WjxIp9g.js";
|
|
11
|
-
import { i as scopeColumn } from "./compile-
|
|
12
|
-
import { t as authorizeSql } from "./supabase-
|
|
12
|
+
import { i as scopeColumn } from "./compile-B_oJqmIg.js";
|
|
13
|
+
import { t as authorizeSql } from "./supabase-BiViJpQ4.js";
|
|
13
14
|
import { a as hookApiNames, d as keptKeys, t as AUTHZ_VERSION_TABLE, u as roleManifest } from "./sources-C4vkzZJV.js";
|
|
14
|
-
import { o as readMemberships } from "./postgrest-
|
|
15
|
+
import { o as readMemberships } from "./postgrest-BrjrckDG.js";
|
|
15
16
|
import { t as beforeFirst } from "./text-BMFRfBqc.js";
|
|
16
17
|
import { n as GRANTS_MARKER, r as HOOK_MARKER, s as hookMarkerFields } from "./markers-BeHZ4x9Q.js";
|
|
17
18
|
import { n as formatManifestJson, t as MANIFEST_FILE } from "./manifest-json-CAGzls-C.js";
|
|
18
19
|
import { n as MIGRATION_DIRS } from "./constants-DcJABbLW.js";
|
|
19
|
-
import { f as writeOutputFiles, l as partPath, r as driftOf, u as pgDeltaPath } from "./output-files-
|
|
20
|
-
import { A as quoteQualified, D as qualified, F as firstScopeType, I as scopeTypeOf, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, l as USER_ID_HELPER, r as HELPERS, y as subjectIdSql } from "./shared-
|
|
21
|
-
import { E as TOKEN_SCOPE_ALLOWS, J as apiKeyFields, K as API_KEY_ALLOWS, R as globalRoleSource, _ as PERMISSION_HELPERS, at as memberForHelper, b as permissionKeysForHelper, bt as checkSuspension, ct as memberIdsHelper, dt as permittedForHelper, et as hasMemberFor, ft as permittedIdsHelper, g as OWNERSHIP, h as ASSIGNMENTS, lt as memberOfHelper, ot as memberForSources, rt as isTeamScope, st as memberForTable, tt as hasPermittedUsers, ut as memberRoleOf, v as checkName, vt as activeRowSql, x as permittedByPermissionHelper } from "./tables-
|
|
22
|
-
import { a as guardedTables, t as ownershipRules, u as roleNames } from "./ownership-
|
|
20
|
+
import { f as writeOutputFiles, l as partPath, r as driftOf, u as pgDeltaPath } from "./output-files-CM0BnH05.js";
|
|
21
|
+
import { A as quoteQualified, D as qualified, F as firstScopeType, I as scopeTypeOf, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, l as USER_ID_HELPER, r as HELPERS, y as subjectIdSql } from "./shared-DyYVEjKC.js";
|
|
22
|
+
import { E as TOKEN_SCOPE_ALLOWS, J as apiKeyFields, K as API_KEY_ALLOWS, R as globalRoleSource, _ as PERMISSION_HELPERS, at as memberForHelper, b as permissionKeysForHelper, bt as checkSuspension, ct as memberIdsHelper, dt as permittedForHelper, et as hasMemberFor, ft as permittedIdsHelper, g as OWNERSHIP, h as ASSIGNMENTS, lt as memberOfHelper, ot as memberForSources, rt as isTeamScope, st as memberForTable, tt as hasPermittedUsers, ut as memberRoleOf, v as checkName, vt as activeRowSql, x as permittedByPermissionHelper } from "./tables-BfOk0ymL.js";
|
|
23
|
+
import { a as guardedTables, t as ownershipRules, u as roleNames } from "./ownership-D-mIt-w0.js";
|
|
23
24
|
import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
|
|
24
25
|
import { a as splitUndiffed, r as tableKey, t as decidingColumns } from "./deciding-columns-NB4wcyBf.js";
|
|
25
|
-
import { n as pgConnector } from "./pg-
|
|
26
|
-
import { c as ACTOR_MAY_WRITE, f as readOnlyActorKinds } from "./fields-
|
|
27
|
-
import { r as permittedUsersHelper, t as resolveNames } from "./resolve-names-
|
|
26
|
+
import { n as pgConnector } from "./pg-Ddxsd5ZB.js";
|
|
27
|
+
import { c as ACTOR_MAY_WRITE, f as readOnlyActorKinds } from "./fields-CrjL6A49.js";
|
|
28
|
+
import { r as permittedUsersHelper, t as resolveNames } from "./resolve-names-CBl4r4_r.js";
|
|
28
29
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
29
30
|
import { dirname, join, posix, resolve } from "node:path";
|
|
30
31
|
//#region ../../node_modules/.pnpm/smol-toml@1.9.1/node_modules/smol-toml/dist/error.js
|
|
@@ -1885,6 +1886,246 @@ function customRolesOfSql(parts) {
|
|
|
1885
1886
|
);`;
|
|
1886
1887
|
}
|
|
1887
1888
|
//#endregion
|
|
1889
|
+
//#region src/cli/rls/approval-managers.ts
|
|
1890
|
+
/** Whether the signed-in user manages a requester; better-supabase reads it. */
|
|
1891
|
+
const MANAGES = "permdock_manages";
|
|
1892
|
+
/**
|
|
1893
|
+
* The approver check with `manager` leaves; only `permdock_is_approver` calls
|
|
1894
|
+
* it.
|
|
1895
|
+
*/
|
|
1896
|
+
const APPROVES = "permdock_approves";
|
|
1897
|
+
const MANAGES_FOR = "permdock_manages_for";
|
|
1898
|
+
function named(value) {
|
|
1899
|
+
return typeof value === "string" && value !== "";
|
|
1900
|
+
}
|
|
1901
|
+
function checked(managers) {
|
|
1902
|
+
if (typeof managers !== "object" || managers === null || !("table" in managers && named(managers.table)) || !("user" in managers && named(managers.user)) || !("manager" in managers && named(managers.manager))) throw configError("PermDock CLI: rls.approvals.managers needs { table, user, manager }: the table that names each user's manager, its user column and its manager column");
|
|
1903
|
+
return {
|
|
1904
|
+
table: managers.table,
|
|
1905
|
+
user: managers.user,
|
|
1906
|
+
manager: managers.manager
|
|
1907
|
+
};
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* `rls.approvals.managers`: `permdock_manages(p_requester, p_levels)` walks the
|
|
1911
|
+
* app's manager table up to `levels` steps (at most `MAX_MANAGER_LEVELS`) with
|
|
1912
|
+
* a cycle guard, and `permdock_approves` decides `manager` leaves with it and
|
|
1913
|
+
* every other leaf through the two-argument `permdock_is_approver`. The
|
|
1914
|
+
* requester never manages themselves into an approval. Without `delegations`,
|
|
1915
|
+
* the four-argument `permdock_is_approver` is written here; with them,
|
|
1916
|
+
* `approvalDelegationsSql` writes it and calls `permdock_approves` first.
|
|
1917
|
+
*/
|
|
1918
|
+
function approvalManagersSql(ctx, given, isApprover, delegations) {
|
|
1919
|
+
const managers = checked(given);
|
|
1920
|
+
const table = quoteQualified(managers.table);
|
|
1921
|
+
const user = quoteIdent(managers.user);
|
|
1922
|
+
const boss = quoteIdent(managers.manager);
|
|
1923
|
+
const manages = qualified(ctx, MANAGES);
|
|
1924
|
+
const managesFor = qualified(ctx, MANAGES_FOR);
|
|
1925
|
+
const approves = qualified(ctx, APPROVES);
|
|
1926
|
+
const me = `${subjectIdSql(ctx)}::text`;
|
|
1927
|
+
const entry = delegations ? "" : `
|
|
1928
|
+
-- approvers with managers: permdock_approves for the signed-in user
|
|
1929
|
+
create or replace function ${isApprover}(p_approvers jsonb, p_tenant text, p_requester text, p_resource text)
|
|
1930
|
+
returns boolean
|
|
1931
|
+
language sql
|
|
1932
|
+
stable
|
|
1933
|
+
security definer
|
|
1934
|
+
set search_path = ''
|
|
1935
|
+
as $$
|
|
1936
|
+
select ${approves}(p_approvers, p_tenant, p_requester)
|
|
1937
|
+
$$;
|
|
1938
|
+
revoke execute on function ${isApprover}(jsonb, text, text, text) from public, anon;
|
|
1939
|
+
grant execute on function ${isApprover}(jsonb, text, text, text) to authenticated;
|
|
1940
|
+
`;
|
|
1941
|
+
return `
|
|
1942
|
+
-- approval managers: whether p_user manages p_requester within p_levels steps of ${managers.table}
|
|
1943
|
+
create or replace function ${managesFor}(p_user text, p_requester text, p_levels integer)
|
|
1944
|
+
returns boolean
|
|
1945
|
+
language sql
|
|
1946
|
+
stable
|
|
1947
|
+
security definer
|
|
1948
|
+
set search_path = ''
|
|
1949
|
+
as $$
|
|
1950
|
+
with recursive chain (id, depth, path) as (
|
|
1951
|
+
select m.${boss}::text, 1, array[p_requester, m.${boss}::text]
|
|
1952
|
+
from ${table} m
|
|
1953
|
+
where m.${user}::text = p_requester
|
|
1954
|
+
and m.${boss} is not null
|
|
1955
|
+
union all
|
|
1956
|
+
select m.${boss}::text, c.depth + 1, c.path || m.${boss}::text
|
|
1957
|
+
from chain c
|
|
1958
|
+
join ${table} m on m.${user}::text = c.id
|
|
1959
|
+
where c.depth < least(p_levels, ${String(8)})
|
|
1960
|
+
and m.${boss} is not null
|
|
1961
|
+
and not (m.${boss}::text = any (c.path))
|
|
1962
|
+
)
|
|
1963
|
+
select coalesce(
|
|
1964
|
+
p_requester <> ''
|
|
1965
|
+
and p_user <> ''
|
|
1966
|
+
and p_levels between 1 and ${String(8)}
|
|
1967
|
+
and p_user <> p_requester
|
|
1968
|
+
and exists (select 1 from chain c where c.id = p_user),
|
|
1969
|
+
false
|
|
1970
|
+
)
|
|
1971
|
+
$$;
|
|
1972
|
+
revoke execute on function ${managesFor}(text, text, integer) from public, anon, authenticated;
|
|
1973
|
+
|
|
1974
|
+
-- approval managers: whether the signed-in user manages p_requester within p_levels steps of ${managers.table}
|
|
1975
|
+
create or replace function ${manages}(p_requester text, p_levels integer)
|
|
1976
|
+
returns boolean
|
|
1977
|
+
language sql
|
|
1978
|
+
stable
|
|
1979
|
+
security definer
|
|
1980
|
+
set search_path = ''
|
|
1981
|
+
as $$
|
|
1982
|
+
select ${managesFor}(${me}, p_requester, p_levels)
|
|
1983
|
+
$$;
|
|
1984
|
+
revoke execute on function ${manages}(text, integer) from public, anon, authenticated;
|
|
1985
|
+
|
|
1986
|
+
-- approval managers: approvers.by with manager leaves; only permdock_is_approver calls it
|
|
1987
|
+
create or replace function ${approves}(p_approvers jsonb, p_tenant text, p_requester text)
|
|
1988
|
+
returns boolean
|
|
1989
|
+
language plpgsql
|
|
1990
|
+
stable
|
|
1991
|
+
security definer
|
|
1992
|
+
set search_path = ''
|
|
1993
|
+
as $$
|
|
1994
|
+
declare
|
|
1995
|
+
v_item jsonb;
|
|
1996
|
+
v_levels jsonb;
|
|
1997
|
+
begin
|
|
1998
|
+
if p_approvers is null then
|
|
1999
|
+
return false;
|
|
2000
|
+
end if;
|
|
2001
|
+
if jsonb_typeof(p_approvers) = 'array' then
|
|
2002
|
+
if jsonb_array_length(p_approvers) = 0 then
|
|
2003
|
+
return false;
|
|
2004
|
+
end if;
|
|
2005
|
+
for v_item in select value from jsonb_array_elements(p_approvers) loop
|
|
2006
|
+
if not ${approves}(v_item, p_tenant, p_requester) then
|
|
2007
|
+
return false;
|
|
2008
|
+
end if;
|
|
2009
|
+
end loop;
|
|
2010
|
+
return true;
|
|
2011
|
+
end if;
|
|
2012
|
+
if jsonb_typeof(p_approvers) <> 'object' then
|
|
2013
|
+
return false;
|
|
2014
|
+
end if;
|
|
2015
|
+
case p_approvers ->> 'kind'
|
|
2016
|
+
when 'manager' then
|
|
2017
|
+
v_levels := coalesce(p_approvers -> 'levels', '1'::jsonb);
|
|
2018
|
+
if jsonb_typeof(v_levels) <> 'number' or v_levels::text !~ '^[0-9]{1,2}$' then
|
|
2019
|
+
return false;
|
|
2020
|
+
end if;
|
|
2021
|
+
return coalesce(${manages}(p_requester, v_levels::text::integer), false);
|
|
2022
|
+
when 'any-of' then
|
|
2023
|
+
if jsonb_typeof(p_approvers -> 'of') <> 'array' then
|
|
2024
|
+
return false;
|
|
2025
|
+
end if;
|
|
2026
|
+
for v_item in select value from jsonb_array_elements(p_approvers -> 'of') loop
|
|
2027
|
+
if ${approves}(v_item, p_tenant, p_requester) then
|
|
2028
|
+
return true;
|
|
2029
|
+
end if;
|
|
2030
|
+
end loop;
|
|
2031
|
+
return false;
|
|
2032
|
+
else
|
|
2033
|
+
return ${isApprover}(p_approvers, p_tenant);
|
|
2034
|
+
end case;
|
|
2035
|
+
end;
|
|
2036
|
+
$$;
|
|
2037
|
+
revoke execute on function ${approves}(jsonb, text, text) from public, anon, authenticated;
|
|
2038
|
+
${entry}`;
|
|
2039
|
+
}
|
|
2040
|
+
//#endregion
|
|
2041
|
+
//#region src/cli/rls/approval-policies.ts
|
|
2042
|
+
/**
|
|
2043
|
+
* The objects `rls.approvals.tenantPolicies` adds; `tableApprovalPolicySource`
|
|
2044
|
+
* calls the function.
|
|
2045
|
+
*/
|
|
2046
|
+
const APPROVAL_POLICIES = {
|
|
2047
|
+
table: "approval_policies",
|
|
2048
|
+
read: "permdock_approval_policies_for"
|
|
2049
|
+
};
|
|
2050
|
+
const KEY = /^[A-Za-z][\w-]*(?:\.[A-Za-z][\w-]*)+$/u;
|
|
2051
|
+
/**
|
|
2052
|
+
* `rls.approvals.tenantPolicies`: one table of `ApprovalPolicy` bodies, a
|
|
2053
|
+
* tenant row per requirement a tenant adds and platform floors with `tenant`
|
|
2054
|
+
* null. Members read their tenants' rows and the floors; a holder of `manage`
|
|
2055
|
+
* in a tenant writes that tenant's rows; nobody but the owner writes a floor.
|
|
2056
|
+
* `permdock_approval_policies_for(p_tenants)` answers the enabled bodies with
|
|
2057
|
+
* the row's tenant set, floors first, and only the owner may execute it, since
|
|
2058
|
+
* it reads every tenant.
|
|
2059
|
+
*/
|
|
2060
|
+
function approvalPoliciesSql(ctx, options, actorMayWrite = false) {
|
|
2061
|
+
if (options === null || typeof options !== "object" || !("manage" in options) || typeof options.manage !== "string" || !KEY.test(options.manage)) throw configError("PermDock CLI: rls.approvals.tenantPolicies needs { manage: '<permission key>' }, the permission whose holders in a tenant edit its approval policies");
|
|
2062
|
+
const root = ctx.scopes[0]?.name;
|
|
2063
|
+
if (root === void 0) throw configError("PermDock CLI: rls.approvals.tenantPolicies needs a tenant scope; declare one in the policy's scopes");
|
|
2064
|
+
const table = qualified(ctx, APPROVAL_POLICIES.table);
|
|
2065
|
+
const fn = qualified(ctx, APPROVAL_POLICIES.read);
|
|
2066
|
+
const member = `tenant in (select m.id::text from ${qualified(ctx, memberIdsHelper(root))}() m(id))`;
|
|
2067
|
+
const manages = `exists (
|
|
2068
|
+
select 1
|
|
2069
|
+
from ${qualified(ctx, checkName(permittedByPermissionHelper(root)))}(${quoteLiteral(options.manage)}) i(id)
|
|
2070
|
+
where i.id::text = tenant
|
|
2071
|
+
)`;
|
|
2072
|
+
const writable = actorMayWrite ? ` and (select ${qualified(ctx, ACTOR_MAY_WRITE)}())` : "";
|
|
2073
|
+
const own = `tenant is not null and ${subjectIdSql(ctx)} is not null and ${manages}${writable}`;
|
|
2074
|
+
const policy = (name) => quoteIdent(`${APPROVAL_POLICIES.table}_${name}`);
|
|
2075
|
+
return `
|
|
2076
|
+
-- approval policies: requirements a tenant keeps as data, plus platform floors (tenant null); tableApprovalPolicySource reads them
|
|
2077
|
+
create table if not exists ${table} (
|
|
2078
|
+
id text primary key default gen_random_uuid()::text,
|
|
2079
|
+
tenant text,
|
|
2080
|
+
name text not null,
|
|
2081
|
+
body jsonb not null,
|
|
2082
|
+
enabled boolean not null default true,
|
|
2083
|
+
created_at timestamptz not null default now(),
|
|
2084
|
+
updated_at timestamptz not null default now(),
|
|
2085
|
+
constraint ${quoteIdent(`${APPROVAL_POLICIES.table}_body`)} check (jsonb_typeof(body) = 'object' and body ? 'approval')
|
|
2086
|
+
);
|
|
2087
|
+
create index if not exists ${quoteIdent(`${APPROVAL_POLICIES.table}_tenant`)} on ${table} (tenant);
|
|
2088
|
+
alter table ${table} enable row level security;
|
|
2089
|
+
revoke all on table ${table} from anon, public;
|
|
2090
|
+
grant select, insert, update, delete on table ${table} to authenticated;
|
|
2091
|
+
drop policy if exists ${policy("read")} on ${table};
|
|
2092
|
+
create policy ${policy("read")} on ${table}
|
|
2093
|
+
for select to authenticated
|
|
2094
|
+
using (tenant is null or ${member});
|
|
2095
|
+
drop policy if exists ${policy("insert")} on ${table};
|
|
2096
|
+
create policy ${policy("insert")} on ${table}
|
|
2097
|
+
for insert to authenticated
|
|
2098
|
+
with check (${own});
|
|
2099
|
+
drop policy if exists ${policy("update")} on ${table};
|
|
2100
|
+
create policy ${policy("update")} on ${table}
|
|
2101
|
+
for update to authenticated
|
|
2102
|
+
using (${own})
|
|
2103
|
+
with check (${own});
|
|
2104
|
+
drop policy if exists ${policy("delete")} on ${table};
|
|
2105
|
+
create policy ${policy("delete")} on ${table}
|
|
2106
|
+
for delete to authenticated
|
|
2107
|
+
using (${own});
|
|
2108
|
+
|
|
2109
|
+
-- approval policies: the enabled bodies for p_tenants and every floor, with the row's tenant; only the owner executes it
|
|
2110
|
+
create or replace function ${fn}(p_tenants text[])
|
|
2111
|
+
returns setof jsonb
|
|
2112
|
+
language sql
|
|
2113
|
+
stable
|
|
2114
|
+
set search_path = ''
|
|
2115
|
+
as $$
|
|
2116
|
+
select case
|
|
2117
|
+
when p.tenant is null then p.body - 'tenant'
|
|
2118
|
+
else p.body || jsonb_build_object('tenant', p.tenant)
|
|
2119
|
+
end
|
|
2120
|
+
from ${table} p
|
|
2121
|
+
where p.enabled
|
|
2122
|
+
and (p.tenant is null or p.tenant = any(coalesce(p_tenants, '{}')))
|
|
2123
|
+
order by p.tenant nulls first, p.created_at, p.id;
|
|
2124
|
+
$$;
|
|
2125
|
+
revoke execute on function ${fn}(text[]) from public, anon, authenticated;
|
|
2126
|
+
`;
|
|
2127
|
+
}
|
|
2128
|
+
//#endregion
|
|
1888
2129
|
//#region src/cli/rls/approvals.ts
|
|
1889
2130
|
/**
|
|
1890
2131
|
* `rls.approvals`' approver check; better-supabase's `isApprover` template
|
|
@@ -2188,17 +2429,30 @@ grant execute on function ${fn}(jsonb, text) to authenticated;
|
|
|
2188
2429
|
}
|
|
2189
2430
|
/**
|
|
2190
2431
|
* Everything `rls.approvals` writes: the generated or adopted store, the
|
|
2191
|
-
* approver check
|
|
2432
|
+
* approver check, with `managers` the manager walk, with `delegations: true`
|
|
2433
|
+
* the covers, and with `tenantPolicies` the tenant approval policies. With
|
|
2192
2434
|
* `actorMayWrite`, the covers' write policies call
|
|
2193
2435
|
* `permdock_actor_may_write()`.
|
|
2194
2436
|
*/
|
|
2195
2437
|
function approvalsSql(ctx, approvals, jsonSchema, actorMayWrite = false) {
|
|
2196
2438
|
if (approvals === void 0 || approvals === false) return;
|
|
2197
2439
|
if (approvals === true) return approvalStoreSql(ctx, jsonSchema) + isApproverSql(ctx);
|
|
2198
|
-
const { table, delegations } = approvals;
|
|
2440
|
+
const { table, delegations, tenantPolicies, managers } = approvals;
|
|
2199
2441
|
if (delegations !== void 0 && typeof delegations !== "boolean") throw new TypeError("PermDock CLI: rls.approvals.delegations must be a boolean");
|
|
2442
|
+
if (approvals.store !== void 0 && typeof approvals.store !== "boolean") throw new TypeError("PermDock CLI: rls.approvals.store must be a boolean");
|
|
2200
2443
|
let store;
|
|
2201
|
-
if (
|
|
2444
|
+
if (approvals.store === false) {
|
|
2445
|
+
const adopted = [
|
|
2446
|
+
"table",
|
|
2447
|
+
"token",
|
|
2448
|
+
"body",
|
|
2449
|
+
"open",
|
|
2450
|
+
"schema",
|
|
2451
|
+
"mirror"
|
|
2452
|
+
].find((key) => approvals[key] !== void 0);
|
|
2453
|
+
if (adopted !== void 0) throw configError(`PermDock CLI: rls.approvals.${adopted} configures the approval store, which rls.approvals.store: false leaves out`);
|
|
2454
|
+
store = "";
|
|
2455
|
+
} else if (table === void 0) {
|
|
2202
2456
|
const adoptOnly = [
|
|
2203
2457
|
"token",
|
|
2204
2458
|
"body",
|
|
@@ -2212,7 +2466,7 @@ function approvalsSql(ctx, approvals, jsonSchema, actorMayWrite = false) {
|
|
|
2212
2466
|
...approvals,
|
|
2213
2467
|
table
|
|
2214
2468
|
}, jsonSchema);
|
|
2215
|
-
return store + isApproverSql(ctx) + (delegations === true ? approvalDelegationsSql(ctx, actorMayWrite) : "");
|
|
2469
|
+
return store + isApproverSql(ctx) + (managers === void 0 ? "" : approvalManagersSql(ctx, managers, qualified(ctx, APPROVAL_STORE.isApprover), delegations === true)) + (delegations === true ? approvalDelegationsSql(ctx, actorMayWrite, managers !== void 0) : "") + (delegations === true || managers !== void 0 ? requestApproversSql(ctx) : "") + (tenantPolicies === void 0 ? "" : approvalPoliciesSql(ctx, tenantPolicies, actorMayWrite));
|
|
2216
2470
|
}
|
|
2217
2471
|
/**
|
|
2218
2472
|
* The objects `rls.approvals.delegations` adds; `tableApprovalDelegationSource`
|
|
@@ -2225,13 +2479,15 @@ const DELEGATIONS = {
|
|
|
2225
2479
|
/**
|
|
2226
2480
|
* `rls.approvals.delegations`: one table of out-of-office covers that a user
|
|
2227
2481
|
* writes for themselves, and a four-argument `permdock_is_approver` that also
|
|
2228
|
-
* answers for a delegate inside an active cover.
|
|
2482
|
+
* answers for a delegate inside an active cover. With `managers`, the signed-in
|
|
2483
|
+
* user's own check is `permdock_approves`, and a cover passes on a `manager`
|
|
2484
|
+
* leaf when the delegator manages the requester. One hop: a cover is checked
|
|
2229
2485
|
* against the delegator's own approver rights, never the delegator's covers. A
|
|
2230
2486
|
* delegator who is the requester never counts. A `holder()` approver through a
|
|
2231
2487
|
* cover needs `rls.mode: "database"`, where the `_for` helpers exist; in `jwt`
|
|
2232
2488
|
* mode only `user()` approvers pass.
|
|
2233
2489
|
*/
|
|
2234
|
-
function approvalDelegationsSql(ctx, actorMayWrite = false) {
|
|
2490
|
+
function approvalDelegationsSql(ctx, actorMayWrite = false, managers = false) {
|
|
2235
2491
|
const table = qualified(ctx, DELEGATIONS.table);
|
|
2236
2492
|
const fn = qualified(ctx, APPROVAL_STORE.isApprover);
|
|
2237
2493
|
const covers = qualified(ctx, DELEGATIONS.covers);
|
|
@@ -2248,7 +2504,15 @@ function approvalDelegationsSql(ctx, actorMayWrite = false) {
|
|
|
2248
2504
|
where i.id::text = p_tenant
|
|
2249
2505
|
)` : "false";
|
|
2250
2506
|
const policy = (name) => quoteIdent(`${DELEGATIONS.table}_${name}`);
|
|
2251
|
-
const
|
|
2507
|
+
const writable = actorMayWrite ? ` and (select ${qualified(ctx, ACTOR_MAY_WRITE)}())` : "";
|
|
2508
|
+
const managerCase = managers ? `
|
|
2509
|
+
when 'manager' then
|
|
2510
|
+
v_levels := coalesce(p_approvers -> 'levels', '1'::jsonb);
|
|
2511
|
+
if jsonb_typeof(v_levels) <> 'number' or v_levels::text !~ '^[0-9]{1,2}$' then
|
|
2512
|
+
return false;
|
|
2513
|
+
end if;
|
|
2514
|
+
return coalesce(${qualified(ctx, MANAGES_FOR)}(p_delegator::text, p_requester, v_levels::text::integer), false);` : "";
|
|
2515
|
+
const mine = `delegator::text = ${me}${writable}`;
|
|
2252
2516
|
const own = `${mine} and (tenant is null or ${member("tenant")})`;
|
|
2253
2517
|
return `
|
|
2254
2518
|
-- approval delegations: out-of-office covers a user writes for themselves; tableApprovalDelegationSource and permdock_is_approver read them
|
|
@@ -2288,7 +2552,7 @@ create policy ${policy("delete")} on ${table}
|
|
|
2288
2552
|
using (${mine});
|
|
2289
2553
|
|
|
2290
2554
|
-- approval delegations: whether a delegator's own rights match approvers.by; only permdock_is_approver calls it
|
|
2291
|
-
create or replace function ${covers}(p_delegator ${user}, p_approvers jsonb, p_tenant text)
|
|
2555
|
+
create or replace function ${covers}(p_delegator ${user}, p_approvers jsonb, p_tenant text, p_requester text)
|
|
2292
2556
|
returns boolean
|
|
2293
2557
|
language plpgsql
|
|
2294
2558
|
stable
|
|
@@ -2296,7 +2560,7 @@ security definer
|
|
|
2296
2560
|
set search_path = ''
|
|
2297
2561
|
as $$
|
|
2298
2562
|
declare
|
|
2299
|
-
v_item jsonb;
|
|
2563
|
+
v_item jsonb;${managers ? "\n v_levels jsonb;" : ""}
|
|
2300
2564
|
begin
|
|
2301
2565
|
if p_delegator is null or p_approvers is null then
|
|
2302
2566
|
return false;
|
|
@@ -2306,7 +2570,7 @@ begin
|
|
|
2306
2570
|
return false;
|
|
2307
2571
|
end if;
|
|
2308
2572
|
for v_item in select value from jsonb_array_elements(p_approvers) loop
|
|
2309
|
-
if not ${covers}(p_delegator, v_item, p_tenant) then
|
|
2573
|
+
if not ${covers}(p_delegator, v_item, p_tenant, p_requester) then
|
|
2310
2574
|
return false;
|
|
2311
2575
|
end if;
|
|
2312
2576
|
end loop;
|
|
@@ -2322,13 +2586,13 @@ begin
|
|
|
2322
2586
|
if p_tenant is null then
|
|
2323
2587
|
return ${holderGlobal};
|
|
2324
2588
|
end if;
|
|
2325
|
-
return ${holderTenant}
|
|
2589
|
+
return ${holderTenant};${managerCase}
|
|
2326
2590
|
when 'any-of' then
|
|
2327
2591
|
if jsonb_typeof(p_approvers -> 'of') <> 'array' then
|
|
2328
2592
|
return false;
|
|
2329
2593
|
end if;
|
|
2330
2594
|
for v_item in select value from jsonb_array_elements(p_approvers -> 'of') loop
|
|
2331
|
-
if ${covers}(p_delegator, v_item, p_tenant) then
|
|
2595
|
+
if ${covers}(p_delegator, v_item, p_tenant, p_requester) then
|
|
2332
2596
|
return true;
|
|
2333
2597
|
end if;
|
|
2334
2598
|
end loop;
|
|
@@ -2338,7 +2602,7 @@ begin
|
|
|
2338
2602
|
end case;
|
|
2339
2603
|
end;
|
|
2340
2604
|
$$;
|
|
2341
|
-
revoke execute on function ${covers}(${user}, jsonb, text) from public, anon, authenticated;
|
|
2605
|
+
revoke execute on function ${covers}(${user}, jsonb, text, text) from public, anon, authenticated;
|
|
2342
2606
|
|
|
2343
2607
|
-- approvers with covers: the signed-in user, or a delegate inside an active cover of a delegator who is not the requester
|
|
2344
2608
|
create or replace function ${fn}(p_approvers jsonb, p_tenant text, p_requester text, p_resource text)
|
|
@@ -2352,7 +2616,7 @@ declare
|
|
|
2352
2616
|
v_delegator ${user};
|
|
2353
2617
|
v_user text := ${me};
|
|
2354
2618
|
begin
|
|
2355
|
-
if ${fn}(p_approvers, p_tenant) then
|
|
2619
|
+
if ${managers ? `${qualified(ctx, APPROVES)}(p_approvers, p_tenant, p_requester)` : `${fn}(p_approvers, p_tenant)`} then
|
|
2356
2620
|
return true;
|
|
2357
2621
|
end if;
|
|
2358
2622
|
if coalesce(v_user, '') = '' or coalesce(p_requester, '') = '' then
|
|
@@ -2373,7 +2637,7 @@ begin
|
|
|
2373
2637
|
and d.permissions is null
|
|
2374
2638
|
and (d.resources is null or p_resource = any (d.resources))
|
|
2375
2639
|
loop
|
|
2376
|
-
if ${covers}(v_delegator, p_approvers, p_tenant) then
|
|
2640
|
+
if ${covers}(v_delegator, p_approvers, p_tenant, p_requester) then
|
|
2377
2641
|
return true;
|
|
2378
2642
|
end if;
|
|
2379
2643
|
end loop;
|
|
@@ -2384,6 +2648,45 @@ revoke execute on function ${fn}(jsonb, text, text, text) from public, anon;
|
|
|
2384
2648
|
grant execute on function ${fn}(jsonb, text, text, text) to authenticated;
|
|
2385
2649
|
`;
|
|
2386
2650
|
}
|
|
2651
|
+
function requestApproversSql(ctx) {
|
|
2652
|
+
const fn = qualified(ctx, APPROVAL_STORE.isApprover);
|
|
2653
|
+
return `
|
|
2654
|
+
-- approvers with the current step: the four-argument check over p_approvers and the step's users, manager and permission
|
|
2655
|
+
create or replace function ${fn}(p_approvers jsonb, p_tenant text, p_requester text, p_resource text, p_request_approvers jsonb)
|
|
2656
|
+
returns boolean
|
|
2657
|
+
language sql
|
|
2658
|
+
stable
|
|
2659
|
+
security definer
|
|
2660
|
+
set search_path = ''
|
|
2661
|
+
as $$
|
|
2662
|
+
select ${fn}(
|
|
2663
|
+
jsonb_build_object(
|
|
2664
|
+
'kind', 'any-of',
|
|
2665
|
+
'of',
|
|
2666
|
+
case when p_approvers is null then '[]'::jsonb else jsonb_build_array(p_approvers) end
|
|
2667
|
+
|| case
|
|
2668
|
+
when jsonb_typeof(p_request_approvers -> 'users') = 'array' then coalesce(
|
|
2669
|
+
(select jsonb_agg(jsonb_build_object('kind', 'user', 'id', u.id)) from jsonb_array_elements_text(p_request_approvers -> 'users') u(id)),
|
|
2670
|
+
'[]'::jsonb
|
|
2671
|
+
)
|
|
2672
|
+
else '[]'::jsonb
|
|
2673
|
+
end
|
|
2674
|
+
|| case when p_request_approvers -> 'manager' = 'true'::jsonb then '[{"kind": "manager"}]'::jsonb else '[]'::jsonb end
|
|
2675
|
+
|| case
|
|
2676
|
+
when jsonb_typeof(p_request_approvers -> 'permission') = 'string'
|
|
2677
|
+
then jsonb_build_array(jsonb_build_object('kind', 'permission', 'permission', p_request_approvers ->> 'permission'))
|
|
2678
|
+
else '[]'::jsonb
|
|
2679
|
+
end
|
|
2680
|
+
),
|
|
2681
|
+
p_tenant,
|
|
2682
|
+
p_requester,
|
|
2683
|
+
p_resource
|
|
2684
|
+
)
|
|
2685
|
+
$$;
|
|
2686
|
+
revoke execute on function ${fn}(jsonb, text, text, text, jsonb) from public, anon;
|
|
2687
|
+
grant execute on function ${fn}(jsonb, text, text, text, jsonb) to authenticated;
|
|
2688
|
+
`;
|
|
2689
|
+
}
|
|
2387
2690
|
/**
|
|
2388
2691
|
* The request fields an adopted table may mirror into its own columns, as SQL
|
|
2389
2692
|
* over a body.
|
|
@@ -2847,6 +3150,10 @@ function hookParts(scopes, config, overrides) {
|
|
|
2847
3150
|
sources: hook.memberships,
|
|
2848
3151
|
budget: positiveInteger(overrides.budget ?? hook.budget ?? 1024, "budget"),
|
|
2849
3152
|
version: hook.version !== false,
|
|
3153
|
+
broadcast: hook.version === false || hook.broadcast === false ? void 0 : {
|
|
3154
|
+
topic: hook.broadcast?.topic ?? "permdock:authz",
|
|
3155
|
+
receivePolicy: hook.broadcast?.receivePolicy ?? true
|
|
3156
|
+
},
|
|
2850
3157
|
jwtExpiry: positiveInteger(hook.jwtExpiry ?? 900, "jwtExpiry"),
|
|
2851
3158
|
tenantClaim,
|
|
2852
3159
|
users: suspension?.users,
|
|
@@ -2964,7 +3271,60 @@ revoke execute on function ${bump}() from public, anon, authenticated;
|
|
|
2964
3271
|
${tables.map(([name, user]) => `drop trigger if exists ${quoteIdent(VERSION_TRIGGER)} on ${quoteQualified(name)};
|
|
2965
3272
|
create trigger ${quoteIdent(VERSION_TRIGGER)}
|
|
2966
3273
|
after insert or update or delete on ${quoteQualified(name)}
|
|
2967
|
-
for each row execute function ${bump}(${quoteLiteral(user)});`).join("\n")}${memberUsersVersionSql(parts, bumpFor)}${roleKeysVersionSql(parts, versionTable)}`;
|
|
3274
|
+
for each row execute function ${bump}(${quoteLiteral(user)});`).join("\n")}${broadcastSql(parts, versionTable)}${memberUsersVersionSql(parts, bumpFor)}${roleKeysVersionSql(parts, versionTable)}`;
|
|
3275
|
+
}
|
|
3276
|
+
/**
|
|
3277
|
+
* Every version row written is sent as `{ user_id, version }` on the server
|
|
3278
|
+
* topic and on the user's `authz:<uid>`, in the shape better-supabase's
|
|
3279
|
+
* `subscribeAuthzVersions` and `SessionProvider` read.
|
|
3280
|
+
*/
|
|
3281
|
+
function broadcastSql(parts, versionTable) {
|
|
3282
|
+
const broadcast = parts.broadcast;
|
|
3283
|
+
if (broadcast === void 0) return "";
|
|
3284
|
+
const send = `${quoteIdent(parts.schema)}.permdock_broadcast_authz_version`;
|
|
3285
|
+
const payload = "jsonb_build_object('user_id', new.user_id, 'version', new.version)";
|
|
3286
|
+
const event = quoteLiteral(AUTHZ_EVENT);
|
|
3287
|
+
const receive = broadcast.receivePolicy ? `
|
|
3288
|
+
|
|
3289
|
+
-- each user receives their own authz:<uid> topic, and no user may join the server topic
|
|
3290
|
+
do $$
|
|
3291
|
+
begin
|
|
3292
|
+
if to_regclass('realtime.messages') is not null and not exists (
|
|
3293
|
+
select 1 from pg_policies
|
|
3294
|
+
where schemaname = 'realtime' and tablename = 'messages'
|
|
3295
|
+
and policyname = 'permdock_authz_version_receive'
|
|
3296
|
+
) then
|
|
3297
|
+
create policy permdock_authz_version_receive on realtime.messages
|
|
3298
|
+
for select to authenticated
|
|
3299
|
+
using (
|
|
3300
|
+
realtime.messages.extension = 'broadcast'
|
|
3301
|
+
and (select realtime.topic()) = 'authz:' || (select auth.uid())::text
|
|
3302
|
+
);
|
|
3303
|
+
end if;
|
|
3304
|
+
end;
|
|
3305
|
+
$$;` : "";
|
|
3306
|
+
return `
|
|
3307
|
+
|
|
3308
|
+
-- sends every version bump on the server topic and on the user's authz:<uid>
|
|
3309
|
+
create or replace function ${send}()
|
|
3310
|
+
returns trigger
|
|
3311
|
+
language plpgsql
|
|
3312
|
+
security definer
|
|
3313
|
+
set search_path = ''
|
|
3314
|
+
as $$
|
|
3315
|
+
begin
|
|
3316
|
+
if to_regprocedure('realtime.send(jsonb, text, text, boolean)') is not null then
|
|
3317
|
+
perform realtime.send(${payload}, ${event}, ${quoteLiteral(broadcast.topic)}, true);
|
|
3318
|
+
perform realtime.send(${payload}, ${event}, 'authz:' || new.user_id::text, true);
|
|
3319
|
+
end if;
|
|
3320
|
+
return null;
|
|
3321
|
+
end;
|
|
3322
|
+
$$;
|
|
3323
|
+
revoke execute on function ${send}() from public, anon, authenticated;
|
|
3324
|
+
drop trigger if exists permdock_authz_version_broadcast on ${versionTable};
|
|
3325
|
+
create trigger permdock_authz_version_broadcast
|
|
3326
|
+
after insert or update on ${versionTable}
|
|
3327
|
+
for each row execute function ${send}();${receive}`;
|
|
2968
3328
|
}
|
|
2969
3329
|
function signedUp(user) {
|
|
2970
3330
|
return `exists (select 1 from auth.users a where a.id = ${user})`;
|
|
@@ -3240,7 +3600,8 @@ function trustedHelpers(parts, config, types, tenantType, policy) {
|
|
|
3240
3600
|
...config.rls?.apiKeys === void 0 ? [] : [helperEntry(API_KEY_ALLOWS, "p_grant text", "boolean", client)],
|
|
3241
3601
|
...config.rls?.tokenScopes === true ? [helperEntry(TOKEN_SCOPE_ALLOWS, "p_grant text", "boolean", client)] : [],
|
|
3242
3602
|
...readOnlyActorKinds(config.rls?.readOnlyActors) === void 0 ? [] : [helperEntry(ACTOR_MAY_WRITE, "", "boolean", client)],
|
|
3243
|
-
...config.rls?.approvals === true || typeof config.rls?.approvals === "object" ? [helperEntry(IS_APPROVER, typeof config.rls.approvals === "object" && config.rls.approvals.delegations === true ? "p_approvers jsonb, p_tenant text, p_requester text, p_resource text" : "p_approvers jsonb, p_tenant text", "boolean", client)] : [],
|
|
3603
|
+
...config.rls?.approvals === true || typeof config.rls?.approvals === "object" ? [helperEntry(IS_APPROVER, typeof config.rls.approvals === "object" && (config.rls.approvals.delegations === true || config.rls.approvals.managers !== void 0) ? "p_approvers jsonb, p_tenant text, p_requester text, p_resource text" : "p_approvers jsonb, p_tenant text", "boolean", client)] : [],
|
|
3604
|
+
...typeof config.rls?.approvals === "object" && config.rls.approvals.managers !== void 0 ? [helperEntry(MANAGES, "p_requester text, p_levels integer", "boolean", [])] : [],
|
|
3244
3605
|
...forUser
|
|
3245
3606
|
];
|
|
3246
3607
|
if (!(policy !== void 0 && (ownershipRules(policy, parts.scopes)?.assigns.length ?? 0) > 0)) return keyed;
|