@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.
- package/LICENSE.md +21 -21
- package/README.md +66 -66
- package/lib/CHANGELOG.md +774 -774
- package/lib/README.md +66 -66
- package/lib/cjs/application/application-factory.js +6 -0
- package/lib/cjs/application/bootstrap.js +117 -213
- package/lib/cjs/config/define-config.js +1 -1
- package/lib/cjs/config/env-field-builders.js +47 -0
- package/lib/cjs/config/index.js +7 -1
- package/lib/cjs/framework-version.js +10 -0
- package/lib/cjs/lazy-loading/index.js +5 -1
- package/lib/cjs/lazy-loading/lazy-module-helpers.js +49 -0
- package/lib/cjs/middleware/index.js +8 -9
- package/lib/cjs/middleware/middleware-service.js +68 -12
- package/lib/cjs/middleware/presets-standalone.js +93 -0
- package/lib/cjs/provider/db-in-memory/adapter/in-memory.adapter.js +23 -0
- package/lib/cjs/provider/db-in-memory/index.js +11 -1
- package/lib/cjs/provider/db-in-memory/query/query-engine.js +28 -0
- package/lib/cjs/provider/db-in-memory/schema/decorators.js +18 -0
- package/lib/cjs/provider/db-in-memory/storage/index.js +3 -1
- package/lib/cjs/provider/db-in-memory/storage/memory-store.js +72 -1
- package/lib/cjs/provider/logger/logger.banner.js +40 -31
- package/lib/cjs/provider/logger/logger.config.js +11 -1
- package/lib/cjs/provider/logger/logger.formatter.js +22 -1
- package/lib/cjs/provider/logger/logger.provider.js +59 -9
- package/lib/cjs/provider/logger/transports/console.transport.js +69 -6
- package/lib/cjs/provider/logger/transports/file.transport.js +27 -18
- package/lib/cjs/provider/logger/utils/log-levels.js +6 -5
- package/lib/cjs/provider/validation/adapters/index.js +12 -5
- package/lib/cjs/provider/validation/adapters/yup.adapter.js +118 -0
- package/lib/cjs/provider/validation/adapters/zod.adapter.js +137 -0
- package/lib/cjs/provider/validation/index.js +5 -1
- package/lib/cjs/render/adapters/react-adapter.js +14 -14
- package/lib/cjs/render/features/type-generator.js +30 -30
- package/lib/cjs/render/features/view-debugger.js +75 -55
- package/lib/cjs/testing/fluent-request.js +7 -0
- package/lib/cjs/testing/snapshot-request.js +2 -0
- package/lib/cjs/types/application/application-factory.d.ts +6 -0
- package/lib/cjs/types/application/bootstrap.d.ts +196 -24
- package/lib/cjs/types/config/config.interfaces.d.ts +7 -1
- package/lib/cjs/types/config/env-field-builders.d.ts +39 -0
- package/lib/cjs/types/config/index.d.ts +1 -1
- package/lib/cjs/types/framework-version.d.ts +7 -0
- package/lib/cjs/types/lazy-loading/index.d.ts +1 -0
- package/lib/cjs/types/lazy-loading/lazy-module-helpers.d.ts +42 -0
- package/lib/cjs/types/middleware/index.d.ts +1 -1
- package/lib/cjs/types/middleware/middleware-service.d.ts +21 -0
- package/lib/cjs/types/middleware/presets-standalone.d.ts +75 -0
- package/lib/cjs/types/provider/db-in-memory/adapter/in-memory.adapter.d.ts +2 -0
- package/lib/cjs/types/provider/db-in-memory/index.d.ts +9 -1
- package/lib/cjs/types/provider/db-in-memory/query/query-engine.d.ts +14 -1
- package/lib/cjs/types/provider/db-in-memory/schema/decorators.d.ts +14 -0
- package/lib/cjs/types/provider/db-in-memory/storage/index.d.ts +1 -1
- package/lib/cjs/types/provider/db-in-memory/storage/memory-store.d.ts +34 -0
- package/lib/cjs/types/provider/logger/logger.banner.d.ts +1 -1
- package/lib/cjs/types/provider/logger/logger.config.d.ts +7 -0
- package/lib/cjs/types/provider/logger/logger.formatter.d.ts +10 -0
- package/lib/cjs/types/provider/logger/logger.provider.d.ts +32 -1
- package/lib/cjs/types/provider/logger/transports/console.transport.d.ts +7 -0
- package/lib/cjs/types/provider/logger/utils/log-levels.d.ts +3 -3
- package/lib/cjs/types/provider/validation/adapters/index.d.ts +7 -4
- package/lib/cjs/types/provider/validation/adapters/yup.adapter.d.ts +65 -0
- package/lib/cjs/types/provider/validation/adapters/zod.adapter.d.ts +84 -0
- package/lib/cjs/types/provider/validation/index.d.ts +1 -1
- package/lib/cjs/types/render/features/view-debugger.d.ts +10 -0
- package/lib/cjs/types/testing/testing.interfaces.d.ts +31 -6
- package/lib/esm/application/application-factory.js +6 -0
- package/lib/esm/application/bootstrap.js +117 -213
- package/lib/esm/config/define-config.js +1 -1
- package/lib/esm/config/env-field-builders.js +48 -0
- package/lib/esm/config/index.js +6 -1
- package/lib/esm/framework-version.js +7 -0
- package/lib/esm/lazy-loading/index.js +2 -0
- package/lib/esm/lazy-loading/lazy-module-helpers.js +45 -0
- package/lib/esm/middleware/index.js +3 -2
- package/lib/esm/middleware/middleware-service.js +68 -12
- package/lib/esm/middleware/presets-standalone.js +87 -0
- package/lib/esm/provider/db-in-memory/adapter/in-memory.adapter.js +23 -0
- package/lib/esm/provider/db-in-memory/index.js +9 -1
- package/lib/esm/provider/db-in-memory/query/query-engine.js +28 -0
- package/lib/esm/provider/db-in-memory/schema/decorators.js +18 -0
- package/lib/esm/provider/db-in-memory/storage/index.js +1 -1
- package/lib/esm/provider/db-in-memory/storage/memory-store.js +75 -0
- package/lib/esm/provider/logger/logger.banner.js +40 -31
- package/lib/esm/provider/logger/logger.config.js +12 -2
- package/lib/esm/provider/logger/logger.formatter.js +22 -1
- package/lib/esm/provider/logger/logger.provider.js +61 -10
- package/lib/esm/provider/logger/transports/console.transport.js +69 -6
- package/lib/esm/provider/logger/transports/file.transport.js +27 -18
- package/lib/esm/provider/logger/utils/log-levels.js +6 -5
- package/lib/esm/provider/validation/adapters/index.js +7 -4
- package/lib/esm/provider/validation/adapters/yup.adapter.js +111 -0
- package/lib/esm/provider/validation/adapters/zod.adapter.js +130 -0
- package/lib/esm/provider/validation/index.js +1 -1
- package/lib/esm/render/adapters/react-adapter.js +14 -14
- package/lib/esm/render/features/type-generator.js +30 -30
- package/lib/esm/render/features/view-debugger.js +75 -55
- package/lib/esm/testing/fluent-request.js +7 -0
- package/lib/esm/testing/snapshot-request.js +2 -0
- package/lib/esm/types/application/application-factory.d.ts +6 -0
- package/lib/esm/types/application/bootstrap.d.ts +196 -24
- package/lib/esm/types/config/config.interfaces.d.ts +7 -1
- package/lib/esm/types/config/env-field-builders.d.ts +39 -0
- package/lib/esm/types/config/index.d.ts +1 -1
- package/lib/esm/types/framework-version.d.ts +7 -0
- package/lib/esm/types/lazy-loading/index.d.ts +1 -0
- package/lib/esm/types/lazy-loading/lazy-module-helpers.d.ts +42 -0
- package/lib/esm/types/middleware/index.d.ts +1 -1
- package/lib/esm/types/middleware/middleware-service.d.ts +21 -0
- package/lib/esm/types/middleware/presets-standalone.d.ts +75 -0
- package/lib/esm/types/provider/db-in-memory/adapter/in-memory.adapter.d.ts +2 -0
- package/lib/esm/types/provider/db-in-memory/index.d.ts +9 -1
- package/lib/esm/types/provider/db-in-memory/query/query-engine.d.ts +14 -1
- package/lib/esm/types/provider/db-in-memory/schema/decorators.d.ts +14 -0
- package/lib/esm/types/provider/db-in-memory/storage/index.d.ts +1 -1
- package/lib/esm/types/provider/db-in-memory/storage/memory-store.d.ts +34 -0
- package/lib/esm/types/provider/logger/logger.banner.d.ts +1 -1
- package/lib/esm/types/provider/logger/logger.config.d.ts +7 -0
- package/lib/esm/types/provider/logger/logger.formatter.d.ts +10 -0
- package/lib/esm/types/provider/logger/logger.provider.d.ts +32 -1
- package/lib/esm/types/provider/logger/transports/console.transport.d.ts +7 -0
- package/lib/esm/types/provider/logger/utils/log-levels.d.ts +3 -3
- package/lib/esm/types/provider/validation/adapters/index.d.ts +7 -4
- package/lib/esm/types/provider/validation/adapters/yup.adapter.d.ts +65 -0
- package/lib/esm/types/provider/validation/adapters/zod.adapter.d.ts +84 -0
- package/lib/esm/types/provider/validation/index.d.ts +1 -1
- package/lib/esm/types/render/features/view-debugger.d.ts +10 -0
- package/lib/esm/types/testing/testing.interfaces.d.ts +31 -6
- package/lib/package.json +23 -8
- package/package.json +23 -8
- package/lib/cjs/middleware/middleware-presets.js +0 -294
- package/lib/cjs/types/middleware/middleware-presets.d.ts +0 -90
- package/lib/esm/middleware/middleware-presets.js +0 -286
- package/lib/esm/types/middleware/middleware-presets.d.ts +0 -90
|
@@ -268,20 +268,20 @@ export class ReactAdapter extends BaseEngineAdapter {
|
|
|
268
268
|
.replace(/</g, "\\u003c")
|
|
269
269
|
.replace(/>/g, "\\u003e")
|
|
270
270
|
.replace(/&/g, "\\u0026");
|
|
271
|
-
return `<!DOCTYPE html>
|
|
272
|
-
<html lang="en">
|
|
273
|
-
<head>
|
|
274
|
-
<meta charset="UTF-8">
|
|
275
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
276
|
-
<script>
|
|
277
|
-
window.__INITIAL_DATA__ = ${safeData};
|
|
278
|
-
window.__COMPONENT__ = "${view}";
|
|
279
|
-
</script>
|
|
280
|
-
</head>
|
|
281
|
-
<body>
|
|
282
|
-
<div id="root">${html}</div>
|
|
283
|
-
<script src="/assets/client.js" defer></script>
|
|
284
|
-
</body>
|
|
271
|
+
return `<!DOCTYPE html>
|
|
272
|
+
<html lang="en">
|
|
273
|
+
<head>
|
|
274
|
+
<meta charset="UTF-8">
|
|
275
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
276
|
+
<script>
|
|
277
|
+
window.__INITIAL_DATA__ = ${safeData};
|
|
278
|
+
window.__COMPONENT__ = "${view}";
|
|
279
|
+
</script>
|
|
280
|
+
</head>
|
|
281
|
+
<body>
|
|
282
|
+
<div id="root">${html}</div>
|
|
283
|
+
<script src="/assets/client.js" defer></script>
|
|
284
|
+
</body>
|
|
285
285
|
</html>`;
|
|
286
286
|
}
|
|
287
287
|
/**
|
|
@@ -89,36 +89,36 @@ export class TypeGenerator {
|
|
|
89
89
|
const propsType = v.propsType || "Record<string, unknown>";
|
|
90
90
|
return ` "${v.name}": ${propsType};`;
|
|
91
91
|
});
|
|
92
|
-
return `/**
|
|
93
|
-
* Auto-generated view types
|
|
94
|
-
* Generated by ExpressoTS Render Engine
|
|
95
|
-
* Do not edit this file manually
|
|
96
|
-
*/
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* View name to props type mapping
|
|
100
|
-
*/
|
|
101
|
-
export interface Views {
|
|
102
|
-
${viewTypes.join("\n")}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* All view names
|
|
107
|
-
*/
|
|
108
|
-
export type ViewName = keyof Views;
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get props type for a specific view
|
|
112
|
-
*/
|
|
113
|
-
export type ViewProps<T extends ViewName> = Views[T];
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Type-safe render function signature
|
|
117
|
-
*/
|
|
118
|
-
export type RenderFunction = <T extends ViewName>(
|
|
119
|
-
view: T,
|
|
120
|
-
data: Views[T],
|
|
121
|
-
) => Promise<string>;
|
|
92
|
+
return `/**
|
|
93
|
+
* Auto-generated view types
|
|
94
|
+
* Generated by ExpressoTS Render Engine
|
|
95
|
+
* Do not edit this file manually
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* View name to props type mapping
|
|
100
|
+
*/
|
|
101
|
+
export interface Views {
|
|
102
|
+
${viewTypes.join("\n")}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* All view names
|
|
107
|
+
*/
|
|
108
|
+
export type ViewName = keyof Views;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get props type for a specific view
|
|
112
|
+
*/
|
|
113
|
+
export type ViewProps<T extends ViewName> = Views[T];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Type-safe render function signature
|
|
117
|
+
*/
|
|
118
|
+
export type RenderFunction = <T extends ViewName>(
|
|
119
|
+
view: T,
|
|
120
|
+
data: Views[T],
|
|
121
|
+
) => Promise<string>;
|
|
122
122
|
`;
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
@@ -28,12 +28,18 @@ export class ViewDebugger {
|
|
|
28
28
|
app.get("/__views", (req, res) => {
|
|
29
29
|
this.handleViewsEndpoint(req, res);
|
|
30
30
|
});
|
|
31
|
-
// Preview a view
|
|
32
|
-
|
|
31
|
+
// Preview a view. The view name can contain slashes (e.g.
|
|
32
|
+
// `users/profile`), so we use a named splat (`*view`) — the
|
|
33
|
+
// path-to-regexp v6 form `:view(*)` shipped by Express 4 is not
|
|
34
|
+
// valid in path-to-regexp v8 (Express 5) and now throws
|
|
35
|
+
// `Missing parameter name`. Path-to-regexp v8 captures the splat
|
|
36
|
+
// segments as `req.params.view: string[]`; the helpers below
|
|
37
|
+
// normalise that to a slash-joined string for backward compat.
|
|
38
|
+
app.get("/__views/preview/*view", (req, res) => {
|
|
33
39
|
this.handlePreviewEndpoint(req, res);
|
|
34
40
|
});
|
|
35
|
-
// Get view info
|
|
36
|
-
app.get("/__views/info
|
|
41
|
+
// Get view info — same shape as preview.
|
|
42
|
+
app.get("/__views/info/*view", (req, res) => {
|
|
37
43
|
this.handleInfoEndpoint(req, res);
|
|
38
44
|
});
|
|
39
45
|
// Get metrics
|
|
@@ -72,7 +78,7 @@ export class ViewDebugger {
|
|
|
72
78
|
*/
|
|
73
79
|
async handlePreviewEndpoint(req, res) {
|
|
74
80
|
try {
|
|
75
|
-
const view = req.params.view;
|
|
81
|
+
const view = this.resolveViewParam(req.params.view);
|
|
76
82
|
const data = req.query.data ? JSON.parse(req.query.data) : {};
|
|
77
83
|
const html = await this.renderService.render(view, data);
|
|
78
84
|
res.setHeader("Content-Type", "text/html");
|
|
@@ -81,16 +87,30 @@ export class ViewDebugger {
|
|
|
81
87
|
catch (error) {
|
|
82
88
|
res.status(500).json({
|
|
83
89
|
error: error.message,
|
|
84
|
-
view: req.params.view,
|
|
90
|
+
view: this.resolveViewParam(req.params.view),
|
|
85
91
|
});
|
|
86
92
|
}
|
|
87
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Normalise the `view` route param across Express 4 and 5.
|
|
96
|
+
*
|
|
97
|
+
* Express 4 / path-to-regexp v6 captured `/__views/preview/:view(*)`
|
|
98
|
+
* as a single string. Express 5 / path-to-regexp v8 changed the
|
|
99
|
+
* named-splat capture to `string[]` (one entry per slash-separated
|
|
100
|
+
* segment). The view engine needs the slash-joined form, so we always
|
|
101
|
+
* collapse the array shape back to that.
|
|
102
|
+
*/
|
|
103
|
+
resolveViewParam(value) {
|
|
104
|
+
if (Array.isArray(value))
|
|
105
|
+
return value.join("/");
|
|
106
|
+
return typeof value === "string" ? value : "";
|
|
107
|
+
}
|
|
88
108
|
/**
|
|
89
109
|
* Handle the view info endpoint.
|
|
90
110
|
*/
|
|
91
111
|
handleInfoEndpoint(req, res) {
|
|
92
112
|
try {
|
|
93
|
-
const view = req.params.view;
|
|
113
|
+
const view = this.resolveViewParam(req.params.view);
|
|
94
114
|
const viewFiles = this.renderService.getViewFiles();
|
|
95
115
|
// Find matching view
|
|
96
116
|
const matchingFiles = viewFiles.filter((file) => file.includes(view));
|
|
@@ -119,54 +139,54 @@ export class ViewDebugger {
|
|
|
119
139
|
* Wrap preview HTML with debug info.
|
|
120
140
|
*/
|
|
121
141
|
wrapPreview(view, html) {
|
|
122
|
-
return `<!DOCTYPE html>
|
|
123
|
-
<html>
|
|
124
|
-
<head>
|
|
125
|
-
<title>View Preview: ${view}</title>
|
|
126
|
-
<style>
|
|
127
|
-
.debug-bar {
|
|
128
|
-
position: fixed;
|
|
129
|
-
top: 0;
|
|
130
|
-
left: 0;
|
|
131
|
-
right: 0;
|
|
132
|
-
background: #1a1a2e;
|
|
133
|
-
color: #eee;
|
|
134
|
-
padding: 8px 16px;
|
|
135
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
136
|
-
font-size: 13px;
|
|
137
|
-
z-index: 99999;
|
|
138
|
-
display: flex;
|
|
139
|
-
align-items: center;
|
|
140
|
-
gap: 16px;
|
|
141
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
142
|
-
}
|
|
143
|
-
.debug-bar strong {
|
|
144
|
-
color: #00d9ff;
|
|
145
|
-
}
|
|
146
|
-
.debug-bar a {
|
|
147
|
-
color: #ff6b6b;
|
|
148
|
-
text-decoration: none;
|
|
149
|
-
}
|
|
150
|
-
.debug-bar a:hover {
|
|
151
|
-
text-decoration: underline;
|
|
152
|
-
}
|
|
153
|
-
.content-wrapper {
|
|
154
|
-
padding-top: 50px;
|
|
155
|
-
}
|
|
156
|
-
</style>
|
|
157
|
-
</head>
|
|
158
|
-
<body>
|
|
159
|
-
<div class="debug-bar">
|
|
160
|
-
<span>📁 <strong>${view}</strong></span>
|
|
161
|
-
<span>|</span>
|
|
162
|
-
<span>Engine: <strong>${this.renderService.getActiveEngine().name}</strong></span>
|
|
163
|
-
<span>|</span>
|
|
164
|
-
<a href="/__views">← Back to Views</a>
|
|
165
|
-
</div>
|
|
166
|
-
<div class="content-wrapper">
|
|
167
|
-
${html}
|
|
168
|
-
</div>
|
|
169
|
-
</body>
|
|
142
|
+
return `<!DOCTYPE html>
|
|
143
|
+
<html>
|
|
144
|
+
<head>
|
|
145
|
+
<title>View Preview: ${view}</title>
|
|
146
|
+
<style>
|
|
147
|
+
.debug-bar {
|
|
148
|
+
position: fixed;
|
|
149
|
+
top: 0;
|
|
150
|
+
left: 0;
|
|
151
|
+
right: 0;
|
|
152
|
+
background: #1a1a2e;
|
|
153
|
+
color: #eee;
|
|
154
|
+
padding: 8px 16px;
|
|
155
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
156
|
+
font-size: 13px;
|
|
157
|
+
z-index: 99999;
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 16px;
|
|
161
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
162
|
+
}
|
|
163
|
+
.debug-bar strong {
|
|
164
|
+
color: #00d9ff;
|
|
165
|
+
}
|
|
166
|
+
.debug-bar a {
|
|
167
|
+
color: #ff6b6b;
|
|
168
|
+
text-decoration: none;
|
|
169
|
+
}
|
|
170
|
+
.debug-bar a:hover {
|
|
171
|
+
text-decoration: underline;
|
|
172
|
+
}
|
|
173
|
+
.content-wrapper {
|
|
174
|
+
padding-top: 50px;
|
|
175
|
+
}
|
|
176
|
+
</style>
|
|
177
|
+
</head>
|
|
178
|
+
<body>
|
|
179
|
+
<div class="debug-bar">
|
|
180
|
+
<span>📁 <strong>${view}</strong></span>
|
|
181
|
+
<span>|</span>
|
|
182
|
+
<span>Engine: <strong>${this.renderService.getActiveEngine().name}</strong></span>
|
|
183
|
+
<span>|</span>
|
|
184
|
+
<a href="/__views">← Back to Views</a>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="content-wrapper">
|
|
187
|
+
${html}
|
|
188
|
+
</div>
|
|
189
|
+
</body>
|
|
170
190
|
</html>`;
|
|
171
191
|
}
|
|
172
192
|
}
|
|
@@ -231,7 +231,13 @@ class FluentRequestImpl {
|
|
|
231
231
|
}
|
|
232
232
|
/**
|
|
233
233
|
* Execute the request and return the response.
|
|
234
|
+
*
|
|
235
|
+
* The generic defaults to `any` (see {@link FluentResponse} for the
|
|
236
|
+
* rationale) so test code can read `response.body.foo` directly. Pass
|
|
237
|
+
* an explicit type — `.execute<UserDto>()` — to opt into strict
|
|
238
|
+
* typing.
|
|
234
239
|
*/
|
|
240
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
235
241
|
async execute() {
|
|
236
242
|
const startTime = Date.now();
|
|
237
243
|
// Build URL with query parameters
|
|
@@ -315,6 +321,7 @@ class FluentRequestImpl {
|
|
|
315
321
|
/**
|
|
316
322
|
* Alias for execute().
|
|
317
323
|
*/
|
|
324
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
318
325
|
end() {
|
|
319
326
|
return this.execute();
|
|
320
327
|
}
|
|
@@ -98,9 +98,11 @@ class SnapshotRequestImpl {
|
|
|
98
98
|
this.fluentRequest.expect(assertion);
|
|
99
99
|
return this;
|
|
100
100
|
}
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
102
|
execute() {
|
|
102
103
|
return this.fluentRequest.execute();
|
|
103
104
|
}
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
106
|
end() {
|
|
105
107
|
return this.fluentRequest.end();
|
|
106
108
|
}
|
|
@@ -112,6 +112,12 @@ export declare class AppFactory {
|
|
|
112
112
|
*
|
|
113
113
|
* @throws {Error} If webServerType is not a valid constructor
|
|
114
114
|
*
|
|
115
|
+
* @deprecated Use `bootstrap()` from `@expressots/core` instead. `bootstrap()`
|
|
116
|
+
* additionally handles environment file loading, port configuration,
|
|
117
|
+
* graceful shutdown, the startup banner, and configuration validation.
|
|
118
|
+
* `AppFactory.create()` will keep working for advanced use cases but is
|
|
119
|
+
* scheduled for removal in a future major release.
|
|
120
|
+
*
|
|
115
121
|
* @public API
|
|
116
122
|
*/
|
|
117
123
|
static create<T extends IWebServer>(webServerType: IWebServerConstructor<T>): Promise<IWebServerBuilder>;
|
|
@@ -216,52 +216,147 @@ export interface EnvironmentFileConfig {
|
|
|
216
216
|
skipFileLoading?: boolean;
|
|
217
217
|
}
|
|
218
218
|
/**
|
|
219
|
-
* Options for loadEnvSync
|
|
220
|
-
*
|
|
219
|
+
* Options for {@link loadEnvSync}.
|
|
220
|
+
*
|
|
221
|
+
* `loadEnvSync()` is the recommended way to populate `process.env` before
|
|
222
|
+
* `bootstrap()` runs. Call it at the top of `src/main.ts` (or your config
|
|
223
|
+
* module) so every subsequent `Env.*` builder, `defineConfig()` call, and
|
|
224
|
+
* DI binding can read the loaded values.
|
|
225
|
+
*
|
|
226
|
+
* ### File-loading order (last wins)
|
|
227
|
+
*
|
|
228
|
+
* | Step | File | Purpose |
|
|
229
|
+
* |------|------|---------|
|
|
230
|
+
* | 1 | `.env` | Shared defaults (committed) |
|
|
231
|
+
* | 2 | `.env.local` | Local-only overrides (gitignored) |
|
|
232
|
+
* | 3 | `.env.{env}.local` | Per-environment local override |
|
|
233
|
+
* | 4 | `.env.{env}` | Per-environment values (highest priority) |
|
|
234
|
+
*
|
|
235
|
+
* `{env}` is resolved from `process.env.NODE_ENV` (defaults to `"development"`).
|
|
236
|
+
* If a `files` mapping is provided, the mapped filename replaces `.env.{env}`.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* // 1. Zero-config (loads .env + .env.development by convention)
|
|
241
|
+
* loadEnvSync();
|
|
242
|
+
*
|
|
243
|
+
* // 2. Custom file names per environment
|
|
244
|
+
* loadEnvSync({
|
|
245
|
+
* files: {
|
|
246
|
+
* development: ".env",
|
|
247
|
+
* production: ".env.prod",
|
|
248
|
+
* staging: ".env.staging",
|
|
249
|
+
* },
|
|
250
|
+
* });
|
|
251
|
+
*
|
|
252
|
+
* // 3. Force reload after hot-module replacement
|
|
253
|
+
* loadEnvSync({ force: true });
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* @see {@link loadEnvSync} for the function itself
|
|
257
|
+
* @see {@link BootstrapOptions.envFileConfig} for the bootstrap()-level alternative
|
|
258
|
+
* @public
|
|
221
259
|
*/
|
|
222
260
|
export interface LoadEnvSyncOptions {
|
|
223
261
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
262
|
+
* Map environment names to custom `.env` file paths.
|
|
263
|
+
*
|
|
264
|
+
* Only the entry matching the **current** `NODE_ENV` is used at runtime.
|
|
265
|
+
* Unmapped environments fall back to the convention `.env.{NODE_ENV}`.
|
|
266
|
+
*
|
|
267
|
+
* @default undefined (convention: `.env.{NODE_ENV}`)
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* files: {
|
|
272
|
+
* development: ".env", // NODE_ENV=development -> loads .env
|
|
273
|
+
* production: ".env.prod", // NODE_ENV=production -> loads .env.prod
|
|
274
|
+
* test: ".env.test", // NODE_ENV=test -> loads .env.test
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
226
277
|
*/
|
|
227
278
|
files?: EnvironmentFileMap;
|
|
228
279
|
/**
|
|
229
|
-
*
|
|
230
|
-
*
|
|
280
|
+
* Reload environment files even if they were already loaded in this process.
|
|
281
|
+
*
|
|
282
|
+
* By default `loadEnvSync()` is a no-op after the first successful call
|
|
283
|
+
* (tracked via `process.env._EXPRESSOTS_ENV_LOADED`). Set `force: true`
|
|
284
|
+
* to re-read all files, useful after a hot-module replacement cycle.
|
|
285
|
+
*
|
|
231
286
|
* @default false
|
|
232
287
|
*/
|
|
233
288
|
force?: boolean;
|
|
234
289
|
}
|
|
235
290
|
/**
|
|
236
|
-
* Synchronously load
|
|
291
|
+
* Synchronously load `.env` files into `process.env`.
|
|
237
292
|
*
|
|
238
|
-
* Call this
|
|
239
|
-
*
|
|
293
|
+
* Call this **before** `bootstrap()` or `defineConfig()` so that every
|
|
294
|
+
* environment variable is available when the rest of the application
|
|
295
|
+
* resolves configuration, binds services, or reads `Env.*` builders.
|
|
240
296
|
*
|
|
241
|
-
*
|
|
297
|
+
* ### How it works
|
|
242
298
|
*
|
|
243
|
-
*
|
|
299
|
+
* 1. Reads `process.env.NODE_ENV` (defaults to `"development"`).
|
|
300
|
+
* 2. Loads files in priority order (last file wins on conflicts):
|
|
301
|
+
* `.env` → `.env.local` → `.env.{env}.local` → `.env.{env}`
|
|
302
|
+
* 3. If `options.files` maps the current environment to a custom name
|
|
303
|
+
* (e.g. `{ production: ".env.prod" }`), that name replaces `.env.{env}`.
|
|
304
|
+
* 4. Missing files are silently skipped.
|
|
305
|
+
* 5. Sets `process.env._EXPRESSOTS_ENV_LOADED = "true"` so subsequent
|
|
306
|
+
* calls are no-ops (unless `force: true`).
|
|
307
|
+
*
|
|
308
|
+
* ### Important
|
|
309
|
+
*
|
|
310
|
+
* `NODE_ENV` must already be set in the **shell** (or inherited from
|
|
311
|
+
* the process) before `loadEnvSync()` runs. The function reads
|
|
312
|
+
* `process.env.NODE_ENV` to decide which file to load; it does **not**
|
|
313
|
+
* derive the environment from file contents.
|
|
314
|
+
*
|
|
315
|
+
* @param options - See {@link LoadEnvSyncOptions} for all fields.
|
|
316
|
+
*
|
|
317
|
+
* @example Zero-config (recommended for most apps)
|
|
244
318
|
* ```typescript
|
|
245
|
-
* //
|
|
246
|
-
* import {
|
|
319
|
+
* // src/main.ts
|
|
320
|
+
* import { bootstrap, loadEnvSync } from "@expressots/core";
|
|
321
|
+
* import { App } from "./app";
|
|
322
|
+
*
|
|
323
|
+
* loadEnvSync(); // .env + .env.development (or .env.production, etc.)
|
|
324
|
+
* void bootstrap(App);
|
|
325
|
+
* ```
|
|
247
326
|
*
|
|
248
|
-
*
|
|
327
|
+
* @example Custom file mapping
|
|
328
|
+
* ```typescript
|
|
249
329
|
* loadEnvSync({
|
|
250
330
|
* files: {
|
|
251
|
-
* development: ".env
|
|
252
|
-
* production:
|
|
331
|
+
* development: ".env",
|
|
332
|
+
* production: ".env.prod",
|
|
333
|
+
* staging: ".env.staging",
|
|
253
334
|
* },
|
|
254
335
|
* });
|
|
336
|
+
* // With NODE_ENV=production -> .env + .env.prod
|
|
337
|
+
* // With NODE_ENV=development -> .env (mapped to itself, so loaded once)
|
|
338
|
+
* ```
|
|
339
|
+
*
|
|
340
|
+
* @example With defineConfig()
|
|
341
|
+
* ```typescript
|
|
342
|
+
* // src/config.ts
|
|
343
|
+
* import { defineConfig, Env, loadEnvSync } from "@expressots/core";
|
|
344
|
+
*
|
|
345
|
+
* loadEnvSync({ files: { production: ".env.prod" } });
|
|
255
346
|
*
|
|
256
|
-
* // Now defineConfig() will read from loaded .env files
|
|
257
347
|
* export const appConfig = defineConfig({
|
|
258
|
-
* server: {
|
|
259
|
-
* port: Env.port("PORT", { default: 3000 }),
|
|
260
|
-
* },
|
|
348
|
+
* server: { port: Env.port("PORT", { default: 3000 }) },
|
|
261
349
|
* });
|
|
262
350
|
* ```
|
|
263
351
|
*
|
|
264
|
-
* @
|
|
352
|
+
* @example Force reload (hot-module replacement)
|
|
353
|
+
* ```typescript
|
|
354
|
+
* loadEnvSync({ force: true });
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* @see {@link LoadEnvSyncOptions} for option details
|
|
358
|
+
* @see {@link BootstrapOptions.envFileConfig} for the bootstrap()-level alternative
|
|
359
|
+
* @public
|
|
265
360
|
*/
|
|
266
361
|
export declare function loadEnvSync(options?: LoadEnvSyncOptions): void;
|
|
267
362
|
/**
|
|
@@ -471,14 +566,91 @@ export interface BootstrapOptions {
|
|
|
471
566
|
envFileConfig?: EnvironmentFileConfig;
|
|
472
567
|
}
|
|
473
568
|
/**
|
|
474
|
-
*
|
|
569
|
+
* Start the application with explicit options.
|
|
570
|
+
*
|
|
571
|
+
* Use this overload when you need to control the port, app metadata,
|
|
572
|
+
* environment selection, or `.env` file loading/validation.
|
|
573
|
+
*
|
|
574
|
+
* @param AppClass - Your class that extends `AppExpress`.
|
|
575
|
+
* @param options - See {@link BootstrapOptions} for every field.
|
|
576
|
+
* @returns The running server instance.
|
|
577
|
+
*
|
|
578
|
+
* @example Port + environment + validation
|
|
579
|
+
* ```typescript
|
|
580
|
+
* await bootstrap(App, {
|
|
581
|
+
* port: 4000,
|
|
582
|
+
* appName: "My API",
|
|
583
|
+
* currentEnvironment: "production",
|
|
584
|
+
* envFileConfig: {
|
|
585
|
+
* files: { production: ".env.prod" },
|
|
586
|
+
* required: ["DATABASE_URL", "JWT_SECRET"],
|
|
587
|
+
* validateValues: true,
|
|
588
|
+
* },
|
|
589
|
+
* });
|
|
590
|
+
* ```
|
|
591
|
+
*
|
|
592
|
+
* @example Dynamic port for testing
|
|
593
|
+
* ```typescript
|
|
594
|
+
* const server = await bootstrap(App, { port: 0 });
|
|
595
|
+
* const port = await server.getPort();
|
|
596
|
+
* ```
|
|
597
|
+
*
|
|
598
|
+
* @example Container / CI (no file I/O)
|
|
599
|
+
* ```typescript
|
|
600
|
+
* await bootstrap(App, {
|
|
601
|
+
* envFileConfig: {
|
|
602
|
+
* skipFileLoading: true,
|
|
603
|
+
* required: ["DATABASE_URL"],
|
|
604
|
+
* },
|
|
605
|
+
* });
|
|
606
|
+
* ```
|
|
607
|
+
*
|
|
608
|
+
* @public
|
|
475
609
|
*/
|
|
476
610
|
export declare function bootstrap(AppClass: new () => IWebServer, options: BootstrapOptions): Promise<IWebServerPublic>;
|
|
477
611
|
/**
|
|
478
|
-
*
|
|
612
|
+
* Start the application with a type-safe config object from `defineConfig()`.
|
|
613
|
+
*
|
|
614
|
+
* Pass the resolved config directly; `bootstrap()` extracts `app`, `server`,
|
|
615
|
+
* and `bootstrap.envFileConfig` automatically.
|
|
616
|
+
*
|
|
617
|
+
* @param AppClass - Your class that extends `AppExpress`.
|
|
618
|
+
* @param config - Object returned by `defineConfig().values` (or matching
|
|
619
|
+
* the {@link BootstrapConfig} shape).
|
|
620
|
+
* @returns The running server instance.
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* ```typescript
|
|
624
|
+
* import { appConfig } from "./config";
|
|
625
|
+
*
|
|
626
|
+
* await bootstrap(App, appConfig.values);
|
|
627
|
+
* // appConfig.values has { app, server, bootstrap } from defineConfig()
|
|
628
|
+
* ```
|
|
629
|
+
*
|
|
630
|
+
* @public
|
|
479
631
|
*/
|
|
480
632
|
export declare function bootstrap(AppClass: new () => IWebServer, config: BootstrapConfig): Promise<IWebServerPublic>;
|
|
481
633
|
/**
|
|
482
|
-
*
|
|
634
|
+
* Start the application with zero configuration.
|
|
635
|
+
*
|
|
636
|
+
* - Listens on `process.env.PORT` or **3000**.
|
|
637
|
+
* - Reads `appName` and `appVersion` from `package.json`.
|
|
638
|
+
* - Does **not** load any `.env` files (opt-in via {@link BootstrapOptions.envFileConfig}
|
|
639
|
+
* or by calling {@link loadEnvSync} before this).
|
|
640
|
+
* - Sets up graceful shutdown on `SIGINT` / `SIGTERM`.
|
|
641
|
+
*
|
|
642
|
+
* @param AppClass - Your class that extends `AppExpress`.
|
|
643
|
+
* @returns The running server instance.
|
|
644
|
+
*
|
|
645
|
+
* @example
|
|
646
|
+
* ```typescript
|
|
647
|
+
* import { bootstrap, loadEnvSync } from "@expressots/core";
|
|
648
|
+
* import { App } from "./app";
|
|
649
|
+
*
|
|
650
|
+
* loadEnvSync(); // optional: load .env files first
|
|
651
|
+
* await bootstrap(App); // starts on PORT from .env or 3000
|
|
652
|
+
* ```
|
|
653
|
+
*
|
|
654
|
+
* @public
|
|
483
655
|
*/
|
|
484
656
|
export declare function bootstrap(AppClass: new () => IWebServer): Promise<IWebServerPublic>;
|
|
@@ -409,7 +409,13 @@ export interface DefineConfigOptions {
|
|
|
409
409
|
throwOnError?: boolean;
|
|
410
410
|
/**
|
|
411
411
|
* Log validation results.
|
|
412
|
-
*
|
|
412
|
+
*
|
|
413
|
+
* - `"warn"` (default): only warnings and errors are printed.
|
|
414
|
+
* - `"info"` / `"debug"`: prints the "CONFIGURATION LOADED" success banner
|
|
415
|
+
* plus warnings and errors.
|
|
416
|
+
* - `"error"`: only errors.
|
|
417
|
+
* - `"none"`: completely silent.
|
|
418
|
+
* @default "warn"
|
|
413
419
|
*/
|
|
414
420
|
logLevel?: ConfigLogLevel;
|
|
415
421
|
/**
|
|
@@ -274,6 +274,42 @@ declare function array<T extends string | number>(envVar: string, options?: Arra
|
|
|
274
274
|
*
|
|
275
275
|
* @public API
|
|
276
276
|
*/
|
|
277
|
+
/**
|
|
278
|
+
* Returns true when the current Node environment (`NODE_ENV`) matches the
|
|
279
|
+
* supplied name. Pass an array to match any of several names. The comparison
|
|
280
|
+
* is case-insensitive and falls back to `"development"` when `NODE_ENV` is
|
|
281
|
+
* unset, mirroring the convention used elsewhere in the framework.
|
|
282
|
+
*
|
|
283
|
+
* ```ts
|
|
284
|
+
* const config = defineConfig({
|
|
285
|
+
* server: { port: when(Env.is("production"), 443, 3000) },
|
|
286
|
+
* });
|
|
287
|
+
* ```
|
|
288
|
+
*
|
|
289
|
+
* @public API
|
|
290
|
+
*/
|
|
291
|
+
declare function isEnvironment(name: string | Array<string>): boolean;
|
|
292
|
+
/**
|
|
293
|
+
* Conditional helper for environment-specific config values.
|
|
294
|
+
*
|
|
295
|
+
* `when(condition, value, fallback)` returns `value` when `condition` is
|
|
296
|
+
* truthy, otherwise `fallback`. The condition can be either a boolean
|
|
297
|
+
* (typically the result of `Env.is(...)`) or a callable that's evaluated
|
|
298
|
+
* lazily. The latter form lets you defer side-effectful checks until the
|
|
299
|
+
* config is actually resolved.
|
|
300
|
+
*
|
|
301
|
+
* ```ts
|
|
302
|
+
* const config = defineConfig({
|
|
303
|
+
* logging: {
|
|
304
|
+
* level: when(Env.is("production"), "info", "debug"),
|
|
305
|
+
* pretty: when(() => process.env.NO_COLOR !== "1", true, false),
|
|
306
|
+
* },
|
|
307
|
+
* });
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* @public API
|
|
311
|
+
*/
|
|
312
|
+
declare function envWhen<TValue, TFallback>(condition: boolean | (() => boolean), value: TValue, fallback: TFallback): TValue | TFallback;
|
|
277
313
|
export declare const Env: {
|
|
278
314
|
readonly string: typeof string;
|
|
279
315
|
readonly number: typeof number;
|
|
@@ -284,5 +320,8 @@ export declare const Env: {
|
|
|
284
320
|
readonly secret: typeof secret;
|
|
285
321
|
readonly json: typeof json;
|
|
286
322
|
readonly array: typeof array;
|
|
323
|
+
readonly is: typeof isEnvironment;
|
|
324
|
+
readonly when: typeof envWhen;
|
|
287
325
|
};
|
|
326
|
+
export { isEnvironment as envIs, envWhen };
|
|
288
327
|
export { string as envString, number as envNumber, boolean as envBoolean, enumField as envEnum, url as envUrl, port as envPort, secret as envSecret, json as envJson, array as envArray, };
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
* ```
|
|
57
57
|
*/
|
|
58
58
|
export { defineConfig, Env } from "./define-config.js";
|
|
59
|
-
export { envString, envNumber, envBoolean, envEnum, envUrl, envPort, envSecret, envJson, envArray, } from "./env-field-builders.js";
|
|
59
|
+
export { envString, envNumber, envBoolean, envEnum, envUrl, envPort, envSecret, envJson, envArray, envIs, envWhen, } from "./env-field-builders.js";
|
|
60
60
|
export type { ConfigValueType, ConfigEnvironment, ConfigLogLevel, BaseFieldOptions, StringFieldOptions, NumberFieldOptions, BooleanFieldOptions, EnumFieldOptions, UrlFieldOptions, PortFieldOptions, SecretFieldOptions, JsonFieldOptions, ArrayFieldOptions, ConfigField, ConfigValidationError, ConfigValidationResult, ConfigSchemaValue, ConfigSchema, DefineConfigOptions, ConfigChangeEvent, SecretValue, ResolvedConfig, IConfigInstance, } from "./config.interfaces.js";
|
|
61
61
|
export { createSecretValue, isSecretValue } from "./secret-value.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework version string surfaced in startup banners and diagnostics.
|
|
3
|
+
*
|
|
4
|
+
* This file is auto-synced from the root `package.json` by
|
|
5
|
+
* `scripts/sync-version.js` before each build. Do not edit by hand.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FRAMEWORK_VERSION = "4.0.0-preview.3";
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
*/
|
|
37
37
|
export type { PreloadHint, ModuleLoadStatus, LazyModuleConfig, LazyModuleFactory, ILazyModule, ILazyModuleLoader, ModuleLoadStatistics, ILazyModuleManager, ModuleRecommendation, ApplyRecommendationsOptions, ILazyLoadMetrics, WarmupStrategy, WarmupConfig, ILazyModuleWarmup, LoadingPhase, ProgressiveLoadingConfig, LazyLoadingOptions, LazyLoadingSetupResult, } from "./lazy.interfaces.js";
|
|
38
38
|
export { LazyModule, CreateLazyModule, createLazyModule, isLazyModule, getModuleName, LAZY_MODULE_METADATA_KEY, } from "./lazy-module.js";
|
|
39
|
+
export { withPreloadHint, withLazyConfig } from "./lazy-module-helpers.js";
|
|
39
40
|
export { LazyModuleLoader, createLazyModuleLoader, } from "./lazy-module-loader.js";
|
|
40
41
|
export { LazyModuleManager, createLazyModuleManager, } from "./lazy-module-manager.js";
|
|
41
42
|
export { LazyLoadMetrics, createLazyLoadMetrics } from "./lazy-load-metrics.js";
|