moost 0.6.44 → 0.6.46
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 +122 -25
- package/dist/index.d.ts +94 -14
- package/dist/index.mjs +122 -25
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -48,7 +48,7 @@ let stamped = false;
|
|
|
48
48
|
if (stamped) return;
|
|
49
49
|
stamped = true;
|
|
50
50
|
stampModuleIdentity({
|
|
51
|
-
version: "0.6.
|
|
51
|
+
version: "0.6.46",
|
|
52
52
|
path: typeof __filename === "string" ? __filename : require("url").pathToFileURL(__filename).href
|
|
53
53
|
});
|
|
54
54
|
}
|
|
@@ -2323,6 +2323,7 @@ function _define_property(obj, key, value) {
|
|
|
2323
2323
|
}
|
|
2324
2324
|
if (typeof a.getProvideRegistry === "function") this.setProvideRegistry(a.getProvideRegistry());
|
|
2325
2325
|
}
|
|
2326
|
+
this.initHookPhase = "pending";
|
|
2326
2327
|
this.unregisteredControllers.unshift({ controller: this });
|
|
2327
2328
|
let auditError;
|
|
2328
2329
|
try {
|
|
@@ -2337,16 +2338,36 @@ function _define_property(obj, key, value) {
|
|
|
2337
2338
|
this.initialized = true;
|
|
2338
2339
|
}
|
|
2339
2340
|
/**
|
|
2340
|
-
* Runs every
|
|
2341
|
-
*
|
|
2342
|
-
*
|
|
2343
|
-
*
|
|
2344
|
-
* init context (no interceptors; params
|
|
2345
|
-
*
|
|
2341
|
+
* Runs every init hook exactly once, after all controllers are bound
|
|
2342
|
+
* (complete `getControllersOverview()`) and before the `adapter.onInit`
|
|
2343
|
+
* loop: `@MoostInit` controller methods and functions registered with
|
|
2344
|
+
* {@link addInitHook}. Hooks run in ascending `priority`, then registration
|
|
2345
|
+
* order. Each runs inside a synthetic init context (no interceptors; params
|
|
2346
|
+
* of `@MoostInit` methods resolve via the RESOLVE pipe only). Hooks added
|
|
2347
|
+
* while the pass runs are picked up. A throwing hook rejects `init()`
|
|
2348
|
+
* (fail-fast).
|
|
2346
2349
|
*/ async runInitHooks() {
|
|
2347
|
-
|
|
2348
|
-
const
|
|
2349
|
-
|
|
2350
|
+
this.initHookPhase = "running";
|
|
2351
|
+
const done = /* @__PURE__ */ new Set();
|
|
2352
|
+
try {
|
|
2353
|
+
for (;;) {
|
|
2354
|
+
let next;
|
|
2355
|
+
for (const hook of this.initHooks) if (!done.has(hook) && (!next || hook.priority < next.priority)) next = hook;
|
|
2356
|
+
if (!next) break;
|
|
2357
|
+
done.add(next);
|
|
2358
|
+
await this.runInitHook(next);
|
|
2359
|
+
}
|
|
2360
|
+
} finally {
|
|
2361
|
+
this.initHookPhase = "done";
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
async runInitHook(hook) {
|
|
2365
|
+
await (0, _wooksjs_event_core.createEventContext)({ logger: this.logger }, async () => {
|
|
2366
|
+
if (hook.kind === "fn") {
|
|
2367
|
+
setControllerContext(this, "init", "", { prefix: "" });
|
|
2368
|
+
await hook.fn(this);
|
|
2369
|
+
return;
|
|
2370
|
+
}
|
|
2350
2371
|
const instance = await hook.getInstance();
|
|
2351
2372
|
setControllerContext(instance, hook.method, "", { prefix: hook.computedPrefix });
|
|
2352
2373
|
const args = hook.resolveArgs ? await hook.resolveArgs() : [];
|
|
@@ -2354,6 +2375,37 @@ function _define_property(obj, key, value) {
|
|
|
2354
2375
|
});
|
|
2355
2376
|
}
|
|
2356
2377
|
/**
|
|
2378
|
+
* ### addInitHook
|
|
2379
|
+
* Programmatic counterpart of `@MoostInit`: runs `fn` once during `init()`,
|
|
2380
|
+
* after every controller is bound (complete `getControllersOverview()`) and
|
|
2381
|
+
* before the adapters' `onInit`, in the same pass as `@MoostInit` hooks:
|
|
2382
|
+
* ascending `priority` (default 0), then registration order. Runs inside the
|
|
2383
|
+
* same synthetic init context (controller context = the app; no
|
|
2384
|
+
* interceptors, no request composables). A throwing hook rejects `init()`.
|
|
2385
|
+
*
|
|
2386
|
+
* May be called at any time:
|
|
2387
|
+
* - before the hook pass starts (including from a controller constructor
|
|
2388
|
+
* during binding) — queued;
|
|
2389
|
+
* - while the pass runs (from another hook) — runs later in the same pass;
|
|
2390
|
+
* - after the pass finished — runs immediately (asynchronously, in its own
|
|
2391
|
+
* init context); a failure is logged, since there is no `init()` left to
|
|
2392
|
+
* reject.
|
|
2393
|
+
*
|
|
2394
|
+
* No de-duplication: registering the same function twice runs it twice.
|
|
2395
|
+
* Hooks re-run on re-init exactly like `@MoostInit` hooks.
|
|
2396
|
+
* @since 0.6.46
|
|
2397
|
+
*/ addInitHook(fn, opts) {
|
|
2398
|
+
const hook = {
|
|
2399
|
+
kind: "fn",
|
|
2400
|
+
priority: opts?.priority ?? 0,
|
|
2401
|
+
fn
|
|
2402
|
+
};
|
|
2403
|
+
this.initHooks.push(hook);
|
|
2404
|
+
if (this.initHookPhase === "done") this.runInitHook(hook).catch((error) => {
|
|
2405
|
+
this.logger.error(`Late init hook failed: ${errorMessage(error)}`);
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2357
2409
|
* ### dispose
|
|
2358
2410
|
* Graceful shutdown: stops the adapters, then runs every `@MoostDispose`
|
|
2359
2411
|
* hook of every singleton this app can reach — DI registry singletons
|
|
@@ -2457,15 +2509,8 @@ function _define_property(obj, key, value) {
|
|
|
2457
2509
|
if (fatal.length > 0 && this.paramAuditMode === "error") return formatParamAuditError(fatal);
|
|
2458
2510
|
}
|
|
2459
2511
|
async bindControllers() {
|
|
2460
|
-
const
|
|
2461
|
-
const
|
|
2462
|
-
...thisMeta?.provide,
|
|
2463
|
-
...this.provide
|
|
2464
|
-
};
|
|
2465
|
-
const replace = {
|
|
2466
|
-
...thisMeta?.replace,
|
|
2467
|
-
...this.replace
|
|
2468
|
-
};
|
|
2512
|
+
const provide = this.appProvideRegistry();
|
|
2513
|
+
const replace = this.appReplaceRegistry();
|
|
2469
2514
|
const globalPrefix = this.options?.globalPrefix || "";
|
|
2470
2515
|
for (const { controller, prependPrefix, replaceOwnPrefix } of this.unregisteredControllers) await this.bindController(controller, provide, replace, prependPrefix ? `${globalPrefix}/${prependPrefix}` : globalPrefix, replaceOwnPrefix);
|
|
2471
2516
|
this.unregisteredControllers = [];
|
|
@@ -2523,7 +2568,7 @@ function _define_property(obj, key, value) {
|
|
|
2523
2568
|
...classMeta.provide
|
|
2524
2569
|
};
|
|
2525
2570
|
const mergedReplace = {
|
|
2526
|
-
...this.
|
|
2571
|
+
...this.appReplaceRegistry(),
|
|
2527
2572
|
...classMeta.replace
|
|
2528
2573
|
};
|
|
2529
2574
|
for (const ic of classMeta.importController) if (ic.typeResolver) {
|
|
@@ -2590,10 +2635,17 @@ function _define_property(obj, key, value) {
|
|
|
2590
2635
|
* controller — it flows parent → child through `@ImportController`, never
|
|
2591
2636
|
* to siblings.
|
|
2592
2637
|
* @param provide - Provide Registry (use createProvideRegistry from '\@prostojs/infact')
|
|
2638
|
+
* @param opts - `{ override: false }` registers a default: used only when neither `@Provide`
|
|
2639
|
+
* on the app subclass nor a normal `setProvideRegistry` entry exists for the token,
|
|
2640
|
+
* regardless of call order. @since 0.6.45
|
|
2593
2641
|
* @returns
|
|
2594
|
-
*/ setProvideRegistry(provide) {
|
|
2642
|
+
*/ setProvideRegistry(provide, opts) {
|
|
2595
2643
|
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.");
|
|
2596
|
-
this.
|
|
2644
|
+
if (opts?.override === false) this.defaultProvide = {
|
|
2645
|
+
...this.defaultProvide,
|
|
2646
|
+
...provide
|
|
2647
|
+
};
|
|
2648
|
+
else this.provide = {
|
|
2597
2649
|
...this.provide,
|
|
2598
2650
|
...provide
|
|
2599
2651
|
};
|
|
@@ -2606,16 +2658,61 @@ function _define_property(obj, key, value) {
|
|
|
2606
2658
|
* replace registry once when binding controllers, so replacements added
|
|
2607
2659
|
* later are never seen by already-bound controllers.
|
|
2608
2660
|
* @param replace - Replace Registry (use createReplaceRegistry from '\@prostojs/infact')
|
|
2661
|
+
* @param opts - `{ override: false }` registers a default: used only when neither `@Replace`
|
|
2662
|
+
* on the app subclass nor a normal `setReplaceRegistry` entry exists for the class,
|
|
2663
|
+
* regardless of call order. @since 0.6.45
|
|
2609
2664
|
* @returns
|
|
2610
|
-
*/ setReplaceRegistry(replace) {
|
|
2665
|
+
*/ setReplaceRegistry(replace, opts) {
|
|
2611
2666
|
if (this.initialized) this.logger.warn("[moost] setReplaceRegistry() called after init() — already-bound controllers will not see these replacements. Register replacements before init().");
|
|
2612
|
-
this.
|
|
2667
|
+
if (opts?.override === false) this.defaultReplace = {
|
|
2668
|
+
...this.defaultReplace,
|
|
2669
|
+
...replace
|
|
2670
|
+
};
|
|
2671
|
+
else this.replace = {
|
|
2613
2672
|
...this.replace,
|
|
2614
2673
|
...replace
|
|
2615
2674
|
};
|
|
2616
2675
|
return this;
|
|
2617
2676
|
}
|
|
2618
2677
|
/**
|
|
2678
|
+
* Effective app-level replace registry, lowest to highest precedence: defaults
|
|
2679
|
+
* (`override: false`), `@Replace` on the app subclass, `setReplaceRegistry()` entries.
|
|
2680
|
+
* A controller's own `@Replace` is NOT app-level (it only reaches that controller's direct imports).
|
|
2681
|
+
*/ appReplaceRegistry() {
|
|
2682
|
+
return {
|
|
2683
|
+
...this.defaultReplace,
|
|
2684
|
+
...getMoostMate().read(this)?.replace,
|
|
2685
|
+
...this.replace
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
/** Effective app-level provide registry (same layering as `appReplaceRegistry`). */ appProvideRegistry() {
|
|
2689
|
+
return {
|
|
2690
|
+
...this.defaultProvide,
|
|
2691
|
+
...getMoostMate().read(this)?.provide,
|
|
2692
|
+
...this.provide
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
/**
|
|
2696
|
+
* The class `type` is replaced with app-wide (one hop, like the DI container), or `undefined`.
|
|
2697
|
+
* Works before and after `init()`; never warns. Per-controller `@Replace` is not reported.
|
|
2698
|
+
* @since 0.6.45
|
|
2699
|
+
*/ getReplacement(type) {
|
|
2700
|
+
return this.appReplaceRegistry()[(0, _prostojs_infact.getClassKey)(type)];
|
|
2701
|
+
}
|
|
2702
|
+
/**
|
|
2703
|
+
* `getReplacement(type) !== undefined`.
|
|
2704
|
+
* @since 0.6.45
|
|
2705
|
+
*/ hasReplacement(type) {
|
|
2706
|
+
return this.getReplacement(type) !== void 0;
|
|
2707
|
+
}
|
|
2708
|
+
/**
|
|
2709
|
+
* Frozen shallow copy of the effective app-level replace registry
|
|
2710
|
+
* (keys are `getClassKey(Class)` symbols). Mutating it never affects the app.
|
|
2711
|
+
* @since 0.6.45
|
|
2712
|
+
*/ getReplaceRegistry() {
|
|
2713
|
+
return Object.freeze(this.appReplaceRegistry());
|
|
2714
|
+
}
|
|
2715
|
+
/**
|
|
2619
2716
|
* Register controllers with the app (similar to the `@ImportController` decorator).
|
|
2620
2717
|
*
|
|
2621
2718
|
* Accepted forms (mixable in one call):
|
|
@@ -2666,7 +2763,7 @@ function _define_property(obj, key, value) {
|
|
|
2666
2763
|
this.logger.info(`${prefix || ""}${c}${eventName} ${"\x1B[0m\x1B[2m\x1B[32m" + c}→ ${classConstructor.name}.${"\x1B[36m" + c}${method}[32m()${coff}`);
|
|
2667
2764
|
}
|
|
2668
2765
|
constructor(options) {
|
|
2669
|
-
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, "singletonInstances", void 0), _define_property(this, "disposePromise", 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, this.singletonInstances = /* @__PURE__ */ new Set();
|
|
2766
|
+
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, "initHookPhase", void 0), _define_property(this, "provide", void 0), _define_property(this, "replace", void 0), _define_property(this, "defaultProvide", void 0), _define_property(this, "defaultReplace", 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, "singletonInstances", void 0), _define_property(this, "disposePromise", 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.initHookPhase = "pending", this.provide = (0, _prostojs_infact.createProvideRegistry)([_prostojs_infact.Infact, getMoostInfact], [_prostojs_mate.Mate, getMoostMate]), this.replace = {}, this.defaultProvide = {}, this.defaultReplace = {}, this.unregisteredControllers = [], this.paramAuditFindings = [], this.initialized = false, this.singletonInstances = /* @__PURE__ */ new Set();
|
|
2670
2767
|
this.paramAuditMode = resolveParamAuditMode(options?.diagnostics?.paramTypes);
|
|
2671
2768
|
this.inheritanceAuditMode = options?.diagnostics?.inheritance || "warn";
|
|
2672
2769
|
this.logger = options?.logger || getDefaultLogger(`[2m[35mmoost`);
|
package/dist/index.d.ts
CHANGED
|
@@ -468,17 +468,25 @@ interface TParamAuditFinding {
|
|
|
468
468
|
type TParamAuditMode = 'error' | 'warn' | 'off';
|
|
469
469
|
|
|
470
470
|
/**
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
* applied; params
|
|
474
|
-
|
|
475
|
-
|
|
471
|
+
* An init hook collected for `Moost.init()`: either a `@MoostInit`-decorated
|
|
472
|
+
* controller method (collected at bind time) or a function registered with
|
|
473
|
+
* `Moost.addInitHook`. Interceptors are not applied; params of method hooks
|
|
474
|
+
* resolve through the RESOLVE pipe only.
|
|
475
|
+
*/
|
|
476
|
+
type TInitHook = TMethodInitHook | TFnInitHook;
|
|
477
|
+
interface TMethodInitHook {
|
|
478
|
+
kind?: 'method';
|
|
476
479
|
priority: number;
|
|
477
480
|
method: string;
|
|
478
481
|
computedPrefix: string;
|
|
479
482
|
getInstance: () => Promise<TObject> | TObject;
|
|
480
483
|
resolveArgs?: () => unknown[] | Promise<unknown[]>;
|
|
481
484
|
}
|
|
485
|
+
interface TFnInitHook {
|
|
486
|
+
kind: 'fn';
|
|
487
|
+
priority: number;
|
|
488
|
+
fn: (app: never) => unknown;
|
|
489
|
+
}
|
|
482
490
|
|
|
483
491
|
/** Mode for the bind-time inheritance audit (see `TMoostOptions['diagnostics']`). */
|
|
484
492
|
type TInheritanceAuditMode = 'warn' | 'off';
|
|
@@ -623,6 +631,16 @@ interface TControllerRegistration {
|
|
|
623
631
|
*/
|
|
624
632
|
prependPrefix?: string;
|
|
625
633
|
}
|
|
634
|
+
/** Options of `setProvideRegistry` / `setReplaceRegistry`. @since 0.6.45 */
|
|
635
|
+
interface TRegistryMergeOptions {
|
|
636
|
+
/**
|
|
637
|
+
* `true` (default): entries replace existing ones for the same token.
|
|
638
|
+
* `false`: register a lowest-precedence default, used only when neither the app subclass's
|
|
639
|
+
* class-level decorator nor a normal `set*Registry()` entry exists for the token — regardless
|
|
640
|
+
* of call order.
|
|
641
|
+
*/
|
|
642
|
+
override?: boolean;
|
|
643
|
+
}
|
|
626
644
|
/**
|
|
627
645
|
* ## Moost
|
|
628
646
|
* Main moostjs class that serves as a shell for Moost Adapters
|
|
@@ -682,8 +700,12 @@ declare class Moost extends Hookable {
|
|
|
682
700
|
protected controllersOverview: TControllerOverview[];
|
|
683
701
|
protected handlerOverviewIndex?: Map<TFunction, Map<string, THandlerOverview[]>>;
|
|
684
702
|
protected initHooks: TInitHook[];
|
|
703
|
+
protected initHookPhase: 'pending' | 'running' | 'done';
|
|
685
704
|
protected provide: TProvideRegistry;
|
|
686
705
|
protected replace: TReplaceRegistry;
|
|
706
|
+
/** Lowest-precedence layers, filled by `set*Registry(reg, { override: false })`. */
|
|
707
|
+
protected defaultProvide: TProvideRegistry;
|
|
708
|
+
protected defaultReplace: TReplaceRegistry;
|
|
687
709
|
protected unregisteredControllers: TControllerRegistration[];
|
|
688
710
|
/** D1 param-audit findings collected while binding controllers, flushed by `init()`. */
|
|
689
711
|
protected paramAuditFindings: TParamAuditFinding[];
|
|
@@ -731,14 +753,41 @@ declare class Moost extends Hookable {
|
|
|
731
753
|
*/
|
|
732
754
|
init(): Promise<void>;
|
|
733
755
|
/**
|
|
734
|
-
* Runs every
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
*
|
|
738
|
-
* init context (no interceptors; params
|
|
739
|
-
*
|
|
756
|
+
* Runs every init hook exactly once, after all controllers are bound
|
|
757
|
+
* (complete `getControllersOverview()`) and before the `adapter.onInit`
|
|
758
|
+
* loop: `@MoostInit` controller methods and functions registered with
|
|
759
|
+
* {@link addInitHook}. Hooks run in ascending `priority`, then registration
|
|
760
|
+
* order. Each runs inside a synthetic init context (no interceptors; params
|
|
761
|
+
* of `@MoostInit` methods resolve via the RESOLVE pipe only). Hooks added
|
|
762
|
+
* while the pass runs are picked up. A throwing hook rejects `init()`
|
|
763
|
+
* (fail-fast).
|
|
740
764
|
*/
|
|
741
765
|
protected runInitHooks(): Promise<void>;
|
|
766
|
+
protected runInitHook(hook: TInitHook): Promise<void>;
|
|
767
|
+
/**
|
|
768
|
+
* ### addInitHook
|
|
769
|
+
* Programmatic counterpart of `@MoostInit`: runs `fn` once during `init()`,
|
|
770
|
+
* after every controller is bound (complete `getControllersOverview()`) and
|
|
771
|
+
* before the adapters' `onInit`, in the same pass as `@MoostInit` hooks:
|
|
772
|
+
* ascending `priority` (default 0), then registration order. Runs inside the
|
|
773
|
+
* same synthetic init context (controller context = the app; no
|
|
774
|
+
* interceptors, no request composables). A throwing hook rejects `init()`.
|
|
775
|
+
*
|
|
776
|
+
* May be called at any time:
|
|
777
|
+
* - before the hook pass starts (including from a controller constructor
|
|
778
|
+
* during binding) — queued;
|
|
779
|
+
* - while the pass runs (from another hook) — runs later in the same pass;
|
|
780
|
+
* - after the pass finished — runs immediately (asynchronously, in its own
|
|
781
|
+
* init context); a failure is logged, since there is no `init()` left to
|
|
782
|
+
* reject.
|
|
783
|
+
*
|
|
784
|
+
* No de-duplication: registering the same function twice runs it twice.
|
|
785
|
+
* Hooks re-run on re-init exactly like `@MoostInit` hooks.
|
|
786
|
+
* @since 0.6.46
|
|
787
|
+
*/
|
|
788
|
+
addInitHook(fn: (app: this) => unknown, opts?: {
|
|
789
|
+
priority?: number;
|
|
790
|
+
}): void;
|
|
742
791
|
/**
|
|
743
792
|
* ### dispose
|
|
744
793
|
* Graceful shutdown: stops the adapters, then runs every `@MoostDispose`
|
|
@@ -833,9 +882,12 @@ declare class Moost extends Hookable {
|
|
|
833
882
|
* controller — it flows parent → child through `@ImportController`, never
|
|
834
883
|
* to siblings.
|
|
835
884
|
* @param provide - Provide Registry (use createProvideRegistry from '\@prostojs/infact')
|
|
885
|
+
* @param opts - `{ override: false }` registers a default: used only when neither `@Provide`
|
|
886
|
+
* on the app subclass nor a normal `setProvideRegistry` entry exists for the token,
|
|
887
|
+
* regardless of call order. @since 0.6.45
|
|
836
888
|
* @returns
|
|
837
889
|
*/
|
|
838
|
-
setProvideRegistry(provide: TProvideRegistry): this;
|
|
890
|
+
setProvideRegistry(provide: TProvideRegistry, opts?: TRegistryMergeOptions): this;
|
|
839
891
|
/**
|
|
840
892
|
* Register replace classes to provide as dependency injections
|
|
841
893
|
*
|
|
@@ -843,9 +895,37 @@ declare class Moost extends Hookable {
|
|
|
843
895
|
* replace registry once when binding controllers, so replacements added
|
|
844
896
|
* later are never seen by already-bound controllers.
|
|
845
897
|
* @param replace - Replace Registry (use createReplaceRegistry from '\@prostojs/infact')
|
|
898
|
+
* @param opts - `{ override: false }` registers a default: used only when neither `@Replace`
|
|
899
|
+
* on the app subclass nor a normal `setReplaceRegistry` entry exists for the class,
|
|
900
|
+
* regardless of call order. @since 0.6.45
|
|
846
901
|
* @returns
|
|
847
902
|
*/
|
|
848
|
-
setReplaceRegistry(replace: TReplaceRegistry): this;
|
|
903
|
+
setReplaceRegistry(replace: TReplaceRegistry, opts?: TRegistryMergeOptions): this;
|
|
904
|
+
/**
|
|
905
|
+
* Effective app-level replace registry, lowest to highest precedence: defaults
|
|
906
|
+
* (`override: false`), `@Replace` on the app subclass, `setReplaceRegistry()` entries.
|
|
907
|
+
* A controller's own `@Replace` is NOT app-level (it only reaches that controller's direct imports).
|
|
908
|
+
*/
|
|
909
|
+
protected appReplaceRegistry(): TReplaceRegistry;
|
|
910
|
+
/** Effective app-level provide registry (same layering as `appReplaceRegistry`). */
|
|
911
|
+
protected appProvideRegistry(): TProvideRegistry;
|
|
912
|
+
/**
|
|
913
|
+
* The class `type` is replaced with app-wide (one hop, like the DI container), or `undefined`.
|
|
914
|
+
* Works before and after `init()`; never warns. Per-controller `@Replace` is not reported.
|
|
915
|
+
* @since 0.6.45
|
|
916
|
+
*/
|
|
917
|
+
getReplacement<T>(type: TClassConstructor<T>): TClassConstructor<T> | undefined;
|
|
918
|
+
/**
|
|
919
|
+
* `getReplacement(type) !== undefined`.
|
|
920
|
+
* @since 0.6.45
|
|
921
|
+
*/
|
|
922
|
+
hasReplacement(type: TClassConstructor): boolean;
|
|
923
|
+
/**
|
|
924
|
+
* Frozen shallow copy of the effective app-level replace registry
|
|
925
|
+
* (keys are `getClassKey(Class)` symbols). Mutating it never affects the app.
|
|
926
|
+
* @since 0.6.45
|
|
927
|
+
*/
|
|
928
|
+
getReplaceRegistry(): Readonly<TReplaceRegistry>;
|
|
849
929
|
/**
|
|
850
930
|
* Register controllers with the app (similar to the `@ImportController` decorator).
|
|
851
931
|
*
|
|
@@ -1541,4 +1621,4 @@ declare function createLogger(opts?: Partial<TProstoLoggerOptions>): ProstoLogge
|
|
|
1541
1621
|
declare const loggerConsoleTransport: _prostojs_logger.TProstoLoggerTransportFn<any>;
|
|
1542
1622
|
|
|
1543
1623
|
export { After, ApplyDecorators, Before, Circular, Const, ConstFactory, Controller, Description, HandlerPaths, Id, ImportController, Inherit, Inject, InjectEventLogger, InjectFromScope, InjectMoost, InjectMoostLogger, InjectScopeVars, Injectable, Intercept, Interceptor, InterceptorHandler, Label, LoggerTopic, MOOST_ADAPTER_BRAND, MOOST_MODULE_IDENTITY_KEY, Moost, MoostDispose, MoostInit, OnError, Optional, Overtake, Param, Params, Pipe, Provide, Replace, Required, Resolve, Response, TInterceptorPriority, TPipePriority, Value, createLogger, defineAfterInterceptor, defineBeforeInterceptor, defineErrorInterceptor, defineInfactScope, defineInterceptor, defineMoostEventHandler, definePipeFn, disposeInstances, forkEventContext, getHandlerPaths, getInfactScopeVars, getInfactSingletonInstances, getInstanceOwnMethods, getInstanceOwnProps, getMoostInfact, getMoostMate, getNewMoostInfact, globalKey, isThenable, loggerConsoleTransport, mergeSorted, registerEventScope, resolvePipe, setControllerContext, setInfactLoggingOptions, setInterceptResult, setOvertake, stampModuleIdentity, stampOnce, useControllerContext, useHandlerPaths, useInterceptResult, useOvertake, useScopeId, withControllerContext };
|
|
1544
|
-
export type { TAny, TAnyFn, TClassConstructor, TContextInjectorHook, TControllerOverview, TControllerRegistration, TControllersGroup, TDisposeError, TDisposeOptions, TDisposeResult, TEmpty, TForkEventContextOptions, TFunction, TGetHandlerPathsOptions, TInjectableScope, TInterceptorAfterFn, TInterceptorBeforeFn, TInterceptorData, TInterceptorDef, TInterceptorDefFactory, TInterceptorEntry, TInterceptorErrorFn, TIsolatedSlot, TLogger, TMoostAdapter, TMoostAdapterOptions, TMoostEventHandlerHookOptions, TMoostEventHandlerOptions, TMoostHandler, TMoostMetadata, TMoostModuleIdentity, TMoostOptions, TMoostParamsMetadata, TObject, TOvertakeFn, TPipeData, TPipeFn, TPipeMetas, TPrimitives, TWithControllerContextOptions };
|
|
1624
|
+
export type { TAny, TAnyFn, TClassConstructor, TContextInjectorHook, TControllerOverview, TControllerRegistration, TControllersGroup, TDisposeError, TDisposeOptions, TDisposeResult, TEmpty, TForkEventContextOptions, TFunction, TGetHandlerPathsOptions, TInjectableScope, TInterceptorAfterFn, TInterceptorBeforeFn, TInterceptorData, TInterceptorDef, TInterceptorDefFactory, TInterceptorEntry, TInterceptorErrorFn, TIsolatedSlot, TLogger, TMoostAdapter, TMoostAdapterOptions, TMoostEventHandlerHookOptions, TMoostEventHandlerOptions, TMoostHandler, TMoostMetadata, TMoostModuleIdentity, TMoostOptions, TMoostParamsMetadata, TObject, TOvertakeFn, TPipeData, TPipeFn, TPipeMetas, TPrimitives, TRegistryMergeOptions, TWithControllerContextOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -47,7 +47,7 @@ let stamped = false;
|
|
|
47
47
|
if (stamped) return;
|
|
48
48
|
stamped = true;
|
|
49
49
|
stampModuleIdentity({
|
|
50
|
-
version: "0.6.
|
|
50
|
+
version: "0.6.46",
|
|
51
51
|
path: typeof __filename === "string" ? __filename : import.meta.url
|
|
52
52
|
});
|
|
53
53
|
}
|
|
@@ -2322,6 +2322,7 @@ function _define_property(obj, key, value) {
|
|
|
2322
2322
|
}
|
|
2323
2323
|
if (typeof a.getProvideRegistry === "function") this.setProvideRegistry(a.getProvideRegistry());
|
|
2324
2324
|
}
|
|
2325
|
+
this.initHookPhase = "pending";
|
|
2325
2326
|
this.unregisteredControllers.unshift({ controller: this });
|
|
2326
2327
|
let auditError;
|
|
2327
2328
|
try {
|
|
@@ -2336,16 +2337,36 @@ function _define_property(obj, key, value) {
|
|
|
2336
2337
|
this.initialized = true;
|
|
2337
2338
|
}
|
|
2338
2339
|
/**
|
|
2339
|
-
* Runs every
|
|
2340
|
-
*
|
|
2341
|
-
*
|
|
2342
|
-
*
|
|
2343
|
-
* init context (no interceptors; params
|
|
2344
|
-
*
|
|
2340
|
+
* Runs every init hook exactly once, after all controllers are bound
|
|
2341
|
+
* (complete `getControllersOverview()`) and before the `adapter.onInit`
|
|
2342
|
+
* loop: `@MoostInit` controller methods and functions registered with
|
|
2343
|
+
* {@link addInitHook}. Hooks run in ascending `priority`, then registration
|
|
2344
|
+
* order. Each runs inside a synthetic init context (no interceptors; params
|
|
2345
|
+
* of `@MoostInit` methods resolve via the RESOLVE pipe only). Hooks added
|
|
2346
|
+
* while the pass runs are picked up. A throwing hook rejects `init()`
|
|
2347
|
+
* (fail-fast).
|
|
2345
2348
|
*/ async runInitHooks() {
|
|
2346
|
-
|
|
2347
|
-
const
|
|
2348
|
-
|
|
2349
|
+
this.initHookPhase = "running";
|
|
2350
|
+
const done = /* @__PURE__ */ new Set();
|
|
2351
|
+
try {
|
|
2352
|
+
for (;;) {
|
|
2353
|
+
let next;
|
|
2354
|
+
for (const hook of this.initHooks) if (!done.has(hook) && (!next || hook.priority < next.priority)) next = hook;
|
|
2355
|
+
if (!next) break;
|
|
2356
|
+
done.add(next);
|
|
2357
|
+
await this.runInitHook(next);
|
|
2358
|
+
}
|
|
2359
|
+
} finally {
|
|
2360
|
+
this.initHookPhase = "done";
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
async runInitHook(hook) {
|
|
2364
|
+
await createEventContext$1({ logger: this.logger }, async () => {
|
|
2365
|
+
if (hook.kind === "fn") {
|
|
2366
|
+
setControllerContext(this, "init", "", { prefix: "" });
|
|
2367
|
+
await hook.fn(this);
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2349
2370
|
const instance = await hook.getInstance();
|
|
2350
2371
|
setControllerContext(instance, hook.method, "", { prefix: hook.computedPrefix });
|
|
2351
2372
|
const args = hook.resolveArgs ? await hook.resolveArgs() : [];
|
|
@@ -2353,6 +2374,37 @@ function _define_property(obj, key, value) {
|
|
|
2353
2374
|
});
|
|
2354
2375
|
}
|
|
2355
2376
|
/**
|
|
2377
|
+
* ### addInitHook
|
|
2378
|
+
* Programmatic counterpart of `@MoostInit`: runs `fn` once during `init()`,
|
|
2379
|
+
* after every controller is bound (complete `getControllersOverview()`) and
|
|
2380
|
+
* before the adapters' `onInit`, in the same pass as `@MoostInit` hooks:
|
|
2381
|
+
* ascending `priority` (default 0), then registration order. Runs inside the
|
|
2382
|
+
* same synthetic init context (controller context = the app; no
|
|
2383
|
+
* interceptors, no request composables). A throwing hook rejects `init()`.
|
|
2384
|
+
*
|
|
2385
|
+
* May be called at any time:
|
|
2386
|
+
* - before the hook pass starts (including from a controller constructor
|
|
2387
|
+
* during binding) — queued;
|
|
2388
|
+
* - while the pass runs (from another hook) — runs later in the same pass;
|
|
2389
|
+
* - after the pass finished — runs immediately (asynchronously, in its own
|
|
2390
|
+
* init context); a failure is logged, since there is no `init()` left to
|
|
2391
|
+
* reject.
|
|
2392
|
+
*
|
|
2393
|
+
* No de-duplication: registering the same function twice runs it twice.
|
|
2394
|
+
* Hooks re-run on re-init exactly like `@MoostInit` hooks.
|
|
2395
|
+
* @since 0.6.46
|
|
2396
|
+
*/ addInitHook(fn, opts) {
|
|
2397
|
+
const hook = {
|
|
2398
|
+
kind: "fn",
|
|
2399
|
+
priority: opts?.priority ?? 0,
|
|
2400
|
+
fn
|
|
2401
|
+
};
|
|
2402
|
+
this.initHooks.push(hook);
|
|
2403
|
+
if (this.initHookPhase === "done") this.runInitHook(hook).catch((error) => {
|
|
2404
|
+
this.logger.error(`Late init hook failed: ${errorMessage(error)}`);
|
|
2405
|
+
});
|
|
2406
|
+
}
|
|
2407
|
+
/**
|
|
2356
2408
|
* ### dispose
|
|
2357
2409
|
* Graceful shutdown: stops the adapters, then runs every `@MoostDispose`
|
|
2358
2410
|
* hook of every singleton this app can reach — DI registry singletons
|
|
@@ -2456,15 +2508,8 @@ function _define_property(obj, key, value) {
|
|
|
2456
2508
|
if (fatal.length > 0 && this.paramAuditMode === "error") return formatParamAuditError(fatal);
|
|
2457
2509
|
}
|
|
2458
2510
|
async bindControllers() {
|
|
2459
|
-
const
|
|
2460
|
-
const
|
|
2461
|
-
...thisMeta?.provide,
|
|
2462
|
-
...this.provide
|
|
2463
|
-
};
|
|
2464
|
-
const replace = {
|
|
2465
|
-
...thisMeta?.replace,
|
|
2466
|
-
...this.replace
|
|
2467
|
-
};
|
|
2511
|
+
const provide = this.appProvideRegistry();
|
|
2512
|
+
const replace = this.appReplaceRegistry();
|
|
2468
2513
|
const globalPrefix = this.options?.globalPrefix || "";
|
|
2469
2514
|
for (const { controller, prependPrefix, replaceOwnPrefix } of this.unregisteredControllers) await this.bindController(controller, provide, replace, prependPrefix ? `${globalPrefix}/${prependPrefix}` : globalPrefix, replaceOwnPrefix);
|
|
2470
2515
|
this.unregisteredControllers = [];
|
|
@@ -2522,7 +2567,7 @@ function _define_property(obj, key, value) {
|
|
|
2522
2567
|
...classMeta.provide
|
|
2523
2568
|
};
|
|
2524
2569
|
const mergedReplace = {
|
|
2525
|
-
...this.
|
|
2570
|
+
...this.appReplaceRegistry(),
|
|
2526
2571
|
...classMeta.replace
|
|
2527
2572
|
};
|
|
2528
2573
|
for (const ic of classMeta.importController) if (ic.typeResolver) {
|
|
@@ -2589,10 +2634,17 @@ function _define_property(obj, key, value) {
|
|
|
2589
2634
|
* controller — it flows parent → child through `@ImportController`, never
|
|
2590
2635
|
* to siblings.
|
|
2591
2636
|
* @param provide - Provide Registry (use createProvideRegistry from '\@prostojs/infact')
|
|
2637
|
+
* @param opts - `{ override: false }` registers a default: used only when neither `@Provide`
|
|
2638
|
+
* on the app subclass nor a normal `setProvideRegistry` entry exists for the token,
|
|
2639
|
+
* regardless of call order. @since 0.6.45
|
|
2592
2640
|
* @returns
|
|
2593
|
-
*/ setProvideRegistry(provide) {
|
|
2641
|
+
*/ setProvideRegistry(provide, opts) {
|
|
2594
2642
|
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.");
|
|
2595
|
-
this.
|
|
2643
|
+
if (opts?.override === false) this.defaultProvide = {
|
|
2644
|
+
...this.defaultProvide,
|
|
2645
|
+
...provide
|
|
2646
|
+
};
|
|
2647
|
+
else this.provide = {
|
|
2596
2648
|
...this.provide,
|
|
2597
2649
|
...provide
|
|
2598
2650
|
};
|
|
@@ -2605,16 +2657,61 @@ function _define_property(obj, key, value) {
|
|
|
2605
2657
|
* replace registry once when binding controllers, so replacements added
|
|
2606
2658
|
* later are never seen by already-bound controllers.
|
|
2607
2659
|
* @param replace - Replace Registry (use createReplaceRegistry from '\@prostojs/infact')
|
|
2660
|
+
* @param opts - `{ override: false }` registers a default: used only when neither `@Replace`
|
|
2661
|
+
* on the app subclass nor a normal `setReplaceRegistry` entry exists for the class,
|
|
2662
|
+
* regardless of call order. @since 0.6.45
|
|
2608
2663
|
* @returns
|
|
2609
|
-
*/ setReplaceRegistry(replace) {
|
|
2664
|
+
*/ setReplaceRegistry(replace, opts) {
|
|
2610
2665
|
if (this.initialized) this.logger.warn("[moost] setReplaceRegistry() called after init() — already-bound controllers will not see these replacements. Register replacements before init().");
|
|
2611
|
-
this.
|
|
2666
|
+
if (opts?.override === false) this.defaultReplace = {
|
|
2667
|
+
...this.defaultReplace,
|
|
2668
|
+
...replace
|
|
2669
|
+
};
|
|
2670
|
+
else this.replace = {
|
|
2612
2671
|
...this.replace,
|
|
2613
2672
|
...replace
|
|
2614
2673
|
};
|
|
2615
2674
|
return this;
|
|
2616
2675
|
}
|
|
2617
2676
|
/**
|
|
2677
|
+
* Effective app-level replace registry, lowest to highest precedence: defaults
|
|
2678
|
+
* (`override: false`), `@Replace` on the app subclass, `setReplaceRegistry()` entries.
|
|
2679
|
+
* A controller's own `@Replace` is NOT app-level (it only reaches that controller's direct imports).
|
|
2680
|
+
*/ appReplaceRegistry() {
|
|
2681
|
+
return {
|
|
2682
|
+
...this.defaultReplace,
|
|
2683
|
+
...getMoostMate().read(this)?.replace,
|
|
2684
|
+
...this.replace
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
2687
|
+
/** Effective app-level provide registry (same layering as `appReplaceRegistry`). */ appProvideRegistry() {
|
|
2688
|
+
return {
|
|
2689
|
+
...this.defaultProvide,
|
|
2690
|
+
...getMoostMate().read(this)?.provide,
|
|
2691
|
+
...this.provide
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* The class `type` is replaced with app-wide (one hop, like the DI container), or `undefined`.
|
|
2696
|
+
* Works before and after `init()`; never warns. Per-controller `@Replace` is not reported.
|
|
2697
|
+
* @since 0.6.45
|
|
2698
|
+
*/ getReplacement(type) {
|
|
2699
|
+
return this.appReplaceRegistry()[getClassKey$1(type)];
|
|
2700
|
+
}
|
|
2701
|
+
/**
|
|
2702
|
+
* `getReplacement(type) !== undefined`.
|
|
2703
|
+
* @since 0.6.45
|
|
2704
|
+
*/ hasReplacement(type) {
|
|
2705
|
+
return this.getReplacement(type) !== void 0;
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Frozen shallow copy of the effective app-level replace registry
|
|
2709
|
+
* (keys are `getClassKey(Class)` symbols). Mutating it never affects the app.
|
|
2710
|
+
* @since 0.6.45
|
|
2711
|
+
*/ getReplaceRegistry() {
|
|
2712
|
+
return Object.freeze(this.appReplaceRegistry());
|
|
2713
|
+
}
|
|
2714
|
+
/**
|
|
2618
2715
|
* Register controllers with the app (similar to the `@ImportController` decorator).
|
|
2619
2716
|
*
|
|
2620
2717
|
* Accepted forms (mixable in one call):
|
|
@@ -2665,7 +2762,7 @@ function _define_property(obj, key, value) {
|
|
|
2665
2762
|
this.logger.info(`${prefix || ""}${c}${eventName} ${"\x1B[0m\x1B[2m\x1B[32m" + c}→ ${classConstructor.name}.${"\x1B[36m" + c}${method}[32m()${coff}`);
|
|
2666
2763
|
}
|
|
2667
2764
|
constructor(options) {
|
|
2668
|
-
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, "singletonInstances", void 0), _define_property(this, "disposePromise", 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, this.singletonInstances = /* @__PURE__ */ new Set();
|
|
2765
|
+
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, "initHookPhase", void 0), _define_property(this, "provide", void 0), _define_property(this, "replace", void 0), _define_property(this, "defaultProvide", void 0), _define_property(this, "defaultReplace", 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, "singletonInstances", void 0), _define_property(this, "disposePromise", 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.initHookPhase = "pending", this.provide = createProvideRegistry$1([Infact, getMoostInfact], [Mate, getMoostMate]), this.replace = {}, this.defaultProvide = {}, this.defaultReplace = {}, this.unregisteredControllers = [], this.paramAuditFindings = [], this.initialized = false, this.singletonInstances = /* @__PURE__ */ new Set();
|
|
2669
2766
|
this.paramAuditMode = resolveParamAuditMode(options?.diagnostics?.paramTypes);
|
|
2670
2767
|
this.inheritanceAuditMode = options?.diagnostics?.inheritance || "warn";
|
|
2671
2768
|
this.logger = options?.logger || getDefaultLogger(`[2m[35mmoost`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moost",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.46",
|
|
4
4
|
"description": "moost",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"composables",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@wooksjs/event-http": "^0.7.26",
|
|
50
50
|
"@wooksjs/http-body": "^0.7.26",
|
|
51
51
|
"vitest": "3.2.7",
|
|
52
|
-
"@moostjs/event-http": "^0.6.
|
|
52
|
+
"@moostjs/event-http": "^0.6.46"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"pub": "pnpm publish --access public",
|