@angelitosystems/nest-devtools 1.0.13 → 1.0.15
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/dist/index.cjs +178 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +177 -57
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -621,12 +621,29 @@ var PerformanceInstrumentation = class {
|
|
|
621
621
|
};
|
|
622
622
|
|
|
623
623
|
// src/instrumentation/app-explorer.ts
|
|
624
|
+
var import_module = require("module");
|
|
625
|
+
var import_meta = {};
|
|
626
|
+
var safeRequire = (() => {
|
|
627
|
+
try {
|
|
628
|
+
return (0, import_module.createRequire)(import_meta.url);
|
|
629
|
+
} catch {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
})();
|
|
633
|
+
var PATH_METADATA = "path";
|
|
634
|
+
var METHOD_METADATA = "method";
|
|
635
|
+
var GUARDS_METADATA = "__guards__";
|
|
636
|
+
var INTERCEPTORS_METADATA = "__interceptors__";
|
|
637
|
+
var PIPES_METADATA = "__pipes__";
|
|
638
|
+
var EXCEPTION_FILTERS_METADATA = "__exceptionFilters__";
|
|
639
|
+
var ROUTE_ARGS_METADATA = "__routeArguments__";
|
|
640
|
+
var BODY_PARAM_TYPE = 3;
|
|
641
|
+
var HTTP_METHOD_NAMES = ["GET", "POST", "PUT", "DELETE", "PATCH", "ALL", "OPTIONS", "HEAD"];
|
|
624
642
|
var AppExplorer = class {
|
|
625
643
|
constructor(ctx) {
|
|
626
644
|
this.ctx = ctx;
|
|
627
645
|
}
|
|
628
646
|
ctx;
|
|
629
|
-
/** Walk the container and emit app.snapshot. Returns a no-op cleanup. */
|
|
630
647
|
attach(app) {
|
|
631
648
|
try {
|
|
632
649
|
const snapshot = this.buildSnapshot(app);
|
|
@@ -638,12 +655,13 @@ var AppExplorer = class {
|
|
|
638
655
|
}
|
|
639
656
|
buildSnapshot(app) {
|
|
640
657
|
const internal = app.container;
|
|
658
|
+
const globals = this.extractGlobals(app);
|
|
641
659
|
const modules = [];
|
|
642
660
|
const modulesMap = internal?.getModules?.();
|
|
643
661
|
if (modulesMap) {
|
|
644
662
|
for (const [id, node] of modulesMap) {
|
|
645
663
|
const moduleName = node.metatype?.name ?? String(id);
|
|
646
|
-
const members = this.extractMembers(node);
|
|
664
|
+
const members = this.extractMembers(node, globals);
|
|
647
665
|
modules.push({
|
|
648
666
|
name: moduleName,
|
|
649
667
|
imports: [],
|
|
@@ -658,23 +676,55 @@ var AppExplorer = class {
|
|
|
658
676
|
projectName: this.ctx.projectInfo.projectName,
|
|
659
677
|
modules,
|
|
660
678
|
nestjsVersion: this.ctx.projectInfo.nestjsVersion,
|
|
661
|
-
capturedAt: Date.now()
|
|
679
|
+
capturedAt: Date.now(),
|
|
680
|
+
globals
|
|
662
681
|
};
|
|
663
682
|
}
|
|
664
|
-
|
|
683
|
+
/** Global prefix, versioning, and APP_GUARD/APP_INTERCEPTOR/APP_FILTER/APP_PIPE providers (from AppModule's `providers` array). */
|
|
684
|
+
extractGlobals(app) {
|
|
685
|
+
const result = { prefix: null, versioning: null, guards: [], interceptors: [], filters: [], pipes: [] };
|
|
686
|
+
try {
|
|
687
|
+
const config = app.config;
|
|
688
|
+
result.prefix = typeof config?.getGlobalPrefix === "function" ? config.getGlobalPrefix() || null : null;
|
|
689
|
+
const versioning = typeof config?.getVersioning === "function" ? config.getVersioning() : null;
|
|
690
|
+
if (versioning) result.versioning = { type: String(versioning.type), defaultVersion: versioning.defaultVersion };
|
|
691
|
+
const internal = app.container;
|
|
692
|
+
const modulesMap = internal?.getModules?.();
|
|
693
|
+
if (modulesMap) {
|
|
694
|
+
for (const node of modulesMap.values()) {
|
|
695
|
+
const providersMap = node.providers;
|
|
696
|
+
if (!(providersMap instanceof Map)) continue;
|
|
697
|
+
for (const wrapper of providersMap.values()) {
|
|
698
|
+
const w = wrapper;
|
|
699
|
+
const name = w?.metatype?.name ?? w?.name;
|
|
700
|
+
if (!name || typeof name !== "string") continue;
|
|
701
|
+
const instance = w?.instance;
|
|
702
|
+
if (!instance) continue;
|
|
703
|
+
if (typeof instance.canActivate === "function" && name.endsWith("Guard")) pushUnique(result.guards, name);
|
|
704
|
+
else if (typeof instance.intercept === "function" && name.endsWith("Interceptor")) pushUnique(result.interceptors, name);
|
|
705
|
+
else if (typeof instance.catch === "function" && name.endsWith("Filter")) pushUnique(result.filters, name);
|
|
706
|
+
else if (typeof instance.transform === "function" && name.endsWith("Pipe")) pushUnique(result.pipes, name);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
} catch {
|
|
711
|
+
}
|
|
712
|
+
return result;
|
|
713
|
+
}
|
|
714
|
+
extractMembers(node, globals) {
|
|
665
715
|
const controllers = [];
|
|
666
716
|
const providers = [];
|
|
667
717
|
const controllersMap = node.controllers;
|
|
668
718
|
if (controllersMap instanceof Map) {
|
|
669
719
|
for (const [id, wrapper] of controllersMap) {
|
|
670
|
-
const member = this.memberFromWrapper(id, wrapper, "controller");
|
|
720
|
+
const member = this.memberFromWrapper(id, wrapper, globals, "controller");
|
|
671
721
|
if (member) controllers.push(member);
|
|
672
722
|
}
|
|
673
723
|
}
|
|
674
724
|
const providersMap = node.providers;
|
|
675
725
|
if (providersMap instanceof Map) {
|
|
676
726
|
for (const [id, wrapper] of providersMap) {
|
|
677
|
-
const member = this.memberFromWrapper(id, wrapper);
|
|
727
|
+
const member = this.memberFromWrapper(id, wrapper, globals);
|
|
678
728
|
if (!member) continue;
|
|
679
729
|
if (wrapper && wrapper.subtype === "httpController") {
|
|
680
730
|
controllers.push(member);
|
|
@@ -685,73 +735,144 @@ var AppExplorer = class {
|
|
|
685
735
|
}
|
|
686
736
|
return { controllers, providers };
|
|
687
737
|
}
|
|
688
|
-
memberFromWrapper(id, wrapper, forcedType) {
|
|
738
|
+
memberFromWrapper(id, wrapper, globals, forcedType) {
|
|
689
739
|
const w = wrapper;
|
|
690
740
|
const name = w?.metatype?.name ?? (typeof id === "string" ? id.replace(/^[A-Z_0-9]+:/, "") : "unknown");
|
|
691
741
|
const type = forcedType ?? classify(name, w?.instance);
|
|
692
|
-
|
|
693
|
-
|
|
742
|
+
if (type !== "controller" || !w?.metatype) {
|
|
743
|
+
return { name, type };
|
|
744
|
+
}
|
|
745
|
+
const { basePath, routes } = this.extractRoutes(w.metatype, globals);
|
|
746
|
+
return {
|
|
747
|
+
name,
|
|
748
|
+
type,
|
|
749
|
+
basePath,
|
|
750
|
+
routeDetails: routes,
|
|
751
|
+
routes: routes.map((r) => `${r.method} ${r.path}`)
|
|
752
|
+
// legacy field, kept for old dashboards
|
|
753
|
+
};
|
|
694
754
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if (name.endsWith("Gateway")) return "gateway";
|
|
698
|
-
if (name.endsWith("Guard")) return "guard";
|
|
699
|
-
if (name.endsWith("Interceptor")) return "interceptor";
|
|
700
|
-
if (name.endsWith("Pipe")) return "pipe";
|
|
701
|
-
if (name.endsWith("Filter")) return "filter";
|
|
702
|
-
if (instance && typeof instance.canActivate === "function") return "guard";
|
|
703
|
-
if (instance && typeof instance.intercept === "function") return "interceptor";
|
|
704
|
-
if (instance && typeof instance.transform === "function") return "pipe";
|
|
705
|
-
if (instance && typeof instance.catch === "function") return "filter";
|
|
706
|
-
return "provider";
|
|
707
|
-
}
|
|
708
|
-
function extractControllerRoutes(metatype) {
|
|
709
|
-
if (!metatype) return [];
|
|
710
|
-
try {
|
|
711
|
-
const proto = metatype.prototype;
|
|
712
|
-
if (!proto) return [];
|
|
713
|
-
const props = Object.getOwnPropertyNames(proto).filter((name) => name !== "constructor");
|
|
755
|
+
/** Extract every HTTP route of a controller class, with method/path/guards/interceptors/pipes/filters/dto. */
|
|
756
|
+
extractRoutes(controller, globals) {
|
|
714
757
|
const routes = [];
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
758
|
+
let basePath = "";
|
|
759
|
+
try {
|
|
760
|
+
const R = Reflect;
|
|
761
|
+
basePath = normalizeSegment(R.getMetadata?.(PATH_METADATA, controller) ?? "");
|
|
762
|
+
const classGuards = readMetaNames(R, GUARDS_METADATA, controller);
|
|
763
|
+
const classInterceptors = readMetaNames(R, INTERCEPTORS_METADATA, controller);
|
|
764
|
+
const classPipes = readMetaNames(R, PIPES_METADATA, controller);
|
|
765
|
+
const classFilters = readMetaNames(R, EXCEPTION_FILTERS_METADATA, controller);
|
|
766
|
+
const proto = controller.prototype;
|
|
767
|
+
if (!proto) return { basePath, routes };
|
|
768
|
+
const version = globals.versioning?.defaultVersion;
|
|
769
|
+
const versionSegment = globals.versioning?.type === "URI" && version && version !== "-1" ? `v${Array.isArray(version) ? version[0] : version}` : "";
|
|
770
|
+
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
771
|
+
if (key === "constructor") continue;
|
|
772
|
+
const handler = proto[key];
|
|
773
|
+
if (typeof handler !== "function") continue;
|
|
774
|
+
const httpMethod = R.getMetadata?.(METHOD_METADATA, handler);
|
|
775
|
+
if (httpMethod === void 0) continue;
|
|
776
|
+
const methodPath = normalizeSegment(R.getMetadata?.(PATH_METADATA, handler) ?? "");
|
|
777
|
+
const fullPath = ["/", globals.prefix, versionSegment, basePath, methodPath].filter((segment) => segment && segment !== "/").join("/").replace(/\/+/g, "/");
|
|
778
|
+
const methodGuards = readMetaNames(R, GUARDS_METADATA, handler);
|
|
779
|
+
const methodInterceptors = readMetaNames(R, INTERCEPTORS_METADATA, handler);
|
|
780
|
+
const methodPipes = readMetaNames(R, PIPES_METADATA, handler);
|
|
781
|
+
const methodFilters = readMetaNames(R, EXCEPTION_FILTERS_METADATA, handler);
|
|
782
|
+
routes.push({
|
|
783
|
+
method: HTTP_METHOD_NAMES[httpMethod] ?? "GET",
|
|
784
|
+
path: fullPath.startsWith("/") ? fullPath : `/${fullPath}`,
|
|
785
|
+
handlerName: key,
|
|
786
|
+
guards: dedupe([...classGuards, ...methodGuards]),
|
|
787
|
+
interceptors: dedupe([...classInterceptors, ...methodInterceptors]),
|
|
788
|
+
pipes: dedupe([...classPipes, ...methodPipes]),
|
|
789
|
+
filters: dedupe([...classFilters, ...methodFilters]),
|
|
790
|
+
dto: this.extractBodyDto(R, controller, proto, key)
|
|
791
|
+
});
|
|
722
792
|
}
|
|
793
|
+
} catch {
|
|
723
794
|
}
|
|
724
|
-
return routes;
|
|
725
|
-
} catch {
|
|
726
|
-
return [];
|
|
795
|
+
return { basePath, routes };
|
|
727
796
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
for (const
|
|
735
|
-
|
|
736
|
-
|
|
797
|
+
/** Best-effort: find the @Body() parameter's class and describe its fields via class-validator, if present. */
|
|
798
|
+
extractBodyDto(R, controller, proto, methodName) {
|
|
799
|
+
try {
|
|
800
|
+
const paramTypes = R.getMetadata?.("design:paramtypes", proto, methodName) ?? [];
|
|
801
|
+
const routeArgs = R.getMetadata?.(ROUTE_ARGS_METADATA, controller, methodName) ?? {};
|
|
802
|
+
let bodyIndex = -1;
|
|
803
|
+
for (const key of Object.keys(routeArgs)) {
|
|
804
|
+
const [paramType] = key.split(":");
|
|
805
|
+
if (Number(paramType) === BODY_PARAM_TYPE) {
|
|
806
|
+
bodyIndex = routeArgs[key]?.index ?? -1;
|
|
807
|
+
break;
|
|
737
808
|
}
|
|
738
809
|
}
|
|
810
|
+
if (bodyIndex === -1) return null;
|
|
811
|
+
const dtoClass = paramTypes[bodyIndex];
|
|
812
|
+
if (!dtoClass || !dtoClass.name || ["Object", "String", "Number", "Boolean", "Array"].includes(dtoClass.name)) {
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
return { name: dtoClass.name, fields: this.describeDtoFields(dtoClass) };
|
|
816
|
+
} catch {
|
|
817
|
+
return null;
|
|
739
818
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
if (
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
819
|
+
}
|
|
820
|
+
/** Reads class-validator's metadata storage if the package is installed in the host app. Falls back to []. */
|
|
821
|
+
describeDtoFields(dtoClass) {
|
|
822
|
+
try {
|
|
823
|
+
if (!safeRequire) return [];
|
|
824
|
+
const cv = safeRequire("class-validator");
|
|
825
|
+
const storage = cv.getMetadataStorage?.();
|
|
826
|
+
const metas = storage?.getTargetValidationMetadatas?.(dtoClass, "", true, false) ?? [];
|
|
827
|
+
const byProperty = /* @__PURE__ */ new Map();
|
|
828
|
+
for (const meta of metas) {
|
|
829
|
+
const entry = byProperty.get(meta.propertyName) ?? { types: [], optional: false };
|
|
830
|
+
if (meta.name === "isOptional") entry.optional = true;
|
|
831
|
+
if (meta.name) entry.types.push(meta.name);
|
|
832
|
+
byProperty.set(meta.propertyName, entry);
|
|
748
833
|
}
|
|
834
|
+
return [...byProperty.entries()].map(([name, info]) => ({
|
|
835
|
+
name,
|
|
836
|
+
type: info.types.find((t) => /^is[A-Z]/.test(t))?.replace(/^is/, "") ?? "unknown",
|
|
837
|
+
optional: info.optional,
|
|
838
|
+
rules: dedupe(info.types)
|
|
839
|
+
}));
|
|
840
|
+
} catch {
|
|
841
|
+
return [];
|
|
749
842
|
}
|
|
750
|
-
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
function readMetaNames(R, key, target) {
|
|
846
|
+
try {
|
|
847
|
+
const value = R.getMetadata?.(key, target);
|
|
848
|
+
if (!Array.isArray(value)) return [];
|
|
849
|
+
return value.map((fn) => fn?.name).filter((name) => Boolean(name));
|
|
751
850
|
} catch {
|
|
752
851
|
return [];
|
|
753
852
|
}
|
|
754
853
|
}
|
|
854
|
+
function normalizeSegment(segment) {
|
|
855
|
+
const s = Array.isArray(segment) ? segment[0] ?? "" : segment;
|
|
856
|
+
return String(s ?? "").replace(/^\/+|\/+$/g, "");
|
|
857
|
+
}
|
|
858
|
+
function dedupe(items) {
|
|
859
|
+
return [...new Set(items)];
|
|
860
|
+
}
|
|
861
|
+
function pushUnique(list, value) {
|
|
862
|
+
if (!list.includes(value)) list.push(value);
|
|
863
|
+
}
|
|
864
|
+
function classify(name, instance) {
|
|
865
|
+
if (name.endsWith("Gateway")) return "gateway";
|
|
866
|
+
if (name.endsWith("Guard")) return "guard";
|
|
867
|
+
if (name.endsWith("Interceptor")) return "interceptor";
|
|
868
|
+
if (name.endsWith("Pipe")) return "pipe";
|
|
869
|
+
if (name.endsWith("Filter")) return "filter";
|
|
870
|
+
if (instance && typeof instance.canActivate === "function") return "guard";
|
|
871
|
+
if (instance && typeof instance.intercept === "function") return "interceptor";
|
|
872
|
+
if (instance && typeof instance.transform === "function") return "pipe";
|
|
873
|
+
if (instance && typeof instance.catch === "function") return "filter";
|
|
874
|
+
return "provider";
|
|
875
|
+
}
|
|
755
876
|
|
|
756
877
|
// src/instrumentation/websockets.ts
|
|
757
878
|
var import_devtools_core7 = require("@angelitosystems/devtools-core");
|
|
@@ -1428,7 +1549,7 @@ function detectNestJsVersion() {
|
|
|
1428
1549
|
}
|
|
1429
1550
|
|
|
1430
1551
|
// src/version.ts
|
|
1431
|
-
var SDK_VERSION = "1.0.
|
|
1552
|
+
var SDK_VERSION = "1.0.15";
|
|
1432
1553
|
|
|
1433
1554
|
// src/banner.ts
|
|
1434
1555
|
var RESET = "\x1B[0m";
|