feat: add Tier 3 shared auth store patterns

- Create @manacore/shared-auth-stores package with Svelte 5 factories:
  - createAuthStore<T>(): Generic factory with custom auth service adapter
  - createSupabaseAuthStore(): Direct Supabase integration for simpler setups
- Add standardized auth error types to @manacore/shared-types:
  - AuthErrorCode enum for consistent error handling
  - mapSupabaseErrorToCode() helper function
  - createAuthError() factory function

This enables apps to share auth state management while supporting
both middleware-based auth (ManaCore/Manadeck) and direct Supabase
auth (ManaCore-web simple mode).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Till-JS 2025-11-24 23:54:27 +01:00
parent 10325026f9
commit 9449fff6f7
8 changed files with 717 additions and 0 deletions

View file

@ -7,6 +7,65 @@
*/
export type AuthState = 'loading' | 'authenticated' | 'unauthenticated';
/**
* Standard authentication error codes
*/
export type AuthErrorCode =
| 'INVALID_CREDENTIALS'
| 'EMAIL_NOT_CONFIRMED'
| 'USER_NOT_FOUND'
| 'EMAIL_ALREADY_EXISTS'
| 'WEAK_PASSWORD'
| 'INVALID_EMAIL'
| 'RATE_LIMITED'
| 'TOKEN_EXPIRED'
| 'TOKEN_INVALID'
| 'NETWORK_ERROR'
| 'SERVER_ERROR'
| 'UNKNOWN_ERROR';
/**
* Structured authentication error
*/
export interface AuthError {
code: AuthErrorCode;
message: string;
originalError?: unknown;
}
/**
* Map common Supabase error messages to AuthErrorCode
*/
export function mapSupabaseErrorToCode(message: string): AuthErrorCode {
const lowerMessage = message.toLowerCase();
if (lowerMessage.includes('invalid login credentials')) return 'INVALID_CREDENTIALS';
if (lowerMessage.includes('email not confirmed')) return 'EMAIL_NOT_CONFIRMED';
if (lowerMessage.includes('user not found')) return 'USER_NOT_FOUND';
if (lowerMessage.includes('already registered') || lowerMessage.includes('already exists'))
return 'EMAIL_ALREADY_EXISTS';
if (lowerMessage.includes('password') && lowerMessage.includes('weak')) return 'WEAK_PASSWORD';
if (lowerMessage.includes('invalid email')) return 'INVALID_EMAIL';
if (lowerMessage.includes('rate') || lowerMessage.includes('too many')) return 'RATE_LIMITED';
if (lowerMessage.includes('token') && lowerMessage.includes('expired')) return 'TOKEN_EXPIRED';
if (lowerMessage.includes('token') && lowerMessage.includes('invalid')) return 'TOKEN_INVALID';
if (lowerMessage.includes('network') || lowerMessage.includes('fetch')) return 'NETWORK_ERROR';
if (lowerMessage.includes('server') || lowerMessage.includes('500')) return 'SERVER_ERROR';
return 'UNKNOWN_ERROR';
}
/**
* Create an AuthError from a Supabase error message
*/
export function createAuthError(message: string, originalError?: unknown): AuthError {
return {
code: mapSupabaseErrorToCode(message),
message,
originalError
};
}
/**
* User session
*/