@startsimpli/auth 0.1.0 → 0.1.2

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 (39) hide show
  1. package/dist/chunk-CDNZRZ7Q.mjs +767 -0
  2. package/dist/chunk-CDNZRZ7Q.mjs.map +1 -0
  3. package/dist/chunk-S6J5FYQY.mjs +134 -0
  4. package/dist/chunk-S6J5FYQY.mjs.map +1 -0
  5. package/dist/chunk-TA46ASDJ.mjs +37 -0
  6. package/dist/chunk-TA46ASDJ.mjs.map +1 -0
  7. package/dist/client/index.d.mts +175 -0
  8. package/dist/client/index.d.ts +175 -0
  9. package/dist/client/index.js +858 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/client/index.mjs +5 -0
  12. package/dist/client/index.mjs.map +1 -0
  13. package/dist/index.d.mts +68 -0
  14. package/dist/index.d.ts +68 -0
  15. package/dist/index.js +971 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/index.mjs +5 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/server/index.d.mts +83 -0
  20. package/dist/server/index.d.ts +83 -0
  21. package/dist/server/index.js +242 -0
  22. package/dist/server/index.js.map +1 -0
  23. package/dist/server/index.mjs +191 -0
  24. package/dist/server/index.mjs.map +1 -0
  25. package/dist/types/index.d.mts +209 -0
  26. package/dist/types/index.d.ts +209 -0
  27. package/dist/types/index.js +43 -0
  28. package/dist/types/index.js.map +1 -0
  29. package/dist/types/index.mjs +3 -0
  30. package/dist/types/index.mjs.map +1 -0
  31. package/package.json +50 -18
  32. package/src/__tests__/auth-client.test.ts +125 -0
  33. package/src/__tests__/auth-fetch.test.ts +128 -0
  34. package/src/__tests__/token-storage.test.ts +61 -0
  35. package/src/__tests__/validation.test.ts +60 -0
  36. package/src/client/auth-client.ts +11 -1
  37. package/src/client/functions.ts +83 -14
  38. package/src/types/index.ts +100 -0
  39. package/src/utils/validation.ts +190 -0
@@ -140,3 +140,103 @@ export function hasRolePermission(
140
140
  ): boolean {
141
141
  return ROLE_HIERARCHY[userRole] >= ROLE_HIERARCHY[requiredRole];
142
142
  }
143
+
144
+ /**
145
+ * Password reset request payload
146
+ * Initiates password reset flow by sending reset email
147
+ */
148
+ export interface PasswordResetRequest {
149
+ email: string;
150
+ clientMetadata?: Record<string, any>;
151
+ }
152
+
153
+ /**
154
+ * Password reset confirmation payload
155
+ * Completes password reset with token and new password
156
+ */
157
+ export interface PasswordResetConfirm {
158
+ token: string;
159
+ password: string;
160
+ passwordConfirm: string;
161
+ }
162
+
163
+ /**
164
+ * Email verification request payload
165
+ * Verifies user email with token from verification email
166
+ */
167
+ export interface EmailVerificationRequest {
168
+ token: string;
169
+ }
170
+
171
+ /**
172
+ * Email verification response
173
+ * Returns updated user data after successful verification
174
+ */
175
+ export interface EmailVerificationResponse {
176
+ detail: string;
177
+ user: {
178
+ id: string;
179
+ email: string;
180
+ isEmailVerified: boolean;
181
+ };
182
+ }
183
+
184
+ /**
185
+ * API error response from Django backend
186
+ * Standard error format for all API errors
187
+ */
188
+ export interface ApiErrorResponse {
189
+ detail?: string;
190
+ message?: string;
191
+ errors?: Record<string, string[]>;
192
+ code?: string;
193
+ status?: number;
194
+ }
195
+
196
+ /**
197
+ * Validation error detail
198
+ * Individual field validation error
199
+ */
200
+ export interface ValidationError {
201
+ field: string;
202
+ message: string;
203
+ code?: string;
204
+ }
205
+
206
+ /**
207
+ * Validation errors map
208
+ * Maps field names to error messages
209
+ */
210
+ export type ValidationErrorsMap = Record<string, string[]>;
211
+
212
+ /**
213
+ * Password validation error codes
214
+ */
215
+ export enum PasswordErrorCode {
216
+ TOO_SHORT = 'password_too_short',
217
+ TOO_COMMON = 'password_too_common',
218
+ ENTIRELY_NUMERIC = 'password_entirely_numeric',
219
+ TOO_SIMILAR = 'password_too_similar',
220
+ MISMATCH = 'password_mismatch',
221
+ REQUIRED = 'password_required',
222
+ }
223
+
224
+ /**
225
+ * Email validation error codes
226
+ */
227
+ export enum EmailErrorCode {
228
+ INVALID_FORMAT = 'email_invalid_format',
229
+ REQUIRED = 'email_required',
230
+ NOT_FOUND = 'email_not_found',
231
+ ALREADY_EXISTS = 'email_already_exists',
232
+ }
233
+
234
+ /**
235
+ * General validation error codes
236
+ */
237
+ export enum ValidationErrorCode {
238
+ REQUIRED = 'required',
239
+ INVALID = 'invalid',
240
+ TOO_SHORT = 'too_short',
241
+ TOO_LONG = 'too_long',
242
+ }
@@ -0,0 +1,190 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ PasswordErrorCode,
4
+ EmailErrorCode,
5
+ ValidationErrorsMap,
6
+ } from '../types';
7
+
8
+ /**
9
+ * Email validation schema
10
+ * Matches Django email validation rules
11
+ */
12
+ export const emailSchema = z
13
+ .string({
14
+ message: EmailErrorCode.REQUIRED,
15
+ })
16
+ .email({
17
+ message: EmailErrorCode.INVALID_FORMAT,
18
+ })
19
+ .min(1, { message: EmailErrorCode.REQUIRED })
20
+ .max(254, { message: 'Email must be less than 254 characters' })
21
+ .toLowerCase()
22
+ .trim();
23
+
24
+ /**
25
+ * Password validation schema
26
+ * Matches Django password validation rules:
27
+ * - Minimum 8 characters
28
+ * - Cannot be entirely numeric
29
+ * - Cannot be too common (basic check)
30
+ */
31
+ export const passwordSchema = z
32
+ .string({
33
+ message: PasswordErrorCode.REQUIRED,
34
+ })
35
+ .min(8, { message: PasswordErrorCode.TOO_SHORT })
36
+ .refine((val) => !/^\d+$/.test(val), {
37
+ message: PasswordErrorCode.ENTIRELY_NUMERIC,
38
+ })
39
+ .refine(
40
+ (val) => {
41
+ // Common password check (basic list)
42
+ const commonPasswords = [
43
+ 'password',
44
+ '12345678',
45
+ 'password1',
46
+ 'qwerty123',
47
+ 'abc123456',
48
+ ];
49
+ return !commonPasswords.includes(val.toLowerCase());
50
+ },
51
+ {
52
+ message: PasswordErrorCode.TOO_COMMON,
53
+ }
54
+ );
55
+
56
+ /**
57
+ * Password confirmation schema
58
+ * Validates password and confirmation match
59
+ */
60
+ export const passwordConfirmSchema = z
61
+ .object({
62
+ password: passwordSchema,
63
+ passwordConfirm: z.string(),
64
+ })
65
+ .refine((data) => data.password === data.passwordConfirm, {
66
+ message: PasswordErrorCode.MISMATCH,
67
+ path: ['passwordConfirm'],
68
+ });
69
+
70
+ /**
71
+ * Password reset request schema
72
+ */
73
+ export const passwordResetRequestSchema = z.object({
74
+ email: emailSchema,
75
+ clientMetadata: z.record(z.string(), z.any()).optional(),
76
+ });
77
+
78
+ /**
79
+ * Password reset confirm schema
80
+ */
81
+ export const passwordResetConfirmSchema = z
82
+ .object({
83
+ token: z.string().min(1, { message: 'Token is required' }),
84
+ password: passwordSchema,
85
+ passwordConfirm: z.string(),
86
+ })
87
+ .refine((data) => data.password === data.passwordConfirm, {
88
+ message: PasswordErrorCode.MISMATCH,
89
+ path: ['passwordConfirm'] as const,
90
+ });
91
+
92
+ /**
93
+ * Email verification request schema
94
+ */
95
+ export const emailVerificationRequestSchema = z.object({
96
+ token: z.string().min(1, { message: 'Token is required' }),
97
+ });
98
+
99
+ /**
100
+ * Convert Zod error to validation errors map
101
+ * Matches Django error response format
102
+ */
103
+ export function zodErrorToValidationMap(
104
+ error: z.ZodError<any>
105
+ ): ValidationErrorsMap {
106
+ const errors: ValidationErrorsMap = {};
107
+
108
+ error.issues.forEach((err) => {
109
+ const field = err.path.join('.');
110
+ if (!errors[field]) {
111
+ errors[field] = [];
112
+ }
113
+ errors[field].push(err.message);
114
+ });
115
+
116
+ return errors;
117
+ }
118
+
119
+ /**
120
+ * Validate email and return errors
121
+ */
122
+ export function validateEmail(email: string): string[] {
123
+ const result = emailSchema.safeParse(email);
124
+ if (!result.success) {
125
+ return result.error.issues.map((err) => err.message);
126
+ }
127
+ return [];
128
+ }
129
+
130
+ /**
131
+ * Validate password and return errors
132
+ */
133
+ export function validatePassword(password: string): string[] {
134
+ const result = passwordSchema.safeParse(password);
135
+ if (!result.success) {
136
+ return result.error.issues.map((err) => err.message);
137
+ }
138
+ return [];
139
+ }
140
+
141
+ /**
142
+ * Validate password reset request and return errors
143
+ */
144
+ export function validatePasswordResetRequest(data: unknown): {
145
+ success: boolean;
146
+ errors?: ValidationErrorsMap;
147
+ } {
148
+ const result = passwordResetRequestSchema.safeParse(data);
149
+ if (!result.success) {
150
+ return {
151
+ success: false,
152
+ errors: zodErrorToValidationMap(result.error),
153
+ };
154
+ }
155
+ return { success: true };
156
+ }
157
+
158
+ /**
159
+ * Validate password reset confirmation and return errors
160
+ */
161
+ export function validatePasswordResetConfirm(data: unknown): {
162
+ success: boolean;
163
+ errors?: ValidationErrorsMap;
164
+ } {
165
+ const result = passwordResetConfirmSchema.safeParse(data);
166
+ if (!result.success) {
167
+ return {
168
+ success: false,
169
+ errors: zodErrorToValidationMap(result.error),
170
+ };
171
+ }
172
+ return { success: true };
173
+ }
174
+
175
+ /**
176
+ * Validate email verification request and return errors
177
+ */
178
+ export function validateEmailVerificationRequest(data: unknown): {
179
+ success: boolean;
180
+ errors?: ValidationErrorsMap;
181
+ } {
182
+ const result = emailVerificationRequestSchema.safeParse(data);
183
+ if (!result.success) {
184
+ return {
185
+ success: false,
186
+ errors: zodErrorToValidationMap(result.error),
187
+ };
188
+ }
189
+ return { success: true };
190
+ }