c33ee3dfe7
- Create modular project structure with src/backend, src/frontend, public - Hono server with routing, static file serving, and API endpoints - TailwindCSS styling pipeline with Tailwind CLI - Vanilla JS frontend (extensible for frameworks) - Complete TypeScript configuration and type checking - Auth module as self-contained submodule - Ready for development: bun run dev (port 3000) - All dependencies installed and tested Also: - Lock main branch with read-only settings in VS Code - Create .github/copilot-instructions.md with Monica persona - Initialize session logging system Status: Project ready for feature development
128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
// Auth Module: Universal, pattern-based token management
|
|
//
|
|
// How it works:
|
|
// - Manages tokens for multiple auth patterns (PocketBase, Microsoft Graph, etc.)
|
|
// - Stores tokens in localStorage under standardized keys
|
|
// - Supports composition of patterns (e.g., 'pb+graph' enables both)
|
|
// - All operations are synchronous and immutable
|
|
//
|
|
// Usage:
|
|
// Auth.configure('pb+graph').then(() => {
|
|
// const token = Auth.getToken('pb-user');
|
|
// const graphToken = Auth.getToken('graph-user');
|
|
// })
|
|
//
|
|
// Token types available:
|
|
// - pb-user: PocketBase user token
|
|
// - pb-agent: PocketBase service account token
|
|
// - graph-user: Microsoft Graph delegated token
|
|
// - graph-agent: Microsoft Graph app-only token
|
|
//
|
|
// Dependencies:
|
|
// - PocketBase (optional, for pb tokens): window.PocketBase
|
|
// - localStorage: browser API for token persistence
|
|
//
|
|
// Gotchas:
|
|
// - Tokens are stored in plaintext in localStorage (security consideration)
|
|
// - Pattern must be set before accessing tokens
|
|
// - All token types must be explicitly enabled via configure()
|
|
|
|
type TokenType = 'pb-user' | 'pb-agent' | 'graph-user' | 'graph-agent';
|
|
|
|
interface TokenConfig {
|
|
[key in TokenType]: string;
|
|
}
|
|
|
|
interface AuthConfig {
|
|
pbUrl?: string;
|
|
graphApiUrl?: string;
|
|
}
|
|
|
|
const TOKEN_STORAGE_KEYS: TokenConfig = {
|
|
'pb-user': 'auth:pb-user',
|
|
'pb-agent': 'auth:pb-agent',
|
|
'graph-user': 'auth:graph-user',
|
|
'graph-agent': 'auth:graph-agent'
|
|
};
|
|
|
|
class AuthManager {
|
|
private pattern: TokenType[] = [];
|
|
private pbInstance: any = null;
|
|
private config: AuthConfig = {};
|
|
|
|
async configure(patternString: string, config?: AuthConfig): Promise<void> {
|
|
this.pattern = this.parsePattern(patternString);
|
|
this.config = config || {};
|
|
|
|
if (this.pattern.some(t => t.startsWith('pb'))) {
|
|
await this.initPocketBase();
|
|
}
|
|
}
|
|
|
|
private parsePattern(pattern: string): TokenType[] {
|
|
return pattern
|
|
.split('+')
|
|
.map(s => s.trim())
|
|
.filter(Boolean) as TokenType[];
|
|
}
|
|
|
|
private async initPocketBase(): Promise<void> {
|
|
if (this.pbInstance) return;
|
|
|
|
const pbUrl = this.config.pbUrl || 'http://127.0.0.1:8090';
|
|
const PocketBase = (window as any).PocketBase;
|
|
|
|
if (!PocketBase) {
|
|
throw new Error('PocketBase library not loaded. Include PocketBase script before Auth initialization.');
|
|
}
|
|
|
|
this.pbInstance = new PocketBase(pbUrl);
|
|
}
|
|
|
|
getToken(type: TokenType): string | null {
|
|
const key = TOKEN_STORAGE_KEYS[type];
|
|
if (!key) return null;
|
|
return localStorage.getItem(key);
|
|
}
|
|
|
|
setToken(type: TokenType, token: string | null): void {
|
|
const key = TOKEN_STORAGE_KEYS[type];
|
|
if (!key) return;
|
|
|
|
if (token) {
|
|
localStorage.setItem(key, token);
|
|
} else {
|
|
localStorage.removeItem(key);
|
|
}
|
|
}
|
|
|
|
clearToken(type: TokenType): void {
|
|
this.setToken(type, null);
|
|
}
|
|
|
|
clearAllTokens(): void {
|
|
Object.keys(TOKEN_STORAGE_KEYS).forEach(key => {
|
|
localStorage.removeItem(TOKEN_STORAGE_KEYS[key as TokenType]);
|
|
});
|
|
}
|
|
|
|
isConfigured(): boolean {
|
|
return this.pattern.length > 0;
|
|
}
|
|
|
|
getEnabledTypes(): TokenType[] {
|
|
return [...this.pattern];
|
|
}
|
|
}
|
|
|
|
// Export singleton instance
|
|
const Auth = new AuthManager();
|
|
|
|
// Make available globally for browser environments
|
|
if (typeof window !== 'undefined') {
|
|
(window as any).Auth = Auth;
|
|
}
|
|
|
|
export default Auth;
|
|
export { TokenType, AuthManager };
|