permdock 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/{2020-C9VN-x8c.js → 2020-CJbO8Bvz.js} +1 -3
- package/dist/a2a/index.d.ts +5 -5
- package/dist/a2a/index.js +4 -4
- package/dist/{adoption-scan-DCYe60Pi.js → adoption-scan-D-feE7BE.js} +1 -1
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +1 -1
- package/dist/ai-sdk/index.d.ts +21 -6
- package/dist/ai-sdk/index.js +19 -9
- package/dist/{approval-prompt-DvSSPQJX.d.ts → approval-prompt-K0faOLFp.d.ts} +2 -2
- package/dist/approvals/index.d.ts +4 -4
- package/dist/approvals/index.js +4 -4
- package/dist/{approvals-p1PGoVjb.js → approvals-CMRfsbBh.js} +74 -48
- package/dist/{arazzo-41WuzHou.js → arazzo-ClrF3PVb.js} +2 -2
- package/dist/{arazzo-CaUVBn7D.js → arazzo-rdeJ8n1J.js} +4 -4
- package/dist/{args-IIolxxKA.js → args-CC3OwyHW.js} +112 -2
- package/dist/astro/index.d.ts +6 -6
- package/dist/astro/index.js +2 -2
- package/dist/{audience-DabClFLQ.js → audience-BrMs8c4o.js} +1 -1
- package/dist/{auth-DRLEizbL.js → auth-CscUX8Sy.js} +3 -4
- package/dist/authzen/index.d.ts +162 -22
- package/dist/authzen/index.js +315 -146
- package/dist/{automation-BNM3TtDo.d.ts → automation-DOtAFWdy.d.ts} +3 -3
- package/dist/{automation-DVjOckjV.js → automation-ySsxp_Yp.js} +1 -1
- package/dist/base-url-BQbddZO5.js +9 -0
- package/dist/better-auth/index.d.ts +2 -2
- package/dist/better-auth/index.js +2 -2
- package/dist/better-supabase/index.d.ts +50 -8
- package/dist/better-supabase/index.js +94 -32
- package/dist/{bind-CAvgUuKs.js → bind-D1nO6fiC.js} +5 -5
- package/dist/{bind-DOyrv6zi.d.ts → bind-JDuvxjuW.d.ts} +7 -7
- package/dist/{build-instance-Bu_eDqYw.js → build-instance-DxE7czo9.js} +1 -1
- package/dist/{canonical-json-BC8_nMTw.js → canonical-json-DwilZ1iB.js} +6 -3
- package/dist/{capability-Drg-1YhL.d.ts → capability-D4UC9TTW.d.ts} +2 -2
- package/dist/{capability-N1K9IpqS.js → capability-L7NnfhiE.js} +1 -1
- package/dist/{casbin-Cr7RLtA3.js → casbin-BHijLuHY.js} +2 -2
- package/dist/{casbin-Dyu2gnUD.js → casbin-BW9pS47J.js} +1 -1
- package/dist/{casl-64gpT-8x.js → casl-CmJlgziS.js} +2 -2
- package/dist/{casl-DjEDhTCP.js → casl-UbI8v-Wq.js} +1 -1
- package/dist/catalog/index.d.ts +70 -10
- package/dist/catalog/index.js +112 -6
- package/dist/catalog-BCCjSAdH.js +1 -0
- package/dist/{catalog-DZVbrF-z.js → catalog-BaMQfQ6Y.js} +3 -3
- package/dist/{catalog-HD2gf5mY.js → catalog-D69WhFii.js} +43 -13
- package/dist/{catalog-doc-Cdn7-0pQ.js → catalog-doc-CV9s6B1S.js} +28 -5
- package/dist/{catalog-fingerprint-CCP0-yQS.js → catalog-fingerprint-C144oW4M.js} +1 -1
- package/dist/{create-CQWIpUG-.js → challenge-nGWma08S.js} +122 -25
- 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-BC_0mPIq.js +37 -0
- package/dist/claude-agent/index.d.ts +3 -3
- package/dist/claude-agent/index.js +2 -2
- package/dist/clerk/index.d.ts +3 -3
- package/dist/clerk/index.js +1 -1
- package/dist/cli/bin.js +2 -2
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +3 -3
- package/dist/cloud/index.d.ts +127 -11
- package/dist/cloud/index.js +251 -3
- package/dist/{cloud-ytQ3uviA.js → cloud-CO8pYtwr.js} +5 -5
- package/dist/{codemod-ua2hHy7w.js → codemod-BP6n8N9L.js} +3 -3
- package/dist/{codemod-5mpSpnUY.js → codemod-i4N2BhDc.js} +3 -3
- package/dist/{collect-mLTY4nwb.js → collect-BaWeMjwV.js} +17 -8
- package/dist/{collect-Ci6akVwH.js → collect-DNm3oKOk.js} +6 -5
- package/dist/collect-k_Dulxr5.js +1 -0
- package/dist/compile/index.d.ts +1 -1
- package/dist/compile/index.js +1 -1
- package/dist/{compile-CMqMx_IN.js → compile-BAEO5bOk.js} +2 -2
- package/dist/{compile-1bsAezL0.d.ts → compile-COM2VKuN.d.ts} +3 -3
- package/dist/{completion-BTFrHZhX.js → completion-BNdVf7X2.js} +3 -3
- package/dist/{config-bs_kZeYq.js → config-CoQHDrDi.js} +7 -3
- package/dist/{config-Bj2Ixq3d.js → config-DGZzMV1B.js} +2 -2
- package/dist/{config-report-DSpsLpCE.js → config-report-Cm7UITNA.js} +3 -3
- package/dist/connector-schema-_VCSsdtD.js +433 -0
- package/dist/{context-B_u3_bDJ.js → context--uM9V3Ui.js} +2 -2
- package/dist/convex/index.d.ts +5 -5
- package/dist/convex/index.js +2 -2
- package/dist/core-B5-w6Kw9.js +335 -0
- package/dist/core-CQkE8Esr.d.ts +179 -0
- package/dist/{create-B30OMUOJ.d.ts → create-B2-CQqCI.d.ts} +5 -5
- package/dist/{create-CGm28gyI.js → create-Cb86Z8Im.js} +9 -8
- package/dist/{create-DCF2SvoT.js → create-DJrlhEp9.js} +5 -5
- package/dist/{create-D_NmPOdH.d.ts → create-QHuuPw3q.d.ts} +7 -7
- package/dist/{create-CBMmFie-.d.ts → create-UTnUVETj.d.ts} +30 -10
- package/dist/{credential-BcoiejpY.js → credential-CIM7wHwA.js} +4 -4
- package/dist/{credentials-DPyHmYz5.js → credentials-BpuTwd7a.js} +1 -1
- package/dist/{deciding-columns-Sq12mEA6.js → deciding-columns-DRo2QM6E.js} +13 -2
- package/dist/{delegation-j6-rc37o.js → delegation-C5rOdTp5.js} +5 -5
- package/dist/delivery/index.d.ts +5 -5
- package/dist/delivery/index.js +4 -3
- package/dist/{delivery-DCAgNyCn.js → delivery-rwOKLWRm.js} +51 -2
- package/dist/{denied-text-CiFQNuMV.d.ts → denied-text-D4qkEtFz.d.ts} +2 -2
- package/dist/{describe-BybMRY7A.js → describe-DZlnEtLy.js} +1 -0
- package/dist/{describe-B5qgDvEW.d.ts → describe-O0SwYIK8.d.ts} +2 -2
- package/dist/{diff-CmuSD3vc.js → diff-Btr1c1Ow.js} +2 -2
- package/dist/{diff-3jbx6Rm4.js → diff-DzT-xD13.js} +10 -10
- package/dist/{doctor-BdZw53-k.js → doctor-BU1szn63.js} +241 -49
- package/dist/{doctor-3ZqNHX_G.js → doctor-BoK_y0KO.js} +4 -4
- package/dist/drizzle/index.d.ts +3 -3
- package/dist/drizzle/index.js +1 -1
- package/dist/elysia/index.d.ts +5 -5
- package/dist/elysia/index.js +3 -3
- package/dist/{errors-DH5QEGXh.d.ts → errors-B_Qg9D3e.d.ts} +2 -2
- package/dist/{errors-CWTY6uih.js → errors-DpP_U6Bf.js} +1 -0
- package/dist/{evaluate-CNClBvcj.js → evaluate-B_oqFbWC.js} +55 -12
- package/dist/{evaluations-C_1vdSZc.d.ts → evaluations-BCddEOfO.d.ts} +4 -4
- package/dist/{evaluations-beAooV0n.js → evaluations-DReoiVBw.js} +4 -4
- package/dist/eve/index.d.ts +5 -5
- package/dist/eve/index.js +3 -3
- package/dist/express/index.d.ts +5 -5
- package/dist/express/index.js +3 -3
- package/dist/fastify/index.d.ts +5 -5
- package/dist/fastify/index.js +3 -3
- package/dist/{fetch-adapter-Dw0MTS3D.d.ts → fetch-adapter-CuhyYwC1.d.ts} +4 -4
- package/dist/{fetch-adapter-DD_gfmrC.js → fetch-adapter-De-u6vhJ.js} +3 -3
- package/dist/{fields-OYG_JR78.js → fields-ClcQLrVc.js} +48 -13
- package/dist/{files-C5ZI27eV.js → files-acUbNwWt.js} +15 -2
- package/dist/{fixtures-B7XrLeY7.js → fixtures-BTMW6zgU.js} +2 -2
- package/dist/{flags-C3DktBDY.js → flags-aaeRAdiD.js} +2 -2
- package/dist/{from-snapshot-CTCMsFZk.js → from-snapshot-Bz469dIh.js} +17 -10
- package/dist/generate-3FNO5P5Q.js +159 -0
- package/dist/{grantee-hxrUsbpM.js → grantee-BrRANrpT.js} +1 -1
- package/dist/{grantee-conditions-CcXf8hMM.js → grantee-conditions-C6P1Tvol.js} +1 -1
- package/dist/{grantee-match-DbENBHLB.js → grantee-match-0RtHWQDx.js} +3 -3
- package/dist/h3/index.d.ts +4 -4
- package/dist/h3/index.js +3 -3
- package/dist/{helpers-CBYVMjwh.js → helpers-DY3vXuGs.js} +3 -3
- package/dist/hono/index.d.ts +5 -5
- package/dist/hono/index.js +3 -3
- package/dist/{hosted-BPk51-kX.d.ts → hosted-BmjzxQhp.d.ts} +14 -2
- package/dist/{hosted-B46-5LYE.js → hosted-XBgU6RGT.js} +34 -12
- package/dist/{http-DXJ37RDA.js → http-Ca3Sr5x1.js} +1 -1
- package/dist/{import-wyqXUyjm.js → import-Bz0GefWg.js} +5 -5
- package/dist/{import-CNV7I2Dw.js → import-DB2EG_iy.js} +3 -3
- package/dist/{index-C-6Letxg.d.ts → index-BE8y3moU.d.ts} +50 -8
- package/dist/{index-B8YjkEZ4.d.ts → index-BSfRl0hZ.d.ts} +6 -6
- package/dist/{index-DuWxc5dt.d.ts → index-BTkwrK7v.d.ts} +143 -14
- package/dist/index-CMiPH2Tv.d.ts +206 -0
- package/dist/{index-Ch8LpNDp.d.ts → index-DH9DUDEM.d.ts} +18 -3
- package/dist/{index-CueFnxQc.d.ts → index-DLwcuCN_.d.ts} +86 -7
- package/dist/index.d.ts +18 -17
- package/dist/index.js +27 -25
- package/dist/{init-GG6Jh8HD.js → init-5TXNji88.js} +5 -5
- package/dist/{init-DeMYsnYJ.js → init-B-4t1NzC.js} +4 -4
- package/dist/{instance-options-BsVpyGIk.d.ts → instance-options-CU0YQCLH.d.ts} +1 -1
- package/dist/{instance-snapshot-BOEhcqIF.js → instance-snapshot-CjcwnEiV.js} +16 -11
- package/dist/jwt/index.d.ts +83 -5
- package/dist/jwt/index.js +143 -5
- package/dist/{kernel-D0NVb1cK.js → kernel-DVExUwkp.js} +138 -12
- package/dist/kysely/index.d.ts +3 -3
- package/dist/kysely/index.js +1 -1
- package/dist/load-DrMHXzgN.js +1 -0
- package/dist/{load-DFS_ry0W.js → load-DxroEzH1.js} +2 -2
- package/dist/{login-Dfe5RlYk.js → login-ClSJh5t5.js} +4 -4
- package/dist/{login-imhuwvn3.js → login-WC9HPJpU.js} +6 -10
- package/dist/{manifest-C8IzW3Do.js → manifest-B79YuF2T.js} +6 -2
- package/dist/{manifest-mx5ghSFM.d.ts → manifest-BVhExYhw.d.ts} +23 -2
- package/dist/{manifest-dvL2XEe1.js → manifest-Dv6q4i5s.js} +54 -35
- package/dist/{manifest-schema-C0kK_8V0.js → manifest-schema-Cv492Qev.js} +37 -7
- package/dist/{map-claims-D3oRmTk0.js → map-claims-etGIS_Dv.js} +14 -11
- package/dist/{map-error-Dr70oA_3.js → map-error-BQGyDm_M.js} +1 -1
- package/dist/mcp/index.d.ts +64 -10
- package/dist/mcp/index.js +151 -22
- package/dist/{migrate-CIq4-E9F.js → migrate-Dodel0IJ.js} +77 -24
- package/dist/nest/index.d.ts +5 -5
- package/dist/nest/index.js +3 -3
- package/dist/next/index.d.ts +9 -9
- package/dist/next/index.js +5 -5
- package/dist/next/plugin.d.ts +1 -1
- package/dist/next/plugin.js +2 -2
- package/dist/node/index.d.ts +5 -5
- package/dist/node/index.js +2 -2
- package/dist/openai/index.d.ts +5 -5
- package/dist/openai/index.js +3 -3
- package/dist/openapi/index.d.ts +14 -4
- package/dist/openapi/index.js +1 -1
- package/dist/{openapi-C4dDTVEd.js → openapi-DMocl1bh.js} +4 -4
- package/dist/{openapi-B7HZ0f-r.js → openapi-Ddb4628T.js} +2 -7
- package/dist/{openapi-DD1SV-5-.js → openapi-ztVaux6j.js} +8 -8
- package/dist/{operation-findings-DgATDpvh.js → operation-findings-kRcEp8lE.js} +1 -1
- package/dist/{operations-X0VM7F3m.d.ts → operations-BNLes61x.d.ts} +1 -1
- package/dist/orpc/index.d.ts +6 -6
- package/dist/orpc/index.js +4 -4
- package/dist/otel/index.d.ts +3 -3
- package/dist/otel/index.js +1 -1
- package/dist/{output-1im__-08.js → output-DgSDLrta.js} +7 -3
- package/dist/{output-files-DhRBBE4n.js → output-files-CCMdcFWb.js} +2 -2
- package/dist/output-files-DPAY7-GX.js +1 -0
- package/dist/{ownership-DqaJNJPn.js → ownership-Z2LpxsGa.js} +443 -40
- package/dist/parse-Ddhz2xf4.js +148 -0
- package/dist/{parse-local-manifest-CVSs6J9I.js → parse-local-manifest-T1Q8X3A2.js} +24 -1
- package/dist/{parse-local-manifest-5ODwqu8b.d.ts → parse-local-manifest-e4mdwAKd.d.ts} +1 -1
- package/dist/pdp/index.d.ts +3 -3
- package/dist/pdp/index.js +7 -3
- package/dist/peer-12Q5I_RH.js +976 -0
- package/dist/{peer-CRvC7Hg1.js → peer-DOzzMfZL.js} +1 -1
- package/dist/{permdock-BrAscV28.js → permdock-BfWEeMqk.js} +177 -49
- package/dist/{permdock-SV8ZINYT.d.ts → permdock-Dco6dyCK.d.ts} +34 -5
- package/dist/{permission-registry-Br4jSNVi.js → permission-registry-DpPtSKNZ.js} +1 -1
- package/dist/{vocabulary-CN8H_9UF.d.ts → permission-types-DhNEmoRG.d.ts} +4 -64
- package/dist/{permissions-u_KHg-sN.d.ts → permissions-CoqCOfJ3.d.ts} +2 -1
- package/dist/{permissions-B-wCP5ZC.js → permissions-CyH2MV_B.js} +1 -1
- package/dist/{permissions-BPxlwVhN.js → permissions-DArULThq.js} +4 -4
- package/dist/pkce-5h8NgMQJ.js +21 -0
- package/dist/{policies-DP2nqRoF.js → policies-B2lZIurj.js} +3 -3
- package/dist/{policy-77FSAq_V.d.ts → policy-B7dg_yzu.d.ts} +2 -2
- package/dist/{policy-DbM5YYtV.js → policy-DaJy4nK4.js} +17 -8
- package/dist/{policy-from-catalog-C2gMa2Dj.js → policy-from-catalog-DFWYkNdu.js} +9 -9
- package/dist/{policy-types-n0uRTsW8.d.ts → policy-types-B-F-qAZk.d.ts} +83 -4
- package/dist/postgres-store-BL9M_CA1.js +1001 -0
- package/dist/{postgrest-CEgRbefE.d.ts → postgrest-CYacM_u7.d.ts} +12 -1
- package/dist/{postgrest-DAjUkF9w.js → postgrest-r5faDIzD.js} +37 -4
- package/dist/{powersync-DISt6SUe.js → powersync-13odBwiM.js} +3 -3
- package/dist/powersync-53ryOZip.js +1059 -0
- package/dist/powersync-CExtTLyA.js +1 -0
- package/dist/preset/index.js +1 -1
- package/dist/{preset-DZdU0tne.js → preset-CHTbd-DQ.js} +2 -2
- package/dist/prisma/index.d.ts +2 -2
- package/dist/prisma/index.js +1 -1
- package/dist/{problem-details-B45V5d2b.d.ts → problem-details-Tcfmj3bV.d.ts} +1 -1
- package/dist/prompt-DwtVemER.js +935 -0
- package/dist/{protected-RFGpakN9.d.ts → protected-BwZYL1X_.d.ts} +6 -5
- package/dist/{protected-BlF0F6wL.js → protected-DXE3cQYg.js} +2 -2
- package/dist/{provider-B1al-AZz.js → provider-BQsTYYy0.js} +2 -2
- package/dist/{provider-DILL9oPK.d.ts → provider-Csk-THAn.d.ts} +1 -1
- package/dist/{provider-store-DM6DNcta.js → provider-store-IgqQipCO.js} +2 -2
- package/dist/{pull-jEwbf80J.js → pull-CN5OLxrF.js} +7 -7
- package/dist/pull-Cty6Ovyu.js +1 -0
- package/dist/{push-BD4f15co.js → push-tVdG8dUL.js} +54 -14
- package/dist/{pushed-policy-DCW91KQU.d.ts → pushed-policy-BbcY9r_4.d.ts} +1 -1
- package/dist/{pushed-policy-CqtxkV4G.js → pushed-policy-CmYeSQqq.js} +1 -1
- package/dist/react/index.d.ts +6 -6
- package/dist/react/index.js +3 -3
- package/dist/react/provider-client.d.ts +1 -1
- package/dist/react/provider-client.js +1 -1
- package/dist/react-native/index.d.ts +25 -11
- package/dist/react-native/index.js +209 -21
- package/dist/{refs-K6eWUJ0H.js → refs-CNJBiTFo.js} +15 -1
- package/dist/{replay-Bkm-Ne4l.d.ts → replay-DCDD_ZfL.d.ts} +1 -1
- package/dist/{request-context-C81Pip9n.js → request-context-BykKLmyE.js} +2 -2
- package/dist/resend/index.d.ts +4 -4
- package/dist/{retire-CALjIQ7e.js → retire-Wj6dkyDE.js} +2 -2
- package/dist/{rls-BAqP4q66.js → rls-Ck_PocSp.js} +32 -8
- package/dist/{rls-DTvYd-lI.js → rls-CxBZb4rZ.js} +478 -534
- package/dist/{role-builder-uWQZ4v84.js → role-builder-C1VJzvcr.js} +3 -3
- package/dist/rolldown-runtime-C3I60J0A.js +4 -0
- package/dist/{rpc-VSl5ylaQ.js → rpc-Bk1bE-ch.js} +1 -1
- package/dist/run-Bz7DXGEv.js +1 -0
- package/dist/{run-ticket-sxFI6LAk.js → run-ticket-B5d_63Ma.js} +22 -1
- package/dist/{run-ticket-DocwaTKn.d.ts → run-ticket-BpNi7BCi.d.ts} +8 -3
- package/dist/{run-CUKuz0A8.js → run-uLD2aWuO.js} +7 -7
- package/dist/{runtime-D3VTAiCA.js → runtime-Vif3_-zf.js} +1 -1
- package/dist/{saas-BCXRuXca.js → saas-Az_Kz-4D.js} +7 -7
- package/dist/{scan-qvOe0hS3.js → scan-DSljDE1Y.js} +1 -1
- package/dist/{schema-yLuBWWsh.js → schema-gIcCx7zM.js} +1 -1
- package/dist/scim/index.d.ts +3 -2
- package/dist/scim/index.js +3 -1
- package/dist/scim-C7JYhySg.js +44 -0
- package/dist/{scim-ClHtpyV3.js → scim-YNieBO1U.js} +3 -537
- package/dist/{scopes-CUPSjo9q.js → scopes-BHsc-wp-.js} +1 -1
- package/dist/server/index.d.ts +11 -11
- package/dist/server/index.js +7 -7
- package/dist/{server-C3WXAHZj.js → server-Bnga6I50.js} +3 -3
- package/dist/{server-types-CKQiCnON.d.ts → server-types-C4gZUEZy.d.ts} +9 -9
- package/dist/{shared-DvvFzYXe.js → shared-C8LjUdVU.js} +1 -1
- package/dist/{shared-BAK8t4Uo.js → shared-fMKOv8hP.js} +44 -38
- package/dist/{sink-4-eQIRWf.d.ts → sink-Cp_Eot9W.d.ts} +4 -4
- package/dist/{skills-B6lVdD_W.js → skills-Dcjw9_1C.js} +5 -5
- package/dist/{skills-CTYwkl44.js → skills-g_3BS9NC.js} +3 -3
- package/dist/{snapshot-B7DkYg6g.js → snapshot-CbGmYiJx.js} +4 -4
- package/dist/{snapshot-cache-DZHQ0KF6.js → snapshot-cache-DT2Kx1F8.js} +1 -1
- package/dist/{snapshot-cache-PXI-vGpY.d.ts → snapshot-cache-Pahd3IYJ.d.ts} +1 -1
- package/dist/solid/index.d.ts +6 -5
- package/dist/solid/index.js +4 -4
- package/dist/solid-start/index.d.ts +6 -6
- package/dist/solid-start/index.js +3 -3
- package/dist/{sources-vs5dGOsS.js → sources-B-zYB4GS.js} +111 -25
- package/dist/{sources-Xc4zkszI.d.ts → sources-DEEuGb8S.d.ts} +63 -14
- package/dist/sources-qoIJQrJv.js +11 -0
- package/dist/{sql-B5T1IL83.js → sql-B96movIM.js} +5 -1
- package/dist/sql-CDEPCA0g.d.ts +10 -0
- package/dist/{src-Cu2m75uo.js → src-DLFrtrrC.js} +140 -48
- package/dist/ssf/index.d.ts +4 -4
- package/dist/ssf/index.js +640 -211
- package/dist/{standard-webhooks-rbD7LS6h.d.ts → standard-webhooks-B_qRg0ws.d.ts} +2 -2
- package/dist/{store-BDutJkDL.js → store-DSP9oGvh.js} +15 -7
- package/dist/{store-options-u0ycEe8s.js → store-options-B_poyYvg.js} +6 -6
- package/dist/{stores-BUGNbJTt.d.ts → stores-BAZwSYZA.d.ts} +6 -5
- package/dist/{stores-CGhM8BN_.js → stores-BqEuHC05.js} +2 -2
- package/dist/{stream-CeCMJmBB.d.ts → stream-2Vwhl7Er.d.ts} +2 -2
- package/dist/{style-Uao76wO7.js → style-Cqo7-73x.js} +1 -0
- package/dist/{style-DiKWnAvn.js → style-Ds1gNm77.js} +1 -1
- package/dist/supabase/index.d.ts +8 -7
- package/dist/supabase/index.js +5 -5
- package/dist/supabase/middleware.d.ts +6 -6
- package/dist/supabase/middleware.js +6 -6
- package/dist/{supabase-x5JtR2tc.js → supabase--0aJdLEd.js} +8 -6
- package/dist/{supabase-By_frk3U.js → supabase-Bqp7iIY2.js} +3 -3
- package/dist/supabase-hook-DJxC4PoP.js +1 -0
- package/dist/{supabase-hook-BMoEhZir.js → supabase-hook-Dg0SrQWR.js} +1060 -119
- package/dist/supautils-MESd81bF.js +689 -0
- package/dist/{support-session-C6xJQYut.js → support-session-Cna49-3f.js} +2 -2
- package/dist/svelte/index.d.ts +5 -5
- package/dist/svelte/index.js +5 -5
- package/dist/svelte/runtime.d.ts +3 -3
- package/dist/svelte/runtime.js +3 -3
- package/dist/svelte/source.d.ts +5 -5
- package/dist/svelte/source.js +2 -2
- package/dist/sveltekit/index.d.ts +6 -6
- package/dist/sveltekit/index.js +2 -2
- package/dist/tanstack-start/index.d.ts +6 -6
- package/dist/tanstack-start/index.js +2 -2
- package/dist/{tenancy-DN2QAx9z.js → tenancy-CmeBQ6Nv.js} +12 -3
- package/dist/terminal/index.d.ts +6 -6
- package/dist/terminal/index.js +3 -3
- package/dist/testing/core.d.ts +2 -0
- package/dist/testing/core.js +1 -0
- package/dist/testing/fixtures/index.d.ts +12 -0
- package/dist/testing/fixtures/index.js +770 -0
- package/dist/testing/index.d.ts +41 -174
- package/dist/testing/index.js +241 -731
- package/dist/testing/saas/index.d.ts +5 -5
- package/dist/testing/saas/index.js +2 -2
- package/dist/testing/saas/permissions.d.ts +1 -1
- package/dist/testing/saas/permissions.js +1 -1
- package/dist/text-diff-DhITNCnD.js +444 -0
- package/dist/{token-BLZcjQgt.js → token-2qYDvXz2.js} +1 -1
- package/dist/{tool-refusal-CMLN5xhn.js → tool-refusal-reAhIzdl.js} +1 -1
- package/dist/trpc/index.d.ts +6 -6
- package/dist/trpc/index.js +3 -3
- package/dist/{types-Dfv0aTER.d.ts → types-BWZybqs9.d.ts} +110 -8
- package/dist/{types-Druu9wLM.d.ts → types-BXMYB7BY.d.ts} +2 -2
- package/dist/{types-BzzaHxt3.d.ts → types-BfVmNJO5.d.ts} +14 -3
- package/dist/{types-lUlG3TVd.d.ts → types-CIeZcG8v.d.ts} +2 -2
- package/dist/{types-B3_ooZgZ.d.ts → types-CKV71kKh.d.ts} +4 -4
- package/dist/{types-CX7AvRqP.d.ts → types-CQVEQawv.d.ts} +4 -4
- package/dist/{types-C863OQiR.d.ts → types-CeIscIKp.d.ts} +4 -4
- package/dist/{types-C_IiEs64.d.ts → types-CfiKC5aN.d.ts} +1 -1
- package/dist/{types-_WhUP7ud.d.ts → types-D3A19w4A.d.ts} +8 -4
- package/dist/{types-8RnwUAvE.d.ts → types-DBHftjgS.d.ts} +15 -8
- package/dist/{types-BdtSDbBO.d.ts → types-DC44-hqb.d.ts} +2 -2
- package/dist/{types-CVZSNocA.d.ts → types-DXmwu78Z.d.ts} +4 -4
- package/dist/{types-C791HFu9.d.ts → types-cTos-H7p.d.ts} +2 -2
- package/dist/{types-BtHtcKMr.d.ts → types-g7Oy6Zg4.d.ts} +3 -3
- package/dist/unplugin/index.d.ts +1 -1
- package/dist/unplugin/index.js +2 -2
- package/dist/{usage-SveTRTyr.js → usage-Bybmck7f.js} +7 -7
- package/dist/{usage-CRVl9V3t.js → usage-CDaLXCfL.js} +2 -2
- package/dist/usage-y-kBNdqs.js +1 -0
- package/dist/{validation-error-DHUrAkku.d.ts → validation-error-CQpoquwj.d.ts} +1 -1
- package/dist/{verify-BaAKx7t6.js → verify-pe8rL_Qw.js} +350 -83
- package/dist/{views-DTIIO-oQ.js → views-BB8E9dTP.js} +1 -1
- package/dist/vocabulary-Bg3eeT2H.d.ts +67 -0
- package/dist/vue/index.d.ts +6 -5
- package/dist/vue/index.js +4 -4
- package/dist/{waiter-B986w1oK.d.ts → waiter-DwEyouan.d.ts} +2 -2
- package/dist/watch-Bd9mx3rd.js +1 -0
- package/dist/{watch-vea54PRw.js → watch-C-4VmFlL.js} +3 -3
- package/dist/webmcp/index.d.ts +2 -2
- package/dist/webmcp/index.js +2 -2
- package/dist/{where-scope-C9vfEphl.js → where-scope-wq2coopv.js} +41 -21
- package/dist/{who-can-DWBAcaCQ.js → who-can-BwNsI_Js.js} +6 -6
- package/dist/workflow/index.d.ts +3 -3
- package/dist/workflow/index.js +5 -5
- package/dist/workflow-sdk/index.d.ts +5 -5
- package/dist/{wrap-C5jC6sKI.d.ts → wrap-B6R0cMRL.d.ts} +2 -2
- package/dist/{wrap-gX61EtpB.js → wrap-CiSc_KCq.js} +8 -2
- package/package.json +22 -11
- package/schemas/cli-result-v1.json +1 -0
- package/schemas/cloud-api-v1.json +152 -7
- package/schemas/connector-v1.json +8 -0
- package/schemas/supabase-claims-v1.json +5 -0
- package/schemas/supabase-manifest-v1.json +276 -75
- package/skills/permdock/SKILL.md +1 -0
- package/skills/permdock-agents/references/runtimes.md +3 -1
- package/skills/permdock-approvals/references/stores-and-resume.md +2 -1
- package/skills/permdock-data/references/queries-and-rls.md +4 -1
- package/skills/permdock-tenancy/SKILL.md +1 -1
- package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +1 -0
- package/skills/permdock-wire/references/adapters.md +14 -0
- package/skills/permdock-wire/references/policy-options.md +1 -0
- package/dist/catalog-BoWglDPI.js +0 -1
- package/dist/collect-D7eQDffE.js +0 -1
- package/dist/index-Cp_ilKi1.d.ts +0 -91
- package/dist/load-BxEtwlBS.js +0 -1
- package/dist/output-files-B3IZJksC.js +0 -1
- package/dist/parse-Cxq0WxrA.js +0 -53
- package/dist/peer-C8swJ2GH.js +0 -50
- package/dist/powersync-BkWWCS1K.js +0 -538
- package/dist/powersync-MMJ2mI2q.js +0 -1
- package/dist/prompt-DfZLJLIn.js +0 -32
- package/dist/pull-CvpINcMK.js +0 -1
- package/dist/run-DDwUaJDU.js +0 -1
- package/dist/supabase-hook-CCw5m35C.js +0 -1
- package/dist/supautils-B6HYL9eL.js +0 -91
- package/dist/text-diff-BQcUapOb.js +0 -15
- package/dist/usage-CZpSQP6L.js +0 -1
- package/dist/watch--ovlPOc0.js +0 -1
package/dist/ssf/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { r as isRecord, t as compact } from "../compact-CAf557ZB.js";
|
|
2
|
+
import { o as statusProblem } from "../problem-details-cn5X30gZ.js";
|
|
2
3
|
import { o as epochSeconds } from "../time-DkWjdL98.js";
|
|
3
4
|
import { n as readBodyText } from "../body-text-QcXok_SI.js";
|
|
4
|
-
import {
|
|
5
|
+
import { a as methodNotAllowed, c as problemResponse, d as validationProblem, o as notFoundProblem } from "../problem-CTviyH5L.js";
|
|
6
|
+
import { t as cancelApprovals } from "../helpers-DY3vXuGs.js";
|
|
5
7
|
import { i as issuerFromDiscovery, t as joseTokenVerifier } from "../verifier-DHuh-okk.js";
|
|
6
8
|
import { t as memoryReplayStore } from "../replay-Du1tJjG7.js";
|
|
7
9
|
import { t as timeoutSignal } from "../timeout-D51niuQP.js";
|
|
@@ -78,73 +80,15 @@ function eventName(uri) {
|
|
|
78
80
|
return RISC_NAMES.find((known) => known === name);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
83
|
+
/** Every CAEP and RISC event URI PermDock's receiver handles. */
|
|
84
|
+
function knownEventTypes() {
|
|
85
|
+
return [...CAEP_NAMES.map((name) => `${CAEP_PREFIX}${name}`), ...RISC_NAMES.map((name) => `${RISC_PREFIX}${name}`)];
|
|
86
|
+
}
|
|
81
87
|
/** RISC events that end every session of the subject. */
|
|
82
88
|
function revokesAccount(name) {
|
|
83
89
|
return RISC_NAMES.some((known) => known === name);
|
|
84
90
|
}
|
|
85
91
|
//#endregion
|
|
86
|
-
//#region src/ssf/poll.ts
|
|
87
|
-
/** Milliseconds a poll or acknowledgement request may take. */
|
|
88
|
-
const POLL_TIMEOUT_MS = 3e4;
|
|
89
|
-
/**
|
|
90
|
-
* One RFC 8936 poll round: fetch the pending SETs, ingest them and acknowledge
|
|
91
|
-
* the ones that were accepted. Returns the acknowledged `jti` values.
|
|
92
|
-
*/
|
|
93
|
-
async function pollOnce(input) {
|
|
94
|
-
const { options, acks, ingest, emit } = input;
|
|
95
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
96
|
-
const headers = { "content-type": "application/json" };
|
|
97
|
-
if (options.token !== void 0) headers["authorization"] = `Bearer ${options.token}`;
|
|
98
|
-
const body = {
|
|
99
|
-
maxEvents: 100,
|
|
100
|
-
returnImmediately: true
|
|
101
|
-
};
|
|
102
|
-
if (acks.length > 0) body["acks"] = acks;
|
|
103
|
-
const requestInit = compact({
|
|
104
|
-
method: "POST",
|
|
105
|
-
headers,
|
|
106
|
-
body: JSON.stringify(body),
|
|
107
|
-
signal: timeoutSignal(POLL_TIMEOUT_MS, options.signal)
|
|
108
|
-
});
|
|
109
|
-
const response = await fetchFn(options.endpoint, requestInit);
|
|
110
|
-
if (!response.ok) {
|
|
111
|
-
emit({
|
|
112
|
-
type: "poll-failed",
|
|
113
|
-
err: "connection_failed"
|
|
114
|
-
});
|
|
115
|
-
return [];
|
|
116
|
-
}
|
|
117
|
-
const parsed = await response.json();
|
|
118
|
-
if (!isRecord(parsed) || !isRecord(parsed["sets"])) return [];
|
|
119
|
-
const tokens = Object.entries(parsed["sets"]).flatMap(([jti, jwt]) => typeof jwt === "string" ? [{
|
|
120
|
-
jti,
|
|
121
|
-
jwt
|
|
122
|
-
}] : []);
|
|
123
|
-
const outcomes = await Promise.all(tokens.map(async ({ jti, jwt }) => ({
|
|
124
|
-
jti,
|
|
125
|
-
result: await ingest(jwt)
|
|
126
|
-
})));
|
|
127
|
-
const processed = outcomes.flatMap((row) => row.result.ok ? [row.jti] : []);
|
|
128
|
-
const setErrs = {};
|
|
129
|
-
for (const { jti, result } of outcomes) if (!result.ok && result.cause !== void 0) setErrs[jti] = {
|
|
130
|
-
err: result.err,
|
|
131
|
-
description: result.description
|
|
132
|
-
};
|
|
133
|
-
const failed = Object.keys(setErrs).length;
|
|
134
|
-
if (processed.length > 0 || failed > 0) await fetchFn(options.endpoint, compact({
|
|
135
|
-
method: "POST",
|
|
136
|
-
headers,
|
|
137
|
-
body: JSON.stringify(compact({
|
|
138
|
-
acks: processed,
|
|
139
|
-
setErrs: failed > 0 ? setErrs : void 0,
|
|
140
|
-
maxEvents: 0,
|
|
141
|
-
returnImmediately: true
|
|
142
|
-
})),
|
|
143
|
-
signal: timeoutSignal(POLL_TIMEOUT_MS, options.signal)
|
|
144
|
-
}));
|
|
145
|
-
return processed;
|
|
146
|
-
}
|
|
147
|
-
//#endregion
|
|
148
92
|
//#region src/ssf/wire.ts
|
|
149
93
|
const SET_TYP = "secevent+jwt";
|
|
150
94
|
const LOGOUT_TYP = "logout+jwt";
|
|
@@ -207,6 +151,282 @@ function parseEvery(every) {
|
|
|
207
151
|
return Number(match[1]) * scale;
|
|
208
152
|
}
|
|
209
153
|
//#endregion
|
|
154
|
+
//#region src/ssf/transmitter.ts
|
|
155
|
+
/** SSF 1.0 delivery method URN for RFC 8935 push. */
|
|
156
|
+
const SSF_PUSH_DELIVERY = "urn:ietf:rfc:8935";
|
|
157
|
+
/** SSF 1.0 delivery method URN for RFC 8936 poll. */
|
|
158
|
+
const SSF_POLL_DELIVERY = "urn:ietf:rfc:8936";
|
|
159
|
+
/** Milliseconds one push may take. */
|
|
160
|
+
const PUSH_TIMEOUT_MS = 3e4;
|
|
161
|
+
/** The largest error body `pushSet` reads. */
|
|
162
|
+
const MAX_ERROR_BYTES = 16384;
|
|
163
|
+
/**
|
|
164
|
+
* Signs one event as an RFC 8417 Security Event Token (`typ: secevent+jwt`):
|
|
165
|
+
* `sub_id` is the event's subject and `events` holds exactly one entry, as
|
|
166
|
+
* SSF 1.0 requires. `iss` is the signer's own.
|
|
167
|
+
*/
|
|
168
|
+
function signSet(event, signer, options) {
|
|
169
|
+
return signer.sign(compact({
|
|
170
|
+
sub_id: event.subject,
|
|
171
|
+
events: { [event.type]: event.payload },
|
|
172
|
+
txn: options.txn
|
|
173
|
+
}), compact({
|
|
174
|
+
typ: SET_TYP,
|
|
175
|
+
audience: options.audience,
|
|
176
|
+
jti: options.jti,
|
|
177
|
+
issuedAt: options.issuedAt
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
const ERR_CAUSES = {
|
|
181
|
+
invalid_request: "invalid-request",
|
|
182
|
+
invalid_key: "invalid-key",
|
|
183
|
+
invalid_issuer: "invalid-issuer",
|
|
184
|
+
invalid_audience: "invalid-audience",
|
|
185
|
+
authentication_failed: "authentication-failed",
|
|
186
|
+
access_denied: "access-denied"
|
|
187
|
+
};
|
|
188
|
+
async function errorBody(response) {
|
|
189
|
+
const read = await readBodyText(response, MAX_ERROR_BYTES);
|
|
190
|
+
if (!read.ok) return {};
|
|
191
|
+
try {
|
|
192
|
+
const parsed = JSON.parse(read.text);
|
|
193
|
+
if (!isRecord(parsed)) return {};
|
|
194
|
+
return compact({
|
|
195
|
+
err: typeof parsed["err"] === "string" ? parsed["err"] : void 0,
|
|
196
|
+
description: typeof parsed["description"] === "string" ? parsed["description"] : void 0
|
|
197
|
+
});
|
|
198
|
+
} catch {
|
|
199
|
+
return {};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Pushes one SET to a receiver (RFC 8935). A `2xx` is delivery; a `400`
|
|
204
|
+
* maps the receiver's `err` to a cause; `401` and `403` are
|
|
205
|
+
* `authentication-failed` and `access-denied`; a network failure, a timeout,
|
|
206
|
+
* a `429` or a `5xx` is `unavailable` with `retry: true`. Never throws.
|
|
207
|
+
*/
|
|
208
|
+
async function pushSet(set, options) {
|
|
209
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
210
|
+
let response;
|
|
211
|
+
try {
|
|
212
|
+
response = await fetchFn(options.endpoint, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers: compact({
|
|
215
|
+
"content-type": SET_CONTENT,
|
|
216
|
+
accept: "application/json",
|
|
217
|
+
authorization: options.authorization
|
|
218
|
+
}),
|
|
219
|
+
body: set,
|
|
220
|
+
signal: timeoutSignal(PUSH_TIMEOUT_MS, options.signal)
|
|
221
|
+
});
|
|
222
|
+
} catch {
|
|
223
|
+
return {
|
|
224
|
+
ok: false,
|
|
225
|
+
cause: "unavailable",
|
|
226
|
+
retry: true
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (response.ok) {
|
|
230
|
+
await response.body?.cancel();
|
|
231
|
+
return { ok: true };
|
|
232
|
+
}
|
|
233
|
+
return deliveryFailure(response);
|
|
234
|
+
}
|
|
235
|
+
/** The `SetDelivery` failure for a non-`2xx` RFC 8935 or RFC 8936 response. */
|
|
236
|
+
async function deliveryFailure(response) {
|
|
237
|
+
const { err, description } = await errorBody(response);
|
|
238
|
+
if (response.status === 429 || response.status >= 500) return compact({
|
|
239
|
+
ok: false,
|
|
240
|
+
cause: "unavailable",
|
|
241
|
+
description,
|
|
242
|
+
retry: true
|
|
243
|
+
});
|
|
244
|
+
const cause = (response.status === 401 ? "authentication-failed" : response.status === 403 ? "access-denied" : void 0) ?? (err !== void 0 && Object.hasOwn(ERR_CAUSES, err) ? ERR_CAUSES[err] : void 0) ?? "invalid-request";
|
|
245
|
+
return compact({
|
|
246
|
+
ok: false,
|
|
247
|
+
cause,
|
|
248
|
+
description,
|
|
249
|
+
retry: false
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
function reason(value) {
|
|
253
|
+
return typeof value === "string" ? { en: value } : value;
|
|
254
|
+
}
|
|
255
|
+
function caep(name, input, extra) {
|
|
256
|
+
return Object.freeze({
|
|
257
|
+
type: `${CAEP_PREFIX}${name}`,
|
|
258
|
+
subject: input.subject,
|
|
259
|
+
payload: Object.freeze(compact({
|
|
260
|
+
event_timestamp: input.eventTimestamp ?? epochSeconds(),
|
|
261
|
+
initiating_entity: input.initiatingEntity,
|
|
262
|
+
reason_admin: reason(input.reasonAdmin),
|
|
263
|
+
reason_user: reason(input.reasonUser),
|
|
264
|
+
...extra
|
|
265
|
+
}))
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/** CAEP 1.0 event builders; each returns a `SetEvent` for `signSet`. */
|
|
269
|
+
const caepEvents = Object.freeze({
|
|
270
|
+
sessionRevoked: (input) => caep("session-revoked", input, {}),
|
|
271
|
+
credentialChange: (input) => caep("credential-change", input, compact({
|
|
272
|
+
credential_type: input.credentialType,
|
|
273
|
+
change_type: input.changeType,
|
|
274
|
+
friendly_name: input.friendlyName,
|
|
275
|
+
x509_issuer: input.x509Issuer,
|
|
276
|
+
x509_serial: input.x509Serial,
|
|
277
|
+
fido2_aaguid: input.fido2Aaguid
|
|
278
|
+
})),
|
|
279
|
+
tokenClaimsChange: (input) => caep("token-claims-change", input, { claims: input.claims }),
|
|
280
|
+
assuranceLevelChange: (input) => caep("assurance-level-change", input, compact({
|
|
281
|
+
namespace: input.namespace,
|
|
282
|
+
current_level: input.currentLevel,
|
|
283
|
+
previous_level: input.previousLevel,
|
|
284
|
+
change_direction: input.changeDirection
|
|
285
|
+
})),
|
|
286
|
+
deviceComplianceChange: (input) => caep("device-compliance-change", input, {
|
|
287
|
+
previous_status: input.previousStatus,
|
|
288
|
+
current_status: input.currentStatus
|
|
289
|
+
})
|
|
290
|
+
});
|
|
291
|
+
function risc(name, subject, payload) {
|
|
292
|
+
return Object.freeze({
|
|
293
|
+
type: `${RISC_PREFIX}${name}`,
|
|
294
|
+
subject,
|
|
295
|
+
payload: Object.freeze(payload)
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/** RISC 1.0 event builders for the events PermDock's receiver treats as revoking every session. */
|
|
299
|
+
const riscEvents = Object.freeze({
|
|
300
|
+
accountDisabled: (input) => risc("account-disabled", input.subject, compact({ reason: input.reason })),
|
|
301
|
+
accountPurged: (input) => risc("account-purged", input.subject, {}),
|
|
302
|
+
credentialCompromise: (input) => risc("credential-compromise", input.subject, compact({
|
|
303
|
+
credential_type: input.credentialType,
|
|
304
|
+
event_timestamp: input.eventTimestamp ?? epochSeconds(),
|
|
305
|
+
initiating_entity: input.initiatingEntity,
|
|
306
|
+
reason_admin: reason(input.reasonAdmin),
|
|
307
|
+
reason_user: reason(input.reasonUser)
|
|
308
|
+
}))
|
|
309
|
+
});
|
|
310
|
+
/**
|
|
311
|
+
* The SSF 1.0 section 8.1.4 verification event for `stream`, echoing the
|
|
312
|
+
* receiver's `state`. Its subject is the stream, never a principal.
|
|
313
|
+
*/
|
|
314
|
+
function streamVerificationEvent(stream, state) {
|
|
315
|
+
return Object.freeze({
|
|
316
|
+
type: VERIFICATION_EVENT,
|
|
317
|
+
subject: Object.freeze({
|
|
318
|
+
format: "opaque",
|
|
319
|
+
id: stream
|
|
320
|
+
}),
|
|
321
|
+
payload: Object.freeze(compact({ state }))
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/ssf/poll-client.ts
|
|
326
|
+
/** Milliseconds one poll request may take. */
|
|
327
|
+
const POLL_TIMEOUT_MS = 3e4;
|
|
328
|
+
/** The largest poll response read. */
|
|
329
|
+
const MAX_SETS_BYTES = 4194304;
|
|
330
|
+
/**
|
|
331
|
+
* One RFC 8936 poll request: sends `acks` and `setErrs` and answers the SETs
|
|
332
|
+
* the transmitter returns, unverified. A failure maps as `pushSet`'s does; a
|
|
333
|
+
* `2xx` body without a `sets` object is `invalid-request`. Never throws.
|
|
334
|
+
*/
|
|
335
|
+
async function pollSets(options) {
|
|
336
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
337
|
+
const acks = options.acks ?? [];
|
|
338
|
+
const setErrs = options.setErrs ?? {};
|
|
339
|
+
let response;
|
|
340
|
+
try {
|
|
341
|
+
response = await fetchFn(options.endpoint, {
|
|
342
|
+
method: "POST",
|
|
343
|
+
headers: compact({
|
|
344
|
+
"content-type": "application/json",
|
|
345
|
+
accept: "application/json",
|
|
346
|
+
authorization: options.authorization
|
|
347
|
+
}),
|
|
348
|
+
body: JSON.stringify(compact({
|
|
349
|
+
acks: acks.length > 0 ? acks : void 0,
|
|
350
|
+
setErrs: Object.keys(setErrs).length > 0 ? setErrs : void 0,
|
|
351
|
+
maxEvents: options.maxEvents ?? 100,
|
|
352
|
+
returnImmediately: options.returnImmediately ?? true
|
|
353
|
+
})),
|
|
354
|
+
signal: timeoutSignal(POLL_TIMEOUT_MS, options.signal)
|
|
355
|
+
});
|
|
356
|
+
} catch {
|
|
357
|
+
return {
|
|
358
|
+
ok: false,
|
|
359
|
+
cause: "unavailable",
|
|
360
|
+
retry: true
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
if (!response.ok) return deliveryFailure(response);
|
|
364
|
+
const read = await readBodyText(response, MAX_SETS_BYTES);
|
|
365
|
+
let parsed;
|
|
366
|
+
try {
|
|
367
|
+
parsed = read.ok ? JSON.parse(read.text) : void 0;
|
|
368
|
+
} catch {
|
|
369
|
+
parsed = void 0;
|
|
370
|
+
}
|
|
371
|
+
if (!isRecord(parsed) || !isRecord(parsed["sets"])) return {
|
|
372
|
+
ok: false,
|
|
373
|
+
cause: "invalid-request",
|
|
374
|
+
description: "poll response has no sets object",
|
|
375
|
+
retry: false
|
|
376
|
+
};
|
|
377
|
+
return {
|
|
378
|
+
ok: true,
|
|
379
|
+
sets: Object.entries(parsed["sets"]).flatMap(([jti, set]) => typeof set === "string" ? [{
|
|
380
|
+
jti,
|
|
381
|
+
set
|
|
382
|
+
}] : []),
|
|
383
|
+
moreAvailable: parsed["moreAvailable"] === true
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
//#endregion
|
|
387
|
+
//#region src/ssf/poll.ts
|
|
388
|
+
/**
|
|
389
|
+
* One RFC 8936 poll round: fetch the pending SETs, ingest them and acknowledge
|
|
390
|
+
* the ones that were accepted. Returns the acknowledged `jti` values.
|
|
391
|
+
*/
|
|
392
|
+
async function pollOnce(input) {
|
|
393
|
+
const { options, acks, ingest, emit } = input;
|
|
394
|
+
const transport = compact({
|
|
395
|
+
endpoint: options.endpoint,
|
|
396
|
+
authorization: options.token === void 0 ? void 0 : `Bearer ${options.token}`,
|
|
397
|
+
fetch: options.fetch,
|
|
398
|
+
signal: options.signal
|
|
399
|
+
});
|
|
400
|
+
const polled = await pollSets({
|
|
401
|
+
...transport,
|
|
402
|
+
acks
|
|
403
|
+
});
|
|
404
|
+
if (!polled.ok) {
|
|
405
|
+
emit({
|
|
406
|
+
type: "poll-failed",
|
|
407
|
+
err: "connection_failed"
|
|
408
|
+
});
|
|
409
|
+
return [];
|
|
410
|
+
}
|
|
411
|
+
const outcomes = await Promise.all(polled.sets.map(async ({ jti, set }) => ({
|
|
412
|
+
jti,
|
|
413
|
+
result: await ingest(set)
|
|
414
|
+
})));
|
|
415
|
+
const processed = outcomes.flatMap((row) => row.result.ok ? [row.jti] : []);
|
|
416
|
+
const setErrs = {};
|
|
417
|
+
for (const { jti, result } of outcomes) if (!result.ok && result.cause !== void 0) setErrs[jti] = {
|
|
418
|
+
err: result.err,
|
|
419
|
+
description: result.description
|
|
420
|
+
};
|
|
421
|
+
if (processed.length > 0 || Object.keys(setErrs).length > 0) await pollSets({
|
|
422
|
+
...transport,
|
|
423
|
+
acks: processed,
|
|
424
|
+
setErrs,
|
|
425
|
+
maxEvents: 0
|
|
426
|
+
});
|
|
427
|
+
return processed;
|
|
428
|
+
}
|
|
429
|
+
//#endregion
|
|
210
430
|
//#region src/ssf/receiver.ts
|
|
211
431
|
/** Seconds a SET without `exp` stays acceptable after its `iat`. */
|
|
212
432
|
const DEFAULT_SET_MAX_AGE = 86400;
|
|
@@ -760,171 +980,380 @@ function setPollHandler(options) {
|
|
|
760
980
|
};
|
|
761
981
|
}
|
|
762
982
|
//#endregion
|
|
763
|
-
//#region src/ssf/
|
|
764
|
-
/** SSF 1.0 delivery method URN for RFC 8935 push. */
|
|
765
|
-
const SSF_PUSH_DELIVERY = "urn:ietf:rfc:8935";
|
|
766
|
-
/** SSF 1.0 delivery method URN for RFC 8936 poll. */
|
|
767
|
-
const SSF_POLL_DELIVERY = "urn:ietf:rfc:8936";
|
|
768
|
-
/** Milliseconds one push may take. */
|
|
769
|
-
const PUSH_TIMEOUT_MS = 3e4;
|
|
770
|
-
/** The largest error body `pushSet` reads. */
|
|
771
|
-
const MAX_ERROR_BYTES = 16384;
|
|
983
|
+
//#region src/ssf/streams.ts
|
|
772
984
|
/**
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
* SSF 1.0 requires. `iss` is the signer's own.
|
|
985
|
+
* An in-process `SsfStreamStore`. A process restart loses every stream; a
|
|
986
|
+
* deployment with more than one instance needs a shared store.
|
|
776
987
|
*/
|
|
777
|
-
function
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
988
|
+
function memorySsfStreamStore() {
|
|
989
|
+
const entries = /* @__PURE__ */ new Map();
|
|
990
|
+
return Object.freeze({
|
|
991
|
+
name: "memory",
|
|
992
|
+
create(owner, configuration) {
|
|
993
|
+
const id = configuration.stream_id;
|
|
994
|
+
entries.set(id, {
|
|
995
|
+
stream: Object.freeze({
|
|
996
|
+
owner,
|
|
997
|
+
configuration
|
|
998
|
+
}),
|
|
999
|
+
status: Object.freeze({
|
|
1000
|
+
stream_id: id,
|
|
1001
|
+
status: "enabled"
|
|
1002
|
+
})
|
|
1003
|
+
});
|
|
1004
|
+
},
|
|
1005
|
+
get(streamId) {
|
|
1006
|
+
return entries.get(streamId)?.stream ?? null;
|
|
1007
|
+
},
|
|
1008
|
+
list(owner) {
|
|
1009
|
+
return [...entries.values()].map((entry) => entry.stream).filter((stream) => owner === void 0 || stream.owner === owner);
|
|
1010
|
+
},
|
|
1011
|
+
update(configuration) {
|
|
1012
|
+
const entry = entries.get(configuration.stream_id);
|
|
1013
|
+
if (entry !== void 0) entries.set(configuration.stream_id, {
|
|
1014
|
+
stream: Object.freeze({
|
|
1015
|
+
owner: entry.stream.owner,
|
|
1016
|
+
configuration
|
|
1017
|
+
}),
|
|
1018
|
+
status: entry.status
|
|
1019
|
+
});
|
|
1020
|
+
},
|
|
1021
|
+
delete(streamId) {
|
|
1022
|
+
entries.delete(streamId);
|
|
1023
|
+
},
|
|
1024
|
+
status(streamId) {
|
|
1025
|
+
return entries.get(streamId)?.status ?? null;
|
|
1026
|
+
},
|
|
1027
|
+
setStatus(status) {
|
|
1028
|
+
const entry = entries.get(status.stream_id);
|
|
1029
|
+
if (entry !== void 0) entries.set(status.stream_id, {
|
|
1030
|
+
stream: entry.stream,
|
|
1031
|
+
status: Object.freeze({ ...status })
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
788
1035
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1036
|
+
//#endregion
|
|
1037
|
+
//#region src/ssf/transmitter-handler.ts
|
|
1038
|
+
/** The largest stream-management request body read. */
|
|
1039
|
+
const MAX_BODY_BYTES = 65536;
|
|
1040
|
+
/** SETs drained or flushed per queue read. */
|
|
1041
|
+
const BATCH = 100;
|
|
1042
|
+
const STATUSES = [
|
|
1043
|
+
"enabled",
|
|
1044
|
+
"paused",
|
|
1045
|
+
"disabled"
|
|
1046
|
+
];
|
|
1047
|
+
function isStatus(value) {
|
|
1048
|
+
return STATUSES.some((status) => status === value);
|
|
1049
|
+
}
|
|
1050
|
+
function isHttpUrl(value) {
|
|
1051
|
+
if (typeof value !== "string" || !URL.canParse(value)) return false;
|
|
1052
|
+
const { protocol } = new URL(value);
|
|
1053
|
+
return protocol === "https:" || protocol === "http:";
|
|
1054
|
+
}
|
|
1055
|
+
function readDelivery(value) {
|
|
1056
|
+
if (!isRecord(value)) return "delivery must be an object";
|
|
1057
|
+
const { method, endpoint_url, authorization_header } = value;
|
|
1058
|
+
if (method === "urn:ietf:rfc:8936") return { method };
|
|
1059
|
+
if (method !== "urn:ietf:rfc:8935") return `delivery.method must be ${SSF_PUSH_DELIVERY} or ${SSF_POLL_DELIVERY}`;
|
|
1060
|
+
if (!isHttpUrl(endpoint_url)) return "delivery.endpoint_url must be an http or https URL for push";
|
|
1061
|
+
if (authorization_header !== void 0 && typeof authorization_header !== "string") return "delivery.authorization_header must be a string";
|
|
1062
|
+
return compact({
|
|
1063
|
+
method,
|
|
1064
|
+
endpoint_url,
|
|
1065
|
+
authorization_header
|
|
1066
|
+
});
|
|
810
1067
|
}
|
|
811
1068
|
/**
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
* a `429` or a `5xx` is `unavailable` with `retry: true`. Never throws.
|
|
1069
|
+
* The receiver-supplied properties of a stream request (SSF 1.0 section
|
|
1070
|
+
* 8.1.1). `previous` keeps the properties a PATCH leaves out; without it an
|
|
1071
|
+
* absent property takes its default. Transmitter-supplied properties are ignored.
|
|
816
1072
|
*/
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
headers: compact({
|
|
824
|
-
"content-type": SET_CONTENT,
|
|
825
|
-
accept: "application/json",
|
|
826
|
-
authorization: options.authorization
|
|
827
|
-
}),
|
|
828
|
-
body: set,
|
|
829
|
-
signal: timeoutSignal(PUSH_TIMEOUT_MS, options.signal)
|
|
830
|
-
});
|
|
831
|
-
} catch {
|
|
832
|
-
return {
|
|
833
|
-
ok: false,
|
|
834
|
-
cause: "unavailable",
|
|
835
|
-
retry: true
|
|
836
|
-
};
|
|
1073
|
+
function readProperties(body, previous) {
|
|
1074
|
+
let delivery = previous?.delivery ?? { method: "urn:ietf:rfc:8936" };
|
|
1075
|
+
if (body["delivery"] !== void 0) {
|
|
1076
|
+
const read = readDelivery(body["delivery"]);
|
|
1077
|
+
if (typeof read === "string") return read;
|
|
1078
|
+
delivery = read;
|
|
837
1079
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
description,
|
|
847
|
-
retry: true
|
|
1080
|
+
const requested = body["events_requested"];
|
|
1081
|
+
if (requested !== void 0 && !(Array.isArray(requested) && requested.every((event) => typeof event === "string"))) return "events_requested must be an array of strings";
|
|
1082
|
+
const description = body["description"];
|
|
1083
|
+
if (description !== void 0 && typeof description !== "string") return "description must be a string";
|
|
1084
|
+
return compact({
|
|
1085
|
+
delivery,
|
|
1086
|
+
events_requested: requested ?? previous?.events_requested ?? [],
|
|
1087
|
+
description: description ?? previous?.description
|
|
848
1088
|
});
|
|
849
|
-
|
|
1089
|
+
}
|
|
1090
|
+
function propertiesOf(configuration) {
|
|
850
1091
|
return compact({
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
description
|
|
854
|
-
retry: false
|
|
1092
|
+
delivery: configuration.delivery,
|
|
1093
|
+
events_requested: configuration.events_requested ?? [],
|
|
1094
|
+
description: configuration.description
|
|
855
1095
|
});
|
|
856
1096
|
}
|
|
857
|
-
function
|
|
858
|
-
|
|
1097
|
+
async function readBody(request) {
|
|
1098
|
+
const read = await readBodyText(request, MAX_BODY_BYTES);
|
|
1099
|
+
if (!read.ok) return problemResponse(statusProblem(413, `request body exceeds ${MAX_BODY_BYTES} bytes`));
|
|
1100
|
+
let parsed;
|
|
1101
|
+
try {
|
|
1102
|
+
parsed = JSON.parse(read.text);
|
|
1103
|
+
} catch {
|
|
1104
|
+
return validationProblem("body was not valid JSON");
|
|
1105
|
+
}
|
|
1106
|
+
return isRecord(parsed) ? parsed : validationProblem("body must be a JSON object");
|
|
859
1107
|
}
|
|
860
|
-
function
|
|
861
|
-
return
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1108
|
+
async function owned(streams, id, owner) {
|
|
1109
|
+
if (typeof id !== "string" || id === "") return validationProblem("stream_id is required");
|
|
1110
|
+
const stream = await streams.get(id);
|
|
1111
|
+
return stream?.owner === owner ? stream : notFoundProblem();
|
|
1112
|
+
}
|
|
1113
|
+
/** Acknowledges every pending SET of `stream`; a queue that never empties is read at most until it repeats. */
|
|
1114
|
+
async function drain(queue, stream) {
|
|
1115
|
+
let previous;
|
|
1116
|
+
for (;;) {
|
|
1117
|
+
const pending = await queue.pending(stream, BATCH);
|
|
1118
|
+
const first = pending[0]?.jti;
|
|
1119
|
+
if (first === void 0 || first === previous) return;
|
|
1120
|
+
previous = first;
|
|
1121
|
+
await Promise.all(pending.map(({ jti }) => Promise.resolve(queue.ack(stream, jti))));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
/** Pushes the SETs a paused push stream held, oldest first, until one may be retried. */
|
|
1125
|
+
async function flush(queue, configuration, fetchFn) {
|
|
1126
|
+
const { stream_id: stream, delivery } = configuration;
|
|
1127
|
+
if (delivery.endpoint_url === void 0) return;
|
|
1128
|
+
let previous;
|
|
1129
|
+
for (;;) {
|
|
1130
|
+
const pending = await queue.pending(stream, BATCH);
|
|
1131
|
+
const first = pending[0]?.jti;
|
|
1132
|
+
if (first === void 0 || first === previous) return;
|
|
1133
|
+
previous = first;
|
|
1134
|
+
for (const { jti, set } of pending) {
|
|
1135
|
+
const result = await pushSet(set, compact({
|
|
1136
|
+
endpoint: delivery.endpoint_url,
|
|
1137
|
+
authorization: delivery.authorization_header,
|
|
1138
|
+
fetch: fetchFn
|
|
1139
|
+
}));
|
|
1140
|
+
if (result.ok) await queue.ack(stream, jti);
|
|
1141
|
+
else if (result.retry) return;
|
|
1142
|
+
else await queue.fail(stream, jti, {
|
|
1143
|
+
err: result.cause.replaceAll("-", "_"),
|
|
1144
|
+
description: result.description ?? result.cause
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
async function deliver(stream, status, jti, set, options) {
|
|
1150
|
+
const { stream_id: id, delivery } = stream.configuration;
|
|
1151
|
+
if (delivery.method === "urn:ietf:rfc:8936" || status === "paused" || delivery.endpoint_url === void 0) {
|
|
1152
|
+
await options.queue.enqueue(id, jti, set);
|
|
1153
|
+
return {
|
|
1154
|
+
stream: id,
|
|
1155
|
+
jti,
|
|
1156
|
+
queued: true,
|
|
1157
|
+
delivery: { ok: true }
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
return {
|
|
1161
|
+
stream: id,
|
|
1162
|
+
jti,
|
|
1163
|
+
queued: false,
|
|
1164
|
+
delivery: await pushSet(set, compact({
|
|
1165
|
+
endpoint: delivery.endpoint_url,
|
|
1166
|
+
authorization: delivery.authorization_header,
|
|
1167
|
+
fetch: options.fetch
|
|
870
1168
|
}))
|
|
871
|
-
}
|
|
1169
|
+
};
|
|
872
1170
|
}
|
|
873
|
-
/**
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1171
|
+
/**
|
|
1172
|
+
* Signs `event` once per distinct stream audience and delivers it to every
|
|
1173
|
+
* stream that is not disabled and has the event in `events_delivered`: a
|
|
1174
|
+
* push stream through `pushSet`, a poll stream or a paused stream into the
|
|
1175
|
+
* queue. Answers one row per stream that took the event.
|
|
1176
|
+
*/
|
|
1177
|
+
async function fanOutSet(event, options) {
|
|
1178
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1179
|
+
for (const stream of await options.streams.list()) {
|
|
1180
|
+
const { configuration } = stream;
|
|
1181
|
+
const status = (await options.streams.status(configuration.stream_id))?.status;
|
|
1182
|
+
const delivered = configuration.events_delivered ?? configuration.events_requested ?? [];
|
|
1183
|
+
if (status === void 0 || status === "disabled" || !delivered.includes(event.type)) continue;
|
|
1184
|
+
const key = JSON.stringify(configuration.aud);
|
|
1185
|
+
const group = groups.get(key) ?? {
|
|
1186
|
+
audience: configuration.aud,
|
|
1187
|
+
targets: []
|
|
1188
|
+
};
|
|
1189
|
+
group.targets.push({
|
|
1190
|
+
stream,
|
|
1191
|
+
status
|
|
1192
|
+
});
|
|
1193
|
+
groups.set(key, group);
|
|
1194
|
+
}
|
|
1195
|
+
return (await Promise.all([...groups.values()].map(async ({ audience, targets }) => {
|
|
1196
|
+
const jti = globalThis.crypto.randomUUID();
|
|
1197
|
+
const set = await signSet(event, options.signer, {
|
|
1198
|
+
audience,
|
|
1199
|
+
jti
|
|
1200
|
+
});
|
|
1201
|
+
return Promise.all(targets.map(({ stream, status }) => deliver(stream, status, jti, set, options)));
|
|
1202
|
+
}))).flat();
|
|
902
1203
|
}
|
|
903
|
-
/** RISC 1.0 event builders for the events PermDock's receiver treats as revoking every session. */
|
|
904
|
-
const riscEvents = Object.freeze({
|
|
905
|
-
accountDisabled: (input) => risc("account-disabled", input.subject, compact({ reason: input.reason })),
|
|
906
|
-
accountPurged: (input) => risc("account-purged", input.subject, {}),
|
|
907
|
-
credentialCompromise: (input) => risc("credential-compromise", input.subject, compact({
|
|
908
|
-
credential_type: input.credentialType,
|
|
909
|
-
event_timestamp: input.eventTimestamp ?? epochSeconds(),
|
|
910
|
-
initiating_entity: input.initiatingEntity,
|
|
911
|
-
reason_admin: reason(input.reasonAdmin),
|
|
912
|
-
reason_user: reason(input.reasonUser)
|
|
913
|
-
}))
|
|
914
|
-
});
|
|
915
1204
|
/**
|
|
916
|
-
*
|
|
917
|
-
*
|
|
1205
|
+
* An SSF 1.0 transmitter as one Fetch handler, routed by path suffix:
|
|
1206
|
+
* `/.well-known/ssf-configuration` (section 7.1), `/stream` (8.1.1),
|
|
1207
|
+
* `/status` (8.1.2), `/verify` (8.1.4) and `/poll` (RFC 8936). Each receiver
|
|
1208
|
+
* sees only the streams it created. Disabling or deleting a stream drops its
|
|
1209
|
+
* pending SETs; a paused stream holds them until it is enabled again.
|
|
918
1210
|
*/
|
|
919
|
-
function
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1211
|
+
function ssfTransmitter(options) {
|
|
1212
|
+
const base = (options.endpoint ?? options.issuer).replace(/\/+$/u, "");
|
|
1213
|
+
const supported = options.eventsSupported ?? knownEventTypes();
|
|
1214
|
+
const audienceOf = options.audience ?? ((receiver) => receiver);
|
|
1215
|
+
const cap = options.maxEvents ?? 100;
|
|
1216
|
+
const { streams, queue } = options;
|
|
1217
|
+
const metadata = compact({
|
|
1218
|
+
spec_version: "1_0",
|
|
1219
|
+
issuer: options.issuer,
|
|
1220
|
+
jwks_uri: options.jwksUri,
|
|
1221
|
+
delivery_methods_supported: [SSF_PUSH_DELIVERY, SSF_POLL_DELIVERY],
|
|
1222
|
+
configuration_endpoint: `${base}/stream`,
|
|
1223
|
+
status_endpoint: `${base}/status`,
|
|
1224
|
+
verification_endpoint: `${base}/verify`,
|
|
1225
|
+
authorization_schemes: [{ spec_urn: "urn:ietf:rfc:6750" }],
|
|
1226
|
+
default_subjects: "ALL"
|
|
1227
|
+
});
|
|
1228
|
+
const configurationOf = (id, owner, properties) => compact({
|
|
1229
|
+
stream_id: id,
|
|
1230
|
+
iss: options.issuer,
|
|
1231
|
+
aud: audienceOf(owner),
|
|
1232
|
+
events_supported: supported,
|
|
1233
|
+
events_requested: properties.events_requested,
|
|
1234
|
+
events_delivered: properties.events_requested.filter((event) => supported.includes(event)),
|
|
1235
|
+
delivery: properties.delivery.method === "urn:ietf:rfc:8936" ? {
|
|
1236
|
+
method: SSF_POLL_DELIVERY,
|
|
1237
|
+
endpoint_url: `${base}/poll?stream_id=${encodeURIComponent(id)}`
|
|
1238
|
+
} : properties.delivery,
|
|
1239
|
+
description: properties.description
|
|
927
1240
|
});
|
|
1241
|
+
const stream = async (request, url, owner) => {
|
|
1242
|
+
switch (request.method) {
|
|
1243
|
+
case "GET": {
|
|
1244
|
+
const id = url.searchParams.get("stream_id");
|
|
1245
|
+
if (id === null) return jsonResponse(200, (await streams.list(owner)).map((entry) => entry.configuration));
|
|
1246
|
+
const found = await owned(streams, id, owner);
|
|
1247
|
+
return found instanceof Response ? found : jsonResponse(200, found.configuration);
|
|
1248
|
+
}
|
|
1249
|
+
case "POST": {
|
|
1250
|
+
const body = await readBody(request);
|
|
1251
|
+
if (body instanceof Response) return body;
|
|
1252
|
+
const properties = readProperties(body);
|
|
1253
|
+
if (typeof properties === "string") return validationProblem(properties);
|
|
1254
|
+
const configuration = configurationOf(globalThis.crypto.randomUUID(), owner, properties);
|
|
1255
|
+
await streams.create(owner, configuration);
|
|
1256
|
+
return jsonResponse(201, configuration);
|
|
1257
|
+
}
|
|
1258
|
+
case "PATCH":
|
|
1259
|
+
case "PUT": {
|
|
1260
|
+
const body = await readBody(request);
|
|
1261
|
+
if (body instanceof Response) return body;
|
|
1262
|
+
const found = await owned(streams, body["stream_id"], owner);
|
|
1263
|
+
if (found instanceof Response) return found;
|
|
1264
|
+
const properties = readProperties(body, request.method === "PATCH" ? propertiesOf(found.configuration) : void 0);
|
|
1265
|
+
if (typeof properties === "string") return validationProblem(properties);
|
|
1266
|
+
const configuration = configurationOf(found.configuration.stream_id, owner, properties);
|
|
1267
|
+
await streams.update(configuration);
|
|
1268
|
+
return jsonResponse(200, configuration);
|
|
1269
|
+
}
|
|
1270
|
+
case "DELETE": {
|
|
1271
|
+
const found = await owned(streams, url.searchParams.get("stream_id"), owner);
|
|
1272
|
+
if (found instanceof Response) return found;
|
|
1273
|
+
await streams.delete(found.configuration.stream_id);
|
|
1274
|
+
await drain(queue, found.configuration.stream_id);
|
|
1275
|
+
return new Response(null, { status: 204 });
|
|
1276
|
+
}
|
|
1277
|
+
default: return methodNotAllowed("GET, POST, PATCH, PUT, DELETE");
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
const statusOf = async (id) => await streams.status(id) ?? {
|
|
1281
|
+
stream_id: id,
|
|
1282
|
+
status: "enabled"
|
|
1283
|
+
};
|
|
1284
|
+
const status = async (request, url, owner) => {
|
|
1285
|
+
if (request.method === "GET") {
|
|
1286
|
+
const found = await owned(streams, url.searchParams.get("stream_id"), owner);
|
|
1287
|
+
return found instanceof Response ? found : jsonResponse(200, await statusOf(found.configuration.stream_id));
|
|
1288
|
+
}
|
|
1289
|
+
if (request.method !== "POST") return methodNotAllowed("GET, POST");
|
|
1290
|
+
const body = await readBody(request);
|
|
1291
|
+
if (body instanceof Response) return body;
|
|
1292
|
+
const found = await owned(streams, body["stream_id"], owner);
|
|
1293
|
+
if (found instanceof Response) return found;
|
|
1294
|
+
const next = body["status"];
|
|
1295
|
+
const reason = body["reason"];
|
|
1296
|
+
if (!isStatus(next)) return validationProblem(`status must be one of ${STATUSES.join(", ")}`);
|
|
1297
|
+
if (reason !== void 0 && typeof reason !== "string") return validationProblem("reason must be a string");
|
|
1298
|
+
const id = found.configuration.stream_id;
|
|
1299
|
+
const before = await statusOf(id);
|
|
1300
|
+
const updated = compact({
|
|
1301
|
+
stream_id: id,
|
|
1302
|
+
status: next,
|
|
1303
|
+
reason
|
|
1304
|
+
});
|
|
1305
|
+
await streams.setStatus(updated);
|
|
1306
|
+
if (next === "disabled") await drain(queue, id);
|
|
1307
|
+
else if (next === "enabled" && before.status === "paused" && found.configuration.delivery.method === "urn:ietf:rfc:8935") await flush(queue, found.configuration, options.fetch);
|
|
1308
|
+
return jsonResponse(200, updated);
|
|
1309
|
+
};
|
|
1310
|
+
const verify = async (request, owner) => {
|
|
1311
|
+
if (request.method !== "POST") return methodNotAllowed("POST");
|
|
1312
|
+
const body = await readBody(request);
|
|
1313
|
+
if (body instanceof Response) return body;
|
|
1314
|
+
const found = await owned(streams, body["stream_id"], owner);
|
|
1315
|
+
if (found instanceof Response) return found;
|
|
1316
|
+
const state = body["state"];
|
|
1317
|
+
if (state !== void 0 && typeof state !== "string") return validationProblem("state must be a string");
|
|
1318
|
+
const { configuration } = found;
|
|
1319
|
+
const current = await statusOf(configuration.stream_id);
|
|
1320
|
+
if (current.status === "disabled") return problemResponse(statusProblem(409, "stream is disabled"));
|
|
1321
|
+
const jti = globalThis.crypto.randomUUID();
|
|
1322
|
+
const set = await signSet(streamVerificationEvent(configuration.stream_id, state), options.signer, {
|
|
1323
|
+
audience: configuration.aud,
|
|
1324
|
+
jti
|
|
1325
|
+
});
|
|
1326
|
+
await deliver(found, current.status, jti, set, options);
|
|
1327
|
+
return new Response(null, { status: 204 });
|
|
1328
|
+
};
|
|
1329
|
+
const poll = async (request, url, owner) => {
|
|
1330
|
+
const id = url.searchParams.get("stream_id");
|
|
1331
|
+
const found = id === null ? null : await streams.get(id);
|
|
1332
|
+
if (found?.owner !== owner || found.configuration.delivery.method !== "urn:ietf:rfc:8936") return notFoundProblem();
|
|
1333
|
+
const current = await statusOf(found.configuration.stream_id);
|
|
1334
|
+
return setPollHandler({
|
|
1335
|
+
queue,
|
|
1336
|
+
authorize: () => found.configuration.stream_id,
|
|
1337
|
+
maxEvents: current.status === "enabled" ? cap : 0
|
|
1338
|
+
})(request);
|
|
1339
|
+
};
|
|
1340
|
+
return async (request) => {
|
|
1341
|
+
const url = new URL(request.url);
|
|
1342
|
+
const path = url.pathname.replace(/\/+$/u, "");
|
|
1343
|
+
if (path.endsWith("/.well-known/ssf-configuration")) return request.method === "GET" ? jsonResponse(200, metadata) : methodNotAllowed("GET");
|
|
1344
|
+
let owner;
|
|
1345
|
+
try {
|
|
1346
|
+
owner = await options.authorize(request);
|
|
1347
|
+
} catch {
|
|
1348
|
+
owner = null;
|
|
1349
|
+
}
|
|
1350
|
+
if (owner === null) return problemResponse(statusProblem(401, "stream management not authorized"), void 0, void 0, { "WWW-Authenticate": "Bearer" });
|
|
1351
|
+
if (path.endsWith("/stream")) return stream(request, url, owner);
|
|
1352
|
+
if (path.endsWith("/status")) return status(request, url, owner);
|
|
1353
|
+
if (path.endsWith("/verify")) return verify(request, owner);
|
|
1354
|
+
if (path.endsWith("/poll")) return poll(request, url, owner);
|
|
1355
|
+
return notFoundProblem();
|
|
1356
|
+
};
|
|
928
1357
|
}
|
|
929
1358
|
//#endregion
|
|
930
|
-
export { SSF_POLL_DELIVERY, SSF_PUSH_DELIVERY, caepEvents, createPermDock, memoryReplayStore, memorySetQueue, pushSet, riscEvents, setPollHandler, signSet, streamVerificationEvent };
|
|
1359
|
+
export { SSF_POLL_DELIVERY, SSF_PUSH_DELIVERY, caepEvents, createPermDock, fanOutSet, memoryReplayStore, memorySetQueue, memorySsfStreamStore, pollSets, pushSet, riscEvents, setPollHandler, signSet, ssfTransmitter, streamVerificationEvent };
|