import { Args, RemeshCommandAction, RemeshDomain, RemeshDomainDefinition, RemeshEventAction, Serializable, SerializableObject, } from './remesh' import type { RemeshDomainStorage, RemeshQueryStorage, RemeshStateStorage, RemeshStore, RemeshStoreInspector, RemeshStoreOptions, } from './store' export type RemeshDomainStorageEventData> = { type: 'Domain::Created' | 'Domain::Discarded' | 'Domain::Reused' storage: RemeshDomainStorage } export type RemeshStateStorageEventData = { type: 'State::Created' | 'State::Updated' | 'State::Discarded' | 'State::Reused' storage: RemeshStateStorage } export type RemeshQueryStorageEventData, U> = { type: 'Query::Created' | 'Query::Updated' | 'Query::Discarded' | 'Query::Reused' storage: RemeshQueryStorage } export type RemeshEventEmittedEventData = { type: 'Event::Emitted' action: RemeshEventAction } export type RemeshCommandReceivedEventData = { type: 'Command::Received' action: RemeshCommandAction } export const InspectorType = { DomainCreated: 'Domain::Created', DomainDiscarded: 'Domain::Discarded', DomainReused: 'Domain::Reused', StateCreated: 'State::Created', StateUpdated: 'State::Updated', StateDiscarded: 'State::Discarded', StateReused: 'State::Reused', QueryCreated: 'Query::Created', QueryUpdated: 'Query::Updated', QueryDiscarded: 'Query::Discarded', QueryReused: 'Query::Reused', EventEmitted: 'Event::Emitted', CommandReceived: 'Command::Received', } as const export const RemeshInspectorDomain = RemeshDomain({ name: 'RemeshInspectorDomain', impl: (domain) => { const RemeshDomainStorageEvent = domain.event>({ name: 'RemeshDomainStorageEvent', }) const RemeshDomainStorageCommand = domain.command({ name: 'RemeshDomainStorageCommand', impl: ({}, event: RemeshDomainStorageEventData) => { return RemeshDomainStorageEvent(event) }, }) const RemeshStateStorageEvent = domain.event>({ name: 'RemeshStateStorageEvent', }) const RemeshStateStorageCommand = domain.command({ name: 'RemeshStateStorageCommand', impl: ({}, event: RemeshStateStorageEventData) => { return RemeshStateStorageEvent(event) }, }) const RemeshQueryStorageEvent = domain.event>({ name: 'RemeshQueryStorageEvent', }) const RemeshQueryStorageCommand = domain.command({ name: 'RemeshQueryStorageCommand', impl: ({}, event: RemeshQueryStorageEventData) => { return RemeshQueryStorageEvent(event) }, }) const RemeshEventEmittedEvent = domain.event>({ name: 'RemeshEventEmittedEvent', }) const RemeshEventEmittedCommand = domain.command({ name: 'RemeshEventEmittedCommand', impl: ({}, event: RemeshEventEmittedEventData) => { return RemeshEventEmittedEvent(event) }, }) const RemeshCommandReceivedEvent = domain.event>({ name: 'RemeshCommandReceivedEvent', }) const RemeshCommandReceivedCommand = domain.command({ name: 'RemeshCommandReceivedCommand', impl: ({}, event: RemeshCommandReceivedEventData) => { return RemeshCommandReceivedEvent(event) }, }) return { command: { RemeshDomainStorageCommand, RemeshStateStorageCommand, RemeshQueryStorageCommand, RemeshEventEmittedCommand, RemeshCommandReceivedCommand, }, event: { RemeshDomainStorageEvent, RemeshStateStorageEvent, RemeshQueryStorageEvent, RemeshEventEmittedEvent, RemeshCommandReceivedEvent, }, } }, }) export type InspectInput = { inspectable: boolean owner?: { Domain: { inspectable: boolean } } } export const isInspectable = (input: InspectInput): boolean => { if (input.owner) { return input.owner.Domain.inspectable && input.inspectable } return input.inspectable } const initInspectors = (options: RemeshStoreOptions) => { return (options.inspectors ?? []) .filter((inspector): inspector is RemeshStoreInspector => !!inspector) .map((inspector) => { const { inspectors, ...rest } = options return inspector(rest) }) } export const createInspectorManager = (options: RemeshStoreOptions) => { let inspectors: RemeshStore[] | null = null const getInspectors = (): RemeshStore[] => { if (!inspectors) { inspectors = initInspectors(options) } return inspectors } const destroyInspectors = () => { if (inspectors) { for (const inspector of inspectors) { inspector.discard() } inspectors = null } } const inspectDomainStorage = >( type: RemeshDomainStorageEventData['type'], domainStorage: RemeshDomainStorage, ) => { if (isInspectable(domainStorage.Domain)) { for (const inspector of getInspectors()) { const inspectorDomain = inspector.getDomain(RemeshInspectorDomain()) inspector.send( inspectorDomain.command.RemeshDomainStorageCommand({ type, storage: domainStorage, }), ) } } } const inspectStateStorage = ( type: RemeshStateStorageEventData['type'], stateStorage: RemeshStateStorage, ) => { if (isInspectable(stateStorage.State)) { for (const inspector of getInspectors()) { const inspectorDomain = inspector.getDomain(RemeshInspectorDomain()) inspector.send( inspectorDomain.command.RemeshStateStorageCommand({ type, storage: stateStorage, }), ) } } } const inspectQueryStorage = , U>( type: RemeshQueryStorageEventData['type'], queryStorage: RemeshQueryStorage, ) => { if (isInspectable(queryStorage.Query)) { for (const inspector of getInspectors()) { const inspectorDomain = inspector.getDomain(RemeshInspectorDomain()) inspector.send( inspectorDomain.command.RemeshQueryStorageCommand({ type, storage: queryStorage, }), ) } } } const inspectEventEmitted = ( type: RemeshEventEmittedEventData['type'], eventAction: RemeshEventAction, ) => { if (isInspectable(eventAction.Event)) { for (const inspector of getInspectors()) { const inspectorDomain = inspector.getDomain(RemeshInspectorDomain()) inspector.send( inspectorDomain.command.RemeshEventEmittedCommand({ type, action: eventAction, }), ) } } } const inspectCommandReceived = ( type: RemeshCommandReceivedEventData['type'], commandAction: RemeshCommandAction, ) => { if (isInspectable(commandAction.Command)) { for (const inspector of getInspectors()) { const inspectorDomain = inspector.getDomain(RemeshInspectorDomain()) inspector.send( inspectorDomain.command.RemeshCommandReceivedCommand({ type, action: commandAction, }), ) } } } return { destroyInspectors, inspectDomainStorage, inspectStateStorage, inspectQueryStorage, inspectEventEmitted, inspectCommandReceived, } }