@expressots/adapter-express 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 +61 -61
- package/lib/CHANGELOG.md +10 -5
- package/lib/README.md +61 -61
- package/lib/cjs/adapter-express/application-express.js +401 -45
- package/lib/cjs/adapter-express/express-utils/decorators.js +44 -15
- package/lib/cjs/adapter-express/express-utils/inversify-express-server.js +20 -4
- package/lib/cjs/adapter-express/express-utils/path-pattern-compat.js +129 -0
- package/lib/cjs/adapter-express/express-utils/route-constraints.js +12 -3
- package/lib/cjs/adapter-express/micro-api/application-express-micro.js +5 -9
- package/lib/cjs/adapter-express/micro-api/micro.js +96 -41
- package/lib/cjs/adapter-express/studio/index.js +2 -1
- package/lib/cjs/adapter-express/studio/studio-integration.js +64 -11
- package/lib/cjs/types/adapter-express/application-express.d.ts +51 -9
- package/lib/cjs/types/adapter-express/express-utils/path-pattern-compat.d.ts +66 -0
- package/lib/cjs/types/adapter-express/express-utils/route-constraints.d.ts +12 -3
- package/lib/cjs/types/adapter-express/micro-api/micro.d.ts +19 -2
- package/lib/cjs/types/adapter-express/studio/index.d.ts +1 -1
- package/lib/cjs/types/adapter-express/studio/studio-integration.d.ts +78 -0
- package/lib/esm/adapter-express/application-express.js +402 -46
- package/lib/esm/adapter-express/express-utils/decorators.js +44 -15
- package/lib/esm/adapter-express/express-utils/inversify-express-server.js +20 -4
- package/lib/esm/adapter-express/express-utils/path-pattern-compat.js +125 -0
- package/lib/esm/adapter-express/express-utils/route-constraints.js +12 -3
- package/lib/esm/adapter-express/micro-api/application-express-micro.js +6 -10
- package/lib/esm/adapter-express/micro-api/micro.js +97 -42
- package/lib/esm/adapter-express/studio/index.js +1 -1
- package/lib/esm/adapter-express/studio/studio-integration.js +63 -11
- package/lib/esm/types/adapter-express/application-express.d.ts +51 -9
- package/lib/esm/types/adapter-express/express-utils/path-pattern-compat.d.ts +66 -0
- package/lib/esm/types/adapter-express/express-utils/route-constraints.d.ts +12 -3
- package/lib/esm/types/adapter-express/micro-api/micro.d.ts +19 -2
- package/lib/esm/types/adapter-express/studio/index.d.ts +1 -1
- package/lib/esm/types/adapter-express/studio/studio-integration.d.ts +78 -0
- package/lib/package.json +24 -10
- package/package.json +25 -11
|
@@ -32,27 +32,56 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
33
|
exports.initializeStudio = initializeStudio;
|
|
34
34
|
exports.reportStudioRuntimeInfo = reportStudioRuntimeInfo;
|
|
35
|
+
exports.rescanStudioRoutes = rescanStudioRoutes;
|
|
35
36
|
exports.stopStudio = stopStudio;
|
|
36
37
|
exports.isStudioEnabled = isStudioEnabled;
|
|
37
38
|
exports.getStudioAgent = getStudioAgent;
|
|
39
|
+
const core_1 = require("@expressots/core");
|
|
40
|
+
// Lazy logger accessor so `new Logger()` only fires the first time we
|
|
41
|
+
// actually emit a Studio message. Routing through Logger means the
|
|
42
|
+
// framework's log-level configuration (e.g. `LOG_LEVEL=WARN`) silences
|
|
43
|
+
// the "listening" line as expected, instead of `console.log` always
|
|
44
|
+
// printing it. Lazy construction also keeps consumers that mock
|
|
45
|
+
// `@expressots/core` (test environments) from blowing up at module
|
|
46
|
+
// load when their Logger mock omits `.withContext`.
|
|
47
|
+
let _studioLogger = null;
|
|
48
|
+
function logger() {
|
|
49
|
+
if (!_studioLogger) {
|
|
50
|
+
_studioLogger = new core_1.Logger().withContext("studio");
|
|
51
|
+
}
|
|
52
|
+
return _studioLogger;
|
|
53
|
+
}
|
|
38
54
|
let studioAgent = null;
|
|
39
55
|
let studioEnabled = false;
|
|
40
56
|
/**
|
|
41
|
-
* Check if
|
|
57
|
+
* Check if `@expressots/studio-agent` is installed and importable from the
|
|
58
|
+
* current process. Uses a dynamic `import()` rather than `require.resolve`
|
|
59
|
+
* because the latter is unavailable in pure-ESM consumers — adapter-express
|
|
60
|
+
* is published as a dual CJS/ESM build and this helper is exercised by both
|
|
61
|
+
* targets.
|
|
62
|
+
*
|
|
63
|
+
* The result is cached on first hit (success) so we avoid paying for the
|
|
64
|
+
* import twice. On failure we always retry, since the user may install the
|
|
65
|
+
* package mid-session in `expressots dev` workflows.
|
|
42
66
|
*/
|
|
67
|
+
let _studioAgentModule = null;
|
|
43
68
|
async function isStudioAgentInstalled() {
|
|
44
69
|
const debug = process.env.EXPRESSOTS_STUDIO_DEBUG === "true";
|
|
70
|
+
if (_studioAgentModule !== null)
|
|
71
|
+
return true;
|
|
45
72
|
try {
|
|
46
|
-
//
|
|
47
|
-
|
|
73
|
+
// Dynamic import works for both CJS (returns module.exports) and ESM
|
|
74
|
+
// (returns the ESM namespace). If the package isn't installed, Node
|
|
75
|
+
// throws ERR_MODULE_NOT_FOUND / MODULE_NOT_FOUND, which we treat as
|
|
76
|
+
// "agent not present" — adapter-express continues without Studio.
|
|
77
|
+
_studioAgentModule = await Promise.resolve().then(() => __importStar(require("@expressots/studio-agent")));
|
|
48
78
|
if (debug)
|
|
49
|
-
console.log("[Studio]
|
|
79
|
+
console.log("[Studio] Loaded studio-agent successfully");
|
|
50
80
|
return true;
|
|
51
81
|
}
|
|
52
82
|
catch (error) {
|
|
53
83
|
if (debug)
|
|
54
|
-
console.log("[Studio] Cannot
|
|
55
|
-
// Module not installed
|
|
84
|
+
console.log("[Studio] Cannot load studio-agent:", error instanceof Error ? error.message : error);
|
|
56
85
|
return false;
|
|
57
86
|
}
|
|
58
87
|
}
|
|
@@ -108,9 +137,9 @@ async function initializeStudio(app, config = {}, appContainer) {
|
|
|
108
137
|
const studioAgentModuleAny = studioAgentModule;
|
|
109
138
|
const StudioAgent = studioAgentModuleAny.StudioAgent || studioAgentModuleAny.default?.StudioAgent;
|
|
110
139
|
if (!StudioAgent) {
|
|
111
|
-
|
|
140
|
+
logger().warn("Studio Agent module found but StudioAgent class not exported");
|
|
112
141
|
if (debug)
|
|
113
|
-
|
|
142
|
+
logger().debug(`Module contents: ${Object.keys(studioAgentModule).join(", ")}`);
|
|
114
143
|
return false;
|
|
115
144
|
}
|
|
116
145
|
if (debug)
|
|
@@ -133,7 +162,7 @@ async function initializeStudio(app, config = {}, appContainer) {
|
|
|
133
162
|
// Start the agent (this also scans routes)
|
|
134
163
|
await studioAgent.start();
|
|
135
164
|
studioEnabled = true;
|
|
136
|
-
|
|
165
|
+
logger().info(`Studio Agent listening on ws://localhost:${agentOptions.port}`);
|
|
137
166
|
return true;
|
|
138
167
|
}
|
|
139
168
|
catch (error) {
|
|
@@ -161,12 +190,12 @@ async function initializeStudio(app, config = {}, appContainer) {
|
|
|
161
190
|
// Friendlier message for the most common failure mode: hot-reload
|
|
162
191
|
// race left the port in TIME_WAIT.
|
|
163
192
|
if (errorCode === "EADDRINUSE") {
|
|
164
|
-
|
|
193
|
+
logger().warn(`Studio Agent could not bind its WebSocket port ` +
|
|
165
194
|
`(${errorMessage}). The host app will continue without Studio. ` +
|
|
166
195
|
`If this happened during hot-reload, the next restart should recover.`);
|
|
167
196
|
return false;
|
|
168
197
|
}
|
|
169
|
-
|
|
198
|
+
logger().warn(`Failed to initialize Studio Agent: ${errorMessage}`);
|
|
170
199
|
return false;
|
|
171
200
|
}
|
|
172
201
|
}
|
|
@@ -190,6 +219,30 @@ function reportStudioRuntimeInfo(patch) {
|
|
|
190
219
|
// Best-effort — never break the host on a status-page update.
|
|
191
220
|
}
|
|
192
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Re-trigger the Studio Agent's route discovery. Used by the host
|
|
224
|
+
* after `app.listen()` so that the agent's runtime route scanner sees
|
|
225
|
+
* the fully-populated Express `_router` stack (controllers are bound
|
|
226
|
+
* by `InversifyExpressServer.build()` AFTER `initializeStudio()` runs,
|
|
227
|
+
* so the agent's first scan only catches static-source routes).
|
|
228
|
+
*
|
|
229
|
+
* No-ops when:
|
|
230
|
+
* - Studio isn't enabled, or
|
|
231
|
+
* - the installed agent is too old to expose `scanRoutes()`.
|
|
232
|
+
*/
|
|
233
|
+
async function rescanStudioRoutes() {
|
|
234
|
+
if (!studioAgent)
|
|
235
|
+
return;
|
|
236
|
+
if (typeof studioAgent.scanRoutes !== "function")
|
|
237
|
+
return;
|
|
238
|
+
try {
|
|
239
|
+
await studioAgent.scanRoutes();
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
// Best-effort — never break the host on a Studio rescan.
|
|
243
|
+
logger().warn(`Studio route rescan failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
193
246
|
/**
|
|
194
247
|
* Stop the Studio Agent
|
|
195
248
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Server as HTTPServer } from "http";
|
|
2
|
-
import { AppContainer, IConsoleMessage, IMiddleware, ProviderManager, BannerConfig } from "@expressots/core";
|
|
2
|
+
import { AppContainer, IConsoleMessage, IMiddleware, Logger, ProviderManager, BannerConfig } from "@expressots/core";
|
|
3
3
|
import { IWebServerPublic, RenderEngine, Server } from "@expressots/shared";
|
|
4
4
|
import { interfaces } from "@expressots/core";
|
|
5
5
|
/**
|
|
@@ -14,7 +14,7 @@ import { interfaces } from "@expressots/core";
|
|
|
14
14
|
* @method isDevelopment - Verifies if the current environment is development.
|
|
15
15
|
*/
|
|
16
16
|
export declare class AppExpress implements Server.IWebServer {
|
|
17
|
-
|
|
17
|
+
protected logger: Logger;
|
|
18
18
|
private console;
|
|
19
19
|
private app;
|
|
20
20
|
private serverInstance;
|
|
@@ -51,9 +51,7 @@ export declare class AppExpress implements Server.IWebServer {
|
|
|
51
51
|
private static originalStderrWrite;
|
|
52
52
|
private static logBuffer;
|
|
53
53
|
private static isBuffering;
|
|
54
|
-
private static bufferingInitialized;
|
|
55
54
|
private static originalGlobalConsole;
|
|
56
|
-
private static initBuffering;
|
|
57
55
|
/**
|
|
58
56
|
* Disable log buffering. Called by micro() to restore normal console output
|
|
59
57
|
* since micro API doesn't use the banner system.
|
|
@@ -61,11 +59,17 @@ export declare class AppExpress implements Server.IWebServer {
|
|
|
61
59
|
*/
|
|
62
60
|
static disableBuffering(): void;
|
|
63
61
|
/**
|
|
64
|
-
* Start buffering all console output.
|
|
65
|
-
*
|
|
66
|
-
*
|
|
62
|
+
* Start buffering all console output for the banner-first display flow.
|
|
63
|
+
* Captures both `console.*` and direct `process.stdout.write` / `process.stderr.write`
|
|
64
|
+
* calls so they can be flushed in the correct order after the banner displays.
|
|
65
|
+
*
|
|
66
|
+
* Idempotent: calling this multiple times is safe.
|
|
67
|
+
*
|
|
68
|
+
* @public API — called by `bootstrap()` so logs emitted during container
|
|
69
|
+
* setup are captured before the `AppExpress` instance exists. Also called
|
|
70
|
+
* automatically inside the constructor as a safety net.
|
|
67
71
|
*/
|
|
68
|
-
|
|
72
|
+
static startLogBuffering(): void;
|
|
69
73
|
/**
|
|
70
74
|
* Stop buffering but keep the buffered logs for later flushing.
|
|
71
75
|
* This restores normal console/stdout output.
|
|
@@ -390,9 +394,47 @@ export declare class AppExpress implements Server.IWebServer {
|
|
|
390
394
|
* harvested (keeps the WS payload small).
|
|
391
395
|
*/
|
|
392
396
|
private collectStudioRuntimeItems;
|
|
397
|
+
/**
|
|
398
|
+
* Harvest controller- and route-scoped middleware bindings from
|
|
399
|
+
* Reflect metadata. Each entry describes a single edge the Studio
|
|
400
|
+
* architecture map should draw, e.g. "AuthMiddleware → UserController
|
|
401
|
+
* (route POST /users/:id)".
|
|
402
|
+
*
|
|
403
|
+
* The middleware values stored on `ControllerMetadata.middleware` are
|
|
404
|
+
* a polymorphic union (class, function, registered name, conditional
|
|
405
|
+
* config, …). We normalise each to a display name; entries we can't
|
|
406
|
+
* name (anonymous arrow functions, plain object configs without a
|
|
407
|
+
* `name` field) are omitted. The agent's static scan picks up the
|
|
408
|
+
* remaining named cases via decorator parsing — between the two
|
|
409
|
+
* sources Studio sees a complete graph for the common patterns.
|
|
410
|
+
*/
|
|
411
|
+
private collectMiddlewareBindings;
|
|
412
|
+
/**
|
|
413
|
+
* Combine a controller's base path with a route path, normalising
|
|
414
|
+
* leading/trailing slashes. Mirrors the simpler logic Studio uses to
|
|
415
|
+
* build `RouteInfo.path` so the bindings line up with route entries.
|
|
416
|
+
*/
|
|
417
|
+
private joinRoutePath;
|
|
418
|
+
/**
|
|
419
|
+
* Collect the ordered middleware pipeline from the Middleware service
|
|
420
|
+
* for forwarding to Studio. Uses feature-detection so older core
|
|
421
|
+
* versions that lack `getPipelineInfo()` won't break.
|
|
422
|
+
*/
|
|
423
|
+
private collectMiddlewarePipelineItems;
|
|
424
|
+
/**
|
|
425
|
+
* Build the middleware preset info snapshot for Studio. Reads the
|
|
426
|
+
* last applied preset from the Middleware service and transforms it
|
|
427
|
+
* into the shape Studio expects.
|
|
428
|
+
*/
|
|
429
|
+
private collectMiddlewarePresetInfo;
|
|
393
430
|
/**
|
|
394
431
|
* Display middleware startup logs after the banner.
|
|
395
|
-
*
|
|
432
|
+
*
|
|
433
|
+
* Warnings (e.g. missing optional packages like `helmet`) are always surfaced
|
|
434
|
+
* so the developer can act on them. Informational entries (e.g. "Security
|
|
435
|
+
* configured", "Applied preset: api") are demoted to `debug` since the
|
|
436
|
+
* dashboard already shows the active middleware count; set `LOG_LEVEL=DEBUG`
|
|
437
|
+
* to see the full breakdown.
|
|
396
438
|
* @private
|
|
397
439
|
*/
|
|
398
440
|
private displayMiddlewareStartupLogs;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express 5 / path-to-regexp v8 compatibility for the `:name(regex)`
|
|
3
|
+
* inline-constraint syntax.
|
|
4
|
+
*
|
|
5
|
+
* `path-to-regexp` v8 (the parser Express 5 ships with) removed the
|
|
6
|
+
* inline regex form entirely — `/users/:id(\\d+)` now throws
|
|
7
|
+
*
|
|
8
|
+
* Unexpected ( at index 10: /users/:id(\\d+)
|
|
9
|
+
*
|
|
10
|
+
* That breaks two things we ship as public API:
|
|
11
|
+
*
|
|
12
|
+
* 1. The {@link Patterns} / {@link pattern} helpers in
|
|
13
|
+
* `route-constraints.ts`, which were introduced specifically to
|
|
14
|
+
* encourage that pattern.
|
|
15
|
+
* 2. Hand-written controller routes upgraded from v3, where users
|
|
16
|
+
* relied on Express 4 inline regex.
|
|
17
|
+
*
|
|
18
|
+
* Rather than break those at the surface of preview-3, we keep the
|
|
19
|
+
* authoring-time syntax and translate it at decorator time:
|
|
20
|
+
*
|
|
21
|
+
* - {@link splitPathConstraints} parses the path into a
|
|
22
|
+
* plain-`:name`-only form plus a list of `(name, regex)` pairs.
|
|
23
|
+
* - {@link createPathConstraintMiddleware} returns a middleware that
|
|
24
|
+
* runs at request time and 404s when any captured `req.params[name]`
|
|
25
|
+
* fails to match its constraint.
|
|
26
|
+
*
|
|
27
|
+
* The middleware emits an HTTP 404 (not 400) so the behaviour matches
|
|
28
|
+
* Express 4's "no route matched" semantics — under v6 of path-to-regexp,
|
|
29
|
+
* a non-matching `:id(\\d+)` simply meant the route wasn't selected and
|
|
30
|
+
* the request fell through to the framework's NotFound handler.
|
|
31
|
+
*/
|
|
32
|
+
import type { RequestHandler } from "express";
|
|
33
|
+
export interface PathConstraint {
|
|
34
|
+
/** The `:name` placeholder, without the leading colon. */
|
|
35
|
+
paramName: string;
|
|
36
|
+
/** Compiled regex. Anchored with `^...$` to match the whole segment. */
|
|
37
|
+
regex: RegExp;
|
|
38
|
+
/** The original raw regex text, for diagnostics. */
|
|
39
|
+
rawPattern: string;
|
|
40
|
+
}
|
|
41
|
+
export interface SplitPath {
|
|
42
|
+
/** Path string ready to hand to Express 5 / path-to-regexp v8. */
|
|
43
|
+
path: string;
|
|
44
|
+
/** Param-level regex constraints, in path declaration order. */
|
|
45
|
+
constraints: Array<PathConstraint>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Split `:name(regex)` segments out of an Express-style route path.
|
|
49
|
+
*
|
|
50
|
+
* The walker honours balanced parens inside the regex (e.g.
|
|
51
|
+
* `(\\d{4})` or `((a|b)+)`), which is more forgiving than a naive
|
|
52
|
+
* single-pass regex match would be. Returns the original path and an
|
|
53
|
+
* empty constraints list when no inline patterns are found, so this is
|
|
54
|
+
* a no-op for the common case.
|
|
55
|
+
*/
|
|
56
|
+
export declare function splitPathConstraints(path: string): SplitPath;
|
|
57
|
+
/**
|
|
58
|
+
* Build a middleware that enforces the given param-level regex
|
|
59
|
+
* constraints on `req.params`. Returns `null` when the list is empty
|
|
60
|
+
* (so callers can avoid wiring an unnecessary middleware).
|
|
61
|
+
*
|
|
62
|
+
* When a constraint fails, the middleware delegates to `next()` without
|
|
63
|
+
* a value; the framework's NotFound handler then converts that into a
|
|
64
|
+
* 404 — same observable behaviour as Express 4's "no route matched".
|
|
65
|
+
*/
|
|
66
|
+
export declare function createPathConstraintMiddleware(constraints: Array<PathConstraint>): RequestHandler | null;
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Route parameter patterns for common use cases.
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* Express 5 / path-to-regexp v8 dropped the inline-regex form
|
|
5
|
+
* (`:id(\\d+)`), so the framework no longer hands these patterns to
|
|
6
|
+
* the underlying matcher verbatim. Instead, the HTTP-method decorators
|
|
7
|
+
* (`@Get`, `@Post`, …) parse the constraint out of the path at decorator
|
|
8
|
+
* time, register the route under a plain `:id` placeholder, and inject
|
|
9
|
+
* a small validator middleware that 404s when the captured value
|
|
10
|
+
* doesn't match. The user-facing semantics are unchanged: a path that
|
|
11
|
+
* uses `Patterns.NUMERIC_ID` still rejects `/users/abc` and only
|
|
12
|
+
* dispatches the handler for matches like `/users/123`.
|
|
4
13
|
*
|
|
5
14
|
* @example
|
|
6
15
|
* ```typescript
|
|
@@ -8,12 +17,12 @@
|
|
|
8
17
|
*
|
|
9
18
|
* @Get(`/users/${pattern("id", Patterns.NUMERIC_ID)}`)
|
|
10
19
|
* getUserById(@param("id") id: number) {
|
|
11
|
-
* // Only
|
|
20
|
+
* // Only dispatches for numeric IDs like /users/123
|
|
12
21
|
* }
|
|
13
22
|
*
|
|
14
23
|
* @Get(`/documents/${pattern("uuid", Patterns.UUID)}`)
|
|
15
24
|
* getDocument(@param("uuid") uuid: string) {
|
|
16
|
-
* // Only
|
|
25
|
+
* // Only dispatches for valid UUIDs
|
|
17
26
|
* }
|
|
18
27
|
* ```
|
|
19
28
|
*
|
|
@@ -12,6 +12,19 @@ export interface MicroConfig {
|
|
|
12
12
|
globalPrefix?: string;
|
|
13
13
|
/** Show startup banner (default: true) */
|
|
14
14
|
showBanner?: boolean;
|
|
15
|
+
/** Application environment. Auto-detected from NODE_ENV if not provided. */
|
|
16
|
+
environment?: string;
|
|
17
|
+
/** Studio Agent configuration. Auto-enabled in development when the package is installed. */
|
|
18
|
+
studio?: {
|
|
19
|
+
/** Explicitly enable/disable Studio (default: auto-detect in development) */
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
/** WebSocket port for the Studio Agent (default: 3334) */
|
|
22
|
+
port?: number;
|
|
23
|
+
/** Path to the SQLite database (default: ".studio/studio.db") */
|
|
24
|
+
dbPath?: string;
|
|
25
|
+
/** Service name shown in Studio (default: "expressots-micro") */
|
|
26
|
+
serviceName?: string;
|
|
27
|
+
};
|
|
15
28
|
}
|
|
16
29
|
/**
|
|
17
30
|
* Route handler that can return a value or use res directly
|
|
@@ -43,10 +56,14 @@ export interface MicroApp {
|
|
|
43
56
|
setErrorHandler(handler: express.ErrorRequestHandler): this;
|
|
44
57
|
/** Start listening for requests */
|
|
45
58
|
listen(port: number | string, appInfo?: IConsoleMessage): Promise<void>;
|
|
46
|
-
/** Get the underlying HTTP server (
|
|
47
|
-
getHttpServer(): Server;
|
|
59
|
+
/** Get the underlying HTTP server (null before listen resolves) */
|
|
60
|
+
getHttpServer(): Server | null;
|
|
48
61
|
/** Get the Express app instance (for advanced use) */
|
|
49
62
|
getApp(): express.Application;
|
|
63
|
+
/** Configure Studio integration (call before listen) */
|
|
64
|
+
setStudio(config: NonNullable<MicroConfig["studio"]>): this;
|
|
65
|
+
/** Check if Studio Agent is currently enabled */
|
|
66
|
+
isStudioEnabled(): boolean;
|
|
50
67
|
}
|
|
51
68
|
/**
|
|
52
69
|
* Create a new micro API instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { initializeStudio, stopStudio, isStudioEnabled, getStudioAgent, reportStudioRuntimeInfo, } from "./studio-integration.js";
|
|
1
|
+
export { initializeStudio, stopStudio, isStudioEnabled, getStudioAgent, reportStudioRuntimeInfo, rescanStudioRoutes, } from "./studio-integration.js";
|
|
@@ -23,6 +23,7 @@ interface StudioAgentInstance {
|
|
|
23
23
|
providerCount?: number;
|
|
24
24
|
middlewareCount?: number;
|
|
25
25
|
runtimeItems?: StudioRuntimeItems;
|
|
26
|
+
middlewarePreset?: StudioMiddlewarePresetInfo;
|
|
26
27
|
}): void;
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
@@ -45,6 +46,70 @@ export interface StudioRuntimeItems {
|
|
|
45
46
|
priority?: number;
|
|
46
47
|
source?: string;
|
|
47
48
|
}>;
|
|
49
|
+
middleware?: Array<{
|
|
50
|
+
name: string;
|
|
51
|
+
category: string;
|
|
52
|
+
type: "built-in" | "custom";
|
|
53
|
+
order: number;
|
|
54
|
+
path?: string;
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Controller- and route-scoped middleware bindings, harvested from
|
|
58
|
+
* `ControllerMetadata.middleware` Reflect entries after
|
|
59
|
+
* `app.listen()`. Used by the agent to draw scope-aware
|
|
60
|
+
* "middleware → controller / route" edges on the architecture map.
|
|
61
|
+
*
|
|
62
|
+
* Mirrors `MiddlewareBinding` in `@expressots/studio-agent`.
|
|
63
|
+
*/
|
|
64
|
+
middlewareBindings?: Array<{
|
|
65
|
+
middlewareName: string;
|
|
66
|
+
scope: "controller" | "route";
|
|
67
|
+
controllerName: string;
|
|
68
|
+
controllerMethod?: string;
|
|
69
|
+
httpMethod?: string;
|
|
70
|
+
routePath?: string;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Middleware preset info forwarded to the Studio Agent. Mirrors
|
|
75
|
+
* `MiddlewarePresetInfo` in `@expressots/studio-agent` so the adapter
|
|
76
|
+
* doesn't need to import from the studio package.
|
|
77
|
+
*/
|
|
78
|
+
export interface StudioMiddlewarePresetInfo {
|
|
79
|
+
name: string;
|
|
80
|
+
hasOverrides: boolean;
|
|
81
|
+
parse?: {
|
|
82
|
+
json?: {
|
|
83
|
+
limit?: string;
|
|
84
|
+
};
|
|
85
|
+
urlencoded?: {
|
|
86
|
+
limit?: string;
|
|
87
|
+
extended?: boolean;
|
|
88
|
+
};
|
|
89
|
+
cookies?: boolean;
|
|
90
|
+
};
|
|
91
|
+
security?: {
|
|
92
|
+
tier?: string;
|
|
93
|
+
helmet?: boolean;
|
|
94
|
+
cors?: {
|
|
95
|
+
origin?: boolean | string;
|
|
96
|
+
credentials?: boolean;
|
|
97
|
+
methods?: Array<string>;
|
|
98
|
+
allowedHeaders?: Array<string>;
|
|
99
|
+
};
|
|
100
|
+
rateLimit?: {
|
|
101
|
+
windowMs?: number;
|
|
102
|
+
max?: number;
|
|
103
|
+
} | false;
|
|
104
|
+
};
|
|
105
|
+
compress?: {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
level?: number;
|
|
108
|
+
};
|
|
109
|
+
logger?: {
|
|
110
|
+
enabled: boolean;
|
|
111
|
+
implementation?: string;
|
|
112
|
+
};
|
|
48
113
|
}
|
|
49
114
|
interface StudioIntegrationConfig {
|
|
50
115
|
enabled?: boolean;
|
|
@@ -76,7 +141,20 @@ export declare function reportStudioRuntimeInfo(patch: {
|
|
|
76
141
|
providerCount?: number;
|
|
77
142
|
middlewareCount?: number;
|
|
78
143
|
runtimeItems?: StudioRuntimeItems;
|
|
144
|
+
middlewarePreset?: StudioMiddlewarePresetInfo;
|
|
79
145
|
}): void;
|
|
146
|
+
/**
|
|
147
|
+
* Re-trigger the Studio Agent's route discovery. Used by the host
|
|
148
|
+
* after `app.listen()` so that the agent's runtime route scanner sees
|
|
149
|
+
* the fully-populated Express `_router` stack (controllers are bound
|
|
150
|
+
* by `InversifyExpressServer.build()` AFTER `initializeStudio()` runs,
|
|
151
|
+
* so the agent's first scan only catches static-source routes).
|
|
152
|
+
*
|
|
153
|
+
* No-ops when:
|
|
154
|
+
* - Studio isn't enabled, or
|
|
155
|
+
* - the installed agent is too old to expose `scanRoutes()`.
|
|
156
|
+
*/
|
|
157
|
+
export declare function rescanStudioRoutes(): Promise<void>;
|
|
80
158
|
/**
|
|
81
159
|
* Stop the Studio Agent
|
|
82
160
|
*/
|