@expressots/core 4.0.0-preview.1 → 4.0.0-preview.3

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 (134) hide show
  1. package/LICENSE.md +21 -21
  2. package/README.md +66 -66
  3. package/lib/CHANGELOG.md +774 -774
  4. package/lib/README.md +66 -66
  5. package/lib/cjs/application/application-factory.js +6 -0
  6. package/lib/cjs/application/bootstrap.js +117 -213
  7. package/lib/cjs/config/define-config.js +1 -1
  8. package/lib/cjs/config/env-field-builders.js +47 -0
  9. package/lib/cjs/config/index.js +7 -1
  10. package/lib/cjs/framework-version.js +10 -0
  11. package/lib/cjs/lazy-loading/index.js +5 -1
  12. package/lib/cjs/lazy-loading/lazy-module-helpers.js +49 -0
  13. package/lib/cjs/middleware/index.js +8 -9
  14. package/lib/cjs/middleware/middleware-service.js +68 -12
  15. package/lib/cjs/middleware/presets-standalone.js +93 -0
  16. package/lib/cjs/provider/db-in-memory/adapter/in-memory.adapter.js +23 -0
  17. package/lib/cjs/provider/db-in-memory/index.js +11 -1
  18. package/lib/cjs/provider/db-in-memory/query/query-engine.js +28 -0
  19. package/lib/cjs/provider/db-in-memory/schema/decorators.js +18 -0
  20. package/lib/cjs/provider/db-in-memory/storage/index.js +3 -1
  21. package/lib/cjs/provider/db-in-memory/storage/memory-store.js +72 -1
  22. package/lib/cjs/provider/logger/logger.banner.js +40 -31
  23. package/lib/cjs/provider/logger/logger.config.js +11 -1
  24. package/lib/cjs/provider/logger/logger.formatter.js +22 -1
  25. package/lib/cjs/provider/logger/logger.provider.js +59 -9
  26. package/lib/cjs/provider/logger/transports/console.transport.js +69 -6
  27. package/lib/cjs/provider/logger/transports/file.transport.js +27 -18
  28. package/lib/cjs/provider/logger/utils/log-levels.js +6 -5
  29. package/lib/cjs/provider/validation/adapters/index.js +12 -5
  30. package/lib/cjs/provider/validation/adapters/yup.adapter.js +118 -0
  31. package/lib/cjs/provider/validation/adapters/zod.adapter.js +137 -0
  32. package/lib/cjs/provider/validation/index.js +5 -1
  33. package/lib/cjs/render/adapters/react-adapter.js +14 -14
  34. package/lib/cjs/render/features/type-generator.js +30 -30
  35. package/lib/cjs/render/features/view-debugger.js +75 -55
  36. package/lib/cjs/testing/fluent-request.js +7 -0
  37. package/lib/cjs/testing/snapshot-request.js +2 -0
  38. package/lib/cjs/types/application/application-factory.d.ts +6 -0
  39. package/lib/cjs/types/application/bootstrap.d.ts +196 -24
  40. package/lib/cjs/types/config/config.interfaces.d.ts +7 -1
  41. package/lib/cjs/types/config/env-field-builders.d.ts +39 -0
  42. package/lib/cjs/types/config/index.d.ts +1 -1
  43. package/lib/cjs/types/framework-version.d.ts +7 -0
  44. package/lib/cjs/types/lazy-loading/index.d.ts +1 -0
  45. package/lib/cjs/types/lazy-loading/lazy-module-helpers.d.ts +42 -0
  46. package/lib/cjs/types/middleware/index.d.ts +1 -1
  47. package/lib/cjs/types/middleware/middleware-service.d.ts +21 -0
  48. package/lib/cjs/types/middleware/presets-standalone.d.ts +75 -0
  49. package/lib/cjs/types/provider/db-in-memory/adapter/in-memory.adapter.d.ts +2 -0
  50. package/lib/cjs/types/provider/db-in-memory/index.d.ts +9 -1
  51. package/lib/cjs/types/provider/db-in-memory/query/query-engine.d.ts +14 -1
  52. package/lib/cjs/types/provider/db-in-memory/schema/decorators.d.ts +14 -0
  53. package/lib/cjs/types/provider/db-in-memory/storage/index.d.ts +1 -1
  54. package/lib/cjs/types/provider/db-in-memory/storage/memory-store.d.ts +34 -0
  55. package/lib/cjs/types/provider/logger/logger.banner.d.ts +1 -1
  56. package/lib/cjs/types/provider/logger/logger.config.d.ts +7 -0
  57. package/lib/cjs/types/provider/logger/logger.formatter.d.ts +10 -0
  58. package/lib/cjs/types/provider/logger/logger.provider.d.ts +32 -1
  59. package/lib/cjs/types/provider/logger/transports/console.transport.d.ts +7 -0
  60. package/lib/cjs/types/provider/logger/utils/log-levels.d.ts +3 -3
  61. package/lib/cjs/types/provider/validation/adapters/index.d.ts +7 -4
  62. package/lib/cjs/types/provider/validation/adapters/yup.adapter.d.ts +65 -0
  63. package/lib/cjs/types/provider/validation/adapters/zod.adapter.d.ts +84 -0
  64. package/lib/cjs/types/provider/validation/index.d.ts +1 -1
  65. package/lib/cjs/types/render/features/view-debugger.d.ts +10 -0
  66. package/lib/cjs/types/testing/testing.interfaces.d.ts +31 -6
  67. package/lib/esm/application/application-factory.js +6 -0
  68. package/lib/esm/application/bootstrap.js +117 -213
  69. package/lib/esm/config/define-config.js +1 -1
  70. package/lib/esm/config/env-field-builders.js +48 -0
  71. package/lib/esm/config/index.js +6 -1
  72. package/lib/esm/framework-version.js +7 -0
  73. package/lib/esm/lazy-loading/index.js +2 -0
  74. package/lib/esm/lazy-loading/lazy-module-helpers.js +45 -0
  75. package/lib/esm/middleware/index.js +3 -2
  76. package/lib/esm/middleware/middleware-service.js +68 -12
  77. package/lib/esm/middleware/presets-standalone.js +87 -0
  78. package/lib/esm/provider/db-in-memory/adapter/in-memory.adapter.js +23 -0
  79. package/lib/esm/provider/db-in-memory/index.js +9 -1
  80. package/lib/esm/provider/db-in-memory/query/query-engine.js +28 -0
  81. package/lib/esm/provider/db-in-memory/schema/decorators.js +18 -0
  82. package/lib/esm/provider/db-in-memory/storage/index.js +1 -1
  83. package/lib/esm/provider/db-in-memory/storage/memory-store.js +75 -0
  84. package/lib/esm/provider/logger/logger.banner.js +40 -31
  85. package/lib/esm/provider/logger/logger.config.js +12 -2
  86. package/lib/esm/provider/logger/logger.formatter.js +22 -1
  87. package/lib/esm/provider/logger/logger.provider.js +61 -10
  88. package/lib/esm/provider/logger/transports/console.transport.js +69 -6
  89. package/lib/esm/provider/logger/transports/file.transport.js +27 -18
  90. package/lib/esm/provider/logger/utils/log-levels.js +6 -5
  91. package/lib/esm/provider/validation/adapters/index.js +7 -4
  92. package/lib/esm/provider/validation/adapters/yup.adapter.js +111 -0
  93. package/lib/esm/provider/validation/adapters/zod.adapter.js +130 -0
  94. package/lib/esm/provider/validation/index.js +1 -1
  95. package/lib/esm/render/adapters/react-adapter.js +14 -14
  96. package/lib/esm/render/features/type-generator.js +30 -30
  97. package/lib/esm/render/features/view-debugger.js +75 -55
  98. package/lib/esm/testing/fluent-request.js +7 -0
  99. package/lib/esm/testing/snapshot-request.js +2 -0
  100. package/lib/esm/types/application/application-factory.d.ts +6 -0
  101. package/lib/esm/types/application/bootstrap.d.ts +196 -24
  102. package/lib/esm/types/config/config.interfaces.d.ts +7 -1
  103. package/lib/esm/types/config/env-field-builders.d.ts +39 -0
  104. package/lib/esm/types/config/index.d.ts +1 -1
  105. package/lib/esm/types/framework-version.d.ts +7 -0
  106. package/lib/esm/types/lazy-loading/index.d.ts +1 -0
  107. package/lib/esm/types/lazy-loading/lazy-module-helpers.d.ts +42 -0
  108. package/lib/esm/types/middleware/index.d.ts +1 -1
  109. package/lib/esm/types/middleware/middleware-service.d.ts +21 -0
  110. package/lib/esm/types/middleware/presets-standalone.d.ts +75 -0
  111. package/lib/esm/types/provider/db-in-memory/adapter/in-memory.adapter.d.ts +2 -0
  112. package/lib/esm/types/provider/db-in-memory/index.d.ts +9 -1
  113. package/lib/esm/types/provider/db-in-memory/query/query-engine.d.ts +14 -1
  114. package/lib/esm/types/provider/db-in-memory/schema/decorators.d.ts +14 -0
  115. package/lib/esm/types/provider/db-in-memory/storage/index.d.ts +1 -1
  116. package/lib/esm/types/provider/db-in-memory/storage/memory-store.d.ts +34 -0
  117. package/lib/esm/types/provider/logger/logger.banner.d.ts +1 -1
  118. package/lib/esm/types/provider/logger/logger.config.d.ts +7 -0
  119. package/lib/esm/types/provider/logger/logger.formatter.d.ts +10 -0
  120. package/lib/esm/types/provider/logger/logger.provider.d.ts +32 -1
  121. package/lib/esm/types/provider/logger/transports/console.transport.d.ts +7 -0
  122. package/lib/esm/types/provider/logger/utils/log-levels.d.ts +3 -3
  123. package/lib/esm/types/provider/validation/adapters/index.d.ts +7 -4
  124. package/lib/esm/types/provider/validation/adapters/yup.adapter.d.ts +65 -0
  125. package/lib/esm/types/provider/validation/adapters/zod.adapter.d.ts +84 -0
  126. package/lib/esm/types/provider/validation/index.d.ts +1 -1
  127. package/lib/esm/types/render/features/view-debugger.d.ts +10 -0
  128. package/lib/esm/types/testing/testing.interfaces.d.ts +31 -6
  129. package/lib/package.json +23 -8
  130. package/package.json +23 -8
  131. package/lib/cjs/middleware/middleware-presets.js +0 -294
  132. package/lib/cjs/types/middleware/middleware-presets.d.ts +0 -90
  133. package/lib/esm/middleware/middleware-presets.js +0 -286
  134. package/lib/esm/types/middleware/middleware-presets.d.ts +0 -90
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Standalone (free-function) wrappers around `LazyModule` chain methods.
3
+ *
4
+ * The fluent API (`module.withPreloadHint(...).withLazyConfig(...)`) remains
5
+ * the recommended style. These helpers exist so users can compose lazy
6
+ * configurations with point-free style or apply the same hint to a list of
7
+ * modules:
8
+ *
9
+ * ```ts
10
+ * import { CreateLazyModule, withPreloadHint, withLazyConfig } from "@expressots/core";
11
+ *
12
+ * const Admin = withPreloadHint(
13
+ * CreateLazyModule([AdminController]),
14
+ * "low",
15
+ * );
16
+ *
17
+ * const Analytics = withLazyConfig(
18
+ * CreateLazyModule([AnalyticsController]),
19
+ * { preloadHint: "medium", prefetchAfterIdle: 5000 },
20
+ * );
21
+ * ```
22
+ *
23
+ * @public API
24
+ */
25
+ import type { ILazyModule, LazyModuleConfig, PreloadHint } from "./lazy.interfaces.js";
26
+ /**
27
+ * Set a preload hint on the supplied lazy module and return it.
28
+ *
29
+ * Equivalent to `module.withPreloadHint(hint)`. Returned reference is the same
30
+ * instance — no copy is made.
31
+ *
32
+ * @public API
33
+ */
34
+ export declare function withPreloadHint(module: ILazyModule, hint: PreloadHint): ILazyModule;
35
+ /**
36
+ * Merge the supplied partial config into the lazy module and return it.
37
+ *
38
+ * Equivalent to `module.withLazyConfig(config)`.
39
+ *
40
+ * @public API
41
+ */
42
+ export declare function withLazyConfig(module: ILazyModule, config: Partial<LazyModuleConfig>): ILazyModule;
@@ -2,7 +2,6 @@ export { Middleware, ExpressHandler, ExpressoMiddleware, MiddlewareOptions, Midd
2
2
  export { ErrorHandlerOptions, IMiddleware, HealthCheckOptions, } from "./middleware-interface.js";
3
3
  export { middlewareResolver, isMiddlewareAvailable, isPackageAvailable, resolvePackage, getAvailableMiddleware, getRegisteredMiddleware, clearMiddlewareCache, getPackageName, MIDDLEWARE_REGISTRY, RegisteredMiddlewareName, } from "./middleware-resolver.js";
4
4
  export { MiddlewareProfiler, MiddlewareMetrics, ProfilerStats, } from "./middleware-profiler.js";
5
- export { MiddlewarePresetName, MiddlewarePreset, PresetMiddlewareConfig, ApplyPresetOptions, MIDDLEWARE_PRESETS, getPreset, getPresetNames, getPresetsByTag, createPreset, mergePresets, } from "./middleware-presets.js";
6
5
  export type { OptionsJson } from "./interfaces/body-parser.interface.js";
7
6
  export type { CorsOptions } from "./interfaces/cors.interface.js";
8
7
  export type { CompressionOptions } from "./interfaces/compression.interface.js";
@@ -19,6 +18,7 @@ export type * as IMorgan from "./interfaces/morgan.interface.js";
19
18
  export { ContentNegotiationService, FormatterRegistry, AcceptHeaderParser, JsonFormatter, XmlFormatter, CsvFormatter, YamlFormatter, PlainTextFormatter, } from "./content-negotiation/index.js";
20
19
  export type { IContentFormatter, ContentNegotiationOptions, AcceptHeaderEntry, NegotiationResult, CsvFormatOptions, XmlFormatOptions, YamlFormatOptions, } from "./interfaces/content-negotiation.interface.js";
21
20
  export { use, compose, when, parallel, timeout } from "./middleware-utils.js";
21
+ export { definePreset, applyPreset, getStandalonePresetNames, clearStandalonePresets, } from "./presets-standalone.js";
22
22
  export { MiddlewareRegistry, getMiddlewareRegistry, resetMiddlewareRegistry, } from "./middleware-registry.js";
23
23
  export type { MiddlewareEntry as RegistryMiddlewareEntry } from "./middleware-registry.js";
24
24
  export { setGlobalUploadConfig, getGlobalUploadConfig, hasGlobalUploadConfig, clearGlobalUploadConfig, mergeUploadConfigs, } from "./upload-registry.js";
@@ -250,6 +250,7 @@ export declare class Middleware implements IMiddleware {
250
250
  private profiler;
251
251
  private profilingEnabled;
252
252
  private customPresets;
253
+ private _lastPreset;
253
254
  private registry;
254
255
  private startupLogs;
255
256
  private registeredMiddlewareNames;
@@ -699,8 +700,28 @@ export declare class Middleware implements IMiddleware {
699
700
  * Get all available presets.
700
701
  */
701
702
  getAllPresets(): Record<string, V4MiddlewareConfig>;
703
+ /**
704
+ * Returns info about the last applied preset (name, whether overrides
705
+ * were used, and the effective merged config). Used by the adapter to
706
+ * forward preset metadata to Studio.
707
+ */
708
+ getLastAppliedPreset(): {
709
+ name: string;
710
+ hasOverrides: boolean;
711
+ config: V4MiddlewareConfig;
712
+ } | null;
702
713
  /**
703
714
  * Get built-in presets.
715
+ *
716
+ * Each preset is tuned for a specific workload:
717
+ * - api: REST APIs (large payloads, rate-limited, strict CORS)
718
+ * - web: traditional server-rendered apps (cookies, sessions, relaxed CORS)
719
+ * - spa: single-page apps served with static fallback
720
+ * - microservice: internal service-to-service (minimal surface, no security)
721
+ * - graphql: single endpoint with large JSON payloads
722
+ * - minimal: parsing only, no security or compression
723
+ * - development: relaxed for local iteration, verbose logging
724
+ * - production: hardened defaults for shipped deployments
704
725
  */
705
726
  private getBuiltInPresets;
706
727
  /**
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Standalone (free-function) wrappers around the v4 middleware preset system.
3
+ *
4
+ * These exist alongside the `Middleware.definePreset` / `Middleware.applyPreset`
5
+ * instance methods so user code that doesn't have DI access to the `Middleware`
6
+ * provider — for example, declarative config files outside of the request
7
+ * lifecycle — can still register and apply presets.
8
+ *
9
+ * Usage:
10
+ * ```ts
11
+ * import { definePreset, applyPreset } from "@expressots/core";
12
+ *
13
+ * definePreset("my-api", {
14
+ * parse: { json: { limit: "1mb" } },
15
+ * security: { cors: { origin: "https://app.example.com" } },
16
+ * });
17
+ *
18
+ * // ...later, inside configureServices(), with the Middleware DI provider:
19
+ * applyPreset(this.services.middleware, "my-api");
20
+ * ```
21
+ *
22
+ * @public API
23
+ */
24
+ import type { Middleware } from "./middleware-service.js";
25
+ import type { MiddlewareConfig } from "./middleware-config.js";
26
+ /**
27
+ * Register a custom middleware preset under the given name.
28
+ *
29
+ * The preset is stored in a module-level registry so it can be referenced
30
+ * later by `applyPreset(middleware, name)`. Calling `definePreset` with an
31
+ * existing name overwrites the previous definition.
32
+ *
33
+ * @param name unique identifier for the preset
34
+ * @param config v4 middleware config object describing the preset
35
+ *
36
+ * @public API
37
+ */
38
+ export declare function definePreset(name: string, config: MiddlewareConfig): void;
39
+ /**
40
+ * Apply a previously defined preset (built-in or registered via
41
+ * `definePreset`) to the supplied `Middleware` instance.
42
+ *
43
+ * Resolution order:
44
+ * 1. Built-in v4 presets (`api`, `web`, `spa`, `microservice`, `graphql`,
45
+ * `minimal`, `development`, `production`) are matched by the
46
+ * `Middleware` instance itself.
47
+ * 2. Custom presets previously registered via `Middleware.definePreset`
48
+ * on the same instance.
49
+ * 3. Custom presets registered via the standalone `definePreset` here —
50
+ * these are forwarded to the instance on demand.
51
+ *
52
+ * @param middleware the active `Middleware` provider (typically resolved from
53
+ * the DI container inside `configureServices()`)
54
+ * @param name preset to apply
55
+ * @param overrides optional partial config that is merged on top of the
56
+ * preset before application
57
+ *
58
+ * @public API
59
+ */
60
+ export declare function applyPreset(middleware: Middleware, name: string, overrides?: Partial<MiddlewareConfig>): void;
61
+ /**
62
+ * Returns the names of every preset registered through the standalone
63
+ * `definePreset` helper. Built-in presets and per-instance custom presets
64
+ * are NOT included — those live on the `Middleware` instance.
65
+ *
66
+ * @public API
67
+ */
68
+ export declare function getStandalonePresetNames(): Array<string>;
69
+ /**
70
+ * Remove every preset registered through the standalone `definePreset`
71
+ * helper. Useful in tests; rarely needed at runtime.
72
+ *
73
+ * @public API
74
+ */
75
+ export declare function clearStandalonePresets(): void;
@@ -125,6 +125,8 @@ export interface InMemoryDatabaseOptions {
125
125
  timestamps?: boolean;
126
126
  /** Enable soft deletes by default for all tables */
127
127
  softDelete?: boolean;
128
+ /** Maximum number of records per table (0 = unlimited) */
129
+ maxRecordsPerTable?: number;
128
130
  /** Persistence configuration */
129
131
  persist?: {
130
132
  /** Storage type */
@@ -4,6 +4,14 @@
4
4
  * A high-performance, Prisma-compatible in-memory database
5
5
  * for ExpressoTS applications.
6
6
  *
7
+ * Scope: this database is intended for development, testing, and
8
+ * prototyping. Data lives in process memory (with optional file
9
+ * snapshots) and does not provide the crash safety, concurrency, or
10
+ * multi-process guarantees of a real database engine. It implements the
11
+ * universal `IDataAdapter` contract so it can be swapped for a
12
+ * production adapter (Prisma, TypeORM, etc.) without rewriting
13
+ * repositories.
14
+ *
7
15
  * Features:
8
16
  * - Prisma-like query API
9
17
  * - Type-safe queries with TypeScript
@@ -56,7 +64,7 @@ export { InMemoryDBProvider, InMemoryDBConfig, BaseRepository, } from "./db.prov
56
64
  export { IDataAdapter, ITableAdapter, IMultiTableAdapter, IReactiveDataAdapter, ISubscription, ChangeEvent, ChangeType, InMemoryAdapter, InMemoryAdapterOptions, InMemoryDatabase, InMemoryDatabaseOptions, } from "./adapter/index.js";
57
65
  export { IEntity, ITimestampedEntity, ISoftDeleteEntity, Entity, EntityOptions, EntityMetadata, PrimaryKey, AutoGenerate, AutoGenerateStrategy, Index, IndexOptions, Unique, Nullable, Default, HasMany, HasOne, BelongsTo, ManyToMany, RelationType, RelationMetadata, SchemaRegistry, DB_METADATA_KEYS, } from "./schema/index.js";
58
66
  export { StringFilter, NumberFilter, BooleanFilter, DateFilter, FieldFilter, WhereInput, WhereUniqueInput, OrderByInput, SortOrder, SelectInput, IncludeInput, FindUniqueArgs, FindFirstArgs, FindManyArgs, CreateArgs, CreateInput, CreateManyArgs, UpdateArgs, UpdateInput, UpdateManyArgs, UpsertArgs, DeleteArgs, DeleteManyArgs, CountArgs, CountSelect, AggregateArgs, AggregateResult, NumericFieldsOnly, GroupByArgs, BatchPayload, TransactionClient, QueryEngine, } from "./query/index.js";
59
- export { MemoryStore, MemoryStoreOptions, IndexManager, IdGenerator, UniqueConstraintError, EntityNotFoundError, EntityAlreadyExistsError, } from "./storage/index.js";
67
+ export { MemoryStore, MemoryStoreOptions, IndexManager, IdGenerator, UniqueConstraintError, EntityNotFoundError, EntityAlreadyExistsError, MaxRecordsExceededError, EntityValidationError, } from "./storage/index.js";
60
68
  export { IRepository, IDataTable, IDataProvider, } from "./db-in-memory.interface.js";
61
69
  export { InMemoryDataProvider, InMemoryDataTable, } from "./db-in-memory.provider.js";
62
70
  export { EntityNotFoundError as LegacyEntityNotFoundError, EntityAlreadyExistsError as LegacyEntityAlreadyExistsError, } from "./db-in-memory.types.js";
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { IEntity } from "../schema/entity.interface.js";
9
9
  import { MemoryStore } from "../storage/memory-store.js";
10
- import { WhereInput, OrderByInput, FindManyArgs, SelectInput, AggregateArgs, AggregateResult } from "./query.types.js";
10
+ import { WhereInput, WhereUniqueInput, OrderByInput, FindManyArgs, SelectInput, AggregateArgs, AggregateResult } from "./query.types.js";
11
11
  /**
12
12
  * Query Engine for parsing and executing Prisma-like queries.
13
13
  *
@@ -72,6 +72,19 @@ export declare class QueryEngine<T extends IEntity> {
72
72
  * @returns Paginated entities
73
73
  */
74
74
  executePagination(entities: Array<T>, skip?: number, take?: number): Array<T>;
75
+ /**
76
+ * Apply cursor-based pagination. The cursor identifies a record (by id or
77
+ * any other field combination) within the ordered result set; the returned
78
+ * slice starts at that record. Combine with `skip` (typically `skip: 1` to
79
+ * exclude the cursor itself) and `take`.
80
+ *
81
+ * Should be applied after `orderBy` and before `skip`/`take`.
82
+ *
83
+ * @param entities - Ordered entities to slice
84
+ * @param cursor - Unique cursor identifying the start record
85
+ * @returns Entities starting at the cursor (empty array if not found)
86
+ */
87
+ executeCursor(entities: Array<T>, cursor?: WhereUniqueInput<T>): Array<T>;
75
88
  /**
76
89
  * Get distinct entities by specified fields.
77
90
  * @param entities - Entities to filter
@@ -306,6 +306,20 @@ export declare class SchemaRegistry {
306
306
  * @public API
307
307
  */
308
308
  static getRelations(target: new (...args: Array<unknown>) => unknown): Array<RelationMetadata>;
309
+ /**
310
+ * Get primary key field names for an entity.
311
+ * @param target - Entity class
312
+ * @returns Array of primary key field names
313
+ * @public API
314
+ */
315
+ static getPrimaryKeys(target: new (...args: Array<unknown>) => unknown): Array<string | symbol>;
316
+ /**
317
+ * Get nullable field names for an entity.
318
+ * @param target - Entity class
319
+ * @returns Array of nullable field names
320
+ * @public API
321
+ */
322
+ static getNullableFields(target: new (...args: Array<unknown>) => unknown): Array<string | symbol>;
309
323
  /**
310
324
  * Clear all registered entities (useful for testing).
311
325
  * @public API
@@ -2,4 +2,4 @@
2
2
  * Storage Module Exports
3
3
  * @module db-in-memory/storage
4
4
  */
5
- export { MemoryStore, MemoryStoreOptions, IndexManager, IdGenerator, UniqueConstraintError, EntityNotFoundError, EntityAlreadyExistsError, } from "./memory-store.js";
5
+ export { MemoryStore, MemoryStoreOptions, IndexManager, IdGenerator, UniqueConstraintError, EntityNotFoundError, EntityAlreadyExistsError, MaxRecordsExceededError, EntityValidationError, } from "./memory-store.js";
@@ -102,6 +102,24 @@ export declare class EntityNotFoundError extends Error {
102
102
  id: string;
103
103
  constructor(entityName: string, id: string);
104
104
  }
105
+ /**
106
+ * Error thrown when a table reaches its configured record limit.
107
+ * @public API
108
+ */
109
+ export declare class MaxRecordsExceededError extends Error {
110
+ tableName: string;
111
+ limit: number;
112
+ constructor(tableName: string, limit: number);
113
+ }
114
+ /**
115
+ * Error thrown when entity validation fails (when `@Entity({ validate: true })`).
116
+ * @public API
117
+ */
118
+ export declare class EntityValidationError extends Error {
119
+ tableName: string;
120
+ field: string;
121
+ constructor(tableName: string, field: string, message?: string);
122
+ }
105
123
  /**
106
124
  * Error thrown when an entity already exists.
107
125
  * @public API
@@ -143,6 +161,8 @@ export interface MemoryStoreOptions {
143
161
  timestamps?: boolean;
144
162
  /** Enable soft deletes */
145
163
  softDelete?: boolean;
164
+ /** Maximum number of records allowed in the table (0 = unlimited) */
165
+ maxRecordsPerTable?: number;
146
166
  }
147
167
  /**
148
168
  * High-performance in-memory storage for a single table/collection.
@@ -175,12 +195,26 @@ export declare class MemoryStore<T extends IEntity> {
175
195
  private autoGenerateFields;
176
196
  /** Default values */
177
197
  private defaultValues;
198
+ /** Maximum number of records allowed (0 = unlimited) */
199
+ private maxRecords;
200
+ /** Enable runtime validation (from @Entity({ validate: true })) */
201
+ private validate;
202
+ /** Fields that must be present and non-null when validation is enabled */
203
+ private requiredFields;
178
204
  constructor(tableName: string, options?: MemoryStoreOptions);
179
205
  /**
180
206
  * Load schema metadata from decorators.
181
207
  * @private
182
208
  */
183
209
  private loadSchemaMetadata;
210
+ /**
211
+ * Validate an entity against the schema (only when `validate` is enabled).
212
+ * Ensures required fields (primary key + unique, excluding @Nullable) are
213
+ * present and non-null.
214
+ * @private
215
+ * @throws ValidationError when a required field is missing or null
216
+ */
217
+ private validateEntity;
184
218
  /**
185
219
  * Apply auto-generation and defaults to entity.
186
220
  * @private
@@ -72,7 +72,7 @@ export declare class BannerGenerator {
72
72
  */
73
73
  private displayFullBanner;
74
74
  /**
75
- * Display compact banner.
75
+ * Display compact banner using structured log format (cloud-friendly).
76
76
  */
77
77
  private displayCompactBanner;
78
78
  /**
@@ -50,6 +50,13 @@ export interface LoggerConfig {
50
50
  }
51
51
  /**
52
52
  * Default logger configuration.
53
+ *
54
+ * Honours `process.env.LOG_LEVEL` when set so that any logs emitted
55
+ * BEFORE the application's `globalConfiguration()` runs (e.g. interceptor
56
+ * registration during container construction) are gated by the user's
57
+ * desired log level instead of the development default of `DEBUG`.
58
+ * Falls back to `DEBUG` in development and `INFO` in production.
59
+ *
53
60
  * @public API
54
61
  */
55
62
  export declare function getDefaultLoggerConfig(): LoggerConfig;
@@ -9,6 +9,16 @@ export interface FormatOptions {
9
9
  redact?: boolean;
10
10
  /** Custom redactor instance (uses global if not provided) */
11
11
  redactor?: Redactor;
12
+ /**
13
+ * Emit ANSI color escape codes. When false, the formatted output is
14
+ * post-processed to strip every ANSI escape. Defaults to true (colored).
15
+ *
16
+ * Disable this for non-TTY consumers like cloud log viewers (Azure
17
+ * App Service, AWS CloudWatch, Heroku, Kubernetes, etc.) and Studio's
18
+ * Live Logs panel, all of which display the raw text without
19
+ * interpreting terminal escape sequences.
20
+ */
21
+ colors?: boolean;
12
22
  }
13
23
  /**
14
24
  * Format log entry for development (human-readable, colored).
@@ -12,7 +12,7 @@ import { LogQueryOptions, LogQuery, QueryStats } from "./logger.query.js";
12
12
  * - Automatic context detection (class/method names)
13
13
  * - Request-scoped context via AsyncLocalStorage
14
14
  * - Child logger creation with inherited context
15
- * - Multiple log levels (TRACE, DEBUG, INFO, WARN, ERROR, FATAL)
15
+ * - Multiple log levels (ALL, DEBUG, INFO, WARN, ERROR, FATAL, SILENT)
16
16
  * - Pluggable transports (console, file, HTTP)
17
17
  * @public API
18
18
  */
@@ -26,11 +26,42 @@ declare class Logger implements IProvider {
26
26
  private groupingManager;
27
27
  private healthMonitor;
28
28
  private queryManager;
29
+ /**
30
+ * Module-level overrides applied by `Logger.configure(...)` on top of the
31
+ * built-in defaults. Used by the constructor of every future `Logger`
32
+ * instance so application-wide config (e.g. log level, transports) can be
33
+ * set once before bootstrap, before any DI container exists.
34
+ */
35
+ private static defaultOverrides;
29
36
  name: string;
30
37
  version: string;
31
38
  author: string;
32
39
  repo: string;
33
40
  constructor();
41
+ /**
42
+ * Configure the default LoggerConfig used by every future `Logger`
43
+ * instance constructed in this process.
44
+ *
45
+ * Use this from application config files **before** bootstrap so the DI
46
+ * container's Logger picks up the correct level / transports / grouping /
47
+ * health / redaction settings without needing to inject and reconfigure it.
48
+ * Calls are merged: later calls override earlier ones, but unspecified
49
+ * keys keep their previously-set values.
50
+ *
51
+ * Already-constructed Logger instances are NOT mutated by this call —
52
+ * use the instance method `logger.configure(...)` to update a live one.
53
+ *
54
+ * @param config - Partial configuration to merge with the defaults.
55
+ * @public API
56
+ */
57
+ static configure(config: Partial<LoggerConfig>): void;
58
+ /**
59
+ * Reset the module-level overrides set by `Logger.configure`. Useful in
60
+ * tests to undo cross-test pollution.
61
+ *
62
+ * @public API
63
+ */
64
+ static resetConfigure(): void;
34
65
  /**
35
66
  * Configure the logger.
36
67
  * @param config - Partial configuration to merge with defaults
@@ -32,6 +32,13 @@ export declare class ConsoleTransport implements ILogTransport {
32
32
  });
33
33
  /**
34
34
  * Create a console transport optimized for development.
35
+ *
36
+ * Colors are auto-detected: they're emitted when stdout is a TTY
37
+ * (your terminal) and disabled when stdout is piped or captured by
38
+ * a cloud log collector (Azure App Service, AWS CloudWatch, Heroku,
39
+ * Docker, Kubernetes, etc.). Respects the standard `NO_COLOR` and
40
+ * `FORCE_COLOR` environment variables.
41
+ *
35
42
  * @param redact - Enable redaction (default: false for development)
36
43
  * @returns ConsoleTransport configured for development
37
44
  * @public API
@@ -4,8 +4,8 @@
4
4
  * @public API
5
5
  */
6
6
  export declare enum LogLevel {
7
- /** Ultra-detailed diagnostic information (function entry/exit) */
8
- TRACE = 0,
7
+ /** Show all logs (ultra-detailed diagnostic information, function entry/exit) */
8
+ ALL = 0,
9
9
  /** Detailed diagnostic information for debugging */
10
10
  DEBUG = 1,
11
11
  /** General informational messages */
@@ -23,7 +23,7 @@ export declare enum LogLevel {
23
23
  * String representation of log levels for backward compatibility.
24
24
  * @public API
25
25
  */
26
- export type LogLevelString = "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL" | "SILENT" | "NONE";
26
+ export type LogLevelString = "ALL" | "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL" | "SILENT" | "NONE";
27
27
  /**
28
28
  * Legacy log level for backward compatibility.
29
29
  * Maps to INFO level.
@@ -2,9 +2,12 @@
2
2
  * Validation Adapters
3
3
  * @module @expressots/core/validation/adapters
4
4
  *
5
- * Built-in adapters for validation libraries.
6
- * Additional adapters (Zod, Yup, Joi) available as separate packages:
7
- * - @expressots/validator-zod
8
- * - @expressots/validator-yup
5
+ * Built-in adapters for validation libraries. The validation libraries
6
+ * themselves (`class-validator`, `zod`, `yup`) are *optional peer
7
+ * dependencies* — install only the one(s) you actually use.
8
+ *
9
+ * Additional Joi adapter is on the roadmap.
9
10
  */
10
11
  export { ClassValidatorAdapter } from "./class-validator.adapter.js";
12
+ export { ZodValidatorAdapter, createZodValidator } from "./zod.adapter.js";
13
+ export { YupValidatorAdapter, createYupValidator } from "./yup.adapter.js";
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Yup Validation Adapter
3
+ * @module @expressots/core/validation
4
+ *
5
+ * Built-in adapter for the [yup](https://github.com/jquense/yup) validation
6
+ * library. `yup` is declared as an *optional* peer dependency: install it
7
+ * explicitly (`npm i yup`) to enable this adapter.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import * as yup from "yup";
12
+ * import { validationRegistry, createYupValidator } from "@expressots/core";
13
+ *
14
+ * validationRegistry.register(createYupValidator());
15
+ *
16
+ * const CreateUserSchema = yup.object({
17
+ * email: yup.string().email().required(),
18
+ * age: yup.number().integer().min(18).required(),
19
+ * });
20
+ *
21
+ * @controller("/users")
22
+ * class UsersController {
23
+ * @Post("/")
24
+ * create(@body(CreateUserSchema) input: yup.InferType<typeof CreateUserSchema>) {
25
+ * // input is fully typed and validated
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ import { IValidationAdapter, ValidationOptions, ValidationResult } from "../validation.interface.js";
31
+ /** Subset of yup's surface we depend on, structurally typed. */
32
+ interface YupLikeSchema {
33
+ readonly __isYupSchema__?: boolean;
34
+ validate?(data: unknown, options?: YupOptions): Promise<unknown>;
35
+ validateSync?(data: unknown, options?: YupOptions): unknown;
36
+ cast?(data: unknown, options?: YupOptions): unknown;
37
+ }
38
+ interface YupOptions {
39
+ abortEarly?: boolean;
40
+ stripUnknown?: boolean;
41
+ context?: unknown;
42
+ }
43
+ /**
44
+ * Adapter for [yup](https://github.com/jquense/yup). Detects yup schemas at
45
+ * runtime by checking for the `__isYupSchema__` brand or the presence of a
46
+ * `validate` + `cast` method pair.
47
+ *
48
+ * @public API
49
+ */
50
+ export declare class YupValidatorAdapter implements IValidationAdapter<YupLikeSchema> {
51
+ readonly name = "yup";
52
+ readonly priority = 80;
53
+ canHandle(schema: unknown): boolean;
54
+ validate(data: unknown, schema: YupLikeSchema, options?: ValidationOptions): Promise<ValidationResult>;
55
+ transform(data: unknown, schema: YupLikeSchema): Promise<unknown>;
56
+ private mapIssues;
57
+ }
58
+ /**
59
+ * Convenience factory matching the `createXxxValidator` naming used by the
60
+ * other adapters. Equivalent to `new YupValidatorAdapter()`.
61
+ *
62
+ * @public API
63
+ */
64
+ export declare function createYupValidator(): YupValidatorAdapter;
65
+ export {};
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Zod Validation Adapter
3
+ * @module @expressots/core/validation
4
+ *
5
+ * Built-in adapter for the [zod](https://zod.dev) validation library.
6
+ * `zod` is declared as an *optional* peer dependency: install it explicitly
7
+ * (`npm i zod`) to enable this adapter; otherwise validation falls back to
8
+ * the next registered adapter.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { z } from "zod";
13
+ * import { validationRegistry, ZodValidatorAdapter, createZodValidator } from "@expressots/core";
14
+ *
15
+ * validationRegistry.register(createZodValidator());
16
+ *
17
+ * const CreateUserSchema = z.object({
18
+ * email: z.string().email(),
19
+ * age: z.number().int().min(18),
20
+ * });
21
+ *
22
+ * @controller("/users")
23
+ * class UsersController {
24
+ * @Post("/")
25
+ * create(@body(CreateUserSchema) input: z.infer<typeof CreateUserSchema>) {
26
+ * // input is fully typed and validated
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+ import { IValidationAdapter, ValidationOptions, ValidationResult } from "../validation.interface.js";
32
+ /**
33
+ * Minimal structural typing for the subset of zod we actually call. We cannot
34
+ * import zod directly from core (it is an optional peer), but we type the
35
+ * schema we receive as `unknown` and refine via the runtime `canHandle` check.
36
+ */
37
+ interface ZodLikeSchema {
38
+ readonly _def?: unknown;
39
+ parse?(data: unknown): unknown;
40
+ parseAsync?(data: unknown): Promise<unknown>;
41
+ safeParseAsync?(data: unknown): Promise<{
42
+ success: boolean;
43
+ data?: unknown;
44
+ error?: {
45
+ issues: Array<ZodIssue>;
46
+ };
47
+ }>;
48
+ safeParse?(data: unknown): {
49
+ success: boolean;
50
+ data?: unknown;
51
+ error?: {
52
+ issues: Array<ZodIssue>;
53
+ };
54
+ };
55
+ }
56
+ interface ZodIssue {
57
+ path: Array<string | number>;
58
+ message: string;
59
+ code?: string;
60
+ received?: unknown;
61
+ }
62
+ /**
63
+ * Adapter for [zod](https://zod.dev). Picks up any zod schema (`z.object`,
64
+ * `z.string`, ...) at runtime by structural detection — no compile-time
65
+ * dependency on `zod` is required.
66
+ *
67
+ * @public API
68
+ */
69
+ export declare class ZodValidatorAdapter implements IValidationAdapter<ZodLikeSchema> {
70
+ readonly name = "zod";
71
+ readonly priority = 90;
72
+ canHandle(schema: unknown): boolean;
73
+ validate(data: unknown, schema: ZodLikeSchema, _options?: ValidationOptions): Promise<ValidationResult>;
74
+ transform(data: unknown, schema: ZodLikeSchema): Promise<unknown>;
75
+ private mapIssues;
76
+ }
77
+ /**
78
+ * Convenience factory matching the `createXxxValidator` naming used by the
79
+ * other adapters. Equivalent to `new ZodValidatorAdapter()`.
80
+ *
81
+ * @public API
82
+ */
83
+ export declare function createZodValidator(): ZodValidatorAdapter;
84
+ export {};
@@ -16,4 +16,4 @@ export { ValidationRegistry } from "./validation-registry.js";
16
16
  export { SmartFieldDetector } from "./smart-field-detector.js";
17
17
  export { HelpfulErrorFormatter, type ErrorFormat, type FormattedErrorResponse, } from "./helpful-error-formatter.js";
18
18
  export { getParameterType, getAllParameterTypes, getClassProperties, hasClassValidatorDecorators, isZodSchema, isClassConstructor, detectSchemaType, type InferredTypeInfo, type InferredPropertyInfo, } from "./type-inference.js";
19
- export { ClassValidatorAdapter } from "./adapters/index.js";
19
+ export { ClassValidatorAdapter, ZodValidatorAdapter, createZodValidator, YupValidatorAdapter, createYupValidator, } from "./adapters/index.js";
@@ -27,6 +27,16 @@ export declare class ViewDebugger {
27
27
  * Handle the view preview endpoint.
28
28
  */
29
29
  private handlePreviewEndpoint;
30
+ /**
31
+ * Normalise the `view` route param across Express 4 and 5.
32
+ *
33
+ * Express 4 / path-to-regexp v6 captured `/__views/preview/:view(*)`
34
+ * as a single string. Express 5 / path-to-regexp v8 changed the
35
+ * named-splat capture to `string[]` (one entry per slash-separated
36
+ * segment). The view engine needs the slash-joined form, so we always
37
+ * collapse the array shape back to that.
38
+ */
39
+ private resolveViewParam;
30
40
  /**
31
41
  * Handle the view info endpoint.
32
42
  */