@ebarahona/loopback-transport-core 1.0.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 +21 -0
- package/README.md +297 -0
- package/dist/client/client-proxy.d.ts +147 -0
- package/dist/client/client-proxy.js +225 -0
- package/dist/client/client-proxy.js.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +18 -0
- package/dist/client/index.js.map +1 -0
- package/dist/context/execution-context.d.ts +102 -0
- package/dist/context/execution-context.js +110 -0
- package/dist/context/execution-context.js.map +1 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/index.js +18 -0
- package/dist/context/index.js.map +1 -0
- package/dist/decorators/constants.d.ts +41 -0
- package/dist/decorators/constants.js +13 -0
- package/dist/decorators/constants.js.map +1 -0
- package/dist/decorators/event-handler.decorator.d.ts +28 -0
- package/dist/decorators/event-handler.decorator.js +42 -0
- package/dist/decorators/event-handler.decorator.js.map +1 -0
- package/dist/decorators/index.d.ts +4 -0
- package/dist/decorators/index.js +21 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/message-handler.decorator.d.ts +26 -0
- package/dist/decorators/message-handler.decorator.js +40 -0
- package/dist/decorators/message-handler.decorator.js.map +1 -0
- package/dist/decorators/payload.decorator.d.ts +30 -0
- package/dist/decorators/payload.decorator.js +42 -0
- package/dist/decorators/payload.decorator.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/index.d.ts +4 -0
- package/dist/interfaces/index.js +21 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/message-handler.interface.d.ts +21 -0
- package/dist/interfaces/message-handler.interface.js +3 -0
- package/dist/interfaces/message-handler.interface.js.map +1 -0
- package/dist/interfaces/packet.interface.d.ts +42 -0
- package/dist/interfaces/packet.interface.js +3 -0
- package/dist/interfaces/packet.interface.js.map +1 -0
- package/dist/interfaces/transport-client.interface.d.ts +41 -0
- package/dist/interfaces/transport-client.interface.js +3 -0
- package/dist/interfaces/transport-client.interface.js.map +1 -0
- package/dist/interfaces/transport-server.interface.d.ts +44 -0
- package/dist/interfaces/transport-server.interface.js +3 -0
- package/dist/interfaces/transport-server.interface.js.map +1 -0
- package/dist/keys.d.ts +88 -0
- package/dist/keys.js +123 -0
- package/dist/keys.js.map +1 -0
- package/dist/registry/handler-registry.d.ts +77 -0
- package/dist/registry/handler-registry.js +265 -0
- package/dist/registry/handler-registry.js.map +1 -0
- package/dist/registry/index.d.ts +1 -0
- package/dist/registry/index.js +18 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/serializers/index.d.ts +1 -0
- package/dist/serializers/index.js +18 -0
- package/dist/serializers/index.js.map +1 -0
- package/dist/serializers/serializer.interface.d.ts +62 -0
- package/dist/serializers/serializer.interface.js +52 -0
- package/dist/serializers/serializer.interface.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +18 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/server-base.d.ts +154 -0
- package/dist/server/server-base.js +287 -0
- package/dist/server/server-base.js.map +1 -0
- package/dist/transport-booter.d.ts +31 -0
- package/dist/transport-booter.js +117 -0
- package/dist/transport-booter.js.map +1 -0
- package/dist/transport.component.d.ts +26 -0
- package/dist/transport.component.js +42 -0
- package/dist/transport.component.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/normalize-pattern.d.ts +18 -0
- package/dist/utils/normalize-pattern.js +75 -0
- package/dist/utils/normalize-pattern.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ServerBase = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const debug_1 = require("debug");
|
|
6
|
+
const serializers_1 = require("../serializers");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
const debug = (0, debug_1.default)('loopback:transport:server');
|
|
9
|
+
const DEFAULT_HANDLER_TIMEOUT_MS = 30000;
|
|
10
|
+
/**
|
|
11
|
+
* Abstract base class for transport servers.
|
|
12
|
+
*
|
|
13
|
+
* Manages the handler registry, message dispatching, and serialization.
|
|
14
|
+
* Each transport (Kafka, RabbitMQ, gRPC, MQTT, NATS) extends this
|
|
15
|
+
* class and implements listen/close/unwrap.
|
|
16
|
+
*
|
|
17
|
+
* Subclasses should:
|
|
18
|
+
* - Call deserializer.deserialize() on raw broker messages before
|
|
19
|
+
* passing them to handleMessage()/handleEvent()
|
|
20
|
+
* - Call serializer.serialize() on outbound responses
|
|
21
|
+
* - Call setStatus('connected') in listen() when ready
|
|
22
|
+
* - Call setStatus('disconnected') in close() when stopped
|
|
23
|
+
* - Call dispose() only when the server will never be restarted
|
|
24
|
+
*/
|
|
25
|
+
class ServerBase {
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.messageHandlers = new Map();
|
|
28
|
+
this.statusSubject = new rxjs_1.ReplaySubject(1);
|
|
29
|
+
this.status$ = this.statusSubject.asObservable();
|
|
30
|
+
this.serializer = options?.serializer ?? new serializers_1.JsonSerializer();
|
|
31
|
+
this.deserializer = options?.deserializer ?? new serializers_1.JsonDeserializer();
|
|
32
|
+
this.handlerTimeoutMs = options?.handlerTimeoutMs ?? DEFAULT_HANDLER_TIMEOUT_MS;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Emit a status change. Called by transport adapters in listen() and close().
|
|
36
|
+
*/
|
|
37
|
+
setStatus(status) {
|
|
38
|
+
this.statusSubject.next(status);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Permanently complete the status stream. After this call, no further
|
|
42
|
+
* status emissions are possible and the server instance cannot restart.
|
|
43
|
+
* Existing subscribers receive the complete notification.
|
|
44
|
+
*
|
|
45
|
+
* Call only when the server is being permanently disposed.
|
|
46
|
+
* Normal close() should call setStatus('disconnected'), NOT dispose().
|
|
47
|
+
*/
|
|
48
|
+
dispose() {
|
|
49
|
+
this.statusSubject.next('disconnected');
|
|
50
|
+
this.statusSubject.complete();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Register a handler for a message pattern.
|
|
54
|
+
*
|
|
55
|
+
* For request/response handlers (@messageHandler): duplicate patterns
|
|
56
|
+
* throw an error. Only one handler per pattern is allowed.
|
|
57
|
+
*
|
|
58
|
+
* For event handlers (@eventHandler): multiple handlers on the same
|
|
59
|
+
* pattern are stored in an array and all execute.
|
|
60
|
+
*
|
|
61
|
+
* Mixing @messageHandler and @eventHandler on the same pattern throws.
|
|
62
|
+
*
|
|
63
|
+
* Handlers are never mutated. Each server owns its own handler array,
|
|
64
|
+
* so the same handler object can be safely shared across servers.
|
|
65
|
+
*/
|
|
66
|
+
addHandler(pattern, handler) {
|
|
67
|
+
const normalized = this.normalizePattern(pattern);
|
|
68
|
+
const existing = this.messageHandlers.get(normalized);
|
|
69
|
+
if (existing) {
|
|
70
|
+
// Reject mixed handler types on the same pattern
|
|
71
|
+
if (existing[0].isEventHandler !== handler.isEventHandler) {
|
|
72
|
+
throw new Error(`Cannot mix @messageHandler and @eventHandler for pattern: ${normalized}. ` +
|
|
73
|
+
'A pattern must be exclusively request/response or event, not both.');
|
|
74
|
+
}
|
|
75
|
+
// Reject duplicate request/response handlers
|
|
76
|
+
if (!handler.isEventHandler) {
|
|
77
|
+
throw new Error(`Handler already registered for pattern: ${normalized}. ` +
|
|
78
|
+
'Only one @messageHandler per pattern is allowed. ' +
|
|
79
|
+
'Use @eventHandler for multiple handlers on the same pattern.');
|
|
80
|
+
}
|
|
81
|
+
// Append event handler to the array
|
|
82
|
+
existing.push(handler);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.messageHandlers.set(normalized, [handler]);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get all registered handlers. Returns a defensive copy.
|
|
89
|
+
*/
|
|
90
|
+
getHandlers() {
|
|
91
|
+
const copy = new Map();
|
|
92
|
+
for (const [key, handlers] of this.messageHandlers) {
|
|
93
|
+
copy.set(key, [...handlers]);
|
|
94
|
+
}
|
|
95
|
+
return copy;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Remove all registered handlers.
|
|
99
|
+
* Called before rebinding on restart to prevent duplicate registration.
|
|
100
|
+
*/
|
|
101
|
+
clearHandlers() {
|
|
102
|
+
this.messageHandlers.clear();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get handlers by pattern. Normalizes the pattern before lookup.
|
|
106
|
+
* Returns a defensive copy for external consumers.
|
|
107
|
+
*/
|
|
108
|
+
getHandlersByPattern(pattern) {
|
|
109
|
+
const handlers = this.lookupHandlers(pattern);
|
|
110
|
+
return handlers ? [...handlers] : undefined;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Internal handler lookup. Returns the live array for dispatch performance.
|
|
114
|
+
*/
|
|
115
|
+
lookupHandlers(pattern) {
|
|
116
|
+
return this.messageHandlers.get(this.normalizePattern(pattern));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Handle a request/response message.
|
|
120
|
+
*
|
|
121
|
+
* Invokes the handler and calls respond() with each result value.
|
|
122
|
+
* Observable subscriptions are tracked and cleaned up on completion,
|
|
123
|
+
* error, or timeout.
|
|
124
|
+
*
|
|
125
|
+
* Returns a HandlerResult that separates response semantics from
|
|
126
|
+
* broker settlement semantics:
|
|
127
|
+
*
|
|
128
|
+
* - `success`: Handler completed normally. Ack the message.
|
|
129
|
+
* - `handler-error`: Handler threw or Observable errored. The error
|
|
130
|
+
* response was already sent to the caller. Ack the message --
|
|
131
|
+
* the error was handled as an application-level response.
|
|
132
|
+
* - `infrastructure-error`: No handler found or framework failure.
|
|
133
|
+
* Nack/dead-letter the message.
|
|
134
|
+
*
|
|
135
|
+
* Observable handlers that do not complete within handlerTimeoutMs
|
|
136
|
+
* are terminated with a timeout error (handler-error).
|
|
137
|
+
*
|
|
138
|
+
* If respond() throws (adapter publication failure), the error is
|
|
139
|
+
* caught and returned as infrastructure-error.
|
|
140
|
+
*/
|
|
141
|
+
async handleMessage(request, respond, context) {
|
|
142
|
+
// Wrap respond to catch adapter publication failures
|
|
143
|
+
const safeRespond = (packet) => {
|
|
144
|
+
try {
|
|
145
|
+
respond(packet);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
debug('respond() failed for pattern [%s]: %O', request.pattern, err);
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
return await this.executeHandler(request, safeRespond, context);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
return { outcome: 'infrastructure-error', error: err };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Core handler execution. Separated from handleMessage so that
|
|
161
|
+
* respond() failures bubble up and are caught by the outer wrapper.
|
|
162
|
+
*/
|
|
163
|
+
async executeHandler(request, respond, context) {
|
|
164
|
+
const handlers = this.lookupHandlers(request.pattern);
|
|
165
|
+
if (!handlers || handlers.length === 0) {
|
|
166
|
+
const err = `No handler for pattern: ${request.pattern}`;
|
|
167
|
+
respond({ err: this.serializeError(err), isDisposed: true });
|
|
168
|
+
return { outcome: 'infrastructure-error', error: new Error(err) };
|
|
169
|
+
}
|
|
170
|
+
const handler = handlers[0];
|
|
171
|
+
let result;
|
|
172
|
+
try {
|
|
173
|
+
result = await handler(request.data, context);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
respond({ err: this.serializeError(err), isDisposed: true });
|
|
177
|
+
return { outcome: 'handler-error', error: err };
|
|
178
|
+
}
|
|
179
|
+
if ((0, rxjs_1.isObservable)(result)) {
|
|
180
|
+
const obs = result.pipe((0, rxjs_1.timeout)(this.handlerTimeoutMs));
|
|
181
|
+
return new Promise((resolve) => {
|
|
182
|
+
let settled = false;
|
|
183
|
+
const settle = (result) => {
|
|
184
|
+
if (settled)
|
|
185
|
+
return;
|
|
186
|
+
settled = true;
|
|
187
|
+
subscription?.unsubscribe();
|
|
188
|
+
resolve(result);
|
|
189
|
+
};
|
|
190
|
+
let subscription;
|
|
191
|
+
subscription = obs.subscribe({
|
|
192
|
+
next: value => {
|
|
193
|
+
if (settled)
|
|
194
|
+
return;
|
|
195
|
+
try {
|
|
196
|
+
respond({ response: value });
|
|
197
|
+
}
|
|
198
|
+
catch (respondErr) {
|
|
199
|
+
settle({ outcome: 'infrastructure-error', error: respondErr });
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
error: err => {
|
|
203
|
+
if (settled)
|
|
204
|
+
return;
|
|
205
|
+
if (err instanceof rxjs_1.TimeoutError) {
|
|
206
|
+
debug('handler timeout after %dms for pattern [%s]', this.handlerTimeoutMs, request.pattern);
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
respond({ err: this.serializeError(err), isDisposed: true });
|
|
210
|
+
}
|
|
211
|
+
catch (respondErr) {
|
|
212
|
+
settle({ outcome: 'infrastructure-error', error: respondErr });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
settle({ outcome: 'handler-error', error: err });
|
|
216
|
+
},
|
|
217
|
+
complete: () => {
|
|
218
|
+
if (settled)
|
|
219
|
+
return;
|
|
220
|
+
try {
|
|
221
|
+
respond({ isDisposed: true });
|
|
222
|
+
}
|
|
223
|
+
catch (respondErr) {
|
|
224
|
+
settle({ outcome: 'infrastructure-error', error: respondErr });
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
settle({ outcome: 'success' });
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
respond({ response: result, isDisposed: true });
|
|
233
|
+
return { outcome: 'success' };
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Handle a fire-and-forget event.
|
|
237
|
+
*
|
|
238
|
+
* Invokes all chained handlers for the pattern.
|
|
239
|
+
* Errors are logged but not propagated (fire-and-forget semantics).
|
|
240
|
+
*
|
|
241
|
+
* Observable event handlers that do not complete within handlerTimeoutMs
|
|
242
|
+
* are terminated and logged.
|
|
243
|
+
*/
|
|
244
|
+
async handleEvent(event, context) {
|
|
245
|
+
const handlers = this.lookupHandlers(event.pattern);
|
|
246
|
+
if (!handlers || handlers.length === 0)
|
|
247
|
+
return;
|
|
248
|
+
for (const handler of handlers) {
|
|
249
|
+
try {
|
|
250
|
+
const result = await handler(event.data, context);
|
|
251
|
+
if ((0, rxjs_1.isObservable)(result)) {
|
|
252
|
+
const obs = result.pipe((0, rxjs_1.timeout)(this.handlerTimeoutMs));
|
|
253
|
+
await (0, rxjs_1.lastValueFrom)(obs, { defaultValue: undefined });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
if (err instanceof rxjs_1.TimeoutError) {
|
|
258
|
+
debug('event handler timeout after %dms for pattern [%s]', this.handlerTimeoutMs, event.pattern);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
debug('event handler failed for pattern [%s]: %O', event.pattern, err);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Normalize a pattern to a consistent string key.
|
|
268
|
+
* Delegates to the shared normalizePattern utility.
|
|
269
|
+
*/
|
|
270
|
+
normalizePattern(pattern) {
|
|
271
|
+
return (0, utils_1.normalizePattern)(pattern);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Serialize an error to a string for transport.
|
|
275
|
+
*/
|
|
276
|
+
serializeError(err) {
|
|
277
|
+
if (err instanceof rxjs_1.TimeoutError)
|
|
278
|
+
return 'Handler timeout';
|
|
279
|
+
if (err instanceof Error)
|
|
280
|
+
return `${err.name}: ${err.message}`;
|
|
281
|
+
if (typeof err === 'string')
|
|
282
|
+
return err;
|
|
283
|
+
return String(err);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
exports.ServerBase = ServerBase;
|
|
287
|
+
//# sourceMappingURL=server-base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-base.js","sourceRoot":"","sources":["../../src/server/server-base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Application, LifeCycleObserver } from '@loopback/core';
|
|
2
|
+
import { HandlerRegistry } from './registry';
|
|
3
|
+
/**
|
|
4
|
+
* Lifecycle observer that discovers transport handlers after boot
|
|
5
|
+
* and starts/stops transport servers.
|
|
6
|
+
*
|
|
7
|
+
* Runs after all controllers are registered (boot phase complete).
|
|
8
|
+
* Scans controllers for @messageHandler/@eventHandler metadata,
|
|
9
|
+
* registers handlers with transport servers, then starts listeners.
|
|
10
|
+
*
|
|
11
|
+
* Startup behavior: sequential with deterministic rollback.
|
|
12
|
+
* Servers start one at a time. If any fails, all previously started
|
|
13
|
+
* servers are rolled back. No race between concurrent starts.
|
|
14
|
+
*
|
|
15
|
+
* Shutdown behavior: best-effort parallel. All servers stop concurrently.
|
|
16
|
+
* Individual errors are logged but don't prevent other servers from stopping.
|
|
17
|
+
*
|
|
18
|
+
* Restart safety: servers are cleared of handlers before rebinding
|
|
19
|
+
* to prevent duplicate registration on stop/start cycles.
|
|
20
|
+
*/
|
|
21
|
+
export declare class TransportBooter implements LifeCycleObserver {
|
|
22
|
+
private app;
|
|
23
|
+
private registry;
|
|
24
|
+
constructor(app: Application, registry: HandlerRegistry);
|
|
25
|
+
start(): Promise<void>;
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve all registered transport servers with their names.
|
|
29
|
+
*/
|
|
30
|
+
private getServerEntries;
|
|
31
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.TransportBooter = void 0;
|
|
16
|
+
const core_1 = require("@loopback/core");
|
|
17
|
+
const debug_1 = require("debug");
|
|
18
|
+
const registry_1 = require("./registry");
|
|
19
|
+
const keys_1 = require("./keys");
|
|
20
|
+
const debug = (0, debug_1.default)('loopback:transport:booter');
|
|
21
|
+
/**
|
|
22
|
+
* Lifecycle observer that discovers transport handlers after boot
|
|
23
|
+
* and starts/stops transport servers.
|
|
24
|
+
*
|
|
25
|
+
* Runs after all controllers are registered (boot phase complete).
|
|
26
|
+
* Scans controllers for @messageHandler/@eventHandler metadata,
|
|
27
|
+
* registers handlers with transport servers, then starts listeners.
|
|
28
|
+
*
|
|
29
|
+
* Startup behavior: sequential with deterministic rollback.
|
|
30
|
+
* Servers start one at a time. If any fails, all previously started
|
|
31
|
+
* servers are rolled back. No race between concurrent starts.
|
|
32
|
+
*
|
|
33
|
+
* Shutdown behavior: best-effort parallel. All servers stop concurrently.
|
|
34
|
+
* Individual errors are logged but don't prevent other servers from stopping.
|
|
35
|
+
*
|
|
36
|
+
* Restart safety: servers are cleared of handlers before rebinding
|
|
37
|
+
* to prevent duplicate registration on stop/start cycles.
|
|
38
|
+
*/
|
|
39
|
+
let TransportBooter = class TransportBooter {
|
|
40
|
+
constructor(app, registry) {
|
|
41
|
+
this.app = app;
|
|
42
|
+
this.registry = registry;
|
|
43
|
+
}
|
|
44
|
+
async start() {
|
|
45
|
+
debug('transport booter starting');
|
|
46
|
+
// Discover handlers from controllers (idempotent: clears first)
|
|
47
|
+
await this.registry.discoverHandlers(this.app);
|
|
48
|
+
// Clear existing handlers from servers before rebinding
|
|
49
|
+
const entries = await this.getServerEntries();
|
|
50
|
+
for (const { server } of entries) {
|
|
51
|
+
server.clearHandlers();
|
|
52
|
+
}
|
|
53
|
+
// Bind handlers to transport servers
|
|
54
|
+
await this.registry.bindToServers(this.app);
|
|
55
|
+
// Start servers sequentially for deterministic rollback
|
|
56
|
+
const started = [];
|
|
57
|
+
try {
|
|
58
|
+
for (const { name, server } of entries) {
|
|
59
|
+
await server.listen();
|
|
60
|
+
started.push({ name, server });
|
|
61
|
+
debug('transport server [%s] started', name);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
debug('startup failed, rolling back %d started servers', started.length);
|
|
66
|
+
for (const { name, server } of started.reverse()) {
|
|
67
|
+
try {
|
|
68
|
+
await server.close();
|
|
69
|
+
debug('transport server [%s] rolled back', name);
|
|
70
|
+
}
|
|
71
|
+
catch (closeErr) {
|
|
72
|
+
debug('transport server [%s] rollback failed: %O', name, closeErr);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
debug('transport booter started (%d handlers, %d servers)', this.registry.getHandlers().size, entries.length);
|
|
78
|
+
}
|
|
79
|
+
async stop() {
|
|
80
|
+
debug('transport booter stopping');
|
|
81
|
+
const entries = await this.getServerEntries();
|
|
82
|
+
const results = await Promise.allSettled(entries.map(async ({ name, server }) => {
|
|
83
|
+
await server.close();
|
|
84
|
+
debug('transport server [%s] stopped', name);
|
|
85
|
+
}));
|
|
86
|
+
const failures = results.filter((r) => r.status === 'rejected');
|
|
87
|
+
if (failures.length > 0) {
|
|
88
|
+
debug('%d transport server(s) failed to stop cleanly', failures.length);
|
|
89
|
+
for (const failure of failures) {
|
|
90
|
+
debug('transport server shutdown failure: %O', failure.reason);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
debug('transport booter stopped');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve all registered transport servers with their names.
|
|
97
|
+
*/
|
|
98
|
+
async getServerEntries() {
|
|
99
|
+
const bindings = this.app.findByTag(keys_1.TRANSPORT_SERVER_TAG);
|
|
100
|
+
const entries = [];
|
|
101
|
+
for (const binding of bindings) {
|
|
102
|
+
const server = await this.app.get(binding.key);
|
|
103
|
+
const name = String(binding.tagMap?.[keys_1.TRANSPORT_NAME_TAG] ?? binding.key);
|
|
104
|
+
entries.push({ name, server });
|
|
105
|
+
}
|
|
106
|
+
return entries;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
exports.TransportBooter = TransportBooter;
|
|
110
|
+
exports.TransportBooter = TransportBooter = __decorate([
|
|
111
|
+
(0, core_1.lifeCycleObserver)('transport'),
|
|
112
|
+
__param(0, (0, core_1.inject)(core_1.CoreBindings.APPLICATION_INSTANCE)),
|
|
113
|
+
__param(1, (0, core_1.inject)(keys_1.TransportBindings.HANDLER_REGISTRY)),
|
|
114
|
+
__metadata("design:paramtypes", [core_1.Application,
|
|
115
|
+
registry_1.HandlerRegistry])
|
|
116
|
+
], TransportBooter);
|
|
117
|
+
//# sourceMappingURL=transport-booter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport-booter.js","sourceRoot":"","sources":["../src/transport-booter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Binding, Component, Constructor, LifeCycleObserver } from '@loopback/core';
|
|
2
|
+
/**
|
|
3
|
+
* LoopBack 4 component that enables transport-agnostic microservices.
|
|
4
|
+
*
|
|
5
|
+
* Registers the core transport extension points:
|
|
6
|
+
* - HandlerRegistry (singleton): discovers and manages transport handlers
|
|
7
|
+
* - TransportBooter (lifecycle observer): wires handlers to servers at boot
|
|
8
|
+
*
|
|
9
|
+
* The component intentionally stays thin. Discovery, validation,
|
|
10
|
+
* server binding, and listener lifecycle management live in the
|
|
11
|
+
* TransportBooter/HandlerRegistry layer so the component remains a
|
|
12
|
+
* stable package boundary for transport adapters.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const app = new Application();
|
|
17
|
+
* app.component(TransportComponent);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Transport adapters can build on top of this component by contributing
|
|
21
|
+
* server bindings and configuration under TransportBindings.
|
|
22
|
+
*/
|
|
23
|
+
export declare class TransportComponent implements Component {
|
|
24
|
+
readonly bindings: Binding<unknown>[];
|
|
25
|
+
readonly lifeCycleObservers: Constructor<LifeCycleObserver>[];
|
|
26
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransportComponent = void 0;
|
|
4
|
+
const core_1 = require("@loopback/core");
|
|
5
|
+
const keys_1 = require("./keys");
|
|
6
|
+
const registry_1 = require("./registry");
|
|
7
|
+
const transport_booter_1 = require("./transport-booter");
|
|
8
|
+
/**
|
|
9
|
+
* LoopBack 4 component that enables transport-agnostic microservices.
|
|
10
|
+
*
|
|
11
|
+
* Registers the core transport extension points:
|
|
12
|
+
* - HandlerRegistry (singleton): discovers and manages transport handlers
|
|
13
|
+
* - TransportBooter (lifecycle observer): wires handlers to servers at boot
|
|
14
|
+
*
|
|
15
|
+
* The component intentionally stays thin. Discovery, validation,
|
|
16
|
+
* server binding, and listener lifecycle management live in the
|
|
17
|
+
* TransportBooter/HandlerRegistry layer so the component remains a
|
|
18
|
+
* stable package boundary for transport adapters.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const app = new Application();
|
|
23
|
+
* app.component(TransportComponent);
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Transport adapters can build on top of this component by contributing
|
|
27
|
+
* server bindings and configuration under TransportBindings.
|
|
28
|
+
*/
|
|
29
|
+
class TransportComponent {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.bindings = [
|
|
32
|
+
core_1.Binding.bind(keys_1.TransportBindings.HANDLER_REGISTRY)
|
|
33
|
+
.toClass(registry_1.HandlerRegistry)
|
|
34
|
+
.inScope(core_1.BindingScope.SINGLETON),
|
|
35
|
+
];
|
|
36
|
+
this.lifeCycleObservers = [
|
|
37
|
+
transport_booter_1.TransportBooter,
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.TransportComponent = TransportComponent;
|
|
42
|
+
//# sourceMappingURL=transport.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.component.js","sourceRoot":"","sources":["../src/transport.component.ts"],"names":[],"mappings":";;;AAAA,yCAMwB;AACxB,iCAAyC;AACzC,yCAA2C;AAC3C,yDAAmD;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAa,kBAAkB;IAA/B;QACW,aAAQ,GAAuB;YACtC,cAAO,CAAC,IAAI,CAAC,wBAAiB,CAAC,gBAAgB,CAAC;iBAC7C,OAAO,CAAC,0BAAe,CAAC;iBACxB,OAAO,CAAC,mBAAY,CAAC,SAAS,CAAC;SACnC,CAAC;QAEO,uBAAkB,GAAqC;YAC9D,kCAAe;SAChB,CAAC;IACJ,CAAC;CAAA;AAVD,gDAUC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { normalizePattern } from './normalize-pattern';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizePattern = void 0;
|
|
4
|
+
var normalize_pattern_1 = require("./normalize-pattern");
|
|
5
|
+
Object.defineProperty(exports, "normalizePattern", { enumerable: true, get: function () { return normalize_pattern_1.normalizePattern; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;AAAA,yDAAqD;AAA7C,qHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize a pattern to a consistent string key.
|
|
3
|
+
*
|
|
4
|
+
* Strings pass through as-is. Objects are deep-sorted by key
|
|
5
|
+
* and JSON-stringified for consistent lookup regardless of
|
|
6
|
+
* property insertion order.
|
|
7
|
+
*
|
|
8
|
+
* Only JSON-compatible values are accepted: strings, finite numbers,
|
|
9
|
+
* booleans, null, plain objects, and arrays. Non-JSON values
|
|
10
|
+
* (undefined, functions, symbols, NaN, Infinity, BigInt, Date,
|
|
11
|
+
* RegExp, Map, Set, class instances) are rejected deterministically.
|
|
12
|
+
*
|
|
13
|
+
* Shared (non-circular) object references are allowed. Only true
|
|
14
|
+
* cycles throw.
|
|
15
|
+
*
|
|
16
|
+
* @throws Error on circular references, non-JSON values, or non-plain objects.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizePattern(pattern: string | Record<string, unknown>): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizePattern = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Normalize a pattern to a consistent string key.
|
|
6
|
+
*
|
|
7
|
+
* Strings pass through as-is. Objects are deep-sorted by key
|
|
8
|
+
* and JSON-stringified for consistent lookup regardless of
|
|
9
|
+
* property insertion order.
|
|
10
|
+
*
|
|
11
|
+
* Only JSON-compatible values are accepted: strings, finite numbers,
|
|
12
|
+
* booleans, null, plain objects, and arrays. Non-JSON values
|
|
13
|
+
* (undefined, functions, symbols, NaN, Infinity, BigInt, Date,
|
|
14
|
+
* RegExp, Map, Set, class instances) are rejected deterministically.
|
|
15
|
+
*
|
|
16
|
+
* Shared (non-circular) object references are allowed. Only true
|
|
17
|
+
* cycles throw.
|
|
18
|
+
*
|
|
19
|
+
* @throws Error on circular references, non-JSON values, or non-plain objects.
|
|
20
|
+
*/
|
|
21
|
+
function normalizePattern(pattern) {
|
|
22
|
+
if (typeof pattern === 'string')
|
|
23
|
+
return pattern;
|
|
24
|
+
return stableStringify(pattern, new Set());
|
|
25
|
+
}
|
|
26
|
+
exports.normalizePattern = normalizePattern;
|
|
27
|
+
function isPlainObject(obj) {
|
|
28
|
+
if (typeof obj !== 'object' || obj === null)
|
|
29
|
+
return false;
|
|
30
|
+
const proto = Object.getPrototypeOf(obj);
|
|
31
|
+
return proto === Object.prototype || proto === null;
|
|
32
|
+
}
|
|
33
|
+
function stableStringify(obj, seen) {
|
|
34
|
+
if (obj === null)
|
|
35
|
+
return 'null';
|
|
36
|
+
const type = typeof obj;
|
|
37
|
+
if (type === 'string' || type === 'boolean') {
|
|
38
|
+
return JSON.stringify(obj);
|
|
39
|
+
}
|
|
40
|
+
if (type === 'number') {
|
|
41
|
+
const n = obj;
|
|
42
|
+
if (!Number.isFinite(n)) {
|
|
43
|
+
throw new Error(`Pattern contains ${String(n)}, which is not JSON-serializable`);
|
|
44
|
+
}
|
|
45
|
+
return JSON.stringify(n);
|
|
46
|
+
}
|
|
47
|
+
if (type === 'undefined' ||
|
|
48
|
+
type === 'function' ||
|
|
49
|
+
type === 'symbol' ||
|
|
50
|
+
type === 'bigint') {
|
|
51
|
+
throw new Error(`Pattern contains ${type} value, which is not JSON-serializable`);
|
|
52
|
+
}
|
|
53
|
+
// At this point, type === 'object' and obj !== null
|
|
54
|
+
const o = obj;
|
|
55
|
+
if (seen.has(o)) {
|
|
56
|
+
throw new Error('Circular reference detected in pattern object');
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(o)) {
|
|
59
|
+
seen.add(o);
|
|
60
|
+
const result = '[' + o.map(item => stableStringify(item, seen)).join(',') + ']';
|
|
61
|
+
seen.delete(o);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
if (!isPlainObject(o)) {
|
|
65
|
+
const name = o.constructor?.name ?? 'unknown';
|
|
66
|
+
throw new Error(`Pattern contains ${name} instance, which is not a plain object`);
|
|
67
|
+
}
|
|
68
|
+
seen.add(o);
|
|
69
|
+
const keys = Object.keys(o).sort();
|
|
70
|
+
const pairs = keys.map(key => `${JSON.stringify(key)}:${stableStringify(o[key], seen)}`);
|
|
71
|
+
const result = '{' + pairs.join(',') + '}';
|
|
72
|
+
seen.delete(o);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=normalize-pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-pattern.js","sourceRoot":"","sources":["../../src/utils/normalize-pattern.ts"],"names":[],"mappings":"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"}
|