@nice-code/action 0.2.10 → 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/build/index.js CHANGED
@@ -1,60 +1,2275 @@
1
- // src/index.ts
2
- import { ActionCore } from "./ActionDefinition/Action/Core/ActionCore";
1
+ // src/ActionDefinition/Action/Core/ActionCore.ts
2
+ import { nanoid } from "nanoid";
3
3
 
4
- export * from "./ActionDefinition/Action/Core/ActionCore.types";
5
- export * from "./ActionDefinition/Action/Payload/ActionPayload.types";
6
- import { RunningAction } from "./ActionDefinition/Action/RunningAction";
7
- import {
8
- ERunningActionFinishedType,
9
- ERunningActionState,
10
- ERunningActionUpdateType
11
- } from "./ActionDefinition/Action/RunningAction.types";
12
- import { ActionDomain } from "./ActionDefinition/Domain/ActionDomain";
13
- import { ActionRootDomain } from "./ActionDefinition/Domain/ActionRootDomain";
14
- import { createActionRootDomain } from "./ActionDefinition/Domain/helpers/createRootActionDomain";
15
- import {
16
- ActionSchema,
17
- actionSchema
18
- } from "./ActionDefinition/Schema/ActionSchema";
19
- import { ActionRuntime } from "./ActionRuntime/ActionRuntime";
20
- import {
21
- ActionExternalClientHandler,
22
- createExternalClientHandler
23
- } from "./ActionRuntime/Handler/ExternalClient/ActionExternalClientHandler";
24
-
25
- export * from "./ActionRuntime/Handler/ExternalClient/err_nice_external_client";
26
- export * from "./ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport";
27
- export * from "./ActionRuntime/Handler/ExternalClient/Transport/err_nice_transport_ws";
28
- export * from "./ActionRuntime/Handler/ExternalClient/Transport/Http/TransportHttp";
29
- export * from "./ActionRuntime/Handler/ExternalClient/Transport/Transport";
30
- export * from "./ActionRuntime/Handler/ExternalClient/Transport/Transport.types";
31
- export * from "./ActionRuntime/Handler/ExternalClient/Transport/WebSocket/TransportWebSocket";
32
- import {
33
- ActionLocalHandler,
34
- createLocalHandler
35
- } from "./ActionRuntime/Handler/Local/ActionLocalHandler";
36
- import {
37
- RuntimeCoordinate
38
- } from "./ActionRuntime/RuntimeCoordinate";
39
- import { EErrId_NiceAction, err_nice_action } from "./errors/err_nice_action";
40
- import { isActionPayload_Any_JsonObject } from "./utils/isActionPayload_Any_JsonObject";
41
-
42
- export * from "./utils/isActionPayload_Request_JsonObject";
43
- export * from "./utils/isActionPayload_Result_JsonObject";
44
- export * from "./utils/typescript/MaybePromise";
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,