UNPKG

@deepkit/framework

Version:

446 lines 20.7 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; const __ΩPick = ['T', 'K', 'Pick', 'l+e#!e"!fRb!b"Pde""N#!w#y']; function __assignType(fn, args) { fn.__type = args; return fn; } /* * Deepkit Framework * Copyright (C) 2021 Deepkit UG, Marc J. Schmidt * * This program is free software: you can redistribute it and/or modify * it under the terms of the MIT License. * * You should have received a copy of the MIT License along with this program. */ import { Config, Database, DebugControllerInterface, DebugRequest, decodeFrameData, decodeFrames, deserializeFrameData, Event, Filesystem, ModuleApi, ModuleImportedService, ModuleService, Route, RpcAction, RpcActionParameter, Workflow, } from '@deepkit/framework-debug-api'; import { rpc, rpcClass } from '@deepkit/rpc'; import { HttpRouter, parseRouteControllerAction } from '@deepkit/http'; import { changeClass, getClassName, isClass } from '@deepkit/core'; import { EventDispatcher, isEventListenerContainerEntryService } from '@deepkit/event'; import { DatabaseRegistry } from '@deepkit/orm'; import { existsSync, readFileSync, statSync, truncateSync } from 'fs'; import { join } from 'path'; import { FrameworkConfig } from '../module.config.js'; import { FileStopwatchStore } from './stopwatch/store.js'; import { Subject } from 'rxjs'; import { unlink } from 'fs/promises'; import { getScope, resolveToken } from '@deepkit/injector'; import { AppModule, ServiceContainer } from '@deepkit/app'; import { RpcControllers } from '../rpc.js'; import { isType, ReflectionClass, serializeType, stringifyType } from '@deepkit/type'; import { FilesystemRegistry } from '../filesystem.js'; import { FrameCategory, FrameType } from '@deepkit/stopwatch'; let DebugController = class DebugController { constructor(serviceContainer, eventDispatcher, router, config, rpcControllers, databaseRegistry, filesystemRegistry, stopwatchStore) { this.serviceContainer = serviceContainer; this.eventDispatcher = eventDispatcher; this.router = router; this.config = config; this.rpcControllers = rpcControllers; this.databaseRegistry = databaseRegistry; this.filesystemRegistry = filesystemRegistry; this.stopwatchStore = stopwatchStore; this.reservedTokenIds = (Map.Ω = [['Token', '"w!'], ['\'']], new Map()); this.idToTokenMap = (Map.Ω = [['\''], ['Token', '"w!']], new Map()); } async subscribeStopwatchFramesData() { if (!this.stopwatchStore || !this.stopwatchStore.frameDataChannel) throw new Error('not enabled'); const subject = (Subject.Ω = [['W']], new Subject()); const close = await this.stopwatchStore.frameDataChannel.subscribe(__assignType((v) => { subject.next(v); }, ['v', '', 'P"2!"/"'])); subject.subscribe().add(() => { close(); }); return subject; } async subscribeStopwatchFrames() { if (!this.stopwatchStore || !this.stopwatchStore.frameChannel) throw new Error('not enabled'); const subject = (Subject.Ω = [['W']], new Subject()); const close = await this.stopwatchStore.frameChannel.subscribe(__assignType((v) => { subject.next(v); }, ['v', '', 'P"2!"/"'])); subject.subscribe().add(() => { close(); }); return subject; } resetProfilerFrames() { const path = join(this.config.varPath, this.config.debugStorePath); unlink(join(path, 'frames.bin')).catch(); unlink(join(path, 'frames-data.bin')).catch(); } getProfilerFrames() { const framesPath = join(this.config.varPath, this.config.debugStorePath, 'frames.bin'); const frameDataPath = join(this.config.varPath, this.config.debugStorePath, 'frames-data.bin'); const analyticsPath = join(this.config.varPath, this.config.debugStorePath, 'analytics.bin'); for (const file of [framesPath, frameDataPath, analyticsPath]) { try { const stat = statSync(file); if (stat.size > 1000000) { //make sure that file is not too big truncateSync(file); } } catch { } } return [ existsSync(framesPath) ? readFileSync(framesPath) : new Uint8Array(), existsSync(frameDataPath) ? readFileSync(frameDataPath) : new Uint8Array(), existsSync(frameDataPath) ? readFileSync(frameDataPath) : new Uint8Array(), ]; } getFrames() { const framesPath = join(this.config.varPath, this.config.debugStorePath, 'frames.bin'); return readFileSync(framesPath); } getFramesData() { const frameDataPath = join(this.config.varPath, this.config.debugStorePath, 'frames-data.bin'); return readFileSync(frameDataPath); } httpRequests() { const requests = {}; decodeFrames(this.getFrames(), __assignType((frame) => { if (frame.type === FrameType.start) { if (frame.category !== FrameCategory.http) return; requests[frame.cid] = new DebugRequest(frame.cid, frame.timestamp, '', '', ''); } else if (frame.type === FrameType.end) { const r = requests[frame.cid]; if (!r) return; r.ended = frame.timestamp; } }, ['frame', '', 'P"2!"/"'])); decodeFrameData(this.getFramesData(), __assignType((frame) => { const r = requests[frame.cid]; if (!r) return; const data = deserializeFrameData(frame); if (data.clientIp) r.clientIp = data.clientIp; if (data.method) r.method = data.method; if (data.url) r.url = data.url; if (data.responseStatus) r.statusCode = data.responseStatus; }, ['frame', '', 'P"2!"/"'])); return Object.values(requests); } databases() { if (!this.databaseRegistry) return []; const databases = []; for (const db of this.databaseRegistry.getDatabases()) { const entities = []; for (const classSchema of db.entityRegistry.all()) { entities.push({ name: classSchema.name, className: classSchema.getClassName() }); } databases.push({ name: db.name, entities, adapter: db.adapter.getName() }); } return databases; } filesystems() { const filesystems = []; for (const fs of this.filesystemRegistry.getFilesystems()) { filesystems.push({ name: getClassName(fs), adapter: getClassName(fs.adapter), options: {} }); } return filesystems; } events() { const events = []; for (const token of this.eventDispatcher.getTokens()) { const listeners = this.eventDispatcher.getListeners(token); for (const listener of listeners) { if (isEventListenerContainerEntryService(listener)) { events.push({ event: token.id, controller: getClassName(listener.classType), methodName: listener.methodName, priority: listener.order, }); } } } return events; } routes() { const routes = []; for (const route of this.router.getRoutes()) { const routeD = { path: route.getFullPath(), httpMethods: route.httpMethods, parameters: [], groups: route.groups, category: route.category, controller: route.action.type === 'controller' ? getClassName(route.action.controller) + '.' + route.action.methodName : route.action.fn.name, description: route.description, }; const parsedRoute = parseRouteControllerAction(route); const queryParameters = []; for (const parameter of parsedRoute.getParameters()) { if (parameter.body || parameter.bodyValidation) { routeD.bodyType = stringifyType(parameter.getType()); } else if (parameter.query) { routeD.parameters.push({ name: parameter.getName(), type: 'query', stringType: stringifyType(parameter.parameter.parameter), }); queryParameters.push(`${parameter.getName()}=TODO`); // queryParameters.push(`${parameter.getName()}=${stringifyType(parameter.parameter.type)}`); } else if (parameter.isPartOfPath()) { routeD.parameters.push({ name: parameter.getName(), type: 'url', stringType: stringifyType(parameter.parameter.parameter), }); } else { //its a dependency injection token } } if (queryParameters.length) { routeD.path += '?' + queryParameters.join('&'); } routes.push(routeD); } return routes; } configuration() { const appConfig = []; if (this.serviceContainer.appModule.configDefinition) { const schema = ReflectionClass.from(this.serviceContainer.appModule.configDefinition); for (const [name, value] of Object.entries(this.serviceContainer.appModule.getConfig())) { const property = schema.getProperty(name); appConfig.push({ name: name, value: value, defaultValue: property.getDefaultValue(), description: property.getDescription(), type: stringifyType(property.property), }); } } const modulesConfig = []; for (const module of this.serviceContainer.appModule.getImports()) { if (!module.configDefinition) continue; const schema = ReflectionClass.from(module.configDefinition); for (const [name, value] of Object.entries(module.getConfig())) { const property = schema.getProperty(name); modulesConfig.push({ name: module.getName() + '.' + name, value: value, defaultValue: property.getDefaultValue(), description: property.getDescription(), type: stringifyType(property.property), }); } } return changeClass({ appConfig, modulesConfig, }, Config); } actions() { const result = []; for (const { controller } of this.rpcControllers.controllers.values()) { const rpcConfig = rpcClass._fetch(controller); if (!rpcConfig) continue; for (const action of rpcConfig.actions.values()) { const parameters = []; for (const parameter of ReflectionClass.from(controller).getMethodParameters(action.name || '')) { parameters.push(new RpcActionParameter(parameter.name, stringifyType(parameter.parameter))); } result.push({ path: rpcConfig.getPath(), controller: getClassName(controller), methodName: action.name || '', parameters: parameters, }); } } return result; } getWorkflow(name) { const w = this.serviceContainer.workflowRegistry.get(name); return changeClass({ places: Object.keys(w.places), transitions: w.transitions, }, Workflow); } // @rpc.action() // httpRequests(): Promise<Collection<DebugRequest>> { // return this.liveDatabase.query(DebugRequest).find(); // } modules() { const injectorContext = this.serviceContainer.getInjectorContext(); const getTokenId = __assignType((token) => { const found = this.reservedTokenIds.get(token); if (found === undefined) { const id = this.reservedTokenIds.size; this.idToTokenMap.set(id, token); this.reservedTokenIds.set(token, id); return id; } return found; }, ['Token', 'token', '', 'P"w!2"\'/#']); function getTokenLabel(token) { if (isClass(token)) return getClassName(token); if (isType(token)) return stringifyType(token); return String(token); } getTokenLabel.__type = ['Token', 'token', 'getTokenLabel', 'P"w!2"&/#']; function extract(module) { const moduleApi = new ModuleApi(module.name, module.id, getClassName(module)); moduleApi.config = module.getConfig(); if (module.configDefinition) { moduleApi.configSchemas = serializeType(ReflectionClass.from(module.configDefinition).type); } for (const provider of module.getProviders()) { const token = resolveToken(provider); const service = new ModuleService(getTokenId(token), getTokenLabel(token)); service.scope = getScope(provider); service.instantiations = injectorContext.instantiationCount(token, module, service.scope); if (isClass(token) && module.controllers.includes(token)) { service.type = 'controller'; } else if (isClass(token) && module.listeners.includes(token)) { service.type = 'listener'; } moduleApi.services.push(service); service.exported = module.isExported(token); service.forRoot = module.root; } const builtPreparedProviders = module.getBuiltPreparedProviders(); if (builtPreparedProviders) { for (const preparedProvider of builtPreparedProviders) { const token = preparedProvider.token; //We want to know which token has been imported by whom if (preparedProvider.modules[0] !== module) { //was imported from originally preparedProvider.modules[0] moduleApi.importedServices.push(new ModuleImportedService(getTokenId(token), getTokenLabel(token), getClassName(preparedProvider.modules[0]))); } else if (preparedProvider.modules.length > 1) { //was imported and overwritten by this module moduleApi.importedServices.push(new ModuleImportedService(getTokenId(token), getTokenLabel(token), getClassName(preparedProvider.modules[1]))); } } } for (const m of module.getImports()) { moduleApi.imports.push(extract(m)); } return moduleApi; } extract.__type = [() => AppModule, 'module', () => ModuleApi, 'extract', 'PP"7!2"P7#/$']; return extract(this.serviceContainer.appModule); } }; DebugController.__type = ['reservedTokenIds', function () { return (Map.Ω = [['Token', '"w!'], ['\'']], new Map()); }, 'idToTokenMap', function () { return (Map.Ω = [['\''], ['Token', '"w!']], new Map()); }, () => ServiceContainer, 'serviceContainer', () => EventDispatcher, 'eventDispatcher', () => HttpRouter, 'router', () => __ΩPick, () => FrameworkConfig, "varPath", "debugStorePath", 'config', () => RpcControllers, 'rpcControllers', () => DatabaseRegistry, 'databaseRegistry', () => FilesystemRegistry, 'filesystemRegistry', () => FileStopwatchStore, 'stopwatchStore', 'constructor', () => Subject, 'subscribeStopwatchFramesData', () => Subject, 'subscribeStopwatchFrames', 'resetProfilerFrames', 'getProfilerFrames', 'getFrames', 'getFramesData', () => DebugRequest, 'httpRequests', () => Database, 'databases', () => Filesystem, 'filesystems', () => Event, 'events', () => Route, 'routes', () => Config, 'configuration', () => RpcAction, 'actions', 'name', () => Workflow, 'getWorkflow', () => ModuleApi, 'modules', 'DebugController', '!3!<>"!3#<>$PP7%2&<P7\'2(<P7)2*<P7,P.-..Jo+#2/<P7021<P7223<P7425<P76278<"08PPW79`0:PPW7;`0<P$0=PPWWWG0>P"0?<P"0@<PP7AF0BPP7CF0DPP7EF0FPP7GF0HPP7IF0JPP7K0LPP7MF0NP&2OP7P0QPP7R0S5!x"wT']; __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], DebugController.prototype, "subscribeStopwatchFramesData", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], DebugController.prototype, "subscribeStopwatchFrames", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], DebugController.prototype, "resetProfilerFrames", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "getProfilerFrames", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "httpRequests", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "databases", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "filesystems", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "events", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "routes", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Config) ], DebugController.prototype, "configuration", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], DebugController.prototype, "actions", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Workflow) ], DebugController.prototype, "getWorkflow", null); __decorate([ rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", ModuleApi) ], DebugController.prototype, "modules", null); DebugController = __decorate([ rpc.controller(DebugControllerInterface), __metadata("design:paramtypes", [ServiceContainer, EventDispatcher, HttpRouter, Object, RpcControllers, DatabaseRegistry, FilesystemRegistry, FileStopwatchStore]) ], DebugController); export { DebugController }; //# sourceMappingURL=debug.controller.js.map