@nice-code/action 0.6.3 → 0.8.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/build/devtools/browser/index.js +590 -1246
- package/build/devtools/server/index.js +7 -1
- package/build/index.js +1257 -972
- package/build/types/ActionRuntime/ActionRuntime.d.ts +23 -1
- package/build/types/ActionRuntime/Handler/ExternalClient/Transport/Transport.types.d.ts +6 -0
- package/build/types/ActionRuntime/Handler/ExternalClient/Transport/WebSocket/WebSocketConnection.d.ts +2 -1
- package/build/types/ActionRuntime/Handler/ExternalClient/Transport/WebSocket/secureWsChannel.d.ts +63 -0
- package/build/types/ActionRuntime/Handler/Server/ActionServerHandler.d.ts +64 -1
- package/build/types/ActionRuntime/Handler/Server/WsConnectionStateStore.d.ts +61 -0
- package/build/types/ActionRuntime/Handler/Server/createActionFetchHandler.d.ts +40 -0
- package/build/types/ActionRuntime/Handler/Server/createSecureActionServer.d.ts +71 -0
- package/build/types/devtools/browser/NiceActionDevtools.d.ts +1 -1
- package/build/types/devtools/browser/components/ActionErrorDisplay.d.ts +1 -1
- package/build/types/devtools/browser/components/CallStackSection.d.ts +1 -1
- package/build/types/devtools/browser/components/ChildDispatchChips.d.ts +1 -1
- package/build/types/devtools/browser/components/Chip.d.ts +1 -1
- package/build/types/devtools/browser/components/DetailSection.d.ts +1 -1
- package/build/types/devtools/browser/components/DomainChip.d.ts +1 -1
- package/build/types/devtools/browser/components/HandlerChips.d.ts +1 -1
- package/build/types/devtools/browser/components/Icon.d.ts +1 -1
- package/build/types/devtools/browser/components/MetaSection.d.ts +1 -1
- package/build/types/devtools/browser/components/NiceErrorDisplay.d.ts +2 -2
- package/build/types/devtools/browser/components/OriginChip.d.ts +1 -1
- package/build/types/devtools/browser/components/RoutingSection.d.ts +1 -1
- package/build/types/devtools/browser/components/RunningTimer.d.ts +2 -2
- package/build/types/devtools/browser/components/SectionLabel.d.ts +1 -4
- package/build/types/devtools/browser/components/StackTraceSection.d.ts +1 -1
- package/build/types/devtools/browser/components/Tooltip.d.ts +1 -24
- package/build/types/devtools/browser/components/action_detail/ActionDetailPanel.d.ts +1 -1
- package/build/types/devtools/browser/components/action_list/ActionEntryRow.d.ts +1 -1
- package/build/types/devtools/browser/components/action_list/ActionInputAndOutputChip.d.ts +1 -1
- package/build/types/devtools/browser/components/action_list/ActionList.d.ts +1 -1
- package/build/types/devtools/browser/components/action_list/IoTooltipContent.d.ts +1 -4
- package/build/types/devtools/browser/components/utils.d.ts +1 -3
- package/build/types/devtools/core/ActionDevtools.types.d.ts +1 -1
- package/build/types/devtools/core/ActionDevtoolsCore.d.ts +4 -1
- package/build/types/devtools/core/devtools_colors.d.ts +1 -26
- package/build/types/index.d.ts +5 -1
- package/package.json +33 -29
- package/build/types/devtools/browser/components/PanelChrome.d.ts +0 -41
- package/build/types/devtools/browser/devtools_dock.d.ts +0 -54
package/build/index.js
CHANGED
|
@@ -689,7 +689,7 @@ var isActionPayload_Result_JsonObject = (obj) => {
|
|
|
689
689
|
|
|
690
690
|
// src/ActionRuntime/ActionRuntime.ts
|
|
691
691
|
import { castNiceError } from "@nice-code/error";
|
|
692
|
-
import { nanoid as
|
|
692
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
693
693
|
|
|
694
694
|
// src/utils/getAssumedRuntimeEnvironment.ts
|
|
695
695
|
import { runtime } from "std-env";
|
|
@@ -715,6 +715,21 @@ function isActionPayload_Any_JsonObject(obj) {
|
|
|
715
715
|
return isActionPayload_Request_JsonObject(obj) || isActionPayload_Result_JsonObject(obj) || isActionPayload_Progress_JsonObject(obj);
|
|
716
716
|
}
|
|
717
717
|
|
|
718
|
+
// src/ActionRuntime/Handler/ExternalClient/ActionExternalClientHandler.ts
|
|
719
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
720
|
+
|
|
721
|
+
// src/ActionRuntime/HandlerCallStack.ts
|
|
722
|
+
var _stack = [];
|
|
723
|
+
function pushHandlerCuid(cuid) {
|
|
724
|
+
_stack.push(cuid);
|
|
725
|
+
}
|
|
726
|
+
function popHandlerCuid() {
|
|
727
|
+
_stack.pop();
|
|
728
|
+
}
|
|
729
|
+
function peekHandlerCuid() {
|
|
730
|
+
return _stack[_stack.length - 1];
|
|
731
|
+
}
|
|
732
|
+
|
|
718
733
|
// src/ActionRuntime/ActionDomainManager.ts
|
|
719
734
|
class ActionDomainManager {
|
|
720
735
|
_domains = new Map;
|
|
@@ -899,693 +914,753 @@ class ActionRouter {
|
|
|
899
914
|
}
|
|
900
915
|
}
|
|
901
916
|
|
|
902
|
-
// src/ActionRuntime/
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
_registeredExternalHandlers = [];
|
|
910
|
-
_applied = false;
|
|
911
|
-
static getDefault() {
|
|
912
|
-
return getDefaultActionRuntime();
|
|
913
|
-
}
|
|
914
|
-
constructor(coordinate) {
|
|
915
|
-
this._coordinate = coordinate.specifyIfUnset({
|
|
916
|
-
insId: nanoid2(14)
|
|
917
|
-
});
|
|
918
|
-
this.timeCreated = Date.now();
|
|
919
|
-
this.actionRouter = new ActionRouter({
|
|
920
|
-
contextType: "runtime_to_handler" /* runtime_to_handler */,
|
|
921
|
-
runtime: this
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
get coordinate() {
|
|
925
|
-
return this._coordinate;
|
|
917
|
+
// src/ActionRuntime/Handler/ActionHandler.ts
|
|
918
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
919
|
+
|
|
920
|
+
class ActionHandler {
|
|
921
|
+
cuid;
|
|
922
|
+
constructor() {
|
|
923
|
+
this.cuid = nanoid2();
|
|
926
924
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
930
|
-
label: `updating RuntimeCoordinate with a different "envId" ("${this._coordinate.envId}" → "${specifics.envId}")`
|
|
931
|
-
});
|
|
932
|
-
}
|
|
933
|
-
this._coordinate = this._coordinate.specify(specifics);
|
|
934
|
-
this.apply();
|
|
925
|
+
getActionRouter() {
|
|
926
|
+
return this.actionRouter;
|
|
935
927
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport.ts
|
|
931
|
+
import { err as err2 } from "@nice-code/error";
|
|
932
|
+
|
|
933
|
+
// src/ActionRuntime/Handler/ExternalClient/err_nice_external_client.ts
|
|
934
|
+
var err_nice_external_client = err_nice_action.createChildDomain({
|
|
935
|
+
domain: "err_nice_external_client",
|
|
936
|
+
schema: {}
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport.ts
|
|
940
|
+
var EErrId_NiceTransport;
|
|
941
|
+
((EErrId_NiceTransport2) => {
|
|
942
|
+
EErrId_NiceTransport2["timeout"] = "timeout";
|
|
943
|
+
EErrId_NiceTransport2["not_found"] = "not_found";
|
|
944
|
+
EErrId_NiceTransport2["unsupported"] = "unsupported";
|
|
945
|
+
EErrId_NiceTransport2["initialization_failed"] = "initialization_failed";
|
|
946
|
+
EErrId_NiceTransport2["send_failed"] = "send_failed";
|
|
947
|
+
EErrId_NiceTransport2["invalid_action_response"] = "invalid_action_response";
|
|
948
|
+
})(EErrId_NiceTransport ||= {});
|
|
949
|
+
var err_nice_transport = err_nice_external_client.createChildDomain({
|
|
950
|
+
domain: "err_nice_transport",
|
|
951
|
+
schema: {
|
|
952
|
+
["timeout" /* timeout */]: err2({
|
|
953
|
+
message: ({ timeout }) => `ActionConnect transport timed out after ${timeout}ms.`
|
|
954
|
+
}),
|
|
955
|
+
["not_found" /* not_found */]: err2({
|
|
956
|
+
message: ({ actionId }) => `No connected transport found for action "${actionId}".`
|
|
957
|
+
}),
|
|
958
|
+
["unsupported" /* unsupported */]: err2({
|
|
959
|
+
message: ({ transportTypes }) => `${transportTypes.length} Transport(s) [${transportTypes.join(", ")}] found but returned "unsupported" status.`
|
|
960
|
+
}),
|
|
961
|
+
["initialization_failed" /* initialization_failed */]: err2({
|
|
962
|
+
message: ({ actionId }) => `Transports found for action "${actionId}", but none are ready.`
|
|
963
|
+
}),
|
|
964
|
+
["send_failed" /* send_failed */]: err2({
|
|
965
|
+
message: ({ actionId, httpStatusCode, message }) => `Failed to send action "${actionId}" [${httpStatusCode ?? "Unknown status"}]: ${message ?? "Unknown error"}.`,
|
|
966
|
+
httpStatusCode: ({ httpStatusCode }) => httpStatusCode ?? 500
|
|
967
|
+
}),
|
|
968
|
+
["invalid_action_response" /* invalid_action_response */]: err2({
|
|
969
|
+
message: ({ actionId }) => `Invalid action response JSON structure for action "${actionId}"`
|
|
970
|
+
})
|
|
945
971
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/Transport.types.ts
|
|
975
|
+
var ETransportType;
|
|
976
|
+
((ETransportType2) => {
|
|
977
|
+
ETransportType2["ws"] = "ws";
|
|
978
|
+
ETransportType2["http"] = "http";
|
|
979
|
+
ETransportType2["custom"] = "custom";
|
|
980
|
+
})(ETransportType ||= {});
|
|
981
|
+
var ETransportStatus;
|
|
982
|
+
((ETransportStatus2) => {
|
|
983
|
+
ETransportStatus2["uninitialized"] = "uninitialized";
|
|
984
|
+
ETransportStatus2["unsupported"] = "unsupported";
|
|
985
|
+
ETransportStatus2["initializing"] = "initializing";
|
|
986
|
+
ETransportStatus2["ready"] = "ready";
|
|
987
|
+
ETransportStatus2["failed"] = "failed";
|
|
988
|
+
})(ETransportStatus ||= {});
|
|
989
|
+
|
|
990
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/ConnectionTransportManager.ts
|
|
991
|
+
class ConnectionTransportManager {
|
|
992
|
+
_cache;
|
|
993
|
+
_transports = [];
|
|
994
|
+
constructor(_cache) {
|
|
995
|
+
this._cache = _cache;
|
|
954
996
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
if (isActionPayload_Any_JsonObject(wire)) {
|
|
958
|
-
const domain = this.actionRouter.domainManager.getActionDomainOrThrow(wire);
|
|
959
|
-
action = domain.hydrateAnyAction(wire);
|
|
960
|
-
}
|
|
961
|
-
if (action == null) {
|
|
962
|
-
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
963
|
-
}
|
|
964
|
-
return this.handleActionPayload(action);
|
|
997
|
+
addTransport(transport) {
|
|
998
|
+
this._transports.push(transport);
|
|
965
999
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
const observers = action.context._domain._collectActionObservers();
|
|
969
|
-
let handlerForAction;
|
|
970
|
-
try {
|
|
971
|
-
handlerForAction = this.getHandlerForActionOrThrow(action, options);
|
|
972
|
-
} catch (err2) {
|
|
973
|
-
const runningAction2 = new RunningAction({
|
|
974
|
-
context: action.context,
|
|
975
|
-
request: action
|
|
976
|
-
});
|
|
977
|
-
runningAction2.addUpdateListeners(observers);
|
|
978
|
-
runningAction2._completeWithResult(action.errorResult(castNiceError(err2)));
|
|
979
|
-
return runningAction2;
|
|
980
|
-
}
|
|
981
|
-
const runningAction = await handlerForAction.handleActionRequest(action, {
|
|
982
|
-
...options,
|
|
983
|
-
targetLocalRuntime: this
|
|
984
|
-
});
|
|
985
|
-
runningAction.addUpdateListeners(observers);
|
|
986
|
-
this._trySetupReturnDispatch(runningAction);
|
|
987
|
-
return runningAction;
|
|
988
|
-
}
|
|
989
|
-
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
990
|
-
label: `Handling incoming action payloads of type "${action.type}"`
|
|
991
|
-
});
|
|
1000
|
+
getPreferredTransport() {
|
|
1001
|
+
return this._transports[0];
|
|
992
1002
|
}
|
|
993
|
-
|
|
994
|
-
const
|
|
995
|
-
const
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1003
|
+
async getReadyTransport(routeActionParams) {
|
|
1004
|
+
const action = routeActionParams.action;
|
|
1005
|
+
const candidates = [];
|
|
1006
|
+
const unavailableTransports = [];
|
|
1007
|
+
for (const transport of this._transports) {
|
|
1008
|
+
const cacheKey = transport.getCacheKey(routeActionParams);
|
|
1009
|
+
if (cacheKey != null) {
|
|
1010
|
+
const cached = this._cache.get(cacheKey);
|
|
1011
|
+
if (cached != null) {
|
|
1012
|
+
if (cached instanceof Promise) {
|
|
1013
|
+
candidates.push(cached);
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
candidates.push(Promise.resolve({ ...cached, transport }));
|
|
1017
|
+
break;
|
|
1000
1018
|
}
|
|
1001
|
-
return true;
|
|
1002
|
-
}
|
|
1003
|
-
if (targetExternalClient != null) {
|
|
1004
|
-
return false;
|
|
1005
1019
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1020
|
+
const statusInfo = transport.getTransport(routeActionParams);
|
|
1021
|
+
if (statusInfo.status === "ready" /* ready */) {
|
|
1022
|
+
const readyData = statusInfo.readyData;
|
|
1023
|
+
if (cacheKey != null) {
|
|
1024
|
+
const entry = { methods: readyData, transport };
|
|
1025
|
+
this._cache.set(cacheKey, entry);
|
|
1026
|
+
readyData.addOnDisconnectListener?.(() => {
|
|
1027
|
+
if (this._cache.get(cacheKey) === entry)
|
|
1028
|
+
this._cache.delete(cacheKey);
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
candidates.push(Promise.resolve({ methods: readyData, transport }));
|
|
1032
|
+
break;
|
|
1008
1033
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
return;
|
|
1013
|
-
}
|
|
1014
|
-
const scoringExternalClient = targetExternalClient ?? RuntimeCoordinate.unknown;
|
|
1015
|
-
let handlerScore = -1;
|
|
1016
|
-
let handler;
|
|
1017
|
-
for (const possibleHandler of possibleHandlers) {
|
|
1018
|
-
if (possibleHandler.handlerType === "local" /* local */ && handler == null) {
|
|
1019
|
-
return possibleHandler;
|
|
1034
|
+
if (statusInfo.status === "unsupported" /* unsupported */) {
|
|
1035
|
+
unavailableTransports.push(transport);
|
|
1036
|
+
continue;
|
|
1020
1037
|
}
|
|
1021
|
-
if (
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1038
|
+
if (statusInfo.status === "initializing" /* initializing */) {
|
|
1039
|
+
const promise = statusInfo.initializationPromise.then((info) => {
|
|
1040
|
+
if (info.status === "failed" /* failed */) {
|
|
1041
|
+
throw info.error;
|
|
1042
|
+
}
|
|
1043
|
+
if (info.status === "unsupported" /* unsupported */) {
|
|
1044
|
+
throw err_nice_transport.fromId("unsupported" /* unsupported */, {
|
|
1045
|
+
transportTypes: [transport.type]
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
const readyData = info.readyData;
|
|
1049
|
+
const entry = { methods: readyData, transport };
|
|
1050
|
+
if (cacheKey != null) {
|
|
1051
|
+
if (this._cache.get(cacheKey) === promise) {
|
|
1052
|
+
this._cache.set(cacheKey, entry);
|
|
1053
|
+
readyData.addOnDisconnectListener?.(() => {
|
|
1054
|
+
if (this._cache.get(cacheKey) === entry)
|
|
1055
|
+
this._cache.delete(cacheKey);
|
|
1056
|
+
});
|
|
1057
|
+
} else {
|
|
1058
|
+
readyData.disconnect?.();
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
return entry;
|
|
1062
|
+
}).catch((e) => {
|
|
1063
|
+
if (cacheKey != null && this._cache.get(cacheKey) === promise) {
|
|
1064
|
+
this._cache.delete(cacheKey);
|
|
1065
|
+
}
|
|
1066
|
+
throw e;
|
|
1067
|
+
});
|
|
1068
|
+
if (cacheKey != null) {
|
|
1069
|
+
this._cache.set(cacheKey, promise);
|
|
1026
1070
|
}
|
|
1071
|
+
candidates.push(promise);
|
|
1027
1072
|
}
|
|
1028
1073
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
1035
|
-
actionId: action.id,
|
|
1036
|
-
domain: action.domain,
|
|
1037
|
-
specifiedClient: options?.targetExternalClient
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1040
|
-
return handler;
|
|
1041
|
-
}
|
|
1042
|
-
addHandlers(handlers) {
|
|
1043
|
-
for (const handler of handlers) {
|
|
1044
|
-
if (handler.handlerType === "external" /* external */) {
|
|
1045
|
-
handler._setIncomingActionDataListener((json) => this.resolveIncomingActionPayload(json));
|
|
1046
|
-
this._registeredExternalHandlers.push(handler);
|
|
1047
|
-
}
|
|
1048
|
-
const handlerRouter = handler.getActionRouter();
|
|
1049
|
-
this.actionRouter.addDomainsFromOther(handlerRouter);
|
|
1050
|
-
if (this._applied) {
|
|
1051
|
-
this.apply();
|
|
1052
|
-
}
|
|
1053
|
-
for (const key of handlerRouter.getRegisteredKeys()) {
|
|
1054
|
-
const alreadyRegistered = this.actionRouter.getForKey(key).some((h) => h.cuid === handler.cuid);
|
|
1055
|
-
if (!alreadyRegistered) {
|
|
1056
|
-
this.actionRouter.addForKey(key, handler);
|
|
1057
|
-
}
|
|
1074
|
+
if (candidates.length === 0) {
|
|
1075
|
+
if (unavailableTransports.length > 0) {
|
|
1076
|
+
throw err_nice_transport.fromId("unsupported" /* unsupported */, {
|
|
1077
|
+
transportTypes: unavailableTransports.map((t) => t.type)
|
|
1078
|
+
});
|
|
1058
1079
|
}
|
|
1080
|
+
throw err_nice_transport.fromId("not_found" /* not_found */, {
|
|
1081
|
+
actionId: action.id
|
|
1082
|
+
});
|
|
1059
1083
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
apply() {
|
|
1069
|
-
this._applied = true;
|
|
1070
|
-
for (const domain of this.actionRouter.getDomains()) {
|
|
1071
|
-
this.applyRuntimeForDomain(domain);
|
|
1072
|
-
}
|
|
1073
|
-
return this;
|
|
1074
|
-
}
|
|
1075
|
-
getReturnHandlerForOrigin(originClient) {
|
|
1076
|
-
if (originClient.envId === UNSET_RUNTIME_ENV_ID)
|
|
1077
|
-
return;
|
|
1078
|
-
let bestScore = -1;
|
|
1079
|
-
let bestHandler;
|
|
1080
|
-
for (const handler of this._registeredExternalHandlers) {
|
|
1081
|
-
const score = originClient.similarityLevel(handler.externalClient);
|
|
1082
|
-
if (score > bestScore) {
|
|
1083
|
-
bestScore = score;
|
|
1084
|
-
bestHandler = handler;
|
|
1084
|
+
let lastError;
|
|
1085
|
+
for (const candidate of candidates) {
|
|
1086
|
+
try {
|
|
1087
|
+
return await candidate;
|
|
1088
|
+
} catch (e) {
|
|
1089
|
+
lastError = e;
|
|
1085
1090
|
}
|
|
1086
1091
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
for (const ra of this._pendingRunningActions.values()) {
|
|
1091
|
-
ra._abort(err_nice_action.fromId("runtime_reset" /* runtime_reset */));
|
|
1092
|
-
}
|
|
1093
|
-
for (const handler of this._registeredExternalHandlers) {
|
|
1094
|
-
handler.clearTransportCache();
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
_trySetupReturnDispatch(runningAction) {
|
|
1098
|
-
const originClient = runningAction.context.originClient;
|
|
1099
|
-
if (originClient.envId === UNSET_RUNTIME_ENV_ID || originClient.isSameFor(this._coordinate).id) {
|
|
1100
|
-
return;
|
|
1101
|
-
}
|
|
1102
|
-
runningAction.addUpdateListeners([
|
|
1103
|
-
(update) => {
|
|
1104
|
-
if (update.type === "finished" /* finished */ && update.finishType === "success" /* success */) {
|
|
1105
|
-
const returnHandler = this.getReturnHandlerForOrigin(originClient);
|
|
1106
|
-
returnHandler?.sendReturnPayload(update.response, { targetLocalRuntime: this }).catch(() => {});
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
]);
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
var runtimeState = {
|
|
1113
|
-
defaultLocalRuntime: undefined,
|
|
1114
|
-
assumedRuntimeInfo: undefined
|
|
1115
|
-
};
|
|
1116
|
-
function getDefaultActionRuntime() {
|
|
1117
|
-
if (runtimeState.assumedRuntimeInfo == null) {
|
|
1118
|
-
runtimeState.assumedRuntimeInfo = getAssumedRuntimeInfo();
|
|
1119
|
-
}
|
|
1120
|
-
if (runtimeState.defaultLocalRuntime == null) {
|
|
1121
|
-
runtimeState.defaultLocalRuntime = new ActionRuntime(RuntimeCoordinate.unknown.specify({
|
|
1122
|
-
perId: `${runtimeState.assumedRuntimeInfo?.runtimeName ?? "unknown"}-runtime`
|
|
1123
|
-
}));
|
|
1092
|
+
throw err_nice_transport.fromId("initialization_failed" /* initialization_failed */, {
|
|
1093
|
+
actionId: action.id
|
|
1094
|
+
}).withOriginError(lastError);
|
|
1124
1095
|
}
|
|
1125
|
-
return runtimeState.defaultLocalRuntime;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
// src/ActionRuntime/HandlerCallStack.ts
|
|
1129
|
-
var _stack = [];
|
|
1130
|
-
function pushHandlerCuid(cuid) {
|
|
1131
|
-
_stack.push(cuid);
|
|
1132
|
-
}
|
|
1133
|
-
function popHandlerCuid() {
|
|
1134
|
-
_stack.pop();
|
|
1135
1096
|
}
|
|
1136
|
-
function peekHandlerCuid() {
|
|
1137
|
-
return _stack[_stack.length - 1];
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
// src/ActionRuntime/Handler/ActionHandler.ts
|
|
1141
|
-
import { nanoid as nanoid3 } from "nanoid";
|
|
1142
1097
|
|
|
1143
|
-
|
|
1098
|
+
// src/ActionRuntime/Handler/ExternalClient/ActionExternalClientHandler.ts
|
|
1099
|
+
class ActionExternalClientHandler extends ActionHandler {
|
|
1100
|
+
externalClient;
|
|
1101
|
+
handlerType = "external" /* external */;
|
|
1144
1102
|
cuid;
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
return this.actionRouter;
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
// src/ActionRuntime/Handler/Local/ActionLocalHandler.ts
|
|
1154
|
-
class ActionLocalHandler extends ActionHandler {
|
|
1155
|
-
handlerType = "local" /* local */;
|
|
1103
|
+
_defaultTimeout;
|
|
1104
|
+
_transportCache = new Map;
|
|
1105
|
+
transportManager = new ConnectionTransportManager(this._transportCache);
|
|
1106
|
+
_incomingActionDataListeners = [];
|
|
1156
1107
|
actionRouter = new ActionRouter({
|
|
1157
1108
|
contextType: "handler_route" /* handler_route */,
|
|
1158
1109
|
handler: this
|
|
1159
1110
|
});
|
|
1160
|
-
constructor(
|
|
1111
|
+
constructor({
|
|
1112
|
+
runtimeCoordinate: externalClientSpecifier,
|
|
1113
|
+
transports,
|
|
1114
|
+
defaultTimeout
|
|
1115
|
+
}) {
|
|
1161
1116
|
super();
|
|
1117
|
+
this.externalClient = externalClientSpecifier;
|
|
1118
|
+
this.cuid = nanoid3();
|
|
1119
|
+
this._defaultTimeout = defaultTimeout ?? DEFAULT_TRANSPORT_TIMEOUT;
|
|
1120
|
+
for (const transport of transports) {
|
|
1121
|
+
const connection = transport._createConnection({
|
|
1122
|
+
resolvers: {
|
|
1123
|
+
onIncomingActionDataJson: (json) => {
|
|
1124
|
+
for (const l of this._incomingActionDataListeners)
|
|
1125
|
+
l(json);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
connection.definition = transport;
|
|
1130
|
+
this.transportManager.addTransport(connection);
|
|
1131
|
+
}
|
|
1162
1132
|
}
|
|
1163
|
-
forDomain(domain
|
|
1164
|
-
this.actionRouter.forDomain(domain,
|
|
1133
|
+
forDomain(domain) {
|
|
1134
|
+
this.actionRouter.forDomain(domain, true);
|
|
1165
1135
|
return this;
|
|
1166
1136
|
}
|
|
1167
|
-
forAction(action
|
|
1168
|
-
this.actionRouter.forAction(action,
|
|
1137
|
+
forAction(action) {
|
|
1138
|
+
this.actionRouter.forAction(action, true);
|
|
1169
1139
|
return this;
|
|
1170
1140
|
}
|
|
1171
|
-
forActionIds(domain, ids
|
|
1172
|
-
this.actionRouter.forActionIds(domain, ids,
|
|
1141
|
+
forActionIds(domain, ids) {
|
|
1142
|
+
this.actionRouter.forActionIds(domain, ids, true);
|
|
1173
1143
|
return this;
|
|
1174
1144
|
}
|
|
1175
|
-
|
|
1176
|
-
this.
|
|
1177
|
-
return this;
|
|
1145
|
+
_setIncomingActionDataListener(listener) {
|
|
1146
|
+
this._incomingActionDataListeners.push(listener);
|
|
1178
1147
|
}
|
|
1179
1148
|
async handleActionRequest(action, config) {
|
|
1180
|
-
const
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
action.
|
|
1185
|
-
|
|
1186
|
-
|
|
1149
|
+
const localRuntime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();
|
|
1150
|
+
const localClient = localRuntime.coordinate;
|
|
1151
|
+
const incomingTimeout = config?.timeout ?? this._defaultTimeout;
|
|
1152
|
+
const parentCuid = peekHandlerCuid();
|
|
1153
|
+
const callSite = action._callSite ?? new Error().stack;
|
|
1154
|
+
const routeParams = {
|
|
1155
|
+
action,
|
|
1156
|
+
localClient,
|
|
1157
|
+
externalClient: this.externalClient
|
|
1158
|
+
};
|
|
1159
|
+
const preferredTransport = this.transportManager.getPreferredTransport();
|
|
1160
|
+
const routeItem = preferredTransport != null ? {
|
|
1161
|
+
runtime: localClient,
|
|
1162
|
+
handler: this.toHandlerRouteItem(preferredTransport, routeParams),
|
|
1187
1163
|
time: Date.now()
|
|
1188
|
-
}
|
|
1164
|
+
} : undefined;
|
|
1165
|
+
if (routeItem != null)
|
|
1166
|
+
action.context.addRouteItem(routeItem);
|
|
1189
1167
|
const runningAction = new RunningAction({
|
|
1190
1168
|
context: action.context,
|
|
1191
1169
|
request: action,
|
|
1192
|
-
parentCuid
|
|
1193
|
-
callSite
|
|
1194
|
-
});
|
|
1195
|
-
this._handleRunningAction(handler, runningAction).catch((err2) => {
|
|
1196
|
-
if (err2 instanceof NiceError) {
|
|
1197
|
-
runningAction._completeWithResult(action.errorResult(err2));
|
|
1198
|
-
} else if (isNiceErrorObject(err2)) {
|
|
1199
|
-
runningAction._completeWithResult(action.errorResult(castNiceError2(err2)));
|
|
1200
|
-
} else {
|
|
1201
|
-
runningAction._abort(err2);
|
|
1202
|
-
}
|
|
1170
|
+
parentCuid,
|
|
1171
|
+
callSite
|
|
1203
1172
|
});
|
|
1173
|
+
localRuntime.registerRunningAction(runningAction);
|
|
1174
|
+
this._dispatchWhenTransportReady(runningAction, routeParams, routeItem, incomingTimeout);
|
|
1204
1175
|
return runningAction;
|
|
1205
1176
|
}
|
|
1206
|
-
async
|
|
1207
|
-
const
|
|
1208
|
-
if (state.result != null) {
|
|
1209
|
-
return;
|
|
1210
|
-
}
|
|
1211
|
-
await Promise.resolve();
|
|
1212
|
-
pushHandlerCuid(runningAction.cuid);
|
|
1177
|
+
async _dispatchWhenTransportReady(runningAction, routeParams, routeItem, incomingTimeout) {
|
|
1178
|
+
const action = routeParams.action;
|
|
1213
1179
|
try {
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
if (
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
const domain = this.actionRouter.domainManager.getActionDomainOrThrow(state.request);
|
|
1220
|
-
result = domain.hydrateResultPayload(rawResult);
|
|
1180
|
+
const { methods, transport } = await this.transportManager.getReadyTransport(routeParams);
|
|
1181
|
+
const handlerRouteItem = this.toHandlerRouteItem(transport, routeParams);
|
|
1182
|
+
if (routeItem != null) {
|
|
1183
|
+
routeItem.handler = handlerRouteItem;
|
|
1184
|
+
routeItem.time = Date.now();
|
|
1221
1185
|
} else {
|
|
1222
|
-
|
|
1186
|
+
action.context.addRouteItem({
|
|
1187
|
+
runtime: routeParams.localClient,
|
|
1188
|
+
handler: handlerRouteItem,
|
|
1189
|
+
time: Date.now()
|
|
1190
|
+
});
|
|
1223
1191
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1192
|
+
const sendInput = {
|
|
1193
|
+
...routeParams,
|
|
1194
|
+
runningAction,
|
|
1195
|
+
timeout: incomingTimeout
|
|
1196
|
+
};
|
|
1197
|
+
if (action.type === "request" /* request */ && methods.updateRunConfig != null) {
|
|
1198
|
+
const runConfig = methods.updateRunConfig(sendInput);
|
|
1199
|
+
sendInput.timeout = runConfig?.timeout ?? incomingTimeout;
|
|
1200
|
+
}
|
|
1201
|
+
methods.sendActionData(sendInput);
|
|
1202
|
+
} catch (err3) {
|
|
1203
|
+
runningAction._abort(err3);
|
|
1227
1204
|
}
|
|
1228
1205
|
}
|
|
1229
|
-
async
|
|
1230
|
-
const
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1206
|
+
async sendReturnPayload(payload, config) {
|
|
1207
|
+
const localClient = config.targetLocalRuntime.coordinate;
|
|
1208
|
+
try {
|
|
1209
|
+
const { methods } = await this.transportManager.getReadyTransport({
|
|
1210
|
+
action: payload,
|
|
1211
|
+
localClient,
|
|
1212
|
+
externalClient: this.externalClient
|
|
1236
1213
|
});
|
|
1214
|
+
if (methods.sendReturnData == null)
|
|
1215
|
+
return false;
|
|
1216
|
+
methods.sendReturnData(payload, { localClient, externalClient: this.externalClient });
|
|
1217
|
+
return true;
|
|
1218
|
+
} catch {
|
|
1219
|
+
return false;
|
|
1237
1220
|
}
|
|
1238
|
-
return await this.handleActionRequest(hydratedAction, config);
|
|
1239
1221
|
}
|
|
1240
1222
|
toJsonObject() {
|
|
1241
1223
|
return {
|
|
1242
|
-
type: this.handlerType
|
|
1224
|
+
type: this.handlerType,
|
|
1225
|
+
client: this.externalClient
|
|
1243
1226
|
};
|
|
1244
1227
|
}
|
|
1245
|
-
toHandlerRouteItem() {
|
|
1228
|
+
toHandlerRouteItem(transport, input) {
|
|
1246
1229
|
return {
|
|
1247
|
-
type: this.handlerType
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
return new ActionLocalHandler;
|
|
1253
|
-
};
|
|
1254
|
-
|
|
1255
|
-
// src/utils/isAction_Context_JsonObject.ts
|
|
1256
|
-
var isAction_Context_JsonObject = (obj) => {
|
|
1257
|
-
return isAction_Base_JsonObject(obj) && obj.form === "context" /* context */;
|
|
1258
|
-
};
|
|
1259
|
-
|
|
1260
|
-
// src/utils/isAction_Core_JsonObject.ts
|
|
1261
|
-
var isAction_Core_JsonObject = (obj) => {
|
|
1262
|
-
return isAction_Base_JsonObject(obj) && obj.form === "core" /* core */;
|
|
1263
|
-
};
|
|
1264
|
-
|
|
1265
|
-
// src/utils/isAction_Any_JsonObject.ts
|
|
1266
|
-
function isAction_Any_JsonObject(obj) {
|
|
1267
|
-
return isActionPayload_Any_JsonObject(obj) || isAction_Context_JsonObject(obj) || isAction_Core_JsonObject(obj);
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
// src/utils/assertIsActionJson.ts
|
|
1271
|
-
function assertIsActionJson(obj) {
|
|
1272
|
-
if (!isAction_Any_JsonObject(obj)) {
|
|
1273
|
-
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
// src/utils/isAction_Any_Instance.ts
|
|
1278
|
-
function isAction_Any_Instance(value) {
|
|
1279
|
-
return value instanceof ActionCore || value instanceof ActionPayload || value instanceof ActionContext;
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
|
-
// src/ActionDefinition/Domain/ActionDomainBase.ts
|
|
1283
|
-
class ActionDomainBase {
|
|
1284
|
-
domain;
|
|
1285
|
-
allDomains;
|
|
1286
|
-
actionSchema;
|
|
1287
|
-
_listeners = [];
|
|
1288
|
-
constructor(definition) {
|
|
1289
|
-
this.domain = definition.domain;
|
|
1290
|
-
this.allDomains = definition.allDomains;
|
|
1291
|
-
this.actionSchema = definition.actionSchema;
|
|
1292
|
-
}
|
|
1293
|
-
addActionListener(listener) {
|
|
1294
|
-
this._listeners.push(listener);
|
|
1295
|
-
return () => {
|
|
1296
|
-
this._listeners = this._listeners.filter((l) => l !== listener);
|
|
1230
|
+
type: this.handlerType,
|
|
1231
|
+
client: this.externalClient,
|
|
1232
|
+
transOrd: transport.transOrd,
|
|
1233
|
+
transType: transport.type,
|
|
1234
|
+
transInfo: transport.getRouteInfo(input)
|
|
1297
1235
|
};
|
|
1298
1236
|
}
|
|
1299
|
-
|
|
1300
|
-
|
|
1237
|
+
clearTransportCache() {
|
|
1238
|
+
for (const entry of this._transportCache.values()) {
|
|
1239
|
+
if (entry instanceof Promise) {
|
|
1240
|
+
entry.then((ready) => ready.methods.disconnect?.()).catch(() => {});
|
|
1241
|
+
} else {
|
|
1242
|
+
entry.methods.disconnect?.();
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
this._transportCache.clear();
|
|
1301
1246
|
}
|
|
1302
1247
|
}
|
|
1248
|
+
var createExternalClientHandler = (config) => {
|
|
1249
|
+
return new ActionExternalClientHandler(config);
|
|
1250
|
+
};
|
|
1303
1251
|
|
|
1304
|
-
// src/
|
|
1305
|
-
class
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
get rootDomain() {
|
|
1316
|
-
return this._rootDomain;
|
|
1252
|
+
// src/ActionRuntime/ActionRuntime.ts
|
|
1253
|
+
class ActionRuntime {
|
|
1254
|
+
_coordinate;
|
|
1255
|
+
timeCreated;
|
|
1256
|
+
runtimeInfo = getAssumedRuntimeInfo();
|
|
1257
|
+
actionRouter;
|
|
1258
|
+
_pendingRunningActions = new Map;
|
|
1259
|
+
_registeredExternalHandlers = [];
|
|
1260
|
+
_applied = false;
|
|
1261
|
+
static getDefault() {
|
|
1262
|
+
return getDefaultActionRuntime();
|
|
1317
1263
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1264
|
+
constructor(coordinate) {
|
|
1265
|
+
this._coordinate = coordinate.specifyIfUnset({
|
|
1266
|
+
insId: nanoid4(14)
|
|
1267
|
+
});
|
|
1268
|
+
this.timeCreated = Date.now();
|
|
1269
|
+
this.actionRouter = new ActionRouter({
|
|
1270
|
+
contextType: "runtime_to_handler" /* runtime_to_handler */,
|
|
1271
|
+
runtime: this
|
|
1272
|
+
});
|
|
1320
1273
|
}
|
|
1321
|
-
|
|
1322
|
-
this.
|
|
1274
|
+
get coordinate() {
|
|
1275
|
+
return this._coordinate;
|
|
1323
1276
|
}
|
|
1324
|
-
|
|
1325
|
-
if (this.
|
|
1326
|
-
throw err_nice_action.fromId("
|
|
1327
|
-
|
|
1328
|
-
allParentDomains: this.allDomains,
|
|
1329
|
-
parentDomain: this.domain
|
|
1277
|
+
specifyRuntimeCoordinate(specifics) {
|
|
1278
|
+
if (specifics.envId != null && this._coordinate.envId !== specifics.envId) {
|
|
1279
|
+
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
1280
|
+
label: `updating RuntimeCoordinate with a different "envId" ("${this._coordinate.envId}" → "${specifics.envId}")`
|
|
1330
1281
|
});
|
|
1331
1282
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
domain: subDomainDef.domain,
|
|
1335
|
-
actionSchema: subDomainDef.actions
|
|
1336
|
-
}, { rootDomain: this._rootDomain });
|
|
1337
|
-
}
|
|
1338
|
-
get action() {
|
|
1339
|
-
return this._actionMap;
|
|
1283
|
+
this._coordinate = this._coordinate.specify(specifics);
|
|
1284
|
+
this.apply();
|
|
1340
1285
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1286
|
+
registerRunningAction(ra) {
|
|
1287
|
+
this._pendingRunningActions.set(ra.cuid, ra);
|
|
1288
|
+
ra.addUpdateListeners([
|
|
1289
|
+
(update) => {
|
|
1290
|
+
if (update.type === "finished" /* finished */) {
|
|
1291
|
+
this._pendingRunningActions.delete(ra.cuid);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
]);
|
|
1343
1295
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
domain: this.domain,
|
|
1349
|
-
actionId: id
|
|
1296
|
+
resolveIncomingActionPayload(json) {
|
|
1297
|
+
if (json.type === "request" /* request */) {
|
|
1298
|
+
this.handleActionPayloadWire(json).catch((err3) => {
|
|
1299
|
+
console.error(`[ActionRuntime] Incoming action [${json.domain}:${json.id}:${json.form}:${json.type}] unhandled:`, err3);
|
|
1350
1300
|
});
|
|
1301
|
+
return;
|
|
1351
1302
|
}
|
|
1352
|
-
|
|
1353
|
-
}
|
|
1354
|
-
wrapAsPartialLocalHandler(wrappedActionExecutor) {
|
|
1355
|
-
const _handler = new ActionLocalHandler;
|
|
1356
|
-
const executor = wrappedActionExecutor;
|
|
1357
|
-
for (const actionKey in wrappedActionExecutor) {
|
|
1358
|
-
if (!this.actionSchema[actionKey]) {
|
|
1359
|
-
continue;
|
|
1360
|
-
}
|
|
1361
|
-
_handler.forAction(this.actionForId(actionKey), (request) => executor[request.id](request.input));
|
|
1362
|
-
}
|
|
1363
|
-
return _handler;
|
|
1364
|
-
}
|
|
1365
|
-
wrapAsLocalHandler(wrappedActionExecutor) {
|
|
1366
|
-
const _handler = new ActionLocalHandler;
|
|
1367
|
-
const executor = wrappedActionExecutor;
|
|
1368
|
-
return _handler.forDomain(this, (request) => executor[request.id](request.input));
|
|
1369
|
-
}
|
|
1370
|
-
hydrateContext(id, contextData) {
|
|
1371
|
-
return new ActionContext(this, id, {
|
|
1372
|
-
timeCreated: contextData.timeCreated,
|
|
1373
|
-
cuid: contextData.cuid,
|
|
1374
|
-
routing: contextData.routing.map((item) => {
|
|
1375
|
-
return {
|
|
1376
|
-
runtime: new RuntimeCoordinate(item.runtime),
|
|
1377
|
-
handler: item.handler,
|
|
1378
|
-
time: item.time
|
|
1379
|
-
};
|
|
1380
|
-
}),
|
|
1381
|
-
originClient: contextData.originClient ? new RuntimeCoordinate(contextData.originClient) : RuntimeCoordinate.unknown
|
|
1382
|
-
});
|
|
1383
|
-
}
|
|
1384
|
-
isDomainAction(action) {
|
|
1385
|
-
return isAction_Any_Instance(action) && action.domain === this.domain;
|
|
1303
|
+
this._pendingRunningActions.get(json.context.cuid)?._resolveFromJson(json);
|
|
1386
1304
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
});
|
|
1305
|
+
async handleActionPayloadWire(wire) {
|
|
1306
|
+
let action;
|
|
1307
|
+
if (isActionPayload_Any_JsonObject(wire)) {
|
|
1308
|
+
const domain = this.actionRouter.domainManager.getActionDomainOrThrow(wire);
|
|
1309
|
+
action = domain.hydrateAnyAction(wire);
|
|
1393
1310
|
}
|
|
1394
|
-
if (
|
|
1395
|
-
throw err_nice_action.fromId("
|
|
1396
|
-
expected: this.domain,
|
|
1397
|
-
received: serialized.domain
|
|
1398
|
-
});
|
|
1311
|
+
if (action == null) {
|
|
1312
|
+
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
1399
1313
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1314
|
+
return this.handleActionPayload(action);
|
|
1315
|
+
}
|
|
1316
|
+
async handleActionPayload(action, options) {
|
|
1317
|
+
if (action.type === "request" /* request */) {
|
|
1318
|
+
const observers = action.context._domain._collectActionObservers();
|
|
1319
|
+
let handlerForAction;
|
|
1320
|
+
try {
|
|
1321
|
+
handlerForAction = this.getHandlerForActionOrThrow(action, options);
|
|
1322
|
+
} catch (err3) {
|
|
1323
|
+
const runningAction2 = new RunningAction({
|
|
1324
|
+
context: action.context,
|
|
1325
|
+
request: action
|
|
1326
|
+
});
|
|
1327
|
+
runningAction2.addUpdateListeners(observers);
|
|
1328
|
+
runningAction2._completeWithResult(action.errorResult(castNiceError(err3)));
|
|
1329
|
+
return runningAction2;
|
|
1330
|
+
}
|
|
1331
|
+
const runningAction = await handlerForAction.handleActionRequest(action, {
|
|
1332
|
+
...options,
|
|
1333
|
+
targetLocalRuntime: this
|
|
1405
1334
|
});
|
|
1335
|
+
runningAction.addUpdateListeners(observers);
|
|
1336
|
+
this._trySetupReturnDispatch(runningAction);
|
|
1337
|
+
return runningAction;
|
|
1406
1338
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
time: serialized.time
|
|
1339
|
+
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
1340
|
+
label: `Handling incoming action payloads of type "${action.type}"`
|
|
1410
1341
|
});
|
|
1411
1342
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
expected: this.domain,
|
|
1422
|
-
received: serialized.domain
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
const id = serialized.id;
|
|
1426
|
-
if (!this.actionSchema[id]) {
|
|
1427
|
-
throw err_nice_action.fromId("hydration_action_id_not_found" /* hydration_action_id_not_found */, {
|
|
1428
|
-
domain: this.domain,
|
|
1429
|
-
actionId: serialized.id
|
|
1430
|
-
});
|
|
1431
|
-
}
|
|
1432
|
-
const contextAction = this.hydrateContext(id, serialized.context);
|
|
1433
|
-
const result = serialized.result.ok ? {
|
|
1434
|
-
ok: true,
|
|
1435
|
-
output: contextAction.schema.deserializeOutput(serialized.result.output)
|
|
1436
|
-
} : serialized.result;
|
|
1437
|
-
return new ActionPayload_Result({ context: contextAction }, result, {
|
|
1438
|
-
time: serialized.time
|
|
1439
|
-
});
|
|
1440
|
-
}
|
|
1441
|
-
hydrateAnyAction(actionJson) {
|
|
1442
|
-
assertIsActionJson(actionJson);
|
|
1443
|
-
if (actionJson.form === "data" /* data */) {
|
|
1444
|
-
if (actionJson.type === "request" /* request */) {
|
|
1445
|
-
return this.hydrateRequestPayload(actionJson);
|
|
1343
|
+
_getHandlerForAction(action, options) {
|
|
1344
|
+
const handlers = this.actionRouter.getRouteDataEntriesForAction(action);
|
|
1345
|
+
const targetExternalClient = options?.targetExternalClient;
|
|
1346
|
+
const possibleHandlers = handlers.filter((handler2) => {
|
|
1347
|
+
if (handler2.handlerType === "external" /* external */) {
|
|
1348
|
+
if (targetExternalClient && !targetExternalClient.isSameFor(handler2.externalClient).id) {
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
return true;
|
|
1446
1352
|
}
|
|
1447
|
-
if (
|
|
1448
|
-
return
|
|
1353
|
+
if (targetExternalClient != null) {
|
|
1354
|
+
return false;
|
|
1449
1355
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
const allListeners = [
|
|
1455
|
-
...options?.listeners ?? [],
|
|
1456
|
-
...this._listeners
|
|
1457
|
-
];
|
|
1458
|
-
return this._rootDomain._runAction(request, {
|
|
1459
|
-
...options,
|
|
1460
|
-
listeners: allListeners
|
|
1356
|
+
if (action.type === "request" /* request */) {
|
|
1357
|
+
return true;
|
|
1358
|
+
}
|
|
1359
|
+
return false;
|
|
1461
1360
|
});
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
const map = {};
|
|
1465
|
-
for (const id in this.actionSchema) {
|
|
1466
|
-
map[id] = new ActionCore(this, id);
|
|
1361
|
+
if (possibleHandlers.length === 0) {
|
|
1362
|
+
return;
|
|
1467
1363
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1364
|
+
const scoringExternalClient = targetExternalClient ?? RuntimeCoordinate.unknown;
|
|
1365
|
+
let handlerScore = -1;
|
|
1366
|
+
let handler;
|
|
1367
|
+
for (const possibleHandler of possibleHandlers) {
|
|
1368
|
+
if (possibleHandler.handlerType === "local" /* local */ && handler == null) {
|
|
1369
|
+
return possibleHandler;
|
|
1370
|
+
}
|
|
1371
|
+
if (possibleHandler.handlerType === "external" /* external */) {
|
|
1372
|
+
const score = scoringExternalClient.similarityLevel(possibleHandler.externalClient);
|
|
1373
|
+
if (score > handlerScore) {
|
|
1374
|
+
handlerScore = score;
|
|
1375
|
+
handler = possibleHandler;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return handler;
|
|
1478
1380
|
}
|
|
1479
|
-
|
|
1480
|
-
const
|
|
1481
|
-
if (
|
|
1482
|
-
throw err_nice_action.fromId("
|
|
1483
|
-
|
|
1484
|
-
|
|
1381
|
+
getHandlerForActionOrThrow(action, options) {
|
|
1382
|
+
const handler = this._getHandlerForAction(action, options);
|
|
1383
|
+
if (handler == null) {
|
|
1384
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
1385
|
+
actionId: action.id,
|
|
1386
|
+
domain: action.domain,
|
|
1387
|
+
specifiedClient: options?.targetExternalClient
|
|
1485
1388
|
});
|
|
1486
1389
|
}
|
|
1487
|
-
|
|
1488
|
-
if (this._runtimes.has(id)) {
|
|
1489
|
-
continue;
|
|
1490
|
-
}
|
|
1491
|
-
this._runtimes.set(id, runtime2);
|
|
1492
|
-
}
|
|
1390
|
+
return handler;
|
|
1493
1391
|
}
|
|
1494
|
-
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
return;
|
|
1392
|
+
addHandlers(handlers) {
|
|
1393
|
+
for (const handler of handlers) {
|
|
1394
|
+
if (handler.handlerType === "external" /* external */) {
|
|
1395
|
+
handler._setIncomingActionDataListener((json) => this.resolveIncomingActionPayload(json));
|
|
1396
|
+
this._registeredExternalHandlers.push(handler);
|
|
1500
1397
|
}
|
|
1501
|
-
const
|
|
1502
|
-
|
|
1503
|
-
|
|
1398
|
+
const handlerRouter = handler.getActionRouter();
|
|
1399
|
+
this.actionRouter.addDomainsFromOther(handlerRouter);
|
|
1400
|
+
if (this._applied) {
|
|
1401
|
+
this.apply();
|
|
1504
1402
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
});
|
|
1403
|
+
for (const key of handlerRouter.getRegisteredKeys()) {
|
|
1404
|
+
const alreadyRegistered = this.actionRouter.getForKey(key).some((h) => h.cuid === handler.cuid);
|
|
1405
|
+
if (!alreadyRegistered) {
|
|
1406
|
+
this.actionRouter.addForKey(key, handler);
|
|
1407
|
+
}
|
|
1511
1408
|
}
|
|
1512
1409
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1410
|
+
return this;
|
|
1411
|
+
}
|
|
1412
|
+
connectTo(externalCoordinate, options) {
|
|
1413
|
+
const handler = new ActionExternalClientHandler({
|
|
1414
|
+
runtimeCoordinate: externalCoordinate,
|
|
1415
|
+
transports: options.transports,
|
|
1416
|
+
defaultTimeout: options.defaultTimeout
|
|
1417
|
+
});
|
|
1418
|
+
for (const domain of options.domains ?? []) {
|
|
1419
|
+
handler.forDomain(domain);
|
|
1518
1420
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
domain: action.domain,
|
|
1522
|
-
actionId: action.id,
|
|
1523
|
-
specifiedClient: options?.targetLocalRuntime?.coordinate
|
|
1524
|
-
});
|
|
1421
|
+
for (const action of options.actions ?? []) {
|
|
1422
|
+
handler.forAction(action);
|
|
1525
1423
|
}
|
|
1424
|
+
this.addHandlers([handler, ...options.localHandlers ?? []]);
|
|
1425
|
+
this.apply();
|
|
1426
|
+
return handler;
|
|
1526
1427
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1428
|
+
applyRuntimeForDomain(domain) {
|
|
1429
|
+
const rootDomain = domain.rootDomain;
|
|
1430
|
+
if (!rootDomain._hasRuntime(this)) {
|
|
1431
|
+
rootDomain._registerRuntime(this);
|
|
1432
|
+
}
|
|
1529
1433
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
this.
|
|
1434
|
+
apply() {
|
|
1435
|
+
this._applied = true;
|
|
1436
|
+
for (const domain of this.actionRouter.getDomains()) {
|
|
1437
|
+
this.applyRuntimeForDomain(domain);
|
|
1438
|
+
}
|
|
1439
|
+
return this;
|
|
1533
1440
|
}
|
|
1534
|
-
|
|
1535
|
-
if (
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1441
|
+
getReturnHandlerForOrigin(originClient) {
|
|
1442
|
+
if (originClient.envId === UNSET_RUNTIME_ENV_ID)
|
|
1443
|
+
return;
|
|
1444
|
+
let bestScore = -1;
|
|
1445
|
+
let bestHandler;
|
|
1446
|
+
for (const handler of this._registeredExternalHandlers) {
|
|
1447
|
+
const score = originClient.similarityLevel(handler.externalClient);
|
|
1448
|
+
if (score > bestScore) {
|
|
1449
|
+
bestScore = score;
|
|
1450
|
+
bestHandler = handler;
|
|
1539
1451
|
}
|
|
1540
1452
|
}
|
|
1541
|
-
return
|
|
1453
|
+
return bestScore > 0 ? bestHandler : undefined;
|
|
1542
1454
|
}
|
|
1543
|
-
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
return runtime2;
|
|
1550
|
-
}
|
|
1455
|
+
resetRuntime() {
|
|
1456
|
+
for (const ra of this._pendingRunningActions.values()) {
|
|
1457
|
+
ra._abort(err_nice_action.fromId("runtime_reset" /* runtime_reset */));
|
|
1458
|
+
}
|
|
1459
|
+
for (const handler of this._registeredExternalHandlers) {
|
|
1460
|
+
handler.clearTransportCache();
|
|
1551
1461
|
}
|
|
1552
1462
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1463
|
+
_trySetupReturnDispatch(runningAction) {
|
|
1464
|
+
const originClient = runningAction.context.originClient;
|
|
1465
|
+
if (originClient.envId === UNSET_RUNTIME_ENV_ID || originClient.isSameFor(this._coordinate).id) {
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
runningAction.addUpdateListeners([
|
|
1469
|
+
(update) => {
|
|
1470
|
+
if (update.type === "finished" /* finished */ && update.finishType === "success" /* success */) {
|
|
1471
|
+
const returnHandler = this.getReturnHandlerForOrigin(originClient);
|
|
1472
|
+
returnHandler?.sendReturnPayload(update.response, { targetLocalRuntime: this }).catch(() => {});
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
]);
|
|
1555
1476
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1477
|
+
}
|
|
1478
|
+
var runtimeState = {
|
|
1479
|
+
defaultLocalRuntime: undefined,
|
|
1480
|
+
assumedRuntimeInfo: undefined
|
|
1481
|
+
};
|
|
1482
|
+
function getDefaultActionRuntime() {
|
|
1483
|
+
if (runtimeState.assumedRuntimeInfo == null) {
|
|
1484
|
+
runtimeState.assumedRuntimeInfo = getAssumedRuntimeInfo();
|
|
1558
1485
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
throw err_nice_action.fromId("no_client_runtimes_registered" /* no_client_runtimes_registered */, {
|
|
1564
|
-
context: this._context
|
|
1565
|
-
});
|
|
1566
|
-
}
|
|
1567
|
-
throw err_nice_action.fromId("client_runtime_not_registered" /* client_runtime_not_registered */, {
|
|
1568
|
-
context: this._context,
|
|
1569
|
-
clientStringId: runtimeCoordinateToStringIds(specifier)[0]
|
|
1570
|
-
});
|
|
1571
|
-
}
|
|
1572
|
-
return runtime2;
|
|
1486
|
+
if (runtimeState.defaultLocalRuntime == null) {
|
|
1487
|
+
runtimeState.defaultLocalRuntime = new ActionRuntime(RuntimeCoordinate.unknown.specify({
|
|
1488
|
+
perId: `${runtimeState.assumedRuntimeInfo?.runtimeName ?? "unknown"}-runtime`
|
|
1489
|
+
}));
|
|
1573
1490
|
}
|
|
1491
|
+
return runtimeState.defaultLocalRuntime;
|
|
1574
1492
|
}
|
|
1575
1493
|
|
|
1576
|
-
// src/
|
|
1577
|
-
class
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1494
|
+
// src/ActionRuntime/Handler/Local/ActionLocalHandler.ts
|
|
1495
|
+
class ActionLocalHandler extends ActionHandler {
|
|
1496
|
+
handlerType = "local" /* local */;
|
|
1497
|
+
actionRouter = new ActionRouter({
|
|
1498
|
+
contextType: "handler_route" /* handler_route */,
|
|
1499
|
+
handler: this
|
|
1500
|
+
});
|
|
1501
|
+
constructor() {
|
|
1502
|
+
super();
|
|
1503
|
+
}
|
|
1504
|
+
forDomain(domain, handler) {
|
|
1505
|
+
this.actionRouter.forDomain(domain, handler);
|
|
1506
|
+
return this;
|
|
1507
|
+
}
|
|
1508
|
+
forAction(action, handler) {
|
|
1509
|
+
this.actionRouter.forAction(action, handler);
|
|
1510
|
+
return this;
|
|
1511
|
+
}
|
|
1512
|
+
forActionIds(domain, ids, handler) {
|
|
1513
|
+
this.actionRouter.forActionIds(domain, ids, handler);
|
|
1514
|
+
return this;
|
|
1515
|
+
}
|
|
1516
|
+
forDomainActionCases(domain, cases) {
|
|
1517
|
+
this.actionRouter.forDomainActionCases(domain, cases);
|
|
1518
|
+
return this;
|
|
1519
|
+
}
|
|
1520
|
+
async handleActionRequest(action, config) {
|
|
1521
|
+
const targetLocalRuntime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();
|
|
1522
|
+
const handler = this.actionRouter.getRouteDataForActionOrThrow(action, {
|
|
1523
|
+
targetLocalRuntime
|
|
1586
1524
|
});
|
|
1587
|
-
|
|
1588
|
-
|
|
1525
|
+
action.context.addRouteItem({
|
|
1526
|
+
runtime: targetLocalRuntime.coordinate,
|
|
1527
|
+
handler: this.toHandlerRouteItem(),
|
|
1528
|
+
time: Date.now()
|
|
1529
|
+
});
|
|
1530
|
+
const runningAction = new RunningAction({
|
|
1531
|
+
context: action.context,
|
|
1532
|
+
request: action,
|
|
1533
|
+
parentCuid: peekHandlerCuid(),
|
|
1534
|
+
callSite: action._callSite ?? new Error().stack
|
|
1535
|
+
});
|
|
1536
|
+
this._handleRunningAction(handler, runningAction).catch((err3) => {
|
|
1537
|
+
if (err3 instanceof NiceError) {
|
|
1538
|
+
runningAction._completeWithResult(action.errorResult(err3));
|
|
1539
|
+
} else if (isNiceErrorObject(err3)) {
|
|
1540
|
+
runningAction._completeWithResult(action.errorResult(castNiceError2(err3)));
|
|
1541
|
+
} else {
|
|
1542
|
+
runningAction._abort(err3);
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
return runningAction;
|
|
1546
|
+
}
|
|
1547
|
+
async _handleRunningAction(handler, runningAction) {
|
|
1548
|
+
const state = runningAction.state;
|
|
1549
|
+
if (state.result != null) {
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
await Promise.resolve();
|
|
1553
|
+
pushHandlerCuid(runningAction.cuid);
|
|
1554
|
+
try {
|
|
1555
|
+
const rawResult = await handler(state.request);
|
|
1556
|
+
let result;
|
|
1557
|
+
if (rawResult instanceof ActionPayload_Result) {
|
|
1558
|
+
result = rawResult;
|
|
1559
|
+
} else if (rawResult != null && isActionPayload_Result_JsonObject(rawResult)) {
|
|
1560
|
+
const domain = this.actionRouter.domainManager.getActionDomainOrThrow(state.request);
|
|
1561
|
+
result = domain.hydrateResultPayload(rawResult);
|
|
1562
|
+
} else {
|
|
1563
|
+
result = state.request.successResult(rawResult);
|
|
1564
|
+
}
|
|
1565
|
+
runningAction._completeWithResult(result);
|
|
1566
|
+
} finally {
|
|
1567
|
+
popHandlerCuid();
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
async handlePayloadWireOrThrow(wire, config) {
|
|
1571
|
+
const hydratedAction = this.actionRouter.domainManager.hydrateActionPayload(wire);
|
|
1572
|
+
if (!(hydratedAction instanceof ActionPayload_Request)) {
|
|
1573
|
+
throw err_nice_action.fromId("wire_action_not_payload" /* wire_action_not_payload */, {
|
|
1574
|
+
domain: hydratedAction.domain,
|
|
1575
|
+
actionId: hydratedAction.id,
|
|
1576
|
+
actionState: hydratedAction.type ?? hydratedAction.form
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1579
|
+
return await this.handleActionRequest(hydratedAction, config);
|
|
1580
|
+
}
|
|
1581
|
+
toJsonObject() {
|
|
1582
|
+
return {
|
|
1583
|
+
type: this.handlerType
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
toHandlerRouteItem() {
|
|
1587
|
+
return {
|
|
1588
|
+
type: this.handlerType
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
var createLocalHandler = () => {
|
|
1593
|
+
return new ActionLocalHandler;
|
|
1594
|
+
};
|
|
1595
|
+
|
|
1596
|
+
// src/utils/isAction_Context_JsonObject.ts
|
|
1597
|
+
var isAction_Context_JsonObject = (obj) => {
|
|
1598
|
+
return isAction_Base_JsonObject(obj) && obj.form === "context" /* context */;
|
|
1599
|
+
};
|
|
1600
|
+
|
|
1601
|
+
// src/utils/isAction_Core_JsonObject.ts
|
|
1602
|
+
var isAction_Core_JsonObject = (obj) => {
|
|
1603
|
+
return isAction_Base_JsonObject(obj) && obj.form === "core" /* core */;
|
|
1604
|
+
};
|
|
1605
|
+
|
|
1606
|
+
// src/utils/isAction_Any_JsonObject.ts
|
|
1607
|
+
function isAction_Any_JsonObject(obj) {
|
|
1608
|
+
return isActionPayload_Any_JsonObject(obj) || isAction_Context_JsonObject(obj) || isAction_Core_JsonObject(obj);
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
// src/utils/assertIsActionJson.ts
|
|
1612
|
+
function assertIsActionJson(obj) {
|
|
1613
|
+
if (!isAction_Any_JsonObject(obj)) {
|
|
1614
|
+
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
// src/utils/isAction_Any_Instance.ts
|
|
1619
|
+
function isAction_Any_Instance(value) {
|
|
1620
|
+
return value instanceof ActionCore || value instanceof ActionPayload || value instanceof ActionContext;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// src/ActionDefinition/Domain/ActionDomainBase.ts
|
|
1624
|
+
class ActionDomainBase {
|
|
1625
|
+
domain;
|
|
1626
|
+
allDomains;
|
|
1627
|
+
actionSchema;
|
|
1628
|
+
_listeners = [];
|
|
1629
|
+
constructor(definition) {
|
|
1630
|
+
this.domain = definition.domain;
|
|
1631
|
+
this.allDomains = definition.allDomains;
|
|
1632
|
+
this.actionSchema = definition.actionSchema;
|
|
1633
|
+
}
|
|
1634
|
+
addActionListener(listener) {
|
|
1635
|
+
this._listeners.push(listener);
|
|
1636
|
+
return () => {
|
|
1637
|
+
this._listeners = this._listeners.filter((l) => l !== listener);
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
_getActionObservers() {
|
|
1641
|
+
return this._listeners;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
// src/ActionDefinition/Domain/ActionDomain.ts
|
|
1646
|
+
class ActionDomain extends ActionDomainBase {
|
|
1647
|
+
_rootDomain;
|
|
1648
|
+
_actionMap;
|
|
1649
|
+
constructor(definition, {
|
|
1650
|
+
rootDomain
|
|
1651
|
+
}) {
|
|
1652
|
+
super(definition);
|
|
1653
|
+
this._rootDomain = rootDomain;
|
|
1654
|
+
this._actionMap = this.createActionMap();
|
|
1655
|
+
}
|
|
1656
|
+
get rootDomain() {
|
|
1657
|
+
return this._rootDomain;
|
|
1658
|
+
}
|
|
1659
|
+
_collectActionObservers() {
|
|
1660
|
+
return [...this._rootDomain._getActionObservers(), ...this._getActionObservers()];
|
|
1661
|
+
}
|
|
1662
|
+
_registerRuntime(runtime2) {
|
|
1663
|
+
this._rootDomain._registerRuntime(runtime2);
|
|
1589
1664
|
}
|
|
1590
1665
|
createChildDomain(subDomainDef) {
|
|
1591
1666
|
if (this.allDomains.includes(subDomainDef.domain)) {
|
|
@@ -1599,440 +1674,402 @@ class ActionRootDomain extends ActionDomainBase {
|
|
|
1599
1674
|
allDomains: [...this.allDomains, subDomainDef.domain],
|
|
1600
1675
|
domain: subDomainDef.domain,
|
|
1601
1676
|
actionSchema: subDomainDef.actions
|
|
1602
|
-
}, { rootDomain: this });
|
|
1603
|
-
}
|
|
1604
|
-
_registerRuntime(runtime2) {
|
|
1605
|
-
this._actionRuntimeManager.registerRuntime(runtime2);
|
|
1677
|
+
}, { rootDomain: this._rootDomain });
|
|
1606
1678
|
}
|
|
1607
|
-
|
|
1608
|
-
return this.
|
|
1679
|
+
get action() {
|
|
1680
|
+
return this._actionMap;
|
|
1609
1681
|
}
|
|
1610
|
-
|
|
1611
|
-
return this.
|
|
1682
|
+
actionsMap() {
|
|
1683
|
+
return this._actionMap;
|
|
1612
1684
|
}
|
|
1613
|
-
|
|
1614
|
-
const
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
const runningAction2 = new RunningAction({
|
|
1620
|
-
context: actionPayload.context,
|
|
1621
|
-
request: actionPayload,
|
|
1622
|
-
callSite: actionPayload._callSite
|
|
1685
|
+
actionForId(id) {
|
|
1686
|
+
const actionSchema = this.actionSchema[id];
|
|
1687
|
+
if (!actionSchema) {
|
|
1688
|
+
throw err_nice_action.fromId("action_id_not_in_domain" /* action_id_not_in_domain */, {
|
|
1689
|
+
domain: this.domain,
|
|
1690
|
+
actionId: id
|
|
1623
1691
|
});
|
|
1624
|
-
runningAction2.addUpdateListeners(allListeners);
|
|
1625
|
-
runningAction2._failWithError(err2);
|
|
1626
|
-
throw err2;
|
|
1627
1692
|
}
|
|
1628
|
-
|
|
1629
|
-
actionPayload.context._setOriginClient(runtime2.coordinate);
|
|
1630
|
-
const runningAction = await handler.handleActionRequest(actionPayload, {
|
|
1631
|
-
targetLocalRuntime: runtime2
|
|
1632
|
-
});
|
|
1633
|
-
runningAction.addUpdateListeners(allListeners);
|
|
1634
|
-
return runningAction;
|
|
1693
|
+
return new ActionCore(this, id);
|
|
1635
1694
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
outputOptions;
|
|
1647
|
-
get inputSchema() {
|
|
1648
|
-
return this.inputOptions?.schema;
|
|
1695
|
+
wrapAsPartialLocalHandler(wrappedActionExecutor) {
|
|
1696
|
+
const _handler = new ActionLocalHandler;
|
|
1697
|
+
const executor = wrappedActionExecutor;
|
|
1698
|
+
for (const actionKey in wrappedActionExecutor) {
|
|
1699
|
+
if (!this.actionSchema[actionKey]) {
|
|
1700
|
+
continue;
|
|
1701
|
+
}
|
|
1702
|
+
_handler.forAction(this.actionForId(actionKey), (request) => executor[request.id](request.input));
|
|
1703
|
+
}
|
|
1704
|
+
return _handler;
|
|
1649
1705
|
}
|
|
1650
|
-
|
|
1651
|
-
|
|
1706
|
+
wrapAsLocalHandler(wrappedActionExecutor) {
|
|
1707
|
+
const _handler = new ActionLocalHandler;
|
|
1708
|
+
const executor = wrappedActionExecutor;
|
|
1709
|
+
return _handler.forDomain(this, (request) => executor[request.id](request.input));
|
|
1652
1710
|
}
|
|
1653
|
-
|
|
1654
|
-
this
|
|
1655
|
-
|
|
1711
|
+
hydrateContext(id, contextData) {
|
|
1712
|
+
return new ActionContext(this, id, {
|
|
1713
|
+
timeCreated: contextData.timeCreated,
|
|
1714
|
+
cuid: contextData.cuid,
|
|
1715
|
+
routing: contextData.routing.map((item) => {
|
|
1716
|
+
return {
|
|
1717
|
+
runtime: new RuntimeCoordinate(item.runtime),
|
|
1718
|
+
handler: item.handler,
|
|
1719
|
+
time: item.time
|
|
1720
|
+
};
|
|
1721
|
+
}),
|
|
1722
|
+
originClient: contextData.originClient ? new RuntimeCoordinate(contextData.originClient) : RuntimeCoordinate.unknown
|
|
1723
|
+
});
|
|
1656
1724
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
return this;
|
|
1725
|
+
isDomainAction(action) {
|
|
1726
|
+
return isAction_Any_Instance(action) && action.domain === this.domain;
|
|
1660
1727
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
return this.inputOptions.serialization.serialize(rawInput);
|
|
1668
|
-
}
|
|
1669
|
-
return rawInput;
|
|
1670
|
-
}
|
|
1671
|
-
deserializeInput(serialized) {
|
|
1672
|
-
if (this.inputOptions?.serialization) {
|
|
1673
|
-
return this.inputOptions.serialization.deserialize(serialized);
|
|
1674
|
-
}
|
|
1675
|
-
return serialized;
|
|
1676
|
-
}
|
|
1677
|
-
validateInput(value, meta) {
|
|
1678
|
-
if (this.inputOptions?.schema == null) {
|
|
1679
|
-
return value;
|
|
1728
|
+
hydrateRequestPayload(serialized) {
|
|
1729
|
+
if (serialized.type !== "request" /* request */) {
|
|
1730
|
+
throw err_nice_action.fromId("hydration_action_state_mismatch" /* hydration_action_state_mismatch */, {
|
|
1731
|
+
expected: "request" /* request */,
|
|
1732
|
+
received: serialized.type
|
|
1733
|
+
});
|
|
1680
1734
|
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
actionId: meta.actionId
|
|
1735
|
+
if (serialized.domain !== this.domain) {
|
|
1736
|
+
throw err_nice_action.fromId("hydration_domain_mismatch" /* hydration_domain_mismatch */, {
|
|
1737
|
+
expected: this.domain,
|
|
1738
|
+
received: serialized.domain
|
|
1686
1739
|
});
|
|
1687
1740
|
}
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1741
|
+
const id = serialized.id;
|
|
1742
|
+
if (!this.actionSchema[id]) {
|
|
1743
|
+
throw err_nice_action.fromId("hydration_action_id_not_found" /* hydration_action_id_not_found */, {
|
|
1744
|
+
domain: this.domain,
|
|
1745
|
+
actionId: serialized.id
|
|
1693
1746
|
});
|
|
1694
1747
|
}
|
|
1695
|
-
|
|
1748
|
+
const contextAction = this.hydrateContext(id, serialized.context);
|
|
1749
|
+
return new ActionPayload_Request({ context: contextAction }, contextAction.deserializeInput(serialized.input), {
|
|
1750
|
+
time: serialized.time
|
|
1751
|
+
});
|
|
1696
1752
|
}
|
|
1697
|
-
|
|
1698
|
-
if (
|
|
1699
|
-
|
|
1753
|
+
hydrateResultPayload(serialized) {
|
|
1754
|
+
if (serialized.type !== "result" /* result */) {
|
|
1755
|
+
throw err_nice_action.fromId("hydration_action_state_mismatch" /* hydration_action_state_mismatch */, {
|
|
1756
|
+
expected: "result" /* result */,
|
|
1757
|
+
received: serialized.type
|
|
1758
|
+
});
|
|
1700
1759
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
actionId: meta.actionId
|
|
1760
|
+
if (serialized.domain !== this.domain) {
|
|
1761
|
+
throw err_nice_action.fromId("hydration_domain_mismatch" /* hydration_domain_mismatch */, {
|
|
1762
|
+
expected: this.domain,
|
|
1763
|
+
received: serialized.domain
|
|
1706
1764
|
});
|
|
1707
1765
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1766
|
+
const id = serialized.id;
|
|
1767
|
+
if (!this.actionSchema[id]) {
|
|
1768
|
+
throw err_nice_action.fromId("hydration_action_id_not_found" /* hydration_action_id_not_found */, {
|
|
1769
|
+
domain: this.domain,
|
|
1770
|
+
actionId: serialized.id
|
|
1713
1771
|
});
|
|
1714
1772
|
}
|
|
1715
|
-
|
|
1773
|
+
const contextAction = this.hydrateContext(id, serialized.context);
|
|
1774
|
+
const result = serialized.result.ok ? {
|
|
1775
|
+
ok: true,
|
|
1776
|
+
output: contextAction.schema.deserializeOutput(serialized.result.output)
|
|
1777
|
+
} : serialized.result;
|
|
1778
|
+
return new ActionPayload_Result({ context: contextAction }, result, {
|
|
1779
|
+
time: serialized.time
|
|
1780
|
+
});
|
|
1716
1781
|
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1782
|
+
hydrateAnyAction(actionJson) {
|
|
1783
|
+
assertIsActionJson(actionJson);
|
|
1784
|
+
if (actionJson.form === "data" /* data */) {
|
|
1785
|
+
if (actionJson.type === "request" /* request */) {
|
|
1786
|
+
return this.hydrateRequestPayload(actionJson);
|
|
1787
|
+
}
|
|
1788
|
+
if (actionJson.type === "result" /* result */) {
|
|
1789
|
+
return this.hydrateResultPayload(actionJson);
|
|
1790
|
+
}
|
|
1720
1791
|
}
|
|
1721
|
-
return
|
|
1792
|
+
return this.actionForId(actionJson.id);
|
|
1722
1793
|
}
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1794
|
+
async runAction(request, options) {
|
|
1795
|
+
const allListeners = [
|
|
1796
|
+
...options?.listeners ?? [],
|
|
1797
|
+
...this._listeners
|
|
1798
|
+
];
|
|
1799
|
+
return this._rootDomain._runAction(request, {
|
|
1800
|
+
...options,
|
|
1801
|
+
listeners: allListeners
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
createActionMap() {
|
|
1805
|
+
const map = {};
|
|
1806
|
+
for (const id in this.actionSchema) {
|
|
1807
|
+
map[id] = new ActionCore(this, id);
|
|
1726
1808
|
}
|
|
1727
|
-
return
|
|
1809
|
+
return map;
|
|
1728
1810
|
}
|
|
1729
1811
|
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
import { err as err2 } from "@nice-code/error";
|
|
1738
|
-
|
|
1739
|
-
// src/ActionRuntime/Handler/ExternalClient/err_nice_external_client.ts
|
|
1740
|
-
var err_nice_external_client = err_nice_action.createChildDomain({
|
|
1741
|
-
domain: "err_nice_external_client",
|
|
1742
|
-
schema: {}
|
|
1743
|
-
});
|
|
1744
|
-
|
|
1745
|
-
// src/ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport.ts
|
|
1746
|
-
var EErrId_NiceTransport;
|
|
1747
|
-
((EErrId_NiceTransport2) => {
|
|
1748
|
-
EErrId_NiceTransport2["timeout"] = "timeout";
|
|
1749
|
-
EErrId_NiceTransport2["not_found"] = "not_found";
|
|
1750
|
-
EErrId_NiceTransport2["unsupported"] = "unsupported";
|
|
1751
|
-
EErrId_NiceTransport2["initialization_failed"] = "initialization_failed";
|
|
1752
|
-
EErrId_NiceTransport2["send_failed"] = "send_failed";
|
|
1753
|
-
EErrId_NiceTransport2["invalid_action_response"] = "invalid_action_response";
|
|
1754
|
-
})(EErrId_NiceTransport ||= {});
|
|
1755
|
-
var err_nice_transport = err_nice_external_client.createChildDomain({
|
|
1756
|
-
domain: "err_nice_transport",
|
|
1757
|
-
schema: {
|
|
1758
|
-
["timeout" /* timeout */]: err2({
|
|
1759
|
-
message: ({ timeout }) => `ActionConnect transport timed out after ${timeout}ms.`
|
|
1760
|
-
}),
|
|
1761
|
-
["not_found" /* not_found */]: err2({
|
|
1762
|
-
message: ({ actionId }) => `No connected transport found for action "${actionId}".`
|
|
1763
|
-
}),
|
|
1764
|
-
["unsupported" /* unsupported */]: err2({
|
|
1765
|
-
message: ({ transportTypes }) => `${transportTypes.length} Transport(s) [${transportTypes.join(", ")}] found but returned "unsupported" status.`
|
|
1766
|
-
}),
|
|
1767
|
-
["initialization_failed" /* initialization_failed */]: err2({
|
|
1768
|
-
message: ({ actionId }) => `Transports found for action "${actionId}", but none are ready.`
|
|
1769
|
-
}),
|
|
1770
|
-
["send_failed" /* send_failed */]: err2({
|
|
1771
|
-
message: ({ actionId, httpStatusCode, message }) => `Failed to send action "${actionId}" [${httpStatusCode ?? "Unknown status"}]: ${message ?? "Unknown error"}.`,
|
|
1772
|
-
httpStatusCode: ({ httpStatusCode }) => httpStatusCode ?? 500
|
|
1773
|
-
}),
|
|
1774
|
-
["invalid_action_response" /* invalid_action_response */]: err2({
|
|
1775
|
-
message: ({ actionId }) => `Invalid action response JSON structure for action "${actionId}"`
|
|
1776
|
-
})
|
|
1777
|
-
}
|
|
1778
|
-
});
|
|
1779
|
-
|
|
1780
|
-
// src/ActionRuntime/Handler/ExternalClient/Transport/Transport.types.ts
|
|
1781
|
-
var ETransportType;
|
|
1782
|
-
((ETransportType2) => {
|
|
1783
|
-
ETransportType2["ws"] = "ws";
|
|
1784
|
-
ETransportType2["http"] = "http";
|
|
1785
|
-
ETransportType2["custom"] = "custom";
|
|
1786
|
-
})(ETransportType ||= {});
|
|
1787
|
-
var ETransportStatus;
|
|
1788
|
-
((ETransportStatus2) => {
|
|
1789
|
-
ETransportStatus2["uninitialized"] = "uninitialized";
|
|
1790
|
-
ETransportStatus2["unsupported"] = "unsupported";
|
|
1791
|
-
ETransportStatus2["initializing"] = "initializing";
|
|
1792
|
-
ETransportStatus2["ready"] = "ready";
|
|
1793
|
-
ETransportStatus2["failed"] = "failed";
|
|
1794
|
-
})(ETransportStatus ||= {});
|
|
1795
|
-
|
|
1796
|
-
// src/ActionRuntime/Handler/ExternalClient/Transport/ConnectionTransportManager.ts
|
|
1797
|
-
class ConnectionTransportManager {
|
|
1798
|
-
_cache;
|
|
1799
|
-
_transports = [];
|
|
1800
|
-
constructor(_cache) {
|
|
1801
|
-
this._cache = _cache;
|
|
1802
|
-
}
|
|
1803
|
-
addTransport(transport) {
|
|
1804
|
-
this._transports.push(transport);
|
|
1805
|
-
}
|
|
1806
|
-
getPreferredTransport() {
|
|
1807
|
-
return this._transports[0];
|
|
1812
|
+
// src/ActionRuntime/ActionRuntimeManager.ts
|
|
1813
|
+
class ActionRuntimeManager {
|
|
1814
|
+
_runtimes = new Map;
|
|
1815
|
+
_preferredRuntimeClientId = null;
|
|
1816
|
+
_context;
|
|
1817
|
+
constructor(context) {
|
|
1818
|
+
this._context = context ?? {};
|
|
1808
1819
|
}
|
|
1809
|
-
|
|
1810
|
-
const
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
continue;
|
|
1821
|
-
}
|
|
1822
|
-
candidates.push(Promise.resolve({ ...cached, transport }));
|
|
1823
|
-
break;
|
|
1824
|
-
}
|
|
1820
|
+
registerRuntime(runtime2) {
|
|
1821
|
+
const runtimeId = runtime2.coordinate.stringId;
|
|
1822
|
+
if (this._runtimes.has(runtimeId)) {
|
|
1823
|
+
throw err_nice_action.fromId("client_runtime_already_registered" /* client_runtime_already_registered */, {
|
|
1824
|
+
context: this._context,
|
|
1825
|
+
client: runtime2.coordinate
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
for (const id of runtime2.coordinate.toStringIds()) {
|
|
1829
|
+
if (this._runtimes.has(id)) {
|
|
1830
|
+
continue;
|
|
1825
1831
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1832
|
+
this._runtimes.set(id, runtime2);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
getRuntimeAndHandlerForAction(action, options, throwOnIssue) {
|
|
1836
|
+
const localRuntime = options?.targetLocalRuntime;
|
|
1837
|
+
if (localRuntime != null) {
|
|
1838
|
+
const runtime2 = throwOnIssue ? this.getBestRuntimeOrThrow(options?.targetLocalRuntime?.coordinate) : this.getBestRuntime(options?.targetLocalRuntime?.coordinate);
|
|
1839
|
+
if (runtime2 == null) {
|
|
1840
|
+
return;
|
|
1835
1841
|
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1842
|
+
const handler = runtime2._getHandlerForAction(action, options);
|
|
1843
|
+
if (handler != null) {
|
|
1844
|
+
return { handler, runtime: runtime2 };
|
|
1839
1845
|
}
|
|
1840
|
-
if (
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
if (info.status === "unsupported" /* unsupported */) {
|
|
1846
|
-
throw err_nice_transport.fromId("unsupported" /* unsupported */, {
|
|
1847
|
-
transportTypes: [transport.type]
|
|
1848
|
-
});
|
|
1849
|
-
}
|
|
1850
|
-
const readyData = info.readyData;
|
|
1851
|
-
if (cacheKey != null) {
|
|
1852
|
-
this._cache.set(cacheKey, { methods: readyData, transport });
|
|
1853
|
-
readyData.addOnDisconnectListener?.(() => this._cache.delete(cacheKey));
|
|
1854
|
-
}
|
|
1855
|
-
return { methods: readyData, transport };
|
|
1856
|
-
}).catch((e) => {
|
|
1857
|
-
if (cacheKey != null)
|
|
1858
|
-
this._cache.delete(cacheKey);
|
|
1859
|
-
throw e;
|
|
1846
|
+
if (throwOnIssue) {
|
|
1847
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
1848
|
+
domain: action.domain,
|
|
1849
|
+
actionId: action.id,
|
|
1850
|
+
specifiedClient: localRuntime.coordinate
|
|
1860
1851
|
});
|
|
1861
|
-
if (cacheKey != null) {
|
|
1862
|
-
this._cache.set(cacheKey, promise);
|
|
1863
|
-
}
|
|
1864
|
-
candidates.push(promise);
|
|
1865
1852
|
}
|
|
1866
1853
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
});
|
|
1854
|
+
for (const runtime2 of this._runtimes.values()) {
|
|
1855
|
+
const handler = runtime2._getHandlerForAction(action);
|
|
1856
|
+
if (handler) {
|
|
1857
|
+
return { handler, runtime: runtime2 };
|
|
1872
1858
|
}
|
|
1873
|
-
|
|
1874
|
-
|
|
1859
|
+
}
|
|
1860
|
+
if (throwOnIssue) {
|
|
1861
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
1862
|
+
domain: action.domain,
|
|
1863
|
+
actionId: action.id,
|
|
1864
|
+
specifiedClient: options?.targetLocalRuntime?.coordinate
|
|
1875
1865
|
});
|
|
1876
1866
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1867
|
+
}
|
|
1868
|
+
getRuntimeAndHandlerForActionOrThrow(action, options) {
|
|
1869
|
+
return this.getRuntimeAndHandlerForAction(action, options, true);
|
|
1870
|
+
}
|
|
1871
|
+
setPreferredRuntime(runtime2) {
|
|
1872
|
+
const runtimeId = runtime2.coordinate.stringId;
|
|
1873
|
+
this._preferredRuntimeClientId = runtimeId;
|
|
1874
|
+
}
|
|
1875
|
+
getPreferredRuntime() {
|
|
1876
|
+
if (this._preferredRuntimeClientId) {
|
|
1877
|
+
const runtime2 = this._runtimes.get(this._preferredRuntimeClientId);
|
|
1878
|
+
if (runtime2) {
|
|
1879
|
+
return runtime2;
|
|
1883
1880
|
}
|
|
1884
1881
|
}
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1882
|
+
return this._runtimes.values().next().value;
|
|
1883
|
+
}
|
|
1884
|
+
getBestRuntimeForSpecifier(clientSpecifier) {
|
|
1885
|
+
const actionClient = new RuntimeCoordinate(clientSpecifier);
|
|
1886
|
+
const ids = actionClient.toStringIds();
|
|
1887
|
+
for (const id of ids) {
|
|
1888
|
+
const runtime2 = this._runtimes.get(id);
|
|
1889
|
+
if (runtime2) {
|
|
1890
|
+
return runtime2;
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
getBestRuntime(clientSpecifier) {
|
|
1895
|
+
return clientSpecifier != null ? this.getBestRuntimeForSpecifier(clientSpecifier) : this.getPreferredRuntime();
|
|
1896
|
+
}
|
|
1897
|
+
hasRuntime(runtime2) {
|
|
1898
|
+
return this._runtimes.has(runtime2.coordinate.stringId);
|
|
1899
|
+
}
|
|
1900
|
+
getBestRuntimeOrThrow(specifier) {
|
|
1901
|
+
const runtime2 = this.getBestRuntime(specifier);
|
|
1902
|
+
if (!runtime2) {
|
|
1903
|
+
if (specifier == null) {
|
|
1904
|
+
throw err_nice_action.fromId("no_client_runtimes_registered" /* no_client_runtimes_registered */, {
|
|
1905
|
+
context: this._context
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
throw err_nice_action.fromId("client_runtime_not_registered" /* client_runtime_not_registered */, {
|
|
1909
|
+
context: this._context,
|
|
1910
|
+
clientStringId: runtimeCoordinateToStringIds(specifier)[0]
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
return runtime2;
|
|
1888
1914
|
}
|
|
1889
1915
|
}
|
|
1890
1916
|
|
|
1891
|
-
// src/
|
|
1892
|
-
class
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
this.cuid = nanoid4();
|
|
1912
|
-
this._defaultTimeout = defaultTimeout ?? DEFAULT_TRANSPORT_TIMEOUT;
|
|
1913
|
-
for (const transport of transports) {
|
|
1914
|
-
const connection = transport._createConnection({
|
|
1915
|
-
resolvers: {
|
|
1916
|
-
onIncomingActionDataJson: (json) => {
|
|
1917
|
-
for (const l of this._incomingActionDataListeners)
|
|
1918
|
-
l(json);
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1917
|
+
// src/ActionDefinition/Domain/ActionRootDomain.ts
|
|
1918
|
+
class ActionRootDomain extends ActionDomainBase {
|
|
1919
|
+
domainDefinition;
|
|
1920
|
+
_actionRuntimeManager;
|
|
1921
|
+
constructor(domainDefinition) {
|
|
1922
|
+
const domainId = domainDefinition.domain;
|
|
1923
|
+
super({
|
|
1924
|
+
domain: domainId,
|
|
1925
|
+
allDomains: [domainId],
|
|
1926
|
+
actionSchema: {}
|
|
1927
|
+
});
|
|
1928
|
+
this.domainDefinition = domainDefinition;
|
|
1929
|
+
this._actionRuntimeManager = new ActionRuntimeManager({ domain: domainId });
|
|
1930
|
+
}
|
|
1931
|
+
createChildDomain(subDomainDef) {
|
|
1932
|
+
if (this.allDomains.includes(subDomainDef.domain)) {
|
|
1933
|
+
throw err_nice_action.fromId("domain_already_exists_in_hierarchy" /* domain_already_exists_in_hierarchy */, {
|
|
1934
|
+
domain: subDomainDef.domain,
|
|
1935
|
+
allParentDomains: this.allDomains,
|
|
1936
|
+
parentDomain: this.domain
|
|
1921
1937
|
});
|
|
1922
|
-
connection.definition = transport;
|
|
1923
|
-
this.transportManager.addTransport(connection);
|
|
1924
1938
|
}
|
|
1939
|
+
return new ActionDomain({
|
|
1940
|
+
allDomains: [...this.allDomains, subDomainDef.domain],
|
|
1941
|
+
domain: subDomainDef.domain,
|
|
1942
|
+
actionSchema: subDomainDef.actions
|
|
1943
|
+
}, { rootDomain: this });
|
|
1944
|
+
}
|
|
1945
|
+
_registerRuntime(runtime2) {
|
|
1946
|
+
this._actionRuntimeManager.registerRuntime(runtime2);
|
|
1947
|
+
}
|
|
1948
|
+
_hasRuntime(runtime2) {
|
|
1949
|
+
return this._actionRuntimeManager.hasRuntime(runtime2);
|
|
1950
|
+
}
|
|
1951
|
+
getRuntime(clientSpecifier) {
|
|
1952
|
+
return this._actionRuntimeManager.getBestRuntimeForSpecifier(clientSpecifier);
|
|
1953
|
+
}
|
|
1954
|
+
async _runAction(actionPayload, options) {
|
|
1955
|
+
const allListeners = [...this._listeners, ...options?.listeners ?? []];
|
|
1956
|
+
let handlerAndRuntime;
|
|
1957
|
+
try {
|
|
1958
|
+
handlerAndRuntime = this._actionRuntimeManager.getRuntimeAndHandlerForActionOrThrow(actionPayload, options);
|
|
1959
|
+
} catch (err3) {
|
|
1960
|
+
const runningAction2 = new RunningAction({
|
|
1961
|
+
context: actionPayload.context,
|
|
1962
|
+
request: actionPayload,
|
|
1963
|
+
callSite: actionPayload._callSite
|
|
1964
|
+
});
|
|
1965
|
+
runningAction2.addUpdateListeners(allListeners);
|
|
1966
|
+
runningAction2._failWithError(err3);
|
|
1967
|
+
throw err3;
|
|
1968
|
+
}
|
|
1969
|
+
const { handler, runtime: runtime2 } = handlerAndRuntime;
|
|
1970
|
+
actionPayload.context._setOriginClient(runtime2.coordinate);
|
|
1971
|
+
const runningAction = await handler.handleActionRequest(actionPayload, {
|
|
1972
|
+
targetLocalRuntime: runtime2
|
|
1973
|
+
});
|
|
1974
|
+
runningAction.addUpdateListeners(allListeners);
|
|
1975
|
+
return runningAction;
|
|
1925
1976
|
}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1977
|
+
}
|
|
1978
|
+
// src/ActionDefinition/Domain/helpers/createRootActionDomain.ts
|
|
1979
|
+
var createActionRootDomain = (definition) => {
|
|
1980
|
+
return new ActionRootDomain(definition);
|
|
1981
|
+
};
|
|
1982
|
+
// src/ActionDefinition/Schema/ActionSchema.ts
|
|
1983
|
+
import { extractMessageFromStandardSchema } from "@nice-code/common-errors";
|
|
1984
|
+
class ActionSchema {
|
|
1985
|
+
_errorDeclarations = [];
|
|
1986
|
+
inputOptions;
|
|
1987
|
+
outputOptions;
|
|
1988
|
+
get inputSchema() {
|
|
1989
|
+
return this.inputOptions?.schema;
|
|
1929
1990
|
}
|
|
1930
|
-
|
|
1931
|
-
this.
|
|
1991
|
+
get outputSchema() {
|
|
1992
|
+
return this.outputOptions?.schema;
|
|
1993
|
+
}
|
|
1994
|
+
input(options) {
|
|
1995
|
+
this.inputOptions = options;
|
|
1932
1996
|
return this;
|
|
1933
1997
|
}
|
|
1934
|
-
|
|
1935
|
-
this.
|
|
1998
|
+
output(options) {
|
|
1999
|
+
this.outputOptions = options;
|
|
1936
2000
|
return this;
|
|
1937
2001
|
}
|
|
1938
|
-
|
|
1939
|
-
this.
|
|
2002
|
+
throws(domain, ids) {
|
|
2003
|
+
this._errorDeclarations.push({ _domain: domain, _ids: ids });
|
|
2004
|
+
return this;
|
|
1940
2005
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
const callSite = action._callSite ?? new Error().stack;
|
|
1947
|
-
const routeParams = {
|
|
1948
|
-
action,
|
|
1949
|
-
localClient,
|
|
1950
|
-
externalClient: this.externalClient
|
|
1951
|
-
};
|
|
1952
|
-
const preferredTransport = this.transportManager.getPreferredTransport();
|
|
1953
|
-
const routeItem = preferredTransport != null ? {
|
|
1954
|
-
runtime: localClient,
|
|
1955
|
-
handler: this.toHandlerRouteItem(preferredTransport, routeParams),
|
|
1956
|
-
time: Date.now()
|
|
1957
|
-
} : undefined;
|
|
1958
|
-
if (routeItem != null)
|
|
1959
|
-
action.context.addRouteItem(routeItem);
|
|
1960
|
-
const runningAction = new RunningAction({
|
|
1961
|
-
context: action.context,
|
|
1962
|
-
request: action,
|
|
1963
|
-
parentCuid,
|
|
1964
|
-
callSite
|
|
1965
|
-
});
|
|
1966
|
-
localRuntime.registerRunningAction(runningAction);
|
|
1967
|
-
this._dispatchWhenTransportReady(runningAction, routeParams, routeItem, incomingTimeout);
|
|
1968
|
-
return runningAction;
|
|
2006
|
+
serializeInput(rawInput) {
|
|
2007
|
+
if (this.inputOptions?.serialization) {
|
|
2008
|
+
return this.inputOptions.serialization.serialize(rawInput);
|
|
2009
|
+
}
|
|
2010
|
+
return rawInput;
|
|
1969
2011
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
const { methods, transport } = await this.transportManager.getReadyTransport(routeParams);
|
|
1974
|
-
const handlerRouteItem = this.toHandlerRouteItem(transport, routeParams);
|
|
1975
|
-
if (routeItem != null) {
|
|
1976
|
-
routeItem.handler = handlerRouteItem;
|
|
1977
|
-
routeItem.time = Date.now();
|
|
1978
|
-
} else {
|
|
1979
|
-
action.context.addRouteItem({
|
|
1980
|
-
runtime: routeParams.localClient,
|
|
1981
|
-
handler: handlerRouteItem,
|
|
1982
|
-
time: Date.now()
|
|
1983
|
-
});
|
|
1984
|
-
}
|
|
1985
|
-
const sendInput = {
|
|
1986
|
-
...routeParams,
|
|
1987
|
-
runningAction,
|
|
1988
|
-
timeout: incomingTimeout
|
|
1989
|
-
};
|
|
1990
|
-
if (action.type === "request" /* request */ && methods.updateRunConfig != null) {
|
|
1991
|
-
const runConfig = methods.updateRunConfig(sendInput);
|
|
1992
|
-
sendInput.timeout = runConfig?.timeout ?? incomingTimeout;
|
|
1993
|
-
}
|
|
1994
|
-
methods.sendActionData(sendInput);
|
|
1995
|
-
} catch (err3) {
|
|
1996
|
-
runningAction._abort(err3);
|
|
2012
|
+
deserializeInput(serialized) {
|
|
2013
|
+
if (this.inputOptions?.serialization) {
|
|
2014
|
+
return this.inputOptions.serialization.deserialize(serialized);
|
|
1997
2015
|
}
|
|
2016
|
+
return serialized;
|
|
1998
2017
|
}
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2018
|
+
validateInput(value, meta) {
|
|
2019
|
+
if (this.inputOptions?.schema == null) {
|
|
2020
|
+
return value;
|
|
2021
|
+
}
|
|
2022
|
+
const result = this.inputOptions.schema["~standard"].validate(value);
|
|
2023
|
+
if (result instanceof Promise) {
|
|
2024
|
+
throw err_nice_action.fromId("action_input_validation_promise" /* action_input_validation_promise */, {
|
|
2025
|
+
domain: meta.domain,
|
|
2026
|
+
actionId: meta.actionId
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
if (result.issues != null) {
|
|
2030
|
+
throw err_nice_action.fromId("action_input_validation_failed" /* action_input_validation_failed */, {
|
|
2031
|
+
domain: meta.domain,
|
|
2032
|
+
actionId: meta.actionId,
|
|
2033
|
+
validationMessage: extractMessageFromStandardSchema(result)
|
|
2006
2034
|
});
|
|
2007
|
-
if (methods.sendReturnData == null)
|
|
2008
|
-
return false;
|
|
2009
|
-
methods.sendReturnData(payload, { localClient, externalClient: this.externalClient });
|
|
2010
|
-
return true;
|
|
2011
|
-
} catch {
|
|
2012
|
-
return false;
|
|
2013
2035
|
}
|
|
2036
|
+
return result.value;
|
|
2014
2037
|
}
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2038
|
+
validateOutput(value, meta) {
|
|
2039
|
+
if (this.outputOptions?.schema == null) {
|
|
2040
|
+
return value;
|
|
2041
|
+
}
|
|
2042
|
+
const result = this.outputOptions.schema["~standard"].validate(value);
|
|
2043
|
+
if (result instanceof Promise) {
|
|
2044
|
+
throw err_nice_action.fromId("action_output_validation_promise" /* action_output_validation_promise */, {
|
|
2045
|
+
domain: meta.domain,
|
|
2046
|
+
actionId: meta.actionId
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
if (result.issues != null) {
|
|
2050
|
+
throw err_nice_action.fromId("action_output_validation_failed" /* action_output_validation_failed */, {
|
|
2051
|
+
domain: meta.domain,
|
|
2052
|
+
actionId: meta.actionId,
|
|
2053
|
+
validationMessage: extractMessageFromStandardSchema(result)
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
return result.value;
|
|
2020
2057
|
}
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
transType: transport.type,
|
|
2027
|
-
transInfo: transport.getRouteInfo(input)
|
|
2028
|
-
};
|
|
2058
|
+
serializeOutput(rawOutput) {
|
|
2059
|
+
if (this.outputOptions?.serialization) {
|
|
2060
|
+
return this.outputOptions.serialization.serialize(rawOutput);
|
|
2061
|
+
}
|
|
2062
|
+
return rawOutput;
|
|
2029
2063
|
}
|
|
2030
|
-
|
|
2031
|
-
this.
|
|
2064
|
+
deserializeOutput(serialized) {
|
|
2065
|
+
if (this.outputOptions?.serialization) {
|
|
2066
|
+
return this.outputOptions.serialization.deserialize(serialized);
|
|
2067
|
+
}
|
|
2068
|
+
return serialized;
|
|
2032
2069
|
}
|
|
2033
2070
|
}
|
|
2034
|
-
var
|
|
2035
|
-
return new
|
|
2071
|
+
var actionSchema = () => {
|
|
2072
|
+
return new ActionSchema;
|
|
2036
2073
|
};
|
|
2037
2074
|
// src/ActionRuntime/Handler/ExternalClient/Transport/Transport.ts
|
|
2038
2075
|
class Transport {
|
|
@@ -2956,6 +2993,9 @@ function createBinaryWsSessionFactory(domains, options) {
|
|
|
2956
2993
|
};
|
|
2957
2994
|
};
|
|
2958
2995
|
}
|
|
2996
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/WebSocket/secureWsChannel.ts
|
|
2997
|
+
import { ClientCryptoKeyLink } from "@nice-code/util";
|
|
2998
|
+
|
|
2959
2999
|
// src/utils/decodeActionFrame.ts
|
|
2960
3000
|
function decodeActionFrame(frame, decoder) {
|
|
2961
3001
|
const decoded = decoder?.incoming?.(frame) ?? (typeof frame === "string" ? parseJsonActionFrame(frame) : undefined);
|
|
@@ -3006,8 +3046,8 @@ var HANDSHAKE_TIMEOUT_MS = 15000;
|
|
|
3006
3046
|
|
|
3007
3047
|
class WebSocketConnection extends TransportConnection {
|
|
3008
3048
|
resolvers;
|
|
3009
|
-
_abortSet = new Set;
|
|
3010
3049
|
_liveSocketUrl;
|
|
3050
|
+
_intentionalCloses = new WeakSet;
|
|
3011
3051
|
constructor(def, resolvers) {
|
|
3012
3052
|
super({ ...def, type: "ws" /* ws */ });
|
|
3013
3053
|
this.resolvers = resolvers ?? createUnsetTransportResolvers("ws" /* ws */);
|
|
@@ -3089,20 +3129,22 @@ class WebSocketConnection extends TransportConnection {
|
|
|
3089
3129
|
_finalizeTransportMethods(wsData) {
|
|
3090
3130
|
const ws = wsData.ws;
|
|
3091
3131
|
const disconnectListeners = [];
|
|
3132
|
+
const abortSet = new Set;
|
|
3092
3133
|
this._captureSocketUrl(ws);
|
|
3093
|
-
this._attachLifecycle(ws, disconnectListeners);
|
|
3134
|
+
this._attachLifecycle(ws, disconnectListeners, abortSet);
|
|
3094
3135
|
ws.addEventListener("message", async (event) => {
|
|
3095
3136
|
const frame = await this._normalizeFrame(event.data);
|
|
3096
3137
|
if (frame !== undefined)
|
|
3097
3138
|
await this._handleIncomingActionFrame(frame, wsData, undefined);
|
|
3098
3139
|
});
|
|
3099
|
-
return this._buildSendMethods(ws, wsData, undefined, disconnectListeners);
|
|
3140
|
+
return this._buildSendMethods(ws, wsData, undefined, disconnectListeners, abortSet);
|
|
3100
3141
|
}
|
|
3101
3142
|
async _finalizeSecureMethods(wsData) {
|
|
3102
3143
|
const ws = wsData.ws;
|
|
3103
3144
|
const disconnectListeners = [];
|
|
3145
|
+
const abortSet = new Set;
|
|
3104
3146
|
this._captureSocketUrl(ws);
|
|
3105
|
-
this._attachLifecycle(ws, disconnectListeners);
|
|
3147
|
+
this._attachLifecycle(ws, disconnectListeners, abortSet);
|
|
3106
3148
|
let active = false;
|
|
3107
3149
|
let crypto;
|
|
3108
3150
|
const handshakeQueue = [];
|
|
@@ -3146,7 +3188,7 @@ class WebSocketConnection extends TransportConnection {
|
|
|
3146
3188
|
for (const frame of pendingActionFrames)
|
|
3147
3189
|
await this._handleIncomingActionFrame(frame, wsData, crypto);
|
|
3148
3190
|
pendingActionFrames.length = 0;
|
|
3149
|
-
return this._buildSendMethods(ws, wsData, crypto, disconnectListeners);
|
|
3191
|
+
return this._buildSendMethods(ws, wsData, crypto, disconnectListeners, abortSet);
|
|
3150
3192
|
}
|
|
3151
3193
|
async _runClientHandshake(ws, secure, nextHandshakeMessage) {
|
|
3152
3194
|
await secure.link.initialize();
|
|
@@ -3175,20 +3217,31 @@ class WebSocketConnection extends TransportConnection {
|
|
|
3175
3217
|
const result = await handshake.onAccept(accept);
|
|
3176
3218
|
return result.securityLevel === "encrypted" /* encrypted */ ? createActionFrameCrypto({ link: secure.link, linkedClientId: result.linkedClientId }) : undefined;
|
|
3177
3219
|
}
|
|
3178
|
-
_buildSendMethods(ws, wsData, crypto, disconnectListeners) {
|
|
3220
|
+
_buildSendMethods(ws, wsData, crypto, disconnectListeners, abortSet) {
|
|
3179
3221
|
let sendChain = Promise.resolve();
|
|
3180
3222
|
const enqueueSend = (frame) => {
|
|
3223
|
+
if (ws.readyState !== WebSocket.OPEN)
|
|
3224
|
+
return;
|
|
3181
3225
|
if (crypto == null) {
|
|
3182
3226
|
sendFrame(ws, frame);
|
|
3183
3227
|
return;
|
|
3184
3228
|
}
|
|
3185
3229
|
const bytes = toFrameBytes(frame);
|
|
3186
|
-
sendChain = sendChain.then(() => crypto.encryptFrame(bytes)).then((encrypted) =>
|
|
3230
|
+
sendChain = sendChain.then(() => crypto.encryptFrame(bytes)).then((encrypted) => {
|
|
3231
|
+
if (ws.readyState === WebSocket.OPEN)
|
|
3232
|
+
sendFrame(ws, encrypted);
|
|
3233
|
+
}).catch((err4) => console.error("[ws] failed to encrypt/send frame", err4));
|
|
3187
3234
|
};
|
|
3188
3235
|
const sendActionData = (inputs) => {
|
|
3189
3236
|
const { action, runningAction, timeout } = inputs;
|
|
3237
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
3238
|
+
if (action.type === "request" /* request */) {
|
|
3239
|
+
runningAction._abort(err_nice_transport_ws.fromId("ws_disconnected" /* ws_disconnected */));
|
|
3240
|
+
}
|
|
3241
|
+
return;
|
|
3242
|
+
}
|
|
3190
3243
|
if (action.type === "request" /* request */) {
|
|
3191
|
-
|
|
3244
|
+
abortSet.add(runningAction);
|
|
3192
3245
|
const timeoutId = setTimeout(() => {
|
|
3193
3246
|
runningAction._abort(err_nice_transport.fromId("timeout" /* timeout */, { timeout }));
|
|
3194
3247
|
}, timeout);
|
|
@@ -3196,7 +3249,7 @@ class WebSocketConnection extends TransportConnection {
|
|
|
3196
3249
|
(update) => {
|
|
3197
3250
|
if (update.type === "finished" /* finished */) {
|
|
3198
3251
|
clearTimeout(timeoutId);
|
|
3199
|
-
|
|
3252
|
+
abortSet.delete(runningAction);
|
|
3200
3253
|
}
|
|
3201
3254
|
}
|
|
3202
3255
|
]);
|
|
@@ -3209,6 +3262,12 @@ class WebSocketConnection extends TransportConnection {
|
|
|
3209
3262
|
addOnDisconnectListener: (cb) => {
|
|
3210
3263
|
disconnectListeners.push(cb);
|
|
3211
3264
|
},
|
|
3265
|
+
disconnect: () => {
|
|
3266
|
+
this._intentionalCloses.add(ws);
|
|
3267
|
+
try {
|
|
3268
|
+
ws.close();
|
|
3269
|
+
} catch {}
|
|
3270
|
+
},
|
|
3212
3271
|
sendReturnData: (payload, clients) => {
|
|
3213
3272
|
const formatted = clients != null ? wsData.formatMessage?.outgoing({ action: payload, ...clients }) : undefined;
|
|
3214
3273
|
enqueueSend(formatted ?? JSON.stringify(payload.toJsonObject()));
|
|
@@ -3243,24 +3302,25 @@ class WebSocketConnection extends TransportConnection {
|
|
|
3243
3302
|
if (ws.url != null && ws.url !== "")
|
|
3244
3303
|
this._liveSocketUrl = ws.url;
|
|
3245
3304
|
}
|
|
3246
|
-
_attachLifecycle(ws, disconnectListeners) {
|
|
3305
|
+
_attachLifecycle(ws, disconnectListeners, abortSet) {
|
|
3247
3306
|
ws.addEventListener("close", (event) => {
|
|
3248
|
-
|
|
3307
|
+
if (!this._intentionalCloses.has(ws))
|
|
3308
|
+
console.error("WebSocket closed:", event);
|
|
3249
3309
|
for (const cb of disconnectListeners)
|
|
3250
3310
|
cb();
|
|
3251
|
-
this._abortAll(err_nice_transport_ws.fromId("ws_disconnected" /* ws_disconnected */));
|
|
3311
|
+
this._abortAll(abortSet, err_nice_transport_ws.fromId("ws_disconnected" /* ws_disconnected */));
|
|
3252
3312
|
});
|
|
3253
3313
|
ws.addEventListener("error", (event) => {
|
|
3254
3314
|
console.error("WebSocket error:", event);
|
|
3255
3315
|
for (const cb of disconnectListeners)
|
|
3256
3316
|
cb();
|
|
3257
|
-
this._abortAll(err_nice_transport_ws.fromId("ws_error" /* ws_error */, {
|
|
3317
|
+
this._abortAll(abortSet, err_nice_transport_ws.fromId("ws_error" /* ws_error */, {
|
|
3258
3318
|
originalError: event instanceof Error ? event : undefined
|
|
3259
3319
|
}));
|
|
3260
3320
|
});
|
|
3261
3321
|
}
|
|
3262
|
-
_abortAll(error) {
|
|
3263
|
-
const snapshot = [...
|
|
3322
|
+
_abortAll(abortSet, error) {
|
|
3323
|
+
const snapshot = [...abortSet];
|
|
3264
3324
|
for (const ra of snapshot) {
|
|
3265
3325
|
ra._abort(error);
|
|
3266
3326
|
}
|
|
@@ -3313,11 +3373,109 @@ class WebSocketTransport extends Transport {
|
|
|
3313
3373
|
};
|
|
3314
3374
|
}
|
|
3315
3375
|
}
|
|
3376
|
+
|
|
3377
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/WebSocket/secureWsChannel.ts
|
|
3378
|
+
function deriveDictionaryVersion(domains) {
|
|
3379
|
+
const { intToRoute } = buildActionRouteDictionary(domains);
|
|
3380
|
+
const signature = intToRoute.map((route) => `${route.domain}:${route.id}`).join(",");
|
|
3381
|
+
let hash = 2166136261;
|
|
3382
|
+
for (let i = 0;i < signature.length; i++) {
|
|
3383
|
+
hash ^= signature.charCodeAt(i);
|
|
3384
|
+
hash = Math.imul(hash, 16777619);
|
|
3385
|
+
}
|
|
3386
|
+
return `auto:${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
3387
|
+
}
|
|
3388
|
+
function defineSecureWsChannel(options) {
|
|
3389
|
+
return {
|
|
3390
|
+
dictionaryVersion: options.dictionaryVersion ?? deriveDictionaryVersion(options.domains),
|
|
3391
|
+
createCodec: createBinaryWsSessionFactory(options.domains, options.sessionOptions)
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
3394
|
+
function createSecureWebSocketTransport(options) {
|
|
3395
|
+
const link = new ClientCryptoKeyLink({ storageAdapter: options.storageAdapter });
|
|
3396
|
+
return WebSocketTransport.create({
|
|
3397
|
+
createWebSocket: options.createWebSocket ?? (() => {
|
|
3398
|
+
const ws = new WebSocket(options.url);
|
|
3399
|
+
ws.binaryType = "arraybuffer";
|
|
3400
|
+
return ws;
|
|
3401
|
+
}),
|
|
3402
|
+
getTransportCacheKey: options.getTransportCacheKey ?? (() => [options.url]),
|
|
3403
|
+
createFormatMessage: options.channel.createCodec,
|
|
3404
|
+
updateRunConfig: options.updateRunConfig,
|
|
3405
|
+
getRouteInfo: options.getRouteInfo,
|
|
3406
|
+
security: {
|
|
3407
|
+
securityLevel: options.securityLevel,
|
|
3408
|
+
link,
|
|
3409
|
+
localCoordinate: options.runtime.coordinate.toJsonObject(),
|
|
3410
|
+
dictionaryVersion: options.channel.dictionaryVersion
|
|
3411
|
+
}
|
|
3412
|
+
});
|
|
3413
|
+
}
|
|
3414
|
+
// src/ActionRuntime/Handler/Server/WsConnectionStateStore.ts
|
|
3415
|
+
class WsConnectionStateStore {
|
|
3416
|
+
options;
|
|
3417
|
+
constructor(options) {
|
|
3418
|
+
this.options = options;
|
|
3419
|
+
}
|
|
3420
|
+
get(connection) {
|
|
3421
|
+
return this._readAttachment(connection).app ?? null;
|
|
3422
|
+
}
|
|
3423
|
+
set(connection, app) {
|
|
3424
|
+
const existing = this._readAttachment(connection);
|
|
3425
|
+
this.options.write(connection, { app, binding: existing.binding });
|
|
3426
|
+
}
|
|
3427
|
+
clearApp(connection) {
|
|
3428
|
+
const existing = this._readAttachment(connection);
|
|
3429
|
+
this.options.write(connection, { binding: existing.binding });
|
|
3430
|
+
}
|
|
3431
|
+
entries() {
|
|
3432
|
+
return this.options.getConnections().map((connection) => [connection, this._readAttachment(connection).app ?? null]);
|
|
3433
|
+
}
|
|
3434
|
+
_persistBinding(connection, binding) {
|
|
3435
|
+
const existing = this._readAttachment(connection);
|
|
3436
|
+
this.options.write(connection, { app: existing.app, binding });
|
|
3437
|
+
}
|
|
3438
|
+
_readBinding(connection) {
|
|
3439
|
+
return this._readAttachment(connection).binding;
|
|
3440
|
+
}
|
|
3441
|
+
_readAttachment(connection) {
|
|
3442
|
+
try {
|
|
3443
|
+
const raw = this.options.read(connection);
|
|
3444
|
+
if (typeof raw !== "object" || raw === null)
|
|
3445
|
+
return {};
|
|
3446
|
+
const attachment = raw;
|
|
3447
|
+
const result = {};
|
|
3448
|
+
if (attachment.binding != null)
|
|
3449
|
+
result.binding = attachment.binding;
|
|
3450
|
+
if (attachment.app !== undefined) {
|
|
3451
|
+
const app = this._validateApp(attachment.app);
|
|
3452
|
+
if (app !== undefined)
|
|
3453
|
+
result.app = app;
|
|
3454
|
+
}
|
|
3455
|
+
return result;
|
|
3456
|
+
} catch {
|
|
3457
|
+
return {};
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3460
|
+
_validateApp(value) {
|
|
3461
|
+
const schema = this.options.schema;
|
|
3462
|
+
if (schema == null)
|
|
3463
|
+
return value;
|
|
3464
|
+
const result = schema["~standard"].validate(value);
|
|
3465
|
+
if (result instanceof Promise)
|
|
3466
|
+
return;
|
|
3467
|
+
if (result.issues != null)
|
|
3468
|
+
return;
|
|
3469
|
+
return result.value;
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3316
3473
|
// src/ActionRuntime/Handler/Server/ActionServerHandler.ts
|
|
3317
3474
|
class ActionServerHandler extends ActionExternalClientHandler {
|
|
3318
3475
|
_formatMessage;
|
|
3319
3476
|
_createFormatMessage;
|
|
3320
3477
|
_send;
|
|
3478
|
+
_runtime;
|
|
3321
3479
|
_serverTimeout;
|
|
3322
3480
|
_onConnectionBound;
|
|
3323
3481
|
_incomingListeners = [];
|
|
@@ -3340,6 +3498,7 @@ class ActionServerHandler extends ActionExternalClientHandler {
|
|
|
3340
3498
|
this._formatMessage = options.formatMessage;
|
|
3341
3499
|
this._createFormatMessage = options.createFormatMessage;
|
|
3342
3500
|
this._send = options.send;
|
|
3501
|
+
this._runtime = options.runtime;
|
|
3343
3502
|
this._serverTimeout = options.defaultTimeout ?? DEFAULT_TRANSPORT_TIMEOUT;
|
|
3344
3503
|
this._onConnectionBound = options.onConnectionBound;
|
|
3345
3504
|
this._security = options.security;
|
|
@@ -3365,6 +3524,19 @@ class ActionServerHandler extends ActionExternalClientHandler {
|
|
|
3365
3524
|
_setIncomingActionDataListener(listener) {
|
|
3366
3525
|
this._incomingListeners.push(listener);
|
|
3367
3526
|
}
|
|
3527
|
+
setOnConnectionBound(onConnectionBound) {
|
|
3528
|
+
this._onConnectionBound = onConnectionBound;
|
|
3529
|
+
}
|
|
3530
|
+
createConnectionState(options) {
|
|
3531
|
+
const store = new WsConnectionStateStore(options);
|
|
3532
|
+
this.setOnConnectionBound((connection, binding) => store._persistBinding(connection, binding));
|
|
3533
|
+
for (const connection of options.getConnections()) {
|
|
3534
|
+
const binding = store._readBinding(connection);
|
|
3535
|
+
if (binding != null)
|
|
3536
|
+
this.rehydrateConnection(connection, binding);
|
|
3537
|
+
}
|
|
3538
|
+
return store;
|
|
3539
|
+
}
|
|
3368
3540
|
receive(connection, frame) {
|
|
3369
3541
|
if (this._security == null || !this._handshakeMode) {
|
|
3370
3542
|
this._receivePlain(connection, frame);
|
|
@@ -3539,6 +3711,41 @@ class ActionServerHandler extends ActionExternalClientHandler {
|
|
|
3539
3711
|
const connection = this._resolveConnection(target);
|
|
3540
3712
|
return this._dispatch(runtime2, connection, request, options?.timeout);
|
|
3541
3713
|
}
|
|
3714
|
+
forConnectionDomainCases(domain, cases) {
|
|
3715
|
+
const handler = new ActionLocalHandler;
|
|
3716
|
+
const executor = cases;
|
|
3717
|
+
const wrapped = {};
|
|
3718
|
+
const wrappedRecord = wrapped;
|
|
3719
|
+
for (const id in cases) {
|
|
3720
|
+
const caseFn = executor[id];
|
|
3721
|
+
if (caseFn == null)
|
|
3722
|
+
continue;
|
|
3723
|
+
wrappedRecord[id] = (request) => caseFn(request, this.getConnectionForClient(request.context.originClient));
|
|
3724
|
+
}
|
|
3725
|
+
return handler.forDomainActionCases(domain, wrapped);
|
|
3726
|
+
}
|
|
3727
|
+
broadcast(makeRequest, options) {
|
|
3728
|
+
const runtime2 = options?.runtime ?? this._runtime;
|
|
3729
|
+
if (runtime2 == null) {
|
|
3730
|
+
throw err_nice_transport.fromId("not_found" /* not_found */, {
|
|
3731
|
+
actionId: "server-handler-runtime (construct with `runtime` or pass `options.runtime`)"
|
|
3732
|
+
});
|
|
3733
|
+
}
|
|
3734
|
+
for (const connection of this._clientByConn.keys()) {
|
|
3735
|
+
if (options?.except != null && connection === options.except)
|
|
3736
|
+
continue;
|
|
3737
|
+
if (options?.where != null && !options.where(connection))
|
|
3738
|
+
continue;
|
|
3739
|
+
try {
|
|
3740
|
+
this.pushToClient(runtime2, connection, makeRequest(), { timeout: options?.timeout });
|
|
3741
|
+
} catch (error) {
|
|
3742
|
+
if (options?.onError != null)
|
|
3743
|
+
options.onError(error, connection);
|
|
3744
|
+
else
|
|
3745
|
+
console.error("[ws-server] broadcast push failed", error);
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3542
3749
|
async sendReturnPayload(payload, config) {
|
|
3543
3750
|
const connection = this._connByClient.get(payload.context.originClient.stringId);
|
|
3544
3751
|
if (connection == null)
|
|
@@ -3627,6 +3834,78 @@ class ActionServerHandler extends ActionExternalClientHandler {
|
|
|
3627
3834
|
var createServerHandler = (options) => {
|
|
3628
3835
|
return new ActionServerHandler(options);
|
|
3629
3836
|
};
|
|
3837
|
+
// src/ActionRuntime/Handler/Server/createActionFetchHandler.ts
|
|
3838
|
+
var DEFAULT_CORS_HEADERS = {
|
|
3839
|
+
"Access-Control-Allow-Origin": "*",
|
|
3840
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
3841
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
3842
|
+
"Access-Control-Max-Age": "86400"
|
|
3843
|
+
};
|
|
3844
|
+
function createActionFetchHandler(runtime2, options = {}) {
|
|
3845
|
+
const corsHeaders = options.cors === false ? {} : options.cors ?? DEFAULT_CORS_HEADERS;
|
|
3846
|
+
const isActionPath = options.isActionPath ?? ((url) => url.pathname.endsWith("/action"));
|
|
3847
|
+
const isWebSocketPath = options.isWebSocketPath ?? ((url) => url.pathname.endsWith("/ws"));
|
|
3848
|
+
const withCors = (response) => {
|
|
3849
|
+
if (options.cors === false)
|
|
3850
|
+
return response;
|
|
3851
|
+
const headers = new Headers(response.headers);
|
|
3852
|
+
for (const [key, value] of Object.entries(corsHeaders))
|
|
3853
|
+
headers.set(key, value);
|
|
3854
|
+
return new Response(response.body, { status: response.status, headers });
|
|
3855
|
+
};
|
|
3856
|
+
return async (request) => {
|
|
3857
|
+
if (request.method === "OPTIONS") {
|
|
3858
|
+
return withCors(new Response(null, { status: 204 }));
|
|
3859
|
+
}
|
|
3860
|
+
const url = new URL(request.url);
|
|
3861
|
+
if (options.onWebSocketUpgrade != null && request.headers.get("Upgrade") === "websocket" && isWebSocketPath(url)) {
|
|
3862
|
+
return options.onWebSocketUpgrade(request, url);
|
|
3863
|
+
}
|
|
3864
|
+
if (request.method === "POST" && isActionPath(url)) {
|
|
3865
|
+
const running = await runtime2.handleActionPayloadWire(await request.json());
|
|
3866
|
+
const result = await running.waitForResultPayload();
|
|
3867
|
+
return withCors(result.toHttpResponse({ useErrorStatus: options.useErrorStatus }));
|
|
3868
|
+
}
|
|
3869
|
+
return withCors(new Response("Not found", { status: 404 }));
|
|
3870
|
+
};
|
|
3871
|
+
}
|
|
3872
|
+
// src/ActionRuntime/Handler/Server/createSecureActionServer.ts
|
|
3873
|
+
import { ClientCryptoKeyLink as ClientCryptoKeyLink2 } from "@nice-code/util";
|
|
3874
|
+
var DEFAULT_SERVER_SECURITY_LEVELS = [
|
|
3875
|
+
"none" /* none */,
|
|
3876
|
+
"authenticated" /* authenticated */,
|
|
3877
|
+
"encrypted" /* encrypted */
|
|
3878
|
+
];
|
|
3879
|
+
function createSecureActionServerHandler(options) {
|
|
3880
|
+
const link = new ClientCryptoKeyLink2({ storageAdapter: options.storageAdapter });
|
|
3881
|
+
return new ActionServerHandler({
|
|
3882
|
+
clientEnv: options.clientEnv,
|
|
3883
|
+
createFormatMessage: options.channel.createCodec,
|
|
3884
|
+
send: options.send,
|
|
3885
|
+
runtime: options.runtime,
|
|
3886
|
+
defaultTimeout: options.defaultTimeout,
|
|
3887
|
+
security: {
|
|
3888
|
+
securityLevel: options.securityLevel ?? DEFAULT_SERVER_SECURITY_LEVELS,
|
|
3889
|
+
link,
|
|
3890
|
+
localCoordinate: options.runtime.coordinate.toJsonObject(),
|
|
3891
|
+
dictionaryVersion: options.channel.dictionaryVersion,
|
|
3892
|
+
verifyKeyResolver: options.verifyKeyResolver ?? createStorageTofuVerifyKeyResolver(options.storageAdapter)
|
|
3893
|
+
}
|
|
3894
|
+
});
|
|
3895
|
+
}
|
|
3896
|
+
function createHibernatableWsServerAdapter(options) {
|
|
3897
|
+
const { handler, getWebSockets, getAttachment, setAttachment } = options;
|
|
3898
|
+
handler.setOnConnectionBound(setAttachment);
|
|
3899
|
+
for (const connection of getWebSockets()) {
|
|
3900
|
+
const binding = getAttachment(connection);
|
|
3901
|
+
if (binding != null)
|
|
3902
|
+
handler.rehydrateConnection(connection, binding);
|
|
3903
|
+
}
|
|
3904
|
+
return {
|
|
3905
|
+
receive: (connection, frame) => handler.receive(connection, frame),
|
|
3906
|
+
drop: (connection) => handler.dropConnection(connection)
|
|
3907
|
+
};
|
|
3908
|
+
}
|
|
3630
3909
|
export {
|
|
3631
3910
|
runtimeLinkId,
|
|
3632
3911
|
isActionPayload_Result_JsonObject,
|
|
@@ -3637,20 +3916,26 @@ export {
|
|
|
3637
3916
|
err_nice_external_client,
|
|
3638
3917
|
err_nice_action,
|
|
3639
3918
|
encodeHandshakeMessage,
|
|
3919
|
+
defineSecureWsChannel,
|
|
3640
3920
|
decodeHandshakeMessage,
|
|
3641
3921
|
decodeActionFrame,
|
|
3642
3922
|
createStorageTofuVerifyKeyResolver,
|
|
3643
3923
|
createServerHandshake,
|
|
3644
3924
|
createServerHandler,
|
|
3925
|
+
createSecureWebSocketTransport,
|
|
3926
|
+
createSecureActionServerHandler,
|
|
3645
3927
|
createLocalHandler,
|
|
3646
3928
|
createInMemoryTofuVerifyKeyResolver,
|
|
3929
|
+
createHibernatableWsServerAdapter,
|
|
3647
3930
|
createExternalClientHandler,
|
|
3648
3931
|
createClientHandshake,
|
|
3649
3932
|
createBinaryWsSessionFactory,
|
|
3650
3933
|
createBinaryWsAdapter,
|
|
3651
3934
|
createActionRootDomain,
|
|
3652
3935
|
createActionFrameCrypto,
|
|
3936
|
+
createActionFetchHandler,
|
|
3653
3937
|
actionSchema,
|
|
3938
|
+
WsConnectionStateStore,
|
|
3654
3939
|
WebSocketTransport,
|
|
3655
3940
|
Transport,
|
|
3656
3941
|
RuntimeCoordinate,
|