UNPKG

mcp-casual-interview

Version:

MCP server for casual interview preparation workflow management

193 lines 7.69 kB
import { ok, err } from 'neverthrow'; import { getCurrentState, forceSetState, updateNotionPageUrl, getNotionPageUrl, clearState } from '../workflow-state-storage.js'; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // In-Memory Storage Implementation (for development/testing) // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class InMemoryWorkflowState { state = 'information_initially_registered'; notionPageUrl = null; // null means unregistered lastUpdated = new Date(); get() { try { return ok(this.state); } catch (cause) { return err({ type: 'StorageUnavailable', message: 'Failed to retrieve workflow state from memory', cause }); } } set(newState) { try { this.state = newState; this.lastUpdated = new Date(); return ok(undefined); } catch (cause) { return err({ type: 'StorageUnavailable', message: 'Failed to store workflow state in memory', cause }); } } clear() { try { this.state = 'information_initially_registered'; this.lastUpdated = new Date(); return ok(undefined); } catch (cause) { return err({ type: 'StorageUnavailable', message: 'Failed to clear workflow state from memory', cause }); } } getLastUpdated() { return this.lastUpdated; } getNotionPageUrl() { try { // Return "未登録です" if URL is not registered (null) return ok(this.notionPageUrl ?? "未登録です"); } catch (cause) { return err({ type: 'StorageUnavailable', message: 'Failed to retrieve notion page URL from memory', cause }); } } setNotionPageUrl(url) { try { this.notionPageUrl = url; this.lastUpdated = new Date(); return ok(undefined); } catch (cause) { return err({ type: 'StorageUnavailable', message: 'Failed to store notion page URL in memory', cause }); } } } // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Storage Implementations // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Global instance for in-memory storage const inMemoryStorage = new InMemoryWorkflowState(); /** * Database storage implementation (placeholder for future use) */ const createDatabaseStorageEffects = (connectionString) => { // For now, delegate to in-memory storage // This can be extended to use actual database persistence return { get: () => inMemoryStorage.get(), set: (state) => inMemoryStorage.set(state), clear: () => inMemoryStorage.clear(), getNotionPageUrl: () => inMemoryStorage.getNotionPageUrl(), setNotionPageUrl: (url) => inMemoryStorage.setNotionPageUrl(url) }; }; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Error Mapping Utilities // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const mapStorageErrorToWorkflowError = (storageError) => { switch (storageError.type) { case 'StorageUnavailable': return { type: 'ValidationFailed', message: `Storage unavailable: ${storageError.message}` }; case 'SerializationError': return { type: 'ValidationFailed', message: `Serialization error: ${storageError.message}` }; case 'StateNotFound': return { type: 'ValidationFailed', message: `State not found: ${storageError.message}` }; default: const _exhaustive = storageError.type; return { type: 'ValidationFailed', message: `Unknown storage error: ${_exhaustive}` }; } }; // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Public API // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ // Default effects using new file-based storage export const WorkflowStateEffects = { getWorkflowState: async () => { const result = await getCurrentState(); return result .map(data => data.state) .mapErr(error => ({ type: 'StorageUnavailable', message: error.message, cause: error.cause })); }, setWorkflowState: async (state) => { const result = await forceSetState(state); return result .map(() => undefined) .mapErr(error => ({ type: 'StorageUnavailable', message: error.message, cause: error.cause })); }, clearWorkflowState: async () => { const result = await clearState(); return result .map(() => undefined) .mapErr(error => ({ type: 'StorageUnavailable', message: error.message, cause: error.cause })); }, getNotionPageUrl: async () => { const result = await getNotionPageUrl(); return result .mapErr(error => ({ type: 'StorageUnavailable', message: error.message, cause: error.cause })); }, setNotionPageUrl: async (url) => { const result = await updateNotionPageUrl(url); return result .map(() => undefined) .mapErr(error => ({ type: 'StorageUnavailable', message: error.message, cause: error.cause })); }, getLastUpdated: () => { // This is synchronous, so we'll return current time as fallback return new Date(); } }; // Effect factories for different storage types (legacy compatibility) export const createWorkflowStateEffectsWithConfig = () => WorkflowStateEffects; // Utilities export const ErrorMapping = { mapStorageErrorToWorkflowError }; //# sourceMappingURL=index.js.map