permdock 0.1.0 → 0.3.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 +106 -47
- package/dist/a2a/index.d.ts +7 -16
- package/dist/a2a/index.js +59 -98
- package/dist/adapter-context-mlWsVGGg.js +23 -0
- package/dist/ai-sdk/index.d.ts +37 -16
- package/dist/ai-sdk/index.js +30 -13
- package/dist/approvals/index.d.ts +3 -3
- package/dist/approvals/index.js +5 -4
- package/dist/{approvals-DaxY-Bdg.js → approvals-DbYAuNkG.js} +17 -11
- package/dist/approvers-DT4AVyIg.js +52 -0
- package/dist/{arazzo-CTeVuXr5.js → arazzo-BAgw9ap6.js} +2 -2
- package/dist/{arazzo-aoTkqYsJ.js → arazzo-CKwwqFWz.js} +2 -2
- package/dist/authzen/index.d.ts +4 -13
- package/dist/authzen/index.js +16 -50
- package/dist/better-auth/index.d.ts +20 -3
- package/dist/better-auth/index.js +27 -7
- package/dist/better-supabase/index.d.ts +223 -0
- package/dist/better-supabase/index.js +648 -0
- package/dist/bind-C_ob3LKa.d.ts +25 -0
- package/dist/bind-CuzGytRf.js +97 -0
- package/dist/boundary-BM8a_P6E.js +13 -0
- package/dist/boundary-BmHxVH1J.d.ts +15 -0
- package/dist/canonical-json-DemiK4Vp.js +26 -0
- package/dist/{capability-BDG_nkxt.d.ts → capability-2kYTMWDv.d.ts} +2 -2
- package/dist/{capability-B68OFnZx.js → capability-4qPdO9gk.js} +7 -5
- package/dist/catalog/index.d.ts +1 -1
- package/dist/catalog/index.js +1 -1
- package/dist/catalog-CRW5Mx_B.js +2 -0
- package/dist/{catalog-H-vFGwWK.js → catalog-DWF5cYqB.js} +4 -4
- package/dist/{catalog-B0E6bggc.js → catalog-dFZdWCGN.js} +2 -2
- package/dist/{catalog-doc-BSo_Q_-6.js → catalog-doc-DdGm82XT.js} +20 -32
- package/dist/claude-agent/index.d.ts +5 -14
- package/dist/claude-agent/index.js +4 -10
- package/dist/clerk/index.d.ts +12 -3
- package/dist/clerk/index.js +26 -5
- package/dist/cli/bin.js +1 -1
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +2 -2
- package/dist/clients-C7zLFuWT.d.ts +12 -0
- package/dist/clients-DjU5ABMy.js +23 -0
- package/dist/cloud/index.d.ts +4 -5
- package/dist/cloud/index.js +20 -6
- package/dist/{cloud-BNQTrmrr.js → cloud-CB_ELYuX.js} +2 -2
- package/dist/{cloud-Cuxr6Czw.js → cloud-DWLXO2af.js} +7 -6
- package/dist/collect-DClJsheJ.js +83 -0
- package/dist/{collect-O-tOtbnk.js → collect-DSTE3ml9.js} +194 -42
- package/dist/collect-DSWOk19R.js +2 -0
- package/dist/{commands-BMh_Etm2.js → commands-DSxCqG9A.js} +16 -12
- package/dist/compile/index.d.ts +3 -0
- package/dist/compile/index.js +2 -0
- package/dist/{compile-D22iwvuV.js → compile-Ba4blROR.js} +85 -30
- package/dist/compile-BkRyBDBw.d.ts +94 -0
- package/dist/config-BJiM-xAm.js +157 -0
- package/dist/config-Dnszbv-6.js +36 -0
- package/dist/config-report-DMvWKUxL.js +44 -0
- package/dist/{connection-JvqwHODC.js → connection-CU8MQxRi.js} +1 -1
- package/dist/{context-CKEAabd7.js → context-Bcy85rGi.js} +36 -27
- package/dist/convex/index.d.ts +9 -4
- package/dist/convex/index.js +14 -4
- package/dist/create-B1d519XK.d.ts +245 -0
- package/dist/create-CMwIl-w2.js +253 -0
- package/dist/{credential-B_rkUNlY.js → credential-8P81ff4u.js} +26 -46
- package/dist/delegation-D8pUEuce.js +103 -0
- package/dist/{describe-Bt1YD5uS.js → describe-B_gVZEVi.js} +10 -15
- package/dist/{describe-DernyItf.d.ts → describe-DMYiCjJV.d.ts} +9 -10
- package/dist/{diff-x5Il8LVa.js → diff-2VaeChzX.js} +44 -11
- package/dist/{diff-BUzf5Poi.js → diff-DBIhz_f2.js} +2 -2
- package/dist/{doctor-Bqo6FwUa.js → doctor-BwCAMLx_.js} +2 -2
- package/dist/doctor-collect-CHk6XWOA.js +665 -0
- package/dist/doctor-igIiM_Hl.js +1194 -0
- package/dist/drizzle/index.d.ts +4 -3
- package/dist/drizzle/index.js +3 -3
- package/dist/elysia/index.d.ts +6 -28
- package/dist/elysia/index.js +16 -60
- package/dist/{errors-DSMnAVNa.js → errors-CWfoNg9N.js} +8 -4
- package/dist/{errors-Iy71s7Oj.js → errors-Cz5zn0mW.js} +17 -71
- package/dist/{errors-DbZ1YOnb.d.ts → errors-DPdqI50v.d.ts} +8 -21
- package/dist/{errors-m3u9TmDu.js → errors-DRnGZHzF.js} +4 -1
- package/dist/evaluation-items-CfCCejQd.js +40 -0
- package/dist/{evaluations-DsAU9ppl.js → evaluations-tz6D9A2G.js} +28 -46
- package/dist/eve/index.d.ts +6 -15
- package/dist/eve/index.js +7 -12
- package/dist/expiry-BoBJ8Tvc.js +7 -0
- package/dist/express/index.d.ts +6 -29
- package/dist/express/index.js +28 -58
- package/dist/fastify/index.d.ts +6 -29
- package/dist/fastify/index.js +16 -65
- package/dist/fields-BMl1RxoX.js +26 -0
- package/dist/{files-B_wAGYmt.js → files-DWUN9PzI.js} +5 -1
- package/dist/{fixtures-Cvaw0gDG.js → fixtures-ht28Cplr.js} +5 -2
- package/dist/{freeze-y1_jQL4v.js → freeze-CrU8nQeX.js} +31 -2
- package/dist/{from-snapshot-BMGnhmgv.js → from-snapshot-CTLijvdm.js} +66 -48
- package/dist/{grantee-Bv04_Vzf.js → grantee-Cv5Sogfv.js} +88 -7
- package/dist/graph-sql-B-dsAT6j.d.ts +29 -0
- package/dist/{headers-B5RRv3Xm.js → headers-BZSDieNT.js} +1 -1
- package/dist/{headers-C8SHQccD.d.ts → headers-Cf-zWvsO.d.ts} +1 -1
- package/dist/helpers-H_KARDVC.js +421 -0
- package/dist/hono/index.d.ts +6 -28
- package/dist/hono/index.js +11 -43
- package/dist/{hosted-BwKQ1BTA.js → hosted-DJQw46hn.js} +6 -5
- package/dist/{http-GgVApX1k.js → http-BIhmLfCc.js} +4 -20
- package/dist/http-SO7qGttf.js +44 -0
- package/dist/ids-DC4V4CFu.js +18 -0
- package/dist/index-0nNqHspG.d.ts +6 -0
- package/dist/{index-xIxJLwOQ.d.ts → index-BNc7Wer_.d.ts} +75 -7
- package/dist/{index-CltcQ4Bf.d.ts → index-C7Tw7MaW.d.ts} +68 -5
- package/dist/{index-LF_hS-yn.d.ts → index-C8z4RjQV.d.ts} +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.js +22 -17
- package/dist/instance-options-Dhhcnm3y.js +22 -0
- package/dist/instance-options-jARdwfPN.d.ts +11 -0
- package/dist/{parse-DPfIvFMU.js → json-schema-BsAflUGW.js} +28 -57
- package/dist/jwt/index.d.ts +10 -6
- package/dist/jwt/index.js +32 -13
- package/dist/kernel-_RRHmnMY.js +208 -0
- package/dist/kysely/index.d.ts +4 -3
- package/dist/kysely/index.js +3 -3
- package/dist/live-options-H2eG8dfJ.js +60 -0
- package/dist/{load-BZ24CpZP.js → load-DhWEB9P1.js} +16 -10
- package/dist/load-DwJUafYN.js +2 -0
- package/dist/manifest-iaoBXHKc.js +783 -0
- package/dist/manifest-uDS9y5de.d.ts +206 -0
- package/dist/{map-DowSO96j.js → map-AcxK9o_D.js} +4 -15
- package/dist/{map-claims-B_6I1Rn-.js → map-claims-Z4QZOiFF.js} +13 -4
- package/dist/map-error-pgUWNNtG.js +23 -0
- package/dist/may-use-DndQ5tQ-.js +77 -0
- package/dist/mcp/index.d.ts +54 -22
- package/dist/mcp/index.js +218 -178
- package/dist/nest/index.d.ts +26 -31
- package/dist/nest/index.js +75 -84
- package/dist/next/client.d.ts +7 -8
- package/dist/next/client.js +11 -9
- package/dist/next/index.d.ts +30 -47
- package/dist/next/index.js +45 -60
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +32 -1
- package/dist/node/index.d.ts +9 -28
- package/dist/node/index.js +11 -43
- package/dist/openai/index.d.ts +6 -15
- package/dist/openai/index.js +7 -20
- package/dist/openapi/index.d.ts +87 -4
- package/dist/openapi/index.js +3 -3
- package/dist/{openapi-DcqM8nU7.js → openapi-BqRBvAng.js} +237 -5
- package/dist/{openapi-DWD0Uc_4.js → openapi-CqqEbHsL.js} +5 -5
- package/dist/{openapi-import-BWRUNNeW.js → openapi-import-cmwetbzw.js} +1 -1
- package/dist/{openapi-CwePaF7C.js → openapi-l0xYHkcv.js} +3 -3
- package/dist/{openapi-schema-D8j_T9tO.js → openapi-schema--ARjyfQr.js} +2 -2
- package/dist/orpc/index.d.ts +15 -28
- package/dist/orpc/index.js +74 -117
- package/dist/otel/index.d.ts +2 -2
- package/dist/parse-BuyjxhZV.js +53 -0
- package/dist/parse-local-manifest-BrMozJCo.js +36 -0
- package/dist/parse-local-manifest-JLnaBH0S.d.ts +10 -0
- package/dist/pdp/index.d.ts +2 -2
- package/dist/pdp/index.js +14 -127
- package/dist/{permdock-yoZ7EjxX.js → permdock-CbgvLnuo.js} +672 -149
- package/dist/{permissions-B8vCg_bI.d.ts → permissions-CDgvKG5L.d.ts} +2 -2
- package/dist/{permissions-DC7GROPA.js → permissions-DVoF6dMt.js} +77 -15
- package/dist/{permissions-B4apnahQ.d.ts → permissions-DttnqqxC.d.ts} +34 -5
- package/dist/{permissions-CofRqesP.js → permissions-RJrovw98.js} +3 -3
- package/dist/{pins-CqE1jZuF.js → pins-8ILTftC9.js} +2 -2
- package/dist/{policy-Cq2fB8Q5.d.ts → policy-D2W7uv19.d.ts} +2 -2
- package/dist/{policy-CInmNGkM.d.ts → policy-IB6yxpC3.d.ts} +351 -42
- package/dist/{policy-ANp36PnI.js → policy-xyWg7QdR.js} +173 -22
- package/dist/powersync-BylawD_U.js +540 -0
- package/dist/powersync-DliZK_-y.js +62 -0
- package/dist/powersync-e_AZrKbg.js +2 -0
- package/dist/prisma/index.d.ts +3 -2
- package/dist/prisma/index.js +45 -20
- package/dist/{problem-Cgp9-KZA.js → problem-B43ztKIm.js} +74 -109
- package/dist/problem-details-DX075l9V.d.ts +7 -0
- package/dist/problem-details-_AMOYz-w.js +144 -0
- package/dist/{protected-BuPAycJT.d.ts → protected-BdnIEFkY.d.ts} +5 -4
- package/dist/protected-utU-SLuy.js +100 -0
- package/dist/protected-xAr24FEC.d.ts +40 -0
- package/dist/provider-CSQd7m92.js +52 -0
- package/dist/{provider-wTAUda2v.d.ts → provider-DZY281jO.d.ts} +1 -1
- package/dist/provider-store-Cfbvo4DE.js +43 -0
- package/dist/react/index.d.ts +7 -5
- package/dist/react/index.js +5 -4
- package/dist/react/provider-client.d.ts +1 -1
- package/dist/react/provider-client.js +1 -1
- package/dist/react-native/index.d.ts +166 -10
- package/dist/react-native/index.js +607 -85
- package/dist/{refs-ChLSxbST.js → refs-KYb4ntaz.js} +4 -3
- package/dist/{relations-r4soIFZB.js → relations-cjOL01hZ.js} +110 -31
- package/dist/replay-BsOyTrdV.js +28 -0
- package/dist/replay-CYyiLiwO.d.ts +5 -0
- package/dist/resource-ref-CaS9yVPi.js +20 -0
- package/dist/revocations-Bhr0aMIC.js +27 -0
- package/dist/{rls-BOFU3chG.js → rls-B4ur8nKQ.js} +8 -3
- package/dist/rls-DQtdgTHB.js +2521 -0
- package/dist/rls-fields-74oZPXWL.js +3582 -0
- package/dist/{rls-graph-DxQ39PJj.js → rls-graph-CHwx0V8q.js} +100 -36
- package/dist/{rls-import-CXV6LBlS.js → rls-import-BTFVk3jH.js} +7 -6
- package/dist/{rls-migrate-DrFPbf8p.js → rls-migrate-CN4TlJTO.js} +6 -5
- package/dist/rls-ownership-RuFqaqGz.js +843 -0
- package/dist/rls-shared-Cewd_-zI.js +495 -0
- package/dist/rls-verify-CVQTHTh5.js +746 -0
- package/dist/{row-check-BajTgQZ-.d.ts → row-check-Dt35czLy.d.ts} +12 -15
- package/dist/row-conditions-h2HythXQ.js +27 -0
- package/dist/rpc-DL9Sqvb1.js +89 -0
- package/dist/{run-CJ6UvS3a.js → run-DKDbM4Du.js} +31 -12
- package/dist/runtime-CB8gQFvS.js +11 -0
- package/dist/{saas-BRrZzJkM.js → saas-DhpJjnBA.js} +17 -7
- package/dist/{schema-P8yoma__.js → schema-D3MnDMxa.js} +8 -4
- package/dist/scim/index.d.ts +1 -1
- package/dist/scim/index.js +1 -1
- package/dist/{scim-9NFa0XVZ.js → scim-BFGBBAqR.js} +1 -1
- package/dist/{scopes-cKVp_WTw.js → scopes-CVdPrWN-.js} +35 -8
- package/dist/server/index.d.ts +22 -11
- package/dist/server/index.js +11 -8
- package/dist/{credentials-BgRX3WEg.js → server-DlZ28Oz5.js} +1 -1
- package/dist/shared-DRu8VFVM.js +123 -0
- package/dist/{sink-Cfr9-7YC.d.ts → sink-B1fZzIMf.d.ts} +1 -1
- package/dist/skills-Biq5uup3.js +192 -0
- package/dist/{skills-C_lpV4Jx.js → skills-Bx-U0irG.js} +10 -4
- package/dist/{snapshot-DE8dE_hz.js → snapshot-Enxd0n-s.js} +138 -214
- package/dist/snapshot-cache-B-LxUahj.d.ts +45 -0
- package/dist/snapshot-cache-D6jLelln.js +44 -0
- package/dist/solid/index.d.ts +39 -9
- package/dist/solid/index.js +76 -85
- package/dist/sources-4p0-4xQm.js +545 -0
- package/dist/sources-BdOYLw9j.d.ts +192 -0
- package/dist/{sql-Bll1d7y0.js → sql-xdg5f4Fi.js} +6 -1
- package/dist/{src-CTNT-PBW.js → src-BDwEZWrZ.js} +149 -11
- package/dist/ssf/index.d.ts +3 -2
- package/dist/ssf/index.js +3 -29
- package/dist/store-DMAWwAJV.js +371 -0
- package/dist/{store-Bq90395i.d.ts → store-jOBYpiXC.d.ts} +13 -4
- package/dist/store-options-ByhZq1jV.js +716 -0
- package/dist/{stores-CkG2HrSg.js → stores-BT2pSCub.js} +10 -63
- package/dist/{stores-CvOnu_2T.d.ts → stores-C0IMQrGI.d.ts} +20 -9
- package/dist/{stream-BhMfZOwr.d.ts → stream-D1RXubw2.d.ts} +2 -2
- package/dist/{stream-Q_xlB6Ko.js → stream-DDpvynSB.js} +16 -2
- package/dist/subject-settings-BwBmCdTR.js +128 -0
- package/dist/supabase/index.d.ts +133 -6
- package/dist/supabase/index.js +4 -3
- package/dist/supabase/middleware.d.ts +32 -27
- package/dist/supabase/middleware.js +56 -22
- package/dist/{supabase-D8UlBA7Z.js → supabase-Boqb9a_Y.js} +3 -3
- package/dist/{supabase-DTxGtYdi.js → supabase-C0qESOa-.js} +347 -367
- package/dist/supabase-config-BpPXt3x1.js +472 -0
- package/dist/supabase-hook-6sYLXg_u.js +2 -0
- package/dist/{supabase-hook-D_OqGb_V.js → supabase-hook-CSLQ4zJ3.js} +1037 -705
- package/dist/supautils-Cn4R4cJ4.js +91 -0
- package/dist/svelte/PermissionBoundary.svelte +37 -0
- package/dist/svelte/Protected.svelte +8 -2
- package/dist/svelte/index.d.ts +9 -6
- package/dist/svelte/index.js +61 -7
- package/dist/svelte/runtime.d.ts +4 -3
- package/dist/svelte/runtime.js +4 -3
- package/dist/svelte/source.d.ts +9 -6
- package/dist/svelte/source.js +7 -4
- package/dist/terminal/index.d.ts +6 -14
- package/dist/terminal/index.js +44 -32
- package/dist/testing/index.d.ts +105 -16
- package/dist/testing/index.js +504 -40
- package/dist/testing/saas/index.d.ts +4 -4
- package/dist/testing/saas/index.js +2 -2
- package/dist/testing/saas/permissions.d.ts +1 -1
- package/dist/testing/saas/permissions.js +1 -1
- package/dist/token-CIWxJOCh.js +50 -0
- package/dist/trpc/index.d.ts +7 -26
- package/dist/trpc/index.js +17 -100
- package/dist/types-BnIEz1sU.d.ts +48 -0
- package/dist/{types-CxquUByI.d.ts → types-Bvc4oWT6.d.ts} +1 -1
- package/dist/{sources-DOpW5Ila.d.ts → types-C97IskBw.d.ts} +86 -127
- package/dist/types-CKNSyIf_.d.ts +52 -0
- package/dist/types-Cq_H8N_X.d.ts +197 -0
- package/dist/{types-D6Z6-rKJ.d.ts → types-DbjRN55U.d.ts} +273 -22
- package/dist/{types-BBK-exvJ.d.ts → types-Dnemwd77.d.ts} +7 -1
- package/dist/{types-BvBk1wgn.d.ts → types-DxiCGmmd.d.ts} +5 -3
- package/dist/{types-B9dmiiab.d.ts → types-QCuYJh4q.d.ts} +1 -1
- package/dist/{types-B8w5PFtS.d.ts → types-aqOHTHcp.d.ts} +17 -1
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +10 -9
- package/dist/usage-DorAJiU_.js +2 -0
- package/dist/{usage-1ozMubLY.js → usage-GTixvDDU.js} +2 -2
- package/dist/{usage-CUnK6Ou9.js → usage-ItS7nLcl.js} +225 -62
- package/dist/validation-error-Ba264OaJ.d.ts +26 -0
- package/dist/validation-error-CnjZ4t92.js +33 -0
- package/dist/{validity-D0uRmJKJ.js → validity-uOp8UpYn.js} +57 -36
- package/dist/{verifier-B90agnhl.js → verifier-BxBo6I44.js} +10 -5
- package/dist/version-BvacVTZR.js +17 -0
- package/dist/views-Soe7bGSC.js +95 -0
- package/dist/{vocabulary-Dk0fs-Jk.d.ts → vocabulary-DA8a8zif.d.ts} +1 -1
- package/dist/vue/index.d.ts +35 -13
- package/dist/vue/index.js +86 -93
- package/dist/watch-BwxLTYMZ.js +2 -0
- package/dist/watch-DVBJ9cBq.js +128 -0
- package/dist/webmcp/index.d.ts +2 -2
- package/dist/webmcp/index.js +7 -13
- package/package.json +62 -36
- package/schemas/approval-request-v1.json +175 -0
- package/schemas/catalog-v1.json +29 -1
- package/schemas/supabase-claims-v1.json +6 -1
- package/schemas/supabase-manifest-v1.json +150 -6
- package/skills/permdock/SKILL.md +7 -7
- package/skills/permdock-agents/SKILL.md +5 -5
- package/skills/permdock-agents/references/runtimes.md +12 -10
- package/skills/permdock-approvals/SKILL.md +4 -4
- package/skills/permdock-approvals/references/stores-and-resume.md +15 -4
- package/skills/permdock-audit/SKILL.md +3 -3
- package/skills/permdock-credentials/SKILL.md +4 -4
- package/skills/permdock-credentials/references/tokens-keys-links.md +7 -2
- package/skills/permdock-data/SKILL.md +4 -4
- package/skills/permdock-data/references/queries-and-rls.md +14 -6
- package/skills/permdock-data/references/relationships.md +5 -3
- package/skills/permdock-tenancy/SKILL.md +9 -6
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +14 -8
- package/skills/permdock-wire/SKILL.md +4 -4
- package/skills/permdock-wire/references/adapters.md +42 -30
- package/skills/permdock-wire/references/policy-options.md +5 -3
- package/dist/approvers-aH0PJkmf.js +0 -20
- package/dist/catalog-idsHc0vo.js +0 -2
- package/dist/collect-B7_TIfmg.js +0 -49
- package/dist/collect-fRPAQIWb.js +0 -2
- package/dist/compile-CQbvyIBr.d.ts +0 -30
- package/dist/config-BPYmjTOp.js +0 -26
- package/dist/context-gtAwAILx.js +0 -6
- package/dist/create-BKF3dgFk.d.ts +0 -162
- package/dist/create-CSkhDU9T.js +0 -222
- package/dist/doctor-BGle8Gqi.js +0 -1314
- package/dist/helpers-DnSOrhB9.js +0 -682
- package/dist/index-fG6NSXlc.d.ts +0 -9
- package/dist/kernel-YOGCWNLf.js +0 -211
- package/dist/load-QOOm1z70.js +0 -2
- package/dist/manifest-DDQbC6K0.d.ts +0 -118
- package/dist/map-error-RJ3ZsUyA.js +0 -16
- package/dist/may-use-CnFEjVEp.js +0 -37
- package/dist/pg-4GJWDUxG.js +0 -953
- package/dist/plugin-4gr7IxFJ.js +0 -65
- package/dist/protected-B4K3BKoX.js +0 -138
- package/dist/protected-wY7nXhY9.d.ts +0 -23
- package/dist/provider-_wx46HpB.js +0 -48
- package/dist/rls-CJVja9Ww.js +0 -2119
- package/dist/rls-helpers-BxRuif0l.js +0 -1346
- package/dist/runtime-DP9ttFh1.js +0 -27
- package/dist/skills-Dx3QLnMY.js +0 -110
- package/dist/source-DoBBYJi2.js +0 -6
- package/dist/sources-DVHM3Mwq.js +0 -284
- package/dist/store-C6hFW6ta.js +0 -508
- package/dist/subject-settings-xt7V845g.js +0 -82
- package/dist/supabase-hook-DW-xP4hU.js +0 -2
- package/dist/types-DbWdEfcm.d.ts +0 -87
- package/dist/types-bva3i4Gf.d.ts +0 -98
- package/dist/types-i4BAOvdb.d.ts +0 -97
- package/dist/usage-PyEor6GA.js +0 -2
- package/dist/version-CnSh33Fj.js +0 -16
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { t as compact } from "./compact-y6vfu2_f.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
5
|
-
import { o as
|
|
2
|
+
import { t as canonicalJson } from "./canonical-json-DemiK4Vp.js";
|
|
3
|
+
import { o as parseCapability } from "./capability-4qPdO9gk.js";
|
|
4
|
+
import { t as ApprovalError } from "./errors-DRnGZHzF.js";
|
|
5
|
+
import { a as decodeApprovalCursor, i as approvalPageSize, o as encodeApprovalCursor, t as applyApprovalVerdict } from "./store-DMAWwAJV.js";
|
|
6
6
|
import { t as loadJose } from "./load-jose-BL6LH4bL.js";
|
|
7
7
|
import "./budget-NbEtbJC_.js";
|
|
8
|
-
import { a as quoteSqlTable, i as quoteSqlLiteral, r as quoteSqlIdent } from "./sql-
|
|
9
|
-
import "./sources-
|
|
8
|
+
import { a as quoteSqlTable, i as quoteSqlLiteral, r as quoteSqlIdent } from "./sql-xdg5f4Fi.js";
|
|
9
|
+
import { c as hookApiNames, d as keptKeys, l as roleColumn } from "./sources-4p0-4xQm.js";
|
|
10
|
+
import { i as readMemberships } from "./manifest-iaoBXHKc.js";
|
|
10
11
|
//#region src/supabase/capability.ts
|
|
11
12
|
const DEFAULT_TTL = 300;
|
|
12
13
|
const MAX_TTL = 3600;
|
|
@@ -62,7 +63,7 @@ const KNOWN = /* @__PURE__ */ new Set([
|
|
|
62
63
|
"act",
|
|
63
64
|
"app_metadata"
|
|
64
65
|
]);
|
|
65
|
-
function isRecord$
|
|
66
|
+
function isRecord$2(value) {
|
|
66
67
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
67
68
|
}
|
|
68
69
|
function own(record, key) {
|
|
@@ -83,7 +84,7 @@ function optional(record, key, path, issues, check, expected) {
|
|
|
83
84
|
}
|
|
84
85
|
const isString = (value) => typeof value === "string";
|
|
85
86
|
function checkMembership(item, path, issues) {
|
|
86
|
-
if (!isRecord$
|
|
87
|
+
if (!isRecord$2(item)) {
|
|
87
88
|
issue(issues, path, "Expected a membership object");
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
@@ -98,13 +99,14 @@ function checkMembership(item, path, issues) {
|
|
|
98
99
|
"grantedBy",
|
|
99
100
|
"reason"
|
|
100
101
|
]) optional(item, key, path, issues, isString, "a string");
|
|
101
|
-
optional(item, "within", path, issues, (value) => isRecord$
|
|
102
|
-
optional(item, "on", path, issues, (value) => isRecord$
|
|
102
|
+
optional(item, "within", path, issues, (value) => isRecord$2(value) && Object.values(value).every((id) => typeof id === "string"), "an object of string ids");
|
|
103
|
+
optional(item, "on", path, issues, (value) => isRecord$2(value) && typeof own(value, "resource") === "string" && typeof own(value, "id") === "string", "an object with string resource and id");
|
|
103
104
|
optional(item, "expiresAt", path, issues, (value) => typeof value === "number" && Number.isFinite(value), "a number of seconds since the epoch");
|
|
104
|
-
optional(item, "member", path, issues, (value) => isRecord$
|
|
105
|
+
optional(item, "member", path, issues, (value) => isRecord$2(value) && typeof own(value, "group") === "string" && own(value, "group") !== "", "an object with a non-empty string group");
|
|
105
106
|
optional(item, "managedBy", path, issues, (value) => value === "idp", "'idp'");
|
|
106
107
|
optional(item, "entitlements", path, issues, isStrings, "an array of strings");
|
|
107
|
-
optional(item, "
|
|
108
|
+
optional(item, "keep", path, issues, isStrings, "an array of strings");
|
|
109
|
+
optional(item, "grants", path, issues, isRecord$2, "an object");
|
|
108
110
|
if (!(own(item, "scope") !== void 0 && own(item, "id") !== void 0 || own(item, "tenant") !== void 0 || own(item, "team") !== void 0 || own(item, "on") !== void 0)) issue(issues, path, "Expected scope and id, tenant, team or on");
|
|
109
111
|
}
|
|
110
112
|
function checkPermDockClaims(record, tenantClaim, path, issues) {
|
|
@@ -121,7 +123,7 @@ function checkPermDockClaims(record, tenantClaim, path, issues) {
|
|
|
121
123
|
}
|
|
122
124
|
optional(record, "memberships_truncated", path, issues, (value) => typeof value === "boolean", "a boolean");
|
|
123
125
|
optional(record, tenantClaim, path, issues, isString, "a string");
|
|
124
|
-
optional(record, "attrs", path, issues, isRecord$
|
|
126
|
+
optional(record, "attrs", path, issues, isRecord$2, "an object");
|
|
125
127
|
optional(record, "authz_ver", path, issues, (value) => Number.isInteger(value), "an integer");
|
|
126
128
|
}
|
|
127
129
|
/** The outer level's `kind`: none, `support` with a `session_id`, or `impersonation`. */
|
|
@@ -142,7 +144,7 @@ function checkAct(value, issues) {
|
|
|
142
144
|
let current = value;
|
|
143
145
|
const path = ["act"];
|
|
144
146
|
while (current !== void 0) {
|
|
145
|
-
if (!isRecord$
|
|
147
|
+
if (!isRecord$2(current)) {
|
|
146
148
|
issue(issues, path, "Expected an object");
|
|
147
149
|
return;
|
|
148
150
|
}
|
|
@@ -155,7 +157,7 @@ function checkAct(value, issues) {
|
|
|
155
157
|
}
|
|
156
158
|
function checkClaims(value, tenantClaim) {
|
|
157
159
|
const issues = [];
|
|
158
|
-
if (!isRecord$
|
|
160
|
+
if (!isRecord$2(value)) {
|
|
159
161
|
issue(issues, [], "Expected a claims object");
|
|
160
162
|
return issues;
|
|
161
163
|
}
|
|
@@ -166,7 +168,7 @@ function checkClaims(value, tenantClaim) {
|
|
|
166
168
|
if (act !== void 0) checkAct(act, issues);
|
|
167
169
|
const meta = own(value, "app_metadata");
|
|
168
170
|
if (meta !== void 0) {
|
|
169
|
-
if (isRecord$
|
|
171
|
+
if (isRecord$2(meta)) checkPermDockClaims(meta, tenantClaim, ["app_metadata"], issues);
|
|
170
172
|
else issue(issues, ["app_metadata"], "Expected an object");
|
|
171
173
|
}
|
|
172
174
|
return issues;
|
|
@@ -176,8 +178,8 @@ function merge(base, app) {
|
|
|
176
178
|
if (issues.length > 0) return { issues };
|
|
177
179
|
const baseValue = base.value;
|
|
178
180
|
const appValue = app.value;
|
|
179
|
-
if (!isRecord$
|
|
180
|
-
return { value: isRecord$
|
|
181
|
+
if (!isRecord$2(appValue)) return { issues: [{ message: "Expected the extension to output an object" }] };
|
|
182
|
+
return { value: isRecord$2(baseValue) ? {
|
|
181
183
|
...baseValue,
|
|
182
184
|
...appValue
|
|
183
185
|
} : appValue };
|
|
@@ -190,9 +192,9 @@ function schemaOf(validate) {
|
|
|
190
192
|
validate
|
|
191
193
|
}),
|
|
192
194
|
extend(app) {
|
|
193
|
-
if (!isRecord$
|
|
195
|
+
if (!isRecord$2(app) && typeof app !== "function") throw new TypeError("PermDock: supabaseClaims().extend needs a Standard Schema");
|
|
194
196
|
const props = Reflect.get(app, "~standard");
|
|
195
|
-
if (!isRecord$
|
|
197
|
+
if (!isRecord$2(props) || typeof props["validate"] !== "function") throw new TypeError("PermDock: supabaseClaims().extend needs a Standard Schema");
|
|
196
198
|
const run = app["~standard"].validate.bind(app["~standard"]);
|
|
197
199
|
return schemaOf((value) => {
|
|
198
200
|
const base = validate(value);
|
|
@@ -223,6 +225,289 @@ function supabaseClaims(options = {}) {
|
|
|
223
225
|
});
|
|
224
226
|
}
|
|
225
227
|
//#endregion
|
|
228
|
+
//#region src/supabase/postgrest.ts
|
|
229
|
+
function callRpc(client, schema, fn, args) {
|
|
230
|
+
return client.schema(schema).rpc(fn, args);
|
|
231
|
+
}
|
|
232
|
+
function isRecord$1(value) {
|
|
233
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
234
|
+
}
|
|
235
|
+
function strings(value) {
|
|
236
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
237
|
+
}
|
|
238
|
+
function grantOf(value) {
|
|
239
|
+
if (!isRecord$1(value) || typeof value["permission"] !== "string") return;
|
|
240
|
+
return compact({
|
|
241
|
+
permission: value["permission"],
|
|
242
|
+
effect: value["effect"] === "deny" ? "deny" : "allow",
|
|
243
|
+
level: typeof value["level"] === "string" ? value["level"] : void 0
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
function customRoleOf(value) {
|
|
247
|
+
if (!isRecord$1(value) || typeof value["name"] !== "string") return;
|
|
248
|
+
const grants = Array.isArray(value["grants"]) ? value["grants"].flatMap((item) => {
|
|
249
|
+
const grant = grantOf(item);
|
|
250
|
+
return grant === void 0 ? [] : [grant];
|
|
251
|
+
}) : [];
|
|
252
|
+
const includes = strings(value["includes"]);
|
|
253
|
+
const body = {
|
|
254
|
+
name: value["name"],
|
|
255
|
+
grants,
|
|
256
|
+
...includes.length === 0 ? {} : { includes }
|
|
257
|
+
};
|
|
258
|
+
if (value["scope"] === "global") return value["tenant"] === void 0 ? {
|
|
259
|
+
...body,
|
|
260
|
+
scope: "global"
|
|
261
|
+
} : void 0;
|
|
262
|
+
if (typeof value["tenant"] !== "string") return;
|
|
263
|
+
return compact({
|
|
264
|
+
...body,
|
|
265
|
+
tenant: value["tenant"],
|
|
266
|
+
scope: typeof value["scope"] === "string" ? value["scope"] : void 0,
|
|
267
|
+
id: typeof value["id"] === "string" ? value["id"] : void 0
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function readMemberEntries(value) {
|
|
271
|
+
if (!Array.isArray(value)) return [];
|
|
272
|
+
return value.flatMap((item) => {
|
|
273
|
+
if (!isRecord$1(item) || !isRecord$1(item["principal"])) return [];
|
|
274
|
+
const id = item["principal"]["id"];
|
|
275
|
+
const [membership] = readMemberships([item["membership"]]).memberships;
|
|
276
|
+
return typeof id === "string" && id !== "" && membership !== void 0 ? [{
|
|
277
|
+
principal: { id },
|
|
278
|
+
membership
|
|
279
|
+
}] : [];
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function versionOf(value) {
|
|
283
|
+
const version = typeof value === "string" ? Number(value) : value;
|
|
284
|
+
return typeof version === "number" && Number.isFinite(version) ? version : void 0;
|
|
285
|
+
}
|
|
286
|
+
/** Reads `subject_for`'s JSON; anything it cannot read is left out, and a malformed record is no record. */
|
|
287
|
+
function readSubjectRecord(value) {
|
|
288
|
+
if (!isRecord$1(value) || typeof value["id"] !== "string") return;
|
|
289
|
+
if (value["active"] !== true) return {
|
|
290
|
+
id: value["id"],
|
|
291
|
+
active: false,
|
|
292
|
+
roles: [],
|
|
293
|
+
memberships: [],
|
|
294
|
+
customRoles: []
|
|
295
|
+
};
|
|
296
|
+
const version = value["authzVersion"];
|
|
297
|
+
return compact({
|
|
298
|
+
id: value["id"],
|
|
299
|
+
active: true,
|
|
300
|
+
roles: strings(value["roles"]),
|
|
301
|
+
memberships: readMemberships(value["memberships"]).memberships,
|
|
302
|
+
customRoles: Array.isArray(value["customRoles"]) ? value["customRoles"].flatMap((item) => {
|
|
303
|
+
const role = customRoleOf(item);
|
|
304
|
+
return role === void 0 ? [] : [role];
|
|
305
|
+
}) : [],
|
|
306
|
+
authzVersion: typeof version === "number" && Number.isFinite(version) ? version : void 0
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Membership, custom-role and subject sources over the `subject_for(p_user)`,
|
|
311
|
+
* `authz_version_for(p_user)` and `members_of(p_scope, p_id)` functions
|
|
312
|
+
* `permdock supabase hook generate` writes, for a backend that reaches
|
|
313
|
+
* Postgres only through PostgREST. `memberships.version` reads only the
|
|
314
|
+
* version, so `claimsFirst` with `onStale: 'reread'` reads the full subject
|
|
315
|
+
* only for a stale token; when the version function is missing it falls back
|
|
316
|
+
* to `subject_for`. With `policy`, a token that claims a custom role has its
|
|
317
|
+
* subject read in one `subject_for` call instead, and custom roles are read
|
|
318
|
+
* only for a subject that holds one. Each user and each instance is read once per
|
|
319
|
+
* `postgrestSources` call, so create it per request or per job.
|
|
320
|
+
*/
|
|
321
|
+
function postgrestSources(client, options = {}) {
|
|
322
|
+
const api = options.api;
|
|
323
|
+
const names = api === void 0 ? void 0 : hookApiNames(api.prefix);
|
|
324
|
+
const schema = options.schema ?? (api === void 0 ? "permdock" : api.schema ?? "public");
|
|
325
|
+
const fn = options.fn ?? names?.subjectFor ?? "subject_for";
|
|
326
|
+
const membersFn = options.membersFn ?? names?.membersOf ?? "members_of";
|
|
327
|
+
const versionFn = options.versionFn ?? names?.authzVersionFor ?? "authz_version_for";
|
|
328
|
+
const declared = options.policy === void 0 ? void 0 : options.policy.index.declaredRoles;
|
|
329
|
+
const onlyDeclared = (held) => declared !== void 0 && held?.every((name) => declared.has(name)) === true;
|
|
330
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
331
|
+
const versions = /* @__PURE__ */ new Map();
|
|
332
|
+
const listed = /* @__PURE__ */ new Map();
|
|
333
|
+
const list = (query) => {
|
|
334
|
+
const key = JSON.stringify([query.scope, query.id]);
|
|
335
|
+
const cached = listed.get(key);
|
|
336
|
+
if (cached !== void 0) return cached.then((entries) => [...entries]);
|
|
337
|
+
const pending = Promise.resolve(callRpc(client, schema, membersFn, {
|
|
338
|
+
p_scope: query.scope,
|
|
339
|
+
p_id: query.id
|
|
340
|
+
})).then((result) => {
|
|
341
|
+
if (result.error !== null) throw new Error(`PermDock: ${schema}.${membersFn} failed: ${result.error.message}`);
|
|
342
|
+
return readMemberEntries(result.data);
|
|
343
|
+
});
|
|
344
|
+
listed.set(key, pending);
|
|
345
|
+
return pending.then((entries) => [...entries]);
|
|
346
|
+
};
|
|
347
|
+
const record = (userId) => {
|
|
348
|
+
const cached = loaded.get(userId);
|
|
349
|
+
if (cached !== void 0) return cached;
|
|
350
|
+
const pending = Promise.resolve(callRpc(client, schema, fn, { p_user: userId })).then((result) => {
|
|
351
|
+
if (result.error !== null) throw new Error(`PermDock: ${schema}.${fn} failed: ${result.error.message}`);
|
|
352
|
+
return readSubjectRecord(result.data);
|
|
353
|
+
});
|
|
354
|
+
loaded.set(userId, pending);
|
|
355
|
+
return pending;
|
|
356
|
+
};
|
|
357
|
+
const version = (userId) => {
|
|
358
|
+
const read = loaded.get(userId);
|
|
359
|
+
if (read !== void 0) return read.then((found) => found?.authzVersion);
|
|
360
|
+
const cached = versions.get(userId);
|
|
361
|
+
if (cached !== void 0) return cached;
|
|
362
|
+
const pending = Promise.resolve(callRpc(client, schema, versionFn, { p_user: userId })).then((result) => result.error === null ? versionOf(result.data) : record(userId).then((found) => found?.authzVersion));
|
|
363
|
+
versions.set(userId, pending);
|
|
364
|
+
return pending;
|
|
365
|
+
};
|
|
366
|
+
const live = async (userId) => {
|
|
367
|
+
const found = await record(userId);
|
|
368
|
+
return found?.active === true ? found : void 0;
|
|
369
|
+
};
|
|
370
|
+
return {
|
|
371
|
+
memberships: {
|
|
372
|
+
async membershipsFor(principal) {
|
|
373
|
+
return [...(await live(principal.id))?.memberships ?? []];
|
|
374
|
+
},
|
|
375
|
+
version(principal) {
|
|
376
|
+
return declared !== void 0 && !onlyDeclared([...principal.roles ?? [], ...(principal.memberships ?? []).flatMap((membership) => membership.roles)]) ? record(principal.id).then((found) => found?.authzVersion) : version(principal.id);
|
|
377
|
+
},
|
|
378
|
+
list
|
|
379
|
+
},
|
|
380
|
+
customRoles(principal) {
|
|
381
|
+
return {
|
|
382
|
+
async rolesFor(tenant, context) {
|
|
383
|
+
if (onlyDeclared(context?.held)) return [];
|
|
384
|
+
return ((await live(principal.id))?.customRoles ?? []).filter((role) => role.tenant === tenant);
|
|
385
|
+
},
|
|
386
|
+
async globalRoles(context) {
|
|
387
|
+
if (onlyDeclared(context?.held)) return [];
|
|
388
|
+
return ((await live(principal.id))?.customRoles ?? []).filter((role) => role.scope === "global");
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
},
|
|
392
|
+
async subject(userId) {
|
|
393
|
+
const found = await live(userId);
|
|
394
|
+
if (found === void 0) return {
|
|
395
|
+
principal: null,
|
|
396
|
+
context: {}
|
|
397
|
+
};
|
|
398
|
+
return {
|
|
399
|
+
principal: compact({
|
|
400
|
+
id: found.id,
|
|
401
|
+
roles: found.roles,
|
|
402
|
+
memberships: found.memberships,
|
|
403
|
+
authzVersion: found.authzVersion
|
|
404
|
+
}),
|
|
405
|
+
context: {}
|
|
406
|
+
};
|
|
407
|
+
},
|
|
408
|
+
record
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
//#endregion
|
|
412
|
+
//#region src/supabase/approval-store.ts
|
|
413
|
+
function isRecord(value) {
|
|
414
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
415
|
+
}
|
|
416
|
+
/** A stored body as the request it is; the store wrote it from an `ApprovalRequest`. */
|
|
417
|
+
function requestOf(value) {
|
|
418
|
+
if (!isRecord(value) || value["v"] !== 1 || typeof value["token"] !== "string") return null;
|
|
419
|
+
return value;
|
|
420
|
+
}
|
|
421
|
+
function filterOf(filter) {
|
|
422
|
+
return compact({
|
|
423
|
+
status: filter.status,
|
|
424
|
+
tenant: filter.tenant,
|
|
425
|
+
principalId: filter.principalId,
|
|
426
|
+
actorId: filter.actorId,
|
|
427
|
+
session: filter.session
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* An `ApprovalStore` over the table and functions `rls.approvals` generates,
|
|
432
|
+
* called through supabase-js (`client.schema(schema).rpc(...)`) with a
|
|
433
|
+
* client that may execute them, such as a `service_role` client. Each method
|
|
434
|
+
* is one atomic statement in the database: a repeated ask keeps the open
|
|
435
|
+
* request, two racing approvers both count towards a quorum, and two racing
|
|
436
|
+
* resumes never both consume an approval.
|
|
437
|
+
*/
|
|
438
|
+
function supabaseApprovalStore(client, options = {}) {
|
|
439
|
+
const schema = options.schema ?? "permdock";
|
|
440
|
+
const call = async (fn, args) => {
|
|
441
|
+
const result = await callRpc(client, schema, fn, args);
|
|
442
|
+
if (result.error !== null) throw new Error(`PermDock: ${schema}.${fn} failed: ${result.error.message}`);
|
|
443
|
+
return result.data;
|
|
444
|
+
};
|
|
445
|
+
const get = async (token) => requestOf(await call("permdock_approval_get", { p_token: token }));
|
|
446
|
+
return {
|
|
447
|
+
...options.ttl === void 0 ? {} : { ttl: options.ttl },
|
|
448
|
+
async create(request) {
|
|
449
|
+
await call("permdock_approval_open", { p_request: request });
|
|
450
|
+
if (options.onOpen !== void 0) {
|
|
451
|
+
const stored = await get(request.token);
|
|
452
|
+
if (stored !== null && canonicalJson(stored) === canonicalJson(request)) await options.onOpen(stored);
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
get,
|
|
456
|
+
async resolve(token, verdict) {
|
|
457
|
+
const current = await get(token);
|
|
458
|
+
if (current === null) throw new ApprovalError("approval-not-found", "approval was not found");
|
|
459
|
+
const next = applyApprovalVerdict(current, verdict);
|
|
460
|
+
const written = requestOf(await call("permdock_approval_resolve", {
|
|
461
|
+
p_token: token,
|
|
462
|
+
p_next: next,
|
|
463
|
+
p_seen: current.approvals?.length ?? 0
|
|
464
|
+
}));
|
|
465
|
+
if (written === null) throw new ApprovalError("approval-not-pending", "approval is not pending");
|
|
466
|
+
return written;
|
|
467
|
+
},
|
|
468
|
+
async consume(token, now = /* @__PURE__ */ new Date()) {
|
|
469
|
+
return requestOf(await call("permdock_approval_consume", {
|
|
470
|
+
p_token: token,
|
|
471
|
+
p_now: now.toISOString()
|
|
472
|
+
}));
|
|
473
|
+
},
|
|
474
|
+
async list(query) {
|
|
475
|
+
const after = query.cursor === void 0 ? void 0 : decodeApprovalCursor(query.cursor);
|
|
476
|
+
if (after === null) return { items: [] };
|
|
477
|
+
const size = approvalPageSize(query.limit);
|
|
478
|
+
const data = await call("permdock_approval_list", {
|
|
479
|
+
p_filter: filterOf(query),
|
|
480
|
+
p_after_created: after?.[0] ?? null,
|
|
481
|
+
p_after_token: after?.[1] ?? null,
|
|
482
|
+
p_limit: size + 1
|
|
483
|
+
});
|
|
484
|
+
const rows = Array.isArray(data) ? data.flatMap((row) => {
|
|
485
|
+
const request = requestOf(row);
|
|
486
|
+
return request === null ? [] : [request];
|
|
487
|
+
}) : [];
|
|
488
|
+
const items = rows.slice(0, size);
|
|
489
|
+
const last = items.at(-1);
|
|
490
|
+
return rows.length > size && last !== void 0 ? {
|
|
491
|
+
items,
|
|
492
|
+
next: encodeApprovalCursor(last)
|
|
493
|
+
} : { items };
|
|
494
|
+
},
|
|
495
|
+
async expire(now = /* @__PURE__ */ new Date()) {
|
|
496
|
+
const count = await call("permdock_approval_expire", { p_now: now.toISOString() });
|
|
497
|
+
return typeof count === "number" ? count : 0;
|
|
498
|
+
},
|
|
499
|
+
async cancel(filter, meta) {
|
|
500
|
+
const count = await call("permdock_approval_cancel", {
|
|
501
|
+
p_filter: filterOf(filter),
|
|
502
|
+
p_by: meta.by,
|
|
503
|
+
p_note: meta.note ?? null,
|
|
504
|
+
p_now: (/* @__PURE__ */ new Date()).toISOString()
|
|
505
|
+
});
|
|
506
|
+
return typeof count === "number" ? count : 0;
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
//#endregion
|
|
226
511
|
//#region src/supabase/rls.ts
|
|
227
512
|
function isTable(value) {
|
|
228
513
|
return value !== null && typeof value === "object" && "table" in value && typeof value.table === "string";
|
|
@@ -236,7 +521,9 @@ function supabaseRls(options = {}) {
|
|
|
236
521
|
tenantClaim: options.tenantClaim ?? "tenant_id",
|
|
237
522
|
tenantType: options.tenantType,
|
|
238
523
|
memberships,
|
|
239
|
-
suspension: options.suspension
|
|
524
|
+
suspension: options.suspension,
|
|
525
|
+
realtime: options.realtime,
|
|
526
|
+
storage: options.storage
|
|
240
527
|
});
|
|
241
528
|
}
|
|
242
529
|
const ident = (name) => quoteSqlIdent(name);
|
|
@@ -245,6 +532,13 @@ const literal = quoteSqlLiteral;
|
|
|
245
532
|
function qualifiedTable(name) {
|
|
246
533
|
return table(name.includes(".") ? name : `public.${name}`);
|
|
247
534
|
}
|
|
535
|
+
/** The memberships table's role key over alias `m`, joined to its roles table when it holds a reference. */
|
|
536
|
+
function tenantRole(memberships) {
|
|
537
|
+
return roleColumn(memberships.role, memberships.table.includes(".") ? memberships.table : `public.${memberships.table}`, "m", {
|
|
538
|
+
label: "authorizeSql tenant.role",
|
|
539
|
+
indent: " "
|
|
540
|
+
});
|
|
541
|
+
}
|
|
248
542
|
function textArray(values) {
|
|
249
543
|
return values.length === 0 ? `'{}'::text[]` : `array[${values.map(literal).join(", ")}]::text[]`;
|
|
250
544
|
}
|
|
@@ -258,7 +552,10 @@ function activeRow(row, id, text = false) {
|
|
|
258
552
|
if (row.disabledAt === void 0 && row.status === void 0) throw new TypeError("PermDock: a suspension table needs disabledAt or status");
|
|
259
553
|
return `exists (select 1 from ${qualifiedTable(row.table)} s where ${parts.join(" and ")})`;
|
|
260
554
|
}
|
|
261
|
-
/**
|
|
555
|
+
/**
|
|
556
|
+
* Early `return false` for a suspended user, or a tenant request for a
|
|
557
|
+
* suspended instance unless its scope keeps the requested permission.
|
|
558
|
+
*/
|
|
262
559
|
function suspendedGuards(suspension, scope, uid) {
|
|
263
560
|
const lines = [];
|
|
264
561
|
const users = suspension?.users;
|
|
@@ -266,9 +563,13 @@ function suspendedGuards(suspension, scope, uid) {
|
|
|
266
563
|
return false; -- suspended user
|
|
267
564
|
end if;`);
|
|
268
565
|
const tenant = suspension?.scopes?.[scope];
|
|
269
|
-
if (tenant !== void 0)
|
|
566
|
+
if (tenant !== void 0) {
|
|
567
|
+
const keep = keptKeys(tenant);
|
|
568
|
+
const kept = keep.length === 0 ? "" : ` and not (requested_permission::text = any(${textArray(keep)}))`;
|
|
569
|
+
lines.push(` if requested_tenant is not null and not ${activeRow(tenant, "requested_tenant", true)}${kept} then
|
|
270
570
|
return false; -- suspended ${scope}
|
|
271
571
|
end if;`);
|
|
572
|
+
}
|
|
272
573
|
return lines.map((line) => `\n${line}`).join("");
|
|
273
574
|
}
|
|
274
575
|
function claimEntries(where, value) {
|
|
@@ -289,16 +590,26 @@ function customHolds(q, scope, allows, denies, includes) {
|
|
|
289
590
|
))
|
|
290
591
|
)`;
|
|
291
592
|
}
|
|
292
|
-
function
|
|
293
|
-
|
|
593
|
+
function disabledLine(memberships, suspension) {
|
|
594
|
+
if (memberships.disabledAt === void 0) return "";
|
|
595
|
+
const column = `m.${ident(memberships.disabledAt)}`;
|
|
596
|
+
const keep = keptKeys(suspension?.memberships);
|
|
597
|
+
return keep.length === 0 ? `\n and ${column} is null` : `\n and (${column} is null or requested_permission::text = any(${textArray(keep)}))`;
|
|
598
|
+
}
|
|
599
|
+
function claimKept(suspension) {
|
|
600
|
+
return keptKeys(suspension?.memberships).length === 0 ? "" : `\n and case coalesce(jsonb_typeof(m -> 'keep'), 'null') when 'null' then true when 'array' then m -> 'keep' @> jsonb_build_array(requested_permission::text) else false end`;
|
|
601
|
+
}
|
|
602
|
+
function customDatabaseBranch(q, scope, memberships, declared, levels, suspension) {
|
|
603
|
+
const role = tenantRole(memberships);
|
|
604
|
+
const match = `c.tenant_id::text = requested_tenant and c.scope = ${literal(scope)} and c.scope_id is null and c.role = ${role.sql}`;
|
|
294
605
|
const rows = (source, value, extra) => `array(select c.${value} from ${q(source)} c where ${match}${extra})`;
|
|
295
606
|
return ` or exists (
|
|
296
607
|
select 1
|
|
297
|
-
from ${qualifiedTable(memberships.table)} m
|
|
608
|
+
from ${qualifiedTable(memberships.table)} m${role.join}
|
|
298
609
|
where m.${ident(memberships.user)} = v_member_user
|
|
299
610
|
and m.${ident(memberships.tenant)} = v_member_tenant
|
|
300
|
-
and not (
|
|
301
|
-
and ${customHolds(q, scope, rows("custom_role_permissions", "permission", " and c.effect = 'allow'"), rows("custom_role_permissions", "permission", " and c.effect = 'deny'"), rows("custom_role_includes", "include_role", ""))}
|
|
611
|
+
and not (${role.sql} = any(${textArray(declared)}))${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}${disabledLine(memberships, suspension)}
|
|
612
|
+
and ${customHolds(q, scope, rows("custom_role_permissions", levels ? "permission || coalesce('@' || c.level, '')" : "permission", " and c.effect = 'allow'"), rows("custom_role_permissions", "permission", " and c.effect = 'deny'"), rows("custom_role_includes", "include_role", ""))}
|
|
302
613
|
)`;
|
|
303
614
|
}
|
|
304
615
|
/**
|
|
@@ -324,13 +635,14 @@ function databaseBody(q, scope, memberships, custom, suspension) {
|
|
|
324
635
|
return false; -- no memberships table configured
|
|
325
636
|
end if;`;
|
|
326
637
|
if (memberships !== void 0 && tenantColumn !== void 0) {
|
|
638
|
+
const role = tenantRole(memberships);
|
|
327
639
|
const held = (effect) => `exists (
|
|
328
640
|
select 1
|
|
329
|
-
from ${qualifiedTable(memberships.table)} m
|
|
330
|
-
join ${q("role_permissions")} rp on rp.role =
|
|
641
|
+
from ${qualifiedTable(memberships.table)} m${role.join}
|
|
642
|
+
join ${q("role_permissions")} rp on rp.role = ${role.sql}
|
|
331
643
|
where m.${ident(memberships.user)} = v_member_user
|
|
332
644
|
and m.${ident(tenantColumn)} = v_member_tenant
|
|
333
|
-
and ${effectMatch(literal(scope), effect)}${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}
|
|
645
|
+
and ${effectMatch(literal(scope), effect)}${memberships.expiresAt === void 0 ? "" : `\n and (m.${ident(memberships.expiresAt)} is null or m.${ident(memberships.expiresAt)} > now())`}${disabledLine(memberships, suspension)}
|
|
334
646
|
)`;
|
|
335
647
|
tenantBranch = ` if requested_tenant is not null then
|
|
336
648
|
begin
|
|
@@ -342,7 +654,7 @@ function databaseBody(q, scope, memberships, custom, suspension) {
|
|
|
342
654
|
return (${held("allow")}${custom === void 0 ? "" : customDatabaseBranch(q, scope, {
|
|
343
655
|
...memberships,
|
|
344
656
|
tenant: tenantColumn
|
|
345
|
-
}, custom.declared)})
|
|
657
|
+
}, custom.declared, custom.levels === true, suspension)})
|
|
346
658
|
and not ${held("deny")}
|
|
347
659
|
and not ${global("deny")};
|
|
348
660
|
end if;`;
|
|
@@ -381,7 +693,7 @@ function jwtBody(q, scope, custom, suspension) {
|
|
|
381
693
|
cross join lateral (select m -> 'grants' -> r.role as g) cg
|
|
382
694
|
where m ->> 'scope' = ${literal(scope)}
|
|
383
695
|
and m ->> 'id' = requested_tenant
|
|
384
|
-
and ${CLAIM_UNEXPIRED}
|
|
696
|
+
and ${CLAIM_UNEXPIRED}${claimKept(suspension)}
|
|
385
697
|
and jsonb_typeof(cg.g) = 'array'
|
|
386
698
|
and not (r.role = any(${textArray(custom.declared)}))
|
|
387
699
|
and ${customHolds(q, scope, claimEntries("left(e, 1) not in ('-', '@')", "e"), claimEntries("left(e, 1) = '-'", "substr(e, 2)"), claimEntries("left(e, 1) = '@'", "substr(e, 2)"))}
|
|
@@ -392,7 +704,7 @@ function jwtBody(q, scope, custom, suspension) {
|
|
|
392
704
|
join ${q("role_permissions")} rp on rp.role = r.role
|
|
393
705
|
where m ->> 'scope' = ${literal(scope)}
|
|
394
706
|
and m ->> 'id' = requested_tenant
|
|
395
|
-
and ${CLAIM_UNEXPIRED}
|
|
707
|
+
and ${CLAIM_UNEXPIRED}${claimKept(suspension)}
|
|
396
708
|
and ${effectMatch(literal(scope), effect)}
|
|
397
709
|
)`;
|
|
398
710
|
const global = (effect) => `exists (
|
|
@@ -461,336 +773,4 @@ grant execute on function ${signature} to authenticated;
|
|
|
461
773
|
`;
|
|
462
774
|
}
|
|
463
775
|
//#endregion
|
|
464
|
-
|
|
465
|
-
const REGISTERED = /* @__PURE__ */ new Set([
|
|
466
|
-
"sub",
|
|
467
|
-
"role",
|
|
468
|
-
"iss",
|
|
469
|
-
"aud",
|
|
470
|
-
"exp",
|
|
471
|
-
"iat",
|
|
472
|
-
"nbf",
|
|
473
|
-
"aal",
|
|
474
|
-
"amr",
|
|
475
|
-
"acr",
|
|
476
|
-
"session_id",
|
|
477
|
-
"email",
|
|
478
|
-
"phone",
|
|
479
|
-
"is_anonymous",
|
|
480
|
-
"app_metadata",
|
|
481
|
-
"user_metadata",
|
|
482
|
-
"act",
|
|
483
|
-
"client_id",
|
|
484
|
-
"scope"
|
|
485
|
-
]);
|
|
486
|
-
function isRecord(value) {
|
|
487
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
488
|
-
}
|
|
489
|
-
/** Top-level first, then `app_metadata`. `null` counts as absent: the RBAC hook writes `null` for a user with no role row. */
|
|
490
|
-
function readClaim(claims, name) {
|
|
491
|
-
const top = Object.hasOwn(claims, name) ? claims[name] : void 0;
|
|
492
|
-
if (top !== void 0 && top !== null) return top;
|
|
493
|
-
const meta = claims["app_metadata"];
|
|
494
|
-
if (isRecord(meta) && Object.hasOwn(meta, name)) return meta[name] ?? void 0;
|
|
495
|
-
}
|
|
496
|
-
function asRoles(value, declared) {
|
|
497
|
-
const raw = typeof value === "string" ? value === "" ? [] : [value] : Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
498
|
-
if (declared === void 0) return raw;
|
|
499
|
-
const allowed = new Set(declared);
|
|
500
|
-
return raw.filter((role) => allowed.has(role));
|
|
501
|
-
}
|
|
502
|
-
/** Reads the `memberships` claim; an entry it cannot read is dropped and its index reported. */
|
|
503
|
-
function readMemberships(value) {
|
|
504
|
-
if (!Array.isArray(value)) return {
|
|
505
|
-
memberships: [],
|
|
506
|
-
dropped: []
|
|
507
|
-
};
|
|
508
|
-
const out = [];
|
|
509
|
-
const dropped = [];
|
|
510
|
-
for (const [index, item] of value.entries()) {
|
|
511
|
-
const membership = asMembership(item);
|
|
512
|
-
if (membership === void 0) dropped.push(index);
|
|
513
|
-
else out.push(membership);
|
|
514
|
-
}
|
|
515
|
-
return {
|
|
516
|
-
memberships: out,
|
|
517
|
-
dropped
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
function asMembership(item) {
|
|
521
|
-
if (!isRecord(item) || !Array.isArray(item["roles"])) return;
|
|
522
|
-
const roles = item["roles"].filter((role) => typeof role === "string");
|
|
523
|
-
if (roles.length === 0) return;
|
|
524
|
-
const scope = typeof item["scope"] === "string" ? item["scope"] : void 0;
|
|
525
|
-
const id = typeof item["id"] === "string" ? item["id"] : void 0;
|
|
526
|
-
const within = isRecord(item["within"]) ? Object.fromEntries(Object.entries(item["within"]).filter((entry) => typeof entry[1] === "string")) : void 0;
|
|
527
|
-
const tenant = typeof item["tenant"] === "string" ? item["tenant"] : void 0;
|
|
528
|
-
const team = typeof item["team"] === "string" ? item["team"] : void 0;
|
|
529
|
-
const onRecord = isRecord(item["on"]) ? item["on"] : void 0;
|
|
530
|
-
const on = onRecord !== void 0 && typeof onRecord["resource"] === "string" && typeof onRecord["id"] === "string" ? {
|
|
531
|
-
resource: onRecord["resource"],
|
|
532
|
-
id: onRecord["id"]
|
|
533
|
-
} : void 0;
|
|
534
|
-
if ((scope === void 0 || id === void 0) && tenant === void 0 && team === void 0 && on === void 0) return;
|
|
535
|
-
return compact({
|
|
536
|
-
roles,
|
|
537
|
-
scope,
|
|
538
|
-
id,
|
|
539
|
-
within,
|
|
540
|
-
tenant,
|
|
541
|
-
team,
|
|
542
|
-
on,
|
|
543
|
-
via: typeof item["via"] === "string" ? item["via"] : void 0,
|
|
544
|
-
expiresAt: typeof item["expiresAt"] === "number" ? item["expiresAt"] : void 0,
|
|
545
|
-
grantedBy: typeof item["grantedBy"] === "string" ? item["grantedBy"] : void 0,
|
|
546
|
-
reason: typeof item["reason"] === "string" ? item["reason"] : void 0,
|
|
547
|
-
member: memberOf(item["member"]),
|
|
548
|
-
managedBy: item["managedBy"] === "idp" ? "idp" : void 0,
|
|
549
|
-
entitlements: Array.isArray(item["entitlements"]) ? item["entitlements"].filter((seat) => typeof seat === "string") : void 0
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
function memberOf(value) {
|
|
553
|
-
if (value === null || typeof value !== "object" || !Object.hasOwn(value, "group")) return;
|
|
554
|
-
const group = value.group;
|
|
555
|
-
return typeof group === "string" && group !== "" ? { group } : void 0;
|
|
556
|
-
}
|
|
557
|
-
function asStrings(value) {
|
|
558
|
-
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
559
|
-
}
|
|
560
|
-
/** `claims[plans][tenant]`: only the active tenant's entry, never another tenant's. */
|
|
561
|
-
function plansFor(claims, name, tenant) {
|
|
562
|
-
if (name === void 0 || tenant === void 0) return [];
|
|
563
|
-
const byTenant = readClaim(claims, name);
|
|
564
|
-
if (!isRecord(byTenant) || !Object.hasOwn(byTenant, tenant)) return [];
|
|
565
|
-
return asStrings(byTenant[tenant]);
|
|
566
|
-
}
|
|
567
|
-
const INVALID_CHAIN = Object.freeze({
|
|
568
|
-
ok: false,
|
|
569
|
-
reason: "invalid-chain"
|
|
570
|
-
});
|
|
571
|
-
const NO_ACTOR = Object.freeze({ ok: true });
|
|
572
|
-
/** Own entries of one `act` level, with the nested `act` copied the same way. */
|
|
573
|
-
function copyAct(level) {
|
|
574
|
-
const entries = Object.entries(level).map(([key, value]) => [key, key === "act" && isRecord(value) ? copyAct(value) : value]);
|
|
575
|
-
return Object.fromEntries(entries);
|
|
576
|
-
}
|
|
577
|
-
/**
|
|
578
|
-
* The outer `act` level by its `kind`, the marker better-supabase writes: none is an OAuth client
|
|
579
|
-
* or agent chain, `support` a support session (with `session_id`), `impersonation` an admin acting
|
|
580
|
-
* as the user. Any other `kind`, or a support level without `session_id`, is invalid.
|
|
581
|
-
*/
|
|
582
|
-
function actingParty(outer, id) {
|
|
583
|
-
const marked = Object.hasOwn(outer, "kind") ? outer["kind"] : void 0;
|
|
584
|
-
const kind = marked === void 0 && Object.hasOwn(outer, "session_id") ? "support" : marked;
|
|
585
|
-
const chain = copyAct(outer);
|
|
586
|
-
const reason = typeof outer["reason"] === "string" ? outer["reason"] : void 0;
|
|
587
|
-
switch (kind) {
|
|
588
|
-
case void 0: return freezeDeep({
|
|
589
|
-
ok: true,
|
|
590
|
-
actor: {
|
|
591
|
-
id,
|
|
592
|
-
kind: "oauth-client",
|
|
593
|
-
chain
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
case "support": {
|
|
597
|
-
const session = outer["session_id"];
|
|
598
|
-
const readOnly = Object.hasOwn(outer, "read_only") ? outer["read_only"] : false;
|
|
599
|
-
if (typeof session !== "string" || session === "" || typeof readOnly !== "boolean") return INVALID_CHAIN;
|
|
600
|
-
return freezeDeep({
|
|
601
|
-
ok: true,
|
|
602
|
-
actor: compact({
|
|
603
|
-
id,
|
|
604
|
-
kind: "support",
|
|
605
|
-
sessionId: session,
|
|
606
|
-
readOnly,
|
|
607
|
-
reason,
|
|
608
|
-
chain
|
|
609
|
-
})
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
case "impersonation": return freezeDeep({
|
|
613
|
-
ok: true,
|
|
614
|
-
actor: compact({
|
|
615
|
-
id,
|
|
616
|
-
kind: "impersonation",
|
|
617
|
-
reason,
|
|
618
|
-
chain
|
|
619
|
-
})
|
|
620
|
-
});
|
|
621
|
-
default: return INVALID_CHAIN;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
function readActor(claims) {
|
|
625
|
-
if (Object.hasOwn(claims, "act") && claims["act"] !== void 0) {
|
|
626
|
-
let current = claims["act"];
|
|
627
|
-
while (current !== void 0) {
|
|
628
|
-
const level = isRecord(current) ? current["sub"] : void 0;
|
|
629
|
-
if (!isRecord(current) || typeof level !== "string" || level === "") return INVALID_CHAIN;
|
|
630
|
-
current = Object.hasOwn(current, "act") ? current["act"] : void 0;
|
|
631
|
-
}
|
|
632
|
-
const outer = claims["act"];
|
|
633
|
-
const sub = isRecord(outer) ? outer["sub"] : void 0;
|
|
634
|
-
if (!isRecord(outer) || typeof sub !== "string") return INVALID_CHAIN;
|
|
635
|
-
return actingParty(outer, sub);
|
|
636
|
-
}
|
|
637
|
-
const client = Object.hasOwn(claims, "client_id") ? claims["client_id"] : void 0;
|
|
638
|
-
if (typeof client === "string" && client !== "") return freezeDeep({
|
|
639
|
-
ok: true,
|
|
640
|
-
actor: {
|
|
641
|
-
id: client,
|
|
642
|
-
kind: "oauth-client"
|
|
643
|
-
}
|
|
644
|
-
});
|
|
645
|
-
return NO_ACTOR;
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Who acts for the user: the outermost `sub` of an RFC 8693 `act` chain (the current
|
|
649
|
-
* actor; nested levels are prior actors, kept on `chain` for audit), else the
|
|
650
|
-
* OAuth `client_id` of a third-party app. The outer level's `kind` names the actor:
|
|
651
|
-
* none is `oauth-client`, `support` a support session, `impersonation` an admin acting as the
|
|
652
|
-
* user. Reads only `act` and `client_id`; the caller applies the role rule first (`anon` and
|
|
653
|
-
* `service_role` are anonymous and carry no actor). An `act` that is not a chain of objects each
|
|
654
|
-
* with a non-empty `sub`, that names another `kind`, or a support level without `session_id`,
|
|
655
|
-
* is `{ ok: false }` and must deny.
|
|
656
|
-
*/
|
|
657
|
-
function actorOf(claims) {
|
|
658
|
-
try {
|
|
659
|
-
return isRecord(claims) ? readActor(claims) : NO_ACTOR;
|
|
660
|
-
} catch {
|
|
661
|
-
return INVALID_CHAIN;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
/** The OAuth `scope` claim (a space-separated string or a list) as `scopes`; `undefined` when empty. */
|
|
665
|
-
function delegationOf(claims) {
|
|
666
|
-
try {
|
|
667
|
-
if (!isRecord(claims) || !Object.hasOwn(claims, "scope")) return;
|
|
668
|
-
const scope = claims["scope"];
|
|
669
|
-
const scopes = typeof scope === "string" ? scope.split(/\s+/u).filter(Boolean) : asStrings(scope);
|
|
670
|
-
return scopes.length > 0 ? freezeDeep({ scopes }) : void 0;
|
|
671
|
-
} catch {
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
function subjectDelegation(claims, chain) {
|
|
676
|
-
const delegation = compact({
|
|
677
|
-
scopes: delegationOf(claims)?.scopes,
|
|
678
|
-
chain
|
|
679
|
-
});
|
|
680
|
-
return Object.keys(delegation).length === 0 ? void 0 : delegation;
|
|
681
|
-
}
|
|
682
|
-
function emit(options, reason, cause) {
|
|
683
|
-
try {
|
|
684
|
-
options.onAuth?.({
|
|
685
|
-
reason,
|
|
686
|
-
cause,
|
|
687
|
-
source: "supabase"
|
|
688
|
-
});
|
|
689
|
-
} catch {}
|
|
690
|
-
}
|
|
691
|
-
function validateClaims(extra, schema) {
|
|
692
|
-
const result = schema["~standard"].validate(extra);
|
|
693
|
-
if (result instanceof Promise) {
|
|
694
|
-
ignoreRejection(result);
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
if ("issues" in result && result.issues !== void 0) return;
|
|
698
|
-
const value = result.value;
|
|
699
|
-
return isRecord(value) ? value : void 0;
|
|
700
|
-
}
|
|
701
|
-
function extraClaims(claims) {
|
|
702
|
-
const extra = {};
|
|
703
|
-
const meta = claims["app_metadata"];
|
|
704
|
-
if (isRecord(meta)) for (const [key, value] of Object.entries(meta)) extra[key] = value;
|
|
705
|
-
for (const [key, value] of Object.entries(claims)) {
|
|
706
|
-
if (REGISTERED.has(key) || key === "user_metadata") continue;
|
|
707
|
-
extra[key] = value;
|
|
708
|
-
}
|
|
709
|
-
return extra;
|
|
710
|
-
}
|
|
711
|
-
function mapClaims(claims, options) {
|
|
712
|
-
const role = claims["role"];
|
|
713
|
-
if (role === "anon" || role === "service_role") return anonymousSubject();
|
|
714
|
-
const id = claims["sub"];
|
|
715
|
-
if (typeof id !== "string" || id === "") return anonymousSubject();
|
|
716
|
-
const act = readActor(claims);
|
|
717
|
-
if (!act.ok) {
|
|
718
|
-
emit(options, "invalid-token", act.reason);
|
|
719
|
-
return anonymousSubject();
|
|
720
|
-
}
|
|
721
|
-
if (options.anonymousSignIns === "deny" && claims["is_anonymous"] === true) return anonymousSubject();
|
|
722
|
-
const actor = act.actor === void 0 ? void 0 : act.actor.kind === "support" ? {
|
|
723
|
-
id: act.actor.id,
|
|
724
|
-
kind: act.actor.kind,
|
|
725
|
-
sessionId: act.actor.sessionId,
|
|
726
|
-
readOnly: act.actor.readOnly
|
|
727
|
-
} : {
|
|
728
|
-
id: act.actor.id,
|
|
729
|
-
kind: act.actor.kind
|
|
730
|
-
};
|
|
731
|
-
const roleClaim = options.roles ?? "user_role";
|
|
732
|
-
const tenantClaim = options.tenant ?? "tenant_id";
|
|
733
|
-
const membershipsClaim = options.memberships ?? "memberships";
|
|
734
|
-
let extra = extraClaims(claims);
|
|
735
|
-
if (options.schema !== void 0) extra = validateClaims(extra, options.schema) ?? {};
|
|
736
|
-
const include = new Set(options.include ?? []);
|
|
737
|
-
const tenantValue = readClaim(claims, tenantClaim);
|
|
738
|
-
const version = readClaim(claims, "authz_ver");
|
|
739
|
-
const tenant = typeof tenantValue === "string" ? tenantValue : void 0;
|
|
740
|
-
const { memberships, dropped } = readMemberships(readClaim(claims, membershipsClaim));
|
|
741
|
-
if (dropped.length > 0) emit(options, "schema", "membership-dropped");
|
|
742
|
-
const plans = plansFor(claims, options.plans, tenant);
|
|
743
|
-
const principal = compact({
|
|
744
|
-
id,
|
|
745
|
-
kind: "user",
|
|
746
|
-
roles: asRoles(readClaim(claims, roleClaim), options.declared),
|
|
747
|
-
tenant,
|
|
748
|
-
plans: plans.length > 0 ? plans : void 0,
|
|
749
|
-
memberships,
|
|
750
|
-
membershipsTruncated: readClaim(claims, "memberships_truncated") === true ? true : void 0,
|
|
751
|
-
authzVersion: typeof version === "number" && Number.isInteger(version) ? version : void 0,
|
|
752
|
-
issuer: typeof claims["iss"] === "string" ? claims["iss"] : void 0,
|
|
753
|
-
assurance: typeof claims["aal"] === "string" ? { acr: claims["aal"] } : void 0,
|
|
754
|
-
claims: Object.keys(extra).length === 0 ? void 0 : extra,
|
|
755
|
-
email: include.has("email") && typeof claims["email"] === "string" ? claims["email"] : void 0,
|
|
756
|
-
phone: include.has("phone") && typeof claims["phone"] === "string" ? claims["phone"] : void 0,
|
|
757
|
-
is_anonymous: include.has("is_anonymous") && typeof claims["is_anonymous"] === "boolean" ? claims["is_anonymous"] : void 0
|
|
758
|
-
});
|
|
759
|
-
const session = typeof claims["session_id"] === "string" ? claims["session_id"] : void 0;
|
|
760
|
-
const expiresAt = typeof claims["exp"] === "number" ? claims["exp"] : void 0;
|
|
761
|
-
return freezeDeep(compact({
|
|
762
|
-
principal,
|
|
763
|
-
actor,
|
|
764
|
-
delegation: act.actor?.kind === "oauth-client" ? subjectDelegation(claims, act.actor.chain) : void 0,
|
|
765
|
-
context: {},
|
|
766
|
-
session,
|
|
767
|
-
expiresAt
|
|
768
|
-
}));
|
|
769
|
-
}
|
|
770
|
-
function subjectFromSupabase(claims, options = {}) {
|
|
771
|
-
try {
|
|
772
|
-
if (!isRecord(claims)) return anonymousSubject();
|
|
773
|
-
const rest = {};
|
|
774
|
-
for (const [key, value] of Object.entries(claims)) {
|
|
775
|
-
if (key === "user_metadata") continue;
|
|
776
|
-
rest[key] = value;
|
|
777
|
-
}
|
|
778
|
-
return mapClaims(rest, options);
|
|
779
|
-
} catch {
|
|
780
|
-
return anonymousSubject();
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
/**
|
|
784
|
-
* A verified session object (for example better-supabase's `AuthSession`) in, `Subject` out.
|
|
785
|
-
* Only `kind: 'user'` sessions map; `anon`, `service`, `invalid` and anything else are anonymous.
|
|
786
|
-
*/
|
|
787
|
-
function subjectFromSupabaseSession(session, options = {}) {
|
|
788
|
-
try {
|
|
789
|
-
if (session === null || session === void 0 || session.kind !== "user") return anonymousSubject();
|
|
790
|
-
return subjectFromSupabase(session.claims, options);
|
|
791
|
-
} catch {
|
|
792
|
-
return anonymousSubject();
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
//#endregion
|
|
796
|
-
export { subjectFromSupabaseSession as a, supabaseClaims as c, subjectFromSupabase as i, exchangeCapability as l, delegationOf as n, authorizeSql as o, readMemberships as r, supabaseRls as s, actorOf as t };
|
|
776
|
+
export { readSubjectRecord as a, postgrestSources as i, supabaseRls as n, supabaseClaims as o, supabaseApprovalStore as r, exchangeCapability as s, authorizeSql as t };
|