alepha 0.6.10 → 0.7.1

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 (100) hide show
  1. package/README.md +14 -3
  2. package/assets/logo.png +0 -0
  3. package/cache.cjs +0 -1
  4. package/cache.d.ts +30 -13
  5. package/cache.js +0 -1
  6. package/core.cjs +0 -1
  7. package/core.d.ts +465 -183
  8. package/core.js +0 -1
  9. package/datetime.cjs +0 -1
  10. package/datetime.d.ts +32 -31
  11. package/datetime.js +0 -1
  12. package/lock.cjs +0 -1
  13. package/lock.d.ts +2 -2
  14. package/lock.js +0 -1
  15. package/package.json +55 -47
  16. package/postgres.cjs +0 -1
  17. package/postgres.d.ts +3276 -124
  18. package/postgres.js +0 -1
  19. package/queue.cjs +0 -1
  20. package/queue.d.ts +2 -2
  21. package/queue.js +0 -1
  22. package/react/auth.cjs +0 -1
  23. package/react/auth.d.ts +40 -32
  24. package/react/auth.js +0 -1
  25. package/react.cjs +0 -1
  26. package/react.d.ts +417 -234
  27. package/react.js +0 -1
  28. package/redis.cjs +0 -1
  29. package/redis.js +0 -1
  30. package/retry.cjs +12 -0
  31. package/retry.d.ts +68 -0
  32. package/retry.js +1 -0
  33. package/scheduler.cjs +0 -1
  34. package/scheduler.js +0 -1
  35. package/security.cjs +0 -1
  36. package/security.d.ts +71 -17
  37. package/security.js +0 -1
  38. package/server/cookies.cjs +0 -1
  39. package/server/cookies.d.ts +1 -1
  40. package/server/cookies.js +0 -1
  41. package/server/metrics.cjs +0 -1
  42. package/server/metrics.d.ts +1 -1
  43. package/server/metrics.js +0 -1
  44. package/server/proxy.cjs +0 -1
  45. package/server/proxy.d.ts +1 -35
  46. package/server/proxy.js +0 -1
  47. package/server/static.cjs +0 -1
  48. package/server/static.d.ts +6 -0
  49. package/server/static.js +0 -1
  50. package/server/swagger.cjs +0 -1
  51. package/server/swagger.d.ts +1 -0
  52. package/server/swagger.js +0 -1
  53. package/server.cjs +0 -1
  54. package/server.d.ts +639 -346
  55. package/server.js +0 -1
  56. package/src/retry.ts +1 -0
  57. package/topic.cjs +0 -1
  58. package/topic.d.ts +3 -3
  59. package/topic.js +0 -1
  60. package/vite.cjs +0 -1
  61. package/vite.d.ts +29 -30
  62. package/vite.js +0 -1
  63. package/cache.cjs.map +0 -1
  64. package/cache.js.map +0 -1
  65. package/core.cjs.map +0 -1
  66. package/core.js.map +0 -1
  67. package/datetime.cjs.map +0 -1
  68. package/datetime.js.map +0 -1
  69. package/lock.cjs.map +0 -1
  70. package/lock.js.map +0 -1
  71. package/postgres.cjs.map +0 -1
  72. package/postgres.js.map +0 -1
  73. package/queue.cjs.map +0 -1
  74. package/queue.js.map +0 -1
  75. package/react/auth.cjs.map +0 -1
  76. package/react/auth.js.map +0 -1
  77. package/react.cjs.map +0 -1
  78. package/react.js.map +0 -1
  79. package/redis.cjs.map +0 -1
  80. package/redis.js.map +0 -1
  81. package/scheduler.cjs.map +0 -1
  82. package/scheduler.js.map +0 -1
  83. package/security.cjs.map +0 -1
  84. package/security.js.map +0 -1
  85. package/server/cookies.cjs.map +0 -1
  86. package/server/cookies.js.map +0 -1
  87. package/server/metrics.cjs.map +0 -1
  88. package/server/metrics.js.map +0 -1
  89. package/server/proxy.cjs.map +0 -1
  90. package/server/proxy.js.map +0 -1
  91. package/server/static.cjs.map +0 -1
  92. package/server/static.js.map +0 -1
  93. package/server/swagger.cjs.map +0 -1
  94. package/server/swagger.js.map +0 -1
  95. package/server.cjs.map +0 -1
  96. package/server.js.map +0 -1
  97. package/topic.cjs.map +0 -1
  98. package/topic.js.map +0 -1
  99. package/vite.cjs.map +0 -1
  100. package/vite.js.map +0 -1
package/core.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import * as TypeBox from '@sinclair/typebox';
2
- import { TSchema, Static, TObject, FormatRegistry, SchemaOptions, ObjectOptions, Union, TProperties, ArrayOptions, TArray, StringOptions, TString, TBoolean, NumberOptions, TNumber, IntegerOptions, TInteger, TOptionalWithFlag, TNull, TIntersect, TUnsafe, UnsafeOptions } from '@sinclair/typebox';
2
+ import { TSchema, Static, TObject, SchemaOptions, ObjectOptions, Union, TProperties, ArrayOptions, TArray, StringOptions, TString, TBoolean, NumberOptions, TNumber, IntegerOptions, TInteger, TOptionalWithFlag, TNull, TIntersect, TUnsafe, UnsafeOptions } from '@sinclair/typebox';
3
3
  export { TypeBox };
4
4
  export { Static, StaticDecode, StaticEncode, TObject, TSchema, TypeGuard } from '@sinclair/typebox';
5
5
  import { TypeCheck } from '@sinclair/typebox/compiler';
6
6
  import { AsyncLocalStorage } from 'node:async_hooks';
7
7
  import { ValueError } from '@sinclair/typebox/errors';
8
- import { ReadableStream as ReadableStream$1 } from 'node:stream/web';
9
8
  import * as TypeBoxValue from '@sinclair/typebox/value';
10
9
  export { TypeBoxValue };
10
+ import { ReadableStream as ReadableStream$1 } from 'node:stream/web';
11
11
  import { Readable } from 'node:stream';
12
12
 
13
13
  /**
@@ -18,7 +18,7 @@ import { Readable } from 'node:stream';
18
18
  declare const KIND: unique symbol;
19
19
 
20
20
  /**
21
- * Used for identifying descriptors.
21
+ * Used for descriptors options.
22
22
  *
23
23
  * @internal
24
24
  */
@@ -36,60 +36,44 @@ type PromiseFn = (...args: any[]) => Promise<any>;
36
36
  * Represents a function that returns an async value.
37
37
  */
38
38
  type AsyncFn = (...args: any[]) => Async<any>;
39
+ type MaybePromise<T> = T extends Promise<any> ? T : Promise<T>;
39
40
 
40
41
  /**
41
- * Represents a generic definition type in TypeScript.
42
+ * In Alepha, a service is a class that can be instantiated. Nothing more, nothing less.
42
43
  */
43
- interface Class<T extends object = any> {
44
- new (...args: any[]): T;
45
- }
44
+ type Service<T extends object = any> = InstantiableService<T> | AbstractService<T>;
45
+ type InstantiableService<T extends object = any> = new (...args: any[]) => T;
46
+ type AbstractService<T extends object = any> = abstract new (...args: any[]) => T;
46
47
  /**
47
- *
48
+ * Service substitution allows you to register a class as a different class.
48
49
  */
49
- interface ClassSwap<T extends object = any> {
50
+ interface ServiceSubstitution<T extends object = any> {
50
51
  /**
51
- * Class to register.
52
+ * Every time someone asks for this service, it will be provided with the 'use' service.
52
53
  */
53
- provide: Class<T>;
54
+ provide: Service<T>;
54
55
  /**
55
- * Class to use AS the provided class.
56
+ * Service to use instead of the 'provide' service.
57
+ *
58
+ * Note: Syntax is based on Angular's DI system.
56
59
  */
57
- use: Class<T>;
60
+ use: Service<T>;
58
61
  /**
59
- * If true, "use" only if class is not already registered.
62
+ * If true, will not throw an error if the service already exists.
63
+ * Mostly used for plugins to enforce a substitution without throwing an error.
60
64
  */
61
65
  default?: boolean;
62
- /**
63
- * If true, class will be removed if nobody is using it.
64
- */
65
- optional?: boolean;
66
66
  }
67
67
  /**
68
+ * Every time you register a service, you can use this type to define it.
68
69
  *
70
+ * alepha.with( ServiceEntry )
71
+ * or
72
+ * alepha.with( provide: ServiceEntry, use: MyOwnServiceEntry )
73
+ *
74
+ * And yes, you declare the *type* of the service, not the *instance*.
69
75
  */
70
- type ClassEntry<T extends object = any> = Class<T> | ClassSwap<T>;
71
- /**
72
- * Represents a definition for a class.
73
- */
74
- interface ClassProvider<T extends object = any> {
75
- /**
76
- * The class or type definition to provide.
77
- */
78
- provide: Class<T>;
79
- /**
80
- * The class or type definition to use. This will override the 'provide' property.
81
- */
82
- use?: Class<T>;
83
- /**
84
- * The instance of the class or type definition.
85
- * Mostly used for caching / singleton but can be used for other purposes like forcing the instance.
86
- */
87
- instance: T;
88
- /**
89
- * List of classes which use this class.
90
- */
91
- parents: Array<Class | null>;
92
- }
76
+ type ServiceEntry<T extends object = any> = Service<T> | ServiceSubstitution<T>;
93
77
 
94
78
  declare const KEY = "HOOK";
95
79
  interface HookOptions<T extends keyof Hooks> {
@@ -101,12 +85,21 @@ interface HookOptions<T extends keyof Hooks> {
101
85
  * The handler to run when the hook is triggered.
102
86
  */
103
87
  handler: (app: Hooks[T]) => Async<any>;
88
+ /**
89
+ * Force the hook to run first or last on the list of hooks.
90
+ */
91
+ priority?: "first" | "last";
92
+ /**
93
+ * Empty placeholder, not working yet. :-)
94
+ */
104
95
  before?: object | Array<object>;
96
+ /**
97
+ * Empty placeholder, not working yet. :-)
98
+ */
105
99
  after?: object | Array<object>;
106
- priority?: "first" | "last";
107
100
  }
108
101
  interface Hook<T extends keyof Hooks = any> {
109
- caller?: Class;
102
+ caller?: Service;
110
103
  priority?: "first" | "last";
111
104
  callback: (payload: Hooks[T]) => Async<void>;
112
105
  }
@@ -133,44 +126,114 @@ interface HookDescriptor<T extends keyof Hooks> {
133
126
  *
134
127
  * Hooks are used to run async functions from all registered providers/services.
135
128
  *
136
- * - You can't unregister a hook once it has been registered.
137
- * - You can't register a hook after the App has started.
129
+ * You can't register a hook after the App has started.
138
130
  *
139
131
  * It's used under the hood by the `configure`, `start`, and `stop` methods.
140
- * Some modules also use hooks to run their own logic.
132
+ * Some modules also use hooks to run their own logic. (e.g. `@alepha/server`).
133
+ *
134
+ * You can create your own hooks by using module augmentation:
135
+ *
136
+ * ```ts
137
+ * declare module "alepha" {
138
+ *
139
+ * interface Hooks {
140
+ * "my:custom:hook": {
141
+ * arg1: string;
142
+ * }
143
+ * }
144
+ * }
145
+ *
146
+ * await alepha.emit("my:custom:hook", { arg1: "value" });
147
+ * ```
148
+ *
141
149
  */
142
150
  declare const $hook: {
143
151
  <T extends keyof Hooks>(options: HookOptions<T>): HookDescriptor<T>;
144
152
  [KIND]: string;
145
153
  };
146
154
 
155
+ interface ModuleDescriptorOptions<T extends TSchema> {
156
+ name: string;
157
+ version?: string;
158
+ description?: string;
159
+ services?: ServiceEntry[] | ((args: Alepha & {
160
+ env: Static<T>;
161
+ }) => ServiceEntry[]);
162
+ env?: T;
163
+ }
164
+ type ModuleDescriptor<T extends TSchema = TSchema> = {
165
+ [KIND]: "MODULE";
166
+ [OPTIONS]: ModuleDescriptorOptions<T>;
167
+ };
168
+ /**
169
+ * This descriptor can be used to define the application metadata and services.
170
+ */
171
+ declare const $module: <T extends TSchema>(opts: ModuleDescriptorOptions<T>) => ModuleDescriptor<T>;
172
+ interface Module {
173
+ /**
174
+ * The name of the module.
175
+ */
176
+ name: string;
177
+ /**
178
+ * The version of the module.
179
+ */
180
+ version?: string;
181
+ /**
182
+ * The description of the module.
183
+ */
184
+ description?: string;
185
+ /**
186
+ * The services provided by the module.
187
+ */
188
+ services?: Service[];
189
+ }
190
+
147
191
  /**
148
- * Used to store the current context and definition during injections.
192
+ * /!\ Global variable /!\
193
+ *
194
+ * Store the current context and definition during injection phase.
149
195
  *
150
196
  * @internal
151
197
  */
152
198
  declare const __alephaRef: {
153
199
  context?: Alepha;
154
- definition?: Class;
200
+ definition?: Service;
201
+ module?: Module;
155
202
  };
156
203
  /**
157
204
  * Cursor descriptor.
158
205
  */
159
206
  interface CursorDescriptor {
160
207
  context: Alepha;
161
- definition?: Class;
208
+ definition?: Service;
209
+ module?: Module;
162
210
  }
163
211
  /**
164
212
  * Get Alepha instance and Class definition from the current context.
165
- *
166
213
  * This should be used inside a descriptor only.
167
214
  *
215
+ * ```ts
216
+ * import { $cursor } from "@alepha/core";
217
+ *
218
+ * const $ = () => {
219
+ *
220
+ * const { context, definition } = $cursor();
221
+ *
222
+ * // context - alepha instance
223
+ * // definition - class which is creating this descriptor
224
+ *
225
+ * return {};
226
+ * }
227
+ *
228
+ * ```
229
+ *
168
230
  * @internal
169
231
  */
170
232
  declare const $cursor: () => CursorDescriptor;
171
233
 
172
234
  /**
173
- * Light-weight event emitter like.
235
+ * Low-cost event emitter like for internal use.
236
+ * Used only for descriptor implicit registration.
174
237
  */
175
238
  declare class EventEmitterLike<TEvents extends {
176
239
  [key: string]: any;
@@ -179,6 +242,7 @@ declare class EventEmitterLike<TEvents extends {
179
242
  on<T extends keyof TEvents>(event: T, callback: (data: TEvents[T]) => void): void;
180
243
  emit<T extends keyof TEvents>(event: T, data: TEvents[T]): void;
181
244
  }
245
+
182
246
  /**
183
247
  * Descriptor events.
184
248
  *
@@ -208,7 +272,7 @@ declare const __descriptor: (kind: string) => void;
208
272
  */
209
273
  declare const __bind: (descriptor: {
210
274
  [KIND]: string;
211
- }, ...to: Class[]) => void;
275
+ }, ...to: Service[]) => void;
212
276
  /**
213
277
  * Check if the value is a descriptor value.
214
278
  *
@@ -242,7 +306,7 @@ interface DescriptorItem<T extends Descriptor> {
242
306
  type AsyncLocalStorageData = any;
243
307
  declare class AsyncLocalStorageProvider {
244
308
  protected als?: AsyncLocalStorage<AsyncLocalStorageData>;
245
- configure(): Promise<void>;
309
+ init(): Promise<void>;
246
310
  run<R>(data: AsyncLocalStorageData, callback: () => R): R;
247
311
  get<T>(key: string): T | undefined;
248
312
  set<T>(key: string, value: T): void;
@@ -356,6 +420,7 @@ declare class Logger {
356
420
  * @protected
357
421
  */
358
422
  protected formatJson(level: LogLevel, message: unknown, data?: object | Error | string): string;
423
+ protected formatJsonError(error: Error): object;
359
424
  /**
360
425
  * Format a log message to a string.
361
426
  *
@@ -365,6 +430,7 @@ declare class Logger {
365
430
  * @protected
366
431
  */
367
432
  protected formatLog(level: LogLevel, message: string, data?: object | Error): string;
433
+ protected colorize(color: string, text: string, reset?: string): string;
368
434
  /**
369
435
  * Format an error to a string.
370
436
  *
@@ -393,16 +459,19 @@ interface MockLoggerStore {
393
459
  interface Env extends LoggerEnv {
394
460
  [key: string]: string | boolean | number | undefined;
395
461
  /**
396
- *
462
+ * Optional environment variable that indicates the current environment.
397
463
  */
398
464
  NODE_ENV?: "dev" | "test" | "production";
399
465
  /**
400
- * Optional name of the application.
466
+ * Optional name of the application. Same as `state.name`.
401
467
  */
402
468
  APP_NAME?: string;
403
469
  /**
404
- * If true, the container will not automatically register the default providers.
405
- * Default is false.
470
+ * If true, the container will not automatically register the default providers based on the descriptors.
471
+ *
472
+ * It means that you have to alepha.with(ServiceModule) manually. No magic.
473
+ *
474
+ * @default false
406
475
  */
407
476
  EXPLICIT_PROVIDERS?: boolean;
408
477
  }
@@ -418,38 +487,69 @@ interface Hooks {
418
487
  echo: any;
419
488
  /**
420
489
  * Triggered during the configuration phase. Before the start phase.
421
- *
422
- * - Configuration should technically be called many times without any side effects.
423
- * - Spamming Alepha#configure() should not cause any issues.
424
490
  */
425
491
  configure: Alepha;
426
492
  /**
427
493
  * Triggered during the start phase. When `Alepha#start()` is called.
428
- *
429
- * - Start is called only once. It should not be called multiple times.
430
494
  */
431
495
  start: Alepha;
432
496
  /**
433
497
  * Triggered during the ready phase. After the start phase.
434
- *
435
- * - Ready is called only once. It should not be called multiple times.
436
498
  */
437
499
  ready: Alepha;
438
500
  /**
439
501
  * Triggered during the stop phase.
440
502
  *
441
- * - Stop is called only once. It should not be called multiple times.
442
- * - Stop should be called after a SIGINT or SIGTERM signal in order to gracefully shutdown the application.
503
+ * - Stop should be called after a SIGINT or SIGTERM signal in order to gracefully shutdown the application. (@see `run()` method)
504
+ *
443
505
  */
444
506
  stop: Alepha;
507
+ /**
508
+ * Triggered when a state value is mutated.
509
+ */
510
+ "state:mutate": {
511
+ /**
512
+ * The key of the state that was mutated.
513
+ */
514
+ key: keyof State;
515
+ /**
516
+ * The new value of the state.
517
+ */
518
+ value: any;
519
+ /**
520
+ * The previous value of the state.
521
+ */
522
+ prevValue: any;
523
+ };
445
524
  }
446
525
  /**
526
+ * Core container of the Alepha framework.
447
527
  *
528
+ * It is responsible for managing the lifecycle of services,
529
+ * handling dependency injection,
530
+ * and providing a unified interface for the application.
448
531
  *
449
532
  * @example
450
533
  * ```ts
451
- * const app = Alepha.create();
534
+ * import { Alepha, run } from "@alepha/core";
535
+ *
536
+ * class MyService {
537
+ * // business logic here
538
+ * }
539
+ *
540
+ * const alepha = Alepha.create({
541
+ * // state, env, and other properties
542
+ * })
543
+ *
544
+ * alepha.register(MyService);
545
+ *
546
+ * run(alepha); // trigger .start (and .stop) automatically
452
547
  * ```
548
+ *
549
+ * > Some alepha methods are not intended to be used directly, use descriptors instead.
550
+ *
551
+ * - $hook -> alepha.on()
552
+ * - $inject -> alepha.get(), alepha.parseEnv()
453
553
  */
454
554
  declare class Alepha {
455
555
  /**
@@ -460,7 +560,7 @@ declare class Alepha {
460
560
  /**
461
561
  * List of all services + how they are provided.
462
562
  */
463
- protected registry: Map<Class, ClassProvider>;
563
+ protected registry: Map<Service, Definition>;
464
564
  /**
465
565
  * Flag indicating whether the App won't accept any further changes.
466
566
  * Pass to true when #start() is called.
@@ -479,31 +579,92 @@ declare class Alepha {
479
579
  */
480
580
  protected ready: boolean;
481
581
  /**
482
- * The state of the App.
483
- */
484
- protected _starting?: PromiseWithResolvers<this>;
485
- protected _state: State;
486
- protected _dependencyStack: Class[];
487
- protected _lazyRegistrations: Array<Promise<{
488
- default: Class<object>;
489
- }>>;
490
- protected _cacheEnv: Map<TSchema, any>;
491
- protected _cacheTypeCheck: Map<TSchema, TypeCheck<TSchema>>;
492
- protected _events: Record<string, Array<Hook>>;
493
- readonly als: AsyncLocalStorageProvider;
582
+ * A promise that resolves when the App has started.
583
+ */
584
+ protected starting?: PromiseWithResolvers<this>;
585
+ /**
586
+ * The current state of the App.
587
+ *
588
+ * It contains the environment variables, logger, and other state-related properties.
589
+ *
590
+ * You can declare your own state properties by extending the `State` interface.
591
+ *
592
+ * ```ts
593
+ * declare module "alepha/core" {
594
+ * interface State {
595
+ * myCustomValue: string;
596
+ * }
597
+ * }
598
+ * ```
599
+ *
600
+ * Same story for the `Env` interface.
601
+ * ```ts
602
+ * declare module "@alepha/core" {
603
+ * interface Env {
604
+ * readonly myCustomValue: string;
605
+ * }
606
+ * }
607
+ * ```
608
+ *
609
+ * State values can be function or primitive values.
610
+ * However, all .env variables must serializable to JSON.
611
+ */
612
+ protected store: State;
613
+ /**
614
+ * During the instantiation process, we keep a list of pending instantiations.
615
+ * > It allows us to detect circular dependencies.
616
+ */
617
+ protected pendingInstantiations: Service[];
618
+ /**
619
+ * Cache for environment variables.
620
+ * > It allows us to avoid parsing the same schema multiple times.
621
+ */
622
+ protected cacheEnv: Map<TSchema, any>;
623
+ /**
624
+ * Cache for TypeBox type checks.
625
+ * > It allows us to avoid compiling the same schema multiple times.
626
+ */
627
+ protected cacheTypeCheck: Map<TSchema, TypeCheck<TSchema>>;
628
+ /**
629
+ * List of events that can be triggered. Powered by $hook().
630
+ */
631
+ protected events: Record<string, Array<Hook>>;
632
+ /**
633
+ * List of modules that are registered in the container.
634
+ *
635
+ * Modules are used to group services and provide a way to register them in the container.
636
+ */
637
+ protected modules: Array<Module>;
638
+ /**
639
+ * Node.js feature that allows to store context across asynchronous calls.
640
+ *
641
+ * This is used for logging, tracing, and other context-related features.
642
+ *
643
+ * Mocked for browser environments.
644
+ */
645
+ readonly context: AsyncLocalStorageProvider;
646
+ /**
647
+ * Get logger instance.
648
+ */
494
649
  get log(): Logger;
495
- handle?: (req: any, res: any) => Promise<any>;
496
650
  /**
497
651
  * The environment variables for the App.
498
652
  */
499
653
  get env(): Readonly<Env>;
500
654
  constructor(state?: Partial<State>);
501
655
  /**
502
- * State accessor.
656
+ * Generic handle function used as generic interface for serverless functions.
657
+ * You should not use this property directly.
658
+ */
659
+ handle?: (req: any, res: any) => Promise<any>;
660
+ /**
661
+ * State accessor and mutator.
503
662
  */
504
663
  state<Key extends keyof State>(key: Key, value?: State[Key]): State[Key];
505
664
  /**
665
+ * Dump the current dependency graph of the App.
506
666
  *
667
+ * This method returns a record where the keys are the names of the services.
507
668
  */
508
669
  graph(): Record<string, {
509
670
  from: string[];
@@ -524,35 +685,50 @@ declare class Alepha {
524
685
  */
525
686
  isReady(): boolean;
526
687
  /**
527
- * True when start() is called. No more services can be added.
688
+ * True when start() is called.
689
+ *
690
+ * -> No more services can be added, it's over, bye!
528
691
  */
529
692
  isLocked(): boolean;
693
+ /**
694
+ * Returns whether the App is configured.
695
+ *
696
+ * It means that Alepha#configure() has been called.
697
+ *
698
+ * > By default, configure() is called automatically when start() is called, but you can also call it manually.
699
+ */
530
700
  isConfigured(): boolean;
531
701
  /**
532
702
  * Returns whether the App is running in a serverless environment.
703
+ *
704
+ * > Vite developer mode is also considered serverless.
533
705
  */
534
706
  isServerless(): boolean | "vite" | "vercel";
535
707
  /**
536
708
  * Returns whether the App is in test mode. (Running in a test environment)
709
+ *
710
+ * > This is automatically set when running tests with Jest or Vitest.
537
711
  */
538
712
  isTest(): boolean;
539
713
  /**
540
714
  * Returns whether the App is in production mode. (Running in a production environment)
715
+ *
716
+ * > This is automatically set by Vite or Vercel. However, you have to set it manually when running Docker apps.
541
717
  */
542
718
  isProduction(): boolean;
543
719
  /**
544
- * > configure() is automatically called by start().
545
- * Use this method only if you need to configure the App without starting it.
720
+ * Trigger configuration of the App manually.
546
721
  *
547
- * @internal
722
+ * > configure() is called automatically when start() is called, you should not need to call it manually.
548
723
  */
549
724
  configure(): Promise<this | undefined>;
550
725
  /**
551
726
  * Starts the App.
552
727
  *
553
728
  * - Lock any further changes to the container.
554
- * - Run "configure" hook for all services.
555
- * - Run "start" hook for all services.
729
+ * - Run "configure" hook for all services. Descriptors will be processed.
730
+ * - Run "start" hook for all services. Providers will connect/listen/...
731
+ * - Run "ready" hook for all services. This is the point where the App is ready to serve requests.
556
732
  *
557
733
  * @return A promise that resolves when the App has started.
558
734
  */
@@ -562,27 +738,38 @@ declare class Alepha {
562
738
  *
563
739
  * - Run "stop" hook for all services.
564
740
  *
741
+ * Stop will NOT reset the container.
742
+ * Stop will NOT unlock the container.
743
+ *
744
+ * > Stop is used to gracefully shut down the application, nothing more. There is no "restart".
745
+ *
565
746
  * @return A promise that resolves when the App has stopped.
566
747
  */
567
748
  stop(): Promise<void>;
568
749
  /**
569
- * Returns whether the specified class or type is registered in the container.
570
- *
571
- * @param injectable - The class or type definition to check.
572
- * @param opts - Additional options for the check.
573
- * @return True if the class or type is registered in the container, false otherwise.
750
+ * Check if entry is registered in the container.
574
751
  */
575
- has(injectable: ClassEntry, opts?: {
576
- overridden?: boolean;
577
- pending?: boolean;
752
+ has(entry: ServiceEntry, opts?: {
753
+ /**
754
+ * Check if the entry is registered in the pending instantiation stack.
755
+ *
756
+ * Default: true
757
+ */
758
+ inStack?: boolean;
759
+ /**
760
+ * Check if the entry is registered in the container registry.
761
+ *
762
+ * Default: true
763
+ */
764
+ inRegistry?: boolean;
578
765
  }): boolean;
579
766
  /**
580
- * Registers the specified class or type in the container.
767
+ * Registers the specified service in the container.
581
768
  *
582
- * - If the class or type is already registered, the method does nothing.
583
- * - If the class or type is not registered, a new instance is created and registered.
769
+ * - If the service is already registered, the method does nothing.
770
+ * - If the service is not registered, a new instance is created and registered.
584
771
  *
585
- * ClassEntry allows to provide a class swapping feature.
772
+ * > ServiceEntry allows to provide a service substitution feature.
586
773
  *
587
774
  * @example
588
775
  * ```ts
@@ -593,51 +780,76 @@ declare class Alepha {
593
780
  * Alepha.create().register({ provide: A, use: B }).get(M).a.value; // "b"
594
781
  * ```
595
782
  *
596
- * > Swapping is an advanced feature that allows you to replace a class with another class.
597
- * > It's useful for testing or for providing different implementations of a class.
783
+ * > Substitution is an advanced feature that allows you to replace a service with another service.
784
+ * > It's useful for testing or for providing different implementations of a service.
598
785
  *
599
- * @param it - The class or type definitions to register in the container.
600
- * @return The current instance of the container.
786
+ * @param entry - The service to register in the container.
787
+ * @return Current instance of Alepha.
601
788
  */
602
- register<T extends object>(it: ClassEntry<T> | Promise<{
603
- default: Class<object>;
604
- }>): this;
789
+ register(...entries: Array<ServiceEntry | ModuleDescriptor>): this;
605
790
  /**
606
791
  * Alias for the 'register' method.
607
792
  *
608
793
  * @alias {Alepha#register}
609
794
  */
610
- with: <T extends object>(it: ClassEntry<T> | Promise<{
611
- default: Class<object>;
612
- }>) => this;
795
+ with: (...entries: Array<ServiceEntry | ModuleDescriptor>) => this;
613
796
  /**
614
- * Works like 'Alepha#register' but it must return the instance.
797
+ * Works like 'Alepha#register' but it will return the instance.
798
+ *
799
+ * > This method is used by $inject() under the hood.
615
800
  *
616
- * @param entry - The class or type definition to retrieve or create.
617
- * @param opts
618
- * @param opts.parent - The parent class that requested the instance.
619
801
  * @return The instance of the specified class or type.
620
802
  */
621
- get<T extends object>(entry: ClassEntry<T>, opts?: {
622
- parent?: Class | null;
803
+ get<T extends object>(serviceEntry: ServiceEntry<T>, opts?: {
804
+ /**
805
+ * Parent service that requested the instance.
806
+ */
807
+ parent?: Service | null;
808
+ /**
809
+ * Ignore current existing instance.
810
+ */
623
811
  skipCache?: boolean;
812
+ /**
813
+ * Don't store the instance in the registry.
814
+ */
624
815
  skipRegistration?: boolean;
816
+ /**
817
+ * Constructor arguments to pass when creating a new instance.
818
+ */
625
819
  args?: any[];
626
820
  }): T;
821
+ /**
822
+ * Registers a hook for the specified event.
823
+ */
627
824
  on<T extends keyof Hooks>(event: T, hookOrFunc: Hook<T> | ((payload: Hooks[T]) => Async<void>)): () => void;
825
+ /**
826
+ * Emits the specified event with the given payload.
827
+ */
628
828
  emit<T extends keyof Hooks>(func: keyof Hooks, payload: Hooks[T], options?: {
829
+ /**
830
+ * If true, the hooks will be executed in reverse order.
831
+ * This is useful for "stop" hooks that should be executed in reverse order.
832
+ *
833
+ * @default false
834
+ */
629
835
  reverse?: boolean;
836
+ /**
837
+ * If true, the hooks will be logged with their execution time.
838
+ *
839
+ * @default false
840
+ */
630
841
  log?: boolean;
842
+ /**
843
+ * If true, errors will be caught and logged instead of throwing.
844
+ *
845
+ * @default false
846
+ */
631
847
  catch?: boolean;
632
848
  }): Promise<void>;
633
849
  /**
634
850
  * Casts the given value to the specified schema.
635
851
  *
636
852
  * It uses the TypeBox library to validate the value against the schema.
637
- *
638
- * @param schema - The schema to cast the value to.
639
- * @param value - The value to cast.
640
- * @param opts - default: true, clean: true, convert: true, decode: true, encode: false
641
853
  */
642
854
  parse<T extends TSchema>(schema: T, value?: any, opts?: {
643
855
  /**
@@ -675,12 +887,6 @@ declare class Alepha {
675
887
  * @return The schema object with environment variables applied.
676
888
  */
677
889
  parseEnv<T extends TObject>(schema: T): Static<T>;
678
- /**
679
- * Returns all registered services that match the specified descriptor.
680
- *
681
- * @param descriptor
682
- */
683
- getDescriptorValues<T extends Descriptor>(descriptor: T): Array<DescriptorItem<T>>;
684
890
  /**
685
891
  * Create a new instance of a logger.
686
892
  *
@@ -688,27 +894,40 @@ declare class Alepha {
688
894
  */
689
895
  protected createLogger(env: Env): Logger;
690
896
  /**
691
- * Creates a new instance of a given class with dependency injection.
692
- *
693
- * @param definition - The class for which to create a new instance.
694
- * @param args - The arguments to pass to the class constructor
695
- * @returns The newly created instance of the given class.
897
+ * @internal
696
898
  */
697
- protected new<T extends object>(definition: Class<T>, args?: any[]): T;
899
+ getDescriptorValues<T extends Descriptor>(descriptor: T): Array<DescriptorItem<T>>;
698
900
  /**
699
- * Removes all useless dependencies.
700
- *
701
- * @protected
901
+ * @internal
702
902
  */
703
- protected removeUselessDependencies(): void;
903
+ protected new<T extends object>(definition: Service<T>, args?: any[]): T;
904
+ /**
905
+ * @interface
906
+ */
907
+ moduleOf(service: Service): Module | undefined;
704
908
  }
705
-
706
909
  /**
707
- * Symbol to mark a value create from a provider.
708
- *
709
- * @internal
910
+ * This is how we store services in the Alepha container.
710
911
  */
711
- declare const PROVIDER: unique symbol;
912
+ interface Definition<T extends object = any> {
913
+ /**
914
+ * The class or type definition to provide.
915
+ */
916
+ provide: Service<T>;
917
+ /**
918
+ * The class or type definition to use. This will override the 'provide' property.
919
+ */
920
+ use?: Service<T>;
921
+ /**
922
+ * The instance of the class or type definition.
923
+ * Mostly used for caching / singleton but can be used for other purposes like forcing the instance.
924
+ */
925
+ instance: T;
926
+ /**
927
+ * List of classes which use this class.
928
+ */
929
+ parents: Array<Service | null>;
930
+ }
712
931
 
713
932
  /**
714
933
  * Get the instance of the specified type from the context.
@@ -727,42 +946,32 @@ declare const PROVIDER: unique symbol;
727
946
  * @returns Instance of the specified type
728
947
  */
729
948
  declare function $inject<T extends TObject>(type: T): Static<T>;
730
- declare function $inject<T extends object>(type: Class<T>): T;
731
-
732
- declare const $logger: (name?: string) => Logger;
733
-
949
+ declare function $inject<T extends object>(type: Service<T>): T;
734
950
  /**
735
- * Retry Descriptor options.
951
+ * @alias $inject
736
952
  */
737
- interface RetryDescriptorOptions<T extends (...args: any[]) => any> {
738
- /**
739
- * Maximum number of attempts.
740
- *
741
- * @default 3
742
- */
743
- max?: number;
744
- /**
745
- * Delay in milliseconds.
746
- *
747
- * @default 0
748
- */
749
- delay?: number;
750
- /**
751
- *
752
- */
753
- when?: (error: Error) => boolean;
754
- /**
755
- *
756
- */
757
- handler: T;
758
- }
953
+ declare const $env: typeof $inject;
954
+
759
955
  /**
760
- * Retry descriptor.
956
+ * Create a logger.
761
957
  *
762
- * @param opts - Retry descriptor options.
763
- * @returns A function that will retry the handler.
958
+ * `name` is optional, by default it will use the name of the service.
959
+ *
960
+ * @example
961
+ * ```ts
962
+ * import { $logger } from "@alepha/core";
963
+ *
964
+ * class MyService {
965
+ * log = $logger();
966
+ *
967
+ * constructor() {
968
+ * // print something like 'date - [MyService] Service initialized'
969
+ * this.log.info("Service initialized");
970
+ * }
971
+ * }
972
+ * ```
764
973
  */
765
- declare const $retry: <T extends (...args: any[]) => any>(opts: RetryDescriptorOptions<T>) => ((...parameters: Parameters<T>) => Promise<ReturnType<T>>);
974
+ declare const $logger: (name?: string) => Logger;
766
975
 
767
976
  declare class AppNotStartedError extends Error {
768
977
  constructor();
@@ -790,7 +999,7 @@ declare class TypeProvider {
790
999
  static DEFAULT_LONG_STRING_MAX_LENGTH: number;
791
1000
  static DEFAULT_RICH_STRING_MAX_LENGTH: number;
792
1001
  static DEFAULT_ARRAY_MAX_ITEMS: number;
793
- static FormatRegistry: typeof FormatRegistry;
1002
+ static FormatRegistry: typeof TypeBox.FormatRegistry;
794
1003
  Type: TypeBox.JavaScriptTypeBuilder;
795
1004
  any: (options?: SchemaOptions) => TypeBox.TAny;
796
1005
  void: (options?: SchemaOptions) => TypeBox.TVoid;
@@ -857,16 +1066,17 @@ declare class TypeProvider {
857
1066
  uchar: (options?: IntegerOptions) => TInteger;
858
1067
  /**
859
1068
  * Create a schema for an unsigned 32-bit integer.
860
- *
861
- * @param options
862
1069
  */
863
1070
  uint: (options?: IntegerOptions) => TNumber;
864
1071
  /**
865
1072
  * Create a schema for a signed 32-bit integer.
866
- *
867
- * @param options
868
1073
  */
869
1074
  int: (options?: IntegerOptions) => TInteger;
1075
+ /**
1076
+ * Create a schema for a bigint. Bigint is a 64-bit integer.
1077
+ * This is a workaround for TypeBox, which does not support bigint natively.
1078
+ */
1079
+ bigint: (options?: IntegerOptions) => TNumber;
870
1080
  /**
871
1081
  * Make a schema optional.
872
1082
  *
@@ -953,32 +1163,104 @@ declare class TypeProvider {
953
1163
  stream: () => TStream;
954
1164
  }
955
1165
  interface FileLike {
1166
+ /**
1167
+ * Filename.
1168
+ * @default "file"
1169
+ */
956
1170
  name: string;
1171
+ /**
1172
+ * Mandatory MIME type of the file.
1173
+ * @default "application/octet-stream"
1174
+ */
957
1175
  type: string;
1176
+ /**
1177
+ * Size of the file in bytes.
1178
+ *
1179
+ * Always 0 for streams, as the size is not known until the stream is fully read.
1180
+ *
1181
+ * @default 0
1182
+ */
958
1183
  size: number;
1184
+ /**
1185
+ * Last modified timestamp in milliseconds since epoch.
1186
+ *
1187
+ * Always the current timestamp for streams, as the last modified time is not known.
1188
+ * We use this field to ensure compatibility with File API.
1189
+ *
1190
+ * @default Date.now()
1191
+ */
959
1192
  lastModified: number;
1193
+ /**
1194
+ * Returns a ReadableStream or Node.js Readable stream of the file content.
1195
+ *
1196
+ * For streams, this is the original stream.
1197
+ */
960
1198
  stream(): StreamLike;
1199
+ /**
1200
+ * Returns the file content as an ArrayBuffer.
1201
+ *
1202
+ * For streams, this reads the entire stream into memory.
1203
+ */
961
1204
  arrayBuffer(): Promise<ArrayBuffer>;
1205
+ /**
1206
+ * Returns the file content as a string.
1207
+ *
1208
+ * For streams, this reads the entire stream into memory and converts it to a string.
1209
+ */
962
1210
  text(): Promise<string>;
1211
+ /**
1212
+ * Optional file path, if the file is stored on disk.
1213
+ *
1214
+ * This is not from the File API, but rather a custom field to indicate where the file is stored.
1215
+ */
963
1216
  filepath?: string;
964
1217
  }
1218
+ /**
1219
+ * TypeBox view of FileLike.
1220
+ */
965
1221
  type TFile = TUnsafe<FileLike>;
966
- type StreamLike = ReadableStream | ReadableStream$1 | Readable;
967
- type TStream = TUnsafe<StreamLike>;
968
- declare const t: TypeProvider;
969
1222
  declare const isTypeFile: (value: TSchema) => value is TFile;
970
1223
  declare const isFileLike: (value: any) => value is FileLike;
1224
+ type StreamLike = ReadableStream | ReadableStream$1 | Readable | NodeJS.ReadableStream;
1225
+ type TStream = TUnsafe<StreamLike>;
971
1226
  declare const isTypeStream: (value: TSchema) => value is TStream;
972
1227
  type TextLength = "short" | "long" | "rich";
973
1228
  interface AlephaStringOptions extends StringOptions {
974
1229
  size?: TextLength;
975
1230
  }
1231
+ declare const t: TypeProvider;
976
1232
  declare const isUUID: (value: string) => boolean;
977
1233
 
978
- declare const run: (arg: Alepha | Class | ((env?: Env) => Alepha), opts?: {
1234
+ declare const substitute: <T extends object>(rule: {
1235
+ provide: T;
1236
+ use: T;
1237
+ default?: boolean;
1238
+ }) => {
1239
+ use: T;
1240
+ provide: T;
1241
+ default?: boolean;
1242
+ };
1243
+ interface RunOptions {
1244
+ /**
1245
+ * Environment variables to be used by the application.
1246
+ * If not provided, it will use the current process environment.
1247
+ */
979
1248
  env?: Env;
1249
+ /**
1250
+ * A callback that will be executed before the application starts.
1251
+ */
980
1252
  configure?: (alepha: Alepha) => Async<void>;
1253
+ /**
1254
+ * A callback that will be executed once the application is ready.
1255
+ * This is useful for initializing resources or starting background tasks.
1256
+ */
981
1257
  ready?: (alepha: Alepha) => Async<void>;
982
- }) => Alepha;
1258
+ /**
1259
+ * If true, the application will stop after the ready callback is executed.
1260
+ */
1261
+ once?: boolean;
1262
+ }
1263
+
1264
+ declare const run: (entry: Alepha | Service | Array<Service>, opts?: RunOptions) => Alepha;
983
1265
 
984
- export { $cursor, $hook, $inject, $logger, $retry, Alepha, type AlephaStringOptions, AppNotStartedError, type Async, type AsyncFn, type AsyncLocalStorageData, AsyncLocalStorageProvider, COLORS, CircularDependencyError, type Class, type ClassEntry, type ClassProvider, type ClassSwap, ContainerLockedError, type CursorDescriptor, type Descriptor, type DescriptorIdentifier, type DescriptorItem, type Env, EventEmitterLike, type FileLike, type Hook, type HookDescriptor, type HookOptions, type Hooks, KIND, LEVEL_COLORS, type LogLevel, Logger, type LoggerEnv, type LoggerOptions, MockLogger, type MockLoggerStore, NotImplementedError, OPTIONS, PROVIDER, type PromiseFn, type RetryDescriptorOptions, type State, type StreamLike, type TFile, type TStream, type TextLength, TypeBoxError, TypeProvider, __alephaRef, __bind, __descriptor, descriptorEvents, isDescriptorValue, isFileLike, isTypeFile, isTypeStream, isUUID, run, t };
1266
+ export { $cursor, $env, $hook, $inject, $logger, $module, type AbstractService, Alepha, type AlephaStringOptions, AppNotStartedError, type Async, type AsyncFn, type AsyncLocalStorageData, AsyncLocalStorageProvider, COLORS, CircularDependencyError, ContainerLockedError, type CursorDescriptor, type Descriptor, type DescriptorIdentifier, type DescriptorItem, type Env, type FileLike, type Hook, type HookDescriptor, type HookOptions, type Hooks, type InstantiableService, KIND, LEVEL_COLORS, type LogLevel, Logger, type LoggerEnv, type LoggerOptions, type MaybePromise, MockLogger, type MockLoggerStore, type Module, type ModuleDescriptor, type ModuleDescriptorOptions, NotImplementedError, OPTIONS, type PromiseFn, type RunOptions, type Service, type ServiceEntry, type ServiceSubstitution, type State, type StreamLike, type TFile, type TStream, type TextLength, TypeBoxError, TypeProvider, __alephaRef, __bind, __descriptor, descriptorEvents, isDescriptorValue, isFileLike, isTypeFile, isTypeStream, isUUID, run, substitute, t };