@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,1089 @@
1
+ import { S as SpecBuilderOptions, O as OpenAPISpec, a as OpenAPIMethods } from './index-D054pcb-.cjs';
2
+ import { g as IamService, i as AuthService, F as FortressLogger, T as TelemetryProvider } from './auth-service-BcyQ2PuZ.cjs';
3
+ import { E as EndpointDefinition, h as FortressSchema, H as HttpMethod, O as EndpointPermission, g as SecurityRequirement, C as ComponentSchemas, c as InferEndpointCallInput, r as InferEndpointSuccessResponse, F as FortressPlugin, o as FortressConfig, R as ResolvedCookieConfig, M as MiddlewareDefinition, B as PluginRequestContext } from './config-GtlVt6ZD.cjs';
4
+ import { l as PendingReason, g as AuthMethod, S as Subject, T as TokenClaims } from './types-et0R8tsC.cjs';
5
+ import { D as DatabaseAdapter } from './index-CxEkfCA0.cjs';
6
+ import { ApiKeyMethods } from './plugins/api-key.cjs';
7
+ import { AuditLogMethods } from './plugins/audit-log.cjs';
8
+ import { DataIsolationMethods } from './plugins/data-isolation.cjs';
9
+ import { EmailVerificationMethods } from './plugins/email-verification.cjs';
10
+ import { MagicLinkMethods } from './plugins/magic-link.cjs';
11
+ import { OAuthMethods } from './plugins/oauth.cjs';
12
+ import { SocialLoginMethods } from './plugins/social-login.cjs';
13
+ import { TenancyMethods } from './plugins/tenancy.cjs';
14
+ import { TwoFactorMethods } from './plugins/two-factor.cjs';
15
+ import { WebAuthnMethods } from './plugins/webauthn.cjs';
16
+
17
+ interface EmptyInput$1 {
18
+ }
19
+ /** Wire shape of a fortress user — domain `Date` fields are ISO strings on the wire. */
20
+ interface UserWire {
21
+ id: string;
22
+ email: string;
23
+ name: string;
24
+ isActive: boolean;
25
+ emailVerified?: boolean;
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ }
29
+ /** Wire shape of a pending post-auth challenge. */
30
+ interface AuthChallengeWire {
31
+ reason: PendingReason;
32
+ continuationToken: string;
33
+ }
34
+ /** Wire shape of a successful sign-in. */
35
+ interface AuthSuccessWire {
36
+ status: 'success';
37
+ user: UserWire;
38
+ method: AuthMethod;
39
+ accessToken: string;
40
+ refreshToken: string;
41
+ pluginData?: Record<string, unknown>;
42
+ }
43
+ /** Wire shape of a pending sign-in (2FA, email verification, etc.). */
44
+ interface AuthPendingWire {
45
+ status: 'pending';
46
+ user: UserWire;
47
+ pending: AuthChallengeWire;
48
+ pluginData?: Record<string, unknown>;
49
+ }
50
+ /** Wire shape of an impersonation sign-in (no refresh token). */
51
+ interface AuthImpersonationWire {
52
+ status: 'impersonation';
53
+ user: UserWire;
54
+ accessToken: string;
55
+ refreshToken: null;
56
+ pluginData?: Record<string, unknown>;
57
+ }
58
+ /** Discriminated union of every auth-flow wire outcome. */
59
+ type AuthResultWire = AuthSuccessWire | AuthPendingWire | AuthImpersonationWire;
60
+ /** Wire shape of a refreshed access/refresh token pair. */
61
+ interface AuthTokenPairWire {
62
+ accessToken: string;
63
+ refreshToken: string;
64
+ }
65
+ /** Wire shape of a persisted refresh-token session. */
66
+ interface SessionInfoWire {
67
+ id: string;
68
+ ipAddress?: string | null;
69
+ userAgent?: string | null;
70
+ deviceName?: string | null;
71
+ createdAt: string;
72
+ lastActiveAt?: string | null;
73
+ }
74
+ /** Wire shape of the create-user input body. */
75
+ interface CreateUserInputWire {
76
+ email: string;
77
+ name: string;
78
+ password?: string;
79
+ isActive?: boolean;
80
+ }
81
+ /** Wire shape of a structured error response. */
82
+ interface ErrorResponseWire {
83
+ code: string;
84
+ message: string;
85
+ statusCode: number;
86
+ }
87
+ /** Wire shape of a login identifier. */
88
+ interface LoginIdentifierWire {
89
+ id: string;
90
+ userId: string;
91
+ type: 'email' | 'phone' | 'username';
92
+ value: string;
93
+ }
94
+ /** Empty `{ ok: boolean }` ack. */
95
+ interface OkResponseWire {
96
+ ok: boolean;
97
+ }
98
+ /** Explicit registry type so JSR's fast-check doesn't walk into the deeply-inferred `defineComponents` return. */
99
+ interface AuthComponents {
100
+ readonly components: {
101
+ readonly User: FortressSchema<UserWire>;
102
+ readonly AuthChallenge: FortressSchema<AuthChallengeWire>;
103
+ readonly AuthResult: FortressSchema<AuthResultWire>;
104
+ readonly AuthTokenPair: FortressSchema<AuthTokenPairWire>;
105
+ readonly SessionInfo: FortressSchema<SessionInfoWire>;
106
+ readonly CreateUserInput: FortressSchema<CreateUserInputWire>;
107
+ readonly ErrorResponse: FortressSchema<ErrorResponseWire>;
108
+ readonly LoginIdentifier: FortressSchema<LoginIdentifierWire>;
109
+ };
110
+ readonly ref: <K extends keyof AuthComponents['components']>(name: K) => FortressSchema<AuthComponents['components'][K] extends FortressSchema<infer U> ? U : never>;
111
+ }
112
+ /** Reusable OpenAPI component schemas referenced by the core auth endpoints. */
113
+ declare const authComponentSchemas: AuthComponents['components'];
114
+ /**
115
+ * Typed record of every core auth endpoint. Declared explicitly (not
116
+ * inferred from the builder) so JSR's fast-check passes without
117
+ * `--allow-slow-types`, while `InferEndpointCallInput<typeof authEndpoints.login>`
118
+ * and friends still resolve to the precise per-endpoint shapes.
119
+ */
120
+ interface AuthEndpointsMap {
121
+ login: EndpointDefinition<{
122
+ identifier: string;
123
+ password: string;
124
+ trustedDeviceToken?: string;
125
+ }, EmptyInput$1, EmptyInput$1, {
126
+ 200: AuthResultWire;
127
+ 401: ErrorResponseWire;
128
+ }>;
129
+ verifyTwoFactor: EndpointDefinition<{
130
+ continuationToken: string;
131
+ code: string;
132
+ rememberDevice?: boolean;
133
+ }, EmptyInput$1, EmptyInput$1, {
134
+ 200: AuthResultWire;
135
+ 400: ErrorResponseWire;
136
+ 401: ErrorResponseWire;
137
+ }>;
138
+ verifyMagicLink: EndpointDefinition<{
139
+ token: string;
140
+ }, EmptyInput$1, EmptyInput$1, {
141
+ 200: AuthResultWire;
142
+ 400: ErrorResponseWire;
143
+ 404: ErrorResponseWire;
144
+ }>;
145
+ createUser: EndpointDefinition<CreateUserInputWire, EmptyInput$1, EmptyInput$1, {
146
+ 201: UserWire;
147
+ 409: ErrorResponseWire;
148
+ }>;
149
+ refresh: EndpointDefinition<{
150
+ refreshToken: string;
151
+ }, EmptyInput$1, EmptyInput$1, {
152
+ 200: AuthTokenPairWire;
153
+ 401: ErrorResponseWire;
154
+ }>;
155
+ logout: EndpointDefinition<{
156
+ refreshToken: string;
157
+ }, EmptyInput$1, EmptyInput$1, {
158
+ 200: OkResponseWire;
159
+ }>;
160
+ me: EndpointDefinition<EmptyInput$1, EmptyInput$1, EmptyInput$1, {
161
+ 200: UserWire;
162
+ 401: ErrorResponseWire;
163
+ }>;
164
+ listSessions: EndpointDefinition<EmptyInput$1, EmptyInput$1, EmptyInput$1, {
165
+ 200: SessionInfoWire[];
166
+ 401: ErrorResponseWire;
167
+ }>;
168
+ revokeSession: EndpointDefinition<EmptyInput$1, EmptyInput$1, {
169
+ id: string;
170
+ }, {
171
+ 200: OkResponseWire;
172
+ 401: ErrorResponseWire;
173
+ }>;
174
+ revokeAllOtherSessions: EndpointDefinition<{
175
+ currentTokenId: string;
176
+ }, EmptyInput$1, EmptyInput$1, {
177
+ 200: OkResponseWire;
178
+ 401: ErrorResponseWire;
179
+ }>;
180
+ addLoginIdentifier: EndpointDefinition<{
181
+ type: 'email' | 'phone' | 'username';
182
+ value: string;
183
+ }, EmptyInput$1, EmptyInput$1, {
184
+ 200: OkResponseWire;
185
+ 401: ErrorResponseWire;
186
+ }>;
187
+ removeLoginIdentifier: EndpointDefinition<{
188
+ type: 'email' | 'phone' | 'username';
189
+ value: string;
190
+ }, EmptyInput$1, EmptyInput$1, {
191
+ 200: OkResponseWire;
192
+ 401: ErrorResponseWire;
193
+ }>;
194
+ getLoginIdentifiers: EndpointDefinition<EmptyInput$1, EmptyInput$1, EmptyInput$1, {
195
+ 200: LoginIdentifierWire[];
196
+ 401: ErrorResponseWire;
197
+ }>;
198
+ impersonate: EndpointDefinition<{
199
+ targetUserId: string;
200
+ reason?: string;
201
+ expirySeconds?: number;
202
+ }, EmptyInput$1, EmptyInput$1, {
203
+ 200: AuthResultWire;
204
+ 401: ErrorResponseWire;
205
+ 404: ErrorResponseWire;
206
+ }>;
207
+ }
208
+ /**
209
+ * Declarative endpoint definitions for fortress's built-in auth routes
210
+ * (sign in, refresh, sessions, impersonation).
211
+ *
212
+ * The explicit `AuthEndpointsMap` annotation is what keeps JSR fast-check
213
+ * happy — each entry's `EndpointDefinition<TBody, TQuery, TParams, TResponses>`
214
+ * generics are stated declaratively, not inferred from the builder chain.
215
+ * `fortress.call.*` type inference still resolves because `typeof
216
+ * authEndpoints.login` picks up the exact generics declared on the map.
217
+ */
218
+ declare const authEndpoints: AuthEndpointsMap;
219
+
220
+ /**
221
+ * Cookie serialization for fortress auth tokens.
222
+ *
223
+ * Produces and parses cookie strings for the access/refresh token pair using
224
+ * the resolved {@link ResolvedCookieConfig} (which already accounts for
225
+ * `__Host-` prefix rules and dev-vs-prod relaxation).
226
+ *
227
+ * Returns raw `Set-Cookie` header values so any framework adapter can append
228
+ * them to a `Response` directly without depending on a framework cookie API.
229
+ */
230
+
231
+ /** Result of an auth flow that may set cookies on a Response. */
232
+ interface AuthCookiePayload {
233
+ accessToken: string;
234
+ refreshToken?: string | null;
235
+ }
236
+
237
+ /**
238
+ * Shared principal resolution for `fortress.handleRequest` and user-route
239
+ * adapters (Hono / Express / SvelteKit).
240
+ *
241
+ * Plugins that register a `resolvePrincipal` capability (e.g. `api-key`) are
242
+ * tried in registration order; the first non-null result wins. If no plugin
243
+ * resolves the request, a JWT bearer token is attempted as a fallback.
244
+ *
245
+ * Two variants are exported:
246
+ *
247
+ * - {@link tryPluginPrincipal} — only walks the plugin chain. Used by
248
+ * `handle-request.ts`, which needs to decide whether to enforce the JWT
249
+ * fallback based on the endpoint's `security` metadata.
250
+ * - {@link resolveRequestPrincipal} — plugin chain + non-throwing JWT
251
+ * fallback. Used by adapter user-route middleware so that API keys and
252
+ * cookies/bearer tokens authenticate uniformly on *any* route, not just
253
+ * Fortress-owned routes.
254
+ */
255
+
256
+ /** Result of a successful principal resolution. */
257
+ interface ResolvedPrincipal {
258
+ subject: Subject;
259
+ claims?: TokenClaims;
260
+ /** Credential-level narrowing scopes (e.g. API-key scopes). null/undefined = unscoped. */
261
+ scopes?: string[] | null;
262
+ }
263
+
264
+ /**
265
+ * Manifest-driven permission seeding.
266
+ *
267
+ * `endpoint().permission(resource, action)` declares the permission an
268
+ * endpoint needs, but a freshly migrated database has no `Permission` row
269
+ * for it. Every consumer used to write the same seed script: walk
270
+ * `fortress.endpoints`, dedupe `(resource, action)` pairs, call
271
+ * `iam.createPermission(...)` for each, optionally bind defaults onto a
272
+ * couple of well-known roles.
273
+ *
274
+ * This module replaces that script. It's idempotent (re-runs safely on a
275
+ * partially seeded DB) and exposed on the {@link Fortress} instance as
276
+ * `fortress.syncPermissionsFromManifest()`.
277
+ */
278
+
279
+ /** Options accepted by {@link runPermissionSync}. */
280
+ interface PermissionSyncOptions {
281
+ /**
282
+ * Endpoints to scan for `meta.permission` declarations. Defaults to the
283
+ * full set registered on the Fortress instance when called via
284
+ * {@link import('../fortress').Fortress.syncPermissionsFromManifest}.
285
+ */
286
+ endpoints?: EndpointDefinition[];
287
+ /**
288
+ * Optional role-name → permissions map. For each role:
289
+ *
290
+ * - `'*'` binds every permission discovered in `endpoints` to the role.
291
+ * - `['resource:action', ...]` binds only the named permissions (one
292
+ * string per `(resource, action)` pair, colon-separated).
293
+ *
294
+ * Roles are created on demand; existing roles get any missing
295
+ * permissions added. Permissions on a role that aren't requested here
296
+ * are left in place \u2014 this only grants, never revokes.
297
+ *
298
+ * ```ts
299
+ * await fortress.syncPermissionsFromManifest({\n * defaultRoles: {\n * admin: '*',\n * member: ['school:read', 'school:list'],\n * },\n * });\n * ```
300
+ */
301
+ defaultRoles?: Record<string, '*' | readonly string[]>;
302
+ }
303
+ /** Result returned by {@link runPermissionSync}. */
304
+ interface PermissionSyncResult {
305
+ /** Number of unique `(resource, action)` pairs discovered. */
306
+ discovered: number;
307
+ /**
308
+ * Number of permissions that already existed in the database before
309
+ * the sync started. (The adapter's `findOrCreatePermission` doesn't
310
+ * distinguish, so this is computed by counting pre-existing
311
+ * permissions; new inserts = `discovered - existing`.)
312
+ */
313
+ existing: number;
314
+ /** Number of new permission rows inserted by this sync run. */
315
+ created: number;
316
+ /**
317
+ * Roles touched by `defaultRoles`, keyed by role name. `bound` is the
318
+ * number of permission bindings newly added during this sync run.
319
+ * Already-bound permissions do not double-count.
320
+ */
321
+ roles: Record<string, {
322
+ created: boolean;
323
+ bound: number;
324
+ }>;
325
+ }
326
+ /**
327
+ * Seed permissions from a set of endpoints and (optionally) bind them onto
328
+ * default roles. Safe to call repeatedly. See {@link PermissionSyncOptions}
329
+ * for shape.
330
+ */
331
+ declare function runPermissionSync(iam: IamService, endpoints: EndpointDefinition[], opts?: PermissionSyncOptions): Promise<PermissionSyncResult>;
332
+
333
+ type RouteClassification = 'public' | 'authenticated' | 'rbac' | 'oauth-protocol' | 'default-deny';
334
+ interface RouteManifestEntry {
335
+ method: HttpMethod;
336
+ path: string;
337
+ handler: string;
338
+ plugin: string | null;
339
+ classification: RouteClassification;
340
+ permission?: EndpointPermission;
341
+ security: SecurityRequirement[];
342
+ bearerKind?: 'jwt' | 'oauth';
343
+ csrfApplicable: boolean;
344
+ rateLimited: boolean;
345
+ mounted: boolean;
346
+ }
347
+ declare function buildRouteManifest(fortress: Pick<Fortress, 'endpoints' | 'config'>): RouteManifestEntry[];
348
+
349
+ type MigrationDialect = 'sqlite' | 'pg';
350
+ interface FortressMigration {
351
+ version: number;
352
+ name: string;
353
+ dialect: MigrationDialect;
354
+ up: string;
355
+ down: string;
356
+ /** SQL used only when provisioning an empty database from concatenated DDL. */
357
+ freshUp?: string;
358
+ /** Stable identity included in the migration checksum for a JS data step. */
359
+ dataStep?: string;
360
+ /** Runs immediately before `up` while the migration lock/transaction is held. */
361
+ beforeUp?: (db: DatabaseAdapter) => Promise<void>;
362
+ }
363
+ declare const fortressMigrations: Record<MigrationDialect, FortressMigration[]>;
364
+ declare function getFortressMigrations(dialect: MigrationDialect): FortressMigration[];
365
+ declare function getLatestMigrationVersion(dialect: MigrationDialect): number;
366
+ /**
367
+ * Concatenated forward SQL for every bundled migration of a dialect, in
368
+ * version order. `src/testing/index.ts` provisions its in-memory schema
369
+ * from this so the test adapter and production migrations can never drift.
370
+ */
371
+ declare function getMigrationUpSql(dialect: MigrationDialect): string;
372
+ /**
373
+ * Canonical list of every Fortress-owned table. Used by
374
+ * {@link detectMigrationDrift} to surface live-DB drift beyond just the
375
+ * `fortress_schema_version` checkpoint — any of these tables missing in
376
+ * the target database signals an incomplete or stale migration state.
377
+ *
378
+ * Keep in sync with `src/drizzle/{schema,pg/schema}.ts` and the bundled
379
+ * migrations. The list is asserted by `src/core/migrations/engine.test.ts`
380
+ * against the test adapter so an accidental drop/add is caught at test time.
381
+ */
382
+ declare const FORTRESS_TABLES: readonly string[];
383
+ /**
384
+ * Parse the expected column set of every Fortress table directly out of the
385
+ * bundled migration DDL. Because the migrations are the SQL-first source of
386
+ * truth, this needs no schema description maintained on the side and no
387
+ * Drizzle-specific tooling — it works for any adapter. Powers the
388
+ * column-level half of {@link detectMigrationDrift}.
389
+ *
390
+ * The parser is intentionally narrow: it understands the controlled DDL
391
+ * Fortress emits (`CREATE TABLE [IF NOT EXISTS] name ( ... );` with
392
+ * comma-separated definitions, plus the controlled `ALTER TABLE` add-column
393
+ * and rename forms used by incremental migrations). Constraint-only lines
394
+ * (PRIMARY KEY (...), UNIQUE (...), etc.) and
395
+ * standalone CREATE INDEX statements are skipped.
396
+ */
397
+ declare function getExpectedColumns(dialect: MigrationDialect): Record<string, string[]>;
398
+
399
+ interface MigrationStatus {
400
+ dialect: MigrationDialect;
401
+ currentVersion: number;
402
+ latestVersion: number;
403
+ pending: FortressMigration[];
404
+ applied: FortressMigration[];
405
+ upToDate: boolean;
406
+ hasVersionTable: boolean;
407
+ }
408
+ interface MigrationApplyResult {
409
+ dialect: MigrationDialect;
410
+ fromVersion: number;
411
+ toVersion: number;
412
+ applied: FortressMigration[];
413
+ }
414
+ interface MigrationDownResult {
415
+ dialect: MigrationDialect;
416
+ fromVersion: number;
417
+ toVersion: number;
418
+ rolledBack: FortressMigration[];
419
+ }
420
+ interface MigrationDrift {
421
+ dialect: MigrationDialect;
422
+ currentVersion: number;
423
+ latestVersion: number;
424
+ missingVersionTable: boolean;
425
+ unknownFutureVersion: boolean;
426
+ pendingVersions: number[];
427
+ /**
428
+ * Fortress-owned tables expected by the runtime but missing from the
429
+ * live database. A non-empty list almost always means an upgrade was
430
+ * skipped or the database was provisioned from an out-of-date schema
431
+ * dump. Compared against {@link FORTRESS_TABLES}.
432
+ */
433
+ missingTables: string[];
434
+ /**
435
+ * Per-table columns that the bundled migration DDL defines but the live
436
+ * database is missing. Surfaces a partially-applied or hand-patched
437
+ * schema where the table exists but is missing a column added by a later
438
+ * migration. Expected columns are parsed from the migration SQL itself
439
+ * (see `getExpectedColumns`), so this works for any adapter. Only tables
440
+ * that are present in the live DB are inspected — fully missing tables are
441
+ * reported via {@link missingTables} instead.
442
+ */
443
+ missingColumns: {
444
+ table: string;
445
+ columns: string[];
446
+ }[];
447
+ /** Required hot-path indexes absent from the live database. */
448
+ missingIndexes: string[];
449
+ }
450
+ declare function getMigrationStatus(db: DatabaseAdapter, dialect?: MigrationDialect): Promise<MigrationStatus>;
451
+ declare function migrateUp(db: DatabaseAdapter, dialect?: MigrationDialect, targetVersion?: number): Promise<MigrationApplyResult>;
452
+ declare function migrateDown(db: DatabaseAdapter, dialect?: MigrationDialect, targetVersion?: number): Promise<MigrationDownResult>;
453
+ declare function detectMigrationDrift(db: DatabaseAdapter, dialect?: MigrationDialect): Promise<MigrationDrift>;
454
+ declare function hasMigrationDrift(drift: MigrationDrift): boolean;
455
+
456
+ /** Options accepted by {@link toOpenAPI}. */
457
+ interface ToOpenAPIOptions extends Partial<SpecBuilderOptions> {
458
+ /** Additional reusable schemas to place under `components.schemas`. */
459
+ schemas?: ComponentSchemas;
460
+ }
461
+ /**
462
+ * Emit an OpenAPI 3.1 spec from a set of Fortress endpoint definitions.
463
+ *
464
+ * This is the env/DB-free helper for build scripts and codegen pipelines.
465
+ * If you already have a configured Fortress instance, prefer
466
+ * `fortress.toOpenAPI()` so the endpoint list defaults to everything that
467
+ * instance knows about.
468
+ *
469
+ * ```ts
470
+ * import { toOpenAPI } from '@bajustone/fortress';
471
+ * import { appEndpointList } from './routes/v1/endpoints';
472
+ *
473
+ * export const OPENAPI_SPEC = toOpenAPI(appEndpointList, {
474
+ * title: 'My API',
475
+ * version: '0.0.0',
476
+ * servers: [{ url: 'http://localhost:3001' }],
477
+ * tags: [{ name: 'Schools' }],
478
+ * });
479
+ * ```
480
+ *
481
+ * Defaults to endpoint `handler` values for `operationId`, matching host
482
+ * route-contract names. Pass `operationId: 'methodPath'` for Fortress's
483
+ * historical generated IDs.
484
+ */
485
+ declare function toOpenAPI(endpoints: readonly EndpointDefinition[], opts?: ToOpenAPIOptions): OpenAPISpec;
486
+
487
+ /**
488
+ * Typed in-process client for fortress endpoints.
489
+ *
490
+ * `buildCall` takes a flat map of `EndpointDefinition`s (keyed by handler
491
+ * name) and returns an object with one callable per entry. Each callable:
492
+ *
493
+ * 1. Splits the flat input object into `body`, `query`, and `params` based
494
+ * on the endpoint's declared schemas.
495
+ * 2. Substitutes `:param` placeholders in the path.
496
+ * 3. Serializes the query string.
497
+ * 4. Builds a web-standard `Request` with a JSON body (when applicable).
498
+ * 5. Delegates to `fortress.handleRequest`, exercising the full pipeline
499
+ * (plugin middleware → token verification → RBAC → validation →
500
+ * dispatch → cookie attachment).
501
+ * 6. Parses the JSON response body. On non-2xx, throws a structured
502
+ * `FortressError` reconstructed via `Errors.fromHttpResponse`.
503
+ *
504
+ * This is the foundation of the typed client SDK: the same code works
505
+ * in-process today and will work over the network tomorrow by swapping
506
+ * `handleRequest` for `fetch`. All of the type machinery lives on the
507
+ * `EndpointDefinition` generic parameters and the `InferEndpoint*` helpers
508
+ * in `src/core/endpoint.ts`.
509
+ *
510
+ * **Authentication.** Protected endpoints expect a bearer token. Callers
511
+ * pass it via the optional second argument: `call.me({}, { headers:
512
+ * { authorization: 'Bearer …' } })`. The in-process client does not share
513
+ * state with any active session; it is purely a typed wire formatter.
514
+ *
515
+ * **Runs the full pipeline.** Because each call lands in
516
+ * `fortress.handleRequest`, the following all fire: plugin middleware (incl.
517
+ * rate limits), principal resolution, RBAC, JSON Schema / Standard Schema
518
+ * validation, auth observers, IAM observers, OpenTelemetry spans, and any
519
+ * `wrapAdapter` hooks. This is intentional — it's the same code path a
520
+ * network client would hit, so tests that exercise `fortress.call.*` give
521
+ * the same behavioral guarantees as production traffic.
522
+ *
523
+ * **Bypassing hooks in tests.** If a test fixture needs to create users or
524
+ * log in *without* tripping rate limits, emitting audit entries, or running
525
+ * observers, call the service layer directly — `fortress.auth.createUser`,
526
+ * `fortress.auth.login`, `fortress.iam.createRole` — instead of the typed
527
+ * call surface. The service layer still validates inputs but skips the
528
+ * middleware chain.
529
+ */
530
+
531
+ /** Optional per-call options. */
532
+ interface CallOptions {
533
+ /** Extra headers to attach to the synthesized request (e.g. bearer auth). */
534
+ headers?: Record<string, string>;
535
+ }
536
+ /**
537
+ * Build an object of typed callables from a keyed {@link EndpointDefinition}
538
+ * map. Each callable invokes `fortress.handleRequest` with a synthesized
539
+ * `Request` and returns the parsed JSON body on success.
540
+ *
541
+ * The returned type is intentionally loose (`Record<string, ...>`). The
542
+ * strong typing happens at the call site via the `TypedCall` helper in
543
+ * `src/core/fortress.ts`, which layers a mapped type over the runtime
544
+ * callable map to expose per-handler inferred I/O.
545
+ */
546
+ declare function buildCall(fortress: Fortress, endpoints: Record<string, EndpointDefinition>): Record<string, (input?: Record<string, unknown>, options?: CallOptions) => Promise<unknown>>;
547
+
548
+ /**
549
+ * Type-level map of every built-in plugin name to its method-surface
550
+ * interface. {@link InferPlugins} uses this to expose typed plugin methods
551
+ * on the fortress instance.
552
+ */
553
+ interface PluginMethodsMap {
554
+ 'api-key': ApiKeyMethods;
555
+ 'audit-log': AuditLogMethods;
556
+ 'data-isolation': DataIsolationMethods;
557
+ 'email-verification': EmailVerificationMethods;
558
+ 'magic-link': MagicLinkMethods;
559
+ 'oauth': OAuthMethods;
560
+ 'openapi': OpenAPIMethods;
561
+ 'social-login': SocialLoginMethods;
562
+ 'tenancy': TenancyMethods;
563
+ 'two-factor': TwoFactorMethods;
564
+ 'webauthn': WebAuthnMethods;
565
+ }
566
+ /** Infer the typed plugin-methods record from a `plugins` tuple passed to {@link createFortress}. */
567
+ type InferPlugins<T extends readonly FortressPlugin[]> = {
568
+ [P in T[number] as P['name']]: P['name'] extends keyof PluginMethodsMap ? PluginMethodsMap[P['name']] : Record<string, (...args: any[]) => any>;
569
+ };
570
+ /** Distributes a union into an intersection — the classic TS trick. Used by {@link InferPluginCallMap}. */
571
+ type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
572
+ /**
573
+ * Turn a record of {@link EndpointDefinition}s into a record of typed
574
+ * callables: each key becomes a function whose input is the endpoint's
575
+ * inferred body+query+params intersection and whose output is the inferred
576
+ * success-response body.
577
+ */
578
+ type CallableForEndpoints<E> = E extends Record<string, EndpointDefinition<any, any, any, any>> ? {
579
+ [K in keyof E]: (input: InferEndpointCallInput<E[K]>, options?: CallOptions) => Promise<InferEndpointSuccessResponse<E[K]>>;
580
+ } : Record<string, never>;
581
+ /**
582
+ * Infer the typed call surface contributed by a plugins tuple. Walks every
583
+ * plugin's `routes` record (if present) and unions the callables into one
584
+ * flat object keyed by handler name.
585
+ */
586
+ type InferPluginCallMap<T extends readonly FortressPlugin[]> = UnionToIntersection<T[number] extends infer P ? P extends {
587
+ routes?: infer R;
588
+ } ? R extends Record<string, EndpointDefinition<any, any, any, any>> ? CallableForEndpoints<R> : Record<string, never> : Record<string, never> : Record<string, never>>;
589
+
590
+ interface EmptyInput {
591
+ }
592
+ /** Wire shape of a persisted role. `description` and `isSystem` are optional nullable on the wire. */
593
+ interface RoleWire {
594
+ id: string;
595
+ name: string;
596
+ description?: string | null;
597
+ isSystem?: boolean;
598
+ }
599
+ /** Wire shape of a persisted group. */
600
+ interface GroupWire {
601
+ id: string;
602
+ name: string;
603
+ description?: string | null;
604
+ }
605
+ /** Wire shape of a permission condition. `operator` is restricted to the supported set. */
606
+ interface PermissionConditionWire {
607
+ field: string;
608
+ operator: 'eq' | 'neq' | 'in' | 'startsWith';
609
+ value: string;
610
+ }
611
+ /** Wire shape of a persisted permission. */
612
+ interface PermissionWire {
613
+ id: string;
614
+ resource: string;
615
+ action: string;
616
+ effect: 'ALLOW' | 'DENY';
617
+ conditions?: PermissionConditionWire[];
618
+ description?: string | null;
619
+ }
620
+ /** Wire shape of a permission-creation input. */
621
+ interface PermissionInputWire {
622
+ resource: string;
623
+ action: string;
624
+ effect?: 'ALLOW' | 'DENY';
625
+ conditions?: PermissionConditionWire[];
626
+ }
627
+ /** Wire shape of a persisted service account. Date fields are ISO strings on the wire. */
628
+ interface ServiceAccountWire {
629
+ id: string;
630
+ name: string;
631
+ displayName?: string | null;
632
+ description?: string | null;
633
+ isActive: boolean;
634
+ createdAt?: string;
635
+ updatedAt?: string;
636
+ }
637
+ /** Explicit registry type so JSR's fast-check doesn't walk into the deeply-inferred `defineComponents` return. */
638
+ interface IamComponents {
639
+ readonly components: {
640
+ readonly Role: FortressSchema<RoleWire>;
641
+ readonly Group: FortressSchema<GroupWire>;
642
+ readonly Permission: FortressSchema<PermissionWire>;
643
+ readonly PermissionInput: FortressSchema<PermissionInputWire>;
644
+ readonly ServiceAccount: FortressSchema<ServiceAccountWire>;
645
+ };
646
+ readonly ref: <K extends keyof IamComponents['components']>(name: K) => FortressSchema<IamComponents['components'][K] extends FortressSchema<infer U> ? U : never>;
647
+ }
648
+ /** Reusable OpenAPI component schemas referenced by the core IAM endpoints. */
649
+ declare const iamComponentSchemas: IamComponents['components'];
650
+ /** Resource catalog response shape. */
651
+ interface ResourceCatalogWire {
652
+ resources: Record<string, {
653
+ actions: string[];
654
+ description?: string;
655
+ }>;
656
+ }
657
+ /** Paged service-account list response shape. */
658
+ interface ServiceAccountsListWire {
659
+ serviceAccounts: ServiceAccountWire[];
660
+ total: number;
661
+ }
662
+ /**
663
+ * Typed record of every core IAM endpoint. Declared explicitly so JSR's
664
+ * fast-check passes without `--allow-slow-types`, while
665
+ * `InferEndpointCallInput<typeof iamEndpoints.X>` still resolves per-handler.
666
+ */
667
+ interface IamEndpointsMap {
668
+ getResources: EndpointDefinition<EmptyInput, EmptyInput, EmptyInput, {
669
+ 200: ResourceCatalogWire;
670
+ 401: ErrorResponseWire;
671
+ }>;
672
+ getRoles: EndpointDefinition<EmptyInput, EmptyInput, EmptyInput, {
673
+ 200: RoleWire[];
674
+ 401: ErrorResponseWire;
675
+ }>;
676
+ createRole: EndpointDefinition<{
677
+ name: string;
678
+ permissions: PermissionInputWire[];
679
+ description?: string;
680
+ }, EmptyInput, EmptyInput, {
681
+ 201: RoleWire;
682
+ 401: ErrorResponseWire;
683
+ }>;
684
+ deleteRole: EndpointDefinition<EmptyInput, EmptyInput, {
685
+ id: string;
686
+ }, {
687
+ 200: OkResponseWire;
688
+ 400: ErrorResponseWire;
689
+ 401: ErrorResponseWire;
690
+ }>;
691
+ bindRoleToUser: EndpointDefinition<{
692
+ userId: string;
693
+ tenantId?: string;
694
+ }, EmptyInput, {
695
+ id: string;
696
+ }, {
697
+ 200: OkResponseWire;
698
+ 401: ErrorResponseWire;
699
+ }>;
700
+ bindRoleToGroup: EndpointDefinition<{
701
+ groupId: string;
702
+ tenantId?: string;
703
+ }, EmptyInput, {
704
+ id: string;
705
+ }, {
706
+ 200: OkResponseWire;
707
+ 401: ErrorResponseWire;
708
+ }>;
709
+ unbindRole: EndpointDefinition<{
710
+ subjectType: 'USER' | 'GROUP' | 'SERVICE_ACCOUNT';
711
+ subjectId: string;
712
+ tenantId?: string;
713
+ }, EmptyInput, {
714
+ id: string;
715
+ }, {
716
+ 200: OkResponseWire;
717
+ 401: ErrorResponseWire;
718
+ }>;
719
+ createGroup: EndpointDefinition<{
720
+ name: string;
721
+ description?: string;
722
+ }, EmptyInput, EmptyInput, {
723
+ 201: GroupWire;
724
+ 401: ErrorResponseWire;
725
+ }>;
726
+ addUserToGroup: EndpointDefinition<{
727
+ userId: string;
728
+ }, EmptyInput, {
729
+ id: string;
730
+ }, {
731
+ 200: OkResponseWire;
732
+ 401: ErrorResponseWire;
733
+ }>;
734
+ removeUserFromGroup: EndpointDefinition<EmptyInput, EmptyInput, {
735
+ id: string;
736
+ userId: string;
737
+ }, {
738
+ 200: OkResponseWire;
739
+ 401: ErrorResponseWire;
740
+ }>;
741
+ getUserPermissions: EndpointDefinition<EmptyInput, {
742
+ tenantId?: string;
743
+ }, {
744
+ id: string;
745
+ }, {
746
+ 200: PermissionWire[];
747
+ 401: ErrorResponseWire;
748
+ }>;
749
+ checkPermission: EndpointDefinition<{
750
+ userId: string;
751
+ resource: string;
752
+ action: string;
753
+ context?: Record<string, unknown>;
754
+ }, EmptyInput, EmptyInput, {
755
+ 200: {
756
+ allowed: boolean;
757
+ };
758
+ 401: ErrorResponseWire;
759
+ }>;
760
+ bindPermissionToUser: EndpointDefinition<{
761
+ userId: string;
762
+ permission: PermissionInputWire;
763
+ tenantId?: string;
764
+ }, EmptyInput, EmptyInput, {
765
+ 200: OkResponseWire;
766
+ 401: ErrorResponseWire;
767
+ }>;
768
+ bindPermissionToGroup: EndpointDefinition<{
769
+ groupId: string;
770
+ permission: PermissionInputWire;
771
+ tenantId?: string;
772
+ }, EmptyInput, EmptyInput, {
773
+ 200: OkResponseWire;
774
+ 401: ErrorResponseWire;
775
+ }>;
776
+ unbindPermissionFromUser: EndpointDefinition<{
777
+ userId: string;
778
+ permissionId: string;
779
+ tenantId?: string;
780
+ }, EmptyInput, EmptyInput, {
781
+ 200: OkResponseWire;
782
+ 401: ErrorResponseWire;
783
+ }>;
784
+ unbindPermissionFromGroup: EndpointDefinition<{
785
+ groupId: string;
786
+ permissionId: string;
787
+ tenantId?: string;
788
+ }, EmptyInput, EmptyInput, {
789
+ 200: OkResponseWire;
790
+ 401: ErrorResponseWire;
791
+ }>;
792
+ createServiceAccount: EndpointDefinition<{
793
+ name: string;
794
+ displayName?: string;
795
+ description?: string;
796
+ }, EmptyInput, EmptyInput, {
797
+ 201: ServiceAccountWire;
798
+ 400: ErrorResponseWire;
799
+ 401: ErrorResponseWire;
800
+ }>;
801
+ listServiceAccounts: EndpointDefinition<EmptyInput, {
802
+ limit?: number;
803
+ offset?: number;
804
+ }, EmptyInput, {
805
+ 200: ServiceAccountsListWire;
806
+ 401: ErrorResponseWire;
807
+ }>;
808
+ getServiceAccount: EndpointDefinition<EmptyInput, EmptyInput, {
809
+ id: string;
810
+ }, {
811
+ 200: ServiceAccountWire;
812
+ 401: ErrorResponseWire;
813
+ 404: ErrorResponseWire;
814
+ }>;
815
+ updateServiceAccount: EndpointDefinition<{
816
+ displayName?: string | null;
817
+ description?: string | null;
818
+ isActive?: boolean;
819
+ }, EmptyInput, {
820
+ id: string;
821
+ }, {
822
+ 200: ServiceAccountWire;
823
+ 401: ErrorResponseWire;
824
+ 404: ErrorResponseWire;
825
+ }>;
826
+ deleteServiceAccount: EndpointDefinition<EmptyInput, EmptyInput, {
827
+ id: string;
828
+ }, {
829
+ 200: OkResponseWire;
830
+ 401: ErrorResponseWire;
831
+ 404: ErrorResponseWire;
832
+ }>;
833
+ getServiceAccountPermissions: EndpointDefinition<EmptyInput, {
834
+ tenantId?: string;
835
+ }, {
836
+ id: string;
837
+ }, {
838
+ 200: PermissionWire[];
839
+ 401: ErrorResponseWire;
840
+ }>;
841
+ bindRoleToServiceAccount: EndpointDefinition<{
842
+ serviceAccountId: string;
843
+ tenantId?: string;
844
+ }, EmptyInput, {
845
+ id: string;
846
+ }, {
847
+ 200: OkResponseWire;
848
+ 401: ErrorResponseWire;
849
+ }>;
850
+ unbindRoleFromServiceAccount: EndpointDefinition<{
851
+ serviceAccountId: string;
852
+ tenantId?: string;
853
+ }, EmptyInput, {
854
+ id: string;
855
+ }, {
856
+ 200: OkResponseWire;
857
+ 401: ErrorResponseWire;
858
+ }>;
859
+ bindPermissionToServiceAccount: EndpointDefinition<{
860
+ serviceAccountId: string;
861
+ permission: PermissionInputWire;
862
+ tenantId?: string;
863
+ }, EmptyInput, EmptyInput, {
864
+ 200: OkResponseWire;
865
+ 401: ErrorResponseWire;
866
+ }>;
867
+ unbindPermissionFromServiceAccount: EndpointDefinition<{
868
+ serviceAccountId: string;
869
+ permissionId: string;
870
+ tenantId?: string;
871
+ }, EmptyInput, EmptyInput, {
872
+ 200: OkResponseWire;
873
+ 401: ErrorResponseWire;
874
+ }>;
875
+ }
876
+ /**
877
+ * Declarative endpoint definitions for fortress's built-in IAM admin routes.
878
+ * The explicit `IamEndpointsMap` annotation keeps JSR fast-check happy
879
+ * without sacrificing per-handler inference for `fortress.call.*`.
880
+ */
881
+ declare const iamEndpoints: IamEndpointsMap;
882
+
883
+ /**
884
+ * Typed in-process call surface. Composes auth + IAM endpoint callables
885
+ * with any plugin-contributed routes (derived from the plugins tuple).
886
+ *
887
+ * Each handler becomes a `(input, options?) => Promise<successBody>` where
888
+ * the input shape is the inferred intersection of the endpoint's body,
889
+ * query, and params schemas, and the output is the inferred 2xx response
890
+ * type. Non-2xx responses throw a `FortressError`.
891
+ */
892
+ type TypedCall<T extends readonly FortressPlugin[]> = CallableForEndpoints<typeof authEndpoints> & CallableForEndpoints<typeof iamEndpoints> & InferPluginCallMap<T>;
893
+ /**
894
+ * Configured fortress instance returned by {@link createFortress}. Holds the
895
+ * core auth and IAM services, the resolved config, every endpoint definition
896
+ * (auth + IAM + plugin routes), and the typed plugin method surface.
897
+ *
898
+ * Also exposes the framework-agnostic HTTP entry points
899
+ * ({@link Fortress.handleRequest}, {@link Fortress.runPluginMiddleware},
900
+ * {@link Fortress.extractAccessToken}, {@link Fortress.serializeAuthCookies})
901
+ * that adapters delegate to. See `src/core/http/`.
902
+ */
903
+ interface Fortress<TPlugins = Record<string, Record<string, Function>>, TCall = Record<string, (input?: any, options?: any) => Promise<any>>> {
904
+ auth: AuthService;
905
+ iam: IamService;
906
+ plugins: TPlugins;
907
+ /**
908
+ * Typed in-process client. Each key is a handler name (from the core
909
+ * auth/IAM endpoint records or a plugin's `routes` record); each value is
910
+ * an async function whose input/output types are inferred from the
911
+ * endpoint's declared body/query/params/response schemas.
912
+ *
913
+ * Under the hood, each callable serializes its input to a `Request` and
914
+ * delegates to `fortress.handleRequest`, so middleware, token
915
+ * verification, RBAC, and validation all run — the same path a network
916
+ * client would eventually hit. See `src/core/http/call.ts`.
917
+ */
918
+ call: TCall;
919
+ config: Readonly<FortressConfig>;
920
+ /** All endpoint definitions (auth + IAM + plugins) with JSON Schema metadata. */
921
+ endpoints: EndpointDefinition[];
922
+ /** Canonical generated route-security manifest derived from endpoint metadata. */
923
+ manifest: RouteManifestEntry[];
924
+ /** Resolved auth-cookie names and attributes (NODE_ENV-aware). */
925
+ cookies: ResolvedCookieConfig;
926
+ /** Resolved logger (defaults to a silent no-op when `config.logger` is unset). */
927
+ logger: FortressLogger;
928
+ /** Resolved telemetry provider (defaults to a no-op when `config.observability` is unset). */
929
+ telemetry: TelemetryProvider;
930
+ /**
931
+ * Handle a Fortress-managed request and return a web-standard `Response`.
932
+ * Composes plugin middleware, token verification, default-deny RBAC,
933
+ * validation, and dispatch.
934
+ *
935
+ * Adapters call this for paths owned by Fortress (e.g. `/auth/*`,
936
+ * `/iam/*`, plugin-registered routes). See `src/core/http/handle-request.ts`.
937
+ */
938
+ handleRequest: (request: Request) => Promise<Response>;
939
+ /**
940
+ * Run plugin middleware at a given lifecycle phase, passing a duck-typed
941
+ * request context. Adapters call this on user-owned routes so plugins
942
+ * like rate-limit and audit-log still apply outside Fortress paths.
943
+ */
944
+ runPluginMiddleware: (phase: MiddlewareDefinition['position'], ctx: PluginRequestContext) => Promise<void>;
945
+ /**
946
+ * Extract the access token from a request, preferring the configured
947
+ * cookie and falling back to `Authorization: Bearer`.
948
+ */
949
+ extractAccessToken: (request: Request) => string | null;
950
+ /**
951
+ * Resolve the request principal by trying plugin `resolvePrincipal`
952
+ * hooks (e.g. `api-key`) first, then falling back to the configured JWT
953
+ * bearer token. Non-throwing — returns `null` when no credential is
954
+ * present or the JWT fails to verify.
955
+ *
956
+ * Adapter user-route middleware calls this so api-keys, cookies, and
957
+ * bearer tokens authenticate uniformly on user-owned routes — not just
958
+ * Fortress-owned routes dispatched through `handleRequest`.
959
+ */
960
+ resolvePrincipal: (request: Request) => Promise<ResolvedPrincipal | null>;
961
+ /**
962
+ * Serialize an auth result (or pair of tokens) into one or two
963
+ * `Set-Cookie` header values using the resolved cookie config and the
964
+ * configured token expiries.
965
+ */
966
+ serializeAuthCookies: (payload: AuthCookiePayload) => string[];
967
+ /**
968
+ * Run Fortress's pending schema migrations against the configured database
969
+ * and, optionally, an application-supplied migration step afterwards.
970
+ *
971
+ * Fortress migrations always run first because app schemas commonly
972
+ * reference fortress tables (foreign keys to `user.id`, etc.). The
973
+ * `migrateApp` callback (when provided) is awaited after Fortress
974
+ * migrations complete, so a host can do something like:
975
+ *
976
+ * ```ts
977
+ * await fortress.migrate({
978
+ * migrateApp: () => migrate(db, { migrationsFolder: './drizzle' }),
979
+ * });
980
+ * ```
981
+ *
982
+ * Eliminates the two-step "forget to call `migrateUp` and silently
983
+ * have no auth tables" footgun.
984
+ */
985
+ migrate: (opts?: MigrateOptions) => Promise<MigrateResult>;
986
+ /**
987
+ * Seed permissions discovered on registered endpoints (`fortress.endpoints`)
988
+ * into the IAM database and, optionally, bind them onto a set of default
989
+ * roles. Idempotent — re-running adds only what's missing and never
990
+ * revokes anything that was already there.
991
+ *
992
+ * Typical bootstrap sequence:
993
+ *
994
+ * ```ts
995
+ * await fortress.migrate({ migrateApp: () => migrate(db, '...') });
996
+ * await fortress.syncPermissionsFromManifest({
997
+ * defaultRoles: { admin: '*', member: ['school:read', 'school:list'] },
998
+ * });
999
+ * ```
1000
+ *
1001
+ * Replaces the seed script every consumer used to write that walked
1002
+ * `fortress.endpoints`, deduped `(resource, action)` pairs, and called
1003
+ * `iam.createPermission(...)` for each.
1004
+ */
1005
+ syncPermissionsFromManifest: (opts?: PermissionSyncOptions) => Promise<PermissionSyncResult>;
1006
+ /**
1007
+ * Emit a complete OpenAPI 3.1 spec from the endpoint definitions Fortress
1008
+ * knows about: core auth/IAM routes, plugin routes, and any top-level
1009
+ * host `routes` registered on {@link FortressConfig}.
1010
+ *
1011
+ * This is the programmatic companion to the OpenAPI plugin. Use it when
1012
+ * you already own the docs route or when a build script needs to write
1013
+ * `openapi.json` for client codegen:
1014
+ *
1015
+ * ```ts
1016
+ * const spec = fortress.toOpenAPI({
1017
+ * title: 'My API',
1018
+ * version: '0.0.0',
1019
+ * servers: [{ url: 'http://localhost:3001', description: 'Local' }],
1020
+ * tags: [{ name: 'Schools' }],
1021
+ * });
1022
+ * ```
1023
+ *
1024
+ * Defaults to endpoint `handler` names for `operationId`, matching most
1025
+ * host route-contract files. Pass `operationId: 'methodPath'` to keep the
1026
+ * historical OpenAPI-plugin ID style.
1027
+ */
1028
+ toOpenAPI: (opts?: FortressToOpenAPIOptions) => OpenAPISpec;
1029
+ }
1030
+ /** Options accepted by {@link Fortress.toOpenAPI}. */
1031
+ interface FortressToOpenAPIOptions extends ToOpenAPIOptions {
1032
+ /** Override the endpoints to emit. Defaults to `fortress.endpoints`. */
1033
+ endpoints?: EndpointDefinition[];
1034
+ }
1035
+ /** Options accepted by {@link Fortress.migrate}. */
1036
+ interface MigrateOptions {
1037
+ /**
1038
+ * Optional host-app migration step. Runs after Fortress migrations
1039
+ * complete; any thrown error propagates after Fortress migrations have
1040
+ * already been applied. Library-agnostic: pass any `() => Promise<void>`
1041
+ * — e.g. drizzle's `migrate(db, { migrationsFolder })`, Knex's
1042
+ * `db.migrate.latest()`, a hand-rolled SQL runner.
1043
+ */
1044
+ migrateApp?: () => Promise<void>;
1045
+ /**
1046
+ * Override the migration dialect. Defaults to the adapter's `dialect`
1047
+ * property (matches the behavior of {@link migrateUp}).
1048
+ */
1049
+ dialect?: 'sqlite' | 'pg';
1050
+ /** Stop applying Fortress migrations after this version. Defaults to the latest. */
1051
+ targetVersion?: number;
1052
+ }
1053
+ /** Result returned by {@link Fortress.migrate}. */
1054
+ interface MigrateResult {
1055
+ /** Result of the Fortress-managed migration step. */
1056
+ fortress: MigrationApplyResult;
1057
+ /** `true` if `migrateApp` was supplied and ran to completion. */
1058
+ appRan: boolean;
1059
+ }
1060
+ /**
1061
+ * Type-safe helper to retrieve a plugin's methods from a Fortress instance.
1062
+ *
1063
+ * Since plugin methods are dynamically typed at runtime, this helper lets
1064
+ * consumers provide a known interface for type-safe access without casting.
1065
+ *
1066
+ * @example
1067
+ * ```ts
1068
+ * interface TwoFactorMethods {
1069
+ * setup: (userId: string) => Promise<{ secret: string; qrCode: string }>;
1070
+ * verify: (userId: string, code: string) => Promise<boolean>;
1071
+ * }
1072
+ *
1073
+ * const twoFactor = getPluginMethods<TwoFactorMethods>(fortress, 'two-factor');
1074
+ * const result = await twoFactor.setup(userId); // fully typed
1075
+ * ```
1076
+ */
1077
+ declare function getPluginMethods<T>(fortress: Fortress, pluginName: string): T;
1078
+ /**
1079
+ * Build a configured {@link Fortress} instance from a {@link FortressConfig}.
1080
+ *
1081
+ * Validates the JWT secret strength, deduplicates and processes the plugin
1082
+ * list, wires up auth/IAM services, and returns the assembled instance with
1083
+ * type-safe plugin method access for any plugins listed in the config.
1084
+ */
1085
+ declare function createFortress<const T extends readonly FortressPlugin[]>(config: FortressConfig & {
1086
+ plugins?: T;
1087
+ }): Fortress<InferPlugins<T>, TypedCall<T>>;
1088
+
1089
+ export { type AuthChallengeWire as A, getExpectedColumns as B, type CallOptions as C, getFortressMigrations as D, getLatestMigrationVersion as E, type Fortress as F, getMigrationStatus as G, getMigrationUpSql as H, type InferPluginCallMap as I, getPluginMethods as J, hasMigrationDrift as K, iamComponentSchemas as L, type MigrationDialect as M, iamEndpoints as N, migrateDown as O, type PermissionSyncOptions as P, migrateUp as Q, type RouteManifestEntry as R, runPermissionSync as S, type ToOpenAPIOptions as T, toOpenAPI as U, type AuthCookiePayload as V, type RouteClassification as a, type MigrationDrift as b, type AuthImpersonationWire as c, type AuthPendingWire as d, type AuthResultWire as e, type AuthSuccessWire as f, type CallableForEndpoints as g, FORTRESS_TABLES as h, type FortressMigration as i, type FortressToOpenAPIOptions as j, type InferPlugins as k, type MigrateOptions as l, type MigrateResult as m, type MigrationApplyResult as n, type MigrationDownResult as o, type MigrationStatus as p, type PermissionSyncResult as q, type PluginMethodsMap as r, type TypedCall as s, authComponentSchemas as t, authEndpoints as u, buildCall as v, buildRouteManifest as w, createFortress as x, detectMigrationDrift as y, fortressMigrations as z };