@nice-code/action 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +273 -1
- package/build/index.js +2258 -43
- package/build/react-query/index.js +43 -3
- package/package.json +3 -3
package/build/index.js
CHANGED
|
@@ -1,60 +1,2275 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
1
|
+
// src/ActionDefinition/Action/Core/ActionCore.ts
|
|
2
|
+
import { nanoid } from "nanoid";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
4
|
+
// src/nice_action.static.ts
|
|
5
|
+
var DEFAULT_TRANSPORT_TIMEOUT = 1e4;
|
|
6
|
+
var UNSET_RUNTIME_ENV_ID = "_unset_";
|
|
7
|
+
|
|
8
|
+
// src/ActionRuntime/utils/runtimeCoordinateToStringIds.ts
|
|
9
|
+
function runtimeCoordinateToStringIds(coordinate) {
|
|
10
|
+
return [
|
|
11
|
+
`envId[${coordinate.envId}]perId[${coordinate.perId ?? "_"}]:insId[${coordinate.insId ?? "_"}]`,
|
|
12
|
+
`envId[${coordinate.envId}]perId[${coordinate.perId ?? "_"}]:insId[_]`,
|
|
13
|
+
`envId[${coordinate.envId}]perId[_]:insId[_]`
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/ActionRuntime/RuntimeCoordinate.ts
|
|
18
|
+
class RuntimeCoordinate {
|
|
19
|
+
envId;
|
|
20
|
+
perId;
|
|
21
|
+
insId;
|
|
22
|
+
static get unknown() {
|
|
23
|
+
return new RuntimeCoordinate({
|
|
24
|
+
envId: UNSET_RUNTIME_ENV_ID
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
static env(envId) {
|
|
28
|
+
return new RuntimeCoordinate({
|
|
29
|
+
envId
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
withPersistentId(perId) {
|
|
33
|
+
return this.specify({ perId });
|
|
34
|
+
}
|
|
35
|
+
constructor({ envId, perId, insId }) {
|
|
36
|
+
this.envId = envId;
|
|
37
|
+
this.perId = perId;
|
|
38
|
+
this.insId = insId;
|
|
39
|
+
}
|
|
40
|
+
specify(newInputs) {
|
|
41
|
+
return new RuntimeCoordinate({
|
|
42
|
+
envId: this.envId,
|
|
43
|
+
perId: this.perId,
|
|
44
|
+
insId: this.insId,
|
|
45
|
+
...newInputs
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
specifyIfUnset(newInputs) {
|
|
49
|
+
return new RuntimeCoordinate({
|
|
50
|
+
envId: this.envId,
|
|
51
|
+
perId: this.perId ?? newInputs.perId,
|
|
52
|
+
insId: this.insId ?? newInputs.insId
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
toJsonObject() {
|
|
56
|
+
return {
|
|
57
|
+
envId: this.envId,
|
|
58
|
+
perId: this.perId,
|
|
59
|
+
insId: this.insId
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
isExactlySame(other) {
|
|
63
|
+
return this.envId === other.envId && this.perId === other.perId && this.insId === other.insId;
|
|
64
|
+
}
|
|
65
|
+
isSameFor(other) {
|
|
66
|
+
return {
|
|
67
|
+
id: this.envId === other.envId,
|
|
68
|
+
perId: this.envId === other.envId && this.perId === other.perId,
|
|
69
|
+
insId: this.envId === other.envId && this.perId === other.perId && this.insId === other.insId
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
similarityLevel(other) {
|
|
73
|
+
const sameFor = this.isSameFor(other);
|
|
74
|
+
if (sameFor.insId)
|
|
75
|
+
return 3;
|
|
76
|
+
if (sameFor.perId)
|
|
77
|
+
return 2;
|
|
78
|
+
if (sameFor.id)
|
|
79
|
+
return 1;
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
get stringId() {
|
|
83
|
+
return `envId[${this.envId}]perId[${this.perId ?? "_"}]:insId[${this.insId ?? "_"}]`;
|
|
84
|
+
}
|
|
85
|
+
toStringIds() {
|
|
86
|
+
return runtimeCoordinateToStringIds(this);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/ActionDefinition/Action/ActionBase.ts
|
|
91
|
+
class ActionBase {
|
|
92
|
+
form;
|
|
93
|
+
_domain;
|
|
94
|
+
id;
|
|
95
|
+
domain;
|
|
96
|
+
allDomains;
|
|
97
|
+
schema;
|
|
98
|
+
constructor(form, _domain, id) {
|
|
99
|
+
this.form = form;
|
|
100
|
+
this._domain = _domain;
|
|
101
|
+
this.id = id;
|
|
102
|
+
this.domain = _domain.domain;
|
|
103
|
+
this.allDomains = _domain.allDomains;
|
|
104
|
+
this.schema = _domain.actionSchema[id];
|
|
105
|
+
}
|
|
106
|
+
toJsonObject() {
|
|
107
|
+
return {
|
|
108
|
+
form: this.form,
|
|
109
|
+
domain: this.domain,
|
|
110
|
+
allDomains: this.allDomains,
|
|
111
|
+
id: this.id
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
toJsonString() {
|
|
115
|
+
return JSON.stringify(this.toJsonObject());
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/ActionDefinition/Action/Context/ActionContext.ts
|
|
120
|
+
class ActionContext extends ActionBase {
|
|
121
|
+
_domain;
|
|
122
|
+
form = "context" /* context */;
|
|
123
|
+
_routing;
|
|
124
|
+
timeCreated;
|
|
125
|
+
cuid;
|
|
126
|
+
originClient;
|
|
127
|
+
constructor(_domain, id, hydrationData) {
|
|
128
|
+
super("context" /* context */, _domain, id);
|
|
129
|
+
this._domain = _domain;
|
|
130
|
+
this.timeCreated = hydrationData.timeCreated;
|
|
131
|
+
this.cuid = hydrationData.cuid;
|
|
132
|
+
this._routing = hydrationData.routing;
|
|
133
|
+
this.originClient = hydrationData.originClient;
|
|
134
|
+
}
|
|
135
|
+
_setOriginClient(client) {
|
|
136
|
+
this.originClient = client;
|
|
137
|
+
}
|
|
138
|
+
toJsonString() {
|
|
139
|
+
return JSON.stringify(this.toJsonObject());
|
|
140
|
+
}
|
|
141
|
+
toContextDataJsonObject() {
|
|
142
|
+
return {
|
|
143
|
+
timeCreated: this.timeCreated,
|
|
144
|
+
cuid: this.cuid,
|
|
145
|
+
routing: this.routing.map((item) => ({
|
|
146
|
+
runtime: item.runtime.toJsonObject(),
|
|
147
|
+
handler: item.handler,
|
|
148
|
+
time: item.time
|
|
149
|
+
})),
|
|
150
|
+
originClient: this.originClient.toJsonObject()
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
toJsonObject() {
|
|
154
|
+
return {
|
|
155
|
+
...super.toJsonObject(),
|
|
156
|
+
...this.toContextDataJsonObject()
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
get routing() {
|
|
160
|
+
return this._routing;
|
|
161
|
+
}
|
|
162
|
+
addRouteItem(item) {
|
|
163
|
+
this._routing.push(item);
|
|
164
|
+
}
|
|
165
|
+
deserializeInput(serialized) {
|
|
166
|
+
return this.schema.deserializeInput(serialized);
|
|
167
|
+
}
|
|
168
|
+
serializeInput(raw) {
|
|
169
|
+
return this.schema.serializeInput(raw);
|
|
170
|
+
}
|
|
171
|
+
validateInput(input) {
|
|
172
|
+
return this.schema.validateInput(input, {
|
|
173
|
+
domain: this.domain,
|
|
174
|
+
actionId: this.id
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
validateOutput(output) {
|
|
178
|
+
return this.schema.validateOutput(output, {
|
|
179
|
+
domain: this.domain,
|
|
180
|
+
actionId: this.id
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/ActionDefinition/Action/Payload/ActionPayload.ts
|
|
186
|
+
class ActionPayload extends ActionBase {
|
|
187
|
+
form = "data" /* data */;
|
|
188
|
+
type;
|
|
189
|
+
context;
|
|
190
|
+
time;
|
|
191
|
+
constructor(context, type, data) {
|
|
192
|
+
super("data" /* data */, context._domain, context.id);
|
|
193
|
+
this.context = context;
|
|
194
|
+
this.type = type;
|
|
195
|
+
this.time = data.time;
|
|
196
|
+
}
|
|
197
|
+
toBaseJsonObject() {
|
|
198
|
+
return {
|
|
199
|
+
...super.toJsonObject(),
|
|
200
|
+
type: this.type,
|
|
201
|
+
context: this.context.toContextDataJsonObject(),
|
|
202
|
+
time: this.time
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/ActionDefinition/Action/Payload/ActionPayload.types.ts
|
|
208
|
+
var EActionPayloadType;
|
|
209
|
+
((EActionPayloadType2) => {
|
|
210
|
+
EActionPayloadType2["request"] = "request";
|
|
211
|
+
EActionPayloadType2["progress"] = "progress";
|
|
212
|
+
EActionPayloadType2["result"] = "result";
|
|
213
|
+
EActionPayloadType2["stream"] = "stream";
|
|
214
|
+
EActionPayloadType2["push"] = "push";
|
|
215
|
+
})(EActionPayloadType ||= {});
|
|
216
|
+
var EActionProgressType;
|
|
217
|
+
((EActionProgressType2) => {
|
|
218
|
+
EActionProgressType2["none"] = "none";
|
|
219
|
+
EActionProgressType2["percentage"] = "percentage";
|
|
220
|
+
EActionProgressType2["custom"] = "custom";
|
|
221
|
+
})(EActionProgressType ||= {});
|
|
222
|
+
|
|
223
|
+
// src/ActionDefinition/Action/Payload/ActionPayload_Progress.ts
|
|
224
|
+
class ActionPayload_Progress extends ActionPayload {
|
|
225
|
+
progress;
|
|
226
|
+
constructor(params, progress, data) {
|
|
227
|
+
super(params.context, "progress" /* progress */, data);
|
|
228
|
+
this.progress = progress;
|
|
229
|
+
}
|
|
230
|
+
toJsonObject() {
|
|
231
|
+
return {
|
|
232
|
+
...this.toBaseJsonObject(),
|
|
233
|
+
progress: this.progress
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
toJsonString() {
|
|
237
|
+
return JSON.stringify(this.toJsonObject());
|
|
238
|
+
}
|
|
239
|
+
toHttpResponse() {
|
|
240
|
+
return new Response(this.toJsonString(), {
|
|
241
|
+
status: 200,
|
|
242
|
+
headers: { "Content-Type": "application/json" }
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/ActionDefinition/Action/Payload/ActionPayload_Result.ts
|
|
248
|
+
class ActionPayload_Result extends ActionPayload {
|
|
249
|
+
result;
|
|
250
|
+
constructor(params, result, data) {
|
|
251
|
+
super(params.context, "result" /* result */, data);
|
|
252
|
+
this.result = result;
|
|
253
|
+
}
|
|
254
|
+
toJsonObject() {
|
|
255
|
+
return {
|
|
256
|
+
...this.toBaseJsonObject(),
|
|
257
|
+
result: this.result
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
toJsonString() {
|
|
261
|
+
return JSON.stringify(this.toJsonObject());
|
|
262
|
+
}
|
|
263
|
+
toHttpResponse({ useErrorStatus = true } = {}) {
|
|
264
|
+
return new Response(this.toJsonString(), {
|
|
265
|
+
status: this.result.ok ? 200 : useErrorStatus ? this.result.error.httpStatusCode : 500,
|
|
266
|
+
headers: { "Content-Type": "application/json" }
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/ActionDefinition/Action/Payload/ActionPayload_Request.ts
|
|
272
|
+
class ActionPayload_Request extends ActionPayload {
|
|
273
|
+
input;
|
|
274
|
+
constructor(params, input, data) {
|
|
275
|
+
super(params.context, "request" /* request */, data);
|
|
276
|
+
this.input = input;
|
|
277
|
+
}
|
|
278
|
+
successResult(...args) {
|
|
279
|
+
const output = args[0];
|
|
280
|
+
const finalOutput = this.context.schema.validateOutput(output, {
|
|
281
|
+
domain: this.domain,
|
|
282
|
+
actionId: this.id
|
|
283
|
+
});
|
|
284
|
+
return new ActionPayload_Result(this, { ok: true, output: finalOutput }, { time: Date.now() });
|
|
285
|
+
}
|
|
286
|
+
errorResult(err) {
|
|
287
|
+
return new ActionPayload_Result(this, { ok: false, error: err }, { time: Date.now() });
|
|
288
|
+
}
|
|
289
|
+
progress(progress) {
|
|
290
|
+
return new ActionPayload_Progress(this, progress, { time: Date.now() });
|
|
291
|
+
}
|
|
292
|
+
toJsonObject() {
|
|
293
|
+
return {
|
|
294
|
+
...super.toBaseJsonObject(),
|
|
295
|
+
input: this.context.schema.serializeInput(this.input)
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
toJsonString() {
|
|
299
|
+
return JSON.stringify(this.toJsonObject());
|
|
300
|
+
}
|
|
301
|
+
async runToOutput(options) {
|
|
302
|
+
const running = await this.run(options);
|
|
303
|
+
const result = await running.waitForResultPayload();
|
|
304
|
+
if (result.result.ok)
|
|
305
|
+
return result.result.output;
|
|
306
|
+
throw result.result.error;
|
|
307
|
+
}
|
|
308
|
+
async runToResultPayload(options) {
|
|
309
|
+
const value = await this.run(options);
|
|
310
|
+
return value.waitForResultPayload();
|
|
311
|
+
}
|
|
312
|
+
async run(options) {
|
|
313
|
+
return this._domain.runAction(this, options);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/ActionDefinition/Action/Core/ActionCore.ts
|
|
318
|
+
class ActionCore extends ActionBase {
|
|
319
|
+
_domain;
|
|
320
|
+
form = "core" /* core */;
|
|
321
|
+
constructor(_domain, id) {
|
|
322
|
+
super("core" /* core */, _domain, id);
|
|
323
|
+
this._domain = _domain;
|
|
324
|
+
}
|
|
325
|
+
is(action) {
|
|
326
|
+
return action instanceof ActionPayload && action.domain === this.domain && action.id === this.id;
|
|
327
|
+
}
|
|
328
|
+
toJsonObject() {
|
|
329
|
+
return {
|
|
330
|
+
id: this.id,
|
|
331
|
+
form: this.form,
|
|
332
|
+
domain: this.domain,
|
|
333
|
+
allDomains: this.allDomains
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
request(...args) {
|
|
337
|
+
const input = args[0];
|
|
338
|
+
const validatedInput = this.schema.validateInput(input, {
|
|
339
|
+
actionId: this.id,
|
|
340
|
+
domain: this.domain
|
|
341
|
+
});
|
|
342
|
+
const context = new ActionContext(this._domain, this.id, {
|
|
343
|
+
cuid: nanoid(),
|
|
344
|
+
timeCreated: Date.now(),
|
|
345
|
+
routing: [],
|
|
346
|
+
originClient: RuntimeCoordinate.unknown
|
|
347
|
+
});
|
|
348
|
+
return new ActionPayload_Request({ context }, validatedInput, {
|
|
349
|
+
time: Date.now()
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
deserializeInput(serialized) {
|
|
353
|
+
return this.schema.deserializeInput(serialized);
|
|
354
|
+
}
|
|
355
|
+
serializeInput(raw) {
|
|
356
|
+
return this.schema.serializeInput(raw);
|
|
357
|
+
}
|
|
358
|
+
validateInput(input) {
|
|
359
|
+
return this.schema.validateInput(input, {
|
|
360
|
+
domain: this.domain,
|
|
361
|
+
actionId: this.id
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
validateOutput(output) {
|
|
365
|
+
return this.schema.validateOutput(output, {
|
|
366
|
+
domain: this.domain,
|
|
367
|
+
actionId: this.id
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// src/ActionDefinition/Action/RunningAction.types.ts
|
|
372
|
+
var ERunningActionState;
|
|
373
|
+
((ERunningActionState2) => {
|
|
374
|
+
ERunningActionState2["running"] = "running";
|
|
375
|
+
ERunningActionState2["completed"] = "completed";
|
|
376
|
+
})(ERunningActionState ||= {});
|
|
377
|
+
var ERunningActionUpdateType;
|
|
378
|
+
((ERunningActionUpdateType2) => {
|
|
379
|
+
ERunningActionUpdateType2["started"] = "started";
|
|
380
|
+
ERunningActionUpdateType2["progress"] = "progress";
|
|
381
|
+
ERunningActionUpdateType2["finished"] = "finished";
|
|
382
|
+
})(ERunningActionUpdateType ||= {});
|
|
383
|
+
var ERunningActionFinishedType;
|
|
384
|
+
((ERunningActionFinishedType2) => {
|
|
385
|
+
ERunningActionFinishedType2["aborted"] = "aborted";
|
|
386
|
+
ERunningActionFinishedType2["failed"] = "failed";
|
|
387
|
+
ERunningActionFinishedType2["success"] = "success";
|
|
388
|
+
})(ERunningActionFinishedType ||= {});
|
|
389
|
+
|
|
390
|
+
// src/ActionDefinition/Action/RunningAction.ts
|
|
391
|
+
class RunningAction {
|
|
392
|
+
_state;
|
|
393
|
+
context;
|
|
394
|
+
cuid;
|
|
395
|
+
id;
|
|
396
|
+
_domain;
|
|
397
|
+
domain;
|
|
398
|
+
allDomains;
|
|
399
|
+
_resultPayloadPromise;
|
|
400
|
+
_resolveResult;
|
|
401
|
+
_rejectResult;
|
|
402
|
+
_isAborted = false;
|
|
403
|
+
_updates = [];
|
|
404
|
+
_updateListeners = [];
|
|
405
|
+
constructor(initialState) {
|
|
406
|
+
this.context = initialState.context;
|
|
407
|
+
this.cuid = initialState.context.cuid;
|
|
408
|
+
this.id = initialState.context.id;
|
|
409
|
+
this.domain = initialState.context.domain;
|
|
410
|
+
this.allDomains = initialState.context.allDomains;
|
|
411
|
+
this._domain = initialState.context._domain;
|
|
412
|
+
this._resultPayloadPromise = new Promise((resolve, reject) => {
|
|
413
|
+
this._resolveResult = resolve;
|
|
414
|
+
this._rejectResult = reject;
|
|
415
|
+
});
|
|
416
|
+
this._state = {
|
|
417
|
+
request: initialState.request,
|
|
418
|
+
progress: initialState.progress ?? [],
|
|
419
|
+
result: initialState.result
|
|
420
|
+
};
|
|
421
|
+
this._sendUpdate({
|
|
422
|
+
type: "started" /* started */,
|
|
423
|
+
runningAction: this,
|
|
424
|
+
time: Date.now()
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
get state() {
|
|
428
|
+
return this._state;
|
|
429
|
+
}
|
|
430
|
+
abort(reason) {
|
|
431
|
+
this._abort(reason);
|
|
432
|
+
}
|
|
433
|
+
addUpdateListeners(listeners) {
|
|
434
|
+
this._updateListeners.push(...listeners);
|
|
435
|
+
for (const event of this._updates) {
|
|
436
|
+
for (const listener of listeners) {
|
|
437
|
+
listener(event);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return () => {
|
|
441
|
+
for (const listener of listeners) {
|
|
442
|
+
const i = this._updateListeners.indexOf(listener);
|
|
443
|
+
if (i !== -1)
|
|
444
|
+
this._updateListeners.splice(i, 1);
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
async* iterateUpdates() {
|
|
449
|
+
const queue = [];
|
|
450
|
+
let resolveWaiter = null;
|
|
451
|
+
const unsubscribe = this.addUpdateListeners([
|
|
452
|
+
(event) => {
|
|
453
|
+
queue.push(event);
|
|
454
|
+
if (resolveWaiter) {
|
|
455
|
+
resolveWaiter();
|
|
456
|
+
resolveWaiter = null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
]);
|
|
460
|
+
try {
|
|
461
|
+
while (true) {
|
|
462
|
+
if (queue.length === 0) {
|
|
463
|
+
await new Promise((resolve) => {
|
|
464
|
+
resolveWaiter = resolve;
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
const event = queue.shift();
|
|
468
|
+
yield event;
|
|
469
|
+
if (event.type === "finished" /* finished */) {
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
} finally {
|
|
474
|
+
unsubscribe();
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
_sendUpdate(update) {
|
|
478
|
+
this._updates.push(update);
|
|
479
|
+
for (const listener of this._updateListeners)
|
|
480
|
+
listener(update);
|
|
481
|
+
}
|
|
482
|
+
_completeWithResult(result) {
|
|
483
|
+
if (this._state.result != null || this._isAborted)
|
|
484
|
+
return false;
|
|
485
|
+
this._state = {
|
|
486
|
+
request: this._state.request,
|
|
487
|
+
progress: this._state.progress,
|
|
488
|
+
result
|
|
489
|
+
};
|
|
490
|
+
this._resolveResult(result);
|
|
491
|
+
this._sendUpdate({
|
|
492
|
+
type: "finished" /* finished */,
|
|
493
|
+
finishType: "success" /* success */,
|
|
494
|
+
runningAction: this,
|
|
495
|
+
time: Date.now(),
|
|
496
|
+
response: result
|
|
497
|
+
});
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
_abort(reason) {
|
|
501
|
+
if (this._state.result != null || this._isAborted)
|
|
502
|
+
return false;
|
|
503
|
+
this._isAborted = true;
|
|
504
|
+
this._rejectResult(reason);
|
|
505
|
+
this._sendUpdate({
|
|
506
|
+
type: "finished" /* finished */,
|
|
507
|
+
finishType: "aborted" /* aborted */,
|
|
508
|
+
runningAction: this,
|
|
509
|
+
time: Date.now(),
|
|
510
|
+
reason
|
|
511
|
+
});
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
_updateProgress(progress) {
|
|
515
|
+
if (this._state.result != null || this._isAborted)
|
|
516
|
+
return;
|
|
517
|
+
this._state.progress.push(progress);
|
|
518
|
+
this._sendUpdate({
|
|
519
|
+
type: "progress" /* progress */,
|
|
520
|
+
runningAction: this,
|
|
521
|
+
time: Date.now(),
|
|
522
|
+
progress: progress.progress
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
waitForResultPayload() {
|
|
526
|
+
return this._resultPayloadPromise;
|
|
527
|
+
}
|
|
528
|
+
_resolveFromJson(resultJson) {
|
|
529
|
+
if (this._state.result != null || this._isAborted)
|
|
530
|
+
return false;
|
|
531
|
+
const result = this._domain.hydrateResultPayload(resultJson);
|
|
532
|
+
return this._completeWithResult(result);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
// src/errors/err_nice_action.ts
|
|
536
|
+
import { err, err_nice } from "@nice-code/error";
|
|
537
|
+
var EErrId_NiceAction;
|
|
538
|
+
((EErrId_NiceAction2) => {
|
|
539
|
+
EErrId_NiceAction2["not_implemented"] = "not_implemented";
|
|
540
|
+
EErrId_NiceAction2["action_id_not_in_domain"] = "action_id_not_in_domain";
|
|
541
|
+
EErrId_NiceAction2["domain_already_exists_in_hierarchy"] = "domain_already_exists_in_hierarchy";
|
|
542
|
+
EErrId_NiceAction2["domain_no_handler"] = "domain_no_handler";
|
|
543
|
+
EErrId_NiceAction2["hydration_domain_mismatch"] = "hydration_domain_mismatch";
|
|
544
|
+
EErrId_NiceAction2["hydration_action_state_mismatch"] = "hydration_action_state_mismatch";
|
|
545
|
+
EErrId_NiceAction2["hydration_action_id_not_found"] = "hydration_action_id_not_found";
|
|
546
|
+
EErrId_NiceAction2["no_action_execution_handler"] = "no_action_execution_handler";
|
|
547
|
+
EErrId_NiceAction2["wire_action_not_payload"] = "wire_action_not_payload";
|
|
548
|
+
EErrId_NiceAction2["wire_not_action_data"] = "wire_not_action_data";
|
|
549
|
+
EErrId_NiceAction2["client_runtime_already_registered"] = "client_runtime_already_registered";
|
|
550
|
+
EErrId_NiceAction2["client_runtime_not_registered"] = "client_runtime_not_registered";
|
|
551
|
+
EErrId_NiceAction2["no_client_runtimes_registered"] = "no_client_runtimes_registered";
|
|
552
|
+
EErrId_NiceAction2["action_input_validation_failed"] = "action_input_validation_failed";
|
|
553
|
+
EErrId_NiceAction2["action_input_validation_promise"] = "action_input_validation_promise";
|
|
554
|
+
EErrId_NiceAction2["action_output_validation_failed"] = "action_output_validation_failed";
|
|
555
|
+
EErrId_NiceAction2["action_output_validation_promise"] = "action_output_validation_promise";
|
|
556
|
+
})(EErrId_NiceAction ||= {});
|
|
557
|
+
var err_nice_action = err_nice.createChildDomain({
|
|
558
|
+
domain: "err_nice_action",
|
|
559
|
+
defaultHttpStatusCode: 500,
|
|
560
|
+
schema: {
|
|
561
|
+
["not_implemented" /* not_implemented */]: err({
|
|
562
|
+
message: ({ label }) => `The "${label}" functionality is not implemented yet.`
|
|
563
|
+
}),
|
|
564
|
+
["action_id_not_in_domain" /* action_id_not_in_domain */]: err({
|
|
565
|
+
message: ({ actionId, domain }) => `Action with id "${actionId}" does not exist in domain "${domain}".`
|
|
566
|
+
}),
|
|
567
|
+
["domain_already_exists_in_hierarchy" /* domain_already_exists_in_hierarchy */]: err({
|
|
568
|
+
message: ({ domain, allParentDomains, parentDomain }) => `Domain "${domain}" already exists in the hierarchy under the parent "${parentDomain}". All parent domains ["${allParentDomains.join(", ")}"]`
|
|
569
|
+
}),
|
|
570
|
+
["domain_no_handler" /* domain_no_handler */]: err({
|
|
571
|
+
message: ({ domain }) => `Domain "${domain}" has no action handler registered.`
|
|
572
|
+
}),
|
|
573
|
+
["hydration_domain_mismatch" /* hydration_domain_mismatch */]: err({
|
|
574
|
+
message: ({ expected, received }) => `Cannot hydrate action: domain mismatch. Expected "${expected}", got "${received}".`
|
|
575
|
+
}),
|
|
576
|
+
["hydration_action_state_mismatch" /* hydration_action_state_mismatch */]: err({
|
|
577
|
+
message: ({ expected, received }) => `Cannot hydrate action: action state type mismatch. Expected "${expected}", got "${received}".`
|
|
578
|
+
}),
|
|
579
|
+
["hydration_action_id_not_found" /* hydration_action_id_not_found */]: err({
|
|
580
|
+
message: ({ domain, actionId }) => `Cannot hydrate action: id "${actionId}" does not exist in domain "${domain}".`
|
|
581
|
+
}),
|
|
582
|
+
["no_action_execution_handler" /* no_action_execution_handler */]: err({
|
|
583
|
+
message: ({ domain, actionId, specifiedClient }) => `${specifiedClient ? ` The targeted client runtime [${specifiedClient.stringId}] has no` : "No"} action handler registered for "${actionId}" in domain "${domain}".`
|
|
584
|
+
}),
|
|
585
|
+
["wire_action_not_payload" /* wire_action_not_payload */]: err({
|
|
586
|
+
message: ({ domain, actionId, actionState }) => `Cannot handle wire for action "${actionId}" in domain "${domain}": expected action form of "${"data" /* data */}" and type of "${"request" /* request */}", "${"progress" /* progress */}" or "${"result" /* result */}", got "${actionState}".`
|
|
587
|
+
}),
|
|
588
|
+
["wire_not_action_data" /* wire_not_action_data */]: err({
|
|
589
|
+
message: () => `Cannot handle wire for action: expected an object with a "domain" property of type string, a "form" property of "${"data" /* data */}" and a "type" property of "${"request" /* request */}", "${"progress" /* progress */}" or "${"result" /* result */}".`
|
|
590
|
+
}),
|
|
591
|
+
["client_runtime_already_registered" /* client_runtime_already_registered */]: err({
|
|
592
|
+
message: ({ context, client }) => `Environment is already registered${context?.domain ? ` on domain "${context.domain}"` : ""} for client [${client.stringId}]. Each client specifier (exact match on all properties) may only be registered once.`
|
|
593
|
+
}),
|
|
594
|
+
["client_runtime_not_registered" /* client_runtime_not_registered */]: err({
|
|
595
|
+
message: ({ context, clientStringId }) => `No runtime registered${context?.domain ? ` on domain "${context.domain}"` : ""} for client [${clientStringId}].`
|
|
596
|
+
}),
|
|
597
|
+
["no_client_runtimes_registered" /* no_client_runtimes_registered */]: err({
|
|
598
|
+
message: ({ context }) => `No runtimes registered${context?.domain ? ` on domain "${context.domain}"` : ""}. Add handlers to a runtime via runtime.addHandlers([handler]) before executing actions.`
|
|
599
|
+
}),
|
|
600
|
+
["action_input_validation_failed" /* action_input_validation_failed */]: err({
|
|
601
|
+
message: ({ domain, actionId, validationMessage }) => `Input validation failed for action "${actionId}" in domain "${domain}":
|
|
602
|
+
${validationMessage}`,
|
|
603
|
+
httpStatusCode: 400
|
|
604
|
+
}),
|
|
605
|
+
["action_input_validation_promise" /* action_input_validation_promise */]: err({
|
|
606
|
+
message: ({ domain, actionId }) => `Input validation for action "${actionId}" in domain "${domain}" returned a promise, which is not supported.`,
|
|
607
|
+
httpStatusCode: 400
|
|
608
|
+
}),
|
|
609
|
+
["action_output_validation_failed" /* action_output_validation_failed */]: err({
|
|
610
|
+
message: ({ domain, actionId, validationMessage }) => `Output validation failed for action "${actionId}" in domain "${domain}":
|
|
611
|
+
${validationMessage}`,
|
|
612
|
+
httpStatusCode: 500
|
|
613
|
+
}),
|
|
614
|
+
["action_output_validation_promise" /* action_output_validation_promise */]: err({
|
|
615
|
+
message: ({ domain, actionId }) => `Output validation for action "${actionId}" in domain "${domain}" returned a promise, which is not supported.`,
|
|
616
|
+
httpStatusCode: 500
|
|
617
|
+
})
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// src/utils/isAction_Base_JsonObject.ts
|
|
622
|
+
var isAction_Base_JsonObject = (obj) => {
|
|
623
|
+
return typeof obj === "object" && obj !== null && typeof obj.domain === "string" && typeof obj.id === "string" && typeof obj.form === "string";
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// src/utils/isActionPayload_Result_JsonObject.ts
|
|
627
|
+
var isActionPayload_Result_JsonObject = (obj) => {
|
|
628
|
+
return isAction_Base_JsonObject(obj) && obj.result != null && obj.form === "data" /* data */ && obj.type === "result" /* result */;
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
// src/ActionRuntime/ActionRuntime.ts
|
|
632
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
633
|
+
|
|
634
|
+
// src/utils/getAssumedRuntimeEnvironment.ts
|
|
635
|
+
import { runtime } from "std-env";
|
|
636
|
+
var getAssumedRuntimeInfo = () => {
|
|
637
|
+
return {
|
|
638
|
+
assumed: true,
|
|
639
|
+
runtimeName: runtime
|
|
640
|
+
};
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// src/utils/isActionPayload_Progress_JsonObject.ts
|
|
644
|
+
var isActionPayload_Progress_JsonObject = (obj) => {
|
|
645
|
+
return isAction_Base_JsonObject(obj) && "progress" in obj && obj.form === "data" /* data */ && obj.type === "progress" /* progress */;
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// src/utils/isActionPayload_Request_JsonObject.ts
|
|
649
|
+
var isActionPayload_Request_JsonObject = (obj) => {
|
|
650
|
+
return isAction_Base_JsonObject(obj) && "input" in obj && obj.form === "data" /* data */ && obj.type === "request" /* request */;
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// src/utils/isActionPayload_Any_JsonObject.ts
|
|
654
|
+
function isActionPayload_Any_JsonObject(obj) {
|
|
655
|
+
return isActionPayload_Request_JsonObject(obj) || isActionPayload_Result_JsonObject(obj) || isActionPayload_Progress_JsonObject(obj);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// src/ActionRuntime/ActionDomainManager.ts
|
|
659
|
+
class ActionDomainManager {
|
|
660
|
+
_domains = new Map;
|
|
661
|
+
addDomain(domain) {
|
|
662
|
+
this._domains.set(domain.domain, domain);
|
|
663
|
+
}
|
|
664
|
+
getDomains() {
|
|
665
|
+
return [...this._domains.values()];
|
|
666
|
+
}
|
|
667
|
+
verifyIsActionJson(action) {
|
|
668
|
+
if (typeof action.domain !== "string" || typeof action.id !== "string") {
|
|
669
|
+
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
getActionDomain(action) {
|
|
673
|
+
this.verifyIsActionJson(action);
|
|
674
|
+
const domain = this._domains.get(action.domain);
|
|
675
|
+
if (!domain) {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
return domain;
|
|
679
|
+
}
|
|
680
|
+
getActionDomainOrThrow(action) {
|
|
681
|
+
this.verifyIsActionJson(action);
|
|
682
|
+
const domain = this._domains.get(action.domain);
|
|
683
|
+
if (!domain) {
|
|
684
|
+
throw err_nice_action.fromId("domain_no_handler" /* domain_no_handler */, {
|
|
685
|
+
domain: action.domain
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
return domain;
|
|
689
|
+
}
|
|
690
|
+
hydrateActionPayload(actionJson) {
|
|
691
|
+
const domain = this.getActionDomainOrThrow(actionJson);
|
|
692
|
+
return domain.hydrateAnyAction(actionJson);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// src/ActionRuntime/Routing/ActionRouter.ts
|
|
697
|
+
class ActionRouter {
|
|
698
|
+
domainManager = new ActionDomainManager;
|
|
699
|
+
actionRouteData = new Map;
|
|
700
|
+
_context;
|
|
701
|
+
constructor(context) {
|
|
702
|
+
this._context = context;
|
|
703
|
+
}
|
|
704
|
+
mergeRouter(actionRouter) {
|
|
705
|
+
for (const domain of actionRouter.getDomains()) {
|
|
706
|
+
this.domainManager.addDomain(domain);
|
|
707
|
+
}
|
|
708
|
+
for (const [matchKey, routeDataEntries] of actionRouter.actionRouteData.entries()) {
|
|
709
|
+
this.actionRouteData.set(matchKey, [...routeDataEntries]);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
addDomainsFromOther(actionRouter) {
|
|
713
|
+
for (const domain of actionRouter.getDomains()) {
|
|
714
|
+
this.domainManager.addDomain(domain);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
getRouteDataEntriesForAction(action) {
|
|
718
|
+
const idKey = `dom[${action.domain}]id[${action.id}]`;
|
|
719
|
+
const domKey = `dom[${action.domain}]id[_]`;
|
|
720
|
+
return [
|
|
721
|
+
...this.actionRouteData.get(idKey) ?? [],
|
|
722
|
+
...this.actionRouteData.get(domKey) ?? []
|
|
723
|
+
];
|
|
724
|
+
}
|
|
725
|
+
getRouteDataForAction(action) {
|
|
726
|
+
return this.getRouteDataEntriesForAction(action)[0];
|
|
727
|
+
}
|
|
728
|
+
throwNoHandlerForAction(action, context) {
|
|
729
|
+
if (this._context.contextType === "handler_route" /* handler_route */) {
|
|
730
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
731
|
+
domain: action.domain,
|
|
732
|
+
actionId: action.id,
|
|
733
|
+
specifiedClient: context.targetLocalRuntime?.coordinate
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
if (this._context.contextType === "runtime_to_handler" /* runtime_to_handler */) {
|
|
737
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
738
|
+
domain: action.domain,
|
|
739
|
+
actionId: action.id,
|
|
740
|
+
specifiedClient: this._context.runtime.coordinate
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
744
|
+
domain: action.domain,
|
|
745
|
+
actionId: action.id
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
getRouteDataEntriesForActionOrThrow(action, context) {
|
|
749
|
+
const entries = this.getRouteDataEntriesForAction(action);
|
|
750
|
+
if (entries.length === 0) {
|
|
751
|
+
this.throwNoHandlerForAction(action, context);
|
|
752
|
+
}
|
|
753
|
+
return entries;
|
|
754
|
+
}
|
|
755
|
+
getRouteDataForActionOrThrow(action, context) {
|
|
756
|
+
const routeData = this.getRouteDataForAction(action);
|
|
757
|
+
if (!routeData) {
|
|
758
|
+
this.throwNoHandlerForAction(action, context);
|
|
759
|
+
}
|
|
760
|
+
return routeData;
|
|
761
|
+
}
|
|
762
|
+
getForKey(key) {
|
|
763
|
+
return this.actionRouteData.get(key) ?? [];
|
|
764
|
+
}
|
|
765
|
+
getRegisteredKeys() {
|
|
766
|
+
return [...this.actionRouteData.keys()];
|
|
767
|
+
}
|
|
768
|
+
getDomains() {
|
|
769
|
+
return this.domainManager.getDomains();
|
|
770
|
+
}
|
|
771
|
+
forDomain(domain, routeData) {
|
|
772
|
+
this.domainManager.addDomain(domain);
|
|
773
|
+
this.actionRouteData.set(`dom[${domain.domain}]id[_]`, [routeData]);
|
|
774
|
+
return this;
|
|
775
|
+
}
|
|
776
|
+
forAction(action, routeData) {
|
|
777
|
+
return this.forActionId(action._domain, action.id, routeData);
|
|
778
|
+
}
|
|
779
|
+
forActionId(domain, id, routeData) {
|
|
780
|
+
this.domainManager.addDomain(domain);
|
|
781
|
+
this.actionRouteData.set(`dom[${domain.domain}]id[${id}]`, [routeData]);
|
|
782
|
+
return this;
|
|
783
|
+
}
|
|
784
|
+
forActionIds(domain, ids, routeData) {
|
|
785
|
+
this.domainManager.addDomain(domain);
|
|
786
|
+
for (const id of ids) {
|
|
787
|
+
this.forActionId(domain, id, routeData);
|
|
788
|
+
}
|
|
789
|
+
return this;
|
|
790
|
+
}
|
|
791
|
+
forDomainActionCases(domain, cases) {
|
|
792
|
+
this.domainManager.addDomain(domain);
|
|
793
|
+
for (const id of Object.keys(cases)) {
|
|
794
|
+
const routeData = cases[id];
|
|
795
|
+
if (routeData != null) {
|
|
796
|
+
this.actionRouteData.set(`dom[${domain.domain}]id[${id}]`, [routeData]);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return this;
|
|
800
|
+
}
|
|
801
|
+
addForDomain(domain, routeData) {
|
|
802
|
+
this.domainManager.addDomain(domain);
|
|
803
|
+
this._push(`dom[${domain.domain}]id[_]`, routeData);
|
|
804
|
+
return this;
|
|
805
|
+
}
|
|
806
|
+
addForAction(domain, id, routeData) {
|
|
807
|
+
this.domainManager.addDomain(domain);
|
|
808
|
+
this._push(`dom[${domain.domain}]id[${id}]`, routeData);
|
|
809
|
+
return this;
|
|
810
|
+
}
|
|
811
|
+
addForActionIds(domain, ids, routeData) {
|
|
812
|
+
this.domainManager.addDomain(domain);
|
|
813
|
+
for (const id of ids) {
|
|
814
|
+
this.addForAction(domain, id, routeData);
|
|
815
|
+
}
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
addForDomainActionCases(domain, cases) {
|
|
819
|
+
this.domainManager.addDomain(domain);
|
|
820
|
+
for (const id of Object.keys(cases)) {
|
|
821
|
+
const routeData = cases[id];
|
|
822
|
+
if (routeData != null) {
|
|
823
|
+
this._push(`dom[${domain.domain}]id[${id}]`, routeData);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return this;
|
|
827
|
+
}
|
|
828
|
+
addForKey(key, routeData) {
|
|
829
|
+
this._push(key, routeData);
|
|
830
|
+
return this;
|
|
831
|
+
}
|
|
832
|
+
_push(key, routeData) {
|
|
833
|
+
const existing = this.actionRouteData.get(key);
|
|
834
|
+
if (existing != null) {
|
|
835
|
+
existing.push(routeData);
|
|
836
|
+
} else {
|
|
837
|
+
this.actionRouteData.set(key, [routeData]);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// src/ActionRuntime/ActionRuntime.ts
|
|
843
|
+
class ActionRuntime {
|
|
844
|
+
_coordinate;
|
|
845
|
+
timeCreated;
|
|
846
|
+
runtimeInfo = getAssumedRuntimeInfo();
|
|
847
|
+
actionRouter;
|
|
848
|
+
_pendingRunningActions = new Map;
|
|
849
|
+
_registeredExternalHandlers = [];
|
|
850
|
+
_applied = false;
|
|
851
|
+
static getDefault() {
|
|
852
|
+
return getDefaultActionRuntime();
|
|
853
|
+
}
|
|
854
|
+
constructor(coordinate) {
|
|
855
|
+
this._coordinate = coordinate.specifyIfUnset({
|
|
856
|
+
insId: nanoid2(14)
|
|
857
|
+
});
|
|
858
|
+
this.timeCreated = Date.now();
|
|
859
|
+
this.actionRouter = new ActionRouter({
|
|
860
|
+
contextType: "runtime_to_handler" /* runtime_to_handler */,
|
|
861
|
+
runtime: this
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
get coordinate() {
|
|
865
|
+
return this._coordinate;
|
|
866
|
+
}
|
|
867
|
+
updateRuntimeCoordinate(newCoordinate) {
|
|
868
|
+
if (this._coordinate.envId !== newCoordinate.envId) {
|
|
869
|
+
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
870
|
+
label: `updating RuntimeCoordinate with a different "envId" ("${this._coordinate.envId}" → "${newCoordinate.envId}")`
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
this._coordinate = newCoordinate;
|
|
874
|
+
this.apply();
|
|
875
|
+
}
|
|
876
|
+
registerRunningAction(ra) {
|
|
877
|
+
this._pendingRunningActions.set(ra.cuid, ra);
|
|
878
|
+
ra.addUpdateListeners([
|
|
879
|
+
(update) => {
|
|
880
|
+
if (update.type === "finished" /* finished */) {
|
|
881
|
+
this._pendingRunningActions.delete(ra.cuid);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
]);
|
|
885
|
+
}
|
|
886
|
+
resolveIncomingActionPayload(json) {
|
|
887
|
+
if (json.type === "request" /* request */) {
|
|
888
|
+
this.handleActionPayloadWire(json).catch((err2) => {
|
|
889
|
+
console.error(`[ActionRuntime] Incoming action [${json.domain}:${json.id}:${json.form}:${json.type}] unhandled:`, err2);
|
|
890
|
+
});
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
this._pendingRunningActions.get(json.context.cuid)?._resolveFromJson(json);
|
|
894
|
+
}
|
|
895
|
+
async handleActionPayloadWire(wire) {
|
|
896
|
+
let action;
|
|
897
|
+
if (isActionPayload_Any_JsonObject(wire)) {
|
|
898
|
+
const domain = this.actionRouter.domainManager.getActionDomainOrThrow(wire);
|
|
899
|
+
action = domain.hydrateAnyAction(wire);
|
|
900
|
+
}
|
|
901
|
+
if (action == null) {
|
|
902
|
+
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
903
|
+
}
|
|
904
|
+
return this.handleActionPayload(action);
|
|
905
|
+
}
|
|
906
|
+
async handleActionPayload(action, options) {
|
|
907
|
+
const handlerForAction = this.getHandlerForActionOrThrow(action, options);
|
|
908
|
+
if (action.type === "request" /* request */) {
|
|
909
|
+
const runningAction = await handlerForAction.handleActionRequest(action, {
|
|
910
|
+
...options,
|
|
911
|
+
targetLocalRuntime: this
|
|
912
|
+
});
|
|
913
|
+
this._trySetupReturnDispatch(runningAction);
|
|
914
|
+
return runningAction;
|
|
915
|
+
}
|
|
916
|
+
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
917
|
+
label: `Handling incoming action payloads of type "${action.type}"`
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
_getHandlerForAction(action, options) {
|
|
921
|
+
const handlers = this.actionRouter.getRouteDataEntriesForAction(action);
|
|
922
|
+
const targetExternalClient = options?.targetExternalClient;
|
|
923
|
+
const possibleHandlers = handlers.filter((handler2) => {
|
|
924
|
+
if (handler2.handlerType === "external" /* external */) {
|
|
925
|
+
if (targetExternalClient && !targetExternalClient.isSameFor(handler2.externalClient).id) {
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
return true;
|
|
929
|
+
}
|
|
930
|
+
if (targetExternalClient != null) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
if (action.type === "request" /* request */) {
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
936
|
+
return false;
|
|
937
|
+
});
|
|
938
|
+
if (possibleHandlers.length === 0) {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
const scoringExternalClient = targetExternalClient ?? RuntimeCoordinate.unknown;
|
|
942
|
+
let handlerScore = -1;
|
|
943
|
+
let handler;
|
|
944
|
+
for (const possibleHandler of possibleHandlers) {
|
|
945
|
+
if (possibleHandler.handlerType === "local" /* local */ && handler == null) {
|
|
946
|
+
return possibleHandler;
|
|
947
|
+
}
|
|
948
|
+
if (possibleHandler.handlerType === "external" /* external */) {
|
|
949
|
+
const score = scoringExternalClient.similarityLevel(possibleHandler.externalClient);
|
|
950
|
+
if (score > handlerScore) {
|
|
951
|
+
handlerScore = score;
|
|
952
|
+
handler = possibleHandler;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return handler;
|
|
957
|
+
}
|
|
958
|
+
getHandlerForActionOrThrow(action, options) {
|
|
959
|
+
const handler = this._getHandlerForAction(action, options);
|
|
960
|
+
if (handler == null) {
|
|
961
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
962
|
+
actionId: action.id,
|
|
963
|
+
domain: action.domain,
|
|
964
|
+
specifiedClient: options?.targetExternalClient
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
return handler;
|
|
968
|
+
}
|
|
969
|
+
addHandlers(handlers) {
|
|
970
|
+
for (const handler of handlers) {
|
|
971
|
+
if (handler.handlerType === "external" /* external */) {
|
|
972
|
+
handler._setIncomingActionDataListener((json) => this.resolveIncomingActionPayload(json));
|
|
973
|
+
this._registeredExternalHandlers.push(handler);
|
|
974
|
+
}
|
|
975
|
+
const handlerRouter = handler.getActionRouter();
|
|
976
|
+
this.actionRouter.addDomainsFromOther(handlerRouter);
|
|
977
|
+
if (this._applied) {
|
|
978
|
+
this.apply();
|
|
979
|
+
}
|
|
980
|
+
for (const key of handlerRouter.getRegisteredKeys()) {
|
|
981
|
+
const alreadyRegistered = this.actionRouter.getForKey(key).some((h) => h.cuid === handler.cuid);
|
|
982
|
+
if (!alreadyRegistered) {
|
|
983
|
+
this.actionRouter.addForKey(key, handler);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
return this;
|
|
988
|
+
}
|
|
989
|
+
applyRuntimeForDomain(domain) {
|
|
990
|
+
const rootDomain = domain.rootDomain;
|
|
991
|
+
if (!rootDomain._hasRuntime(this)) {
|
|
992
|
+
rootDomain._registerRuntime(this);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
apply() {
|
|
996
|
+
this._applied = true;
|
|
997
|
+
for (const domain of this.actionRouter.getDomains()) {
|
|
998
|
+
this.applyRuntimeForDomain(domain);
|
|
999
|
+
}
|
|
1000
|
+
return this;
|
|
1001
|
+
}
|
|
1002
|
+
getReturnHandlerForOrigin(originClient) {
|
|
1003
|
+
if (originClient.envId === UNSET_RUNTIME_ENV_ID)
|
|
1004
|
+
return;
|
|
1005
|
+
let bestScore = -1;
|
|
1006
|
+
let bestHandler;
|
|
1007
|
+
for (const handler of this._registeredExternalHandlers) {
|
|
1008
|
+
const score = originClient.similarityLevel(handler.externalClient);
|
|
1009
|
+
if (score > bestScore) {
|
|
1010
|
+
bestScore = score;
|
|
1011
|
+
bestHandler = handler;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
return bestScore > 0 ? bestHandler : undefined;
|
|
1015
|
+
}
|
|
1016
|
+
_trySetupReturnDispatch(runningAction) {
|
|
1017
|
+
const originClient = runningAction.context.originClient;
|
|
1018
|
+
if (originClient.envId === UNSET_RUNTIME_ENV_ID || originClient.isSameFor(this._coordinate).id) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
runningAction.addUpdateListeners([
|
|
1022
|
+
(update) => {
|
|
1023
|
+
if (update.type === "finished" /* finished */ && update.finishType === "success" /* success */) {
|
|
1024
|
+
const returnHandler = this.getReturnHandlerForOrigin(originClient);
|
|
1025
|
+
returnHandler?.sendReturnPayload(update.response, { targetLocalRuntime: this }).catch(() => {});
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
]);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
var runtimeState = {
|
|
1032
|
+
defaultLocalRuntime: undefined,
|
|
1033
|
+
assumedRuntimeInfo: undefined
|
|
1034
|
+
};
|
|
1035
|
+
function getDefaultActionRuntime() {
|
|
1036
|
+
if (runtimeState.assumedRuntimeInfo == null) {
|
|
1037
|
+
runtimeState.assumedRuntimeInfo = getAssumedRuntimeInfo();
|
|
1038
|
+
}
|
|
1039
|
+
if (runtimeState.defaultLocalRuntime == null) {
|
|
1040
|
+
runtimeState.defaultLocalRuntime = new ActionRuntime(RuntimeCoordinate.unknown.specify({
|
|
1041
|
+
perId: `${runtimeState.assumedRuntimeInfo?.runtimeName ?? "unknown"}-runtime`
|
|
1042
|
+
}));
|
|
1043
|
+
}
|
|
1044
|
+
return runtimeState.defaultLocalRuntime;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// src/ActionRuntime/Handler/ActionHandler.ts
|
|
1048
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
1049
|
+
|
|
1050
|
+
class ActionHandler {
|
|
1051
|
+
cuid;
|
|
1052
|
+
constructor() {
|
|
1053
|
+
this.cuid = nanoid3();
|
|
1054
|
+
}
|
|
1055
|
+
getActionRouter() {
|
|
1056
|
+
return this.actionRouter;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// src/ActionRuntime/Handler/Local/ActionLocalHandler.ts
|
|
1061
|
+
class ActionLocalHandler extends ActionHandler {
|
|
1062
|
+
handlerType = "local" /* local */;
|
|
1063
|
+
actionRouter = new ActionRouter({
|
|
1064
|
+
contextType: "handler_route" /* handler_route */,
|
|
1065
|
+
handler: this
|
|
1066
|
+
});
|
|
1067
|
+
constructor() {
|
|
1068
|
+
super();
|
|
1069
|
+
}
|
|
1070
|
+
forDomain(domain, handler) {
|
|
1071
|
+
this.actionRouter.forDomain(domain, handler);
|
|
1072
|
+
return this;
|
|
1073
|
+
}
|
|
1074
|
+
forAction(action, handler) {
|
|
1075
|
+
this.actionRouter.forAction(action, handler);
|
|
1076
|
+
return this;
|
|
1077
|
+
}
|
|
1078
|
+
forActionIds(domain, ids, handler) {
|
|
1079
|
+
this.actionRouter.forActionIds(domain, ids, handler);
|
|
1080
|
+
return this;
|
|
1081
|
+
}
|
|
1082
|
+
forDomainActionCases(domain, cases) {
|
|
1083
|
+
this.actionRouter.forDomainActionCases(domain, cases);
|
|
1084
|
+
return this;
|
|
1085
|
+
}
|
|
1086
|
+
async handleActionRequest(action, config) {
|
|
1087
|
+
const targetLocalRuntime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();
|
|
1088
|
+
const handler = this.actionRouter.getRouteDataForActionOrThrow(action, {
|
|
1089
|
+
targetLocalRuntime
|
|
1090
|
+
});
|
|
1091
|
+
action.context.addRouteItem({
|
|
1092
|
+
runtime: targetLocalRuntime.coordinate,
|
|
1093
|
+
handler: this.toHandlerRouteItem(),
|
|
1094
|
+
time: Date.now()
|
|
1095
|
+
});
|
|
1096
|
+
const runningAction = new RunningAction({ context: action.context, request: action });
|
|
1097
|
+
this._handleRunningAction(handler, runningAction).catch((err2) => runningAction._abort(err2));
|
|
1098
|
+
return runningAction;
|
|
1099
|
+
}
|
|
1100
|
+
async _handleRunningAction(handler, runningAction) {
|
|
1101
|
+
const state = runningAction.state;
|
|
1102
|
+
if (state.result != null) {
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
const rawResult = await handler(state.request);
|
|
1106
|
+
let result;
|
|
1107
|
+
if (rawResult instanceof ActionPayload_Result) {
|
|
1108
|
+
result = rawResult;
|
|
1109
|
+
} else if (rawResult != null && isActionPayload_Result_JsonObject(rawResult)) {
|
|
1110
|
+
const domain = this.actionRouter.domainManager.getActionDomainOrThrow(state.request);
|
|
1111
|
+
result = domain.hydrateResultPayload(rawResult);
|
|
1112
|
+
} else {
|
|
1113
|
+
result = state.request.successResult(rawResult);
|
|
1114
|
+
}
|
|
1115
|
+
runningAction._completeWithResult(result);
|
|
1116
|
+
}
|
|
1117
|
+
async handlePayloadWireOrThrow(wire, config) {
|
|
1118
|
+
const hydratedAction = this.actionRouter.domainManager.hydrateActionPayload(wire);
|
|
1119
|
+
if (!(hydratedAction instanceof ActionPayload_Request)) {
|
|
1120
|
+
throw err_nice_action.fromId("wire_action_not_payload" /* wire_action_not_payload */, {
|
|
1121
|
+
domain: hydratedAction.domain,
|
|
1122
|
+
actionId: hydratedAction.id,
|
|
1123
|
+
actionState: hydratedAction.type ?? hydratedAction.form
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
return await this.handleActionRequest(hydratedAction, config);
|
|
1127
|
+
}
|
|
1128
|
+
toJsonObject() {
|
|
1129
|
+
return {
|
|
1130
|
+
type: this.handlerType
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
toHandlerRouteItem() {
|
|
1134
|
+
return {
|
|
1135
|
+
type: this.handlerType
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
var createLocalHandler = () => {
|
|
1140
|
+
return new ActionLocalHandler;
|
|
1141
|
+
};
|
|
1142
|
+
|
|
1143
|
+
// src/utils/isAction_Context_JsonObject.ts
|
|
1144
|
+
var isAction_Context_JsonObject = (obj) => {
|
|
1145
|
+
return isAction_Base_JsonObject(obj) && obj.form === "context" /* context */;
|
|
1146
|
+
};
|
|
1147
|
+
|
|
1148
|
+
// src/utils/isAction_Core_JsonObject.ts
|
|
1149
|
+
var isAction_Core_JsonObject = (obj) => {
|
|
1150
|
+
return isAction_Base_JsonObject(obj) && obj.form === "core" /* core */;
|
|
1151
|
+
};
|
|
1152
|
+
|
|
1153
|
+
// src/utils/isAction_Any_JsonObject.ts
|
|
1154
|
+
function isAction_Any_JsonObject(obj) {
|
|
1155
|
+
return isActionPayload_Any_JsonObject(obj) || isAction_Context_JsonObject(obj) || isAction_Core_JsonObject(obj);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// src/utils/assertIsActionJson.ts
|
|
1159
|
+
function assertIsActionJson(obj) {
|
|
1160
|
+
if (!isAction_Any_JsonObject(obj)) {
|
|
1161
|
+
throw err_nice_action.fromId("wire_not_action_data" /* wire_not_action_data */);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// src/utils/isAction_Any_Instance.ts
|
|
1166
|
+
function isAction_Any_Instance(value) {
|
|
1167
|
+
return value instanceof ActionCore || value instanceof ActionPayload || value instanceof ActionContext;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/ActionDefinition/Domain/ActionDomainBase.ts
|
|
1171
|
+
class ActionDomainBase {
|
|
1172
|
+
domain;
|
|
1173
|
+
allDomains;
|
|
1174
|
+
actionSchema;
|
|
1175
|
+
_listeners = [];
|
|
1176
|
+
constructor(definition) {
|
|
1177
|
+
this.domain = definition.domain;
|
|
1178
|
+
this.allDomains = definition.allDomains;
|
|
1179
|
+
this.actionSchema = definition.actionSchema;
|
|
1180
|
+
}
|
|
1181
|
+
addActionListener(listener) {
|
|
1182
|
+
this._listeners.push(listener);
|
|
1183
|
+
return () => {
|
|
1184
|
+
this._listeners = this._listeners.filter((l) => l !== listener);
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
// src/ActionDefinition/Domain/ActionDomain.ts
|
|
1190
|
+
class ActionDomain extends ActionDomainBase {
|
|
1191
|
+
_rootDomain;
|
|
1192
|
+
_actionMap;
|
|
1193
|
+
constructor(definition, {
|
|
1194
|
+
rootDomain
|
|
1195
|
+
}) {
|
|
1196
|
+
super(definition);
|
|
1197
|
+
this._rootDomain = rootDomain;
|
|
1198
|
+
this._actionMap = this.createActionMap();
|
|
1199
|
+
}
|
|
1200
|
+
get rootDomain() {
|
|
1201
|
+
return this._rootDomain;
|
|
1202
|
+
}
|
|
1203
|
+
_registerRuntime(runtime2) {
|
|
1204
|
+
this._rootDomain._registerRuntime(runtime2);
|
|
1205
|
+
}
|
|
1206
|
+
createChildDomain(subDomainDef) {
|
|
1207
|
+
if (this.allDomains.includes(subDomainDef.domain)) {
|
|
1208
|
+
throw err_nice_action.fromId("domain_already_exists_in_hierarchy" /* domain_already_exists_in_hierarchy */, {
|
|
1209
|
+
domain: subDomainDef.domain,
|
|
1210
|
+
allParentDomains: this.allDomains,
|
|
1211
|
+
parentDomain: this.domain
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
return new ActionDomain({
|
|
1215
|
+
allDomains: [...this.allDomains, subDomainDef.domain],
|
|
1216
|
+
domain: subDomainDef.domain,
|
|
1217
|
+
actionSchema: subDomainDef.actions
|
|
1218
|
+
}, { rootDomain: this._rootDomain });
|
|
1219
|
+
}
|
|
1220
|
+
get action() {
|
|
1221
|
+
return this._actionMap;
|
|
1222
|
+
}
|
|
1223
|
+
actionsMap() {
|
|
1224
|
+
return this._actionMap;
|
|
1225
|
+
}
|
|
1226
|
+
actionForId(id) {
|
|
1227
|
+
const actionSchema = this.actionSchema[id];
|
|
1228
|
+
if (!actionSchema) {
|
|
1229
|
+
throw err_nice_action.fromId("action_id_not_in_domain" /* action_id_not_in_domain */, {
|
|
1230
|
+
domain: this.domain,
|
|
1231
|
+
actionId: id
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
return new ActionCore(this, id);
|
|
1235
|
+
}
|
|
1236
|
+
wrapAsLocalHandler(wrappedActionExecutor) {
|
|
1237
|
+
const _handler = new ActionLocalHandler;
|
|
1238
|
+
const executor = wrappedActionExecutor;
|
|
1239
|
+
return _handler.forDomain(this, (request) => executor[request.id](request.input));
|
|
1240
|
+
}
|
|
1241
|
+
hydrateContext(id, contextData) {
|
|
1242
|
+
return new ActionContext(this, id, {
|
|
1243
|
+
timeCreated: contextData.timeCreated,
|
|
1244
|
+
cuid: contextData.cuid,
|
|
1245
|
+
routing: contextData.routing.map((item) => {
|
|
1246
|
+
return {
|
|
1247
|
+
runtime: new RuntimeCoordinate(item.runtime),
|
|
1248
|
+
handler: item.handler,
|
|
1249
|
+
time: item.time
|
|
1250
|
+
};
|
|
1251
|
+
}),
|
|
1252
|
+
originClient: contextData.originClient ? new RuntimeCoordinate(contextData.originClient) : RuntimeCoordinate.unknown
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1255
|
+
isDomainAction(action) {
|
|
1256
|
+
return isAction_Any_Instance(action) && action.domain === this.domain;
|
|
1257
|
+
}
|
|
1258
|
+
hydrateRequestPayload(serialized) {
|
|
1259
|
+
if (serialized.type !== "request" /* request */) {
|
|
1260
|
+
throw err_nice_action.fromId("hydration_action_state_mismatch" /* hydration_action_state_mismatch */, {
|
|
1261
|
+
expected: "request" /* request */,
|
|
1262
|
+
received: serialized.type
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
if (serialized.domain !== this.domain) {
|
|
1266
|
+
throw err_nice_action.fromId("hydration_domain_mismatch" /* hydration_domain_mismatch */, {
|
|
1267
|
+
expected: this.domain,
|
|
1268
|
+
received: serialized.domain
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
const id = serialized.id;
|
|
1272
|
+
if (!this.actionSchema[id]) {
|
|
1273
|
+
throw err_nice_action.fromId("hydration_action_id_not_found" /* hydration_action_id_not_found */, {
|
|
1274
|
+
domain: this.domain,
|
|
1275
|
+
actionId: serialized.id
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
const contextAction = this.hydrateContext(id, serialized.context);
|
|
1279
|
+
return new ActionPayload_Request({ context: contextAction }, contextAction.deserializeInput(serialized.input), {
|
|
1280
|
+
time: serialized.time
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
hydrateResultPayload(serialized) {
|
|
1284
|
+
if (serialized.type !== "result" /* result */) {
|
|
1285
|
+
throw err_nice_action.fromId("hydration_action_state_mismatch" /* hydration_action_state_mismatch */, {
|
|
1286
|
+
expected: "result" /* result */,
|
|
1287
|
+
received: serialized.type
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
if (serialized.domain !== this.domain) {
|
|
1291
|
+
throw err_nice_action.fromId("hydration_domain_mismatch" /* hydration_domain_mismatch */, {
|
|
1292
|
+
expected: this.domain,
|
|
1293
|
+
received: serialized.domain
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
const id = serialized.id;
|
|
1297
|
+
if (!this.actionSchema[id]) {
|
|
1298
|
+
throw err_nice_action.fromId("hydration_action_id_not_found" /* hydration_action_id_not_found */, {
|
|
1299
|
+
domain: this.domain,
|
|
1300
|
+
actionId: serialized.id
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
const contextAction = this.hydrateContext(id, serialized.context);
|
|
1304
|
+
return new ActionPayload_Result({ context: contextAction }, serialized.result, {
|
|
1305
|
+
time: serialized.time
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
hydrateAnyAction(actionJson) {
|
|
1309
|
+
assertIsActionJson(actionJson);
|
|
1310
|
+
if (actionJson.form === "data" /* data */) {
|
|
1311
|
+
if (actionJson.type === "request" /* request */) {
|
|
1312
|
+
return this.hydrateRequestPayload(actionJson);
|
|
1313
|
+
}
|
|
1314
|
+
if (actionJson.type === "result" /* result */) {
|
|
1315
|
+
return this.hydrateResultPayload(actionJson);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return this.actionForId(actionJson.id);
|
|
1319
|
+
}
|
|
1320
|
+
async runAction(request, options) {
|
|
1321
|
+
const allListeners = [
|
|
1322
|
+
...options?.listeners ?? [],
|
|
1323
|
+
...this._listeners
|
|
1324
|
+
];
|
|
1325
|
+
return this._rootDomain._runAction(request, {
|
|
1326
|
+
...options,
|
|
1327
|
+
listeners: allListeners
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
createActionMap() {
|
|
1331
|
+
const map = {};
|
|
1332
|
+
for (const id in this.actionSchema) {
|
|
1333
|
+
map[id] = new ActionCore(this, id);
|
|
1334
|
+
}
|
|
1335
|
+
return map;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
// src/ActionRuntime/ActionRuntimeManager.ts
|
|
1339
|
+
class ActionRuntimeManager {
|
|
1340
|
+
_runtimes = new Map;
|
|
1341
|
+
_preferredRuntimeClientId = null;
|
|
1342
|
+
_context;
|
|
1343
|
+
constructor(context) {
|
|
1344
|
+
this._context = context ?? {};
|
|
1345
|
+
}
|
|
1346
|
+
registerRuntime(runtime2) {
|
|
1347
|
+
const runtimeId = runtime2.coordinate.stringId;
|
|
1348
|
+
if (this._runtimes.has(runtimeId)) {
|
|
1349
|
+
throw err_nice_action.fromId("client_runtime_already_registered" /* client_runtime_already_registered */, {
|
|
1350
|
+
context: this._context,
|
|
1351
|
+
client: runtime2.coordinate
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
for (const id of runtime2.coordinate.toStringIds()) {
|
|
1355
|
+
if (this._runtimes.has(id)) {
|
|
1356
|
+
continue;
|
|
1357
|
+
}
|
|
1358
|
+
this._runtimes.set(id, runtime2);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
getRuntimeAndHandlerForAction(action, options, throwOnIssue) {
|
|
1362
|
+
const localRuntime = options?.targetLocalRuntime;
|
|
1363
|
+
if (localRuntime != null) {
|
|
1364
|
+
const runtime2 = throwOnIssue ? this.getBestRuntimeOrThrow(options?.targetLocalRuntime?.coordinate) : this.getBestRuntime(options?.targetLocalRuntime?.coordinate);
|
|
1365
|
+
if (runtime2 == null) {
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
const handler = runtime2._getHandlerForAction(action, options);
|
|
1369
|
+
if (handler != null) {
|
|
1370
|
+
return { handler, runtime: runtime2 };
|
|
1371
|
+
}
|
|
1372
|
+
if (throwOnIssue) {
|
|
1373
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
1374
|
+
domain: action.domain,
|
|
1375
|
+
actionId: action.id,
|
|
1376
|
+
specifiedClient: localRuntime.coordinate
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
for (const runtime2 of this._runtimes.values()) {
|
|
1381
|
+
const handler = runtime2._getHandlerForAction(action);
|
|
1382
|
+
if (handler) {
|
|
1383
|
+
return { handler, runtime: runtime2 };
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
if (throwOnIssue) {
|
|
1387
|
+
throw err_nice_action.fromId("no_action_execution_handler" /* no_action_execution_handler */, {
|
|
1388
|
+
domain: action.domain,
|
|
1389
|
+
actionId: action.id,
|
|
1390
|
+
specifiedClient: options?.targetLocalRuntime?.coordinate
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
getRuntimeAndHandlerForActionOrThrow(action, options) {
|
|
1395
|
+
return this.getRuntimeAndHandlerForAction(action, options, true);
|
|
1396
|
+
}
|
|
1397
|
+
setPreferredRuntime(runtime2) {
|
|
1398
|
+
const runtimeId = runtime2.coordinate.stringId;
|
|
1399
|
+
this._preferredRuntimeClientId = runtimeId;
|
|
1400
|
+
}
|
|
1401
|
+
getPreferredRuntime() {
|
|
1402
|
+
if (this._preferredRuntimeClientId) {
|
|
1403
|
+
const runtime2 = this._runtimes.get(this._preferredRuntimeClientId);
|
|
1404
|
+
if (runtime2) {
|
|
1405
|
+
return runtime2;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return this._runtimes.values().next().value;
|
|
1409
|
+
}
|
|
1410
|
+
getBestRuntimeForSpecifier(clientSpecifier) {
|
|
1411
|
+
const actionClient = new RuntimeCoordinate(clientSpecifier);
|
|
1412
|
+
const ids = actionClient.toStringIds();
|
|
1413
|
+
for (const id of ids) {
|
|
1414
|
+
const runtime2 = this._runtimes.get(id);
|
|
1415
|
+
if (runtime2) {
|
|
1416
|
+
return runtime2;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
getBestRuntime(clientSpecifier) {
|
|
1421
|
+
return clientSpecifier != null ? this.getBestRuntimeForSpecifier(clientSpecifier) : this.getPreferredRuntime();
|
|
1422
|
+
}
|
|
1423
|
+
hasRuntime(runtime2) {
|
|
1424
|
+
return this._runtimes.has(runtime2.coordinate.stringId);
|
|
1425
|
+
}
|
|
1426
|
+
getBestRuntimeOrThrow(specifier) {
|
|
1427
|
+
const runtime2 = this.getBestRuntime(specifier);
|
|
1428
|
+
if (!runtime2) {
|
|
1429
|
+
if (specifier == null) {
|
|
1430
|
+
throw err_nice_action.fromId("no_client_runtimes_registered" /* no_client_runtimes_registered */, {
|
|
1431
|
+
context: this._context
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
throw err_nice_action.fromId("client_runtime_not_registered" /* client_runtime_not_registered */, {
|
|
1435
|
+
context: this._context,
|
|
1436
|
+
clientStringId: runtimeCoordinateToStringIds(specifier)[0]
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
return runtime2;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// src/ActionDefinition/Domain/ActionRootDomain.ts
|
|
1444
|
+
class ActionRootDomain extends ActionDomainBase {
|
|
1445
|
+
domainDefinition;
|
|
1446
|
+
_actionRuntimeManager;
|
|
1447
|
+
constructor(domainDefinition) {
|
|
1448
|
+
const domainId = domainDefinition.domain;
|
|
1449
|
+
super({
|
|
1450
|
+
domain: domainId,
|
|
1451
|
+
allDomains: [domainId],
|
|
1452
|
+
actionSchema: {}
|
|
1453
|
+
});
|
|
1454
|
+
this.domainDefinition = domainDefinition;
|
|
1455
|
+
this._actionRuntimeManager = new ActionRuntimeManager({ domain: domainId });
|
|
1456
|
+
}
|
|
1457
|
+
createChildDomain(subDomainDef) {
|
|
1458
|
+
if (this.allDomains.includes(subDomainDef.domain)) {
|
|
1459
|
+
throw err_nice_action.fromId("domain_already_exists_in_hierarchy" /* domain_already_exists_in_hierarchy */, {
|
|
1460
|
+
domain: subDomainDef.domain,
|
|
1461
|
+
allParentDomains: this.allDomains,
|
|
1462
|
+
parentDomain: this.domain
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
return new ActionDomain({
|
|
1466
|
+
allDomains: [...this.allDomains, subDomainDef.domain],
|
|
1467
|
+
domain: subDomainDef.domain,
|
|
1468
|
+
actionSchema: subDomainDef.actions
|
|
1469
|
+
}, { rootDomain: this });
|
|
1470
|
+
}
|
|
1471
|
+
_registerRuntime(runtime2) {
|
|
1472
|
+
this._actionRuntimeManager.registerRuntime(runtime2);
|
|
1473
|
+
}
|
|
1474
|
+
_hasRuntime(runtime2) {
|
|
1475
|
+
return this._actionRuntimeManager.hasRuntime(runtime2);
|
|
1476
|
+
}
|
|
1477
|
+
getRuntime(clientSpecifier) {
|
|
1478
|
+
return this._actionRuntimeManager.getBestRuntimeForSpecifier(clientSpecifier);
|
|
1479
|
+
}
|
|
1480
|
+
async _runAction(actionPayload, options) {
|
|
1481
|
+
const { handler, runtime: runtime2 } = this._actionRuntimeManager.getRuntimeAndHandlerForActionOrThrow(actionPayload, options);
|
|
1482
|
+
actionPayload.context._setOriginClient(runtime2.coordinate);
|
|
1483
|
+
const allListeners = [...this._listeners, ...options?.listeners ?? []];
|
|
1484
|
+
const runningAction = await handler.handleActionRequest(actionPayload, {
|
|
1485
|
+
targetLocalRuntime: runtime2
|
|
1486
|
+
});
|
|
1487
|
+
runningAction.addUpdateListeners(allListeners);
|
|
1488
|
+
return runningAction;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
// src/ActionDefinition/Domain/helpers/createRootActionDomain.ts
|
|
1492
|
+
var createActionRootDomain = (definition) => {
|
|
1493
|
+
return new ActionRootDomain(definition);
|
|
1494
|
+
};
|
|
1495
|
+
// src/ActionDefinition/Schema/ActionSchema.ts
|
|
1496
|
+
import { extractMessageFromStandardSchema } from "@nice-code/common-errors";
|
|
1497
|
+
class ActionSchema {
|
|
1498
|
+
_errorDeclarations = [];
|
|
1499
|
+
inputOptions;
|
|
1500
|
+
outputOptions;
|
|
1501
|
+
get inputSchema() {
|
|
1502
|
+
return this.inputOptions?.schema;
|
|
1503
|
+
}
|
|
1504
|
+
get outputSchema() {
|
|
1505
|
+
return this.outputOptions?.schema;
|
|
1506
|
+
}
|
|
1507
|
+
input(options, serialize, deserialize) {
|
|
1508
|
+
if (serialize != null && deserialize != null) {
|
|
1509
|
+
this.inputOptions = { ...options, serialization: { serialize, deserialize } };
|
|
1510
|
+
} else {
|
|
1511
|
+
this.inputOptions = options;
|
|
1512
|
+
}
|
|
1513
|
+
return this;
|
|
1514
|
+
}
|
|
1515
|
+
output(options, serialize, deserialize) {
|
|
1516
|
+
if (serialize != null && deserialize != null) {
|
|
1517
|
+
this.outputOptions = { ...options, serialization: { serialize, deserialize } };
|
|
1518
|
+
} else {
|
|
1519
|
+
this.outputOptions = options;
|
|
1520
|
+
}
|
|
1521
|
+
return this;
|
|
1522
|
+
}
|
|
1523
|
+
throws(domain, ids) {
|
|
1524
|
+
this._errorDeclarations.push({ _domain: domain, _ids: ids });
|
|
1525
|
+
return this;
|
|
1526
|
+
}
|
|
1527
|
+
serializeInput(rawInput) {
|
|
1528
|
+
if (this.inputOptions?.serialization) {
|
|
1529
|
+
return this.inputOptions.serialization.serialize(rawInput);
|
|
1530
|
+
}
|
|
1531
|
+
return rawInput;
|
|
1532
|
+
}
|
|
1533
|
+
deserializeInput(serialized) {
|
|
1534
|
+
if (this.inputOptions?.serialization) {
|
|
1535
|
+
return this.inputOptions.serialization.deserialize(serialized);
|
|
1536
|
+
}
|
|
1537
|
+
return serialized;
|
|
1538
|
+
}
|
|
1539
|
+
validateInput(value, meta) {
|
|
1540
|
+
if (this.inputOptions?.schema == null) {
|
|
1541
|
+
return value;
|
|
1542
|
+
}
|
|
1543
|
+
const result = this.inputOptions.schema["~standard"].validate(value);
|
|
1544
|
+
if (result instanceof Promise) {
|
|
1545
|
+
throw err_nice_action.fromId("action_input_validation_promise" /* action_input_validation_promise */, {
|
|
1546
|
+
domain: meta.domain,
|
|
1547
|
+
actionId: meta.actionId
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
if (result.issues != null) {
|
|
1551
|
+
throw err_nice_action.fromId("action_input_validation_failed" /* action_input_validation_failed */, {
|
|
1552
|
+
domain: meta.domain,
|
|
1553
|
+
actionId: meta.actionId,
|
|
1554
|
+
validationMessage: extractMessageFromStandardSchema(result)
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
return result.value;
|
|
1558
|
+
}
|
|
1559
|
+
validateOutput(value, meta) {
|
|
1560
|
+
if (this.outputOptions?.schema == null) {
|
|
1561
|
+
return value;
|
|
1562
|
+
}
|
|
1563
|
+
const result = this.outputOptions.schema["~standard"].validate(value);
|
|
1564
|
+
if (result instanceof Promise) {
|
|
1565
|
+
throw err_nice_action.fromId("action_output_validation_promise" /* action_output_validation_promise */, {
|
|
1566
|
+
domain: meta.domain,
|
|
1567
|
+
actionId: meta.actionId
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
if (result.issues != null) {
|
|
1571
|
+
throw err_nice_action.fromId("action_output_validation_failed" /* action_output_validation_failed */, {
|
|
1572
|
+
domain: meta.domain,
|
|
1573
|
+
actionId: meta.actionId,
|
|
1574
|
+
validationMessage: extractMessageFromStandardSchema(result)
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
return result.value;
|
|
1578
|
+
}
|
|
1579
|
+
serializeOutput(rawOutput) {
|
|
1580
|
+
if (this.outputOptions?.serialization) {
|
|
1581
|
+
return this.outputOptions.serialization.serialize(rawOutput);
|
|
1582
|
+
}
|
|
1583
|
+
return rawOutput;
|
|
1584
|
+
}
|
|
1585
|
+
deserializeOutput(serialized) {
|
|
1586
|
+
if (this.outputOptions?.serialization) {
|
|
1587
|
+
return this.outputOptions.serialization.deserialize(serialized);
|
|
1588
|
+
}
|
|
1589
|
+
return serialized;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
var actionSchema = () => {
|
|
1593
|
+
return new ActionSchema;
|
|
1594
|
+
};
|
|
1595
|
+
// src/ActionRuntime/Handler/ExternalClient/ActionExternalClientHandler.ts
|
|
1596
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
1597
|
+
|
|
1598
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport.ts
|
|
1599
|
+
import { err as err2 } from "@nice-code/error";
|
|
1600
|
+
|
|
1601
|
+
// src/ActionRuntime/Handler/ExternalClient/err_nice_external_client.ts
|
|
1602
|
+
var err_nice_external_client = err_nice_action.createChildDomain({
|
|
1603
|
+
domain: "err_nice_external_client",
|
|
1604
|
+
schema: {}
|
|
1605
|
+
});
|
|
1606
|
+
|
|
1607
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport.ts
|
|
1608
|
+
var EErrId_NiceTransport;
|
|
1609
|
+
((EErrId_NiceTransport2) => {
|
|
1610
|
+
EErrId_NiceTransport2["timeout"] = "timeout";
|
|
1611
|
+
EErrId_NiceTransport2["not_found"] = "not_found";
|
|
1612
|
+
EErrId_NiceTransport2["unsupported"] = "unsupported";
|
|
1613
|
+
EErrId_NiceTransport2["initialization_failed"] = "initialization_failed";
|
|
1614
|
+
EErrId_NiceTransport2["send_failed"] = "send_failed";
|
|
1615
|
+
EErrId_NiceTransport2["invalid_action_response"] = "invalid_action_response";
|
|
1616
|
+
})(EErrId_NiceTransport ||= {});
|
|
1617
|
+
var err_nice_transport = err_nice_external_client.createChildDomain({
|
|
1618
|
+
domain: "err_nice_transport",
|
|
1619
|
+
schema: {
|
|
1620
|
+
["timeout" /* timeout */]: err2({
|
|
1621
|
+
message: ({ timeout }) => `ActionConnect transport timed out after ${timeout}ms.`
|
|
1622
|
+
}),
|
|
1623
|
+
["not_found" /* not_found */]: err2({
|
|
1624
|
+
message: ({ actionId }) => `No connected transport found for action "${actionId}".`
|
|
1625
|
+
}),
|
|
1626
|
+
["unsupported" /* unsupported */]: err2({
|
|
1627
|
+
message: ({ transportTypes }) => `${transportTypes.length} Transport(s) [${transportTypes.join(", ")}] found but returned "unsupported" status.`
|
|
1628
|
+
}),
|
|
1629
|
+
["initialization_failed" /* initialization_failed */]: err2({
|
|
1630
|
+
message: ({ actionId }) => `Transports found for action "${actionId}", but none are ready.`
|
|
1631
|
+
}),
|
|
1632
|
+
["send_failed" /* send_failed */]: err2({
|
|
1633
|
+
message: ({ actionId, httpStatusCode, message }) => `Failed to send action "${actionId}" [${httpStatusCode ?? "Unknown status"}]: ${message ?? "Unknown error"}.`,
|
|
1634
|
+
httpStatusCode: ({ httpStatusCode }) => httpStatusCode ?? 500
|
|
1635
|
+
}),
|
|
1636
|
+
["invalid_action_response" /* invalid_action_response */]: err2({
|
|
1637
|
+
message: ({ actionId }) => `Invalid action response JSON structure for action "${actionId}"`
|
|
1638
|
+
})
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/Transport.types.ts
|
|
1643
|
+
var ETransportType;
|
|
1644
|
+
((ETransportType2) => {
|
|
1645
|
+
ETransportType2["ws"] = "ws";
|
|
1646
|
+
ETransportType2["http"] = "http";
|
|
1647
|
+
ETransportType2["custom"] = "custom";
|
|
1648
|
+
})(ETransportType ||= {});
|
|
1649
|
+
var ETransportStatus;
|
|
1650
|
+
((ETransportStatus2) => {
|
|
1651
|
+
ETransportStatus2["uninitialized"] = "uninitialized";
|
|
1652
|
+
ETransportStatus2["unsupported"] = "unsupported";
|
|
1653
|
+
ETransportStatus2["initializing"] = "initializing";
|
|
1654
|
+
ETransportStatus2["ready"] = "ready";
|
|
1655
|
+
ETransportStatus2["failed"] = "failed";
|
|
1656
|
+
})(ETransportStatus ||= {});
|
|
1657
|
+
|
|
1658
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/ConnectionTransportManager.ts
|
|
1659
|
+
class ConnectionTransportManager {
|
|
1660
|
+
_cache;
|
|
1661
|
+
_transports = [];
|
|
1662
|
+
constructor(_cache) {
|
|
1663
|
+
this._cache = _cache;
|
|
1664
|
+
}
|
|
1665
|
+
addTransport(transport) {
|
|
1666
|
+
this._transports.push(transport);
|
|
1667
|
+
}
|
|
1668
|
+
async getReadyTransport(routeActionParams) {
|
|
1669
|
+
const initializingWaiters = [];
|
|
1670
|
+
const unavailableTransports = [];
|
|
1671
|
+
const action = routeActionParams.action;
|
|
1672
|
+
for (const transport of this._transports) {
|
|
1673
|
+
const cacheKey = transport.getCacheKey(routeActionParams);
|
|
1674
|
+
if (cacheKey != null) {
|
|
1675
|
+
const cached = this._cache.get(cacheKey);
|
|
1676
|
+
if (cached != null) {
|
|
1677
|
+
if (cached instanceof Promise) {
|
|
1678
|
+
initializingWaiters.push(cached);
|
|
1679
|
+
continue;
|
|
1680
|
+
}
|
|
1681
|
+
return { ...cached, transport };
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
const statusInfo = transport.getTransport(routeActionParams);
|
|
1685
|
+
if (statusInfo.status === "ready" /* ready */) {
|
|
1686
|
+
const readyData = statusInfo.readyData;
|
|
1687
|
+
if (cacheKey != null) {
|
|
1688
|
+
this._cache.set(cacheKey, { methods: readyData, transport });
|
|
1689
|
+
readyData.addOnDisconnectListener?.(() => this._cache.delete(cacheKey));
|
|
1690
|
+
}
|
|
1691
|
+
return { methods: readyData, transport };
|
|
1692
|
+
}
|
|
1693
|
+
if (statusInfo.status === "unsupported" /* unsupported */) {
|
|
1694
|
+
unavailableTransports.push(transport);
|
|
1695
|
+
continue;
|
|
1696
|
+
}
|
|
1697
|
+
if (statusInfo.status === "initializing" /* initializing */) {
|
|
1698
|
+
const promise = statusInfo.initializationPromise.then((info) => {
|
|
1699
|
+
if (info.status === "failed" /* failed */) {
|
|
1700
|
+
throw info.error;
|
|
1701
|
+
}
|
|
1702
|
+
if (info.status === "unsupported" /* unsupported */) {
|
|
1703
|
+
throw err_nice_transport.fromId("unsupported" /* unsupported */, {
|
|
1704
|
+
transportTypes: [transport.type]
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
const readyData = info.readyData;
|
|
1708
|
+
if (cacheKey != null) {
|
|
1709
|
+
this._cache.set(cacheKey, { methods: readyData, transport });
|
|
1710
|
+
readyData.addOnDisconnectListener?.(() => this._cache.delete(cacheKey));
|
|
1711
|
+
}
|
|
1712
|
+
return { methods: readyData, transport };
|
|
1713
|
+
}).catch((e) => {
|
|
1714
|
+
if (cacheKey != null)
|
|
1715
|
+
this._cache.delete(cacheKey);
|
|
1716
|
+
throw e;
|
|
1717
|
+
});
|
|
1718
|
+
if (cacheKey != null) {
|
|
1719
|
+
this._cache.set(cacheKey, promise);
|
|
1720
|
+
}
|
|
1721
|
+
initializingWaiters.push(promise);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
if (initializingWaiters.length === 0) {
|
|
1725
|
+
if (unavailableTransports.length > 0) {
|
|
1726
|
+
throw err_nice_transport.fromId("unsupported" /* unsupported */, {
|
|
1727
|
+
transportTypes: unavailableTransports.map((t) => t.type)
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
throw err_nice_transport.fromId("not_found" /* not_found */, {
|
|
1731
|
+
actionId: action.id
|
|
1732
|
+
});
|
|
1733
|
+
}
|
|
1734
|
+
try {
|
|
1735
|
+
return await Promise.any(initializingWaiters).then();
|
|
1736
|
+
} catch (e) {
|
|
1737
|
+
throw err_nice_transport.fromId("initialization_failed" /* initialization_failed */, {
|
|
1738
|
+
actionId: action.id
|
|
1739
|
+
}).withOriginError(e);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/helpers/addTransportStatusMetadata.ts
|
|
1745
|
+
function addTransportStatusMetadata(transportStatus) {
|
|
1746
|
+
if (transportStatus.status === "ready" /* ready */) {
|
|
1747
|
+
return {
|
|
1748
|
+
status: "ready" /* ready */,
|
|
1749
|
+
readyData: transportStatus.readyData
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
if (transportStatus.status === "initializing" /* initializing */) {
|
|
1753
|
+
return {
|
|
1754
|
+
status: "initializing" /* initializing */,
|
|
1755
|
+
initializationPromise: transportStatus.initializationPromise,
|
|
1756
|
+
timeStarted: Date.now()
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
if (transportStatus.status === "failed" /* failed */) {
|
|
1760
|
+
return {
|
|
1761
|
+
status: "failed" /* failed */,
|
|
1762
|
+
error: transportStatus.error,
|
|
1763
|
+
timeFailed: Date.now()
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
if (transportStatus.status === "unsupported" /* unsupported */) {
|
|
1767
|
+
return {
|
|
1768
|
+
status: "unsupported" /* unsupported */
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
return {
|
|
1772
|
+
status: "uninitialized" /* uninitialized */
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/Transport.ts
|
|
1777
|
+
var transportOrd = 0;
|
|
1778
|
+
|
|
1779
|
+
class Transport {
|
|
1780
|
+
def;
|
|
1781
|
+
transOrd = transportOrd++;
|
|
1782
|
+
type;
|
|
1783
|
+
initialized;
|
|
1784
|
+
constructor(def) {
|
|
1785
|
+
this.def = def;
|
|
1786
|
+
this.type = def.type;
|
|
1787
|
+
this.initialized = def.initialize();
|
|
1788
|
+
}
|
|
1789
|
+
_getCacheKey(input) {
|
|
1790
|
+
const parts = this.initialized.getTransportCacheKey?.(input);
|
|
1791
|
+
if (parts == null)
|
|
1792
|
+
return null;
|
|
1793
|
+
return parts.join("\x00");
|
|
1794
|
+
}
|
|
1795
|
+
getCacheKey(input) {
|
|
1796
|
+
const inner = this._getCacheKey(input);
|
|
1797
|
+
if (inner == null)
|
|
1798
|
+
return null;
|
|
1799
|
+
return `${this.transOrd}:${inner}`;
|
|
1800
|
+
}
|
|
1801
|
+
getTransport(input) {
|
|
1802
|
+
return this._processTransportStatus(input);
|
|
1803
|
+
}
|
|
1804
|
+
_processTransportStatus(input) {
|
|
1805
|
+
const transportStatusInfo = addTransportStatusMetadata(this.initialized.getTransport(input));
|
|
1806
|
+
if (transportStatusInfo.status !== "initializing" /* initializing */ && transportStatusInfo.status !== "ready" /* ready */) {
|
|
1807
|
+
return transportStatusInfo;
|
|
1808
|
+
}
|
|
1809
|
+
if (transportStatusInfo.status === "initializing" /* initializing */) {
|
|
1810
|
+
const promiseForReadyData = transportStatusInfo.initializationPromise.then((result) => {
|
|
1811
|
+
if (result.status === "ready" /* ready */) {
|
|
1812
|
+
return {
|
|
1813
|
+
status: "ready" /* ready */,
|
|
1814
|
+
readyData: this._finalizeTransportMethods(result.readyData)
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
return result;
|
|
1818
|
+
});
|
|
1819
|
+
return {
|
|
1820
|
+
status: "initializing" /* initializing */,
|
|
1821
|
+
timeStarted: transportStatusInfo.timeStarted,
|
|
1822
|
+
initializationPromise: promiseForReadyData
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
return {
|
|
1826
|
+
status: "ready" /* ready */,
|
|
1827
|
+
readyData: this._finalizeTransportMethods(transportStatusInfo.readyData)
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/Custom/TransportCustom.ts
|
|
1833
|
+
class TransportCustom extends Transport {
|
|
1834
|
+
constructor(def) {
|
|
1835
|
+
super({
|
|
1836
|
+
...def,
|
|
1837
|
+
type: "custom" /* custom */
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
_finalizeTransportMethods(inputs) {
|
|
1841
|
+
return {
|
|
1842
|
+
sendActionData: inputs.sendActionData,
|
|
1843
|
+
sendReturnData: inputs.sendReturnData,
|
|
1844
|
+
updateRunConfig: inputs.updateRunConfig
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/Http/TransportHttp.ts
|
|
1850
|
+
import { castNiceError, NiceError } from "@nice-code/error";
|
|
1851
|
+
class TransportHttp extends Transport {
|
|
1852
|
+
constructor(def) {
|
|
1853
|
+
super({
|
|
1854
|
+
...def,
|
|
1855
|
+
type: "http" /* http */
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
_finalizeTransportMethods(methods) {
|
|
1859
|
+
return {
|
|
1860
|
+
sendActionData: (input) => {
|
|
1861
|
+
const request = methods.createRequest(input);
|
|
1862
|
+
this.send({ ...input, params: { request }, runningAction: input.runningAction }).catch((err3) => input.runningAction._abort(err3));
|
|
1863
|
+
},
|
|
1864
|
+
updateRunConfig: methods.updateRunConfig
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1867
|
+
async send(input) {
|
|
1868
|
+
const {
|
|
1869
|
+
action,
|
|
1870
|
+
runningAction,
|
|
1871
|
+
timeout,
|
|
1872
|
+
params: { request }
|
|
1873
|
+
} = input;
|
|
1874
|
+
const wire = action.toJsonObject();
|
|
1875
|
+
const ac = new AbortController;
|
|
1876
|
+
let timedOut = false;
|
|
1877
|
+
const timeoutId = setTimeout(() => {
|
|
1878
|
+
timedOut = true;
|
|
1879
|
+
ac.abort();
|
|
1880
|
+
}, timeout);
|
|
1881
|
+
const unsubscribe = input.runningAction.addUpdateListeners([
|
|
1882
|
+
(update) => {
|
|
1883
|
+
if (update.type === "finished" /* finished */) {
|
|
1884
|
+
clearTimeout(timeoutId);
|
|
1885
|
+
ac.abort();
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
]);
|
|
1889
|
+
try {
|
|
1890
|
+
const res = await fetch(request.url, {
|
|
1891
|
+
method: "POST",
|
|
1892
|
+
headers: { "Content-Type": "application/json", ...request.headers },
|
|
1893
|
+
body: request.body ?? JSON.stringify(wire),
|
|
1894
|
+
signal: ac.signal
|
|
1895
|
+
});
|
|
1896
|
+
if (!res.ok) {
|
|
1897
|
+
if (action.type === "request" /* request */) {
|
|
1898
|
+
try {
|
|
1899
|
+
const jsonData = await res.json();
|
|
1900
|
+
if (isActionPayload_Result_JsonObject(jsonData)) {
|
|
1901
|
+
runningAction._completeWithResult(action._domain.hydrateResultPayload(jsonData));
|
|
1902
|
+
} else {
|
|
1903
|
+
runningAction._completeWithResult(action.errorResult(castNiceError(jsonData)));
|
|
1904
|
+
}
|
|
1905
|
+
} catch (e) {
|
|
1906
|
+
throw err_nice_transport.fromId("send_failed" /* send_failed */, {
|
|
1907
|
+
actionState: action.type,
|
|
1908
|
+
actionId: action.id,
|
|
1909
|
+
httpStatusCode: res.status,
|
|
1910
|
+
message: e.message
|
|
1911
|
+
}).withOriginError(e);
|
|
1912
|
+
}
|
|
1913
|
+
} else {
|
|
1914
|
+
let text;
|
|
1915
|
+
try {
|
|
1916
|
+
text = await res.text();
|
|
1917
|
+
} catch (e) {
|
|
1918
|
+
console.warn(`Failed to read error response body for failed HTTP request in TransportHttp:`, e);
|
|
1919
|
+
}
|
|
1920
|
+
throw err_nice_transport.fromId("send_failed" /* send_failed */, {
|
|
1921
|
+
actionState: action.type,
|
|
1922
|
+
actionId: action.id,
|
|
1923
|
+
httpStatusCode: res.status,
|
|
1924
|
+
message: text ?? `HTTP error with status ${res.status}`
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
if (action.type === "request" /* request */) {
|
|
1930
|
+
const json = await res.json();
|
|
1931
|
+
if (!isActionPayload_Result_JsonObject(json)) {
|
|
1932
|
+
throw err_nice_transport.fromId("invalid_action_response" /* invalid_action_response */, {
|
|
1933
|
+
actionId: action.id
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
runningAction._completeWithResult(action._domain.hydrateResultPayload(json));
|
|
1937
|
+
}
|
|
1938
|
+
} catch (err3) {
|
|
1939
|
+
if (timedOut) {
|
|
1940
|
+
throw err_nice_transport.fromId("timeout" /* timeout */, { timeout });
|
|
1941
|
+
}
|
|
1942
|
+
if (err3 instanceof NiceError) {
|
|
1943
|
+
throw err3;
|
|
1944
|
+
}
|
|
1945
|
+
throw err_nice_transport.fromId("send_failed" /* send_failed */, {
|
|
1946
|
+
actionState: action.type,
|
|
1947
|
+
actionId: action.id,
|
|
1948
|
+
message: err3 instanceof Error ? err3.message : String(err3)
|
|
1949
|
+
}).withOriginError(err3 instanceof Error ? err3 : undefined);
|
|
1950
|
+
} finally {
|
|
1951
|
+
clearTimeout(timeoutId);
|
|
1952
|
+
unsubscribe();
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport_ws.ts
|
|
1958
|
+
import { err as err3 } from "@nice-code/error";
|
|
1959
|
+
var EErrId_NiceTransport_WebSocket;
|
|
1960
|
+
((EErrId_NiceTransport_WebSocket2) => {
|
|
1961
|
+
EErrId_NiceTransport_WebSocket2["ws_disconnected"] = "ws_disconnected";
|
|
1962
|
+
EErrId_NiceTransport_WebSocket2["ws_create_failed"] = "ws_create_failed";
|
|
1963
|
+
EErrId_NiceTransport_WebSocket2["ws_error"] = "ws_error";
|
|
1964
|
+
})(EErrId_NiceTransport_WebSocket ||= {});
|
|
1965
|
+
var err_nice_transport_ws = err_nice_transport.createChildDomain({
|
|
1966
|
+
domain: "ws_transport",
|
|
1967
|
+
schema: {
|
|
1968
|
+
["ws_disconnected" /* ws_disconnected */]: err3({
|
|
1969
|
+
message: () => `WebSocket transport disconnected.`
|
|
1970
|
+
}),
|
|
1971
|
+
["ws_create_failed" /* ws_create_failed */]: err3({
|
|
1972
|
+
message: ({ originalError }) => `Failed to create WebSocket transport.${originalError ? ` Original error: ${originalError.message}` : ""}`
|
|
1973
|
+
}),
|
|
1974
|
+
["ws_error" /* ws_error */]: err3({
|
|
1975
|
+
message: ({ originalError }) => `WebSocket transport error.${originalError ? ` Original error: ${originalError.message}` : ""}`
|
|
1976
|
+
})
|
|
1977
|
+
}
|
|
1978
|
+
});
|
|
1979
|
+
|
|
1980
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/helpers/createUnsetTransportResolvers.ts
|
|
1981
|
+
var createUnsetTransportResolvers = (type) => ({
|
|
1982
|
+
onIncomingActionDataJson: (json) => {
|
|
1983
|
+
console.warn(`Received incoming action JSON [${json.domain}:${json.id}] on Transport [${type}] but no incoming data listener has been set.`);
|
|
1984
|
+
}
|
|
1985
|
+
});
|
|
1986
|
+
|
|
1987
|
+
// src/ActionRuntime/Handler/ExternalClient/Transport/WebSocket/TransportWebSocket.ts
|
|
1988
|
+
class TransportWebSocket extends Transport {
|
|
1989
|
+
resolvers;
|
|
1990
|
+
_abortSet = new Set;
|
|
1991
|
+
constructor(def, resolvers) {
|
|
1992
|
+
super({ ...def, type: "ws" /* ws */ });
|
|
1993
|
+
this.resolvers = resolvers ?? createUnsetTransportResolvers("ws" /* ws */);
|
|
1994
|
+
}
|
|
1995
|
+
_getCacheKey(_input) {
|
|
1996
|
+
return this.initialized.getTransportCacheKey?.(_input).join("\x00") ?? "";
|
|
1997
|
+
}
|
|
1998
|
+
_processTransportStatus(input) {
|
|
1999
|
+
const transportStatusInfo = addTransportStatusMetadata(this.initialized.getTransport(input));
|
|
2000
|
+
if (transportStatusInfo.status !== "initializing" /* initializing */ && transportStatusInfo.status !== "ready" /* ready */) {
|
|
2001
|
+
return transportStatusInfo;
|
|
2002
|
+
}
|
|
2003
|
+
if (transportStatusInfo.status === "ready" /* ready */) {
|
|
2004
|
+
const ws = transportStatusInfo.readyData.ws;
|
|
2005
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
2006
|
+
const initialization = async () => {
|
|
2007
|
+
await new Promise((resolve, reject) => {
|
|
2008
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
2009
|
+
ws.addEventListener("error", (event) => reject(event), { once: true });
|
|
2010
|
+
ws.addEventListener("close", (event) => reject(new Error(`WebSocket closed before open: code=${event.code}`)), { once: true });
|
|
2011
|
+
});
|
|
2012
|
+
return {
|
|
2013
|
+
status: "ready" /* ready */,
|
|
2014
|
+
readyData: this._finalizeTransportMethods(transportStatusInfo.readyData)
|
|
2015
|
+
};
|
|
2016
|
+
};
|
|
2017
|
+
return {
|
|
2018
|
+
status: "initializing" /* initializing */,
|
|
2019
|
+
timeStarted: Date.now(),
|
|
2020
|
+
initializationPromise: initialization()
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
if (transportStatusInfo.status === "initializing" /* initializing */) {
|
|
2025
|
+
const promiseForReadyData = transportStatusInfo.initializationPromise.then(async (result) => {
|
|
2026
|
+
if (result.status === "ready" /* ready */) {
|
|
2027
|
+
const ws = result.readyData.ws;
|
|
2028
|
+
await new Promise((resolve, reject) => {
|
|
2029
|
+
ws.addEventListener("open", () => resolve(), { once: true });
|
|
2030
|
+
ws.addEventListener("error", (event) => reject(event), { once: true });
|
|
2031
|
+
ws.addEventListener("close", (event) => reject(new Error(`WebSocket closed before open: code=${event.code}`)), { once: true });
|
|
2032
|
+
});
|
|
2033
|
+
return {
|
|
2034
|
+
status: "ready" /* ready */,
|
|
2035
|
+
readyData: this._finalizeTransportMethods(result.readyData)
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
return result;
|
|
2039
|
+
});
|
|
2040
|
+
return {
|
|
2041
|
+
status: "initializing" /* initializing */,
|
|
2042
|
+
initializationPromise: promiseForReadyData,
|
|
2043
|
+
timeStarted: transportStatusInfo.timeStarted
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
return {
|
|
2047
|
+
status: "ready" /* ready */,
|
|
2048
|
+
readyData: this._finalizeTransportMethods(transportStatusInfo.readyData)
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
_finalizeTransportMethods(wsData) {
|
|
2052
|
+
const ws = wsData.ws;
|
|
2053
|
+
const disconnectListeners = [];
|
|
2054
|
+
const sendActionData = (inputs) => {
|
|
2055
|
+
const { action, runningAction, timeout } = inputs;
|
|
2056
|
+
if (action.type === "request" /* request */) {
|
|
2057
|
+
this._abortSet.add(runningAction);
|
|
2058
|
+
const timeoutId = setTimeout(() => {
|
|
2059
|
+
runningAction._abort(err_nice_transport.fromId("timeout" /* timeout */, { timeout }));
|
|
2060
|
+
}, timeout);
|
|
2061
|
+
runningAction.addUpdateListeners([
|
|
2062
|
+
(update) => {
|
|
2063
|
+
if (update.type === "finished" /* finished */) {
|
|
2064
|
+
clearTimeout(timeoutId);
|
|
2065
|
+
this._abortSet.delete(runningAction);
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
]);
|
|
2069
|
+
}
|
|
2070
|
+
ws.send(wsData.formatMessage?.outgoing(inputs) ?? JSON.stringify(inputs.action.toJsonObject()));
|
|
2071
|
+
};
|
|
2072
|
+
ws.addEventListener("message", (event) => {
|
|
2073
|
+
if (typeof event.data === "string") {
|
|
2074
|
+
const rawJson = wsData.formatMessage?.incoming?.(event.data) ?? this._parseActionMessage(event.data);
|
|
2075
|
+
if (rawJson != null && isActionPayload_Any_JsonObject(rawJson)) {
|
|
2076
|
+
this.resolvers.onIncomingActionDataJson(rawJson);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
});
|
|
2080
|
+
ws.addEventListener("close", (event) => {
|
|
2081
|
+
console.error("WebSocket closed:", event);
|
|
2082
|
+
for (const cb of disconnectListeners)
|
|
2083
|
+
cb();
|
|
2084
|
+
this._abortAll(err_nice_transport_ws.fromId("ws_disconnected" /* ws_disconnected */));
|
|
2085
|
+
});
|
|
2086
|
+
ws.addEventListener("error", (event) => {
|
|
2087
|
+
console.error("WebSocket error:", event);
|
|
2088
|
+
for (const cb of disconnectListeners)
|
|
2089
|
+
cb();
|
|
2090
|
+
this._abortAll(err_nice_transport_ws.fromId("ws_error" /* ws_error */, {
|
|
2091
|
+
originalError: event instanceof Error ? event : undefined
|
|
2092
|
+
}));
|
|
2093
|
+
});
|
|
2094
|
+
return {
|
|
2095
|
+
sendActionData,
|
|
2096
|
+
updateRunConfig: wsData.updateRunConfig,
|
|
2097
|
+
addOnDisconnectListener: (cb) => {
|
|
2098
|
+
disconnectListeners.push(cb);
|
|
2099
|
+
},
|
|
2100
|
+
sendReturnData: (payload) => {
|
|
2101
|
+
ws.send(JSON.stringify(payload.toJsonObject()));
|
|
2102
|
+
}
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
_parseActionMessage(message) {
|
|
2106
|
+
let json;
|
|
2107
|
+
try {
|
|
2108
|
+
json = JSON.parse(message);
|
|
2109
|
+
} catch {
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
return isActionPayload_Any_JsonObject(json) ? json : undefined;
|
|
2113
|
+
}
|
|
2114
|
+
_abortAll(error) {
|
|
2115
|
+
const snapshot = [...this._abortSet];
|
|
2116
|
+
for (const ra of snapshot) {
|
|
2117
|
+
ra._abort(error);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
// src/ActionRuntime/Handler/ExternalClient/ActionExternalClientHandler.ts
|
|
2123
|
+
class ActionExternalClientHandler extends ActionHandler {
|
|
2124
|
+
externalClient;
|
|
2125
|
+
handlerType = "external" /* external */;
|
|
2126
|
+
cuid;
|
|
2127
|
+
_defaultTimeout;
|
|
2128
|
+
_transportCache = new Map;
|
|
2129
|
+
transportManager = new ConnectionTransportManager(this._transportCache);
|
|
2130
|
+
_incomingActionDataListeners = [];
|
|
2131
|
+
actionRouter = new ActionRouter({
|
|
2132
|
+
contextType: "handler_route" /* handler_route */,
|
|
2133
|
+
handler: this
|
|
2134
|
+
});
|
|
2135
|
+
constructor({
|
|
2136
|
+
externalClientSpecifier,
|
|
2137
|
+
transports,
|
|
2138
|
+
defaultTimeout
|
|
2139
|
+
}) {
|
|
2140
|
+
super();
|
|
2141
|
+
this.externalClient = externalClientSpecifier;
|
|
2142
|
+
this.cuid = nanoid4();
|
|
2143
|
+
this._defaultTimeout = defaultTimeout ?? DEFAULT_TRANSPORT_TIMEOUT;
|
|
2144
|
+
for (const def of transports) {
|
|
2145
|
+
if (def.type === "ws" /* ws */) {
|
|
2146
|
+
this.transportManager.addTransport(new TransportWebSocket(def, {
|
|
2147
|
+
onIncomingActionDataJson: (json) => {
|
|
2148
|
+
for (const l of this._incomingActionDataListeners)
|
|
2149
|
+
l(json);
|
|
2150
|
+
}
|
|
2151
|
+
}));
|
|
2152
|
+
} else if (def.type === "http" /* http */) {
|
|
2153
|
+
this.transportManager.addTransport(new TransportHttp(def));
|
|
2154
|
+
} else if (def.type === "custom" /* custom */) {
|
|
2155
|
+
this.transportManager.addTransport(new TransportCustom(def));
|
|
2156
|
+
} else {
|
|
2157
|
+
throw err_nice_action.fromId("not_implemented" /* not_implemented */, {
|
|
2158
|
+
label: `transport type "${def.type}"`
|
|
2159
|
+
});
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
forDomain(domain) {
|
|
2164
|
+
this.actionRouter.forDomain(domain, true);
|
|
2165
|
+
return this;
|
|
2166
|
+
}
|
|
2167
|
+
forAction(action) {
|
|
2168
|
+
this.actionRouter.forAction(action, true);
|
|
2169
|
+
return this;
|
|
2170
|
+
}
|
|
2171
|
+
forActionIds(domain, ids) {
|
|
2172
|
+
this.actionRouter.forActionIds(domain, ids, true);
|
|
2173
|
+
return this;
|
|
2174
|
+
}
|
|
2175
|
+
_setIncomingActionDataListener(listener) {
|
|
2176
|
+
this._incomingActionDataListeners.push(listener);
|
|
2177
|
+
}
|
|
2178
|
+
async handleActionRequest(action, config) {
|
|
2179
|
+
const localRuntime = config?.targetLocalRuntime ?? ActionRuntime.getDefault();
|
|
2180
|
+
const localClient = localRuntime.coordinate;
|
|
2181
|
+
const incomingTimeout = config?.timeout ?? this._defaultTimeout;
|
|
2182
|
+
const { methods, transport } = await this.transportManager.getReadyTransport({
|
|
2183
|
+
action,
|
|
2184
|
+
localClient,
|
|
2185
|
+
externalClient: this.externalClient
|
|
2186
|
+
});
|
|
2187
|
+
action.context.addRouteItem({
|
|
2188
|
+
runtime: localClient,
|
|
2189
|
+
handler: this.toHandlerRouteItem(transport),
|
|
2190
|
+
time: Date.now()
|
|
2191
|
+
});
|
|
2192
|
+
const runningAction = new RunningAction({ context: action.context, request: action });
|
|
2193
|
+
localRuntime.registerRunningAction(runningAction);
|
|
2194
|
+
const routeActionParams = {
|
|
2195
|
+
action,
|
|
2196
|
+
runningAction,
|
|
2197
|
+
localClient,
|
|
2198
|
+
externalClient: this.externalClient,
|
|
2199
|
+
timeout: incomingTimeout
|
|
2200
|
+
};
|
|
2201
|
+
if (action.type === "request" /* request */ && methods.updateRunConfig != null) {
|
|
2202
|
+
const runConfig = methods.updateRunConfig(routeActionParams);
|
|
2203
|
+
routeActionParams.timeout = runConfig?.timeout ?? incomingTimeout;
|
|
2204
|
+
}
|
|
2205
|
+
try {
|
|
2206
|
+
methods.sendActionData(routeActionParams);
|
|
2207
|
+
} catch (err4) {
|
|
2208
|
+
runningAction._abort(err4);
|
|
2209
|
+
}
|
|
2210
|
+
return runningAction;
|
|
2211
|
+
}
|
|
2212
|
+
async sendReturnPayload(payload, config) {
|
|
2213
|
+
const localClient = config.targetLocalRuntime.coordinate;
|
|
2214
|
+
try {
|
|
2215
|
+
const { methods } = await this.transportManager.getReadyTransport({
|
|
2216
|
+
action: payload,
|
|
2217
|
+
localClient,
|
|
2218
|
+
externalClient: this.externalClient
|
|
2219
|
+
});
|
|
2220
|
+
if (methods.sendReturnData == null)
|
|
2221
|
+
return false;
|
|
2222
|
+
methods.sendReturnData(payload);
|
|
2223
|
+
return true;
|
|
2224
|
+
} catch {
|
|
2225
|
+
return false;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
toJsonObject() {
|
|
2229
|
+
return {
|
|
2230
|
+
type: this.handlerType,
|
|
2231
|
+
client: this.externalClient
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
toHandlerRouteItem(transport) {
|
|
2235
|
+
return {
|
|
2236
|
+
type: this.handlerType,
|
|
2237
|
+
client: this.externalClient,
|
|
2238
|
+
transOrd: transport.transOrd,
|
|
2239
|
+
transType: transport.type
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
var createExternalClientHandler = (config) => {
|
|
2244
|
+
return new ActionExternalClientHandler(config);
|
|
2245
|
+
};
|
|
45
2246
|
export {
|
|
2247
|
+
isActionPayload_Result_JsonObject,
|
|
2248
|
+
isActionPayload_Request_JsonObject,
|
|
46
2249
|
isActionPayload_Any_JsonObject,
|
|
2250
|
+
err_nice_transport_ws,
|
|
2251
|
+
err_nice_transport,
|
|
2252
|
+
err_nice_external_client,
|
|
47
2253
|
err_nice_action,
|
|
48
2254
|
createLocalHandler,
|
|
49
2255
|
createExternalClientHandler,
|
|
50
2256
|
createActionRootDomain,
|
|
51
2257
|
actionSchema,
|
|
2258
|
+
TransportWebSocket,
|
|
2259
|
+
TransportHttp,
|
|
2260
|
+
Transport,
|
|
52
2261
|
RuntimeCoordinate,
|
|
53
2262
|
RunningAction,
|
|
2263
|
+
ETransportType,
|
|
2264
|
+
ETransportStatus,
|
|
54
2265
|
ERunningActionUpdateType,
|
|
55
2266
|
ERunningActionState,
|
|
56
2267
|
ERunningActionFinishedType,
|
|
2268
|
+
EErrId_NiceTransport_WebSocket,
|
|
2269
|
+
EErrId_NiceTransport,
|
|
57
2270
|
EErrId_NiceAction,
|
|
2271
|
+
EActionProgressType,
|
|
2272
|
+
EActionPayloadType,
|
|
58
2273
|
ActionSchema,
|
|
59
2274
|
ActionRuntime,
|
|
60
2275
|
ActionRootDomain,
|