@cadenza.io/service 2.15.0 → 2.17.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/README.md +46 -0
- package/dist/browser/index.js +8005 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/index.mjs +7978 -0
- package/dist/browser/index.mjs.map +1 -0
- package/dist/index.d.mts +196 -22
- package/dist/index.d.ts +196 -22
- package/dist/index.js +1521 -476
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1515 -472
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Actor: () => import_core5.Actor,
|
|
34
|
+
DatabaseController: () => DatabaseController,
|
|
34
35
|
DatabaseTask: () => DatabaseTask,
|
|
35
36
|
DebounceTask: () => import_core5.DebounceTask,
|
|
36
37
|
DeputyTask: () => DeputyTask,
|
|
@@ -43,6 +44,7 @@ __export(index_exports, {
|
|
|
43
44
|
SignalTransmissionTask: () => SignalTransmissionTask,
|
|
44
45
|
SocketController: () => SocketController,
|
|
45
46
|
Task: () => import_core5.Task,
|
|
47
|
+
createSSRInquiryBridge: () => createSSRInquiryBridge,
|
|
46
48
|
default: () => index_default
|
|
47
49
|
});
|
|
48
50
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -87,7 +89,7 @@ var DeputyTask = class extends import_core.Task {
|
|
|
87
89
|
return;
|
|
88
90
|
}
|
|
89
91
|
if (context.__metadata.__skipRemoteExecution) {
|
|
90
|
-
resolve(
|
|
92
|
+
resolve(context);
|
|
91
93
|
return;
|
|
92
94
|
}
|
|
93
95
|
const processId = (0, import_uuid.v4)();
|
|
@@ -190,6 +192,8 @@ var DeputyTask = class extends import_core.Task {
|
|
|
190
192
|
__executionTraceId: metadata.__executionTraceId ?? null,
|
|
191
193
|
__metadata: {
|
|
192
194
|
...metadata,
|
|
195
|
+
__skipRemoteExecution: metadata.__skipRemoteExecution ?? ctx.__skipRemoteExecution ?? false,
|
|
196
|
+
__blockRemoteExecution: metadata.__blockRemoteExecution ?? ctx.__blockRemoteExecution ?? false,
|
|
193
197
|
__deputyTaskName: this.name
|
|
194
198
|
},
|
|
195
199
|
...ctx
|
|
@@ -268,6 +272,7 @@ var DatabaseTask = class extends DeputyTask {
|
|
|
268
272
|
const dynamicQueryData = ctx.queryData ?? {};
|
|
269
273
|
delete ctx.queryData;
|
|
270
274
|
const deputyContext = {
|
|
275
|
+
...ctx,
|
|
271
276
|
__localTaskName: this.name,
|
|
272
277
|
__localTaskVersion: this.version,
|
|
273
278
|
__localServiceName: CadenzaService.serviceRegistry.serviceName,
|
|
@@ -278,6 +283,8 @@ var DatabaseTask = class extends DeputyTask {
|
|
|
278
283
|
__localRoutineExecId: metadata.__routineExecId ?? metadata.__metadata?.__routineExecId,
|
|
279
284
|
__metadata: {
|
|
280
285
|
...metadata,
|
|
286
|
+
__skipRemoteExecution: metadata.__skipRemoteExecution ?? ctx.__skipRemoteExecution ?? false,
|
|
287
|
+
__blockRemoteExecution: metadata.__blockRemoteExecution ?? ctx.__blockRemoteExecution ?? false,
|
|
281
288
|
__deputyTaskName: this.name
|
|
282
289
|
},
|
|
283
290
|
queryData: {
|
|
@@ -364,6 +371,167 @@ function summarizeResponderStatuses(statuses) {
|
|
|
364
371
|
return { responded, failed, timedOut, pending };
|
|
365
372
|
}
|
|
366
373
|
|
|
374
|
+
// src/utils/transport.ts
|
|
375
|
+
var DEFAULT_PROTOCOLS = ["rest", "socket"];
|
|
376
|
+
function normalizeString(value) {
|
|
377
|
+
return typeof value === "string" ? value.trim() : "";
|
|
378
|
+
}
|
|
379
|
+
function normalizeTransportProtocols(value) {
|
|
380
|
+
const rawValues = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
|
|
381
|
+
const normalized = rawValues.map((entry) => normalizeString(entry)).filter(
|
|
382
|
+
(entry) => entry === "rest" || entry === "socket"
|
|
383
|
+
);
|
|
384
|
+
return Array.from(new Set(normalized));
|
|
385
|
+
}
|
|
386
|
+
function normalizeTransportOrigin(origin) {
|
|
387
|
+
const raw = normalizeString(origin);
|
|
388
|
+
if (!raw) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
let parsed;
|
|
392
|
+
try {
|
|
393
|
+
parsed = new URL(raw);
|
|
394
|
+
} catch {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
if (parsed.pathname && parsed.pathname !== "/") {
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
if (parsed.search || parsed.hash) {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
return parsed.origin;
|
|
407
|
+
}
|
|
408
|
+
function normalizeSecurityProfile(value) {
|
|
409
|
+
const normalized = normalizeString(value);
|
|
410
|
+
if (normalized === "low" || normalized === "medium" || normalized === "high") {
|
|
411
|
+
return normalized;
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
function normalizeServiceTransportConfig(value) {
|
|
416
|
+
const raw = value ?? {};
|
|
417
|
+
const role = normalizeString(raw.role);
|
|
418
|
+
const origin = normalizeTransportOrigin(raw.origin);
|
|
419
|
+
const protocols = normalizeTransportProtocols(raw.protocols);
|
|
420
|
+
if (!origin) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
if (role !== "internal" && role !== "public") {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
role,
|
|
428
|
+
origin,
|
|
429
|
+
protocols: protocols.length > 0 ? protocols : [...DEFAULT_PROTOCOLS],
|
|
430
|
+
securityProfile: normalizeSecurityProfile(raw.securityProfile),
|
|
431
|
+
authStrategy: normalizeString(raw.authStrategy) || null
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function normalizeServiceTransportDescriptor(value) {
|
|
435
|
+
const raw = value ?? {};
|
|
436
|
+
const uuid5 = normalizeString(raw.uuid);
|
|
437
|
+
const serviceInstanceId = normalizeString(
|
|
438
|
+
raw.serviceInstanceId ?? raw.service_instance_id
|
|
439
|
+
);
|
|
440
|
+
const config = normalizeServiceTransportConfig(raw);
|
|
441
|
+
if (!uuid5 || !serviceInstanceId || !config) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
return {
|
|
445
|
+
uuid: uuid5,
|
|
446
|
+
serviceInstanceId,
|
|
447
|
+
role: config.role,
|
|
448
|
+
origin: config.origin,
|
|
449
|
+
protocols: config.protocols ?? [...DEFAULT_PROTOCOLS],
|
|
450
|
+
securityProfile: config.securityProfile ?? null,
|
|
451
|
+
authStrategy: config.authStrategy ?? null,
|
|
452
|
+
deleted: Boolean(raw.deleted),
|
|
453
|
+
clientCreated: Boolean(raw.clientCreated ?? raw.client_created ?? false)
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function transportSupportsProtocol(transport, protocol) {
|
|
457
|
+
return !!transport && transport.protocols.includes(protocol);
|
|
458
|
+
}
|
|
459
|
+
function selectTransportForRole(transports, role, protocol) {
|
|
460
|
+
const filtered = transports.filter(
|
|
461
|
+
(transport) => !transport.deleted && transport.role === role && (!protocol || transportSupportsProtocol(transport, protocol))
|
|
462
|
+
);
|
|
463
|
+
return filtered[0];
|
|
464
|
+
}
|
|
465
|
+
function buildTransportClientKey(transport) {
|
|
466
|
+
return transport.uuid;
|
|
467
|
+
}
|
|
468
|
+
function parseTransportOrigin(origin) {
|
|
469
|
+
const normalized = normalizeTransportOrigin(origin);
|
|
470
|
+
if (!normalized) {
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
const parsed = new URL(normalized);
|
|
474
|
+
const protocol = parsed.protocol === "https:" ? "https" : "http";
|
|
475
|
+
const port = parsed.port ? Number(parsed.port) : protocol === "https" ? 443 : 80;
|
|
476
|
+
return {
|
|
477
|
+
protocol,
|
|
478
|
+
hostname: parsed.hostname,
|
|
479
|
+
port
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/utils/serviceInstance.ts
|
|
484
|
+
function normalizeString2(value) {
|
|
485
|
+
return typeof value === "string" ? value.trim() : "";
|
|
486
|
+
}
|
|
487
|
+
function normalizeTransportArray(value, serviceInstanceId) {
|
|
488
|
+
if (!Array.isArray(value)) {
|
|
489
|
+
return [];
|
|
490
|
+
}
|
|
491
|
+
return value.map(
|
|
492
|
+
(entry) => normalizeServiceTransportDescriptor({
|
|
493
|
+
...entry ?? {},
|
|
494
|
+
service_instance_id: entry?.service_instance_id ?? entry?.serviceInstanceId ?? serviceInstanceId
|
|
495
|
+
})
|
|
496
|
+
).filter((transport) => !!transport).sort((left, right) => left.origin.localeCompare(right.origin));
|
|
497
|
+
}
|
|
498
|
+
function normalizeServiceInstanceDescriptor(value) {
|
|
499
|
+
const raw = value ?? {};
|
|
500
|
+
const uuid5 = normalizeString2(raw.uuid);
|
|
501
|
+
const serviceName = normalizeString2(raw.serviceName ?? raw.service_name);
|
|
502
|
+
if (!uuid5 || !serviceName) {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
const transports = normalizeTransportArray(raw.transports, uuid5);
|
|
506
|
+
return {
|
|
507
|
+
uuid: uuid5,
|
|
508
|
+
serviceName,
|
|
509
|
+
numberOfRunningGraphs: Math.max(
|
|
510
|
+
0,
|
|
511
|
+
Math.trunc(
|
|
512
|
+
Number(raw.numberOfRunningGraphs ?? raw.number_of_running_graphs ?? 0) || 0
|
|
513
|
+
)
|
|
514
|
+
),
|
|
515
|
+
isPrimary: Boolean(raw.isPrimary ?? raw.is_primary ?? false),
|
|
516
|
+
isActive: Boolean(raw.isActive ?? raw.is_active ?? true),
|
|
517
|
+
isNonResponsive: Boolean(
|
|
518
|
+
raw.isNonResponsive ?? raw.is_non_responsive ?? false
|
|
519
|
+
),
|
|
520
|
+
isBlocked: Boolean(raw.isBlocked ?? raw.is_blocked ?? false),
|
|
521
|
+
runtimeState: raw.runtimeState === "healthy" || raw.runtimeState === "degraded" || raw.runtimeState === "overloaded" || raw.runtimeState === "unavailable" ? raw.runtimeState : void 0,
|
|
522
|
+
acceptingWork: typeof raw.acceptingWork === "boolean" ? raw.acceptingWork : void 0,
|
|
523
|
+
reportedAt: typeof raw.reportedAt === "string" ? raw.reportedAt : typeof raw.reported_at === "string" ? raw.reported_at : void 0,
|
|
524
|
+
health: raw.health ?? {},
|
|
525
|
+
isFrontend: Boolean(raw.isFrontend ?? raw.is_frontend ?? false),
|
|
526
|
+
isDatabase: Boolean(raw.isDatabase ?? raw.is_database ?? false),
|
|
527
|
+
transports,
|
|
528
|
+
clientCreatedTransportIds: Array.isArray(raw.clientCreatedTransportIds) ? raw.clientCreatedTransportIds.map((entry) => normalizeString2(entry)).filter((entry) => entry.length > 0) : void 0
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function getRouteableTransport(instance, role, protocol) {
|
|
532
|
+
return selectTransportForRole(instance.transports ?? [], role, protocol);
|
|
533
|
+
}
|
|
534
|
+
|
|
367
535
|
// src/utils/readiness.ts
|
|
368
536
|
function evaluateDependencyReadiness(input) {
|
|
369
537
|
const missedHeartbeats = Math.max(
|
|
@@ -610,6 +778,7 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
610
778
|
this.numberOfRunningGraphs = 0;
|
|
611
779
|
this.useSocket = false;
|
|
612
780
|
this.retryCount = 3;
|
|
781
|
+
this.isFrontend = false;
|
|
613
782
|
CadenzaService.defineIntent({
|
|
614
783
|
name: META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT,
|
|
615
784
|
description: "Gather transport diagnostics across all services and communication clients.",
|
|
@@ -757,57 +926,60 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
757
926
|
this.handleInstanceUpdateTask = CadenzaService.createMetaTask(
|
|
758
927
|
"Handle Instance Update",
|
|
759
928
|
(ctx, emit) => {
|
|
760
|
-
const serviceInstance =
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
if (!serviceInstance
|
|
929
|
+
const serviceInstance = normalizeServiceInstanceDescriptor(
|
|
930
|
+
ctx.serviceInstance ?? ctx.data ?? ctx.queryData?.data ?? (ctx.__serviceInstanceId || ctx.serviceInstanceId ? {
|
|
931
|
+
uuid: ctx.__serviceInstanceId ?? ctx.serviceInstanceId,
|
|
932
|
+
serviceName: ctx.__serviceName ?? ctx.serviceName,
|
|
933
|
+
isFrontend: !!ctx.isFrontend,
|
|
934
|
+
isActive: typeof ctx.isActive === "boolean" ? ctx.isActive : typeof ctx.__active === "boolean" ? ctx.__active : true,
|
|
935
|
+
isNonResponsive: !!ctx.isNonResponsive,
|
|
936
|
+
isBlocked: !!ctx.isBlocked,
|
|
937
|
+
health: ctx.health ?? ctx.__health ?? {},
|
|
938
|
+
numberOfRunningGraphs: ctx.numberOfRunningGraphs ?? ctx.__numberOfRunningGraphs ?? 0,
|
|
939
|
+
isPrimary: false,
|
|
940
|
+
transports: ctx.transports ?? []
|
|
941
|
+
} : void 0)
|
|
942
|
+
);
|
|
943
|
+
if (!serviceInstance) {
|
|
775
944
|
return false;
|
|
776
945
|
}
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
isFrontend,
|
|
784
|
-
deleted
|
|
785
|
-
} = serviceInstance;
|
|
786
|
-
if (uuid4 === this.serviceInstanceId) return;
|
|
946
|
+
const uuid5 = serviceInstance.uuid;
|
|
947
|
+
const serviceName = serviceInstance.serviceName;
|
|
948
|
+
const deleted = Boolean(
|
|
949
|
+
ctx.deleted ?? ctx.serviceInstance?.deleted ?? ctx.data?.deleted
|
|
950
|
+
);
|
|
951
|
+
if (uuid5 === this.serviceInstanceId) return;
|
|
787
952
|
if (deleted) {
|
|
788
|
-
const
|
|
789
|
-
|
|
953
|
+
const existingInstance = this.instances.get(serviceName)?.find((instance) => instance.uuid === uuid5);
|
|
954
|
+
const indexToDelete = this.instances.get(serviceName)?.findIndex((i) => i.uuid === uuid5) ?? -1;
|
|
955
|
+
if (indexToDelete >= 0 && existingInstance) {
|
|
790
956
|
this.instances.get(serviceName)?.splice(indexToDelete, 1);
|
|
957
|
+
for (const transport of existingInstance.transports) {
|
|
958
|
+
const transportKey = buildTransportClientKey(transport);
|
|
959
|
+
emit(`meta.socket_shutdown_requested:${transportKey}`, {});
|
|
960
|
+
emit(`meta.fetch.destroy_requested:${transportKey}`, {});
|
|
961
|
+
}
|
|
791
962
|
}
|
|
792
963
|
if (this.instances.get(serviceName)?.length === 0) {
|
|
793
964
|
this.instances.delete(serviceName);
|
|
794
|
-
} else if (this.instances.get(serviceName)?.filter((i) => i.address === address && i.port === port).length === 0) {
|
|
795
|
-
emit(`meta.socket_shutdown_requested:${address}_${port}`, {});
|
|
796
|
-
emit(`meta.fetch.destroy_requested:${address}_${port}`, {});
|
|
797
965
|
}
|
|
798
|
-
this.unregisterDependee(
|
|
966
|
+
this.unregisterDependee(uuid5, serviceName);
|
|
799
967
|
return;
|
|
800
968
|
}
|
|
801
969
|
if (!this.instances.has(serviceName))
|
|
802
970
|
this.instances.set(serviceName, []);
|
|
803
971
|
const instances = this.instances.get(serviceName);
|
|
804
|
-
const existing = instances.find((i) => i.uuid ===
|
|
972
|
+
const existing = instances.find((i) => i.uuid === uuid5);
|
|
805
973
|
if (existing) {
|
|
806
|
-
Object.assign(existing,
|
|
974
|
+
Object.assign(existing, {
|
|
975
|
+
...serviceInstance,
|
|
976
|
+
transports: serviceInstance.transports.length > 0 ? serviceInstance.transports : existing.transports,
|
|
977
|
+
clientCreatedTransportIds: existing.clientCreatedTransportIds ?? []
|
|
978
|
+
});
|
|
807
979
|
} else {
|
|
808
980
|
instances.push(serviceInstance);
|
|
809
981
|
}
|
|
810
|
-
const trackedInstance = existing ?? instances.find((instance) => instance.uuid ===
|
|
982
|
+
const trackedInstance = existing ?? instances.find((instance) => instance.uuid === uuid5);
|
|
811
983
|
if (trackedInstance) {
|
|
812
984
|
const snapshot = this.resolveRuntimeStatusSnapshot(
|
|
813
985
|
trackedInstance.numberOfRunningGraphs ?? 0,
|
|
@@ -822,31 +994,44 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
822
994
|
if (this.serviceName === serviceName) {
|
|
823
995
|
return false;
|
|
824
996
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
997
|
+
const trackedTransport = this.getRouteableTransport(
|
|
998
|
+
trackedInstance,
|
|
999
|
+
this.useSocket ? "socket" : "rest"
|
|
1000
|
+
);
|
|
1001
|
+
if (!serviceInstance.isFrontend && (this.deputies.has(serviceName) || this.remoteIntents.has(serviceName)) || this.remoteSignals.has(serviceName)) {
|
|
1002
|
+
const communicationTypes = Array.from(
|
|
1003
|
+
new Set(
|
|
1004
|
+
this.deputies.get(serviceName)?.map((d) => d.communicationType) ?? []
|
|
1005
|
+
)
|
|
828
1006
|
);
|
|
829
|
-
if (!
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1007
|
+
if (!communicationTypes.includes("signal") && this.remoteSignals.has(serviceName)) {
|
|
1008
|
+
communicationTypes.push("signal");
|
|
1009
|
+
}
|
|
1010
|
+
if (trackedTransport) {
|
|
1011
|
+
const clientCreated = this.hasTransportClientCreated(
|
|
1012
|
+
trackedInstance,
|
|
1013
|
+
trackedTransport.uuid
|
|
834
1014
|
);
|
|
835
|
-
if (!
|
|
836
|
-
|
|
1015
|
+
if (!clientCreated) {
|
|
1016
|
+
emit("meta.service_registry.dependee_registered", {
|
|
1017
|
+
serviceName,
|
|
1018
|
+
serviceInstanceId: uuid5,
|
|
1019
|
+
serviceTransportId: trackedTransport.uuid,
|
|
1020
|
+
serviceOrigin: trackedTransport.origin,
|
|
1021
|
+
transportProtocols: trackedTransport.protocols,
|
|
1022
|
+
communicationTypes
|
|
1023
|
+
});
|
|
1024
|
+
this.markTransportClientCreated(
|
|
1025
|
+
trackedInstance,
|
|
1026
|
+
trackedTransport.uuid
|
|
1027
|
+
);
|
|
837
1028
|
}
|
|
838
|
-
|
|
1029
|
+
} else {
|
|
1030
|
+
emit("meta.service_registry.routeable_transport_missing", {
|
|
839
1031
|
serviceName,
|
|
840
|
-
serviceInstanceId:
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
protocol: exposed ? "https" : "http",
|
|
844
|
-
communicationTypes
|
|
845
|
-
});
|
|
846
|
-
instances?.filter(
|
|
847
|
-
(i) => i.address === address && i.port === port && i.isActive
|
|
848
|
-
).forEach((i) => {
|
|
849
|
-
i.clientCreated = true;
|
|
1032
|
+
serviceInstanceId: uuid5,
|
|
1033
|
+
requiredRole: this.getRoutingTransportRole(),
|
|
1034
|
+
isFrontend: this.isFrontend
|
|
850
1035
|
});
|
|
851
1036
|
}
|
|
852
1037
|
}
|
|
@@ -864,6 +1049,81 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
864
1049
|
"meta.socket_shutdown_requested",
|
|
865
1050
|
"meta.fetch.destroy_requested"
|
|
866
1051
|
);
|
|
1052
|
+
this.handleTransportUpdateTask = CadenzaService.createMetaTask(
|
|
1053
|
+
"Handle Transport Update",
|
|
1054
|
+
(ctx, emit) => {
|
|
1055
|
+
const transport = normalizeServiceTransportDescriptor(
|
|
1056
|
+
ctx.serviceTransport ?? ctx.data ?? ctx.queryData?.data ?? ctx
|
|
1057
|
+
);
|
|
1058
|
+
if (!transport) {
|
|
1059
|
+
return false;
|
|
1060
|
+
}
|
|
1061
|
+
let ownerInstance;
|
|
1062
|
+
for (const instances of this.instances.values()) {
|
|
1063
|
+
ownerInstance = instances.find(
|
|
1064
|
+
(instance) => instance.uuid === transport.serviceInstanceId
|
|
1065
|
+
);
|
|
1066
|
+
if (ownerInstance) {
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (!ownerInstance) {
|
|
1071
|
+
return false;
|
|
1072
|
+
}
|
|
1073
|
+
if (transport.deleted) {
|
|
1074
|
+
ownerInstance.transports = ownerInstance.transports.filter(
|
|
1075
|
+
(existingTransport2) => existingTransport2.uuid !== transport.uuid
|
|
1076
|
+
);
|
|
1077
|
+
const transportKey = buildTransportClientKey(transport);
|
|
1078
|
+
emit(`meta.socket_shutdown_requested:${transportKey}`, {});
|
|
1079
|
+
emit(`meta.fetch.destroy_requested:${transportKey}`, {});
|
|
1080
|
+
return true;
|
|
1081
|
+
}
|
|
1082
|
+
const existingTransport = this.getTransportById(ownerInstance, transport.uuid);
|
|
1083
|
+
if (existingTransport) {
|
|
1084
|
+
Object.assign(existingTransport, transport);
|
|
1085
|
+
} else {
|
|
1086
|
+
ownerInstance.transports.push(transport);
|
|
1087
|
+
}
|
|
1088
|
+
if (ownerInstance.uuid === this.serviceInstanceId) {
|
|
1089
|
+
return true;
|
|
1090
|
+
}
|
|
1091
|
+
const hasRemoteInterest = (!ownerInstance.isFrontend && (this.deputies.has(ownerInstance.serviceName) || this.remoteIntents.has(ownerInstance.serviceName)) || this.remoteSignals.has(ownerInstance.serviceName)) && transport.role === this.getRoutingTransportRole();
|
|
1092
|
+
if (!hasRemoteInterest) {
|
|
1093
|
+
return true;
|
|
1094
|
+
}
|
|
1095
|
+
if (!this.hasTransportClientCreated(ownerInstance, transport.uuid)) {
|
|
1096
|
+
const communicationTypes = Array.from(
|
|
1097
|
+
new Set(
|
|
1098
|
+
this.deputies.get(ownerInstance.serviceName)?.map((descriptor) => descriptor.communicationType) ?? []
|
|
1099
|
+
)
|
|
1100
|
+
);
|
|
1101
|
+
if (!communicationTypes.includes("signal") && this.remoteSignals.has(ownerInstance.serviceName)) {
|
|
1102
|
+
communicationTypes.push("signal");
|
|
1103
|
+
}
|
|
1104
|
+
emit("meta.service_registry.dependee_registered", {
|
|
1105
|
+
serviceName: ownerInstance.serviceName,
|
|
1106
|
+
serviceInstanceId: ownerInstance.uuid,
|
|
1107
|
+
serviceTransportId: transport.uuid,
|
|
1108
|
+
serviceOrigin: transport.origin,
|
|
1109
|
+
transportProtocols: transport.protocols,
|
|
1110
|
+
communicationTypes
|
|
1111
|
+
});
|
|
1112
|
+
this.markTransportClientCreated(ownerInstance, transport.uuid);
|
|
1113
|
+
}
|
|
1114
|
+
return true;
|
|
1115
|
+
},
|
|
1116
|
+
"Handles service transport updates independently from instance rows."
|
|
1117
|
+
).doOn(
|
|
1118
|
+
"global.meta.service_instance_transport.inserted",
|
|
1119
|
+
"global.meta.service_instance_transport.updated",
|
|
1120
|
+
"meta.service_instance_transport.inserted",
|
|
1121
|
+
"meta.service_instance_transport.updated"
|
|
1122
|
+
).attachSignal(
|
|
1123
|
+
"meta.service_registry.dependee_registered",
|
|
1124
|
+
"meta.socket_shutdown_requested",
|
|
1125
|
+
"meta.fetch.destroy_requested"
|
|
1126
|
+
);
|
|
867
1127
|
CadenzaService.createMetaTask(
|
|
868
1128
|
"Track dependee registration",
|
|
869
1129
|
(ctx) => {
|
|
@@ -959,17 +1219,25 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
959
1219
|
this.handleServiceNotRespondingTask = CadenzaService.createMetaTask(
|
|
960
1220
|
"Handle service not responding",
|
|
961
1221
|
(ctx, emit) => {
|
|
962
|
-
const { serviceName,
|
|
1222
|
+
const { serviceName, serviceInstanceId, serviceTransportId } = ctx;
|
|
963
1223
|
const serviceInstances = this.instances.get(serviceName);
|
|
964
|
-
const instances = serviceInstances?.filter(
|
|
965
|
-
(
|
|
966
|
-
|
|
1224
|
+
const instances = serviceInstances?.filter((instance) => {
|
|
1225
|
+
if (serviceInstanceId && instance.uuid === serviceInstanceId) {
|
|
1226
|
+
return true;
|
|
1227
|
+
}
|
|
1228
|
+
if (serviceTransportId) {
|
|
1229
|
+
return instance.transports.some(
|
|
1230
|
+
(transport) => transport.uuid === serviceTransportId
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
return false;
|
|
1234
|
+
});
|
|
967
1235
|
CadenzaService.log(
|
|
968
1236
|
"Service not responding.",
|
|
969
1237
|
{
|
|
970
1238
|
serviceName,
|
|
971
|
-
|
|
972
|
-
|
|
1239
|
+
serviceInstanceId,
|
|
1240
|
+
serviceTransportId,
|
|
973
1241
|
instances
|
|
974
1242
|
},
|
|
975
1243
|
"warning",
|
|
@@ -1010,7 +1278,7 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1010
1278
|
this.handleServiceHandshakeTask = CadenzaService.createMetaTask(
|
|
1011
1279
|
"Handle service handshake",
|
|
1012
1280
|
(ctx, emit) => {
|
|
1013
|
-
const { serviceName, serviceInstanceId
|
|
1281
|
+
const { serviceName, serviceInstanceId } = ctx;
|
|
1014
1282
|
const serviceInstances = this.instances.get(serviceName);
|
|
1015
1283
|
const instance = serviceInstances?.find(
|
|
1016
1284
|
(i) => i.uuid === serviceInstanceId
|
|
@@ -1038,26 +1306,6 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1038
1306
|
uuid: instance.uuid
|
|
1039
1307
|
}
|
|
1040
1308
|
});
|
|
1041
|
-
const instancesToDelete = serviceInstances?.filter(
|
|
1042
|
-
(i) => i.uuid !== serviceInstanceId && i.address === serviceAddress && i.port === servicePort
|
|
1043
|
-
);
|
|
1044
|
-
for (const i of instancesToDelete ?? []) {
|
|
1045
|
-
const indexToDelete = this.instances.get(serviceName)?.indexOf(i) ?? -1;
|
|
1046
|
-
if (indexToDelete >= 0) {
|
|
1047
|
-
this.instances.get(serviceName)?.splice(indexToDelete, 1);
|
|
1048
|
-
}
|
|
1049
|
-
this.unregisterDependee(i.uuid, serviceName);
|
|
1050
|
-
emit("global.meta.service_registry.deleted", {
|
|
1051
|
-
data: {
|
|
1052
|
-
isActive: false,
|
|
1053
|
-
isNonResponsive: false,
|
|
1054
|
-
deleted: true
|
|
1055
|
-
},
|
|
1056
|
-
filter: {
|
|
1057
|
-
uuid: i.uuid
|
|
1058
|
-
}
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
1309
|
return true;
|
|
1062
1310
|
},
|
|
1063
1311
|
"Handles service handshake"
|
|
@@ -1076,16 +1324,13 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1076
1324
|
return false;
|
|
1077
1325
|
}
|
|
1078
1326
|
let applied = this.applyRuntimeStatusReport(report);
|
|
1079
|
-
if (!applied && report.
|
|
1327
|
+
if (!applied && report.transportId && report.transportOrigin) {
|
|
1080
1328
|
if (!this.instances.has(report.serviceName)) {
|
|
1081
1329
|
this.instances.set(report.serviceName, []);
|
|
1082
1330
|
}
|
|
1083
1331
|
this.instances.get(report.serviceName).push({
|
|
1084
1332
|
uuid: report.serviceInstanceId,
|
|
1085
1333
|
serviceName: report.serviceName,
|
|
1086
|
-
address: report.serviceAddress,
|
|
1087
|
-
port: report.servicePort,
|
|
1088
|
-
exposed: !!report.exposed,
|
|
1089
1334
|
isFrontend: !!report.isFrontend,
|
|
1090
1335
|
isActive: report.isActive,
|
|
1091
1336
|
isNonResponsive: report.isNonResponsive,
|
|
@@ -1095,7 +1340,18 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1095
1340
|
acceptingWork: report.acceptingWork,
|
|
1096
1341
|
reportedAt: report.reportedAt,
|
|
1097
1342
|
health: report.health ?? {},
|
|
1098
|
-
isPrimary: false
|
|
1343
|
+
isPrimary: false,
|
|
1344
|
+
transports: [
|
|
1345
|
+
{
|
|
1346
|
+
uuid: report.transportId,
|
|
1347
|
+
serviceInstanceId: report.serviceInstanceId,
|
|
1348
|
+
role: this.getRoutingTransportRole(),
|
|
1349
|
+
origin: report.transportOrigin,
|
|
1350
|
+
protocols: report.transportProtocols && report.transportProtocols.length > 0 ? report.transportProtocols : ["rest", "socket"],
|
|
1351
|
+
securityProfile: null,
|
|
1352
|
+
authStrategy: null
|
|
1353
|
+
}
|
|
1354
|
+
]
|
|
1099
1355
|
});
|
|
1100
1356
|
applied = true;
|
|
1101
1357
|
}
|
|
@@ -1136,21 +1392,9 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1136
1392
|
deleted: !!m.deleted
|
|
1137
1393
|
})
|
|
1138
1394
|
);
|
|
1139
|
-
const serviceInstances = (inquiryResult.serviceInstances ?? []).filter(
|
|
1140
|
-
(instance) =>
|
|
1141
|
-
)
|
|
1142
|
-
uuid: instance.uuid,
|
|
1143
|
-
address: instance.address,
|
|
1144
|
-
port: instance.port,
|
|
1145
|
-
serviceName: instance.serviceName,
|
|
1146
|
-
isActive: !!instance.isActive,
|
|
1147
|
-
isNonResponsive: !!instance.isNonResponsive,
|
|
1148
|
-
isBlocked: !!instance.isBlocked,
|
|
1149
|
-
health: instance.health ?? {},
|
|
1150
|
-
exposed: !!instance.exposed,
|
|
1151
|
-
created: instance.created,
|
|
1152
|
-
isFrontend: !!instance.isFrontend
|
|
1153
|
-
}));
|
|
1395
|
+
const serviceInstances = (inquiryResult.serviceInstances ?? []).map((instance) => normalizeServiceInstanceDescriptor(instance)).filter(
|
|
1396
|
+
(instance) => !!instance && !!instance.isActive && !instance.isNonResponsive && !instance.isBlocked
|
|
1397
|
+
);
|
|
1154
1398
|
return {
|
|
1155
1399
|
...ctx,
|
|
1156
1400
|
signalToTaskMaps,
|
|
@@ -1237,7 +1481,19 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1237
1481
|
const { __serviceName, __triedInstances, __retries, __broadcast } = context;
|
|
1238
1482
|
let retries = __retries ?? 0;
|
|
1239
1483
|
let triedInstances = __triedInstances ?? [];
|
|
1240
|
-
const
|
|
1484
|
+
const preferredRole = this.getRoutingTransportRole();
|
|
1485
|
+
const instances = this.instances.get(__serviceName)?.filter((instance) => {
|
|
1486
|
+
if (!instance.isActive || instance.isNonResponsive || instance.isBlocked) {
|
|
1487
|
+
return false;
|
|
1488
|
+
}
|
|
1489
|
+
return Boolean(
|
|
1490
|
+
this.getRouteableTransport(
|
|
1491
|
+
instance,
|
|
1492
|
+
this.useSocket ? "socket" : "rest",
|
|
1493
|
+
preferredRole
|
|
1494
|
+
) ?? this.getRouteableTransport(instance, "rest", preferredRole)
|
|
1495
|
+
);
|
|
1496
|
+
}).sort((a, b) => {
|
|
1241
1497
|
const leftStatus = this.resolveRuntimeStatusSnapshot(
|
|
1242
1498
|
a.numberOfRunningGraphs ?? 0,
|
|
1243
1499
|
a.isActive,
|
|
@@ -1258,9 +1514,7 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1258
1514
|
});
|
|
1259
1515
|
if (!instances || instances.length === 0 || retries > this.retryCount) {
|
|
1260
1516
|
context.errored = true;
|
|
1261
|
-
context.__error = `No
|
|
1262
|
-
__serviceName
|
|
1263
|
-
)}`;
|
|
1517
|
+
context.__error = this.isFrontend && preferredRole === "public" ? `No public transport available for ${__serviceName}.` : `No routeable ${preferredRole} transport available for ${__serviceName}. Retries: ${retries}.`;
|
|
1264
1518
|
emit(
|
|
1265
1519
|
`meta.service_registry.load_balance_failed:${context.__metadata.__deputyExecId}`,
|
|
1266
1520
|
context
|
|
@@ -1269,10 +1523,21 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1269
1523
|
}
|
|
1270
1524
|
if (__broadcast || instances[0].isFrontend) {
|
|
1271
1525
|
for (const instance of instances) {
|
|
1272
|
-
const
|
|
1526
|
+
const selectedTransport2 = this.getRouteableTransport(instance, "socket", preferredRole) ?? this.getRouteableTransport(instance, "rest", preferredRole);
|
|
1527
|
+
if (!selectedTransport2) {
|
|
1528
|
+
continue;
|
|
1529
|
+
}
|
|
1530
|
+
const transportKey = buildTransportClientKey(selectedTransport2);
|
|
1273
1531
|
emit(
|
|
1274
|
-
|
|
1275
|
-
|
|
1532
|
+
`${this.useSocket && transportSupportsProtocol(selectedTransport2, "socket") ? "meta.service_registry.selected_instance_for_socket" : "meta.service_registry.selected_instance_for_fetch"}:${transportKey}`,
|
|
1533
|
+
{
|
|
1534
|
+
...context,
|
|
1535
|
+
__instance: instance.uuid,
|
|
1536
|
+
__transportId: selectedTransport2.uuid,
|
|
1537
|
+
__transportOrigin: selectedTransport2.origin,
|
|
1538
|
+
__transportProtocols: selectedTransport2.protocols,
|
|
1539
|
+
__fetchId: transportKey
|
|
1540
|
+
}
|
|
1276
1541
|
);
|
|
1277
1542
|
}
|
|
1278
1543
|
return context;
|
|
@@ -1295,12 +1560,25 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1295
1560
|
if (retries > 0) {
|
|
1296
1561
|
selected = instancesToTry[Math.floor(Math.random() * instancesToTry.length)];
|
|
1297
1562
|
}
|
|
1563
|
+
const selectedTransport = this.getRouteableTransport(selected, "socket", preferredRole) ?? this.getRouteableTransport(selected, "rest", preferredRole);
|
|
1564
|
+
if (!selectedTransport) {
|
|
1565
|
+
context.errored = true;
|
|
1566
|
+
context.__error = `No routeable ${preferredRole} transport available for ${selected.serviceName}/${selected.uuid}.`;
|
|
1567
|
+
emit(
|
|
1568
|
+
`meta.service_registry.load_balance_failed:${context.__metadata.__deputyExecId}`,
|
|
1569
|
+
context
|
|
1570
|
+
);
|
|
1571
|
+
return context;
|
|
1572
|
+
}
|
|
1298
1573
|
context.__instance = selected.uuid;
|
|
1299
|
-
context.
|
|
1574
|
+
context.__transportId = selectedTransport.uuid;
|
|
1575
|
+
context.__transportOrigin = selectedTransport.origin;
|
|
1576
|
+
context.__transportProtocols = selectedTransport.protocols;
|
|
1577
|
+
context.__fetchId = buildTransportClientKey(selectedTransport);
|
|
1300
1578
|
context.__triedInstances = triedInstances;
|
|
1301
1579
|
context.__triedInstances.push(selected.uuid);
|
|
1302
1580
|
context.__retries = retries;
|
|
1303
|
-
if (this.useSocket) {
|
|
1581
|
+
if (this.useSocket && transportSupportsProtocol(selectedTransport, "socket")) {
|
|
1304
1582
|
emit(
|
|
1305
1583
|
`meta.service_registry.selected_instance_for_socket:${context.__fetchId}`,
|
|
1306
1584
|
context
|
|
@@ -1492,9 +1770,9 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1492
1770
|
__active: report.isActive,
|
|
1493
1771
|
serviceName: report.serviceName,
|
|
1494
1772
|
serviceInstanceId: report.serviceInstanceId,
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1773
|
+
transportId: report.transportId,
|
|
1774
|
+
transportOrigin: report.transportOrigin,
|
|
1775
|
+
transportProtocols: report.transportProtocols,
|
|
1498
1776
|
isFrontend: report.isFrontend,
|
|
1499
1777
|
reportedAt: report.reportedAt,
|
|
1500
1778
|
numberOfRunningGraphs: report.numberOfRunningGraphs,
|
|
@@ -1537,12 +1815,17 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1537
1815
|
continue;
|
|
1538
1816
|
}
|
|
1539
1817
|
this.runtimeStatusFallbackInFlightByInstance.add(serviceInstanceId);
|
|
1818
|
+
const transport = this.getRouteableTransport(
|
|
1819
|
+
instance,
|
|
1820
|
+
this.useSocket ? "socket" : "rest"
|
|
1821
|
+
);
|
|
1540
1822
|
emit("meta.service_registry.runtime_status_fallback_requested", {
|
|
1541
1823
|
...ctx,
|
|
1542
1824
|
serviceName,
|
|
1543
1825
|
serviceInstanceId,
|
|
1544
|
-
|
|
1545
|
-
|
|
1826
|
+
serviceTransportId: transport?.uuid,
|
|
1827
|
+
serviceOrigin: transport?.origin,
|
|
1828
|
+
transportProtocols: transport?.protocols
|
|
1546
1829
|
});
|
|
1547
1830
|
}
|
|
1548
1831
|
}
|
|
@@ -1576,6 +1859,10 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1576
1859
|
};
|
|
1577
1860
|
} catch (error) {
|
|
1578
1861
|
const instance = this.getInstance(serviceName, serviceInstanceId);
|
|
1862
|
+
const transport = instance ? this.getRouteableTransport(
|
|
1863
|
+
instance,
|
|
1864
|
+
this.useSocket ? "socket" : "rest"
|
|
1865
|
+
) : void 0;
|
|
1579
1866
|
const message = error instanceof Error ? error.message : String(error);
|
|
1580
1867
|
CadenzaService.log(
|
|
1581
1868
|
"Runtime status fallback inquiry failed.",
|
|
@@ -1590,8 +1877,9 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1590
1877
|
...ctx,
|
|
1591
1878
|
serviceName,
|
|
1592
1879
|
serviceInstanceId,
|
|
1593
|
-
|
|
1594
|
-
|
|
1880
|
+
serviceTransportId: transport?.uuid ?? ctx.serviceTransportId,
|
|
1881
|
+
serviceOrigin: transport?.origin ?? ctx.serviceOrigin,
|
|
1882
|
+
transportProtocols: transport?.protocols ?? ctx.transportProtocols,
|
|
1595
1883
|
__error: message,
|
|
1596
1884
|
errored: true
|
|
1597
1885
|
});
|
|
@@ -1704,85 +1992,185 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1704
1992
|
inputSchema: {
|
|
1705
1993
|
type: "object",
|
|
1706
1994
|
properties: {
|
|
1707
|
-
|
|
1708
|
-
type: "
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1995
|
+
data: {
|
|
1996
|
+
type: "object",
|
|
1997
|
+
properties: {
|
|
1998
|
+
uuid: {
|
|
1999
|
+
type: "string"
|
|
2000
|
+
},
|
|
2001
|
+
process_pid: {
|
|
2002
|
+
type: "number"
|
|
2003
|
+
},
|
|
2004
|
+
is_primary: {
|
|
2005
|
+
type: "boolean"
|
|
2006
|
+
},
|
|
2007
|
+
service_name: {
|
|
2008
|
+
type: "string"
|
|
2009
|
+
},
|
|
2010
|
+
is_active: {
|
|
2011
|
+
type: "boolean"
|
|
2012
|
+
},
|
|
2013
|
+
is_frontend: {
|
|
2014
|
+
type: "boolean"
|
|
2015
|
+
},
|
|
2016
|
+
is_database: {
|
|
2017
|
+
type: "boolean"
|
|
2018
|
+
},
|
|
2019
|
+
is_non_responsive: {
|
|
2020
|
+
type: "boolean"
|
|
2021
|
+
},
|
|
2022
|
+
is_blocked: {
|
|
2023
|
+
type: "boolean"
|
|
2024
|
+
},
|
|
2025
|
+
health: {
|
|
2026
|
+
type: "object"
|
|
2027
|
+
}
|
|
2028
|
+
},
|
|
2029
|
+
required: ["uuid", "process_pid", "service_name"]
|
|
1736
2030
|
}
|
|
1737
2031
|
},
|
|
1738
|
-
required: [
|
|
1739
|
-
"id",
|
|
1740
|
-
"address",
|
|
1741
|
-
"port",
|
|
1742
|
-
"process_pid",
|
|
1743
|
-
"service_name",
|
|
1744
|
-
"exposed"
|
|
1745
|
-
]
|
|
2032
|
+
required: ["data"]
|
|
1746
2033
|
},
|
|
1747
|
-
// validateInputContext: true,
|
|
1748
2034
|
outputSchema: {
|
|
1749
2035
|
type: "object",
|
|
1750
2036
|
properties: {
|
|
1751
|
-
|
|
2037
|
+
uuid: {
|
|
1752
2038
|
type: "string"
|
|
1753
2039
|
}
|
|
1754
2040
|
},
|
|
1755
|
-
required: ["
|
|
2041
|
+
required: ["uuid"]
|
|
1756
2042
|
},
|
|
1757
|
-
// validateOutputContext: true,
|
|
1758
2043
|
retryCount: 5,
|
|
1759
2044
|
retryDelay: 1e3
|
|
1760
2045
|
}
|
|
1761
|
-
).doOn("
|
|
2046
|
+
).doOn("meta.service_registry.instance_registration_requested").then(
|
|
1762
2047
|
CadenzaService.createMetaTask(
|
|
1763
2048
|
"Setup service",
|
|
1764
2049
|
(ctx) => {
|
|
1765
|
-
const {
|
|
1766
|
-
|
|
2050
|
+
const {
|
|
2051
|
+
serviceInstance,
|
|
2052
|
+
data,
|
|
2053
|
+
queryData,
|
|
2054
|
+
__useSocket,
|
|
2055
|
+
__retryCount,
|
|
2056
|
+
__isFrontend
|
|
2057
|
+
} = ctx;
|
|
2058
|
+
const normalizedLocalInstance = normalizeServiceInstanceDescriptor({
|
|
2059
|
+
...serviceInstance ?? data ?? queryData?.data ?? {},
|
|
2060
|
+
transports: ctx.transportData ?? []
|
|
2061
|
+
});
|
|
2062
|
+
if (!normalizedLocalInstance?.uuid || !normalizedLocalInstance.serviceName) {
|
|
2063
|
+
return false;
|
|
2064
|
+
}
|
|
2065
|
+
this.serviceInstanceId = normalizedLocalInstance.uuid;
|
|
1767
2066
|
this.instances.set(
|
|
1768
|
-
|
|
1769
|
-
[{ ...
|
|
2067
|
+
normalizedLocalInstance.serviceName,
|
|
2068
|
+
[{ ...normalizedLocalInstance }]
|
|
1770
2069
|
);
|
|
1771
2070
|
this.useSocket = __useSocket;
|
|
1772
2071
|
this.retryCount = __retryCount;
|
|
2072
|
+
this.isFrontend = typeof __isFrontend === "boolean" ? __isFrontend : !!normalizedLocalInstance.isFrontend;
|
|
1773
2073
|
console.log("SETUP SERVICE", this.serviceInstanceId);
|
|
1774
2074
|
return true;
|
|
1775
2075
|
},
|
|
1776
2076
|
"Sets service instance id after insertion"
|
|
1777
|
-
).emits("meta.service_registry.instance_inserted")
|
|
2077
|
+
).emits("meta.service_registry.instance_inserted").then(
|
|
2078
|
+
CadenzaService.createMetaTask(
|
|
2079
|
+
"Prepare service transport inserts",
|
|
2080
|
+
function* (ctx, emit) {
|
|
2081
|
+
const transportData = Array.isArray(ctx.transportData) ? ctx.transportData : [];
|
|
2082
|
+
for (const transport of transportData) {
|
|
2083
|
+
const transportContext = {
|
|
2084
|
+
...ctx,
|
|
2085
|
+
data: {
|
|
2086
|
+
...transport,
|
|
2087
|
+
service_instance_id: transport.service_instance_id ?? ctx.__serviceInstanceId
|
|
2088
|
+
}
|
|
2089
|
+
};
|
|
2090
|
+
emit(
|
|
2091
|
+
"meta.service_registry.transport_registration_requested",
|
|
2092
|
+
transportContext
|
|
2093
|
+
);
|
|
2094
|
+
yield transportContext;
|
|
2095
|
+
}
|
|
2096
|
+
},
|
|
2097
|
+
"Splits declared service transports into individual insert payloads."
|
|
2098
|
+
).attachSignal("meta.service_registry.transport_registration_requested")
|
|
2099
|
+
)
|
|
1778
2100
|
);
|
|
2101
|
+
this.insertServiceTransportTask = CadenzaService.createCadenzaDBInsertTask(
|
|
2102
|
+
"service_instance_transport",
|
|
2103
|
+
{
|
|
2104
|
+
onConflict: {
|
|
2105
|
+
target: ["service_instance_id", "role", "origin"],
|
|
2106
|
+
action: {
|
|
2107
|
+
do: "update",
|
|
2108
|
+
set: {
|
|
2109
|
+
protocols: "excluded",
|
|
2110
|
+
security_profile: "excluded",
|
|
2111
|
+
auth_strategy: "excluded",
|
|
2112
|
+
deleted: "false"
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
},
|
|
2117
|
+
{
|
|
2118
|
+
inputSchema: {
|
|
2119
|
+
type: "object",
|
|
2120
|
+
properties: {
|
|
2121
|
+
data: {
|
|
2122
|
+
type: "object",
|
|
2123
|
+
properties: {
|
|
2124
|
+
uuid: {
|
|
2125
|
+
type: "string"
|
|
2126
|
+
},
|
|
2127
|
+
service_instance_id: {
|
|
2128
|
+
type: "string"
|
|
2129
|
+
},
|
|
2130
|
+
role: {
|
|
2131
|
+
type: "string"
|
|
2132
|
+
},
|
|
2133
|
+
origin: {
|
|
2134
|
+
type: "string"
|
|
2135
|
+
},
|
|
2136
|
+
protocols: {
|
|
2137
|
+
type: "array",
|
|
2138
|
+
items: {
|
|
2139
|
+
type: "string"
|
|
2140
|
+
}
|
|
2141
|
+
},
|
|
2142
|
+
security_profile: {
|
|
2143
|
+
type: "string"
|
|
2144
|
+
},
|
|
2145
|
+
auth_strategy: {
|
|
2146
|
+
type: "string"
|
|
2147
|
+
}
|
|
2148
|
+
},
|
|
2149
|
+
required: ["uuid", "service_instance_id", "role", "origin"]
|
|
2150
|
+
}
|
|
2151
|
+
},
|
|
2152
|
+
required: ["data"]
|
|
2153
|
+
},
|
|
2154
|
+
outputSchema: {
|
|
2155
|
+
type: "object",
|
|
2156
|
+
properties: {
|
|
2157
|
+
uuid: {
|
|
2158
|
+
type: "string"
|
|
2159
|
+
}
|
|
2160
|
+
},
|
|
2161
|
+
required: ["uuid"]
|
|
2162
|
+
},
|
|
2163
|
+
retryCount: 5,
|
|
2164
|
+
retryDelay: 1e3
|
|
2165
|
+
}
|
|
2166
|
+
).doOn("meta.service_registry.transport_registration_requested").emits("meta.service_registry.transport_registered").emitsOnFail("meta.service_registry.transport_registration_failed");
|
|
1779
2167
|
CadenzaService.createMetaTask(
|
|
1780
2168
|
"Handle service creation",
|
|
1781
2169
|
(ctx) => {
|
|
1782
2170
|
if (!ctx.__cadenzaDBConnect) {
|
|
1783
2171
|
ctx.__skipRemoteExecution = true;
|
|
1784
2172
|
}
|
|
1785
|
-
if (isBrowser) {
|
|
2173
|
+
if (isBrowser || ctx.__isFrontend) {
|
|
1786
2174
|
CadenzaService.createMetaTask("Prepare for signal sync", () => {
|
|
1787
2175
|
return {};
|
|
1788
2176
|
}).then(
|
|
@@ -1815,28 +2203,24 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1815
2203
|
for (const service of services) {
|
|
1816
2204
|
const instances = this.instances.get(service).filter((i) => i.isActive);
|
|
1817
2205
|
for (const instance of instances) {
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
const clientCreated = instances?.some(
|
|
1822
|
-
(i) => i.address === address && i.port === port && i.clientCreated && i.isActive
|
|
2206
|
+
const transport = this.getRouteableTransport(
|
|
2207
|
+
instance,
|
|
2208
|
+
this.useSocket ? "socket" : "rest"
|
|
1823
2209
|
);
|
|
1824
|
-
if (!
|
|
2210
|
+
if (!transport) {
|
|
2211
|
+
continue;
|
|
2212
|
+
}
|
|
2213
|
+
if (!this.hasTransportClientCreated(instance, transport.uuid)) {
|
|
1825
2214
|
emit("meta.service_registry.dependee_registered", {
|
|
1826
2215
|
serviceName: service,
|
|
1827
2216
|
serviceInstanceId: instance.uuid,
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
2217
|
+
serviceTransportId: transport.uuid,
|
|
2218
|
+
serviceOrigin: transport.origin,
|
|
2219
|
+
transportProtocols: transport.protocols,
|
|
1831
2220
|
communicationTypes: ["signal"]
|
|
1832
2221
|
});
|
|
2222
|
+
this.markTransportClientCreated(instance, transport.uuid);
|
|
1833
2223
|
}
|
|
1834
|
-
instance.clientCreated = true;
|
|
1835
|
-
instances.forEach((i) => {
|
|
1836
|
-
if (i.address === address && i.port === port) {
|
|
1837
|
-
i.clientCreated = true;
|
|
1838
|
-
}
|
|
1839
|
-
});
|
|
1840
2224
|
}
|
|
1841
2225
|
}
|
|
1842
2226
|
return {};
|
|
@@ -1975,6 +2359,33 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
1975
2359
|
}
|
|
1976
2360
|
return this.getInstance(this.serviceName, this.serviceInstanceId);
|
|
1977
2361
|
}
|
|
2362
|
+
getRoutingTransportRole() {
|
|
2363
|
+
return this.isFrontend ? "public" : "internal";
|
|
2364
|
+
}
|
|
2365
|
+
getTransportById(instance, transportId) {
|
|
2366
|
+
return instance.transports.find((transport) => transport.uuid === transportId);
|
|
2367
|
+
}
|
|
2368
|
+
getRouteableTransport(instance, protocol, role = this.getRoutingTransportRole()) {
|
|
2369
|
+
return getRouteableTransport(instance, role, protocol);
|
|
2370
|
+
}
|
|
2371
|
+
getTransportClientKey(instance, protocol, role = this.getRoutingTransportRole()) {
|
|
2372
|
+
const transport = this.getRouteableTransport(instance, protocol, role);
|
|
2373
|
+
if (!transport) {
|
|
2374
|
+
return null;
|
|
2375
|
+
}
|
|
2376
|
+
return buildTransportClientKey(transport);
|
|
2377
|
+
}
|
|
2378
|
+
hasTransportClientCreated(instance, transportId) {
|
|
2379
|
+
return (instance.clientCreatedTransportIds ?? []).includes(transportId);
|
|
2380
|
+
}
|
|
2381
|
+
markTransportClientCreated(instance, transportId) {
|
|
2382
|
+
if (!instance.clientCreatedTransportIds) {
|
|
2383
|
+
instance.clientCreatedTransportIds = [];
|
|
2384
|
+
}
|
|
2385
|
+
if (!instance.clientCreatedTransportIds.includes(transportId)) {
|
|
2386
|
+
instance.clientCreatedTransportIds.push(transportId);
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
1978
2389
|
registerDependee(serviceName, serviceInstanceId, options = {}) {
|
|
1979
2390
|
if (!serviceName || !serviceInstanceId) {
|
|
1980
2391
|
return;
|
|
@@ -2052,7 +2463,13 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
2052
2463
|
if (!serviceName || !serviceInstanceId) {
|
|
2053
2464
|
return null;
|
|
2054
2465
|
}
|
|
2055
|
-
const
|
|
2466
|
+
const transportId = ctx.transportId ?? ctx.serviceTransportId ?? ctx.serviceTransport?.uuid ?? void 0;
|
|
2467
|
+
const transportOrigin = ctx.transportOrigin ?? ctx.serviceOrigin ?? ctx.serviceTransport?.origin ?? void 0;
|
|
2468
|
+
const transportProtocols = Array.isArray(
|
|
2469
|
+
ctx.transportProtocols ?? ctx.serviceTransport?.protocols
|
|
2470
|
+
) ? (ctx.transportProtocols ?? ctx.serviceTransport?.protocols).map((entry) => String(entry)).filter(
|
|
2471
|
+
(entry) => entry === "rest" || entry === "socket"
|
|
2472
|
+
) : void 0;
|
|
2056
2473
|
const numberOfRunningGraphs = Math.max(
|
|
2057
2474
|
0,
|
|
2058
2475
|
Math.trunc(
|
|
@@ -2071,9 +2488,9 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
2071
2488
|
return {
|
|
2072
2489
|
serviceName,
|
|
2073
2490
|
serviceInstanceId,
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2491
|
+
transportId: typeof transportId === "string" && transportId.trim().length > 0 ? transportId : void 0,
|
|
2492
|
+
transportOrigin: typeof transportOrigin === "string" && transportOrigin.trim().length > 0 ? transportOrigin : void 0,
|
|
2493
|
+
transportProtocols: transportProtocols && transportProtocols.length > 0 ? Array.from(new Set(transportProtocols)) : void 0,
|
|
2077
2494
|
isFrontend: typeof ctx.isFrontend === "boolean" ? ctx.isFrontend : typeof ctx.serviceInstance?.isFrontend === "boolean" ? ctx.serviceInstance.isFrontend : void 0,
|
|
2078
2495
|
reportedAt: ctx.reportedAt ?? (typeof ctx.__reportedAt === "string" ? ctx.__reportedAt : void 0) ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2079
2496
|
state: ctx.state === "healthy" || ctx.state === "degraded" || ctx.state === "overloaded" || ctx.state === "unavailable" ? ctx.state : resolved.state,
|
|
@@ -2090,14 +2507,23 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
2090
2507
|
if (!instance) {
|
|
2091
2508
|
return false;
|
|
2092
2509
|
}
|
|
2093
|
-
if (report.
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2510
|
+
if (report.transportId && report.transportOrigin) {
|
|
2511
|
+
const protocols = report.transportProtocols && report.transportProtocols.length > 0 ? report.transportProtocols : ["rest", "socket"];
|
|
2512
|
+
const existingTransport = this.getTransportById(instance, report.transportId);
|
|
2513
|
+
if (existingTransport) {
|
|
2514
|
+
existingTransport.origin = report.transportOrigin;
|
|
2515
|
+
existingTransport.protocols = protocols;
|
|
2516
|
+
} else {
|
|
2517
|
+
instance.transports.push({
|
|
2518
|
+
uuid: report.transportId,
|
|
2519
|
+
serviceInstanceId: report.serviceInstanceId,
|
|
2520
|
+
role: this.getRoutingTransportRole(),
|
|
2521
|
+
origin: report.transportOrigin,
|
|
2522
|
+
protocols,
|
|
2523
|
+
securityProfile: null,
|
|
2524
|
+
authStrategy: null
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2101
2527
|
}
|
|
2102
2528
|
if (typeof report.isFrontend === "boolean") {
|
|
2103
2529
|
instance.isFrontend = report.isFrontend;
|
|
@@ -2140,9 +2566,21 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
2140
2566
|
const report = {
|
|
2141
2567
|
serviceName: this.serviceName,
|
|
2142
2568
|
serviceInstanceId: this.serviceInstanceId,
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2569
|
+
transportId: this.getRouteableTransport(
|
|
2570
|
+
localInstance,
|
|
2571
|
+
this.useSocket ? "socket" : "rest",
|
|
2572
|
+
"internal"
|
|
2573
|
+
)?.uuid ?? void 0,
|
|
2574
|
+
transportOrigin: this.getRouteableTransport(
|
|
2575
|
+
localInstance,
|
|
2576
|
+
this.useSocket ? "socket" : "rest",
|
|
2577
|
+
"internal"
|
|
2578
|
+
)?.origin ?? void 0,
|
|
2579
|
+
transportProtocols: this.getRouteableTransport(
|
|
2580
|
+
localInstance,
|
|
2581
|
+
this.useSocket ? "socket" : "rest",
|
|
2582
|
+
"internal"
|
|
2583
|
+
)?.protocols ?? void 0,
|
|
2146
2584
|
isFrontend: localInstance.isFrontend,
|
|
2147
2585
|
reportedAt,
|
|
2148
2586
|
state: snapshot.state,
|
|
@@ -2357,6 +2795,7 @@ var ServiceRegistry = class _ServiceRegistry {
|
|
|
2357
2795
|
this.numberOfRunningGraphs = 0;
|
|
2358
2796
|
this.runtimeStatusHeartbeatStarted = false;
|
|
2359
2797
|
this.lastRuntimeStatusSnapshot = null;
|
|
2798
|
+
this.isFrontend = false;
|
|
2360
2799
|
}
|
|
2361
2800
|
};
|
|
2362
2801
|
|
|
@@ -2528,13 +2967,10 @@ var RestController = class _RestController {
|
|
|
2528
2967
|
CadenzaService.createMetaTask(
|
|
2529
2968
|
"Setup Express app security",
|
|
2530
2969
|
(ctx, emit) => {
|
|
2531
|
-
if (isBrowser) {
|
|
2532
|
-
emit("meta.
|
|
2970
|
+
if (isBrowser || ctx.__isFrontend) {
|
|
2971
|
+
emit("meta.service_registry.instance_registration_requested", {
|
|
2533
2972
|
data: {
|
|
2534
2973
|
uuid: ctx.__serviceInstanceId,
|
|
2535
|
-
address: `browser:${ctx.__serviceInstanceId}`,
|
|
2536
|
-
port: 0,
|
|
2537
|
-
exposed: false,
|
|
2538
2974
|
process_pid: 1,
|
|
2539
2975
|
service_name: ctx.__serviceName,
|
|
2540
2976
|
is_frontend: true,
|
|
@@ -2543,6 +2979,7 @@ var RestController = class _RestController {
|
|
|
2543
2979
|
is_blocked: false,
|
|
2544
2980
|
health: {}
|
|
2545
2981
|
},
|
|
2982
|
+
transportData: [],
|
|
2546
2983
|
...ctx
|
|
2547
2984
|
});
|
|
2548
2985
|
return;
|
|
@@ -2615,7 +3052,7 @@ var RestController = class _RestController {
|
|
|
2615
3052
|
return { ...ctx, __app: app };
|
|
2616
3053
|
},
|
|
2617
3054
|
"Sets up the Express server according to the security profile"
|
|
2618
|
-
).attachSignal("meta.
|
|
3055
|
+
).attachSignal("meta.service_registry.instance_registration_requested").then(
|
|
2619
3056
|
CadenzaService.createMetaTask(
|
|
2620
3057
|
"Define RestServer",
|
|
2621
3058
|
(ctx) => {
|
|
@@ -2735,28 +3172,32 @@ var RestController = class _RestController {
|
|
|
2735
3172
|
CadenzaService.createMetaTask(
|
|
2736
3173
|
"Configure network",
|
|
2737
3174
|
async (ctx) => {
|
|
2738
|
-
let
|
|
2739
|
-
let
|
|
2740
|
-
|
|
3175
|
+
let httpOrigin = null;
|
|
3176
|
+
let httpsOrigin = null;
|
|
3177
|
+
const resolveBoundAddress = (server) => {
|
|
3178
|
+
if (typeof server?.address() === "string") {
|
|
3179
|
+
return server.address();
|
|
3180
|
+
}
|
|
3181
|
+
if (server?.address()?.address === "::") {
|
|
3182
|
+
if (process.env.NODE_ENV === "development") {
|
|
3183
|
+
return "localhost";
|
|
3184
|
+
}
|
|
3185
|
+
if (process.env.IS_DOCKER === "true") {
|
|
3186
|
+
return process.env.CADENZA_SERVER_URL || "localhost";
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
return server?.address()?.address || "localhost";
|
|
3190
|
+
};
|
|
2741
3191
|
const createHttpServer = async (ctx2) => {
|
|
2742
3192
|
await new Promise((resolve) => {
|
|
2743
3193
|
const server = import_node_http.default.createServer(ctx2.__app);
|
|
2744
3194
|
ctx2.httpServer = server;
|
|
2745
3195
|
server.listen(ctx2.__port, () => {
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
} else if (process.env.IS_DOCKER === "true") {
|
|
2752
|
-
address = process.env.CADENZA_SERVER_URL || "localhost";
|
|
2753
|
-
}
|
|
2754
|
-
} else {
|
|
2755
|
-
address = server?.address()?.address || "undefined";
|
|
2756
|
-
}
|
|
2757
|
-
console.log(
|
|
2758
|
-
`Server is running on ${address}:${port}`
|
|
2759
|
-
);
|
|
3196
|
+
const addressInfo = server.address();
|
|
3197
|
+
const address = resolveBoundAddress(server);
|
|
3198
|
+
const port = typeof addressInfo === "object" && addressInfo ? addressInfo.port || ctx2.__port : ctx2.__port;
|
|
3199
|
+
httpOrigin = `http://${address}:${port}`;
|
|
3200
|
+
console.log(`Server is running on ${httpOrigin}`);
|
|
2760
3201
|
resolve(address);
|
|
2761
3202
|
});
|
|
2762
3203
|
CadenzaService.createMetaTask(
|
|
@@ -2782,22 +3223,12 @@ var RestController = class _RestController {
|
|
|
2782
3223
|
ctx2.__app
|
|
2783
3224
|
);
|
|
2784
3225
|
ctx2.httpsServer = httpsServer;
|
|
2785
|
-
ctx2.__port = 443;
|
|
2786
|
-
port = 443;
|
|
2787
3226
|
httpsServer.listen(443, () => {
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
}
|
|
2794
|
-
} else {
|
|
2795
|
-
address = httpsServer?.address()?.address || "";
|
|
2796
|
-
}
|
|
2797
|
-
exposed = true;
|
|
2798
|
-
console.log(
|
|
2799
|
-
`HTTPS Server is running on ${address}:443`
|
|
2800
|
-
);
|
|
3227
|
+
const addressInfo = httpsServer.address();
|
|
3228
|
+
const address = resolveBoundAddress(httpsServer);
|
|
3229
|
+
const port = typeof addressInfo === "object" && addressInfo ? addressInfo.port || 443 : 443;
|
|
3230
|
+
httpsOrigin = `https://${address}:${port}`;
|
|
3231
|
+
console.log(`HTTPS Server is running on ${httpsOrigin}`);
|
|
2801
3232
|
resolve(address);
|
|
2802
3233
|
});
|
|
2803
3234
|
CadenzaService.createMetaTask(
|
|
@@ -2817,11 +3248,34 @@ var RestController = class _RestController {
|
|
|
2817
3248
|
} else if (ctx.__networkMode === "auto") {
|
|
2818
3249
|
await createHttpServer(ctx);
|
|
2819
3250
|
}
|
|
3251
|
+
const declaredTransports = Array.isArray(ctx.__declaredTransports) ? ctx.__declaredTransports : [];
|
|
3252
|
+
const hasExplicitInternalTransport = declaredTransports.some(
|
|
3253
|
+
(transport) => transport.role === "internal"
|
|
3254
|
+
);
|
|
3255
|
+
const transportData = declaredTransports.map((transport) => ({
|
|
3256
|
+
uuid: transport.uuid,
|
|
3257
|
+
service_instance_id: ctx.__serviceInstanceId,
|
|
3258
|
+
role: transport.role,
|
|
3259
|
+
origin: transport.origin,
|
|
3260
|
+
protocols: transport.protocols ?? ["rest", "socket"],
|
|
3261
|
+
...transport.securityProfile ? { security_profile: transport.securityProfile } : {},
|
|
3262
|
+
...transport.authStrategy ? { auth_strategy: transport.authStrategy } : {}
|
|
3263
|
+
}));
|
|
3264
|
+
if (!hasExplicitInternalTransport) {
|
|
3265
|
+
const internalOrigin = httpOrigin ?? httpsOrigin;
|
|
3266
|
+
if (internalOrigin) {
|
|
3267
|
+
transportData.unshift({
|
|
3268
|
+
uuid: `${ctx.__serviceInstanceId}-internal-auto`,
|
|
3269
|
+
service_instance_id: ctx.__serviceInstanceId,
|
|
3270
|
+
role: "internal",
|
|
3271
|
+
origin: internalOrigin,
|
|
3272
|
+
protocols: ["rest", "socket"],
|
|
3273
|
+
...ctx.__securityProfile ? { security_profile: ctx.__securityProfile } : {}
|
|
3274
|
+
});
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
2820
3277
|
ctx.data = {
|
|
2821
3278
|
uuid: ctx.__serviceInstanceId,
|
|
2822
|
-
address,
|
|
2823
|
-
port,
|
|
2824
|
-
exposed,
|
|
2825
3279
|
process_pid: process.pid,
|
|
2826
3280
|
service_name: ctx.__serviceName,
|
|
2827
3281
|
is_active: true,
|
|
@@ -2830,7 +3284,12 @@ var RestController = class _RestController {
|
|
|
2830
3284
|
is_blocked: false,
|
|
2831
3285
|
health: {}
|
|
2832
3286
|
};
|
|
3287
|
+
ctx.transportData = transportData;
|
|
2833
3288
|
delete ctx.__app;
|
|
3289
|
+
CadenzaService.emit(
|
|
3290
|
+
"meta.service_registry.instance_registration_requested",
|
|
3291
|
+
ctx
|
|
3292
|
+
);
|
|
2834
3293
|
return ctx;
|
|
2835
3294
|
},
|
|
2836
3295
|
"Configures network mode"
|
|
@@ -2880,10 +3339,12 @@ var RestController = class _RestController {
|
|
|
2880
3339
|
CadenzaService.createMetaTask(
|
|
2881
3340
|
"Setup fetch client",
|
|
2882
3341
|
(ctx) => {
|
|
2883
|
-
const
|
|
2884
|
-
const
|
|
2885
|
-
const
|
|
2886
|
-
|
|
3342
|
+
const serviceName = String(ctx.serviceName ?? "");
|
|
3343
|
+
const URL2 = String(ctx.serviceOrigin ?? "");
|
|
3344
|
+
const fetchId = String(ctx.serviceTransportId ?? "");
|
|
3345
|
+
if (!serviceName || !URL2 || !fetchId) {
|
|
3346
|
+
return false;
|
|
3347
|
+
}
|
|
2887
3348
|
const fetchDiagnostics = this.ensureFetchClientDiagnostics(
|
|
2888
3349
|
fetchId,
|
|
2889
3350
|
serviceName,
|
|
@@ -3135,18 +3596,18 @@ var RestController = class _RestController {
|
|
|
3135
3596
|
serviceName,
|
|
3136
3597
|
serviceInstanceId,
|
|
3137
3598
|
communicationTypes,
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3599
|
+
serviceTransportId,
|
|
3600
|
+
serviceOrigin,
|
|
3601
|
+
transportProtocols
|
|
3141
3602
|
} = ctx;
|
|
3142
|
-
const fetchId =
|
|
3603
|
+
const fetchId = String(serviceTransportId ?? "");
|
|
3143
3604
|
emit(`meta.fetch.handshake_requested:${fetchId}`, {
|
|
3144
3605
|
serviceInstanceId,
|
|
3145
3606
|
serviceName,
|
|
3146
3607
|
communicationTypes,
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3608
|
+
serviceTransportId,
|
|
3609
|
+
serviceOrigin,
|
|
3610
|
+
transportProtocols,
|
|
3150
3611
|
handshakeData: {
|
|
3151
3612
|
instanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
3152
3613
|
serviceName: CadenzaService.serviceRegistry.serviceName
|
|
@@ -3329,9 +3790,8 @@ var RestController = class _RestController {
|
|
|
3329
3790
|
};
|
|
3330
3791
|
|
|
3331
3792
|
// src/network/SocketController.ts
|
|
3332
|
-
var import_socket = require("socket.io");
|
|
3333
3793
|
var import_rate_limiter_flexible2 = require("rate-limiter-flexible");
|
|
3334
|
-
var
|
|
3794
|
+
var import_socket = require("socket.io-client");
|
|
3335
3795
|
|
|
3336
3796
|
// src/network/socketClientUtils.ts
|
|
3337
3797
|
var waitForSocketConnection = async (socket, timeoutMs, createError) => {
|
|
@@ -3372,6 +3832,13 @@ var waitForSocketConnection = async (socket, timeoutMs, createError) => {
|
|
|
3372
3832
|
};
|
|
3373
3833
|
|
|
3374
3834
|
// src/network/SocketController.ts
|
|
3835
|
+
var dynamicImport = new Function(
|
|
3836
|
+
"specifier",
|
|
3837
|
+
"return import(specifier);"
|
|
3838
|
+
);
|
|
3839
|
+
async function importNodeModule(specifier) {
|
|
3840
|
+
return dynamicImport(specifier);
|
|
3841
|
+
}
|
|
3375
3842
|
var SocketController = class _SocketController {
|
|
3376
3843
|
constructor() {
|
|
3377
3844
|
this.diagnosticsErrorHistoryLimit = 100;
|
|
@@ -3396,9 +3863,9 @@ var SocketController = class _SocketController {
|
|
|
3396
3863
|
serviceInstanceId: "",
|
|
3397
3864
|
communicationTypes: [],
|
|
3398
3865
|
serviceName: "",
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3866
|
+
serviceTransportId: "",
|
|
3867
|
+
serviceOrigin: "",
|
|
3868
|
+
transportProtocols: [],
|
|
3402
3869
|
url: "",
|
|
3403
3870
|
socketId: null,
|
|
3404
3871
|
connected: false,
|
|
@@ -3571,7 +4038,7 @@ var SocketController = class _SocketController {
|
|
|
3571
4038
|
const setupSocketServerTask = CadenzaService.createMetaTask(
|
|
3572
4039
|
"Setup SocketServer",
|
|
3573
4040
|
this.socketServerActor.task(
|
|
3574
|
-
({ state, runtimeState, input, actor, setState, setRuntimeState, emit }) => {
|
|
4041
|
+
async ({ state, runtimeState, input, actor, setState, setRuntimeState, emit }) => {
|
|
3575
4042
|
const serverKey = this.resolveSocketServerKey(input) ?? actor.key ?? this.socketServerDefaultKey;
|
|
3576
4043
|
const shouldUseSocket = Boolean(input.__useSocket);
|
|
3577
4044
|
if (!shouldUseSocket) {
|
|
@@ -3590,7 +4057,9 @@ var SocketController = class _SocketController {
|
|
|
3590
4057
|
}
|
|
3591
4058
|
let runtimeHandle = runtimeState;
|
|
3592
4059
|
if (!runtimeHandle) {
|
|
3593
|
-
runtimeHandle = this.createSocketServerRuntimeHandleFromContext(
|
|
4060
|
+
runtimeHandle = await this.createSocketServerRuntimeHandleFromContext(
|
|
4061
|
+
input
|
|
4062
|
+
);
|
|
3594
4063
|
setRuntimeState(runtimeHandle);
|
|
3595
4064
|
}
|
|
3596
4065
|
const profile = String(input.__securityProfile ?? state.securityProfile ?? "medium");
|
|
@@ -3848,21 +4317,21 @@ var SocketController = class _SocketController {
|
|
|
3848
4317
|
if (input.serviceName !== void 0) {
|
|
3849
4318
|
next.serviceName = String(input.serviceName);
|
|
3850
4319
|
}
|
|
3851
|
-
if (input.
|
|
3852
|
-
next.
|
|
4320
|
+
if (input.serviceTransportId !== void 0) {
|
|
4321
|
+
next.serviceTransportId = String(input.serviceTransportId);
|
|
3853
4322
|
}
|
|
3854
4323
|
if (input.serviceInstanceId !== void 0) {
|
|
3855
4324
|
next.serviceInstanceId = String(input.serviceInstanceId);
|
|
3856
4325
|
}
|
|
3857
|
-
if (input.
|
|
3858
|
-
next.
|
|
4326
|
+
if (input.serviceOrigin !== void 0) {
|
|
4327
|
+
next.serviceOrigin = String(input.serviceOrigin);
|
|
4328
|
+
}
|
|
4329
|
+
if (input.transportProtocols !== void 0) {
|
|
4330
|
+
next.transportProtocols = Array.isArray(input.transportProtocols) ? input.transportProtocols.map((entry) => String(entry)) : [];
|
|
3859
4331
|
}
|
|
3860
4332
|
if (input.url !== void 0) {
|
|
3861
4333
|
next.url = String(input.url);
|
|
3862
4334
|
}
|
|
3863
|
-
if (input.servicePort !== void 0) {
|
|
3864
|
-
next.servicePort = Number(input.servicePort);
|
|
3865
|
-
}
|
|
3866
4335
|
if (input.fetchId !== void 0) {
|
|
3867
4336
|
next.fetchId = String(input.fetchId);
|
|
3868
4337
|
}
|
|
@@ -3906,25 +4375,24 @@ var SocketController = class _SocketController {
|
|
|
3906
4375
|
input.communicationTypes
|
|
3907
4376
|
);
|
|
3908
4377
|
const serviceName = String(input.serviceName ?? "");
|
|
3909
|
-
const
|
|
3910
|
-
const
|
|
3911
|
-
const
|
|
3912
|
-
if (!
|
|
4378
|
+
const serviceTransportId = String(input.serviceTransportId ?? "");
|
|
4379
|
+
const serviceOrigin = String(input.serviceOrigin ?? "");
|
|
4380
|
+
const parsedOrigin = parseTransportOrigin(serviceOrigin);
|
|
4381
|
+
if (!serviceTransportId || !serviceOrigin || !parsedOrigin) {
|
|
3913
4382
|
CadenzaService.log(
|
|
3914
|
-
"Socket client setup skipped due to missing
|
|
4383
|
+
"Socket client setup skipped due to missing transport origin",
|
|
3915
4384
|
{
|
|
3916
4385
|
serviceName,
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
protocol
|
|
4386
|
+
serviceTransportId,
|
|
4387
|
+
serviceOrigin
|
|
3920
4388
|
},
|
|
3921
4389
|
"warning"
|
|
3922
4390
|
);
|
|
3923
4391
|
return false;
|
|
3924
4392
|
}
|
|
3925
|
-
const socketProtocol = protocol === "https" ? "wss" : "ws";
|
|
3926
|
-
const url = `${socketProtocol}://${
|
|
3927
|
-
const fetchId =
|
|
4393
|
+
const socketProtocol = parsedOrigin.protocol === "https" ? "wss" : "ws";
|
|
4394
|
+
const url = `${socketProtocol}://${parsedOrigin.hostname}:${parsedOrigin.port}`;
|
|
4395
|
+
const fetchId = serviceTransportId;
|
|
3928
4396
|
const applySessionOperation = (operation, patch = {}) => {
|
|
3929
4397
|
CadenzaService.emit("meta.socket_client.session_operation_requested", {
|
|
3930
4398
|
fetchId,
|
|
@@ -3933,9 +4401,9 @@ var SocketController = class _SocketController {
|
|
|
3933
4401
|
serviceInstanceId,
|
|
3934
4402
|
communicationTypes,
|
|
3935
4403
|
serviceName,
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
4404
|
+
serviceTransportId,
|
|
4405
|
+
serviceOrigin,
|
|
4406
|
+
transportProtocols: input.transportProtocols,
|
|
3939
4407
|
url
|
|
3940
4408
|
});
|
|
3941
4409
|
};
|
|
@@ -3954,9 +4422,9 @@ var SocketController = class _SocketController {
|
|
|
3954
4422
|
serviceInstanceId,
|
|
3955
4423
|
communicationTypes,
|
|
3956
4424
|
serviceName,
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
4425
|
+
serviceTransportId,
|
|
4426
|
+
serviceOrigin,
|
|
4427
|
+
transportProtocols: Array.isArray(input.transportProtocols) ? input.transportProtocols.map((entry) => String(entry)) : [],
|
|
3960
4428
|
url,
|
|
3961
4429
|
destroyed: false,
|
|
3962
4430
|
updatedAt: Date.now()
|
|
@@ -4284,8 +4752,8 @@ var SocketController = class _SocketController {
|
|
|
4284
4752
|
);
|
|
4285
4753
|
CadenzaService.emit(`meta.socket_client.disconnected:${fetchId}`, {
|
|
4286
4754
|
serviceName,
|
|
4287
|
-
|
|
4288
|
-
|
|
4755
|
+
serviceTransportId,
|
|
4756
|
+
serviceOrigin
|
|
4289
4757
|
});
|
|
4290
4758
|
runtimeHandle.handshake = false;
|
|
4291
4759
|
});
|
|
@@ -4306,7 +4774,7 @@ var SocketController = class _SocketController {
|
|
|
4306
4774
|
{
|
|
4307
4775
|
serviceInstanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
4308
4776
|
serviceName: CadenzaService.serviceRegistry.serviceName,
|
|
4309
|
-
isFrontend: isBrowser,
|
|
4777
|
+
isFrontend: CadenzaService.serviceRegistry.isFrontend || isBrowser,
|
|
4310
4778
|
__status: "success"
|
|
4311
4779
|
},
|
|
4312
4780
|
1e4,
|
|
@@ -4484,9 +4952,9 @@ var SocketController = class _SocketController {
|
|
|
4484
4952
|
serviceInstanceId,
|
|
4485
4953
|
serviceName,
|
|
4486
4954
|
communicationTypes,
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4955
|
+
serviceTransportId,
|
|
4956
|
+
serviceOrigin,
|
|
4957
|
+
transportProtocols: input.transportProtocols,
|
|
4490
4958
|
handshakeData: {
|
|
4491
4959
|
instanceId: CadenzaService.serviceRegistry.serviceInstanceId,
|
|
4492
4960
|
serviceName: CadenzaService.serviceRegistry.serviceName
|
|
@@ -4525,32 +4993,21 @@ var SocketController = class _SocketController {
|
|
|
4525
4993
|
if (explicitFetchId) {
|
|
4526
4994
|
return explicitFetchId;
|
|
4527
4995
|
}
|
|
4528
|
-
const
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
return void 0;
|
|
4533
|
-
}
|
|
4534
|
-
return `${serviceAddress}_${port}`;
|
|
4535
|
-
}
|
|
4536
|
-
resolveServicePort(protocol, rawPort) {
|
|
4537
|
-
if (protocol === "https") {
|
|
4538
|
-
return 443;
|
|
4539
|
-
}
|
|
4540
|
-
const parsed = Number(rawPort);
|
|
4541
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
4542
|
-
return void 0;
|
|
4543
|
-
}
|
|
4544
|
-
return Math.trunc(parsed);
|
|
4996
|
+
const transportId = String(
|
|
4997
|
+
input.serviceTransportId ?? input.transportId ?? ""
|
|
4998
|
+
).trim();
|
|
4999
|
+
return transportId || void 0;
|
|
4545
5000
|
}
|
|
4546
|
-
createSocketServerRuntimeHandleFromContext(context) {
|
|
5001
|
+
async createSocketServerRuntimeHandleFromContext(context) {
|
|
4547
5002
|
const baseServer = context.httpsServer ?? context.httpServer;
|
|
4548
5003
|
if (!baseServer) {
|
|
4549
5004
|
throw new Error(
|
|
4550
5005
|
"Socket server runtime setup requires either httpsServer or httpServer"
|
|
4551
5006
|
);
|
|
4552
5007
|
}
|
|
4553
|
-
const
|
|
5008
|
+
const socketServerModule = await importNodeModule("socket.io");
|
|
5009
|
+
const Server = socketServerModule.Server;
|
|
5010
|
+
const server = new Server(baseServer, {
|
|
4554
5011
|
pingInterval: 3e4,
|
|
4555
5012
|
pingTimeout: 2e4,
|
|
4556
5013
|
maxHttpBufferSize: 1e7,
|
|
@@ -4583,7 +5040,7 @@ var SocketController = class _SocketController {
|
|
|
4583
5040
|
createSocketClientRuntimeHandle(url) {
|
|
4584
5041
|
return {
|
|
4585
5042
|
url,
|
|
4586
|
-
socket: (0,
|
|
5043
|
+
socket: (0, import_socket.io)(url, {
|
|
4587
5044
|
reconnection: true,
|
|
4588
5045
|
reconnectionAttempts: 5,
|
|
4589
5046
|
reconnectionDelay: 2e3,
|
|
@@ -4840,16 +5297,140 @@ var SignalController = class _SignalController {
|
|
|
4840
5297
|
service_name: CadenzaService.serviceRegistry.serviceName,
|
|
4841
5298
|
service_instance_id: CadenzaService.serviceRegistry.serviceInstanceId
|
|
4842
5299
|
}
|
|
4843
|
-
};
|
|
4844
|
-
},
|
|
4845
|
-
"",
|
|
4846
|
-
{ isSubMeta: true, concurrency: 100 }
|
|
4847
|
-
).doOn("sub_meta.signal_broker.emitting_signal").emits("global.sub_meta.signal_controller.signal_emitted");
|
|
4848
|
-
}
|
|
4849
|
-
};
|
|
5300
|
+
};
|
|
5301
|
+
},
|
|
5302
|
+
"",
|
|
5303
|
+
{ isSubMeta: true, concurrency: 100 }
|
|
5304
|
+
).doOn("sub_meta.signal_broker.emitting_signal").emits("global.sub_meta.signal_controller.signal_emitted");
|
|
5305
|
+
}
|
|
5306
|
+
};
|
|
5307
|
+
|
|
5308
|
+
// src/graph/controllers/registerActorSessionPersistence.ts
|
|
5309
|
+
var import_core3 = require("@cadenza.io/core");
|
|
5310
|
+
function registerActorSessionPersistenceTasks() {
|
|
5311
|
+
if (CadenzaService.get("Persist actor session state")) {
|
|
5312
|
+
return;
|
|
5313
|
+
}
|
|
5314
|
+
const actorSessionStateInsertTask = CadenzaService.get("dbInsertActorSessionState") ?? CadenzaService.get("Insert actor_session_state in CadenzaDB") ?? CadenzaService.createCadenzaDBInsertTask(
|
|
5315
|
+
"actor_session_state",
|
|
5316
|
+
{},
|
|
5317
|
+
{ concurrency: 100, isSubMeta: true }
|
|
5318
|
+
);
|
|
5319
|
+
const validateActorSessionStatePersistenceTask = CadenzaService.createMetaTask(
|
|
5320
|
+
"Validate actor session state persistence",
|
|
5321
|
+
(ctx) => {
|
|
5322
|
+
if (ctx.errored || ctx.failed || ctx.__success !== true) {
|
|
5323
|
+
throw new Error(
|
|
5324
|
+
String(
|
|
5325
|
+
ctx.__error ?? ctx.error ?? "actor_session_state persistence query failed"
|
|
5326
|
+
)
|
|
5327
|
+
);
|
|
5328
|
+
}
|
|
5329
|
+
const rowCount = Number(ctx.rowCount ?? 0);
|
|
5330
|
+
if (!Number.isFinite(rowCount) || rowCount <= 0) {
|
|
5331
|
+
throw new Error(
|
|
5332
|
+
"actor_session_state persistence did not affect any rows (possible stale durable_version)"
|
|
5333
|
+
);
|
|
5334
|
+
}
|
|
5335
|
+
return {
|
|
5336
|
+
__success: true,
|
|
5337
|
+
persisted: true,
|
|
5338
|
+
actor_name: ctx.actor_name,
|
|
5339
|
+
actor_version: ctx.actor_version,
|
|
5340
|
+
actor_key: ctx.actor_key,
|
|
5341
|
+
service_name: ctx.service_name,
|
|
5342
|
+
durable_version: ctx.durable_version
|
|
5343
|
+
};
|
|
5344
|
+
},
|
|
5345
|
+
"Enforces strict actor session persistence success contract.",
|
|
5346
|
+
{ isSubMeta: true, concurrency: 100 }
|
|
5347
|
+
);
|
|
5348
|
+
const insertAndValidateActorSessionStateTask = actorSessionStateInsertTask.then(
|
|
5349
|
+
validateActorSessionStatePersistenceTask
|
|
5350
|
+
);
|
|
5351
|
+
CadenzaService.createMetaTask(
|
|
5352
|
+
"Persist actor session state",
|
|
5353
|
+
(ctx) => {
|
|
5354
|
+
const actorName = typeof ctx.actor_name === "string" ? ctx.actor_name.trim() : "";
|
|
5355
|
+
const actorKey = typeof ctx.actor_key === "string" ? ctx.actor_key.trim() : "";
|
|
5356
|
+
const actorVersion = Number(ctx.actor_version ?? 1);
|
|
5357
|
+
const durableVersion = Number(ctx.durable_version);
|
|
5358
|
+
if (!actorName) {
|
|
5359
|
+
throw new Error("actor_name is required for actor session persistence");
|
|
5360
|
+
}
|
|
5361
|
+
if (!actorKey) {
|
|
5362
|
+
throw new Error("actor_key is required for actor session persistence");
|
|
5363
|
+
}
|
|
5364
|
+
if (!Number.isInteger(actorVersion) || actorVersion < 1) {
|
|
5365
|
+
throw new Error("actor_version must be a positive integer");
|
|
5366
|
+
}
|
|
5367
|
+
if (!Number.isInteger(durableVersion) || durableVersion < 0) {
|
|
5368
|
+
throw new Error("durable_version must be a non-negative integer");
|
|
5369
|
+
}
|
|
5370
|
+
if (typeof ctx.durable_state !== "object" || ctx.durable_state === null || Array.isArray(ctx.durable_state)) {
|
|
5371
|
+
throw new Error("durable_state must be a non-null object");
|
|
5372
|
+
}
|
|
5373
|
+
const serviceName = CadenzaService.serviceRegistry.serviceName;
|
|
5374
|
+
if (!serviceName) {
|
|
5375
|
+
throw new Error("service_name is not available for actor session persistence");
|
|
5376
|
+
}
|
|
5377
|
+
let expiresAt = null;
|
|
5378
|
+
if (ctx.expires_at !== void 0 && ctx.expires_at !== null) {
|
|
5379
|
+
if (ctx.expires_at instanceof Date) {
|
|
5380
|
+
expiresAt = ctx.expires_at.toISOString();
|
|
5381
|
+
} else if (typeof ctx.expires_at === "string" && ctx.expires_at.trim().length > 0) {
|
|
5382
|
+
expiresAt = ctx.expires_at;
|
|
5383
|
+
} else {
|
|
5384
|
+
throw new Error("expires_at must be null, Date, or non-empty string");
|
|
5385
|
+
}
|
|
5386
|
+
}
|
|
5387
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5388
|
+
return {
|
|
5389
|
+
...ctx,
|
|
5390
|
+
actor_name: actorName,
|
|
5391
|
+
actor_key: actorKey,
|
|
5392
|
+
actor_version: actorVersion,
|
|
5393
|
+
durable_version: durableVersion,
|
|
5394
|
+
expires_at: expiresAt,
|
|
5395
|
+
service_name: serviceName,
|
|
5396
|
+
queryData: {
|
|
5397
|
+
data: {
|
|
5398
|
+
actor_name: actorName,
|
|
5399
|
+
actor_version: actorVersion,
|
|
5400
|
+
actor_key: actorKey,
|
|
5401
|
+
service_name: serviceName,
|
|
5402
|
+
durable_state: ctx.durable_state,
|
|
5403
|
+
durable_version: durableVersion,
|
|
5404
|
+
expires_at: expiresAt,
|
|
5405
|
+
updated: updatedAt
|
|
5406
|
+
},
|
|
5407
|
+
onConflict: {
|
|
5408
|
+
target: [
|
|
5409
|
+
"actor_name",
|
|
5410
|
+
"actor_version",
|
|
5411
|
+
"actor_key",
|
|
5412
|
+
"service_name"
|
|
5413
|
+
],
|
|
5414
|
+
action: {
|
|
5415
|
+
do: "update",
|
|
5416
|
+
set: {
|
|
5417
|
+
durable_state: "excluded",
|
|
5418
|
+
durable_version: "excluded",
|
|
5419
|
+
expires_at: "excluded",
|
|
5420
|
+
updated: "excluded"
|
|
5421
|
+
},
|
|
5422
|
+
where: "actor_session_state.durable_version <= excluded.durable_version"
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
};
|
|
5427
|
+
},
|
|
5428
|
+
"Validates and prepares actor_session_state payload for strict write-through persistence.",
|
|
5429
|
+
{ isSubMeta: true, concurrency: 100 }
|
|
5430
|
+
).then(insertAndValidateActorSessionStateTask).respondsTo(import_core3.META_ACTOR_SESSION_STATE_PERSIST_INTENT);
|
|
5431
|
+
}
|
|
4850
5432
|
|
|
4851
5433
|
// src/graph/controllers/GraphMetadataController.ts
|
|
4852
|
-
var import_core3 = require("@cadenza.io/core");
|
|
4853
5434
|
var GraphMetadataController = class _GraphMetadataController {
|
|
4854
5435
|
static get instance() {
|
|
4855
5436
|
if (!this._instance) this._instance = new _GraphMetadataController();
|
|
@@ -5083,123 +5664,7 @@ var GraphMetadataController = class _GraphMetadataController {
|
|
|
5083
5664
|
}
|
|
5084
5665
|
};
|
|
5085
5666
|
}).doOn("meta.actor.task_associated").emits("global.meta.graph_metadata.actor_task_associated");
|
|
5086
|
-
|
|
5087
|
-
"actor_session_state",
|
|
5088
|
-
{},
|
|
5089
|
-
{ concurrency: 100, isSubMeta: true }
|
|
5090
|
-
);
|
|
5091
|
-
const validateActorSessionStatePersistenceTask = CadenzaService.createMetaTask(
|
|
5092
|
-
"Validate actor session state persistence",
|
|
5093
|
-
(ctx) => {
|
|
5094
|
-
if (ctx.errored || ctx.failed || ctx.__success !== true) {
|
|
5095
|
-
throw new Error(
|
|
5096
|
-
String(
|
|
5097
|
-
ctx.__error ?? ctx.error ?? "actor_session_state persistence query failed"
|
|
5098
|
-
)
|
|
5099
|
-
);
|
|
5100
|
-
}
|
|
5101
|
-
const rowCount = Number(ctx.rowCount ?? 0);
|
|
5102
|
-
if (!Number.isFinite(rowCount) || rowCount <= 0) {
|
|
5103
|
-
throw new Error(
|
|
5104
|
-
"actor_session_state persistence did not affect any rows (possible stale durable_version)"
|
|
5105
|
-
);
|
|
5106
|
-
}
|
|
5107
|
-
return {
|
|
5108
|
-
__success: true,
|
|
5109
|
-
persisted: true,
|
|
5110
|
-
actor_name: ctx.actor_name,
|
|
5111
|
-
actor_version: ctx.actor_version,
|
|
5112
|
-
actor_key: ctx.actor_key,
|
|
5113
|
-
service_name: ctx.service_name,
|
|
5114
|
-
durable_version: ctx.durable_version
|
|
5115
|
-
};
|
|
5116
|
-
},
|
|
5117
|
-
"Enforces strict actor session persistence success contract.",
|
|
5118
|
-
{ isSubMeta: true, concurrency: 100 }
|
|
5119
|
-
);
|
|
5120
|
-
const insertAndValidateActorSessionStateTask = actorSessionStateInsertTask.then(
|
|
5121
|
-
validateActorSessionStatePersistenceTask
|
|
5122
|
-
);
|
|
5123
|
-
CadenzaService.createMetaTask(
|
|
5124
|
-
"Persist actor session state",
|
|
5125
|
-
(ctx) => {
|
|
5126
|
-
const actorName = typeof ctx.actor_name === "string" ? ctx.actor_name.trim() : "";
|
|
5127
|
-
const actorKey = typeof ctx.actor_key === "string" ? ctx.actor_key.trim() : "";
|
|
5128
|
-
const actorVersion = Number(ctx.actor_version ?? 1);
|
|
5129
|
-
const durableVersion = Number(ctx.durable_version);
|
|
5130
|
-
if (!actorName) {
|
|
5131
|
-
throw new Error("actor_name is required for actor session persistence");
|
|
5132
|
-
}
|
|
5133
|
-
if (!actorKey) {
|
|
5134
|
-
throw new Error("actor_key is required for actor session persistence");
|
|
5135
|
-
}
|
|
5136
|
-
if (!Number.isInteger(actorVersion) || actorVersion < 1) {
|
|
5137
|
-
throw new Error("actor_version must be a positive integer");
|
|
5138
|
-
}
|
|
5139
|
-
if (!Number.isInteger(durableVersion) || durableVersion < 0) {
|
|
5140
|
-
throw new Error("durable_version must be a non-negative integer");
|
|
5141
|
-
}
|
|
5142
|
-
if (typeof ctx.durable_state !== "object" || ctx.durable_state === null || Array.isArray(ctx.durable_state)) {
|
|
5143
|
-
throw new Error("durable_state must be a non-null object");
|
|
5144
|
-
}
|
|
5145
|
-
const serviceName = CadenzaService.serviceRegistry.serviceName;
|
|
5146
|
-
if (!serviceName) {
|
|
5147
|
-
throw new Error("service_name is not available for actor session persistence");
|
|
5148
|
-
}
|
|
5149
|
-
let expiresAt = null;
|
|
5150
|
-
if (ctx.expires_at !== void 0 && ctx.expires_at !== null) {
|
|
5151
|
-
if (ctx.expires_at instanceof Date) {
|
|
5152
|
-
expiresAt = ctx.expires_at.toISOString();
|
|
5153
|
-
} else if (typeof ctx.expires_at === "string" && ctx.expires_at.trim().length > 0) {
|
|
5154
|
-
expiresAt = ctx.expires_at;
|
|
5155
|
-
} else {
|
|
5156
|
-
throw new Error("expires_at must be null, Date, or non-empty string");
|
|
5157
|
-
}
|
|
5158
|
-
}
|
|
5159
|
-
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5160
|
-
return {
|
|
5161
|
-
...ctx,
|
|
5162
|
-
actor_name: actorName,
|
|
5163
|
-
actor_key: actorKey,
|
|
5164
|
-
actor_version: actorVersion,
|
|
5165
|
-
durable_version: durableVersion,
|
|
5166
|
-
expires_at: expiresAt,
|
|
5167
|
-
service_name: serviceName,
|
|
5168
|
-
queryData: {
|
|
5169
|
-
data: {
|
|
5170
|
-
actor_name: actorName,
|
|
5171
|
-
actor_version: actorVersion,
|
|
5172
|
-
actor_key: actorKey,
|
|
5173
|
-
service_name: serviceName,
|
|
5174
|
-
durable_state: ctx.durable_state,
|
|
5175
|
-
durable_version: durableVersion,
|
|
5176
|
-
expires_at: expiresAt,
|
|
5177
|
-
updated: updatedAt
|
|
5178
|
-
},
|
|
5179
|
-
onConflict: {
|
|
5180
|
-
target: [
|
|
5181
|
-
"actor_name",
|
|
5182
|
-
"actor_version",
|
|
5183
|
-
"actor_key",
|
|
5184
|
-
"service_name"
|
|
5185
|
-
],
|
|
5186
|
-
action: {
|
|
5187
|
-
do: "update",
|
|
5188
|
-
set: {
|
|
5189
|
-
durable_state: "excluded",
|
|
5190
|
-
durable_version: "excluded",
|
|
5191
|
-
expires_at: "excluded",
|
|
5192
|
-
updated: "excluded"
|
|
5193
|
-
},
|
|
5194
|
-
where: "actor_session_state.durable_version <= excluded.durable_version"
|
|
5195
|
-
}
|
|
5196
|
-
}
|
|
5197
|
-
}
|
|
5198
|
-
};
|
|
5199
|
-
},
|
|
5200
|
-
"Validates and prepares actor_session_state payload for strict write-through persistence.",
|
|
5201
|
-
{ isSubMeta: true, concurrency: 100 }
|
|
5202
|
-
).then(insertAndValidateActorSessionStateTask).respondsTo(import_core3.META_ACTOR_SESSION_STATE_PERSIST_INTENT);
|
|
5667
|
+
registerActorSessionPersistenceTasks();
|
|
5203
5668
|
CadenzaService.createMetaTask("Handle Intent Creation", (ctx) => {
|
|
5204
5669
|
const intentName = ctx.data?.name;
|
|
5205
5670
|
return {
|
|
@@ -5263,6 +5728,32 @@ function validateIntentName(intentName) {
|
|
|
5263
5728
|
function defaultOperationIntentDescription(operation, tableName) {
|
|
5264
5729
|
return `Perform a ${operation} operation on the ${tableName} table`;
|
|
5265
5730
|
}
|
|
5731
|
+
function isExplicitSqlLiteral(value) {
|
|
5732
|
+
return /^'.*'::[a-z_][a-z0-9_]*(\[\])?$/i.test(value.trim());
|
|
5733
|
+
}
|
|
5734
|
+
function serializeInitialDataValueForSql(value, field) {
|
|
5735
|
+
if (value === void 0 || value === null) {
|
|
5736
|
+
return "NULL";
|
|
5737
|
+
}
|
|
5738
|
+
if (typeof value === "number") {
|
|
5739
|
+
return String(value);
|
|
5740
|
+
}
|
|
5741
|
+
if (typeof value === "boolean") {
|
|
5742
|
+
return value ? "TRUE" : "FALSE";
|
|
5743
|
+
}
|
|
5744
|
+
if (field?.type === "jsonb") {
|
|
5745
|
+
if (typeof value === "string" && isExplicitSqlLiteral(value)) {
|
|
5746
|
+
return value;
|
|
5747
|
+
}
|
|
5748
|
+
const jsonString = JSON.stringify(value);
|
|
5749
|
+
return `'${jsonString.replace(/'/g, "''")}'::jsonb`;
|
|
5750
|
+
}
|
|
5751
|
+
const stringValue = String(value);
|
|
5752
|
+
if (isExplicitSqlLiteral(stringValue)) {
|
|
5753
|
+
return stringValue;
|
|
5754
|
+
}
|
|
5755
|
+
return `'${stringValue.replace(/'/g, "''")}'`;
|
|
5756
|
+
}
|
|
5266
5757
|
function readCustomIntentConfig(customIntent) {
|
|
5267
5758
|
if (typeof customIntent === "string") {
|
|
5268
5759
|
return {
|
|
@@ -6276,14 +6767,12 @@ var DatabaseController = class _DatabaseController {
|
|
|
6276
6767
|
if (table.initialData) {
|
|
6277
6768
|
ddl.push(
|
|
6278
6769
|
`INSERT INTO ${tableName} (${table.initialData.fields.map(import_lodash_es.snakeCase).join(", ")}) VALUES ${table.initialData.data.map(
|
|
6279
|
-
(row) => `(${row.map(
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
return `'${stringValue.replace(/'/g, "''")}'`;
|
|
6286
|
-
}).join(", ")})`
|
|
6770
|
+
(row) => `(${row.map(
|
|
6771
|
+
(value, index) => serializeInitialDataValueForSql(
|
|
6772
|
+
value,
|
|
6773
|
+
table.fields[table.initialData.fields[index]]
|
|
6774
|
+
)
|
|
6775
|
+
).join(", ")})`
|
|
6287
6776
|
).join(", ")} ON CONFLICT DO NOTHING;`
|
|
6288
6777
|
);
|
|
6289
6778
|
}
|
|
@@ -7835,6 +8324,165 @@ var GraphSyncController = class _GraphSyncController {
|
|
|
7835
8324
|
}
|
|
7836
8325
|
};
|
|
7837
8326
|
|
|
8327
|
+
// src/utils/bootstrap.ts
|
|
8328
|
+
var DEFAULT_BOOTSTRAP_GLOBAL_KEY = "__CADENZA_RUNTIME__";
|
|
8329
|
+
function normalizeString3(value) {
|
|
8330
|
+
if (typeof value !== "string") {
|
|
8331
|
+
return void 0;
|
|
8332
|
+
}
|
|
8333
|
+
const normalized = value.trim();
|
|
8334
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
8335
|
+
}
|
|
8336
|
+
function readEnvString(name) {
|
|
8337
|
+
if (typeof process === "undefined") {
|
|
8338
|
+
return void 0;
|
|
8339
|
+
}
|
|
8340
|
+
return normalizeString3(process.env?.[name]);
|
|
8341
|
+
}
|
|
8342
|
+
function readConfiguredPort(value) {
|
|
8343
|
+
if (value === void 0 || value === null || value === "") {
|
|
8344
|
+
return void 0;
|
|
8345
|
+
}
|
|
8346
|
+
const parsed = Number(value);
|
|
8347
|
+
if (!Number.isFinite(parsed)) {
|
|
8348
|
+
throw new Error(`Invalid port value: ${String(value)}`);
|
|
8349
|
+
}
|
|
8350
|
+
const normalized = Math.trunc(parsed);
|
|
8351
|
+
if (normalized <= 0) {
|
|
8352
|
+
throw new Error(`Port must be a positive integer: ${String(value)}`);
|
|
8353
|
+
}
|
|
8354
|
+
return normalized;
|
|
8355
|
+
}
|
|
8356
|
+
function buildBootstrapUrl(protocol, address, port) {
|
|
8357
|
+
return `${protocol}://${address}:${port}`;
|
|
8358
|
+
}
|
|
8359
|
+
function resolveInjectedBootstrapUrl(injectedGlobalKey) {
|
|
8360
|
+
if (typeof globalThis === "undefined") {
|
|
8361
|
+
return void 0;
|
|
8362
|
+
}
|
|
8363
|
+
const runtimeConfig = globalThis[injectedGlobalKey];
|
|
8364
|
+
return normalizeString3(runtimeConfig?.bootstrapUrl);
|
|
8365
|
+
}
|
|
8366
|
+
function resolveExplicitBootstrapValue(options) {
|
|
8367
|
+
const injectedGlobalKey = normalizeString3(options.bootstrap?.injectedGlobalKey) ?? DEFAULT_BOOTSTRAP_GLOBAL_KEY;
|
|
8368
|
+
const explicitBootstrapUrl = normalizeString3(options.bootstrap?.url);
|
|
8369
|
+
if (explicitBootstrapUrl) {
|
|
8370
|
+
return {
|
|
8371
|
+
value: explicitBootstrapUrl,
|
|
8372
|
+
port: readConfiguredPort(options.cadenzaDB?.port),
|
|
8373
|
+
injectedGlobalKey
|
|
8374
|
+
};
|
|
8375
|
+
}
|
|
8376
|
+
if (options.runtime === "browser") {
|
|
8377
|
+
const injected = resolveInjectedBootstrapUrl(injectedGlobalKey);
|
|
8378
|
+
if (injected) {
|
|
8379
|
+
return {
|
|
8380
|
+
value: injected,
|
|
8381
|
+
port: readConfiguredPort(options.cadenzaDB?.port),
|
|
8382
|
+
injectedGlobalKey
|
|
8383
|
+
};
|
|
8384
|
+
}
|
|
8385
|
+
}
|
|
8386
|
+
const explicitAddress = normalizeString3(options.cadenzaDB?.address);
|
|
8387
|
+
if (explicitAddress) {
|
|
8388
|
+
return {
|
|
8389
|
+
value: explicitAddress,
|
|
8390
|
+
port: readConfiguredPort(options.cadenzaDB?.port),
|
|
8391
|
+
injectedGlobalKey
|
|
8392
|
+
};
|
|
8393
|
+
}
|
|
8394
|
+
const envAddress = readEnvString("CADENZA_DB_ADDRESS");
|
|
8395
|
+
return {
|
|
8396
|
+
value: envAddress,
|
|
8397
|
+
port: readConfiguredPort(options.cadenzaDB?.port ?? readEnvString("CADENZA_DB_PORT")),
|
|
8398
|
+
injectedGlobalKey
|
|
8399
|
+
};
|
|
8400
|
+
}
|
|
8401
|
+
function readIntegerEnv(name, fallback) {
|
|
8402
|
+
const raw = readEnvString(name);
|
|
8403
|
+
if (!raw) {
|
|
8404
|
+
return fallback;
|
|
8405
|
+
}
|
|
8406
|
+
const parsed = Number(raw);
|
|
8407
|
+
if (!Number.isFinite(parsed)) {
|
|
8408
|
+
return fallback;
|
|
8409
|
+
}
|
|
8410
|
+
const normalized = Math.trunc(parsed);
|
|
8411
|
+
if (normalized <= 0) {
|
|
8412
|
+
return fallback;
|
|
8413
|
+
}
|
|
8414
|
+
return normalized;
|
|
8415
|
+
}
|
|
8416
|
+
function readStringEnv(name) {
|
|
8417
|
+
return readEnvString(name);
|
|
8418
|
+
}
|
|
8419
|
+
function readListEnv(name) {
|
|
8420
|
+
const raw = readEnvString(name);
|
|
8421
|
+
if (!raw) {
|
|
8422
|
+
return [];
|
|
8423
|
+
}
|
|
8424
|
+
return raw.split("|").map((entry) => entry.trim()).filter((entry) => entry.length > 0).map((entry) => entry.split(",").map((part) => part.trim()));
|
|
8425
|
+
}
|
|
8426
|
+
function resolveBootstrapEndpoint(options) {
|
|
8427
|
+
const { value, port: fallbackPort, injectedGlobalKey } = resolveExplicitBootstrapValue(options);
|
|
8428
|
+
if (!value) {
|
|
8429
|
+
throw new Error(
|
|
8430
|
+
options.runtime === "browser" ? `No bootstrap URL available. Pass bootstrap.url or inject globalThis.${injectedGlobalKey}.bootstrapUrl.` : "No bootstrap URL available. Set CADENZA_DB_ADDRESS or pass bootstrap.url."
|
|
8431
|
+
);
|
|
8432
|
+
}
|
|
8433
|
+
const raw = value.trim();
|
|
8434
|
+
if (raw.length === 0) {
|
|
8435
|
+
throw new Error("Bootstrap URL cannot be empty");
|
|
8436
|
+
}
|
|
8437
|
+
if (raw.includes("://")) {
|
|
8438
|
+
const parsed2 = new URL(raw);
|
|
8439
|
+
const protocol2 = parsed2.protocol.replace(":", "");
|
|
8440
|
+
if (protocol2 !== "http" && protocol2 !== "https") {
|
|
8441
|
+
throw new Error(`Unsupported bootstrap protocol: ${parsed2.protocol}`);
|
|
8442
|
+
}
|
|
8443
|
+
if (parsed2.pathname && parsed2.pathname !== "/" && parsed2.pathname.trim().length > 0) {
|
|
8444
|
+
throw new Error(
|
|
8445
|
+
"Bootstrap URL must be an origin without a path component."
|
|
8446
|
+
);
|
|
8447
|
+
}
|
|
8448
|
+
const port2 = parsed2.port ? readConfiguredPort(parsed2.port) : fallbackPort;
|
|
8449
|
+
if (!port2) {
|
|
8450
|
+
throw new Error(
|
|
8451
|
+
"Bootstrap URL must include a port or CADENZA_DB_PORT must be provided."
|
|
8452
|
+
);
|
|
8453
|
+
}
|
|
8454
|
+
return {
|
|
8455
|
+
url: buildBootstrapUrl(protocol2, parsed2.hostname, port2),
|
|
8456
|
+
protocol: protocol2,
|
|
8457
|
+
address: parsed2.hostname,
|
|
8458
|
+
port: port2,
|
|
8459
|
+
exposed: protocol2 === "https",
|
|
8460
|
+
injectedGlobalKey
|
|
8461
|
+
};
|
|
8462
|
+
}
|
|
8463
|
+
if (raw.includes("/") || raw.includes("?") || raw.includes("#")) {
|
|
8464
|
+
throw new Error(
|
|
8465
|
+
"Bootstrap address without protocol must not include a path, query, or hash."
|
|
8466
|
+
);
|
|
8467
|
+
}
|
|
8468
|
+
const parsed = new URL(`http://${raw}`);
|
|
8469
|
+
const protocol = "http";
|
|
8470
|
+
const port = parsed.port ? readConfiguredPort(parsed.port) : fallbackPort;
|
|
8471
|
+
if (!port) {
|
|
8472
|
+
throw new Error(
|
|
8473
|
+
"Bootstrap address must include a port or CADENZA_DB_PORT must be provided."
|
|
8474
|
+
);
|
|
8475
|
+
}
|
|
8476
|
+
return {
|
|
8477
|
+
url: buildBootstrapUrl(protocol, parsed.hostname, port),
|
|
8478
|
+
protocol,
|
|
8479
|
+
address: parsed.hostname,
|
|
8480
|
+
port,
|
|
8481
|
+
exposed: false,
|
|
8482
|
+
injectedGlobalKey
|
|
8483
|
+
};
|
|
8484
|
+
}
|
|
8485
|
+
|
|
7838
8486
|
// src/Cadenza.ts
|
|
7839
8487
|
var CadenzaService = class {
|
|
7840
8488
|
/**
|
|
@@ -7853,11 +8501,60 @@ var CadenzaService = class {
|
|
|
7853
8501
|
this.metaRunner = import_core4.default.metaRunner;
|
|
7854
8502
|
this.registry = import_core4.default.registry;
|
|
7855
8503
|
this.serviceRegistry = ServiceRegistry.instance;
|
|
7856
|
-
SignalController.instance;
|
|
7857
8504
|
RestController.instance;
|
|
7858
8505
|
SocketController.instance;
|
|
7859
8506
|
console.log("BOOTSTRAPPED");
|
|
7860
8507
|
}
|
|
8508
|
+
static ensureTransportControllers(isFrontend) {
|
|
8509
|
+
if (!isFrontend) {
|
|
8510
|
+
SignalController.instance;
|
|
8511
|
+
}
|
|
8512
|
+
}
|
|
8513
|
+
static setHydrationResults(hydration) {
|
|
8514
|
+
this.hydratedInquiryResults = /* @__PURE__ */ new Map();
|
|
8515
|
+
const initialInquiryResults = hydration?.initialInquiryResults ?? {};
|
|
8516
|
+
for (const [key, value] of Object.entries(initialInquiryResults)) {
|
|
8517
|
+
this.hydratedInquiryResults.set(key, value);
|
|
8518
|
+
}
|
|
8519
|
+
}
|
|
8520
|
+
static consumeHydratedInquiryResult(hydrationKey) {
|
|
8521
|
+
if (!hydrationKey) {
|
|
8522
|
+
return void 0;
|
|
8523
|
+
}
|
|
8524
|
+
const result = this.hydratedInquiryResults.get(hydrationKey);
|
|
8525
|
+
if (result === void 0) {
|
|
8526
|
+
return void 0;
|
|
8527
|
+
}
|
|
8528
|
+
this.hydratedInquiryResults.delete(hydrationKey);
|
|
8529
|
+
return result;
|
|
8530
|
+
}
|
|
8531
|
+
static ensureFrontendSyncLoop() {
|
|
8532
|
+
if (this.frontendSyncScheduled) {
|
|
8533
|
+
return;
|
|
8534
|
+
}
|
|
8535
|
+
this.frontendSyncScheduled = true;
|
|
8536
|
+
import_core4.default.interval("meta.sync_requested", { __syncing: false }, 18e4);
|
|
8537
|
+
import_core4.default.schedule("meta.sync_requested", { __syncing: false }, 250);
|
|
8538
|
+
}
|
|
8539
|
+
static normalizeDeclaredTransports(transports, serviceId) {
|
|
8540
|
+
return (transports ?? []).map((transport) => normalizeServiceTransportConfig(transport)).filter(
|
|
8541
|
+
(transport) => !!transport
|
|
8542
|
+
).map((transport, index) => ({
|
|
8543
|
+
...transport,
|
|
8544
|
+
uuid: `${serviceId}-transport-${index + 1}`
|
|
8545
|
+
}));
|
|
8546
|
+
}
|
|
8547
|
+
static createBootstrapTransport(serviceInstanceId, role, endpoint) {
|
|
8548
|
+
return {
|
|
8549
|
+
uuid: `${serviceInstanceId}-${role}-bootstrap`,
|
|
8550
|
+
service_instance_id: serviceInstanceId,
|
|
8551
|
+
role,
|
|
8552
|
+
origin: endpoint.url,
|
|
8553
|
+
protocols: ["rest", "socket"],
|
|
8554
|
+
security_profile: null,
|
|
8555
|
+
auth_strategy: null
|
|
8556
|
+
};
|
|
8557
|
+
}
|
|
7861
8558
|
/**
|
|
7862
8559
|
* Validates the provided service name based on specific rules.
|
|
7863
8560
|
*
|
|
@@ -7970,6 +8667,12 @@ var CadenzaService = class {
|
|
|
7970
8667
|
}
|
|
7971
8668
|
static async inquire(inquiry, context, options = {}) {
|
|
7972
8669
|
this.bootstrap();
|
|
8670
|
+
const hydratedResult = this.consumeHydratedInquiryResult(
|
|
8671
|
+
options.hydrationKey
|
|
8672
|
+
);
|
|
8673
|
+
if (hydratedResult !== void 0) {
|
|
8674
|
+
return hydratedResult;
|
|
8675
|
+
}
|
|
7973
8676
|
const observer = this.inquiryBroker?.inquiryObservers.get(inquiry);
|
|
7974
8677
|
const allResponders = observer ? Array.from(observer.tasks).map((task) => ({
|
|
7975
8678
|
task,
|
|
@@ -8574,58 +9277,97 @@ var CadenzaService = class {
|
|
|
8574
9277
|
const serviceId = options.customServiceId ?? (0, import_uuid3.v4)();
|
|
8575
9278
|
this.serviceRegistry.serviceName = serviceName;
|
|
8576
9279
|
this.serviceRegistry.serviceInstanceId = serviceId;
|
|
9280
|
+
this.setHydrationResults(options.hydration);
|
|
9281
|
+
const explicitFrontendMode = options.isFrontend;
|
|
8577
9282
|
options = {
|
|
8578
9283
|
loadBalance: true,
|
|
8579
9284
|
useSocket: true,
|
|
8580
9285
|
displayName: void 0,
|
|
8581
9286
|
isMeta: false,
|
|
8582
|
-
port:
|
|
8583
|
-
securityProfile:
|
|
8584
|
-
networkMode:
|
|
9287
|
+
port: readIntegerEnv("HTTP_PORT", 3e3),
|
|
9288
|
+
securityProfile: readStringEnv("SECURITY_PROFILE") ?? "medium",
|
|
9289
|
+
networkMode: readStringEnv("NETWORK_MODE") ?? "dev",
|
|
8585
9290
|
retryCount: 3,
|
|
8586
9291
|
cadenzaDB: {
|
|
8587
|
-
connect: true
|
|
8588
|
-
address: process.env.CADENZA_DB_ADDRESS ?? "localhost",
|
|
8589
|
-
port: parseInt(process.env.CADENZA_DB_PORT ?? "5000")
|
|
9292
|
+
connect: true
|
|
8590
9293
|
},
|
|
8591
|
-
relatedServices:
|
|
8592
|
-
|
|
8593
|
-
) : [],
|
|
8594
|
-
isFrontend: isBrowser,
|
|
9294
|
+
relatedServices: readListEnv("RELATED_SERVICES"),
|
|
9295
|
+
isFrontend: typeof explicitFrontendMode === "boolean" ? explicitFrontendMode : isBrowser,
|
|
8595
9296
|
...options
|
|
8596
9297
|
};
|
|
9298
|
+
const isFrontend = !!options.isFrontend;
|
|
9299
|
+
const declaredTransports = this.normalizeDeclaredTransports(
|
|
9300
|
+
options.transports,
|
|
9301
|
+
serviceId
|
|
9302
|
+
);
|
|
9303
|
+
this.serviceRegistry.isFrontend = isFrontend;
|
|
9304
|
+
this.serviceRegistry.useSocket = !!options.useSocket;
|
|
9305
|
+
this.serviceRegistry.retryCount = options.retryCount ?? 3;
|
|
9306
|
+
this.ensureTransportControllers(isFrontend);
|
|
9307
|
+
const resolvedBootstrapEndpoint = options.cadenzaDB?.connect ? resolveBootstrapEndpoint({
|
|
9308
|
+
runtime: isFrontend ? "browser" : "server",
|
|
9309
|
+
bootstrap: options.bootstrap,
|
|
9310
|
+
cadenzaDB: options.cadenzaDB
|
|
9311
|
+
}) : void 0;
|
|
9312
|
+
if (resolvedBootstrapEndpoint) {
|
|
9313
|
+
options.cadenzaDB = {
|
|
9314
|
+
...options.cadenzaDB,
|
|
9315
|
+
connect: true,
|
|
9316
|
+
address: resolvedBootstrapEndpoint.address,
|
|
9317
|
+
port: resolvedBootstrapEndpoint.port
|
|
9318
|
+
};
|
|
9319
|
+
}
|
|
8597
9320
|
if (options.cadenzaDB?.connect) {
|
|
8598
9321
|
this.emit("meta.initializing_service", {
|
|
8599
9322
|
// Seed the CadenzaDB
|
|
8600
9323
|
serviceInstance: {
|
|
8601
9324
|
uuid: "cadenza-db",
|
|
8602
9325
|
serviceName: "CadenzaDB",
|
|
8603
|
-
address: options.cadenzaDB?.address,
|
|
8604
|
-
port: options.cadenzaDB?.port,
|
|
8605
|
-
exposed: options.networkMode !== "dev",
|
|
8606
9326
|
numberOfRunningGraphs: 0,
|
|
8607
9327
|
isActive: true,
|
|
8608
9328
|
// Assume it is deployed
|
|
8609
9329
|
isNonResponsive: false,
|
|
8610
9330
|
isBlocked: false,
|
|
8611
|
-
health: {}
|
|
9331
|
+
health: {},
|
|
9332
|
+
isFrontend: false,
|
|
9333
|
+
transports: resolvedBootstrapEndpoint ? [
|
|
9334
|
+
this.createBootstrapTransport(
|
|
9335
|
+
"cadenza-db",
|
|
9336
|
+
isFrontend ? "public" : "internal",
|
|
9337
|
+
resolvedBootstrapEndpoint
|
|
9338
|
+
)
|
|
9339
|
+
] : []
|
|
8612
9340
|
}
|
|
8613
9341
|
});
|
|
8614
9342
|
}
|
|
8615
9343
|
options.relatedServices?.forEach((service) => {
|
|
9344
|
+
const relatedTransport = normalizeServiceTransportConfig({
|
|
9345
|
+
role: isFrontend ? "public" : "internal",
|
|
9346
|
+
origin: service[2].includes("://") ? service[2] : `http://${service[2]}`,
|
|
9347
|
+
protocols: ["rest", "socket"]
|
|
9348
|
+
});
|
|
8616
9349
|
this.emit("meta.initializing_service", {
|
|
8617
9350
|
serviceInstance: {
|
|
8618
9351
|
uuid: service[0],
|
|
8619
9352
|
serviceName: service[1],
|
|
8620
|
-
address: service[2].split(":")[0],
|
|
8621
|
-
port: service[2].split(":")[1] ?? 3e3,
|
|
8622
|
-
exposed: options.networkMode !== "dev",
|
|
8623
9353
|
numberOfRunningGraphs: 0,
|
|
8624
9354
|
isActive: true,
|
|
8625
9355
|
// Assume it is deployed
|
|
8626
9356
|
isNonResponsive: false,
|
|
8627
9357
|
isBlocked: false,
|
|
8628
|
-
health: {}
|
|
9358
|
+
health: {},
|
|
9359
|
+
isFrontend: false,
|
|
9360
|
+
transports: relatedTransport ? [
|
|
9361
|
+
{
|
|
9362
|
+
uuid: `${service[0]}-${relatedTransport.role}`,
|
|
9363
|
+
service_instance_id: service[0],
|
|
9364
|
+
role: relatedTransport.role,
|
|
9365
|
+
origin: relatedTransport.origin,
|
|
9366
|
+
protocols: relatedTransport.protocols ?? ["rest", "socket"],
|
|
9367
|
+
security_profile: relatedTransport.securityProfile ?? null,
|
|
9368
|
+
auth_strategy: relatedTransport.authStrategy ?? null
|
|
9369
|
+
}
|
|
9370
|
+
] : []
|
|
8629
9371
|
}
|
|
8630
9372
|
});
|
|
8631
9373
|
});
|
|
@@ -8646,7 +9388,9 @@ var CadenzaService = class {
|
|
|
8646
9388
|
__networkMode: options.networkMode,
|
|
8647
9389
|
__retryCount: options.retryCount,
|
|
8648
9390
|
__cadenzaDBConnect: options.cadenzaDB?.connect,
|
|
8649
|
-
__isDatabase: options.isDatabase
|
|
9391
|
+
__isDatabase: options.isDatabase,
|
|
9392
|
+
__isFrontend: isFrontend,
|
|
9393
|
+
__declaredTransports: declaredTransports
|
|
8650
9394
|
};
|
|
8651
9395
|
if (options.cadenzaDB?.connect) {
|
|
8652
9396
|
this.createEphemeralMetaTask("Create service", async (context, emit) => {
|
|
@@ -8662,12 +9406,42 @@ var CadenzaService = class {
|
|
|
8662
9406
|
}).doOn("meta.rest.handshake");
|
|
8663
9407
|
}
|
|
8664
9408
|
this.createMetaTask("Handle service setup completion", () => {
|
|
8665
|
-
|
|
8666
|
-
|
|
8667
|
-
|
|
9409
|
+
if (isFrontend) {
|
|
9410
|
+
registerActorSessionPersistenceTasks();
|
|
9411
|
+
this.ensureFrontendSyncLoop();
|
|
9412
|
+
} else {
|
|
9413
|
+
GraphMetadataController.instance;
|
|
9414
|
+
GraphSyncController.instance.isCadenzaDBReady = !!options.cadenzaDB?.connect;
|
|
9415
|
+
GraphSyncController.instance.init();
|
|
9416
|
+
}
|
|
8668
9417
|
this.log("Service created.");
|
|
8669
9418
|
return true;
|
|
8670
9419
|
}).doOn("meta.service_registry.instance_inserted");
|
|
9420
|
+
if (!options.cadenzaDB?.connect && isFrontend) {
|
|
9421
|
+
import_core4.default.schedule(
|
|
9422
|
+
"meta.service_registry.instance_registration_requested",
|
|
9423
|
+
{
|
|
9424
|
+
data: {
|
|
9425
|
+
uuid: serviceId,
|
|
9426
|
+
process_pid: 1,
|
|
9427
|
+
service_name: serviceName,
|
|
9428
|
+
is_frontend: true,
|
|
9429
|
+
is_active: true,
|
|
9430
|
+
is_non_responsive: false,
|
|
9431
|
+
is_blocked: false,
|
|
9432
|
+
health: {}
|
|
9433
|
+
},
|
|
9434
|
+
transportData: [],
|
|
9435
|
+
__serviceName: serviceName,
|
|
9436
|
+
__serviceInstanceId: serviceId,
|
|
9437
|
+
__useSocket: options.useSocket,
|
|
9438
|
+
__retryCount: options.retryCount,
|
|
9439
|
+
__isFrontend: true,
|
|
9440
|
+
__skipRemoteExecution: true
|
|
9441
|
+
},
|
|
9442
|
+
0
|
|
9443
|
+
);
|
|
9444
|
+
}
|
|
8671
9445
|
this.serviceCreated = true;
|
|
8672
9446
|
}
|
|
8673
9447
|
/**
|
|
@@ -8693,9 +9467,9 @@ var CadenzaService = class {
|
|
|
8693
9467
|
* @return {void}
|
|
8694
9468
|
*/
|
|
8695
9469
|
static createPostgresActor(name, schema, description = "", options = {}) {
|
|
8696
|
-
if (isBrowser) {
|
|
9470
|
+
if (isBrowser || options.isFrontend) {
|
|
8697
9471
|
console.warn(
|
|
8698
|
-
"PostgresActor creation is not supported in
|
|
9472
|
+
"PostgresActor creation is not supported in frontend mode."
|
|
8699
9473
|
);
|
|
8700
9474
|
return;
|
|
8701
9475
|
}
|
|
@@ -8740,9 +9514,9 @@ var CadenzaService = class {
|
|
|
8740
9514
|
* Creates a dedicated database service by composing a PostgresActor and a Cadenza service.
|
|
8741
9515
|
*/
|
|
8742
9516
|
static createDatabaseService(name, schema, description = "", options = {}) {
|
|
8743
|
-
if (isBrowser) {
|
|
9517
|
+
if (isBrowser || options.isFrontend) {
|
|
8744
9518
|
console.warn(
|
|
8745
|
-
"Database service creation is not supported in
|
|
9519
|
+
"Database service creation is not supported in frontend mode. Use the CadenzaDB service instead."
|
|
8746
9520
|
);
|
|
8747
9521
|
return;
|
|
8748
9522
|
}
|
|
@@ -8837,7 +9611,7 @@ var CadenzaService = class {
|
|
|
8837
9611
|
retryCount: 3,
|
|
8838
9612
|
databaseType: "postgres",
|
|
8839
9613
|
databaseName: (0, import_lodash_es2.snakeCase)(name),
|
|
8840
|
-
poolSize:
|
|
9614
|
+
poolSize: readIntegerEnv("DATABASE_POOL_SIZE", 10),
|
|
8841
9615
|
ownerServiceName: options.ownerServiceName ?? this.serviceRegistry?.serviceName ?? null,
|
|
8842
9616
|
...options
|
|
8843
9617
|
};
|
|
@@ -8848,18 +9622,16 @@ var CadenzaService = class {
|
|
|
8848
9622
|
useSocket: true,
|
|
8849
9623
|
displayName: void 0,
|
|
8850
9624
|
isMeta: false,
|
|
8851
|
-
port:
|
|
8852
|
-
securityProfile:
|
|
8853
|
-
networkMode:
|
|
9625
|
+
port: readIntegerEnv("HTTP_PORT", 3e3),
|
|
9626
|
+
securityProfile: readStringEnv("SECURITY_PROFILE") ?? "medium",
|
|
9627
|
+
networkMode: readStringEnv("NETWORK_MODE") ?? "dev",
|
|
8854
9628
|
retryCount: 3,
|
|
8855
9629
|
cadenzaDB: {
|
|
8856
|
-
connect: true
|
|
8857
|
-
address: process.env.CADENZA_DB_ADDRESS ?? "localhost",
|
|
8858
|
-
port: parseInt(process.env.CADENZA_DB_PORT ?? "5000")
|
|
9630
|
+
connect: true
|
|
8859
9631
|
},
|
|
8860
9632
|
databaseType: "postgres",
|
|
8861
9633
|
databaseName: (0, import_lodash_es2.snakeCase)(name),
|
|
8862
|
-
poolSize:
|
|
9634
|
+
poolSize: readIntegerEnv("DATABASE_POOL_SIZE", 10),
|
|
8863
9635
|
isDatabase: true,
|
|
8864
9636
|
ownerServiceName: options.ownerServiceName ?? name,
|
|
8865
9637
|
...options
|
|
@@ -9307,19 +10079,291 @@ var CadenzaService = class {
|
|
|
9307
10079
|
}
|
|
9308
10080
|
static reset() {
|
|
9309
10081
|
import_core4.default.reset();
|
|
9310
|
-
this.serviceRegistry
|
|
10082
|
+
this.serviceRegistry?.reset();
|
|
10083
|
+
this.isBootstrapped = false;
|
|
10084
|
+
this.serviceCreated = false;
|
|
10085
|
+
this.warnedInvalidMetaIntentResponderKeys = /* @__PURE__ */ new Set();
|
|
10086
|
+
this.hydratedInquiryResults = /* @__PURE__ */ new Map();
|
|
10087
|
+
this.frontendSyncScheduled = false;
|
|
9311
10088
|
}
|
|
9312
10089
|
};
|
|
9313
10090
|
CadenzaService.isBootstrapped = false;
|
|
9314
10091
|
CadenzaService.serviceCreated = false;
|
|
9315
10092
|
CadenzaService.warnedInvalidMetaIntentResponderKeys = /* @__PURE__ */ new Set();
|
|
10093
|
+
CadenzaService.hydratedInquiryResults = /* @__PURE__ */ new Map();
|
|
10094
|
+
CadenzaService.frontendSyncScheduled = false;
|
|
9316
10095
|
|
|
9317
10096
|
// src/index.ts
|
|
9318
10097
|
var import_core5 = require("@cadenza.io/core");
|
|
10098
|
+
|
|
10099
|
+
// src/ssr/createSSRInquiryBridge.ts
|
|
10100
|
+
var import_uuid4 = require("uuid");
|
|
10101
|
+
function ensureFetch() {
|
|
10102
|
+
if (typeof globalThis.fetch !== "function") {
|
|
10103
|
+
throw new Error("SSR inquiry bridge requires global fetch support.");
|
|
10104
|
+
}
|
|
10105
|
+
return globalThis.fetch.bind(globalThis);
|
|
10106
|
+
}
|
|
10107
|
+
function normalizeArrayResponse(value, keys) {
|
|
10108
|
+
for (const key of keys) {
|
|
10109
|
+
if (Array.isArray(value?.[key])) {
|
|
10110
|
+
return value[key];
|
|
10111
|
+
}
|
|
10112
|
+
}
|
|
10113
|
+
if (Array.isArray(value?.rows)) {
|
|
10114
|
+
return value.rows;
|
|
10115
|
+
}
|
|
10116
|
+
if (Array.isArray(value?.data)) {
|
|
10117
|
+
return value.data;
|
|
10118
|
+
}
|
|
10119
|
+
return [];
|
|
10120
|
+
}
|
|
10121
|
+
function normalizeIntentMap(raw) {
|
|
10122
|
+
const intentName = String(raw.intentName ?? raw.intent_name ?? "").trim();
|
|
10123
|
+
const serviceName = String(raw.serviceName ?? raw.service_name ?? "").trim();
|
|
10124
|
+
const taskName = String(raw.taskName ?? raw.task_name ?? "").trim();
|
|
10125
|
+
const taskVersion = Math.max(
|
|
10126
|
+
1,
|
|
10127
|
+
Math.trunc(Number(raw.taskVersion ?? raw.task_version ?? 1) || 1)
|
|
10128
|
+
);
|
|
10129
|
+
if (!intentName || !serviceName || !taskName) {
|
|
10130
|
+
return null;
|
|
10131
|
+
}
|
|
10132
|
+
return {
|
|
10133
|
+
intentName,
|
|
10134
|
+
serviceName,
|
|
10135
|
+
taskName,
|
|
10136
|
+
taskVersion,
|
|
10137
|
+
deleted: Boolean(raw.deleted)
|
|
10138
|
+
};
|
|
10139
|
+
}
|
|
10140
|
+
function buildInquiryMeta(inquiry, startedAt, statuses) {
|
|
10141
|
+
const counts = summarizeResponderStatuses(statuses);
|
|
10142
|
+
return {
|
|
10143
|
+
inquiry,
|
|
10144
|
+
isMetaInquiry: isMetaIntentName(inquiry),
|
|
10145
|
+
totalResponders: statuses.length,
|
|
10146
|
+
eligibleResponders: statuses.length,
|
|
10147
|
+
filteredOutResponders: 0,
|
|
10148
|
+
responded: counts.responded,
|
|
10149
|
+
failed: counts.failed,
|
|
10150
|
+
timedOut: counts.timedOut,
|
|
10151
|
+
pending: counts.pending,
|
|
10152
|
+
durationMs: Date.now() - startedAt,
|
|
10153
|
+
responders: statuses
|
|
10154
|
+
};
|
|
10155
|
+
}
|
|
10156
|
+
function createSSRInquiryBridge(options = {}) {
|
|
10157
|
+
const bootstrapEndpoint = resolveBootstrapEndpoint({
|
|
10158
|
+
runtime: "server",
|
|
10159
|
+
bootstrap: options.bootstrap,
|
|
10160
|
+
cadenzaDB: options.cadenzaDB
|
|
10161
|
+
});
|
|
10162
|
+
const fetchImplementation = ensureFetch();
|
|
10163
|
+
const initialInquiryResults = {};
|
|
10164
|
+
const postDelegation = async (targetUrl, remoteRoutineName, context, timeoutMs) => {
|
|
10165
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
10166
|
+
const response = await fetchImplementation(`${targetUrl}/delegation`, {
|
|
10167
|
+
method: "POST",
|
|
10168
|
+
headers: {
|
|
10169
|
+
"Content-Type": "application/json"
|
|
10170
|
+
},
|
|
10171
|
+
body: JSON.stringify({
|
|
10172
|
+
...context,
|
|
10173
|
+
__remoteRoutineName: remoteRoutineName,
|
|
10174
|
+
__metadata: {
|
|
10175
|
+
...context.__metadata ?? {},
|
|
10176
|
+
__deputyExecId: (0, import_uuid4.v4)()
|
|
10177
|
+
}
|
|
10178
|
+
}),
|
|
10179
|
+
signal
|
|
10180
|
+
});
|
|
10181
|
+
return await response.json();
|
|
10182
|
+
};
|
|
10183
|
+
const queryTable = async (tableName, queryData, timeoutMs) => {
|
|
10184
|
+
const response = await postDelegation(
|
|
10185
|
+
bootstrapEndpoint.url,
|
|
10186
|
+
`Query ${tableName}`,
|
|
10187
|
+
{ queryData },
|
|
10188
|
+
timeoutMs
|
|
10189
|
+
);
|
|
10190
|
+
return normalizeArrayResponse(response, [
|
|
10191
|
+
`${tableName}Rows`,
|
|
10192
|
+
`${tableName}s`,
|
|
10193
|
+
tableName,
|
|
10194
|
+
tableName.replace(/_([a-z])/g, (_match, char) => char.toUpperCase())
|
|
10195
|
+
]);
|
|
10196
|
+
};
|
|
10197
|
+
return {
|
|
10198
|
+
async inquire(inquiry, context = {}, inquiryOptions = {}) {
|
|
10199
|
+
const startedAt = Date.now();
|
|
10200
|
+
const overallTimeoutMs = inquiryOptions.overallTimeoutMs ?? inquiryOptions.timeout ?? 3e4;
|
|
10201
|
+
const perResponderTimeoutMs = inquiryOptions.perResponderTimeoutMs ?? overallTimeoutMs;
|
|
10202
|
+
const intentMaps = (await queryTable(
|
|
10203
|
+
"intent_to_task_map",
|
|
10204
|
+
{
|
|
10205
|
+
filter: {
|
|
10206
|
+
intent_name: inquiry
|
|
10207
|
+
}
|
|
10208
|
+
},
|
|
10209
|
+
overallTimeoutMs
|
|
10210
|
+
)).map(normalizeIntentMap).filter(
|
|
10211
|
+
(item) => !!item && item.intentName === inquiry && !item.deleted
|
|
10212
|
+
);
|
|
10213
|
+
if (intentMaps.length === 0) {
|
|
10214
|
+
return {
|
|
10215
|
+
__inquiryMeta: buildInquiryMeta(inquiry, startedAt, [])
|
|
10216
|
+
};
|
|
10217
|
+
}
|
|
10218
|
+
const relevantServiceNames = Array.from(
|
|
10219
|
+
new Set(intentMaps.map((item) => item.serviceName))
|
|
10220
|
+
);
|
|
10221
|
+
const rawServiceInstances = await queryTable(
|
|
10222
|
+
"service_instance",
|
|
10223
|
+
{
|
|
10224
|
+
filter: {
|
|
10225
|
+
service_name: relevantServiceNames
|
|
10226
|
+
}
|
|
10227
|
+
},
|
|
10228
|
+
overallTimeoutMs
|
|
10229
|
+
);
|
|
10230
|
+
const rawServiceTransports = await queryTable(
|
|
10231
|
+
"service_instance_transport",
|
|
10232
|
+
{
|
|
10233
|
+
filter: {
|
|
10234
|
+
deleted: false
|
|
10235
|
+
}
|
|
10236
|
+
},
|
|
10237
|
+
overallTimeoutMs
|
|
10238
|
+
);
|
|
10239
|
+
const transportsByInstance = /* @__PURE__ */ new Map();
|
|
10240
|
+
for (const transport of rawServiceTransports) {
|
|
10241
|
+
const serviceInstanceId = String(
|
|
10242
|
+
transport.serviceInstanceId ?? transport.service_instance_id ?? ""
|
|
10243
|
+
).trim();
|
|
10244
|
+
if (!serviceInstanceId) {
|
|
10245
|
+
continue;
|
|
10246
|
+
}
|
|
10247
|
+
if (!transportsByInstance.has(serviceInstanceId)) {
|
|
10248
|
+
transportsByInstance.set(serviceInstanceId, []);
|
|
10249
|
+
}
|
|
10250
|
+
transportsByInstance.get(serviceInstanceId).push(transport);
|
|
10251
|
+
}
|
|
10252
|
+
const serviceInstances = rawServiceInstances.map(
|
|
10253
|
+
(instance) => normalizeServiceInstanceDescriptor({
|
|
10254
|
+
...instance,
|
|
10255
|
+
transports: transportsByInstance.get(String(instance.uuid ?? "").trim()) ?? []
|
|
10256
|
+
})
|
|
10257
|
+
).filter(
|
|
10258
|
+
(item) => !!item && relevantServiceNames.includes(item.serviceName) && item.isActive && !item.isNonResponsive && !item.isBlocked
|
|
10259
|
+
).sort((left, right) => {
|
|
10260
|
+
if (left.serviceName !== right.serviceName) {
|
|
10261
|
+
return left.serviceName.localeCompare(right.serviceName);
|
|
10262
|
+
}
|
|
10263
|
+
if (left.isPrimary !== right.isPrimary) {
|
|
10264
|
+
return left.isPrimary ? -1 : 1;
|
|
10265
|
+
}
|
|
10266
|
+
return (left.numberOfRunningGraphs ?? 0) - (right.numberOfRunningGraphs ?? 0);
|
|
10267
|
+
});
|
|
10268
|
+
const statuses = intentMaps.map((map) => ({
|
|
10269
|
+
isRemote: true,
|
|
10270
|
+
serviceName: map.serviceName,
|
|
10271
|
+
taskName: map.taskName,
|
|
10272
|
+
taskVersion: map.taskVersion,
|
|
10273
|
+
localTaskName: `SSR inquiry via ${map.serviceName} (${map.taskName} v${map.taskVersion})`,
|
|
10274
|
+
status: "timed_out",
|
|
10275
|
+
durationMs: 0
|
|
10276
|
+
}));
|
|
10277
|
+
const fulfilledContexts = await Promise.all(
|
|
10278
|
+
intentMaps.map(async (map, index) => {
|
|
10279
|
+
const status = statuses[index];
|
|
10280
|
+
const startedAtForResponder = Date.now();
|
|
10281
|
+
const selectedInstance = serviceInstances.find(
|
|
10282
|
+
(instance) => instance.serviceName === map.serviceName
|
|
10283
|
+
);
|
|
10284
|
+
if (!selectedInstance) {
|
|
10285
|
+
status.status = "failed";
|
|
10286
|
+
status.error = `No active instances for ${map.serviceName}`;
|
|
10287
|
+
status.durationMs = Date.now() - startedAtForResponder;
|
|
10288
|
+
return null;
|
|
10289
|
+
}
|
|
10290
|
+
const targetTransport = selectTransportForRole(
|
|
10291
|
+
selectedInstance.transports,
|
|
10292
|
+
"internal",
|
|
10293
|
+
"rest"
|
|
10294
|
+
);
|
|
10295
|
+
if (!targetTransport) {
|
|
10296
|
+
status.status = "failed";
|
|
10297
|
+
status.error = `No internal transport for ${selectedInstance.serviceName}/${selectedInstance.uuid}`;
|
|
10298
|
+
status.durationMs = Date.now() - startedAtForResponder;
|
|
10299
|
+
return null;
|
|
10300
|
+
}
|
|
10301
|
+
const targetUrl = targetTransport.origin;
|
|
10302
|
+
try {
|
|
10303
|
+
const result = await postDelegation(
|
|
10304
|
+
targetUrl,
|
|
10305
|
+
map.taskName,
|
|
10306
|
+
context,
|
|
10307
|
+
perResponderTimeoutMs
|
|
10308
|
+
);
|
|
10309
|
+
status.durationMs = Date.now() - startedAtForResponder;
|
|
10310
|
+
if (result?.errored || result?.failed) {
|
|
10311
|
+
status.status = "failed";
|
|
10312
|
+
status.error = String(
|
|
10313
|
+
result?.__error ?? result?.error ?? "Remote inquiry failed"
|
|
10314
|
+
);
|
|
10315
|
+
return null;
|
|
10316
|
+
}
|
|
10317
|
+
status.status = "fulfilled";
|
|
10318
|
+
return result;
|
|
10319
|
+
} catch (error) {
|
|
10320
|
+
status.durationMs = Date.now() - startedAtForResponder;
|
|
10321
|
+
if (error instanceof Error && (error.name === "AbortError" || /timed out/i.test(error.message))) {
|
|
10322
|
+
status.status = "timed_out";
|
|
10323
|
+
status.error = error.message;
|
|
10324
|
+
return null;
|
|
10325
|
+
}
|
|
10326
|
+
status.status = "failed";
|
|
10327
|
+
status.error = error instanceof Error ? error.message : String(error);
|
|
10328
|
+
return null;
|
|
10329
|
+
}
|
|
10330
|
+
})
|
|
10331
|
+
);
|
|
10332
|
+
const mergedContext = mergeInquiryContexts(
|
|
10333
|
+
fulfilledContexts.filter(
|
|
10334
|
+
(item) => item !== null
|
|
10335
|
+
)
|
|
10336
|
+
);
|
|
10337
|
+
const responseContext = {
|
|
10338
|
+
...mergedContext,
|
|
10339
|
+
__inquiryMeta: buildInquiryMeta(inquiry, startedAt, statuses)
|
|
10340
|
+
};
|
|
10341
|
+
if (inquiryOptions.hydrationKey) {
|
|
10342
|
+
initialInquiryResults[inquiryOptions.hydrationKey] = responseContext;
|
|
10343
|
+
}
|
|
10344
|
+
if (inquiryOptions.requireComplete && statuses.some((status) => status.status !== "fulfilled")) {
|
|
10345
|
+
throw {
|
|
10346
|
+
...responseContext,
|
|
10347
|
+
__error: `Inquiry '${inquiry}' did not complete successfully`,
|
|
10348
|
+
errored: true
|
|
10349
|
+
};
|
|
10350
|
+
}
|
|
10351
|
+
return responseContext;
|
|
10352
|
+
},
|
|
10353
|
+
dehydrate() {
|
|
10354
|
+
return {
|
|
10355
|
+
initialInquiryResults: { ...initialInquiryResults }
|
|
10356
|
+
};
|
|
10357
|
+
}
|
|
10358
|
+
};
|
|
10359
|
+
}
|
|
10360
|
+
|
|
10361
|
+
// src/index.ts
|
|
9319
10362
|
var index_default = CadenzaService;
|
|
9320
10363
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9321
10364
|
0 && (module.exports = {
|
|
9322
10365
|
Actor,
|
|
10366
|
+
DatabaseController,
|
|
9323
10367
|
DatabaseTask,
|
|
9324
10368
|
DebounceTask,
|
|
9325
10369
|
DeputyTask,
|
|
@@ -9331,6 +10375,7 @@ var index_default = CadenzaService;
|
|
|
9331
10375
|
SignalController,
|
|
9332
10376
|
SignalTransmissionTask,
|
|
9333
10377
|
SocketController,
|
|
9334
|
-
Task
|
|
10378
|
+
Task,
|
|
10379
|
+
createSSRInquiryBridge
|
|
9335
10380
|
});
|
|
9336
10381
|
//# sourceMappingURL=index.js.map
|