moost 0.6.31 → 0.6.32
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 +457 -76
- package/dist/index.d.ts +241 -30
- package/dist/index.mjs +455 -77
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,55 @@ let _prostojs_logger = require("@prostojs/logger");
|
|
|
6
6
|
let hookable = require("hookable");
|
|
7
7
|
let wooks = require("wooks");
|
|
8
8
|
|
|
9
|
+
//#region packages/moost/src/module-identity.ts
|
|
10
|
+
/**
|
|
11
|
+
* Duplicate-copy detection for moost
|
|
12
|
+
*
|
|
13
|
+
* Mate stores decorator metadata in WeakMaps keyed by constructor
|
|
14
|
+
* reference, and moost keeps module-scoped DI singletons
|
|
15
|
+
* (`sharedMoostInfact`, `moostMate`). If a bundler loads two copies of
|
|
16
|
+
* moost, decorators run against one copy while lookups hit the other,
|
|
17
|
+
* and DI fails with distant "Class is not Injectable" errors. The first
|
|
18
|
+
* loaded copy stamps `globalThis` under a global symbol; any subsequent
|
|
19
|
+
* copy finds the stamp and warns.
|
|
20
|
+
*/ const MOOST_MODULE_IDENTITY_KEY = Symbol.for("moost:module-identity");
|
|
21
|
+
function describeCopy(identity) {
|
|
22
|
+
return `${identity.version || "unknown version"} at ${identity.path || "unknown path"}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stamps the global object with this module's identity and warns when
|
|
26
|
+
* another copy of moost was already loaded — decorator metadata and DI
|
|
27
|
+
* singletons do not interoperate between copies.
|
|
28
|
+
*
|
|
29
|
+
* Exported for testability; invoked once at module scope.
|
|
30
|
+
*/ function stampModuleIdentity(identity, globalObject = globalThis) {
|
|
31
|
+
const holder = globalObject;
|
|
32
|
+
const existing = holder[MOOST_MODULE_IDENTITY_KEY];
|
|
33
|
+
if (existing) console.warn(`[moost] A second copy of moost was loaded (${describeCopy(existing)}, now ${describeCopy(identity)}). Decorator metadata and DI singletons will NOT interoperate between copies. Check your bundler config / dedupe settings.`);
|
|
34
|
+
else holder[MOOST_MODULE_IDENTITY_KEY] = identity;
|
|
35
|
+
}
|
|
36
|
+
let stamped = false;
|
|
37
|
+
/**
|
|
38
|
+
* One-shot wrapper around `stampModuleIdentity` for this module copy.
|
|
39
|
+
*
|
|
40
|
+
* Invoked at module scope AND from `getMoostMate()`: the package ships
|
|
41
|
+
* `"sideEffects": false`, so a tree-shaking bundler may drop the
|
|
42
|
+
* module-scope invocation when nothing imports from this file — the
|
|
43
|
+
* `getMoostMate()` call keeps the duplicate check reachable in bundled
|
|
44
|
+
* apps (it fires on first decorator use, exactly when per-copy metadata
|
|
45
|
+
* divergence begins), which are the environments that produce duplicate
|
|
46
|
+
* copies in the first place.
|
|
47
|
+
*/ function stampOnce() {
|
|
48
|
+
if (stamped) return;
|
|
49
|
+
stamped = true;
|
|
50
|
+
stampModuleIdentity({
|
|
51
|
+
version: "0.6.32",
|
|
52
|
+
path: typeof __filename === "string" ? __filename : require("url").pathToFileURL(__filename).href
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
stampOnce();
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
9
58
|
//#region packages/moost/src/logger.ts
|
|
10
59
|
let defaultLogger;
|
|
11
60
|
function setDefaultLogger(logger) {
|
|
@@ -63,6 +112,74 @@ function runPipes(pipes, initialValue, metas, level) {
|
|
|
63
112
|
return v;
|
|
64
113
|
}
|
|
65
114
|
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region packages/moost/src/metadata/diagnostics.ts
|
|
117
|
+
let sourceRefs = [];
|
|
118
|
+
/** Dereferences the registered sources, pruning refs whose target was collected. */ function scanLiveSources() {
|
|
119
|
+
const live = [];
|
|
120
|
+
const keep = [];
|
|
121
|
+
for (const ref of sourceRefs) {
|
|
122
|
+
const source = ref.deref();
|
|
123
|
+
if (source) {
|
|
124
|
+
live.push(source);
|
|
125
|
+
keep.push(ref);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
sourceRefs = keep;
|
|
129
|
+
return live;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Registers a Moost app as a source for DI diagnostics scans (D4 scope
|
|
133
|
+
* hints). Held via `WeakRef` so a dropped app never leaks; registering the
|
|
134
|
+
* same app again is a no-op.
|
|
135
|
+
*/ function registerDiagnosticsSource(source) {
|
|
136
|
+
if (scanLiveSources().includes(source)) return;
|
|
137
|
+
sourceRefs.push(new WeakRef(source));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Scans the registered apps' controllers for a class-scoped `@Provide`
|
|
141
|
+
* carrying `token` and returns the provider controller class names. Both
|
|
142
|
+
* string and symbol keys are checked — symbol class-tokens match by identity
|
|
143
|
+
* because infact keys them via `Symbol.for` (same class source, same symbol).
|
|
144
|
+
*/ function findTokenProviders(token) {
|
|
145
|
+
const providers = [];
|
|
146
|
+
for (const source of scanLiveSources()) for (const entry of source.getControllersOverview()) if (Reflect.ownKeys(entry.meta?.provide ?? {}).includes(token) && !providers.includes(entry.type.name)) providers.push(entry.type.name);
|
|
147
|
+
return providers;
|
|
148
|
+
}
|
|
149
|
+
const CLASS_SOURCE_RE = /^class\s+([\w$]+)/;
|
|
150
|
+
/** Renders a provide token readably: strings as-is, class-source symbols by class name. */ function stringifyToken(token) {
|
|
151
|
+
if (typeof token === "string") return token;
|
|
152
|
+
const description = token.description ?? token.toString();
|
|
153
|
+
const match = CLASS_SOURCE_RE.exec(description);
|
|
154
|
+
return match ? match[1] : description;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* D4: when an unresolved `@Inject(token)` IS provided somewhere — via a
|
|
158
|
+
* class-scoped `@Provide` on a sibling controller — teaches the actual
|
|
159
|
+
* scoping rule (providers flow parent → child, never to siblings) and names
|
|
160
|
+
* both remedies. Returns `undefined` when no provider was found.
|
|
161
|
+
*/ function formatScopeHint(token, providerNames) {
|
|
162
|
+
if (providerNames.length === 0) return;
|
|
163
|
+
const subject = providerNames.length === 1 ? `sibling controller ${providerNames[0]}` : `sibling controllers ${providerNames.join(", ")}`;
|
|
164
|
+
return `Token "${stringifyToken(token)}" is provided on ${subject} via class-scoped @Provide, which is only visible to that controller's own subtree (providers flow parent → child through @ImportController, never to siblings). Move it to app.setProvideRegistry(...) or to a common parent @ImportController.`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* D2: renders an infact instantiation error with the consumer-side context
|
|
168
|
+
* carried by `detail` — parameter position/label/type plus the resolution
|
|
169
|
+
* hierarchy — as one multi-line message (single `logger.error` call). The
|
|
170
|
+
* `import type` hint is already appended to `message` upstream by infact and
|
|
171
|
+
* is deliberately not duplicated here.
|
|
172
|
+
*/ function formatInfactErrorContext(targetClassName, message, detail) {
|
|
173
|
+
let head = `Failed to instantiate ${targetClassName}`;
|
|
174
|
+
if (typeof detail.paramIndex === "number") {
|
|
175
|
+
const qualifiers = [detail.paramLabel === void 0 ? "" : `label "${detail.paramLabel}"`, detail.paramTypeName === void 0 ? "" : `type ${detail.paramTypeName}`].filter(Boolean).join(", ");
|
|
176
|
+
head += `: constructor parameter #${detail.paramIndex}${qualifiers ? ` (${qualifiers})` : ""}`;
|
|
177
|
+
}
|
|
178
|
+
const lines = [`${head} — ${message}`];
|
|
179
|
+
if (detail.hierarchy && detail.hierarchy.length > 0) lines.push(` Hierarchy: ${detail.hierarchy.join(" → ")}`);
|
|
180
|
+
return lines.join("\n");
|
|
181
|
+
}
|
|
182
|
+
|
|
66
183
|
//#endregion
|
|
67
184
|
//#region packages/moost/src/metadata/moost-metadata.ts
|
|
68
185
|
const METADATA_WORKSPACE = "moost";
|
|
@@ -86,6 +203,7 @@ const moostMate = new _prostojs_mate.Mate(METADATA_WORKSPACE, {
|
|
|
86
203
|
}
|
|
87
204
|
});
|
|
88
205
|
/** Returns the shared `Mate` instance operating in the `'moost'` metadata workspace. */ function getMoostMate() {
|
|
206
|
+
stampOnce();
|
|
89
207
|
return moostMate;
|
|
90
208
|
}
|
|
91
209
|
|
|
@@ -125,6 +243,66 @@ const scopeVarsMap = /* @__PURE__ */ new Map();
|
|
|
125
243
|
*/ function getInfactScopeVars(name) {
|
|
126
244
|
return scopeVarsMap.get(name);
|
|
127
245
|
}
|
|
246
|
+
/** Applies the `setInfactLoggingOptions` filters to an Infact event. */ function shouldLogInfactEvent(event, targetClass) {
|
|
247
|
+
if (event === "warn") return !!loggingOptions.warn;
|
|
248
|
+
if (event === "error") return !!loggingOptions.error;
|
|
249
|
+
const scope = getMoostMate().read(targetClass)?.injectable || "SINGLETON";
|
|
250
|
+
return loggingOptions.newInstance !== false && (loggingOptions.newInstance === scope || loggingOptions.newInstance === "SINGLETON" && scope === true);
|
|
251
|
+
}
|
|
252
|
+
/** Renders the DI resolution-hierarchy breadcrumb (`⋱ A → B`). */ function formatHierarchy(args) {
|
|
253
|
+
return `[2m[34m⋱ ${args?.map(String).join(" → ") || ""}`;
|
|
254
|
+
}
|
|
255
|
+
function formatNewInstanceArg(a) {
|
|
256
|
+
switch (typeof a) {
|
|
257
|
+
case "number":
|
|
258
|
+
case "boolean": return `[33m${a}[2m[34m`;
|
|
259
|
+
case "string": return `[92m"${a.slice(0, 1)}..."[2m[34m`;
|
|
260
|
+
case "object":
|
|
261
|
+
if (Array.isArray(a)) return `[${a.length}]`;
|
|
262
|
+
if ((0, _prostojs_mate.getConstructor)(a)) return (0, _prostojs_mate.getConstructor)(a).name;
|
|
263
|
+
return "{}";
|
|
264
|
+
default: return "*";
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Renders the resolved constructor args for the `new-instance` log line. */ function formatNewInstanceParams(args) {
|
|
268
|
+
return args?.map((a) => `[2m[1m${formatNewInstanceArg(a)}[22m[2m`).join(", ") || "";
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Renders an `'error'` event. Without `detail` (everything the installed
|
|
272
|
+
* @prostojs/infact@0.4.1 ever produces) the output is exactly the legacy
|
|
273
|
+
* format. With `detail` (newer infact) the D2 consumer context is rendered
|
|
274
|
+
* and, when the failing `@Inject` token is class-provided on a sibling
|
|
275
|
+
* controller of a registered app, the D4 scope hint is appended.
|
|
276
|
+
*/ function renderInfactError(targetClass, message, args, detail) {
|
|
277
|
+
if (!detail) return `Failed to instantiate ${`[4m${targetClass.name}[24m`}. ${message} ${formatHierarchy(args)}`;
|
|
278
|
+
let text = formatInfactErrorContext(targetClass.name, message, detail);
|
|
279
|
+
if (detail.injectToken !== void 0) {
|
|
280
|
+
const hint = formatScopeHint(detail.injectToken, findTokenProviders(detail.injectToken));
|
|
281
|
+
if (hint) text += `\n ${hint}`;
|
|
282
|
+
}
|
|
283
|
+
return text;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Infact event sink. Declared with the forward-compatible 5-param signature:
|
|
287
|
+
* the installed @prostojs/infact (0.4.1) calls it with 4 args (never passes
|
|
288
|
+
* `detail`), while newer infact versions pass a `detail` payload on `'error'`
|
|
289
|
+
* events that unlocks the rich D2/D4 rendering (see `renderInfactError`).
|
|
290
|
+
*
|
|
291
|
+
* Exported for tests — since 0.4.1 never passes `detail` at runtime, the
|
|
292
|
+
* detail-driven path is exercised by invoking this function directly.
|
|
293
|
+
*/ function onInfactEvent(event, targetClass, message, args, detail) {
|
|
294
|
+
if (!shouldLogInfactEvent(event, targetClass)) return;
|
|
295
|
+
let logger;
|
|
296
|
+
try {
|
|
297
|
+
logger = event === "error" ? getDefaultLogger(INFACT_BANNER) : (0, _wooksjs_event_core.useLogger)(INFACT_BANNER);
|
|
298
|
+
} catch {
|
|
299
|
+
logger = getDefaultLogger(INFACT_BANNER);
|
|
300
|
+
}
|
|
301
|
+
const instance = `[4m${targetClass.name}[24m`;
|
|
302
|
+
if (event === "new-instance") logger.info(`new ${instance}[2m[34m(${formatNewInstanceParams(args)})`);
|
|
303
|
+
else if (event === "warn") logger.warn(`${instance} - ${message} ${formatHierarchy(args)}`);
|
|
304
|
+
else logger.error(renderInfactError(targetClass, message, args, detail));
|
|
305
|
+
}
|
|
128
306
|
/**
|
|
129
307
|
* Get Infact instance (used for Dependency Injections)
|
|
130
308
|
*/ function getNewMoostInfact() {
|
|
@@ -168,58 +346,7 @@ const scopeVarsMap = /* @__PURE__ */ new Map();
|
|
|
168
346
|
}, "PROP");
|
|
169
347
|
},
|
|
170
348
|
storeProvideRegByInstance: true,
|
|
171
|
-
on:
|
|
172
|
-
switch (event) {
|
|
173
|
-
case "new-instance": {
|
|
174
|
-
const scope = getMoostMate().read(targetClass)?.injectable || "SINGLETON";
|
|
175
|
-
if (loggingOptions.newInstance === false || !(loggingOptions.newInstance === scope || loggingOptions.newInstance === "SINGLETON" && scope === true)) return;
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
case "warn":
|
|
179
|
-
if (!loggingOptions.warn) return;
|
|
180
|
-
break;
|
|
181
|
-
case "error":
|
|
182
|
-
if (!loggingOptions.error) return;
|
|
183
|
-
break;
|
|
184
|
-
default:
|
|
185
|
-
}
|
|
186
|
-
let logger;
|
|
187
|
-
try {
|
|
188
|
-
logger = event === "error" ? getDefaultLogger(INFACT_BANNER) : (0, _wooksjs_event_core.useLogger)(INFACT_BANNER);
|
|
189
|
-
} catch {
|
|
190
|
-
logger = getDefaultLogger(INFACT_BANNER);
|
|
191
|
-
}
|
|
192
|
-
const instance = `[4m${targetClass.name}[24m`;
|
|
193
|
-
switch (event) {
|
|
194
|
-
case "new-instance": {
|
|
195
|
-
const params = args?.map((a) => {
|
|
196
|
-
switch (typeof a) {
|
|
197
|
-
case "number":
|
|
198
|
-
case "boolean": return `[33m${a}[2m[34m`;
|
|
199
|
-
case "string": return `[92m"${a.slice(0, 1)}..."[2m[34m`;
|
|
200
|
-
case "object":
|
|
201
|
-
if (Array.isArray(a)) return `[${a.length}]`;
|
|
202
|
-
if ((0, _prostojs_mate.getConstructor)(a)) return (0, _prostojs_mate.getConstructor)(a).name;
|
|
203
|
-
return "{}";
|
|
204
|
-
default: return "*";
|
|
205
|
-
}
|
|
206
|
-
}).map((a) => `[2m[1m${a}[22m[2m`).join(", ") || "";
|
|
207
|
-
logger.info(`new ${instance}[2m[34m(${params})`);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
case "warn": {
|
|
211
|
-
const hier = `[2m[34m⋱ ${args?.map(String).join(" → ") || ""}`;
|
|
212
|
-
logger.warn(`${instance} - ${message} ${hier}`);
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
case "error": {
|
|
216
|
-
const hier = `[2m[34m⋱ ${args?.map(String).join(" → ") || ""}`;
|
|
217
|
-
logger.error(`Failed to instantiate ${instance}. ${message} ${hier}`);
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
|
-
default: break;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
349
|
+
on: onInfactEvent
|
|
223
350
|
});
|
|
224
351
|
}
|
|
225
352
|
|
|
@@ -482,11 +609,20 @@ function nextScopeId() {
|
|
|
482
609
|
...Object.getOwnPropertyNames(instance)
|
|
483
610
|
])].filter((m) => typeof instance[m] !== "function");
|
|
484
611
|
}
|
|
485
|
-
|
|
612
|
+
/**
|
|
613
|
+
* Walks the user-defined ancestor classes of a constructor, closest first.
|
|
614
|
+
* Terminates at `Function.prototype` (it is a function but has no `.prototype`).
|
|
615
|
+
*/ function* ancestorsOf(classConstructor) {
|
|
616
|
+
let parent = Object.getPrototypeOf(classConstructor);
|
|
617
|
+
while (typeof parent === "function" && parent.prototype) {
|
|
618
|
+
yield parent;
|
|
619
|
+
parent = Object.getPrototypeOf(parent);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
486
622
|
function getParentProps(constructor) {
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
return
|
|
623
|
+
const props = [];
|
|
624
|
+
for (const parent of ancestorsOf(constructor)) props.unshift(...Object.getOwnPropertyNames(parent.prototype));
|
|
625
|
+
return props;
|
|
490
626
|
}
|
|
491
627
|
|
|
492
628
|
//#endregion
|
|
@@ -644,11 +780,20 @@ function ImportController(prefix, controller, provide) {
|
|
|
644
780
|
return getMoostMate().apply(getMoostMate().decorate("paramSource", "ROUTE"), getMoostMate().decorate("paramName", name), Resolve(() => (0, _wooksjs_event_core.useRouteParams)().get(name), name));
|
|
645
781
|
}
|
|
646
782
|
/**
|
|
647
|
-
* Get Parsed Params from url
|
|
783
|
+
* Get Parsed Params from url path
|
|
784
|
+
*
|
|
785
|
+
* Stamps `paramSource: 'ROUTE'` metadata (like `@Param(name)` does), so
|
|
786
|
+
* source-aware pipes (e.g. coercion pipes that only coerce string-transport
|
|
787
|
+
* input) recognize the whole params object as route input.
|
|
788
|
+
*
|
|
789
|
+
* Tip: type the argument with an interface-based DTO (e.g. an atscript `.as`
|
|
790
|
+
* interface) — interfaces emit as `declare class`, so the design type survives
|
|
791
|
+
* every metadata toolchain, unlike scalar type aliases which only survive
|
|
792
|
+
* syntactic emitters.
|
|
648
793
|
* @decorator
|
|
649
794
|
* @paramType object
|
|
650
795
|
*/ function Params() {
|
|
651
|
-
return Resolve(() => (0, _wooksjs_event_core.useRouteParams)().params, "params");
|
|
796
|
+
return getMoostMate().apply(getMoostMate().decorate("paramSource", "ROUTE"), Resolve(() => (0, _wooksjs_event_core.useRouteParams)().params, "params"));
|
|
652
797
|
}
|
|
653
798
|
/**
|
|
654
799
|
* Provide Const Value
|
|
@@ -1381,6 +1526,51 @@ function getIterceptorHandlerFactory(interceptors, getTargetInstance, pipes) {
|
|
|
1381
1526
|
return () => new InterceptorHandler(precomputedHandlers);
|
|
1382
1527
|
}
|
|
1383
1528
|
|
|
1529
|
+
//#endregion
|
|
1530
|
+
//#region packages/moost/src/binding/param-audit.ts
|
|
1531
|
+
/**
|
|
1532
|
+
* Resolves the effective param-audit mode: an explicit setting wins; otherwise
|
|
1533
|
+
* `'error'` in dev (`NODE_ENV !== 'production'`) and `'warn'` in production.
|
|
1534
|
+
*/ function resolveParamAuditMode(setting) {
|
|
1535
|
+
if (setting) return setting;
|
|
1536
|
+
return process.env.NODE_ENV === "production" ? "warn" : "error";
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* True when the param carries no explicit resolution (`@Resolve`-based
|
|
1540
|
+
* decorators, `@Inject`, `@Circular`) and its emitted design type is unusable
|
|
1541
|
+
* for DI — `Object` (class erased by `import type`, or an interface/union) or
|
|
1542
|
+
* `undefined` (circular import). Such a param falls through to
|
|
1543
|
+
* `infact.get(param.type)` and fails there or silently injects `undefined`.
|
|
1544
|
+
*/ function isBrokenFallThrough(param) {
|
|
1545
|
+
return !param.resolver && !param.inject && !param.circular && (param.type === Object || param.type === void 0);
|
|
1546
|
+
}
|
|
1547
|
+
function buildMessage(ctx, index, param) {
|
|
1548
|
+
const where = `[moost] ${ctx.className}.${ctx.methodName ?? "constructor"} parameter #${index}`;
|
|
1549
|
+
if (!ctx.methodName) return param.type === void 0 ? `${where} has no emitted design type — usually a circular import. Use @Circular(() => Type).` : `${where} has type Object — its class was likely imported with 'import type', or it is an interface/union type. Use a value import, an explicit @Inject(token) or @Resolve(), or mark it @Optional() to silence.`;
|
|
1550
|
+
return param.type === void 0 ? `${where} has no emitted design type (usually a circular import) and no param decorator — it will resolve to undefined at event time. Add a param decorator (e.g. @Param/@Body) or @Resolve().` : `${where} has type Object and no param decorator — it will resolve to undefined at event time. Add a param decorator (e.g. @Param/@Body) or @Resolve(); if the type is a class imported with 'import type', use a value import.`;
|
|
1551
|
+
}
|
|
1552
|
+
function severityOf(ctx, param) {
|
|
1553
|
+
if (ctx.methodName) return "warn-only";
|
|
1554
|
+
return param.optional || param.nullable ? "warn-only" : "fatal-capable";
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* D1 bind-time param audit: returns a finding for every param that will fall
|
|
1558
|
+
* through to DI class-instantiation with a broken emitted type (`Object` or
|
|
1559
|
+
* `undefined`) and no explicit resolution. Pure — the caller decides how to
|
|
1560
|
+
* log/throw (see `Moost.init()`).
|
|
1561
|
+
*/ function auditParams(params, ctx) {
|
|
1562
|
+
const findings = [];
|
|
1563
|
+
for (const [index, param] of (params || []).entries()) if (param && isBrokenFallThrough(param)) findings.push({
|
|
1564
|
+
message: buildMessage(ctx, index, param),
|
|
1565
|
+
severity: severityOf(ctx, param)
|
|
1566
|
+
});
|
|
1567
|
+
return findings;
|
|
1568
|
+
}
|
|
1569
|
+
/** Formats the aggregate error thrown by `init()` when fatal-capable findings exist. */ function formatParamAuditError(findings) {
|
|
1570
|
+
const list = findings.map((f) => ` - ${f.message}`).join("\n");
|
|
1571
|
+
return `[moost] DI param audit failed (${findings.length} finding${findings.length === 1 ? "" : "s"}):\n${list}\nSet diagnostics: { paramTypes: 'warn' } (or 'off') on Moost options to downgrade.`;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1384
1574
|
//#endregion
|
|
1385
1575
|
//#region packages/moost/src/binding/bind-controller.ts
|
|
1386
1576
|
async function bindControllerMethods(options) {
|
|
@@ -1403,6 +1593,10 @@ async function bindControllerMethods(options) {
|
|
|
1403
1593
|
};
|
|
1404
1594
|
for (const method of methods) {
|
|
1405
1595
|
const methodMeta = getMoostMate().read(fakeInstance, method) || {};
|
|
1596
|
+
if (options.reportParamAudit && (methodMeta.moostInit || methodMeta.handlers?.length)) options.reportParamAudit(auditParams(methodMeta.params, {
|
|
1597
|
+
className: classConstructor.name,
|
|
1598
|
+
methodName: method
|
|
1599
|
+
}));
|
|
1406
1600
|
if (methodMeta.moostInit) {
|
|
1407
1601
|
if (meta.injectable === "FOR_EVENT") throw new Error(`@MoostInit is not allowed on a FOR_EVENT controller (${classConstructor.name}.${String(method)}). Init hooks run once at boot on the SINGLETON instance; FOR_EVENT controllers have no init-time instance.`);
|
|
1408
1602
|
const initArgsPipes = (methodMeta.params || []).map((p) => ({
|
|
@@ -1473,6 +1667,93 @@ async function bindControllerMethods(options) {
|
|
|
1473
1667
|
return controllerOverview;
|
|
1474
1668
|
}
|
|
1475
1669
|
|
|
1670
|
+
//#endregion
|
|
1671
|
+
//#region packages/moost/src/binding/inheritance-audit.ts
|
|
1672
|
+
/** Counts handler metas on the class' own prototype methods (its inherit rules applied). */ function countHandlers(classConstructor) {
|
|
1673
|
+
const mate = getMoostMate();
|
|
1674
|
+
let count = 0;
|
|
1675
|
+
for (const name of Object.getOwnPropertyNames(classConstructor.prototype)) if (name !== "constructor") count += mate.read(classConstructor, name)?.handlers?.length ?? 0;
|
|
1676
|
+
return count;
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Names the classes strictly between `classConstructor` and `ancestor` that
|
|
1680
|
+
* carry no truthy `@Inherit` — the links that break the metadata bridge
|
|
1681
|
+
* (both `@Inherit()` and the parent-params fallback cross one level at a time).
|
|
1682
|
+
*/ function brokenLinksBetween(classConstructor, ancestor) {
|
|
1683
|
+
const mate = getMoostMate();
|
|
1684
|
+
const links = [];
|
|
1685
|
+
for (const parent of ancestorsOf(classConstructor)) {
|
|
1686
|
+
if (parent === ancestor) break;
|
|
1687
|
+
if (!mate.read(parent)?.inherit) links.push(parent.name);
|
|
1688
|
+
}
|
|
1689
|
+
return links;
|
|
1690
|
+
}
|
|
1691
|
+
/**
|
|
1692
|
+
* Route-drop trap: the registered class contributed 0 handlers while an
|
|
1693
|
+
* ancestor defines some — its routes silently 404. Fires when the class
|
|
1694
|
+
* carries no `@Inherit` decision (routes never flow by default) AND when it
|
|
1695
|
+
* carries `@Inherit()` but nothing flowed (that combination is always a bridge
|
|
1696
|
+
* broken by intermediate classes without `@Inherit()` of their own). An
|
|
1697
|
+
* explicit `@Inherit(false)` is a deliberate opt-out and stays silent.
|
|
1698
|
+
*/ function auditRouteDrop(input) {
|
|
1699
|
+
if (input.ownHandlersCount > 0 || input.classMeta?.inherit === false) return;
|
|
1700
|
+
for (const ancestor of ancestorsOf(input.classConstructor)) {
|
|
1701
|
+
const count = countHandlers(ancestor);
|
|
1702
|
+
if (count > 0) return {
|
|
1703
|
+
severity: "warn-only",
|
|
1704
|
+
message: routeDropMessage(input, ancestor, count)
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
function routeDropMessage(input, ancestor, count) {
|
|
1709
|
+
const name = input.classConstructor.name;
|
|
1710
|
+
if (input.classMeta?.inherit) {
|
|
1711
|
+
const links = brokenLinksBetween(input.classConstructor, ancestor);
|
|
1712
|
+
const brokenBy = links.length > 0 ? `the intermediate class(es) ${links.join(", ")} carry no @Inherit()` : "the inherit chain between them is broken";
|
|
1713
|
+
return `[moost] ${name} has @Inherit() but registered 0 route handler(s) while its ancestor ${ancestor.name} defines ${count} — @Inherit() bridges one level at a time and ${brokenBy}. Add @Inherit() to each intermediate class or re-declare the routes.`;
|
|
1714
|
+
}
|
|
1715
|
+
return `[moost] ${name} extends ${ancestor.name} which defines ${count} route handler(s), but ${name} registered 0 and has no @Inherit() — parent routes are not inherited without it. Add @Inherit() or re-declare the routes.`;
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Lost-constructor-params trap: a DI-instantiated class whose effective params
|
|
1719
|
+
* metadata is absent while a decorated ancestor declares constructor params.
|
|
1720
|
+
* Covers two shapes:
|
|
1721
|
+
* - the class carries no Moost metadata at all (undecorated subclass registered
|
|
1722
|
+
* as a controller) — it is not even seen as injectable;
|
|
1723
|
+
* - the class is decorated but an undecorated intermediate class breaks the
|
|
1724
|
+
* automatic parent-params fallback (metadata reads walk one level only).
|
|
1725
|
+
* An own zero-param constructor emits `params: []` and is a deliberate choice —
|
|
1726
|
+
* only truly absent params fire.
|
|
1727
|
+
*/ function auditLostCtorParams(input) {
|
|
1728
|
+
if (!input.diInstantiated || input.classMeta?.params) return;
|
|
1729
|
+
const mate = getMoostMate();
|
|
1730
|
+
for (const ancestor of ancestorsOf(input.classConstructor)) {
|
|
1731
|
+
const count = mate.read(ancestor)?.params?.length ?? 0;
|
|
1732
|
+
if (count > 0) return {
|
|
1733
|
+
severity: "warn-only",
|
|
1734
|
+
message: lostCtorParamsMessage(input, ancestor, count)
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
function lostCtorParamsMessage(input, ancestor, count) {
|
|
1739
|
+
const name = input.classConstructor.name;
|
|
1740
|
+
if (input.classMeta) {
|
|
1741
|
+
const links = brokenLinksBetween(input.classConstructor, ancestor);
|
|
1742
|
+
const intermediates = links.length > 0 ? ` (${links.join(", ")})` : "";
|
|
1743
|
+
return `[moost] ${name} has no constructor param metadata, but its ancestor ${ancestor.name} declares ${count} constructor param(s) — the inherited constructor would be invoked with zero resolved arguments (dependencies undefined). The parent-params fallback crosses one level at a time: add @Inherit() to the intermediate class(es)${intermediates} or re-declare the constructor with its param decorators.`;
|
|
1744
|
+
}
|
|
1745
|
+
return `[moost] ${name} extends ${ancestor.name} whose constructor declares ${count} DI param(s), but ${name} carries no Moost metadata of its own — it is not seen as injectable and the constructor params will not resolve. Add @Inherit() to ${name} or re-declare the constructor.`;
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Bind-time inheritance audit (IMPROVEMENTS.md §3): detects the two real traps
|
|
1749
|
+
* of subclassing decorated classes — parent routes silently dropping without a
|
|
1750
|
+
* working `@Inherit()` bridge, and parent constructor params silently not
|
|
1751
|
+
* resolving. Pure and warn-only: findings join the D1 collector and
|
|
1752
|
+
* `Moost.init()` logs them as warnings (they never reject `init()`).
|
|
1753
|
+
*/ function auditInheritance(input) {
|
|
1754
|
+
return [auditRouteDrop(input), auditLostCtorParams(input)].filter((f) => f !== void 0);
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1476
1757
|
//#endregion
|
|
1477
1758
|
//#region packages/moost/src/moost.ts
|
|
1478
1759
|
function _define_property(obj, key, value) {
|
|
@@ -1486,6 +1767,16 @@ function _define_property(obj, key, value) {
|
|
|
1486
1767
|
return obj;
|
|
1487
1768
|
}
|
|
1488
1769
|
/**
|
|
1770
|
+
* Detects the object registration form of `registerControllers`: a plain
|
|
1771
|
+
* object (no class prototype) carrying a `controllers` array. Controller
|
|
1772
|
+
* instances are class instances and never match, so all pre-existing
|
|
1773
|
+
* registration forms bind unchanged.
|
|
1774
|
+
*/ function isControllersGroup(entry) {
|
|
1775
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return false;
|
|
1776
|
+
const proto = Object.getPrototypeOf(entry);
|
|
1777
|
+
return (proto === Object.prototype || proto === null) && Array.isArray(entry.controllers);
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1489
1780
|
* ## Moost
|
|
1490
1781
|
* Main moostjs class that serves as a shell for Moost Adapters
|
|
1491
1782
|
*
|
|
@@ -1595,10 +1886,18 @@ function _define_property(obj, key, value) {
|
|
|
1595
1886
|
if (constructor) this.setProvideRegistry((0, _prostojs_infact.createProvideRegistry)([constructor, () => a]));
|
|
1596
1887
|
if (typeof a.getProvideRegistry === "function") this.setProvideRegistry(a.getProvideRegistry());
|
|
1597
1888
|
}
|
|
1598
|
-
this.unregisteredControllers.unshift(this);
|
|
1599
|
-
|
|
1889
|
+
this.unregisteredControllers.unshift({ controller: this });
|
|
1890
|
+
let auditError;
|
|
1891
|
+
try {
|
|
1892
|
+
await this.bindControllers();
|
|
1893
|
+
} finally {
|
|
1894
|
+
registerDiagnosticsSource(this);
|
|
1895
|
+
auditError = this.flushParamAudit();
|
|
1896
|
+
}
|
|
1897
|
+
if (auditError) throw new Error(auditError);
|
|
1600
1898
|
await this.runInitHooks();
|
|
1601
1899
|
for (const a of this.adapters) await (a.onInit && a.onInit(this));
|
|
1900
|
+
this.initialized = true;
|
|
1602
1901
|
}
|
|
1603
1902
|
/**
|
|
1604
1903
|
* Runs every `@MoostInit`-decorated controller method exactly once, after all
|
|
@@ -1617,6 +1916,31 @@ function _define_property(obj, key, value) {
|
|
|
1617
1916
|
await instance[hook.method](...args);
|
|
1618
1917
|
});
|
|
1619
1918
|
}
|
|
1919
|
+
/**
|
|
1920
|
+
* D1 audit of a DI-instantiated controller class' constructor params.
|
|
1921
|
+
* Findings are collected for `init()` to flush. Returns `true` when the
|
|
1922
|
+
* bind-time SINGLETON instantiation must be skipped: in `'error'` mode a
|
|
1923
|
+
* fatal-capable finding guarantees `init()` rejects with the aggregated
|
|
1924
|
+
* audit error (naming class and param), which the generic infact
|
|
1925
|
+
* instantiation error would otherwise preempt.
|
|
1926
|
+
*/ collectConstructorAudit(className, classMeta) {
|
|
1927
|
+
if (this.paramAuditMode === "off" || !classMeta?.injectable) return false;
|
|
1928
|
+
const findings = auditParams(classMeta.params, { className });
|
|
1929
|
+
this.paramAuditFindings.push(...findings);
|
|
1930
|
+
return this.paramAuditMode === "error" && findings.some((f) => f.severity === "fatal-capable");
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Flushes D1 findings collected during binding: every finding is logged as a
|
|
1934
|
+
* warning; in `'error'` mode, fatal-capable findings are folded into one
|
|
1935
|
+
* aggregate error message listing all of them, returned for `init()` to
|
|
1936
|
+
* throw (`init()` owns the precedence between this and a bind error).
|
|
1937
|
+
*/ flushParamAudit() {
|
|
1938
|
+
const findings = this.paramAuditFindings;
|
|
1939
|
+
this.paramAuditFindings = [];
|
|
1940
|
+
for (const f of findings) this.logger.warn(f.message);
|
|
1941
|
+
const fatal = findings.filter((f) => f.severity === "fatal-capable");
|
|
1942
|
+
if (fatal.length > 0 && this.paramAuditMode === "error") return formatParamAuditError(fatal);
|
|
1943
|
+
}
|
|
1620
1944
|
async bindControllers() {
|
|
1621
1945
|
const thisMeta = getMoostMate().read(this);
|
|
1622
1946
|
const provide = {
|
|
@@ -1627,15 +1951,8 @@ function _define_property(obj, key, value) {
|
|
|
1627
1951
|
...thisMeta?.replace,
|
|
1628
1952
|
...this.replace
|
|
1629
1953
|
};
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
let controller = _controller;
|
|
1633
|
-
if (Array.isArray(_controller) && typeof _controller[0] === "string") {
|
|
1634
|
-
newPrefix = _controller[0];
|
|
1635
|
-
controller = _controller[1];
|
|
1636
|
-
}
|
|
1637
|
-
await this.bindController(controller, provide, replace, this.options?.globalPrefix || "", newPrefix);
|
|
1638
|
-
}
|
|
1954
|
+
const globalPrefix = this.options?.globalPrefix || "";
|
|
1955
|
+
for (const { controller, prependPrefix, replaceOwnPrefix } of this.unregisteredControllers) await this.bindController(controller, provide, replace, prependPrefix ? `${globalPrefix}/${prependPrefix}` : globalPrefix, replaceOwnPrefix);
|
|
1639
1956
|
this.unregisteredControllers = [];
|
|
1640
1957
|
}
|
|
1641
1958
|
async bindController(controller, provide, replace, globalPrefix, replaceOwnPrefix) {
|
|
@@ -1650,7 +1967,7 @@ function _define_property(obj, key, value) {
|
|
|
1650
1967
|
replace,
|
|
1651
1968
|
customData: { pipes }
|
|
1652
1969
|
};
|
|
1653
|
-
if (isControllerConsructor && (classMeta?.injectable === "SINGLETON" || classMeta?.injectable === true)) await (0, _wooksjs_event_core.createEventContext)({ logger: this.logger }, async () => {
|
|
1970
|
+
if (!(isControllerConsructor && this.collectConstructorAudit(controller.name, classMeta)) && isControllerConsructor && (classMeta?.injectable === "SINGLETON" || classMeta?.injectable === true)) await (0, _wooksjs_event_core.createEventContext)({ logger: this.logger }, async () => {
|
|
1654
1971
|
setControllerContext(this, "bindController", "", { prefix: computedPrefix });
|
|
1655
1972
|
instance = await infact.get(controller, infactOpts);
|
|
1656
1973
|
});
|
|
@@ -1660,7 +1977,7 @@ function _define_property(obj, key, value) {
|
|
|
1660
1977
|
}
|
|
1661
1978
|
const getInstance = instance ? () => instance : async () => await infact.get(controller, { ...infactOpts });
|
|
1662
1979
|
const classConstructor = (0, _prostojs_mate.isConstructor)(controller) ? controller : (0, _prostojs_mate.getConstructor)(controller);
|
|
1663
|
-
|
|
1980
|
+
const controllerOverview = await bindControllerMethods({
|
|
1664
1981
|
getInstance,
|
|
1665
1982
|
classConstructor,
|
|
1666
1983
|
adapters: this.adapters,
|
|
@@ -1672,7 +1989,15 @@ function _define_property(obj, key, value) {
|
|
|
1672
1989
|
replace: classMeta?.replace,
|
|
1673
1990
|
logger: this.logger,
|
|
1674
1991
|
moostInstance: this,
|
|
1675
|
-
registerInitHook: (hook) => this.initHooks.push(hook)
|
|
1992
|
+
registerInitHook: (hook) => this.initHooks.push(hook),
|
|
1993
|
+
reportParamAudit: this.paramAuditMode === "off" ? void 0 : (findings) => this.paramAuditFindings.push(...findings)
|
|
1994
|
+
});
|
|
1995
|
+
this.controllersOverview.push(controllerOverview);
|
|
1996
|
+
if (this.inheritanceAuditMode !== "off") this.paramAuditFindings.push(...auditInheritance({
|
|
1997
|
+
classConstructor,
|
|
1998
|
+
classMeta,
|
|
1999
|
+
ownHandlersCount: controllerOverview.handlers.length,
|
|
2000
|
+
diInstantiated: isControllerConsructor
|
|
1676
2001
|
}));
|
|
1677
2002
|
this.handlerOverviewIndex = void 0;
|
|
1678
2003
|
if (classMeta?.importController) {
|
|
@@ -1740,9 +2065,18 @@ function _define_property(obj, key, value) {
|
|
|
1740
2065
|
}
|
|
1741
2066
|
/**
|
|
1742
2067
|
* Register new entries to provide as dependency injections
|
|
2068
|
+
*
|
|
2069
|
+
* Ordering rule: call this **before `init()`**. `init()` snapshots the
|
|
2070
|
+
* provide registry once when binding controllers, so entries added later are
|
|
2071
|
+
* never seen by already-bound controllers (sibling registration order does
|
|
2072
|
+
* not matter — only the before/after-`init()` boundary does). To scope
|
|
2073
|
+
* providers to part of the app, use class-level `@Provide` on a parent
|
|
2074
|
+
* controller — it flows parent → child through `@ImportController`, never
|
|
2075
|
+
* to siblings.
|
|
1743
2076
|
* @param provide - Provide Registry (use createProvideRegistry from '\@prostojs/infact')
|
|
1744
2077
|
* @returns
|
|
1745
2078
|
*/ setProvideRegistry(provide) {
|
|
2079
|
+
if (this.initialized) this.logger.warn("[moost] setProvideRegistry() called after init() — already-bound controllers will not see these providers. Register providers before init(), or provide them via @Provide on a parent controller.");
|
|
1746
2080
|
this.provide = {
|
|
1747
2081
|
...this.provide,
|
|
1748
2082
|
...provide
|
|
@@ -1751,9 +2085,14 @@ function _define_property(obj, key, value) {
|
|
|
1751
2085
|
}
|
|
1752
2086
|
/**
|
|
1753
2087
|
* Register replace classes to provide as dependency injections
|
|
2088
|
+
*
|
|
2089
|
+
* Ordering rule: call this **before `init()`**. `init()` snapshots the
|
|
2090
|
+
* replace registry once when binding controllers, so replacements added
|
|
2091
|
+
* later are never seen by already-bound controllers.
|
|
1754
2092
|
* @param replace - Replace Registry (use createReplaceRegistry from '\@prostojs/infact')
|
|
1755
2093
|
* @returns
|
|
1756
2094
|
*/ setReplaceRegistry(replace) {
|
|
2095
|
+
if (this.initialized) this.logger.warn("[moost] setReplaceRegistry() called after init() — already-bound controllers will not see these replacements. Register replacements before init().");
|
|
1757
2096
|
this.replace = {
|
|
1758
2097
|
...this.replace,
|
|
1759
2098
|
...replace
|
|
@@ -1761,11 +2100,48 @@ function _define_property(obj, key, value) {
|
|
|
1761
2100
|
return this;
|
|
1762
2101
|
}
|
|
1763
2102
|
/**
|
|
1764
|
-
* Register controllers (similar to
|
|
1765
|
-
*
|
|
2103
|
+
* Register controllers with the app (similar to the `@ImportController` decorator).
|
|
2104
|
+
*
|
|
2105
|
+
* Accepted forms (mixable in one call):
|
|
2106
|
+
*
|
|
2107
|
+
* 1. **Class or instance** — `registerControllers(UsersController)`.
|
|
2108
|
+
* Mounted at `globalPrefix + '/' + own @Controller prefix`.
|
|
2109
|
+
*
|
|
2110
|
+
* 2. **Tuple `[prefix, controller]`** — `registerControllers(['api/users', UsersController])`.
|
|
2111
|
+
* **IMPORTANT: the string REPLACES the controller's own `@Controller(...)` prefix — it does
|
|
2112
|
+
* NOT prepend to it.** `['api', UsersController]` mounts a `@Controller('users')` class at
|
|
2113
|
+
* `/api`, not `/api/users`, so every tuple registration must repeat the full path.
|
|
2114
|
+
* To compose prefixes instead, use the object form below.
|
|
2115
|
+
*
|
|
2116
|
+
* 3. **Object group `{ prefix, controllers, mode? }`** —
|
|
2117
|
+
* `registerControllers({ prefix: 'api', controllers: [UsersController] })`.
|
|
2118
|
+
* Registers every entry of `controllers` under `prefix`:
|
|
2119
|
+
* - `mode: 'prepend'` (default) composes the prefixes:
|
|
2120
|
+
* `globalPrefix + '/' + prefix + '/' + own @Controller prefix`
|
|
2121
|
+
* (a `@Controller('users')` class mounts at `/api/users`);
|
|
2122
|
+
* - `mode: 'replace'` replaces each controller's own prefix with `prefix`
|
|
2123
|
+
* (same semantics as the tuple form).
|
|
2124
|
+
*
|
|
2125
|
+
* The object form is detected only for plain objects with a `controllers` array, so
|
|
2126
|
+
* controller classes, instances and tuples keep working unchanged. To mount the whole
|
|
2127
|
+
* app under one segment, prefer the `globalPrefix` option (see {@link TMoostOptions}).
|
|
2128
|
+
*
|
|
2129
|
+
* @param controllers - controllers to register: classes, instances,
|
|
2130
|
+
* `[prefix, controller]` tuples or `{ prefix, controllers, mode? }` groups
|
|
1766
2131
|
* @returns
|
|
1767
2132
|
*/ registerControllers(...controllers) {
|
|
1768
|
-
this.unregisteredControllers.push(
|
|
2133
|
+
for (const entry of controllers) if (Array.isArray(entry) && typeof entry[0] === "string") this.unregisteredControllers.push({
|
|
2134
|
+
controller: entry[1],
|
|
2135
|
+
replaceOwnPrefix: entry[0]
|
|
2136
|
+
});
|
|
2137
|
+
else if (isControllersGroup(entry)) for (const controller of entry.controllers) this.unregisteredControllers.push(entry.mode === "replace" ? {
|
|
2138
|
+
controller,
|
|
2139
|
+
replaceOwnPrefix: entry.prefix
|
|
2140
|
+
} : {
|
|
2141
|
+
controller,
|
|
2142
|
+
prependPrefix: entry.prefix
|
|
2143
|
+
});
|
|
2144
|
+
else this.unregisteredControllers.push({ controller: entry });
|
|
1769
2145
|
return this;
|
|
1770
2146
|
}
|
|
1771
2147
|
logMappedHandler(eventName, classConstructor, method, stroke, prefix) {
|
|
@@ -1774,7 +2150,9 @@ function _define_property(obj, key, value) {
|
|
|
1774
2150
|
this.logger.info(`${prefix || ""}${c}${eventName} ${"\x1B[0m\x1B[2m\x1B[32m" + c}→ ${classConstructor.name}.${"\x1B[36m" + c}${method}[32m()${coff}`);
|
|
1775
2151
|
}
|
|
1776
2152
|
constructor(options) {
|
|
1777
|
-
super(), _define_property(this, "options", void 0), _define_property(this, "logger", void 0), _define_property(this, "pipes", void 0), _define_property(this, "interceptors", void 0), _define_property(this, "adapters", void 0), _define_property(this, "controllersOverview", void 0), _define_property(this, "handlerOverviewIndex", void 0), _define_property(this, "initHooks", void 0), _define_property(this, "provide", void 0), _define_property(this, "replace", void 0), _define_property(this, "unregisteredControllers", void 0), _define_property(this, "globalInterceptorHandler", void 0), this.options = options, this.pipes = Array.from(sharedPipes), this.interceptors = [], this.adapters = [], this.controllersOverview = [], this.initHooks = [], this.provide = (0, _prostojs_infact.createProvideRegistry)([_prostojs_infact.Infact, getMoostInfact], [_prostojs_mate.Mate, getMoostMate]), this.replace = {}, this.unregisteredControllers = [];
|
|
2153
|
+
super(), _define_property(this, "options", void 0), _define_property(this, "logger", void 0), _define_property(this, "pipes", void 0), _define_property(this, "interceptors", void 0), _define_property(this, "adapters", void 0), _define_property(this, "controllersOverview", void 0), _define_property(this, "handlerOverviewIndex", void 0), _define_property(this, "initHooks", void 0), _define_property(this, "provide", void 0), _define_property(this, "replace", void 0), _define_property(this, "unregisteredControllers", void 0), _define_property(this, "paramAuditFindings", void 0), _define_property(this, "paramAuditMode", void 0), _define_property(this, "inheritanceAuditMode", void 0), _define_property(this, "initialized", void 0), _define_property(this, "globalInterceptorHandler", void 0), this.options = options, this.pipes = Array.from(sharedPipes), this.interceptors = [], this.adapters = [], this.controllersOverview = [], this.initHooks = [], this.provide = (0, _prostojs_infact.createProvideRegistry)([_prostojs_infact.Infact, getMoostInfact], [_prostojs_mate.Mate, getMoostMate]), this.replace = {}, this.unregisteredControllers = [], this.paramAuditFindings = [], this.initialized = false;
|
|
2154
|
+
this.paramAuditMode = resolveParamAuditMode(options?.diagnostics?.paramTypes);
|
|
2155
|
+
this.inheritanceAuditMode = options?.diagnostics?.inheritance || "warn";
|
|
1778
2156
|
this.logger = options?.logger || getDefaultLogger(`[2m[35mmoost`);
|
|
1779
2157
|
setDefaultLogger(this.logger);
|
|
1780
2158
|
const mate = getMoostMate();
|
|
@@ -1880,6 +2258,7 @@ exports.Interceptor = Interceptor;
|
|
|
1880
2258
|
exports.InterceptorHandler = InterceptorHandler;
|
|
1881
2259
|
exports.Label = Label;
|
|
1882
2260
|
exports.LoggerTopic = LoggerTopic;
|
|
2261
|
+
exports.MOOST_MODULE_IDENTITY_KEY = MOOST_MODULE_IDENTITY_KEY;
|
|
1883
2262
|
exports.Moost = Moost;
|
|
1884
2263
|
exports.MoostInit = MoostInit;
|
|
1885
2264
|
exports.OnError = OnError;
|
|
@@ -2017,6 +2396,8 @@ exports.setControllerContext = setControllerContext;
|
|
|
2017
2396
|
exports.setInfactLoggingOptions = setInfactLoggingOptions;
|
|
2018
2397
|
exports.setInterceptResult = setInterceptResult;
|
|
2019
2398
|
exports.setOvertake = setOvertake;
|
|
2399
|
+
exports.stampModuleIdentity = stampModuleIdentity;
|
|
2400
|
+
exports.stampOnce = stampOnce;
|
|
2020
2401
|
exports.useControllerContext = useControllerContext;
|
|
2021
2402
|
exports.useHandlerPaths = useHandlerPaths;
|
|
2022
2403
|
exports.useInterceptResult = useInterceptResult;
|