Instruction file imported from manujoz/iracing-api-sdk-node (
.github/instructions/library.instructions.md). Copyright stays with the author.
iracing-api-sdk-node Library Development Standards
| Component | Purpose | Key Classes |
|---|---|---|
| config/ | Environment configuration | Config |
| crypto/ | Credential masking for iRacing | Masker |
| data/ | iRacing Data API client | DataApiClient, services/* |
| errors/ | Exception hierarchy | ApiException, HttpException, ApiError |
| http/ | HTTP communication | HttpClient, HttpClientInterface, HttpResponse |
| log/ | Logging abstraction | LoggerInterface, ConsoleLogger |
| oauth/ | OAuth2 (password_limited, authorization_code+PKCE) | OAuthClient, AuthorizeUrlBuilder, Pkce |
| rate-limit/ | Rate limiting and request throttling | RateLimitGuard, RateLimitedHttpClient, RateLimitStoreInterface |
| response/ | API response wrapper | ClientResult |
| sessions/ | iRacing OAuth Session Management | SessionsClient |
| token/ | Token management + expiration | TokenSet, TokenStorageInterface, FileTokenStorage |
Interface-Based Design: All abstractions use interfaces for flexibility (HTTP, Logger, Sessions, Token Storage)
Dependency Injection: Constructor injection with optional defaults (logger?: LoggerInterface → new ConsoleLogger())
Configuration: Factory method Config.fromEnv() loads from environment variables with defaults
Error Handling: Catch exceptions, log safely (no sensitive data), throw custom exceptions (ApiException, HttpException)
<oauth_flows>
Password Limited: Client secret masked with client ID, password masked with username (via crypto/Masker)
Authorization Code: PKCE mandatory (code_verifier via oauth/Pkce), state parameter for CSRF, redirect URI validation
Token Management: TokenSet encapsulates access_token/refresh_token/expires_in, isExpired() checks expiration, OAuthClient.refreshAccessToken() handles refresh
</oauth_flows>
<http_implementation>
HttpClientInterface: Abstract HTTP for testability (request(method, url, headers, body): Promise<HttpResponse>)
HttpResponse: Readonly properties (statusCode, body, headers)
Pattern: POST with JSON → check statusCode → JSON.parse(body) → throw ApiException on error
</http_implementation>
NEVER log: OAuth2 tokens, client secrets, user passwords, masked credentials
ALWAYS: Use crypto/Masker for iRacing credentials (mask secret with clientId, mask password with username)
Logging: Safe info only (endpoint names, success/failure status, no sensitive values)
Unit Tests: Mock HttpClientInterface, test individual components (TokenSet, Masker, Config), organized in tests/unit/
Integration Tests: Real OAuth flows marked with appropriate tags to exclude from regular runs
Mocking: Use Vitest mocking (vi.fn()) → return HttpResponse with test data
- ❌ NEVER: External pnpm dependencies (except dev), log tokens/secrets/passwords, static methods (except factories), modify global state
- ✅ ALWAYS: Strict typing (TypeScript strict mode), interfaces for abstractions, constructor injection, graceful error handling with exceptions, JSDoc for public methods
<code_quality>
Type Safety: All parameters and return types declared explicitly, nullable types with ? prefix or | null, no implicit any
Null Handling: Optional dependencies with param?: Type → nullish coalescing operator for defaults
JSDoc: Public methods require summary, @param with types/descriptions, @return, @throws for exceptions
Naming: PascalCase (classes), camelCase (methods/properties), UPPER_SNAKE_CASE (constants)
File Structure: One class per file, filename matches class name in kebab-case, exports at bottom
</code_quality>
Public API: Every public method needs JSDoc (summary, parameters, return, exceptions), usage examples in docs/
File Level: Brief class purpose, key responsibilities, usage patterns, security considerations if applicable