@pluv/io 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +25 -0
- package/dist/index.d.ts +29 -24
- package/dist/index.js +200 -179
- package/dist/index.mjs +200 -179
- package/package.json +9 -9
- package/src/IORoom.ts +243 -199
- package/src/PluvIO.ts +169 -59
- package/src/types.ts +38 -7
package/src/IORoom.ts
CHANGED
|
@@ -15,16 +15,20 @@ import type {
|
|
|
15
15
|
JsonObject,
|
|
16
16
|
Maybe,
|
|
17
17
|
MaybePromise,
|
|
18
|
+
Spread,
|
|
18
19
|
} from "@pluv/types";
|
|
19
20
|
import colors from "kleur";
|
|
20
21
|
import type { AbstractPlatform, InferWebSocketType } from "./AbstractPlatform";
|
|
21
22
|
import { authorize } from "./authorize";
|
|
22
23
|
import type {
|
|
24
|
+
EventResolver,
|
|
23
25
|
EventResolverContext,
|
|
26
|
+
EventResolverObject,
|
|
24
27
|
InferEventConfig,
|
|
25
28
|
SendMessageOptions,
|
|
26
29
|
WebSocketSession,
|
|
27
30
|
} from "./types";
|
|
31
|
+
import { AbstractMessageEvent } from "./AbstractWebSocket";
|
|
28
32
|
|
|
29
33
|
const PING_TIMEOUT_MS = 30_000;
|
|
30
34
|
|
|
@@ -46,12 +50,20 @@ export type IORoomConfig<
|
|
|
46
50
|
TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize,
|
|
47
51
|
TContext extends JsonObject = {},
|
|
48
52
|
TInput extends EventRecord<string, any> = {},
|
|
49
|
-
|
|
53
|
+
TOutputBroadcast extends EventRecord<string, any> = {},
|
|
54
|
+
TOutputSelf extends EventRecord<string, any> = {},
|
|
55
|
+
TOutputSync extends EventRecord<string, any> = {}
|
|
50
56
|
> = Partial<IORoomListeners> & {
|
|
51
57
|
authorize?: TAuthorize;
|
|
52
58
|
context: TContext;
|
|
53
59
|
debug: boolean;
|
|
54
|
-
events: InferEventConfig<
|
|
60
|
+
events: InferEventConfig<
|
|
61
|
+
TContext,
|
|
62
|
+
TInput,
|
|
63
|
+
TOutputBroadcast,
|
|
64
|
+
TOutputSelf,
|
|
65
|
+
TOutputSync
|
|
66
|
+
>;
|
|
55
67
|
initialStorage?: () => MaybePromise<Maybe<string>>;
|
|
56
68
|
platform: TPlatform;
|
|
57
69
|
};
|
|
@@ -70,8 +82,11 @@ export class IORoom<
|
|
|
70
82
|
TAuthorize extends IOAuthorize<any, any> = BaseIOAuthorize,
|
|
71
83
|
TContext extends JsonObject = {},
|
|
72
84
|
TInput extends EventRecord<string, any> = {},
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
TOutputBroadcast extends EventRecord<string, any> = {},
|
|
86
|
+
TOutputSelf extends EventRecord<string, any> = {},
|
|
87
|
+
TOutputSync extends EventRecord<string, any> = {}
|
|
88
|
+
> implements
|
|
89
|
+
IOLike<TAuthorize, TInput, TOutputBroadcast, TOutputSelf, TOutputSync>
|
|
75
90
|
{
|
|
76
91
|
private readonly _context: TContext;
|
|
77
92
|
private readonly _debug: boolean;
|
|
@@ -84,13 +99,27 @@ export class IORoom<
|
|
|
84
99
|
private _uninitialize: (() => Promise<void>) | null = null;
|
|
85
100
|
|
|
86
101
|
readonly _authorize: TAuthorize | null = null;
|
|
87
|
-
readonly _events: InferEventConfig<
|
|
102
|
+
readonly _events: InferEventConfig<
|
|
103
|
+
TContext,
|
|
104
|
+
TInput,
|
|
105
|
+
TOutputBroadcast,
|
|
106
|
+
TOutputSelf,
|
|
107
|
+
TOutputSync
|
|
108
|
+
>;
|
|
88
109
|
|
|
89
110
|
readonly id: string;
|
|
90
111
|
|
|
91
112
|
constructor(
|
|
92
113
|
id: string,
|
|
93
|
-
config: IORoomConfig<
|
|
114
|
+
config: IORoomConfig<
|
|
115
|
+
TPlatform,
|
|
116
|
+
TAuthorize,
|
|
117
|
+
TContext,
|
|
118
|
+
TInput,
|
|
119
|
+
TOutputBroadcast,
|
|
120
|
+
TOutputSelf,
|
|
121
|
+
TOutputSync
|
|
122
|
+
>
|
|
94
123
|
) {
|
|
95
124
|
const {
|
|
96
125
|
authorize,
|
|
@@ -110,7 +139,9 @@ export class IORoom<
|
|
|
110
139
|
this.id = id;
|
|
111
140
|
|
|
112
141
|
this._listeners = {
|
|
113
|
-
onDestroy: (encodedState) =>
|
|
142
|
+
onDestroy: (encodedState) => {
|
|
143
|
+
onDestroy?.(encodedState);
|
|
144
|
+
},
|
|
114
145
|
};
|
|
115
146
|
|
|
116
147
|
if (authorize) this._authorize = authorize;
|
|
@@ -208,120 +239,14 @@ export class IORoom<
|
|
|
208
239
|
user ?? {}
|
|
209
240
|
);
|
|
210
241
|
|
|
211
|
-
this.
|
|
212
|
-
this.
|
|
213
|
-
this._emitUserJoined(session);
|
|
214
|
-
|
|
215
|
-
const context: EventResolverContext<TContext> = {
|
|
216
|
-
context: this._context,
|
|
217
|
-
doc: this._doc,
|
|
218
|
-
room: this.id,
|
|
219
|
-
session,
|
|
220
|
-
sessions: this._sessions,
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
pluvWs.addEventListener("message", (event) => {
|
|
224
|
-
if (!this._uninitialize) return;
|
|
225
|
-
|
|
226
|
-
if (session.quit) {
|
|
227
|
-
session.webSocket.close(1011, "WebSocket broken.");
|
|
228
|
-
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const message = this._parseMessage(event);
|
|
233
|
-
|
|
234
|
-
if (!message) return;
|
|
235
|
-
|
|
236
|
-
const eventConfig = this._getEventConfig(message);
|
|
237
|
-
|
|
238
|
-
if (!eventConfig) return;
|
|
239
|
-
|
|
240
|
-
this._resolveMessage(message, context).then((output) => {
|
|
241
|
-
if (!output) return;
|
|
242
|
-
|
|
243
|
-
const eventType = eventConfig.options?.type ?? "broadcast";
|
|
242
|
+
const onClose = this._onClose(session, uninitializeWs).bind(this);
|
|
243
|
+
const onMessage = this._onMessage(session).bind(this);
|
|
244
244
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
this._sendSelfMessage({ data, type }, session);
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
case "sync": {
|
|
254
|
-
this._platform.pubSub.publish(this.id, {
|
|
255
|
-
connectionId: session.id,
|
|
256
|
-
options: eventConfig.options,
|
|
257
|
-
room: this.id,
|
|
258
|
-
user: session.user,
|
|
259
|
-
...message,
|
|
260
|
-
});
|
|
245
|
+
pluvWs.addEventListener("close", onClose);
|
|
246
|
+
pluvWs.addEventListener("error", onClose);
|
|
247
|
+
pluvWs.addEventListener("message", onMessage);
|
|
261
248
|
|
|
262
|
-
|
|
263
|
-
this._sendSelfMessage({ data, type }, session);
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
case "broadcast":
|
|
269
|
-
default: {
|
|
270
|
-
Object.entries(output).forEach(([type, data]: any) => {
|
|
271
|
-
this._broadcast({
|
|
272
|
-
message: { data, type },
|
|
273
|
-
senderId: session.id,
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
const closeHandler = () => {
|
|
282
|
-
if (!this._uninitialize) return;
|
|
283
|
-
|
|
284
|
-
session.quit = true;
|
|
285
|
-
|
|
286
|
-
this._logDebug(
|
|
287
|
-
`${colors.blue(
|
|
288
|
-
`(Unregistering connection for room ${this.id}:`
|
|
289
|
-
)} ${sessionId}`
|
|
290
|
-
);
|
|
291
|
-
this._sessions.delete(session.id);
|
|
292
|
-
|
|
293
|
-
this._platform.persistance
|
|
294
|
-
.deleteUser(this.id, session.id)
|
|
295
|
-
.finally(() => {
|
|
296
|
-
this._broadcast({
|
|
297
|
-
message: {
|
|
298
|
-
type: "$EXIT",
|
|
299
|
-
data: { sessionId: session.id },
|
|
300
|
-
},
|
|
301
|
-
senderId: session.id,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
uninitializeWs();
|
|
305
|
-
|
|
306
|
-
const size = this.getSize();
|
|
307
|
-
|
|
308
|
-
this._logDebug(
|
|
309
|
-
`${colors.blue(
|
|
310
|
-
`Unregistered connection for room ${this.id}:`
|
|
311
|
-
)} ${sessionId}`
|
|
312
|
-
);
|
|
313
|
-
this._logDebug(
|
|
314
|
-
`${colors.blue(`Room ${this.id} size:`)} ${size}`
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
if (size) return;
|
|
318
|
-
|
|
319
|
-
this._uninitialize?.();
|
|
320
|
-
});
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
pluvWs.addEventListener("close", closeHandler);
|
|
324
|
-
pluvWs.addEventListener("error", closeHandler);
|
|
249
|
+
this._emitRegistered(session);
|
|
325
250
|
|
|
326
251
|
this._logDebug(
|
|
327
252
|
`${colors.blue(
|
|
@@ -382,42 +307,6 @@ export class IORoom<
|
|
|
382
307
|
);
|
|
383
308
|
}
|
|
384
309
|
|
|
385
|
-
private _emitStorageReceived(session: WebSocketSession): void {
|
|
386
|
-
this._platform.persistance
|
|
387
|
-
.getStorageState(this.id)
|
|
388
|
-
.then(async (_state) => {
|
|
389
|
-
const state =
|
|
390
|
-
_state ??
|
|
391
|
-
(await this._initialStorage?.()) ??
|
|
392
|
-
this._doc.encodeStateAsUpdate();
|
|
393
|
-
|
|
394
|
-
this._sendSelfMessage(
|
|
395
|
-
{
|
|
396
|
-
type: "$STORAGE_RECEIVED",
|
|
397
|
-
data: { state },
|
|
398
|
-
},
|
|
399
|
-
session
|
|
400
|
-
);
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private _emitUserJoined(session: WebSocketSession): void {
|
|
405
|
-
const user = session.user as any;
|
|
406
|
-
|
|
407
|
-
if (!user) return;
|
|
408
|
-
|
|
409
|
-
this._broadcast({
|
|
410
|
-
message: {
|
|
411
|
-
type: "$USER_JOINED",
|
|
412
|
-
data: {
|
|
413
|
-
connectionId: session.id,
|
|
414
|
-
user,
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
senderId: session.id,
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
|
|
421
310
|
private async _getAuthorizedUser(
|
|
422
311
|
token: string | undefined
|
|
423
312
|
): Promise<InferIOAuthorizeUser<InferIOAuthorize<this>> | null> {
|
|
@@ -459,10 +348,66 @@ export class IORoom<
|
|
|
459
348
|
|
|
460
349
|
private _getEventConfig(
|
|
461
350
|
message: EventMessage<string, any>
|
|
462
|
-
):
|
|
351
|
+
):
|
|
352
|
+
| InferEventConfig<
|
|
353
|
+
TContext,
|
|
354
|
+
TInput,
|
|
355
|
+
TOutputBroadcast,
|
|
356
|
+
TOutputSelf,
|
|
357
|
+
TOutputSync
|
|
358
|
+
>[keyof TInput]
|
|
359
|
+
| null {
|
|
463
360
|
return this._events[message.type as keyof TInput] ?? null;
|
|
464
361
|
}
|
|
465
362
|
|
|
363
|
+
private _getEventInputs(
|
|
364
|
+
message: EventMessage<string, any>
|
|
365
|
+
): TInput[string] {
|
|
366
|
+
const eventConfig = this._getEventConfig(message);
|
|
367
|
+
|
|
368
|
+
if (!eventConfig) return message.data;
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* !HACK
|
|
372
|
+
* @description If the config doesn't specify validation, we
|
|
373
|
+
* assume no input is to be expected, but pass through all values
|
|
374
|
+
* regardless. Leave this up to the implementer of the event.
|
|
375
|
+
* @author leedavidcs
|
|
376
|
+
* @date September 25, 2022
|
|
377
|
+
*/
|
|
378
|
+
return eventConfig.input
|
|
379
|
+
? (eventConfig.input.parse(message.data) as TInput[string])
|
|
380
|
+
: message.data;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
private _getEventResolverObject(
|
|
384
|
+
message: EventMessage<string, any>
|
|
385
|
+
): EventResolverObject<
|
|
386
|
+
TContext,
|
|
387
|
+
TInput[string],
|
|
388
|
+
TOutputBroadcast,
|
|
389
|
+
TOutputSelf,
|
|
390
|
+
TOutputSync
|
|
391
|
+
> {
|
|
392
|
+
const eventConfig = this._getEventConfig(message);
|
|
393
|
+
|
|
394
|
+
if (!eventConfig) return {};
|
|
395
|
+
|
|
396
|
+
const resolver:
|
|
397
|
+
| EventResolver<TContext, TInput[string], TOutputBroadcast>
|
|
398
|
+
| EventResolverObject<
|
|
399
|
+
TContext,
|
|
400
|
+
TInput[string],
|
|
401
|
+
TOutputBroadcast,
|
|
402
|
+
TOutputSelf,
|
|
403
|
+
TOutputSync
|
|
404
|
+
> = eventConfig.resolver;
|
|
405
|
+
|
|
406
|
+
return typeof resolver === "function"
|
|
407
|
+
? { broadcast: resolver }
|
|
408
|
+
: { ...resolver };
|
|
409
|
+
}
|
|
410
|
+
|
|
466
411
|
private async _initialize(): Promise<void> {
|
|
467
412
|
this._logDebug(`${colors.blue(`Initializing room ${this.id}:`)}`);
|
|
468
413
|
|
|
@@ -493,6 +438,8 @@ export class IORoom<
|
|
|
493
438
|
this._doc = doc();
|
|
494
439
|
|
|
495
440
|
this._listeners.onDestroy(encodedState);
|
|
441
|
+
|
|
442
|
+
this._uninitialize = null;
|
|
496
443
|
};
|
|
497
444
|
}
|
|
498
445
|
|
|
@@ -500,6 +447,130 @@ export class IORoom<
|
|
|
500
447
|
this._debug && console.log(...data);
|
|
501
448
|
}
|
|
502
449
|
|
|
450
|
+
private _onClose(
|
|
451
|
+
session: WebSocketSession,
|
|
452
|
+
callback?: () => void
|
|
453
|
+
): () => void {
|
|
454
|
+
return (): void => {
|
|
455
|
+
if (!this._uninitialize) return;
|
|
456
|
+
|
|
457
|
+
session.quit = true;
|
|
458
|
+
|
|
459
|
+
this._logDebug(
|
|
460
|
+
`${colors.blue(
|
|
461
|
+
`(Unregistering connection for room ${this.id}:`
|
|
462
|
+
)} ${session.id}`
|
|
463
|
+
);
|
|
464
|
+
this._sessions.delete(session.id);
|
|
465
|
+
|
|
466
|
+
this._platform.persistance
|
|
467
|
+
.deleteUser(this.id, session.id)
|
|
468
|
+
.finally(() => {
|
|
469
|
+
this._broadcast({
|
|
470
|
+
message: {
|
|
471
|
+
type: "$EXIT",
|
|
472
|
+
data: { sessionId: session.id },
|
|
473
|
+
},
|
|
474
|
+
senderId: session.id,
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
callback?.();
|
|
478
|
+
|
|
479
|
+
const size = this.getSize();
|
|
480
|
+
|
|
481
|
+
this._logDebug(
|
|
482
|
+
`${colors.blue(
|
|
483
|
+
`Unregistered connection for room ${this.id}:`
|
|
484
|
+
)} ${session.id}`
|
|
485
|
+
);
|
|
486
|
+
this._logDebug(
|
|
487
|
+
`${colors.blue(`Room ${this.id} size:`)} ${size}`
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
if (size) return;
|
|
491
|
+
|
|
492
|
+
this._uninitialize?.();
|
|
493
|
+
});
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
private _onMessage(
|
|
498
|
+
session: WebSocketSession
|
|
499
|
+
): (event: AbstractMessageEvent) => void {
|
|
500
|
+
return (event: AbstractMessageEvent): void => {
|
|
501
|
+
const context: EventResolverContext<TContext> = {
|
|
502
|
+
context: this._context,
|
|
503
|
+
doc: this._doc,
|
|
504
|
+
room: this.id,
|
|
505
|
+
session,
|
|
506
|
+
sessions: this._sessions,
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
if (!this._uninitialize) return;
|
|
510
|
+
|
|
511
|
+
if (session.quit) {
|
|
512
|
+
session.webSocket.close(1011, "WebSocket broken.");
|
|
513
|
+
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const message = this._parseMessage(event);
|
|
518
|
+
|
|
519
|
+
if (!message) return;
|
|
520
|
+
|
|
521
|
+
const resolver = this._getEventResolverObject(message);
|
|
522
|
+
|
|
523
|
+
let inputs: TInput[string];
|
|
524
|
+
|
|
525
|
+
try {
|
|
526
|
+
inputs = this._getEventInputs(message);
|
|
527
|
+
} catch (error) {
|
|
528
|
+
session?.webSocket.handleError({
|
|
529
|
+
error,
|
|
530
|
+
message: "Invalid input",
|
|
531
|
+
session,
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
Promise.all([
|
|
538
|
+
resolver.broadcast?.(inputs, context),
|
|
539
|
+
resolver.self?.(inputs, context),
|
|
540
|
+
resolver.sync?.(inputs, context),
|
|
541
|
+
]).then(([broadcast, self, sync]) => {
|
|
542
|
+
if (broadcast) {
|
|
543
|
+
Object.entries(broadcast).forEach(([type, data]: any) => {
|
|
544
|
+
this._broadcast({
|
|
545
|
+
message: { data, type },
|
|
546
|
+
senderId: session.id,
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (self) {
|
|
552
|
+
Object.entries(self).forEach(([type, data]) => {
|
|
553
|
+
this._sendSelfMessage({ data, type }, session);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (sync) {
|
|
558
|
+
this._platform.pubSub.publish(this.id, {
|
|
559
|
+
connectionId: session.id,
|
|
560
|
+
options: { type: "sync" },
|
|
561
|
+
room: this.id,
|
|
562
|
+
user: session.user,
|
|
563
|
+
...message,
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
Object.entries(sync).forEach(([type, data]) => {
|
|
567
|
+
this._sendSelfMessage({ data, type }, session);
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
503
574
|
private _parseMessage(message: {
|
|
504
575
|
data: string | ArrayBuffer;
|
|
505
576
|
}): EventMessage<string, any> | null {
|
|
@@ -516,47 +587,6 @@ export class IORoom<
|
|
|
516
587
|
}
|
|
517
588
|
}
|
|
518
589
|
|
|
519
|
-
private async _resolveMessage(
|
|
520
|
-
message: EventMessage<string, any>,
|
|
521
|
-
context: EventResolverContext<TContext>
|
|
522
|
-
): Promise<TOutput | null> {
|
|
523
|
-
const { session } = context;
|
|
524
|
-
|
|
525
|
-
const eventConfig = this._getEventConfig(message);
|
|
526
|
-
|
|
527
|
-
if (!eventConfig) return null;
|
|
528
|
-
|
|
529
|
-
let input: TInput[string];
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* !HACK
|
|
533
|
-
* @description If the config doesn't specify validation, we
|
|
534
|
-
* assume no input is to be expected, but pass through all values
|
|
535
|
-
* regardless. Leave this up to the implementer of the event.
|
|
536
|
-
* @author leedavidcs
|
|
537
|
-
* @date September 25, 2022
|
|
538
|
-
*/
|
|
539
|
-
try {
|
|
540
|
-
input = eventConfig.input
|
|
541
|
-
? (eventConfig.input.parse(message.data) as TInput[string])
|
|
542
|
-
: message.data;
|
|
543
|
-
} catch (error) {
|
|
544
|
-
session?.webSocket.handleError({
|
|
545
|
-
error,
|
|
546
|
-
message: "Invalid input",
|
|
547
|
-
session,
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
return null;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const output = await eventConfig.resolver(input, context);
|
|
554
|
-
|
|
555
|
-
if (!output) return null;
|
|
556
|
-
|
|
557
|
-
return output;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
590
|
private _sendMessage(
|
|
561
591
|
message: EventMessage<string, any>,
|
|
562
592
|
sender: SendMessageSender | null,
|
|
@@ -634,13 +664,27 @@ export class IORoom<
|
|
|
634
664
|
|
|
635
665
|
if (!senderId) return;
|
|
636
666
|
|
|
637
|
-
|
|
667
|
+
const context: EventResolverContext<TContext> = {
|
|
638
668
|
context: this._context,
|
|
639
669
|
doc: this._doc,
|
|
640
670
|
room: this.id,
|
|
641
671
|
session: null,
|
|
642
672
|
sessions: this._sessions,
|
|
643
|
-
}
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
const resolver = this._getEventResolverObject(message).sync;
|
|
676
|
+
|
|
677
|
+
if (!resolver) return;
|
|
678
|
+
|
|
679
|
+
let inputs: TInput[string];
|
|
680
|
+
|
|
681
|
+
try {
|
|
682
|
+
inputs = this._getEventInputs(message);
|
|
683
|
+
} catch {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
Promise.resolve(resolver(inputs, context)).then((output) => {
|
|
644
688
|
if (!output) return;
|
|
645
689
|
|
|
646
690
|
Object.keys(output).forEach((type: string) => {
|