@atproto/oauth-provider 0.6.6 → 0.7.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 +49 -0
  2. package/dist/access-token/access-token-mode.d.ts +5 -0
  3. package/dist/access-token/access-token-mode.d.ts.map +1 -0
  4. package/dist/access-token/access-token-mode.js +9 -0
  5. package/dist/access-token/access-token-mode.js.map +1 -0
  6. package/dist/account/account-manager.d.ts +13 -7
  7. package/dist/account/account-manager.d.ts.map +1 -1
  8. package/dist/account/account-manager.js +69 -52
  9. package/dist/account/account-manager.js.map +1 -1
  10. package/dist/account/account-store.d.ts +88 -77
  11. package/dist/account/account-store.d.ts.map +1 -1
  12. package/dist/account/account-store.js +24 -73
  13. package/dist/account/account-store.js.map +1 -1
  14. package/dist/account/sign-in-data.d.ts +4 -13
  15. package/dist/account/sign-in-data.d.ts.map +1 -1
  16. package/dist/account/sign-in-data.js +9 -9
  17. package/dist/account/sign-in-data.js.map +1 -1
  18. package/dist/account/sign-up-input.d.ts +4 -5
  19. package/dist/account/sign-up-input.d.ts.map +1 -1
  20. package/dist/account/sign-up-input.js +13 -3
  21. package/dist/account/sign-up-input.js.map +1 -1
  22. package/dist/client/client-manager.d.ts +4 -1
  23. package/dist/client/client-manager.d.ts.map +1 -1
  24. package/dist/client/client-manager.js +13 -1
  25. package/dist/client/client-manager.js.map +1 -1
  26. package/dist/client/client-store.d.ts +1 -1
  27. package/dist/client/client-store.d.ts.map +1 -1
  28. package/dist/constants.d.ts +5 -1
  29. package/dist/constants.d.ts.map +1 -1
  30. package/dist/constants.js +6 -2
  31. package/dist/constants.js.map +1 -1
  32. package/dist/customization/branding.d.ts +54 -0
  33. package/dist/customization/branding.d.ts.map +1 -0
  34. package/dist/customization/branding.js +13 -0
  35. package/dist/customization/branding.js.map +1 -0
  36. package/dist/customization/build-customization-css.d.ts +3 -0
  37. package/dist/customization/build-customization-css.d.ts.map +1 -0
  38. package/dist/customization/build-customization-css.js +27 -0
  39. package/dist/customization/build-customization-css.js.map +1 -0
  40. package/dist/customization/build-customization-data.d.ts +4 -0
  41. package/dist/customization/build-customization-data.d.ts.map +1 -0
  42. package/dist/customization/build-customization-data.js +18 -0
  43. package/dist/customization/build-customization-data.js.map +1 -0
  44. package/dist/customization/colors.d.ts +7 -0
  45. package/dist/customization/colors.d.ts.map +1 -0
  46. package/dist/customization/colors.js +27 -0
  47. package/dist/customization/colors.js.map +1 -0
  48. package/dist/customization/customization.d.ts +129 -0
  49. package/dist/customization/customization.d.ts.map +1 -0
  50. package/dist/customization/customization.js +26 -0
  51. package/dist/customization/customization.js.map +1 -0
  52. package/dist/customization/links.d.ts +26 -0
  53. package/dist/customization/links.d.ts.map +1 -0
  54. package/dist/customization/links.js +12 -0
  55. package/dist/customization/links.js.map +1 -0
  56. package/dist/device/device-id.d.ts +1 -0
  57. package/dist/device/device-id.d.ts.map +1 -1
  58. package/dist/device/device-id.js +4 -0
  59. package/dist/device/device-id.js.map +1 -1
  60. package/dist/device/device-manager.d.ts +6 -36
  61. package/dist/device/device-manager.d.ts.map +1 -1
  62. package/dist/device/device-manager.js +49 -43
  63. package/dist/device/device-manager.js.map +1 -1
  64. package/dist/device/device-store.d.ts +1 -0
  65. package/dist/device/device-store.d.ts.map +1 -1
  66. package/dist/device/device-store.js.map +1 -1
  67. package/dist/dpop/dpop-manager.d.ts +3 -3
  68. package/dist/dpop/dpop-nonce.d.ts +3 -3
  69. package/dist/dpop/dpop-nonce.d.ts.map +1 -1
  70. package/dist/errors/access-denied-error.d.ts +4 -3
  71. package/dist/errors/access-denied-error.d.ts.map +1 -1
  72. package/dist/errors/access-denied-error.js +5 -6
  73. package/dist/errors/access-denied-error.js.map +1 -1
  74. package/dist/{output/build-error-payload.d.ts → errors/error-parser.d.ts} +1 -1
  75. package/dist/errors/error-parser.d.ts.map +1 -0
  76. package/dist/{output/build-error-payload.js → errors/error-parser.js} +2 -2
  77. package/dist/errors/error-parser.js.map +1 -0
  78. package/dist/errors/invalid-grant-error.d.ts +1 -0
  79. package/dist/errors/invalid-grant-error.d.ts.map +1 -1
  80. package/dist/errors/invalid-grant-error.js +5 -0
  81. package/dist/errors/invalid-grant-error.js.map +1 -1
  82. package/dist/errors/login-required-error.d.ts +1 -0
  83. package/dist/errors/login-required-error.d.ts.map +1 -1
  84. package/dist/errors/login-required-error.js +5 -0
  85. package/dist/errors/login-required-error.js.map +1 -1
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +1 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/lib/html/build-document.d.ts +2 -2
  91. package/dist/lib/html/build-document.d.ts.map +1 -1
  92. package/dist/lib/html/build-document.js +4 -0
  93. package/dist/lib/html/build-document.js.map +1 -1
  94. package/dist/lib/html/hydration-data.d.ts +4 -0
  95. package/dist/lib/html/hydration-data.d.ts.map +1 -0
  96. package/dist/{output/backend-data.js → lib/html/hydration-data.js} +8 -8
  97. package/dist/lib/html/hydration-data.js.map +1 -0
  98. package/dist/lib/html/tags.d.ts +1 -1
  99. package/dist/lib/html/tags.d.ts.map +1 -1
  100. package/dist/lib/html/tags.js +1 -1
  101. package/dist/lib/html/tags.js.map +1 -1
  102. package/dist/lib/http/accept.d.ts +2 -2
  103. package/dist/lib/http/accept.d.ts.map +1 -1
  104. package/dist/lib/http/accept.js +1 -1
  105. package/dist/lib/http/accept.js.map +1 -1
  106. package/dist/lib/http/context.d.ts +2 -4
  107. package/dist/lib/http/context.d.ts.map +1 -1
  108. package/dist/lib/http/context.js +29 -4
  109. package/dist/lib/http/context.js.map +1 -1
  110. package/dist/lib/http/headers.d.ts +3 -0
  111. package/dist/lib/http/headers.d.ts.map +1 -0
  112. package/dist/lib/http/headers.js +14 -0
  113. package/dist/lib/http/headers.js.map +1 -0
  114. package/dist/lib/http/index.d.ts +1 -0
  115. package/dist/lib/http/index.d.ts.map +1 -1
  116. package/dist/lib/http/index.js +1 -0
  117. package/dist/lib/http/index.js.map +1 -1
  118. package/dist/lib/http/middleware.d.ts +1 -1
  119. package/dist/lib/http/middleware.d.ts.map +1 -1
  120. package/dist/lib/http/middleware.js +8 -24
  121. package/dist/lib/http/middleware.js.map +1 -1
  122. package/dist/lib/http/parser.d.ts +3 -3
  123. package/dist/lib/http/parser.d.ts.map +1 -1
  124. package/dist/lib/http/request.d.ts +13 -9
  125. package/dist/lib/http/request.d.ts.map +1 -1
  126. package/dist/lib/http/request.js +27 -49
  127. package/dist/lib/http/request.js.map +1 -1
  128. package/dist/lib/http/response.d.ts +6 -2
  129. package/dist/lib/http/response.d.ts.map +1 -1
  130. package/dist/lib/http/response.js +31 -11
  131. package/dist/lib/http/response.js.map +1 -1
  132. package/dist/lib/http/route.d.ts +3 -3
  133. package/dist/lib/http/route.d.ts.map +1 -1
  134. package/dist/lib/http/route.js +1 -1
  135. package/dist/lib/http/route.js.map +1 -1
  136. package/dist/lib/http/router.d.ts +12 -11
  137. package/dist/lib/http/router.d.ts.map +1 -1
  138. package/dist/lib/http/router.js +26 -34
  139. package/dist/lib/http/router.js.map +1 -1
  140. package/dist/lib/http/security-headers.js +1 -1
  141. package/dist/lib/http/security-headers.js.map +1 -1
  142. package/dist/lib/http/stream.d.ts +3 -3
  143. package/dist/lib/http/stream.d.ts.map +1 -1
  144. package/dist/lib/http/types.d.ts +1 -1
  145. package/dist/lib/http/types.d.ts.map +1 -1
  146. package/dist/lib/send-web-page.d.ts +8 -0
  147. package/dist/lib/send-web-page.d.ts.map +1 -0
  148. package/dist/{output → lib}/send-web-page.js +9 -7
  149. package/dist/lib/send-web-page.js.map +1 -0
  150. package/dist/lib/util/authorization-header.d.ts.map +1 -1
  151. package/dist/lib/util/color.d.ts +32 -0
  152. package/dist/lib/util/color.d.ts.map +1 -0
  153. package/dist/lib/util/color.js +116 -0
  154. package/dist/lib/util/color.js.map +1 -0
  155. package/dist/lib/util/crypto.d.ts +1 -0
  156. package/dist/lib/util/crypto.d.ts.map +1 -1
  157. package/dist/lib/util/crypto.js +8 -3
  158. package/dist/lib/util/crypto.js.map +1 -1
  159. package/dist/lib/util/function.d.ts +1 -0
  160. package/dist/lib/util/function.d.ts.map +1 -1
  161. package/dist/lib/util/function.js +12 -0
  162. package/dist/lib/util/function.js.map +1 -1
  163. package/dist/lib/util/locale.d.ts +20 -0
  164. package/dist/lib/util/locale.d.ts.map +1 -0
  165. package/dist/lib/util/locale.js +14 -0
  166. package/dist/lib/util/locale.js.map +1 -0
  167. package/dist/lib/util/time.d.ts +1 -1
  168. package/dist/lib/util/time.d.ts.map +1 -1
  169. package/dist/lib/util/time.js +1 -1
  170. package/dist/lib/util/time.js.map +1 -1
  171. package/dist/lib/util/type.d.ts +22 -0
  172. package/dist/lib/util/type.d.ts.map +1 -1
  173. package/dist/lib/util/type.js.map +1 -1
  174. package/dist/lib/util/ui8.d.ts +4 -0
  175. package/dist/lib/util/ui8.d.ts.map +1 -0
  176. package/dist/lib/util/ui8.js +17 -0
  177. package/dist/lib/util/ui8.js.map +1 -0
  178. package/dist/lib/util/zod-error.d.ts +2 -0
  179. package/dist/lib/util/zod-error.d.ts.map +1 -0
  180. package/dist/lib/util/zod-error.js +16 -0
  181. package/dist/lib/util/zod-error.js.map +1 -0
  182. package/dist/oauth-errors.d.ts +22 -22
  183. package/dist/oauth-errors.d.ts.map +1 -1
  184. package/dist/oauth-errors.js +37 -45
  185. package/dist/oauth-errors.js.map +1 -1
  186. package/dist/oauth-hooks.d.ts +11 -23
  187. package/dist/oauth-hooks.d.ts.map +1 -1
  188. package/dist/oauth-hooks.js.map +1 -1
  189. package/dist/oauth-middleware.d.ts +12 -0
  190. package/dist/oauth-middleware.d.ts.map +1 -0
  191. package/dist/oauth-middleware.js +32 -0
  192. package/dist/oauth-middleware.js.map +1 -0
  193. package/dist/oauth-provider.d.ts +109 -113
  194. package/dist/oauth-provider.d.ts.map +1 -1
  195. package/dist/oauth-provider.js +124 -542
  196. package/dist/oauth-provider.js.map +1 -1
  197. package/dist/oauth-verifier.d.ts +7 -26
  198. package/dist/oauth-verifier.d.ts.map +1 -1
  199. package/dist/oauth-verifier.js +6 -16
  200. package/dist/oauth-verifier.js.map +1 -1
  201. package/dist/request/code.d.ts.map +1 -1
  202. package/dist/request/request-data.d.ts +2 -4
  203. package/dist/request/request-data.d.ts.map +1 -1
  204. package/dist/request/request-data.js.map +1 -1
  205. package/dist/request/request-manager.d.ts +4 -2
  206. package/dist/request/request-manager.d.ts.map +1 -1
  207. package/dist/request/request-manager.js +9 -8
  208. package/dist/request/request-manager.js.map +1 -1
  209. package/dist/request/request-store.d.ts +6 -0
  210. package/dist/request/request-store.d.ts.map +1 -1
  211. package/dist/request/request-store.js +3 -1
  212. package/dist/request/request-store.js.map +1 -1
  213. package/dist/result/authorization-redirect-parameters.d.ts +18 -0
  214. package/dist/result/authorization-redirect-parameters.d.ts.map +1 -0
  215. package/dist/result/authorization-redirect-parameters.js +3 -0
  216. package/dist/result/authorization-redirect-parameters.js.map +1 -0
  217. package/dist/result/authorization-result-authorize-page.d.ts +13 -0
  218. package/dist/result/authorization-result-authorize-page.d.ts.map +1 -0
  219. package/dist/result/authorization-result-authorize-page.js +3 -0
  220. package/dist/result/authorization-result-authorize-page.js.map +1 -0
  221. package/dist/result/authorization-result-redirect.d.ts +8 -0
  222. package/dist/result/authorization-result-redirect.d.ts.map +1 -0
  223. package/dist/result/authorization-result-redirect.js +3 -0
  224. package/dist/result/authorization-result-redirect.js.map +1 -0
  225. package/dist/router/assets/assets-manifest.d.ts +10 -0
  226. package/dist/router/assets/assets-manifest.d.ts.map +1 -0
  227. package/dist/router/assets/assets-manifest.js +77 -0
  228. package/dist/router/assets/assets-manifest.js.map +1 -0
  229. package/dist/router/assets/assets.d.ts +16 -0
  230. package/dist/router/assets/assets.d.ts.map +1 -0
  231. package/dist/router/assets/assets.js +43 -0
  232. package/dist/router/assets/assets.js.map +1 -0
  233. package/dist/router/assets/csrf.d.ts +4 -0
  234. package/dist/router/assets/csrf.d.ts.map +1 -0
  235. package/dist/router/assets/csrf.js +51 -0
  236. package/dist/router/assets/csrf.js.map +1 -0
  237. package/dist/router/assets/send-account-page.d.ts +7 -0
  238. package/dist/router/assets/send-account-page.d.ts.map +1 -0
  239. package/dist/router/assets/send-account-page.js +34 -0
  240. package/dist/router/assets/send-account-page.js.map +1 -0
  241. package/dist/router/assets/send-authorization-page.d.ts +5 -0
  242. package/dist/router/assets/send-authorization-page.d.ts.map +1 -0
  243. package/dist/router/assets/send-authorization-page.js +49 -0
  244. package/dist/router/assets/send-authorization-page.js.map +1 -0
  245. package/dist/router/assets/send-error-page.d.ts +4 -0
  246. package/dist/router/assets/send-error-page.d.ts.map +1 -0
  247. package/dist/router/assets/send-error-page.js +34 -0
  248. package/dist/router/assets/send-error-page.js.map +1 -0
  249. package/dist/router/create-account-page-middleware.d.ts +6 -0
  250. package/dist/router/create-account-page-middleware.d.ts.map +1 -0
  251. package/dist/router/create-account-page-middleware.js +39 -0
  252. package/dist/router/create-account-page-middleware.js.map +1 -0
  253. package/dist/router/create-api-middleware.d.ts +8 -0
  254. package/dist/router/create-api-middleware.d.ts.map +1 -0
  255. package/dist/router/create-api-middleware.js +501 -0
  256. package/dist/router/create-api-middleware.js.map +1 -0
  257. package/dist/router/create-authorization-page-middleware.d.ts +6 -0
  258. package/dist/router/create-authorization-page-middleware.d.ts.map +1 -0
  259. package/dist/router/create-authorization-page-middleware.js +104 -0
  260. package/dist/router/create-authorization-page-middleware.js.map +1 -0
  261. package/dist/router/create-oauth-middleware.d.ts +6 -0
  262. package/dist/router/create-oauth-middleware.d.ts.map +1 -0
  263. package/dist/router/create-oauth-middleware.js +142 -0
  264. package/dist/router/create-oauth-middleware.js.map +1 -0
  265. package/dist/router/error-handler.d.ts +3 -0
  266. package/dist/router/error-handler.d.ts.map +1 -0
  267. package/dist/{account/account.js → router/error-handler.js} +1 -1
  268. package/dist/router/error-handler.js.map +1 -0
  269. package/dist/router/middleware-options.d.ts +6 -0
  270. package/dist/router/middleware-options.d.ts.map +1 -0
  271. package/dist/router/middleware-options.js +3 -0
  272. package/dist/router/middleware-options.js.map +1 -0
  273. package/dist/router/send-redirect.d.ts +16 -0
  274. package/dist/router/send-redirect.d.ts.map +1 -0
  275. package/dist/{output/send-authorize-redirect.js → router/send-redirect.js} +40 -24
  276. package/dist/router/send-redirect.js.map +1 -0
  277. package/dist/{token/token-claims.d.ts → signer/api-token-payload.d.ts} +237 -232
  278. package/dist/signer/api-token-payload.d.ts.map +1 -0
  279. package/dist/signer/api-token-payload.js +17 -0
  280. package/dist/signer/api-token-payload.js.map +1 -0
  281. package/dist/signer/signed-token-payload.d.ts +164 -159
  282. package/dist/signer/signed-token-payload.d.ts.map +1 -1
  283. package/dist/signer/signed-token-payload.js +10 -16
  284. package/dist/signer/signed-token-payload.js.map +1 -1
  285. package/dist/signer/signer.d.ts +42 -11246
  286. package/dist/signer/signer.d.ts.map +1 -1
  287. package/dist/signer/signer.js +30 -15
  288. package/dist/signer/signer.js.map +1 -1
  289. package/dist/token/refresh-token.d.ts.map +1 -1
  290. package/dist/token/token-data.d.ts +1 -1
  291. package/dist/token/token-data.d.ts.map +1 -1
  292. package/dist/token/token-id.d.ts.map +1 -1
  293. package/dist/token/token-manager.d.ts +28 -26
  294. package/dist/token/token-manager.d.ts.map +1 -1
  295. package/dist/token/token-manager.js +138 -196
  296. package/dist/token/token-manager.js.map +1 -1
  297. package/dist/token/token-store.d.ts +4 -4
  298. package/dist/token/token-store.d.ts.map +1 -1
  299. package/dist/token/token-store.js +1 -0
  300. package/dist/token/token-store.js.map +1 -1
  301. package/dist/token/verify-token-claims.d.ts +3 -3
  302. package/dist/token/verify-token-claims.d.ts.map +1 -1
  303. package/dist/token/verify-token-claims.js +1 -1
  304. package/dist/token/verify-token-claims.js.map +1 -1
  305. package/dist/types/email-otp.d.ts +3 -0
  306. package/dist/types/email-otp.d.ts.map +1 -0
  307. package/dist/types/email-otp.js +6 -0
  308. package/dist/types/email-otp.js.map +1 -0
  309. package/dist/types/email.d.ts +3 -0
  310. package/dist/types/email.d.ts.map +1 -0
  311. package/dist/types/email.js +29 -0
  312. package/dist/types/email.js.map +1 -0
  313. package/dist/types/handle.d.ts +3 -0
  314. package/dist/types/handle.d.ts.map +1 -0
  315. package/dist/types/handle.js +22 -0
  316. package/dist/types/handle.js.map +1 -0
  317. package/dist/types/invite-code.d.ts +4 -0
  318. package/dist/types/invite-code.d.ts.map +1 -0
  319. package/dist/types/invite-code.js +6 -0
  320. package/dist/types/invite-code.js.map +1 -0
  321. package/dist/types/password.d.ts +4 -0
  322. package/dist/types/password.d.ts.map +1 -0
  323. package/dist/types/password.js +7 -0
  324. package/dist/types/password.js.map +1 -0
  325. package/package.json +11 -14
  326. package/src/access-token/access-token-mode.ts +4 -0
  327. package/src/account/account-manager.ts +105 -75
  328. package/src/account/account-store.ts +118 -114
  329. package/src/account/sign-in-data.ts +10 -10
  330. package/src/account/sign-up-input.ts +13 -4
  331. package/src/client/client-manager.ts +34 -2
  332. package/src/client/client-store.ts +1 -1
  333. package/src/constants.ts +6 -1
  334. package/src/customization/branding.ts +12 -0
  335. package/src/customization/build-customization-css.ts +30 -0
  336. package/src/customization/build-customization-data.ts +22 -0
  337. package/src/customization/colors.ts +30 -0
  338. package/src/customization/customization.ts +25 -0
  339. package/src/customization/links.ts +10 -0
  340. package/src/device/device-id.ts +5 -0
  341. package/src/device/device-manager.ts +76 -66
  342. package/src/device/device-store.ts +2 -0
  343. package/src/errors/access-denied-error.ts +24 -17
  344. package/src/{output/build-error-payload.ts → errors/error-parser.ts} +1 -1
  345. package/src/errors/invalid-grant-error.ts +5 -0
  346. package/src/errors/login-required-error.ts +10 -0
  347. package/src/index.ts +1 -0
  348. package/src/lib/html/build-document.ts +6 -4
  349. package/src/{output/backend-data.ts → lib/html/hydration-data.ts} +7 -5
  350. package/src/lib/html/tags.ts +2 -2
  351. package/src/lib/http/accept.ts +3 -3
  352. package/src/lib/http/context.ts +41 -10
  353. package/src/lib/http/headers.ts +15 -0
  354. package/src/lib/http/index.ts +1 -0
  355. package/src/lib/http/middleware.ts +8 -23
  356. package/src/lib/http/request.ts +40 -75
  357. package/src/lib/http/response.ts +39 -15
  358. package/src/lib/http/route.ts +8 -5
  359. package/src/lib/http/router.ts +40 -46
  360. package/src/lib/http/security-headers.ts +1 -1
  361. package/src/lib/http/types.ts +1 -6
  362. package/src/{output → lib}/send-web-page.ts +10 -9
  363. package/src/lib/util/color.ts +132 -0
  364. package/src/lib/util/crypto.ts +9 -4
  365. package/src/lib/util/function.ts +14 -0
  366. package/src/lib/util/locale.ts +18 -0
  367. package/src/lib/util/time.ts +3 -4
  368. package/src/lib/util/type.ts +24 -0
  369. package/src/lib/util/ui8.ts +14 -0
  370. package/src/lib/util/zod-error.ts +14 -0
  371. package/src/oauth-errors.ts +22 -22
  372. package/src/oauth-hooks.ts +11 -24
  373. package/src/oauth-middleware.ts +53 -0
  374. package/src/oauth-provider.ts +290 -1061
  375. package/src/oauth-verifier.ts +9 -55
  376. package/src/request/request-data.ts +5 -4
  377. package/src/request/request-manager.ts +11 -11
  378. package/src/request/request-store.ts +7 -0
  379. package/src/result/authorization-redirect-parameters.ts +24 -0
  380. package/src/result/authorization-result-authorize-page.ts +14 -0
  381. package/src/result/authorization-result-redirect.ts +8 -0
  382. package/src/router/assets/assets-manifest.ts +115 -0
  383. package/src/router/assets/assets.ts +54 -0
  384. package/src/router/assets/csrf.ts +63 -0
  385. package/src/router/assets/send-account-page.ts +43 -0
  386. package/src/router/assets/send-authorization-page.ts +62 -0
  387. package/src/router/assets/send-error-page.ts +42 -0
  388. package/src/router/create-account-page-middleware.ts +69 -0
  389. package/src/router/create-api-middleware.ts +814 -0
  390. package/src/router/create-authorization-page-middleware.ts +173 -0
  391. package/src/router/create-oauth-middleware.ts +247 -0
  392. package/src/router/error-handler.ts +6 -0
  393. package/src/router/middleware-options.ts +9 -0
  394. package/src/router/send-redirect.ts +142 -0
  395. package/src/signer/api-token-payload.ts +18 -0
  396. package/src/signer/signed-token-payload.ts +18 -28
  397. package/src/signer/signer.ts +49 -34
  398. package/src/token/token-data.ts +1 -1
  399. package/src/token/token-manager.ts +190 -239
  400. package/src/token/token-store.ts +6 -4
  401. package/src/token/verify-token-claims.ts +4 -4
  402. package/src/types/email-otp.ts +3 -0
  403. package/src/types/email.ts +26 -0
  404. package/src/types/handle.ts +18 -0
  405. package/src/types/invite-code.ts +4 -0
  406. package/src/types/password.ts +4 -0
  407. package/tsconfig.build.tsbuildinfo +1 -0
  408. package/tsconfig.json +1 -1
  409. package/dist/access-token/access-token-type.d.ts +0 -6
  410. package/dist/access-token/access-token-type.d.ts.map +0 -1
  411. package/dist/access-token/access-token-type.js +0 -10
  412. package/dist/access-token/access-token-type.js.map +0 -1
  413. package/dist/account/account.d.ts +0 -2
  414. package/dist/account/account.d.ts.map +0 -1
  415. package/dist/account/account.js.map +0 -1
  416. package/dist/assets/assets-middleware.d.ts +0 -5
  417. package/dist/assets/assets-middleware.d.ts.map +0 -1
  418. package/dist/assets/assets-middleware.js +0 -41
  419. package/dist/assets/assets-middleware.js.map +0 -1
  420. package/dist/lib/locale.d.ts +0 -15
  421. package/dist/lib/locale.d.ts.map +0 -1
  422. package/dist/lib/locale.js +0 -17
  423. package/dist/lib/locale.js.map +0 -1
  424. package/dist/output/backend-data.d.ts +0 -4
  425. package/dist/output/backend-data.d.ts.map +0 -1
  426. package/dist/output/backend-data.js.map +0 -1
  427. package/dist/output/build-authorize-data.d.ts +0 -29
  428. package/dist/output/build-authorize-data.d.ts.map +0 -1
  429. package/dist/output/build-authorize-data.js +0 -21
  430. package/dist/output/build-authorize-data.js.map +0 -1
  431. package/dist/output/build-customization-data.d.ts +0 -234
  432. package/dist/output/build-customization-data.d.ts.map +0 -1
  433. package/dist/output/build-customization-data.js +0 -174
  434. package/dist/output/build-customization-data.js.map +0 -1
  435. package/dist/output/build-error-data.d.ts +0 -3
  436. package/dist/output/build-error-data.d.ts.map +0 -1
  437. package/dist/output/build-error-data.js +0 -10
  438. package/dist/output/build-error-data.js.map +0 -1
  439. package/dist/output/build-error-payload.d.ts.map +0 -1
  440. package/dist/output/build-error-payload.js.map +0 -1
  441. package/dist/output/output-manager.d.ts +0 -28
  442. package/dist/output/output-manager.d.ts.map +0 -1
  443. package/dist/output/output-manager.js +0 -134
  444. package/dist/output/output-manager.js.map +0 -1
  445. package/dist/output/send-authorize-redirect.d.ts +0 -25
  446. package/dist/output/send-authorize-redirect.d.ts.map +0 -1
  447. package/dist/output/send-authorize-redirect.js.map +0 -1
  448. package/dist/output/send-web-page.d.ts +0 -8
  449. package/dist/output/send-web-page.d.ts.map +0 -1
  450. package/dist/output/send-web-page.js.map +0 -1
  451. package/dist/token/token-claims.d.ts.map +0 -1
  452. package/dist/token/token-claims.js +0 -27
  453. package/dist/token/token-claims.js.map +0 -1
  454. package/src/access-token/access-token-type.ts +0 -5
  455. package/src/account/account.ts +0 -1
  456. package/src/assets/assets-middleware.ts +0 -44
  457. package/src/lib/locale.ts +0 -21
  458. package/src/output/build-authorize-data.ts +0 -53
  459. package/src/output/build-customization-data.ts +0 -217
  460. package/src/output/build-error-data.ts +0 -8
  461. package/src/output/output-manager.ts +0 -188
  462. package/src/output/send-authorize-redirect.ts +0 -137
  463. package/src/token/token-claims.ts +0 -30
  464. package/tsconfig.backend.tsbuildinfo +0 -1
  465. /package/{tsconfig.backend.json → tsconfig.build.json} +0 -0
@@ -1,11 +1,13 @@
1
- import { isEmailValid } from '@hapi/address'
2
- import { isDisposableEmail } from 'disposable-email-domains-js'
3
- import { z } from 'zod'
4
- import { ensureValidHandle, normalizeHandle } from '@atproto/syntax'
1
+ import {
2
+ Account,
3
+ ConfirmResetPasswordInput,
4
+ InitiatePasswordResetInput,
5
+ } from '@atproto/oauth-provider-api'
6
+ import { OAuthScope } from '@atproto/oauth-types'
5
7
  import { ClientId } from '../client/client-id.js'
6
8
  import { DeviceId } from '../device/device-id.js'
9
+ import { DeviceData } from '../device/device-store.js'
7
10
  import { HcaptchaVerifyResult } from '../lib/hcaptcha.js'
8
- import { localeSchema } from '../lib/locale.js'
9
11
  import { Awaitable, buildInterfaceChecker } from '../lib/util/type.js'
10
12
  import {
11
13
  HandleUnavailableError,
@@ -13,112 +15,83 @@ import {
13
15
  SecondAuthenticationFactorRequiredError,
14
16
  } from '../oauth-errors.js'
15
17
  import { Sub } from '../oidc/sub.js'
16
- import { Account } from './account.js'
18
+ import { InviteCode } from '../types/invite-code.js'
17
19
  import { SignUpInput } from './sign-up-input.js'
18
20
 
19
- // @NOTE Change the length here to force stronger passwords (through a reset)
20
- export const oldPasswordSchema = z.string().min(1)
21
- export const newPasswordSchema = z.string().min(8)
22
- export const tokenSchema = z
23
- .string()
24
- .regex(/^[A-Z2-7]{5}-[A-Z2-7]{5}$/, 'Invalid token format')
25
- export const handleSchema = z
26
- .string()
27
- // @NOTE: We only check against validity towards ATProto's syntax. Additional
28
- // rules may be imposed by the store implementation.
29
- .superRefine((value, ctx) => {
30
- try {
31
- ensureValidHandle(value)
32
- } catch (err) {
33
- ctx.addIssue({
34
- code: z.ZodIssueCode.custom,
35
- message: err instanceof Error ? err.message : 'Invalid handle',
36
- })
37
- }
38
- })
39
- .transform(normalizeHandle)
40
- export const emailSchema = z
41
- .string()
42
- .email()
43
- // @NOTE using @hapi/address here, in addition to the email() check to ensure
44
- // compatibility with the current email validation in the PDS's account
45
- // manager
46
- .refine(isEmailValid, {
47
- message: 'Invalid email address',
48
- })
49
- .refine((email) => !isDisposableEmail(email), {
50
- message: 'Disposable email addresses are not allowed',
51
- })
52
- .transform((value) => value.toLowerCase())
53
- export const inviteCodeSchema = z.string().min(1)
54
- export type InviteCode = z.infer<typeof inviteCodeSchema>
55
-
56
- export const authenticateAccountDataSchema = z
57
- .object({
58
- locale: localeSchema,
59
- username: z.string(),
60
- password: oldPasswordSchema,
61
- emailOtp: tokenSchema.optional(),
62
- })
63
- .strict()
64
-
65
- export type AuthenticateAccountData = z.TypeOf<
66
- typeof authenticateAccountDataSchema
67
- >
68
-
69
- export const createAccountDataSchema = z
70
- .object({
71
- locale: localeSchema,
72
- handle: handleSchema,
73
- email: emailSchema,
74
- password: z.intersection(oldPasswordSchema, newPasswordSchema),
75
- inviteCode: inviteCodeSchema.optional(),
76
- })
77
- .strict()
78
-
79
- export type CreateAccountData = z.TypeOf<typeof createAccountDataSchema>
80
-
81
- export const resetPasswordRequestDataSchema = z
82
- .object({
83
- locale: localeSchema,
84
- email: emailSchema,
85
- })
86
- .strict()
87
-
88
- export type ResetPasswordRequestData = z.TypeOf<
89
- typeof resetPasswordRequestDataSchema
90
- >
91
-
92
- export const resetPasswordConfirmDataSchema = z
93
- .object({
94
- token: tokenSchema,
95
- password: z.intersection(oldPasswordSchema, newPasswordSchema),
96
- })
97
- .strict()
98
-
99
- export type ResetPasswordConfirmData = z.TypeOf<
100
- typeof resetPasswordConfirmDataSchema
101
- >
102
-
103
- export type DeviceAccountInfo = {
104
- remembered: boolean
105
- authenticatedAt: Date
106
- authorizedClients: readonly ClientId[]
21
+ // Export all types needed to implement the AccountStore interface
22
+
23
+ export * from '../client/client-id.js'
24
+ export * from '../device/device-data.js'
25
+ export * from '../device/device-id.js'
26
+ export * from '../oidc/sub.js'
27
+ export * from '../request/request-id.js'
28
+
29
+ export type {
30
+ Account,
31
+ HcaptchaVerifyResult,
32
+ InviteCode,
33
+ OAuthScope,
34
+ SignUpInput,
107
35
  }
108
36
 
109
- // Export all types needed to implement the AccountStore interface
110
37
  export {
111
- type Account,
112
- type DeviceId,
113
38
  HandleUnavailableError,
114
39
  InvalidRequestError,
115
40
  SecondAuthenticationFactorRequiredError,
116
- type Sub,
117
41
  }
118
42
 
119
- export type AccountInfo = {
43
+ export type ResetPasswordRequestData = InitiatePasswordResetInput
44
+ export type ResetPasswordConfirmData = ConfirmResetPasswordInput
45
+ export type CreateAccountData = {
46
+ locale: string
47
+ email: string
48
+ password: string
49
+ handle: string
50
+ inviteCode?: string | undefined
51
+ }
52
+
53
+ export type AuthenticateAccountData = {
54
+ locale: string
55
+ password: string
56
+ username: string
57
+ emailOtp?: string | undefined
58
+ }
59
+
60
+ export type AuthorizedClientData = { authorizedScopes: readonly string[] }
61
+ export type AuthorizedClients = Map<ClientId, AuthorizedClientData>
62
+
63
+ export type DeviceAccount = {
64
+ deviceId: DeviceId
65
+
66
+ /**
67
+ * The data associated with the device, created through the
68
+ * {@link DeviceStore}. This data is used to identify devices on which a user
69
+ * has logged in.
70
+ */
71
+ deviceData: DeviceData
72
+
73
+ /**
74
+ * The account associated with the device account.
75
+ */
120
76
  account: Account
121
- info: DeviceAccountInfo
77
+
78
+ /**
79
+ * The list of clients that are authorized by the account, as created through
80
+ * the {@link AccountStore.setAuthorizedClient} method.
81
+ */
82
+ authorizedClients: AuthorizedClients
83
+
84
+ /**
85
+ * The date at which the device account was created. This value is currently
86
+ * not used.
87
+ */
88
+ createdAt: Date
89
+
90
+ /**
91
+ * The date at which the device account was last updated. This value is used
92
+ * to determine the date at which the user last authenticated on a device
93
+ */
94
+ updatedAt: Date
122
95
  }
123
96
 
124
97
  export type SignUpData = SignUpInput & {
@@ -139,33 +112,63 @@ export interface AccountStore {
139
112
  */
140
113
  authenticateAccount(data: AuthenticateAccountData): Awaitable<Account>
141
114
 
142
- addAuthorizedClient(
143
- deviceId: DeviceId,
115
+ /**
116
+ * Add a client & scopes to the list of authorized clients for the given account.
117
+ */
118
+ setAuthorizedClient(
144
119
  sub: Sub,
145
120
  clientId: ClientId,
121
+ data: AuthorizedClientData,
146
122
  ): Awaitable<void>
147
123
 
148
124
  /**
149
- * @param remember If false, the account must not be returned from
150
- * {@link AccountStore.listDeviceAccounts}.
125
+ * @throws {InvalidRequestError} - When the credentials are not valid
126
+ */
127
+ getAccount(sub: Sub): Awaitable<{
128
+ account: Account
129
+ authorizedClients: AuthorizedClients
130
+ }>
131
+
132
+ /**
133
+ * @param data.requestId - If provided, the inserted account must be bound to
134
+ * that particular requestId.
135
+ *
136
+ * @note Whenever a particular device account is created, all **unbound**
137
+ * device accounts for the same `deviceId` & `sub` should be deleted.
138
+ *
139
+ * @note When a particular request is deleted (through
140
+ * {@link RequestStore.deleteRequest}), all accounts bound to that request
141
+ * should be deleted as well.
142
+ */
143
+ upsertDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>
144
+
145
+ /**
146
+ * @param requestId - If provided, the result must either have the same
147
+ * requestId, or not be bound to a particular requestId. If `null`, the
148
+ * result must not be bound to a particular requestId.
149
+ * @throws {InvalidRequestError} - Instead of returning `null` in order to
150
+ * provide a custom error message
151
151
  */
152
- addDeviceAccount(
152
+ getDeviceAccount(
153
153
  deviceId: DeviceId,
154
154
  sub: Sub,
155
- remember: boolean,
156
- ): Awaitable<DeviceAccountInfo>
155
+ ): Awaitable<DeviceAccount | null>
157
156
 
158
157
  /**
159
- * @returns The account info, whether the account, even if remember was false.
158
+ * Removes *all* the unbound device-accounts associated with the given device
159
+ * & account.
160
+ *
161
+ * @note Noop if the device-account is not found.
160
162
  */
161
- getDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<AccountInfo | null>
162
163
  removeDeviceAccount(deviceId: DeviceId, sub: Sub): Awaitable<void>
163
164
 
164
165
  /**
165
- * @note Only the accounts that where logged in with `remember: true` need to
166
- * be returned. The others will be ignored.
166
+ * @returns **all** the device accounts that match the {@link requestId}
167
+ * criteria and given {@link filter}.
167
168
  */
168
- listDeviceAccounts(deviceId: DeviceId): Awaitable<AccountInfo[]>
169
+ listDeviceAccounts(
170
+ filter: { sub: Sub } | { deviceId: DeviceId },
171
+ ): Awaitable<DeviceAccount[]>
169
172
 
170
173
  resetPasswordRequest(data: ResetPasswordRequestData): Awaitable<void>
171
174
  resetPasswordConfirm(data: ResetPasswordConfirmData): Awaitable<void>
@@ -179,8 +182,9 @@ export interface AccountStore {
179
182
  export const isAccountStore = buildInterfaceChecker<AccountStore>([
180
183
  'createAccount',
181
184
  'authenticateAccount',
182
- 'addAuthorizedClient',
183
- 'addDeviceAccount',
185
+ 'setAuthorizedClient',
186
+ 'getAccount',
187
+ 'upsertDeviceAccount',
184
188
  'getDeviceAccount',
185
189
  'removeDeviceAccount',
186
190
  'listDeviceAccounts',
@@ -1,15 +1,15 @@
1
1
  import { z } from 'zod'
2
- import { authenticateAccountDataSchema } from './account-store.js'
2
+ import { localeSchema } from '../lib/util/locale.js'
3
+ import { emailOtpSchema } from '../types/email-otp.js'
4
+ import { newPasswordSchema, oldPasswordSchema } from '../types/password.js'
3
5
 
4
- export const signInDataSchema = authenticateAccountDataSchema
5
- .extend({
6
- /**
7
- * If false, the account must not be returned from
8
- * {@link AccountStore.listDeviceAccounts}. Note that this only makes sense when
9
- * used with a device ID.
10
- */
11
- remember: z.boolean().optional().default(false),
6
+ export const signInDataSchema = z
7
+ .object({
8
+ locale: localeSchema,
9
+ username: z.string(),
10
+ password: z.union([oldPasswordSchema, newPasswordSchema]),
11
+ emailOtp: emailOtpSchema.optional(),
12
12
  })
13
13
  .strict()
14
14
 
15
- export type SignInData = z.TypeOf<typeof signInDataSchema>
15
+ export type SignInData = z.output<typeof signInDataSchema>
@@ -1,11 +1,20 @@
1
1
  import { z } from 'zod'
2
2
  import { hcaptchaTokenSchema } from '../lib/hcaptcha.js'
3
- import { createAccountDataSchema } from './account-store.js'
3
+ import { localeSchema } from '../lib/util/locale.js'
4
+ import { emailSchema } from '../types/email.js'
5
+ import { handleSchema } from '../types/handle.js'
6
+ import { inviteCodeSchema } from '../types/invite-code.js'
7
+ import { newPasswordSchema } from '../types/password.js'
4
8
 
5
- export const signUpInputSchema = createAccountDataSchema
6
- .extend({
9
+ export const signUpInputSchema = z
10
+ .object({
11
+ locale: localeSchema,
12
+ handle: handleSchema,
13
+ email: emailSchema,
14
+ password: newPasswordSchema,
15
+ inviteCode: inviteCodeSchema.optional(),
7
16
  hcaptchaToken: hcaptchaTokenSchema.optional(),
8
17
  })
9
18
  .strict()
10
19
 
11
- export type SignUpInput = z.TypeOf<typeof signUpInputSchema>
20
+ export type SignUpInput = z.output<typeof signUpInputSchema>
@@ -93,7 +93,7 @@ export class ClientManager {
93
93
  *
94
94
  * @see {@link https://openid.net/specs/openid-connect-registration-1_0.html#rfc.section.2 OIDC Client Registration}
95
95
  */
96
- public async getClient(clientId: string) {
96
+ public async getClient(clientId: ClientId) {
97
97
  const metadata = await this.getClientMetadata(clientId).catch((err) => {
98
98
  throw InvalidClientMetadataError.from(
99
99
  err,
@@ -126,6 +126,38 @@ export class ClientManager {
126
126
  return new Client(clientId, metadata, jwks, { isFirstParty, isTrusted })
127
127
  }
128
128
 
129
+ public async loadClients(
130
+ clientIds: Iterable<ClientId>,
131
+ {
132
+ onError = (err) => {
133
+ throw err
134
+ },
135
+ }: {
136
+ onError?: (
137
+ err: unknown,
138
+ clientId: ClientId,
139
+ ) => Awaitable<Client | null | undefined>
140
+ } = {},
141
+ ): Promise<Map<ClientId, Client>> {
142
+ // Make sure we don't load the same client multiple times
143
+ const uniqueClientIds =
144
+ clientIds instanceof Set ? clientIds : new Set(clientIds)
145
+
146
+ // Load all (unique) clients in parallel
147
+ const clients = await Promise.all(
148
+ Array.from(uniqueClientIds, async (clientId) =>
149
+ this.getClient(clientId).catch((err) => onError(err, clientId)),
150
+ ),
151
+ )
152
+
153
+ // Return a map for easy lookups
154
+ return new Map(
155
+ clients
156
+ .filter((c) => c != null && c instanceof Client)
157
+ .map((c) => [c.id, c]),
158
+ )
159
+ }
160
+
129
161
  protected async getClientMetadata(
130
162
  clientId: ClientId,
131
163
  ): Promise<OAuthClientMetadata> {
@@ -257,7 +289,7 @@ export class ClientManager {
257
289
  `Grant type "${grantType}" is not allowed`,
258
290
  )
259
291
 
260
- // @TODO: Add support (e.g. for first party client)
292
+ // @TODO Add support (e.g. for first party client)
261
293
  // case 'client_credentials':
262
294
  // case 'password':
263
295
  case 'authorization_code':
@@ -5,7 +5,7 @@ import { ClientId } from './client-id.js'
5
5
  // Export all types needed to implement the ClientStore interface
6
6
  export * from './client-data.js'
7
7
  export * from './client-id.js'
8
- export type { Awaitable }
8
+ export type { Awaitable, OAuthClientMetadata }
9
9
 
10
10
  export interface ClientStore {
11
11
  findClient(clientId: ClientId): Awaitable<OAuthClientMetadata>
package/src/constants.ts CHANGED
@@ -29,6 +29,9 @@ const MONTH = YEAR / 12
29
29
  /** 7 days */
30
30
  export const AUTHENTICATION_MAX_AGE = 7 * DAY
31
31
 
32
+ /** 15 minutes */
33
+ export const EPHEMERAL_SESSION_MAX_AGE = 15 * MINUTE
34
+
32
35
  /** 60 minutes */
33
36
  export const TOKEN_MAX_AGE = 60 * MINUTE
34
37
 
@@ -53,7 +56,9 @@ export const PAR_EXPIRES_IN = 5 * MINUTE
53
56
  /**
54
57
  * 59 seconds (should be less than a minute)
55
58
  *
56
- * @see {@link https://datatracker.ietf.org/doc/html/rfc9101#section-10.2}
59
+ * > "A general guidance for the validity time would be less than a minute."
60
+ *
61
+ * @see {@link https://datatracker.ietf.org/doc/html/rfc9101#section-10.2 | JWT-Secured Authorization Request (JAR) - Section 10.2 (d)}
57
62
  */
58
63
  export const JAR_MAX_AGE = 59 * SECOND
59
64
 
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod'
2
+ import { colorsSchema } from './colors.js'
3
+ import { linksSchema } from './links.js'
4
+
5
+ export const brandingSchema = z.object({
6
+ name: z.string().optional(),
7
+ logo: z.string().url().optional(),
8
+ colors: colorsSchema.optional(),
9
+ links: z.array(linksSchema).optional(),
10
+ })
11
+ export type BrandingInput = z.input<typeof brandingSchema>
12
+ export type Branding = z.infer<typeof brandingSchema>
@@ -0,0 +1,30 @@
1
+ import { extractHue, pickContrastColor } from '../lib/util/color.js'
2
+ import { Branding } from './branding.js'
3
+ import { COLOR_NAMES } from './colors.js'
4
+ import { Customization } from './customization.js'
5
+
6
+ export function buildCustomizationCss({
7
+ branding,
8
+ }: Customization): undefined | string {
9
+ const vars = Array.from(buildCustomizationVars(branding))
10
+ if (vars.length) return `:root { ${vars.join(' ')} }`
11
+ }
12
+
13
+ function* buildCustomizationVars(branding?: Branding): Generator<string> {
14
+ if (branding?.colors) {
15
+ // @NOTE these could come from branding (in the future)
16
+ const contrastLight = { r: 255, g: 255, b: 255 }
17
+ const contrastDark = { r: 0, g: 0, b: 0 }
18
+
19
+ for (const name of COLOR_NAMES) {
20
+ const value = branding.colors[name]
21
+ if (!value) continue // Skip missing colors
22
+
23
+ const contrast = pickContrastColor(value, contrastLight, contrastDark)
24
+
25
+ yield `--branding-color-${name}: ${value.r} ${value.g} ${value.b};`
26
+ yield `--branding-color-${name}-contrast: ${contrast.r} ${contrast.g} ${contrast.b};`
27
+ yield `--branding-color-${name}-hue: ${extractHue(value)};`
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,22 @@
1
+ import { CustomizationData } from '@atproto/oauth-provider-api'
2
+ import { Customization } from './customization.js'
3
+
4
+ export function buildCustomizationData({
5
+ branding,
6
+ availableUserDomains,
7
+ inviteCodeRequired,
8
+ hcaptcha,
9
+ }: Customization): CustomizationData {
10
+ // @NOTE the front end does not need colors here as they will be injected as
11
+ // CSS variables.
12
+ // @NOTE We only copy the values explicitly needed to avoid leaking sensitive
13
+ // data (in case the caller passed more than what we expect).
14
+ return {
15
+ availableUserDomains,
16
+ inviteCodeRequired,
17
+ hcaptchaSiteKey: hcaptcha?.siteKey,
18
+ name: branding?.name,
19
+ logo: branding?.logo,
20
+ links: branding?.links,
21
+ }
22
+ }
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod'
2
+ import { RgbColor, parseColor } from '../lib/util/color.js'
3
+
4
+ export const COLOR_NAMES = ['primary', 'error', 'warning', 'success'] as const
5
+
6
+ export const rgbColorSchema = z.string().transform((value, ctx): RgbColor => {
7
+ try {
8
+ const parsed = parseColor(value)
9
+ if ('a' in parsed && parsed.a !== undefined) {
10
+ ctx.addIssue({
11
+ code: z.ZodIssueCode.custom,
12
+ message: 'Alpha values are not supported',
13
+ })
14
+ }
15
+ return parsed
16
+ } catch (e) {
17
+ ctx.addIssue({
18
+ code: z.ZodIssueCode.custom,
19
+ message: e instanceof Error ? e.message : 'Invalid color value',
20
+ })
21
+ return z.NEVER
22
+ }
23
+ })
24
+
25
+ export const colorsSchema = z.record(
26
+ z.enum(COLOR_NAMES),
27
+ rgbColorSchema.optional(),
28
+ )
29
+
30
+ export type Colors = z.infer<typeof colorsSchema>
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod'
2
+ import { hcaptchaConfigSchema } from '../lib/hcaptcha.js'
3
+ import { brandingSchema } from './branding.js'
4
+
5
+ export const customizationSchema = z.object({
6
+ /**
7
+ * Available user domains that can be used to sign up. A non-empty array
8
+ * is required to enable the sign-up feature.
9
+ */
10
+ availableUserDomains: z.array(z.string()).optional(),
11
+ /**
12
+ * UI customizations
13
+ */
14
+ branding: brandingSchema.optional(),
15
+ /**
16
+ * Is an invite code required to sign up?
17
+ */
18
+ inviteCodeRequired: z.boolean().optional(),
19
+ /**
20
+ * Enables hCaptcha during sign-up.
21
+ */
22
+ hcaptcha: hcaptchaConfigSchema.optional(),
23
+ })
24
+ export type CustomizationInput = z.input<typeof customizationSchema>
25
+ export type Customization = z.infer<typeof customizationSchema>
@@ -0,0 +1,10 @@
1
+ import { z } from 'zod'
2
+ import { isLinkRel } from '../lib/html/build-document.js'
3
+ import { localizedStringSchema } from '../lib/util/locale.js'
4
+
5
+ export const linksSchema = z.object({
6
+ title: localizedStringSchema,
7
+ href: z.string().url(),
8
+ rel: z.string().refine(isLinkRel, 'Invalid link rel').optional(),
9
+ })
10
+ export type Links = z.infer<typeof linksSchema>
@@ -17,6 +17,11 @@ export const deviceIdSchema = z
17
17
  )
18
18
 
19
19
  export type DeviceId = z.infer<typeof deviceIdSchema>
20
+
21
+ export function isDeviceId(value: unknown): value is DeviceId {
22
+ return deviceIdSchema.safeParse(value).success
23
+ }
24
+
20
25
  export const generateDeviceId = async (): Promise<DeviceId> => {
21
26
  return `${DEVICE_ID_PREFIX}${await randomHexId(DEVICE_ID_BYTES_LENGTH)}`
22
27
  }