@zlink-systems/nestjs 0.10.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 +105 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/auto-discovery-marker.d.ts +3 -0
- package/dist/auto-discovery-marker.js +12 -0
- package/dist/contracts.d.ts +229 -0
- package/dist/contracts.js +4 -0
- package/dist/decorators.d.ts +16 -0
- package/dist/decorators.js +174 -0
- package/dist/dispatch-scope.d.ts +5 -0
- package/dist/dispatch-scope.js +19 -0
- package/dist/drain-health-indicator.d.ts +9 -0
- package/dist/drain-health-indicator.js +32 -0
- package/dist/framework-integration-contracts.d.ts +368 -0
- package/dist/framework-integration-contracts.js +2 -0
- package/dist/framework-loader.d.ts +50 -0
- package/dist/framework-loader.js +16 -0
- package/dist/handler-adapters.d.ts +13 -0
- package/dist/handler-adapters.js +155 -0
- package/dist/handler-metadata.d.ts +55 -0
- package/dist/handler-metadata.js +84 -0
- package/dist/http-client-module.d.ts +28 -0
- package/dist/http-client-module.js +96 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +27 -0
- package/dist/internal-tokens.d.ts +2 -0
- package/dist/internal-tokens.js +5 -0
- package/dist/module.d.ts +11 -0
- package/dist/module.js +203 -0
- package/dist/options-builder.d.ts +2 -0
- package/dist/options-builder.js +973 -0
- package/dist/provider-discovery.d.ts +36 -0
- package/dist/provider-discovery.js +186 -0
- package/dist/providers.d.ts +16 -0
- package/dist/providers.js +426 -0
- package/dist/registration-composer.d.ts +7 -0
- package/dist/registration-composer.js +310 -0
- package/dist/spot-node-handler-registry.d.ts +24 -0
- package/dist/spot-node-handler-registry.js +105 -0
- package/dist/tokens.d.ts +19 -0
- package/dist/tokens.js +22 -0
- package/package.json +26 -0
|
@@ -0,0 +1,973 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createZLinkNestFrameworkOptionsBuilder = createZLinkNestFrameworkOptionsBuilder;
|
|
4
|
+
const framework_1 = require("@zlink-systems/framework");
|
|
5
|
+
const contracts_1 = require("./contracts");
|
|
6
|
+
const framework_loader_1 = require("./framework-loader");
|
|
7
|
+
function createBuilderState() {
|
|
8
|
+
const codecOptions = { serializers: [], streamCodecs: [] };
|
|
9
|
+
return {
|
|
10
|
+
additionalOptions: {},
|
|
11
|
+
implicitHandlerAutoRegistration: true,
|
|
12
|
+
clientServerChannels: {},
|
|
13
|
+
fanoutChannels: {},
|
|
14
|
+
streams: {},
|
|
15
|
+
spotNodes: {},
|
|
16
|
+
codecOptions,
|
|
17
|
+
codecRegistry: framework_loader_1.framework.createIntegrationCodecRegistryBuilder(codecOptions)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function registerSerializer(state, contentType, serializer, canSerialize) {
|
|
21
|
+
if (canSerialize === undefined) {
|
|
22
|
+
state.codecRegistry.addSerializer(contentType, serializer);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
state.codecRegistry.addSerializer(contentType, serializer, canSerialize);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function registerStreamCodec(state, contentType, codec) {
|
|
29
|
+
state.codecRegistry.addStreamCodec(contentType, codec);
|
|
30
|
+
}
|
|
31
|
+
function ensureChannelAvailable(state, name) {
|
|
32
|
+
if (name.trim().length === 0 || name.trim() !== name) {
|
|
33
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Channel name must not be empty or padded.');
|
|
34
|
+
}
|
|
35
|
+
if (Object.prototype.hasOwnProperty.call(state.fanoutChannels, name)
|
|
36
|
+
|| Object.prototype.hasOwnProperty.call(state.clientServerChannels, name)) {
|
|
37
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Duplicate channel '${name}'.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function ensureClientServerChannelAvailable(state, name) {
|
|
41
|
+
if (name.trim().length === 0 || name.trim() !== name) {
|
|
42
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Channel name must not be empty or padded.');
|
|
43
|
+
}
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(state.fanoutChannels, name)) {
|
|
45
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Duplicate channel '${name}'.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class ZLinkNestOptionsBuilder {
|
|
49
|
+
state;
|
|
50
|
+
constructor(state) {
|
|
51
|
+
this.state = state;
|
|
52
|
+
}
|
|
53
|
+
options(options) {
|
|
54
|
+
this.state.additionalOptions = { ...this.state.additionalOptions, ...options };
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
disableImplicitHandlerAutoRegistration() {
|
|
58
|
+
this.state.implicitHandlerAutoRegistration = false;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
codecs() {
|
|
62
|
+
return new DefaultZLinkNestCodecRegistryBuilder(this.state);
|
|
63
|
+
}
|
|
64
|
+
configureDispatch() {
|
|
65
|
+
this.state.additionalOptions = {
|
|
66
|
+
...this.state.additionalOptions,
|
|
67
|
+
dispatch: this.state.additionalOptions.dispatch ?? {
|
|
68
|
+
unhandled: {
|
|
69
|
+
request: framework_1.ZLinkUnhandledDispatchAction.ReplyError,
|
|
70
|
+
send: framework_1.ZLinkUnhandledDispatchAction.LogAndDrop,
|
|
71
|
+
publish: framework_1.ZLinkUnhandledDispatchAction.LogAndDrop
|
|
72
|
+
},
|
|
73
|
+
diagnostics: {
|
|
74
|
+
messageFlow: 'errors',
|
|
75
|
+
sampleRate: 1,
|
|
76
|
+
includeMessageSizes: false
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return framework_loader_1.framework.createIntegrationDispatchOptionsBuilder(this.state.additionalOptions.dispatch);
|
|
81
|
+
}
|
|
82
|
+
configureInboundDispatch() {
|
|
83
|
+
const options = { ...this.state.additionalOptions };
|
|
84
|
+
this.state.additionalOptions = options;
|
|
85
|
+
return framework_loader_1.framework.createIntegrationInboundDispatchOptionsBuilder(options);
|
|
86
|
+
}
|
|
87
|
+
addLocationStore(store) {
|
|
88
|
+
this.state.additionalOptions = {
|
|
89
|
+
...this.state.additionalOptions,
|
|
90
|
+
locations: {
|
|
91
|
+
...(this.state.additionalOptions.locations ?? {}),
|
|
92
|
+
storeInstance: store
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
addRelocationStore(store) {
|
|
98
|
+
this.state.additionalOptions = {
|
|
99
|
+
...this.state.additionalOptions,
|
|
100
|
+
locations: {
|
|
101
|
+
...(this.state.additionalOptions.locations ?? {}),
|
|
102
|
+
relocationStoreInstance: store
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
setApplicationVersion(version) {
|
|
108
|
+
this.state.additionalOptions = {
|
|
109
|
+
...this.state.additionalOptions,
|
|
110
|
+
applicationVersion: version
|
|
111
|
+
};
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
setMaintenanceWave(waveId) {
|
|
115
|
+
this.state.additionalOptions = {
|
|
116
|
+
...this.state.additionalOptions,
|
|
117
|
+
maintenanceWave: waveId
|
|
118
|
+
};
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
setActorTransferTimeout(timeoutMs) {
|
|
122
|
+
this.state.additionalOptions = {
|
|
123
|
+
...this.state.additionalOptions,
|
|
124
|
+
actorTransferTimeoutMs: framework_loader_1.framework.validateActorTransferTimeout(timeoutMs)
|
|
125
|
+
};
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
setMessageFollowDuration(timeoutMs) {
|
|
129
|
+
this.state.additionalOptions = {
|
|
130
|
+
...this.state.additionalOptions,
|
|
131
|
+
messageFollowDurationMs: framework_loader_1.framework.validateMessageFollowDuration(timeoutMs)
|
|
132
|
+
};
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
setSessionReplacementCallbackTimeout(timeoutMs) {
|
|
136
|
+
this.state.additionalOptions = {
|
|
137
|
+
...this.state.additionalOptions,
|
|
138
|
+
sessionReplacementCallbackTimeoutMs: framework_loader_1.framework.validateSessionReplacementCallbackTimeout(timeoutMs)
|
|
139
|
+
};
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
configureStreamCompression() {
|
|
143
|
+
const compression = { ...(this.state.additionalOptions.streamCompression ?? {}) };
|
|
144
|
+
this.state.additionalOptions = { ...this.state.additionalOptions, streamCompression: compression };
|
|
145
|
+
return framework_loader_1.framework.createIntegrationStreamCompressionBuilder(compression);
|
|
146
|
+
}
|
|
147
|
+
configureLocations() {
|
|
148
|
+
this.state.additionalOptions = {
|
|
149
|
+
...this.state.additionalOptions,
|
|
150
|
+
locations: this.state.additionalOptions.locations ?? { options: {} }
|
|
151
|
+
};
|
|
152
|
+
const locations = this.state.additionalOptions.locations;
|
|
153
|
+
locations.options ??= {};
|
|
154
|
+
return framework_loader_1.framework.createIntegrationLocationOptionsBuilder(locations.options);
|
|
155
|
+
}
|
|
156
|
+
configureNetwork() {
|
|
157
|
+
const network = {
|
|
158
|
+
bindHost: '127.0.0.1',
|
|
159
|
+
...(this.state.additionalOptions.network ?? {})
|
|
160
|
+
};
|
|
161
|
+
this.state.additionalOptions = {
|
|
162
|
+
...this.state.additionalOptions,
|
|
163
|
+
network
|
|
164
|
+
};
|
|
165
|
+
return network;
|
|
166
|
+
}
|
|
167
|
+
addFanoutChannel(name) {
|
|
168
|
+
ensureChannelAvailable(this.state, name);
|
|
169
|
+
this.state.fanoutChannels[name] = {};
|
|
170
|
+
return new DefaultZLinkNestFanoutChannelBuilder(this.state, name, this.state.fanoutChannels[name]);
|
|
171
|
+
}
|
|
172
|
+
addClientServerChannel(name) {
|
|
173
|
+
ensureClientServerChannelAvailable(this.state, name);
|
|
174
|
+
this.state.clientServerChannels[name] ??= {};
|
|
175
|
+
return new DefaultZLinkNestClientServerChannelRoleBuilder(this.state, name, this.state.clientServerChannels[name]);
|
|
176
|
+
}
|
|
177
|
+
addRouteMesh(name) {
|
|
178
|
+
if (name.trim().length === 0 || name.trim() !== name) {
|
|
179
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('RouteMesh name must not be empty or padded.');
|
|
180
|
+
}
|
|
181
|
+
if (Object.prototype.hasOwnProperty.call(this.state.spotNodes, name)) {
|
|
182
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Duplicate RouteMesh '${name}'.`);
|
|
183
|
+
}
|
|
184
|
+
this.state.spotNodes[name] = { router: { port: 0 } };
|
|
185
|
+
return new DefaultZLinkNestMeshNodeBuilder(this.state, name, this.state.spotNodes[name]);
|
|
186
|
+
}
|
|
187
|
+
addStreamNode(name) {
|
|
188
|
+
this.state.streams[name] ??= {};
|
|
189
|
+
return new DefaultZLinkNestStreamNodeBuilder(this.state, this.state.streams[name]);
|
|
190
|
+
}
|
|
191
|
+
build() {
|
|
192
|
+
const options = {
|
|
193
|
+
[contracts_1.ZLINK_MODULE_OPTIONS_BRAND]: true,
|
|
194
|
+
implicitHandlerAutoRegistration: this.state.implicitHandlerAutoRegistration,
|
|
195
|
+
...this.state.additionalOptions,
|
|
196
|
+
clientServerChannels: { ...this.state.clientServerChannels },
|
|
197
|
+
fanoutChannels: { ...this.state.fanoutChannels },
|
|
198
|
+
streams: { ...this.state.streams },
|
|
199
|
+
spotNodes: { ...this.state.spotNodes },
|
|
200
|
+
codecs: this.state.codecOptions.serializers.length === 0 &&
|
|
201
|
+
this.state.codecOptions.streamCodecs.length === 0
|
|
202
|
+
? undefined
|
|
203
|
+
: {
|
|
204
|
+
serializers: [...this.state.codecOptions.serializers],
|
|
205
|
+
streamCodecs: [...this.state.codecOptions.streamCodecs]
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
return options;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
class DefaultZLinkNestFrameworkOptionsBuilder extends ZLinkNestOptionsBuilder {
|
|
212
|
+
constructor() {
|
|
213
|
+
super(createBuilderState());
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
class DefaultZLinkNestCodecRegistryBuilder extends ZLinkNestOptionsBuilder {
|
|
217
|
+
constructor(state) {
|
|
218
|
+
super(state);
|
|
219
|
+
}
|
|
220
|
+
addSerializer(contentType, serializer, canSerialize) {
|
|
221
|
+
registerSerializer(this.state, contentType, serializer, canSerialize);
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
addStreamCodec(contentType, codec) {
|
|
225
|
+
if (contentType.trim().length === 0) {
|
|
226
|
+
throw new Error('Codec content type must not be empty.');
|
|
227
|
+
}
|
|
228
|
+
registerStreamCodec(this.state, contentType, codec);
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
use(extension) {
|
|
232
|
+
extension.register(this);
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
class DefaultZLinkNestFanoutChannelBuilder extends ZLinkNestOptionsBuilder {
|
|
237
|
+
name;
|
|
238
|
+
channelOptions;
|
|
239
|
+
subscriberMode;
|
|
240
|
+
constructor(state, name, channelOptions) {
|
|
241
|
+
super(state);
|
|
242
|
+
this.name = name;
|
|
243
|
+
this.channelOptions = channelOptions;
|
|
244
|
+
}
|
|
245
|
+
enablePublisher(endpointOrPort) {
|
|
246
|
+
this.channelOptions.publisher = typeof endpointOrPort === 'string'
|
|
247
|
+
? { bind: endpointOrPort }
|
|
248
|
+
: { port: requireListenerPort(endpointOrPort, `Fanout channel '${this.name}' publisher`) };
|
|
249
|
+
return this;
|
|
250
|
+
}
|
|
251
|
+
setBindHost(bindHost) {
|
|
252
|
+
requireClientServerText(bindHost, `Fanout channel '${this.name}' publisher bind host`);
|
|
253
|
+
this.updatePublisher({ bindHost });
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
setAdvertiseHost(advertiseHost) {
|
|
257
|
+
requireClientServerText(advertiseHost, `Fanout channel '${this.name}' publisher advertise host`);
|
|
258
|
+
this.updatePublisher({ advertiseHost });
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
routingId(routingId) {
|
|
262
|
+
rejectGeneratedRoutingId(this.channelOptions.routingIdPrefix, this.name);
|
|
263
|
+
this.channelOptions.routingId = routingId;
|
|
264
|
+
return this;
|
|
265
|
+
}
|
|
266
|
+
setRoutingIdPrefix(prefix) {
|
|
267
|
+
rejectFixedRoutingId(this.channelOptions.routingId, this.name);
|
|
268
|
+
this.channelOptions.routingIdPrefix = framework_loader_1.framework.validateRoutingIdPrefix(prefix);
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
enableSubscriber(endpoint) {
|
|
272
|
+
const mode = endpoint === undefined ? 'automatic' : 'manual';
|
|
273
|
+
if (this.subscriberMode !== undefined && this.subscriberMode !== mode) {
|
|
274
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Fanout channel '${this.name}' cannot combine automatic and manual subscriber sources.`);
|
|
275
|
+
}
|
|
276
|
+
this.subscriberMode = mode;
|
|
277
|
+
this.channelOptions.subscriber = endpoint === undefined ? {} : { manualConnections: endpointList(endpoint) };
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
addHandlerGroup(groupName) {
|
|
281
|
+
this.channelOptions.handlerGroups = [...(this.channelOptions.handlerGroups ?? []), groupName];
|
|
282
|
+
return this;
|
|
283
|
+
}
|
|
284
|
+
addPublishHandler(packetName, handlerType) {
|
|
285
|
+
this.channelOptions.publishHandlerTypes = [...(this.channelOptions.publishHandlerTypes ?? []), { packetName, handlerType }];
|
|
286
|
+
return this;
|
|
287
|
+
}
|
|
288
|
+
updatePublisher(values) {
|
|
289
|
+
if (this.channelOptions.publisher === undefined) {
|
|
290
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Fanout channel '${this.name}' publisher must be enabled before configuring its listener.`);
|
|
291
|
+
}
|
|
292
|
+
this.channelOptions.publisher = { ...this.channelOptions.publisher, ...values };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
class DefaultZLinkNestClientServerChannelRoleBuilder extends ZLinkNestOptionsBuilder {
|
|
296
|
+
name;
|
|
297
|
+
channel;
|
|
298
|
+
constructor(state, name, channel) {
|
|
299
|
+
super(state);
|
|
300
|
+
this.name = name;
|
|
301
|
+
this.channel = channel;
|
|
302
|
+
}
|
|
303
|
+
client() {
|
|
304
|
+
if (this.channel.client !== undefined) {
|
|
305
|
+
throw this.duplicate('Client');
|
|
306
|
+
}
|
|
307
|
+
this.channel.client = { manualConnections: [] };
|
|
308
|
+
return new DefaultZLinkNestClientServerChannelClientBuilder(this.state, this.name, this.channel);
|
|
309
|
+
}
|
|
310
|
+
server() {
|
|
311
|
+
if (this.channel.server !== undefined) {
|
|
312
|
+
throw this.duplicate('Server');
|
|
313
|
+
}
|
|
314
|
+
this.channel.server = {};
|
|
315
|
+
return new DefaultZLinkNestClientServerChannelServerBuilder(this.state, this.name, this.channel);
|
|
316
|
+
}
|
|
317
|
+
duplicate(role) {
|
|
318
|
+
return new framework_loader_1.framework.ZLinkConfigurationException(`ClientServer channel '${this.name}' ${role} role is already registered.`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
class DefaultZLinkNestClientServerChannelClientBuilder extends ZLinkNestOptionsBuilder {
|
|
322
|
+
name;
|
|
323
|
+
channel;
|
|
324
|
+
constructor(state, name, channel) {
|
|
325
|
+
super(state);
|
|
326
|
+
this.name = name;
|
|
327
|
+
this.channel = channel;
|
|
328
|
+
}
|
|
329
|
+
connect(endpoint) {
|
|
330
|
+
requireClientServerText(endpoint, `ClientServer channel '${this.name}' endpoint`);
|
|
331
|
+
const connections = [...(this.channel.client?.manualConnections ?? [])];
|
|
332
|
+
if (!connections.includes(endpoint))
|
|
333
|
+
connections.push(endpoint);
|
|
334
|
+
this.channel.client = { ...this.channel.client, manualConnections: connections };
|
|
335
|
+
return this;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
class DefaultZLinkNestClientServerChannelServerBuilder extends ZLinkNestOptionsBuilder {
|
|
339
|
+
name;
|
|
340
|
+
channel;
|
|
341
|
+
constructor(state, name, channel) {
|
|
342
|
+
super(state);
|
|
343
|
+
this.name = name;
|
|
344
|
+
this.channel = channel;
|
|
345
|
+
}
|
|
346
|
+
listen(port = 0) {
|
|
347
|
+
if (!Number.isInteger(port) || port < 0 || port > 65_535) {
|
|
348
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`ClientServer channel '${this.name}' port must be between 0 and 65535.`);
|
|
349
|
+
}
|
|
350
|
+
this.updateServer({ port });
|
|
351
|
+
this.updateBind();
|
|
352
|
+
return this;
|
|
353
|
+
}
|
|
354
|
+
setBindHost(bindHost) {
|
|
355
|
+
requireClientServerText(bindHost, `ClientServer channel '${this.name}' bind host`);
|
|
356
|
+
this.updateServer({ bindHost });
|
|
357
|
+
if (this.server.port !== undefined)
|
|
358
|
+
this.updateBind();
|
|
359
|
+
return this;
|
|
360
|
+
}
|
|
361
|
+
setAdvertiseHost(advertiseHost) {
|
|
362
|
+
requireClientServerText(advertiseHost, `ClientServer channel '${this.name}' advertise host`);
|
|
363
|
+
this.updateServer({ advertiseHost });
|
|
364
|
+
return this;
|
|
365
|
+
}
|
|
366
|
+
setWeight(weight) {
|
|
367
|
+
if (!Number.isInteger(weight) || weight < 0 || weight > 10_000) {
|
|
368
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`ClientServer channel '${this.name}' weight must be between 0 and 10000.`);
|
|
369
|
+
}
|
|
370
|
+
this.updateServer({ weight });
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
addSendHandler(packetName, handlerType) {
|
|
374
|
+
requireClientServerText(packetName, `ClientServer channel '${this.name}' send packet name`);
|
|
375
|
+
this.channel.sendHandlerTypes = [
|
|
376
|
+
...(this.channel.sendHandlerTypes ?? []),
|
|
377
|
+
{ packetName, handlerType }
|
|
378
|
+
];
|
|
379
|
+
return this;
|
|
380
|
+
}
|
|
381
|
+
addRequestHandler(packetName, handlerType) {
|
|
382
|
+
requireClientServerText(packetName, `ClientServer channel '${this.name}' request packet name`);
|
|
383
|
+
this.channel.requestHandlerTypes = [
|
|
384
|
+
...(this.channel.requestHandlerTypes ?? []),
|
|
385
|
+
{ packetName, handlerType }
|
|
386
|
+
];
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
addHandlerGroup(groupName) {
|
|
390
|
+
requireClientServerText(groupName, `ClientServer channel '${this.name}' handler group`);
|
|
391
|
+
this.channel.handlerGroups = [...(this.channel.handlerGroups ?? []), groupName];
|
|
392
|
+
return this;
|
|
393
|
+
}
|
|
394
|
+
get server() {
|
|
395
|
+
return this.channel.server;
|
|
396
|
+
}
|
|
397
|
+
updateServer(values) {
|
|
398
|
+
this.channel.server = { ...this.channel.server, ...values };
|
|
399
|
+
}
|
|
400
|
+
updateBind() {
|
|
401
|
+
const host = this.server.bindHost ?? '127.0.0.1';
|
|
402
|
+
const endpointHost = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
|
|
403
|
+
this.updateServer({ bind: `tcp://${endpointHost}:${this.server.port ?? 0}` });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function requireClientServerText(value, label) {
|
|
407
|
+
if (value.trim().length === 0 || value.trim() !== value) {
|
|
408
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} must not be empty or padded.`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function requireListenerPort(port, label) {
|
|
412
|
+
const normalized = port ?? 0;
|
|
413
|
+
if (!Number.isInteger(normalized) || normalized < 0 || normalized > 65_535) {
|
|
414
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} port must be between 0 and 65535.`);
|
|
415
|
+
}
|
|
416
|
+
return normalized;
|
|
417
|
+
}
|
|
418
|
+
function requirePublicWeight(value, label) {
|
|
419
|
+
if (!Number.isInteger(value) || value < 0 || value > 10_000) {
|
|
420
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} must be an integer in 0..10000.`);
|
|
421
|
+
}
|
|
422
|
+
return value;
|
|
423
|
+
}
|
|
424
|
+
function rejectFixedRoutingId(routingId, memberName) {
|
|
425
|
+
if (routingId !== undefined) {
|
|
426
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Mesh member '${memberName}' cannot combine a fixed routing id with a generated prefix.`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function rejectGeneratedRoutingId(prefix, memberName) {
|
|
430
|
+
if (prefix !== undefined) {
|
|
431
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Mesh member '${memberName}' cannot combine a generated routing-id prefix with a fixed id.`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
class DefaultZLinkNestStreamNodeBuilder extends ZLinkNestOptionsBuilder {
|
|
435
|
+
streamOptions;
|
|
436
|
+
constructor(state, streamOptions) {
|
|
437
|
+
super(state);
|
|
438
|
+
this.streamOptions = streamOptions;
|
|
439
|
+
}
|
|
440
|
+
bind(endpointOrPort) {
|
|
441
|
+
if (typeof endpointOrPort === 'string') {
|
|
442
|
+
this.streamOptions.bind = endpointOrPort;
|
|
443
|
+
delete this.streamOptions.port;
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
this.streamOptions.port = requireListenerPort(endpointOrPort, 'STREAM listener');
|
|
447
|
+
delete this.streamOptions.bind;
|
|
448
|
+
}
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
setBindHost(bindHost) {
|
|
452
|
+
requireClientServerText(bindHost, 'STREAM bind host');
|
|
453
|
+
this.streamOptions.bindHost = bindHost;
|
|
454
|
+
return this;
|
|
455
|
+
}
|
|
456
|
+
setAdvertiseHost(advertiseHost) {
|
|
457
|
+
requireClientServerText(advertiseHost, 'STREAM advertise host');
|
|
458
|
+
this.streamOptions.advertiseHost = advertiseHost;
|
|
459
|
+
return this;
|
|
460
|
+
}
|
|
461
|
+
enableActorDispatch() {
|
|
462
|
+
if (this.streamOptions.actorDispatchEnabled === true) {
|
|
463
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('STREAM node actor dispatch is already enabled.');
|
|
464
|
+
}
|
|
465
|
+
this.streamOptions.actorDispatchEnabled = true;
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
setTlsServer(certificatePath, keyPath, requireClientCertificate = false) {
|
|
469
|
+
this.streamOptions.tlsServer = {
|
|
470
|
+
certificatePath,
|
|
471
|
+
keyPath,
|
|
472
|
+
requireClientCertificate
|
|
473
|
+
};
|
|
474
|
+
return this;
|
|
475
|
+
}
|
|
476
|
+
registerSession(sessionType) {
|
|
477
|
+
if (this.streamOptions.session !== undefined) {
|
|
478
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('STREAM node cannot register more than one header stream session.');
|
|
479
|
+
}
|
|
480
|
+
this.streamOptions.session = sessionType;
|
|
481
|
+
return this;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
class DefaultZLinkNestMeshNodeBuilder extends ZLinkNestOptionsBuilder {
|
|
485
|
+
name;
|
|
486
|
+
spotOptions;
|
|
487
|
+
constructor(state, name, spotOptions) {
|
|
488
|
+
super(state);
|
|
489
|
+
this.name = name;
|
|
490
|
+
this.spotOptions = spotOptions;
|
|
491
|
+
}
|
|
492
|
+
channel(name) {
|
|
493
|
+
if (name.trim().length === 0 || name.trim() !== name) {
|
|
494
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Mesh channel name must not be empty or padded.');
|
|
495
|
+
}
|
|
496
|
+
const channels = {
|
|
497
|
+
...(this.spotOptions.meshChannels ?? {})
|
|
498
|
+
};
|
|
499
|
+
if (Object.prototype.hasOwnProperty.call(channels, name)) {
|
|
500
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Duplicate channel '${name}' in RouteMesh '${this.name}'.`);
|
|
501
|
+
}
|
|
502
|
+
channels[name] = {};
|
|
503
|
+
this.spotOptions.meshChannels = channels;
|
|
504
|
+
return new DefaultZLinkNestMeshChannelBuilder(this.state, channels[name]);
|
|
505
|
+
}
|
|
506
|
+
listen(endpointOrPort) {
|
|
507
|
+
this.spotOptions.router = typeof endpointOrPort === 'string'
|
|
508
|
+
? { ...(this.spotOptions.router ?? {}), bind: endpointOrPort, port: undefined }
|
|
509
|
+
: {
|
|
510
|
+
...(this.spotOptions.router ?? {}),
|
|
511
|
+
bind: undefined,
|
|
512
|
+
port: requireListenerPort(endpointOrPort, `RouteMesh '${this.name}' listener`)
|
|
513
|
+
};
|
|
514
|
+
return this;
|
|
515
|
+
}
|
|
516
|
+
setBindHost(bindHost) {
|
|
517
|
+
requireClientServerText(bindHost, `RouteMesh '${this.name}' bind host`);
|
|
518
|
+
this.spotOptions.router = { ...(this.spotOptions.router ?? {}), bindHost };
|
|
519
|
+
return this;
|
|
520
|
+
}
|
|
521
|
+
setAdvertiseHost(advertiseHost) {
|
|
522
|
+
requireClientServerText(advertiseHost, `RouteMesh '${this.name}' advertise host`);
|
|
523
|
+
this.spotOptions.router = { ...(this.spotOptions.router ?? {}), advertiseHost };
|
|
524
|
+
return this;
|
|
525
|
+
}
|
|
526
|
+
routingId(routingId) {
|
|
527
|
+
rejectGeneratedRoutingId(this.spotOptions.routingIdPrefix, this.name);
|
|
528
|
+
this.spotOptions.routingId = routingId;
|
|
529
|
+
if (this.spotOptions.router !== undefined) {
|
|
530
|
+
this.spotOptions.router.routingId = routingId;
|
|
531
|
+
}
|
|
532
|
+
if (this.spotOptions.pubSub !== undefined) {
|
|
533
|
+
this.spotOptions.pubSub.routingId = routingId;
|
|
534
|
+
}
|
|
535
|
+
return this;
|
|
536
|
+
}
|
|
537
|
+
setRoutingIdPrefix(prefix) {
|
|
538
|
+
rejectFixedRoutingId(this.spotOptions.routingId, this.name);
|
|
539
|
+
this.spotOptions.routingIdPrefix = framework_loader_1.framework.validateRoutingIdPrefix(prefix);
|
|
540
|
+
return this;
|
|
541
|
+
}
|
|
542
|
+
setPlacementWeight(weight) {
|
|
543
|
+
if (!Number.isInteger(weight) || weight < 0 || weight > 10_000) {
|
|
544
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Placement weight must be an integer in 0..10000.');
|
|
545
|
+
}
|
|
546
|
+
this.spotOptions.placementWeight = weight;
|
|
547
|
+
return this;
|
|
548
|
+
}
|
|
549
|
+
setActorLimit(limit) {
|
|
550
|
+
this.spotOptions.actorLimit = requireCapacity(limit, 'Actor limit');
|
|
551
|
+
return this;
|
|
552
|
+
}
|
|
553
|
+
setSpotLimit(limit) {
|
|
554
|
+
this.spotOptions.spotLimit = requireCapacity(limit, 'Spot limit');
|
|
555
|
+
return this;
|
|
556
|
+
}
|
|
557
|
+
setActivationConcurrency(limit) {
|
|
558
|
+
this.spotOptions.activationConcurrencyLimit = requirePositiveCapacity(limit, 'Activation concurrency limit');
|
|
559
|
+
return this;
|
|
560
|
+
}
|
|
561
|
+
setInstanceSpotIdleTimeout(timeoutMs) {
|
|
562
|
+
this.spotOptions.instanceSpotIdleTimeoutMs = requireNonNegativeSafeInteger(timeoutMs, 'Instance Spot idle timeout');
|
|
563
|
+
return this;
|
|
564
|
+
}
|
|
565
|
+
configureRouterSocket() {
|
|
566
|
+
this.spotOptions.router ??= {};
|
|
567
|
+
return this.spotOptions.router;
|
|
568
|
+
}
|
|
569
|
+
configureSpotPublisher() {
|
|
570
|
+
this.spotOptions.publisherConfig ??= {};
|
|
571
|
+
return this.spotOptions.publisherConfig;
|
|
572
|
+
}
|
|
573
|
+
peerConnections() {
|
|
574
|
+
this.spotOptions.router ??= {};
|
|
575
|
+
return new DefaultZLinkNestMeshPeerConnections(this.spotOptions.router);
|
|
576
|
+
}
|
|
577
|
+
objects() {
|
|
578
|
+
return new DefaultZLinkNestMeshObjectRoleBuilder(this.state, this.name, this.spotOptions);
|
|
579
|
+
}
|
|
580
|
+
addSendHandler(packetName, handlerType) {
|
|
581
|
+
this.spotOptions.routeSendHandlers = [
|
|
582
|
+
...(this.spotOptions.routeSendHandlers ?? []),
|
|
583
|
+
{ packetName, handlerType }
|
|
584
|
+
];
|
|
585
|
+
return this;
|
|
586
|
+
}
|
|
587
|
+
addRequestHandler(packetName, handlerType) {
|
|
588
|
+
this.spotOptions.routeRequestHandlers = [
|
|
589
|
+
...(this.spotOptions.routeRequestHandlers ?? []),
|
|
590
|
+
{ packetName, handlerType }
|
|
591
|
+
];
|
|
592
|
+
return this;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
class DefaultZLinkNestMeshObjectRoleBuilder extends ZLinkNestOptionsBuilder {
|
|
596
|
+
meshName;
|
|
597
|
+
node;
|
|
598
|
+
constructor(state, meshName, node) {
|
|
599
|
+
super(state);
|
|
600
|
+
this.meshName = meshName;
|
|
601
|
+
this.node = node;
|
|
602
|
+
}
|
|
603
|
+
client() {
|
|
604
|
+
this.node.objectRole = 'client';
|
|
605
|
+
return new DefaultZLinkNestMeshObjectClientBuilder(this.state);
|
|
606
|
+
}
|
|
607
|
+
server() {
|
|
608
|
+
this.node.objectRole = 'server';
|
|
609
|
+
return new DefaultZLinkNestMeshObjectServerBuilder(this.state, this.meshName, this.node);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
class DefaultZLinkNestMeshObjectClientBuilder extends ZLinkNestOptionsBuilder {
|
|
613
|
+
}
|
|
614
|
+
class DefaultZLinkNestFactoryBuilder {
|
|
615
|
+
relocation;
|
|
616
|
+
sealed = false;
|
|
617
|
+
disable() {
|
|
618
|
+
this.select({ kind: 'disabled' });
|
|
619
|
+
}
|
|
620
|
+
recreate() {
|
|
621
|
+
this.select({ kind: 'recreate' });
|
|
622
|
+
}
|
|
623
|
+
preserve(adapterType) {
|
|
624
|
+
if (typeof adapterType !== 'function') {
|
|
625
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('PreserveStateWith relocation requires an adapter type.');
|
|
626
|
+
}
|
|
627
|
+
this.select({ kind: 'snapshot', adapterType });
|
|
628
|
+
}
|
|
629
|
+
relocationConfiguration() {
|
|
630
|
+
if (this.relocation === undefined) {
|
|
631
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Factory configure callback must select exactly one relocation policy.');
|
|
632
|
+
}
|
|
633
|
+
return this.relocation;
|
|
634
|
+
}
|
|
635
|
+
seal() {
|
|
636
|
+
this.sealed = true;
|
|
637
|
+
}
|
|
638
|
+
assertMutable() {
|
|
639
|
+
if (this.sealed) {
|
|
640
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Factory builder cannot be changed after the configure callback returns.');
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
select(relocation) {
|
|
644
|
+
this.assertMutable();
|
|
645
|
+
if (this.relocation !== undefined) {
|
|
646
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Factory configure callback must select exactly one relocation policy.');
|
|
647
|
+
}
|
|
648
|
+
this.relocation = relocation;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
class DefaultZLinkNestActorFactoryBuilder extends DefaultZLinkNestFactoryBuilder {
|
|
652
|
+
disableRelocation() {
|
|
653
|
+
this.disable();
|
|
654
|
+
}
|
|
655
|
+
recreateOnRelocation() {
|
|
656
|
+
this.recreate();
|
|
657
|
+
}
|
|
658
|
+
preserveStateWith(adapterType) {
|
|
659
|
+
this.preserve(adapterType);
|
|
660
|
+
}
|
|
661
|
+
build() {
|
|
662
|
+
return { options: {}, relocation: this.relocationConfiguration() };
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
class DefaultZLinkNestUserSpotFactoryBuilder extends DefaultZLinkNestFactoryBuilder {
|
|
666
|
+
stableTypeLimitValue;
|
|
667
|
+
executionModeValue = framework_1.ZLinkUserSpotExecutionMode.SpotWide;
|
|
668
|
+
relocationCoordinationModeValue = framework_1.ZLinkSpotRelocationCoordinationMode.FrameworkManaged;
|
|
669
|
+
stableTypeLimit(limit) {
|
|
670
|
+
this.assertMutable();
|
|
671
|
+
validateStableTypeLimit(limit);
|
|
672
|
+
this.stableTypeLimitValue = limit;
|
|
673
|
+
return this;
|
|
674
|
+
}
|
|
675
|
+
executionMode(mode) {
|
|
676
|
+
this.assertMutable();
|
|
677
|
+
this.executionModeValue = mode;
|
|
678
|
+
return this;
|
|
679
|
+
}
|
|
680
|
+
relocationCoordinationMode(mode) {
|
|
681
|
+
this.assertMutable();
|
|
682
|
+
this.relocationCoordinationModeValue = mode;
|
|
683
|
+
return this;
|
|
684
|
+
}
|
|
685
|
+
disableRelocation() {
|
|
686
|
+
this.disable();
|
|
687
|
+
}
|
|
688
|
+
recreateOnRelocation() {
|
|
689
|
+
this.recreate();
|
|
690
|
+
}
|
|
691
|
+
preserveStateWith(adapterType) {
|
|
692
|
+
this.preserve(adapterType);
|
|
693
|
+
}
|
|
694
|
+
build() {
|
|
695
|
+
const relocation = this.relocationConfiguration();
|
|
696
|
+
const options = {
|
|
697
|
+
stableTypeLimit: this.stableTypeLimitValue,
|
|
698
|
+
executionMode: this.executionModeValue,
|
|
699
|
+
relocationCoordinationMode: this.relocationCoordinationModeValue
|
|
700
|
+
};
|
|
701
|
+
validateUserSpotFactoryConfiguration(options);
|
|
702
|
+
if (options.executionMode === framework_1.ZLinkUserSpotExecutionMode.PerActor
|
|
703
|
+
&& relocation.kind !== 'recreate') {
|
|
704
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('PerActor User Spots require RecreateOnRelocation.');
|
|
705
|
+
}
|
|
706
|
+
return { options, relocation };
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
class DefaultZLinkNestInstanceSpotFactoryBuilder extends DefaultZLinkNestFactoryBuilder {
|
|
710
|
+
stableTypeLimitValue;
|
|
711
|
+
stableTypeLimit(limit) {
|
|
712
|
+
this.assertMutable();
|
|
713
|
+
validateStableTypeLimit(limit);
|
|
714
|
+
this.stableTypeLimitValue = limit;
|
|
715
|
+
return this;
|
|
716
|
+
}
|
|
717
|
+
disableRelocation() {
|
|
718
|
+
this.disable();
|
|
719
|
+
}
|
|
720
|
+
recreateOnRelocation() {
|
|
721
|
+
this.recreate();
|
|
722
|
+
}
|
|
723
|
+
preserveStateWith(adapterType) {
|
|
724
|
+
this.preserve(adapterType);
|
|
725
|
+
}
|
|
726
|
+
build() {
|
|
727
|
+
return {
|
|
728
|
+
options: { stableTypeLimit: this.stableTypeLimitValue },
|
|
729
|
+
relocation: this.relocationConfiguration()
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
class DefaultZLinkNestMeshObjectServerBuilder extends ZLinkNestOptionsBuilder {
|
|
734
|
+
meshName;
|
|
735
|
+
node;
|
|
736
|
+
constructor(state, meshName, node) {
|
|
737
|
+
super(state);
|
|
738
|
+
this.meshName = meshName;
|
|
739
|
+
this.node = node;
|
|
740
|
+
}
|
|
741
|
+
addEntrySpot(entrySpotType) {
|
|
742
|
+
framework_loader_1.framework.registerEntrySpot(this.node, entrySpotType);
|
|
743
|
+
return this;
|
|
744
|
+
}
|
|
745
|
+
addSpotFactory(spotType, implementation, configure) {
|
|
746
|
+
const stableType = validateObjectFactory(spotType, 'User Spot type');
|
|
747
|
+
requireFactoryConfigure(configure);
|
|
748
|
+
const factory = new DefaultZLinkNestUserSpotFactoryBuilder();
|
|
749
|
+
let built;
|
|
750
|
+
try {
|
|
751
|
+
configure(factory);
|
|
752
|
+
built = factory.build();
|
|
753
|
+
}
|
|
754
|
+
finally {
|
|
755
|
+
factory.seal();
|
|
756
|
+
}
|
|
757
|
+
const { options, relocation } = built;
|
|
758
|
+
const registrations = {
|
|
759
|
+
...(this.node.spotFactoryRegistrations ?? {})
|
|
760
|
+
};
|
|
761
|
+
rejectDuplicateObjectType(registrations, stableType, this.meshName);
|
|
762
|
+
registrations[stableType] = {
|
|
763
|
+
implementation,
|
|
764
|
+
options: {
|
|
765
|
+
...options,
|
|
766
|
+
executionMode: options.executionMode
|
|
767
|
+
},
|
|
768
|
+
relocation
|
|
769
|
+
};
|
|
770
|
+
this.node.spotFactoryRegistrations = registrations;
|
|
771
|
+
const factories = [...(this.node.spotFactories ?? [])];
|
|
772
|
+
framework_loader_1.framework.registerSpotFactory({ spotFactories: factories }, implementation);
|
|
773
|
+
this.node.spotFactories = factories;
|
|
774
|
+
return this;
|
|
775
|
+
}
|
|
776
|
+
addInstanceSpotFactory(instanceSpotType, implementation, configure) {
|
|
777
|
+
const stableType = validateObjectFactory(instanceSpotType, 'Instance Spot type');
|
|
778
|
+
requireFactoryConfigure(configure);
|
|
779
|
+
const factory = new DefaultZLinkNestInstanceSpotFactoryBuilder();
|
|
780
|
+
let built;
|
|
781
|
+
try {
|
|
782
|
+
configure(factory);
|
|
783
|
+
built = factory.build();
|
|
784
|
+
}
|
|
785
|
+
finally {
|
|
786
|
+
factory.seal();
|
|
787
|
+
}
|
|
788
|
+
const { options, relocation } = built;
|
|
789
|
+
validateStableTypeLimit(options.stableTypeLimit);
|
|
790
|
+
const factories = {
|
|
791
|
+
...(this.node.instanceSpotFactories ?? {})
|
|
792
|
+
};
|
|
793
|
+
if (Object.hasOwn(factories, stableType)) {
|
|
794
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Duplicate Instance Spot factory '${stableType}' on RouteMesh '${this.meshName}'.`);
|
|
795
|
+
}
|
|
796
|
+
factories[stableType] = implementation;
|
|
797
|
+
this.node.instanceSpotFactories = factories;
|
|
798
|
+
this.node.instanceSpotFactoryRegistrations = {
|
|
799
|
+
...(this.node.instanceSpotFactoryRegistrations ?? {}),
|
|
800
|
+
[stableType]: { implementation, options, relocation }
|
|
801
|
+
};
|
|
802
|
+
return this;
|
|
803
|
+
}
|
|
804
|
+
addActorFactory(actorType, implementation, configure) {
|
|
805
|
+
const stableType = validateObjectFactory(actorType, 'Actor type');
|
|
806
|
+
requireFactoryConfigure(configure);
|
|
807
|
+
const factory = new DefaultZLinkNestActorFactoryBuilder();
|
|
808
|
+
let built;
|
|
809
|
+
try {
|
|
810
|
+
configure(factory);
|
|
811
|
+
built = factory.build();
|
|
812
|
+
}
|
|
813
|
+
finally {
|
|
814
|
+
factory.seal();
|
|
815
|
+
}
|
|
816
|
+
const { options, relocation } = built;
|
|
817
|
+
const registrations = {
|
|
818
|
+
...(this.node.actorFactoryRegistrations ?? {})
|
|
819
|
+
};
|
|
820
|
+
rejectDuplicateObjectType(registrations, stableType, this.meshName);
|
|
821
|
+
const actorFactories = {
|
|
822
|
+
...this.node.actorFactories
|
|
823
|
+
};
|
|
824
|
+
framework_loader_1.framework.registerActorFactory({ actorFactories }, stableType, implementation);
|
|
825
|
+
this.node.actorFactories = actorFactories;
|
|
826
|
+
registrations[stableType] = { implementation, options, relocation };
|
|
827
|
+
this.node.actorFactoryRegistrations = registrations;
|
|
828
|
+
return this;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
function validateObjectFactory(stableType, label) {
|
|
832
|
+
if (typeof stableType !== 'string'
|
|
833
|
+
|| Buffer.byteLength(stableType) < 1
|
|
834
|
+
|| Buffer.byteLength(stableType) > 255
|
|
835
|
+
|| stableType.includes('\0')) {
|
|
836
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} must contain 1..255 UTF-8 bytes and no NUL.`);
|
|
837
|
+
}
|
|
838
|
+
return stableType;
|
|
839
|
+
}
|
|
840
|
+
function requireFactoryConfigure(configure) {
|
|
841
|
+
if (typeof configure !== 'function') {
|
|
842
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('Object factory requires a configure callback.');
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
function validateUserSpotFactoryConfiguration(options) {
|
|
846
|
+
validateStableTypeLimit(options.stableTypeLimit);
|
|
847
|
+
const executionMode = options.executionMode;
|
|
848
|
+
const relocationCoordinationMode = options.relocationCoordinationMode;
|
|
849
|
+
if (executionMode !== framework_1.ZLinkUserSpotExecutionMode.SpotWide
|
|
850
|
+
&& executionMode !== framework_1.ZLinkUserSpotExecutionMode.PerActor) {
|
|
851
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('User Spot executionMode is invalid.');
|
|
852
|
+
}
|
|
853
|
+
if (relocationCoordinationMode !== framework_1.ZLinkSpotRelocationCoordinationMode.FrameworkManaged
|
|
854
|
+
&& relocationCoordinationMode !== framework_1.ZLinkSpotRelocationCoordinationMode.ApplicationSignaled) {
|
|
855
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('User Spot relocationCoordinationMode is invalid.');
|
|
856
|
+
}
|
|
857
|
+
if (options.executionMode === framework_1.ZLinkUserSpotExecutionMode.PerActor
|
|
858
|
+
&& options.relocationCoordinationMode === framework_1.ZLinkSpotRelocationCoordinationMode.ApplicationSignaled) {
|
|
859
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('ApplicationSignaled relocation coordination mode is valid only for SpotWide User Spots.');
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
function validateStableTypeLimit(value) {
|
|
863
|
+
if (value !== undefined
|
|
864
|
+
&& (!Number.isInteger(value) || value < 0 || value > 2_147_483_647)) {
|
|
865
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('stableTypeLimit must be an integer from 0 through 2147483647.');
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
function requirePositiveCapacity(value, label) {
|
|
869
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > 0x7fff_ffff) {
|
|
870
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} must be an integer in 1..2147483647.`);
|
|
871
|
+
}
|
|
872
|
+
return value;
|
|
873
|
+
}
|
|
874
|
+
function requireCapacity(value, label) {
|
|
875
|
+
if (!Number.isSafeInteger(value) || value < 0 || value > 0x7fff_ffff) {
|
|
876
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} must be an integer in 0..2147483647.`);
|
|
877
|
+
}
|
|
878
|
+
return value;
|
|
879
|
+
}
|
|
880
|
+
function requireNonNegativeSafeInteger(value, label) {
|
|
881
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
882
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`${label} must be a non-negative safe integer.`);
|
|
883
|
+
}
|
|
884
|
+
return value;
|
|
885
|
+
}
|
|
886
|
+
function rejectDuplicateObjectType(registrations, stableType, meshName) {
|
|
887
|
+
if (Object.hasOwn(registrations, stableType)) {
|
|
888
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException(`Duplicate object factory '${stableType}' on RouteMesh '${meshName}'.`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
class DefaultZLinkNestMeshChannelBuilder extends ZLinkNestOptionsBuilder {
|
|
892
|
+
channel;
|
|
893
|
+
constructor(state, channel) {
|
|
894
|
+
super(state);
|
|
895
|
+
this.channel = channel;
|
|
896
|
+
}
|
|
897
|
+
client() {
|
|
898
|
+
if (this.channel.client === true || this.channel.server === true) {
|
|
899
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('RouteMesh channel must register exactly one role; client() and server() cannot both be used or called twice.');
|
|
900
|
+
}
|
|
901
|
+
this.channel.client = true;
|
|
902
|
+
return new DefaultZLinkNestMeshChannelClientBuilder(this.state);
|
|
903
|
+
}
|
|
904
|
+
server() {
|
|
905
|
+
if (this.channel.client === true || this.channel.server === true) {
|
|
906
|
+
throw new framework_loader_1.framework.ZLinkConfigurationException('RouteMesh channel must register exactly one role; client() and server() cannot both be used or called twice.');
|
|
907
|
+
}
|
|
908
|
+
this.channel.server = true;
|
|
909
|
+
return new DefaultZLinkNestMeshChannelServerBuilder(this.state, this.channel);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
class DefaultZLinkNestMeshChannelClientBuilder extends ZLinkNestOptionsBuilder {
|
|
913
|
+
}
|
|
914
|
+
class DefaultZLinkNestMeshChannelServerBuilder extends ZLinkNestOptionsBuilder {
|
|
915
|
+
channel;
|
|
916
|
+
constructor(state, channel) {
|
|
917
|
+
super(state);
|
|
918
|
+
this.channel = channel;
|
|
919
|
+
}
|
|
920
|
+
setWeight(weight) {
|
|
921
|
+
this.channel.weight = requirePublicWeight(weight, 'Mesh channel weight');
|
|
922
|
+
return this;
|
|
923
|
+
}
|
|
924
|
+
addSendHandler(packetName, handlerType) {
|
|
925
|
+
this.channel.sendHandlers = [...(this.channel.sendHandlers ?? []), { packetName, handlerType }];
|
|
926
|
+
return this;
|
|
927
|
+
}
|
|
928
|
+
addRequestHandler(packetName, handlerType) {
|
|
929
|
+
this.channel.requestHandlers = [...(this.channel.requestHandlers ?? []), { packetName, handlerType }];
|
|
930
|
+
return this;
|
|
931
|
+
}
|
|
932
|
+
addHandlerGroup(groupName) {
|
|
933
|
+
this.channel.handlerGroups = [...(this.channel.handlerGroups ?? []), groupName];
|
|
934
|
+
return this;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
class DefaultZLinkNestMeshPeerConnections {
|
|
938
|
+
router;
|
|
939
|
+
constructor(router) {
|
|
940
|
+
this.router = router;
|
|
941
|
+
}
|
|
942
|
+
connect(expectedRoutingIdOrEndpoint, endpoint) {
|
|
943
|
+
if (endpoint === undefined) {
|
|
944
|
+
this.router.manualConnections = [...(this.router.manualConnections ?? []), expectedRoutingIdOrEndpoint];
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
this.router.manualPeerConnections = [
|
|
948
|
+
...(this.router.manualPeerConnections ?? []),
|
|
949
|
+
{ peerRid: expectedRoutingIdOrEndpoint, endpoint }
|
|
950
|
+
];
|
|
951
|
+
}
|
|
952
|
+
disconnect(endpoint) {
|
|
953
|
+
this.router.manualConnections = (this.router.manualConnections ?? [])
|
|
954
|
+
.filter((value) => value !== endpoint);
|
|
955
|
+
this.router.manualPeerConnections = (this.router.manualPeerConnections ?? [])
|
|
956
|
+
.filter((value) => value.endpoint !== endpoint);
|
|
957
|
+
}
|
|
958
|
+
listConnections() {
|
|
959
|
+
return [
|
|
960
|
+
...(this.router.manualConnections ?? []).map((endpoint) => ({ endpoint })),
|
|
961
|
+
...(this.router.manualPeerConnections ?? []).map((connection) => ({
|
|
962
|
+
endpoint: connection.endpoint,
|
|
963
|
+
expectedRoutingId: connection.peerRid
|
|
964
|
+
}))
|
|
965
|
+
];
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
function endpointList(endpoint) {
|
|
969
|
+
return typeof endpoint === 'string' ? [endpoint] : [...endpoint];
|
|
970
|
+
}
|
|
971
|
+
function createZLinkNestFrameworkOptionsBuilder() {
|
|
972
|
+
return new DefaultZLinkNestFrameworkOptionsBuilder();
|
|
973
|
+
}
|