alepha 0.9.4 → 0.10.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.
package/core.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
- import { TypeCheck } from "@sinclair/typebox/compiler";
3
- import * as TypeBoxValue from "@sinclair/typebox/value";
4
- import * as TypeBox from "@sinclair/typebox";
5
- import { ArrayOptions, FormatRegistry, IntegerOptions, NumberOptions, ObjectOptions, SchemaOptions, Static, Static as Static$1, StaticDecode, StaticEncode, StringOptions, TAny, TAny as TAny$1, TArray, TArray as TArray$1, TBoolean, TBoolean as TBoolean$1, TComposite, TInteger, TIntersect, TNull, TNumber, TNumber as TNumber$1, TObject, TObject as TObject$1, TOmit, TOptional, TOptionalWithFlag, TPartial, TPick, TProperties, TProperties as TProperties$1, TRecord, TRecord as TRecord$1, TSchema, TSchema as TSchema$1, TString, TString as TString$1, TUnion, TUnsafe, TypeGuard, UnsafeOptions } from "@sinclair/typebox";
6
- import { ValueError } from "@sinclair/typebox/errors";
2
+ import { Validator } from "typebox/compile";
3
+ import * as TypeBox from "typebox";
4
+ import { Static, Static as Static$1, StaticDecode, StaticEncode, TAny, TAny as TAny$1, TArray, TArray as TArray$1, TArrayOptions, TBigInt, TBoolean, TBoolean as TBoolean$1, TInteger, TInteger as TInteger$1, TKeysToIndexer, TNull, TNull as TNull$1, TNumber, TNumber as TNumber$1, TNumberOptions, TNumberOptions as TNumberOptions$1, TObject, TObject as TObject$1, TObjectOptions, TObjectOptions as TObjectOptions$1, TOptional, TOptionalAdd, TOptionalAdd as TOptionalAdd$1, TPick, TProperties, TProperties as TProperties$1, TRecord, TRecord as TRecord$1, TSchema, TSchema as TSchema$1, TSchemaOptions, TString, TString as TString$1, TStringOptions, TStringOptions as TStringOptions$1, TTuple, TUnion, TUnion as TUnion$1, TUnsafe, TVoid } from "typebox";
5
+ import Format from "typebox/format";
6
+ import * as TypeBoxValue from "typebox/value";
7
7
  import { Readable } from "node:stream";
8
8
  import { ReadableStream as ReadableStream$1 } from "node:stream/web";
9
+ import { TLocalizedValidationError } from "typebox/error";
9
10
 
10
11
  //#region src/constants/KIND.d.ts
11
12
  /**
@@ -118,47 +119,42 @@ declare const $inject: <T extends object>(type: Service<T>, opts?: InjectOptions
118
119
  declare class InjectDescriptor extends Descriptor {}
119
120
  interface InjectOptions<T extends object = any> {
120
121
  /**
121
- * Ignore current existing instance.
122
- */
123
- skipCache?: boolean;
124
- /**
125
- * Don't store the instance in the registry.
122
+ * - 'transient' Always a new instance on every inject. Zero caching.
123
+ * - 'singleton' → One instance per Alepha runtime (per-thread). Never disposed until Alepha shuts down. (default)
124
+ * - 'scoped' → One instance per AsyncLocalStorage context.
125
+ * - A new scope is created when Alepha handles a request, a scheduled job, a queue worker task...
126
+ * - You can also start a manual scope via alepha.context.run(() => { ... }).
127
+ * - When the scope ends, the scoped registry is discarded.
128
+ *
129
+ * @default "singleton"
126
130
  */
127
- skipRegistration?: boolean;
131
+ lifetime?: "transient" | "singleton" | "scoped";
128
132
  /**
129
133
  * Constructor arguments to pass when creating a new instance.
130
134
  */
131
135
  args?: ConstructorParameters<InstantiableClass<T>>;
132
136
  /**
133
- * Parent service that requested the instance.
137
+ * Parent that requested the instance.
138
+ *
134
139
  * @internal
135
140
  */
136
141
  parent?: Service | null;
137
142
  }
138
143
  //#endregion
139
- //#region src/constants/OPTIONS.d.ts
140
- /**
141
- * Used for descriptors options.
142
- *
143
- * @internal
144
- */
145
- declare const OPTIONS: unique symbol;
146
- //#endregion
147
144
  //#region src/descriptors/$module.d.ts
148
145
  /**
149
- * Wrap services and descriptors into a module.
146
+ * Wrap Services and Descriptors into a Module.
150
147
  *
151
- * Module is just a class.
152
- * You must attach a `name` to it.
153
- *
154
- * It's recommended to use `project.module.submodule` format.
148
+ * - A module is just a Service extended {@link Module}.
149
+ * - You must attach a `name` to it.
150
+ * - Name must follow the pattern: `project.module.submodule`.
155
151
  *
156
152
  * @example
157
153
  * ```ts
158
154
  * import { $module } from "alepha";
159
155
  * import { MyService } from "./MyService.ts";
160
156
  *
161
- * // export MyService so it can be used everywhere
157
+ * // export MyService, so it can be used everywhere
162
158
  * export * from "./MyService.ts";
163
159
  *
164
160
  * export default $module({
@@ -168,9 +164,30 @@ declare const OPTIONS: unique symbol;
168
164
  * });
169
165
  * ```
170
166
  *
171
- * - Module is used for logging and other purposes.
172
- * - It's useful for large applications or libraries to group services and descriptors together.
173
- * - It's probably overkill for small applications.
167
+ * ## Why Modules?
168
+ *
169
+ * ### Logging
170
+ *
171
+ * By default, AlephaLogger will log the module name in the logs.
172
+ * This helps to identify where the logs are coming from.
173
+ *
174
+ * You can also set different log levels for different modules.
175
+ * It means you can set 'some.very.specific.module' to 'debug' and keep the rest of the application to 'info'.
176
+ *
177
+ * ### Modulith
178
+ *
179
+ * Force to structure your application in modules, even if it's a single deployable unit.
180
+ * It helps to keep a clean architecture and avoid monolithic applications.
181
+ *
182
+ * You can also use `MODULE_INCLUDE` and `MODULE_EXCLUDE` environment variables to load only specific modules.
183
+ *
184
+ * A strict mode is planned to enforce module boundaries. Throwing errors when a service from another module is injected.
185
+ *
186
+ * ### When not to use Modules?
187
+ *
188
+ * Small applications does not need modules. It's better to keep it simple.
189
+ * Modules are more useful when the application grows and needs to be structured.
190
+ * If we speak with `$actions`, a module should be used when you have more than 30 actions in a single module.
174
191
  */
175
192
  declare const $module: (options: ModuleDescriptorOptions) => Service<Module>;
176
193
  interface ModuleDescriptorOptions {
@@ -195,16 +212,25 @@ interface ModuleDescriptorOptions {
195
212
  */
196
213
  register?: (alepha: Alepha) => void;
197
214
  }
198
- interface Module {
199
- [KIND]: "MODULE";
200
- [OPTIONS]: ModuleDescriptorOptions;
201
- register: (alepha: Alepha) => void;
215
+ /**
216
+ * Base class for all modules.
217
+ */
218
+ declare abstract class Module {
219
+ abstract readonly options: ModuleDescriptorOptions;
220
+ abstract register(alepha: Alepha): void;
221
+ static NAME_REGEX: RegExp;
222
+ /**
223
+ * Check if a Service is a Module.
224
+ */
225
+ static is(ctor: Service): boolean;
226
+ /**
227
+ * Get the Module of a Service.
228
+ */
229
+ static of(ctor: Service): Service<Module> | undefined;
202
230
  }
203
- type ServiceWithModule<T extends object = any> = T & {
231
+ type WithModule<T extends object = any> = T & {
204
232
  [MODULE]?: Service;
205
233
  };
206
- declare const isModule: (value: unknown) => value is Module;
207
- declare const toModuleName: (name: string) => string;
208
234
  //#endregion
209
235
  //#region src/interfaces/Async.d.ts
210
236
  /**
@@ -230,6 +256,45 @@ interface LoggerInterface {
230
256
  error(message: string, data?: unknown): void;
231
257
  }
232
258
  //#endregion
259
+ //#region src/helpers/EventManager.d.ts
260
+ declare class EventManager {
261
+ protected logFn?: () => LoggerInterface | undefined;
262
+ /**
263
+ * List of events that can be triggered. Powered by $hook().
264
+ */
265
+ protected events: Record<string, Array<Hook>>;
266
+ constructor(logFn?: () => LoggerInterface | undefined);
267
+ protected get log(): LoggerInterface | undefined;
268
+ /**
269
+ * Registers a hook for the specified event.
270
+ */
271
+ on<T extends keyof Hooks>(event: T, hookOrFunc: Hook<T> | ((payload: Hooks[T]) => Async<void>)): () => void;
272
+ /**
273
+ * Emits the specified event with the given payload.
274
+ */
275
+ emit<T extends keyof Hooks>(func: keyof Hooks, payload: Hooks[T], options?: {
276
+ /**
277
+ * If true, the hooks will be executed in reverse order.
278
+ * This is useful for "stop" hooks that should be executed in reverse order.
279
+ *
280
+ * @default false
281
+ */
282
+ reverse?: boolean;
283
+ /**
284
+ * If true, the hooks will be logged with their execution time.
285
+ *
286
+ * @default false
287
+ */
288
+ log?: boolean;
289
+ /**
290
+ * If true, errors will be caught and logged instead of throwing.
291
+ *
292
+ * @default false
293
+ */
294
+ catch?: boolean;
295
+ }): Promise<void>;
296
+ }
297
+ //#endregion
233
298
  //#region src/providers/AlsProvider.d.ts
234
299
  type AsyncLocalStorageData = any;
235
300
  declare class AlsProvider {
@@ -243,6 +308,313 @@ declare class AlsProvider {
243
308
  set<T>(key: string, value: T): void;
244
309
  }
245
310
  //#endregion
311
+ //#region src/helpers/StateManager.d.ts
312
+ declare class StateManager<S extends Record<string, any> = State> {
313
+ protected store: Partial<S>;
314
+ protected readonly events?: EventManager;
315
+ protected readonly als?: AlsProvider;
316
+ constructor(events?: EventManager, als?: AlsProvider);
317
+ /**
318
+ * Get a value from the state with proper typing
319
+ */
320
+ get<Key extends keyof S>(key: Key): S[Key] | undefined;
321
+ /**
322
+ * Set a value in the state
323
+ */
324
+ set<Key extends keyof S>(key: Key, value: S[Key] | undefined): this;
325
+ /**
326
+ * Check if a key exists in the state
327
+ */
328
+ has<Key extends keyof S>(key: Key): boolean;
329
+ /**
330
+ * Delete a key from the state (set to undefined)
331
+ */
332
+ del<Key extends keyof S>(key: Key): this;
333
+ /**
334
+ * Clear all state
335
+ */
336
+ clear(): this;
337
+ /**
338
+ * Get all keys that exist in the state
339
+ */
340
+ keys(): (keyof S)[];
341
+ }
342
+ //#endregion
343
+ //#region src/helpers/FileLike.d.ts
344
+ interface FileLike {
345
+ /**
346
+ * Filename.
347
+ * @default "file"
348
+ */
349
+ name: string;
350
+ /**
351
+ * Mandatory MIME type of the file.
352
+ * @default "application/octet-stream"
353
+ */
354
+ type: string;
355
+ /**
356
+ * Size of the file in bytes.
357
+ *
358
+ * Always 0 for streams, as the size is not known until the stream is fully read.
359
+ *
360
+ * @default 0
361
+ */
362
+ size: number;
363
+ /**
364
+ * Last modified timestamp in milliseconds since epoch.
365
+ *
366
+ * Always the current timestamp for streams, as the last modified time is not known.
367
+ * We use this field to ensure compatibility with File API.
368
+ *
369
+ * @default Date.now()
370
+ */
371
+ lastModified: number;
372
+ /**
373
+ * Returns a ReadableStream or Node.js Readable stream of the file content.
374
+ *
375
+ * For streams, this is the original stream.
376
+ */
377
+ stream(): StreamLike;
378
+ /**
379
+ * Returns the file content as an ArrayBuffer.
380
+ *
381
+ * For streams, this reads the entire stream into memory.
382
+ */
383
+ arrayBuffer(): Promise<ArrayBuffer>;
384
+ /**
385
+ * Returns the file content as a string.
386
+ *
387
+ * For streams, this reads the entire stream into memory and converts it to a string.
388
+ */
389
+ text(): Promise<string>;
390
+ /**
391
+ * Optional file path, if the file is stored on disk.
392
+ *
393
+ * This is not from the File API, but rather a custom field to indicate where the file is stored.
394
+ */
395
+ filepath?: string;
396
+ }
397
+ /**
398
+ * TypeBox view of FileLike.
399
+ */
400
+ type TFile = TUnsafe<FileLike>;
401
+ declare const isTypeFile: (value: TSchema$1) => value is TFile;
402
+ declare const isFileLike: (value: any) => value is FileLike;
403
+ type StreamLike = ReadableStream | ReadableStream$1 | Readable | NodeJS.ReadableStream;
404
+ type TStream = TUnsafe<StreamLike>;
405
+ //#endregion
406
+ //#region src/providers/TypeProvider.d.ts
407
+ declare class TypeGuard {
408
+ isSchema: typeof TypeBox.IsSchema;
409
+ isObject: typeof TypeBox.IsObject;
410
+ isNumber: typeof TypeBox.IsNumber;
411
+ isString: typeof TypeBox.IsString;
412
+ isBoolean: typeof TypeBox.IsBoolean;
413
+ isAny: typeof TypeBox.IsAny;
414
+ isArray: typeof TypeBox.IsArray;
415
+ isOptional: typeof TypeBox.IsOptional;
416
+ isUnion: typeof TypeBox.IsUnion;
417
+ isInteger: typeof TypeBox.IsInteger;
418
+ isNull: typeof TypeBox.IsNull;
419
+ isUndefined: typeof TypeBox.IsUndefined;
420
+ isUnsafe: typeof TypeBox.IsUnsafe;
421
+ isRecord: typeof TypeBox.IsRecord;
422
+ isTuple: typeof TypeBox.IsTuple;
423
+ isVoid: typeof TypeBox.IsVoid;
424
+ isFile: (value: TSchema$1) => value is TFile;
425
+ isBigInt: (value: TSchema$1) => value is TString$1;
426
+ isDate: (value: TSchema$1) => value is TString$1;
427
+ isDatetime: (value: TSchema$1) => value is TString$1;
428
+ isUuid: (value: TSchema$1) => value is TString$1;
429
+ }
430
+ declare module "typebox" {
431
+ interface TString {
432
+ format?: string;
433
+ minLength?: number;
434
+ maxLength?: number;
435
+ }
436
+ interface TNumber {
437
+ format?: "int64";
438
+ }
439
+ }
440
+ declare class TypeProvider {
441
+ static format: typeof Format;
442
+ static isValidBigInt(value: string | number): boolean;
443
+ /**
444
+ * Default maximum length for strings.
445
+ *
446
+ * It can be set to a larger value:
447
+ * ```ts
448
+ * TypeProvider.DEFAULT_STRING_MAX_LENGTH = 1000000;
449
+ * TypeProvider.DEFAULT_STRING_MAX_LENGTH = undefined; // no limit (not recommended)
450
+ * ```
451
+ */
452
+ static DEFAULT_STRING_MAX_LENGTH: number | undefined;
453
+ /**
454
+ * Maximum length for short strings, such as names or titles.
455
+ */
456
+ static DEFAULT_SHORT_STRING_MAX_LENGTH: number | undefined;
457
+ /**
458
+ * Maximum length for long strings, such as descriptions or comments.
459
+ * It can be overridden in the string options.
460
+ *
461
+ * It can be set to a larger value:
462
+ * ```ts
463
+ * TypeProvider.DEFAULT_LONG_STRING_MAX_LENGTH = 2048;
464
+ * ```
465
+ */
466
+ static DEFAULT_LONG_STRING_MAX_LENGTH: number | undefined;
467
+ /**
468
+ * Maximum length for rich strings, such as HTML or Markdown.
469
+ * This is a large value to accommodate rich text content.
470
+ * > It's also the maximum length of PG's TEXT type.
471
+ *
472
+ * It can be overridden in the string options.
473
+ *
474
+ * It can be set to a larger value:
475
+ * ```ts
476
+ * TypeProvider.DEFAULT_RICH_STRING_MAX_LENGTH = 1000000;
477
+ * ```
478
+ */
479
+ static DEFAULT_RICH_STRING_MAX_LENGTH: number | undefined;
480
+ /**
481
+ * Maximum number of items in an array.
482
+ * This is a default value to prevent excessive memory usage.
483
+ * It can be overridden in the array options.
484
+ */
485
+ static DEFAULT_ARRAY_MAX_ITEMS: number;
486
+ raw: typeof TypeBox.Type;
487
+ any: typeof TypeBox.Any;
488
+ void: typeof TypeBox.Void;
489
+ undefined: typeof TypeBox.Undefined;
490
+ record: typeof TypeBox.Record;
491
+ omit: typeof TypeBox.Omit;
492
+ partial: typeof TypeBox.Partial;
493
+ union: typeof TypeBox.Union;
494
+ pick: typeof TypeBox.Pick;
495
+ tuple: typeof TypeBox.Tuple;
496
+ interface: typeof TypeBox.Interface;
497
+ readonly schema: TypeGuard;
498
+ /**
499
+ * Create a schema for an object.
500
+ */
501
+ object<T extends TProperties$1>(properties: T, options?: TObjectOptions$1): TObject$1<T>;
502
+ /**
503
+ * Create a schema for an array.
504
+ *
505
+ * @param schema
506
+ * @param options
507
+ */
508
+ array<T extends TSchema$1>(schema: T, options?: TArrayOptions): TArray$1<T>;
509
+ /**
510
+ * Create a schema for a string.
511
+ */
512
+ string(options?: AlephaStringOptions): TString$1;
513
+ /**
514
+ * Create a schema for a JSON object.
515
+ * This is a record with string keys and any values.
516
+ */
517
+ json(options?: TSchemaOptions): TRecord$1<string, TAny$1>;
518
+ /**
519
+ * Create a schema for a boolean.
520
+ */
521
+ boolean(options?: TSchemaOptions): TBoolean$1;
522
+ /**
523
+ * Create a schema for a number.
524
+ */
525
+ number(options?: TNumberOptions$1): TNumber$1;
526
+ /**
527
+ * Create a schema for a signed 32-bit integer.
528
+ */
529
+ int(options?: TNumberOptions$1): TInteger$1;
530
+ /**
531
+ * Mimic a signed 64-bit integer.
532
+ *
533
+ * This is NOT a true int64, as JavaScript cannot represent all int64 values.
534
+ * It is a number that is an integer and between -9007199254740991 and 9007199254740991.
535
+ * Use `t.bigint()` for true int64 values represented as strings.
536
+ */
537
+ int64(options?: TNumberOptions$1): TNumber$1;
538
+ /**
539
+ * Make a schema optional.
540
+ */
541
+ optional<T extends TSchema$1>(schema: T): TOptionalAdd$1<T>;
542
+ /**
543
+ * Make a schema nullable.
544
+ */
545
+ nullable<T extends TSchema$1>(schema: T, options?: TObjectOptions$1): TUnion$1<[TNull$1, T]>;
546
+ /**
547
+ * Create a schema that maps all properties of an object schema to nullable.
548
+ */
549
+ nullify: <T extends TSchema$1>(schema: T, options?: TObjectOptions$1) => TypeBox.TMappedInstantiate<{}, {
550
+ callstack: [];
551
+ }, TypeBox.TIdentifier<"K">, TypeBox.TKeyOfInstantiate<{}, {
552
+ callstack: [];
553
+ }, T>, TypeBox.TRef<"K">, TUnion$1<[TypeBox.TIndexInstantiate<{}, {
554
+ callstack: [];
555
+ }, T, TypeBox.TRef<"K">>, TNull$1]>>;
556
+ /**
557
+ * Create a schema for a string enum.
558
+ */
559
+ enum<T extends string[]>(values: [...T], options?: TStringOptions$1): TUnsafe<T[number]>;
560
+ /**
561
+ * Create a schema for a bigint.
562
+ * This is NOT a BigInt object, but a string that represents a bigint.
563
+ */
564
+ bigint(options?: TStringOptions$1): TString$1;
565
+ /**
566
+ * Create a schema for a datetime.
567
+ * This is NOT a Date object, but a string in ISO 8601 format.
568
+ */
569
+ datetime(options?: TStringOptions$1): TString$1;
570
+ /**
571
+ * Create a schema for a date.
572
+ * This is NOT a Date object, but a string in ISO 8601 date format (YYYY-MM-DD).
573
+ */
574
+ date(options?: TStringOptions$1): TString$1;
575
+ /**
576
+ * Create a schema for a url.
577
+ */
578
+ url(options?: TStringOptions$1): TString$1;
579
+ /**
580
+ * Create a schema for uuid.
581
+ */
582
+ uuid(options?: TStringOptions$1): TString$1;
583
+ /**
584
+ * Create a schema for a file-like object.
585
+ *
586
+ * File like mimics the File API in browsers, but is adapted to work in Node.js as well.
587
+ *
588
+ * Implementation of file-like objects is handled by "alepha/file" package.
589
+ */
590
+ file(options?: {
591
+ maxSize?: number;
592
+ }): TFile;
593
+ /**
594
+ * @experimental
595
+ */
596
+ stream(): TStream;
597
+ /**
598
+ * Create a schema for a string enum e.g. LIKE_THIS.
599
+ *
600
+ * @param options
601
+ */
602
+ snakeCase: (options?: TStringOptions$1) => TString$1;
603
+ /**
604
+ * Create a schema for an object with a value and label.
605
+ */
606
+ valueLabel: (options?: TObjectOptions$1) => TObject$1<{
607
+ value: TString$1;
608
+ label: TString$1;
609
+ description: TypeBox.TOptional<TString$1>;
610
+ }>;
611
+ }
612
+ type TextLength = "short" | "long" | "rich";
613
+ interface AlephaStringOptions extends TStringOptions$1 {
614
+ size?: TextLength;
615
+ }
616
+ declare const t: TypeProvider;
617
+ //#endregion
246
618
  //#region src/Alepha.d.ts
247
619
  /**
248
620
  * Core container of the Alepha framework.
@@ -350,7 +722,7 @@ declare class AlsProvider {
350
722
  * Alepha.create()
351
723
  * .with(App)
352
724
  * .start()
353
- * .then(alepha => alepha.emit("my:custom:hook"));
725
+ * .then(alepha => alepha.events.emit("my:custom:hook"));
354
726
  * ```
355
727
  *
356
728
  * Hooks are fully typed. You can create your own hooks by using module augmentation:
@@ -364,6 +736,8 @@ declare class AlsProvider {
364
736
  * }
365
737
  * }
366
738
  * ```
739
+ *
740
+ * @module alepha
367
741
  */
368
742
  declare class Alepha {
369
743
  /**
@@ -437,16 +811,12 @@ declare class Alepha {
437
811
  * Cache for environment variables.
438
812
  * > It allows us to avoid parsing the same schema multiple times.
439
813
  */
440
- protected cacheEnv: Map<TSchema$1, any>;
814
+ protected cacheEnv: Map<TSchema, any>;
441
815
  /**
442
816
  * Cache for TypeBox type checks.
443
817
  * > It allows us to avoid compiling the same schema multiple times.
444
818
  */
445
- protected cacheTypeCheck: Map<TSchema$1, TypeCheck<TSchema$1>>;
446
- /**
447
- * List of events that can be triggered. Powered by $hook().
448
- */
449
- protected events: Record<string, Array<Hook>>;
819
+ protected cacheTypeCheck: Map<TSchema, Validator>;
450
820
  /**
451
821
  * List of modules that are registered in the container.
452
822
  *
@@ -465,7 +835,15 @@ declare class Alepha {
465
835
  *
466
836
  * Mocked for browser environments.
467
837
  */
468
- readonly context: AlsProvider;
838
+ readonly context: AlsProvider;
839
+ /**
840
+ * Event manager to handle lifecycle events and custom events.
841
+ */
842
+ readonly events: EventManager;
843
+ /**
844
+ * State manager to store arbitrary values.
845
+ */
846
+ readonly state: StateManager<State>;
469
847
  /**
470
848
  * Get logger instance.
471
849
  */
@@ -475,10 +853,6 @@ declare class Alepha {
475
853
  */
476
854
  get env(): Readonly<Env>;
477
855
  constructor(state?: Partial<State>);
478
- /**
479
- * State accessor and mutator.
480
- */
481
- state<Key extends keyof State>(key: Key, value?: State[Key]): State[Key];
482
856
  /**
483
857
  * True when start() is called.
484
858
  *
@@ -556,15 +930,27 @@ declare class Alepha {
556
930
  /**
557
931
  * Check if the entry is registered in the pending instantiation stack.
558
932
  *
559
- * Default: true
933
+ * @default true
560
934
  */
561
935
  inStack?: boolean;
562
936
  /**
563
937
  * Check if the entry is registered in the container registry.
564
938
  *
565
- * Default: true
939
+ * @default true
566
940
  */
567
941
  inRegistry?: boolean;
942
+ /**
943
+ * Check if the entry is registered in the substitutions.
944
+ *
945
+ * @default true
946
+ */
947
+ inSubstitutions?: boolean;
948
+ /**
949
+ * Where to look for registered services.
950
+ *
951
+ * @default this.registry
952
+ */
953
+ registry?: Map<Service, ServiceDefinition>;
568
954
  }): boolean;
569
955
  /**
570
956
  * Registers the specified service in the container.
@@ -596,14 +982,9 @@ declare class Alepha {
596
982
  default: ServiceEntry<T>;
597
983
  }): this;
598
984
  /**
599
- * Get the instance of the specified service and apply some changes, depending on the options.
600
- * - If the service is already registered, it will return the existing instance. (except if `skipCache` is true)
601
- * - If the service is not registered, it will create a new instance and register it. (except if `skipRegistration` is true)
602
- * - New instance can be created with custom constructor arguments. (`args` option)
985
+ * Get an instance of the specified service from the container.
603
986
  *
604
- * > This method is used by $inject() under the hood.
605
- *
606
- * @return The instance of the specified class or type.
987
+ * @see {@link InjectOptions} for the available options.
607
988
  */
608
989
  inject<T extends object>(service: Service<T>, opts?: InjectOptions<T>): T;
609
990
  /**
@@ -626,40 +1007,12 @@ declare class Alepha {
626
1007
  configure<T extends {
627
1008
  options: object;
628
1009
  }>(service: Service<T>, state: Partial<T["options"]>): this;
629
- /**
630
- * Registers a hook for the specified event.
631
- */
632
- on<T extends keyof Hooks>(event: T, hookOrFunc: Hook<T> | ((payload: Hooks[T]) => Async<void>)): () => void;
633
- /**
634
- * Emits the specified event with the given payload.
635
- */
636
- emit<T extends keyof Hooks>(func: keyof Hooks, payload: Hooks[T], options?: {
637
- /**
638
- * If true, the hooks will be executed in reverse order.
639
- * This is useful for "stop" hooks that should be executed in reverse order.
640
- *
641
- * @default false
642
- */
643
- reverse?: boolean;
644
- /**
645
- * If true, the hooks will be logged with their execution time.
646
- *
647
- * @default false
648
- */
649
- log?: boolean;
650
- /**
651
- * If true, errors will be caught and logged instead of throwing.
652
- *
653
- * @default false
654
- */
655
- catch?: boolean;
656
- }): Promise<void>;
657
1010
  /**
658
1011
  * Casts the given value to the specified schema.
659
1012
  *
660
1013
  * It uses the TypeBox library to validate the value against the schema.
661
1014
  */
662
- parse<T extends TSchema$1>(schema: T, value?: any, opts?: {
1015
+ parse<T extends TSchema>(schema: T, value?: unknown, opts?: {
663
1016
  /**
664
1017
  * Clone the value before parsing.
665
1018
  * @default true
@@ -680,6 +1033,11 @@ declare class Alepha {
680
1033
  * @default true
681
1034
  */
682
1035
  convert?: boolean;
1036
+ /**
1037
+ * Convert `null` to `undefined`
1038
+ * @default true
1039
+ */
1040
+ convertNullToUndefined?: boolean;
683
1041
  /**
684
1042
  * Prepare value after being deserialized.
685
1043
  * @default true
@@ -729,10 +1087,6 @@ interface ServiceDefinition<T extends object = any> {
729
1087
  * List of classes which use this class.
730
1088
  */
731
1089
  parents: Array<Service | null>;
732
- /**
733
- * If the service is provided by a module, the module definition.
734
- */
735
- module?: Service;
736
1090
  }
737
1091
  interface Env {
738
1092
  [key: string]: string | boolean | number | undefined;
@@ -828,15 +1182,13 @@ interface RunOptions {
828
1182
  cluster?: boolean;
829
1183
  }
830
1184
  //#endregion
831
- //#region src/constants/PRIMITIVE.d.ts
1185
+ //#region src/constants/OPTIONS.d.ts
832
1186
  /**
833
- * Symbol to mark a value as a primitive.
834
- *
835
- * Used to enhance TypeBox types with metadata. See @alepha/protobuf.
1187
+ * Used for descriptors options.
836
1188
  *
837
1189
  * @internal
838
1190
  */
839
- declare const PRIMITIVE: unique symbol;
1191
+ declare const OPTIONS: unique symbol;
840
1192
  //#endregion
841
1193
  //#region src/descriptors/$cursor.d.ts
842
1194
  /**
@@ -949,7 +1301,7 @@ declare const $env: <T extends TObject$1>(type: T) => Static$1<T>;
949
1301
  * }
950
1302
  * }
951
1303
  *
952
- * await alepha.emit("my:custom:hook", { arg1: "value" });
1304
+ * await alepha.events.emit("my:custom:hook", { arg1: "value" });
953
1305
  * ```
954
1306
  *
955
1307
  */
@@ -993,295 +1345,36 @@ declare class AlephaError extends Error {
993
1345
  }
994
1346
  //#endregion
995
1347
  //#region src/errors/AppNotStartedError.d.ts
996
- declare class AppNotStartedError extends Error {
1348
+ declare class AppNotStartedError extends AlephaError {
997
1349
  readonly name = "AppNotStartedError";
998
1350
  constructor();
999
1351
  }
1000
1352
  //#endregion
1001
1353
  //#region src/errors/CircularDependencyError.d.ts
1002
- declare class CircularDependencyError extends Error {
1354
+ declare class CircularDependencyError extends AlephaError {
1003
1355
  readonly name = "CircularDependencyError";
1004
1356
  constructor(provider: string, parents?: string[]);
1005
1357
  }
1006
1358
  //#endregion
1007
1359
  //#region src/errors/ContainerLockedError.d.ts
1008
- declare class ContainerLockedError extends Error {
1360
+ declare class ContainerLockedError extends AlephaError {
1009
1361
  readonly name = "ContainerLockedError";
1010
1362
  constructor(message?: string);
1011
1363
  }
1012
1364
  //#endregion
1013
- //#region src/errors/TypeBoxError.d.ts
1014
- declare class TypeBoxError extends Error {
1015
- readonly name = "TypeBoxError";
1016
- readonly value: ValueError;
1017
- constructor(value: ValueError);
1365
+ //#region src/errors/TooLateSubstitutionError.d.ts
1366
+ declare class TooLateSubstitutionError extends AlephaError {
1367
+ readonly name = "TooLateSubstitutionError";
1368
+ constructor(original: string, substitution: string);
1018
1369
  }
1019
1370
  //#endregion
1020
- //#region src/providers/TypeProvider.d.ts
1021
- declare class TypeProvider {
1022
- /**
1023
- * Default maximum length for strings.
1024
- *
1025
- * It can be set to a larger value:
1026
- * ```ts
1027
- * TypeProvider.DEFAULT_STRING_MAX_LENGTH = 1000000;
1028
- * TypeProvider.DEFAULT_STRING_MAX_LENGTH = undefined; // no limit (not recommended)
1029
- * ```
1030
- */
1031
- static DEFAULT_STRING_MAX_LENGTH: number | undefined;
1032
- static DEFAULT_SHORT_STRING_MAX_LENGTH: number | undefined;
1033
- /**
1034
- * Maximum length for long strings, such as descriptions or comments.
1035
- * It can be overridden in the string options.
1036
- *
1037
- * It can be set to a larger value:
1038
- * ```ts
1039
- * TypeProvider.DEFAULT_LONG_STRING_MAX_LENGTH = 2048;
1040
- * ```
1041
- */
1042
- static DEFAULT_LONG_STRING_MAX_LENGTH: number | undefined;
1043
- /**
1044
- * Maximum length for rich strings, such as HTML or Markdown.
1045
- * This is a large value to accommodate rich text content.
1046
- * > It's also the maximum length of PG's TEXT type.
1047
- *
1048
- * It can be overridden in the string options.
1049
- *
1050
- * It can be set to a larger value:
1051
- * ```ts
1052
- * TypeProvider.DEFAULT_RICH_STRING_MAX_LENGTH = 1000000;
1053
- * ```
1054
- */
1055
- static DEFAULT_RICH_STRING_MAX_LENGTH: number | undefined;
1056
- /**
1057
- * Maximum number of items in an array.
1058
- * This is a default value to prevent excessive memory usage.
1059
- * It can be overridden in the array options.
1060
- */
1061
- static DEFAULT_ARRAY_MAX_ITEMS: number;
1062
- static FormatRegistry: typeof FormatRegistry;
1063
- raw: TypeBox.JavaScriptTypeBuilder;
1064
- any: (options?: SchemaOptions) => TAny$1;
1065
- void: (options?: SchemaOptions) => TypeBox.TVoid;
1066
- undefined: (options?: SchemaOptions) => TypeBox.TUndefined;
1067
- record: <Key extends TSchema$1, Value extends TSchema$1>(key: Key, value: Value, options?: ObjectOptions) => TypeBox.TRecordOrObject<Key, Value>;
1068
- omit: {
1069
- <Type extends TSchema$1, Key extends PropertyKey[]>(type: Type, key: readonly [...Key], options?: SchemaOptions): TOmit<Type, Key>;
1070
- <Type extends TSchema$1, Key extends TSchema$1>(type: Type, key: Key, options?: SchemaOptions): TOmit<Type, Key>;
1071
- };
1072
- partial: {
1073
- <MappedResult extends TypeBox.TMappedResult>(type: MappedResult, options?: SchemaOptions): TypeBox.TPartialFromMappedResult<MappedResult>;
1074
- <Type extends TSchema$1>(type: Type, options?: SchemaOptions): TPartial<Type>;
1075
- };
1076
- union: <Types extends TSchema$1[]>(types: [...Types], options?: SchemaOptions) => TypeBox.Union<Types>;
1077
- composite: <T extends TSchema$1[]>(schemas: [...T], options?: ObjectOptions) => TComposite<T>;
1078
- pick: {
1079
- <Type extends TSchema$1, Key extends PropertyKey[]>(type: Type, key: readonly [...Key], options?: SchemaOptions): TPick<Type, Key>;
1080
- <Type extends TSchema$1, Key extends TSchema$1>(type: Type, key: Key, options?: SchemaOptions): TPick<Type, Key>;
1081
- };
1082
- /**
1083
- * Create a schema for an object.
1084
- *
1085
- * @param properties The properties of the object.
1086
- * @param options The options for the object.
1087
- */
1088
- object<T extends TProperties$1>(properties: T, options?: ObjectOptions): TObject$1<T>;
1089
- /**
1090
- * Create a schema for an array.
1091
- *
1092
- * @param schema
1093
- * @param options
1094
- */
1095
- array<T extends TSchema$1>(schema: T, options?: ArrayOptions): TArray$1<T>;
1096
- /**
1097
- * Create a schema for a string.
1098
- *
1099
- * @param options
1100
- */
1101
- string(options?: AlephaStringOptions): TString$1;
1102
- /**
1103
- * Create a schema for a JSON object.
1104
- *
1105
- * @param options
1106
- */
1107
- json(options?: SchemaOptions): TRecord$1<TString$1, TAny$1>;
1108
- /**
1109
- * Create a schema for a boolean.
1110
- *
1111
- * @param options
1112
- */
1113
- boolean(options?: SchemaOptions): TBoolean$1;
1114
- /**
1115
- * Create a schema for a number.
1116
- *
1117
- * @param options
1118
- */
1119
- number(options?: NumberOptions): TNumber$1;
1120
- /**
1121
- * Create a schema for an unsigned 8-bit integer.
1122
- *
1123
- * @param options
1124
- */
1125
- uchar(options?: IntegerOptions): TInteger;
1126
- /**
1127
- * Create a schema for an unsigned 32-bit integer.
1128
- */
1129
- uint(options?: IntegerOptions): TNumber$1;
1130
- /**
1131
- * Create a schema for a signed 32-bit integer.
1132
- */
1133
- int(options?: IntegerOptions): TInteger;
1134
- /**
1135
- * Create a schema for a signed 32-bit integer.
1136
- */
1137
- integer(options?: IntegerOptions): TInteger;
1138
- /**
1139
- * Create a schema for a bigint. Bigint is a 64-bit integer.
1140
- * This is a workaround for TypeBox, which does not support bigint natively.
1141
- */
1142
- bigint(options?: NumberOptions): TNumber$1;
1143
- /**
1144
- * Make a schema optional.
1145
- *
1146
- * @param schema The schema to make optional.
1147
- */
1148
- optional<T extends TSchema$1>(schema: T): TOptionalWithFlag<T, true>;
1149
- /**
1150
- * Make a schema nullable.
1151
- *
1152
- * @param schema The schema to make nullable.
1153
- * @param options The options for the schema.
1154
- */
1155
- nullable<T extends TSchema$1>(schema: T, options?: ObjectOptions): TUnion<[TNull, T]>;
1156
- nullify: <T extends TSchema$1>(schema: T, options?: ObjectOptions) => TObject$1<TypeBox.Evaluate<TypeBox.TMappedFunctionReturnType<TypeBox.TIndexPropertyKeys<TypeBox.TKeyOf<T>>, TUnion<[TNull, TypeBox.TMappedResult<TypeBox.Evaluate<TypeBox.TIndexPropertyKeys<TypeBox.TKeyOf<T>> extends infer T_1 ? T_1 extends TypeBox.TIndexPropertyKeys<TypeBox.TKeyOf<T>> ? T_1 extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? Right extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] ? /*elided*/any : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : { [_ in Left]: TypeBox.Assert<TypeBox.TIndexFromPropertyKey<T, Left>, TSchema$1> } : {} : never : never>>]>, {}>>>;
1157
- /**
1158
- * Map a schema to another schema.
1159
- *
1160
- * @param schema The schema to map.
1161
- * @param operations The operations to perform on the schema.
1162
- * @param options The options for the schema.
1163
- * @returns The mapped schema.
1164
- */
1165
- map<T extends TObject$1 | TIntersect, Omit extends (keyof T["properties"])[], Optional extends (keyof T["properties"])[]>(schema: T, operations: {
1166
- omit: readonly [...Omit];
1167
- optional: [...Optional];
1168
- }, options?: ObjectOptions): TComposite<[TOmit<T, [...Omit, ...Optional]>, TPartial<TPick<T, Optional>>]>;
1169
- /**
1170
- * Create a schema for a string enum.
1171
- *
1172
- * @param values
1173
- * @param options
1174
- */
1175
- enum<T extends string[]>(values: [...T], options?: StringOptions): TUnsafe<T[number]>;
1176
- /**
1177
- * Create a schema for a datetime.
1178
- *
1179
- * @param options The options for the date.
1180
- */
1181
- datetime(options?: StringOptions): TString$1;
1182
- /**
1183
- * Create a schema for a date.
1184
- *
1185
- * @param options
1186
- */
1187
- date(options?: StringOptions): TString$1;
1188
- /**
1189
- * Create a schema for uuid.
1190
- *
1191
- * @param options The options for the duration.
1192
- */
1193
- uuid(options?: StringOptions): TString$1;
1194
- unsafe<T>(kind: string, options?: UnsafeOptions): TUnsafe<T>;
1195
- file(options?: {
1196
- max?: number;
1197
- }): TFile;
1198
- stream(): TStream;
1199
- /**
1200
- * Create a schema for a string enum e.g. LIKE_THIS.
1201
- *
1202
- * @param options
1203
- */
1204
- snakeCase: (options?: StringOptions) => TString$1;
1205
- /**
1206
- * Create a schema for an object with a value and label.
1207
- */
1208
- valueLabel: (options?: ObjectOptions) => TObject$1<{
1209
- value: TString$1;
1210
- label: TString$1;
1211
- description: TypeBox.TOptional<TString$1>;
1212
- }>;
1213
- }
1214
- interface FileLike {
1215
- /**
1216
- * Filename.
1217
- * @default "file"
1218
- */
1219
- name: string;
1220
- /**
1221
- * Mandatory MIME type of the file.
1222
- * @default "application/octet-stream"
1223
- */
1224
- type: string;
1225
- /**
1226
- * Size of the file in bytes.
1227
- *
1228
- * Always 0 for streams, as the size is not known until the stream is fully read.
1229
- *
1230
- * @default 0
1231
- */
1232
- size: number;
1233
- /**
1234
- * Last modified timestamp in milliseconds since epoch.
1235
- *
1236
- * Always the current timestamp for streams, as the last modified time is not known.
1237
- * We use this field to ensure compatibility with File API.
1238
- *
1239
- * @default Date.now()
1240
- */
1241
- lastModified: number;
1242
- /**
1243
- * Returns a ReadableStream or Node.js Readable stream of the file content.
1244
- *
1245
- * For streams, this is the original stream.
1246
- */
1247
- stream(): StreamLike;
1248
- /**
1249
- * Returns the file content as an ArrayBuffer.
1250
- *
1251
- * For streams, this reads the entire stream into memory.
1252
- */
1253
- arrayBuffer(): Promise<ArrayBuffer>;
1254
- /**
1255
- * Returns the file content as a string.
1256
- *
1257
- * For streams, this reads the entire stream into memory and converts it to a string.
1258
- */
1259
- text(): Promise<string>;
1260
- /**
1261
- * Optional file path, if the file is stored on disk.
1262
- *
1263
- * This is not from the File API, but rather a custom field to indicate where the file is stored.
1264
- */
1265
- filepath?: string;
1266
- }
1267
- /**
1268
- * TypeBox view of FileLike.
1269
- */
1270
- type TFile = TUnsafe<FileLike>;
1271
- declare const isTypeFile: (value: TSchema$1) => value is TFile;
1272
- declare const isFileLike: (value: any) => value is FileLike;
1273
- type StreamLike = ReadableStream | ReadableStream$1 | Readable | NodeJS.ReadableStream;
1274
- type TStream = TUnsafe<StreamLike>;
1275
- declare const isTypeStream: (value: TSchema$1) => value is TStream;
1276
- type TextLength = "short" | "long" | "rich";
1277
- interface AlephaStringOptions extends StringOptions {
1278
- size?: TextLength;
1371
+ //#region src/errors/TypeBoxError.d.ts
1372
+ declare class TypeBoxError extends AlephaError {
1373
+ readonly name = "TypeBoxError";
1374
+ readonly cause: TLocalizedValidationError;
1375
+ readonly value: any;
1376
+ constructor(error: TLocalizedValidationError, value: any);
1279
1377
  }
1280
- declare const t: TypeProvider;
1281
- declare function isISODate(str: string): boolean;
1282
- declare function isISODateTime(value: string): boolean;
1283
- declare function isUUID(value: string): boolean;
1284
- declare function isEmail(value: string): boolean;
1285
1378
  //#endregion
1286
1379
  //#region src/index.d.ts
1287
1380
  declare global {
@@ -1297,5 +1390,5 @@ declare global {
1297
1390
  */
1298
1391
  declare const run: (entry: Alepha | Service | Array<Service>, opts?: RunOptions) => void;
1299
1392
  //#endregion
1300
- export { $cursor, $env, $hook, $inject, $module, AbstractClass, Alepha, AlephaError, AlephaStringOptions, AlsProvider, AppNotStartedError, Async, AsyncFn, AsyncLocalStorageData, CircularDependencyError, ContainerLockedError, CursorDescriptor, Descriptor, DescriptorArgs, DescriptorConfig, DescriptorFactory, DescriptorFactoryLike, Env, FileLike, Hook, HookDescriptor, HookOptions, Hooks, InjectDescriptor, InjectOptions, InstantiableClass, KIND, LogLevel, LoggerInterface, MaybePromise, Module, ModuleDescriptorOptions, OPTIONS, PRIMITIVE, Service, ServiceEntry, ServiceSubstitution, ServiceWithModule, State, type Static, type StaticDecode, type StaticEncode, StreamLike, type TAny, type TArray, type TBoolean, TFile, type TNumber, type TObject, type TOptional, type TProperties, type TRecord, type TSchema, TStream, type TString, TextLength, TypeBox, TypeBoxError, TypeBoxValue, TypeGuard, TypeProvider, __alephaRef, createDescriptor, isEmail, isFileLike, isISODate, isISODateTime, isModule, isTypeFile, isTypeStream, isUUID, run, t, toModuleName };
1393
+ export { $cursor, $env, $hook, $inject, $module, AbstractClass, Alepha, AlephaError, AlephaStringOptions, AlsProvider, AppNotStartedError, Async, AsyncFn, AsyncLocalStorageData, CircularDependencyError, ContainerLockedError, CursorDescriptor, Descriptor, DescriptorArgs, DescriptorConfig, DescriptorFactory, DescriptorFactoryLike, Env, FileLike, Hook, HookDescriptor, HookOptions, Hooks, InjectDescriptor, InjectOptions, InstantiableClass, KIND, LogLevel, LoggerInterface, MaybePromise, Module, ModuleDescriptorOptions, OPTIONS, Service, ServiceEntry, ServiceSubstitution, State, StateManager, type Static, type StaticDecode, type StaticEncode, StreamLike, type TAny, type TArray, type TBigInt, type TBoolean, TFile, type TInteger, type TKeysToIndexer, type TNull, type TNumber, type TNumberOptions, type TObject, type TObjectOptions, type TOptional, type TOptionalAdd, type TPick, type TProperties, type TRecord, type TSchema, TStream, type TString, type TStringOptions, type TTuple, type TUnion, type TVoid, TextLength, TooLateSubstitutionError, TypeBox, TypeBoxError, TypeBoxValue, TypeGuard, TypeProvider, WithModule, __alephaRef, createDescriptor, isFileLike, isTypeFile, run, t };
1301
1394
  //# sourceMappingURL=index.d.ts.map