@velajs/vela 0.4.2 → 0.5.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 (65) hide show
  1. package/dist/cache/cache.module.d.ts +4 -1
  2. package/dist/cache/cache.module.js +51 -9
  3. package/dist/config/config.module.d.ts +4 -1
  4. package/dist/config/config.module.js +40 -3
  5. package/dist/config/config.types.d.ts +1 -0
  6. package/dist/constants.d.ts +6 -1
  7. package/dist/constants.js +5 -0
  8. package/dist/container/container.d.ts +4 -0
  9. package/dist/container/container.js +52 -15
  10. package/dist/container/decorators.d.ts +3 -1
  11. package/dist/container/decorators.js +27 -6
  12. package/dist/container/index.d.ts +4 -2
  13. package/dist/container/index.js +4 -2
  14. package/dist/container/mixin.d.ts +24 -0
  15. package/dist/container/mixin.js +26 -0
  16. package/dist/container/module-ref.d.ts +21 -0
  17. package/dist/container/module-ref.js +48 -0
  18. package/dist/container/types.d.ts +10 -3
  19. package/dist/container/types.js +9 -0
  20. package/dist/cors/cors.module.js +2 -2
  21. package/dist/factory.js +36 -13
  22. package/dist/fetch/fetch.module.d.ts +6 -0
  23. package/dist/fetch/fetch.module.js +77 -0
  24. package/dist/fetch/fetch.service.d.ts +24 -0
  25. package/dist/fetch/fetch.service.js +145 -0
  26. package/dist/fetch/fetch.types.d.ts +24 -0
  27. package/dist/fetch/fetch.types.js +1 -0
  28. package/dist/fetch/index.d.ts +3 -0
  29. package/dist/fetch/index.js +2 -0
  30. package/dist/http/decorators.d.ts +64 -0
  31. package/dist/http/decorators.js +89 -1
  32. package/dist/http/index.d.ts +3 -1
  33. package/dist/http/index.js +2 -1
  34. package/dist/http/middleware-consumer.d.ts +36 -0
  35. package/dist/http/middleware-consumer.js +71 -0
  36. package/dist/http/route.manager.d.ts +13 -1
  37. package/dist/http/route.manager.js +153 -53
  38. package/dist/index.d.ts +11 -6
  39. package/dist/index.js +7 -4
  40. package/dist/metadata.d.ts +1 -1
  41. package/dist/module/decorators.d.ts +1 -0
  42. package/dist/module/decorators.js +24 -8
  43. package/dist/module/index.d.ts +2 -2
  44. package/dist/module/index.js +1 -1
  45. package/dist/module/module-loader.d.ts +9 -1
  46. package/dist/module/module-loader.js +107 -11
  47. package/dist/module/types.d.ts +13 -3
  48. package/dist/pipeline/index.d.ts +3 -2
  49. package/dist/pipeline/index.js +1 -1
  50. package/dist/pipeline/pipes.d.ts +22 -0
  51. package/dist/pipeline/pipes.js +50 -0
  52. package/dist/pipeline/tokens.d.ts +1 -1
  53. package/dist/pipeline/tokens.js +1 -1
  54. package/dist/pipeline/types.d.ts +16 -0
  55. package/dist/registry/metadata.registry.d.ts +7 -6
  56. package/dist/registry/metadata.registry.js +13 -0
  57. package/dist/registry/types.d.ts +1 -0
  58. package/dist/schedule/schedule.executor.d.ts +11 -2
  59. package/dist/schedule/schedule.executor.js +134 -19
  60. package/dist/schedule/schedule.module.d.ts +4 -1
  61. package/dist/schedule/schedule.module.js +39 -7
  62. package/dist/testing/testing.builder.js +31 -17
  63. package/dist/throttler/throttler.module.d.ts +2 -1
  64. package/dist/throttler/throttler.module.js +47 -9
  65. package/package.json +1 -1
@@ -1,5 +1,8 @@
1
- import type { DynamicModule } from '../module/types';
1
+ import type { AsyncModuleOptions, DynamicModule } from '../module/types';
2
2
  import type { CacheModuleOptions } from './cache.types';
3
3
  export declare class CacheModule {
4
4
  static forRoot(options?: CacheModuleOptions): DynamicModule;
5
+ static registerAsync(options: AsyncModuleOptions<CacheModuleOptions> & {
6
+ isGlobal?: boolean;
7
+ }): DynamicModule;
5
8
  }
@@ -6,16 +6,20 @@ import { CacheInterceptor } from "./cache.interceptor.js";
6
6
  import { CacheService } from "./cache.service.js";
7
7
  import { MemoryCacheStore } from "./cache.store.js";
8
8
  import { CACHE_MANAGER, CACHE_MODULE_OPTIONS } from "./cache.tokens.js";
9
+ function makeCacheModuleClass(name) {
10
+ const moduleClass = class {
11
+ };
12
+ Object.defineProperty(moduleClass, 'name', {
13
+ value: name
14
+ });
15
+ defineMetadata(METADATA_KEYS.MODULE, true, moduleClass);
16
+ return moduleClass;
17
+ }
9
18
  export class CacheModule {
10
19
  static forRoot(options = {}) {
11
20
  const { ttl = 5, max = 100, isGlobal = false } = options;
12
21
  const store = new MemoryCacheStore(ttl, max);
13
- const moduleClass = class CacheDynamicModule {
14
- };
15
- Object.defineProperty(moduleClass, 'name', {
16
- value: 'CacheModule'
17
- });
18
- defineMetadata(METADATA_KEYS.MODULE, true, moduleClass);
22
+ const moduleClass = makeCacheModuleClass('CacheModule');
19
23
  MetadataRegistry.setModuleOptions(moduleClass, {
20
24
  exports: [
21
25
  CACHE_MANAGER,
@@ -26,11 +30,11 @@ export class CacheModule {
26
30
  });
27
31
  const providers = [
28
32
  {
29
- token: CACHE_MANAGER,
33
+ provide: CACHE_MANAGER,
30
34
  useValue: store
31
35
  },
32
36
  {
33
- token: CACHE_MODULE_OPTIONS,
37
+ provide: CACHE_MODULE_OPTIONS,
34
38
  useValue: options
35
39
  },
36
40
  CacheService,
@@ -38,7 +42,45 @@ export class CacheModule {
38
42
  ];
39
43
  if (isGlobal) {
40
44
  providers.push({
41
- token: APP_INTERCEPTOR,
45
+ provide: APP_INTERCEPTOR,
46
+ useExisting: CacheInterceptor
47
+ });
48
+ }
49
+ return {
50
+ module: moduleClass,
51
+ providers
52
+ };
53
+ }
54
+ static registerAsync(options) {
55
+ const moduleClass = makeCacheModuleClass('CacheModule');
56
+ MetadataRegistry.setModuleOptions(moduleClass, {
57
+ imports: options.imports ?? [],
58
+ exports: [
59
+ CACHE_MANAGER,
60
+ CACHE_MODULE_OPTIONS,
61
+ CacheService,
62
+ CacheInterceptor
63
+ ]
64
+ });
65
+ const providers = [
66
+ {
67
+ provide: CACHE_MODULE_OPTIONS,
68
+ useFactory: options.useFactory,
69
+ inject: options.inject ?? []
70
+ },
71
+ {
72
+ provide: CACHE_MANAGER,
73
+ useFactory: (opts)=>new MemoryCacheStore(opts.ttl ?? 5, opts.max ?? 100),
74
+ inject: [
75
+ CACHE_MODULE_OPTIONS
76
+ ]
77
+ },
78
+ CacheService,
79
+ CacheInterceptor
80
+ ];
81
+ if (options.isGlobal) {
82
+ providers.push({
83
+ provide: APP_INTERCEPTOR,
42
84
  useExisting: CacheInterceptor
43
85
  });
44
86
  }
@@ -1,5 +1,8 @@
1
- import type { DynamicModule } from '../module/types';
1
+ import type { AsyncModuleOptions, DynamicModule } from '../module/types';
2
2
  import type { ConfigModuleOptions } from './config.types';
3
3
  export declare class ConfigModule {
4
4
  static forRoot<T extends Record<string, unknown>>(options: ConfigModuleOptions<T>): DynamicModule;
5
+ static forRootAsync<T extends Record<string, unknown>>(options: AsyncModuleOptions<ConfigModuleOptions<T>> & {
6
+ isGlobal?: boolean;
7
+ }): DynamicModule;
5
8
  }
@@ -16,17 +16,54 @@ export class ConfigModule {
16
16
  exports: [
17
17
  ConfigService,
18
18
  CONFIG_OPTIONS
19
- ]
19
+ ],
20
+ isGlobal: options.isGlobal
20
21
  });
21
22
  return {
22
23
  module: moduleClass,
23
24
  providers: [
24
25
  {
25
- token: CONFIG_OPTIONS,
26
+ provide: CONFIG_OPTIONS,
26
27
  useValue: config
27
28
  },
28
29
  ConfigService
29
- ]
30
+ ],
31
+ ...options.isGlobal ? {
32
+ global: true
33
+ } : {}
34
+ };
35
+ }
36
+ static forRootAsync(options) {
37
+ const moduleClass = class ConfigAsyncDynamicModule {
38
+ };
39
+ Object.defineProperty(moduleClass, 'name', {
40
+ value: 'ConfigModule'
41
+ });
42
+ defineMetadata(METADATA_KEYS.MODULE, true, moduleClass);
43
+ MetadataRegistry.setModuleOptions(moduleClass, {
44
+ imports: options.imports ?? [],
45
+ exports: [
46
+ ConfigService,
47
+ CONFIG_OPTIONS
48
+ ],
49
+ isGlobal: options.isGlobal
50
+ });
51
+ return {
52
+ module: moduleClass,
53
+ providers: [
54
+ {
55
+ provide: CONFIG_OPTIONS,
56
+ useFactory: async (...args)=>{
57
+ const opts = await options.useFactory(...args);
58
+ return opts.validate ? opts.validate(opts.config) : opts.config;
59
+ },
60
+ inject: options.inject ?? []
61
+ },
62
+ ConfigService
63
+ ],
64
+ ...options.isGlobal ? {
65
+ global: true
66
+ } : {}
30
67
  };
31
68
  }
32
69
  }
@@ -1,4 +1,5 @@
1
1
  export interface ConfigModuleOptions<T extends Record<string, unknown> = Record<string, unknown>> {
2
2
  config: T;
3
3
  validate?: (config: T) => T;
4
+ isGlobal?: boolean;
4
5
  }
@@ -3,6 +3,7 @@ export declare const METADATA_KEYS: {
3
3
  readonly INJECT: "vela:inject";
4
4
  readonly SCOPE: "vela:scope";
5
5
  readonly MODULE: "vela:module";
6
+ readonly MODULE_OPTIONS: "vela:module-options";
6
7
  readonly CONTROLLER: "vela:controller";
7
8
  readonly ROUTES: "vela:routes";
8
9
  readonly PARAMS: "vela:params";
@@ -26,7 +27,11 @@ export declare enum ParamType {
26
27
  QUERY = "query",
27
28
  PARAM = "param",
28
29
  HEADERS = "headers",
29
- REQUEST = "request"
30
+ REQUEST = "request",
31
+ RESPONSE = "response",
32
+ IP = "ip",
33
+ COOKIE = "cookie",
34
+ RAW_BODY = "raw_body"
30
35
  }
31
36
  export declare enum Scope {
32
37
  SINGLETON = "singleton",
package/dist/constants.js CHANGED
@@ -5,6 +5,7 @@ export const METADATA_KEYS = {
5
5
  SCOPE: 'vela:scope',
6
6
  // Module
7
7
  MODULE: 'vela:module',
8
+ MODULE_OPTIONS: 'vela:module-options',
8
9
  // HTTP
9
10
  CONTROLLER: 'vela:controller',
10
11
  ROUTES: 'vela:routes',
@@ -33,6 +34,10 @@ export var ParamType = /*#__PURE__*/ function(ParamType) {
33
34
  ParamType["PARAM"] = "param";
34
35
  ParamType["HEADERS"] = "headers";
35
36
  ParamType["REQUEST"] = "request";
37
+ ParamType["RESPONSE"] = "response";
38
+ ParamType["IP"] = "ip";
39
+ ParamType["COOKIE"] = "cookie";
40
+ ParamType["RAW_BODY"] = "raw_body";
36
41
  return ParamType;
37
42
  }({});
38
43
  export var Scope = /*#__PURE__*/ function(Scope) {
@@ -1,3 +1,4 @@
1
+ import { Scope } from '../constants';
1
2
  import type { ProviderOptions, Token, Type } from './types';
2
3
  export declare class Container {
3
4
  private providers;
@@ -9,6 +10,7 @@ export declare class Container {
9
10
  private registerOptions;
10
11
  resolve<T>(token: Token<T>): T;
11
12
  has(token: Token): boolean;
13
+ getProviderScope(token: Token): Scope | undefined;
12
14
  getTokens(): Token[];
13
15
  /**
14
16
  * Create a child container for request-scoped resolution.
@@ -16,10 +18,12 @@ export declare class Container {
16
18
  * instances separately per child (per request).
17
19
  */
18
20
  createChild(): Container;
21
+ createDetached(): Container;
19
22
  clear(): void;
20
23
  private resolveRegistration;
21
24
  private resolveClass;
22
25
  private resolveFactory;
23
26
  resolveAsync<T>(token: Token<T>): Promise<T>;
27
+ private createLazyProxy;
24
28
  private tokenToString;
25
29
  }
@@ -1,6 +1,6 @@
1
1
  import { Scope } from "../constants.js";
2
2
  import { getConstructorDependencies, getInjectMetadata, getScope, isInjectable } from "./decorators.js";
3
- import { InjectionToken } from "./types.js";
3
+ import { ForwardRef, InjectionToken } from "./types.js";
4
4
  export class Container {
5
5
  providers = new Map();
6
6
  resolutionStack = new Set();
@@ -20,18 +20,18 @@ export class Container {
20
20
  }
21
21
  const scope = getScope(target);
22
22
  this.providers.set(target, {
23
- token: target,
23
+ provide: target,
24
24
  scope,
25
25
  useClass: target
26
26
  });
27
27
  }
28
28
  registerOptions(options) {
29
- const token = options.token;
29
+ const token = options.provide;
30
30
  if (!token) {
31
31
  throw new Error('Provider registration requires a token');
32
32
  }
33
33
  const registration = {
34
- token,
34
+ provide: token,
35
35
  scope: options.scope ?? Scope.SINGLETON
36
36
  };
37
37
  if (options.useValue !== undefined) {
@@ -40,6 +40,8 @@ export class Container {
40
40
  } else if (options.useFactory) {
41
41
  registration.useFactory = options.useFactory;
42
42
  registration.inject = options.inject;
43
+ } else if (options.useClass) {
44
+ registration.useClass = options.useClass;
43
45
  } else if (options.useExisting) {
44
46
  registration.useExisting = options.useExisting;
45
47
  } else if (typeof token === 'function') {
@@ -56,7 +58,7 @@ export class Container {
56
58
  }
57
59
  if (token instanceof InjectionToken && token.options?.factory) {
58
60
  this.register({
59
- token,
61
+ provide: token,
60
62
  useFactory: token.options.factory
61
63
  });
62
64
  return this.resolve(token);
@@ -68,6 +70,9 @@ export class Container {
68
70
  has(token) {
69
71
  return this.providers.has(token);
70
72
  }
73
+ getProviderScope(token) {
74
+ return this.providers.get(token)?.scope;
75
+ }
71
76
  getTokens() {
72
77
  return Array.from(this.providers.keys());
73
78
  }
@@ -81,6 +86,11 @@ export class Container {
81
86
  child.providers = this.providers; // share provider registrations
82
87
  return child;
83
88
  }
89
+ createDetached() {
90
+ const child = new Container();
91
+ child.providers = new Map(this.providers); // copy, not share
92
+ return child;
93
+ }
84
94
  clear() {
85
95
  this.providers.clear();
86
96
  this.resolutionStack.clear();
@@ -99,19 +109,19 @@ export class Container {
99
109
  }
100
110
  // Request: return cached from this child's requestInstances
101
111
  if (registration.scope === Scope.REQUEST) {
102
- const cached = this.requestInstances.get(registration.token);
112
+ const cached = this.requestInstances.get(registration.provide);
103
113
  if (cached !== undefined) {
104
114
  return cached;
105
115
  }
106
116
  }
107
- if (this.resolutionStack.has(registration.token)) {
117
+ if (this.resolutionStack.has(registration.provide)) {
108
118
  const chain = [
109
119
  ...this.resolutionStack,
110
- registration.token
120
+ registration.provide
111
121
  ].map((t)=>this.tokenToString(t)).join(' -> ');
112
122
  throw new Error(`Circular dependency detected: ${chain}`);
113
123
  }
114
- this.resolutionStack.add(registration.token);
124
+ this.resolutionStack.add(registration.provide);
115
125
  try {
116
126
  let instance;
117
127
  if (registration.useFactory) {
@@ -119,16 +129,16 @@ export class Container {
119
129
  } else if (registration.useClass) {
120
130
  instance = this.resolveClass(registration.useClass);
121
131
  } else {
122
- throw new Error(`Invalid provider registration for: ${this.tokenToString(registration.token)}`);
132
+ throw new Error(`Invalid provider registration for: ${this.tokenToString(registration.provide)}`);
123
133
  }
124
134
  if (registration.scope === Scope.SINGLETON) {
125
135
  registration.instance = instance;
126
136
  } else if (registration.scope === Scope.REQUEST) {
127
- this.requestInstances.set(registration.token, instance);
137
+ this.requestInstances.set(registration.provide, instance);
128
138
  }
129
139
  return instance;
130
140
  } finally{
131
- this.resolutionStack.delete(registration.token);
141
+ this.resolutionStack.delete(registration.provide);
132
142
  }
133
143
  }
134
144
  resolveClass(target) {
@@ -136,13 +146,24 @@ export class Container {
136
146
  const injectMetadata = getInjectMetadata(target);
137
147
  const injectMap = new Map(injectMetadata.map((m)=>[
138
148
  m.index,
139
- m.token
149
+ m
140
150
  ]));
141
151
  const dependencies = paramTypes.map((paramType, index)=>{
142
- const token = injectMap.get(index) ?? paramType;
152
+ const meta = injectMap.get(index);
153
+ const rawToken = meta?.token;
154
+ const isForwardRef = rawToken instanceof ForwardRef;
155
+ const token = isForwardRef ? rawToken.factory() : rawToken ?? paramType;
143
156
  if (!token || token === Object) {
157
+ if (meta?.optional) return undefined;
144
158
  throw new Error(`Cannot resolve dependency at index ${index} for ${target.name}. ` + `Parameter type is undefined or Object. ` + `Use @Inject() to specify the token explicitly.`);
145
159
  }
160
+ if (meta?.optional && !this.has(token)) {
161
+ return undefined;
162
+ }
163
+ // forwardRef with circular dep — break the cycle with a lazy Proxy
164
+ if (isForwardRef && this.resolutionStack.has(token)) {
165
+ return this.createLazyProxy(token);
166
+ }
146
167
  return this.resolve(token);
147
168
  });
148
169
  return new target(...dependencies);
@@ -154,7 +175,7 @@ export class Container {
154
175
  const dependencies = (registration.inject || []).map((token)=>this.resolve(token));
155
176
  const result = registration.useFactory(...dependencies);
156
177
  if (result instanceof Promise) {
157
- throw new Error(`Async factory for ${this.tokenToString(registration.token)} returned a Promise. ` + `Use resolveAsync() for async providers.`);
178
+ throw new Error(`Async factory for ${this.tokenToString(registration.provide)} returned a Promise. ` + `Use resolveAsync() for async providers.`);
158
179
  }
159
180
  return result;
160
181
  }
@@ -180,6 +201,22 @@ export class Container {
180
201
  }
181
202
  return this.resolve(token);
182
203
  }
204
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
205
+ createLazyProxy(token) {
206
+ const container = this;
207
+ return new Proxy({}, {
208
+ get (_target, prop) {
209
+ const instance = container.resolve(token);
210
+ const value = instance[prop];
211
+ return typeof value === 'function' ? value.bind(instance) : value;
212
+ },
213
+ set (_target, prop, value) {
214
+ const instance = container.resolve(token);
215
+ instance[prop] = value;
216
+ return true;
217
+ }
218
+ });
219
+ }
183
220
  tokenToString(token) {
184
221
  if (token instanceof InjectionToken) {
185
222
  return token.toString();
@@ -1,7 +1,9 @@
1
1
  import { Scope } from '../constants';
2
2
  import type { InjectableOptions, InjectMetadata, Token } from './types';
3
+ import { ForwardRef } from './types';
3
4
  export declare function Injectable(options?: InjectableOptions): ClassDecorator;
4
- export declare function Inject(token: Token): ParameterDecorator;
5
+ export declare function Optional(): ParameterDecorator;
6
+ export declare function Inject(token: Token | ForwardRef): ParameterDecorator;
5
7
  export declare function isInjectable(target: object): boolean;
6
8
  export declare function getScope(target: object): Scope;
7
9
  export declare function getConstructorDependencies(target: object): unknown[];
@@ -11,13 +11,34 @@ export function Injectable(options = {}) {
11
11
  defineMetadata(METADATA_KEYS.SCOPE, scope, target);
12
12
  };
13
13
  }
14
+ export function Optional() {
15
+ return (target, _propertyKey, parameterIndex)=>{
16
+ const existing = getInjectMetadata(target);
17
+ const entry = existing.find((m)=>m.index === parameterIndex);
18
+ if (entry) {
19
+ entry.optional = true;
20
+ } else {
21
+ existing.push({
22
+ index: parameterIndex,
23
+ optional: true
24
+ });
25
+ }
26
+ MetadataRegistry.setInjectTokens(target, existing);
27
+ defineMetadata(METADATA_KEYS.INJECT, existing, target);
28
+ };
29
+ }
14
30
  export function Inject(token) {
15
31
  return (target, _propertyKey, parameterIndex)=>{
16
- const existing = MetadataRegistry.getInjectTokens(target) ?? (getMetadata(METADATA_KEYS.INJECT, target) || []);
17
- existing.push({
18
- index: parameterIndex,
19
- token
20
- });
32
+ const existing = getInjectMetadata(target);
33
+ const entry = existing.find((m)=>m.index === parameterIndex);
34
+ if (entry) {
35
+ entry.token = token;
36
+ } else {
37
+ existing.push({
38
+ index: parameterIndex,
39
+ token
40
+ });
41
+ }
21
42
  MetadataRegistry.setInjectTokens(target, existing);
22
43
  defineMetadata(METADATA_KEYS.INJECT, existing, target);
23
44
  };
@@ -32,5 +53,5 @@ export function getConstructorDependencies(target) {
32
53
  return Reflect.getMetadata('design:paramtypes', target) || [];
33
54
  }
34
55
  export function getInjectMetadata(target) {
35
- return MetadataRegistry.getInjectTokens(target) ?? (getMetadata(METADATA_KEYS.INJECT, target) || []);
56
+ return MetadataRegistry.getInjectTokens(target) ?? getMetadata(METADATA_KEYS.INJECT, target) ?? [];
36
57
  }
@@ -1,4 +1,6 @@
1
1
  export { Container } from './container';
2
- export { Injectable, Inject, isInjectable, getScope } from './decorators';
3
- export { InjectionToken } from './types';
2
+ export { Injectable, Inject, Optional, isInjectable, getScope } from './decorators';
3
+ export { InjectionToken, ForwardRef, forwardRef } from './types';
4
+ export { ModuleRef } from './module-ref';
5
+ export { mixin } from './mixin';
4
6
  export type { Type, Token, InjectableOptions, InjectMetadata, ProviderOptions, ProviderRegistration, InjectionTokenOptions, } from './types';
@@ -1,3 +1,5 @@
1
1
  export { Container } from "./container.js";
2
- export { Injectable, Inject, isInjectable, getScope } from "./decorators.js";
3
- export { InjectionToken } from "./types.js";
2
+ export { Injectable, Inject, Optional, isInjectable, getScope } from "./decorators.js";
3
+ export { InjectionToken, ForwardRef, forwardRef } from "./types.js";
4
+ export { ModuleRef } from "./module-ref.js";
5
+ export { mixin } from "./mixin.js";
@@ -0,0 +1,24 @@
1
+ import type { Type } from './types';
2
+ /**
3
+ * Creates a reusable injectable mixin class from a base class.
4
+ * Applies @Injectable() so the returned class can be registered as a provider.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * function RoleGuardMixin(role: string) {
9
+ * class MixedRoleGuard implements CanActivate {
10
+ * canActivate(ctx: ExecutionContext) {
11
+ * return ctx.getRequest().headers.get('x-role') === role;
12
+ * }
13
+ * }
14
+ * return mixin(MixedRoleGuard);
15
+ * }
16
+ *
17
+ * const AdminGuard = RoleGuardMixin('admin');
18
+ *
19
+ * @UseGuards(AdminGuard)
20
+ * @Get('/admin')
21
+ * adminOnly() { ... }
22
+ * ```
23
+ */
24
+ export declare function mixin<T>(mixinClass: Type<T>): Type<T>;
@@ -0,0 +1,26 @@
1
+ import { Injectable } from "./decorators.js";
2
+ /**
3
+ * Creates a reusable injectable mixin class from a base class.
4
+ * Applies @Injectable() so the returned class can be registered as a provider.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * function RoleGuardMixin(role: string) {
9
+ * class MixedRoleGuard implements CanActivate {
10
+ * canActivate(ctx: ExecutionContext) {
11
+ * return ctx.getRequest().headers.get('x-role') === role;
12
+ * }
13
+ * }
14
+ * return mixin(MixedRoleGuard);
15
+ * }
16
+ *
17
+ * const AdminGuard = RoleGuardMixin('admin');
18
+ *
19
+ * @UseGuards(AdminGuard)
20
+ * @Get('/admin')
21
+ * adminOnly() { ... }
22
+ * ```
23
+ */ export function mixin(mixinClass) {
24
+ Injectable()(mixinClass);
25
+ return mixinClass;
26
+ }
@@ -0,0 +1,21 @@
1
+ import type { Token, Type } from './types';
2
+ import type { Container } from './container';
3
+ export declare class ModuleRef {
4
+ private readonly container;
5
+ constructor(container: Container);
6
+ /**
7
+ * Retrieve a provider instance from the DI container.
8
+ * Returns the existing singleton (or cached value) for the token.
9
+ */
10
+ get<T>(token: Token<T>): T;
11
+ /**
12
+ * Resolve a provider, creating a new instance for TRANSIENT-scoped providers.
13
+ * For SINGLETON-scoped providers this is equivalent to get().
14
+ */
15
+ resolve<T>(token: Token<T>): T;
16
+ /**
17
+ * Instantiate a class outside of the DI container's singleton cache.
18
+ * Dependencies are resolved from the container. Each call returns a new instance.
19
+ */
20
+ create<T>(type: Type<T>): T;
21
+ }
@@ -0,0 +1,48 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ function _ts_metadata(k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ }
10
+ import { Scope } from "../constants.js";
11
+ import { Injectable } from "./decorators.js";
12
+ export class ModuleRef {
13
+ container;
14
+ constructor(container){
15
+ this.container = container;
16
+ }
17
+ /**
18
+ * Retrieve a provider instance from the DI container.
19
+ * Returns the existing singleton (or cached value) for the token.
20
+ */ get(token) {
21
+ return this.container.resolve(token);
22
+ }
23
+ /**
24
+ * Resolve a provider, creating a new instance for TRANSIENT-scoped providers.
25
+ * For SINGLETON-scoped providers this is equivalent to get().
26
+ */ resolve(token) {
27
+ return this.container.resolve(token);
28
+ }
29
+ /**
30
+ * Instantiate a class outside of the DI container's singleton cache.
31
+ * Dependencies are resolved from the container. Each call returns a new instance.
32
+ */ create(type) {
33
+ const sandbox = this.container.createDetached();
34
+ sandbox.register({
35
+ provide: type,
36
+ useClass: type,
37
+ scope: Scope.TRANSIENT
38
+ });
39
+ return sandbox.resolve(type);
40
+ }
41
+ }
42
+ ModuleRef = _ts_decorate([
43
+ Injectable(),
44
+ _ts_metadata("design:type", Function),
45
+ _ts_metadata("design:paramtypes", [
46
+ typeof Container === "undefined" ? Object : Container
47
+ ])
48
+ ], ModuleRef);
@@ -9,24 +9,31 @@ export declare class InjectionToken<T = unknown> {
9
9
  constructor(description: string, options?: InjectionTokenOptions<T> | undefined);
10
10
  toString(): string;
11
11
  }
12
+ export declare class ForwardRef<T = unknown> {
13
+ readonly factory: () => Token<T>;
14
+ constructor(factory: () => Token<T>);
15
+ }
16
+ export declare function forwardRef<T>(factory: () => Token<T>): ForwardRef<T>;
12
17
  export type Token<T = any> = Type<T> | InjectionToken<T> | string | symbol;
13
18
  export interface InjectableOptions {
14
19
  scope?: Scope;
15
20
  }
16
21
  export interface InjectMetadata {
17
22
  index: number;
18
- token: Token;
23
+ token?: Token | ForwardRef;
24
+ optional?: boolean;
19
25
  }
20
26
  export interface ProviderOptions<T = unknown> {
21
- token?: Token<T>;
27
+ provide?: Token<T>;
22
28
  scope?: Scope;
23
29
  useValue?: T;
24
30
  useFactory?: (...args: any[]) => T | Promise<T>;
31
+ useClass?: Type<T>;
25
32
  inject?: Token[];
26
33
  useExisting?: Token<T>;
27
34
  }
28
35
  export interface ProviderRegistration<T = unknown> {
29
- token: Token<T>;
36
+ provide: Token<T>;
30
37
  scope: Scope;
31
38
  instance?: T;
32
39
  useValue?: T;
@@ -9,3 +9,12 @@ export class InjectionToken {
9
9
  return `InjectionToken(${this.description})`;
10
10
  }
11
11
  }
12
+ export class ForwardRef {
13
+ factory;
14
+ constructor(factory){
15
+ this.factory = factory;
16
+ }
17
+ }
18
+ export function forwardRef(factory) {
19
+ return new ForwardRef(factory);
20
+ }