phecda-server 3.1.0 → 3.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -1,12 +1,33 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const [module, dir = ''] = process.argv.slice(2)
1
+ const { exec } = require('child_process')
2
+ const pc = require('picocolors')
3
+ const cmd = process.argv.slice(2)[0]
4
+ let child
5
+ function startChild() {
6
+ child = exec(`node --import phecda-server/register ${cmd}`, {
7
+ env: process.env,
8
+ // cwd: process.cwd(),
9
+ })
10
+ child.stderr.pipe(process.stderr)
11
+ child.stdin.pipe(process.stdin)
12
+ child.stdout.pipe(process.stdout)
4
13
 
5
- const dirPath = path.resolve(process.cwd(), dir, module)
6
- fs.mkdirSync(dirPath)
14
+ child.on('exit', (code) => {
15
+ if (code === 3) {
16
+ log('relunch...')
17
+ return startChild()
18
+ }
7
19
 
8
- fs.writeFileSync(path.resolve(dirPath, `${module}.controller.ts`), `
9
- export class ${module.slice(0).toUpperCase()}${module.slice(1)}Controller{
20
+ process.exit(0)
21
+ })
22
+ }
23
+
24
+ process.on('SIGINT', () => {
25
+ child.kill('SIGINT')
26
+ })
10
27
 
28
+ function log(msg, color = 'green') {
29
+ const date = new Date()
30
+ console.log(`${pc.gray(`${date.getHours()} ${date.getMinutes()} ${date.getSeconds()}`)} ${pc.magenta('[phecda-server]')} ${pc[color](msg)}`)
11
31
  }
12
- `)
32
+
33
+ startChild()
package/dist/index.d.ts CHANGED
@@ -149,7 +149,7 @@ declare namespace P {
149
149
  interface Pipe {
150
150
  transform(args: {
151
151
  arg: any;
152
- option?: boolean;
152
+ option?: any;
153
153
  key: string;
154
154
  type: string;
155
155
  index: number;
@@ -158,7 +158,7 @@ declare namespace P {
158
158
  }
159
159
  }
160
160
 
161
- declare class Phistroy {
161
+ declare class Histroy {
162
162
  guard: string[];
163
163
  interceptor: string[];
164
164
  record(name: string, type: 'guard' | 'interceptor'): boolean;
@@ -171,11 +171,10 @@ declare abstract class Context<Data = any> {
171
171
  params: string[];
172
172
  static metaRecord: Record<string, Meta>;
173
173
  static metaDataRecord: Record<string, ReturnType<typeof parseMeta>>;
174
- static instanceRecord: Record<string, any>;
175
174
  static guardsRecord: Record<string, any>;
176
175
  static interceptorsRecord: Record<string, any>;
177
176
  post: ((...params: any) => any)[];
178
- history: Phistroy;
177
+ history: Histroy;
179
178
  constructor(key: string, data: Data);
180
179
  static registerGuard(key: string, handler: any): void;
181
180
  static registerInterceptor(key: string, handler: any): void;
@@ -185,7 +184,6 @@ declare abstract class Context<Data = any> {
185
184
  }
186
185
  declare function addGuard(key: string, handler: P.Guard): void;
187
186
  declare function addInterceptor(key: string, handler: P.Interceptor): void;
188
- declare function getInstance(tag: string): any;
189
187
  declare function parseMeta(meta: Meta): {
190
188
  guards: string[];
191
189
  reflect: any[];
@@ -202,7 +200,7 @@ declare function parseMeta(meta: Meta): {
202
200
 
203
201
  declare class ServerContext extends Context<ServerCtx | ServerMergeCtx> {
204
202
  static pipe: P.Pipe;
205
- static filter: ServerFilter<any>;
203
+ static filter: ServerFilter;
206
204
  static middlewareRecord: Record<string, (...params: any) => any>;
207
205
  static useMiddleware(middlewares: string[]): ((...params: any) => any)[];
208
206
  usePipe(args: {
@@ -220,21 +218,33 @@ declare function addMiddleware(key: string, handler: RequestHandler): void;
220
218
  declare function useServerPipe(pipe: P.Pipe): void;
221
219
  declare function useServerFilter(filter: ServerFilter): void;
222
220
 
221
+ declare const SERIES_SYMBOL = "__symbol_series__";
222
+ declare const MERGE_SYMBOL = "__symbol_req__";
223
+ declare const UNMOUNT_SYMBOL = "__symbol_unmount__";
224
+
223
225
  declare const emitter: Emitter;
224
- declare const constructorMap: Map<any, any>;
225
- declare function Factory(Modules: (new (...args: any) => any)[]): Promise<{
226
+ declare function Factory(Modules: (new (...args: any) => any)[], opts?: {
227
+ dev?: boolean;
228
+ file?: string;
229
+ }): Promise<{
226
230
  moduleMap: Map<string, any>;
227
231
  meta: Meta[];
228
- output: (p?: string) => void;
232
+ constructorMap: Map<any, any>;
233
+ update: (Module: Construct) => Promise<void>;
229
234
  }>;
235
+ declare class Dev {
236
+ [UNMOUNT_SYMBOL]: (() => void)[];
237
+ onUnmount(cb: () => void): void;
238
+ }
230
239
 
231
240
  interface Options {
241
+ dev?: boolean;
232
242
  route?: string;
233
243
  globalGuards?: string[];
234
244
  globalInterceptors?: string[];
235
245
  middlewares?: string[];
236
246
  }
237
- declare function bindApp(app: Express | Router, { meta, moduleMap }: Awaited<ReturnType<typeof Factory>>, options?: Options): void;
247
+ declare function bindApp(app: Express | Router, { moduleMap, meta }: Awaited<ReturnType<typeof Factory>>, options?: Options): void;
238
248
 
239
249
  declare function BaseParam(type: string, key: string, option?: any): any;
240
250
  declare function Body(key?: string, pipeOpts?: any): any;
@@ -260,7 +270,4 @@ declare const defaultPipe: P.Pipe;
260
270
  declare function isMerge(data: ServerCtx | ServerMergeCtx): data is ServerMergeCtx;
261
271
  declare function resolveDep(ret: any, key: string): any;
262
272
 
263
- declare const SERIES_SYMBOL = "__symbol_series__";
264
- declare const MERGE_SYMBOL = "__symbol_req__";
265
-
266
- export { BadGatewayException, BadRequestException, Base, BaseError, BaseParam, Body, ConflictException, Construct, Context, Controller, Define, Delete, Emitter, Factory, ForbiddenException, FrameworkException, Get, Guard, Header, HttpException, Interceptor, InvalidInputException, MERGE_SYMBOL, MergeType, Meta, Middle, NotFoundException, Options, P, Param, Patch, PayloadLargeException, Post, Put, Query, RequestType, Route, SERIES_SYMBOL, ServerContext, ServerCtx, ServerFilter, ServerMergeCtx, ServiceUnavailableException, TimeoutException, UnauthorizedException, UndefinedException, UnsupportedMediaTypeException, ValidateException, addGuard, addInterceptor, addMiddleware, bindApp, constructorMap, defaultPipe, emitter, getInstance, isMerge, parseMeta, resolveDep, useServerFilter, useServerPipe };
273
+ export { BadGatewayException, BadRequestException, Base, BaseError, BaseParam, Body, ConflictException, Construct, Context, Controller, Define, Delete, Dev, Emitter, Factory, ForbiddenException, FrameworkException, Get, Guard, Header, HttpException, Interceptor, InvalidInputException, MERGE_SYMBOL, MergeType, Meta, Middle, NotFoundException, Options, P, Param, Patch, PayloadLargeException, Post, Put, Query, RequestType, Route, SERIES_SYMBOL, ServerContext, ServerCtx, ServerFilter, ServerMergeCtx, ServiceUnavailableException, TimeoutException, UNMOUNT_SYMBOL, UnauthorizedException, UndefinedException, UnsupportedMediaTypeException, ValidateException, addGuard, addInterceptor, addMiddleware, bindApp, defaultPipe, emitter, isMerge, parseMeta, resolveDep, useServerFilter, useServerPipe };
package/dist/index.js CHANGED
@@ -43,6 +43,7 @@ __export(src_exports, {
43
43
  Controller: () => Controller,
44
44
  Define: () => Define,
45
45
  Delete: () => Delete,
46
+ Dev: () => Dev,
46
47
  Factory: () => Factory,
47
48
  ForbiddenException: () => ForbiddenException,
48
49
  FrameworkException: () => FrameworkException,
@@ -67,6 +68,7 @@ __export(src_exports, {
67
68
  ServerContext: () => ServerContext,
68
69
  ServiceUnavailableException: () => ServiceUnavailableException,
69
70
  TimeoutException: () => TimeoutException,
71
+ UNMOUNT_SYMBOL: () => UNMOUNT_SYMBOL,
70
72
  UnauthorizedException: () => UnauthorizedException,
71
73
  UndefinedException: () => UndefinedException,
72
74
  UnsupportedMediaTypeException: () => UnsupportedMediaTypeException,
@@ -75,10 +77,8 @@ __export(src_exports, {
75
77
  addInterceptor: () => addInterceptor,
76
78
  addMiddleware: () => addMiddleware,
77
79
  bindApp: () => bindApp,
78
- constructorMap: () => constructorMap,
79
80
  defaultPipe: () => defaultPipe,
80
81
  emitter: () => emitter,
81
- getInstance: () => getInstance,
82
82
  isMerge: () => isMerge,
83
83
  parseMeta: () => parseMeta,
84
84
  resolveDep: () => resolveDep,
@@ -270,7 +270,7 @@ var serverFilter = /* @__PURE__ */ __name((e) => {
270
270
  }, "serverFilter");
271
271
 
272
272
  // src/history.ts
273
- var Phistroy = class {
273
+ var Histroy = class {
274
274
  guard = [];
275
275
  interceptor = [];
276
276
  record(name, type) {
@@ -281,7 +281,7 @@ var Phistroy = class {
281
281
  return false;
282
282
  }
283
283
  };
284
- __name(Phistroy, "Phistroy");
284
+ __name(Histroy, "Histroy");
285
285
 
286
286
  // src/utils.ts
287
287
  var import_picocolors = __toESM(require("picocolors"));
@@ -304,7 +304,7 @@ var _Context = class {
304
304
  constructor(key, data) {
305
305
  this.key = key;
306
306
  this.data = data;
307
- this.history = new Phistroy();
307
+ this.history = new Histroy();
308
308
  }
309
309
  static registerGuard(key, handler) {
310
310
  _Context.guardsRecord[key] = handler;
@@ -347,7 +347,6 @@ var Context = _Context;
347
347
  __name(Context, "Context");
348
348
  __publicField(Context, "metaRecord", {});
349
349
  __publicField(Context, "metaDataRecord", {});
350
- __publicField(Context, "instanceRecord", {});
351
350
  __publicField(Context, "guardsRecord", {});
352
351
  __publicField(Context, "interceptorsRecord", {});
353
352
  function addGuard(key, handler) {
@@ -358,10 +357,6 @@ function addInterceptor(key, handler) {
358
357
  Context.registerInterceptor(key, handler);
359
358
  }
360
359
  __name(addInterceptor, "addInterceptor");
361
- function getInstance(tag) {
362
- return Context.instanceRecord[tag];
363
- }
364
- __name(getInstance, "getInstance");
365
360
  function parseMeta(meta) {
366
361
  const { data: { params, guards, interceptors, middlewares }, reflect, handlers } = meta;
367
362
  params.forEach(({ index, key }, i) => {
@@ -437,17 +432,17 @@ __name(resolveDep, "resolveDep");
437
432
  // src/common.ts
438
433
  var SERIES_SYMBOL = "__symbol_series__";
439
434
  var MERGE_SYMBOL = "__symbol_req__";
435
+ var UNMOUNT_SYMBOL = "__symbol_unmount__";
440
436
 
441
437
  // src/server/express.ts
442
- function bindApp(app, { meta, moduleMap }, options = {}) {
443
- const { globalGuards, globalInterceptors, route, middlewares: proMiddle } = {
438
+ function bindApp(app, { moduleMap, meta }, options = {}) {
439
+ const { dev = process.env.NODE_ENV !== "production", globalGuards, globalInterceptors, route, middlewares: proMiddle } = {
444
440
  route: "/__PHECDA_SERVER__",
445
441
  globalGuards: [],
446
442
  globalInterceptors: [],
447
443
  middlewares: [],
448
444
  ...options
449
445
  };
450
- const methodMap = {};
451
446
  const contextMeta = {};
452
447
  app.post(route, (req, _res, next) => {
453
448
  req[MERGE_SYMBOL] = true;
@@ -489,7 +484,7 @@ function bindApp(app, { meta, moduleMap }, options = {}) {
489
484
  if (category === "series") {
490
485
  for (const item of data) {
491
486
  const { tag } = item;
492
- const [name] = tag.split("-");
487
+ const [name, method] = tag.split("-");
493
488
  const { reflect, params } = Context.metaDataRecord[tag];
494
489
  const instance = moduleMap.get(name);
495
490
  try {
@@ -518,7 +513,7 @@ function bindApp(app, { meta, moduleMap }, options = {}) {
518
513
  };
519
514
  }), tag);
520
515
  instance.context = contextData;
521
- ret.push(await methodMap[tag](...args));
516
+ ret.push(await moduleMap.get(name)[method](...args));
522
517
  } catch (e) {
523
518
  const m = Context.metaRecord[tag];
524
519
  m.handlers.forEach((handler) => handler.error?.(e));
@@ -531,7 +526,7 @@ function bindApp(app, { meta, moduleMap }, options = {}) {
531
526
  return Promise.all(data.map((item) => {
532
527
  return new Promise(async (resolve) => {
533
528
  const { tag } = item;
534
- const [name] = tag.split("-");
529
+ const [name, method] = tag.split("-");
535
530
  const { reflect, params, handlers } = Context.metaDataRecord[tag];
536
531
  const instance = moduleMap.get(name);
537
532
  try {
@@ -549,7 +544,7 @@ function bindApp(app, { meta, moduleMap }, options = {}) {
549
544
  };
550
545
  }), tag);
551
546
  instance.context = contextData;
552
- resolve(await methodMap[tag](...args));
547
+ resolve(await moduleMap.get(name)[method](...args));
553
548
  } catch (e) {
554
549
  handlers.forEach((handler) => handler.error?.(e));
555
550
  resolve(await context.useFilter(e));
@@ -564,62 +559,72 @@ function bindApp(app, { meta, moduleMap }, options = {}) {
564
559
  res.status(err.status).json(err);
565
560
  }
566
561
  });
567
- for (const i of meta) {
568
- const { name, method, route: route2, header, tag } = i.data;
569
- const instance = moduleMap.get(tag);
570
- const methodTag = `${tag}-${method}`;
571
- contextMeta[methodTag] = i;
572
- Context.metaRecord[methodTag] = i;
573
- let { guards, reflect, interceptors, params, handlers, middlewares } = Context.metaDataRecord[methodTag] ? Context.metaDataRecord[methodTag] : Context.metaDataRecord[methodTag] = parseMeta(i);
574
- guards = [
575
- ...globalGuards,
576
- ...guards
577
- ];
578
- interceptors = [
579
- ...globalInterceptors,
580
- ...interceptors
581
- ];
582
- const handler = instance[method].bind(instance);
583
- methodMap[methodTag] = handler;
584
- Context.instanceRecord[name] = instance;
585
- if (route2) {
586
- app[route2.type](route2.route, ...ServerContext.useMiddleware(middlewares), async (req, res) => {
587
- const contextData = {
588
- request: req,
589
- meta: i,
590
- response: res,
591
- moduleMap
592
- };
593
- const context = new ServerContext(methodTag, contextData);
594
- try {
595
- for (const name2 in header)
596
- res.set(name2, header[name2]);
597
- await context.useGuard(guards);
598
- await context.useInterceptor(interceptors);
599
- const args = await context.usePipe(params.map(({ type, key, option, index }) => {
600
- return {
601
- arg: resolveDep(req[type], key),
602
- option,
603
- key,
604
- type,
605
- index,
606
- reflect: reflect[index]
607
- };
608
- }), methodTag);
609
- instance.context = contextData;
610
- const ret = await context.usePost(await handler(...args));
611
- if (isObject(ret))
612
- res.json(ret);
613
- else
614
- res.send(String(ret));
615
- } catch (e) {
616
- handlers.forEach((handler2) => handler2.error?.(e));
617
- const err = await context.useFilter(e);
618
- res.status(err.status).json(err);
619
- }
620
- });
562
+ async function createRoute() {
563
+ for (const i of meta) {
564
+ const { method, route: route2, header, tag } = i.data;
565
+ const methodTag = `${tag}-${method}`;
566
+ contextMeta[methodTag] = i;
567
+ Context.metaRecord[methodTag] = i;
568
+ let { guards, reflect, interceptors, params, handlers, middlewares } = Context.metaDataRecord[methodTag] ? Context.metaDataRecord[methodTag] : Context.metaDataRecord[methodTag] = parseMeta(i);
569
+ guards = [
570
+ ...globalGuards,
571
+ ...guards
572
+ ];
573
+ interceptors = [
574
+ ...globalInterceptors,
575
+ ...interceptors
576
+ ];
577
+ if (route2) {
578
+ app[route2.type](route2.route, ...ServerContext.useMiddleware(middlewares), async (req, res) => {
579
+ const instance = moduleMap.get(tag);
580
+ const contextData = {
581
+ request: req,
582
+ meta: i,
583
+ response: res,
584
+ moduleMap
585
+ };
586
+ const context = new ServerContext(methodTag, contextData);
587
+ try {
588
+ for (const name in header)
589
+ res.set(name, header[name]);
590
+ await context.useGuard(guards);
591
+ await context.useInterceptor(interceptors);
592
+ const args = await context.usePipe(params.map(({ type, key, option, index }) => {
593
+ return {
594
+ arg: resolveDep(req[type], key),
595
+ option,
596
+ key,
597
+ type,
598
+ index,
599
+ reflect: reflect[index]
600
+ };
601
+ }), methodTag);
602
+ instance.context = contextData;
603
+ const ret = await context.usePost(await instance[method](...args));
604
+ if (isObject(ret))
605
+ res.json(ret);
606
+ else
607
+ res.send(String(ret));
608
+ } catch (e) {
609
+ handlers.forEach((handler) => handler.error?.(e));
610
+ const err = await context.useFilter(e);
611
+ res.status(err.status).json(err);
612
+ }
613
+ });
614
+ }
621
615
  }
622
616
  }
617
+ __name(createRoute, "createRoute");
618
+ createRoute();
619
+ if (dev) {
620
+ const rawMetaHmr = globalThis.__PHECDA_SERVER_META__;
621
+ globalThis.__PHECDA_SERVER_META__ = () => {
622
+ app.stack = app.stack.slice(0, 1);
623
+ Context.metaDataRecord = {};
624
+ createRoute();
625
+ rawMetaHmr?.();
626
+ };
627
+ }
623
628
  }
624
629
  __name(bindApp, "bindApp");
625
630
 
@@ -628,6 +633,7 @@ var import_reflect_metadata = require("reflect-metadata");
628
633
  var import_fs = __toESM(require("fs"));
629
634
  var import_node_events = __toESM(require("events"));
630
635
  var import_phecda_core2 = require("phecda-core");
636
+ var import_debug = __toESM(require("debug"));
631
637
 
632
638
  // src/meta.ts
633
639
  var Meta = class {
@@ -643,11 +649,14 @@ var Meta = class {
643
649
  __name(Meta, "Meta");
644
650
 
645
651
  // src/core.ts
652
+ var debug = (0, import_debug.default)("phecda-server");
646
653
  var emitter = new import_node_events.default();
647
- var constructorMap = /* @__PURE__ */ new Map();
648
- async function Factory(Modules) {
654
+ async function Factory(Modules, opts = {}) {
649
655
  const moduleMap = /* @__PURE__ */ new Map();
650
656
  const meta = [];
657
+ const constructorMap = /* @__PURE__ */ new Map();
658
+ const moduleGraph = /* @__PURE__ */ new WeakMap();
659
+ const { dev = process.env.NODE_ENV === "development", file = "pmeta.js" } = opts;
651
660
  (0, import_phecda_core2.injectProperty)("watcher", ({ eventName, instance, key, options }) => {
652
661
  const fn = typeof instance[key] === "function" ? instance[key].bind(instance) : (v) => instance[key] = v;
653
662
  if (options?.once)
@@ -655,45 +664,94 @@ async function Factory(Modules) {
655
664
  else
656
665
  emitter.on(eventName, fn);
657
666
  });
667
+ async function update(Module) {
668
+ const tag = Module.prototype?.__TAG__ || Module.name;
669
+ if (!moduleMap.has(tag))
670
+ return;
671
+ debug(`update module "${tag}"`);
672
+ const instance = moduleMap.get(tag);
673
+ if (instance?.[UNMOUNT_SYMBOL]) {
674
+ for (const cb of instance[UNMOUNT_SYMBOL])
675
+ await cb();
676
+ }
677
+ moduleMap.delete(tag);
678
+ constructorMap.delete(tag);
679
+ for (let i = meta.length - 1; i >= 0; i--) {
680
+ if (meta[i].data.tag === tag)
681
+ meta.splice(i, 1);
682
+ }
683
+ const newModule = await buildNestModule(Module, moduleMap);
684
+ moduleGraph.get(instance)?.forEach((module2) => {
685
+ for (const key in module2) {
686
+ if (module2[key] === instance)
687
+ module2[key] = newModule;
688
+ }
689
+ });
690
+ moduleGraph.get(instance);
691
+ moduleMap.set(tag, newModule);
692
+ }
693
+ __name(update, "update");
694
+ async function buildNestModule(Module, map) {
695
+ const paramtypes = getParamtypes(Module);
696
+ let instance;
697
+ const tag = Module.prototype?.__TAG__ || Module.name;
698
+ if (map.has(tag)) {
699
+ instance = map.get(tag);
700
+ if (!instance)
701
+ throw new Error(`exist Circular-Dependency or Multiple modules with the same name/tag [tag] ${tag}--[module] ${Module}`);
702
+ if (constructorMap.get(tag) !== Module)
703
+ warn(`Synonym module: Module taged "${tag}" has been loaded before, so phecda-server won't load Module "${Module.name}"`);
704
+ return instance;
705
+ }
706
+ map.set(tag, void 0);
707
+ if (paramtypes) {
708
+ const paramtypesInstances = [];
709
+ for (const i in paramtypes)
710
+ paramtypesInstances[i] = await buildNestModule(paramtypes[i], map);
711
+ instance = new Module(...paramtypesInstances);
712
+ for (const i of paramtypesInstances) {
713
+ if (!moduleGraph.has(i))
714
+ moduleGraph.set(i, []);
715
+ moduleGraph.get(i).push(instance);
716
+ }
717
+ } else {
718
+ instance = new Module();
719
+ }
720
+ meta.push(...getMetaFromInstance(instance, tag, Module.name));
721
+ await (0, import_phecda_core2.registerAsync)(instance);
722
+ map.set(tag, instance);
723
+ constructorMap.set(tag, Module);
724
+ return instance;
725
+ }
726
+ __name(buildNestModule, "buildNestModule");
658
727
  for (const Module of Modules)
659
- await buildNestModule(Module, moduleMap, meta);
660
- constructorMap.clear();
728
+ await buildNestModule(Module, moduleMap);
729
+ function writeMeta() {
730
+ debug("write metadata");
731
+ import_fs.default.promises.writeFile(file, JSON.stringify(meta.map((item) => item.data)));
732
+ }
733
+ __name(writeMeta, "writeMeta");
734
+ writeMeta();
735
+ if (dev) {
736
+ globalThis.__PHECDA_SERVER_HMR__ = async (file2) => {
737
+ debug(`reload file ${file2}`);
738
+ const module2 = await import(file2);
739
+ for (const i in module2) {
740
+ if ((0, import_phecda_core2.isPhecda)(module2[i]))
741
+ await update(module2[i]);
742
+ }
743
+ };
744
+ globalThis.__PHECDA_SERVER_META__ = writeMeta;
745
+ }
661
746
  return {
662
747
  moduleMap,
663
748
  meta,
664
- output: (p = "pmeta.js") => import_fs.default.writeFileSync(p, JSON.stringify(meta.map((item) => item.data)))
749
+ constructorMap,
750
+ update
665
751
  };
666
752
  }
667
753
  __name(Factory, "Factory");
668
- async function buildNestModule(Module, map, meta) {
669
- const paramtypes = getParamtypes(Module);
670
- let instance;
671
- const tag = Module.prototype?.__TAG__ || Module.name;
672
- if (map.has(tag)) {
673
- instance = map.get(tag);
674
- if (!instance)
675
- throw new Error(`exist Circular-Dependency or Multiple modules with the same name/tag [tag] ${tag}--[module] ${Module}`);
676
- if (constructorMap.get(tag) !== Module)
677
- warn(`Synonym module: Module taged "${tag}" has been loaded before, so phecda-server won't load Module "${Module.name}"`);
678
- return instance;
679
- }
680
- map.set(tag, void 0);
681
- if (paramtypes) {
682
- const paramtypesInstances = [];
683
- for (const i in paramtypes)
684
- paramtypesInstances[i] = await buildNestModule(paramtypes[i], map, meta);
685
- instance = new Module(...paramtypesInstances);
686
- } else {
687
- instance = new Module();
688
- }
689
- meta.push(...getMetaFromInstance(instance, Module.name, tag));
690
- await (0, import_phecda_core2.registerAsync)(instance);
691
- map.set(tag, instance);
692
- constructorMap.set(tag, Module);
693
- return instance;
694
- }
695
- __name(buildNestModule, "buildNestModule");
696
- function getMetaFromInstance(instance, name, tag) {
754
+ function getMetaFromInstance(instance, tag, name) {
697
755
  const vars = (0, import_phecda_core2.getExposeKey)(instance).filter((item) => item !== "__CLASS");
698
756
  const baseState = (0, import_phecda_core2.getState)(instance, "__CLASS") || {};
699
757
  initState(baseState);
@@ -764,6 +822,13 @@ function initState(state) {
764
822
  state.interceptors = [];
765
823
  }
766
824
  __name(initState, "initState");
825
+ var Dev = class {
826
+ [UNMOUNT_SYMBOL] = [];
827
+ onUnmount(cb) {
828
+ this[UNMOUNT_SYMBOL].push(cb);
829
+ }
830
+ };
831
+ __name(Dev, "Dev");
767
832
 
768
833
  // src/decorators/index.ts
769
834
  var import_phecda_core5 = require("phecda-core");
@@ -925,6 +990,7 @@ __reExport(src_exports, require("phecda-core"), module.exports);
925
990
  Controller,
926
991
  Define,
927
992
  Delete,
993
+ Dev,
928
994
  Factory,
929
995
  ForbiddenException,
930
996
  FrameworkException,
@@ -949,6 +1015,7 @@ __reExport(src_exports, require("phecda-core"), module.exports);
949
1015
  ServerContext,
950
1016
  ServiceUnavailableException,
951
1017
  TimeoutException,
1018
+ UNMOUNT_SYMBOL,
952
1019
  UnauthorizedException,
953
1020
  UndefinedException,
954
1021
  UnsupportedMediaTypeException,
@@ -957,10 +1024,8 @@ __reExport(src_exports, require("phecda-core"), module.exports);
957
1024
  addInterceptor,
958
1025
  addMiddleware,
959
1026
  bindApp,
960
- constructorMap,
961
1027
  defaultPipe,
962
1028
  emitter,
963
- getInstance,
964
1029
  isMerge,
965
1030
  parseMeta,
966
1031
  resolveDep,