@bajustone/fortress 1.0.0-rc.1

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 (465) hide show
  1. package/CHANGELOG.md +1011 -0
  2. package/LICENSE +21 -0
  3. package/README.md +760 -0
  4. package/SECURITY.md +197 -0
  5. package/bin/fortress.ts +667 -0
  6. package/dist/auth-service-BcyQ2PuZ.d.cts +307 -0
  7. package/dist/auth-service-BkzZkWfH.d.ts +307 -0
  8. package/dist/config-B2366s_G.d.ts +665 -0
  9. package/dist/config-GtlVt6ZD.d.cts +665 -0
  10. package/dist/convert-routes-BLCQT57f.d.ts +72 -0
  11. package/dist/convert-routes-BdMvP2_X.d.cts +72 -0
  12. package/dist/crypto.cjs +61 -0
  13. package/dist/crypto.d.cts +36 -0
  14. package/dist/crypto.d.ts +36 -0
  15. package/dist/crypto.js +35 -0
  16. package/dist/drift-BT1wtMDJ.d.cts +22 -0
  17. package/dist/drift-k9LiYpRP.d.ts +22 -0
  18. package/dist/drizzle/pg.cjs +481 -0
  19. package/dist/drizzle/pg.d.cts +15 -0
  20. package/dist/drizzle/pg.d.ts +15 -0
  21. package/dist/drizzle/pg.js +454 -0
  22. package/dist/drizzle.cjs +1442 -0
  23. package/dist/drizzle.d.cts +85 -0
  24. package/dist/drizzle.d.ts +85 -0
  25. package/dist/drizzle.js +1411 -0
  26. package/dist/express.cjs +1357 -0
  27. package/dist/express.d.cts +333 -0
  28. package/dist/express.d.ts +333 -0
  29. package/dist/express.js +1314 -0
  30. package/dist/fetcher.cjs +77 -0
  31. package/dist/fetcher.d.cts +7 -0
  32. package/dist/fetcher.d.ts +7 -0
  33. package/dist/fetcher.js +41 -0
  34. package/dist/fortress-BmSvFfqK.d.cts +1089 -0
  35. package/dist/fortress-uA-_cheR.d.ts +1089 -0
  36. package/dist/hono.cjs +1530 -0
  37. package/dist/hono.d.cts +514 -0
  38. package/dist/hono.d.ts +514 -0
  39. package/dist/hono.js +1483 -0
  40. package/dist/index-CxEkfCA0.d.cts +77 -0
  41. package/dist/index-CxEkfCA0.d.ts +77 -0
  42. package/dist/index-D054pcb-.d.cts +146 -0
  43. package/dist/index-jAMbbUAY.d.ts +146 -0
  44. package/dist/index.cjs +9046 -0
  45. package/dist/index.d.cts +717 -0
  46. package/dist/index.d.ts +717 -0
  47. package/dist/index.js +8935 -0
  48. package/dist/jwt.cjs +255 -0
  49. package/dist/jwt.d.cts +90 -0
  50. package/dist/jwt.d.ts +90 -0
  51. package/dist/jwt.js +227 -0
  52. package/dist/otel.cjs +108 -0
  53. package/dist/otel.d.cts +62 -0
  54. package/dist/otel.d.ts +62 -0
  55. package/dist/otel.js +73 -0
  56. package/dist/plugins/account-lockout.cjs +322 -0
  57. package/dist/plugins/account-lockout.d.cts +42 -0
  58. package/dist/plugins/account-lockout.d.ts +42 -0
  59. package/dist/plugins/account-lockout.js +295 -0
  60. package/dist/plugins/admin.cjs +2378 -0
  61. package/dist/plugins/admin.d.cts +72 -0
  62. package/dist/plugins/admin.d.ts +72 -0
  63. package/dist/plugins/admin.js +2351 -0
  64. package/dist/plugins/api-key.cjs +792 -0
  65. package/dist/plugins/api-key.d.cts +121 -0
  66. package/dist/plugins/api-key.d.ts +121 -0
  67. package/dist/plugins/api-key.js +765 -0
  68. package/dist/plugins/audit-log.cjs +493 -0
  69. package/dist/plugins/audit-log.d.cts +86 -0
  70. package/dist/plugins/audit-log.d.ts +86 -0
  71. package/dist/plugins/audit-log.js +468 -0
  72. package/dist/plugins/data-isolation.cjs +211 -0
  73. package/dist/plugins/data-isolation.d.cts +49 -0
  74. package/dist/plugins/data-isolation.d.ts +49 -0
  75. package/dist/plugins/data-isolation.js +186 -0
  76. package/dist/plugins/email-verification.cjs +273 -0
  77. package/dist/plugins/email-verification.d.cts +44 -0
  78. package/dist/plugins/email-verification.d.ts +44 -0
  79. package/dist/plugins/email-verification.js +246 -0
  80. package/dist/plugins/magic-link.cjs +231 -0
  81. package/dist/plugins/magic-link.d.cts +39 -0
  82. package/dist/plugins/magic-link.d.ts +39 -0
  83. package/dist/plugins/magic-link.js +204 -0
  84. package/dist/plugins/oauth.cjs +1696 -0
  85. package/dist/plugins/oauth.d.cts +406 -0
  86. package/dist/plugins/oauth.d.ts +406 -0
  87. package/dist/plugins/oauth.js +1669 -0
  88. package/dist/plugins/openapi.cjs +1185 -0
  89. package/dist/plugins/openapi.d.cts +6 -0
  90. package/dist/plugins/openapi.d.ts +6 -0
  91. package/dist/plugins/openapi.js +1158 -0
  92. package/dist/plugins/rate-limit/express.cjs +55 -0
  93. package/dist/plugins/rate-limit/express.d.cts +64 -0
  94. package/dist/plugins/rate-limit/express.d.ts +64 -0
  95. package/dist/plugins/rate-limit/express.js +30 -0
  96. package/dist/plugins/rate-limit/hono.cjs +51 -0
  97. package/dist/plugins/rate-limit/hono.d.cts +59 -0
  98. package/dist/plugins/rate-limit/hono.d.ts +59 -0
  99. package/dist/plugins/rate-limit/hono.js +26 -0
  100. package/dist/plugins/rate-limit/sveltekit.cjs +49 -0
  101. package/dist/plugins/rate-limit/sveltekit.d.cts +59 -0
  102. package/dist/plugins/rate-limit/sveltekit.d.ts +59 -0
  103. package/dist/plugins/rate-limit/sveltekit.js +24 -0
  104. package/dist/plugins/rate-limit.cjs +354 -0
  105. package/dist/plugins/rate-limit.d.cts +140 -0
  106. package/dist/plugins/rate-limit.d.ts +140 -0
  107. package/dist/plugins/rate-limit.js +325 -0
  108. package/dist/plugins/social-login.cjs +905 -0
  109. package/dist/plugins/social-login.d.cts +114 -0
  110. package/dist/plugins/social-login.d.ts +114 -0
  111. package/dist/plugins/social-login.js +880 -0
  112. package/dist/plugins/tenancy.cjs +780 -0
  113. package/dist/plugins/tenancy.d.cts +108 -0
  114. package/dist/plugins/tenancy.d.ts +108 -0
  115. package/dist/plugins/tenancy.js +753 -0
  116. package/dist/plugins/two-factor.cjs +555 -0
  117. package/dist/plugins/two-factor.d.cts +67 -0
  118. package/dist/plugins/two-factor.d.ts +67 -0
  119. package/dist/plugins/two-factor.js +526 -0
  120. package/dist/plugins/webauthn.cjs +786 -0
  121. package/dist/plugins/webauthn.d.cts +72 -0
  122. package/dist/plugins/webauthn.d.ts +72 -0
  123. package/dist/plugins/webauthn.js +766 -0
  124. package/dist/plugins/webhook.cjs +819 -0
  125. package/dist/plugins/webhook.d.cts +254 -0
  126. package/dist/plugins/webhook.d.ts +254 -0
  127. package/dist/plugins/webhook.js +789 -0
  128. package/dist/protect-D1v_0upK.d.cts +123 -0
  129. package/dist/protect-DsxV_-dJ.d.ts +123 -0
  130. package/dist/sveltekit.cjs +1258 -0
  131. package/dist/sveltekit.d.cts +420 -0
  132. package/dist/sveltekit.d.ts +420 -0
  133. package/dist/sveltekit.js +1207 -0
  134. package/dist/testing.cjs +4294 -0
  135. package/dist/testing.d.cts +197 -0
  136. package/dist/testing.d.ts +197 -0
  137. package/dist/testing.js +4264 -0
  138. package/dist/types-et0R8tsC.d.cts +217 -0
  139. package/dist/types-et0R8tsC.d.ts +217 -0
  140. package/docs/adapter-typed-helpers.md +192 -0
  141. package/docs/admin-recipes.md +227 -0
  142. package/docs/architecture.md +434 -0
  143. package/docs/ci/github-actions.yml +59 -0
  144. package/docs/ci.md +109 -0
  145. package/docs/compatibility.md +115 -0
  146. package/docs/deployment.md +305 -0
  147. package/docs/hardening.md +118 -0
  148. package/docs/host-owned-routes.md +154 -0
  149. package/docs/migrations/0001-schema-version.md +54 -0
  150. package/docs/migrations/0002-initial-schema.md +84 -0
  151. package/docs/migrations/upgrade-guide.md +160 -0
  152. package/docs/observability.md +394 -0
  153. package/docs/plugins/account-lockout.md +131 -0
  154. package/docs/plugins/admin.md +402 -0
  155. package/docs/plugins/api-key.md +327 -0
  156. package/docs/plugins/audit-log.md +261 -0
  157. package/docs/plugins/data-isolation.md +186 -0
  158. package/docs/plugins/email-verification.md +121 -0
  159. package/docs/plugins/magic-link.md +123 -0
  160. package/docs/plugins/oauth.md +544 -0
  161. package/docs/plugins/openapi.md +250 -0
  162. package/docs/plugins/rate-limit.md +223 -0
  163. package/docs/plugins/social-login.md +337 -0
  164. package/docs/plugins/tenancy.md +122 -0
  165. package/docs/plugins/two-factor.md +191 -0
  166. package/docs/plugins/webauthn.md +188 -0
  167. package/docs/plugins/webhook.md +242 -0
  168. package/docs/policy-as-code.md +156 -0
  169. package/docs/route-manifest.md +46 -0
  170. package/docs/security.md +261 -0
  171. package/docs/threat-model.md +161 -0
  172. package/examples/README.md +119 -0
  173. package/examples/express-app/index.ts +747 -0
  174. package/examples/hono-app/docker-compose.yml +14 -0
  175. package/examples/hono-app/index.ts +1009 -0
  176. package/examples/policy/fortress.policy.json +47 -0
  177. package/examples/sveltekit-app/README.md +125 -0
  178. package/examples/sveltekit-app/src/app.d.ts +16 -0
  179. package/examples/sveltekit-app/src/hooks.server.ts +23 -0
  180. package/examples/sveltekit-app/src/lib/server/fortress.ts +81 -0
  181. package/examples/sveltekit-app/src/routes/api/echo/[id]/+server.ts +32 -0
  182. package/examples/sveltekit-app/src/routes/api/fortress/[...path]/+server.ts +15 -0
  183. package/examples/sveltekit-app/src/routes/dashboard/+page.server.ts +20 -0
  184. package/examples/sveltekit-app/src/routes/login/+page.server.ts +48 -0
  185. package/examples/sveltekit-app/src/routes/oauth/consent/+page.server.ts +69 -0
  186. package/examples/sveltekit-app/src/routes/oauth/consent/+page.svelte +83 -0
  187. package/migrations/pg/0001_schema_version.down.sql +2 -0
  188. package/migrations/pg/0001_schema_version.sql +8 -0
  189. package/migrations/pg/0002_initial_schema.down.sql +36 -0
  190. package/migrations/pg/0002_initial_schema.sql +376 -0
  191. package/migrations/pg/0003_auth_continuation.down.sql +6 -0
  192. package/migrations/pg/0003_auth_continuation.sql +30 -0
  193. package/migrations/pg/0004_tenant_default_unique.down.sql +1 -0
  194. package/migrations/pg/0004_tenant_default_unique.sql +14 -0
  195. package/migrations/pg/0005_hot_indexes_timestamptz.down.sql +71 -0
  196. package/migrations/pg/0005_hot_indexes_timestamptz.sql +71 -0
  197. package/migrations/pg/0006_canonical_email.down.sql +3 -0
  198. package/migrations/pg/0006_canonical_email.sql +8 -0
  199. package/migrations/pg/0007_audit_chain_anchor.down.sql +1 -0
  200. package/migrations/pg/0007_audit_chain_anchor.sql +8 -0
  201. package/migrations/pg/0008_two_factor_hardening.down.sql +8 -0
  202. package/migrations/pg/0008_two_factor_hardening.sql +8 -0
  203. package/migrations/pg/0009_encrypt_totp_secrets.down.sql +2 -0
  204. package/migrations/pg/0009_encrypt_totp_secrets.sql +5 -0
  205. package/migrations/pg/0010_bigint_append_only_ids.down.sql +2 -0
  206. package/migrations/pg/0010_bigint_append_only_ids.sql +23 -0
  207. package/migrations/sqlite/0001_schema_version.down.sql +2 -0
  208. package/migrations/sqlite/0001_schema_version.sql +8 -0
  209. package/migrations/sqlite/0002_initial_schema.down.sql +36 -0
  210. package/migrations/sqlite/0002_initial_schema.sql +376 -0
  211. package/migrations/sqlite/0003_auth_continuation.down.sql +27 -0
  212. package/migrations/sqlite/0003_auth_continuation.sql +45 -0
  213. package/migrations/sqlite/0004_tenant_default_unique.down.sql +1 -0
  214. package/migrations/sqlite/0004_tenant_default_unique.sql +13 -0
  215. package/migrations/sqlite/0005_hot_indexes_timestamptz.down.sql +10 -0
  216. package/migrations/sqlite/0005_hot_indexes_timestamptz.sql +10 -0
  217. package/migrations/sqlite/0006_canonical_email.down.sql +3 -0
  218. package/migrations/sqlite/0006_canonical_email.sql +8 -0
  219. package/migrations/sqlite/0007_audit_chain_anchor.down.sql +1 -0
  220. package/migrations/sqlite/0007_audit_chain_anchor.sql +8 -0
  221. package/migrations/sqlite/0008_two_factor_hardening.down.sql +14 -0
  222. package/migrations/sqlite/0008_two_factor_hardening.sql +7 -0
  223. package/migrations/sqlite/0009_encrypt_totp_secrets.down.sql +2 -0
  224. package/migrations/sqlite/0009_encrypt_totp_secrets.sql +5 -0
  225. package/migrations/sqlite/0010_bigint_append_only_ids.down.sql +1 -0
  226. package/migrations/sqlite/0010_bigint_append_only_ids.sql +2 -0
  227. package/package.json +398 -0
  228. package/src/adapters/database/index.ts +63 -0
  229. package/src/adapters/database/types.ts +22 -0
  230. package/src/changelog-script.test.ts +21 -0
  231. package/src/cli.test.ts +79 -0
  232. package/src/core/auth/auth-admin.test.ts +247 -0
  233. package/src/core/auth/auth-endpoints.ts +558 -0
  234. package/src/core/auth/auth-observer.test.ts +191 -0
  235. package/src/core/auth/auth-service.ts +1464 -0
  236. package/src/core/auth/email.test.ts +17 -0
  237. package/src/core/auth/email.ts +11 -0
  238. package/src/core/auth/hooks.test.ts +251 -0
  239. package/src/core/auth/impersonation.test.ts +179 -0
  240. package/src/core/auth/jwt.test.ts +184 -0
  241. package/src/core/auth/jwt.ts +239 -0
  242. package/src/core/auth/login-timing.test.ts +77 -0
  243. package/src/core/auth/password-policy.test.ts +253 -0
  244. package/src/core/auth/password-policy.ts +220 -0
  245. package/src/core/auth/password.test.ts +42 -0
  246. package/src/core/auth/password.ts +62 -0
  247. package/src/core/auth/post-auth-gate.test.ts +258 -0
  248. package/src/core/auth/post-auth-gate.ts +228 -0
  249. package/src/core/auth/refresh-token.test.ts +86 -0
  250. package/src/core/auth/refresh-token.ts +105 -0
  251. package/src/core/auth/timing-safe.ts +23 -0
  252. package/src/core/config.ts +212 -0
  253. package/src/core/endpoint.ts +149 -0
  254. package/src/core/errors.ts +199 -0
  255. package/src/core/fetcher-interop.test.ts +106 -0
  256. package/src/core/fortress.test.ts +354 -0
  257. package/src/core/fortress.ts +550 -0
  258. package/src/core/http/call.test.ts +148 -0
  259. package/src/core/http/call.ts +149 -0
  260. package/src/core/http/cookie-serialize.test.ts +198 -0
  261. package/src/core/http/cookie-serialize.ts +107 -0
  262. package/src/core/http/csrf.test.ts +140 -0
  263. package/src/core/http/csrf.ts +173 -0
  264. package/src/core/http/dispatch.ts +652 -0
  265. package/src/core/http/error-response.test.ts +69 -0
  266. package/src/core/http/error-response.ts +93 -0
  267. package/src/core/http/fortress-rbac.test.ts +43 -0
  268. package/src/core/http/fortress-rbac.ts +127 -0
  269. package/src/core/http/handle-request.test.ts +441 -0
  270. package/src/core/http/handle-request.ts +354 -0
  271. package/src/core/http/match.test.ts +122 -0
  272. package/src/core/http/match.ts +126 -0
  273. package/src/core/http/outbound.test.ts +34 -0
  274. package/src/core/http/outbound.ts +105 -0
  275. package/src/core/http/plugin-middleware.ts +67 -0
  276. package/src/core/http/principal.test.ts +345 -0
  277. package/src/core/http/principal.ts +86 -0
  278. package/src/core/http/protect.test.ts +220 -0
  279. package/src/core/http/protect.ts +394 -0
  280. package/src/core/http/token-extraction.test.ts +59 -0
  281. package/src/core/http/token-extraction.ts +53 -0
  282. package/src/core/iam/explain.test.ts +177 -0
  283. package/src/core/iam/explain.ts +302 -0
  284. package/src/core/iam/iam-endpoints.ts +779 -0
  285. package/src/core/iam/iam-service.test.ts +829 -0
  286. package/src/core/iam/iam-service.ts +1137 -0
  287. package/src/core/iam/permission-cache.test.ts +115 -0
  288. package/src/core/iam/permission-cache.ts +71 -0
  289. package/src/core/iam/permission-check-observer.test.ts +90 -0
  290. package/src/core/iam/permission-evaluator.test.ts +291 -0
  291. package/src/core/iam/permission-evaluator.ts +198 -0
  292. package/src/core/iam/permission-sync.test.ts +166 -0
  293. package/src/core/iam/permission-sync.ts +192 -0
  294. package/src/core/iam/resource-sync.test.ts +70 -0
  295. package/src/core/iam/resource-sync.ts +182 -0
  296. package/src/core/iam/service-account-http.test.ts +529 -0
  297. package/src/core/iam/service-account.test.ts +282 -0
  298. package/src/core/internal-adapter.test.ts +389 -0
  299. package/src/core/internal-adapter.ts +435 -0
  300. package/src/core/json-schema.ts +50 -0
  301. package/src/core/manifest/__snapshots__/route-manifest.test.ts.snap +192 -0
  302. package/src/core/manifest/drift.ts +103 -0
  303. package/src/core/manifest/route-manifest.test.ts +142 -0
  304. package/src/core/manifest/route-manifest.ts +154 -0
  305. package/src/core/migrate.test.ts +72 -0
  306. package/src/core/migrations/engine.test.ts +308 -0
  307. package/src/core/migrations/engine.ts +548 -0
  308. package/src/core/migrations/migrations.ts +1771 -0
  309. package/src/core/migrations/pg-migration.integration-test.ts +353 -0
  310. package/src/core/migrations/upgrade-fixture.test.ts +378 -0
  311. package/src/core/observability/db-instrumentation.ts +205 -0
  312. package/src/core/observability/listener-list.test.ts +124 -0
  313. package/src/core/observability/listener-list.ts +73 -0
  314. package/src/core/observability/logger.test.ts +43 -0
  315. package/src/core/observability/logger.ts +49 -0
  316. package/src/core/observability/spans.test.ts +193 -0
  317. package/src/core/observability/types.ts +80 -0
  318. package/src/core/openapi-drift.test.ts +41 -0
  319. package/src/core/openapi.ts +47 -0
  320. package/src/core/plugin-methods-map.ts +75 -0
  321. package/src/core/plugin-runner.test.ts +233 -0
  322. package/src/core/plugin-runner.ts +276 -0
  323. package/src/core/plugin.ts +210 -0
  324. package/src/core/policy/apply.ts +272 -0
  325. package/src/core/policy/diff.ts +288 -0
  326. package/src/core/policy/loader.test.ts +63 -0
  327. package/src/core/policy/loader.ts +214 -0
  328. package/src/core/policy/policy.test.ts +232 -0
  329. package/src/core/policy/types.ts +105 -0
  330. package/src/core/schema-builder.test.ts +660 -0
  331. package/src/core/schema-builder.ts +881 -0
  332. package/src/core/standard-schema.ts +56 -0
  333. package/src/core/types.ts +258 -0
  334. package/src/core/validation.test.ts +195 -0
  335. package/src/core/validation.ts +192 -0
  336. package/src/drizzle/adapter.test.ts +425 -0
  337. package/src/drizzle/adapter.ts +474 -0
  338. package/src/drizzle/index.ts +31 -0
  339. package/src/drizzle/pg/adapter.integration-test.ts +456 -0
  340. package/src/drizzle/pg/index.ts +13 -0
  341. package/src/drizzle/pg/pg.integration-test.ts +1539 -0
  342. package/src/drizzle/pg/schema.ts +539 -0
  343. package/src/drizzle/pg-error-map.test.ts +218 -0
  344. package/src/drizzle/pg-error-map.ts +151 -0
  345. package/src/drizzle/schema.ts +544 -0
  346. package/src/drizzle/sqlite-serialization.test.ts +106 -0
  347. package/src/express/express-api-key-user-routes.test.ts +241 -0
  348. package/src/express/express.test.ts +442 -0
  349. package/src/express/handle.ts +191 -0
  350. package/src/express/index.ts +62 -0
  351. package/src/express/middleware.ts +551 -0
  352. package/src/express/protect.ts +154 -0
  353. package/src/express/validated.test.ts +86 -0
  354. package/src/express/validated.ts +99 -0
  355. package/src/fetcher/index.ts +81 -0
  356. package/src/hono/convert-routes.test.ts +220 -0
  357. package/src/hono/convert-routes.ts +196 -0
  358. package/src/hono/converters.test.ts +50 -0
  359. package/src/hono/converters.ts +43 -0
  360. package/src/hono/handle.ts +79 -0
  361. package/src/hono/helpers.ts +2 -0
  362. package/src/hono/hono-api-key-user-routes.test.ts +225 -0
  363. package/src/hono/hono-handlers.test.ts +861 -0
  364. package/src/hono/hono.test.ts +454 -0
  365. package/src/hono/index.ts +101 -0
  366. package/src/hono/middleware/auth.ts +236 -0
  367. package/src/hono/middleware/auth.types.test.ts +94 -0
  368. package/src/hono/middleware/csrf.test.ts +127 -0
  369. package/src/hono/middleware/csrf.ts +68 -0
  370. package/src/hono/middleware/error-handler.ts +12 -0
  371. package/src/hono/middleware/plugin-middleware.ts +35 -0
  372. package/src/hono/middleware/rbac.ts +131 -0
  373. package/src/hono/middleware/security-headers.test.ts +88 -0
  374. package/src/hono/middleware/security-headers.ts +68 -0
  375. package/src/hono/openapi.ts +237 -0
  376. package/src/hono/protect.ts +87 -0
  377. package/src/hono/validated.test.ts +123 -0
  378. package/src/hono/validated.ts +62 -0
  379. package/src/index.ts +309 -0
  380. package/src/integration.test.ts +718 -0
  381. package/src/internal/changelog.ts +56 -0
  382. package/src/otel/index.ts +158 -0
  383. package/src/otel/otel-types.test.ts +35 -0
  384. package/src/otel/otel.test.ts +235 -0
  385. package/src/plugins/account-lockout/account-lockout.test.ts +367 -0
  386. package/src/plugins/account-lockout/index.ts +267 -0
  387. package/src/plugins/admin/admin-api-key.test.ts +438 -0
  388. package/src/plugins/admin/index.ts +1612 -0
  389. package/src/plugins/api-key/api-key.test.ts +684 -0
  390. package/src/plugins/api-key/core.ts +336 -0
  391. package/src/plugins/api-key/index.ts +315 -0
  392. package/src/plugins/audit-log/audit-log.test.ts +749 -0
  393. package/src/plugins/audit-log/index.ts +680 -0
  394. package/src/plugins/data-isolation/data-isolation.test.ts +197 -0
  395. package/src/plugins/data-isolation/index.ts +157 -0
  396. package/src/plugins/email-verification/email-verification.test.ts +199 -0
  397. package/src/plugins/email-verification/index.ts +190 -0
  398. package/src/plugins/magic-link/index.ts +129 -0
  399. package/src/plugins/magic-link/magic-link.test.ts +156 -0
  400. package/src/plugins/oauth/id-token.ts +86 -0
  401. package/src/plugins/oauth/index.ts +2145 -0
  402. package/src/plugins/oauth/jwks.test.ts +32 -0
  403. package/src/plugins/oauth/jwks.ts +182 -0
  404. package/src/plugins/oauth/oauth.test.ts +2220 -0
  405. package/src/plugins/oauth/pkce.ts +58 -0
  406. package/src/plugins/openapi/index.ts +298 -0
  407. package/src/plugins/openapi/openapi.test.ts +425 -0
  408. package/src/plugins/openapi/spec-builder.ts +287 -0
  409. package/src/plugins/rate-limit/express.test.ts +89 -0
  410. package/src/plugins/rate-limit/express.ts +86 -0
  411. package/src/plugins/rate-limit/hono.test.ts +60 -0
  412. package/src/plugins/rate-limit/hono.ts +74 -0
  413. package/src/plugins/rate-limit/index.ts +383 -0
  414. package/src/plugins/rate-limit/memory-store.ts +61 -0
  415. package/src/plugins/rate-limit/rate-limit.test.ts +756 -0
  416. package/src/plugins/rate-limit/sveltekit.test.ts +58 -0
  417. package/src/plugins/rate-limit/sveltekit.ts +66 -0
  418. package/src/plugins/social-login/index.ts +715 -0
  419. package/src/plugins/social-login/providers/apple.ts +34 -0
  420. package/src/plugins/social-login/providers/discord.ts +26 -0
  421. package/src/plugins/social-login/providers/github.ts +54 -0
  422. package/src/plugins/social-login/providers/google.ts +23 -0
  423. package/src/plugins/social-login/providers/index.ts +22 -0
  424. package/src/plugins/social-login/providers/microsoft.ts +35 -0
  425. package/src/plugins/social-login/providers/oidc.ts +37 -0
  426. package/src/plugins/social-login/providers/providers.test.ts +211 -0
  427. package/src/plugins/social-login/social-login.test.ts +675 -0
  428. package/src/plugins/social-login/types.ts +80 -0
  429. package/src/plugins/tenancy/index.ts +544 -0
  430. package/src/plugins/tenancy/tenancy.test.ts +323 -0
  431. package/src/plugins/two-factor/index.ts +569 -0
  432. package/src/plugins/two-factor/two-factor.test.ts +235 -0
  433. package/src/plugins/webauthn/index.ts +554 -0
  434. package/src/plugins/webauthn/webauthn.test.ts +472 -0
  435. package/src/plugins/webhook/builtin-events.ts +29 -0
  436. package/src/plugins/webhook/delivery.test.ts +51 -0
  437. package/src/plugins/webhook/delivery.ts +154 -0
  438. package/src/plugins/webhook/hooks.ts +89 -0
  439. package/src/plugins/webhook/index.ts +445 -0
  440. package/src/plugins/webhook/queue/database.ts +67 -0
  441. package/src/plugins/webhook/queue/in-memory.test.ts +48 -0
  442. package/src/plugins/webhook/queue/in-memory.ts +71 -0
  443. package/src/plugins/webhook/queue/types.ts +51 -0
  444. package/src/plugins/webhook/registry.test.ts +48 -0
  445. package/src/plugins/webhook/registry.ts +64 -0
  446. package/src/plugins/webhook/signing.ts +45 -0
  447. package/src/plugins/webhook/ssrf.ts +198 -0
  448. package/src/plugins/webhook/types.ts +138 -0
  449. package/src/plugins/webhook/webhook.test.ts +324 -0
  450. package/src/sveltekit/actions.ts +233 -0
  451. package/src/sveltekit/catch-all.ts +43 -0
  452. package/src/sveltekit/cookies.ts +136 -0
  453. package/src/sveltekit/handle.ts +356 -0
  454. package/src/sveltekit/helpers.ts +69 -0
  455. package/src/sveltekit/index.ts +74 -0
  456. package/src/sveltekit/protect.ts +80 -0
  457. package/src/sveltekit/sveltekit-types.test.ts +31 -0
  458. package/src/sveltekit/sveltekit.test.ts +799 -0
  459. package/src/sveltekit/types.ts +134 -0
  460. package/src/sveltekit/validated.test.ts +117 -0
  461. package/src/sveltekit/validated.ts +78 -0
  462. package/src/testing/adapter-conformance.test.ts +408 -0
  463. package/src/testing/checks.test.ts +124 -0
  464. package/src/testing/checks.ts +304 -0
  465. package/src/testing/index.ts +107 -0
@@ -0,0 +1,454 @@
1
+ import type { Fortress } from '../core/fortress';
2
+ import type { PluginRequestContext } from '../core/http/plugin-middleware';
3
+ import type { FortressEnv } from './middleware/auth';
4
+ import { Hono } from 'hono';
5
+ import { beforeEach, describe, expect, it } from 'vitest';
6
+ import { createFortress } from '../core/fortress';
7
+ import { dataIsolation } from '../plugins/data-isolation';
8
+ import { rateLimit } from '../plugins/rate-limit';
9
+ import { createTestAdapter } from '../testing';
10
+ import { getDb, getScopedDb, getUserId } from './helpers';
11
+ import { createHonoMiddleware } from './index';
12
+
13
+ const SECRET = 'hono-test-secret-at-least-32chars!!';
14
+
15
+ let fortress: Fortress;
16
+ let app: Hono<FortressEnv>;
17
+
18
+ beforeEach(async () => {
19
+ fortress = createFortress({
20
+ jwt: { key: SECRET },
21
+ database: createTestAdapter(),
22
+ });
23
+
24
+ const { authMiddleware, rbacMiddleware, errorHandler } = createHonoMiddleware(fortress, {
25
+ routeMap: {
26
+ 'GET /api/posts': { resource: 'post', action: 'list' },
27
+ 'POST /api/posts': { resource: 'post', action: 'create' },
28
+ 'GET /api/posts/:id': { resource: 'post', action: 'read' },
29
+ },
30
+ skipPaths: ['/health', '/auth/*'],
31
+ });
32
+
33
+ app = new Hono<FortressEnv>();
34
+ app.onError(errorHandler);
35
+
36
+ // Public routes
37
+ app.get('/health', c => c.json({ status: 'ok' }));
38
+ app.post('/auth/login', async (c) => {
39
+ const { identifier, password } = await c.req.json();
40
+ const result = await fortress.auth.login(identifier, password);
41
+ return c.json(result);
42
+ });
43
+
44
+ // Protected routes
45
+ app.use('/api/*', authMiddleware);
46
+ app.use('/api/*', rbacMiddleware);
47
+
48
+ app.get('/api/posts', (c) => {
49
+ const userId = getUserId(c);
50
+ return c.json({ userId, posts: [] });
51
+ });
52
+ app.post('/api/posts', c => c.json({ created: true }));
53
+ app.get('/api/posts/:id', c => c.json({ id: c.req.param('id') }));
54
+ app.get('/api/profile', (c) => {
55
+ const userId = getUserId(c);
56
+ return c.json({ userId });
57
+ });
58
+
59
+ // Seed a user
60
+ await fortress.auth.createUser({
61
+ email: 'test@example.com',
62
+ name: 'Test User',
63
+ password: 'password-123456',
64
+ });
65
+ });
66
+
67
+ async function loginAndGetToken(): Promise<string> {
68
+ const res = await app.request('/auth/login', {
69
+ method: 'POST',
70
+ headers: { 'Content-Type': 'application/json' },
71
+ body: JSON.stringify({ identifier: 'test@example.com', password: 'password-123456' }),
72
+ });
73
+ const data = await res.json() as any;
74
+ return data.accessToken;
75
+ }
76
+
77
+ describe('hono errorHandler', () => {
78
+ it('returns 401 for missing auth header', async () => {
79
+ const res = await app.request('/api/posts');
80
+ expect(res.status).toBe(401);
81
+ const body = await res.json() as any;
82
+ expect(body.code).toBe('UNAUTHORIZED');
83
+ });
84
+
85
+ it('returns 401 for invalid token', async () => {
86
+ const res = await app.request('/api/posts', {
87
+ headers: { Authorization: 'Bearer invalid-token' },
88
+ });
89
+ expect(res.status).toBe(401);
90
+ });
91
+ });
92
+
93
+ describe('hono authMiddleware', () => {
94
+ it('allows requests with valid token', async () => {
95
+ const token = await loginAndGetToken();
96
+ const res = await app.request('/api/profile', {
97
+ headers: { Authorization: `Bearer ${token}` },
98
+ });
99
+ // No routeMap for /api/profile → RBAC skips, request goes through
100
+ expect(res.status).toBe(200);
101
+ const body = await res.json() as any;
102
+ expect(body.userId).toBeTruthy();
103
+ });
104
+
105
+ it('skips auth for skip paths', async () => {
106
+ const res = await app.request('/health');
107
+ expect(res.status).toBe(200);
108
+ const body = await res.json() as any;
109
+ expect(body.status).toBe('ok');
110
+ });
111
+
112
+ it('skips auth for wildcard skip paths', async () => {
113
+ const res = await app.request('/auth/login', {
114
+ method: 'POST',
115
+ headers: { 'Content-Type': 'application/json' },
116
+ body: JSON.stringify({ identifier: 'test@example.com', password: 'password-123456' }),
117
+ });
118
+ expect(res.status).toBe(200);
119
+ });
120
+ });
121
+
122
+ describe('hono plugin middleware', () => {
123
+ it('passes resolved auth fields in PluginRequestContext after auth', async () => {
124
+ let captured: PluginRequestContext | undefined;
125
+ const local = createFortress({
126
+ jwt: { key: SECRET },
127
+ database: createTestAdapter(),
128
+ plugins: [{
129
+ name: 'context-spy',
130
+ middleware: [{
131
+ path: '/api/*',
132
+ position: 'after-auth',
133
+ handler: async (_ctx, request, next) => {
134
+ captured = request;
135
+ await next();
136
+ },
137
+ }],
138
+ }],
139
+ });
140
+ const user = await local.auth.createUser({
141
+ email: 'context@example.com',
142
+ name: 'Context',
143
+ password: 'password-123456',
144
+ });
145
+ const login = await local.auth.login('context@example.com', 'password-123456');
146
+ if (login.status !== 'success')
147
+ throw new Error('Expected successful login');
148
+ const { authMiddleware, pluginMiddleware, errorHandler } = createHonoMiddleware(local);
149
+ const localApp = new Hono<FortressEnv>();
150
+ localApp.onError(errorHandler);
151
+ localApp.use('/api/*', authMiddleware);
152
+ localApp.use('/api/*', pluginMiddleware.afterAuth);
153
+ localApp.get('/api/items', c => c.json({ ok: true }));
154
+
155
+ const response = await localApp.request('/api/items?include=all', {
156
+ headers: { authorization: `Bearer ${login.accessToken}` },
157
+ });
158
+ expect(response.status).toBe(200);
159
+ expect(captured?.request.url).toBe('http://localhost/api/items?include=all');
160
+ expect(captured?.fortressSubject).toEqual({ type: 'USER', id: user.id });
161
+ expect(captured?.fortressUserId).toBe(user.id);
162
+ expect(captured?.fortressClaims?.sub).toBe(user.id);
163
+ });
164
+
165
+ it('normalizes PluginRequestContext so path rate limits fire', async () => {
166
+ const limited = createFortress({
167
+ jwt: { key: SECRET },
168
+ database: createTestAdapter(),
169
+ plugins: [rateLimit({
170
+ login: { disabled: true },
171
+ register: { disabled: true },
172
+ paths: [{ match: '/api/*', rule: { maxPerIp: 1, windowSeconds: 60 } }],
173
+ })],
174
+ });
175
+ const { pluginMiddleware, errorHandler } = createHonoMiddleware(limited);
176
+ const limitedApp = new Hono<FortressEnv>();
177
+ limitedApp.onError(errorHandler);
178
+ limitedApp.use('/api/*', pluginMiddleware.beforeAuth);
179
+ limitedApp.get('/api/items', c => c.json({ ok: true }));
180
+
181
+ const headers = { 'x-forwarded-for': '192.0.2.1' };
182
+ expect((await limitedApp.request('/api/items', { headers })).status).toBe(200);
183
+ const rejected = await limitedApp.request('/api/items', { headers });
184
+ expect(rejected.status).toBe(429);
185
+ expect((await rejected.json() as any).code).toBe('RATE_LIMITED');
186
+ });
187
+ });
188
+
189
+ describe('hono rbacMiddleware', () => {
190
+ it('allows access when user has permission', async () => {
191
+ const token = await loginAndGetToken();
192
+
193
+ // Give the user permission to list posts
194
+ const user = await fortress.auth.me('1');
195
+ const role = await fortress.iam.createRole('viewer', [
196
+ { resource: 'post', action: 'list' },
197
+ { resource: 'post', action: 'read' },
198
+ ]);
199
+ await fortress.iam.bindRoleToUser(user.id, role.id);
200
+
201
+ const res = await app.request('/api/posts', {
202
+ headers: { Authorization: `Bearer ${token}` },
203
+ });
204
+ expect(res.status).toBe(200);
205
+ });
206
+
207
+ it('denies access when user lacks permission', async () => {
208
+ const token = await loginAndGetToken();
209
+
210
+ // User has no roles — should be denied for mapped routes
211
+ const res = await app.request('/api/posts', {
212
+ headers: { Authorization: `Bearer ${token}` },
213
+ });
214
+ expect(res.status).toBe(403);
215
+ const body = await res.json() as any;
216
+ expect(body.code).toBe('FORBIDDEN');
217
+ });
218
+
219
+ it('matches parameterized routes', async () => {
220
+ const token = await loginAndGetToken();
221
+
222
+ const role = await fortress.iam.createRole('reader', [
223
+ { resource: 'post', action: 'read' },
224
+ ]);
225
+ await fortress.iam.bindRoleToUser('1', role.id);
226
+
227
+ const res = await app.request('/api/posts/42', {
228
+ headers: { Authorization: `Bearer ${token}` },
229
+ });
230
+ expect(res.status).toBe(200);
231
+ const body = await res.json() as any;
232
+ expect(body.id).toBe('42');
233
+ });
234
+
235
+ it('allows unmapped routes through (no routeMap entry)', async () => {
236
+ const token = await loginAndGetToken();
237
+
238
+ // /api/profile has no routeMap entry → RBAC skips
239
+ const res = await app.request('/api/profile', {
240
+ headers: { Authorization: `Bearer ${token}` },
241
+ });
242
+ expect(res.status).toBe(200);
243
+ });
244
+
245
+ it('denies unmapped routes when unmappedRoutes is deny, but honors skipPaths', async () => {
246
+ const token = await loginAndGetToken();
247
+
248
+ const { authMiddleware, rbacMiddleware, errorHandler } = createHonoMiddleware(fortress, {
249
+ routeMap: { 'GET /api/posts': { resource: 'post', action: 'list' } },
250
+ skipPaths: ['/api/public/*'],
251
+ unmappedRoutes: 'deny',
252
+ });
253
+ const denyApp = new Hono<FortressEnv>();
254
+ denyApp.onError(errorHandler);
255
+ denyApp.use('/api/*', authMiddleware);
256
+ denyApp.use('/api/*', rbacMiddleware);
257
+ denyApp.get('/api/unmapped', c => c.json({ ok: true }));
258
+ denyApp.get('/api/public/info', c => c.json({ ok: true }));
259
+
260
+ // Unmapped, non-skipped route → fail closed with 403.
261
+ const denied = await denyApp.request('/api/unmapped', {
262
+ headers: { Authorization: `Bearer ${token}` },
263
+ });
264
+ expect(denied.status).toBe(403);
265
+ expect((await denied.json() as any).code).toBe('FORBIDDEN');
266
+
267
+ // Skip-listed route is still allowed even under defaultDeny.
268
+ const allowed = await denyApp.request('/api/public/info', {
269
+ headers: { Authorization: `Bearer ${token}` },
270
+ });
271
+ expect(allowed.status).toBe(200);
272
+ });
273
+ });
274
+
275
+ describe('hono authMiddleware — fortressDb and getScopedDb', () => {
276
+ let dbApp: Hono<FortressEnv>;
277
+ let dbFortress: Fortress;
278
+
279
+ beforeEach(async () => {
280
+ dbFortress = createFortress({
281
+ jwt: { key: SECRET },
282
+ database: createTestAdapter(),
283
+ });
284
+
285
+ const { authMiddleware, errorHandler } = createHonoMiddleware(dbFortress);
286
+ dbApp = new Hono<FortressEnv>();
287
+ dbApp.onError(errorHandler);
288
+
289
+ dbApp.post('/auth/login', async (c) => {
290
+ const { identifier, password } = await c.req.json();
291
+ const result = await dbFortress.auth.login(identifier, password);
292
+ return c.json(result);
293
+ });
294
+
295
+ dbApp.use('/api/*', authMiddleware);
296
+
297
+ dbApp.get('/api/db-check', (c) => {
298
+ const db = getDb(c);
299
+ return c.json({
300
+ hasDb: !!db,
301
+ hasCreate: typeof db.create === 'function',
302
+ });
303
+ });
304
+
305
+ dbApp.get('/api/scoped-check', async (c) => {
306
+ const db = await getScopedDb(c, 'post');
307
+ return c.json({
308
+ hasDb: !!db,
309
+ hasCreate: typeof db.create === 'function',
310
+ });
311
+ });
312
+
313
+ await dbFortress.auth.createUser({
314
+ email: 'test@example.com',
315
+ name: 'Test User',
316
+ password: 'password-123456',
317
+ });
318
+ });
319
+
320
+ async function loginDb(): Promise<string> {
321
+ const res = await dbApp.request('/auth/login', {
322
+ method: 'POST',
323
+ headers: { 'Content-Type': 'application/json' },
324
+ body: JSON.stringify({
325
+ identifier: 'test@example.com',
326
+ password: 'password-123456',
327
+ }),
328
+ });
329
+ const data = (await res.json()) as any;
330
+ return data.accessToken;
331
+ }
332
+
333
+ it('sets fortressDb on context after auth', async () => {
334
+ const token = await loginDb();
335
+ const res = await dbApp.request('/api/db-check', {
336
+ headers: { Authorization: `Bearer ${token}` },
337
+ });
338
+ expect(res.status).toBe(200);
339
+ const body = (await res.json()) as any;
340
+ expect(body.hasDb).toBe(true);
341
+ expect(body.hasCreate).toBe(true);
342
+ });
343
+
344
+ it('getScopedDb returns adapter when no plugins define scopeRules', async () => {
345
+ const token = await loginDb();
346
+ const res = await dbApp.request('/api/scoped-check', {
347
+ headers: { Authorization: `Bearer ${token}` },
348
+ });
349
+ expect(res.status).toBe(200);
350
+ const body = (await res.json()) as any;
351
+ expect(body.hasDb).toBe(true);
352
+ expect(body.hasCreate).toBe(true);
353
+ });
354
+ });
355
+
356
+ describe('hono authMiddleware — data-isolation scopeRules', () => {
357
+ let isolatedFortress: Fortress<any>;
358
+ let isolatedApp: Hono<FortressEnv>;
359
+
360
+ beforeEach(async () => {
361
+ const db = createTestAdapter();
362
+
363
+ isolatedFortress = createFortress({
364
+ jwt: { key: SECRET },
365
+ database: db,
366
+ plugins: [
367
+ dataIsolation({
368
+ scopes: [
369
+ {
370
+ name: 'org',
371
+ field: 'orgId',
372
+ models: ['post'],
373
+ resolveValue: async () => 42,
374
+ },
375
+ ],
376
+ }),
377
+ ],
378
+ });
379
+
380
+ const { authMiddleware, errorHandler } = createHonoMiddleware(
381
+ isolatedFortress,
382
+ );
383
+
384
+ isolatedApp = new Hono<FortressEnv>();
385
+ isolatedApp.onError(errorHandler);
386
+
387
+ isolatedApp.post('/auth/login', async (c) => {
388
+ const { identifier, password } = await c.req.json();
389
+ const result = await isolatedFortress.auth.login(identifier, password);
390
+ return c.json(result);
391
+ });
392
+
393
+ isolatedApp.use('/api/*', authMiddleware);
394
+
395
+ isolatedApp.get('/api/scoped-post', async (c) => {
396
+ const db = await getScopedDb(c, 'post');
397
+ // Verify the scoped adapter exists and has methods
398
+ return c.json({
399
+ hasDb: !!db,
400
+ hasFindMany: typeof db.findMany === 'function',
401
+ hasCreate: typeof db.create === 'function',
402
+ });
403
+ });
404
+
405
+ isolatedApp.get('/api/unscoped-user', async (c) => {
406
+ // "user" model is not in the scope config, so no filters applied
407
+ const db = await getScopedDb(c, 'user');
408
+ return c.json({ hasDb: !!db });
409
+ });
410
+
411
+ await isolatedFortress.auth.createUser({
412
+ email: 'test@example.com',
413
+ name: 'Test User',
414
+ password: 'password-123456',
415
+ });
416
+ });
417
+
418
+ async function loginIsolated(): Promise<string> {
419
+ const res = await isolatedApp.request('/auth/login', {
420
+ method: 'POST',
421
+ headers: { 'Content-Type': 'application/json' },
422
+ body: JSON.stringify({
423
+ identifier: 'test@example.com',
424
+ password: 'password-123456',
425
+ }),
426
+ });
427
+ const data = (await res.json()) as any;
428
+ return data.accessToken;
429
+ }
430
+
431
+ it('getScopedDb applies scope rules for matching model', async () => {
432
+ const token = await loginIsolated();
433
+
434
+ const res = await isolatedApp.request('/api/scoped-post', {
435
+ headers: { Authorization: `Bearer ${token}` },
436
+ });
437
+ expect(res.status).toBe(200);
438
+ const body = (await res.json()) as any;
439
+ expect(body.hasDb).toBe(true);
440
+ expect(body.hasFindMany).toBe(true);
441
+ expect(body.hasCreate).toBe(true);
442
+ });
443
+
444
+ it('getScopedDb returns base adapter for non-matching model', async () => {
445
+ const token = await loginIsolated();
446
+
447
+ const res = await isolatedApp.request('/api/unscoped-user', {
448
+ headers: { Authorization: `Bearer ${token}` },
449
+ });
450
+ expect(res.status).toBe(200);
451
+ const body = (await res.json()) as any;
452
+ expect(body.hasDb).toBe(true);
453
+ });
454
+ });
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Hono adapter for fortress.
3
+ *
4
+ * Provides {@link mountFortress}, the modern entry point that delegates to
5
+ * `fortress.handleRequest`, plus the lower-level middleware factories
6
+ * (`createHonoMiddleware`, `createAuthMiddleware`, `createRbacMiddleware`,
7
+ * `createCsrfMiddleware`, `createSecurityHeadersMiddleware`, etc.) for
8
+ * user-owned routes. Also exports `vBody` / `vParam` / `vQuery` typed
9
+ * extraction helpers for custom routes.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { Hono } from 'hono';
14
+ * import { mountFortress, createHonoMiddleware } from '@bajustone/fortress/hono';
15
+ *
16
+ * const app = new Hono();
17
+ *
18
+ * // One-line mount: handles all Fortress routes (auth, IAM, plugins, OAuth, OpenAPI).
19
+ * mountFortress(app, fortress);
20
+ *
21
+ * // Optional: protect your own routes with the IAM middleware.
22
+ * const { authMiddleware, rbacMiddleware, errorHandler } = createHonoMiddleware(fortress, {
23
+ * routeMap: { 'GET /api/users': { resource: 'user', action: 'list' } },
24
+ * });
25
+ * app.use('/api/*', authMiddleware, rbacMiddleware);
26
+ * app.onError(errorHandler);
27
+ * ```
28
+ *
29
+ * @module
30
+ */
31
+
32
+ import type { Fortress } from '../core/fortress';
33
+ import type { RbacOptions } from './middleware/rbac';
34
+ import { createAuthMiddleware } from './middleware/auth';
35
+ import { createErrorHandler } from './middleware/error-handler';
36
+ import { createPluginMiddleware } from './middleware/plugin-middleware';
37
+ import { createRbacMiddleware } from './middleware/rbac';
38
+
39
+ export { convertRoutes } from './convert-routes';
40
+ export type { ConvertRoutesOptions, ExternalRoute, ToJSONSchemaConverter } from './convert-routes';
41
+ export { fetcherSchemaConverter, identitySchemaConverter, toJSONSchemaConverter } from './converters';
42
+ export { mountFortress } from './handle';
43
+ export type { MountFortressOptions } from './handle';
44
+ export { getClaims, getDb, getScopedDb, getSubject, getUserId } from './helpers';
45
+ export type { FortressContext, FortressEnv, FortressVariables } from './middleware/auth';
46
+ export { createCsrfMiddleware } from './middleware/csrf';
47
+ export type { CsrfConfig } from './middleware/csrf';
48
+ export { createPluginMiddleware } from './middleware/plugin-middleware';
49
+ export type { RbacOptions, RouteMapping } from './middleware/rbac';
50
+ export { createSecurityHeadersMiddleware } from './middleware/security-headers';
51
+ export type { SecurityHeadersConfig } from './middleware/security-headers';
52
+ export { buildRouteDefinition, getFortressRoutes, mountFortressOpenAPI } from './openapi';
53
+ export type { SchemaConverter } from './openapi';
54
+ export { protectedRoute } from './protect';
55
+ export type { HonoProtectedRouteHandler, ProtectedRouteContext, ProtectedRouteHandler, ProtectedRouteTarget, ProtectOptions } from './protect';
56
+ export { vBody, vParam, vQuery } from './validated';
57
+ export type { InferOutput } from './validated';
58
+
59
+ /**
60
+ * Options for {@link createHonoMiddleware}. Currently extends {@link RbacOptions}
61
+ * so callers can override which IAM resource/action a route maps to.
62
+ */
63
+ export interface HonoAdapterOptions extends RbacOptions {}
64
+
65
+ /**
66
+ * Create Hono middleware from a Fortress instance.
67
+ *
68
+ * Usage:
69
+ * const { authMiddleware, pluginMiddleware, rbacMiddleware, errorHandler } = createHonoMiddleware(fortress, {
70
+ * routeMap: { 'POST /api/users': { resource: 'user', action: 'create' } },
71
+ * skipPaths: ['/health', '/auth/*'],
72
+ * });
73
+ *
74
+ * app.onError(errorHandler);
75
+ * app.use('/api/*', pluginMiddleware.beforeAuth);
76
+ * app.use('/api/*', authMiddleware);
77
+ * app.use('/api/*', pluginMiddleware.afterAuth);
78
+ * app.use('/api/*', rbacMiddleware);
79
+ * app.use('/api/*', pluginMiddleware.afterRbac);
80
+ */
81
+ export function createHonoMiddleware(fortress: Fortress, options?: HonoAdapterOptions): {
82
+ authMiddleware: ReturnType<typeof createAuthMiddleware>;
83
+ rbacMiddleware: ReturnType<typeof createRbacMiddleware>;
84
+ errorHandler: ReturnType<typeof createErrorHandler>;
85
+ pluginMiddleware: {
86
+ beforeAuth: ReturnType<typeof createPluginMiddleware>;
87
+ afterAuth: ReturnType<typeof createPluginMiddleware>;
88
+ afterRbac: ReturnType<typeof createPluginMiddleware>;
89
+ };
90
+ } {
91
+ return {
92
+ authMiddleware: createAuthMiddleware(fortress),
93
+ rbacMiddleware: createRbacMiddleware(fortress, options),
94
+ errorHandler: createErrorHandler(),
95
+ pluginMiddleware: {
96
+ beforeAuth: createPluginMiddleware(fortress, 'before-auth'),
97
+ afterAuth: createPluginMiddleware(fortress, 'after-auth'),
98
+ afterRbac: createPluginMiddleware(fortress, 'after-rbac'),
99
+ },
100
+ };
101
+ }