@draftlab/auth 0.15.0 → 0.16.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 (272) hide show
  1. package/dist/esm/allow.js +26 -0
  2. package/dist/esm/client.js +254 -0
  3. package/dist/esm/core.js +597 -0
  4. package/dist/esm/css.d.js +0 -0
  5. package/dist/esm/error.js +88 -0
  6. package/dist/esm/index.js +5 -0
  7. package/dist/esm/keys.js +126 -0
  8. package/dist/esm/mutex.js +53 -0
  9. package/dist/esm/pkce.js +87 -0
  10. package/dist/esm/provider/apple.js +15 -0
  11. package/dist/esm/provider/code.js +62 -0
  12. package/dist/esm/provider/discord.js +15 -0
  13. package/dist/esm/provider/facebook.js +15 -0
  14. package/dist/esm/provider/github.js +15 -0
  15. package/dist/esm/provider/gitlab.js +15 -0
  16. package/dist/esm/provider/google.js +16 -0
  17. package/dist/esm/provider/linkedin.js +15 -0
  18. package/dist/esm/provider/magiclink.js +83 -0
  19. package/dist/esm/provider/microsoft.js +15 -0
  20. package/dist/esm/provider/oauth2.js +130 -0
  21. package/dist/esm/provider/password.js +331 -0
  22. package/dist/esm/provider/provider.js +18 -0
  23. package/dist/esm/provider/reddit.js +15 -0
  24. package/dist/esm/provider/slack.js +15 -0
  25. package/dist/esm/provider/spotify.js +15 -0
  26. package/dist/esm/provider/twitch.js +15 -0
  27. package/dist/esm/provider/vercel.js +17 -0
  28. package/dist/esm/random.js +40 -0
  29. package/dist/esm/revocation.js +27 -0
  30. package/dist/esm/storage/memory.js +110 -0
  31. package/dist/esm/storage/storage.js +56 -0
  32. package/dist/esm/storage/turso.js +93 -0
  33. package/dist/esm/storage/unstorage.js +78 -0
  34. package/dist/esm/subject.js +7 -0
  35. package/dist/esm/themes/theme.js +115 -0
  36. package/dist/esm/toolkit/client.js +119 -0
  37. package/dist/esm/toolkit/index.js +25 -0
  38. package/dist/esm/toolkit/providers/facebook.js +11 -0
  39. package/dist/esm/toolkit/providers/github.js +11 -0
  40. package/dist/esm/toolkit/providers/google.js +11 -0
  41. package/dist/esm/toolkit/providers/strategy.js +0 -0
  42. package/dist/esm/toolkit/storage.js +81 -0
  43. package/dist/esm/toolkit/utils.js +18 -0
  44. package/dist/esm/types.js +0 -0
  45. package/dist/esm/ui/base.js +478 -0
  46. package/dist/esm/ui/code.js +186 -0
  47. package/dist/esm/ui/form.js +46 -0
  48. package/dist/esm/ui/icon.js +242 -0
  49. package/dist/esm/ui/magiclink.js +158 -0
  50. package/dist/esm/ui/password.js +435 -0
  51. package/dist/esm/ui/select.js +102 -0
  52. package/dist/esm/util.js +59 -0
  53. package/dist/{allow.d.mts → types/allow.d.ts} +9 -11
  54. package/dist/types/allow.d.ts.map +1 -0
  55. package/dist/types/client.d.ts +462 -0
  56. package/dist/types/client.d.ts.map +1 -0
  57. package/dist/types/core.d.ts +113 -0
  58. package/dist/types/core.d.ts.map +1 -0
  59. package/dist/{error.d.mts → types/error.d.ts} +95 -97
  60. package/dist/types/error.d.ts.map +1 -0
  61. package/dist/types/index.d.ts +2 -0
  62. package/dist/types/index.d.ts.map +1 -0
  63. package/dist/{keys.d.mts → types/keys.d.ts} +20 -24
  64. package/dist/types/keys.d.ts.map +1 -0
  65. package/dist/types/mutex.d.ts +42 -0
  66. package/dist/types/mutex.d.ts.map +1 -0
  67. package/dist/{pkce.d.mts → types/pkce.d.ts} +10 -11
  68. package/dist/types/pkce.d.ts.map +1 -0
  69. package/dist/types/provider/apple.d.ts +197 -0
  70. package/dist/types/provider/apple.d.ts.map +1 -0
  71. package/dist/types/provider/code.d.ts +288 -0
  72. package/dist/types/provider/code.d.ts.map +1 -0
  73. package/dist/types/provider/discord.d.ts +206 -0
  74. package/dist/types/provider/discord.d.ts.map +1 -0
  75. package/dist/types/provider/facebook.d.ts +200 -0
  76. package/dist/types/provider/facebook.d.ts.map +1 -0
  77. package/dist/types/provider/github.d.ts +220 -0
  78. package/dist/types/provider/github.d.ts.map +1 -0
  79. package/dist/types/provider/gitlab.d.ts +180 -0
  80. package/dist/types/provider/gitlab.d.ts.map +1 -0
  81. package/dist/types/provider/google.d.ts +158 -0
  82. package/dist/types/provider/google.d.ts.map +1 -0
  83. package/dist/types/provider/linkedin.d.ts +190 -0
  84. package/dist/types/provider/linkedin.d.ts.map +1 -0
  85. package/dist/types/provider/magiclink.d.ts +141 -0
  86. package/dist/types/provider/magiclink.d.ts.map +1 -0
  87. package/dist/types/provider/microsoft.d.ts +247 -0
  88. package/dist/types/provider/microsoft.d.ts.map +1 -0
  89. package/dist/types/provider/oauth2.d.ts +229 -0
  90. package/dist/types/provider/oauth2.d.ts.map +1 -0
  91. package/dist/types/provider/password.d.ts +408 -0
  92. package/dist/types/provider/password.d.ts.map +1 -0
  93. package/dist/types/provider/provider.d.ts +226 -0
  94. package/dist/types/provider/provider.d.ts.map +1 -0
  95. package/dist/types/provider/reddit.d.ts +159 -0
  96. package/dist/types/provider/reddit.d.ts.map +1 -0
  97. package/dist/types/provider/slack.d.ts +171 -0
  98. package/dist/types/provider/slack.d.ts.map +1 -0
  99. package/dist/types/provider/spotify.d.ts +168 -0
  100. package/dist/types/provider/spotify.d.ts.map +1 -0
  101. package/dist/types/provider/twitch.d.ts +163 -0
  102. package/dist/types/provider/twitch.d.ts.map +1 -0
  103. package/dist/types/provider/vercel.d.ts +294 -0
  104. package/dist/types/provider/vercel.d.ts.map +1 -0
  105. package/dist/{random.d.mts → types/random.d.ts} +4 -6
  106. package/dist/types/random.d.ts.map +1 -0
  107. package/dist/types/revocation.d.ts +76 -0
  108. package/dist/types/revocation.d.ts.map +1 -0
  109. package/dist/{storage/memory.d.mts → types/storage/memory.d.ts} +17 -21
  110. package/dist/types/storage/memory.d.ts.map +1 -0
  111. package/dist/types/storage/storage.d.ts +177 -0
  112. package/dist/types/storage/storage.d.ts.map +1 -0
  113. package/dist/{storage/turso.d.mts → types/storage/turso.d.ts} +4 -8
  114. package/dist/types/storage/turso.d.ts.map +1 -0
  115. package/dist/{storage/unstorage.d.mts → types/storage/unstorage.d.ts} +12 -11
  116. package/dist/types/storage/unstorage.d.ts.map +1 -0
  117. package/dist/types/subject.d.ts +115 -0
  118. package/dist/types/subject.d.ts.map +1 -0
  119. package/dist/types/themes/theme.d.ts +207 -0
  120. package/dist/types/themes/theme.d.ts.map +1 -0
  121. package/dist/types/toolkit/client.d.ts +235 -0
  122. package/dist/types/toolkit/client.d.ts.map +1 -0
  123. package/dist/types/toolkit/index.d.ts +45 -0
  124. package/dist/types/toolkit/index.d.ts.map +1 -0
  125. package/dist/types/toolkit/providers/facebook.d.ts +8 -0
  126. package/dist/types/toolkit/providers/facebook.d.ts.map +1 -0
  127. package/dist/types/toolkit/providers/github.d.ts +8 -0
  128. package/dist/types/toolkit/providers/github.d.ts.map +1 -0
  129. package/dist/types/toolkit/providers/google.d.ts +8 -0
  130. package/dist/types/toolkit/providers/google.d.ts.map +1 -0
  131. package/dist/types/toolkit/providers/strategy.d.ts +38 -0
  132. package/dist/types/toolkit/providers/strategy.d.ts.map +1 -0
  133. package/dist/{toolkit/storage.d.mts → types/toolkit/storage.d.ts} +37 -39
  134. package/dist/types/toolkit/storage.d.ts.map +1 -0
  135. package/dist/{toolkit/utils.d.mts → types/toolkit/utils.d.ts} +2 -4
  136. package/dist/types/toolkit/utils.d.ts.map +1 -0
  137. package/dist/types/types.d.ts +92 -0
  138. package/dist/types/types.d.ts.map +1 -0
  139. package/dist/types/ui/base.d.ts +18 -0
  140. package/dist/types/ui/base.d.ts.map +1 -0
  141. package/dist/types/ui/code.d.ts +43 -0
  142. package/dist/types/ui/code.d.ts.map +1 -0
  143. package/dist/types/ui/form.d.ts +24 -0
  144. package/dist/types/ui/form.d.ts.map +1 -0
  145. package/dist/types/ui/icon.d.ts +60 -0
  146. package/dist/types/ui/icon.d.ts.map +1 -0
  147. package/dist/types/ui/magiclink.d.ts +41 -0
  148. package/dist/types/ui/magiclink.d.ts.map +1 -0
  149. package/dist/types/ui/password.d.ts +43 -0
  150. package/dist/types/ui/password.d.ts.map +1 -0
  151. package/dist/types/ui/select.d.ts +33 -0
  152. package/dist/types/ui/select.d.ts.map +1 -0
  153. package/dist/{util.d.mts → types/util.d.ts} +11 -13
  154. package/dist/types/util.d.ts.map +1 -0
  155. package/package.json +10 -16
  156. package/dist/adapters/node.d.mts +0 -18
  157. package/dist/adapters/node.mjs +0 -69
  158. package/dist/allow.mjs +0 -63
  159. package/dist/client.d.mts +0 -456
  160. package/dist/client.mjs +0 -283
  161. package/dist/core.d.mts +0 -110
  162. package/dist/core.mjs +0 -595
  163. package/dist/error.mjs +0 -237
  164. package/dist/index.d.mts +0 -2
  165. package/dist/index.mjs +0 -3
  166. package/dist/keys.mjs +0 -146
  167. package/dist/mutex.d.mts +0 -44
  168. package/dist/mutex.mjs +0 -110
  169. package/dist/pkce.mjs +0 -157
  170. package/dist/provider/apple.d.mts +0 -111
  171. package/dist/provider/apple.mjs +0 -164
  172. package/dist/provider/code.d.mts +0 -228
  173. package/dist/provider/code.mjs +0 -246
  174. package/dist/provider/discord.d.mts +0 -146
  175. package/dist/provider/discord.mjs +0 -156
  176. package/dist/provider/facebook.d.mts +0 -142
  177. package/dist/provider/facebook.mjs +0 -150
  178. package/dist/provider/github.d.mts +0 -140
  179. package/dist/provider/github.mjs +0 -169
  180. package/dist/provider/gitlab.d.mts +0 -106
  181. package/dist/provider/gitlab.mjs +0 -147
  182. package/dist/provider/google.d.mts +0 -112
  183. package/dist/provider/google.mjs +0 -109
  184. package/dist/provider/linkedin.d.mts +0 -132
  185. package/dist/provider/linkedin.mjs +0 -142
  186. package/dist/provider/magiclink.d.mts +0 -89
  187. package/dist/provider/magiclink.mjs +0 -143
  188. package/dist/provider/microsoft.d.mts +0 -178
  189. package/dist/provider/microsoft.mjs +0 -177
  190. package/dist/provider/oauth2.d.mts +0 -176
  191. package/dist/provider/oauth2.mjs +0 -222
  192. package/dist/provider/passkey.d.mts +0 -104
  193. package/dist/provider/passkey.mjs +0 -320
  194. package/dist/provider/password.d.mts +0 -412
  195. package/dist/provider/password.mjs +0 -363
  196. package/dist/provider/provider.d.mts +0 -227
  197. package/dist/provider/provider.mjs +0 -44
  198. package/dist/provider/reddit.d.mts +0 -107
  199. package/dist/provider/reddit.mjs +0 -127
  200. package/dist/provider/slack.d.mts +0 -114
  201. package/dist/provider/slack.mjs +0 -138
  202. package/dist/provider/spotify.d.mts +0 -113
  203. package/dist/provider/spotify.mjs +0 -135
  204. package/dist/provider/totp.d.mts +0 -112
  205. package/dist/provider/totp.mjs +0 -191
  206. package/dist/provider/twitch.d.mts +0 -108
  207. package/dist/provider/twitch.mjs +0 -131
  208. package/dist/provider/vercel.d.mts +0 -177
  209. package/dist/provider/vercel.mjs +0 -230
  210. package/dist/random.mjs +0 -86
  211. package/dist/revocation.d.mts +0 -55
  212. package/dist/revocation.mjs +0 -63
  213. package/dist/router/context.d.mts +0 -21
  214. package/dist/router/context.mjs +0 -193
  215. package/dist/router/cookies.d.mts +0 -8
  216. package/dist/router/cookies.mjs +0 -13
  217. package/dist/router/index.d.mts +0 -21
  218. package/dist/router/index.mjs +0 -107
  219. package/dist/router/matcher.d.mts +0 -15
  220. package/dist/router/matcher.mjs +0 -76
  221. package/dist/router/middleware/cors.d.mts +0 -15
  222. package/dist/router/middleware/cors.mjs +0 -114
  223. package/dist/router/safe-request.d.mts +0 -52
  224. package/dist/router/safe-request.mjs +0 -160
  225. package/dist/router/types.d.mts +0 -67
  226. package/dist/router/types.mjs +0 -1
  227. package/dist/router/variables.d.mts +0 -12
  228. package/dist/router/variables.mjs +0 -20
  229. package/dist/storage/memory.mjs +0 -125
  230. package/dist/storage/storage.d.mts +0 -179
  231. package/dist/storage/storage.mjs +0 -104
  232. package/dist/storage/turso.mjs +0 -117
  233. package/dist/storage/unstorage.mjs +0 -103
  234. package/dist/subject.d.mts +0 -62
  235. package/dist/subject.mjs +0 -36
  236. package/dist/themes/theme.d.mts +0 -209
  237. package/dist/themes/theme.mjs +0 -120
  238. package/dist/toolkit/client.d.mts +0 -169
  239. package/dist/toolkit/client.mjs +0 -209
  240. package/dist/toolkit/index.d.mts +0 -9
  241. package/dist/toolkit/index.mjs +0 -9
  242. package/dist/toolkit/providers/facebook.d.mts +0 -12
  243. package/dist/toolkit/providers/facebook.mjs +0 -16
  244. package/dist/toolkit/providers/github.d.mts +0 -12
  245. package/dist/toolkit/providers/github.mjs +0 -16
  246. package/dist/toolkit/providers/google.d.mts +0 -12
  247. package/dist/toolkit/providers/google.mjs +0 -20
  248. package/dist/toolkit/providers/strategy.d.mts +0 -40
  249. package/dist/toolkit/providers/strategy.mjs +0 -1
  250. package/dist/toolkit/storage.mjs +0 -157
  251. package/dist/toolkit/utils.mjs +0 -30
  252. package/dist/types.d.mts +0 -94
  253. package/dist/types.mjs +0 -1
  254. package/dist/ui/base.d.mts +0 -30
  255. package/dist/ui/base.mjs +0 -407
  256. package/dist/ui/code.d.mts +0 -43
  257. package/dist/ui/code.mjs +0 -173
  258. package/dist/ui/form.d.mts +0 -32
  259. package/dist/ui/form.mjs +0 -49
  260. package/dist/ui/icon.d.mts +0 -58
  261. package/dist/ui/icon.mjs +0 -247
  262. package/dist/ui/magiclink.d.mts +0 -41
  263. package/dist/ui/magiclink.mjs +0 -152
  264. package/dist/ui/passkey.d.mts +0 -27
  265. package/dist/ui/passkey.mjs +0 -323
  266. package/dist/ui/password.d.mts +0 -42
  267. package/dist/ui/password.mjs +0 -402
  268. package/dist/ui/select.d.mts +0 -34
  269. package/dist/ui/select.mjs +0 -98
  270. package/dist/ui/totp.d.mts +0 -34
  271. package/dist/ui/totp.mjs +0 -270
  272. package/dist/util.mjs +0 -128
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Spotify authentication provider for Draft Auth.
3
+ * Implements OAuth 2.0 flow for authenticating users with their Spotify accounts.
4
+ *
5
+ * ## Quick Setup
6
+ *
7
+ * ```ts
8
+ * import { SpotifyProvider } from "@draftlab/auth/provider/spotify"
9
+ *
10
+ * export default issuer({
11
+ * basePath: "/auth", // Important for callback URL
12
+ * providers: {
13
+ * spotify: SpotifyProvider({
14
+ * clientID: process.env.SPOTIFY_CLIENT_ID,
15
+ * clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
16
+ * scopes: ["user-read-private", "user-read-email"]
17
+ * })
18
+ * }
19
+ * })
20
+ * ```
21
+ *
22
+ * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
23
+ * - Development: `http://localhost:3000/auth/spotify/callback`
24
+ * - Production: `https://yourapp.com/auth/spotify/callback`
25
+ *
26
+ * Register this URL in your Spotify Developer Dashboard.
27
+ *
28
+ * ## Common Scopes
29
+ *
30
+ * - `user-read-private` - Access user's private data
31
+ * - `user-read-email` - Access user's email address
32
+ * - `user-top-read` - Read user's top artists and tracks
33
+ * - `user-read-playback-state` - Read current playback state
34
+ * - `user-modify-playback-state` - Modify playback state
35
+ * - `user-read-currently-playing` - Read currently playing track
36
+ * - `playlist-read-private` - Access private playlists
37
+ * - `playlist-read-public` - Access public playlists
38
+ * - `user-library-read` - Read user's library
39
+ * - `user-follow-read` - Read followed artists and users
40
+ *
41
+ * ## User Data Access
42
+ *
43
+ * ```ts
44
+ * success: async (ctx, value) => {
45
+ * if (value.provider === "spotify") {
46
+ * const accessToken = value.tokenset.access
47
+ *
48
+ * // Fetch user profile
49
+ * const userResponse = await fetch('https://api.spotify.com/v1/me', {
50
+ * headers: { Authorization: `Bearer ${accessToken}` }
51
+ * })
52
+ * const user = await userResponse.json()
53
+ *
54
+ * // User info: id, email, display_name, external_urls, images, followers
55
+ * }
56
+ * }
57
+ * ```
58
+ *
59
+ * @packageDocumentation
60
+ */
61
+ import { type Oauth2WrappedConfig } from "./oauth2";
62
+ /**
63
+ * Configuration options for Spotify OAuth 2.0 provider.
64
+ * Extends the base OAuth 2.0 configuration with Spotify-specific documentation.
65
+ */
66
+ export interface SpotifyConfig extends Oauth2WrappedConfig {
67
+ /**
68
+ * Spotify app client ID.
69
+ * Get this from your Spotify App at https://developer.spotify.com/dashboard
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * {
74
+ * clientID: "abcdef123456"
75
+ * }
76
+ * ```
77
+ */
78
+ readonly clientID: string;
79
+ /**
80
+ * Spotify app client secret.
81
+ * Keep this secure and never expose it to client-side code.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * {
86
+ * clientSecret: process.env.SPOTIFY_CLIENT_SECRET
87
+ * }
88
+ * ```
89
+ */
90
+ readonly clientSecret: string;
91
+ /**
92
+ * Spotify OAuth scopes to request access for.
93
+ * Determines what data and actions your app can access.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * {
98
+ * scopes: [
99
+ * "user-read-private", // Access private user data
100
+ * "user-read-email", // Access user email
101
+ * "user-top-read" // Read top artists and tracks
102
+ * ]
103
+ * }
104
+ * ```
105
+ */
106
+ readonly scopes: string[];
107
+ }
108
+ /**
109
+ * Creates a Spotify OAuth 2.0 authentication provider.
110
+ * Allows users to authenticate using their Spotify accounts.
111
+ *
112
+ * @param config - Spotify OAuth 2.0 configuration
113
+ * @returns OAuth 2.0 provider configured for Spotify
114
+ *
115
+ * @example
116
+ * ```ts
117
+ * // Basic Spotify authentication
118
+ * const basicSpotify = SpotifyProvider({
119
+ * clientID: process.env.SPOTIFY_CLIENT_ID,
120
+ * clientSecret: process.env.SPOTIFY_CLIENT_SECRET
121
+ * })
122
+ *
123
+ * // Spotify with user data access
124
+ * const spotifyWithScopes = SpotifyProvider({
125
+ * clientID: process.env.SPOTIFY_CLIENT_ID,
126
+ * clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
127
+ * scopes: ["user-read-private", "user-read-email", "user-top-read"]
128
+ * })
129
+ *
130
+ * // Using the access token to fetch user data
131
+ * export default issuer({
132
+ * providers: { spotify: spotifyWithScopes },
133
+ * success: async (ctx, value) => {
134
+ * if (value.provider === "spotify") {
135
+ * const token = value.tokenset.access
136
+ *
137
+ * const userRes = await fetch('https://api.spotify.com/v1/me', {
138
+ * headers: { Authorization: `Bearer ${token}` }
139
+ * })
140
+ * const user = await userRes.json()
141
+ *
142
+ * // Optionally fetch top tracks
143
+ * const topRes = await fetch('https://api.spotify.com/v1/me/top/tracks?limit=5', {
144
+ * headers: { Authorization: `Bearer ${token}` }
145
+ * })
146
+ * const { items: topTracks } = await topRes.json()
147
+ *
148
+ * return ctx.subject("user", {
149
+ * spotifyId: user.id,
150
+ * email: user.email,
151
+ * displayName: user.display_name,
152
+ * profileUrl: user.external_urls?.spotify,
153
+ * followers: user.followers?.total,
154
+ * topTracks: topTracks.map(t => t.name)
155
+ * })
156
+ * }
157
+ * }
158
+ * })
159
+ * ```
160
+ *
161
+ * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
162
+ * - Development: `http://localhost:3000/auth/spotify/callback`
163
+ * - Production: `https://yourapp.com/auth/spotify/callback`
164
+ *
165
+ * Register this URL in your Spotify Developer Dashboard.
166
+ */
167
+ export declare const SpotifyProvider: (config: SpotifyConfig) => import("./provider").Provider<import("./oauth2").Oauth2UserData>;
168
+ //# sourceMappingURL=spotify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spotify.d.ts","sourceRoot":"","sources":["../../../src/provider/spotify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IACzD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,aAAa,qEASpD,CAAA"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Twitch authentication provider for Draft Auth.
3
+ * Implements OAuth 2.0 flow for authenticating users with their Twitch accounts.
4
+ *
5
+ * ## Quick Setup
6
+ *
7
+ * ```ts
8
+ * import { TwitchProvider } from "@draftlab/auth/provider/twitch"
9
+ *
10
+ * export default issuer({
11
+ * basePath: "/auth", // Important for callback URL
12
+ * providers: {
13
+ * twitch: TwitchProvider({
14
+ * clientID: process.env.TWITCH_CLIENT_ID,
15
+ * clientSecret: process.env.TWITCH_CLIENT_SECRET,
16
+ * scopes: ["user:read:email"]
17
+ * })
18
+ * }
19
+ * })
20
+ * ```
21
+ *
22
+ * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
23
+ * - Development: `http://localhost:3000/auth/twitch/callback`
24
+ * - Production: `https://yourapp.com/auth/twitch/callback`
25
+ *
26
+ * Register this URL in your Twitch Developer Console.
27
+ *
28
+ * ## Common Scopes
29
+ *
30
+ * - `user:read:email` - Access user's email address
31
+ * - `user:read:subscriptions` - View user subscriptions
32
+ * - `user:read:follows` - View user's follows
33
+ * - `channel:read:subscriptions` - View channel subscribers
34
+ * - `analytics:read:games` - View game analytics
35
+ * - `bits:read` - View bits information
36
+ *
37
+ * ## User Data Access
38
+ *
39
+ * ```ts
40
+ * success: async (ctx, value) => {
41
+ * if (value.provider === "twitch") {
42
+ * const accessToken = value.tokenset.access
43
+ *
44
+ * // Fetch user information
45
+ * const userResponse = await fetch('https://api.twitch.tv/helix/users', {
46
+ * headers: {
47
+ * 'Authorization': `Bearer ${accessToken}`,
48
+ * 'Client-ID': process.env.TWITCH_CLIENT_ID
49
+ * }
50
+ * })
51
+ * const { data } = await userResponse.json()
52
+ * const user = data[0]
53
+ *
54
+ * // User info available: id, login, display_name, email, profile_image_url
55
+ * }
56
+ * }
57
+ * ```
58
+ *
59
+ * @packageDocumentation
60
+ */
61
+ import { type Oauth2WrappedConfig } from "./oauth2";
62
+ /**
63
+ * Configuration options for Twitch OAuth 2.0 provider.
64
+ * Extends the base OAuth 2.0 configuration with Twitch-specific documentation.
65
+ */
66
+ export interface TwitchConfig extends Oauth2WrappedConfig {
67
+ /**
68
+ * Twitch application client ID.
69
+ * Get this from your Twitch Console at https://dev.twitch.tv/console
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * {
74
+ * clientID: "abcdef123456"
75
+ * }
76
+ * ```
77
+ */
78
+ readonly clientID: string;
79
+ /**
80
+ * Twitch application client secret.
81
+ * Keep this secure and never expose it to client-side code.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * {
86
+ * clientSecret: process.env.TWITCH_CLIENT_SECRET
87
+ * }
88
+ * ```
89
+ */
90
+ readonly clientSecret: string;
91
+ /**
92
+ * Twitch OAuth scopes to request access for.
93
+ * Determines what data and actions your app can access.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * {
98
+ * scopes: [
99
+ * "user:read:email", // Access user email
100
+ * "user:read:subscriptions" // View subscriptions
101
+ * ]
102
+ * }
103
+ * ```
104
+ */
105
+ readonly scopes: string[];
106
+ }
107
+ /**
108
+ * Creates a Twitch OAuth 2.0 authentication provider.
109
+ * Allows users to authenticate using their Twitch accounts.
110
+ *
111
+ * @param config - Twitch OAuth 2.0 configuration
112
+ * @returns OAuth 2.0 provider configured for Twitch
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * // Basic Twitch authentication
117
+ * const basicTwitch = TwitchProvider({
118
+ * clientID: process.env.TWITCH_CLIENT_ID,
119
+ * clientSecret: process.env.TWITCH_CLIENT_SECRET
120
+ * })
121
+ *
122
+ * // Twitch with email scope
123
+ * const twitchWithEmail = TwitchProvider({
124
+ * clientID: process.env.TWITCH_CLIENT_ID,
125
+ * clientSecret: process.env.TWITCH_CLIENT_SECRET,
126
+ * scopes: ["user:read:email"]
127
+ * })
128
+ *
129
+ * // Using the access token to fetch user data
130
+ * export default issuer({
131
+ * providers: { twitch: twitchWithEmail },
132
+ * success: async (ctx, value) => {
133
+ * if (value.provider === "twitch") {
134
+ * const token = value.tokenset.access
135
+ *
136
+ * const userRes = await fetch('https://api.twitch.tv/helix/users', {
137
+ * headers: {
138
+ * 'Authorization': `Bearer ${token}`,
139
+ * 'Client-ID': process.env.TWITCH_CLIENT_ID
140
+ * }
141
+ * })
142
+ * const { data } = await userRes.json()
143
+ * const user = data[0]
144
+ *
145
+ * return ctx.subject("user", {
146
+ * twitchId: user.id,
147
+ * login: user.login,
148
+ * email: user.email,
149
+ * displayName: user.display_name
150
+ * })
151
+ * }
152
+ * }
153
+ * })
154
+ * ```
155
+ *
156
+ * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
157
+ * - Development: `http://localhost:3000/auth/twitch/callback`
158
+ * - Production: `https://yourapp.com/auth/twitch/callback`
159
+ *
160
+ * Register this URL in your Twitch Developer Console.
161
+ */
162
+ export declare const TwitchProvider: (config: TwitchConfig) => import("./provider").Provider<import("./oauth2").Oauth2UserData>;
163
+ //# sourceMappingURL=twitch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twitch.d.ts","sourceRoot":"","sources":["../../../src/provider/twitch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACxD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,YAAY,qEASlD,CAAA"}
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Vercel OAuth 2.0 + OpenID Connect authentication provider for Draft Auth.
3
+ * Implements "Sign in with Vercel" for user authentication.
4
+ *
5
+ * ## Quick Setup
6
+ *
7
+ * ```ts
8
+ * import { VercelProvider } from "@draftlab/auth/provider/vercel"
9
+ *
10
+ * export default issuer({
11
+ * basePath: "/auth", // Important for callback URL
12
+ * providers: {
13
+ * vercel: VercelProvider({
14
+ * clientID: process.env.VERCEL_CLIENT_ID,
15
+ * clientSecret: process.env.VERCEL_CLIENT_SECRET,
16
+ * scopes: ["openid", "email", "profile"]
17
+ * })
18
+ * }
19
+ * })
20
+ * ```
21
+ *
22
+ * **Callback URL Pattern**: `{baseURL}{basePath}/{provider}/callback`
23
+ * - Example: `http://localhost:3000/auth/vercel/callback`
24
+ * - Production: `https://yourapp.com/auth/vercel/callback`
25
+ *
26
+ * ## Creating a Vercel App
27
+ *
28
+ * Before using this provider, create a Vercel App in your dashboard:
29
+ *
30
+ * 1. Go to **Team Settings** → **Apps** → **Create**
31
+ * 2. Fill in app name, description, and logo
32
+ * 3. Add **Authorization Callback URLs**:
33
+ * - Development: `http://localhost:3000/auth/vercel/callback`
34
+ * - Production: `https://yourapp.com/auth/vercel/callback`
35
+ * - Pattern: `{baseURL}{basePath}/{provider}/callback`
36
+ * 4. Configure **Scopes** in the app's Permissions page:
37
+ * - ✅ openid (Required)
38
+ * - ✅ email
39
+ * - ✅ profile
40
+ * - ✅ offline_access (optional, for refresh tokens)
41
+ * 5. Generate a **Client Secret** in the Authentication tab
42
+ * 6. Copy the **Client ID** and **Client Secret**
43
+ *
44
+ * **Important**: You must enable the scopes in the Vercel App dashboard before requesting them!
45
+ *
46
+ * ## Available Scopes
47
+ *
48
+ * - `openid` - **Required**. Enables ID Token issuance for user identification
49
+ * - `email` - Access user's email address in ID Token
50
+ * - `profile` - Access user's name, username, and avatar in ID Token
51
+ * - `offline_access` - Issue a Refresh Token for long-lived access (30 days)
52
+ *
53
+ * ## Tokens Returned
54
+ *
55
+ * - **ID Token**: Signed JWT with user identity claims (verified automatically)
56
+ * - **Access Token**: Bearer token for Vercel API calls (1 hour duration)
57
+ * - **Refresh Token**: Rotates on each use (30 days, requires offline_access scope)
58
+ *
59
+ * ## User Data Access
60
+ *
61
+ * ```ts
62
+ * success: async (ctx, value) => {
63
+ * if (value.provider === "vercel") {
64
+ * // ID Token is automatically validated (signature, issuer, audience, expiration)
65
+ * const idToken = value.tokenset.raw.id_token as string | undefined
66
+ * const accessToken = value.tokenset.access
67
+ * const refreshToken = value.tokenset.refresh
68
+ *
69
+ * // Decode ID Token to access user claims
70
+ * if (idToken) {
71
+ * const claims = JSON.parse(
72
+ * Buffer.from(idToken.split('.')[1], 'base64').toString()
73
+ * )
74
+ *
75
+ * // Claims available (depending on scopes):
76
+ * // - sub: Unique Vercel user ID (always present)
77
+ * // - email: User's email (if email scope granted)
78
+ * // - name: User's full name (if profile scope granted)
79
+ * // - picture: Avatar URL (if profile scope granted)
80
+ * // - preferred_username: Vercel username (if profile scope granted)
81
+ *
82
+ * return ctx.subject("user", {
83
+ * email: claims.email || claims.sub
84
+ * })
85
+ * }
86
+ * }
87
+ * }
88
+ * ```
89
+ *
90
+ * ## Calling Vercel API
91
+ *
92
+ * Use the access token to call Vercel's REST API:
93
+ *
94
+ * ```ts
95
+ * // Get user information
96
+ * const userRes = await fetch('https://api.vercel.com/v2/user', {
97
+ * headers: { Authorization: `Bearer ${accessToken}` }
98
+ * })
99
+ *
100
+ * // Get user's teams
101
+ * const teamsRes = await fetch('https://api.vercel.com/v2/teams', {
102
+ * headers: { Authorization: `Bearer ${accessToken}` }
103
+ * })
104
+ *
105
+ * // Get projects (requires appropriate permissions)
106
+ * const projectsRes = await fetch('https://api.vercel.com/v9/projects', {
107
+ * headers: { Authorization: `Bearer ${accessToken}` }
108
+ * })
109
+ * ```
110
+ *
111
+ * ## Consent Page
112
+ *
113
+ * The first time a user signs in, Vercel shows a consent page with:
114
+ * - Your app's name and logo
115
+ * - Requested scopes and permissions
116
+ * - Allow/Cancel buttons
117
+ *
118
+ * If the user grants access, they're redirected back with an authorization code.
119
+ * If they cancel, they're redirected with an error parameter.
120
+ *
121
+ * @packageDocumentation
122
+ */
123
+ import { type Oauth2WrappedConfig } from "./oauth2";
124
+ /**
125
+ * Configuration options for Vercel OAuth 2.0 + OpenID Connect provider.
126
+ * Extends the base OAuth 2.0 configuration with Vercel-specific documentation.
127
+ */
128
+ export interface VercelConfig extends Oauth2WrappedConfig {
129
+ /**
130
+ * Vercel OAuth App client ID.
131
+ * Found in your Vercel App settings under the Authentication tab.
132
+ *
133
+ * To create an app:
134
+ * 1. Go to Team Settings → Apps → Create
135
+ * 2. Configure app details and callback URLs
136
+ * 3. Copy the Client ID from the Authentication tab
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * {
141
+ * clientID: "oac_abc123xyz789" // Vercel OAuth App Client ID
142
+ * }
143
+ * ```
144
+ */
145
+ readonly clientID: string;
146
+ /**
147
+ * Vercel OAuth App client secret.
148
+ * Generated in your Vercel App settings under the Authentication tab.
149
+ * Keep this secure and never expose it to client-side code.
150
+ *
151
+ * To generate:
152
+ * 1. Go to your app's Authentication tab
153
+ * 2. Click "Generate Client Secret"
154
+ * 3. Copy and store securely (shown only once)
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * {
159
+ * clientSecret: process.env.VERCEL_CLIENT_SECRET
160
+ * }
161
+ * ```
162
+ */
163
+ readonly clientSecret: string;
164
+ /**
165
+ * OpenID Connect scopes to request.
166
+ * Controls what user information is included in the ID Token.
167
+ *
168
+ * Available scopes (must be enabled in Vercel App dashboard first):
169
+ * - `openid`: Required for ID Token issuance
170
+ * - `email`: User's email address
171
+ * - `profile`: Name, username, and avatar
172
+ * - `offline_access`: Refresh token for long-lived access (optional)
173
+ *
174
+ * **Important**: Enable scopes in: Vercel App → Permissions page
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * {
179
+ * // Basic scopes (usually sufficient)
180
+ * scopes: ["openid", "email", "profile"]
181
+ *
182
+ * // With refresh token support (enable offline_access in dashboard first)
183
+ * scopes: ["openid", "email", "profile", "offline_access"]
184
+ * }
185
+ * ```
186
+ */
187
+ readonly scopes: string[];
188
+ /**
189
+ * Additional query parameters for Vercel OAuth authorization.
190
+ * Useful for customizing the authorization flow.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * {
195
+ * query: {
196
+ * prompt: "consent" // Force consent screen every time
197
+ * }
198
+ * }
199
+ * ```
200
+ */
201
+ readonly query?: Record<string, string>;
202
+ }
203
+ /**
204
+ * Creates a Vercel OAuth 2.0 + OpenID Connect authentication provider.
205
+ * Implements "Sign in with Vercel" for user authentication.
206
+ *
207
+ * This provider uses the standard OAuth 2.0 Authorization Code Grant flow
208
+ * with PKCE (Proof Key for Code Exchange) for enhanced security.
209
+ *
210
+ * @param config - Vercel OAuth 2.0 configuration
211
+ * @returns OAuth 2.0 provider configured for Vercel
212
+ *
213
+ * @example
214
+ * ```ts
215
+ * // Basic Vercel authentication (email + profile)
216
+ * const basicVercel = VercelProvider({
217
+ * clientID: process.env.VERCEL_CLIENT_ID,
218
+ * clientSecret: process.env.VERCEL_CLIENT_SECRET,
219
+ * scopes: ["openid", "email", "profile"]
220
+ * })
221
+ *
222
+ * // Vercel with refresh token support
223
+ * const vercelWithRefresh = VercelProvider({
224
+ * clientID: process.env.VERCEL_CLIENT_ID,
225
+ * clientSecret: process.env.VERCEL_CLIENT_SECRET,
226
+ * scopes: ["openid", "email", "profile", "offline_access"]
227
+ * })
228
+ *
229
+ * // Minimal setup (only user ID in ID Token)
230
+ * const minimalVercel = VercelProvider({
231
+ * clientID: process.env.VERCEL_CLIENT_ID,
232
+ * clientSecret: process.env.VERCEL_CLIENT_SECRET,
233
+ * scopes: ["openid"] // Only sub claim in ID Token
234
+ * })
235
+ *
236
+ * // Using the tokens in your app
237
+ * export default issuer({
238
+ * providers: { vercel: vercelWithRefresh },
239
+ * success: async (ctx, value) => {
240
+ * if (value.provider === "vercel") {
241
+ * const idToken = value.tokenset.raw.id_token as string | undefined
242
+ * const accessToken = value.tokenset.access
243
+ * const refreshToken = value.tokenset.refresh
244
+ *
245
+ * if (idToken) {
246
+ * // Decode ID Token to access user claims
247
+ * // (Already validated by oauth2.ts - signature, issuer, audience, exp)
248
+ * const claims = JSON.parse(
249
+ * Buffer.from(idToken.split('.')[1], 'base64').toString()
250
+ * )
251
+ *
252
+ * // Claims available (depending on scopes):
253
+ * // - sub: Vercel user ID (always present)
254
+ * // - email: user@example.com (if email scope)
255
+ * // - name: "John Doe" (if profile scope)
256
+ * // - picture: "https://..." (if profile scope)
257
+ * // - preferred_username: "johndoe" (if profile scope)
258
+ *
259
+ * // Optionally call Vercel API for more data
260
+ * const userRes = await fetch('https://api.vercel.com/v2/user', {
261
+ * headers: { Authorization: `Bearer ${accessToken}` }
262
+ * })
263
+ * const user = await userRes.json()
264
+ *
265
+ * // Get user's teams
266
+ * const teamsRes = await fetch('https://api.vercel.com/v2/teams', {
267
+ * headers: { Authorization: `Bearer ${accessToken}` }
268
+ * })
269
+ * const teams = await teamsRes.json()
270
+ *
271
+ * return ctx.subject("user", {
272
+ * vercelId: claims.sub,
273
+ * email: claims.email,
274
+ * name: claims.name,
275
+ * username: claims.preferred_username,
276
+ * avatar: claims.picture,
277
+ * teamCount: teams.teams?.length || 0
278
+ * })
279
+ * }
280
+ * }
281
+ * }
282
+ * })
283
+ * ```
284
+ *
285
+ * @remarks
286
+ * - Requires creating a Vercel App in Team Settings → Apps
287
+ * - PKCE is enabled by default for enhanced security
288
+ * - ID Token is automatically validated (signature, issuer, audience, expiration)
289
+ * - Access tokens expire after 1 hour
290
+ * - Refresh tokens rotate on each use and last 30 days
291
+ * - The `openid` scope is required for ID Token issuance
292
+ */
293
+ export declare const VercelProvider: (config: VercelConfig) => import("./provider").Provider<import("./oauth2").Oauth2UserData>;
294
+ //# sourceMappingURL=vercel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../../src/provider/vercel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyHG;AAEH,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACxD;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAE7B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;IAEzB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,YAAY,qEAYlD,CAAA"}
@@ -1,4 +1,3 @@
1
- //#region src/random.d.ts
2
1
  /**
3
2
  * Cryptographic utilities for secure random generation and comparison operations.
4
3
  * These functions are designed to prevent timing attacks and provide unbiased randomness.
@@ -19,7 +18,7 @@
19
18
  * // Returns: "4A7bC9dF2gH5iJ8kL1mN4pQ7rS0tU" (example)
20
19
  * ```
21
20
  */
22
- declare const generateSecureToken: (length?: number) => string;
21
+ export declare const generateSecureToken: (length?: number) => string;
23
22
  /**
24
23
  * Generates a cryptographically secure string of random digits without modulo bias.
25
24
  * Uses rejection sampling to ensure each digit (0-9) has an equal probability of being selected.
@@ -38,7 +37,7 @@ declare const generateSecureToken: (length?: number) => string;
38
37
  *
39
38
  * @throws {RangeError} If length is not a positive number
40
39
  */
41
- declare const generateUnbiasedDigits: (length: number) => string;
40
+ export declare const generateUnbiasedDigits: (length: number) => string;
42
41
  /**
43
42
  * Performs a timing-safe comparison of two strings to prevent timing attacks.
44
43
  * Always takes the same amount of time regardless of where the strings differ,
@@ -61,6 +60,5 @@ declare const generateUnbiasedDigits: (length: number) => string;
61
60
  * timingSafeCompare("abc", "abcd") // false
62
61
  * ```
63
62
  */
64
- declare const timingSafeCompare: (a: string, b: string) => boolean;
65
- //#endregion
66
- export { generateSecureToken, generateUnbiasedDigits, timingSafeCompare };
63
+ export declare const timingSafeCompare: (a: string, b: string) => boolean;
64
+ //# sourceMappingURL=random.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"random.d.ts","sourceRoot":"","sources":["../../src/random.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAQ,MAAW,KAAG,MAWzD,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,KAAG,MAevD,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,iBAAiB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAQxD,CAAA"}