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