@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,333 @@
1
+ export { C as ConvertRoutesOptions, E as ExternalRoute, T as ToJSONSchemaConverter, c as convertRoutes } from './convert-routes-BdMvP2_X.cjs';
2
+ import { F as Fortress } from './fortress-BmSvFfqK.cjs';
3
+ import { D as DatabaseAdapter } from './index-CxEkfCA0.cjs';
4
+ import { M as MiddlewareDefinition, E as EndpointDefinition, S as StandardSchemaV1 } from './config-GtlVt6ZD.cjs';
5
+ import { S as Subject, T as TokenClaims } from './types-et0R8tsC.cjs';
6
+ import { P as ProtectedRouteContext, a as ProtectOptions } from './protect-D1v_0upK.cjs';
7
+ export { b as ProtectedRouteTarget } from './protect-D1v_0upK.cjs';
8
+ import './index-D054pcb-.cjs';
9
+ import './auth-service-BcyQ2PuZ.cjs';
10
+ import './plugins/api-key.cjs';
11
+ import './jwt.cjs';
12
+ import './plugins/audit-log.cjs';
13
+ import './plugins/data-isolation.cjs';
14
+ import './plugins/email-verification.cjs';
15
+ import './plugins/magic-link.cjs';
16
+ import './plugins/oauth.cjs';
17
+ import './plugins/social-login.cjs';
18
+ import './plugins/tenancy.cjs';
19
+ import './plugins/two-factor.cjs';
20
+ import './plugins/webauthn.cjs';
21
+ import '@simplewebauthn/server';
22
+
23
+ /**
24
+ * Fortress-specific fields attached to the Express `Request` by
25
+ * {@link createAuthMiddleware}. Exported so host apps can declaration-merge
26
+ * them into express's native `Request` type for typed access without casts.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // src/types/express.d.ts
31
+ * import type { FortressExpressFields } from '@bajustone/fortress/express';
32
+ *
33
+ * declare module 'express-serve-static-core' {
34
+ * interface Request extends FortressExpressFields {}
35
+ * }
36
+ * ```
37
+ */
38
+ interface FortressExpressFields {
39
+ /**
40
+ * The resolved principal — set for every authenticated request regardless
41
+ * of credential type (JWT, api-key, future OAuth client_credentials, mTLS).
42
+ */
43
+ fortressSubject?: Subject;
44
+ /**
45
+ * Convenience alias — populated **only** when the subject is a `USER`.
46
+ * Non-USER subjects (e.g. `SERVICE_ACCOUNT` via api-key) leave this
47
+ * undefined; fall back to {@link fortressSubject}.
48
+ */
49
+ fortressUserId?: string;
50
+ fortressClaims?: TokenClaims;
51
+ fortressScopes?: string[] | null;
52
+ fortressDb?: DatabaseAdapter;
53
+ fortressGetScopedDb?: (model: string) => Promise<DatabaseAdapter>;
54
+ }
55
+ /** Minimal Express request shape fortress reads from. Compatible with any modern Express version. */
56
+ interface ExpressRequest extends FortressExpressFields {
57
+ headers: Record<string, string | string[] | undefined>;
58
+ method: string;
59
+ /** Express's route path without the query string. */
60
+ path: string;
61
+ /** Original path including query string, when supplied by Express. */
62
+ originalUrl?: string;
63
+ /** Node/Express request URL fallback, usually including the query string. */
64
+ url?: string;
65
+ /** Resolved request protocol (`http`/`https`) when supplied by Express. */
66
+ protocol?: string;
67
+ /** Parsed request body, if body middleware ran before this slot. */
68
+ body?: unknown;
69
+ }
70
+ /** Minimal Express response shape fortress writes to. */
71
+ interface ExpressResponse {
72
+ status: (code: number) => ExpressResponse;
73
+ json: (body: unknown) => void;
74
+ setHeader: (name: string, value: string) => void;
75
+ }
76
+ /** The `next(err?)` callback Express middleware signs off with. */
77
+ type ExpressNextFunction = (err?: unknown) => void;
78
+ /** Express middleware signature fortress's adapter exports use. */
79
+ type ExpressMiddleware = (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
80
+ /** A `(resource, action)` IAM mapping for an HTTP route. */
81
+ interface RouteMapping {
82
+ resource: string;
83
+ action: string;
84
+ }
85
+ /** Options accepted by {@link createRbacMiddleware} (and the express adapter factory). */
86
+ interface RbacOptions {
87
+ routeMap?: Record<string, RouteMapping>;
88
+ mapRequest?: (method: string, path: string) => RouteMapping | null;
89
+ skipPaths?: string[];
90
+ /**
91
+ * Behavior when a non-skipped route matches no `routeMap`/`mapRequest`
92
+ * entry. `'allow'` (default) treats it as public; `'deny'` fails closed
93
+ * with a 403 so a forgotten mapping can't silently expose a user route.
94
+ * List genuinely public routes in {@link RbacOptions.skipPaths} when using
95
+ * `'deny'`.
96
+ */
97
+ unmappedRoutes?: 'allow' | 'deny';
98
+ }
99
+ /**
100
+ * Build the Express auth middleware. Resolves the request principal via
101
+ * `fortress.resolvePrincipal`, which tries plugin `resolvePrincipal` hooks
102
+ * (api-key, future OAuth client_credentials, mTLS) first and then falls
103
+ * back to the JWT bearer token (cookie-first, `Authorization: Bearer`
104
+ * second). Populates `fortressSubject`, `fortressUserId` (USER alias),
105
+ * `fortressClaims`, `fortressDb`, and `fortressGetScopedDb` on the request.
106
+ */
107
+ declare function createAuthMiddleware(fortress: Fortress): ExpressMiddleware;
108
+ /** Options accepted by {@link createCsrfMiddleware}. */
109
+ interface CsrfConfig {
110
+ /** Header name required on unsafe methods. Default: `X-Fortress-CSRF`. */
111
+ headerName?: string;
112
+ /** Paths/subtrees exempt from CSRF checking. A trailing `/*` is accepted. */
113
+ skipPaths?: string[];
114
+ /** Methods exempt from CSRF checking. Default: GET, HEAD, OPTIONS. */
115
+ safeMethods?: string[];
116
+ }
117
+ /**
118
+ * Build standalone Express CSRF middleware for host-owned routes. Fortress-
119
+ * managed routes already enforce cookie-aware CSRF inside `handleRequest`.
120
+ * This middleware uses the custom-header strategy and rejects cross-site
121
+ * browser requests on unsafe methods.
122
+ */
123
+ declare function createCsrfMiddleware(config?: CsrfConfig): ExpressMiddleware;
124
+ /**
125
+ * Build the Express RBAC middleware for **user-owned routes**. Resolves a
126
+ * `(resource, action)` mapping via `routeMap` / `mapRequest` and enforces
127
+ * the IAM permission check. Fortress-managed routes (`/auth/*`, `/iam/*`,
128
+ * plugin paths) are protected automatically inside `fortress.handleRequest`
129
+ * — this middleware only handles routes the caller registered themselves.
130
+ */
131
+ declare function createRbacMiddleware(fortress: Fortress, options?: RbacOptions): ExpressMiddleware;
132
+ /**
133
+ * Build the Express error handler. Translates {@link FortressError} into the
134
+ * appropriate HTTP response with `Retry-After` for rate-limited responses,
135
+ * and returns a generic 500 for everything else.
136
+ *
137
+ * Stays synchronous so it composes naturally with Express's `(err, req,
138
+ * res, next)` signature. Shares the response *shape* with core's
139
+ * `errorToResponse` via {@link FortressError.toJSON}. When a `Fortress`
140
+ * instance is provided, unhandled errors are routed to its configured
141
+ * {@link FortressLogger}; otherwise they're silently swallowed (matching
142
+ * the silent-by-default posture of the library).
143
+ */
144
+ declare function createErrorHandler(fortress?: Fortress): (err: unknown, req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
145
+ /**
146
+ * Express middleware that executes plugin-defined middleware for a given
147
+ * position (`before-auth`, `after-auth`, `after-rbac`). Used internally by
148
+ * {@link createExpressMiddleware}; expose if you want to mount the plugin
149
+ * middleware slots manually.
150
+ */
151
+ declare function createExpressPluginMiddleware(fortress: Fortress, position: MiddlewareDefinition['position']): ExpressMiddleware;
152
+ /** Options for {@link createExpressMiddleware}. Extends {@link RbacOptions}. */
153
+ interface ExpressAdapterOptions extends RbacOptions {
154
+ /** Standalone CSRF middleware options for host-owned Express routes. */
155
+ csrf?: CsrfConfig;
156
+ }
157
+ /**
158
+ * Build the full set of fortress Express middleware: auth, CSRF, RBAC, error
159
+ * handler, and the three plugin middleware slots (`beforeAuth`, `afterAuth`,
160
+ * `afterRbac`). Mount each in the corresponding place in your Express app.
161
+ */
162
+ declare function createExpressMiddleware(fortress: Fortress, options?: ExpressAdapterOptions): {
163
+ authMiddleware: ExpressMiddleware;
164
+ csrfMiddleware: ExpressMiddleware;
165
+ rbacMiddleware: ExpressMiddleware;
166
+ errorHandler: ReturnType<typeof createErrorHandler>;
167
+ pluginMiddleware: {
168
+ beforeAuth: ExpressMiddleware;
169
+ afterAuth: ExpressMiddleware;
170
+ afterRbac: ExpressMiddleware;
171
+ };
172
+ };
173
+ /**
174
+ * Read the resolved request principal. Works for every subject kind
175
+ * (`USER`, `SERVICE_ACCOUNT`, ...). Throws 401 if the auth middleware did
176
+ * not run or no credential was present.
177
+ */
178
+ declare function getSubject(req: ExpressRequest): Subject;
179
+ /**
180
+ * Read the authenticated user ID. Throws 401 if the request was
181
+ * authenticated by a non-USER subject (e.g. a service account via
182
+ * api-key) — use {@link getSubject} for handlers that accept any
183
+ * principal.
184
+ */
185
+ declare function getUserId(req: ExpressRequest): string;
186
+ /**
187
+ * Read the verified JWT claims. Only populated when the request was
188
+ * authenticated via a JWT — api-key principals have no JWT claims and
189
+ * this helper throws 401.
190
+ */
191
+ declare function getClaims(req: ExpressRequest): TokenClaims;
192
+ /** Read the per-request fortress database adapter (with plugin wrappers applied). */
193
+ declare function getDb(req: ExpressRequest): DatabaseAdapter;
194
+ /** Read the per-request fortress database adapter scoped to a specific model (applies any active row-level scope rules). */
195
+ declare function getScopedDb(req: ExpressRequest, model: string): Promise<DatabaseAdapter>;
196
+
197
+ /**
198
+ * Modern entry point for the Express adapter: register a single fortress
199
+ * middleware that detects Fortress-managed paths and delegates to
200
+ * `fortress.handleRequest`.
201
+ *
202
+ * Bridges Express's `(req, res, next)` callback style to/from web-standard
203
+ * `Request`/`Response`. User routes registered before `mountFortress` keep
204
+ * working — Express's middleware order means earlier handlers win.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * import express from 'express';
209
+ * import { mountFortress } from '@bajustone/fortress/express';
210
+ *
211
+ * const app = express();
212
+ * app.use(express.json());
213
+ * mountFortress(app, fortress);
214
+ * ```
215
+ */
216
+
217
+ interface ExpressApp {
218
+ use: (path: string | ExpressMiddleware, handler?: ExpressMiddleware) => void;
219
+ }
220
+ /** Options for {@link mountFortress}. */
221
+ interface MountFortressOptions {
222
+ /** Optional path prefix (e.g. `/api`). Stripped before delegating to core. */
223
+ prefix?: string;
224
+ }
225
+ /**
226
+ * Mount a single Express middleware that delegates Fortress-managed paths to
227
+ * `fortress.handleRequest` and otherwise calls `next()` so user routes run
228
+ * normally.
229
+ *
230
+ * Cookies emitted by login/refresh/impersonate are passed through verbatim
231
+ * via `Set-Cookie` headers, the way the browser expects them.
232
+ */
233
+ declare function mountFortress(app: ExpressApp, fortress: Fortress, options?: MountFortressOptions): void;
234
+
235
+ /**
236
+ * Express-flavoured host callback. `E` flows in from the endpoint passed to
237
+ * `protectedRoute()`, so `ctx.body` / `ctx.query` / `ctx.params` / `ctx.input`
238
+ * are typed from the endpoint's phantom generics. String targets degrade to
239
+ * the loose default.
240
+ */
241
+ type ExpressProtectedRouteHandler<E extends EndpointDefinition<any, any, any, any> = EndpointDefinition, TResult = unknown> = (req: ExpressRequest, res: ExpressResponse, ctx: ProtectedRouteContext<E>) => TResult | Response | Promise<TResult | Response>;
242
+ /**
243
+ * Wrap a host-owned Express route in Fortress's protection pipeline.
244
+ *
245
+ * Two overloads, mirroring `protect()`:
246
+ *
247
+ * - **Typed target** — passing an `EndpointDefinition` flows its phantom
248
+ * generics through `ctx`.
249
+ * - **String target** — passing a unique `handler` name keeps the loose
250
+ * `Record<string, unknown>` / `unknown` typing.
251
+ */
252
+ declare function protectedRoute<E extends EndpointDefinition<any, any, any, any>, TResult = unknown>(fortress: Fortress, target: E, handler: ExpressProtectedRouteHandler<E, TResult>, options?: ProtectOptions): ExpressMiddleware;
253
+ declare function protectedRoute<TResult = unknown>(fortress: Fortress, target: string, handler: ExpressProtectedRouteHandler<EndpointDefinition, TResult>, options?: ProtectOptions): ExpressMiddleware;
254
+
255
+ /**
256
+ * Typed extraction-and-validation helpers for Express handlers.
257
+ *
258
+ * These helpers extract request data (body, params, query) **and validate
259
+ * it at runtime** against the supplied Standard Schema. On success they
260
+ * return the parsed value with full TypeScript inference; on failure they
261
+ * throw `FortressError('VALIDATION_ERROR', 422)` — the same shape every
262
+ * fortress-managed endpoint produces — so the existing Express error
263
+ * handler (`createErrorHandler`) formats it identically.
264
+ *
265
+ * Works with any Standard Schema V1 library: Zod, Valibot, ArkType, or
266
+ * fortress's built-in schema builders.
267
+ *
268
+ * Assumes body-parsing middleware (e.g. `app.use(express.json())`) has
269
+ * already populated `req.body` for `vBody` to read.
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * import express from 'express';
274
+ * import { vBody, vParam, vQuery, createErrorHandler } from '@bajustone/fortress/express';
275
+ * import { obj, str } from '@bajustone/fortress';
276
+ *
277
+ * const app = express();
278
+ * app.use(express.json());
279
+ *
280
+ * const Body = obj({ name: str() }, 'name');
281
+ * const Param = obj({ id: str() }, 'id');
282
+ *
283
+ * app.patch('/users/:id', async (req, res, next) => {
284
+ * try {
285
+ * const { id } = await vParam(req, Param);
286
+ * const { name } = await vBody(req, Body);
287
+ * res.json({ id, name });
288
+ * }
289
+ * catch (err) { next(err); }
290
+ * });
291
+ *
292
+ * app.use(createErrorHandler());
293
+ * ```
294
+ *
295
+ * Validation runs per call, so the first failing helper throws and any
296
+ * downstream helpers in the same handler do not run. If you need to
297
+ * aggregate body+query+params issues into a single response, use the
298
+ * framework-agnostic `validateRequest` from `@bajustone/fortress` instead.
299
+ */
300
+
301
+ /** Infer the output type of a Standard Schema V1 schema. */
302
+ type InferOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
303
+ /**
304
+ * Structural shape of an Express `Request` accepted by these helpers.
305
+ * Defined locally instead of importing from `express` so fortress can ship
306
+ * without a hard `express` dependency. Compatible by structural typing with
307
+ * the real `express.Request` — consumers pass their `req` directly.
308
+ */
309
+ interface ExpressRequestLike {
310
+ body?: unknown;
311
+ params?: unknown;
312
+ query?: unknown;
313
+ }
314
+ /**
315
+ * Extract and validate the request body. Assumes body-parsing middleware
316
+ * (e.g. `express.json()`) populated `req.body`. Returns the parsed value
317
+ * typed as `InferOutput<T>`, or throws `FortressError('VALIDATION_ERROR', 422)`.
318
+ */
319
+ declare function vBody<T extends StandardSchemaV1>(req: ExpressRequestLike, schema: T): Promise<InferOutput<T>>;
320
+ /**
321
+ * Extract and validate route parameters from `req.params`. Returns the
322
+ * parsed value typed as `InferOutput<T>`, or throws
323
+ * `FortressError('VALIDATION_ERROR', 422)`.
324
+ */
325
+ declare function vParam<T extends StandardSchemaV1>(req: ExpressRequestLike, schema: T): Promise<InferOutput<T>>;
326
+ /**
327
+ * Extract and validate query parameters from `req.query`. Returns the
328
+ * parsed value typed as `InferOutput<T>`, or throws
329
+ * `FortressError('VALIDATION_ERROR', 422)`.
330
+ */
331
+ declare function vQuery<T extends StandardSchemaV1>(req: ExpressRequestLike, schema: T): Promise<InferOutput<T>>;
332
+
333
+ export { type CsrfConfig, type ExpressAdapterOptions, type ExpressMiddleware, type ExpressNextFunction, type ExpressProtectedRouteHandler, type ExpressRequest, type ExpressRequestLike, type ExpressResponse, type FortressExpressFields, type InferOutput, type MountFortressOptions, ProtectOptions, ProtectedRouteContext, type RbacOptions, type RouteMapping, createAuthMiddleware, createCsrfMiddleware, createErrorHandler, createExpressMiddleware, createExpressPluginMiddleware, createRbacMiddleware, getClaims, getDb, getScopedDb, getSubject, getUserId, mountFortress, protectedRoute, vBody, vParam, vQuery };
@@ -0,0 +1,333 @@
1
+ export { C as ConvertRoutesOptions, E as ExternalRoute, T as ToJSONSchemaConverter, c as convertRoutes } from './convert-routes-BLCQT57f.js';
2
+ import { F as Fortress } from './fortress-uA-_cheR.js';
3
+ import { D as DatabaseAdapter } from './index-CxEkfCA0.js';
4
+ import { M as MiddlewareDefinition, E as EndpointDefinition, S as StandardSchemaV1 } from './config-B2366s_G.js';
5
+ import { S as Subject, T as TokenClaims } from './types-et0R8tsC.js';
6
+ import { P as ProtectedRouteContext, a as ProtectOptions } from './protect-DsxV_-dJ.js';
7
+ export { b as ProtectedRouteTarget } from './protect-DsxV_-dJ.js';
8
+ import './index-jAMbbUAY.js';
9
+ import './auth-service-BkzZkWfH.js';
10
+ import './plugins/api-key.js';
11
+ import './jwt.js';
12
+ import './plugins/audit-log.js';
13
+ import './plugins/data-isolation.js';
14
+ import './plugins/email-verification.js';
15
+ import './plugins/magic-link.js';
16
+ import './plugins/oauth.js';
17
+ import './plugins/social-login.js';
18
+ import './plugins/tenancy.js';
19
+ import './plugins/two-factor.js';
20
+ import './plugins/webauthn.js';
21
+ import '@simplewebauthn/server';
22
+
23
+ /**
24
+ * Fortress-specific fields attached to the Express `Request` by
25
+ * {@link createAuthMiddleware}. Exported so host apps can declaration-merge
26
+ * them into express's native `Request` type for typed access without casts.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // src/types/express.d.ts
31
+ * import type { FortressExpressFields } from '@bajustone/fortress/express';
32
+ *
33
+ * declare module 'express-serve-static-core' {
34
+ * interface Request extends FortressExpressFields {}
35
+ * }
36
+ * ```
37
+ */
38
+ interface FortressExpressFields {
39
+ /**
40
+ * The resolved principal — set for every authenticated request regardless
41
+ * of credential type (JWT, api-key, future OAuth client_credentials, mTLS).
42
+ */
43
+ fortressSubject?: Subject;
44
+ /**
45
+ * Convenience alias — populated **only** when the subject is a `USER`.
46
+ * Non-USER subjects (e.g. `SERVICE_ACCOUNT` via api-key) leave this
47
+ * undefined; fall back to {@link fortressSubject}.
48
+ */
49
+ fortressUserId?: string;
50
+ fortressClaims?: TokenClaims;
51
+ fortressScopes?: string[] | null;
52
+ fortressDb?: DatabaseAdapter;
53
+ fortressGetScopedDb?: (model: string) => Promise<DatabaseAdapter>;
54
+ }
55
+ /** Minimal Express request shape fortress reads from. Compatible with any modern Express version. */
56
+ interface ExpressRequest extends FortressExpressFields {
57
+ headers: Record<string, string | string[] | undefined>;
58
+ method: string;
59
+ /** Express's route path without the query string. */
60
+ path: string;
61
+ /** Original path including query string, when supplied by Express. */
62
+ originalUrl?: string;
63
+ /** Node/Express request URL fallback, usually including the query string. */
64
+ url?: string;
65
+ /** Resolved request protocol (`http`/`https`) when supplied by Express. */
66
+ protocol?: string;
67
+ /** Parsed request body, if body middleware ran before this slot. */
68
+ body?: unknown;
69
+ }
70
+ /** Minimal Express response shape fortress writes to. */
71
+ interface ExpressResponse {
72
+ status: (code: number) => ExpressResponse;
73
+ json: (body: unknown) => void;
74
+ setHeader: (name: string, value: string) => void;
75
+ }
76
+ /** The `next(err?)` callback Express middleware signs off with. */
77
+ type ExpressNextFunction = (err?: unknown) => void;
78
+ /** Express middleware signature fortress's adapter exports use. */
79
+ type ExpressMiddleware = (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
80
+ /** A `(resource, action)` IAM mapping for an HTTP route. */
81
+ interface RouteMapping {
82
+ resource: string;
83
+ action: string;
84
+ }
85
+ /** Options accepted by {@link createRbacMiddleware} (and the express adapter factory). */
86
+ interface RbacOptions {
87
+ routeMap?: Record<string, RouteMapping>;
88
+ mapRequest?: (method: string, path: string) => RouteMapping | null;
89
+ skipPaths?: string[];
90
+ /**
91
+ * Behavior when a non-skipped route matches no `routeMap`/`mapRequest`
92
+ * entry. `'allow'` (default) treats it as public; `'deny'` fails closed
93
+ * with a 403 so a forgotten mapping can't silently expose a user route.
94
+ * List genuinely public routes in {@link RbacOptions.skipPaths} when using
95
+ * `'deny'`.
96
+ */
97
+ unmappedRoutes?: 'allow' | 'deny';
98
+ }
99
+ /**
100
+ * Build the Express auth middleware. Resolves the request principal via
101
+ * `fortress.resolvePrincipal`, which tries plugin `resolvePrincipal` hooks
102
+ * (api-key, future OAuth client_credentials, mTLS) first and then falls
103
+ * back to the JWT bearer token (cookie-first, `Authorization: Bearer`
104
+ * second). Populates `fortressSubject`, `fortressUserId` (USER alias),
105
+ * `fortressClaims`, `fortressDb`, and `fortressGetScopedDb` on the request.
106
+ */
107
+ declare function createAuthMiddleware(fortress: Fortress): ExpressMiddleware;
108
+ /** Options accepted by {@link createCsrfMiddleware}. */
109
+ interface CsrfConfig {
110
+ /** Header name required on unsafe methods. Default: `X-Fortress-CSRF`. */
111
+ headerName?: string;
112
+ /** Paths/subtrees exempt from CSRF checking. A trailing `/*` is accepted. */
113
+ skipPaths?: string[];
114
+ /** Methods exempt from CSRF checking. Default: GET, HEAD, OPTIONS. */
115
+ safeMethods?: string[];
116
+ }
117
+ /**
118
+ * Build standalone Express CSRF middleware for host-owned routes. Fortress-
119
+ * managed routes already enforce cookie-aware CSRF inside `handleRequest`.
120
+ * This middleware uses the custom-header strategy and rejects cross-site
121
+ * browser requests on unsafe methods.
122
+ */
123
+ declare function createCsrfMiddleware(config?: CsrfConfig): ExpressMiddleware;
124
+ /**
125
+ * Build the Express RBAC middleware for **user-owned routes**. Resolves a
126
+ * `(resource, action)` mapping via `routeMap` / `mapRequest` and enforces
127
+ * the IAM permission check. Fortress-managed routes (`/auth/*`, `/iam/*`,
128
+ * plugin paths) are protected automatically inside `fortress.handleRequest`
129
+ * — this middleware only handles routes the caller registered themselves.
130
+ */
131
+ declare function createRbacMiddleware(fortress: Fortress, options?: RbacOptions): ExpressMiddleware;
132
+ /**
133
+ * Build the Express error handler. Translates {@link FortressError} into the
134
+ * appropriate HTTP response with `Retry-After` for rate-limited responses,
135
+ * and returns a generic 500 for everything else.
136
+ *
137
+ * Stays synchronous so it composes naturally with Express's `(err, req,
138
+ * res, next)` signature. Shares the response *shape* with core's
139
+ * `errorToResponse` via {@link FortressError.toJSON}. When a `Fortress`
140
+ * instance is provided, unhandled errors are routed to its configured
141
+ * {@link FortressLogger}; otherwise they're silently swallowed (matching
142
+ * the silent-by-default posture of the library).
143
+ */
144
+ declare function createErrorHandler(fortress?: Fortress): (err: unknown, req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => void;
145
+ /**
146
+ * Express middleware that executes plugin-defined middleware for a given
147
+ * position (`before-auth`, `after-auth`, `after-rbac`). Used internally by
148
+ * {@link createExpressMiddleware}; expose if you want to mount the plugin
149
+ * middleware slots manually.
150
+ */
151
+ declare function createExpressPluginMiddleware(fortress: Fortress, position: MiddlewareDefinition['position']): ExpressMiddleware;
152
+ /** Options for {@link createExpressMiddleware}. Extends {@link RbacOptions}. */
153
+ interface ExpressAdapterOptions extends RbacOptions {
154
+ /** Standalone CSRF middleware options for host-owned Express routes. */
155
+ csrf?: CsrfConfig;
156
+ }
157
+ /**
158
+ * Build the full set of fortress Express middleware: auth, CSRF, RBAC, error
159
+ * handler, and the three plugin middleware slots (`beforeAuth`, `afterAuth`,
160
+ * `afterRbac`). Mount each in the corresponding place in your Express app.
161
+ */
162
+ declare function createExpressMiddleware(fortress: Fortress, options?: ExpressAdapterOptions): {
163
+ authMiddleware: ExpressMiddleware;
164
+ csrfMiddleware: ExpressMiddleware;
165
+ rbacMiddleware: ExpressMiddleware;
166
+ errorHandler: ReturnType<typeof createErrorHandler>;
167
+ pluginMiddleware: {
168
+ beforeAuth: ExpressMiddleware;
169
+ afterAuth: ExpressMiddleware;
170
+ afterRbac: ExpressMiddleware;
171
+ };
172
+ };
173
+ /**
174
+ * Read the resolved request principal. Works for every subject kind
175
+ * (`USER`, `SERVICE_ACCOUNT`, ...). Throws 401 if the auth middleware did
176
+ * not run or no credential was present.
177
+ */
178
+ declare function getSubject(req: ExpressRequest): Subject;
179
+ /**
180
+ * Read the authenticated user ID. Throws 401 if the request was
181
+ * authenticated by a non-USER subject (e.g. a service account via
182
+ * api-key) — use {@link getSubject} for handlers that accept any
183
+ * principal.
184
+ */
185
+ declare function getUserId(req: ExpressRequest): string;
186
+ /**
187
+ * Read the verified JWT claims. Only populated when the request was
188
+ * authenticated via a JWT — api-key principals have no JWT claims and
189
+ * this helper throws 401.
190
+ */
191
+ declare function getClaims(req: ExpressRequest): TokenClaims;
192
+ /** Read the per-request fortress database adapter (with plugin wrappers applied). */
193
+ declare function getDb(req: ExpressRequest): DatabaseAdapter;
194
+ /** Read the per-request fortress database adapter scoped to a specific model (applies any active row-level scope rules). */
195
+ declare function getScopedDb(req: ExpressRequest, model: string): Promise<DatabaseAdapter>;
196
+
197
+ /**
198
+ * Modern entry point for the Express adapter: register a single fortress
199
+ * middleware that detects Fortress-managed paths and delegates to
200
+ * `fortress.handleRequest`.
201
+ *
202
+ * Bridges Express's `(req, res, next)` callback style to/from web-standard
203
+ * `Request`/`Response`. User routes registered before `mountFortress` keep
204
+ * working — Express's middleware order means earlier handlers win.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * import express from 'express';
209
+ * import { mountFortress } from '@bajustone/fortress/express';
210
+ *
211
+ * const app = express();
212
+ * app.use(express.json());
213
+ * mountFortress(app, fortress);
214
+ * ```
215
+ */
216
+
217
+ interface ExpressApp {
218
+ use: (path: string | ExpressMiddleware, handler?: ExpressMiddleware) => void;
219
+ }
220
+ /** Options for {@link mountFortress}. */
221
+ interface MountFortressOptions {
222
+ /** Optional path prefix (e.g. `/api`). Stripped before delegating to core. */
223
+ prefix?: string;
224
+ }
225
+ /**
226
+ * Mount a single Express middleware that delegates Fortress-managed paths to
227
+ * `fortress.handleRequest` and otherwise calls `next()` so user routes run
228
+ * normally.
229
+ *
230
+ * Cookies emitted by login/refresh/impersonate are passed through verbatim
231
+ * via `Set-Cookie` headers, the way the browser expects them.
232
+ */
233
+ declare function mountFortress(app: ExpressApp, fortress: Fortress, options?: MountFortressOptions): void;
234
+
235
+ /**
236
+ * Express-flavoured host callback. `E` flows in from the endpoint passed to
237
+ * `protectedRoute()`, so `ctx.body` / `ctx.query` / `ctx.params` / `ctx.input`
238
+ * are typed from the endpoint's phantom generics. String targets degrade to
239
+ * the loose default.
240
+ */
241
+ type ExpressProtectedRouteHandler<E extends EndpointDefinition<any, any, any, any> = EndpointDefinition, TResult = unknown> = (req: ExpressRequest, res: ExpressResponse, ctx: ProtectedRouteContext<E>) => TResult | Response | Promise<TResult | Response>;
242
+ /**
243
+ * Wrap a host-owned Express route in Fortress's protection pipeline.
244
+ *
245
+ * Two overloads, mirroring `protect()`:
246
+ *
247
+ * - **Typed target** — passing an `EndpointDefinition` flows its phantom
248
+ * generics through `ctx`.
249
+ * - **String target** — passing a unique `handler` name keeps the loose
250
+ * `Record<string, unknown>` / `unknown` typing.
251
+ */
252
+ declare function protectedRoute<E extends EndpointDefinition<any, any, any, any>, TResult = unknown>(fortress: Fortress, target: E, handler: ExpressProtectedRouteHandler<E, TResult>, options?: ProtectOptions): ExpressMiddleware;
253
+ declare function protectedRoute<TResult = unknown>(fortress: Fortress, target: string, handler: ExpressProtectedRouteHandler<EndpointDefinition, TResult>, options?: ProtectOptions): ExpressMiddleware;
254
+
255
+ /**
256
+ * Typed extraction-and-validation helpers for Express handlers.
257
+ *
258
+ * These helpers extract request data (body, params, query) **and validate
259
+ * it at runtime** against the supplied Standard Schema. On success they
260
+ * return the parsed value with full TypeScript inference; on failure they
261
+ * throw `FortressError('VALIDATION_ERROR', 422)` — the same shape every
262
+ * fortress-managed endpoint produces — so the existing Express error
263
+ * handler (`createErrorHandler`) formats it identically.
264
+ *
265
+ * Works with any Standard Schema V1 library: Zod, Valibot, ArkType, or
266
+ * fortress's built-in schema builders.
267
+ *
268
+ * Assumes body-parsing middleware (e.g. `app.use(express.json())`) has
269
+ * already populated `req.body` for `vBody` to read.
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * import express from 'express';
274
+ * import { vBody, vParam, vQuery, createErrorHandler } from '@bajustone/fortress/express';
275
+ * import { obj, str } from '@bajustone/fortress';
276
+ *
277
+ * const app = express();
278
+ * app.use(express.json());
279
+ *
280
+ * const Body = obj({ name: str() }, 'name');
281
+ * const Param = obj({ id: str() }, 'id');
282
+ *
283
+ * app.patch('/users/:id', async (req, res, next) => {
284
+ * try {
285
+ * const { id } = await vParam(req, Param);
286
+ * const { name } = await vBody(req, Body);
287
+ * res.json({ id, name });
288
+ * }
289
+ * catch (err) { next(err); }
290
+ * });
291
+ *
292
+ * app.use(createErrorHandler());
293
+ * ```
294
+ *
295
+ * Validation runs per call, so the first failing helper throws and any
296
+ * downstream helpers in the same handler do not run. If you need to
297
+ * aggregate body+query+params issues into a single response, use the
298
+ * framework-agnostic `validateRequest` from `@bajustone/fortress` instead.
299
+ */
300
+
301
+ /** Infer the output type of a Standard Schema V1 schema. */
302
+ type InferOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
303
+ /**
304
+ * Structural shape of an Express `Request` accepted by these helpers.
305
+ * Defined locally instead of importing from `express` so fortress can ship
306
+ * without a hard `express` dependency. Compatible by structural typing with
307
+ * the real `express.Request` — consumers pass their `req` directly.
308
+ */
309
+ interface ExpressRequestLike {
310
+ body?: unknown;
311
+ params?: unknown;
312
+ query?: unknown;
313
+ }
314
+ /**
315
+ * Extract and validate the request body. Assumes body-parsing middleware
316
+ * (e.g. `express.json()`) populated `req.body`. Returns the parsed value
317
+ * typed as `InferOutput<T>`, or throws `FortressError('VALIDATION_ERROR', 422)`.
318
+ */
319
+ declare function vBody<T extends StandardSchemaV1>(req: ExpressRequestLike, schema: T): Promise<InferOutput<T>>;
320
+ /**
321
+ * Extract and validate route parameters from `req.params`. Returns the
322
+ * parsed value typed as `InferOutput<T>`, or throws
323
+ * `FortressError('VALIDATION_ERROR', 422)`.
324
+ */
325
+ declare function vParam<T extends StandardSchemaV1>(req: ExpressRequestLike, schema: T): Promise<InferOutput<T>>;
326
+ /**
327
+ * Extract and validate query parameters from `req.query`. Returns the
328
+ * parsed value typed as `InferOutput<T>`, or throws
329
+ * `FortressError('VALIDATION_ERROR', 422)`.
330
+ */
331
+ declare function vQuery<T extends StandardSchemaV1>(req: ExpressRequestLike, schema: T): Promise<InferOutput<T>>;
332
+
333
+ export { type CsrfConfig, type ExpressAdapterOptions, type ExpressMiddleware, type ExpressNextFunction, type ExpressProtectedRouteHandler, type ExpressRequest, type ExpressRequestLike, type ExpressResponse, type FortressExpressFields, type InferOutput, type MountFortressOptions, ProtectOptions, ProtectedRouteContext, type RbacOptions, type RouteMapping, createAuthMiddleware, createCsrfMiddleware, createErrorHandler, createExpressMiddleware, createExpressPluginMiddleware, createRbacMiddleware, getClaims, getDb, getScopedDb, getSubject, getUserId, mountFortress, protectedRoute, vBody, vParam, vQuery };