@noxfly/noxus 2.4.0 → 3.0.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +403 -341
  2. package/dist/app-injector-Bz3Upc0y.d.mts +125 -0
  3. package/dist/app-injector-Bz3Upc0y.d.ts +125 -0
  4. package/dist/child.d.mts +48 -22
  5. package/dist/child.d.ts +48 -22
  6. package/dist/child.js +1114 -1239
  7. package/dist/child.mjs +1090 -1193
  8. package/dist/main.d.mts +304 -261
  9. package/dist/main.d.ts +304 -261
  10. package/dist/main.js +1473 -1873
  11. package/dist/main.mjs +1423 -1791
  12. package/dist/renderer.d.mts +113 -2
  13. package/dist/renderer.d.ts +113 -2
  14. package/dist/renderer.js +144 -132
  15. package/dist/renderer.mjs +143 -132
  16. package/dist/request-BlTtiHbi.d.ts +112 -0
  17. package/dist/request-qJ9EiDZc.d.mts +112 -0
  18. package/package.json +7 -7
  19. package/src/DI/app-injector.ts +95 -106
  20. package/src/DI/injector-explorer.ts +100 -81
  21. package/src/DI/token.ts +53 -0
  22. package/src/app.ts +141 -131
  23. package/src/bootstrap.ts +79 -40
  24. package/src/decorators/controller.decorator.ts +38 -27
  25. package/src/decorators/guards.decorator.ts +5 -64
  26. package/src/decorators/injectable.decorator.ts +68 -15
  27. package/src/decorators/method.decorator.ts +40 -81
  28. package/src/decorators/middleware.decorator.ts +5 -72
  29. package/src/index.ts +3 -0
  30. package/src/main.ts +4 -11
  31. package/src/non-electron-process.ts +0 -1
  32. package/src/preload-bridge.ts +1 -1
  33. package/src/renderer-client.ts +2 -2
  34. package/src/renderer-events.ts +1 -1
  35. package/src/request.ts +3 -3
  36. package/src/router.ts +221 -369
  37. package/src/routes.ts +78 -0
  38. package/src/socket.ts +4 -4
  39. package/src/window/window-manager.ts +255 -0
  40. package/tsconfig.json +5 -10
  41. package/tsup.config.ts +2 -2
  42. package/dist/app-injector-B3MvgV3k.d.mts +0 -95
  43. package/dist/app-injector-B3MvgV3k.d.ts +0 -95
  44. package/dist/index-BxWQVi6C.d.ts +0 -253
  45. package/dist/index-DQBQQfMw.d.mts +0 -253
  46. package/src/decorators/inject.decorator.ts +0 -24
  47. package/src/decorators/injectable.metadata.ts +0 -15
  48. package/src/decorators/module.decorator.ts +0 -75
@@ -4,159 +4,148 @@
4
4
  * @author NoxFly
5
5
  */
6
6
 
7
- import 'reflect-metadata';
8
- import { INJECT_METADATA_KEY } from 'src/decorators/inject.decorator';
9
- import { InternalServerException } from 'src/exceptions';
10
- import { ForwardReference } from 'src/utils/forward-ref';
11
- import { Type } from 'src/utils/types';
7
+ import { ForwardReference } from '../utils/forward-ref';
8
+ import { Type } from '../utils/types';
9
+ import { Token, TokenKey } from './token';
12
10
 
13
11
  /**
14
- * Represents a lifetime of a binding in the dependency injection system.
15
- * It can be one of the following:
16
- * - 'singleton': The instance is created once and shared across the application.
17
- * - 'scope': The instance is created once per scope (e.g., per request).
18
- * - 'transient': A new instance is created every time it is requested.
12
+ * Lifetime of a binding in the DI container.
13
+ * - singleton: created once, shared for the lifetime of the app.
14
+ * - scope: created once per request scope.
15
+ * - transient: new instance every time it is resolved.
19
16
  */
20
17
  export type Lifetime = 'singleton' | 'scope' | 'transient';
21
18
 
22
19
  /**
23
- * Represents a binding in the dependency injection system.
24
- * It contains the lifetime of the binding, the implementation type, and optionally an instance.
20
+ * Internal representation of a registered binding.
25
21
  */
26
- export interface IBinding {
22
+ export interface IBinding<T = unknown> {
27
23
  lifetime: Lifetime;
28
- implementation: Type<unknown>;
29
- instance?: InstanceType<Type<unknown>>;
24
+ implementation: Type<T>;
25
+ /** Explicit constructor dependencies, declared by the class itself. */
26
+ deps: ReadonlyArray<TokenKey>;
27
+ instance?: T;
28
+ }
29
+
30
+ function keyOf<T>(k: TokenKey<T>): Type<T> | Token<T> {
31
+ return k;
30
32
  }
31
33
 
32
34
  /**
33
- * AppInjector is the root dependency injection container.
34
- * It is used to register and resolve dependencies in the application.
35
- * It supports different lifetimes for dependencies:
36
- * This should not be manually instantiated, outside of the framework.
37
- * Use the `RootInjector` instance instead.
35
+ * AppInjector is the core DI container.
36
+ * It no longer uses reflect-metadata all dependency information
37
+ * comes from explicitly declared `deps` arrays on each binding.
38
38
  */
39
39
  export class AppInjector {
40
- public bindings = new Map<Type<unknown>, IBinding>();
41
- public singletons = new Map<Type<unknown>, InstanceType<Type<unknown>>>();
42
- public scoped = new Map<Type<unknown>, InstanceType<Type<unknown>>>();
40
+ public readonly bindings = new Map<Type<unknown> | Token<unknown>, IBinding<unknown>>();
41
+ public readonly singletons = new Map<Type<unknown> | Token<unknown>, unknown>();
42
+ public readonly scoped = new Map<Type<unknown> | Token<unknown>, unknown>();
43
43
 
44
- constructor(
45
- public readonly name: string | null = null,
46
- ) {}
44
+ constructor(public readonly name: string | null = null) {}
47
45
 
48
46
  /**
49
- * Typically used to create a dependency injection scope
50
- * at the "scope" level (i.e., per-request lifetime).
51
- *
52
- * SHOULD NOT BE USED by anything else than the framework itself.
47
+ * Creates a child scope for per-request lifetime resolution.
53
48
  */
54
49
  public createScope(): AppInjector {
55
50
  const scope = new AppInjector();
56
- scope.bindings = this.bindings; // pass injectable declarations
57
- scope.singletons = this.singletons; // share parent's singletons to avoid recreating them
58
- // do not keep parent's scoped instances
51
+ (scope as any).bindings = this.bindings;
52
+ (scope as any).singletons = this.singletons;
59
53
  return scope;
60
54
  }
61
55
 
62
56
  /**
63
- * Called when resolving a dependency,
64
- * i.e., retrieving the instance of a given class.
57
+ * Registers a binding explicitly.
65
58
  */
66
- public resolve<T>(target: Type<T> | ForwardReference<T>): T {
67
- if (target instanceof ForwardReference) {
68
- return new Proxy({}, {
69
- get: (obj, prop, receiver) => {
70
- const realType = target.forwardRefFn();
71
- const instance = this.resolve(realType) as any;
72
- const value = Reflect.get(instance, prop, receiver);
73
-
74
- return typeof value === 'function' ? value.bind(instance) : value;
75
- },
76
- set: (obj, prop, value, receiver) => {
77
- const realType = target.forwardRefFn();
78
- const instance = this.resolve(realType) as any;
79
- return Reflect.set(instance, prop, value, receiver);
80
- },
81
- getPrototypeOf: () => {
82
- const realType = target.forwardRefFn();
83
- return (realType as any).prototype;
84
- }
85
- }) as T;
59
+ public register<T>(
60
+ key: TokenKey<T>,
61
+ implementation: Type<T>,
62
+ lifetime: Lifetime,
63
+ deps: ReadonlyArray<TokenKey> = [],
64
+ ): void {
65
+ const k = keyOf(key) as TokenKey<unknown>;
66
+ if (!this.bindings.has(k)) {
67
+ this.bindings.set(k, { lifetime, implementation: implementation as Type<unknown>, deps });
86
68
  }
69
+ }
87
70
 
88
- const binding = this.bindings.get(target);
89
-
90
- if(!binding) {
91
- if(target === undefined) {
92
- throw new InternalServerException(
93
- "Failed to resolve a dependency injection : Undefined target type.\n"
94
- + "This might be caused by a circular dependency."
95
- );
96
- }
71
+ /**
72
+ * Resolves a dependency by token or class reference.
73
+ */
74
+ public resolve<T>(target: TokenKey<T> | ForwardReference<T>): T {
75
+ if (target instanceof ForwardReference) {
76
+ return this._resolveForwardRef(target);
77
+ }
97
78
 
98
- const name = target.name || "unknown";
79
+ const k = keyOf(target) as TokenKey<unknown>;
80
+ const binding = this.bindings.get(k);
99
81
 
100
- throw new InternalServerException(
101
- `Failed to resolve a dependency injection : No binding for type ${name}.\n`
102
- + `Did you forget to use @Injectable() decorator ?`
82
+ if (!binding) {
83
+ const name = target instanceof Token ? target.description : (target as Type<unknown>).name ?? 'unknown';
84
+ throw new Error(
85
+ `[Noxus DI] No binding found for "${name}".\n`
86
+ + `Did you forget to declare it in @Injectable({ deps }) or in bootstrapApplication({ singletons })?`,
103
87
  );
104
88
  }
105
89
 
106
- switch(binding.lifetime) {
90
+ switch (binding.lifetime) {
107
91
  case 'transient':
108
- return this.instantiate(binding.implementation) as T;
92
+ return this._instantiate(binding) as T;
109
93
 
110
94
  case 'scope': {
111
- if(this.scoped.has(target)) {
112
- return this.scoped.get(target) as T;
113
- }
114
-
115
- const instance = this.instantiate(binding.implementation);
116
- this.scoped.set(target, instance);
117
-
118
- return instance as T;
95
+ if (this.scoped.has(k)) return this.scoped.get(k) as T;
96
+ const inst = this._instantiate(binding);
97
+ this.scoped.set(k, inst);
98
+ return inst as T;
119
99
  }
120
100
 
121
101
  case 'singleton': {
122
- if(binding.instance === undefined && this.name === 'root') {
123
- binding.instance = this.instantiate(binding.implementation);
124
- this.singletons.set(target, binding.instance);
102
+ if (this.singletons.has(k)) return this.singletons.get(k) as T;
103
+ const inst = this._instantiate(binding);
104
+ this.singletons.set(k, inst);
105
+ if (binding.instance === undefined) {
106
+ (binding as IBinding<unknown>).instance = inst as unknown;
125
107
  }
126
-
127
- return binding.instance as T;
108
+ return inst as T;
128
109
  }
129
110
  }
130
111
  }
131
112
 
132
- /**
133
- * Instantiates a class, resolving its dependencies.
134
- */
135
- private instantiate<T extends Type<unknown>>(target: T): InstanceType<T> {
136
- const paramTypes = Reflect.getMetadata('design:paramtypes', target) || [];
137
- const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];
138
-
139
- const params = paramTypes.map((paramType: any, index: number) => {
140
- const overrideToken = injectParams[index];
141
- const actualToken = overrideToken !== undefined ? overrideToken : paramType;
142
-
143
- return this.resolve(actualToken);
144
- });
113
+ // -------------------------------------------------------------------------
114
+
115
+ private _resolveForwardRef<T>(ref: ForwardReference<T>): T {
116
+ return new Proxy({} as object, {
117
+ get: (_obj, prop, receiver) => {
118
+ const realType = ref.forwardRefFn();
119
+ const instance = this.resolve(realType) as Record<string | symbol, unknown>;
120
+ const value = Reflect.get(instance, prop, receiver);
121
+ return typeof value === 'function' ? (value as Function).bind(instance) : value;
122
+ },
123
+ set: (_obj, prop, value, receiver) => {
124
+ const realType = ref.forwardRefFn();
125
+ const instance = this.resolve(realType) as object;
126
+ return Reflect.set(instance, prop, value, receiver);
127
+ },
128
+ getPrototypeOf: () => {
129
+ const realType = ref.forwardRefFn();
130
+ return (realType as unknown as { prototype: object }).prototype;
131
+ },
132
+ }) as T;
133
+ }
145
134
 
146
- return new target(...params) as InstanceType<T>;
135
+ private _instantiate<T>(binding: IBinding<T>): T {
136
+ const resolvedDeps = binding.deps.map((dep) => this.resolve(dep));
137
+ return new binding.implementation(...resolvedDeps) as T;
147
138
  }
148
139
  }
149
140
 
150
141
  /**
151
- * Injects a type from the dependency injection system.
152
- * This function is used to retrieve an instance of a type that has been registered in the dependency injection system.
153
- * It is typically used in the constructor of a class to inject dependencies.
154
- * @param t - The type to inject.
155
- * @returns An instance of the type.
156
- * @throws If the type is not registered in the dependency injection system.
142
+ * The global root injector. All singletons live here.
157
143
  */
158
- export function inject<T>(t: Type<T> | ForwardReference<T>): T {
144
+ export const RootInjector = new AppInjector('root');
145
+
146
+ /**
147
+ * Convenience function: resolve a token from the root injector.
148
+ */
149
+ export function inject<T>(t: TokenKey<T> | ForwardReference<T>): T {
159
150
  return RootInjector.resolve(t);
160
151
  }
161
-
162
- export const RootInjector = new AppInjector('root');
@@ -4,121 +4,140 @@
4
4
  * @author NoxFly
5
5
  */
6
6
 
7
- import { getControllerMetadata } from "src/decorators/controller.decorator";
8
- import { getInjectableMetadata } from "src/decorators/injectable.metadata";
9
- import { getRouteMetadata } from "src/decorators/method.decorator";
10
- import { getModuleMetadata } from "src/decorators/module.decorator";
11
- import { Lifetime, RootInjector } from "src/DI/app-injector";
12
- import { Router } from "src/router";
13
- import { Logger } from "src/utils/logger";
14
- import { Type } from "src/utils/types";
15
-
16
- interface PendingRegistration {
17
- target: Type<unknown>;
7
+ import { Lifetime, RootInjector } from './app-injector';
8
+ import { TokenKey } from './token';
9
+ import { Type } from '../utils/types';
10
+ import { Logger } from '../utils/logger';
11
+ import { Guard, Middleware } from "src/main";
12
+
13
+ export interface PendingRegistration {
14
+ key: TokenKey;
15
+ implementation: Type<unknown>;
18
16
  lifetime: Lifetime;
17
+ deps: ReadonlyArray<TokenKey>;
18
+ isController: boolean;
19
+ pathPrefix?: string;
19
20
  }
20
21
 
21
22
  /**
22
- * InjectorExplorer is a utility class that explores the dependency injection system at the startup.
23
- * It collects decorated classes during the import phase and defers their actual registration
24
- * and resolution to when {@link processPending} is called by bootstrapApplication.
23
+ * InjectorExplorer accumulates registrations emitted by decorators
24
+ * at import time, then flushes them in two phases (bind resolve)
25
+ * once bootstrapApplication triggers processing.
26
+ *
27
+ * Because deps are now explicit arrays (no reflect-metadata), this class
28
+ * no longer needs to introspect constructor parameter types.
25
29
  */
26
30
  export class InjectorExplorer {
27
31
  private static readonly pending: PendingRegistration[] = [];
28
32
  private static processed = false;
33
+ private static accumulating = false;
29
34
 
30
- /**
31
- * Enqueues a class for deferred registration.
32
- * Called by the @Injectable decorator at import time.
33
- *
34
- * If {@link processPending} has already been called (i.e. after bootstrap),
35
- * the class is registered immediately so that late dynamic imports
36
- * (e.g. middlewares loaded after bootstrap) work correctly.
37
- */
38
- public static enqueue(target: Type<unknown>, lifetime: Lifetime): void {
39
- if(InjectorExplorer.processed) {
40
- InjectorExplorer.registerImmediate(target, lifetime);
35
+ // -------------------------------------------------------------------------
36
+ // Public API
37
+ // -------------------------------------------------------------------------
38
+
39
+ public static enqueue(reg: PendingRegistration): void {
40
+ if (InjectorExplorer.processed && !InjectorExplorer.accumulating) {
41
+ InjectorExplorer._registerImmediate(reg);
41
42
  return;
42
43
  }
43
-
44
- InjectorExplorer.pending.push({ target, lifetime });
44
+ InjectorExplorer.pending.push(reg);
45
45
  }
46
46
 
47
47
  /**
48
- * Processes all pending registrations in two phases:
49
- * 1. Register all bindings (no instantiation) so every dependency is known.
50
- * 2. Resolve singletons, register controllers and log module readiness.
51
- *
52
- * This two-phase approach makes the system resilient to import ordering:
53
- * all bindings exist before any singleton is instantiated.
48
+ * Two-phase flush of all pending registrations collected at startup.
49
+ * Called by bootstrapApplication after app.whenReady().
54
50
  */
55
- public static processPending(): void {
56
- const queue = InjectorExplorer.pending;
57
-
58
- // Phase 1: register all bindings without instantiation
59
- for(const { target, lifetime } of queue) {
60
- if(!RootInjector.bindings.has(target)) {
61
- RootInjector.bindings.set(target, {
62
- implementation: target,
63
- lifetime
64
- });
65
- }
66
- }
51
+ public static processPending(singletonOverrides?: Map<TokenKey, unknown>): void {
52
+ const queue = [...InjectorExplorer.pending];
53
+ InjectorExplorer.pending.length = 0;
67
54
 
68
- // Phase 2: resolve singletons, register controllers, log modules
69
- for(const { target, lifetime } of queue) {
70
- InjectorExplorer.processRegistration(target, lifetime);
71
- }
55
+ InjectorExplorer._phaseOne(queue);
56
+ InjectorExplorer._phaseTwo(queue, singletonOverrides);
72
57
 
73
- queue.length = 0;
74
58
  InjectorExplorer.processed = true;
75
59
  }
76
60
 
61
+ /** Enters accumulation mode for lazy-loaded batches. */
62
+ public static beginAccumulate(): void {
63
+ InjectorExplorer.accumulating = true;
64
+ }
65
+
77
66
  /**
78
- * Registers a single class immediately (post-bootstrap path).
79
- * Used for classes discovered via late dynamic imports.
67
+ * Exits accumulation mode and flushes queued registrations
68
+ * with the same two-phase guarantee as processPending.
80
69
  */
81
- private static registerImmediate(target: Type<unknown>, lifetime: Lifetime): void {
82
- if(RootInjector.bindings.has(target)) {
83
- return;
70
+ public static flushAccumulated(
71
+ routeGuards: Guard[] = [],
72
+ routeMiddlewares: Middleware[] = [],
73
+ pathPrefix = '',
74
+ ): void {
75
+ InjectorExplorer.accumulating = false;
76
+ const queue = [...InjectorExplorer.pending];
77
+ InjectorExplorer.pending.length = 0;
78
+ InjectorExplorer._phaseOne(queue);
79
+
80
+ // Stamp the path prefix on controller registrations
81
+ for (const reg of queue) {
82
+ if (reg.isController) reg.pathPrefix = pathPrefix;
84
83
  }
85
84
 
86
- RootInjector.bindings.set(target, {
87
- implementation: target,
88
- lifetime
89
- });
90
-
91
- InjectorExplorer.processRegistration(target, lifetime);
85
+ InjectorExplorer._phaseTwo(queue, undefined, routeGuards, routeMiddlewares);
92
86
  }
93
87
 
94
- /**
95
- * Performs phase-2 work for a single registration: resolve singletons,
96
- * register controllers, and log module readiness.
97
- */
98
- private static processRegistration(target: Type<unknown>, lifetime: Lifetime): void {
99
- if(lifetime === 'singleton') {
100
- RootInjector.resolve(target);
101
- }
88
+ // -------------------------------------------------------------------------
89
+ // Private helpers
90
+ // -------------------------------------------------------------------------
102
91
 
103
- if(getModuleMetadata(target)) {
104
- Logger.log(`${target.name} dependencies initialized`);
105
- return;
92
+ /** Phase 1: register all bindings without instantiating anything. */
93
+ private static _phaseOne(queue: PendingRegistration[]): void {
94
+ for (const reg of queue) {
95
+ RootInjector.register(reg.key, reg.implementation, reg.lifetime, reg.deps);
106
96
  }
97
+ }
107
98
 
108
- const controllerMeta = getControllerMetadata(target);
99
+ /** Phase 2: resolve singletons and register controllers in the router. */
100
+ private static _phaseTwo(
101
+ queue: PendingRegistration[],
102
+ overrides?: Map<TokenKey, unknown>,
103
+ routeGuards: Guard[] = [],
104
+ routeMiddlewares: Middleware[] = [],
105
+ ): void {
106
+ for (const reg of queue) {
107
+ // Apply value overrides (e.g. singleton instances provided via bootstrapApplication config)
108
+ if (overrides?.has(reg.key)) {
109
+ const override = overrides.get(reg.key);
110
+ RootInjector.singletons.set(reg.key as any, override);
111
+ Logger.log(`Registered ${reg.implementation.name} as singleton (overridden)`);
112
+ continue;
113
+ }
109
114
 
110
- if(controllerMeta) {
111
- const router = RootInjector.resolve(Router);
112
- router?.registerController(target);
113
- return;
115
+ if (reg.lifetime === 'singleton') {
116
+ RootInjector.resolve(reg.key);
117
+ }
118
+
119
+ if (reg.isController) {
120
+ // Lazily import Router to avoid circular dependency at module load time
121
+ const { Router } = require('../router') as { Router: { prototype: { registerController(t: Type<unknown>): void } } };
122
+ const router = RootInjector.resolve(Router as any) as { registerController(t: Type<unknown>, pathPrefix: string, routeGuards: Guard[], routeMiddlewares: Middleware[]): void };
123
+ router.registerController(reg.implementation, reg.pathPrefix ?? '', routeGuards, routeMiddlewares);
124
+ } else if (reg.lifetime !== 'singleton') {
125
+ Logger.log(`Registered ${reg.implementation.name} as ${reg.lifetime}`);
126
+ }
114
127
  }
128
+ }
115
129
 
116
- if(getRouteMetadata(target).length > 0) {
117
- return;
130
+ private static _registerImmediate(reg: PendingRegistration): void {
131
+ RootInjector.register(reg.key, reg.implementation, reg.lifetime, reg.deps);
132
+
133
+ if (reg.lifetime === 'singleton') {
134
+ RootInjector.resolve(reg.key);
118
135
  }
119
136
 
120
- if(getInjectableMetadata(target)) {
121
- Logger.log(`Registered ${target.name} as ${lifetime}`);
137
+ if (reg.isController) {
138
+ const { Router } = require('../router') as { Router: { prototype: { registerController(t: Type<unknown>): void } } };
139
+ const router = RootInjector.resolve(Router as any) as { registerController(t: Type<unknown>): void };
140
+ router.registerController(reg.implementation);
122
141
  }
123
142
  }
124
143
  }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @copyright 2025 NoxFly
3
+ * @license MIT
4
+ * @author NoxFly
5
+ */
6
+
7
+ import { Type } from '../utils/types';
8
+
9
+ /**
10
+ * A DI token uniquely identifies a dependency.
11
+ * It can wrap a class (Type<T>) or be a named symbol token.
12
+ *
13
+ * Using tokens instead of reflect-metadata means dependencies are
14
+ * declared explicitly — no magic type inference, no emitDecoratorMetadata.
15
+ *
16
+ * @example
17
+ * // Class token (most common)
18
+ * const MY_SERVICE = token(MyService);
19
+ *
20
+ * // Named symbol token (for interfaces or non-class values)
21
+ * const DB_URL = token<string>('DB_URL');
22
+ */
23
+ export class Token<T> {
24
+ public readonly description: string;
25
+
26
+ constructor(
27
+ public readonly target: Type<T> | string,
28
+ ) {
29
+ this.description = typeof target === 'string' ? target : target.name;
30
+ }
31
+
32
+ public toString(): string {
33
+ return `Token(${this.description})`;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Creates a DI token for a class type or a named value.
39
+ *
40
+ * @example
41
+ * export const MY_SERVICE = token(MyService);
42
+ * export const DB_URL = token<string>('DB_URL');
43
+ */
44
+ export function token<T>(target: Type<T> | string): Token<T> {
45
+ return new Token<T>(target);
46
+ }
47
+
48
+ /**
49
+ * The key used to look up a class token in the registry.
50
+ * For class tokens, the key is the class constructor itself.
51
+ * For named tokens, the key is the Token instance.
52
+ */
53
+ export type TokenKey<T = unknown> = Type<T> | Token<T>;