@udibo/oauth2 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +174 -0
  3. package/SECURITY.md +77 -0
  4. package/esm/_dnt.polyfills.d.ts +17 -0
  5. package/esm/_dnt.polyfills.js +15 -0
  6. package/esm/adapters/hono/_common.d.ts +66 -0
  7. package/esm/adapters/hono/_common.js +108 -0
  8. package/esm/adapters/hono/authorization-server.d.ts +211 -0
  9. package/esm/adapters/hono/authorization-server.js +214 -0
  10. package/esm/adapters/hono/bff/auth-request-store.d.ts +164 -0
  11. package/esm/adapters/hono/bff/auth-request-store.js +154 -0
  12. package/esm/adapters/hono/bff/bff.d.ts +852 -0
  13. package/esm/adapters/hono/bff/bff.js +1194 -0
  14. package/esm/adapters/hono/bff/cookie-prefix.d.ts +72 -0
  15. package/esm/adapters/hono/bff/cookie-prefix.js +85 -0
  16. package/esm/adapters/hono/bff/mod.d.ts +19 -0
  17. package/esm/adapters/hono/bff/mod.js +19 -0
  18. package/esm/adapters/hono/bff/proxy.d.ts +108 -0
  19. package/esm/adapters/hono/bff/proxy.js +314 -0
  20. package/esm/adapters/hono/bff/session-store.d.ts +250 -0
  21. package/esm/adapters/hono/bff/session-store.js +216 -0
  22. package/esm/adapters/hono/bff/testing.d.ts +165 -0
  23. package/esm/adapters/hono/bff/testing.js +254 -0
  24. package/esm/adapters/hono/identity.d.ts +117 -0
  25. package/esm/adapters/hono/identity.js +215 -0
  26. package/esm/adapters/hono/log.d.ts +49 -0
  27. package/esm/adapters/hono/log.js +66 -0
  28. package/esm/adapters/hono/resource-server.d.ts +101 -0
  29. package/esm/adapters/hono/resource-server.js +108 -0
  30. package/esm/client/_http.d.ts +91 -0
  31. package/esm/client/_http.js +303 -0
  32. package/esm/client/base.d.ts +184 -0
  33. package/esm/client/base.js +93 -0
  34. package/esm/client/bff-client.d.ts +235 -0
  35. package/esm/client/bff-client.js +280 -0
  36. package/esm/client/browser-storage.d.ts +152 -0
  37. package/esm/client/browser-storage.js +246 -0
  38. package/esm/client/check.d.ts +114 -0
  39. package/esm/client/check.js +97 -0
  40. package/esm/client/direct-client.d.ts +707 -0
  41. package/esm/client/direct-client.js +1237 -0
  42. package/esm/client/discovery-cache.d.ts +138 -0
  43. package/esm/client/discovery-cache.js +124 -0
  44. package/esm/client/events.d.ts +54 -0
  45. package/esm/client/events.js +37 -0
  46. package/esm/client/mod.d.ts +35 -0
  47. package/esm/client/mod.js +33 -0
  48. package/esm/client/storage.d.ts +127 -0
  49. package/esm/client/storage.js +81 -0
  50. package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.d.ts +29 -0
  51. package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.js +47 -0
  52. package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.d.ts +28 -0
  53. package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.js +65 -0
  54. package/esm/deps/jsr.io/@std/assert/1.0.19/assert.d.ts +16 -0
  55. package/esm/deps/jsr.io/@std/assert/1.0.19/assert.js +23 -0
  56. package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.d.ts +25 -0
  57. package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.js +30 -0
  58. package/esm/deps/jsr.io/@std/assert/1.0.19/equal.d.ts +24 -0
  59. package/esm/deps/jsr.io/@std/assert/1.0.19/equal.js +193 -0
  60. package/esm/deps/jsr.io/@std/assert/1.0.19/equals.d.ts +36 -0
  61. package/esm/deps/jsr.io/@std/assert/1.0.19/equals.js +61 -0
  62. package/esm/deps/jsr.io/@std/assert/1.0.19/exists.d.ts +17 -0
  63. package/esm/deps/jsr.io/@std/assert/1.0.19/exists.js +27 -0
  64. package/esm/deps/jsr.io/@std/assert/1.0.19/fail.d.ts +14 -0
  65. package/esm/deps/jsr.io/@std/assert/1.0.19/fail.js +20 -0
  66. package/esm/deps/jsr.io/@std/assert/1.0.19/false.d.ts +18 -0
  67. package/esm/deps/jsr.io/@std/assert/1.0.19/false.js +23 -0
  68. package/esm/deps/jsr.io/@std/assert/1.0.19/greater.d.ts +19 -0
  69. package/esm/deps/jsr.io/@std/assert/1.0.19/greater.js +29 -0
  70. package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.d.ts +19 -0
  71. package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.js +29 -0
  72. package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.d.ts +22 -0
  73. package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.js +52 -0
  74. package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.d.ts +24 -0
  75. package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.js +53 -0
  76. package/esm/deps/jsr.io/@std/assert/1.0.19/less.d.ts +18 -0
  77. package/esm/deps/jsr.io/@std/assert/1.0.19/less.js +28 -0
  78. package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.d.ts +19 -0
  79. package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.js +29 -0
  80. package/esm/deps/jsr.io/@std/assert/1.0.19/match.d.ts +17 -0
  81. package/esm/deps/jsr.io/@std/assert/1.0.19/match.js +26 -0
  82. package/esm/deps/jsr.io/@std/assert/1.0.19/mod.d.ts +43 -0
  83. package/esm/deps/jsr.io/@std/assert/1.0.19/mod.js +45 -0
  84. package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.d.ts +26 -0
  85. package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.js +39 -0
  86. package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.d.ts +19 -0
  87. package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.js +29 -0
  88. package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.d.ts +17 -0
  89. package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.js +26 -0
  90. package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.d.ts +22 -0
  91. package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.js +32 -0
  92. package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.d.ts +28 -0
  93. package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.js +177 -0
  94. package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.d.ts +41 -0
  95. package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.js +53 -0
  96. package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.d.ts +23 -0
  97. package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.js +58 -0
  98. package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.d.ts +17 -0
  99. package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.js +26 -0
  100. package/esm/deps/jsr.io/@std/assert/1.0.19/throws.d.ts +44 -0
  101. package/esm/deps/jsr.io/@std/assert/1.0.19/throws.js +44 -0
  102. package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.d.ts +14 -0
  103. package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.js +20 -0
  104. package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.d.ts +14 -0
  105. package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.js +20 -0
  106. package/esm/deps/jsr.io/@std/async/1.5.0/delay.d.ts +44 -0
  107. package/esm/deps/jsr.io/@std/async/1.5.0/delay.js +84 -0
  108. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.d.ts +39 -0
  109. package/esm/deps/jsr.io/@std/crypto/1.1.0/timing_safe_equal.js +61 -0
  110. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.d.ts +22 -0
  111. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common16.js +51 -0
  112. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.d.ts +34 -0
  113. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common32.js +192 -0
  114. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.d.ts +34 -0
  115. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common64.js +113 -0
  116. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.d.ts +3 -0
  117. package/esm/deps/jsr.io/@std/encoding/1.0.11/_common_detach.js +13 -0
  118. package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.d.ts +8 -0
  119. package/esm/deps/jsr.io/@std/encoding/1.0.11/_types.js +2 -0
  120. package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.d.ts +1 -0
  121. package/esm/deps/jsr.io/@std/encoding/1.0.11/_validate_binary_like.js +26 -0
  122. package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.d.ts +60 -0
  123. package/esm/deps/jsr.io/@std/encoding/1.0.11/ascii85.js +152 -0
  124. package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.d.ts +39 -0
  125. package/esm/deps/jsr.io/@std/encoding/1.0.11/base32.js +87 -0
  126. package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.d.ts +39 -0
  127. package/esm/deps/jsr.io/@std/encoding/1.0.11/base58.js +131 -0
  128. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.d.ts +39 -0
  129. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64.js +82 -0
  130. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.d.ts +39 -0
  131. package/esm/deps/jsr.io/@std/encoding/1.0.11/base64url.js +72 -0
  132. package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.d.ts +38 -0
  133. package/esm/deps/jsr.io/@std/encoding/1.0.11/hex.js +87 -0
  134. package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.d.ts +97 -0
  135. package/esm/deps/jsr.io/@std/encoding/1.0.11/mod.js +99 -0
  136. package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.d.ts +119 -0
  137. package/esm/deps/jsr.io/@std/encoding/1.0.11/varint.js +209 -0
  138. package/esm/deps/jsr.io/@std/http/1.1.3/status.d.ts +343 -0
  139. package/esm/deps/jsr.io/@std/http/1.1.3/status.js +343 -0
  140. package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.d.ts +159 -0
  141. package/esm/deps/jsr.io/@std/internal/1.0.14/assertion_state.js +223 -0
  142. package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.d.ts +79 -0
  143. package/esm/deps/jsr.io/@std/internal/1.0.14/build_message.js +116 -0
  144. package/esm/deps/jsr.io/@std/internal/1.0.14/diff.d.ts +139 -0
  145. package/esm/deps/jsr.io/@std/internal/1.0.14/diff.js +277 -0
  146. package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.d.ts +98 -0
  147. package/esm/deps/jsr.io/@std/internal/1.0.14/diff_str.js +181 -0
  148. package/esm/deps/jsr.io/@std/internal/1.0.14/format.d.ts +29 -0
  149. package/esm/deps/jsr.io/@std/internal/1.0.14/format.js +68 -0
  150. package/esm/deps/jsr.io/@std/internal/1.0.14/styles.d.ts +158 -0
  151. package/esm/deps/jsr.io/@std/internal/1.0.14/styles.js +206 -0
  152. package/esm/deps/jsr.io/@std/internal/1.0.14/types.d.ts +24 -0
  153. package/esm/deps/jsr.io/@std/internal/1.0.14/types.js +3 -0
  154. package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.d.ts +91 -0
  155. package/esm/deps/jsr.io/@std/testing/1.0.20/_test_suite.js +347 -0
  156. package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.d.ts +382 -0
  157. package/esm/deps/jsr.io/@std/testing/1.0.20/bdd.js +1110 -0
  158. package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.d.ts +363 -0
  159. package/esm/deps/jsr.io/@udibo/http-error/0.11.1/mod.js +616 -0
  160. package/esm/errors.d.ts +203 -0
  161. package/esm/errors.js +287 -0
  162. package/esm/identity/captcha.d.ts +147 -0
  163. package/esm/identity/captcha.js +64 -0
  164. package/esm/identity/delivery.d.ts +96 -0
  165. package/esm/identity/delivery.js +41 -0
  166. package/esm/identity/errors.d.ts +39 -0
  167. package/esm/identity/errors.js +46 -0
  168. package/esm/identity/events.d.ts +242 -0
  169. package/esm/identity/events.js +39 -0
  170. package/esm/identity/external/_shared.d.ts +86 -0
  171. package/esm/identity/external/_shared.js +107 -0
  172. package/esm/identity/external/_token-exchange.d.ts +61 -0
  173. package/esm/identity/external/_token-exchange.js +179 -0
  174. package/esm/identity/external/apple-client-secret.d.ts +82 -0
  175. package/esm/identity/external/apple-client-secret.js +133 -0
  176. package/esm/identity/external/apple.d.ts +64 -0
  177. package/esm/identity/external/apple.js +248 -0
  178. package/esm/identity/external/discord.d.ts +38 -0
  179. package/esm/identity/external/discord.js +62 -0
  180. package/esm/identity/external/errors.d.ts +48 -0
  181. package/esm/identity/external/errors.js +36 -0
  182. package/esm/identity/external/flow.d.ts +107 -0
  183. package/esm/identity/external/flow.js +158 -0
  184. package/esm/identity/external/github.d.ts +42 -0
  185. package/esm/identity/external/github.js +164 -0
  186. package/esm/identity/external/google.d.ts +52 -0
  187. package/esm/identity/external/google.js +38 -0
  188. package/esm/identity/external/mod.d.ts +63 -0
  189. package/esm/identity/external/mod.js +61 -0
  190. package/esm/identity/external/oauth2.d.ts +110 -0
  191. package/esm/identity/external/oauth2.js +158 -0
  192. package/esm/identity/external/oidc.d.ts +81 -0
  193. package/esm/identity/external/oidc.js +250 -0
  194. package/esm/identity/external/provider.d.ts +132 -0
  195. package/esm/identity/external/provider.js +12 -0
  196. package/esm/identity/hibp.d.ts +67 -0
  197. package/esm/identity/hibp.js +87 -0
  198. package/esm/identity/identifier.d.ts +44 -0
  199. package/esm/identity/identifier.js +47 -0
  200. package/esm/identity/lockout.d.ts +155 -0
  201. package/esm/identity/lockout.js +117 -0
  202. package/esm/identity/mfa/mod.d.ts +42 -0
  203. package/esm/identity/mfa/mod.js +42 -0
  204. package/esm/identity/mfa/recovery-codes.d.ts +96 -0
  205. package/esm/identity/mfa/recovery-codes.js +80 -0
  206. package/esm/identity/mfa/service.d.ts +338 -0
  207. package/esm/identity/mfa/service.js +351 -0
  208. package/esm/identity/mfa/totp.d.ts +186 -0
  209. package/esm/identity/mfa/totp.js +194 -0
  210. package/esm/identity/migration.d.ts +155 -0
  211. package/esm/identity/migration.js +243 -0
  212. package/esm/identity/mod.d.ts +65 -0
  213. package/esm/identity/mod.js +64 -0
  214. package/esm/identity/otp.d.ts +255 -0
  215. package/esm/identity/otp.js +245 -0
  216. package/esm/identity/password-policy.d.ts +45 -0
  217. package/esm/identity/password-policy.js +60 -0
  218. package/esm/identity/password.d.ts +171 -0
  219. package/esm/identity/password.js +160 -0
  220. package/esm/identity/rate-limit.d.ts +192 -0
  221. package/esm/identity/rate-limit.js +168 -0
  222. package/esm/identity/service.d.ts +579 -0
  223. package/esm/identity/service.js +835 -0
  224. package/esm/identity/session.d.ts +122 -0
  225. package/esm/identity/session.js +48 -0
  226. package/esm/identity/token-flow.d.ts +214 -0
  227. package/esm/identity/token-flow.js +173 -0
  228. package/esm/models/authentication.d.ts +24 -0
  229. package/esm/models/authentication.js +1 -0
  230. package/esm/models/authorization-code.d.ts +63 -0
  231. package/esm/models/authorization-code.js +1 -0
  232. package/esm/models/authorization.d.ts +165 -0
  233. package/esm/models/authorization.js +160 -0
  234. package/esm/models/client.d.ts +78 -0
  235. package/esm/models/client.js +1 -0
  236. package/esm/models/device-authorization.d.ts +30 -0
  237. package/esm/models/device-authorization.js +1 -0
  238. package/esm/models/responses.d.ts +93 -0
  239. package/esm/models/responses.js +1 -0
  240. package/esm/models/scope.d.ts +81 -0
  241. package/esm/models/scope.js +125 -0
  242. package/esm/models/token.d.ts +135 -0
  243. package/esm/models/token.js +1 -0
  244. package/esm/package.json +3 -0
  245. package/esm/react/callback.d.ts +52 -0
  246. package/esm/react/callback.js +71 -0
  247. package/esm/react/components/class-names.d.ts +91 -0
  248. package/esm/react/components/class-names.js +118 -0
  249. package/esm/react/components/internal.d.ts +62 -0
  250. package/esm/react/components/internal.js +102 -0
  251. package/esm/react/components/mfa-challenge-form.d.ts +66 -0
  252. package/esm/react/components/mfa-challenge-form.js +46 -0
  253. package/esm/react/components/mfa-enrollment-form.d.ts +83 -0
  254. package/esm/react/components/mfa-enrollment-form.js +41 -0
  255. package/esm/react/components/mod.d.ts +103 -0
  256. package/esm/react/components/mod.js +93 -0
  257. package/esm/react/components/request-password-reset-form.d.ts +61 -0
  258. package/esm/react/components/request-password-reset-form.js +41 -0
  259. package/esm/react/components/reset-password-form.d.ts +66 -0
  260. package/esm/react/components/reset-password-form.js +56 -0
  261. package/esm/react/components/sign-in-form.d.ts +74 -0
  262. package/esm/react/components/sign-in-form.js +43 -0
  263. package/esm/react/components/sign-up-form.d.ts +85 -0
  264. package/esm/react/components/sign-up-form.js +57 -0
  265. package/esm/react/components/types.d.ts +208 -0
  266. package/esm/react/components/types.js +14 -0
  267. package/esm/react/components/use-auth-form.d.ts +118 -0
  268. package/esm/react/components/use-auth-form.js +172 -0
  269. package/esm/react/components/user-menu.d.ts +79 -0
  270. package/esm/react/components/user-menu.js +73 -0
  271. package/esm/react/context.d.ts +51 -0
  272. package/esm/react/context.js +16 -0
  273. package/esm/react/mod.d.ts +26 -0
  274. package/esm/react/mod.js +26 -0
  275. package/esm/react/provider.d.ts +40 -0
  276. package/esm/react/provider.js +189 -0
  277. package/esm/react/require-auth.d.ts +31 -0
  278. package/esm/react/require-auth.js +37 -0
  279. package/esm/react/testing.d.ts +322 -0
  280. package/esm/react/testing.js +461 -0
  281. package/esm/react/use-authorization.d.ts +31 -0
  282. package/esm/react/use-authorization.js +36 -0
  283. package/esm/react/use-oauth2.d.ts +112 -0
  284. package/esm/react/use-oauth2.js +127 -0
  285. package/esm/server/authorization-server.d.ts +736 -0
  286. package/esm/server/authorization-server.js +1304 -0
  287. package/esm/server/client-authentication.d.ts +28 -0
  288. package/esm/server/client-authentication.js +51 -0
  289. package/esm/server/grants/authorization-code.d.ts +179 -0
  290. package/esm/server/grants/authorization-code.js +232 -0
  291. package/esm/server/grants/client-credentials.d.ts +52 -0
  292. package/esm/server/grants/client-credentials.js +53 -0
  293. package/esm/server/grants/device-authorization.d.ts +103 -0
  294. package/esm/server/grants/device-authorization.js +156 -0
  295. package/esm/server/grants/grant.d.ts +165 -0
  296. package/esm/server/grants/grant.js +173 -0
  297. package/esm/server/grants/password.d.ts +80 -0
  298. package/esm/server/grants/password.js +92 -0
  299. package/esm/server/grants/refresh-token.d.ts +80 -0
  300. package/esm/server/grants/refresh-token.js +136 -0
  301. package/esm/server/introspection-token-reader.d.ts +153 -0
  302. package/esm/server/introspection-token-reader.js +164 -0
  303. package/esm/server/jwks-token-reader.d.ts +263 -0
  304. package/esm/server/jwks-token-reader.js +508 -0
  305. package/esm/server/mod.d.ts +23 -0
  306. package/esm/server/mod.js +15 -0
  307. package/esm/server/public-suffix/mod.d.ts +62 -0
  308. package/esm/server/public-suffix/mod.js +103 -0
  309. package/esm/server/public-suffix/rules.d.ts +23 -0
  310. package/esm/server/public-suffix/rules.js +23 -0
  311. package/esm/server/redirect-uri.d.ts +187 -0
  312. package/esm/server/redirect-uri.js +331 -0
  313. package/esm/server/resource-server.d.ts +286 -0
  314. package/esm/server/resource-server.js +365 -0
  315. package/esm/server/services/authorization-code.d.ts +84 -0
  316. package/esm/server/services/authorization-code.js +35 -0
  317. package/esm/server/services/client.d.ts +35 -0
  318. package/esm/server/services/client.js +1 -0
  319. package/esm/server/services/device-authorization.d.ts +134 -0
  320. package/esm/server/services/device-authorization.js +7 -0
  321. package/esm/server/services/token.d.ts +242 -0
  322. package/esm/server/services/token.js +78 -0
  323. package/esm/server/services/user.d.ts +29 -0
  324. package/esm/server/services/user.js +7 -0
  325. package/esm/server/signing-keys.d.ts +201 -0
  326. package/esm/server/signing-keys.js +225 -0
  327. package/esm/server/utils/hash.d.ts +6 -0
  328. package/esm/server/utils/hash.js +11 -0
  329. package/esm/testing/contract/authorization-code.d.ts +37 -0
  330. package/esm/testing/contract/authorization-code.js +93 -0
  331. package/esm/testing/contract/client.d.ts +85 -0
  332. package/esm/testing/contract/client.js +126 -0
  333. package/esm/testing/contract/device-authorization.d.ts +37 -0
  334. package/esm/testing/contract/device-authorization.js +193 -0
  335. package/esm/testing/contract/lockout-store.d.ts +47 -0
  336. package/esm/testing/contract/lockout-store.js +122 -0
  337. package/esm/testing/contract/mfa-store.d.ts +50 -0
  338. package/esm/testing/contract/mfa-store.js +226 -0
  339. package/esm/testing/contract/mod.d.ts +39 -0
  340. package/esm/testing/contract/mod.js +39 -0
  341. package/esm/testing/contract/otp-store.d.ts +48 -0
  342. package/esm/testing/contract/otp-store.js +197 -0
  343. package/esm/testing/contract/rate-limit-store.d.ts +52 -0
  344. package/esm/testing/contract/rate-limit-store.js +105 -0
  345. package/esm/testing/contract/token-flow-store.d.ts +54 -0
  346. package/esm/testing/contract/token-flow-store.js +179 -0
  347. package/esm/testing/contract/token-reader.d.ts +77 -0
  348. package/esm/testing/contract/token-reader.js +78 -0
  349. package/esm/testing/contract/token.d.ts +61 -0
  350. package/esm/testing/contract/token.js +287 -0
  351. package/esm/testing/contract/user.d.ts +63 -0
  352. package/esm/testing/contract/user.js +75 -0
  353. package/esm/testing/mod.d.ts +34 -0
  354. package/esm/testing/mod.js +34 -0
  355. package/esm/testing/server.d.ts +197 -0
  356. package/esm/testing/server.js +193 -0
  357. package/esm/testing/services.d.ts +373 -0
  358. package/esm/testing/services.js +703 -0
  359. package/esm/utils/_buffer.d.ts +10 -0
  360. package/esm/utils/_buffer.js +12 -0
  361. package/esm/utils/_timing-safe.d.ts +13 -0
  362. package/esm/utils/_timing-safe.js +22 -0
  363. package/esm/utils/authentication-context.d.ts +3 -0
  364. package/esm/utils/authentication-context.js +14 -0
  365. package/esm/utils/basic-auth.d.ts +50 -0
  366. package/esm/utils/basic-auth.js +106 -0
  367. package/esm/utils/crypto.d.ts +97 -0
  368. package/esm/utils/crypto.js +162 -0
  369. package/esm/utils/pkce.d.ts +151 -0
  370. package/esm/utils/pkce.js +179 -0
  371. package/esm/utils/text.d.ts +24 -0
  372. package/esm/utils/text.js +28 -0
  373. package/esm/utils/url.d.ts +66 -0
  374. package/esm/utils/url.js +90 -0
  375. package/package.json +92 -0
@@ -0,0 +1,125 @@
1
+ import { InvalidScopeError } from "../errors.js";
2
+ /** NQCHAR as defined in RFC 6749. */
3
+ export const NQCHAR = /[\x21\x23-\x5b\x5d-\x7e]/;
4
+ /** Regex for validating a scope string. */
5
+ export const SCOPE = new RegExp(`^(?:(?:${NQCHAR.source}+)(?: ${NQCHAR.source}+)*)?$`);
6
+ /** Regex for extracting scope tokens. */
7
+ export const SCOPE_TOKEN = new RegExp(`${NQCHAR.source}+`, "g");
8
+ /**
9
+ * Base class for OAuth2 scope implementations.
10
+ *
11
+ * Provides the contract that the authorization server, grants, and adapters
12
+ * rely on. Users who want a custom scope type (e.g. one that enforces a
13
+ * fixed vocabulary, or one that encodes hierarchical scopes) can extend
14
+ * this class; the framework only requires a constructor that accepts an
15
+ * optional scope string and the instance methods declared here.
16
+ *
17
+ * The default implementation is {@link BasicScope}; it stores a set of
18
+ * space-delimited NQCHAR tokens per RFC 6749 Section 3.3.
19
+ */
20
+ export class AbstractScope {
21
+ }
22
+ /** A basic implementation of OAuth2 scope. */
23
+ export class BasicScope extends AbstractScope {
24
+ stringCache;
25
+ tokens;
26
+ /**
27
+ * Parses a space-delimited scope string into its tokens.
28
+ *
29
+ * @throws {InvalidScopeError} If `scope` contains characters outside the
30
+ * RFC 6749 NQCHAR set.
31
+ */
32
+ constructor(scope) {
33
+ super();
34
+ if (scope && !SCOPE.test(scope)) {
35
+ throw new InvalidScopeError("invalid scope");
36
+ }
37
+ this.tokens = scope ? new Set(scope.match(SCOPE_TOKEN)) : new Set();
38
+ }
39
+ /** Creates a new scope from a scope. */
40
+ static from(scope) {
41
+ if (typeof scope === "string")
42
+ return new BasicScope(scope);
43
+ const result = new BasicScope();
44
+ result.add(scope);
45
+ return result;
46
+ }
47
+ /** Creates a new scope with all scope tokens from both scopes. */
48
+ static union(a, b) {
49
+ return BasicScope.from(a).add(b);
50
+ }
51
+ /** Creates a new scope with all scope tokens that are present in both scopes. */
52
+ static intersection(a, b) {
53
+ const result = new BasicScope();
54
+ const scopeA = typeof a === "string" ? new BasicScope(a) : a;
55
+ const scopeB = typeof b === "string" ? new BasicScope(b) : b;
56
+ for (const token of scopeA) {
57
+ if (scopeB.tokens.has(token))
58
+ result.tokens.add(token);
59
+ }
60
+ return result;
61
+ }
62
+ /** Deletes all scope tokens from this scope. */
63
+ clear() {
64
+ this.tokens = new Set();
65
+ delete this.stringCache;
66
+ return this;
67
+ }
68
+ /** Adds all scope tokens in the passed in scope to this scope. */
69
+ add(scope) {
70
+ const other = typeof scope === "string" ? new BasicScope(scope) : scope;
71
+ for (const token of other) {
72
+ this.tokens.add(token);
73
+ }
74
+ delete this.stringCache;
75
+ return this;
76
+ }
77
+ /** Removes all scope tokens in the passed in scope from this scope. */
78
+ remove(scope) {
79
+ const other = typeof scope === "string" ? new BasicScope(scope) : scope;
80
+ for (const token of other) {
81
+ this.tokens.delete(token);
82
+ }
83
+ delete this.stringCache;
84
+ return this;
85
+ }
86
+ /** Checks that this scope has all scope tokens in the passed in scope. */
87
+ has(scope) {
88
+ const other = typeof scope === "string" ? new BasicScope(scope) : scope;
89
+ for (const token of other) {
90
+ if (!this.tokens.has(token))
91
+ return false;
92
+ }
93
+ return true;
94
+ }
95
+ /** Checks that this scope is equal to the passed in scope. */
96
+ equals(scope) {
97
+ const other = typeof scope === "string" ? new BasicScope(scope) : scope;
98
+ if (this.tokens.size !== other.size)
99
+ return false;
100
+ for (const token of other) {
101
+ if (!this.tokens.has(token))
102
+ return false;
103
+ }
104
+ return true;
105
+ }
106
+ /** Returns the number of scope tokens. */
107
+ get size() {
108
+ return this.tokens.size;
109
+ }
110
+ /** Converts the scope to a string representation. */
111
+ toString() {
112
+ if (typeof this.stringCache !== "string") {
113
+ this.stringCache = [...this].join(" ");
114
+ }
115
+ return this.stringCache;
116
+ }
117
+ /** Converts the scope to a JSON representation. */
118
+ toJSON() {
119
+ return this.toString();
120
+ }
121
+ /** Iterates the scope's tokens in insertion order. */
122
+ *[Symbol.iterator]() {
123
+ yield* this.tokens.values();
124
+ }
125
+ }
@@ -0,0 +1,135 @@
1
+ import type { AbstractScope, BasicScope } from "./scope.js";
2
+ import type { ClientInterface } from "./client.js";
3
+ import type { AuthenticationContext } from "./authentication.js";
4
+ /**
5
+ * Token model representing an access token.
6
+ *
7
+ * Returned by the token services and the resource server, and part of the
8
+ * public `TokenServiceInterface` / `TokenReaderInterface` surface that
9
+ * consumers implement. The generic parameters allow customizing the client,
10
+ * user, and scope types.
11
+ */
12
+ export interface Token<Client extends ClientInterface, User, Scope extends AbstractScope = BasicScope> {
13
+ /** The access token string. */
14
+ accessToken: string;
15
+ /** When the access token expires. */
16
+ accessTokenExpiresAt?: Date;
17
+ /** The client this token was issued to. */
18
+ client: Client;
19
+ /** The user this token was issued for (if applicable). */
20
+ user?: User;
21
+ /** The scope granted to this token. */
22
+ scope?: Scope | null;
23
+ /**
24
+ * The verified claims this token carried, when the reader that produced it
25
+ * had them — a validated JWT's payload, or an introspection response. The
26
+ * resource server builds its `Authorization` from these; a DB-backed token
27
+ * service may leave them unset, which yields an authorization with scope
28
+ * only.
29
+ */
30
+ claims?: Record<string, unknown>;
31
+ /** The authorization code used to generate this token, for replay detection per RFC 6819. */
32
+ code?: string;
33
+ /**
34
+ * OIDC nonce carried transiently from the authorization code so the token
35
+ * endpoint can echo it in the id_token. Not persisted by token stores.
36
+ */
37
+ nonce?: string;
38
+ /**
39
+ * Immutable event inherited from the code or refresh ancestor. Token stores
40
+ * must persist and restore it; never reconstruct it from the current session.
41
+ * Machine credentials omit it.
42
+ */
43
+ authenticationContext?: AuthenticationContext;
44
+ }
45
+ /** Token with refresh token capability. */
46
+ export interface RefreshToken<Client extends ClientInterface, User, Scope extends AbstractScope = BasicScope> extends Token<Client, User, Scope> {
47
+ /** The refresh token string. */
48
+ refreshToken: string;
49
+ /** When the refresh token expires. */
50
+ refreshTokenExpiresAt?: Date;
51
+ /**
52
+ * The rotation family this refresh token belongs to: assigned at first
53
+ * issuance and inherited by every rotation, so replay of a rotated-out
54
+ * member can revoke the whole family (reuse detection).
55
+ */
56
+ familyId?: string;
57
+ /**
58
+ * When the rotation family was first issued: set alongside
59
+ * {@linkcode RefreshToken.familyId} at first issuance and carried unchanged
60
+ * through every rotation. It anchors the absolute cap
61
+ * ({@linkcode TokenServiceInterface.refreshTokenFamilyExpiresAt}), so a token
62
+ * service that persists refresh tokens **must** persist and restore it —
63
+ * dropping it on the round trip disables the cap.
64
+ *
65
+ * A record without an anchor (one stored before the cap existed) rotates
66
+ * once uncapped; that rotation is issued with a fresh anchor, so the family
67
+ * is capped from then on.
68
+ */
69
+ familyCreatedAt?: Date;
70
+ }
71
+ /**
72
+ * Standard OAuth2 token response.
73
+ *
74
+ * Returned by the token endpoint as defined in RFC 6749 Section 5.1.
75
+ *
76
+ * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
77
+ */
78
+ export interface TokenResponse {
79
+ /** Always "Bearer" for OAuth2 Bearer tokens. */
80
+ token_type: "Bearer";
81
+ /** The access token issued by the authorization server. */
82
+ access_token: string;
83
+ /** Token lifetime in seconds. */
84
+ expires_in?: number;
85
+ /** Refresh token for obtaining new access tokens. */
86
+ refresh_token?: string;
87
+ /** Space-delimited list of granted scopes. */
88
+ scope?: string;
89
+ /** OIDC ID Token, present when the `openid` scope was granted to a user. */
90
+ id_token?: string;
91
+ }
92
+ /**
93
+ * Token introspection response as defined in RFC 7662.
94
+ *
95
+ * Used by resource servers to query the authorization server
96
+ * about the state of an access token. Authorization servers MAY
97
+ * include additional extension fields; the index signature exposes
98
+ * them to mapping functions like
99
+ * {@linkcode IntrospectionTokenReaderOptions.getClient}.
100
+ *
101
+ * @see https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
102
+ */
103
+ export interface IntrospectionResponse {
104
+ /** Whether the token is currently active. */
105
+ active: boolean;
106
+ /** Space-delimited list of scopes associated with the token. */
107
+ scope?: string;
108
+ /** Client identifier for the OAuth2 client that requested the token. */
109
+ client_id?: string;
110
+ /** Human-readable identifier for the resource owner. */
111
+ username?: string;
112
+ /** Type of the token (e.g., "Bearer"). */
113
+ token_type?: string;
114
+ /** Token expiration time (Unix timestamp). */
115
+ exp?: number;
116
+ /** Token issue time (Unix timestamp). */
117
+ iat?: number;
118
+ /** Token not-before time (Unix timestamp). */
119
+ nbf?: number;
120
+ /**
121
+ * Subject identifier — the resource owner. Absent for a machine token
122
+ * issued without a user (client credentials): its `client_id` identifies
123
+ * the caller, and the missing `sub` marks that no resource owner is behind
124
+ * the token.
125
+ */
126
+ sub?: string;
127
+ /** Audience(s) the token is intended for. */
128
+ aud?: string | string[];
129
+ /** Issuer of the token. */
130
+ iss?: string;
131
+ /** Unique token identifier. */
132
+ jti?: string;
133
+ /** Extension fields. RFC 7662 allows servers to add their own claims. */
134
+ [extension: string]: unknown;
135
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * `<OAuth2Callback>` — mount on the SPA's callback route when the app runs a
3
+ * `DirectClient`. Calls `client.handleAuthorizationCallback` with the current
4
+ * URL, then navigates to the captured `returnTo`.
5
+ *
6
+ * Not for a `BffClient` app — the BFF owns `/auth/callback` there, and this
7
+ * component renders its `fallback` with a clear error rather than pretend
8
+ * otherwise.
9
+ *
10
+ * Idempotent against React 18 strict-mode double-mounts because the
11
+ * client itself dedupes by `code` — the second invocation returns the
12
+ * first call's promise.
13
+ *
14
+ * @module
15
+ */
16
+ import { type ReactNode } from "react";
17
+ import { type OAuth2Error } from "../client/mod.js";
18
+ /** Props for {@link OAuth2Callback}. */
19
+ export interface OAuth2CallbackProps {
20
+ /**
21
+ * Optional navigation hook. Receives the captured `returnTo` (or
22
+ * `"/"` if the original request didn't carry one). Use this to
23
+ * delegate to your router (`react-router`, `tanstack-router`,
24
+ * `wouter`, …). Defaults to
25
+ * `history.replaceState(null, "", returnTo)` so the auth params drop
26
+ * out of the URL bar without a full page navigation.
27
+ */
28
+ onNavigate?: (returnTo: string) => void;
29
+ /**
30
+ * Renders during the in-flight code exchange. Defaults to `null`.
31
+ */
32
+ pending?: ReactNode;
33
+ /**
34
+ * Renders if the callback fails. Defaults to a plain `<pre>` with the
35
+ * message.
36
+ *
37
+ * The error is always a real {@link OAuth2Error}, so `extensions` is safe to
38
+ * read: a failure the authorization server did not describe — a bookmarked
39
+ * callback route with no `code`, an undecodable `id_token` — arrives wrapped
40
+ * as `server_error` with the original error as its `cause`.
41
+ */
42
+ fallback?: (error: OAuth2Error) => ReactNode;
43
+ }
44
+ /**
45
+ * Mount on the callback route. Exchanges the code, then navigates to
46
+ * `returnTo`.
47
+ *
48
+ * @param props Optional navigation hook plus pending / error renderers.
49
+ * @returns The pending node while the exchange is in flight, the fallback on
50
+ * failure, and nothing once it has navigated.
51
+ */
52
+ export declare function OAuth2Callback(props: OAuth2CallbackProps): ReactNode;
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // deno-lint-ignore-file no-window -- browser-only; `window` used only after isBrowser() guards
3
+ /**
4
+ * `<OAuth2Callback>` — mount on the SPA's callback route when the app runs a
5
+ * `DirectClient`. Calls `client.handleAuthorizationCallback` with the current
6
+ * URL, then navigates to the captured `returnTo`.
7
+ *
8
+ * Not for a `BffClient` app — the BFF owns `/auth/callback` there, and this
9
+ * component renders its `fallback` with a clear error rather than pretend
10
+ * otherwise.
11
+ *
12
+ * Idempotent against React 18 strict-mode double-mounts because the
13
+ * client itself dedupes by `code` — the second invocation returns the
14
+ * first call's promise.
15
+ *
16
+ * @module
17
+ */
18
+ import { useEffect, useRef, useState } from "react";
19
+ import { DirectClient } from "../client/mod.js";
20
+ import { ServerError, toOAuth2Error } from "../errors.js";
21
+ import { useOAuth2 } from "./use-oauth2.js";
22
+ const isBrowser = () => typeof window !== "undefined";
23
+ const defaultNavigate = (returnTo) => {
24
+ if (!isBrowser())
25
+ return;
26
+ window.history.replaceState(null, "", returnTo);
27
+ };
28
+ const defaultFallback = (error) => (_jsx("pre", { style: { color: "red" }, children: error.message }));
29
+ /**
30
+ * Mount on the callback route. Exchanges the code, then navigates to
31
+ * `returnTo`.
32
+ *
33
+ * @param props Optional navigation hook plus pending / error renderers.
34
+ * @returns The pending node while the exchange is in flight, the fallback on
35
+ * failure, and nothing once it has navigated.
36
+ */
37
+ export function OAuth2Callback(props) {
38
+ const { onNavigate = defaultNavigate, pending = null, fallback = defaultFallback, } = props;
39
+ const { client } = useOAuth2();
40
+ const [error, setError] = useState(null);
41
+ // Ref so the exchange effect depends only on `client`; a non-memoized
42
+ // `onNavigate` must not re-run it after `code` is stripped from the URL.
43
+ const onNavigateRef = useRef(onNavigate);
44
+ onNavigateRef.current = onNavigate;
45
+ useEffect(() => {
46
+ if (!isBrowser())
47
+ return;
48
+ if (!(client instanceof DirectClient)) {
49
+ setError(new ServerError("<OAuth2Callback> needs the provider's client to be a " +
50
+ `DirectClient, but it is a ${client.constructor.name}. Behind a ` +
51
+ "BffClient the BFF owns the callback route."));
52
+ return;
53
+ }
54
+ let cancelled = false;
55
+ client.handleAuthorizationCallback(window.location.href).then((result) => {
56
+ if (cancelled)
57
+ return;
58
+ onNavigateRef.current(result.returnTo ?? "/");
59
+ }, (err) => {
60
+ if (cancelled)
61
+ return;
62
+ setError(toOAuth2Error(err));
63
+ });
64
+ return () => {
65
+ cancelled = true;
66
+ };
67
+ }, [client]);
68
+ if (error)
69
+ return fallback(error);
70
+ return pending;
71
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The styling seam shared by the prebuilt auth forms
3
+ * (`@udibo/oauth2/react/components`): a React context carrying the per-slot
4
+ * class map ({@link AuthFormClassNames}), so the elements inside a form read
5
+ * their classes from the tree rather than from a `classNames` prop threaded
6
+ * through every wrapper.
7
+ *
8
+ * Wrap a subtree in {@link AuthFormClassNamesProvider} to theme every form
9
+ * under it at once, and read the map in effect from your own components with
10
+ * {@link useAuthFormClassNames}.
11
+ *
12
+ * @module
13
+ */
14
+ import { type ReactNode } from "react";
15
+ import type { AuthFormClassNames } from "./types.js";
16
+ /**
17
+ * Resolves the per-slot class map for this position in the tree: the nearest
18
+ * {@link AuthFormClassNamesProvider}'s map with `overrides` applied slot by
19
+ * slot. An absent or `undefined` slot in `overrides` keeps the inherited value,
20
+ * and with no provider above the map is empty (every slot `undefined`), so the
21
+ * hook is safe to call anywhere. This is the only place the precedence rule is
22
+ * implemented.
23
+ *
24
+ * The result is cached on the slot values, so passing a fresh `overrides`
25
+ * literal every render returns the identical map.
26
+ *
27
+ * Call it with no argument from a component rendered **inside** a form to read
28
+ * the theme in effect; call it with a component's own `classNames` prop to
29
+ * resolve the map that component should both render with and publish.
30
+ *
31
+ * @param overrides Per-slot classes that win over the inherited map.
32
+ * @returns The resolved map, keyed by {@link AuthFormClassNames} slot.
33
+ *
34
+ * @example Theme a custom field to match the form around it
35
+ * ```tsx
36
+ * function TenantField(props: { fieldProps: AuthFieldProps }) {
37
+ * const classNames = useAuthFormClassNames();
38
+ * return (
39
+ * <div className={classNames.field}>
40
+ * <label className={classNames.label} htmlFor={props.fieldProps.id}>
41
+ * Tenant
42
+ * </label>
43
+ * <input {...props.fieldProps} className={classNames.input} />
44
+ * </div>
45
+ * );
46
+ * }
47
+ * ```
48
+ */
49
+ export declare function useAuthFormClassNames(overrides?: AuthFormClassNames): Readonly<AuthFormClassNames>;
50
+ /**
51
+ * Publishes an already-resolved map verbatim, without merging. A form and
52
+ * `AuthFormShell` resolve once through {@link useAuthFormClassNames} and
53
+ * publish through this, so the precedence rule keeps exactly one
54
+ * implementation. App code wants {@link AuthFormClassNamesProvider}.
55
+ */
56
+ export declare function AuthFormClassNamesScope(props: {
57
+ classNames: Readonly<AuthFormClassNames>;
58
+ children?: ReactNode;
59
+ }): ReactNode;
60
+ /** Props for {@link AuthFormClassNamesProvider}. */
61
+ export interface AuthFormClassNamesProviderProps {
62
+ /** Per-slot classes to publish to `children`. See {@link AuthFormClassNames}. */
63
+ classNames: AuthFormClassNames;
64
+ /** The subtree the map applies to. */
65
+ children?: ReactNode;
66
+ }
67
+ /**
68
+ * Publishes a per-slot class map to every prebuilt auth form in `children`, so
69
+ * an app themes its whole auth surface once instead of repeating the same
70
+ * `classNames` on each form. Providers nest: an inner provider — or a form's
71
+ * own `classNames` prop — overrides the inherited map slot by slot, leaving the
72
+ * slots it does not name intact.
73
+ *
74
+ * It themes the auth **forms**; `UserMenu` is deliberately outside its reach
75
+ * and takes its classes from its own `className` / `classNames` props.
76
+ *
77
+ * An inline `classNames` literal is fine here — the published map is cached on
78
+ * the slot values rather than on the object's identity, so re-rendering with an
79
+ * equal literal hands the forms below the identical map.
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * <AuthFormClassNamesProvider
84
+ * classNames={{ input: "input", submit: "btn btn-primary" }}
85
+ * >
86
+ * <SignInForm onSubmit={signIn} />
87
+ * <SignUpForm onSubmit={signUp} />
88
+ * </AuthFormClassNamesProvider>
89
+ * ```
90
+ */
91
+ export declare function AuthFormClassNamesProvider(props: AuthFormClassNamesProviderProps): ReactNode;
@@ -0,0 +1,118 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * The styling seam shared by the prebuilt auth forms
4
+ * (`@udibo/oauth2/react/components`): a React context carrying the per-slot
5
+ * class map ({@link AuthFormClassNames}), so the elements inside a form read
6
+ * their classes from the tree rather than from a `classNames` prop threaded
7
+ * through every wrapper.
8
+ *
9
+ * Wrap a subtree in {@link AuthFormClassNamesProvider} to theme every form
10
+ * under it at once, and read the map in effect from your own components with
11
+ * {@link useAuthFormClassNames}.
12
+ *
13
+ * @module
14
+ */
15
+ import { createContext, useContext, useRef } from "react";
16
+ const EMPTY_CLASS_NAMES = Object.freeze({});
17
+ const AuthFormClassNamesContext = createContext(EMPTY_CLASS_NAMES);
18
+ function merge(inherited, overrides) {
19
+ const resolved = { ...inherited };
20
+ for (const [slot, value] of Object.entries(overrides)) {
21
+ if (value !== undefined) {
22
+ resolved[slot] = value;
23
+ }
24
+ }
25
+ return Object.freeze(resolved);
26
+ }
27
+ function slotKey(classNames) {
28
+ const slots = Object.entries(classNames)
29
+ .filter(([, value]) => value !== undefined)
30
+ .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
31
+ return JSON.stringify(slots);
32
+ }
33
+ /**
34
+ * Resolves the per-slot class map for this position in the tree: the nearest
35
+ * {@link AuthFormClassNamesProvider}'s map with `overrides` applied slot by
36
+ * slot. An absent or `undefined` slot in `overrides` keeps the inherited value,
37
+ * and with no provider above the map is empty (every slot `undefined`), so the
38
+ * hook is safe to call anywhere. This is the only place the precedence rule is
39
+ * implemented.
40
+ *
41
+ * The result is cached on the slot values, so passing a fresh `overrides`
42
+ * literal every render returns the identical map.
43
+ *
44
+ * Call it with no argument from a component rendered **inside** a form to read
45
+ * the theme in effect; call it with a component's own `classNames` prop to
46
+ * resolve the map that component should both render with and publish.
47
+ *
48
+ * @param overrides Per-slot classes that win over the inherited map.
49
+ * @returns The resolved map, keyed by {@link AuthFormClassNames} slot.
50
+ *
51
+ * @example Theme a custom field to match the form around it
52
+ * ```tsx
53
+ * function TenantField(props: { fieldProps: AuthFieldProps }) {
54
+ * const classNames = useAuthFormClassNames();
55
+ * return (
56
+ * <div className={classNames.field}>
57
+ * <label className={classNames.label} htmlFor={props.fieldProps.id}>
58
+ * Tenant
59
+ * </label>
60
+ * <input {...props.fieldProps} className={classNames.input} />
61
+ * </div>
62
+ * );
63
+ * }
64
+ * ```
65
+ */
66
+ export function useAuthFormClassNames(overrides) {
67
+ const inherited = useContext(AuthFormClassNamesContext);
68
+ const key = overrides ? slotKey(overrides) : "";
69
+ const held = useRef(null);
70
+ if (held.current === null || held.current.inherited !== inherited ||
71
+ held.current.key !== key) {
72
+ held.current = {
73
+ inherited,
74
+ key,
75
+ resolved: overrides ? merge(inherited, overrides) : inherited,
76
+ };
77
+ }
78
+ return held.current.resolved;
79
+ }
80
+ /**
81
+ * Publishes an already-resolved map verbatim, without merging. A form and
82
+ * `AuthFormShell` resolve once through {@link useAuthFormClassNames} and
83
+ * publish through this, so the precedence rule keeps exactly one
84
+ * implementation. App code wants {@link AuthFormClassNamesProvider}.
85
+ */
86
+ export function AuthFormClassNamesScope(props) {
87
+ const { classNames, children } = props;
88
+ return (_jsx(AuthFormClassNamesContext.Provider, { value: classNames, children: children }));
89
+ }
90
+ /**
91
+ * Publishes a per-slot class map to every prebuilt auth form in `children`, so
92
+ * an app themes its whole auth surface once instead of repeating the same
93
+ * `classNames` on each form. Providers nest: an inner provider — or a form's
94
+ * own `classNames` prop — overrides the inherited map slot by slot, leaving the
95
+ * slots it does not name intact.
96
+ *
97
+ * It themes the auth **forms**; `UserMenu` is deliberately outside its reach
98
+ * and takes its classes from its own `className` / `classNames` props.
99
+ *
100
+ * An inline `classNames` literal is fine here — the published map is cached on
101
+ * the slot values rather than on the object's identity, so re-rendering with an
102
+ * equal literal hands the forms below the identical map.
103
+ *
104
+ * @example
105
+ * ```tsx
106
+ * <AuthFormClassNamesProvider
107
+ * classNames={{ input: "input", submit: "btn btn-primary" }}
108
+ * >
109
+ * <SignInForm onSubmit={signIn} />
110
+ * <SignUpForm onSubmit={signUp} />
111
+ * </AuthFormClassNamesProvider>
112
+ * ```
113
+ */
114
+ export function AuthFormClassNamesProvider(props) {
115
+ const { classNames, children } = props;
116
+ const resolved = useAuthFormClassNames(classNames);
117
+ return (_jsx(AuthFormClassNamesScope, { classNames: resolved, children: children }));
118
+ }
@@ -0,0 +1,62 @@
1
+ import { type ReactNode, type Ref } from "react";
2
+ import type { AuthFieldProps, AuthFormState } from "./use-auth-form.js";
3
+ import type { AuthFormClassNames, AuthFormValues, SocialProvidersProps } from "./types.js";
4
+ /**
5
+ * The single exit every default form component returns through — it owns both
6
+ * outcomes, so a form has one `return` and cannot leave a subtree unscoped.
7
+ *
8
+ * With no `render`, it lays out the markup the forms share: the root wrapper
9
+ * carrying `data-oauth2-form={name}`, then the `<form>` with its error summary
10
+ * and the caller's fields. Use `aboveForm` for content that belongs inside the
11
+ * root but outside the form (social buttons, an enrollment secret), and
12
+ * `succeeded` for a terminal state that replaces the form entirely. With a
13
+ * `render` — the form's render-prop `children` — that markup is skipped for the
14
+ * caller's own. Either way the already-resolved `classNames` is published to
15
+ * what renders, so the elements inside take their classes from the tree.
16
+ */
17
+ export declare function AuthFormShell<V extends AuthFormValues>(props: {
18
+ name: string;
19
+ form: AuthFormState<V>;
20
+ className: string | undefined;
21
+ classNames: Readonly<AuthFormClassNames>;
22
+ render: ((state: AuthFormState<V>) => ReactNode) | undefined;
23
+ rootProps?: Record<`data-${string}`, string>;
24
+ aboveForm?: ReactNode;
25
+ succeeded?: ReactNode;
26
+ children?: ReactNode;
27
+ action?: string;
28
+ method?: "get" | "post";
29
+ formRef?: Ref<HTMLFormElement>;
30
+ }): ReactNode;
31
+ /** The actions row and its submit button, disabled while the form is in flight. */
32
+ export declare function SubmitButton(props: {
33
+ isSubmitting: boolean;
34
+ label: string;
35
+ submittingLabel: string;
36
+ }): ReactNode;
37
+ export declare function TextField(props: {
38
+ fieldProps: AuthFieldProps;
39
+ label: string;
40
+ type?: string;
41
+ autoComplete?: string;
42
+ required?: boolean;
43
+ error?: string;
44
+ inputRef?: Ref<HTMLInputElement>;
45
+ children?: ReactNode;
46
+ }): ReactNode;
47
+ export declare function ErrorSummary(props: {
48
+ error: string | null;
49
+ focusTrigger?: number;
50
+ }): ReactNode;
51
+ /**
52
+ * Moves keyboard focus to the first field that came back with an error after a
53
+ * failed submit, so a screen-reader / keyboard user lands on the control to fix
54
+ * (its label + error are read via `aria-describedby`) instead of being stranded
55
+ * on the disabled submit button. No-ops on the initial render and when the form
56
+ * carries a form-level error ({@link ErrorSummary} owns that focus). Call it
57
+ * once, unconditionally, from a form component built on {@link useAuthForm}.
58
+ */
59
+ export declare function useFocusFirstError<V extends AuthFormValues>(form: AuthFormState<V>): void;
60
+ export declare function SocialButtons(props: SocialProvidersProps): ReactNode;
61
+ export declare function combineClassNames(className: string | undefined, slot: string | undefined): string | undefined;
62
+ export declare function displayName(user: Record<string, unknown>): string;