npm package: @glitch_protocol/auth-core
Description: Core types, interfaces, and constants for glitch_protocol
Author: drcount-root
Latest version: 0.2.0

# @glitch_protocol/auth-core

Core interfaces, types, and constants for the glitch_protocol SDK. Provides the pluggable adapter interfaces (`DatabaseAdapter`, `CacheAdapter`, `SocketBroadcaster`) that all other packages depend on.

## Install

```bash
npm install @glitch_protocol/auth-core
```

## Interfaces

### DatabaseAdapter

Abstracts all database operations. Implement this to use your own database.

```ts
export interface DatabaseAdapter {
  // User operations
  getUser(userId: string): Promise<AuthUser | null>;

  // Session CRUD
  createSession(
    userId: string,
    deviceName: string | null,
    ipAddress: string,
    userAgent: string | undefined,
    browser: string | null,
    os: string | null,
    expiresAt: Date,
  ): Promise<Session>;

  getActiveSessions(userId: string): Promise<Session[]>;
  getSessionById(sessionId: string): Promise<Session | null>;
  isSessionActive(sessionId: string): Promise<boolean>;
  deactivateSession(sessionId: string): Promise<void>;
  updateSessionActivity(sessionId: string): Promise<void>;
  updateSessionSocketId(sessionId: string, socketId: string | null): Promise<void>;

  // Multi-device ops
  getOtherSessions(userId: string, excludeSessionId: string): Promise<Session[]>;
  deactivateOtherSessions(userId: string, excludeSessionId: string): Promise<void>;

  // Cleanup
  getExpiredSessions(now: Date): Promise<Session[]>;

  // Refresh token CRUD
  createRefreshToken(
    userId: string,
    sessionId: string,
    hashedToken: string,
    expiresAt: Date,
    rotatedFrom?: string,
  ): Promise<RefreshToken>;

  getRefreshToken(hashedToken: string): Promise<RefreshToken | null>;
  revokeRefreshToken(tokenId: string): Promise<void>;
  revokeSessionTokens(sessionId: string): Promise<void>;
  revokeAllUserTokens(userId: string): Promise<void>;
  deactivateAllUserSessions(userId: string): Promise<void>;
}
```

**Existing implementation:** [`@glitch_protocol/auth-adapter-drizzle`](../adapter-drizzle/README.md)

**To implement your own:** extend this interface and pass it to `glitch_protocolEngine`.

---

### CacheAdapter

Optional caching and distributed locking. System works without it but degrades to DB-only.

```ts
export interface CacheAdapter {
  // Cache ops
  get(key: string): Promise<string | null>;
  set(key: string, value: string, ttlSeconds: number): Promise<void>;
  delete(key: string): Promise<void>;
  deleteMany(keys: string[]): Promise<void>;

  // Distributed locking (for cleanup job)
  acquireLock(key: string, ttlSeconds: number): Promise<boolean>;
  releaseLock(key: string): Promise<void>;

  // Availability check
  isAvailable(): Promise<boolean>;
}
```

**Existing implementation:** [`@glitch_protocol/auth-adapter-redis`](../adapter-redis/README.md)

**To implement your own:** extend this interface. All methods should swallow errors gracefully so the system falls back to DB-only operation.

---

### SocketBroadcaster

Real-time event broadcasting. Emit to rooms, disconnect sockets.

```ts
export interface SocketBroadcaster {
  // Emit event to everyone in a room
  emitToRoom(room: string, event: string, data: unknown): Promise<void>;

  // Disconnect a single socket
  disconnectSocket(socketId: string, close?: boolean): Promise<void>;

  // Disconnect all sockets in a room (cross-instance safe via Redis adapter)
  disconnectRoom(room: string, close?: boolean): Promise<void>;
}
```

**To implement:** Use with Socket.IO Redis adapter for multi-instance support.

**Example (Socket.IO + Redis):**
```ts
import { createAdapter } from "@socket.io/redis-adapter";

const io = new Server(server);
io.adapter(createAdapter(pubClient, subClient)); // Redis adapter enables cross-instance broadcasting

const socketBroadcaster: SocketBroadcaster = {
  emitToRoom: async (room, event, data) => io.to(room).emit(event, data),
  disconnectSocket: async (socketId) => io.sockets.sockets.get(socketId)?.disconnect(),
  disconnectRoom: async (room) => io.in(room).disconnectSockets(),
};
```

---

## Types

### AuthUser
```ts
interface AuthUser {
  id: string;
  email: string;
  name: string;
}
```

### Session
```ts
interface Session {
  id: string;
  userId: string;
  deviceName: string | null;
  ipAddress: string;
  userAgent: string | undefined;
  browser: string | null;
  os: string | null;
  isActive: boolean;
  socketId: string | null;
  lastActivity: Date;
  expiresAt: Date;
  createdAt: Date;
  updatedAt: Date;
}
```

### SessionInfo
Client-safe session metadata (excludes userAgent, userId, updatedAt).
```ts
interface SessionInfo {
  id: string;
  deviceName: string | null;
  browser: string | null;
  os: string | null;
  ipAddress: string;
  isActive: boolean;
  isCurrent: boolean;
  lastActivity: string; // ISO string
  createdAt: string; // ISO string
}
```

### RefreshToken
```ts
interface RefreshToken {
  id: string;
  userId: string;
  sessionId: string;
  token: string; // SHA-256 hash
  rotatedFrom: string | null;
  isRevoked: boolean;
  revokedAt: Date | null;
  expiresAt: Date;
  createdAt: Date;
  updatedAt: Date;
}
```

### TokenPair
```ts
interface TokenPair {
  accessToken: string; // JWT
  refreshToken: string; // Raw 64-byte hex token
}
```

### ApiResponse
Standard API response shape.
```ts
type ApiResponse<T> =
  | { success: true; data: T }
  | { success: false; error: string; code?: string };
```

---

## Constants

### SOCKET_EVENTS
```ts
{
  SESSION_NEW: "session:new",
  SESSION_TERMINATED: "session:terminated",
  SESSION_LIST_UPDATED: "session:list-updated",
  SESSION_HEARTBEAT: "session:heartbeat",
  CONNECTION_ERROR: "connection:error",
}
```

### REDIS_KEYS
Functions that generate Redis key names.
```ts
{
  USER: (userId: string) => `user:${userId}`,
  SESSION_ACTIVE: (sessionId: string) => `session:${sessionId}:active`,
  ACTIVE_SESSIONS: (userId: string) => `sessions:active:${userId}`,
  REFRESH_TOKEN: (hashedToken: string) => `rt:hash:${hashedToken}`,
  HEARTBEAT: (sessionId: string) => `heartbeat:${sessionId}`,
  SESSION_ROOM: (sessionId: string) => `session:${sessionId}`,
  CLEANUP_LOCK: () => "cleanup:sessions:lock",
}
```

### REDIS_TTL
Cache expiry times in seconds.
```ts
{
  USER_PROFILE: 3600,           // 1 hour
  SESSION_ACTIVE_CHECK: 300,    // 5 minutes
  ACTIVE_SESSIONS: 300,         // 5 minutes
  REFRESH_TOKEN: 2592000,       // 30 days
  HEARTBEAT_DEBOUNCE: 25,       // 25 seconds
  CLEANUP_LOCK: 840,            // 14 minutes
}
```

### ERROR_CODES
```ts
{
  TOKEN_INVALID: "TOKEN_INVALID",
  TOKEN_EXPIRED: "TOKEN_EXPIRED",
  TOKEN_REUSE_DETECTED: "TOKEN_REUSE_DETECTED",
  SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
  USER_NOT_FOUND: "USER_NOT_FOUND",
  SESSION_EXPIRED: "SESSION_EXPIRED",
  UNAUTHORIZED: "UNAUTHORIZED",
  FORBIDDEN: "FORBIDDEN",
}
```

---

## Implementing a Custom DatabaseAdapter

```ts
import type { DatabaseAdapter } from "@glitch_protocol/auth-core";

export class CustomDatabaseAdapter implements DatabaseAdapter {
  async getUser(userId: string) {
    // Fetch from your database
    return { id: userId, email: "...", name: "..." };
  }

  async createSession(userId, deviceName, ipAddress, userAgent, browser, os, expiresAt) {
    // Insert into your database
    return { id: "...", userId, ... };
  }

  // ... implement all 17 methods
}

// Use it:
const adapter = new CustomDatabaseAdapter();
const engine = new glitch_protocolEngine(adapter, cache, socket, config);
```

## Implementing a Custom CacheAdapter

```ts
import type { CacheAdapter } from "@glitch_protocol/auth-core";

export class InMemoryCacheAdapter implements CacheAdapter {
  private cache = new Map<string, string>();
  private ttls = new Map<string, number>();

  async get(key: string) {
    const expiry = this.ttls.get(key);
    if (expiry && expiry < Date.now()) {
      this.cache.delete(key);
      return null;
    }
    return this.cache.get(key) ?? null;
  }

  async set(key: string, value: string, ttlSeconds: number) {
    this.cache.set(key, value);
    this.ttls.set(key, Date.now() + ttlSeconds * 1000);
  }

  async delete(key: string) {
    this.cache.delete(key);
    this.ttls.delete(key);
  }

  // ... implement remaining methods
}

// Use it:
const cache = new InMemoryCacheAdapter();
const engine = new glitch_protocolEngine(db, cache, socket, config);
```

---

## Exports

All types and interfaces are re-exported from the main entry point:

```ts
import {
  DatabaseAdapter,
  CacheAdapter,
  SocketBroadcaster,
  AuthUser,
  Session,
  SessionInfo,
  RefreshToken,
  TokenPair,
  ApiResponse,
  SOCKET_EVENTS,
  REDIS_KEYS,
  REDIS_TTL,
  ERROR_CODES,
} from "@glitch_protocol/auth-core";
```

## Node Version

**ESM-only.** Requires Node.js >=18.