@draftlab/auth 0.0.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 (86) hide show
  1. package/dist/adapters/node.d.ts +18 -0
  2. package/dist/adapters/node.js +71 -0
  3. package/dist/allow-CixonwTW.d.ts +59 -0
  4. package/dist/allow-DX5cehSc.js +63 -0
  5. package/dist/allow.d.ts +2 -0
  6. package/dist/allow.js +4 -0
  7. package/dist/base-DRutbxgL.js +422 -0
  8. package/dist/client.d.ts +413 -0
  9. package/dist/client.js +209 -0
  10. package/dist/code-l_uvMR1j.d.ts +212 -0
  11. package/dist/core-8WTqfnb4.d.ts +129 -0
  12. package/dist/core-CncE5rPg.js +498 -0
  13. package/dist/core.d.ts +9 -0
  14. package/dist/core.js +14 -0
  15. package/dist/error-CWAdNAzm.d.ts +243 -0
  16. package/dist/error-DgAKK7b2.js +237 -0
  17. package/dist/error.d.ts +2 -0
  18. package/dist/error.js +3 -0
  19. package/dist/form-6XKM_cOk.js +61 -0
  20. package/dist/icon-Ci5uqGB_.js +192 -0
  21. package/dist/index.d.ts +9 -0
  22. package/dist/index.js +14 -0
  23. package/dist/keys-EEfxEGfO.js +140 -0
  24. package/dist/keys.d.ts +67 -0
  25. package/dist/keys.js +5 -0
  26. package/dist/oauth2-B7-6Z7Lc.js +155 -0
  27. package/dist/oauth2-DtKwtl8p.d.ts +176 -0
  28. package/dist/password-Cm0dRMwa.d.ts +385 -0
  29. package/dist/pkce-276Za_rZ.js +162 -0
  30. package/dist/pkce.d.ts +72 -0
  31. package/dist/pkce.js +3 -0
  32. package/dist/provider/code.d.ts +4 -0
  33. package/dist/provider/code.js +145 -0
  34. package/dist/provider/facebook.d.ts +137 -0
  35. package/dist/provider/facebook.js +85 -0
  36. package/dist/provider/github.d.ts +141 -0
  37. package/dist/provider/github.js +88 -0
  38. package/dist/provider/google.d.ts +113 -0
  39. package/dist/provider/google.js +62 -0
  40. package/dist/provider/oauth2.d.ts +4 -0
  41. package/dist/provider/oauth2.js +7 -0
  42. package/dist/provider/password.d.ts +4 -0
  43. package/dist/provider/password.js +366 -0
  44. package/dist/provider/provider.d.ts +3 -0
  45. package/dist/provider/provider.js +44 -0
  46. package/dist/provider-CwWMG-1l.d.ts +227 -0
  47. package/dist/random-SXMYlaVr.js +87 -0
  48. package/dist/random.d.ts +66 -0
  49. package/dist/random.js +3 -0
  50. package/dist/select-BjySLL8I.js +280 -0
  51. package/dist/storage/memory.d.ts +82 -0
  52. package/dist/storage/memory.js +127 -0
  53. package/dist/storage/storage.d.ts +2 -0
  54. package/dist/storage/storage.js +3 -0
  55. package/dist/storage/turso.d.ts +31 -0
  56. package/dist/storage/turso.js +117 -0
  57. package/dist/storage/unstorage.d.ts +38 -0
  58. package/dist/storage/unstorage.js +97 -0
  59. package/dist/storage-BEaqEPNQ.js +62 -0
  60. package/dist/storage-CxKerLlc.d.ts +162 -0
  61. package/dist/subject-DiQdRWGt.d.ts +62 -0
  62. package/dist/subject.d.ts +3 -0
  63. package/dist/subject.js +36 -0
  64. package/dist/theme-C9by7VXf.d.ts +209 -0
  65. package/dist/theme-CswaLtbW.js +120 -0
  66. package/dist/themes/theme.d.ts +2 -0
  67. package/dist/themes/theme.js +3 -0
  68. package/dist/types.d.ts +94 -0
  69. package/dist/types.js +0 -0
  70. package/dist/ui/base.d.ts +43 -0
  71. package/dist/ui/base.js +4 -0
  72. package/dist/ui/code.d.ts +158 -0
  73. package/dist/ui/code.js +197 -0
  74. package/dist/ui/form.d.ts +31 -0
  75. package/dist/ui/form.js +3 -0
  76. package/dist/ui/icon.d.ts +98 -0
  77. package/dist/ui/icon.js +3 -0
  78. package/dist/ui/password.d.ts +54 -0
  79. package/dist/ui/password.js +300 -0
  80. package/dist/ui/select.d.ts +233 -0
  81. package/dist/ui/select.js +6 -0
  82. package/dist/util-CSdHUFOo.js +108 -0
  83. package/dist/util-ChlgVqPN.d.ts +72 -0
  84. package/dist/util.d.ts +2 -0
  85. package/dist/util.js +3 -0
  86. package/package.json +63 -0
@@ -0,0 +1,212 @@
1
+ import { Provider } from "./provider-CwWMG-1l.js";
2
+
3
+ //#region src/provider/code.d.ts
4
+
5
+ /**
6
+ * Configuration options for the PIN code authentication provider.
7
+ *
8
+ * @template Claims - Type of claims collected during authentication (email, phone, etc.)
9
+ */
10
+ interface CodeProviderConfig<Claims extends Record<string, string> = Record<string, string>> {
11
+ /**
12
+ * The length of the generated PIN code.
13
+ * Common values are 4, 6, or 8 digits.
14
+ *
15
+ * @default 6
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * {
20
+ * length: 4 // 4-digit PIN for easier entry
21
+ * }
22
+ * ```
23
+ */
24
+ readonly length?: number;
25
+ /**
26
+ * Request handler for rendering the authentication UI.
27
+ * Handles both the initial claim collection and PIN code entry screens.
28
+ *
29
+ * @param req - The HTTP request object
30
+ * @param state - Current authentication state (start or code verification)
31
+ * @param form - Form data from POST requests (if any)
32
+ * @param error - Authentication error to display (if any)
33
+ * @returns Promise resolving to the authentication page response
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * request: async (req, state, form, error) => {
38
+ * if (state.type === 'start') {
39
+ * return new Response(renderClaimForm(form, error))
40
+ * } else {
41
+ * return new Response(renderCodeForm(state.claims.email, error))
42
+ * }
43
+ * }
44
+ * ```
45
+ */
46
+ request: (req: Request, state: CodeProviderState, form?: FormData, error?: CodeProviderError) => Promise<Response>;
47
+ /**
48
+ * Callback for sending PIN codes to users via their preferred method.
49
+ * Should handle delivery via email, SMS, or other communication channels.
50
+ *
51
+ * @param claims - User claims containing contact information
52
+ * @param code - The generated PIN code to send
53
+ * @returns Promise resolving to undefined on success, or error object on failure
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * sendCode: async (claims, code) => {
58
+ * try {
59
+ * if (claims.email) {
60
+ * await emailService.send({
61
+ * to: claims.email,
62
+ * subject: 'Your verification code',
63
+ * text: `Your PIN code is: ${code}`
64
+ * })
65
+ * } else if (claims.phone) {
66
+ * await smsService.send(claims.phone, `PIN: ${code}`)
67
+ * } else {
68
+ * return {
69
+ * type: "invalid_claim",
70
+ * key: "contact",
71
+ * value: "No email or phone provided"
72
+ * }
73
+ * }
74
+ * } catch (error) {
75
+ * return {
76
+ * type: "invalid_claim",
77
+ * key: "delivery",
78
+ * value: "Failed to send code"
79
+ * }
80
+ * }
81
+ * }
82
+ * ```
83
+ */
84
+ sendCode: (claims: Claims, code: string) => Promise<CodeProviderError | undefined>;
85
+ }
86
+ /**
87
+ * Authentication flow states for the PIN code provider.
88
+ * The provider transitions between these states during authentication.
89
+ */
90
+ type CodeProviderState = {
91
+ /** Initial state: user enters their claims (email, phone, etc.) */
92
+ readonly type: "start";
93
+ } | {
94
+ /** Code verification state: user enters the PIN code */
95
+ readonly type: "code";
96
+ /** Whether this is a code resend request */
97
+ readonly resend?: boolean;
98
+ /** The generated PIN code for verification */
99
+ readonly code: string;
100
+ /** User claims collected during the start phase */
101
+ readonly claims: Record<string, string>;
102
+ };
103
+ /**
104
+ * Possible errors during PIN code authentication.
105
+ */
106
+ type CodeProviderError = {
107
+ /** The entered PIN code is incorrect */
108
+ readonly type: "invalid_code";
109
+ } | {
110
+ /** A user claim is invalid or missing */
111
+ readonly type: "invalid_claim";
112
+ /** The claim field that failed validation */
113
+ readonly key: string;
114
+ /** The invalid value or error description */
115
+ readonly value: string;
116
+ };
117
+ /**
118
+ * User data returned by successful PIN code authentication.
119
+ *
120
+ * @template Claims - Type of claims collected during authentication
121
+ */
122
+ interface CodeUserData<Claims extends Record<string, string> = Record<string, string>> {
123
+ /** The verified claims collected during authentication */
124
+ readonly claims: Claims;
125
+ }
126
+ /**
127
+ * Creates a PIN code authentication provider.
128
+ * Implements a flexible claim-based authentication flow with PIN verification.
129
+ *
130
+ * @template Claims - Type of claims to collect (email, phone, username, etc.)
131
+ * @param config - PIN code provider configuration
132
+ * @returns Provider instance implementing PIN code authentication
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * // Email-based PIN authentication
137
+ * const emailCodeProvider = CodeProvider<{ email: string }>({
138
+ * length: 6,
139
+ * request: async (req, state, form, error) => {
140
+ * if (state.type === 'start') {
141
+ * return new Response(renderEmailForm(form?.get('email'), error))
142
+ * } else {
143
+ * return new Response(renderPinForm(state.claims.email, error, state.resend))
144
+ * }
145
+ * },
146
+ * sendCode: async (claims, code) => {
147
+ * if (!claims.email || !isValidEmail(claims.email)) {
148
+ * return {
149
+ * type: "invalid_claim",
150
+ * key: "email",
151
+ * value: "Invalid email address"
152
+ * }
153
+ * }
154
+ *
155
+ * await emailService.send(claims.email, `Your verification code: ${code}`)
156
+ * }
157
+ * })
158
+ *
159
+ * // Multi-channel PIN authentication (email or phone)
160
+ * const flexibleCodeProvider = CodeProvider<{ email?: string; phone?: string }>({
161
+ * length: 4,
162
+ * request: async (req, state, form, error) => {
163
+ * if (state.type === 'start') {
164
+ * return new Response(renderContactForm(form, error))
165
+ * } else {
166
+ * const contact = state.claims.email || state.claims.phone
167
+ * return new Response(renderPinForm(contact, error))
168
+ * }
169
+ * },
170
+ * sendCode: async (claims, code) => {
171
+ * if (claims.email) {
172
+ * await emailService.send(claims.email, `PIN: ${code}`)
173
+ * } else if (claims.phone) {
174
+ * await smsService.send(claims.phone, `PIN: ${code}`)
175
+ * } else {
176
+ * return {
177
+ * type: "invalid_claim",
178
+ * key: "contact",
179
+ * value: "Provide either email or phone number"
180
+ * }
181
+ * }
182
+ * }
183
+ * })
184
+ *
185
+ * // Usage in issuer
186
+ * export default issuer({
187
+ * providers: {
188
+ * email: emailCodeProvider,
189
+ * flexible: flexibleCodeProvider
190
+ * },
191
+ * success: async (ctx, value) => {
192
+ * if (value.provider === "code") {
193
+ * const email = value.claims.email
194
+ * const phone = value.claims.phone
195
+ *
196
+ * // Look up or create user based on verified claims
197
+ * const userId = await findOrCreateUser({ email, phone })
198
+ *
199
+ * return ctx.subject("user", { userId, email, phone })
200
+ * }
201
+ * }
202
+ * })
203
+ * ```
204
+ */
205
+ declare const CodeProvider: <Claims extends Record<string, string> = Record<string, string>>(config: CodeProviderConfig<Claims>) => Provider<CodeUserData<Claims>>;
206
+ /**
207
+ * Type helper for CodeProvider configuration options.
208
+ * @internal
209
+ */
210
+ type CodeProviderOptions = Parameters<typeof CodeProvider>[0];
211
+ //#endregion
212
+ export { CodeProvider, CodeProviderConfig, CodeProviderError, CodeProviderOptions, CodeProviderState, CodeUserData };
@@ -0,0 +1,129 @@
1
+ import { AllowCheckInput } from "./allow-CixonwTW.js";
2
+ import { UnknownStateError } from "./error-CWAdNAzm.js";
3
+ import { Prettify } from "./util-ChlgVqPN.js";
4
+ import { SubjectPayload, SubjectSchema } from "./subject-DiQdRWGt.js";
5
+ import { StorageAdapter } from "./storage-CxKerLlc.js";
6
+ import { Provider } from "./provider-CwWMG-1l.js";
7
+ import { Theme } from "./theme-C9by7VXf.js";
8
+ import { Router } from "@draftlab/router";
9
+
10
+ //#region src/core.d.ts
11
+
12
+ /**
13
+ * Sets the subject payload in the JWT token and returns the response.
14
+ */
15
+ interface OnSuccessResponder<T extends {
16
+ type: string;
17
+ properties: unknown;
18
+ }> {
19
+ subject<Type extends T["type"]>(type: Type, properties: Extract<T, {
20
+ type: Type;
21
+ }>["properties"], opts?: {
22
+ ttl?: {
23
+ access?: number;
24
+ refresh?: number;
25
+ };
26
+ subject?: string;
27
+ }): Promise<Response>;
28
+ }
29
+ /**
30
+ * Authorization state for OAuth 2.0 flows.
31
+ */
32
+ interface AuthorizationState {
33
+ /** OAuth redirect URI */
34
+ redirect_uri: string;
35
+ /** OAuth response type */
36
+ response_type: string;
37
+ /** OAuth state parameter for CSRF protection */
38
+ state: string;
39
+ /** OAuth client identifier */
40
+ client_id: string;
41
+ /** OAuth audience parameter */
42
+ audience: string;
43
+ /** PKCE challenge data for code verification */
44
+ pkce?: {
45
+ challenge: string;
46
+ method: "S256";
47
+ };
48
+ }
49
+ /**
50
+ * Main issuer input configuration interface.
51
+ */
52
+ interface IssuerInput<Providers extends Record<string, Provider<unknown>>, Subjects extends SubjectSchema, Result = { [Key in keyof Providers]: Prettify<{
53
+ provider: Key;
54
+ } & (Providers[Key] extends Provider<infer T> ? T : Record<string, unknown>)> }[keyof Providers]> {
55
+ /** The storage adapter for persisting tokens and sessions */
56
+ storage: StorageAdapter;
57
+ /** Auth providers configuration */
58
+ providers: Providers;
59
+ /** Subject schemas for token validation */
60
+ subjects: Subjects;
61
+ /** Base path for embedded scenarios */
62
+ basePath?: string;
63
+ /** Success callback for completed authentication */
64
+ success(response: OnSuccessResponder<SubjectPayload<Subjects>>, input: Result, req: Request, clientID: string): Promise<Response>;
65
+ /** Theme configuration for UI */
66
+ theme?: Theme;
67
+ /** TTL configuration for tokens and sessions */
68
+ ttl?: {
69
+ access?: number;
70
+ refresh?: number;
71
+ reuse?: number;
72
+ retention?: number;
73
+ };
74
+ /** Provider selection UI function */
75
+ select?(providers: Record<string, string>, req: Request): Promise<Response>;
76
+ /** Optional start callback */
77
+ start?(req: Request): Promise<void>;
78
+ /** Error handling callback */
79
+ error?(error: UnknownStateError, req: Request): Promise<Response>;
80
+ /** Client authorization check function */
81
+ allow?(input: AllowCheckInput, req: Request): Promise<boolean>;
82
+ /**
83
+ * Refresh callback for updating user claims.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * refresh: async (payload, req) => {
88
+ * const user = await getUserBySubject(payload.subject)
89
+ * if (!user || !user.active) {
90
+ * return undefined // Revoke the token
91
+ * }
92
+ *
93
+ * return {
94
+ * type: payload.type,
95
+ * properties: {
96
+ * userID: user.id,
97
+ * role: user.role,
98
+ * permissions: user.permissions,
99
+ * lastLogin: new Date().toISOString()
100
+ * }
101
+ * }
102
+ * }
103
+ * ```
104
+ */
105
+ refresh?(payload: {
106
+ type: SubjectPayload<Subjects>["type"];
107
+ properties: SubjectPayload<Subjects>["properties"];
108
+ subject: string;
109
+ clientID: string;
110
+ scopes?: string[];
111
+ }, req: Request): Promise<{
112
+ type: SubjectPayload<Subjects>["type"];
113
+ properties: SubjectPayload<Subjects>["properties"];
114
+ subject?: string;
115
+ scopes?: string[];
116
+ } | undefined>;
117
+ }
118
+ /**
119
+ * Create an Draft Auth server, a Router app that handles OAuth 2.0 flows.
120
+ */
121
+ declare const issuer: <Providers extends Record<string, Provider<unknown>>, Subjects extends SubjectSchema, Result = { [key in keyof Providers]: {
122
+ provider: key;
123
+ } & (Providers[key] extends Provider<infer T> ? T : Record<string, unknown>) }[keyof Providers]>(input: IssuerInput<Providers, Subjects, Result>) => Router<{
124
+ Variables: {
125
+ authorization: AuthorizationState;
126
+ };
127
+ }>;
128
+ //#endregion
129
+ export { AuthorizationState, OnSuccessResponder, issuer };