permdock 0.4.0 → 0.5.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.
Files changed (514) hide show
  1. package/README.md +37 -35
  2. package/dist/{schema-Bol6gqXA.js → 2020-C9VN-x8c.js} +5 -130
  3. package/dist/a2a/index.d.ts +6 -6
  4. package/dist/a2a/index.js +14 -17
  5. package/dist/{adapter-context-mlWsVGGg.js → adapter-context-CRhqyzCk.js} +1 -1
  6. package/dist/adoption-scan-B4R5fnMU.js +107 -0
  7. package/dist/agent/index.d.ts +3 -0
  8. package/dist/agent/index.js +1 -0
  9. package/dist/ai-sdk/index.d.ts +18 -35
  10. package/dist/ai-sdk/index.js +37 -23
  11. package/dist/{app-data-CV8pqqMi.js → app-data-MuyzVqX8.js} +2 -1
  12. package/dist/approval-header-CJACtHkv.js +23 -0
  13. package/dist/approval-prompt-Dg5LeAcT.js +62 -0
  14. package/dist/approval-prompt-Djo_PyZc.d.ts +57 -0
  15. package/dist/approvals/index.d.ts +5 -3
  16. package/dist/approvals/index.js +8 -5
  17. package/dist/approvals-DJ6Yd5z1.js +995 -0
  18. package/dist/arazzo-B6lebmiQ.js +36 -0
  19. package/dist/{arazzo-C4BcskbX.js → arazzo-BWhNF-k0.js} +20 -14
  20. package/dist/args-IIolxxKA.js +197 -0
  21. package/dist/astro/index.d.ts +43 -0
  22. package/dist/astro/index.js +27 -0
  23. package/dist/audience-Dg8XsRaO.js +55 -0
  24. package/dist/auth-DRLEizbL.js +178 -0
  25. package/dist/authzen/index.d.ts +26 -6
  26. package/dist/authzen/index.js +94 -79
  27. package/dist/automation-BMZPIVUM.d.ts +114 -0
  28. package/dist/automation-DVjOckjV.js +157 -0
  29. package/dist/better-auth/index.d.ts +8 -6
  30. package/dist/better-auth/index.js +9 -8
  31. package/dist/better-supabase/index.d.ts +357 -30
  32. package/dist/better-supabase/index.js +936 -194
  33. package/dist/{bind-BzqG8SMb.d.ts → bind--9EFVYWF.d.ts} +12 -10
  34. package/dist/{bind-kk-uyCwH.js → bind-CZzhx-Vj.js} +14 -10
  35. package/dist/body-CH5of8Ne.js +10 -0
  36. package/dist/body-text-QcXok_SI.js +52 -0
  37. package/dist/{build-instance-DIIV9DbC.js → build-instance-BMnAudHn.js} +4 -3
  38. package/dist/{canonical-json-CFKyFOke.js → canonical-json-BC8_nMTw.js} +5 -3
  39. package/dist/{capability-CksyCWDH.d.ts → capability-BSslw1QV.d.ts} +44 -25
  40. package/dist/{capability-txATtKV4.js → capability-N1K9IpqS.js} +68 -42
  41. package/dist/casbin-Cr7RLtA3.js +30 -0
  42. package/dist/casbin-Dyu2gnUD.js +234 -0
  43. package/dist/casl-64gpT-8x.js +24 -0
  44. package/dist/casl-DjEDhTCP.js +299 -0
  45. package/dist/catalog/index.d.ts +74 -2
  46. package/dist/catalog/index.js +51 -2
  47. package/dist/{catalog-tZUyOfOv.js → catalog-BECMPrwc.js} +51 -6
  48. package/dist/catalog-DjhMYYCq.js +1 -0
  49. package/dist/catalog-R_A__RsH.js +52 -0
  50. package/dist/{catalog-doc-DWtg0gGR.js → catalog-doc-C9wjsfNY.js} +45 -23
  51. package/dist/catalog-fingerprint-CCP0-yQS.js +153 -0
  52. package/dist/chat/index.d.ts +2 -0
  53. package/dist/chat/index.js +224 -0
  54. package/dist/chat-sdk/index.d.ts +87 -0
  55. package/dist/chat-sdk/index.js +197 -0
  56. package/dist/claims-map-7oQ3ue4X.js +13 -0
  57. package/dist/claims-map-Ca-QX8C6.d.ts +32 -0
  58. package/dist/claude-agent/index.d.ts +7 -14
  59. package/dist/claude-agent/index.js +24 -27
  60. package/dist/clerk/index.d.ts +9 -8
  61. package/dist/clerk/index.js +9 -14
  62. package/dist/cli/bin.js +36 -17
  63. package/dist/cli/index.d.ts +19 -5
  64. package/dist/cli/index.js +164 -4
  65. package/dist/cloud/index.d.ts +102 -63
  66. package/dist/cloud/index.js +239 -340
  67. package/dist/cloud-CIoHNevm.js +87 -0
  68. package/dist/codemod-Bmj9dWMH.js +37 -0
  69. package/dist/codemod-Cxvvc70T.js +2084 -0
  70. package/dist/{collect-2SrB7lfk.js → collect-CrZJJnEF.js} +75 -11
  71. package/dist/collect-DloHbDVa.js +55 -0
  72. package/dist/collect-FlXJlhus.js +1 -0
  73. package/dist/command-L8EstFNm.js +6 -0
  74. package/dist/compile/index.d.ts +1 -1
  75. package/dist/compile/index.js +1 -2
  76. package/dist/{compile-CcEu2ZQ1.js → compile-CMqMx_IN.js} +11 -8
  77. package/dist/{compile-CtTP7eur.d.ts → compile-Ckm2HqBZ.d.ts} +5 -3
  78. package/dist/completion-BqhRBJD8.js +143 -0
  79. package/dist/config-B46rm9sc.js +26 -0
  80. package/dist/{config-BIjREpyE.js → config-bs_kZeYq.js} +12 -7
  81. package/dist/{config-report--Xb9APJS.js → config-report-DUgj62Ai.js} +15 -5
  82. package/dist/{connection-DUsczpB5.js → connection-DjhIJSs2.js} +6 -5
  83. package/dist/{context-DieZVJXu.js → context-bbFHR-0D.js} +2 -2
  84. package/dist/convex/index.d.ts +11 -10
  85. package/dist/convex/index.js +6 -4
  86. package/dist/create-0VZ7Pdiu.d.ts +107 -0
  87. package/dist/create-BDS7wc3y.d.ts +138 -0
  88. package/dist/create-BFfm17UA.d.ts +110 -0
  89. package/dist/create-BWRSXgOF.js +403 -0
  90. package/dist/create-C3b4B5eF.js +130 -0
  91. package/dist/{create-BBO24vj6.js → create-DnrmLnLW.js} +31 -32
  92. package/dist/{credential-kue0qpbm.js → credential-DM2um3ha.js} +152 -31
  93. package/dist/credentials-DPyHmYz5.js +74 -0
  94. package/dist/delegation-DaXVdDhM.js +286 -0
  95. package/dist/delivery/index.d.ts +5 -0
  96. package/dist/delivery/index.js +5 -0
  97. package/dist/delivery-DCAgNyCn.js +499 -0
  98. package/dist/delivery-event-xX4obB8F.js +40 -0
  99. package/dist/{denied-text-DfRk15uw.d.ts → denied-text-D8jDHgsl.d.ts} +5 -5
  100. package/dist/{describe-C3ldA9os.d.ts → describe-BZUsixiL.d.ts} +2 -2
  101. package/dist/{describe-Cgkp7eP0.js → describe-BybMRY7A.js} +6 -2
  102. package/dist/device-BARQ8eYG.js +193 -0
  103. package/dist/diff-CxZo9pTq.js +37 -0
  104. package/dist/{diff-rpqoe7Ag.js → diff-DCePiN6M.js} +60 -54
  105. package/dist/doctor-CxiwSfqH.js +44 -0
  106. package/dist/{doctor-owlv6ddh.js → doctor-DFjUxf2f.js} +245 -50
  107. package/dist/drizzle/index.d.ts +5 -3
  108. package/dist/drizzle/index.js +2 -2
  109. package/dist/elysia/index.d.ts +16 -13
  110. package/dist/elysia/index.js +13 -12
  111. package/dist/env-DJZrPjRi.js +8 -0
  112. package/dist/errors-BDUwg2qC.js +27 -0
  113. package/dist/{errors-drnfxYtm.js → errors-BKy0EfhN.js} +5 -9
  114. package/dist/errors-BWXBMaKK.d.ts +11 -0
  115. package/dist/{errors-OD_4c__H.d.ts → errors-C2PXIv4c.d.ts} +2 -2
  116. package/dist/errors-CWTY6uih.js +143 -0
  117. package/dist/evaluate-_R8QkWaf.js +1732 -0
  118. package/dist/evaluations-16UqqQ6W.d.ts +32 -0
  119. package/dist/{evaluations-C9YJsv3H.js → evaluations-DZ2CbV5k.js} +145 -34
  120. package/dist/eve/index.d.ts +12 -16
  121. package/dist/eve/index.js +22 -28
  122. package/dist/event-time-CsegxXxB.js +23 -0
  123. package/dist/expiry-D4_YKRKD.js +52 -0
  124. package/dist/express/index.d.ts +13 -10
  125. package/dist/express/index.js +12 -11
  126. package/dist/fastify/index.d.ts +25 -22
  127. package/dist/fastify/index.js +13 -12
  128. package/dist/fetch-adapter-g0ypLkID.js +120 -0
  129. package/dist/fetch-adapter-qKJBuRqy.d.ts +31 -0
  130. package/dist/fields-D9tPVUUS.js +203 -0
  131. package/dist/files-C5ZI27eV.js +124 -0
  132. package/dist/{fixtures-h2eG2OZV.js → fixtures-B7XrLeY7.js} +8 -7
  133. package/dist/flags-C3DktBDY.js +86 -0
  134. package/dist/{from-snapshot-7REQZe0H.js → from-snapshot-D2lZt4Dd.js} +55 -52
  135. package/dist/{grantee-CXY-0C87.js → grantee-Cn1HyUsI.js} +3 -3
  136. package/dist/{grantee-conditions-MQs5NIuX.js → grantee-conditions-CcXf8hMM.js} +4 -3
  137. package/dist/{grantee-match-fxYp9Nmt.js → grantee-match-DHArqY82.js} +5 -4
  138. package/dist/h3/index.d.ts +37 -0
  139. package/dist/h3/index.js +35 -0
  140. package/dist/headers-BIjfMaoC.js +8 -0
  141. package/dist/headers-CIbDTUTK.d.ts +7 -0
  142. package/dist/{helpers-C9YmyBIa.js → helpers-DTcZOzhF.js} +45 -38
  143. package/dist/hono/index.d.ts +12 -9
  144. package/dist/hono/index.js +13 -12
  145. package/dist/hosted-BZIAYvon.js +315 -0
  146. package/dist/hosted-DBDX0M-P.d.ts +78 -0
  147. package/dist/{http-DPuDaChb.d.ts → http-B_LphE5Y.d.ts} +1 -2
  148. package/dist/http-DXJ37RDA.js +46 -0
  149. package/dist/{http-BEbdMZ05.js → http-ujKm0JXE.js} +1 -2
  150. package/dist/{import-UHk1N7vH.js → import-CNV7I2Dw.js} +25 -20
  151. package/dist/{import-BFIlhetD.js → import-DMmOG27O.js} +190 -53
  152. package/dist/index-BcHcPyIo.d.ts +110 -0
  153. package/dist/index-CaxrMD1A.d.ts +1 -0
  154. package/dist/index-Chrs5fQ-.d.ts +210 -0
  155. package/dist/index-CxGUswIC.d.ts +431 -0
  156. package/dist/index-D8EovfsP.d.ts +91 -0
  157. package/dist/{index-UdVQgq48.d.ts → index-DOVf7RJv.d.ts} +431 -81
  158. package/dist/{index-BwMe94Xq.d.ts → index-SGdIQyzc.d.ts} +34 -16
  159. package/dist/index.d.ts +19 -15
  160. package/dist/index.js +31 -21
  161. package/dist/init-DeMYsnYJ.js +96 -0
  162. package/dist/init-GG6Jh8HD.js +95 -0
  163. package/dist/{instance-options-plkrsAog.d.ts → instance-options-Omfd793B.d.ts} +2 -2
  164. package/dist/instance-snapshot-Cxq4ygFc.js +600 -0
  165. package/dist/instant-BluqDvyS.js +19 -0
  166. package/dist/internals-Dk8A8fX3.js +17 -0
  167. package/dist/{json-schema-DBkdUuCO.js → json-schema-B-vAwlde.js} +45 -6
  168. package/dist/json-schema-CN_iLFH2.d.ts +40 -0
  169. package/dist/jwt/index.d.ts +18 -11
  170. package/dist/jwt/index.js +156 -135
  171. package/dist/{kernel-CB3LrIJM.js → kernel-5JatXyND.js} +52 -24
  172. package/dist/kysely/index.d.ts +5 -3
  173. package/dist/kysely/index.js +2 -2
  174. package/dist/load-BxEtwlBS.js +1 -0
  175. package/dist/{load-C3_oTHyO.js → load-DFS_ry0W.js} +22 -6
  176. package/dist/{load-jose-BL6LH4bL.js → load-jose-DZ4dnjri.js} +1 -4
  177. package/dist/login-Dfe5RlYk.js +68 -0
  178. package/dist/login-imhuwvn3.js +254 -0
  179. package/dist/manifest-C8IzW3Do.js +42 -0
  180. package/dist/manifest-CtKR3GXL.js +370 -0
  181. package/dist/manifest-json-CAGzls-C.js +9 -0
  182. package/dist/{manifest-uDS9y5de.d.ts → manifest-mx5ghSFM.d.ts} +9 -2
  183. package/dist/manifest-schema-C0kK_8V0.js +399 -0
  184. package/dist/{map-claims-AVlBaJoa.js → map-claims-D3oRmTk0.js} +13 -10
  185. package/dist/{map-error-BE27PYkE.js → map-error-TCAdw-eW.js} +3 -3
  186. package/dist/{markers-CiwAOZtO.js → markers-C6joDI3o.js} +2 -1
  187. package/dist/mcp/index.d.ts +22 -12
  188. package/dist/mcp/index.js +57 -39
  189. package/dist/{migrate-BwlB5-Wk.js → migrate-BShP7Vf4.js} +53 -14
  190. package/dist/nest/index.d.ts +12 -9
  191. package/dist/nest/index.js +15 -14
  192. package/dist/next/index.d.ts +18 -21
  193. package/dist/next/index.js +13 -11
  194. package/dist/next/plugin.d.ts +1 -1
  195. package/dist/next/plugin.js +2 -2
  196. package/dist/node/index.d.ts +10 -10
  197. package/dist/node/index.js +7 -9
  198. package/dist/{ocsf-uYFXGVw2.js → ocsf-BFp-PZZA.js} +22 -11
  199. package/dist/openai/index.d.ts +9 -16
  200. package/dist/openai/index.js +17 -24
  201. package/dist/openapi/index.d.ts +3 -3
  202. package/dist/openapi/index.js +1 -1
  203. package/dist/{openapi-DBzHQbov.js → openapi-B7HZ0f-r.js} +8 -8
  204. package/dist/{openapi-BJdBmYDG.js → openapi-DTaEmTSW.js} +10 -9
  205. package/dist/openapi-ahr8rHu3.js +138 -0
  206. package/dist/operation-findings-DgATDpvh.js +36 -0
  207. package/dist/operations-CxybZErY.d.ts +59 -0
  208. package/dist/orpc/index.d.ts +13 -10
  209. package/dist/orpc/index.js +20 -15
  210. package/dist/otel/index.d.ts +3 -2
  211. package/dist/otel/index.js +30 -7
  212. package/dist/output-Dyw8fyPF.js +88 -0
  213. package/dist/output-files-B3IZJksC.js +1 -0
  214. package/dist/{output-files-CgIsvdSa.js → output-files-DhRBBE4n.js} +24 -26
  215. package/dist/{permission-keys-B26jeyUv.js → ownership-BatFgAA4.js} +1698 -869
  216. package/dist/{package-root-DtNnpmUd.js → package-root-Dk_ETdkp.js} +1 -1
  217. package/dist/{parse-CVFQHk6c.js → parse-Cxq0WxrA.js} +2 -2
  218. package/dist/{parse-local-manifest-C-q02Pal.js → parse-local-manifest-CVSs6J9I.js} +1 -1
  219. package/dist/{parse-local-manifest-DvYUR0QL.d.ts → parse-local-manifest-DgqtruPn.d.ts} +1 -1
  220. package/dist/parse-request-D_tUXG6M.js +26 -0
  221. package/dist/paths-DXSHAMIa.js +42 -0
  222. package/dist/pdp/index.d.ts +7 -3
  223. package/dist/pdp/index.js +45 -26
  224. package/dist/{peer-BOr_kJE1.js → peer-C8swJ2GH.js} +23 -4
  225. package/dist/peer-CRvC7Hg1.js +1 -0
  226. package/dist/permdock-B9JxkBwC.js +868 -0
  227. package/dist/permdock-D7eeLJER.d.ts +502 -0
  228. package/dist/{permission-registry-BsblpB-z.js → permission-registry-Br4jSNVi.js} +3 -3
  229. package/dist/permissions-B-wCP5ZC.js +30 -0
  230. package/dist/{permissions-CCJ6lmxB.js → permissions-CZKiUfFM.js} +4 -3
  231. package/dist/{permissions-COH-KRgT.d.ts → permissions-oEWfl-kl.d.ts} +1 -2
  232. package/dist/policies-CO1oOymN.js +295 -0
  233. package/dist/{policy-ur0BBK_e.d.ts → policy-Czo4n3Hs.d.ts} +2 -2
  234. package/dist/{hosted-CBHgkzDl.js → policy-DLZJ5gAp.js} +17 -273
  235. package/dist/policy-from-catalog-DzhEc3Y9.js +450 -0
  236. package/dist/policy-module-CTlwMvLI.js +89 -0
  237. package/dist/{policy-types-sp9P1iIV.d.ts → policy-types-DzwivBgR.d.ts} +434 -631
  238. package/dist/postgrest-CW0IqC-U.js +566 -0
  239. package/dist/postgrest-NUqZT-RB.d.ts +100 -0
  240. package/dist/powersync-BHfuehf3.js +62 -0
  241. package/dist/powersync-CbzkqL_M.js +1 -0
  242. package/dist/{powersync-cZe4kzhL.js → powersync-bYUDLOAO.js} +23 -24
  243. package/dist/preset/index.d.ts +146 -0
  244. package/dist/preset/index.js +1 -0
  245. package/dist/preset-DZdU0tne.js +1768 -0
  246. package/dist/principal-source-pHneukrx.js +103 -0
  247. package/dist/prisma/index.d.ts +6 -3
  248. package/dist/prisma/index.js +2 -2
  249. package/dist/{problem-CnWraVhC.js → problem-CTviyH5L.js} +13 -23
  250. package/dist/{problem-details-rIIo8B2C.d.ts → problem-details-DXlt-vks.d.ts} +1 -1
  251. package/dist/{problem-details-DECUnXAn.js → problem-details-cn5X30gZ.js} +43 -40
  252. package/dist/problem-types-CJ2325SZ.js +5 -0
  253. package/dist/{prompt-CXYhLfsS.js → prompt-DfZLJLIn.js} +2 -2
  254. package/dist/{protected-B3_P7xuw.d.ts → protected-DEPHc2xV.d.ts} +16 -8
  255. package/dist/{protected-BN7BUdY1.js → protected-DfjY5mLA.js} +21 -4
  256. package/dist/{provider-Bi-0HNL3.js → provider-CC-u3bYP.js} +2 -2
  257. package/dist/{provider-kwHC9CZD.d.ts → provider-DMVt6yYn.d.ts} +1 -1
  258. package/dist/{provider-store-Ctt-81Ni.js → provider-store-B5Yrkhzr.js} +2 -2
  259. package/dist/pull-BgIfno6w.js +256 -0
  260. package/dist/pull-ByOks_Tg.js +1 -0
  261. package/dist/push-CmFVBOeI.js +116 -0
  262. package/dist/pushed-policy-BImMTTIM.d.ts +57 -0
  263. package/dist/pushed-policy-DobP7AHI.js +238 -0
  264. package/dist/react/index.d.ts +8 -8
  265. package/dist/react/index.js +6 -6
  266. package/dist/react/provider-client.d.ts +1 -1
  267. package/dist/react/provider-client.js +1 -2
  268. package/dist/react-native/index.d.ts +24 -72
  269. package/dist/react-native/index.js +24 -22
  270. package/dist/{refs-f3imMjNW.js → refs-K6eWUJ0H.js} +1 -1
  271. package/dist/{relation-walk-BXnlLtg2.js → relation-walk-3OyDBF0S.js} +2 -2
  272. package/dist/{relations-CvmSpG67.js → relations-BnCWnJGI.js} +3 -3
  273. package/dist/renames-CGj7YwcQ.js +175 -0
  274. package/dist/{replay-COpmZUfx.d.ts → replay-D7iKcLFe.d.ts} +1 -1
  275. package/dist/{replay-BsOyTrdV.js → replay-Du1tJjG7.js} +2 -1
  276. package/dist/{request-context-BVM7aWNs.js → request-context-BTRTG7OT.js} +3 -3
  277. package/dist/request-schema-CMreVuFM.js +148 -0
  278. package/dist/resend/index.d.ts +126 -0
  279. package/dist/resend/index.js +379 -0
  280. package/dist/{resource-relations-D1Un3pcz.js → resource-relations-D_jw0BFx.js} +1 -1
  281. package/dist/{retire-BFcxL6un.js → retire-CALjIQ7e.js} +2 -2
  282. package/dist/{revocations-Cy06JNx2.d.ts → revocations-R07lFBnX.d.ts} +2 -0
  283. package/dist/rls-BA8an5Ap.js +336 -0
  284. package/dist/{rls-BEktUaqg.js → rls-j6t43t7n.js} +287 -689
  285. package/dist/{role-builder-B4GbKM-i.js → role-builder-CXbis5-X.js} +14 -207
  286. package/dist/{rpc-nYC3cR_u.js → rpc-aPyNi6tA.js} +7 -7
  287. package/dist/run-CNsApDpd.js +1 -0
  288. package/dist/run-DOfMtc9V.js +723 -0
  289. package/dist/run-ticket-BjhTOi6u.d.ts +124 -0
  290. package/dist/run-ticket-sxFI6LAk.js +337 -0
  291. package/dist/{runtime-D_tMXnsq.js → runtime-D3VTAiCA.js} +1 -1
  292. package/dist/{saas-DtaA4JuW.js → saas-FO-Q8oj0.js} +16 -14
  293. package/dist/scan-BOI5tJ-6.js +29 -0
  294. package/dist/{schema-DjQBcAP9.js → schema-B4v0Qrac.js} +102 -8
  295. package/dist/schema-yLuBWWsh.js +130 -0
  296. package/dist/scim/index.d.ts +2 -2
  297. package/dist/scim/index.js +1 -2
  298. package/dist/{scim-vFR1O5oG.js → scim-ClHtpyV3.js} +208 -76
  299. package/dist/{scopes-tvpa34ep.js → scopes-CUPSjo9q.js} +12 -7
  300. package/dist/server/index.d.ts +12 -143
  301. package/dist/server/index.js +12 -9
  302. package/dist/server-DqCT4CgZ.js +453 -0
  303. package/dist/{server-types-DdqBwZN_.d.ts → server-types-BLd4MnBX.d.ts} +51 -68
  304. package/dist/{sha256-BO0swRXL.js → sha256-D9ihqmvd.js} +8 -1
  305. package/dist/{shared-1uhI-e-b.js → shared-CD11nBbC.js} +18 -8
  306. package/dist/{shared-JhMeOsDF.js → shared-DvvFzYXe.js} +8 -9
  307. package/dist/signals-D3NcTKUS.js +32 -0
  308. package/dist/sink-BEZSlMS_.js +957 -0
  309. package/dist/sink-Bj_lDUDq.d.ts +225 -0
  310. package/dist/{skills-BZdRQkxs.js → skills-B6lVdD_W.js} +13 -6
  311. package/dist/skills-CTYwkl44.js +51 -0
  312. package/dist/snapshot-CXUWfsNy.js +269 -0
  313. package/dist/{snapshot-cache-Cod40D-X.js → snapshot-cache-DZHQ0KF6.js} +11 -5
  314. package/dist/{snapshot-cache-J5T7t_vD.d.ts → snapshot-cache-DqK9eDmM.d.ts} +7 -5
  315. package/dist/solid/index.d.ts +11 -12
  316. package/dist/solid/index.js +7 -7
  317. package/dist/solid-start/index.d.ts +52 -0
  318. package/dist/solid-start/index.js +49 -0
  319. package/dist/{sources-Dljy06zL.d.ts → sources-BV9j0DeZ.d.ts} +7 -13
  320. package/dist/{sources-B1-b-R0t.js → sources-vs5dGOsS.js} +125 -119
  321. package/dist/{sql-t8teWOfo.js → sql-B5T1IL83.js} +13 -1
  322. package/dist/src-DLfUWFAI.js +1851 -0
  323. package/dist/ssf/index.d.ts +4 -4
  324. package/dist/ssf/index.js +384 -47
  325. package/dist/standard-webhooks-6lg8v_is.d.ts +88 -0
  326. package/dist/standard-webhooks-DgFFD-Ga.js +228 -0
  327. package/dist/storage-C2bWdvJH.js +132 -0
  328. package/dist/{store-ILkLUj_o.js → store-4u_hxjWa.js} +40 -53
  329. package/dist/{store-options-CbUHDoSe.js → store-options-BqEakYRa.js} +26 -21
  330. package/dist/{stores-BHXdSbw9.js → stores-BbsD4fAR.js} +2 -2
  331. package/dist/{stores-Cxz_80g-.d.ts → stores-ClZUgeoP.d.ts} +7 -8
  332. package/dist/{stream-Dwsg6WwE.d.ts → stream-7-xmnf3U.d.ts} +2 -2
  333. package/dist/{stream-BMui98KK.js → stream-CvdUS9V1.js} +9 -2
  334. package/dist/style-DiKWnAvn.js +1 -0
  335. package/dist/{style-CTm1AXDT.js → style-Uao76wO7.js} +3 -2
  336. package/dist/subject-BGoM5o8B.js +17 -0
  337. package/dist/supabase/index.d.ts +23 -106
  338. package/dist/supabase/index.js +5 -4
  339. package/dist/supabase/middleware.d.ts +7 -6
  340. package/dist/supabase/middleware.js +13 -11
  341. package/dist/supabase-9pqI57pW.js +92 -0
  342. package/dist/{supabase-C1TWlnYt.js → supabase-Dxlp8A94.js} +98 -205
  343. package/dist/supabase-hook-CXcGpHqq.js +1 -0
  344. package/dist/{supabase-hook-Cva3ikXz.js → supabase-hook-DdDQhMlw.js} +951 -60
  345. package/dist/support-session-C6xJQYut.js +158 -0
  346. package/dist/svelte/Protected.svelte +4 -4
  347. package/dist/svelte/index.d.ts +7 -7
  348. package/dist/svelte/index.js +10 -10
  349. package/dist/svelte/runtime.d.ts +3 -3
  350. package/dist/svelte/runtime.js +3 -3
  351. package/dist/svelte/source.d.ts +7 -7
  352. package/dist/svelte/source.js +4 -4
  353. package/dist/sveltekit/index.d.ts +51 -0
  354. package/dist/sveltekit/index.js +27 -0
  355. package/dist/tanstack-start/index.d.ts +51 -0
  356. package/dist/tanstack-start/index.js +40 -0
  357. package/dist/target-Bw37TFNA.js +51 -0
  358. package/dist/{tenancy-DshjqY0n.js → tenancy-DN2QAx9z.js} +5 -5
  359. package/dist/terminal/index.d.ts +11 -9
  360. package/dist/terminal/index.js +23 -287
  361. package/dist/testing/index.d.ts +311 -38
  362. package/dist/testing/index.js +3475 -201
  363. package/dist/testing/saas/index.d.ts +9 -8
  364. package/dist/testing/saas/index.js +2 -2
  365. package/dist/testing/saas/permissions.d.ts +1 -1
  366. package/dist/testing/saas/permissions.js +1 -2
  367. package/dist/text-BMFRfBqc.js +8 -0
  368. package/dist/{text-diff-BdkkYSbi.js → text-diff-BQcUapOb.js} +1 -1
  369. package/dist/thenable-yD7SabqG.js +31 -0
  370. package/dist/time-DkWjdL98.js +71 -0
  371. package/dist/{token-Bx9qy30p.js → token-BLZcjQgt.js} +15 -6
  372. package/dist/{tool-refusal-CQ7OEia9.js → tool-refusal-CMLN5xhn.js} +2 -2
  373. package/dist/trpc/index.d.ts +12 -9
  374. package/dist/trpc/index.js +16 -14
  375. package/dist/{types-7rJVLWe5.d.ts → types-5Ut_pbKy.d.ts} +61 -11
  376. package/dist/{store-9KO4BlkB.d.ts → types-BNORmDM8.d.ts} +100 -75
  377. package/dist/types-BjV-fqcA.d.ts +57 -0
  378. package/dist/{types-CUcFZfpU.d.ts → types-BqAKcRNW.d.ts} +2 -1
  379. package/dist/types-C8-KNsFf.d.ts +107 -0
  380. package/dist/{types-Br9IXUBG.d.ts → types-CCpc2Dcv.d.ts} +77 -17
  381. package/dist/{types-DpWfQdSh.d.ts → types-CZTnPFzM.d.ts} +46 -11
  382. package/dist/{types-CqrjB9o6.d.ts → types-CdlxsYQh.d.ts} +23 -11
  383. package/dist/{types-CIlTojhq.d.ts → types-ClZaWzfb.d.ts} +9 -6
  384. package/dist/types-DX0LaKTb.d.ts +157 -0
  385. package/dist/types-DiQjupG2.d.ts +332 -0
  386. package/dist/types-DqzsnlSA.js +67 -0
  387. package/dist/types-_sHy8BQf.d.ts +65 -0
  388. package/dist/{types-ByUo56un.d.ts → types-fbZ7JEXr.d.ts} +23 -22
  389. package/dist/{types-DHrmBJLH.d.ts → types-tIgIeIKJ.d.ts} +7 -7
  390. package/dist/unplugin/index.d.ts +1 -1
  391. package/dist/unplugin/index.js +2 -2
  392. package/dist/usage-CHOtwL19.js +1 -0
  393. package/dist/usage-DHtE8j4E.js +32 -0
  394. package/dist/{usage-CG9nOYZw.js → usage-T5mXq98v.js} +54 -11
  395. package/dist/{validation-error-BSSw0l_8.d.ts → validation-error-Bg5Tpluk.d.ts} +1 -1
  396. package/dist/{validity-dVrUEPJt.js → validity-CZ7-y0Cj.js} +32 -15
  397. package/dist/{verifier-DMr_Zmb_.js → verifier-DHuh-okk.js} +18 -7
  398. package/dist/{verify-BztUB3GX.js → verify-DbCL9bnB.js} +645 -50
  399. package/dist/{version-BEogC-rB.js → version-CEbQ5UeM.js} +4 -3
  400. package/dist/version-DXkYUISx.js +1 -0
  401. package/dist/{views-CJsrBS1f.js → views-DTIIO-oQ.js} +22 -5
  402. package/dist/{permission-types-Dg39z9Kv.d.ts → vocabulary-D6lPdb4Z.d.ts} +65 -2
  403. package/dist/vue/index.d.ts +9 -10
  404. package/dist/vue/index.js +8 -8
  405. package/dist/waiter-BGUtGYoU.js +67 -0
  406. package/dist/waiter-CKy4MQSY.d.ts +36 -0
  407. package/dist/watch-Cb-NcaUw.js +1 -0
  408. package/dist/{watch-zeucB7eF.js → watch-CszoTJMq.js} +44 -5
  409. package/dist/webmcp/index.d.ts +2 -2
  410. package/dist/webmcp/index.js +3 -3
  411. package/dist/where-scope-Dv-WTP-w.js +306 -0
  412. package/dist/who-can-D0QoYbEb.js +364 -0
  413. package/dist/wire-delegation-Cv3W2eaM.js +36 -0
  414. package/dist/wire-denial-C7PaVYEM.js +27 -0
  415. package/dist/workflow/index.d.ts +5 -0
  416. package/dist/workflow/index.js +223 -0
  417. package/dist/workflow-sdk/index.d.ts +56 -0
  418. package/dist/workflow-sdk/index.js +78 -0
  419. package/dist/{wrap-Cr93qqdP.d.ts → wrap-Bd1Tejur.d.ts} +2 -1
  420. package/dist/{wrap-DWsU_5Bd.js → wrap-gX61EtpB.js} +7 -6
  421. package/package.json +136 -37
  422. package/schemas/access-event-v1.json +118 -0
  423. package/schemas/approval-request-v1.json +34 -1
  424. package/schemas/approval-signature-v1.json +94 -0
  425. package/schemas/automation-event-v1.json +113 -0
  426. package/schemas/capability-v1.json +84 -0
  427. package/schemas/catalog-event-v1.json +87 -0
  428. package/schemas/catalog-v1.json +123 -12
  429. package/schemas/cli-commands-v1.json +164 -0
  430. package/schemas/cli-result-v1.json +96 -0
  431. package/schemas/cloud-api-v1.json +5407 -0
  432. package/schemas/connector-v1.json +408 -0
  433. package/schemas/credential-event-v1.json +81 -0
  434. package/schemas/credential-v1.json +134 -0
  435. package/schemas/decision-event-v1.json +288 -0
  436. package/schemas/delivery-event-v1.json +117 -0
  437. package/schemas/directory-event-v1.json +85 -0
  438. package/schemas/evidence-export-v1.json +54 -0
  439. package/schemas/membership-event-v1.json +93 -0
  440. package/schemas/policy-v1.json +68 -0
  441. package/schemas/pushed-policy-v1.json +236 -0
  442. package/schemas/run-v1.json +162 -0
  443. package/schemas/snapshot-v1.json +138 -0
  444. package/schemas/supabase-claims-v1.json +4 -4
  445. package/schemas/supabase-manifest-v1.json +5 -1
  446. package/schemas/support-session-v1.json +111 -0
  447. package/skills/permdock/SKILL.md +16 -12
  448. package/skills/permdock-agents/SKILL.md +40 -23
  449. package/skills/permdock-agents/references/operations-automations-chat.md +221 -0
  450. package/skills/permdock-agents/references/runtimes.md +22 -18
  451. package/skills/permdock-approvals/SKILL.md +29 -13
  452. package/skills/permdock-approvals/references/delivery-and-waiters.md +172 -0
  453. package/skills/permdock-approvals/references/stores-and-resume.md +21 -7
  454. package/skills/permdock-audit/SKILL.md +3 -3
  455. package/skills/permdock-credentials/SKILL.md +5 -5
  456. package/skills/permdock-credentials/references/tokens-keys-links.md +14 -10
  457. package/skills/permdock-data/SKILL.md +6 -6
  458. package/skills/permdock-data/references/queries-and-rls.md +9 -8
  459. package/skills/permdock-data/references/relationships.md +3 -3
  460. package/skills/permdock-tenancy/SKILL.md +20 -7
  461. package/skills/permdock-tenancy/references/contacts-and-support-sessions.md +122 -0
  462. package/skills/permdock-tenancy/references/ownership-and-custom-roles.md +5 -4
  463. package/skills/permdock-wire/SKILL.md +17 -11
  464. package/skills/permdock-wire/references/adapters.md +139 -51
  465. package/skills/permdock-wire/references/policy-options.md +5 -5
  466. package/skills/permdock-wire/references/presets-and-recipes.md +58 -0
  467. package/dist/approvals-DZL76lKW.js +0 -240
  468. package/dist/arazzo-CD8d0WLb.js +0 -54
  469. package/dist/catalog-6yWAX6Ps.js +0 -2
  470. package/dist/catalog-WHG4kBq7.js +0 -48
  471. package/dist/cloud-C7bSDgX4.js +0 -50
  472. package/dist/cloud-PeBN3IEn.js +0 -118
  473. package/dist/collect-Bw2Jdq1q.js +0 -2
  474. package/dist/collect-CQx4hX4N.js +0 -83
  475. package/dist/commands-Cpip4ULx.js +0 -97
  476. package/dist/config-DLt6BvV7.js +0 -36
  477. package/dist/diff-Cnghh_Ip.js +0 -48
  478. package/dist/doctor-CuVJvhV_.js +0 -53
  479. package/dist/duration-xK2jGFVc.js +0 -25
  480. package/dist/errors-CWfoNg9N.js +0 -47
  481. package/dist/errors-DRnGZHzF.js +0 -30
  482. package/dist/expiry-BoBJ8Tvc.js +0 -7
  483. package/dist/fields-fwfXN01n.js +0 -1016
  484. package/dist/headers-BZSDieNT.js +0 -6
  485. package/dist/headers-Cf-zWvsO.d.ts +0 -6
  486. package/dist/ids-DC4V4CFu.js +0 -18
  487. package/dist/index-DgM7w96K.d.ts +0 -6
  488. package/dist/index-Dz7didpC.d.ts +0 -201
  489. package/dist/load-B_shHrmd.js +0 -2
  490. package/dist/manifest-BngWKryL.js +0 -770
  491. package/dist/may-use-BOn_dR_w.js +0 -78
  492. package/dist/openapi-DcQ1Kg40.js +0 -164
  493. package/dist/ownership-BgnbOJFT.js +0 -851
  494. package/dist/permdock-L26udHSk.js +0 -3646
  495. package/dist/powersync-BFSbSElQ.js +0 -62
  496. package/dist/powersync-DCDgZgfZ.js +0 -2
  497. package/dist/rls-55DQTuf5.js +0 -250
  498. package/dist/run-DMcNW_8T.js +0 -174
  499. package/dist/server-ZYEHtNHS.js +0 -268
  500. package/dist/sink-BTtmfPnE.js +0 -141
  501. package/dist/sink-CPN4zLfs.d.ts +0 -104
  502. package/dist/skills-Dle4ZoLF.js +0 -56
  503. package/dist/snapshot-Dc9CHPME.js +0 -1078
  504. package/dist/src-Bb7no-hS.js +0 -639
  505. package/dist/subject-C6dLxqHU.js +0 -24
  506. package/dist/supabase-Dbqr141s.js +0 -83
  507. package/dist/supabase-hook-BULg7Ut_.js +0 -2
  508. package/dist/thenable-QSmvt-vZ.js +0 -65
  509. package/dist/types-C0dee0Qf.d.ts +0 -197
  510. package/dist/types-DvupZE0w.d.ts +0 -9
  511. package/dist/usage-4G6t643F.js +0 -42
  512. package/dist/usage-iFLJ0-rr.js +0 -2
  513. package/dist/vocabulary-hhEFLFoL.d.ts +0 -65
  514. package/dist/watch-C8TpsAl4.js +0 -2
@@ -0,0 +1,1768 @@
1
+ //#region src/preset/catalog.ts
2
+ const ARCHETYPES = [
3
+ {
4
+ id: "b2b",
5
+ title: "B2B SaaS",
6
+ description: "Organisations with owner, admin, member and viewer roles, custom roles and a decision log.",
7
+ requires: [
8
+ "tenancy",
9
+ "custom-roles",
10
+ "decision-log"
11
+ ]
12
+ },
13
+ {
14
+ id: "agent",
15
+ title: "AI agent product",
16
+ description: "Tools an agent calls on a user's behalf, with human approval on the ones that change data.",
17
+ requires: [
18
+ "operations",
19
+ "approvals",
20
+ "decision-log"
21
+ ]
22
+ },
23
+ {
24
+ id: "marketplace",
25
+ title: "Marketplace",
26
+ description: "Buyers and sellers who manage what they own, with refunds behind an approval.",
27
+ requires: ["ownership", "approvals"]
28
+ },
29
+ {
30
+ id: "api",
31
+ title: "API product",
32
+ description: "Projects reached through API keys, for developers and their integrations.",
33
+ requires: [
34
+ "tenancy",
35
+ "api-keys",
36
+ "decision-log"
37
+ ]
38
+ },
39
+ {
40
+ id: "internal",
41
+ title: "Internal tool",
42
+ description: "Support staff, leads and admins working tickets, with approval on destructive actions.",
43
+ requires: ["approvals", "decision-log"]
44
+ },
45
+ {
46
+ id: "consumer",
47
+ title: "Consumer app",
48
+ description: "Users who own their data, with free and pro plans and a daily limit on the free plan.",
49
+ requires: [
50
+ "ownership",
51
+ "plans",
52
+ "limits"
53
+ ]
54
+ }
55
+ ];
56
+ const FEATURES = [
57
+ {
58
+ id: "tenancy",
59
+ title: "Organisations",
60
+ description: "Roles held per organisation; every row carries an orgId and a member sees only their organisations."
61
+ },
62
+ {
63
+ id: "custom-roles",
64
+ title: "Custom roles",
65
+ description: "Organisation admins compose their own roles from the permissions they hold.",
66
+ requires: ["tenancy"]
67
+ },
68
+ {
69
+ id: "approvals",
70
+ title: "Approvals",
71
+ description: "Destructive actions return approval-required until a person approves them."
72
+ },
73
+ {
74
+ id: "operations",
75
+ title: "Operations",
76
+ description: "Tools an agent may call, each bound to one permission, in defineOperations."
77
+ },
78
+ {
79
+ id: "decision-log",
80
+ title: "Decision log",
81
+ description: "Every decision goes to a DecisionSink."
82
+ },
83
+ {
84
+ id: "limits",
85
+ title: "Limits",
86
+ description: "A grant allows a number of calls per time window."
87
+ },
88
+ {
89
+ id: "plans",
90
+ title: "Plans",
91
+ description: "Free and pro plans; pro unlocks actions the free plan lacks."
92
+ },
93
+ {
94
+ id: "ownership",
95
+ title: "Ownership",
96
+ description: "A user updates and deletes the rows they own."
97
+ },
98
+ {
99
+ id: "api-keys",
100
+ title: "API keys",
101
+ description: "Keys created with decideCredential, never wider than the person who creates them."
102
+ },
103
+ {
104
+ id: "rls",
105
+ title: "Row-level security",
106
+ description: "Postgres RLS policies generated from the same policy, with permdock rls generate."
107
+ }
108
+ ];
109
+ const AUTH = [
110
+ {
111
+ id: "custom",
112
+ title: "Your own session",
113
+ description: "currentUser() in session.ts returns your signed-in user; until it does, every check denies."
114
+ },
115
+ {
116
+ id: "supabase",
117
+ title: "Supabase Auth",
118
+ description: "subjectFromSupabase over the claims supabase.auth.getClaims() verified."
119
+ },
120
+ {
121
+ id: "better-auth",
122
+ title: "Better Auth",
123
+ description: "subjectFromBetterAuth over the session auth.api.getSession() returns."
124
+ },
125
+ {
126
+ id: "clerk",
127
+ title: "Clerk",
128
+ description: "subjectFromClerk over Clerk's auth object."
129
+ },
130
+ {
131
+ id: "jwt",
132
+ title: "Any OIDC provider",
133
+ description: "subjectFromJwt verifies the bearer token through OpenID Connect Discovery."
134
+ }
135
+ ];
136
+ const BACKENDS = [
137
+ {
138
+ id: "memory",
139
+ title: "In memory",
140
+ description: "Demo rows in a Map and memory sources, for the first run."
141
+ },
142
+ {
143
+ id: "supabase",
144
+ title: "Supabase",
145
+ description: "Memberships read through PostgREST with postgrestSources(), from the subject_for function."
146
+ },
147
+ {
148
+ id: "drizzle",
149
+ title: "Drizzle",
150
+ description: "A Drizzle schema and client; rows load by id and lists filter with toWhere()."
151
+ },
152
+ {
153
+ id: "prisma",
154
+ title: "Prisma",
155
+ description: "A Prisma schema and client; rows load by id and lists filter with toWhere()."
156
+ }
157
+ ];
158
+ const FRAMEWORKS = [
159
+ {
160
+ id: "next",
161
+ title: "Next.js",
162
+ description: "permdock/next for Server Components, actions and routes."
163
+ },
164
+ {
165
+ id: "hono",
166
+ title: "Hono",
167
+ description: "permdock/hono middleware and route guards."
168
+ },
169
+ {
170
+ id: "express",
171
+ title: "Express",
172
+ description: "permdock/express middleware and route guards."
173
+ },
174
+ {
175
+ id: "none",
176
+ title: "No HTTP framework",
177
+ description: "A per-request instance from core getPermDock."
178
+ }
179
+ ];
180
+ /**
181
+ * Agent runtimes and UI recipes. The preset code keeps one bitset per
182
+ * `kind`, each in this list's order, so a new entry goes after the last
183
+ * one of its kind.
184
+ */
185
+ const INTEGRATIONS = [
186
+ {
187
+ id: "ai-sdk",
188
+ kind: "agent",
189
+ title: "Vercel AI SDK",
190
+ description: "toolApproval and needsApproval for AI SDK tools.",
191
+ requires: ["operations"]
192
+ },
193
+ {
194
+ id: "mcp",
195
+ kind: "agent",
196
+ title: "MCP server",
197
+ description: "protectServer for an MCP server's tools.",
198
+ requires: ["operations"]
199
+ },
200
+ {
201
+ id: "shadcn",
202
+ kind: "ui",
203
+ title: "shadcn/ui",
204
+ description: "@permdock recipes built from your shadcn components."
205
+ },
206
+ {
207
+ id: "react-native",
208
+ kind: "ui",
209
+ title: "React Native Reusables",
210
+ description: "@permdock/*-native recipes built from React Native Reusables."
211
+ }
212
+ ];
213
+ const SERVICES = [
214
+ {
215
+ id: "cloud-decision-log",
216
+ title: "Cloud decision log",
217
+ description: "PermDock Cloud as the DecisionSink, with evidence exports."
218
+ },
219
+ {
220
+ id: "cloud-approvals",
221
+ title: "Cloud approvals inbox",
222
+ description: "PermDock Cloud as the ApprovalStore, with Slack and Teams delivery."
223
+ },
224
+ {
225
+ id: "cloud-snapshots",
226
+ title: "Cloud snapshots",
227
+ description: "Signed snapshots served by PermDock Cloud, through permdockCloud.snapshotsFor()."
228
+ },
229
+ {
230
+ id: "cloud-hosted-grants",
231
+ title: "Cloud hosted grants",
232
+ description: "Grants a Cloud admin adds to hostable permissions."
233
+ }
234
+ ];
235
+ /** The choices a preset starts from, in `/create` and in `permdock init`. */
236
+ const PRESET_DEFAULTS = Object.freeze({
237
+ archetype: "b2b",
238
+ features: [],
239
+ auth: "custom",
240
+ backend: "memory",
241
+ framework: "next",
242
+ integrations: [],
243
+ services: []
244
+ });
245
+ /** The integrations of one `kind` in `preset`, in catalogue order. */
246
+ function integrationsOf(preset, kind) {
247
+ return INTEGRATIONS.filter((item) => item.kind === kind && preset.integrations.includes(item.id)).map((item) => item.id);
248
+ }
249
+ function requiredBy(choices, picked) {
250
+ return choices.filter((choice) => picked.includes(choice.id)).flatMap((choice) => choice.requires ?? []);
251
+ }
252
+ /**
253
+ * The preset `input` describes, with every feature its archetype,
254
+ * integrations and other features require turned on, and lists in
255
+ * catalogue order. Features are only ever added, so resolving twice is a
256
+ * no-op.
257
+ */
258
+ function resolvePreset(input) {
259
+ const integrations = INTEGRATIONS.map((item) => item.id).filter((id) => (input.integrations ?? PRESET_DEFAULTS.integrations).includes(id));
260
+ const features = /* @__PURE__ */ new Set([
261
+ ...input.features ?? PRESET_DEFAULTS.features,
262
+ ...requiredBy(ARCHETYPES, [input.archetype]),
263
+ ...requiredBy(INTEGRATIONS, integrations)
264
+ ]);
265
+ for (let added = true; added;) {
266
+ added = false;
267
+ for (const feature of requiredBy(FEATURES, [...features])) if (!features.has(feature)) {
268
+ features.add(feature);
269
+ added = true;
270
+ }
271
+ }
272
+ return Object.freeze({
273
+ archetype: input.archetype,
274
+ features: FEATURES.map((feature) => feature.id).filter((id) => features.has(id)),
275
+ auth: input.auth ?? PRESET_DEFAULTS.auth,
276
+ backend: input.backend ?? PRESET_DEFAULTS.backend,
277
+ framework: input.framework ?? PRESET_DEFAULTS.framework,
278
+ integrations,
279
+ services: SERVICES.map((service) => service.id).filter((id) => (input.services ?? PRESET_DEFAULTS.services).includes(id))
280
+ });
281
+ }
282
+ //#endregion
283
+ //#region src/preset/codec.ts
284
+ /**
285
+ * Preset codes: `p1` followed by base64url bytes. Version 1 packs, in
286
+ * order, one byte each for the archetype, auth, backend and framework
287
+ * index, then a bitset per multi-select list (features, agent
288
+ * integrations, UI integrations, services), each as many bytes as the list
289
+ * needs. A list only grows at the end, so a code keeps its meaning as the
290
+ * catalogue grows; a new layout gets a new version prefix.
291
+ */
292
+ const VERSION = "p1";
293
+ const AGENT_INTEGRATIONS = INTEGRATIONS.filter((item) => item.kind === "agent");
294
+ const UI_INTEGRATIONS = INTEGRATIONS.filter((item) => item.kind === "ui");
295
+ const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
296
+ function toBase64Url(bytes) {
297
+ let out = "";
298
+ for (let index = 0; index < bytes.length; index += 3) {
299
+ const a = bytes[index] ?? 0;
300
+ const b = bytes[index + 1] ?? 0;
301
+ const c = bytes[index + 2] ?? 0;
302
+ const chunk = a << 16 | b << 8 | c;
303
+ const chars = index + 1 >= bytes.length ? 2 : index + 2 >= bytes.length ? 3 : 4;
304
+ for (let char = 0; char < chars; char += 1) out += ALPHABET[chunk >> 18 - 6 * char & 63];
305
+ }
306
+ return out;
307
+ }
308
+ function fromBase64Url(text) {
309
+ const bytes = [];
310
+ for (let index = 0; index < text.length; index += 4) {
311
+ const group = text.slice(index, index + 4);
312
+ if (group.length === 1) return;
313
+ let chunk = 0;
314
+ for (let char = 0; char < 4; char += 1) {
315
+ const symbol = group[char];
316
+ const value = symbol === void 0 ? 0 : ALPHABET.indexOf(symbol);
317
+ if (value < 0) return;
318
+ chunk |= value << 18 - 6 * char;
319
+ }
320
+ bytes.push(chunk >> 16 & 255);
321
+ if (group.length > 2) bytes.push(chunk >> 8 & 255);
322
+ if (group.length > 3) bytes.push(chunk & 255);
323
+ }
324
+ return bytes;
325
+ }
326
+ function bitset(list, picked) {
327
+ const bytes = Array.from({ length: Math.ceil(list.length / 8) }, () => 0);
328
+ for (const [index, item] of list.entries()) if (picked.includes(item.id)) bytes[index >> 3] = (bytes[index >> 3] ?? 0) | 1 << (index & 7);
329
+ return bytes;
330
+ }
331
+ function readBitset(list, bytes) {
332
+ return list.filter((_, index) => (bytes[index >> 3] ?? 0) >> (index & 7) & 1).map((item) => item.id);
333
+ }
334
+ function indexOf(list, id) {
335
+ return Math.max(0, list.findIndex((item) => item.id === id));
336
+ }
337
+ /** The preset code for `preset`, such as `p1AQIDBAc`. */
338
+ function encodePreset(preset) {
339
+ const index = indexOf;
340
+ return VERSION + toBase64Url([
341
+ index(ARCHETYPES, preset.archetype),
342
+ index(AUTH, preset.auth),
343
+ index(BACKENDS, preset.backend),
344
+ index(FRAMEWORKS, preset.framework),
345
+ ...bitset(FEATURES, preset.features),
346
+ ...bitset(AGENT_INTEGRATIONS, preset.integrations),
347
+ ...bitset(UI_INTEGRATIONS, preset.integrations),
348
+ ...bitset(SERVICES, preset.services)
349
+ ]);
350
+ }
351
+ /**
352
+ * The preset a code stands for, resolved, or `undefined` for a code that
353
+ * is not a version this package reads or does not decode.
354
+ */
355
+ function decodePreset(code) {
356
+ if (!code.startsWith(VERSION)) return;
357
+ const bytes = fromBase64Url(code.slice(2));
358
+ if (bytes === void 0) return;
359
+ const pick = (list, at) => list[bytes[at] ?? 0]?.id;
360
+ const archetype = pick(ARCHETYPES, 0);
361
+ const auth = pick(AUTH, 1);
362
+ const backend = pick(BACKENDS, 2);
363
+ const framework = pick(FRAMEWORKS, 3);
364
+ if (archetype === void 0 || auth === void 0 || backend === void 0 || framework === void 0) return;
365
+ let at = 4;
366
+ const take = (size) => {
367
+ const slice = bytes.slice(at, at + size);
368
+ at += size;
369
+ return slice;
370
+ };
371
+ const features = readBitset(FEATURES, take(Math.ceil(FEATURES.length / 8)));
372
+ const agents = readBitset(AGENT_INTEGRATIONS, take(Math.ceil(AGENT_INTEGRATIONS.length / 8)));
373
+ const ui = readBitset(UI_INTEGRATIONS, take(Math.ceil(UI_INTEGRATIONS.length / 8)));
374
+ const services = readBitset(SERVICES, take(Math.ceil(SERVICES.length / 8)));
375
+ return resolvePreset({
376
+ archetype,
377
+ auth,
378
+ backend,
379
+ framework,
380
+ features,
381
+ integrations: [...agents, ...ui],
382
+ services
383
+ });
384
+ }
385
+ //#endregion
386
+ //#region src/preset/flags.ts
387
+ /** One `permdock init` flag per preset key, with the catalogue it takes values from. */
388
+ const PRESET_FLAGS = {
389
+ archetype: {
390
+ flag: "archetype",
391
+ choices: ARCHETYPES,
392
+ repeatable: false
393
+ },
394
+ features: {
395
+ flag: "feature",
396
+ choices: FEATURES,
397
+ repeatable: true
398
+ },
399
+ auth: {
400
+ flag: "auth",
401
+ choices: AUTH,
402
+ repeatable: false
403
+ },
404
+ backend: {
405
+ flag: "backend",
406
+ choices: BACKENDS,
407
+ repeatable: false
408
+ },
409
+ framework: {
410
+ flag: "framework",
411
+ choices: FRAMEWORKS,
412
+ repeatable: false
413
+ },
414
+ integrations: {
415
+ flag: "integration",
416
+ choices: INTEGRATIONS,
417
+ repeatable: true
418
+ },
419
+ services: {
420
+ flag: "service",
421
+ choices: SERVICES,
422
+ repeatable: true
423
+ }
424
+ };
425
+ /**
426
+ * The `permdock init` flags that select `preset`, leaving out defaults and
427
+ * the features its archetype and integrations already turn on, so
428
+ * `permdock init <flags>` resolves to the same preset.
429
+ */
430
+ function presetFlags(preset) {
431
+ const implied = resolvePreset({
432
+ archetype: preset.archetype,
433
+ integrations: preset.integrations
434
+ }).features;
435
+ const args = [];
436
+ const single = (key) => {
437
+ if (key === "archetype" || preset[key] !== PRESET_DEFAULTS[key]) args.push(`--${PRESET_FLAGS[key].flag}`, preset[key]);
438
+ };
439
+ const many = (key) => {
440
+ const values = key === "features" ? preset.features.filter((feature) => !implied.includes(feature)) : preset[key];
441
+ for (const value of values) args.push(`--${PRESET_FLAGS[key].flag}`, value);
442
+ };
443
+ single("archetype");
444
+ single("framework");
445
+ single("auth");
446
+ single("backend");
447
+ many("features");
448
+ many("integrations");
449
+ many("services");
450
+ return args;
451
+ }
452
+ //#endregion
453
+ //#region src/preset/domain.ts
454
+ function all(resource, actions) {
455
+ return actions.map((action) => ({
456
+ resource,
457
+ action
458
+ }));
459
+ }
460
+ const CRUD = [
461
+ "read",
462
+ "update",
463
+ "delete",
464
+ "create",
465
+ "list"
466
+ ];
467
+ const READ = ["read", "list"];
468
+ const DOMAINS = {
469
+ b2b: {
470
+ resources: [{
471
+ name: "project",
472
+ fields: {
473
+ name: "z.string()",
474
+ ownerId: "z.string()"
475
+ },
476
+ preset: "crud",
477
+ actions: ["archive"],
478
+ owner: "ownerId"
479
+ }, {
480
+ name: "invoice",
481
+ fields: {
482
+ amount: "z.number()",
483
+ ownerId: "z.string()"
484
+ },
485
+ preset: "readable",
486
+ actions: ["pay"],
487
+ collection: ["create"],
488
+ owner: "ownerId",
489
+ sensitive: ["pay"]
490
+ }],
491
+ roles: [
492
+ {
493
+ name: "owner",
494
+ top: true,
495
+ grants: [...all("project", [...CRUD, "archive"]), ...all("invoice", [
496
+ ...READ,
497
+ "create",
498
+ "pay"
499
+ ])],
500
+ assigns: [
501
+ "owner",
502
+ "admin",
503
+ "member",
504
+ "viewer"
505
+ ]
506
+ },
507
+ {
508
+ name: "admin",
509
+ grants: [...all("project", [...CRUD, "archive"]), ...all("invoice", [
510
+ ...READ,
511
+ "create",
512
+ "pay"
513
+ ])],
514
+ assigns: ["member", "viewer"]
515
+ },
516
+ {
517
+ name: "member",
518
+ grants: [
519
+ ...all("project", [
520
+ "read",
521
+ "list",
522
+ "create"
523
+ ]),
524
+ {
525
+ resource: "project",
526
+ action: "update",
527
+ own: true
528
+ },
529
+ {
530
+ resource: "project",
531
+ action: "delete",
532
+ own: true
533
+ },
534
+ ...all("invoice", READ)
535
+ ]
536
+ },
537
+ {
538
+ name: "viewer",
539
+ grants: [...all("project", READ), ...all("invoice", READ)]
540
+ }
541
+ ],
542
+ demoRole: "member",
543
+ pro: {
544
+ resource: "project",
545
+ action: "archive"
546
+ }
547
+ },
548
+ agent: {
549
+ resources: [{
550
+ name: "document",
551
+ fields: {
552
+ title: "z.string()",
553
+ ownerId: "z.string()"
554
+ },
555
+ preset: "crud",
556
+ owner: "ownerId"
557
+ }, {
558
+ name: "email",
559
+ fields: { to: "z.string()" },
560
+ preset: "readable",
561
+ collection: ["send"],
562
+ sensitive: ["send"]
563
+ }],
564
+ roles: [{
565
+ name: "member",
566
+ grants: [
567
+ ...all("document", [
568
+ "read",
569
+ "list",
570
+ "create"
571
+ ]),
572
+ {
573
+ resource: "document",
574
+ action: "update",
575
+ own: true
576
+ },
577
+ {
578
+ resource: "document",
579
+ action: "delete",
580
+ own: true
581
+ },
582
+ ...all("email", [...READ, "send"])
583
+ ]
584
+ }, {
585
+ name: "admin",
586
+ top: true,
587
+ grants: [...all("document", CRUD), ...all("email", [...READ, "send"])],
588
+ assigns: ["admin", "member"]
589
+ }],
590
+ demoRole: "member",
591
+ pro: {
592
+ resource: "email",
593
+ action: "send"
594
+ }
595
+ },
596
+ marketplace: {
597
+ resources: [{
598
+ name: "listing",
599
+ fields: {
600
+ title: "z.string()",
601
+ sellerId: "z.string()"
602
+ },
603
+ preset: "crud",
604
+ actions: ["publish"],
605
+ owner: "sellerId"
606
+ }, {
607
+ name: "order",
608
+ fields: {
609
+ listingId: "z.string()",
610
+ buyerId: "z.string()"
611
+ },
612
+ preset: "readable",
613
+ actions: ["refund"],
614
+ collection: ["create"],
615
+ owner: "buyerId",
616
+ sensitive: ["refund"]
617
+ }],
618
+ roles: [
619
+ {
620
+ name: "buyer",
621
+ grants: [
622
+ ...all("listing", READ),
623
+ {
624
+ resource: "order",
625
+ action: "create"
626
+ },
627
+ {
628
+ resource: "order",
629
+ action: "list"
630
+ },
631
+ {
632
+ resource: "order",
633
+ action: "read",
634
+ own: true
635
+ }
636
+ ]
637
+ },
638
+ {
639
+ name: "seller",
640
+ grants: [
641
+ ...all("listing", [
642
+ "read",
643
+ "list",
644
+ "create"
645
+ ]),
646
+ {
647
+ resource: "listing",
648
+ action: "update",
649
+ own: true
650
+ },
651
+ {
652
+ resource: "listing",
653
+ action: "delete",
654
+ own: true
655
+ },
656
+ {
657
+ resource: "listing",
658
+ action: "publish",
659
+ own: true
660
+ },
661
+ ...all("order", READ),
662
+ {
663
+ resource: "order",
664
+ action: "refund"
665
+ }
666
+ ]
667
+ },
668
+ {
669
+ name: "admin",
670
+ top: true,
671
+ grants: [...all("listing", [...CRUD, "publish"]), ...all("order", [
672
+ ...READ,
673
+ "create",
674
+ "refund"
675
+ ])],
676
+ assigns: [
677
+ "admin",
678
+ "seller",
679
+ "buyer"
680
+ ]
681
+ }
682
+ ],
683
+ demoRole: "seller",
684
+ pro: {
685
+ resource: "listing",
686
+ action: "publish"
687
+ }
688
+ },
689
+ api: {
690
+ resources: [{
691
+ name: "project",
692
+ fields: {
693
+ name: "z.string()",
694
+ ownerId: "z.string()"
695
+ },
696
+ preset: "crud",
697
+ owner: "ownerId"
698
+ }, {
699
+ name: "deployment",
700
+ fields: { projectId: "z.string()" },
701
+ preset: "readable",
702
+ actions: ["rollback"],
703
+ collection: ["create"],
704
+ sensitive: ["rollback"]
705
+ }],
706
+ roles: [
707
+ {
708
+ name: "owner",
709
+ top: true,
710
+ grants: [...all("project", CRUD), ...all("deployment", [
711
+ ...READ,
712
+ "create",
713
+ "rollback"
714
+ ])],
715
+ assigns: [
716
+ "owner",
717
+ "developer",
718
+ "viewer"
719
+ ]
720
+ },
721
+ {
722
+ name: "developer",
723
+ grants: [...all("project", [
724
+ "read",
725
+ "list",
726
+ "create",
727
+ "update"
728
+ ]), ...all("deployment", [
729
+ ...READ,
730
+ "create",
731
+ "rollback"
732
+ ])]
733
+ },
734
+ {
735
+ name: "viewer",
736
+ grants: [...all("project", READ), ...all("deployment", READ)]
737
+ }
738
+ ],
739
+ demoRole: "developer",
740
+ pro: {
741
+ resource: "deployment",
742
+ action: "rollback"
743
+ }
744
+ },
745
+ internal: {
746
+ resources: [{
747
+ name: "ticket",
748
+ fields: {
749
+ subject: "z.string()",
750
+ ownerId: "z.string()"
751
+ },
752
+ preset: "crud",
753
+ actions: ["assign", "close"],
754
+ owner: "ownerId"
755
+ }, {
756
+ name: "report",
757
+ fields: { title: "z.string()" },
758
+ preset: "readable"
759
+ }],
760
+ roles: [
761
+ {
762
+ name: "agent",
763
+ grants: [
764
+ ...all("ticket", [
765
+ "read",
766
+ "list",
767
+ "create"
768
+ ]),
769
+ {
770
+ resource: "ticket",
771
+ action: "update",
772
+ own: true
773
+ },
774
+ {
775
+ resource: "ticket",
776
+ action: "close",
777
+ own: true
778
+ }
779
+ ]
780
+ },
781
+ {
782
+ name: "lead",
783
+ grants: [...all("ticket", [
784
+ ...CRUD,
785
+ "assign",
786
+ "close"
787
+ ]), ...all("report", READ)]
788
+ },
789
+ {
790
+ name: "admin",
791
+ top: true,
792
+ grants: [...all("ticket", [
793
+ ...CRUD,
794
+ "assign",
795
+ "close"
796
+ ]), ...all("report", READ)],
797
+ assigns: [
798
+ "admin",
799
+ "lead",
800
+ "agent"
801
+ ]
802
+ }
803
+ ],
804
+ demoRole: "agent",
805
+ pro: {
806
+ resource: "report",
807
+ action: "read"
808
+ }
809
+ },
810
+ consumer: {
811
+ resources: [{
812
+ name: "note",
813
+ fields: {
814
+ body: "z.string()",
815
+ ownerId: "z.string()"
816
+ },
817
+ preset: "crud",
818
+ actions: ["export"],
819
+ owner: "ownerId"
820
+ }],
821
+ roles: [{
822
+ name: "user",
823
+ grants: [
824
+ {
825
+ resource: "note",
826
+ action: "create"
827
+ },
828
+ {
829
+ resource: "note",
830
+ action: "list"
831
+ },
832
+ {
833
+ resource: "note",
834
+ action: "read",
835
+ own: true
836
+ },
837
+ {
838
+ resource: "note",
839
+ action: "update",
840
+ own: true
841
+ },
842
+ {
843
+ resource: "note",
844
+ action: "delete",
845
+ own: true
846
+ }
847
+ ]
848
+ }, {
849
+ name: "admin",
850
+ top: true,
851
+ grants: all("note", [...CRUD, "export"]),
852
+ assigns: ["admin", "user"]
853
+ }],
854
+ demoRole: "user",
855
+ pro: {
856
+ resource: "note",
857
+ action: "export"
858
+ }
859
+ }
860
+ };
861
+ //#endregion
862
+ //#region src/preset/generate-shared.ts
863
+ function pascal(name) {
864
+ return name.charAt(0).toUpperCase() + name.slice(1);
865
+ }
866
+ function quote(value) {
867
+ return JSON.stringify(value);
868
+ }
869
+ /**
870
+ * An environment read in the generated code. Built from parts so this
871
+ * runtime chunk carries no `process.` token, which the WinterTC check reads
872
+ * as a Node global; the generated file has it whole.
873
+ */
874
+ function env(name) {
875
+ return ["process", `env[${quote(name)}]`].join(".");
876
+ }
877
+ function ownedFile(path, contents) {
878
+ return {
879
+ path,
880
+ contents,
881
+ kind: "owned"
882
+ };
883
+ }
884
+ function fieldsOf(ctx, resource) {
885
+ const fields = [["id", "z.string()"], ...Object.entries(resource.fields)];
886
+ if (ctx.has("tenancy")) fields.push(["orgId", "z.string()"]);
887
+ return fields;
888
+ }
889
+ function firstInstance(ctx) {
890
+ const [resource] = ctx.domain.resources;
891
+ if (resource === void 0) throw new Error("PermDock: a preset domain declares at least one resource");
892
+ return {
893
+ resource,
894
+ action: "update"
895
+ };
896
+ }
897
+ //#endregion
898
+ //#region src/preset/generate-auth.ts
899
+ function sessionCall(ctx) {
900
+ return {
901
+ name: ctx.preset.auth === "custom" ? "currentUser" : "currentSubject",
902
+ takesRequest: ctx.preset.framework !== "next"
903
+ };
904
+ }
905
+ function headersOf(ctx) {
906
+ return sessionCall(ctx).takesRequest ? {
907
+ imports: [],
908
+ param: "request: Request",
909
+ read: "request.headers"
910
+ } : {
911
+ imports: [`import { headers } from "next/headers";`],
912
+ param: "",
913
+ read: "(await headers())"
914
+ };
915
+ }
916
+ const BEARER = `const authorization = requestHeaders.get("authorization") ?? "";
917
+ const token = authorization.startsWith("Bearer ")
918
+ ? authorization.slice("Bearer ".length)
919
+ : undefined;`;
920
+ function moduleText(imports, body) {
921
+ return `${imports.join("\n")}\n\n${body}`;
922
+ }
923
+ function customSession(ctx) {
924
+ return `import type { User } from "./policy";
925
+
926
+ /**
927
+ * The signed-in user, read from your session.
928
+ * It returns null until you wire it, so every check fails closed.
929
+ */
930
+ export async function currentUser(${sessionCall(ctx).takesRequest ? "_request: Request" : ""}): Promise<User | null> {
931
+ return null;
932
+ }
933
+ `;
934
+ }
935
+ function supabaseSession(ctx) {
936
+ const h = headersOf(ctx);
937
+ const browser = sessionCall(ctx).takesRequest ? "" : "\n * A browser session keeps the token in cookies: read it there with\n * createServerClient from @supabase/ssr.";
938
+ return moduleText([
939
+ `import { createClient } from "@supabase/supabase-js";`,
940
+ ...h.imports,
941
+ `import { subjectFromSupabase } from "permdock/supabase";`
942
+ ], `/**
943
+ * The subject the Supabase access token in the Authorization header proves;
944
+ * anonymous without a valid one.${browser}
945
+ */
946
+ export async function currentSubject(${h.param}) {
947
+ const requestHeaders = ${h.read};
948
+ ${BEARER}
949
+ if (token === undefined) {
950
+ return subjectFromSupabase(null);
951
+ }
952
+ const supabase = createClient(
953
+ ${env("SUPABASE_URL")} ?? "",
954
+ ${env("SUPABASE_PUBLISHABLE_KEY")} ?? "",
955
+ );
956
+ const { data, error } = await supabase.auth.getClaims(token);
957
+ return subjectFromSupabase(error ? null : (data?.claims ?? null));
958
+ }
959
+ `);
960
+ }
961
+ function betterAuthSession(ctx) {
962
+ const h = headersOf(ctx);
963
+ return moduleText([
964
+ ...h.imports,
965
+ `import { subjectFromBetterAuth } from "permdock/better-auth";`,
966
+ "",
967
+ `import { auth } from "./auth";`
968
+ ], `/** The subject of the Better Auth session on the request; anonymous without one. */
969
+ export async function currentSubject(${h.param}) {
970
+ const session = await auth.api.getSession({ headers: ${h.read} });
971
+ return subjectFromBetterAuth(session, { auth });
972
+ }
973
+ `);
974
+ }
975
+ function betterAuthFile() {
976
+ return `import { betterAuth } from "better-auth";
977
+ import { organization } from "better-auth/plugins";
978
+
979
+ /**
980
+ * Your Better Auth instance: add the database adapter and sign-in methods here.
981
+ * subjectFromBetterAuth reads roles through the organization plugin.
982
+ */
983
+ export const auth = betterAuth({
984
+ plugins: [organization()],
985
+ });
986
+ `;
987
+ }
988
+ function clerkSession(ctx) {
989
+ if (!sessionCall(ctx).takesRequest) return `import { auth } from "@clerk/nextjs/server";
990
+ import { subjectFromClerk } from "permdock/clerk";
991
+
992
+ /** The subject of the Clerk session; anonymous when signed out. */
993
+ export async function currentSubject() {
994
+ return subjectFromClerk(await auth());
995
+ }
996
+ `;
997
+ return `import { createClerkClient } from "@clerk/backend";
998
+ import { subjectFromClerk } from "permdock/clerk";
999
+
1000
+ const clerk = createClerkClient({
1001
+ secretKey: ${env("CLERK_SECRET_KEY")} ?? "",
1002
+ publishableKey: ${env("CLERK_PUBLISHABLE_KEY")} ?? "",
1003
+ });
1004
+
1005
+ /** The subject of the Clerk session on the request; anonymous when signed out. */
1006
+ export async function currentSubject(request: Request) {
1007
+ const state = await clerk.authenticateRequest(request);
1008
+ return subjectFromClerk(state.toAuth());
1009
+ }
1010
+ `;
1011
+ }
1012
+ function jwtSession(ctx) {
1013
+ const h = headersOf(ctx);
1014
+ const request = sessionCall(ctx).takesRequest ? ", request" : "";
1015
+ return moduleText([...h.imports, `import { jwtSubjectResolver } from "permdock/jwt";`], `let resolve: ReturnType<typeof jwtSubjectResolver> | undefined;
1016
+
1017
+ /** One resolver for the process, so Discovery and the JWKS are fetched once. */
1018
+ function resolver() {
1019
+ resolve ??= jwtSubjectResolver({
1020
+ discovery: ${env("OIDC_ISSUER")} ?? "",
1021
+ audience: ${env("OIDC_AUDIENCE")} ?? "",
1022
+ });
1023
+ return resolve;
1024
+ }
1025
+
1026
+ /** The subject the bearer token proves; anonymous without a valid one. */
1027
+ export async function currentSubject(${h.param}) {
1028
+ const requestHeaders = ${h.read};
1029
+ ${BEARER}
1030
+ return resolver()(token${request});
1031
+ }
1032
+ `);
1033
+ }
1034
+ /** `session.ts`, plus `auth.ts` for Better Auth. */
1035
+ function sessionFiles(ctx) {
1036
+ const at = (name) => `${ctx.src}/${name}`;
1037
+ switch (ctx.preset.auth) {
1038
+ case "custom": return [ownedFile(at("session.ts"), customSession(ctx))];
1039
+ case "supabase": return [ownedFile(at("session.ts"), supabaseSession(ctx))];
1040
+ case "better-auth": return [ownedFile(at("auth.ts"), betterAuthFile()), ownedFile(at("session.ts"), betterAuthSession(ctx))];
1041
+ case "clerk": return [ownedFile(at("session.ts"), clerkSession(ctx))];
1042
+ case "jwt": return [ownedFile(at("session.ts"), jwtSession(ctx))];
1043
+ default: return ctx.preset.auth;
1044
+ }
1045
+ }
1046
+ function authDependencies(ctx) {
1047
+ switch (ctx.preset.auth) {
1048
+ case "custom": return [];
1049
+ case "supabase": return ["@supabase/supabase-js"];
1050
+ case "better-auth": return ["better-auth"];
1051
+ case "clerk": return [sessionCall(ctx).takesRequest ? "@clerk/backend" : "@clerk/nextjs"];
1052
+ case "jwt": return ["jose"];
1053
+ default: return ctx.preset.auth;
1054
+ }
1055
+ }
1056
+ function authDocs(ctx) {
1057
+ return ctx.preset.auth === "custom" ? ["/docs/concepts/authentication"] : [`/docs/adapters/${ctx.preset.auth}`];
1058
+ }
1059
+ //#endregion
1060
+ //#region src/preset/generate-backend.ts
1061
+ function memoryData(ctx) {
1062
+ const tenancy = ctx.has("tenancy");
1063
+ const blocks = ctx.domain.resources.map((resource) => {
1064
+ const type = pascal(resource.name);
1065
+ const row = fieldsOf(ctx, resource).map(([name, kind]) => {
1066
+ if (name === "id") return `id: "${resource.name}_1"`;
1067
+ if (name === "orgId") return `orgId: "o1"`;
1068
+ if (name === resource.owner) return `${name}: "u1"`;
1069
+ return kind.startsWith("z.number") ? `${name}: 1` : `${name}: ""`;
1070
+ }).join(", ");
1071
+ return `const ${resource.name}Rows = new Map<string, ${type}>([
1072
+ ["${resource.name}_1", { ${row} }],
1073
+ ]);
1074
+
1075
+ /** Replace with your database read. */
1076
+ export function find${type}(id: string): ${type} | null {
1077
+ return ${resource.name}Rows.get(id) ?? null;
1078
+ }`;
1079
+ });
1080
+ return `import type { ${ctx.domain.resources.map((resource) => pascal(resource.name)).join(", ")} } from "./permissions";
1081
+
1082
+ ${tenancy ? "// Demo rows in organisation o1, owned by the demo user u1.\n" : "// Demo rows owned by the demo user u1.\n"}${blocks.join("\n\n")}
1083
+ `;
1084
+ }
1085
+ function isNumber(kind) {
1086
+ return kind.startsWith("z.number");
1087
+ }
1088
+ function drizzleSchema(ctx) {
1089
+ const numbers = ctx.domain.resources.some((resource) => fieldsOf(ctx, resource).some(([, kind]) => isNumber(kind)));
1090
+ const tables = ctx.domain.resources.map((resource) => {
1091
+ const columns = fieldsOf(ctx, resource).map(([name, kind]) => {
1092
+ return ` ${name}: ${isNumber(kind) ? `doublePrecision("${name}")` : `text("${name}")`}${name === "id" ? ".primaryKey()" : ".notNull()"},`;
1093
+ });
1094
+ return `export const ${resource.name} = pgTable("${resource.name}", {\n${columns.join("\n")}\n});`;
1095
+ });
1096
+ return `import { ${[
1097
+ ...numbers ? ["doublePrecision"] : [],
1098
+ "pgTable",
1099
+ "text"
1100
+ ].join(", ")} } from "drizzle-orm/pg-core";
1101
+
1102
+ // One table per resource, named after it, as permdock rls generate --target drizzle expects.
1103
+ ${tables.join("\n\n")}
1104
+ `;
1105
+ }
1106
+ function drizzleDb() {
1107
+ return `import { drizzle } from "drizzle-orm/node-postgres";
1108
+
1109
+ export const db = drizzle(${env("DATABASE_URL")} ?? "");
1110
+ `;
1111
+ }
1112
+ function drizzleData(ctx) {
1113
+ const blocks = ctx.domain.resources.map((resource) => {
1114
+ const type = pascal(resource.name);
1115
+ return `/** One ${resource.name} by id, or null. */
1116
+ export async function find${type}(id: string): Promise<${type} | null> {
1117
+ const [row] = await db.select().from(${resource.name}).where(eq(${resource.name}.id, id));
1118
+ return row ?? null;
1119
+ }
1120
+
1121
+ /** The ${resource.name}s \`permdock\` may list, filtered in the query. */
1122
+ export function list${type}s(permdock: PermDock) {
1123
+ return db
1124
+ .select()
1125
+ .from(${resource.name})
1126
+ .where(toWhere(permdock.where(permissions.${resource.name}.list), ${resource.name}));
1127
+ }`;
1128
+ });
1129
+ const names = ctx.domain.resources.map((resource) => resource.name);
1130
+ return `import type { PermDock } from "permdock";
1131
+
1132
+ import { eq } from "drizzle-orm";
1133
+ import { toWhere } from "permdock/drizzle";
1134
+
1135
+ import { db } from "./db";
1136
+ import { type ${names.map(pascal).join(", type ")}, permissions } from "./permissions";
1137
+ import { ${names.join(", ")} } from "./schema";
1138
+
1139
+ ${blocks.join("\n\n")}
1140
+ `;
1141
+ }
1142
+ function prismaModel(ctx, resource) {
1143
+ const fields = fieldsOf(ctx, resource).map(([name, kind]) => ` ${name} ${isNumber(kind) ? "Float" : "String"}${name === "id" ? " @id" : ""}`);
1144
+ return `model ${pascal(resource.name)} {\n${fields.join("\n")}\n\n @@map("${resource.name}")\n}`;
1145
+ }
1146
+ function prismaSchema(ctx) {
1147
+ return `generator client {
1148
+ provider = "prisma-client"
1149
+ output = "../${ctx.src}/generated"
1150
+ moduleFormat = "esm"
1151
+ }
1152
+
1153
+ datasource db {
1154
+ provider = "postgresql"
1155
+ }
1156
+
1157
+ ${ctx.domain.resources.map((resource) => prismaModel(ctx, resource)).join("\n\n")}
1158
+ `;
1159
+ }
1160
+ function prismaConfig() {
1161
+ return `import { defineConfig, env } from "prisma/config";
1162
+
1163
+ export default defineConfig({
1164
+ schema: "prisma/schema.prisma",
1165
+ datasource: { url: env("DATABASE_URL") },
1166
+ });
1167
+ `;
1168
+ }
1169
+ function prismaDb() {
1170
+ return `import { PrismaPg } from "@prisma/adapter-pg";
1171
+
1172
+ import { PrismaClient } from "./generated/client";
1173
+
1174
+ // prisma generate writes ./generated from prisma/schema.prisma.
1175
+ export const prisma = new PrismaClient({
1176
+ adapter: new PrismaPg({ connectionString: ${env("DATABASE_URL")} ?? "" }),
1177
+ });
1178
+ `;
1179
+ }
1180
+ function prismaData(ctx) {
1181
+ const blocks = ctx.domain.resources.map((resource) => {
1182
+ const type = pascal(resource.name);
1183
+ return `/** One ${resource.name} by id, or null. */
1184
+ export async function find${type}(id: string): Promise<${type} | null> {
1185
+ return prisma.${resource.name}.findUnique({ where: { id } });
1186
+ }
1187
+
1188
+ /** The ${resource.name}s \`permdock\` may list, filtered in the query. */
1189
+ export function list${type}s(permdock: PermDock) {
1190
+ return prisma.${resource.name}.findMany({
1191
+ where: toWhere<Prisma.${type}WhereInput>(permdock.where(permissions.${resource.name}.list)),
1192
+ });
1193
+ }`;
1194
+ });
1195
+ return `import type { PermDock } from "permdock";
1196
+
1197
+ import { toWhere } from "permdock/prisma";
1198
+
1199
+ import type { Prisma } from "./generated/client";
1200
+
1201
+ import { prisma } from "./db";
1202
+ import { type ${ctx.domain.resources.map((resource) => pascal(resource.name)).join(", type ")}, permissions } from "./permissions";
1203
+
1204
+ ${blocks.join("\n\n")}
1205
+ `;
1206
+ }
1207
+ /** `data.ts` and the files the backend reads it through. */
1208
+ function backendFiles(ctx) {
1209
+ const at = (name) => `${ctx.src}/${name}`;
1210
+ switch (ctx.preset.backend) {
1211
+ case "memory":
1212
+ case "supabase": return [ownedFile(at("data.ts"), memoryData(ctx))];
1213
+ case "drizzle": return [
1214
+ ownedFile(at("schema.ts"), drizzleSchema(ctx)),
1215
+ ownedFile(at("db.ts"), drizzleDb()),
1216
+ ownedFile(at("data.ts"), drizzleData(ctx))
1217
+ ];
1218
+ case "prisma": return [
1219
+ ownedFile("prisma/schema.prisma", prismaSchema(ctx)),
1220
+ ownedFile("prisma.config.ts", prismaConfig()),
1221
+ ownedFile(at("db.ts"), prismaDb()),
1222
+ ownedFile(at("data.ts"), prismaData(ctx))
1223
+ ];
1224
+ default: return ctx.preset.backend;
1225
+ }
1226
+ }
1227
+ /** What `permdock.ts` adds for the backend: imports, statements before `defineApp`, and its options. */
1228
+ function backendApp(ctx) {
1229
+ if (ctx.preset.backend !== "supabase") return {
1230
+ imports: [],
1231
+ preamble: [],
1232
+ options: []
1233
+ };
1234
+ return {
1235
+ imports: [`import { createClient } from "@supabase/supabase-js";`, `import { postgrestSources } from "permdock/supabase";`],
1236
+ preamble: [
1237
+ `// Server-only: the secret key lets subject_for read any user's memberships.`,
1238
+ `const sources = postgrestSources(`,
1239
+ ` createClient(${env("SUPABASE_URL")} ?? "", ${env("SUPABASE_SECRET_KEY")} ?? ""),`,
1240
+ ` { policy },`,
1241
+ `);`
1242
+ ],
1243
+ options: [" memberships: sources.memberships,"]
1244
+ };
1245
+ }
1246
+ function backendDependencies(ctx) {
1247
+ switch (ctx.preset.backend) {
1248
+ case "memory": return [];
1249
+ case "supabase": return ["@supabase/supabase-js"];
1250
+ case "drizzle": return ["drizzle-orm", "pg"];
1251
+ case "prisma": return [
1252
+ "@prisma/client",
1253
+ "@prisma/adapter-pg",
1254
+ "prisma"
1255
+ ];
1256
+ default: return ctx.preset.backend;
1257
+ }
1258
+ }
1259
+ function backendDocs(ctx) {
1260
+ return ctx.preset.backend === "memory" ? [] : [`/docs/adapters/${ctx.preset.backend}`];
1261
+ }
1262
+ //#endregion
1263
+ //#region src/preset/generate.ts
1264
+ const LIMIT = "{ count: 100, per: 86_400 }";
1265
+ function permissionsFile(ctx) {
1266
+ const schemas = ctx.domain.resources.map((resource) => {
1267
+ const fields = fieldsOf(ctx, resource).map(([name, type]) => ` ${name}: ${type},`).join("\n");
1268
+ return `export const ${pascal(resource.name)} = z.object({\n${fields}\n});\nexport type ${pascal(resource.name)} = z.infer<typeof ${pascal(resource.name)}>;`;
1269
+ });
1270
+ const entries = ctx.domain.resources.map((resource) => {
1271
+ const extra = [...resource.actions === void 0 || resource.actions.length === 0 ? [] : [`actions: [${resource.actions.map(quote).join(", ")}]`], ...resource.collection === void 0 || resource.collection.length === 0 ? [] : [`collection: [${resource.collection.map(quote).join(", ")}]`]];
1272
+ const options = [
1273
+ `id: "id"`,
1274
+ ...ctx.has("tenancy") ? [`relations: { org: { field: "orgId", memberOf: "tenant" } }`] : [],
1275
+ ...extra
1276
+ ].join(", ");
1277
+ return ` ${resource.name}: resource(${pascal(resource.name)}, ${resource.preset}({ ${options} })),`;
1278
+ });
1279
+ return `import { definePermissions, ${[...new Set(ctx.domain.resources.map((resource) => resource.preset))].toSorted().join(", ")}, resource } from "permdock";
1280
+ import { z } from "zod";
1281
+
1282
+ ${schemas.join("\n\n")}
1283
+
1284
+ export const permissions = definePermissions({
1285
+ ${entries.join("\n")}
1286
+ });
1287
+ `;
1288
+ }
1289
+ /** What a role's grant becomes under the preset's features; the matrix and the code read the same answer. */
1290
+ function grantShape(preset, role, grant) {
1291
+ const has = (feature) => preset.features.includes(feature);
1292
+ const resource = DOMAINS[preset.archetype].resources.find((item) => item.name === grant.resource);
1293
+ const risky = grant.action === "delete" || (resource?.sensitive ?? []).includes(grant.action);
1294
+ return {
1295
+ owner: grant.own === true && has("ownership") ? resource?.owner : void 0,
1296
+ approval: has("approvals") && risky && role.top !== true,
1297
+ limit: has("limits") && role.name === DOMAINS[preset.archetype].demoRole && grant.action === "create"
1298
+ };
1299
+ }
1300
+ function grantLine(ctx, role, grant) {
1301
+ const shape = grantShape(ctx.preset, role, grant);
1302
+ const options = [];
1303
+ if (shape.owner !== void 0) options.push(`where: { ${shape.owner}: principal.id }`);
1304
+ if (shape.approval) options.push(`approval: "human"`);
1305
+ if (shape.limit) options.push(`limit: ${LIMIT}`);
1306
+ const target = `permissions.${grant.resource}.${grant.action}`;
1307
+ return options.length === 0 ? `allow(${target})` : `allow(${target}, { ${options.join(", ")} })`;
1308
+ }
1309
+ function isPro(ctx, grant) {
1310
+ const pro = ctx.domain.pro;
1311
+ return ctx.has("plans") && pro !== void 0 && grant.resource === pro.resource && grant.action === pro.action;
1312
+ }
1313
+ function policyFile(ctx) {
1314
+ const tenancy = ctx.has("tenancy");
1315
+ const roles = ctx.domain.roles.map((role) => {
1316
+ const grants = role.grants.filter((grant) => role.top === true || !isPro(ctx, grant)).map((grant) => ` ${grantLine(ctx, role, grant)},`).join("\n");
1317
+ const options = [];
1318
+ if (tenancy) {
1319
+ options.push(`on: "tenant"`);
1320
+ if (role.top === true) options.push("min: 1");
1321
+ if (role.assigns !== void 0) options.push(`assigns: [${role.assigns.map(quote).join(", ")}]`);
1322
+ }
1323
+ const tail = options.length === 0 ? "" : `, { ${options.join(", ")} }`;
1324
+ return ` role("${role.name}", [\n${grants}\n ]${tail}),`;
1325
+ });
1326
+ const pro = ctx.domain.pro;
1327
+ const proGrant = ctx.has("plans") && pro !== void 0 ? ` grants: [allow(permissions.${pro.resource}.${pro.action}, { to: plan("pro") })],\n` : "";
1328
+ const usesPrincipal = ctx.has("ownership") && ctx.domain.roles.some((role) => role.grants.some((grant) => grant.own));
1329
+ const imports = [
1330
+ "allow",
1331
+ "definePolicy",
1332
+ ...ctx.has("plans") ? ["plan"] : [],
1333
+ ...usesPrincipal ? ["principal"] : [],
1334
+ "role"
1335
+ ];
1336
+ const userFields = [
1337
+ " readonly id: string;",
1338
+ " readonly roles: readonly string[];",
1339
+ ...tenancy ? [" readonly orgId: string;"] : [],
1340
+ ...ctx.has("plans") ? [" readonly plans: readonly string[];"] : []
1341
+ ];
1342
+ const principalFields = [
1343
+ "id: user.id",
1344
+ ...tenancy ? ["tenant: user.orgId", `memberships: [{ scope: "tenant", id: user.orgId, roles: user.roles }]`] : ["roles: user.roles"],
1345
+ ...ctx.has("plans") ? ["plans: user.plans"] : []
1346
+ ];
1347
+ const demo = [
1348
+ `id: "u1"`,
1349
+ `roles: ["${ctx.domain.demoRole}"]`,
1350
+ ...tenancy ? [`orgId: "o1"`] : [],
1351
+ ...ctx.has("plans") ? [`plans: ["free"]`] : []
1352
+ ];
1353
+ return `import { ${imports.join(", ")} } from "permdock";
1354
+
1355
+ import { permissions } from "./permissions";
1356
+
1357
+ /** The signed-in user as your session or auth provider returns it. */
1358
+ export type User = {
1359
+ ${userFields.join("\n")}
1360
+ };
1361
+
1362
+ export const policy = definePolicy(permissions, {
1363
+ ${tenancy ? ` scopes: { tenant: { key: "orgId" } },\n` : ""} roles: [
1364
+ ${roles.join("\n")}
1365
+ ],
1366
+ ${proGrant} subject: (user: User | null) =>
1367
+ user === null ? null : { ${principalFields.join(", ")} },
1368
+ });
1369
+
1370
+ /** A user for tests and local runs. */
1371
+ export const demoUser: User = { ${demo.join(", ")} };
1372
+ `;
1373
+ }
1374
+ function appFile(ctx) {
1375
+ const valueImports = /* @__PURE__ */ new Set(["defineApp"]);
1376
+ const lines = [];
1377
+ const preamble = [];
1378
+ const services = ctx.preset.services;
1379
+ const cloudServices = services.length > 0;
1380
+ if (cloudServices) preamble.push(`import { cloud } from "permdock/cloud";`);
1381
+ if (services.includes("cloud-hosted-grants")) preamble.push(`import { cloudEndpoints } from "permdock/cloud";`, `import { joseTokenVerifier } from "permdock/jwt";`);
1382
+ if (ctx.has("decision-log")) {
1383
+ if (services.includes("cloud-decision-log")) lines.push(" sink: permdockCloud.sink,");
1384
+ else {
1385
+ valueImports.add("memoryDecisionSink");
1386
+ lines.push(" // A DecisionSink: memory for now; permdock/otel, PermDock Cloud or your own in production.", " sink: memoryDecisionSink(),");
1387
+ }
1388
+ }
1389
+ if (ctx.has("custom-roles")) {
1390
+ valueImports.add("memoryCustomRoleSource");
1391
+ lines.push(" // Custom roles from your database; postgrestSources() reads them on Supabase.", " customRoles: memoryCustomRoleSource([]),");
1392
+ }
1393
+ if (services.includes("cloud-approvals")) lines.push(" store: permdockCloud.approvals,");
1394
+ else if (ctx.has("approvals")) lines.push(" // profile dev uses a memory ApprovalStore; set a persistent one (Postgres, PermDock Cloud) for prod.");
1395
+ if (ctx.has("limits")) lines.push(" // profile dev uses a memory LimitStore; set limits(store) with a shared one (Redis, Postgres) for prod.");
1396
+ if (services.includes("cloud-hosted-grants")) {
1397
+ valueImports.add("hostedPolicies");
1398
+ lines.push(" policies: hostedPolicies(permdockCloud.policies),");
1399
+ }
1400
+ const cloudCall = services.includes("cloud-hosted-grants") ? `cloud({\n verifier: joseTokenVerifier({ jwks: cloudEndpoints().jwks }),\n})` : "cloud()";
1401
+ const snapshots = services.includes("cloud-snapshots") ? `\n/** A client's signed snapshot, served by PermDock Cloud for the caller's token. */\nexport const snapshotsFor = (token: string) => permdockCloud.snapshotsFor(token);\n` : "";
1402
+ const cloudLine = cloudServices ? `\n// PERMDOCK_CLOUD_URL and PERMDOCK_CLOUD_KEY come from the environment.\nexport const permdockCloud = ${cloudCall};\n${snapshots}` : "";
1403
+ const backend = backendApp(ctx);
1404
+ preamble.push(...backend.imports);
1405
+ lines.unshift(...backend.options);
1406
+ const sources = backend.preamble.length === 0 ? "" : `\n${backend.preamble.join("\n")}\n`;
1407
+ return `import { ${[...valueImports].toSorted().join(", ")} } from "permdock";
1408
+ ${preamble.length === 0 ? "" : `${preamble.join("\n")}\n`}
1409
+ import { policy } from "./policy";
1410
+ ${cloudLine}${sources}
1411
+ /**
1412
+ * The app definition every adapter reads. Your own code: change sources,
1413
+ * features and services here; the rules stay in the permdock package.
1414
+ */
1415
+ export const app = defineApp(policy, {
1416
+ profile: ${env("NODE_ENV")} === "production" ? "prod" : "dev",
1417
+ ${lines.join("\n")}${lines.length === 0 ? "" : "\n"}});
1418
+ `;
1419
+ }
1420
+ function frameworkFiles(ctx) {
1421
+ const { resource, action } = firstInstance(ctx);
1422
+ const type = pascal(resource.name);
1423
+ const owned = ownedFile;
1424
+ const { name: current } = sessionCall(ctx);
1425
+ switch (ctx.preset.framework) {
1426
+ case "next": return [owned(`${ctx.src}/permdock/server.ts`, `import { createPermDock } from "permdock/next";
1427
+
1428
+ import { app } from "../permdock";
1429
+ import { ${current} } from "../session";
1430
+
1431
+ // Server-only: Server Components, Server Actions and Route Handlers import
1432
+ // from here; client components import hooks from permdock/react.
1433
+ export const {
1434
+ getPermDock,
1435
+ getPermission,
1436
+ getSnapshot,
1437
+ requirePermission,
1438
+ permdockHandler,
1439
+ } = createPermDock(app, { subject: ${current} });
1440
+ `)];
1441
+ case "hono": return [owned(`${ctx.src}/server.ts`, `import { Hono } from "hono";
1442
+ import { createPermDock } from "permdock/hono";
1443
+
1444
+ import { find${type} } from "./data";
1445
+ import { app as permdockApp } from "./permdock";
1446
+ import { permissions } from "./permissions";
1447
+ import { ${current} } from "./session";
1448
+
1449
+ const { protect } = createPermDock(permdockApp, {
1450
+ subject: (c) => ${current}(c.req.raw),
1451
+ });
1452
+
1453
+ export const app = new Hono();
1454
+
1455
+ app.patch(
1456
+ "/${resource.name}s/:id",
1457
+ protect(permissions.${resource.name}.${action}, (c) => find${type}(c.req.param("id") ?? "")),
1458
+ (c) => c.json({ ok: true }),
1459
+ );
1460
+ `)];
1461
+ case "express": return [owned(`${ctx.src}/server.ts`, `import express from "express";
1462
+ import { createPermDock, toRequest } from "permdock/express";
1463
+
1464
+ import { find${type} } from "./data";
1465
+ import { app as permdockApp } from "./permdock";
1466
+ import { permissions } from "./permissions";
1467
+ import { ${current} } from "./session";
1468
+
1469
+ const { protect } = createPermDock(permdockApp, {
1470
+ subject: (req) => ${current}(toRequest(req)),
1471
+ });
1472
+
1473
+ export const app = express();
1474
+
1475
+ app.patch(
1476
+ "/${resource.name}s/:id",
1477
+ protect(permissions.${resource.name}.${action}, (req) => find${type}(String(req.params["id"]))),
1478
+ (_req, res) => {
1479
+ res.json({ ok: true });
1480
+ },
1481
+ );
1482
+ `)];
1483
+ case "none":
1484
+ if (current === "currentSubject") return [owned(`${ctx.src}/server.ts`, `import { getPermDock } from "permdock";
1485
+
1486
+ import { app } from "./permdock";
1487
+ import { currentSubject } from "./session";
1488
+
1489
+ /** The request-scoped decision object for the caller of \`request\`; create one per request. */
1490
+ export async function permdockFor(request: Request) {
1491
+ return getPermDock(app, await currentSubject(request));
1492
+ }
1493
+ `)];
1494
+ return [owned(`${ctx.src}/server.ts`, `import { getPermDockSync } from "permdock";
1495
+
1496
+ import { app } from "./permdock";
1497
+ import type { User } from "./policy";
1498
+
1499
+ /** The request-scoped decision object for \`user\`; create one per request. */
1500
+ export function permdockFor(user: User | null) {
1501
+ return getPermDockSync(app, user);
1502
+ }
1503
+ `)];
1504
+ default: return ctx.preset.framework;
1505
+ }
1506
+ }
1507
+ function operationsFile(ctx) {
1508
+ const entries = ctx.domain.resources.flatMap((resource) => {
1509
+ const type = pascal(resource.name);
1510
+ const ops = [` list_${resource.name}s: { permission: permissions.${resource.name}.list },`];
1511
+ if (resource.preset === "crud") ops.push(` delete_${resource.name}: {\n permission: permissions.${resource.name}.delete,\n data: (input: { readonly id: string }) => find${type}(input.id),\n },`);
1512
+ for (const action of resource.collection ?? []) ops.push(` ${action}_${resource.name}: { permission: permissions.${resource.name}.${action} },`);
1513
+ return ops;
1514
+ });
1515
+ const finds = ctx.domain.resources.filter((resource) => resource.preset === "crud").map((resource) => `find${pascal(resource.name)}`);
1516
+ return `import { defineOperations } from "permdock";
1517
+
1518
+ ${finds.length === 0 ? "" : `import { ${finds.join(", ")} } from "./data";\n`}import { permissions } from "./permissions";
1519
+
1520
+ /** The tools an agent may call, each bound to one permission. */
1521
+ export const operations = defineOperations(permissions, {
1522
+ ${entries.join("\n")}
1523
+ });
1524
+ `;
1525
+ }
1526
+ function agentFiles(ctx) {
1527
+ const files = [];
1528
+ if (!ctx.has("operations")) return files;
1529
+ files.push({
1530
+ path: `${ctx.src}/operations.ts`,
1531
+ contents: operationsFile(ctx),
1532
+ kind: "owned"
1533
+ });
1534
+ if (ctx.preset.integrations.includes("ai-sdk")) {
1535
+ const session = sessionCall(ctx);
1536
+ const subject = session.takesRequest ? `// Pass the incoming Request as the AI SDK runtimeContext.
1537
+ subject: ({ runtimeContext }) =>
1538
+ runtimeContext instanceof Request ? ${session.name}(runtimeContext) : null,` : `subject: () => ${session.name}(),`;
1539
+ files.push({
1540
+ path: `${ctx.src}/agent.ts`,
1541
+ contents: `import { createPermDock } from "permdock/ai-sdk";
1542
+
1543
+ import { operations } from "./operations";
1544
+ import { app } from "./permdock";
1545
+ import { ${session.name} } from "./session";
1546
+
1547
+ // Pass toolApproval to the AI SDK's tool approval hook, or needsApproval to each tool.
1548
+ export const { toolApproval, needsApproval, capabilityMiddleware } =
1549
+ createPermDock(app, {
1550
+ ${subject}
1551
+ actor: () => ({ id: "assistant", kind: "ai-sdk" }),
1552
+ operations,
1553
+ });
1554
+ `,
1555
+ kind: "owned"
1556
+ });
1557
+ }
1558
+ if (ctx.preset.integrations.includes("mcp")) files.push({
1559
+ path: `${ctx.src}/mcp.ts`,
1560
+ contents: `import { createPermDock } from "permdock/mcp";
1561
+
1562
+ import { app } from "./permdock";
1563
+ import type { User } from "./policy";
1564
+
1565
+ /** Map the verified MCP auth info to your user; null is anonymous. */
1566
+ function userFor(_authInfo: unknown): User | null {
1567
+ return null;
1568
+ }
1569
+
1570
+ // protectServer(new McpServer(...)) returns a server whose registerTool takes a permission.
1571
+ export const { protectServer } = createPermDock(app, {
1572
+ subject: (authInfo) => userFor(authInfo),
1573
+ });
1574
+ `,
1575
+ kind: "owned"
1576
+ });
1577
+ return files;
1578
+ }
1579
+ function keysFile(ctx) {
1580
+ if (!ctx.has("api-keys")) return [];
1581
+ const { resource } = firstInstance(ctx);
1582
+ return [{
1583
+ path: `${ctx.src}/keys.ts`,
1584
+ contents: `import { type PermDock, decideCredential } from "permdock";
1585
+
1586
+ import { permissions } from "./permissions";
1587
+
1588
+ /**
1589
+ * Decides whether the signed-in user may create a read-only key for
1590
+ * ${resource.name}s${ctx.has("tenancy") ? " in their organisation" : ""}. Store the granted credential's hash; show the
1591
+ * key once.
1592
+ */
1593
+ export function decideReadKey(permdock: PermDock, id: string) {
1594
+ return decideCredential(permdock, {
1595
+ kind: "service",
1596
+ id,
1597
+ principal: \`service:\${id}\`,
1598
+ tenant: permdock.subject.principal?.tenant ?? "",
1599
+ roles: ["${ctx.domain.demoRole}"],
1600
+ permissions: [permissions.${resource.name}.read, permissions.${resource.name}.list],
1601
+ name: "read-only key",
1602
+ });
1603
+ }
1604
+ `,
1605
+ kind: "owned"
1606
+ }];
1607
+ }
1608
+ function rlsOption(ctx) {
1609
+ if (!ctx.has("rls")) return null;
1610
+ const table = `{\n table: "org_members",\n tenant: "org_id",\n user: "user_id",\n role: "role",\n }`;
1611
+ return ctx.preset.backend === "supabase" ? `supabaseRls({${ctx.has("tenancy") ? `\n memberships: ${table},\n ` : ""}})` : `{\n dialect: "guc",${ctx.has("tenancy") ? `\n memberships: { tenant: ${table} },` : ""}\n }`;
1612
+ }
1613
+ function configFile(ctx) {
1614
+ const rls = rlsOption(ctx);
1615
+ const options = [
1616
+ ` permissions: "./${ctx.src}/permissions.ts",`,
1617
+ ` policy: "./${ctx.src}/policy.ts",`,
1618
+ ...ctx.has("operations") ? [` operations: "./${ctx.src}/operations.ts",`] : [],
1619
+ ...rls === null ? [] : [` rls: ${rls},`]
1620
+ ];
1621
+ return ownedFile("permdock.config.ts", `import { defineConfig } from "permdock/cli";
1622
+ ${rls !== null && ctx.preset.backend === "supabase" ? `import { supabaseRls } from "permdock/supabase";\n` : ""}
1623
+ // The files permdock doctor, check and rls generate read.
1624
+ export default defineConfig({
1625
+ ${options.join("\n")}
1626
+ });
1627
+ `);
1628
+ }
1629
+ /** The `@permdock` registry recipes for the preset's UI; native has the gate and the upgrade prompt. */
1630
+ function recipesFor(ctx) {
1631
+ const web = ["gated-button"];
1632
+ if (ctx.has("approvals")) web.push("approval-request-dialog");
1633
+ if (ctx.has("tenancy")) web.push("tenant-switcher", "role-picker");
1634
+ if (ctx.has("custom-roles")) web.push("custom-role-editor");
1635
+ if (ctx.has("plans")) web.push("upgrade-prompt");
1636
+ const native = ["gated-button", ...ctx.has("plans") ? ["upgrade-prompt"] : []];
1637
+ return [...ctx.preset.integrations.includes("shadcn") ? web.map((name) => `@permdock/${name}`) : [], ...ctx.preset.integrations.includes("react-native") ? native.map((name) => `@permdock/${name}-native`) : []];
1638
+ }
1639
+ function dependenciesFor(ctx) {
1640
+ const deps = ["permdock", "zod"];
1641
+ deps.push(...{
1642
+ next: [
1643
+ "next",
1644
+ "react",
1645
+ "react-dom"
1646
+ ],
1647
+ hono: ["hono"],
1648
+ express: ["express"],
1649
+ none: []
1650
+ }[ctx.preset.framework]);
1651
+ if (ctx.preset.integrations.includes("ai-sdk")) deps.push("ai");
1652
+ if (ctx.preset.integrations.includes("mcp")) deps.push("@modelcontextprotocol/server");
1653
+ deps.push(...authDependencies(ctx), ...backendDependencies(ctx));
1654
+ if (ctx.preset.services.includes("cloud-hosted-grants")) deps.push("jose");
1655
+ return [...new Set(deps)];
1656
+ }
1657
+ function docsFor(ctx) {
1658
+ const docs = ["/docs/concepts/apps", "/docs/concepts/policies"];
1659
+ const byFeature = {
1660
+ tenancy: "/docs/concepts/tenancy",
1661
+ "custom-roles": "/docs/concepts/custom-roles",
1662
+ approvals: "/docs/adapters/approvals",
1663
+ operations: "/docs/concepts/operations",
1664
+ "decision-log": "/docs/concepts/audit-and-observability",
1665
+ "api-keys": "/docs/concepts/credentials",
1666
+ rls: "/docs/adapters/rls"
1667
+ };
1668
+ for (const feature of ctx.preset.features) {
1669
+ const page = byFeature[feature];
1670
+ if (page !== void 0) docs.push(page);
1671
+ }
1672
+ if (ctx.preset.framework !== "none") docs.push(`/docs/adapters/${ctx.preset.framework}`);
1673
+ docs.push(...authDocs(ctx), ...backendDocs(ctx));
1674
+ if (ctx.preset.services.length > 0) docs.push("/docs/adapters/cloud");
1675
+ return [...new Set(docs)];
1676
+ }
1677
+ /**
1678
+ * The files, dependencies and recipes for `preset`. Pure: no file system
1679
+ * and no network, so the same function runs in the CLI, in a registry route
1680
+ * and in the browser preview on /create.
1681
+ */
1682
+ function generatePreset(preset, options = {}) {
1683
+ const ctx = {
1684
+ preset,
1685
+ domain: DOMAINS[preset.archetype],
1686
+ has: (feature) => preset.features.includes(feature),
1687
+ src: options.src ?? "src"
1688
+ };
1689
+ const owned = (path, contents) => ownedFile(`${ctx.src}/${path}`, contents);
1690
+ return Object.freeze({
1691
+ code: encodePreset(preset),
1692
+ files: Object.freeze([
1693
+ owned("permissions.ts", permissionsFile(ctx)),
1694
+ owned("policy.ts", policyFile(ctx)),
1695
+ owned("permdock.ts", appFile(ctx)),
1696
+ ...backendFiles(ctx),
1697
+ ...sessionFiles(ctx),
1698
+ ...frameworkFiles(ctx),
1699
+ ...agentFiles(ctx),
1700
+ ...keysFile(ctx),
1701
+ configFile(ctx)
1702
+ ]),
1703
+ dependencies: Object.freeze(dependenciesFor(ctx)),
1704
+ recipes: Object.freeze(recipesFor(ctx)),
1705
+ docs: Object.freeze(docsFor(ctx))
1706
+ });
1707
+ }
1708
+ //#endregion
1709
+ //#region src/preset/matrix.ts
1710
+ const NONE = {
1711
+ access: "none",
1712
+ approval: false,
1713
+ limit: false
1714
+ };
1715
+ /**
1716
+ * Who may do what under `preset`, from the same model the generated policy
1717
+ * is written from, for a page that shows the policy without running it.
1718
+ */
1719
+ function presetMatrix(preset) {
1720
+ const domain = DOMAINS[preset.archetype];
1721
+ const plans = preset.features.includes("plans") && domain.pro !== void 0;
1722
+ const rows = domain.resources.flatMap((resource) => {
1723
+ return [
1724
+ ...resource.preset === "crud" ? [
1725
+ "read",
1726
+ "list",
1727
+ "create",
1728
+ "update",
1729
+ "delete"
1730
+ ] : ["read", "list"],
1731
+ ...resource.actions ?? [],
1732
+ ...resource.collection ?? []
1733
+ ].map((action) => ({
1734
+ resource: resource.name,
1735
+ action
1736
+ }));
1737
+ }).map(({ resource, action }) => {
1738
+ const cells = {};
1739
+ const isPro = plans && domain.pro?.resource === resource && domain.pro.action === action;
1740
+ for (const role of domain.roles) {
1741
+ const grant = role.grants.find((item) => item.resource === resource && item.action === action);
1742
+ if (grant === void 0 || isPro && role.top !== true) {
1743
+ cells[role.name] = isPro ? {
1744
+ ...NONE,
1745
+ access: "pro"
1746
+ } : NONE;
1747
+ continue;
1748
+ }
1749
+ const shape = grantShape(preset, role, grant);
1750
+ cells[role.name] = {
1751
+ access: shape.owner === void 0 ? "allow" : "own",
1752
+ approval: shape.approval,
1753
+ limit: shape.limit
1754
+ };
1755
+ }
1756
+ return {
1757
+ resource,
1758
+ action,
1759
+ cells
1760
+ };
1761
+ });
1762
+ return {
1763
+ roles: domain.roles.map((role) => role.name),
1764
+ rows
1765
+ };
1766
+ }
1767
+ //#endregion
1768
+ export { decodePreset as a, AUTH as c, FRAMEWORKS as d, INTEGRATIONS as f, resolvePreset as g, integrationsOf as h, presetFlags as i, BACKENDS as l, SERVICES as m, generatePreset as n, encodePreset as o, PRESET_DEFAULTS as p, PRESET_FLAGS as r, ARCHETYPES as s, presetMatrix as t, FEATURES as u };