@aaspai/react 0.0.0 → 0.0.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 (55) hide show
  1. package/README.md +720 -8
  2. package/dist/atoms.cjs +3565 -0
  3. package/dist/atoms.cjs.map +1 -0
  4. package/dist/atoms.d.cts +255 -0
  5. package/dist/atoms.d.ts +255 -0
  6. package/dist/atoms.js +3530 -0
  7. package/dist/atoms.js.map +1 -0
  8. package/dist/components.cjs +5397 -0
  9. package/dist/components.cjs.map +1 -0
  10. package/dist/components.d.cts +362 -0
  11. package/dist/components.d.ts +362 -0
  12. package/dist/components.js +5344 -0
  13. package/dist/components.js.map +1 -0
  14. package/dist/forms.cjs +3928 -0
  15. package/dist/forms.cjs.map +1 -0
  16. package/dist/forms.d.cts +135 -0
  17. package/dist/forms.d.ts +135 -0
  18. package/dist/forms.js +3903 -0
  19. package/dist/forms.js.map +1 -0
  20. package/dist/hooks.cjs +74 -0
  21. package/dist/hooks.cjs.map +1 -0
  22. package/dist/hooks.d.cts +138 -0
  23. package/dist/hooks.d.ts +138 -0
  24. package/dist/hooks.js +70 -0
  25. package/dist/hooks.js.map +1 -0
  26. package/dist/index.cjs +6030 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.cts +248 -0
  29. package/dist/index.d.ts +248 -0
  30. package/dist/index.js +5952 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/lib.cjs +139 -0
  33. package/dist/lib.cjs.map +1 -0
  34. package/dist/lib.d.cts +111 -0
  35. package/dist/lib.d.ts +111 -0
  36. package/dist/lib.js +128 -0
  37. package/dist/lib.js.map +1 -0
  38. package/dist/navigation.cjs +56 -0
  39. package/dist/navigation.cjs.map +1 -0
  40. package/dist/navigation.d.cts +65 -0
  41. package/dist/navigation.d.ts +65 -0
  42. package/dist/navigation.js +51 -0
  43. package/dist/navigation.js.map +1 -0
  44. package/dist/styles.css +839 -0
  45. package/dist/types.cjs +4 -0
  46. package/dist/types.cjs.map +1 -0
  47. package/dist/types.d.cts +17 -0
  48. package/dist/types.d.ts +17 -0
  49. package/dist/types.js +3 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +67 -28
  52. package/index.cjs +0 -10
  53. package/index.d.ts +0 -6
  54. package/index.js +0 -5
  55. package/styles.css +0 -1
package/dist/lib.cjs ADDED
@@ -0,0 +1,139 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+
5
+ // src/lib/validation.ts
6
+ var emailSchema = zod.z.string().min(1, "Email is required").email("Invalid email address");
7
+ function createPasswordSchema(options) {
8
+ const {
9
+ minLength = 6,
10
+ requireUppercase = false,
11
+ requireLowercase = false,
12
+ requireNumber = false,
13
+ requireSpecialChar = false
14
+ } = options || {};
15
+ let schema = zod.z.string().min(minLength, `Password must be at least ${minLength} characters`);
16
+ if (requireUppercase) {
17
+ schema = schema.regex(/[A-Z]/, "Password must contain at least one uppercase letter");
18
+ }
19
+ if (requireLowercase) {
20
+ schema = schema.regex(/[a-z]/, "Password must contain at least one lowercase letter");
21
+ }
22
+ if (requireNumber) {
23
+ schema = schema.regex(/\d/, "Password must contain at least one number");
24
+ }
25
+ if (requireSpecialChar) {
26
+ schema = schema.regex(
27
+ /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/,
28
+ "Password must contain at least one special character"
29
+ );
30
+ }
31
+ return schema;
32
+ }
33
+ var passwordSchema = createPasswordSchema();
34
+ function validateEmail(email) {
35
+ const result = emailSchema.safeParse(email);
36
+ if (result.success) {
37
+ return { valid: true };
38
+ }
39
+ return { valid: false, error: result.error.message };
40
+ }
41
+ function validatePassword(password, options) {
42
+ const schema = createPasswordSchema(options);
43
+ const result = schema.safeParse(password);
44
+ if (result.success) {
45
+ return { valid: true };
46
+ }
47
+ return { valid: false, error: result.error.message };
48
+ }
49
+ function checkPasswordStrength(password) {
50
+ const feedback = [];
51
+ let score = 0;
52
+ if (password.length >= 8) {
53
+ score += 1;
54
+ } else {
55
+ feedback.push("Use at least 8 characters");
56
+ }
57
+ if (password.length >= 12) {
58
+ score += 1;
59
+ }
60
+ if (/[a-z]/.test(password) && /[A-Z]/.test(password)) {
61
+ score += 1;
62
+ } else {
63
+ feedback.push("Use both uppercase and lowercase letters");
64
+ }
65
+ if (/\d/.test(password)) {
66
+ score += 1;
67
+ } else {
68
+ feedback.push("Include at least one number");
69
+ }
70
+ if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
71
+ score += 1;
72
+ } else {
73
+ feedback.push("Include at least one special character");
74
+ }
75
+ return { score, feedback };
76
+ }
77
+
78
+ // src/lib/path-utils.ts
79
+ function resolveAuthPath(targetPath) {
80
+ if (typeof window === "undefined") {
81
+ return targetPath;
82
+ }
83
+ const currentPath = window.location.pathname;
84
+ if (currentPath.startsWith("/auth/")) {
85
+ if (targetPath.startsWith("/auth/")) {
86
+ return targetPath;
87
+ }
88
+ return `/auth${targetPath}`;
89
+ }
90
+ return targetPath;
91
+ }
92
+ function resolveAuthUrl(targetPath, searchParams) {
93
+ const resolvedPath = resolveAuthPath(targetPath);
94
+ if (!searchParams || searchParams.toString() === "") {
95
+ return resolvedPath;
96
+ }
97
+ return `${resolvedPath}?${searchParams.toString()}`;
98
+ }
99
+
100
+ // src/lib/hosted-auth.ts
101
+ function isHostedAuthEnvironment() {
102
+ if (typeof window === "undefined") {
103
+ return false;
104
+ }
105
+ const { hostname, port, protocol } = window.location;
106
+ if (hostname === "localhost" && port === "7130") {
107
+ return true;
108
+ }
109
+ if (protocol === "https:" && hostname.endsWith(".aaspai.app")) {
110
+ return true;
111
+ }
112
+ return false;
113
+ }
114
+ function buildLegacyAuthUrl(redirectUrl, session) {
115
+ const url = new URL(redirectUrl);
116
+ url.searchParams.set("access_token", session.accessToken);
117
+ url.searchParams.set("user_id", session.userId);
118
+ url.searchParams.set("email", session.email);
119
+ if (session.name) {
120
+ url.searchParams.set("name", session.name);
121
+ }
122
+ if (session.csrfToken) {
123
+ url.searchParams.set("csrf_token", session.csrfToken);
124
+ }
125
+ return url.toString();
126
+ }
127
+
128
+ exports.buildLegacyAuthUrl = buildLegacyAuthUrl;
129
+ exports.checkPasswordStrength = checkPasswordStrength;
130
+ exports.createPasswordSchema = createPasswordSchema;
131
+ exports.emailSchema = emailSchema;
132
+ exports.isHostedAuthEnvironment = isHostedAuthEnvironment;
133
+ exports.passwordSchema = passwordSchema;
134
+ exports.resolveAuthPath = resolveAuthPath;
135
+ exports.resolveAuthUrl = resolveAuthUrl;
136
+ exports.validateEmail = validateEmail;
137
+ exports.validatePassword = validatePassword;
138
+ //# sourceMappingURL=lib.cjs.map
139
+ //# sourceMappingURL=lib.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/validation.ts","../src/lib/path-utils.ts","../src/lib/hosted-auth.ts"],"names":["z"],"mappings":"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","file":"lib.cjs","sourcesContent":["import { z } from 'zod';\r\n\r\n/**\r\n * Email validation schema\r\n */\r\nexport const emailSchema = z.string().min(1, 'Email is required').email('Invalid email address');\r\n\r\n/**\r\n * Password validation schema with configurable requirements\r\n */\r\nexport function createPasswordSchema(options?: {\r\n minLength?: number;\r\n requireUppercase?: boolean;\r\n requireLowercase?: boolean;\r\n requireNumber?: boolean;\r\n requireSpecialChar?: boolean;\r\n}) {\r\n const {\r\n minLength = 6,\r\n requireUppercase = false,\r\n requireLowercase = false,\r\n requireNumber = false,\r\n requireSpecialChar = false,\r\n } = options || {};\r\n\r\n let schema = z.string().min(minLength, `Password must be at least ${minLength} characters`);\r\n\r\n if (requireUppercase) {\r\n schema = schema.regex(/[A-Z]/, 'Password must contain at least one uppercase letter');\r\n }\r\n\r\n if (requireLowercase) {\r\n schema = schema.regex(/[a-z]/, 'Password must contain at least one lowercase letter');\r\n }\r\n\r\n if (requireNumber) {\r\n schema = schema.regex(/\\d/, 'Password must contain at least one number');\r\n }\r\n\r\n if (requireSpecialChar) {\r\n schema = schema.regex(\r\n /[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/,\r\n 'Password must contain at least one special character'\r\n );\r\n }\r\n\r\n return schema;\r\n}\r\n\r\n/**\r\n * Default password schema (minimum 6 characters)\r\n */\r\nexport const passwordSchema = createPasswordSchema();\r\n\r\n/**\r\n * Validate email format\r\n */\r\nexport function validateEmail(email: string): { valid: boolean; error?: string } {\r\n const result = emailSchema.safeParse(email);\r\n if (result.success) {\r\n return { valid: true };\r\n }\r\n return { valid: false, error: result.error.message };\r\n}\r\n\r\n/**\r\n * Validate password format\r\n */\r\nexport function validatePassword(\r\n password: string,\r\n options?: Parameters<typeof createPasswordSchema>[0]\r\n): { valid: boolean; error?: string } {\r\n const schema = createPasswordSchema(options);\r\n const result = schema.safeParse(password);\r\n if (result.success) {\r\n return { valid: true };\r\n }\r\n return { valid: false, error: result.error.message };\r\n}\r\n\r\n/**\r\n * Validate password strength based on multiple criteria\r\n */\r\nexport function checkPasswordStrength(password: string): {\r\n score: number;\r\n feedback: string[];\r\n} {\r\n const feedback: string[] = [];\r\n let score = 0;\r\n\r\n if (password.length >= 8) {\r\n score += 1;\r\n } else {\r\n feedback.push('Use at least 8 characters');\r\n }\r\n\r\n if (password.length >= 12) {\r\n score += 1;\r\n }\r\n\r\n if (/[a-z]/.test(password) && /[A-Z]/.test(password)) {\r\n score += 1;\r\n } else {\r\n feedback.push('Use both uppercase and lowercase letters');\r\n }\r\n\r\n if (/\\d/.test(password)) {\r\n score += 1;\r\n } else {\r\n feedback.push('Include at least one number');\r\n }\r\n\r\n if (/[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/.test(password)) {\r\n score += 1;\r\n } else {\r\n feedback.push('Include at least one special character');\r\n }\r\n\r\n return { score, feedback };\r\n}\r\n","/**\r\n * Path utilities for handling navigation in auth flows.\r\n * Ensures proper path resolution when auth pages are served under a base path (e.g., /auth/)\r\n */\r\n\r\n/**\r\n * Resolves an auth route path relative to the current location.\r\n * If the current path is under /auth/, it will preserve that prefix.\r\n * Otherwise, it returns the path as-is.\r\n *\r\n * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')\r\n * @returns The resolved path with proper base path handling\r\n *\r\n * @example\r\n * // Current URL: http://localhost:5174/auth/sign-in\r\n * resolveAuthPath('/sign-up') // Returns '/auth/sign-up'\r\n *\r\n * @example\r\n * // Current URL: http://localhost:5174/sign-in\r\n * resolveAuthPath('/sign-up') // Returns '/sign-up'\r\n */\r\nexport function resolveAuthPath(targetPath: string): string {\r\n if (typeof window === 'undefined') {\r\n return targetPath;\r\n }\r\n\r\n const currentPath = window.location.pathname;\r\n\r\n // Check if we're currently under /auth/ base path\r\n if (currentPath.startsWith('/auth/')) {\r\n // If target already has /auth/ prefix, return as-is\r\n if (targetPath.startsWith('/auth/')) {\r\n return targetPath;\r\n }\r\n // Add /auth/ prefix to the target path\r\n return `/auth${targetPath}`;\r\n }\r\n\r\n // Not under /auth/, return target path as-is\r\n return targetPath;\r\n}\r\n\r\n/**\r\n * Resolves an auth route URL with search params preserved.\r\n * Similar to resolveAuthPath but returns a full URL string with query parameters.\r\n *\r\n * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')\r\n * @param searchParams - Optional URLSearchParams to append\r\n * @returns The resolved URL as a string\r\n *\r\n * @example\r\n * // Current URL: http://localhost:5174/auth/sign-in?redirect=...\r\n * resolveAuthUrl('/sign-up', searchParams) // Returns '/auth/sign-up?redirect=...'\r\n */\r\nexport function resolveAuthUrl(targetPath: string, searchParams?: URLSearchParams): string {\r\n const resolvedPath = resolveAuthPath(targetPath);\r\n\r\n if (!searchParams || searchParams.toString() === '') {\r\n return resolvedPath;\r\n }\r\n\r\n return `${resolvedPath}?${searchParams.toString()}`;\r\n}\r\n","/**\r\n * Hosted Auth Helpers\r\n *\r\n * Utilities for detecting hosted auth environment and building legacy auth URLs\r\n * for cross-domain authentication flows.\r\n */\r\n\r\n/**\r\n * Get CSRF token from cookie\r\n *\r\n * Reads the aaspai_csrf_token cookie set by the backend after authentication.\r\n * This is needed for OAuth flows where the csrfToken is stored in cookies\r\n * rather than returned in the API response.\r\n *\r\n * @returns The CSRF token value or null if not found\r\n */\r\nexport function getCsrfTokenFromCookie(): string | null {\r\n if (typeof document === 'undefined') return null;\r\n const match = document.cookie.match(/(?:^|;\\s*)aaspai_csrf_token=([^;]*)/);\r\n return match ? decodeURIComponent(match[1]) : null;\r\n}\r\n\r\n/**\r\n * Check if current environment is a hosted auth environment\r\n *\r\n * Returns true for:\r\n * - localhost with port 7130 (hosted auth app dev)\r\n * - https://*.aaspai.app (hosted auth app production)\r\n *\r\n * @returns true if running in hosted auth environment\r\n */\r\nexport function isHostedAuthEnvironment(): boolean {\r\n if (typeof window === 'undefined') {\r\n return false;\r\n }\r\n\r\n const { hostname, port, protocol } = window.location;\r\n\r\n // Local development\r\n if (hostname === 'localhost' && port === '7130') {\r\n return true;\r\n }\r\n\r\n // Production hosted auth\r\n if (protocol === 'https:' && hostname.endsWith('.aaspai.app')) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Session data for building legacy auth URL\r\n */\r\nexport interface LegacyAuthSession {\r\n accessToken: string;\r\n userId: string;\r\n email: string;\r\n name?: string;\r\n csrfToken?: string;\r\n}\r\n\r\n/**\r\n * Build a legacy flow redirect URL with auth params in query string\r\n *\r\n * This is used to pass authentication credentials back to the user's app\r\n * after OAuth completes in the hosted auth environment.\r\n *\r\n * @param redirectUrl - The URL to redirect to (user's app)\r\n * @param session - The session data to include in the URL\r\n * @returns The complete URL with auth params\r\n */\r\nexport function buildLegacyAuthUrl(redirectUrl: string, session: LegacyAuthSession): string {\r\n const url = new URL(redirectUrl);\r\n url.searchParams.set('access_token', session.accessToken);\r\n url.searchParams.set('user_id', session.userId);\r\n url.searchParams.set('email', session.email);\r\n\r\n if (session.name) {\r\n url.searchParams.set('name', session.name);\r\n }\r\n\r\n if (session.csrfToken) {\r\n url.searchParams.set('csrf_token', session.csrfToken);\r\n }\r\n\r\n return url.toString();\r\n}\r\n"]}
package/dist/lib.d.cts ADDED
@@ -0,0 +1,111 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Email validation schema
5
+ */
6
+ declare const emailSchema: z.ZodString;
7
+ /**
8
+ * Password validation schema with configurable requirements
9
+ */
10
+ declare function createPasswordSchema(options?: {
11
+ minLength?: number;
12
+ requireUppercase?: boolean;
13
+ requireLowercase?: boolean;
14
+ requireNumber?: boolean;
15
+ requireSpecialChar?: boolean;
16
+ }): z.ZodString;
17
+ /**
18
+ * Default password schema (minimum 6 characters)
19
+ */
20
+ declare const passwordSchema: z.ZodString;
21
+ /**
22
+ * Validate email format
23
+ */
24
+ declare function validateEmail(email: string): {
25
+ valid: boolean;
26
+ error?: string;
27
+ };
28
+ /**
29
+ * Validate password format
30
+ */
31
+ declare function validatePassword(password: string, options?: Parameters<typeof createPasswordSchema>[0]): {
32
+ valid: boolean;
33
+ error?: string;
34
+ };
35
+ /**
36
+ * Validate password strength based on multiple criteria
37
+ */
38
+ declare function checkPasswordStrength(password: string): {
39
+ score: number;
40
+ feedback: string[];
41
+ };
42
+
43
+ /**
44
+ * Path utilities for handling navigation in auth flows.
45
+ * Ensures proper path resolution when auth pages are served under a base path (e.g., /auth/)
46
+ */
47
+ /**
48
+ * Resolves an auth route path relative to the current location.
49
+ * If the current path is under /auth/, it will preserve that prefix.
50
+ * Otherwise, it returns the path as-is.
51
+ *
52
+ * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')
53
+ * @returns The resolved path with proper base path handling
54
+ *
55
+ * @example
56
+ * // Current URL: http://localhost:5174/auth/sign-in
57
+ * resolveAuthPath('/sign-up') // Returns '/auth/sign-up'
58
+ *
59
+ * @example
60
+ * // Current URL: http://localhost:5174/sign-in
61
+ * resolveAuthPath('/sign-up') // Returns '/sign-up'
62
+ */
63
+ declare function resolveAuthPath(targetPath: string): string;
64
+ /**
65
+ * Resolves an auth route URL with search params preserved.
66
+ * Similar to resolveAuthPath but returns a full URL string with query parameters.
67
+ *
68
+ * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')
69
+ * @param searchParams - Optional URLSearchParams to append
70
+ * @returns The resolved URL as a string
71
+ *
72
+ * @example
73
+ * // Current URL: http://localhost:5174/auth/sign-in?redirect=...
74
+ * resolveAuthUrl('/sign-up', searchParams) // Returns '/auth/sign-up?redirect=...'
75
+ */
76
+ declare function resolveAuthUrl(targetPath: string, searchParams?: URLSearchParams): string;
77
+
78
+ /**
79
+ * Check if current environment is a hosted auth environment
80
+ *
81
+ * Returns true for:
82
+ * - localhost with port 7130 (hosted auth app dev)
83
+ * - https://*.aaspai.app (hosted auth app production)
84
+ *
85
+ * @returns true if running in hosted auth environment
86
+ */
87
+ declare function isHostedAuthEnvironment(): boolean;
88
+ /**
89
+ * Session data for building legacy auth URL
90
+ */
91
+ interface LegacyAuthSession {
92
+ accessToken: string;
93
+ userId: string;
94
+ email: string;
95
+ name?: string;
96
+ csrfToken?: string;
97
+ }
98
+ /**
99
+ * Build a legacy flow redirect URL with auth params in query string
100
+ *
101
+ * This is used to pass authentication credentials back to the user's app
102
+ * after OAuth completes in the hosted auth environment.
103
+ *
104
+ * @param redirectUrl - The URL to redirect to (user's app)
105
+ * @param session - The session data to include in the URL
106
+ * @returns The complete URL with auth params
107
+ */
108
+ declare function buildLegacyAuthUrl(redirectUrl: string, session: LegacyAuthSession): string;
109
+
110
+ export { type LegacyAuthSession, buildLegacyAuthUrl, checkPasswordStrength, createPasswordSchema, emailSchema, isHostedAuthEnvironment, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword };
111
+
package/dist/lib.d.ts ADDED
@@ -0,0 +1,111 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Email validation schema
5
+ */
6
+ declare const emailSchema: z.ZodString;
7
+ /**
8
+ * Password validation schema with configurable requirements
9
+ */
10
+ declare function createPasswordSchema(options?: {
11
+ minLength?: number;
12
+ requireUppercase?: boolean;
13
+ requireLowercase?: boolean;
14
+ requireNumber?: boolean;
15
+ requireSpecialChar?: boolean;
16
+ }): z.ZodString;
17
+ /**
18
+ * Default password schema (minimum 6 characters)
19
+ */
20
+ declare const passwordSchema: z.ZodString;
21
+ /**
22
+ * Validate email format
23
+ */
24
+ declare function validateEmail(email: string): {
25
+ valid: boolean;
26
+ error?: string;
27
+ };
28
+ /**
29
+ * Validate password format
30
+ */
31
+ declare function validatePassword(password: string, options?: Parameters<typeof createPasswordSchema>[0]): {
32
+ valid: boolean;
33
+ error?: string;
34
+ };
35
+ /**
36
+ * Validate password strength based on multiple criteria
37
+ */
38
+ declare function checkPasswordStrength(password: string): {
39
+ score: number;
40
+ feedback: string[];
41
+ };
42
+
43
+ /**
44
+ * Path utilities for handling navigation in auth flows.
45
+ * Ensures proper path resolution when auth pages are served under a base path (e.g., /auth/)
46
+ */
47
+ /**
48
+ * Resolves an auth route path relative to the current location.
49
+ * If the current path is under /auth/, it will preserve that prefix.
50
+ * Otherwise, it returns the path as-is.
51
+ *
52
+ * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')
53
+ * @returns The resolved path with proper base path handling
54
+ *
55
+ * @example
56
+ * // Current URL: http://localhost:5174/auth/sign-in
57
+ * resolveAuthPath('/sign-up') // Returns '/auth/sign-up'
58
+ *
59
+ * @example
60
+ * // Current URL: http://localhost:5174/sign-in
61
+ * resolveAuthPath('/sign-up') // Returns '/sign-up'
62
+ */
63
+ declare function resolveAuthPath(targetPath: string): string;
64
+ /**
65
+ * Resolves an auth route URL with search params preserved.
66
+ * Similar to resolveAuthPath but returns a full URL string with query parameters.
67
+ *
68
+ * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')
69
+ * @param searchParams - Optional URLSearchParams to append
70
+ * @returns The resolved URL as a string
71
+ *
72
+ * @example
73
+ * // Current URL: http://localhost:5174/auth/sign-in?redirect=...
74
+ * resolveAuthUrl('/sign-up', searchParams) // Returns '/auth/sign-up?redirect=...'
75
+ */
76
+ declare function resolveAuthUrl(targetPath: string, searchParams?: URLSearchParams): string;
77
+
78
+ /**
79
+ * Check if current environment is a hosted auth environment
80
+ *
81
+ * Returns true for:
82
+ * - localhost with port 7130 (hosted auth app dev)
83
+ * - https://*.aaspai.app (hosted auth app production)
84
+ *
85
+ * @returns true if running in hosted auth environment
86
+ */
87
+ declare function isHostedAuthEnvironment(): boolean;
88
+ /**
89
+ * Session data for building legacy auth URL
90
+ */
91
+ interface LegacyAuthSession {
92
+ accessToken: string;
93
+ userId: string;
94
+ email: string;
95
+ name?: string;
96
+ csrfToken?: string;
97
+ }
98
+ /**
99
+ * Build a legacy flow redirect URL with auth params in query string
100
+ *
101
+ * This is used to pass authentication credentials back to the user's app
102
+ * after OAuth completes in the hosted auth environment.
103
+ *
104
+ * @param redirectUrl - The URL to redirect to (user's app)
105
+ * @param session - The session data to include in the URL
106
+ * @returns The complete URL with auth params
107
+ */
108
+ declare function buildLegacyAuthUrl(redirectUrl: string, session: LegacyAuthSession): string;
109
+
110
+ export { type LegacyAuthSession, buildLegacyAuthUrl, checkPasswordStrength, createPasswordSchema, emailSchema, isHostedAuthEnvironment, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword };
111
+
package/dist/lib.js ADDED
@@ -0,0 +1,128 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/lib/validation.ts
4
+ var emailSchema = z.string().min(1, "Email is required").email("Invalid email address");
5
+ function createPasswordSchema(options) {
6
+ const {
7
+ minLength = 6,
8
+ requireUppercase = false,
9
+ requireLowercase = false,
10
+ requireNumber = false,
11
+ requireSpecialChar = false
12
+ } = options || {};
13
+ let schema = z.string().min(minLength, `Password must be at least ${minLength} characters`);
14
+ if (requireUppercase) {
15
+ schema = schema.regex(/[A-Z]/, "Password must contain at least one uppercase letter");
16
+ }
17
+ if (requireLowercase) {
18
+ schema = schema.regex(/[a-z]/, "Password must contain at least one lowercase letter");
19
+ }
20
+ if (requireNumber) {
21
+ schema = schema.regex(/\d/, "Password must contain at least one number");
22
+ }
23
+ if (requireSpecialChar) {
24
+ schema = schema.regex(
25
+ /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/,
26
+ "Password must contain at least one special character"
27
+ );
28
+ }
29
+ return schema;
30
+ }
31
+ var passwordSchema = createPasswordSchema();
32
+ function validateEmail(email) {
33
+ const result = emailSchema.safeParse(email);
34
+ if (result.success) {
35
+ return { valid: true };
36
+ }
37
+ return { valid: false, error: result.error.message };
38
+ }
39
+ function validatePassword(password, options) {
40
+ const schema = createPasswordSchema(options);
41
+ const result = schema.safeParse(password);
42
+ if (result.success) {
43
+ return { valid: true };
44
+ }
45
+ return { valid: false, error: result.error.message };
46
+ }
47
+ function checkPasswordStrength(password) {
48
+ const feedback = [];
49
+ let score = 0;
50
+ if (password.length >= 8) {
51
+ score += 1;
52
+ } else {
53
+ feedback.push("Use at least 8 characters");
54
+ }
55
+ if (password.length >= 12) {
56
+ score += 1;
57
+ }
58
+ if (/[a-z]/.test(password) && /[A-Z]/.test(password)) {
59
+ score += 1;
60
+ } else {
61
+ feedback.push("Use both uppercase and lowercase letters");
62
+ }
63
+ if (/\d/.test(password)) {
64
+ score += 1;
65
+ } else {
66
+ feedback.push("Include at least one number");
67
+ }
68
+ if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password)) {
69
+ score += 1;
70
+ } else {
71
+ feedback.push("Include at least one special character");
72
+ }
73
+ return { score, feedback };
74
+ }
75
+
76
+ // src/lib/path-utils.ts
77
+ function resolveAuthPath(targetPath) {
78
+ if (typeof window === "undefined") {
79
+ return targetPath;
80
+ }
81
+ const currentPath = window.location.pathname;
82
+ if (currentPath.startsWith("/auth/")) {
83
+ if (targetPath.startsWith("/auth/")) {
84
+ return targetPath;
85
+ }
86
+ return `/auth${targetPath}`;
87
+ }
88
+ return targetPath;
89
+ }
90
+ function resolveAuthUrl(targetPath, searchParams) {
91
+ const resolvedPath = resolveAuthPath(targetPath);
92
+ if (!searchParams || searchParams.toString() === "") {
93
+ return resolvedPath;
94
+ }
95
+ return `${resolvedPath}?${searchParams.toString()}`;
96
+ }
97
+
98
+ // src/lib/hosted-auth.ts
99
+ function isHostedAuthEnvironment() {
100
+ if (typeof window === "undefined") {
101
+ return false;
102
+ }
103
+ const { hostname, port, protocol } = window.location;
104
+ if (hostname === "localhost" && port === "7130") {
105
+ return true;
106
+ }
107
+ if (protocol === "https:" && hostname.endsWith(".aaspai.app")) {
108
+ return true;
109
+ }
110
+ return false;
111
+ }
112
+ function buildLegacyAuthUrl(redirectUrl, session) {
113
+ const url = new URL(redirectUrl);
114
+ url.searchParams.set("access_token", session.accessToken);
115
+ url.searchParams.set("user_id", session.userId);
116
+ url.searchParams.set("email", session.email);
117
+ if (session.name) {
118
+ url.searchParams.set("name", session.name);
119
+ }
120
+ if (session.csrfToken) {
121
+ url.searchParams.set("csrf_token", session.csrfToken);
122
+ }
123
+ return url.toString();
124
+ }
125
+
126
+ export { buildLegacyAuthUrl, checkPasswordStrength, createPasswordSchema, emailSchema, isHostedAuthEnvironment, passwordSchema, resolveAuthPath, resolveAuthUrl, validateEmail, validatePassword };
127
+ //# sourceMappingURL=lib.js.map
128
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/validation.ts","../src/lib/path-utils.ts","../src/lib/hosted-auth.ts"],"names":[],"mappings":"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","file":"lib.js","sourcesContent":["import { z } from 'zod';\r\n\r\n/**\r\n * Email validation schema\r\n */\r\nexport const emailSchema = z.string().min(1, 'Email is required').email('Invalid email address');\r\n\r\n/**\r\n * Password validation schema with configurable requirements\r\n */\r\nexport function createPasswordSchema(options?: {\r\n minLength?: number;\r\n requireUppercase?: boolean;\r\n requireLowercase?: boolean;\r\n requireNumber?: boolean;\r\n requireSpecialChar?: boolean;\r\n}) {\r\n const {\r\n minLength = 6,\r\n requireUppercase = false,\r\n requireLowercase = false,\r\n requireNumber = false,\r\n requireSpecialChar = false,\r\n } = options || {};\r\n\r\n let schema = z.string().min(minLength, `Password must be at least ${minLength} characters`);\r\n\r\n if (requireUppercase) {\r\n schema = schema.regex(/[A-Z]/, 'Password must contain at least one uppercase letter');\r\n }\r\n\r\n if (requireLowercase) {\r\n schema = schema.regex(/[a-z]/, 'Password must contain at least one lowercase letter');\r\n }\r\n\r\n if (requireNumber) {\r\n schema = schema.regex(/\\d/, 'Password must contain at least one number');\r\n }\r\n\r\n if (requireSpecialChar) {\r\n schema = schema.regex(\r\n /[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/,\r\n 'Password must contain at least one special character'\r\n );\r\n }\r\n\r\n return schema;\r\n}\r\n\r\n/**\r\n * Default password schema (minimum 6 characters)\r\n */\r\nexport const passwordSchema = createPasswordSchema();\r\n\r\n/**\r\n * Validate email format\r\n */\r\nexport function validateEmail(email: string): { valid: boolean; error?: string } {\r\n const result = emailSchema.safeParse(email);\r\n if (result.success) {\r\n return { valid: true };\r\n }\r\n return { valid: false, error: result.error.message };\r\n}\r\n\r\n/**\r\n * Validate password format\r\n */\r\nexport function validatePassword(\r\n password: string,\r\n options?: Parameters<typeof createPasswordSchema>[0]\r\n): { valid: boolean; error?: string } {\r\n const schema = createPasswordSchema(options);\r\n const result = schema.safeParse(password);\r\n if (result.success) {\r\n return { valid: true };\r\n }\r\n return { valid: false, error: result.error.message };\r\n}\r\n\r\n/**\r\n * Validate password strength based on multiple criteria\r\n */\r\nexport function checkPasswordStrength(password: string): {\r\n score: number;\r\n feedback: string[];\r\n} {\r\n const feedback: string[] = [];\r\n let score = 0;\r\n\r\n if (password.length >= 8) {\r\n score += 1;\r\n } else {\r\n feedback.push('Use at least 8 characters');\r\n }\r\n\r\n if (password.length >= 12) {\r\n score += 1;\r\n }\r\n\r\n if (/[a-z]/.test(password) && /[A-Z]/.test(password)) {\r\n score += 1;\r\n } else {\r\n feedback.push('Use both uppercase and lowercase letters');\r\n }\r\n\r\n if (/\\d/.test(password)) {\r\n score += 1;\r\n } else {\r\n feedback.push('Include at least one number');\r\n }\r\n\r\n if (/[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/.test(password)) {\r\n score += 1;\r\n } else {\r\n feedback.push('Include at least one special character');\r\n }\r\n\r\n return { score, feedback };\r\n}\r\n","/**\r\n * Path utilities for handling navigation in auth flows.\r\n * Ensures proper path resolution when auth pages are served under a base path (e.g., /auth/)\r\n */\r\n\r\n/**\r\n * Resolves an auth route path relative to the current location.\r\n * If the current path is under /auth/, it will preserve that prefix.\r\n * Otherwise, it returns the path as-is.\r\n *\r\n * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')\r\n * @returns The resolved path with proper base path handling\r\n *\r\n * @example\r\n * // Current URL: http://localhost:5174/auth/sign-in\r\n * resolveAuthPath('/sign-up') // Returns '/auth/sign-up'\r\n *\r\n * @example\r\n * // Current URL: http://localhost:5174/sign-in\r\n * resolveAuthPath('/sign-up') // Returns '/sign-up'\r\n */\r\nexport function resolveAuthPath(targetPath: string): string {\r\n if (typeof window === 'undefined') {\r\n return targetPath;\r\n }\r\n\r\n const currentPath = window.location.pathname;\r\n\r\n // Check if we're currently under /auth/ base path\r\n if (currentPath.startsWith('/auth/')) {\r\n // If target already has /auth/ prefix, return as-is\r\n if (targetPath.startsWith('/auth/')) {\r\n return targetPath;\r\n }\r\n // Add /auth/ prefix to the target path\r\n return `/auth${targetPath}`;\r\n }\r\n\r\n // Not under /auth/, return target path as-is\r\n return targetPath;\r\n}\r\n\r\n/**\r\n * Resolves an auth route URL with search params preserved.\r\n * Similar to resolveAuthPath but returns a full URL string with query parameters.\r\n *\r\n * @param targetPath - The target auth path (e.g., '/sign-in', '/sign-up')\r\n * @param searchParams - Optional URLSearchParams to append\r\n * @returns The resolved URL as a string\r\n *\r\n * @example\r\n * // Current URL: http://localhost:5174/auth/sign-in?redirect=...\r\n * resolveAuthUrl('/sign-up', searchParams) // Returns '/auth/sign-up?redirect=...'\r\n */\r\nexport function resolveAuthUrl(targetPath: string, searchParams?: URLSearchParams): string {\r\n const resolvedPath = resolveAuthPath(targetPath);\r\n\r\n if (!searchParams || searchParams.toString() === '') {\r\n return resolvedPath;\r\n }\r\n\r\n return `${resolvedPath}?${searchParams.toString()}`;\r\n}\r\n","/**\r\n * Hosted Auth Helpers\r\n *\r\n * Utilities for detecting hosted auth environment and building legacy auth URLs\r\n * for cross-domain authentication flows.\r\n */\r\n\r\n/**\r\n * Get CSRF token from cookie\r\n *\r\n * Reads the aaspai_csrf_token cookie set by the backend after authentication.\r\n * This is needed for OAuth flows where the csrfToken is stored in cookies\r\n * rather than returned in the API response.\r\n *\r\n * @returns The CSRF token value or null if not found\r\n */\r\nexport function getCsrfTokenFromCookie(): string | null {\r\n if (typeof document === 'undefined') return null;\r\n const match = document.cookie.match(/(?:^|;\\s*)aaspai_csrf_token=([^;]*)/);\r\n return match ? decodeURIComponent(match[1]) : null;\r\n}\r\n\r\n/**\r\n * Check if current environment is a hosted auth environment\r\n *\r\n * Returns true for:\r\n * - localhost with port 7130 (hosted auth app dev)\r\n * - https://*.aaspai.app (hosted auth app production)\r\n *\r\n * @returns true if running in hosted auth environment\r\n */\r\nexport function isHostedAuthEnvironment(): boolean {\r\n if (typeof window === 'undefined') {\r\n return false;\r\n }\r\n\r\n const { hostname, port, protocol } = window.location;\r\n\r\n // Local development\r\n if (hostname === 'localhost' && port === '7130') {\r\n return true;\r\n }\r\n\r\n // Production hosted auth\r\n if (protocol === 'https:' && hostname.endsWith('.aaspai.app')) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Session data for building legacy auth URL\r\n */\r\nexport interface LegacyAuthSession {\r\n accessToken: string;\r\n userId: string;\r\n email: string;\r\n name?: string;\r\n csrfToken?: string;\r\n}\r\n\r\n/**\r\n * Build a legacy flow redirect URL with auth params in query string\r\n *\r\n * This is used to pass authentication credentials back to the user's app\r\n * after OAuth completes in the hosted auth environment.\r\n *\r\n * @param redirectUrl - The URL to redirect to (user's app)\r\n * @param session - The session data to include in the URL\r\n * @returns The complete URL with auth params\r\n */\r\nexport function buildLegacyAuthUrl(redirectUrl: string, session: LegacyAuthSession): string {\r\n const url = new URL(redirectUrl);\r\n url.searchParams.set('access_token', session.accessToken);\r\n url.searchParams.set('user_id', session.userId);\r\n url.searchParams.set('email', session.email);\r\n\r\n if (session.name) {\r\n url.searchParams.set('name', session.name);\r\n }\r\n\r\n if (session.csrfToken) {\r\n url.searchParams.set('csrf_token', session.csrfToken);\r\n }\r\n\r\n return url.toString();\r\n}\r\n"]}
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/navigation/NavigationContext.tsx
7
+ var NavigationContext = react.createContext(null);
8
+ function NavigationProvider({ adapter, children }) {
9
+ return /* @__PURE__ */ jsxRuntime.jsx(NavigationContext.Provider, { value: adapter, children });
10
+ }
11
+ function useNavigationAdapter() {
12
+ const adapter = react.useContext(NavigationContext);
13
+ if (!adapter) {
14
+ return {
15
+ useSearchParams: () => new URLSearchParams(),
16
+ Link: ({ href, children, className }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, children })
17
+ };
18
+ }
19
+ return adapter;
20
+ }
21
+ var BrowserNavigationAdapter = {
22
+ /**
23
+ * Returns URLSearchParams from current window.location.search
24
+ * Note: Not reactive - reads once on component mount
25
+ * This is sufficient for auth flows where we read initial URL params
26
+ */
27
+ useSearchParams() {
28
+ const [searchParams] = react.useState(() => {
29
+ if (typeof window === "undefined") {
30
+ return new URLSearchParams();
31
+ }
32
+ return new URLSearchParams(window.location.search);
33
+ });
34
+ return searchParams;
35
+ },
36
+ /**
37
+ * Native <a> tag for navigation
38
+ * Uses full page reload
39
+ */
40
+ Link({ href, className, children }) {
41
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, children });
42
+ }
43
+ };
44
+
45
+ // src/navigation/useSearchParams.ts
46
+ function useSearchParams() {
47
+ const adapter = useNavigationAdapter();
48
+ return adapter.useSearchParams();
49
+ }
50
+
51
+ exports.BrowserNavigationAdapter = BrowserNavigationAdapter;
52
+ exports.NavigationProvider = NavigationProvider;
53
+ exports.useNavigationAdapter = useNavigationAdapter;
54
+ exports.useSearchParams = useSearchParams;
55
+ //# sourceMappingURL=navigation.cjs.map
56
+ //# sourceMappingURL=navigation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/navigation/NavigationContext.tsx","../src/navigation/BrowserNavigationAdapter.tsx","../src/navigation/useSearchParams.ts"],"names":["createContext","useContext","jsx","useState"],"mappings":";;;;;;AAGA,IAAM,iBAAA,GAAoBA,oBAAwC,IAAI,CAAA;AAW/D,SAAS,kBAAA,CAAmB,EAAE,OAAA,EAAS,QAAA,EAAS,EAA4B;AACjF,EAAA,sCAAQ,iBAAA,CAAkB,QAAA,EAAlB,EAA2B,KAAA,EAAO,SAAU,QAAA,EAAS,CAAA;AAC/D;AAMO,SAAS,oBAAA,GAA0C;AACxD,EAAA,MAAM,OAAA,GAAUC,iBAAW,iBAAiB,CAAA;AAE5C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO;AAAA,MACL,eAAA,EAAiB,MAAM,IAAI,eAAA,EAAgB;AAAA,MAC3C,IAAA,EAAM,CAAC,EAAE,IAAA,EAAM,QAAA,EAAU,SAAA,EAAU,qBACjCC,cAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAY,SAAA,EACZ,QAAA,EACH;AAAA,KAEJ;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AC7BO,IAAM,wBAAA,GAA8C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMzD,eAAA,GAAkB;AAChB,IAAA,MAAM,CAAC,YAAY,CAAA,GAAIC,cAAA,CAAS,MAAM;AACpC,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,OAAO,IAAI,eAAA,EAAgB;AAAA,MAC7B;AACA,MAAA,OAAO,IAAI,eAAA,CAAgB,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA;AAAA,IACnD,CAAC,CAAA;AAED,IAAA,OAAO,YAAA;AAAA,EACT,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAA,CAAK,EAAE,IAAA,EAAM,SAAA,EAAW,UAAS,EAAG;AAClC,IAAA,uBACED,cAAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAY,WACZ,QAAA,EACH,CAAA;AAAA,EAEJ;AACF;;;ACnBO,SAAS,eAAA,GAAmC;AACjD,EAAA,MAAM,UAAU,oBAAA,EAAqB;AACrC,EAAA,OAAO,QAAQ,eAAA,EAAgB;AACjC","file":"navigation.cjs","sourcesContent":["import { createContext, useContext, ReactNode } from 'react';\r\nimport type { NavigationAdapter } from './types';\r\n\r\nconst NavigationContext = createContext<NavigationAdapter | null>(null);\r\n\r\nexport interface NavigationProviderProps {\r\n adapter: NavigationAdapter;\r\n children: ReactNode;\r\n}\r\n\r\n/**\r\n * Navigation Provider\r\n * Injects navigation adapter into the component tree\r\n */\r\nexport function NavigationProvider({ adapter, children }: NavigationProviderProps) {\r\n return <NavigationContext.Provider value={adapter}>{children}</NavigationContext.Provider>;\r\n}\r\n\r\n/**\r\n * Hook to access navigation adapter\r\n * @throws Error if used outside NavigationProvider\r\n */\r\nexport function useNavigationAdapter(): NavigationAdapter {\r\n const adapter = useContext(NavigationContext);\r\n\r\n if (!adapter) {\r\n return {\r\n useSearchParams: () => new URLSearchParams(),\r\n Link: ({ href, children, className }) => (\r\n <a href={href} className={className}>\r\n {children}\r\n </a>\r\n ),\r\n };\r\n }\r\n\r\n return adapter;\r\n}\r\n","import { useState } from 'react';\r\nimport type { NavigationAdapter } from './types';\r\n\r\n/**\r\n * Browser native navigation adapter\r\n * Uses browser's native URLSearchParams and <a> tags\r\n * Suitable for vanilla React apps without a routing library\r\n */\r\nexport const BrowserNavigationAdapter: NavigationAdapter = {\r\n /**\r\n * Returns URLSearchParams from current window.location.search\r\n * Note: Not reactive - reads once on component mount\r\n * This is sufficient for auth flows where we read initial URL params\r\n */\r\n useSearchParams() {\r\n const [searchParams] = useState(() => {\r\n if (typeof window === 'undefined') {\r\n return new URLSearchParams();\r\n }\r\n return new URLSearchParams(window.location.search);\r\n });\r\n\r\n return searchParams;\r\n },\r\n\r\n /**\r\n * Native <a> tag for navigation\r\n * Uses full page reload\r\n */\r\n Link({ href, className, children }) {\r\n return (\r\n <a href={href} className={className}>\r\n {children}\r\n </a>\r\n );\r\n },\r\n};\r\n","import { useNavigationAdapter } from './NavigationContext';\r\n\r\n/**\r\n * Hook to get URL search parameters\r\n * Uses the navigation adapter injected by NavigationProvider\r\n *\r\n * @returns URLSearchParams object\r\n *\r\n * @example\r\n * ```tsx\r\n * function MyComponent() {\r\n * const searchParams = useSearchParams();\r\n * const redirectUrl = searchParams.get('redirect') || '/';\r\n * // ...\r\n * }\r\n * ```\r\n */\r\nexport function useSearchParams(): URLSearchParams {\r\n const adapter = useNavigationAdapter();\r\n return adapter.useSearchParams();\r\n}\r\n"]}