@unedio/types 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.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Validation schemas for user-related operations
3
+ */
4
+
5
+ import { z } from '@hono/zod-openapi';
6
+
7
+ // Email validation
8
+ export const emailSchema = z
9
+ .string()
10
+ .email('Invalid email format')
11
+ .min(1, 'Email is required')
12
+ .transform((val) => val.toLowerCase().trim());
13
+
14
+ // User type validation
15
+ export const userTypeSchema = z.enum(['recruiter', 'seeker'], {
16
+ message: 'User type must be either "recruiter" or "seeker"',
17
+ });
18
+
19
+ // Update user profile
20
+ export const updateUserSchema = z.object({
21
+ name: z.string().min(1, 'Name cannot be empty').max(255).optional(),
22
+ avatar_url: z.string().url('Invalid URL format').optional().nullable(),
23
+ });
24
+
25
+ // Register validation
26
+ export const registerSchema = z.object({
27
+ email: emailSchema,
28
+ password: z.string().min(8, 'Password must be at least 8 characters'),
29
+ name: z.string().min(1, 'Name is required').max(255),
30
+ type: userTypeSchema,
31
+ });
32
+
33
+ // Login validation
34
+ export const loginSchema = z.object({
35
+ email: emailSchema,
36
+ password: z.string().min(1, 'Password is required'),
37
+ });
38
+
39
+ // Update seeker profile
40
+ export const updateSeekerProfileSchema = z.object({
41
+ full_name: z.string().min(1).max(255).optional(),
42
+ phone: z.string().max(50).optional().nullable(),
43
+ linkedin_url: z.string().url('Invalid LinkedIn URL').optional().nullable(),
44
+ city: z.string().max(100).optional().nullable(),
45
+ country: z.string().max(100).optional().nullable(),
46
+ summary: z.string().max(2000).optional().nullable(),
47
+ skills: z.array(z.string()).optional(),
48
+ experience_years: z.number().min(0).max(100).optional().nullable(),
49
+ });
50
+
51
+ // Search seekers
52
+ export const searchSeekersSchema = z.object({
53
+ skills: z.array(z.string()).optional(),
54
+ city: z.string().optional(),
55
+ country: z.string().optional(),
56
+ min_experience: z.coerce.number().min(0).optional(),
57
+ max_experience: z.coerce.number().min(0).optional(),
58
+ page: z.coerce.number().min(1).optional().default(1),
59
+ limit: z.coerce.number().min(1).max(100).optional().default(20),
60
+ });
61
+
62
+ // OTP Register validation
63
+ export const otpRegisterSchema = z.object({
64
+ email: emailSchema,
65
+ });
66
+
67
+ // OTP Login validation
68
+ export const otpLoginSchema = z.object({
69
+ email: emailSchema,
70
+ });
71
+
72
+ // OTP Verify validation
73
+ export const otpVerifySchema = z.object({
74
+ email: emailSchema,
75
+ code: z.string().min(1, 'Code is required'),
76
+ state: z.enum(['register', 'login']),
77
+ });
78
+
79
+ export type UpdateUserInput = z.infer<typeof updateUserSchema>;
80
+ export type RegisterInput = z.infer<typeof registerSchema>;
81
+ export type LoginInput = z.infer<typeof loginSchema>;
82
+ export type UpdateSeekerProfileInput = z.infer<typeof updateSeekerProfileSchema>;
83
+ export type SearchSeekersInput = z.infer<typeof searchSeekersSchema>;
84
+ export type OtpRegisterInput = z.infer<typeof otpRegisterSchema>;
85
+ export type OtpLoginInput = z.infer<typeof otpLoginSchema>;
86
+ export type OtpVerifyInput = z.infer<typeof otpVerifySchema>;
@@ -0,0 +1,8 @@
1
+ import { z } from '@hono/zod-openapi';
2
+
3
+ /**
4
+ * Waitlist validators
5
+ */
6
+ export const joinWaitlistSchema = z.object({
7
+ email: z.string().email('Invalid email format').min(1, 'Email is required'),
8
+ });
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Validation schemas for workspace-related operations
3
+ */
4
+
5
+ import { z } from '@hono/zod-openapi';
6
+
7
+ // Subdomain validation (alphanumeric and hyphens only)
8
+ const subdomainSchema = z
9
+ .string()
10
+ .min(3, 'Subdomain must be at least 3 characters')
11
+ .max(63, 'Subdomain must not exceed 63 characters')
12
+ .regex(
13
+ /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/,
14
+ 'Subdomain must contain only lowercase letters, numbers, and hyphens',
15
+ )
16
+ .transform((val) => val.toLowerCase());
17
+
18
+ // Domain validation
19
+ const domainSchema = z
20
+ .string()
21
+ .min(3, 'Domain must be at least 3 characters')
22
+ .max(255, 'Domain must not exceed 255 characters')
23
+ .regex(/^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?(\.[a-zA-Z]{2,})+$/, 'Invalid domain format')
24
+ .transform((val) => val.toLowerCase());
25
+
26
+ // Create workspace
27
+ export const createWorkspaceSchema = z.object({
28
+ name: z.string().min(1, 'Workspace name is required').max(255),
29
+ domain: domainSchema.nullable(),
30
+ subdomain: subdomainSchema.nullable(),
31
+ workspace_mode: z.enum(['company', 'agency']).default('company').optional(),
32
+ language: z.string().min(2).max(10).default('en'),
33
+ });
34
+
35
+ // Update workspace
36
+ export const updateWorkspaceSchema = z.object({
37
+ name: z.string().min(1, 'Workspace name cannot be empty').max(255).optional(),
38
+ domain: domainSchema.optional().nullable(),
39
+ subdomain: subdomainSchema.optional().nullable(),
40
+ workspace_mode: z.enum(['company', 'agency']).optional(),
41
+ language: z.string().min(2).max(10).optional(),
42
+ });
43
+
44
+ // Invite user to workspace
45
+ export const inviteUserSchema = z.object({
46
+ email: z
47
+ .string()
48
+ .email('Invalid email format')
49
+ .transform((val) => val.toLowerCase().trim()),
50
+ role: z
51
+ .enum(['owner', 'member'], {
52
+ message: 'Role must be either "owner" or "member"',
53
+ })
54
+ .default('member'),
55
+ });
56
+
57
+ // Update member role
58
+ export const updateMemberRoleSchema = z.object({
59
+ role: z.enum(['owner', 'member'], {
60
+ message: 'Role must be either "owner" or "member"',
61
+ }),
62
+ });
63
+
64
+ // Update workspace branding
65
+ export const updateBrandingSchema = z.object({
66
+ primary_color: z
67
+ .string()
68
+ .regex(/^#[0-9A-Fa-f]{6}$/, 'Primary color must be a valid hex color (e.g., #6366f1)')
69
+ .optional(),
70
+ secondary_color: z
71
+ .string()
72
+ .regex(/^#[0-9A-Fa-f]{6}$/, 'Secondary color must be a valid hex color (e.g., #1e293b)')
73
+ .optional(),
74
+ font_family: z.string().min(1, 'Font family cannot be empty').max(100).optional(),
75
+ logo_url: z.string().url('Invalid logo URL').optional().nullable(),
76
+ favicon_url: z.string().url('Invalid favicon URL').optional().nullable(),
77
+ });
78
+
79
+ // Upload branding asset
80
+ export const uploadBrandingAssetSchema = z.object({
81
+ file: z
82
+ .instanceof(File, { message: 'File is required' })
83
+ .refine((file) => file.type.startsWith('image/'), { message: 'Only image files are allowed' })
84
+ .refine((file) => file.size <= 2 * 1024 * 1024, { message: 'File size must be less than 2MB' }),
85
+ type: z.enum(['logo', 'favicon'], { message: 'Type must be logo or favicon' }),
86
+ });
87
+
88
+ export type CreateWorkspaceInput = z.infer<typeof createWorkspaceSchema>;
89
+ export type UpdateWorkspaceInput = z.infer<typeof updateWorkspaceSchema>;
90
+ export type InviteUserInput = z.infer<typeof inviteUserSchema>;
91
+ export type UpdateMemberRoleInput = z.infer<typeof updateMemberRoleSchema>;
92
+ export type UpdateBrandingInput = z.infer<typeof updateBrandingSchema>;
93
+ export type UploadBrandingAssetInput = z.infer<typeof uploadBrandingAssetSchema>;
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@api/*": ["src/*"]
11
+ }
12
+ },
13
+ "include": ["src/**/*"]
14
+ }