UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

99 lines 4.54 kB
import { logger } from '../../log'; import { WebSocketErrors } from '../../error'; import { initializeQueries } from '../../queries'; import { buildWebSocketContext, getErrorMessage } from './utils'; /** * Create a WebSocket model initializer middleware * * This middleware initializes Amplify Data model query factories for WebSocket handlers. * It handles lazy initialization with caching, timeout protection, optional in-memory caching, * and automatic retry logic on initialization failures. * * **Initialization Flow:** * 1. Delegates to ClientManager.initializeQueries() for all initialization logic * 2. ClientManager handles global state management and caching automatically * 3. Initializes Amplify client and query factories for specified entities * 4. Adds initialized models to input object for subsequent middleware * 5. Handles initialization failures with proper error responses * * **Caching Behavior:** * - ClientManager handles all caching and state management globally * - Models are initialized once per clientKey and cached automatically * - Concurrent requests are handled efficiently by ClientManager * - Optional in-memory caching with LRU eviction for query results * * **Error Handling:** * - Initialization timeout: Returns 500 error response * - Amplify client errors: Returns 500 error response with details * - Post-initialization errors: Re-throws to be handled by error middleware * * **Performance Considerations:** * - First request bears initialization cost (typically 100-500ms) * - Subsequent requests use ClientManager's cached models (near-zero overhead) * - Timeout protection prevents hanging Lambda functions * - Optional query caching improves read performance * - No duplicate state management - relies on ClientManager singleton * * @template TSchema - Amplify Data schema type with models property * @template TTypes - Record of available Amplify model types * @template TSelected - Selected model types to initialize (subset of TTypes) * @template TReturn - Expected return type of the WebSocket handler * @param config - Configuration for model initialization * @returns Middleware function that adds initialized models to the input */ export function createWebSocketModelInitializer(config) { const { schema, amplifyOutputs, entities, clientKey = 'default', timeout = 5000, cache, } = config; /** * Initialize Amplify models with timeout protection * * Delegates to ClientManager.initializeQueries() which handles all caching and * state management. Uses Promise.race to implement timeout protection. * * @returns Promise resolving to initialized query factories * @throws {Error} When initialization times out or Amplify client fails * @internal */ const initializeWithTimeout = async () => { const models = await Promise.race([ // Use ClientManager's unified initialization with cache support initializeQueries({ amplifyOutputs, schema, entities: entities ?? undefined, clientKey: clientKey ?? undefined, cache, }), new Promise((_, reject) => setTimeout(() => reject(new Error(`Initialization timeout after ${timeout}ms`)), timeout)), ]); return models; }; return async (input, next) => { const context = buildWebSocketContext(input); // Only catch model initialization errors, not errors from next() let models; try { // Let ClientManager handle all caching and state management models = await initializeWithTimeout(); } catch (error) { const message = getErrorMessage(error); logger.error('WebSocket Model Initializer - Initialization failed', { ...context, error: message, clientKey, cacheEnabled: !!cache?.enabled, entitiesRequested: entities || 'all', }); throw WebSocketErrors.internal(message, { ...context, clientKey, cacheEnabled: !!cache?.enabled, entitiesRequested: entities || 'all', originalError: error, }); } // Call next() outside the try-catch so errors from other middlewares bubble up naturally return await next({ ...input, models }); }; } //# sourceMappingURL=WebSocketModelInitializer.js.map