Skip to main content
Glama

Curupira

by drzln
index.ts8.15 kB
/** * Framework integrations index * * Main entry point for all framework integrations */ import type { RuntimeDomain } from '../chrome/domains/runtime.js' import type { DOMDomain } from '../chrome/domains/dom.js' import type { StateInspectionContext, StateSnapshot, ReactRenderInfo, XStateActor, ZustandStoreInfo } from '@curupira/shared/types/state.js' import { ReactIntegration, createReactIntegration } from './react/index.js' import { XStateIntegration, createXStateIntegration } from './xstate/index.js' import { ZustandIntegration, createZustandIntegration } from './zustand/index.js' import { logger } from '../config/logger.js' export interface FrameworkIntegrations { // Individual integrations react: ReactIntegration xstate: XStateIntegration zustand: ZustandIntegration // Combined operations detectAll(): Promise<StateInspectionContext> captureSnapshot(): Promise<StateSnapshot> // Monitoring enableAllMonitoring(): Promise<void> disableAllMonitoring(): Promise<void> } export class FrameworkIntegrationsImpl implements FrameworkIntegrations { public readonly react: ReactIntegration public readonly xstate: XStateIntegration public readonly zustand: ZustandIntegration constructor( runtime: RuntimeDomain, dom: DOMDomain ) { this.react = createReactIntegration(runtime, dom) this.xstate = createXStateIntegration(runtime) this.zustand = createZustandIntegration(runtime) } /** * Detect all frameworks */ async detectAll(): Promise<StateInspectionContext> { const [reactInfo, xstateInfo, zustandInfo] = await Promise.all([ this.react.detect(), this.xstate.detect(), this.zustand.detect() ]) const context: StateInspectionContext = {} // React context if (reactInfo.detected) { const components = await this.react.getComponentTree() context.react = { components: new Map( components.map(c => [c.id, { componentId: c.id, displayName: c.name, type: c.type as 'function' | 'class' | 'memo' | 'forward_ref', interactions: new Set() }]) ) } } // XState context if (xstateInfo.detected) { const actors = await this.xstate.getActors() context.xstate = { actors: new Map( actors.map(a => [a.actor.id, { id: a.actor.id, type: a.machine?.id || 'unknown', machine: a.machine, sessionId: a.actor.sessionId, parent: undefined, children: new Set<XStateActor>(), observers: new Set() } as XStateActor]) ), machines: new Map( xstateInfo.machines?.map(m => [m.id, { id: m.id, states: m.states.reduce((acc, state) => { acc[state] = { key: state } return acc }, {} as any) }]) || [] ), events: [] } } // Zustand context if (zustandInfo.detected) { const stores = await this.zustand.getStores() context.zustand = { stores: new Map( stores.map(s => [s.store.id, { id: s.store.id, name: s.store.name, store: { getState: () => s.state, setState: () => {}, subscribe: () => () => {}, destroy: () => {} }, config: { devtools: { enabled: s.store.config.devtools || false }, persist: s.store.config.persist ? { name: s.store.name } : undefined, immer: s.store.config.immer ? {} : undefined }, subscribers: new Set(), history: s.history } as ZustandStoreInfo]) ) } } return context } /** * Capture a snapshot of all state */ async captureSnapshot(): Promise<StateSnapshot> { const timestamp = Date.now() as any const snapshot: StateSnapshot = { id: `snapshot_${timestamp}` as any, timestamp, react: { components: [], renderCount: 0 }, xstate: { actors: [], eventCount: 0 }, zustand: { stores: [], changeCount: 0 }, apollo: { queries: [], cacheSize: 0, networkRequests: 0 } } // React snapshot if (this.react.isReactDetected()) { const components = await this.react.getComponentTree() const metrics = await this.react.getRenderMetrics() snapshot.react = { components: components.map(c => ({ componentId: c.id, displayName: c.name, type: c.type, interactions: new Set() } as ReactRenderInfo)), renderCount: metrics.renderCount } } // XState snapshot if (this.xstate.isXStateDetected()) { const actors = await this.xstate.getActors() snapshot.xstate = { actors: actors.map(a => ({ id: a.actor.id, type: a.machine?.id || 'unknown', machine: a.machine, sessionId: a.actor.sessionId })), eventCount: actors.reduce((sum, a) => sum + a.eventHistory.length, 0) } } // Zustand snapshot if (this.zustand.isZustandDetected()) { const stores = await this.zustand.getStores() snapshot.zustand = { stores: stores.map(s => ({ id: s.store.id, name: s.store.name, state: s.state })), changeCount: stores.reduce((sum, s) => sum + s.history.length, 0) } } return snapshot } /** * Enable monitoring for all frameworks */ async enableAllMonitoring(): Promise<void> { const promises: Promise<void>[] = [] if (this.react.isReactDetected()) { promises.push( (this.react as any).enablePerformanceMonitoring?.() || Promise.resolve() ) } // XState and Zustand auto-monitor when inspector is installed await Promise.all(promises) logger.info('All framework monitoring enabled') } /** * Disable monitoring for all frameworks */ async disableAllMonitoring(): Promise<void> { const promises: Promise<void>[] = [] if (this.react.isReactDetected()) { promises.push( (this.react as any).disablePerformanceMonitoring?.() || Promise.resolve() ) } await Promise.all(promises) logger.info('All framework monitoring disabled') } /** * Get combined statistics */ async getStatistics(): Promise<{ frameworks: string[] components: number actors: number stores: number totalStateSize: number }> { const frameworks: string[] = [] let components = 0 let actors = 0 let stores = 0 let totalStateSize = 0 if (this.react.isReactDetected()) { frameworks.push('React') const tree = await this.react.getComponentTree() components = tree.length } if (this.xstate.isXStateDetected()) { frameworks.push('XState') const actorList = await this.xstate.getActors() actors = actorList.length // Estimate state size for (const actor of actorList) { totalStateSize += JSON.stringify(actor.snapshot).length } } if (this.zustand.isZustandDetected()) { frameworks.push('Zustand') const storeList = await this.zustand.getStores() stores = storeList.length // Estimate state size for (const store of storeList) { totalStateSize += JSON.stringify(store.state).length } } return { frameworks, components, actors, stores, totalStateSize } } } // Factory function export function createFrameworkIntegrations( runtime: RuntimeDomain, dom: DOMDomain ): FrameworkIntegrations { return new FrameworkIntegrationsImpl(runtime, dom) } // Re-export individual integrations export type { ReactIntegration } from './react/index.js' export type { XStateIntegration } from './xstate/index.js' export type { ZustandIntegration } from './zustand/index.js'

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/drzln/curupira'

If you have feedback or need assistance with the MCP directory API, please join our Discord server