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,14 +1,251 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as compact } from "../compact-y6vfu2_f.js";
|
|
3
|
-
import { n as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
7
|
-
import { n as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
3
|
+
import { n as freezeDeep } from "../freeze-CrU8nQeX.js";
|
|
4
|
+
import { r as requiredPlans } from "../problem-details-_AMOYz-w.js";
|
|
5
|
+
import { t as describe } from "../describe-B_gVZEVi.js";
|
|
6
|
+
import { a as normalizeMemberships, d as scopeList, m as tenantOf$1, o as resolveScope } from "../scopes-CVdPrWN-.js";
|
|
7
|
+
import { n as parseSnapshot, o as bindConditionRefs } from "../snapshot-Enxd0n-s.js";
|
|
8
|
+
import { s as flattenGrantee } from "../grantee-Cv5Sogfv.js";
|
|
9
|
+
import { p as resolveActiveTenant, u as nowSeconds } from "../validity-uOp8UpYn.js";
|
|
10
|
+
import { n as isThenable } from "../thenable-okc2xDsj.js";
|
|
11
|
+
import { r as heldRoleNames, t as emptySnapshot } from "../from-snapshot-CTLijvdm.js";
|
|
12
|
+
import { t as parseLocalSnapshotManifest } from "../parse-local-manifest-BrMozJCo.js";
|
|
13
|
+
import { t as approvalHeaders } from "../headers-BZSDieNT.js";
|
|
14
|
+
import { n as storeOf, r as isJws, t as adapterStore } from "../store-options-ByhZq1jV.js";
|
|
15
|
+
import { i as PermDockStoreContext, n as useKeyed, t as useLiveOptions } from "../live-options-H2eG8dfJ.js";
|
|
16
|
+
import { a as useFilter, c as usePermission, d as useSubject, f as useTenant, i as useAssignableRoles, l as usePermissions, n as useApproval, o as useMemberships, r as useAssignablePermissions, s as usePermDock, t as Protected, u as useRoles } from "../protected-utU-SLuy.js";
|
|
17
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
11
18
|
import { jsx } from "react/jsx-runtime";
|
|
19
|
+
//#region src/react-native/guards.ts
|
|
20
|
+
/** `true` once the provider has a snapshot to answer from: storage was read or a seed was given. Hide the splash screen on it. */
|
|
21
|
+
function useSnapshotReady() {
|
|
22
|
+
return usePermDock().status() !== "pending";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A boolean for `Stack.Protected` and `Tabs.Protected`: `false` while the
|
|
26
|
+
* snapshot is pending, `true` only when every permission is allowed for
|
|
27
|
+
* `data`.
|
|
28
|
+
*/
|
|
29
|
+
function usePermissionGuard(permission, data) {
|
|
30
|
+
const permdock = usePermDock();
|
|
31
|
+
return useMemo(() => {
|
|
32
|
+
if (permdock.status() === "pending") return false;
|
|
33
|
+
const store = storeOf(permdock);
|
|
34
|
+
const list = Array.isArray(permission) ? permission : [permission];
|
|
35
|
+
return list.length > 0 && list.every((item) => store.permissionState(item, data).allowed);
|
|
36
|
+
}, [
|
|
37
|
+
permdock,
|
|
38
|
+
permission,
|
|
39
|
+
data
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/react-native/local.ts
|
|
44
|
+
const CARRIED = /* @__PURE__ */ new Set([
|
|
45
|
+
"id",
|
|
46
|
+
"roles",
|
|
47
|
+
"plans",
|
|
48
|
+
"tenant",
|
|
49
|
+
"memberships"
|
|
50
|
+
]);
|
|
51
|
+
function isClaimRef(ref) {
|
|
52
|
+
const [root, head] = ref.split(".", 2);
|
|
53
|
+
return root === "principal" && !CARRIED.has(String(head));
|
|
54
|
+
}
|
|
55
|
+
function bindGrant(grant, subject) {
|
|
56
|
+
const bind = (condition) => condition === void 0 ? void 0 : bindConditionRefs(condition, subject, isClaimRef);
|
|
57
|
+
return grant.where === void 0 && grant.check === void 0 ? grant : compact({
|
|
58
|
+
...grant,
|
|
59
|
+
where: bind(grant.where),
|
|
60
|
+
check: bind(grant.check)
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function renamed(grant, name) {
|
|
64
|
+
const to = [];
|
|
65
|
+
for (const item of flattenGrantee(grant.to)) to.push(item.kind === "role" && item.role === "\0custom" ? {
|
|
66
|
+
kind: "role",
|
|
67
|
+
role: name,
|
|
68
|
+
scope: item.scope
|
|
69
|
+
} : item);
|
|
70
|
+
return {
|
|
71
|
+
...grant,
|
|
72
|
+
role: name,
|
|
73
|
+
to
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The grants a custom role holds, from the entries the server resolved one
|
|
78
|
+
* by one: an entry the table does not know grants nothing.
|
|
79
|
+
*/
|
|
80
|
+
function customGrants(table, role) {
|
|
81
|
+
const entries = Array.isArray(role.grants) ? role.grants : [];
|
|
82
|
+
const removed = /* @__PURE__ */ new Set();
|
|
83
|
+
const allows = [];
|
|
84
|
+
for (const item of entries) {
|
|
85
|
+
if (item === null || typeof item !== "object") continue;
|
|
86
|
+
const entry = new Map(Object.entries(item));
|
|
87
|
+
const key = entry.get("permission");
|
|
88
|
+
if (typeof key !== "string") continue;
|
|
89
|
+
const effect = entry.get("effect") ?? "allow";
|
|
90
|
+
const level = entry.get("level");
|
|
91
|
+
const known = [...entry.keys()].every((name) => name === "permission" || name === "effect" || name === "level");
|
|
92
|
+
const row = Object.hasOwn(table.permissions, key) ? table.permissions[key] : void 0;
|
|
93
|
+
const unknownLevel = level !== void 0 && (typeof level !== "string" || row?.levels === void 0 || !Object.hasOwn(row.levels, level));
|
|
94
|
+
if (!known || effect !== "allow" || unknownLevel && row !== void 0) {
|
|
95
|
+
removed.add(key);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
allows.push({
|
|
99
|
+
key,
|
|
100
|
+
level
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const out = [];
|
|
104
|
+
const included = /* @__PURE__ */ new Set();
|
|
105
|
+
const names = Array.isArray(role.includes) ? role.includes : [];
|
|
106
|
+
for (const name of names) {
|
|
107
|
+
const list = typeof name === "string" && Object.hasOwn(table.includes, name) ? table.includes[name] : void 0;
|
|
108
|
+
for (const grant of list ?? []) {
|
|
109
|
+
if (grant.effect === "deny" || !removed.has(grant.permission)) out.push(grant);
|
|
110
|
+
if (grant.effect === "allow") included.add(grant.permission);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const { key, level } of allows) {
|
|
114
|
+
if (removed.has(key) || included.has(key)) continue;
|
|
115
|
+
const row = Object.hasOwn(table.permissions, key) ? table.permissions[key] : void 0;
|
|
116
|
+
const grants = typeof level === "string" ? row?.levels?.[level] : row?.all;
|
|
117
|
+
out.push(...grants ?? []);
|
|
118
|
+
}
|
|
119
|
+
return out.map((grant) => renamed(grant, role.name));
|
|
120
|
+
}
|
|
121
|
+
function isList(value) {
|
|
122
|
+
return Array.isArray(value);
|
|
123
|
+
}
|
|
124
|
+
function customScope(role, scopes) {
|
|
125
|
+
if (role.scope === "global") return "global";
|
|
126
|
+
if (role.scope !== void 0) return resolveScope(scopes, role.scope);
|
|
127
|
+
return role.team === void 0 ? scopes[0]?.name : scopes[1]?.name;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The snapshot a server would send for `data`, built from the manifest. It
|
|
131
|
+
* drives UI guards only: the server still decides every request.
|
|
132
|
+
*/
|
|
133
|
+
function buildLocalSnapshot(manifest, data, now = Math.floor(nowSeconds())) {
|
|
134
|
+
if (manifest === null || typeof manifest !== "object" || manifest.v !== 1 || !isList(manifest.grants)) throw new Error("PermDock: unsupported local snapshot manifest");
|
|
135
|
+
const scopes = scopeList(manifest.scopes);
|
|
136
|
+
const input = data.principal;
|
|
137
|
+
const memberships = input === null ? [] : normalizeMemberships(input.memberships, scopes);
|
|
138
|
+
const tenant = input === null ? void 0 : resolveActiveTenant({
|
|
139
|
+
id: input.id,
|
|
140
|
+
memberships
|
|
141
|
+
}, input.tenant, scopes, now);
|
|
142
|
+
const principal = input === null ? null : compact({
|
|
143
|
+
id: input.id,
|
|
144
|
+
roles: input.roles ?? [],
|
|
145
|
+
plans: input.plans,
|
|
146
|
+
tenant,
|
|
147
|
+
memberships
|
|
148
|
+
});
|
|
149
|
+
const subject = {
|
|
150
|
+
principal: principal === null ? null : {
|
|
151
|
+
...input?.attributes,
|
|
152
|
+
...principal
|
|
153
|
+
},
|
|
154
|
+
context: {}
|
|
155
|
+
};
|
|
156
|
+
const declared = new Set(manifest.roles);
|
|
157
|
+
const globalRoles = new Set(input?.roles ?? []);
|
|
158
|
+
const grants = [];
|
|
159
|
+
const attach = (grant, membership) => {
|
|
160
|
+
grants.push(bindGrant(membership === void 0 ? grant : {
|
|
161
|
+
...grant,
|
|
162
|
+
membership
|
|
163
|
+
}, subject));
|
|
164
|
+
};
|
|
165
|
+
for (const grant of manifest.grants) {
|
|
166
|
+
const roleItems = flattenGrantee(grant.to).filter((item) => item.kind === "role");
|
|
167
|
+
if (roleItems.length > 0 && principal === null) continue;
|
|
168
|
+
if (!roleItems.every((item) => item.scope !== "global" || declared.has(item.role) && globalRoles.has(item.role))) continue;
|
|
169
|
+
const scoped = roleItems.filter((item) => item.scope !== "global");
|
|
170
|
+
if (scoped.length === 0) {
|
|
171
|
+
attach(grant);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
for (const membership of memberships) if (scoped.every((item) => declared.has(item.role) && membership.roles.includes(item.role) && (typeof item.scope === "string" ? membership.scope === item.scope : membership.on !== void 0))) attach(grant, membership);
|
|
175
|
+
}
|
|
176
|
+
const custom = (data.customRoles ?? []).filter((role) => role !== null && typeof role === "object" && typeof role.name === "string" && !declared.has(role.name));
|
|
177
|
+
for (const role of custom) {
|
|
178
|
+
const scope = customScope(role, scopes);
|
|
179
|
+
const table = scope !== void 0 && Object.hasOwn(manifest.custom, scope) ? manifest.custom[scope] : void 0;
|
|
180
|
+
if (scope === void 0 || table === void 0) continue;
|
|
181
|
+
const resolved = customGrants(table, role);
|
|
182
|
+
if (scope === "global") {
|
|
183
|
+
if (role.tenant === void 0 && globalRoles.has(role.name)) for (const grant of resolved) attach(grant);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const id = role.team ?? role.id;
|
|
187
|
+
for (const membership of memberships) if (membership.scope === scope && typeof role.tenant === "string" && tenantOf$1(membership, scopes) === role.tenant && (id === void 0 || membership.id === id) && membership.roles.includes(role.name)) for (const grant of resolved) attach(grant, membership);
|
|
188
|
+
}
|
|
189
|
+
const roles = subject.principal === null ? [] : heldRoleNames(subject, tenant, scopes, { rank: manifest.rank ?? [] }, now);
|
|
190
|
+
return freezeDeep(compact({
|
|
191
|
+
v: 1,
|
|
192
|
+
issuedAt: now,
|
|
193
|
+
subject: {
|
|
194
|
+
principal,
|
|
195
|
+
context: {}
|
|
196
|
+
},
|
|
197
|
+
roles,
|
|
198
|
+
grants,
|
|
199
|
+
tenants: tenant === void 0 ? [] : [tenant],
|
|
200
|
+
scopes: manifest.scopes,
|
|
201
|
+
vocabulary: manifest.vocabulary
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* A snapshot source over the device's own membership rows (SQLite, a
|
|
206
|
+
* PowerSync or Electric replica): offline, the UI guards answer from them.
|
|
207
|
+
*/
|
|
208
|
+
function localSnapshot(options) {
|
|
209
|
+
return compact({
|
|
210
|
+
get: async () => buildLocalSnapshot(options.manifest, await options.read()),
|
|
211
|
+
subscribe: options.subscribe
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/react-native/powersync.ts
|
|
216
|
+
/**
|
|
217
|
+
* A `localSnapshot` source over a PowerSync database: `get` runs every query
|
|
218
|
+
* with `db.getAll`, and a `db.watch` per query reports changes. A watch
|
|
219
|
+
* result with unchanged content re-renders nothing (`connectSource`). The source
|
|
220
|
+
* takes the database as an argument; `permdock/react-native` never imports
|
|
221
|
+
* `@powersync/*`.
|
|
222
|
+
*/
|
|
223
|
+
function powersyncSource(db, options) {
|
|
224
|
+
const names = Object.keys(options.queries);
|
|
225
|
+
return localSnapshot({
|
|
226
|
+
manifest: options.manifest,
|
|
227
|
+
read: async () => {
|
|
228
|
+
const results = await Promise.all(names.map(async (name) => {
|
|
229
|
+
const query = options.queries[name];
|
|
230
|
+
return [name, await db.getAll(query.sql, [...query.parameters ?? []])];
|
|
231
|
+
}));
|
|
232
|
+
const rows = {};
|
|
233
|
+
for (const [name, list] of results) rows[name] = list;
|
|
234
|
+
return options.read(rows);
|
|
235
|
+
},
|
|
236
|
+
subscribe: (listener) => {
|
|
237
|
+
const controller = new AbortController();
|
|
238
|
+
for (const name of names) {
|
|
239
|
+
const query = options.queries[name];
|
|
240
|
+
db.watch(query.sql, [...query.parameters ?? []], { onResult: listener }, { signal: controller.signal });
|
|
241
|
+
}
|
|
242
|
+
return () => {
|
|
243
|
+
controller.abort();
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
//#endregion
|
|
12
249
|
//#region src/react-native/storage.ts
|
|
13
250
|
const SNAPSHOT_KEY = "permdock.snapshot";
|
|
14
251
|
const TENANT_KEY = "permdock.tenant";
|
|
@@ -26,67 +263,181 @@ function memoryStorage(initial = {}) {
|
|
|
26
263
|
}
|
|
27
264
|
};
|
|
28
265
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
266
|
+
const NOTHING = {
|
|
267
|
+
stored: void 0,
|
|
268
|
+
tenant: void 0
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* A persisted snapshot the device may use: `subjectId`'s own, and signed
|
|
272
|
+
* whenever a verifier is configured, so a copy edited on the device never
|
|
273
|
+
* stands in for a signed one. `null` reads nothing.
|
|
274
|
+
*/
|
|
275
|
+
function acceptStored(raw, subjectId, signed) {
|
|
276
|
+
if (raw === null || raw.length === 0 || subjectId === null) return;
|
|
277
|
+
if (isJws(raw)) return signed ? {
|
|
278
|
+
kind: "signed",
|
|
279
|
+
jws: raw
|
|
280
|
+
} : void 0;
|
|
281
|
+
if (signed) return;
|
|
34
282
|
try {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
283
|
+
const snapshot = parseSnapshot(JSON.parse(raw));
|
|
284
|
+
return snapshot.subject.principal?.id === subjectId ? {
|
|
285
|
+
kind: "snapshot",
|
|
286
|
+
snapshot
|
|
287
|
+
} : void 0;
|
|
40
288
|
} catch {
|
|
41
289
|
return;
|
|
42
290
|
}
|
|
43
291
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
292
|
+
function tenantOf(raw) {
|
|
293
|
+
return raw === null || raw.length === 0 ? void 0 : raw;
|
|
294
|
+
}
|
|
295
|
+
/** The tenant is read only alongside an accepted snapshot. */
|
|
296
|
+
function storedRead(raw, tenantRaw, subjectId, signed) {
|
|
297
|
+
const stored = acceptStored(raw, subjectId, signed);
|
|
47
298
|
return {
|
|
48
|
-
|
|
49
|
-
tenant:
|
|
299
|
+
stored,
|
|
300
|
+
tenant: stored === void 0 ? void 0 : tenantOf(tenantRaw)
|
|
50
301
|
};
|
|
51
302
|
}
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
303
|
+
function guardStorage(storage) {
|
|
304
|
+
let warned = false;
|
|
305
|
+
const fail = (error) => {
|
|
306
|
+
if (!(Reflect.get(globalThis, "__DEV__") === true) || warned) return;
|
|
307
|
+
warned = true;
|
|
308
|
+
console.warn("PermDock: the snapshot storage failed; guards answer from memory until it works again.", error);
|
|
309
|
+
};
|
|
310
|
+
const settle = (run) => {
|
|
311
|
+
try {
|
|
312
|
+
const result = run();
|
|
313
|
+
if (isThenable(result)) Promise.resolve(result).catch(fail);
|
|
314
|
+
} catch (error) {
|
|
315
|
+
fail(error);
|
|
316
|
+
}
|
|
317
|
+
};
|
|
56
318
|
return {
|
|
57
|
-
|
|
58
|
-
|
|
319
|
+
read(key) {
|
|
320
|
+
try {
|
|
321
|
+
return storage.getItem(key);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
fail(error);
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
write(key, value) {
|
|
328
|
+
settle(() => storage.setItem(key, value));
|
|
329
|
+
},
|
|
330
|
+
remove(key) {
|
|
331
|
+
settle(() => storage.removeItem(key));
|
|
332
|
+
},
|
|
333
|
+
fail
|
|
59
334
|
};
|
|
60
335
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
if (isThenable(
|
|
336
|
+
/** `undefined` when the storage answers asynchronously; any failure reads as empty. */
|
|
337
|
+
function readStoredSync(storage, subjectId, signed) {
|
|
338
|
+
if (subjectId === null) return NOTHING;
|
|
339
|
+
const raw = storage.read(SNAPSHOT_KEY);
|
|
340
|
+
const tenantRaw = storage.read(TENANT_KEY);
|
|
341
|
+
if (isThenable(raw) || isThenable(tenantRaw)) return;
|
|
342
|
+
return storedRead(raw, tenantRaw, subjectId, signed);
|
|
343
|
+
}
|
|
344
|
+
async function readStored(storage, subjectId, signed) {
|
|
345
|
+
if (subjectId === null) return NOTHING;
|
|
346
|
+
try {
|
|
347
|
+
const [raw, tenantRaw] = await Promise.all([Promise.resolve(storage.read(SNAPSHOT_KEY)), Promise.resolve(storage.read(TENANT_KEY))]);
|
|
348
|
+
return storedRead(raw, tenantRaw, subjectId, signed);
|
|
349
|
+
} catch (error) {
|
|
350
|
+
storage.fail(error);
|
|
351
|
+
return NOTHING;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/** Writes `raw` (the snapshot JSON or its JWS) and the tenant. */
|
|
355
|
+
function persistSnapshot(storage, raw, tenant) {
|
|
356
|
+
storage.write(SNAPSHOT_KEY, raw);
|
|
357
|
+
if (tenant !== void 0) storage.write(TENANT_KEY, tenant);
|
|
67
358
|
}
|
|
68
359
|
function clearStorage(storage) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const tenant = storage.removeItem(TENANT_KEY);
|
|
72
|
-
if (isThenable(tenant)) tenant.catch(() => void 0);
|
|
360
|
+
storage.remove(SNAPSHOT_KEY);
|
|
361
|
+
storage.remove(TENANT_KEY);
|
|
73
362
|
}
|
|
74
363
|
//#endregion
|
|
75
364
|
//#region src/react-native/store.ts
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return
|
|
365
|
+
/** The snapshot's content without `issuedAt`, which every local rebuild changes. */
|
|
366
|
+
function contentKey(snapshot) {
|
|
367
|
+
return JSON.stringify({
|
|
368
|
+
...snapshot,
|
|
369
|
+
issuedAt: 0
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Whether a source read changes nothing: same content as the snapshot the
|
|
374
|
+
* store holds, and the store already settled on it.
|
|
375
|
+
*/
|
|
376
|
+
function unchanged(store, next) {
|
|
377
|
+
if (typeof next === "string" || store.get().status() === "stale") return false;
|
|
378
|
+
try {
|
|
379
|
+
return contentKey(parseSnapshot(next)) === contentKey(store.snapshot());
|
|
380
|
+
} catch {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Hydrates `store` from `source` now, on every change it reports and on each
|
|
386
|
+
* return to the foreground. Only the latest read applies; a read with
|
|
387
|
+
* unchanged content re-renders nothing, and a failed read keeps the current
|
|
388
|
+
* snapshot. Returns the unsubscribe.
|
|
389
|
+
*/
|
|
390
|
+
function connectSource(store, source, subscribeForeground) {
|
|
391
|
+
let active = true;
|
|
392
|
+
let seq = 0;
|
|
393
|
+
const pull = () => {
|
|
394
|
+
seq += 1;
|
|
395
|
+
const mine = seq;
|
|
396
|
+
Promise.resolve().then(() => source.get()).then((next) => {
|
|
397
|
+
if (active && mine === seq && !unchanged(store, next)) store.replace(next);
|
|
398
|
+
}, () => void 0);
|
|
399
|
+
};
|
|
400
|
+
pull();
|
|
401
|
+
const unsubscribe = source.subscribe?.(pull);
|
|
402
|
+
const offForeground = subscribeForeground?.((next) => {
|
|
403
|
+
if (next !== false) pull();
|
|
404
|
+
});
|
|
405
|
+
return () => {
|
|
406
|
+
active = false;
|
|
407
|
+
unsubscribe?.();
|
|
408
|
+
offForeground?.();
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function seedOf(stored) {
|
|
412
|
+
if (stored === void 0) return;
|
|
413
|
+
return stored.kind === "signed" ? stored.jws : stored.snapshot;
|
|
414
|
+
}
|
|
415
|
+
function belongsTo(snapshot, subjectId) {
|
|
416
|
+
return subjectId !== null && snapshot.subject.principal?.id === subjectId;
|
|
417
|
+
}
|
|
418
|
+
/** A JWS stays a string for the verifier; anything else parses or is dropped. */
|
|
419
|
+
function parseSeed(given) {
|
|
420
|
+
if (given === void 0) return;
|
|
421
|
+
if (typeof given === "string" && isJws(given)) return given;
|
|
422
|
+
try {
|
|
423
|
+
return parseSnapshot(typeof given === "string" ? JSON.parse(given) : given);
|
|
424
|
+
} catch {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
79
427
|
}
|
|
80
428
|
function createNativeStore(options) {
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
429
|
+
const storage = guardStorage(options.storage);
|
|
430
|
+
const signed = options.verifier !== void 0;
|
|
431
|
+
const revalidates = options.snapshotUrl !== void 0 || options.source !== void 0;
|
|
432
|
+
const seeded = parseSeed(options.snapshot);
|
|
433
|
+
const carried = options.previous !== void 0 && belongsTo(options.previous.snapshot(), options.subjectId) ? options.previous : void 0;
|
|
434
|
+
const sync = seeded === void 0 && carried === void 0 ? readStoredSync(storage, options.subjectId, signed) : void 0;
|
|
435
|
+
const waiting = seeded === void 0 && carried === void 0 && sync === void 0;
|
|
436
|
+
const fromStorage = seedOf(sync?.stored);
|
|
437
|
+
const snapshot = seeded ?? carried?.snapshot() ?? fromStorage ?? emptySnapshot();
|
|
438
|
+
const tenant = options.tenant ?? carried?.tenant() ?? sync?.tenant ?? void 0;
|
|
86
439
|
let booted = false;
|
|
87
|
-
|
|
88
|
-
const store = createClientStore(compact({
|
|
89
|
-
snapshot,
|
|
440
|
+
const store = adapterStore(compact({
|
|
90
441
|
endpoint: options.endpoint,
|
|
91
442
|
snapshotUrl: options.snapshotUrl,
|
|
92
443
|
approvals: options.approvals,
|
|
@@ -95,75 +446,137 @@ function createNativeStore(options) {
|
|
|
95
446
|
headers: options.headers,
|
|
96
447
|
maxAge: options.maxAge,
|
|
97
448
|
verifier: options.verifier,
|
|
449
|
+
awaiting: waiting,
|
|
450
|
+
passCache: true
|
|
451
|
+
}), snapshot, {
|
|
98
452
|
server: false,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
453
|
+
stale: revalidates && (fromStorage !== void 0 || waiting),
|
|
454
|
+
onSnapshot: (next, nextTenant, raw) => {
|
|
455
|
+
if (!booted || !belongsTo(next, options.subjectId)) return;
|
|
456
|
+
if (signed && raw === void 0) return;
|
|
457
|
+
persistSnapshot(storage, raw ?? JSON.stringify(next), nextTenant);
|
|
103
458
|
},
|
|
104
459
|
onClear: () => {
|
|
105
|
-
|
|
106
|
-
clearStorage(options.storage);
|
|
460
|
+
clearStorage(storage);
|
|
107
461
|
}
|
|
108
|
-
}));
|
|
109
|
-
booted = true;
|
|
110
|
-
if (seeded !== void 0) persistSnapshot(options.storage, seeded, tenant);
|
|
111
|
-
if (sync === void 0 && seeded === void 0 && signed === void 0) readStored(options.storage, options.subjectId).then((stored) => {
|
|
112
|
-
if (!touched && stored.snapshot !== void 0) store.replace(stored.snapshot);
|
|
113
462
|
});
|
|
463
|
+
booted = true;
|
|
464
|
+
if (seeded !== void 0 && typeof seeded !== "string") {
|
|
465
|
+
if (belongsTo(seeded, options.subjectId)) persistSnapshot(storage, JSON.stringify(seeded), tenant);
|
|
466
|
+
} else if (seeded !== void 0 && signed) persistSnapshot(storage, seeded, tenant);
|
|
467
|
+
if (options.subjectId === null) clearStorage(storage);
|
|
468
|
+
if (waiting) {
|
|
469
|
+
let storedTenant;
|
|
470
|
+
const read = readStored(storage, options.subjectId, signed).then(({ stored, tenant: persisted }) => {
|
|
471
|
+
const value = seedOf(stored);
|
|
472
|
+
if (value === void 0) throw new Error("nothing stored");
|
|
473
|
+
storedTenant = persisted;
|
|
474
|
+
return value;
|
|
475
|
+
});
|
|
476
|
+
store.track(read);
|
|
477
|
+
read.then(() => {
|
|
478
|
+
if (options.tenant === void 0 && storedTenant !== void 0 && store.tenant() !== storedTenant && store.snapshot().tenants.includes(storedTenant)) store.get().refresh({ tenant: storedTenant });
|
|
479
|
+
}, () => void 0);
|
|
480
|
+
}
|
|
114
481
|
return store;
|
|
115
482
|
}
|
|
116
483
|
//#endregion
|
|
117
484
|
//#region src/react-native/provider.tsx
|
|
118
485
|
function PermDockProvider(props) {
|
|
119
|
-
const
|
|
486
|
+
const live = useLiveOptions(props, false);
|
|
487
|
+
const shown = useRef(null);
|
|
488
|
+
const store = useKeyed(() => createNativeStore(compact({
|
|
120
489
|
storage: props.storage,
|
|
490
|
+
subjectId: props.subjectId,
|
|
121
491
|
snapshot: props.snapshot,
|
|
122
492
|
snapshotUrl: props.snapshotUrl,
|
|
493
|
+
source: props.source,
|
|
123
494
|
endpoint: props.endpoint,
|
|
124
495
|
approvals: props.approvals,
|
|
125
496
|
tenant: props.tenant,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
subscribeForeground: props.subscribeForeground,
|
|
129
|
-
fetch: props.fetch,
|
|
130
|
-
headers: props.headers,
|
|
497
|
+
fetch: live.fetch,
|
|
498
|
+
headers: live.readHeaders,
|
|
131
499
|
maxAge: props.maxAge,
|
|
132
|
-
verifier:
|
|
500
|
+
verifier: live.verifier,
|
|
501
|
+
previous: shown.current ?? void 0
|
|
133
502
|
})), [
|
|
134
503
|
props.storage,
|
|
504
|
+
props.subjectId,
|
|
135
505
|
props.snapshot,
|
|
136
506
|
props.snapshotUrl,
|
|
507
|
+
props.source,
|
|
137
508
|
props.endpoint,
|
|
138
509
|
props.approvals,
|
|
139
510
|
props.tenant,
|
|
140
|
-
|
|
141
|
-
props.revalidate,
|
|
142
|
-
props.subscribeForeground,
|
|
143
|
-
props.fetch,
|
|
144
|
-
props.headers,
|
|
511
|
+
live.fetch,
|
|
145
512
|
props.maxAge,
|
|
146
|
-
|
|
513
|
+
live.verifier
|
|
147
514
|
]);
|
|
148
515
|
useEffect(() => {
|
|
516
|
+
const previous = shown.current;
|
|
517
|
+
shown.current = store;
|
|
518
|
+
if (previous !== null && previous !== store) previous.dispose();
|
|
519
|
+
}, [store]);
|
|
520
|
+
useEffect(() => props.source === void 0 ? void 0 : connectSource(store, props.source, props.subscribeForeground), [
|
|
521
|
+
store,
|
|
522
|
+
props.source,
|
|
523
|
+
props.subscribeForeground
|
|
524
|
+
]);
|
|
525
|
+
useEffect(() => {
|
|
526
|
+
if (props.snapshotUrl === void 0) return;
|
|
149
527
|
const mode = props.revalidate ?? "launch";
|
|
528
|
+
let inFlight = false;
|
|
529
|
+
let online = true;
|
|
530
|
+
let active = true;
|
|
531
|
+
let timer;
|
|
150
532
|
const refresh = () => {
|
|
151
|
-
if (
|
|
152
|
-
|
|
533
|
+
if (inFlight || !online) return;
|
|
534
|
+
inFlight = true;
|
|
535
|
+
store.get().refresh().catch(() => void 0).finally(() => {
|
|
536
|
+
inFlight = false;
|
|
537
|
+
});
|
|
153
538
|
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
539
|
+
const startTimer = () => {
|
|
540
|
+
if (typeof mode === "number" && timer === void 0) timer = setInterval(refresh, mode * 1e3);
|
|
541
|
+
};
|
|
542
|
+
const stopTimer = () => {
|
|
543
|
+
if (timer !== void 0) {
|
|
158
544
|
clearInterval(timer);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
545
|
+
timer = void 0;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
refresh();
|
|
549
|
+
startTimer();
|
|
550
|
+
const offForeground = props.subscribeForeground?.((next) => {
|
|
551
|
+
const now = next !== false;
|
|
552
|
+
if (now === active) {
|
|
553
|
+
if (now && mode === "focus") refresh();
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
active = now;
|
|
557
|
+
if (!active) {
|
|
558
|
+
stopTimer();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
startTimer();
|
|
562
|
+
if (mode === "focus" || typeof mode === "number") refresh();
|
|
563
|
+
});
|
|
564
|
+
const offOnline = props.subscribeOnline?.((next) => {
|
|
565
|
+
const back = next && !online;
|
|
566
|
+
online = next;
|
|
567
|
+
if (back && active) refresh();
|
|
568
|
+
});
|
|
569
|
+
return () => {
|
|
570
|
+
stopTimer();
|
|
571
|
+
offForeground?.();
|
|
572
|
+
offOnline?.();
|
|
573
|
+
};
|
|
162
574
|
}, [
|
|
163
575
|
store,
|
|
164
576
|
props.revalidate,
|
|
165
577
|
props.snapshotUrl,
|
|
166
|
-
props.subscribeForeground
|
|
578
|
+
props.subscribeForeground,
|
|
579
|
+
props.subscribeOnline
|
|
167
580
|
]);
|
|
168
581
|
return /* @__PURE__ */ jsx(PermDockStoreContext, {
|
|
169
582
|
value: store,
|
|
@@ -171,4 +584,113 @@ function PermDockProvider(props) {
|
|
|
171
584
|
});
|
|
172
585
|
}
|
|
173
586
|
//#endregion
|
|
174
|
-
|
|
587
|
+
//#region src/react-native/storage-adapters.ts
|
|
588
|
+
/** SecureStore warns above 2048 bytes and may refuse larger values on some devices. */
|
|
589
|
+
const SECURE_STORE_CHUNK_BYTES = 2048;
|
|
590
|
+
const INDEX_PREFIX = "permdock-chunks:";
|
|
591
|
+
function utf8Length(char) {
|
|
592
|
+
const point = char.codePointAt(0) ?? 0;
|
|
593
|
+
if (point < 128) return 1;
|
|
594
|
+
if (point < 2048) return 2;
|
|
595
|
+
return point < 65536 ? 3 : 4;
|
|
596
|
+
}
|
|
597
|
+
function split(value, max) {
|
|
598
|
+
const out = [];
|
|
599
|
+
let current = "";
|
|
600
|
+
let bytes = 0;
|
|
601
|
+
for (const char of value) {
|
|
602
|
+
const size = utf8Length(char);
|
|
603
|
+
if (bytes + size > max) {
|
|
604
|
+
out.push(current);
|
|
605
|
+
current = "";
|
|
606
|
+
bytes = 0;
|
|
607
|
+
}
|
|
608
|
+
current += char;
|
|
609
|
+
bytes += size;
|
|
610
|
+
}
|
|
611
|
+
out.push(current);
|
|
612
|
+
return out;
|
|
613
|
+
}
|
|
614
|
+
function chunkCount(index) {
|
|
615
|
+
if (index?.startsWith(INDEX_PREFIX) !== true) return;
|
|
616
|
+
const count = Number(index.slice(16));
|
|
617
|
+
return Number.isSafeInteger(count) && count > 0 ? count : void 0;
|
|
618
|
+
}
|
|
619
|
+
function chunkKey(key, index) {
|
|
620
|
+
return `${key}.${index}`;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* A `PermDockStorage` over `expo-secure-store`. Values are split into chunks
|
|
624
|
+
* of at most 2048 bytes under `<key>.<n>`; `<key>` holds the chunk count and
|
|
625
|
+
* is written last, so an interrupted write reads as absent.
|
|
626
|
+
*/
|
|
627
|
+
function secureStoreStorage(store, options) {
|
|
628
|
+
const removeChunks = async (key, from, to) => {
|
|
629
|
+
for (let index = from; index < to; index += 1) await store.deleteItemAsync(chunkKey(key, index), options);
|
|
630
|
+
};
|
|
631
|
+
return {
|
|
632
|
+
getItem: (key) => {
|
|
633
|
+
const count = chunkCount(store.getItem(key, options));
|
|
634
|
+
if (count === void 0) return null;
|
|
635
|
+
let value = "";
|
|
636
|
+
for (let index = 0; index < count; index += 1) {
|
|
637
|
+
const part = store.getItem(chunkKey(key, index), options);
|
|
638
|
+
if (part === null) return null;
|
|
639
|
+
value += part;
|
|
640
|
+
}
|
|
641
|
+
return value;
|
|
642
|
+
},
|
|
643
|
+
setItem: async (key, value) => {
|
|
644
|
+
const before = chunkCount(store.getItem(key, options)) ?? 0;
|
|
645
|
+
await store.deleteItemAsync(key, options);
|
|
646
|
+
const parts = split(value, SECURE_STORE_CHUNK_BYTES);
|
|
647
|
+
for (const [index, part] of parts.entries()) store.setItem(chunkKey(key, index), part, options);
|
|
648
|
+
store.setItem(key, `${INDEX_PREFIX}${parts.length}`, options);
|
|
649
|
+
await removeChunks(key, parts.length, before);
|
|
650
|
+
},
|
|
651
|
+
removeItem: async (key) => {
|
|
652
|
+
const before = chunkCount(store.getItem(key, options)) ?? 0;
|
|
653
|
+
await store.deleteItemAsync(key, options);
|
|
654
|
+
await removeChunks(key, 0, before);
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
/** A synchronous `PermDockStorage` over a `react-native-mmkv` instance: the first frame already has the snapshot. */
|
|
659
|
+
function mmkvStorage(mmkv) {
|
|
660
|
+
return {
|
|
661
|
+
getItem: (key) => mmkv.getString(key) ?? null,
|
|
662
|
+
setItem: (key, value) => {
|
|
663
|
+
mmkv.set(key, value);
|
|
664
|
+
},
|
|
665
|
+
removeItem: (key) => {
|
|
666
|
+
if ("remove" in mmkv) mmkv.remove(key);
|
|
667
|
+
else mmkv.delete(key);
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/react-native/subscriptions.ts
|
|
673
|
+
/**
|
|
674
|
+
* `subscribeForeground` over `AppState`: `active` returns to the foreground
|
|
675
|
+
* and `background` leaves it. iOS `inactive` (a system sheet over the app) is
|
|
676
|
+
* neither.
|
|
677
|
+
*/
|
|
678
|
+
function appStateForeground(appState) {
|
|
679
|
+
return (listener) => {
|
|
680
|
+
const subscription = appState.addEventListener("change", (state) => {
|
|
681
|
+
if (state === "active") listener(true);
|
|
682
|
+
else if (state === "background") listener(false);
|
|
683
|
+
});
|
|
684
|
+
return () => {
|
|
685
|
+
subscription.remove();
|
|
686
|
+
};
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
/** `subscribeOnline` over NetInfo. An unknown (`null`) connection counts as online. */
|
|
690
|
+
function netInfoOnline(netInfo) {
|
|
691
|
+
return (listener) => netInfo.addEventListener((state) => {
|
|
692
|
+
listener(state.isConnected !== false && state.isInternetReachable !== false);
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
//#endregion
|
|
696
|
+
export { PermDockProvider, Protected, appStateForeground, approvalHeaders, buildLocalSnapshot, connectSource, createNativeStore, describe, localSnapshot, memoryStorage, mmkvStorage, netInfoOnline, parseLocalSnapshotManifest, powersyncSource, requiredPlans, secureStoreStorage, useApproval, useAssignablePermissions, useAssignableRoles, useFilter, useMemberships, usePermDock, usePermission, usePermissionGuard, usePermissions, useRoles, useSnapshotReady, useSubject, useTenant };
|