183 lines
5.9 KiB
Markdown
183 lines
5.9 KiB
Markdown
# System Patterns
|
|
|
|
This document outlines the system architecture, key technical decisions, and design patterns used in the G1 TypeScript Common Packages repository.
|
|
|
|
## System Architecture
|
|
|
|
The repository follows a monorepo architecture using pnpm workspaces:
|
|
|
|
```
|
|
g1-ts-common-packages/
|
|
├── packages/ # All packages are stored here
|
|
│ ├── sse-client/ # Server-Sent Events client package
|
|
│ └── [future-packages]/ # Additional packages will be added here
|
|
├── scripts/ # Utility scripts for the repository
|
|
├── docs/ # Documentation
|
|
└── .github/workflows/ # CI/CD workflows
|
|
```
|
|
|
|
Each package within the monorepo is designed to be:
|
|
- **Independent**: Can be used without other packages from the monorepo
|
|
- **Focused**: Solves a specific problem domain
|
|
- **Well-documented**: Includes comprehensive documentation
|
|
- **Well-tested**: Includes unit tests
|
|
|
|
## Key Technical Decisions
|
|
|
|
### 1. Monorepo Structure
|
|
- **Decision**: Use a monorepo structure with pnpm workspaces
|
|
- **Rationale**:
|
|
- Simplifies management of multiple related packages
|
|
- Enables sharing of configuration and tooling
|
|
- Facilitates coordinated changes across packages
|
|
- Reduces duplication of dependencies
|
|
|
|
### 2. Package Scope
|
|
- **Decision**: Use the `@g1` scope for all packages
|
|
- **Rationale**:
|
|
- Provides namespace isolation
|
|
- Makes it clear that packages belong to Generation One
|
|
- Prevents name collisions with other packages
|
|
|
|
### 3. Package Versioning
|
|
- **Decision**: Start packages at version 0.2.0
|
|
- **Rationale**:
|
|
- Follows Generation One's standard starting version
|
|
- Allows for pre-1.0 breaking changes as packages mature
|
|
|
|
### 4. Publishing Strategy
|
|
- **Decision**: Publish packages to Gitea registry
|
|
- **Rationale**:
|
|
- Keeps packages within Generation One's infrastructure
|
|
- Provides access control for private packages (if needed in the future)
|
|
- Simplifies CI/CD integration
|
|
|
|
### 5. TypeScript First
|
|
- **Decision**: Use TypeScript for all packages
|
|
- **Rationale**:
|
|
- Provides type safety
|
|
- Improves developer experience
|
|
- Enables better tooling and IDE support
|
|
- Reduces runtime errors
|
|
|
|
## Design Patterns
|
|
|
|
### SSE Client Package
|
|
|
|
The SSE Client package demonstrates several design patterns:
|
|
|
|
#### 1. Singleton Pattern
|
|
- Used in the `SSEConnectionManager` to ensure only one instance manages all connections
|
|
- Provides a global point of access to the connection manager
|
|
|
|
```typescript
|
|
export class SSEConnectionManager {
|
|
private static instance: SSEConnectionManager;
|
|
|
|
private constructor() {}
|
|
|
|
public static getInstance(): SSEConnectionManager {
|
|
if (!SSEConnectionManager.instance) {
|
|
SSEConnectionManager.instance = new SSEConnectionManager();
|
|
}
|
|
return SSEConnectionManager.instance;
|
|
}
|
|
|
|
// ...
|
|
}
|
|
```
|
|
|
|
#### 2. Factory Pattern
|
|
- Helper functions like `getSSEConnection` act as factories to create or retrieve SSE client instances
|
|
- Simplifies the creation and management of SSE connections
|
|
|
|
```typescript
|
|
export function getSSEConnection(url: string, id: string, options: SSEClientOptions = {}): SSEClient {
|
|
return SSEConnectionManager.getInstance().getConnection(url, id, options);
|
|
}
|
|
```
|
|
|
|
#### 3. Observer Pattern
|
|
- The SSE client implements an event-based system where clients can subscribe to events
|
|
- Uses the browser's `EventTarget` or a custom implementation in Node.js
|
|
|
|
```typescript
|
|
public on(eventName: string, listener: (event: any) => void): SSEClient {
|
|
if (!this.eventListeners.has(eventName)) {
|
|
this.eventListeners.set(eventName, new Set());
|
|
}
|
|
|
|
this.eventListeners.get(eventName)!.add(listener);
|
|
|
|
// ...
|
|
|
|
return this;
|
|
}
|
|
```
|
|
|
|
#### 4. Options Pattern
|
|
- Uses an options object with defaults for configuration
|
|
- Allows for flexible and extensible configuration
|
|
|
|
```typescript
|
|
export interface SSEClientOptions {
|
|
headers?: Record<string, string>;
|
|
withCredentials?: boolean;
|
|
heartbeatTimeout?: number;
|
|
// ...
|
|
}
|
|
|
|
const DEFAULT_OPTIONS: Required<Omit<SSEClientOptions, 'headers'>> = {
|
|
withCredentials: true,
|
|
heartbeatTimeout: 21600000, // 6 hours
|
|
// ...
|
|
};
|
|
```
|
|
|
|
#### 5. Exponential Backoff Pattern
|
|
- Implements exponential backoff for reconnection attempts
|
|
- Helps prevent overwhelming the server during outages
|
|
|
|
```typescript
|
|
private async reconnect(): Promise<void> {
|
|
this.retryCount++;
|
|
|
|
// Calculate delay with exponential backoff
|
|
const delayMs = Math.min(
|
|
this.options.initialRetryDelay * Math.pow(2, this.retryCount - 1),
|
|
this.options.maxRetryDelay
|
|
);
|
|
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## Critical Implementation Paths
|
|
|
|
### SSE Client Connection Flow
|
|
|
|
1. **Initialization**: Create an SSE client with URL and options
|
|
2. **Connection**: Call `connect()` to establish the connection
|
|
3. **Event Handling**: Register event listeners with `on(eventName, listener)`
|
|
4. **Error Handling**: Automatic reconnection with exponential backoff
|
|
5. **Cleanup**: Close connection with `close()` or use automatic cleanup
|
|
|
|
### SSE Client Connection Management
|
|
|
|
1. **Get/Create Connection**: Use `getSSEConnection(url, id, options)` to get or create a connection
|
|
2. **Connection Reuse**: Connections are reused based on the provided ID
|
|
3. **Connection Cleanup**: Close specific connections with `closeSSEConnection(id)` or all with `closeAllSSEConnections()`
|
|
4. **Automatic Cleanup**: Set up with `setupSSECleanup()` to close connections on page unload
|
|
|
|
## Component Relationships
|
|
|
|
- **SSEClient**: Core class that handles the SSE connection and events
|
|
- **SSEConnectionManager**: Singleton that manages multiple SSE connections
|
|
- **Helper Functions**: Provide simplified access to the connection manager
|
|
- `getSSEConnection`: Gets or creates a connection
|
|
- `closeSSEConnection`: Closes a specific connection
|
|
- `closeAllSSEConnections`: Closes all connections
|
|
- `setupSSECleanup`: Sets up automatic cleanup
|
|
- **Debug Utilities**: Provide debug logging capabilities
|
|
- `debugLog`, `debugInfo`, `debugWarn`, `debugError`
|