@pipeline-builder/api-server 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +39 -0
- package/lib/api/app-factory.d.ts +71 -0
- package/lib/api/app-factory.js +212 -0
- package/lib/api/check-quota.d.ts +13 -0
- package/lib/api/check-quota.js +67 -0
- package/lib/api/context-middleware.d.ts +34 -0
- package/lib/api/context-middleware.js +45 -0
- package/lib/api/etag-middleware.d.ts +7 -0
- package/lib/api/etag-middleware.js +37 -0
- package/lib/api/get-context.d.ts +22 -0
- package/lib/api/get-context.js +31 -0
- package/lib/api/health-checks.d.ts +25 -0
- package/lib/api/health-checks.js +36 -0
- package/lib/api/idempotency-middleware.d.ts +9 -0
- package/lib/api/idempotency-middleware.js +64 -0
- package/lib/api/index.d.ts +15 -0
- package/lib/api/index.js +43 -0
- package/lib/api/metrics.d.ts +12 -0
- package/lib/api/metrics.js +83 -0
- package/lib/api/middleware-factory.d.ts +47 -0
- package/lib/api/middleware-factory.js +66 -0
- package/lib/api/middleware.d.ts +1 -0
- package/lib/api/middleware.js +14 -0
- package/lib/api/quota-helpers.d.ts +23 -0
- package/lib/api/quota-helpers.js +25 -0
- package/lib/api/request-types.d.ts +55 -0
- package/lib/api/request-types.js +62 -0
- package/lib/api/require-org-id.d.ts +14 -0
- package/lib/api/require-org-id.js +31 -0
- package/lib/api/route-wrapper.d.ts +50 -0
- package/lib/api/route-wrapper.js +62 -0
- package/lib/api/server.d.ts +79 -0
- package/lib/api/server.js +144 -0
- package/lib/api/tracing.d.ts +15 -0
- package/lib/api/tracing.js +53 -0
- package/lib/http/index.d.ts +2 -0
- package/lib/http/index.js +21 -0
- package/lib/http/sse-connection-manager.d.ts +145 -0
- package/lib/http/sse-connection-manager.js +329 -0
- package/lib/http/ws-manager.d.ts +37 -0
- package/lib/http/ws-manager.js +105 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.js +51 -0
- package/package.json +143 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.startServer = startServer;
|
|
6
|
+
exports.runServer = runServer;
|
|
7
|
+
const api_core_1 = require("@pipeline-builder/api-core");
|
|
8
|
+
const pipeline_core_1 = require("@pipeline-builder/pipeline-core");
|
|
9
|
+
const tracing_1 = require("./tracing");
|
|
10
|
+
const logger = (0, api_core_1.createLogger)('Server');
|
|
11
|
+
/**
|
|
12
|
+
* Start an Express server with graceful shutdown handling
|
|
13
|
+
*
|
|
14
|
+
* Features:
|
|
15
|
+
* - Automatic database connection testing
|
|
16
|
+
* - Graceful shutdown on SIGINT/SIGTERM
|
|
17
|
+
* - SSE connection cleanup
|
|
18
|
+
* - Configurable shutdown timeout
|
|
19
|
+
*
|
|
20
|
+
* @param app - Express application
|
|
21
|
+
* @param options - Server options
|
|
22
|
+
* @returns Server instance and control functions
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const { app, sseManager } = createApp();
|
|
27
|
+
*
|
|
28
|
+
* app.post('/api/resource', requireAuth, handler);
|
|
29
|
+
*
|
|
30
|
+
* await startServer(app, {
|
|
31
|
+
* name: 'My Microservice',
|
|
32
|
+
* sseManager,
|
|
33
|
+
* onStart: (port) => console.log(`Listening on ${port}`),
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
async function startServer(app, options = {}) {
|
|
38
|
+
const serverConfig = pipeline_core_1.Config.get('server');
|
|
39
|
+
const { name = 'Microservice', sseManager, shutdownTimeoutMs = 15000, onStart, onShutdown, onBeforeStart, testDatabase, closeDatabase, } = options;
|
|
40
|
+
const port = options.port ?? serverConfig.port;
|
|
41
|
+
// Validate auth configuration at server startup (not during CDK synthesis)
|
|
42
|
+
pipeline_core_1.Config.validateAuth();
|
|
43
|
+
logger.info(`Starting ${name}...`);
|
|
44
|
+
// Pre-start hook (e.g., initialize external connections)
|
|
45
|
+
if (onBeforeStart) {
|
|
46
|
+
await onBeforeStart();
|
|
47
|
+
}
|
|
48
|
+
// Test database connection
|
|
49
|
+
if (testDatabase !== false) {
|
|
50
|
+
const dbHealthy = testDatabase
|
|
51
|
+
? await testDatabase()
|
|
52
|
+
: await (0, pipeline_core_1.getConnection)().testConnection();
|
|
53
|
+
if (!dbHealthy) {
|
|
54
|
+
throw new Error('Database connection failed');
|
|
55
|
+
}
|
|
56
|
+
logger.info('Database connection established');
|
|
57
|
+
}
|
|
58
|
+
// Start server
|
|
59
|
+
const server = app.listen(port, () => {
|
|
60
|
+
logger.info(`${name} listening on port: ${port}`);
|
|
61
|
+
logger.info(`Platform URL: ${serverConfig.platformUrl}`);
|
|
62
|
+
onStart?.(port);
|
|
63
|
+
});
|
|
64
|
+
// Shutdown handler (guarded against concurrent signals)
|
|
65
|
+
let shuttingDown = false;
|
|
66
|
+
const shutdown = async (signal) => {
|
|
67
|
+
if (shuttingDown)
|
|
68
|
+
return;
|
|
69
|
+
shuttingDown = true;
|
|
70
|
+
if (signal) {
|
|
71
|
+
logger.info(`${signal} received, shutting down gracefully...`);
|
|
72
|
+
}
|
|
73
|
+
// Custom shutdown callback
|
|
74
|
+
if (onShutdown) {
|
|
75
|
+
try {
|
|
76
|
+
await onShutdown();
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
logger.error('Error in onShutdown callback', { error });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Close SSE connections
|
|
83
|
+
if (sseManager) {
|
|
84
|
+
sseManager.shutdown();
|
|
85
|
+
logger.info('SSE connections closed');
|
|
86
|
+
}
|
|
87
|
+
// Close HTTP server
|
|
88
|
+
server.close(async () => {
|
|
89
|
+
logger.info('HTTP server closed');
|
|
90
|
+
// Shutdown OpenTelemetry tracing
|
|
91
|
+
await (0, tracing_1.shutdownTracing)().catch(err => logger.error('Error shutting down tracing', { error: err }));
|
|
92
|
+
// Close database connection
|
|
93
|
+
if (closeDatabase !== false) {
|
|
94
|
+
try {
|
|
95
|
+
if (closeDatabase) {
|
|
96
|
+
await closeDatabase();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
await (0, pipeline_core_1.closeConnection)();
|
|
100
|
+
}
|
|
101
|
+
logger.info('Database connection closed');
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
logger.error('Error closing database', { error });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
process.exit(0);
|
|
108
|
+
});
|
|
109
|
+
// Force shutdown after timeout
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
logger.error('Forced shutdown after timeout');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}, shutdownTimeoutMs).unref();
|
|
114
|
+
};
|
|
115
|
+
// Register signal handlers
|
|
116
|
+
process.once('SIGINT', () => void shutdown('SIGINT'));
|
|
117
|
+
process.once('SIGTERM', () => void shutdown('SIGTERM'));
|
|
118
|
+
return {
|
|
119
|
+
server,
|
|
120
|
+
port,
|
|
121
|
+
shutdown: () => shutdown(),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Simple server start wrapper with error handling
|
|
126
|
+
*
|
|
127
|
+
* @param app - Express application
|
|
128
|
+
* @param options - Server options
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const { app, sseManager } = createApp();
|
|
133
|
+
* app.post('/api/resource', handler);
|
|
134
|
+
*
|
|
135
|
+
* void runServer(app, { name: 'My Service', sseManager });
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
function runServer(app, options = {}) {
|
|
139
|
+
startServer(app, options).catch((error) => {
|
|
140
|
+
logger.error('Failed to start server', { error });
|
|
141
|
+
process.exit(1);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBeUV0QyxrQ0FnSEM7QUFnQkQsOEJBS0M7QUEzTUQseURBQTBEO0FBQzFELG1FQUF5RjtBQUV6Rix1Q0FBNEM7QUFHNUMsTUFBTSxNQUFNLEdBQUcsSUFBQSx1QkFBWSxFQUFDLFFBQVEsQ0FBQyxDQUFDO0FBc0N0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXlCRztBQUNJLEtBQUssVUFBVSxXQUFXLENBQy9CLEdBQVksRUFDWixVQUE4QixFQUFFO0lBRWhDLE1BQU0sWUFBWSxHQUFHLHNCQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzFDLE1BQU0sRUFDSixJQUFJLEdBQUcsY0FBYyxFQUNyQixVQUFVLEVBQ1YsaUJBQWlCLEdBQUcsS0FBSyxFQUN6QixPQUFPLEVBQ1AsVUFBVSxFQUNWLGFBQWEsRUFDYixZQUFZLEVBQ1osYUFBYSxHQUNkLEdBQUcsT0FBTyxDQUFDO0lBQ1osTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDO0lBRS9DLDJFQUEyRTtJQUMzRSxzQkFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBRXRCLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxJQUFJLEtBQUssQ0FBQyxDQUFDO0lBRW5DLHlEQUF5RDtJQUN6RCxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQ2xCLE1BQU0sYUFBYSxFQUFFLENBQUM7SUFDeEIsQ0FBQztJQUVELDJCQUEyQjtJQUMzQixJQUFJLFlBQVksS0FBSyxLQUFLLEVBQUUsQ0FBQztRQUMzQixNQUFNLFNBQVMsR0FBRyxZQUFZO1lBQzVCLENBQUMsQ0FBQyxNQUFNLFlBQVksRUFBRTtZQUN0QixDQUFDLENBQUMsTUFBTSxJQUFBLDZCQUFhLEdB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Q0FBQztJQUVGLDJCQUEyQjtJQUMzQixPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxLQUFLLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQ3RELE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFFeEQsT0FBTztRQUNMLE1BQU07UUFDTixJQUFJO1FBQ0osUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLFFBQVEsRUFBRTtLQUMzQixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxTQUFnQixTQUFTLENBQUMsR0FBWSxFQUFFLFVBQThCLEVBQUU7SUFDdEUsV0FBVyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtRQUN4QyxNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUNsRCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBTZXJ2ZXIgfSBmcm9tICdodHRwJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IENvbmZpZywgZ2V0Q29ubmVjdGlvbiwgY2xvc2VDb25uZWN0aW9uIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtY29yZSc7XG5pbXBvcnQgeyBFeHByZXNzIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyBzaHV0ZG93blRyYWNpbmcgfSBmcm9tICcuL3RyYWNpbmcnO1xuaW1wb3J0IHsgU1NFTWFuYWdlciB9IGZyb20gJy4uL2h0dHAvc3NlLWNvbm5lY3Rpb24tbWFuYWdlcic7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignU2VydmVyJyk7XG5cbi8qKlxuICogT3B0aW9ucyBmb3Igc3RhcnRpbmcgYSBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGFydFNlcnZlck9wdGlvbnMge1xuICAvKiogU2VydmljZSBuYW1lIGZvciBsb2dnaW5nICovXG4gIG5hbWU/OiBzdHJpbmc7XG4gIC8qKiBQb3J0IHRvIGxpc3RlbiBvbiAoZGVmYXVsdDogZnJvbSBjb25maWcpICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKiBTU0UgbWFuYWdlciBmb3IgZ3JhY2VmdWwgc2h1dGRvd24gKi9cbiAgc3NlTWFuYWdlcj86IFNTRU1hbmFnZXI7XG4gIC8qKiBTaHV0ZG93biB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogMTUwMDApICovXG4gIHNodXRkb3duVGltZW91dE1zPzogbnVtYmVyO1xuICAvKiogQ2FsbGJhY2sgYWZ0ZXIgc2VydmVyIHN0YXJ0cyAqL1xuICBvblN0YXJ0PzogKHBvcnQ6IG51bWJlcikgPT4gdm9pZDtcbiAgLyoqIENhbGxiYWNrIGJlZm9yZSBzaHV0ZG93biAqL1xuICBvblNodXRkb3duPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqIFJ1bnMgYmVmb3JlIGRhdGFiYXNlIGNoZWNrIChlLmcuLCBpbml0aWFsaXplIGV4dGVybmFsIGNvbm5lY3Rpb25zKSAqL1xuICBvbkJlZm9yZVN0YXJ0PzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqIEN1c3RvbSBkYXRhYmFzZSBoZWFsdGggY2hlY2ssIG9yIGZhbHNlIHRvIHNraXAuIERlZmF1bHQ6IFBvc3RncmVTUUwgdGVzdENvbm5lY3Rpb24gKi9cbiAgdGVzdERhdGFiYXNlPzogKCgpID0+IFByb21pc2U8Ym9vbGVhbj4pIHwgZmFsc2U7XG4gIC8qKiBDdXN0b20gZGF0YWJhc2UgY2xvc2UsIG9yIGZhbHNlIHRvIHNraXAuIERlZmF1bHQ6IFBvc3RncmVTUUwgY2xvc2VDb25uZWN0aW9uICovXG4gIGNsb3NlRGF0YWJhc2U/OiAoKCkgPT4gUHJvbWlzZTx2b2lkPikgfCBmYWxzZTtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2Ygc3RhcnRpbmcgYSBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGFydFNlcnZlclJlc3VsdCB7XG4gIC8qKiBIVFRQIHNlcnZlciBpbnN0YW5jZSAqL1xuICBzZXJ2ZXI6IFNlcnZlcjtcbiAgLyoqIFBvcnQgdGhlIHNlcnZlciBpcyBsaXN0ZW5pbmcgb24gKi9cbiAgcG9ydDogbnVtYmVyO1xuICAvKiogRnVuY3Rpb24gdG8gbWFudWFsbHkgdHJpZ2dlciBzaHV0ZG93biAqL1xuICBzaHV0ZG93bjogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuLyoqXG4gKiBTdGFydCBhbiBFeHByZXNzIHNlcnZlciB3aXRoIGdyYWNlZnVsIHNodXRkb3duIGhhbmRsaW5nXG4gKlxuICogRmVhdHVyZXM6XG4gKiAtIEF1dG9tYXRpYyBkYXRhYmFzZSBjb25uZWN0aW9uIHRlc3RpbmdcbiAqIC0gR3JhY2VmdWwgc2h1dGRvd24gb24gU0lHSU5UL1NJR1RFUk1cbiAqIC0gU1NFIGNvbm5lY3Rpb24gY2xlYW51cFxuICogLSBDb25maWd1cmFibGUgc2h1dGRvd24gdGltZW91dFxuICpcbiAqIEBwYXJhbSBhcHAgLSBFeHByZXNzIGFwcGxpY2F0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFNlcnZlciBvcHRpb25zXG4gKiBAcmV0dXJucyBTZXJ2ZXIgaW5zdGFuY2UgYW5kIGNvbnRyb2wgZnVuY3Rpb25zXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqXG4gKiBhcHAucG9zdCgnL2FwaS9yZXNvdXJjZScsIHJlcXVpcmVBdXRoLCBoYW5kbGVyKTtcbiAqXG4gKiBhd2FpdCBzdGFydFNlcnZlcihhcHAsIHtcbiAqICAgbmFtZTogJ015IE1pY3Jvc2VydmljZScsXG4gKiAgIHNzZU1hbmFnZXIsXG4gKiAgIG9uU3RhcnQ6IChwb3J0KSA9PiBjb25zb2xlLmxvZyhgTGlzdGVuaW5nIG9uICR7cG9ydH1gKSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFNlcnZlcihcbiAgYXBwOiBFeHByZXNzLFxuICBvcHRpb25zOiBTdGFydFNlcnZlck9wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8U3RhcnRTZXJ2ZXJSZXN1bHQ+IHtcbiAgY29uc3Qgc2VydmVyQ29uZmlnID0gQ29uZmlnLmdldCgnc2VydmVyJyk7XG4gIGNvbnN0IHtcbiAgICBuYW1lID0gJ01pY3Jvc2VydmljZScsXG4gICAgc3NlTWFuYWdlcixcbiAgICBzaHV0ZG93blRpbWVvdXRNcyA9IDE1MDAwLFxuICAgIG9uU3RhcnQsXG4gICAgb25TaHV0ZG93bixcbiAgICBvbkJlZm9yZVN0YXJ0LFxuICAgIHRlc3REYXRhYmFzZSxcbiAgICBjbG9zZURhdGFiYXNlLFxuICB9ID0gb3B0aW9ucztcbiAgY29uc3QgcG9ydCA9IG9wdGlvbnMucG9ydCA/PyBzZXJ2ZXJDb25maWcucG9ydDtcblxuICAvLyBWYWxpZGF0ZSBhdXRoIGNvbmZpZ3VyYXRpb24gYXQgc2VydmVyIHN0YXJ0dXAgKG5vdCBkdXJpbmcgQ0RLIHN5bnRoZXNpcylcbiAgQ29uZmlnLnZhbGlkYXRlQXV0aCgpO1xuXG4gIGxvZ2dlci5pbmZvKGBTdGFydGluZyAke25hbWV9Li4uYCk7XG5cbiAgLy8gUHJlLXN0YXJ0IGhvb2sgKGUuZy4sIGluaXRpYWxpemUgZXh0ZXJuYWwgY29ubmVjdGlvbnMpXG4gIGlmIChvbkJlZm9yZVN0YXJ0KSB7XG4gICAgYXdhaXQgb25CZWZvcmVTdGFydCgpO1xuICB9XG5cbiAgLy8gVGVzdCBkYXRhYmFzZSBjb25uZWN0aW9uXG4gIGlmICh0ZXN0RGF0YWJhc2UgIT09IGZhbHNlKSB7XG4gICAgY29uc3QgZGJIZWFsdGh5ID0gdGVzdERhdGFiYXNlXG4gICAgICA/IGF3YWl0IHRlc3REYXRhYmFzZSgpXG4gICAgICA6IGF3YWl0IGdldENvbm5lY3Rpb24oKS50ZXN0Q29ubmVjdGlvbigpO1xuXG4gICAgaWYgKCFkYkhlYWx0aHkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRGF0YWJhc2UgY29ubmVjdGlvbiBmYWlsZWQnKTtcbiAgICB9XG5cbiAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiBlc3RhYmxpc2hlZCcpO1xuICB9XG5cbiAgLy8gU3RhcnQgc2VydmVyXG4gIGNvbnN0IHNlcnZlciA9IGFwcC5saXN0ZW4ocG9ydCwgKCkgPT4ge1xuICAgIGxvZ2dlci5pbmZvKGAke25hbWV9IGxpc3RlbmluZyBvbiBwb3J0OiAke3BvcnR9YCk7XG4gICAgbG9nZ2VyLmluZm8oYFBsYXRmb3JtIFVSTDogJHtzZXJ2ZXJDb25maWcucGxhdGZvcm1Vcmx9YCk7XG4gICAgb25TdGFydD8uKHBvcnQpO1xuICB9KTtcblxuICAvLyBTaHV0ZG93biBoYW5kbGVyIChndWFyZGVkIGFnYWluc3QgY29uY3VycmVudCBzaWduYWxzKVxuICBsZXQgc2h1dHRpbmdEb3duID0gZmFsc2U7XG4gIGNvbnN0IHNodXRkb3duID0gYXN5bmMgKHNpZ25hbD86IHN0cmluZykgPT4ge1xuICAgIGlmIChzaHV0dGluZ0Rvd24pIHJldHVybjtcbiAgICBzaHV0dGluZ0Rvd24gPSB0cnVlO1xuXG4gICAgaWYgKHNpZ25hbCkge1xuICAgICAgbG9nZ2VyLmluZm8oYCR7c2lnbmFsfSByZWNlaXZlZCwgc2h1dHRpbmcgZG93biBncmFjZWZ1bGx5Li4uYCk7XG4gICAgfVxuXG4gICAgLy8gQ3VzdG9tIHNodXRkb3duIGNhbGxiYWNrXG4gICAgaWYgKG9uU2h1dGRvd24pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IG9uU2h1dGRvd24oKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignRXJyb3IgaW4gb25TaHV0ZG93biBjYWxsYmFjaycsIHsgZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2xvc2UgU1NFIGNvbm5lY3Rpb25zXG4gICAgaWYgKHNzZU1hbmFnZXIpIHtcbiAgICAgIHNzZU1hbmFnZXIuc2h1dGRvd24oKTtcbiAgICAgIGxvZ2dlci5pbmZvKCdTU0UgY29ubmVjdGlvbnMgY2xvc2VkJyk7XG4gICAgfVxuXG4gICAgLy8gQ2xvc2UgSFRUUCBzZXJ2ZXJcbiAgICBzZXJ2ZXIuY2xvc2UoYXN5bmMgKCkgPT4ge1xuICAgICAgbG9nZ2VyLmluZm8oJ0hUVFAgc2VydmVyIGNsb3NlZCcpO1xuXG4gICAgICAvLyBTaHV0ZG93biBPcGVuVGVsZW1ldHJ5IHRyYWNpbmdcbiAgICAgIGF3YWl0IHNodXRkb3duVHJhY2luZygpLmNhdGNoKGVyciA9PiBsb2dnZXIuZXJyb3IoJ0Vycm9yIHNodXR0aW5nIGRvd24gdHJhY2luZycsIHsgZXJyb3I6IGVyciB9KSk7XG5cbiAgICAgIC8vIENsb3NlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAgICAgIGlmIChjbG9zZURhdGFiYXNlICE9PSBmYWxzZSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmIChjbG9zZURhdGFiYXNlKSB7XG4gICAgICAgICAgICBhd2FpdCBjbG9zZURhdGFiYXNlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IGNsb3NlQ29ubmVjdGlvbigpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiBjbG9zZWQnKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIGNsb3NpbmcgZGF0YWJhc2UnLCB7IGVycm9yIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICB9KTtcblxuICAgIC8vIEZvcmNlIHNodXRkb3duIGFmdGVyIHRpbWVvdXRcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGxvZ2dlci5lcnJvcignRm9yY2VkIHNodXRkb3duIGFmdGVyIHRpbWVvdXQnKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9LCBzaHV0ZG93blRpbWVvdXRNcykudW5yZWYoKTtcbiAgfTtcblxuICAvLyBSZWdpc3RlciBzaWduYWwgaGFuZGxlcnNcbiAgcHJvY2Vzcy5vbmNlKCdTSUdJTlQnLCAoKSA9PiB2b2lkIHNodXRkb3duKCdTSUdJTlQnKSk7XG4gIHByb2Nlc3Mub25jZSgnU0lHVEVSTScsICgpID0+IHZvaWQgc2h1dGRvd24oJ1NJR1RFUk0nKSk7XG5cbiAgcmV0dXJuIHtcbiAgICBzZXJ2ZXIsXG4gICAgcG9ydCxcbiAgICBzaHV0ZG93bjogKCkgPT4gc2h1dGRvd24oKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTaW1wbGUgc2VydmVyIHN0YXJ0IHdyYXBwZXIgd2l0aCBlcnJvciBoYW5kbGluZ1xuICpcbiAqIEBwYXJhbSBhcHAgLSBFeHByZXNzIGFwcGxpY2F0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFNlcnZlciBvcHRpb25zXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqIGFwcC5wb3N0KCcvYXBpL3Jlc291cmNlJywgaGFuZGxlcik7XG4gKlxuICogdm9pZCBydW5TZXJ2ZXIoYXBwLCB7IG5hbWU6ICdNeSBTZXJ2aWNlJywgc3NlTWFuYWdlciB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuU2VydmVyKGFwcDogRXhwcmVzcywgb3B0aW9uczogU3RhcnRTZXJ2ZXJPcHRpb25zID0ge30pOiB2b2lkIHtcbiAgc3RhcnRTZXJ2ZXIoYXBwLCBvcHRpb25zKS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBzdGFydCBzZXJ2ZXInLCB7IGVycm9yIH0pO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfSk7XG59XG4iXX0=
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initialize OpenTelemetry tracing with OTLP HTTP exporter.
|
|
3
|
+
* Configured via `Config.get('observability').tracing`.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { initTracing } from '@pipeline-builder/api-server';
|
|
8
|
+
* initTracing('pipeline-service');
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare function initTracing(serviceName: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* Shutdown the OpenTelemetry SDK gracefully.
|
|
14
|
+
*/
|
|
15
|
+
export declare function shutdownTracing(): Promise<void>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.initTracing = initTracing;
|
|
6
|
+
exports.shutdownTracing = shutdownTracing;
|
|
7
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
8
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
9
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
10
|
+
const api_core_1 = require("@pipeline-builder/api-core");
|
|
11
|
+
const pipeline_core_1 = require("@pipeline-builder/pipeline-core");
|
|
12
|
+
const logger = (0, api_core_1.createLogger)('Tracing');
|
|
13
|
+
let sdk = null;
|
|
14
|
+
/**
|
|
15
|
+
* Initialize OpenTelemetry tracing with OTLP HTTP exporter.
|
|
16
|
+
* Configured via `Config.get('observability').tracing`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { initTracing } from '@pipeline-builder/api-server';
|
|
21
|
+
* initTracing('pipeline-service');
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
function initTracing(serviceName) {
|
|
25
|
+
const { tracing } = pipeline_core_1.Config.getAny('observability');
|
|
26
|
+
if (!tracing.enabled) {
|
|
27
|
+
logger.debug('OpenTelemetry tracing disabled (set OTEL_TRACING_ENABLED=true to enable)');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (sdk) {
|
|
31
|
+
logger.debug('OpenTelemetry already initialized');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const exporter = new exporter_trace_otlp_http_1.OTLPTraceExporter({
|
|
35
|
+
url: tracing.endpoint,
|
|
36
|
+
});
|
|
37
|
+
sdk = new sdk_node_1.NodeSDK({
|
|
38
|
+
resource: (0, resources_1.resourceFromAttributes)({ 'service.name': serviceName }),
|
|
39
|
+
traceExporter: exporter,
|
|
40
|
+
});
|
|
41
|
+
sdk.start();
|
|
42
|
+
logger.info(`OpenTelemetry tracing initialized for ${serviceName}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Shutdown the OpenTelemetry SDK gracefully.
|
|
46
|
+
*/
|
|
47
|
+
async function shutdownTracing() {
|
|
48
|
+
if (sdk) {
|
|
49
|
+
await sdk.shutdown();
|
|
50
|
+
sdk = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvdHJhY2luZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUFzQnRDLGtDQXdCQztBQUtELDBDQUtDO0FBdERELHNGQUE0RTtBQUM1RSx3REFBa0U7QUFDbEUsc0RBQWtEO0FBQ2xELHlEQUEwRDtBQUMxRCxtRUFBeUQ7QUFFekQsTUFBTSxNQUFNLEdBQUcsSUFBQSx1QkFBWSxFQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRXZDLElBQUksR0FBRyxHQUFtQixJQUFJLENBQUM7QUFFL0I7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBZ0IsV0FBVyxDQUFDLFdBQW1CO0lBQzdDLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxzQkFBTSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQXdELENBQUM7SUFFMUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNyQixNQUFNLENBQUMsS0FBSyxDQUFDLDBFQUEwRSxDQUFDLENBQUM7UUFDekYsT0FBTztJQUNULENBQUM7SUFFRCxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ1IsTUFBTSxDQUFDLEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBQ2xELE9BQU87SUFDVCxDQUFDO0lBRUQsTUFBTSxRQUFRLEdBQUcsSUFBSSw0Q0FBaUIsQ0FBQztRQUNyQyxHQUFHLEVBQUUsT0FBTyxDQUFDLFFBQVE7S0FDdEIsQ0FBQyxDQUFDO0lBRUgsR0FBRyxHQUFHLElBQUksa0JBQU8sQ0FBQztRQUNoQixRQUFRLEVBQUUsSUFBQSxrQ0FBc0IsRUFBQyxFQUFFLGNBQWMsRUFBRSxXQUFXLEVBQUUsQ0FBQztRQUNqRSxhQUFhLEVBQUUsUUFBUTtLQUN4QixDQUFDLENBQUM7SUFFSCxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDWixNQUFNLENBQUMsSUFBSSxDQUFDLHlDQUF5QyxXQUFXLEVBQUUsQ0FBQyxDQUFDO0FBQ3RFLENBQUM7QUFFRDs7R0FFRztBQUNJLEtBQUssVUFBVSxlQUFlO0lBQ25DLElBQUksR0FBRyxFQUFFLENBQUM7UUFDUixNQUFNLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNyQixHQUFHLEdBQUcsSUFBSSxDQUFDO0lBQ2IsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgT1RMUFRyYWNlRXhwb3J0ZXIgfSBmcm9tICdAb3BlbnRlbGVtZXRyeS9leHBvcnRlci10cmFjZS1vdGxwLWh0dHAnO1xuaW1wb3J0IHsgcmVzb3VyY2VGcm9tQXR0cmlidXRlcyB9IGZyb20gJ0BvcGVudGVsZW1ldHJ5L3Jlc291cmNlcyc7XG5pbXBvcnQgeyBOb2RlU0RLIH0gZnJvbSAnQG9wZW50ZWxlbWV0cnkvc2RrLW5vZGUnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgQ29uZmlnIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtY29yZSc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignVHJhY2luZycpO1xuXG5sZXQgc2RrOiBOb2RlU0RLIHwgbnVsbCA9IG51bGw7XG5cbi8qKlxuICogSW5pdGlhbGl6ZSBPcGVuVGVsZW1ldHJ5IHRyYWNpbmcgd2l0aCBPVExQIEhUVFAgZXhwb3J0ZXIuXG4gKiBDb25maWd1cmVkIHZpYSBgQ29uZmlnLmdldCgnb2JzZXJ2YWJpbGl0eScpLnRyYWNpbmdgLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBpbml0VHJhY2luZyB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1zZXJ2ZXInO1xuICogaW5pdFRyYWNpbmcoJ3BpcGVsaW5lLXNlcnZpY2UnKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5pdFRyYWNpbmcoc2VydmljZU5hbWU6IHN0cmluZyk6IHZvaWQge1xuICBjb25zdCB7IHRyYWNpbmcgfSA9IENvbmZpZy5nZXRBbnkoJ29ic2VydmFiaWxpdHknKSBhcyB7IHRyYWNpbmc6IHsgZW5hYmxlZDogYm9vbGVhbjsgZW5kcG9pbnQ6IHN0cmluZyB9IH07XG5cbiAgaWYgKCF0cmFjaW5nLmVuYWJsZWQpIHtcbiAgICBsb2dnZXIuZGVidWcoJ09wZW5UZWxlbWV0cnkgdHJhY2luZyBkaXNhYmxlZCAoc2V0IE9URUxfVFJBQ0lOR19FTkFCTEVEPXRydWUgdG8gZW5hYmxlKScpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmIChzZGspIHtcbiAgICBsb2dnZXIuZGVidWcoJ09wZW5UZWxlbWV0cnkgYWxyZWFkeSBpbml0aWFsaXplZCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGV4cG9ydGVyID0gbmV3IE9UTFBUcmFjZUV4cG9ydGVyKHtcbiAgICB1cmw6IHRyYWNpbmcuZW5kcG9pbnQsXG4gIH0pO1xuXG4gIHNkayA9IG5ldyBOb2RlU0RLKHtcbiAgICByZXNvdXJjZTogcmVzb3VyY2VGcm9tQXR0cmlidXRlcyh7ICdzZXJ2aWNlLm5hbWUnOiBzZXJ2aWNlTmFtZSB9KSxcbiAgICB0cmFjZUV4cG9ydGVyOiBleHBvcnRlcixcbiAgfSk7XG5cbiAgc2RrLnN0YXJ0KCk7XG4gIGxvZ2dlci5pbmZvKGBPcGVuVGVsZW1ldHJ5IHRyYWNpbmcgaW5pdGlhbGl6ZWQgZm9yICR7c2VydmljZU5hbWV9YCk7XG59XG5cbi8qKlxuICogU2h1dGRvd24gdGhlIE9wZW5UZWxlbWV0cnkgU0RLIGdyYWNlZnVsbHkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaHV0ZG93blRyYWNpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChzZGspIHtcbiAgICBhd2FpdCBzZGsuc2h1dGRvd24oKTtcbiAgICBzZGsgPSBudWxsO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
16
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
__exportStar(require("./sse-connection-manager"), exports);
|
|
20
|
+
__exportStar(require("./ws-manager"), exports);
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaHR0cC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7Ozs7Ozs7Ozs7Ozs7OztBQUV0QywyREFBeUM7QUFDekMsK0NBQTZCIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmV4cG9ydCAqIGZyb20gJy4vc3NlLWNvbm5lY3Rpb24tbWFuYWdlcic7XG5leHBvcnQgKiBmcm9tICcuL3dzLW1hbmFnZXInO1xuIl19
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { Response } from 'express';
|
|
2
|
+
/**
|
|
3
|
+
* Event types for SSE logging
|
|
4
|
+
*/
|
|
5
|
+
export type SSEEventType = 'INFO' | 'WARN' | 'ERROR' | 'COMPLETED' | 'ROLLBACK' | 'MESSAGE';
|
|
6
|
+
/**
|
|
7
|
+
* SSE payload structure
|
|
8
|
+
*/
|
|
9
|
+
export interface SSEPayload {
|
|
10
|
+
ts: string;
|
|
11
|
+
type: SSEEventType;
|
|
12
|
+
message: string;
|
|
13
|
+
data?: unknown;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* SSE client with connection tracking
|
|
17
|
+
*/
|
|
18
|
+
export interface SSEClient {
|
|
19
|
+
id: string;
|
|
20
|
+
res: Response;
|
|
21
|
+
connectedAt: number;
|
|
22
|
+
timeout: NodeJS.Timeout;
|
|
23
|
+
/** Number of consecutive backpressure events (write returned false). */
|
|
24
|
+
backpressureCount: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* SSE Manager configuration options
|
|
28
|
+
*/
|
|
29
|
+
export interface SSEManagerOptions {
|
|
30
|
+
/** Maximum clients allowed per request ID (default: 10) */
|
|
31
|
+
maxClientsPerRequest?: number;
|
|
32
|
+
/** Client timeout in milliseconds (default: 30 minutes) */
|
|
33
|
+
clientTimeoutMs?: number;
|
|
34
|
+
/** Interval for cleanup checks in milliseconds (default: 5 minutes) */
|
|
35
|
+
cleanupIntervalMs?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* SSE Manager statistics
|
|
39
|
+
*/
|
|
40
|
+
export interface SSEManagerStats {
|
|
41
|
+
totalRequests: number;
|
|
42
|
+
totalClients: number;
|
|
43
|
+
oldestConnectionMs: number | null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* SSE helper class with memory leak protection
|
|
47
|
+
*
|
|
48
|
+
* Features:
|
|
49
|
+
* - Client limits per request ID
|
|
50
|
+
* - Automatic timeout for idle connections
|
|
51
|
+
* - Periodic cleanup of stale connections
|
|
52
|
+
* - Connection statistics
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const sseManager = new SSEManager({ maxClientsPerRequest: 5 });
|
|
57
|
+
* app.get('/logs/:requestId', sseManager.middleware());
|
|
58
|
+
*
|
|
59
|
+
* // Send events
|
|
60
|
+
* sseManager.send('request-123', 'INFO', 'Processing...');
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare class SSEManager {
|
|
64
|
+
private clients;
|
|
65
|
+
private readonly maxClientsPerRequest;
|
|
66
|
+
private readonly clientTimeoutMs;
|
|
67
|
+
private cleanupInterval;
|
|
68
|
+
constructor(options?: SSEManagerOptions);
|
|
69
|
+
/**
|
|
70
|
+
* Adds a client to the SSE manager
|
|
71
|
+
*
|
|
72
|
+
* @param requestId - Unique request ID
|
|
73
|
+
* @param res - Express Response object
|
|
74
|
+
* @returns true if client was added, false if rejected (limit reached)
|
|
75
|
+
*/
|
|
76
|
+
addClient(requestId: string, res: Response): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Removes a client from the manager
|
|
79
|
+
*/
|
|
80
|
+
private removeClient;
|
|
81
|
+
/**
|
|
82
|
+
* Sends a message to all SSE clients for a requestId
|
|
83
|
+
*
|
|
84
|
+
* @param requestId - Request ID
|
|
85
|
+
* @param type - Event type
|
|
86
|
+
* @param message - Message string
|
|
87
|
+
* @param data - Optional additional data
|
|
88
|
+
* @returns Number of clients the message was sent to
|
|
89
|
+
*/
|
|
90
|
+
send(requestId: string, type: SSEEventType, message: string, data?: unknown): number;
|
|
91
|
+
/**
|
|
92
|
+
* Broadcast a message to all connected clients across all requests
|
|
93
|
+
*
|
|
94
|
+
* @param type - Event type
|
|
95
|
+
* @param message - Message string
|
|
96
|
+
* @param data - Optional additional data
|
|
97
|
+
* @returns Total number of clients the message was sent to
|
|
98
|
+
*/
|
|
99
|
+
broadcast(type: SSEEventType, message: string, data?: unknown): number;
|
|
100
|
+
/**
|
|
101
|
+
* Close all clients for a specific request
|
|
102
|
+
*
|
|
103
|
+
* @param requestId - Request ID to close
|
|
104
|
+
* @param finalMessage - Optional final message to send before closing
|
|
105
|
+
*/
|
|
106
|
+
closeRequest(requestId: string, finalMessage?: string): void;
|
|
107
|
+
/**
|
|
108
|
+
* Get statistics about current connections
|
|
109
|
+
*/
|
|
110
|
+
getStats(): SSEManagerStats;
|
|
111
|
+
/**
|
|
112
|
+
* Check if a request has any connected clients
|
|
113
|
+
*/
|
|
114
|
+
hasClients(requestId: string): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Get the number of clients for a specific request
|
|
117
|
+
*/
|
|
118
|
+
getClientCount(requestId: string): number;
|
|
119
|
+
/**
|
|
120
|
+
* Middleware to initialize SSE connection
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* app.get('/logs/:requestId', sseManager.middleware());
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
middleware(): (req: {
|
|
128
|
+
params: {
|
|
129
|
+
requestId: string;
|
|
130
|
+
};
|
|
131
|
+
}, res: Response) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Start periodic cleanup of stale connections
|
|
134
|
+
*/
|
|
135
|
+
private startCleanupInterval;
|
|
136
|
+
/**
|
|
137
|
+
* Clean up stale connections using single-pass partition.
|
|
138
|
+
* O(R × C) instead of O(R × C²), and avoids mutation-during-iteration.
|
|
139
|
+
*/
|
|
140
|
+
private cleanup;
|
|
141
|
+
/**
|
|
142
|
+
* Shutdown the SSE manager and close all connections
|
|
143
|
+
*/
|
|
144
|
+
shutdown(): void;
|
|
145
|
+
}
|