@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,717 @@
1
+ import { D as DatabaseAdapter } from './index-CxEkfCA0.js';
2
+ export { C as CoreOperator, S as ScopeRule, W as WhereClause } from './index-CxEkfCA0.js';
3
+ export { A as AuthChallengeWire, c as AuthImpersonationWire, d as AuthPendingWire, e as AuthResultWire, f as AuthSuccessWire, C as CallOptions, g as CallableForEndpoints, h as FORTRESS_TABLES, F as Fortress, i as FortressMigration, j as FortressToOpenAPIOptions, I as InferPluginCallMap, k as InferPlugins, l as MigrateOptions, m as MigrateResult, n as MigrationApplyResult, M as MigrationDialect, o as MigrationDownResult, b as MigrationDrift, p as MigrationStatus, P as PermissionSyncOptions, q as PermissionSyncResult, r as PluginMethodsMap, a as RouteClassification, R as RouteManifestEntry, T as ToOpenAPIOptions, s as TypedCall, t as authComponentSchemas, u as authEndpoints, v as buildCall, w as buildRouteManifest, x as createFortress, y as detectMigrationDrift, z as fortressMigrations, B as getExpectedColumns, D as getFortressMigrations, E as getLatestMigrationVersion, G as getMigrationStatus, H as getMigrationUpSql, J as getPluginMethods, K as hasMigrationDrift, L as iamComponentSchemas, N as iamEndpoints, O as migrateDown, Q as migrateUp, S as runPermissionSync, U as toOpenAPI } from './fortress-uA-_cheR.js';
4
+ import { g as IamService } from './auth-service-BkzZkWfH.js';
5
+ export { A as AttributeValue, a as Attributes, b as AuthEvent, c as AuthEventListener, C as Counter, F as FortressLogger, H as Histogram, I as IamEvent, d as IamEventListener, M as Meter, P as PermissionCheckEvent, e as PermissionCheckListener, R as ResourceDefinition, h as ResourceFile, S as Span, T as TelemetryProvider, f as Tracer, U as Unsubscribe, p as parseResourceFile } from './auth-service-BkzZkWfH.js';
6
+ export { JwtKeyMaterial } from './jwt.js';
7
+ import { H as HttpMethod, g as SecurityRequirement, S as StandardSchemaV1, h as FortressSchema, E as EndpointDefinition, i as Infer, J as JSONSchema, j as Simplify, k as EndpointInput } from './config-B2366s_G.js';
8
+ export { A as AfterHookContext, C as ComponentSchemas, l as EndpointMeta, m as EndpointResponse, n as FieldDefinition, o as FortressConfig, F as FortressPlugin, p as HookContext, q as HookResult, b as InferEndpointBody, c as InferEndpointCallInput, I as InferEndpointParams, a as InferEndpointQuery, d as InferEndpointResponses, r as InferEndpointSuccessResponse, M as MiddlewareDefinition, s as ModelConstraint, t as ModelDefinition, u as PasswordBreachCheckOptions, v as PasswordBreachDegradedEvent, w as PasswordBreachFailureMode, P as PasswordHasher, x as PasswordPolicyConfig, y as PasswordPolicyObserver, e as PluginContext, z as PluginHooks, B as PluginRequestContext, D as PostAuthGateContext, G as PostAuthGateDecision, K as PostAuthGateProvider, L as PostAuthGateVerificationContext, N as SessionConfig } from './config-B2366s_G.js';
9
+ export { a as ProtectOptions, P as ProtectedRouteContext, c as ProtectedRouteHandler, b as ProtectedRouteTarget, d as describeProtectedTarget, p as protect, r as resolveProtectedEndpoint } from './protect-DsxV_-dJ.js';
10
+ import { S as Subject, b as Permission, P as PermissionContext } from './types-et0R8tsC.js';
11
+ export { m as AuthChallenge, n as AuthImpersonation, g as AuthMethod, o as AuthPending, A as AuthResult, p as AuthSuccess, h as AuthTokenPair, q as ConditionRef, r as ConditionValue, i as CreateUserInput, F as FortressUser, G as Group, k as LoginIdentifier, L as LoginIdentifierType, l as PendingReason, s as PermissionCondition, c as PermissionInput, R as RequestMeta, d as Role, e as RoleBinding, a as SubjectType, T as TokenClaims, t as assertSuccess, u as isImpersonation, v as isPending, w as isSuccess } from './types-et0R8tsC.js';
12
+ export { D as DetectRouteManifestDriftOptions, R as RouteManifestDrift, d as detectRouteManifestDrift, h as hasRouteManifestDrift } from './drift-k9LiYpRP.js';
13
+ export { ApiKeyMethods } from './plugins/api-key.js';
14
+ export { AuditLogMethods } from './plugins/audit-log.js';
15
+ export { DataIsolationMethods } from './plugins/data-isolation.js';
16
+ export { EmailVerificationMethods } from './plugins/email-verification.js';
17
+ export { MagicLinkMethods } from './plugins/magic-link.js';
18
+ export { AuthorizeRequestParams, ClientAuth, OAuthMethods, PendingFlowRecord, TokenRequestBody } from './plugins/oauth.js';
19
+ export { O as OpenAPISpec, S as SpecBuilderOptions } from './index-jAMbbUAY.js';
20
+ export { SocialLoginMethods } from './plugins/social-login.js';
21
+ export { TenancyMethods } from './plugins/tenancy.js';
22
+ export { TwoFactorMethods } from './plugins/two-factor.js';
23
+ export { WebAuthnMethods } from './plugins/webauthn.js';
24
+ import '@simplewebauthn/server';
25
+
26
+ /** Discriminated string union of every error code fortress can throw. Maps 1:1 to an HTTP status. */
27
+ type FortressErrorCode = 'UNAUTHORIZED' | 'TOKEN_REUSE' | 'SESSION_IDLE_TIMEOUT' | 'SESSION_ABSOLUTE_TIMEOUT' | 'FORBIDDEN' | 'BAD_REQUEST' | 'NOT_FOUND' | 'CONFLICT' | 'UNPROCESSABLE_ENTITY' | 'RATE_LIMITED' | 'DATABASE_ERROR' | 'VALIDATION_ERROR' | 'SERVICE_UNAVAILABLE';
28
+ /**
29
+ * Machine-readable error codes defined by RFC 6749 §5.2 (token endpoint) and
30
+ * §4.1.2.1 (authorization endpoint). The OAuth plugin uses these as the
31
+ * `error` field in token-endpoint failure responses; the HTTP error mapper
32
+ * detects {@link FortressError.oauthError} and emits the
33
+ * `{ error, error_description }` shape required by the spec.
34
+ */
35
+ type OAuthErrorCode = 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | 'unsupported_grant_type' | 'invalid_scope' | 'access_denied' | 'unsupported_response_type' | 'server_error' | 'temporarily_unavailable';
36
+ /** The single error class fortress throws. Carries an error code, HTTP status, and structured details. */
37
+ declare class FortressError extends Error {
38
+ readonly code: FortressErrorCode;
39
+ readonly statusCode: number;
40
+ readonly retryAfter?: number;
41
+ readonly details?: unknown;
42
+ /** RFC 6749 §5.2 / §4.1.2.1 machine code. Set by `Errors.oauth()`. */
43
+ readonly oauthError?: OAuthErrorCode;
44
+ /** Human-readable description for the OAuth `error_description` field. */
45
+ readonly oauthDescription?: string;
46
+ /** Optional URI for the OAuth `error_uri` field (§5.2). */
47
+ readonly oauthErrorUri?: string;
48
+ constructor(code: FortressErrorCode, message: string, statusCode: number, options?: {
49
+ cause?: unknown;
50
+ retryAfter?: number;
51
+ details?: unknown;
52
+ oauthError?: OAuthErrorCode;
53
+ oauthDescription?: string;
54
+ oauthErrorUri?: string;
55
+ });
56
+ toJSON(): {
57
+ code: FortressErrorCode;
58
+ message: string;
59
+ statusCode: number;
60
+ details?: unknown;
61
+ };
62
+ }
63
+ /** Typed factory of {@link FortressError} constructors — one helper per error code. */
64
+ declare const Errors: {
65
+ readonly unauthorized: (message?: string) => FortressError;
66
+ readonly tokenReuse: () => FortressError;
67
+ readonly sessionIdleTimeout: () => FortressError;
68
+ readonly sessionAbsoluteTimeout: () => FortressError;
69
+ readonly forbidden: (message?: string) => FortressError;
70
+ readonly badRequest: (message?: string) => FortressError;
71
+ readonly notFound: (message?: string) => FortressError;
72
+ readonly conflict: (message?: string, options?: {
73
+ cause?: unknown;
74
+ details?: unknown;
75
+ }) => FortressError;
76
+ readonly unprocessable: (message?: string, options?: {
77
+ cause?: unknown;
78
+ details?: unknown;
79
+ }) => FortressError;
80
+ readonly rateLimited: (retryAfter: number) => FortressError;
81
+ readonly database: (message?: string, cause?: unknown) => FortressError;
82
+ readonly serviceUnavailable: (message?: string, options?: {
83
+ cause?: unknown;
84
+ retryAfter?: number;
85
+ }) => FortressError;
86
+ readonly validationError: (issues: Array<{
87
+ path?: unknown;
88
+ message: string;
89
+ }>) => FortressError;
90
+ /**
91
+ * RFC 6749 §5.2 / §4.1.2.1 OAuth error.
92
+ *
93
+ * The HTTP error mapper detects `oauthError` and emits the OAuth-spec
94
+ * JSON body `{ error, error_description, error_uri? }` instead of the
95
+ * default fortress `{ code, message }` shape, so strict OAuth clients
96
+ * (Moodle, openid-client, Spring Security, etc.) can switch behaviour
97
+ * on the machine-readable `error` field.
98
+ *
99
+ * Status is inferred from the OAuth code per the spec table:
100
+ * - `invalid_client` → 401
101
+ * - everything else → 400
102
+ */
103
+ readonly oauth: (error: OAuthErrorCode, description?: string, options?: {
104
+ status?: number;
105
+ errorUri?: string;
106
+ cause?: unknown;
107
+ }) => FortressError;
108
+ /**
109
+ * Reconstruct a {@link FortressError} from a JSON error body emitted by
110
+ * `errorToResponse`. Used by the in-process `fortress.call.*` client to
111
+ * convert non-2xx responses into typed throws that mirror what a direct
112
+ * service-method call would produce.
113
+ *
114
+ * Maps by HTTP status when the body doesn't carry a recognizable
115
+ * `{ code, message }` payload, so network errors and opaque upstream
116
+ * failures still become structured `FortressError`s.
117
+ */
118
+ readonly fromHttpResponse: (status: number, body: unknown) => FortressError;
119
+ };
120
+
121
+ /**
122
+ * Permission debugging helper (P1-8).
123
+ *
124
+ * Answers the operator-console question "why does subject X have (or not
125
+ * have) permission `resource:action`?" by walking the same data the
126
+ * permission evaluator uses — direct bindings, role bindings, group
127
+ * memberships (for USER subjects) — and emitting a structured
128
+ * explanation listing every grant + its source.
129
+ *
130
+ * Designed as a free function rather than a new {@link IamService} method
131
+ * to keep the surface narrow and the DB queries explicit.
132
+ *
133
+ * @module
134
+ */
135
+
136
+ interface PermissionExplanationSource {
137
+ /** Where the grant came from. */
138
+ via: 'direct-user' | 'direct-group' | 'direct-service-account' | 'role';
139
+ /** Role name when `via === 'role'`. */
140
+ role?: string;
141
+ /** Group id/name when the grant flows through a group (USER subjects only). */
142
+ group?: {
143
+ id: string;
144
+ name: string;
145
+ };
146
+ /** The matching permission row. */
147
+ permission: Permission;
148
+ }
149
+ interface PermissionExplanation {
150
+ subject: Subject;
151
+ resource: string;
152
+ action: string;
153
+ /** Final verdict from the configured IAM evaluation mode and condition context. */
154
+ allowed: boolean;
155
+ /** Every grant source that matched, including DENYs. */
156
+ sources: PermissionExplanationSource[];
157
+ /** Roles the subject is bound to (whether or not their permissions matched). */
158
+ roleBindings: Array<{
159
+ role: string;
160
+ tenantId?: string | null;
161
+ }>;
162
+ /** Groups the subject belongs to (USER only). */
163
+ groupMemberships: Array<{
164
+ id: string;
165
+ name: string;
166
+ }>;
167
+ }
168
+ /**
169
+ * Explain why a subject does (or does not) have a permission. Walks
170
+ * direct bindings, role bindings, and group memberships (USER only) and
171
+ * lists every matching grant with its source so operators can debug
172
+ * unexpected allow/deny results.
173
+ *
174
+ * @param db - Database adapter (typically `fortress.config.database`).
175
+ * @param iam - IAM service used for the authoritative verdict, including
176
+ * configured evaluation mode, conditions, cache semantics, and inactive
177
+ * service-account handling.
178
+ */
179
+ declare function explainPermission(db: DatabaseAdapter, iam: IamService, subject: Subject, resource: string, action: string, context?: PermissionContext): Promise<PermissionExplanation>;
180
+
181
+ /**
182
+ * Declarative policy types for policy-as-code (P1-7).
183
+ *
184
+ * A policy file declares the desired state of Fortress-owned IAM
185
+ * resources: resources/actions, roles + permissions, groups, and
186
+ * service accounts (with their role bindings). The diff/apply pipeline
187
+ * computes the operations needed to reconcile the live database with the
188
+ * declared state.
189
+ *
190
+ * What's covered:
191
+ * - Resources + actions (extends today's `fortress.resources.json`).
192
+ * - Roles with permission lists.
193
+ * - Groups (declared shells; user memberships managed via runtime APIs).
194
+ * - Service accounts with role bindings.
195
+ *
196
+ * What's intentionally NOT covered:
197
+ * - OAuth clients (have secrets; manage via admin endpoints).
198
+ * - User accounts / user-group memberships (user data, not policy).
199
+ * - Tenant data and per-tenant role bindings (large scale; declare in
200
+ * per-tenant policy files if needed).
201
+ *
202
+ * @module
203
+ */
204
+ /** Resource definition (action list shared with the existing `fortress.resources.json` shape). */
205
+ interface PolicyResource {
206
+ name: string;
207
+ actions: string[];
208
+ description?: string;
209
+ }
210
+ /** Permission entry inside a role declaration. `effect` defaults to ALLOW. */
211
+ interface PolicyPermission {
212
+ resource: string;
213
+ action: string;
214
+ effect?: 'ALLOW' | 'DENY';
215
+ }
216
+ /** Role declaration. Permissions are the *complete* desired set for the role; extras are removed on apply. */
217
+ interface PolicyRole {
218
+ name: string;
219
+ description?: string;
220
+ permissions: PolicyPermission[];
221
+ }
222
+ /** Group declaration. User memberships are intentionally not managed via policy files. */
223
+ interface PolicyGroup {
224
+ name: string;
225
+ description?: string;
226
+ }
227
+ /** Service-account declaration. Roles list is the complete desired binding set; extras are unbound on apply. */
228
+ interface PolicyServiceAccount {
229
+ name: string;
230
+ displayName?: string;
231
+ description?: string;
232
+ isActive?: boolean;
233
+ /** Role names to bind to this service account. Bindings outside this list are removed on apply. */
234
+ roles?: string[];
235
+ }
236
+ /** Top-level policy document. */
237
+ interface PolicyDocument {
238
+ resources?: PolicyResource[];
239
+ roles?: PolicyRole[];
240
+ groups?: PolicyGroup[];
241
+ serviceAccounts?: PolicyServiceAccount[];
242
+ }
243
+ /** Single op produced by `diffPolicy`. Tag is human-readable; `description` flattens for logs. */
244
+ type PolicyOp = {
245
+ kind: 'create-resource';
246
+ resource: PolicyResource;
247
+ description: string;
248
+ } | {
249
+ kind: 'add-resource-action';
250
+ resource: string;
251
+ action: string;
252
+ description: string;
253
+ } | {
254
+ kind: 'create-role';
255
+ role: PolicyRole;
256
+ description: string;
257
+ } | {
258
+ kind: 'update-role-description';
259
+ role: string;
260
+ from?: string;
261
+ to?: string;
262
+ description: string;
263
+ } | {
264
+ kind: 'add-role-permission';
265
+ role: string;
266
+ permission: PolicyPermission;
267
+ description: string;
268
+ } | {
269
+ kind: 'remove-role-permission';
270
+ role: string;
271
+ permission: PolicyPermission;
272
+ description: string;
273
+ } | {
274
+ kind: 'delete-role';
275
+ role: string;
276
+ description: string;
277
+ } | {
278
+ kind: 'create-group';
279
+ group: PolicyGroup;
280
+ description: string;
281
+ } | {
282
+ kind: 'update-group-description';
283
+ group: string;
284
+ from?: string;
285
+ to?: string;
286
+ description: string;
287
+ } | {
288
+ kind: 'delete-group';
289
+ group: string;
290
+ description: string;
291
+ } | {
292
+ kind: 'create-service-account';
293
+ serviceAccount: PolicyServiceAccount;
294
+ description: string;
295
+ } | {
296
+ kind: 'update-service-account';
297
+ serviceAccount: string;
298
+ changes: Record<string, unknown>;
299
+ description: string;
300
+ } | {
301
+ kind: 'bind-service-account-role';
302
+ serviceAccount: string;
303
+ role: string;
304
+ description: string;
305
+ } | {
306
+ kind: 'unbind-service-account-role';
307
+ serviceAccount: string;
308
+ role: string;
309
+ description: string;
310
+ } | {
311
+ kind: 'delete-service-account';
312
+ serviceAccount: string;
313
+ description: string;
314
+ };
315
+ /** Diff result returned by `diffPolicy`. */
316
+ interface PolicyPlan {
317
+ ops: PolicyOp[];
318
+ /** `true` when there is nothing to reconcile. */
319
+ inSync: boolean;
320
+ }
321
+ /** Options for `diffPolicy`. */
322
+ interface DiffPolicyOptions {
323
+ /**
324
+ * Prune resources/roles/groups/service-accounts present in the database
325
+ * but absent from the policy file. Default `false` — apply only adds
326
+ * and updates unless the operator opts in to deletions.
327
+ */
328
+ prune?: boolean;
329
+ /** Explicitly acknowledge that pruning with no declared entities deletes all managed IAM state. */
330
+ allowEmptyPrune?: boolean;
331
+ }
332
+
333
+ /**
334
+ * Execute a {@link PolicyPlan} against an {@link IamService}.
335
+ *
336
+ * Ops are applied in dependency-safe order (resources before roles before
337
+ * service accounts) so a single `applyPolicyPlan` call can bring a fresh
338
+ * database to the declared state in one shot.
339
+ *
340
+ * @module
341
+ */
342
+
343
+ /** Result of {@link applyPolicyPlan}. */
344
+ interface ApplyPolicyResult {
345
+ applied: PolicyOp[];
346
+ skipped: PolicyOp[];
347
+ errors: {
348
+ op: PolicyOp;
349
+ message: string;
350
+ }[];
351
+ }
352
+ /**
353
+ * Apply every op in the plan, sorted by op kind so dependencies are
354
+ * satisfied (resources before roles, roles before service-account
355
+ * bindings). Returns a structured result so the caller can log success
356
+ * vs. failure per op.
357
+ */
358
+ declare function applyPolicyPlan(plan: PolicyPlan, iam: IamService): Promise<ApplyPolicyResult>;
359
+ /**
360
+ * Compatibility helper that applies only the resource operations in a plan.
361
+ * The file-path argument is retained for source compatibility but no file is
362
+ * written; resource updates are applied directly through the IAM service.
363
+ */
364
+ declare function applyResourceOps(plan: PolicyPlan, iam: IamService, _syncResourceFile: string): Promise<void>;
365
+
366
+ /**
367
+ * Compute the {@link PolicyPlan} that reconciles the live IAM state with
368
+ * a declarative {@link PolicyDocument}.
369
+ *
370
+ * The diff is intentionally additive-by-default: missing resources,
371
+ * actions, roles, permissions, groups, and service accounts produce
372
+ * `create-*` / `add-*` ops. Deletions only appear when `prune: true` is
373
+ * passed — most operators want their first apply to be safe.
374
+ *
375
+ * @module
376
+ */
377
+
378
+ /**
379
+ * Compute the diff between a {@link PolicyDocument} (desired state) and
380
+ * the live IAM state. Pass the returned {@link PolicyPlan} to
381
+ * {@link applyPolicyPlan} to reconcile.
382
+ */
383
+ declare function diffPolicy(policy: PolicyDocument, iam: IamService, options?: DiffPolicyOptions): Promise<PolicyPlan>;
384
+
385
+ /**
386
+ * Load a {@link PolicyDocument} from disk with optional env-specific
387
+ * override. Node filesystem/path modules are imported only when these
388
+ * file-oriented helpers run, keeping the package root import runtime-neutral.
389
+ *
390
+ * @module
391
+ */
392
+
393
+ interface LoadPolicyOptions {
394
+ /** Override the default `fortress.policy.json` path. */
395
+ filePath?: string;
396
+ /** Pick an env-specific file (`fortress.policy.<env>.json`). Defaults to `process.env.FORTRESS_ENV`. */
397
+ env?: string;
398
+ /** Working directory when resolving the default file paths. Defaults to `process.cwd()`. */
399
+ cwd?: string;
400
+ }
401
+ /** Default base file name. */
402
+ declare const DEFAULT_POLICY_FILE = "fortress.policy.json";
403
+ /** Validate and normalize an untrusted policy JSON value. */
404
+ declare function parsePolicyDocument(value: unknown): PolicyDocument;
405
+ /** Return the resolved policy-file path for an environment, or `null` if no file exists. */
406
+ declare function resolvePolicyPath(options?: LoadPolicyOptions): Promise<string | null>;
407
+ /** Load and parse a policy document. Throws when the file is missing or unparseable. */
408
+ declare function loadPolicy(options?: LoadPolicyOptions): Promise<{
409
+ policy: PolicyDocument;
410
+ filePath: string;
411
+ }>;
412
+
413
+ /** Shorthand for the Standard Schema inferred output type. */
414
+ type InferSchema<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
415
+ /** Distribute a union into an intersection — `A | B` → `A & B`. Used by {@link intersect}. */
416
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
417
+ /** Options accepted by the {@link str} builder (string constraints + annotations). */
418
+ interface StringOptions {
419
+ description?: string;
420
+ /** Minimum length (`minLength`), enforced at runtime. */
421
+ min?: number;
422
+ /** Maximum length (`maxLength`), enforced at runtime. */
423
+ max?: number;
424
+ /** Regular-expression source (`pattern`), enforced at runtime. */
425
+ pattern?: string;
426
+ /** OpenAPI `format` annotation (e.g. `email`, `uuid`). Annotation-only unless paired with `pattern`. */
427
+ format?: string;
428
+ }
429
+ /** Options accepted by the {@link num}/{@link int} builders (numeric bounds + annotations). */
430
+ interface NumberOptions {
431
+ description?: string;
432
+ /** Inclusive minimum (`minimum`), enforced at runtime. */
433
+ min?: number;
434
+ /** Inclusive maximum (`maximum`), enforced at runtime. */
435
+ max?: number;
436
+ }
437
+ /**
438
+ * Build a string {@link FortressSchema}.
439
+ *
440
+ * Pass a string for just a description, or an options object to set
441
+ * `minLength`/`maxLength`/`pattern`/`format` — the length and pattern
442
+ * constraints are enforced at runtime by the validator.
443
+ */
444
+ declare function str(opts?: string | StringOptions): FortressSchema<string>;
445
+ /**
446
+ * Build a number {@link FortressSchema} (any numeric, integer or float).
447
+ *
448
+ * Pass a string for just a description, or an options object to set
449
+ * `minimum`/`maximum` — both are enforced at runtime by the validator.
450
+ */
451
+ declare function num(opts?: string | NumberOptions): FortressSchema<number>;
452
+ /**
453
+ * Build an integer {@link FortressSchema}.
454
+ *
455
+ * Pass a string for just a description, or an options object to set
456
+ * `minimum`/`maximum` — both are enforced at runtime by the validator.
457
+ */
458
+ declare function int(opts?: string | NumberOptions): FortressSchema<number>;
459
+ /**
460
+ * Build a subject-id {@link FortressSchema}.
461
+ *
462
+ * IDs are opaque strings at the fortress API surface (RFC 7519 §4.1.2 for
463
+ * JWT `sub`). Numeric-keyed adapters stringify on read and parse on write
464
+ * at the adapter boundary; consumers never see the underlying representation.
465
+ */
466
+ declare function id(description?: string): FortressSchema<string>;
467
+ /** Build a boolean {@link FortressSchema}. */
468
+ declare function bool(description?: string): FortressSchema<boolean>;
469
+ /** Build an array {@link FortressSchema} whose items match the supplied schema. */
470
+ declare function arr<T>(items: FortressSchema<T>, description?: string): FortressSchema<T[]>;
471
+ /**
472
+ * Build an object {@link FortressSchema}. Pass property names after `properties`
473
+ * to mark them as required — they become non-optional in the inferred type.
474
+ */
475
+ declare function obj<P extends Record<string, FortressSchema<any>>, K extends (keyof P & string)[] = []>(properties: P, ...required: K): FortressSchema<Simplify<{
476
+ [Key in K[number]]: Infer<P[Key]>;
477
+ } & {
478
+ [Key in Exclude<keyof P & string, K[number]>]?: Infer<P[Key]>;
479
+ }>>;
480
+ /** Wrap a schema so it also accepts `null`. */
481
+ declare function nullable<T>(schema: FortressSchema<T>): FortressSchema<T | null>;
482
+ /** Build a discriminated-union schema (exactly one variant must match). */
483
+ declare function oneOf<S extends FortressSchema<any>[]>(...schemas: S): FortressSchema<Infer<S[number]>>;
484
+ /** Build a union schema (any one variant may match). */
485
+ declare function anyOf<S extends FortressSchema<any>[]>(...schemas: S): FortressSchema<Infer<S[number]>>;
486
+ /**
487
+ * Build a `$ref` schema pointing at an OpenAPI component schema by name.
488
+ *
489
+ * Two forms:
490
+ * - `ref(name)` — untyped `$ref`, returns `FortressSchema<unknown>`. Use when
491
+ * the referenced component hasn't been declared yet (e.g. self-references
492
+ * inside a components literal).
493
+ * - `ref(name, schema)` — typed and runtime-bound `$ref`. The supplied schema
494
+ * provides both the inferred TypeScript type and the component definition
495
+ * used for runtime validation. Use when you already have the component
496
+ * schema and want downstream types and validation to flow through.
497
+ *
498
+ * For the common case (typed refs against a known components map), prefer
499
+ * {@link defineComponents} — it returns a bound `ref` that only needs a name.
500
+ */
501
+ declare function ref<T>(name: string, schema: FortressSchema<T>): FortressSchema<T>;
502
+ declare function ref(name: string): FortressSchema<unknown>;
503
+ /**
504
+ * Declare a typed registry of OpenAPI component schemas and return a bound
505
+ * `ref` function that preserves each component's inferred TypeScript type.
506
+ *
507
+ * ```ts
508
+ * const User = obj({ id: int(), email: str() }, 'id', 'email');
509
+ * const { components, ref } = defineComponents({ User });
510
+ *
511
+ * const ep = endpoint('GET', '/me')
512
+ * .response(200, 'Current user', ref('User'))
513
+ * // ^ FortressSchema<{ id: string; email: string }>
514
+ * .handler('me')
515
+ * .build();
516
+ * ```
517
+ *
518
+ * The returned `components` is the same object you passed in (useful for
519
+ * OpenAPI spec emission). The returned `ref` is a generic function that
520
+ * looks up each key in `T` and returns a `$ref` schema carrying the
521
+ * inferred type of the referenced component.
522
+ */
523
+ declare function defineComponents<T extends Record<string, FortressSchema<any>>>(components: T): {
524
+ components: T;
525
+ ref: <K extends keyof T & string>(name: K) => FortressSchema<Infer<T[K]>>;
526
+ };
527
+ /** Build an enum {@link FortressSchema} from a fixed set of string or number literal values. */
528
+ declare function enums<T extends string | number>(...values: T[]): FortressSchema<T>;
529
+ /** Build a string {@link FortressSchema} with an OpenAPI `format` annotation (e.g. `email`, `uri`, `uuid`). */
530
+ declare function strFormat(format: string, description?: string): FortressSchema<string>;
531
+ /** Build a {@link FortressSchema} that only accepts the literal `null`. */
532
+ declare function nullType(): FortressSchema<null>;
533
+ /** An object {@link FortressSchema} with unknown additional properties (e.g. plugin data, metadata). */
534
+ declare function record(description?: string): FortressSchema<Record<string, unknown>>;
535
+ /** An object {@link FortressSchema} where every property value matches the supplied schema. */
536
+ declare function recordOf<T>(valueSchema: FortressSchema<T>, description?: string): FortressSchema<Record<string, T>>;
537
+ /**
538
+ * Build a literal {@link FortressSchema} accepting exactly one constant value
539
+ * (`const`). The value is enforced at runtime and the inferred type narrows to
540
+ * the literal (e.g. `literal('admin')` infers `'admin'`).
541
+ */
542
+ declare function literal<const V extends string | number | boolean>(value: V, description?: string): FortressSchema<V>;
543
+ /**
544
+ * Build an intersection {@link FortressSchema} (`allOf`) — a value must satisfy
545
+ * every supplied schema. The inferred type is the intersection of each schema's
546
+ * inferred type.
547
+ */
548
+ declare function intersect<S extends FortressSchema<any>[]>(...schemas: S): FortressSchema<UnionToIntersection<Infer<S[number]>>>;
549
+ /**
550
+ * Close an object {@link FortressSchema} — sets `additionalProperties: false`,
551
+ * so the validator rejects any key not declared in `properties`. Use to harden
552
+ * request bodies against over-posting (mass assignment).
553
+ */
554
+ declare function strict<T>(schema: FortressSchema<T>): FortressSchema<T>;
555
+ /**
556
+ * Build a discriminated-union {@link FortressSchema}. Emits `oneOf` plus an
557
+ * OpenAPI `discriminator`, which the validator uses to dispatch on
558
+ * `propertyName` (faster, with precise per-variant errors) instead of trying
559
+ * every branch.
560
+ */
561
+ declare function discriminatedUnion<S extends FortressSchema<any>[]>(propertyName: string, ...variants: S): FortressSchema<Infer<S[number]>>;
562
+ /** Email string schema (`format: 'email'`) — enforces the WHATWG HTML5 email grammar at runtime. */
563
+ declare const email: (description?: string) => FortressSchema<string>;
564
+ /** UUID string schema (`format: 'uuid'`) — enforces RFC 9562 versions 1–8 plus nil/max at runtime. */
565
+ declare const uuid: (description?: string) => FortressSchema<string>;
566
+ /** URL string schema (`format: 'uri'`) — enforces an explicit `scheme://` authority at runtime. */
567
+ declare const url: (description?: string) => FortressSchema<string>;
568
+ /** RFC 3339 date-time string schema (`format: 'date-time'`) — field ranges enforced at runtime. */
569
+ declare const datetime: (description?: string) => FortressSchema<string>;
570
+ /** RFC 3339 full-date string schema (`format: 'date'`) — field ranges enforced at runtime. */
571
+ declare const date: (description?: string) => FortressSchema<string>;
572
+ /** RFC 3339 time string schema (`format: 'time'`) — field ranges enforced at runtime. */
573
+ declare const time: (description?: string) => FortressSchema<string>;
574
+ /** Type guard — `true` if the value implements Standard Schema V1. */
575
+ declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
576
+ /** Type guard — `true` if the value is a {@link FortressSchema} (has both JSON Schema fields and Standard Schema wiring). */
577
+ declare function isFortressSchema(value: unknown): value is FortressSchema;
578
+ /**
579
+ * Extract a {@link JSONSchema} from any schema input.
580
+ *
581
+ * - {@link FortressSchema}: returned as-is (it already _is_ JSON Schema).
582
+ * - External Standard Schema with a `~standard.jsonSchema.input()` adapter
583
+ * (Zod, Valibot, ArkType, etc.): extracted via the adapter.
584
+ * - External Standard Schema that already IS a JSON Schema object (fetcher,
585
+ * etc.): returned as-is.
586
+ * - Anything else: empty object fallback.
587
+ */
588
+ declare function extractJsonSchema(schema: FortressSchema<any> | StandardSchemaV1<any>): JSONSchema;
589
+ /** Schema input accepted by `EndpointBuilder.body/query/params` — a fortress schema or any Standard Schema V1 implementation. */
590
+ type SchemaInput = FortressSchema<any> | StandardSchemaV1<any>;
591
+ /**
592
+ * Canonical fortress error response body — the exact wire shape emitted by
593
+ * {@link import('./errors').FortressError.toJSON}. Reference this from
594
+ * endpoint `.response(4xx|5xx, ...)` declarations so host APIs document the
595
+ * same error contract Fortress's own routes produce, and so clients can use
596
+ * a single error parser everywhere.
597
+ *
598
+ * Shape:
599
+ * ```ts
600
+ * {
601
+ * code: string, // FortressErrorCode
602
+ * message: string, // human-readable
603
+ * statusCode: number, // HTTP status
604
+ * details?: unknown, // optional structured payload (e.g. validation issues)
605
+ * }
606
+ * ```
607
+ *
608
+ * See {@link EndpointBuilder.errorResponse} for a shorthand that wires this
609
+ * schema into a status declaration in one call.
610
+ */
611
+ interface ErrorEnvelopeBody {
612
+ code: string;
613
+ message: string;
614
+ statusCode: number;
615
+ details?: unknown;
616
+ }
617
+ declare const ErrorEnvelope: FortressSchema<ErrorEnvelopeBody>;
618
+ /**
619
+ * Fluent builder for {@link EndpointDefinition} objects. Construct via the
620
+ * {@link endpoint} factory and chain `summary`, `body`, `response`, etc.
621
+ * before calling `build()`.
622
+ *
623
+ * The four type parameters accumulate as schemas are declared: each call to
624
+ * `.body()`, `.query()`, `.params()`, and `.response()` returns a new
625
+ * builder type with the inferred schema baked in. By the time `.build()` is
626
+ * called, the returned {@link EndpointDefinition} carries complete phantom
627
+ * type information about its request/response shape, which the
628
+ * `InferEndpoint*` helpers and the `fortress.call.*` proxy read at the call
629
+ * site.
630
+ */
631
+ declare class EndpointBuilder<TBody = {}, TQuery = {}, TParams = {}, TResponses extends Record<number, unknown> = {}> {
632
+ private _method;
633
+ private _path;
634
+ private _handler;
635
+ private _summary;
636
+ private _description?;
637
+ private _tags;
638
+ private _security;
639
+ private _deprecated;
640
+ private _permission?;
641
+ private _body?;
642
+ private _query?;
643
+ private _params?;
644
+ private _responses;
645
+ constructor(method: HttpMethod, path: string);
646
+ summary(s: string): this;
647
+ description(s: string): this;
648
+ tags(...t: string[]): this;
649
+ security(...s: SecurityRequirement[]): this;
650
+ deprecated(): this;
651
+ permission(resource: string, action: string): this;
652
+ body<T extends StandardSchemaV1>(schema: T): EndpointBuilder<InferSchema<T>, TQuery, TParams, TResponses>;
653
+ query<T extends StandardSchemaV1>(schema: T): EndpointBuilder<TBody, InferSchema<T>, TParams, TResponses>;
654
+ params<T extends StandardSchemaV1>(schema: T): EndpointBuilder<TBody, TQuery, InferSchema<T>, TResponses>;
655
+ /**
656
+ * Declare a response for a given status code. Three call shapes:
657
+ *
658
+ * - `.response(200, 'Ok', schema)` — typed. The inferred output type of
659
+ * `schema` becomes the response body at that status.
660
+ * - `.response(401, 'Unauthorized', schema)` — also typed. Error bodies
661
+ * are inferred the same way as success bodies; the `fortress.call.*`
662
+ * proxy treats non-2xx as throws and only exposes 2xx responses.
663
+ * - `.response(204, 'No content')` — untyped. Use when there's no body.
664
+ */
665
+ response<S extends number, T extends StandardSchemaV1>(status: S, description: string, schema: T): EndpointBuilder<TBody, TQuery, TParams, TResponses & {
666
+ [K in S]: InferSchema<T>;
667
+ }>;
668
+ response<S extends number>(status: S, description: string): EndpointBuilder<TBody, TQuery, TParams, TResponses & {
669
+ [K in S]: unknown;
670
+ }>;
671
+ /**
672
+ * Declare an error response that returns the canonical {@link ErrorEnvelope}
673
+ * body. Shorthand for `.response(status, description, ErrorEnvelope)`.
674
+ *
675
+ * Aligns host endpoint error responses with what Fortress's own routes
676
+ * emit, so a single client-side error parser works everywhere.
677
+ *
678
+ * ```ts
679
+ * endpoint('GET', '/schools/:id')
680
+ * .summary('Get a school')
681
+ * .params(obj({ id: str() }, 'id'))
682
+ * .response(200, 'OK', SchoolEnvelope)
683
+ * .errorResponse(404, 'School not found')
684
+ * .errorResponse(403, 'Forbidden')
685
+ * .build();
686
+ * ```
687
+ */
688
+ errorResponse<S extends number>(status: S, description: string): EndpointBuilder<TBody, TQuery, TParams, TResponses & {
689
+ [K in S]: InferSchema<typeof ErrorEnvelope>;
690
+ }>;
691
+ handler(name: string): this;
692
+ build(): EndpointDefinition<TBody, TQuery, TParams, TResponses>;
693
+ }
694
+ /** Start building a new {@link EndpointDefinition} for the given HTTP method and path. */
695
+ declare function endpoint(method: HttpMethod, path: string): EndpointBuilder<{}, {}, {}, {}>;
696
+
697
+ /**
698
+ * Runtime request validation using Standard Schema.
699
+ *
700
+ * Validates body/query/params against schemas stored in EndpointInput.
701
+ * Works with any Standard Schema provider (fortress, Zod, Valibot, ArkType).
702
+ */
703
+
704
+ /**
705
+ * Validate request data against endpoint input schemas.
706
+ * Throws FortressError('VALIDATION_ERROR') on failure.
707
+ *
708
+ * Uses `~standard.validate()` from whichever schema is attached
709
+ * (fortress built-in or external Standard Schema).
710
+ */
711
+ declare function validateRequest(input: EndpointInput | undefined, data: {
712
+ body?: unknown;
713
+ query?: unknown;
714
+ params?: unknown;
715
+ }): Promise<void>;
716
+
717
+ export { type ApplyPolicyResult, DEFAULT_POLICY_FILE, DatabaseAdapter, type DiffPolicyOptions, EndpointBuilder, EndpointDefinition, EndpointInput, ErrorEnvelope, Errors, FortressError, type FortressErrorCode, FortressSchema, HttpMethod, IamService, Infer, JSONSchema, type LoadPolicyOptions, type NumberOptions, type OAuthErrorCode, Permission, PermissionContext, type PermissionExplanation, type PermissionExplanationSource, type PolicyDocument, type PolicyGroup, type PolicyOp, type PolicyPermission, type PolicyPlan, type PolicyResource, type PolicyRole, type PolicyServiceAccount, type SchemaInput, SecurityRequirement, Simplify, StandardSchemaV1, type StringOptions, anyOf, applyPolicyPlan, applyResourceOps, arr, bool, date, datetime, defineComponents, diffPolicy, discriminatedUnion, email, endpoint, enums, explainPermission, extractJsonSchema, id, int, intersect, isFortressSchema, isStandardSchema, literal, loadPolicy, nullType, nullable, num, obj, oneOf, parsePolicyDocument, record, recordOf, ref, resolvePolicyPath, str, strFormat, strict, time, url, uuid, validateRequest };