@positronic/cloudflare 0.0.56 → 0.0.58

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.
Files changed (41) hide show
  1. package/dist/src/api/auth-middleware.js +475 -0
  2. package/dist/src/api/brains.js +160 -0
  3. package/dist/src/api/index.js +39 -1
  4. package/dist/src/api/secrets.js +31 -1
  5. package/dist/src/api/users.js +582 -0
  6. package/dist/src/api/webhooks/coordination.js +43 -8
  7. package/dist/src/api/webhooks/index.js +2 -2
  8. package/dist/src/api/webhooks/system.js +2 -2
  9. package/dist/src/auth-do.js +455 -0
  10. package/dist/src/brain-runner-do.js +255 -97
  11. package/dist/src/event-loader.js +301 -0
  12. package/dist/src/index.js +1 -0
  13. package/dist/src/monitor-do.js +39 -19
  14. package/dist/src/signal-provider.js +179 -0
  15. package/dist/src/sqlite-adapter.js +200 -13
  16. package/dist/types/api/auth-middleware.d.ts +19 -0
  17. package/dist/types/api/auth-middleware.d.ts.map +1 -0
  18. package/dist/types/api/brains.d.ts.map +1 -1
  19. package/dist/types/api/index.d.ts.map +1 -1
  20. package/dist/types/api/secrets.d.ts.map +1 -1
  21. package/dist/types/api/types.d.ts +3 -0
  22. package/dist/types/api/types.d.ts.map +1 -1
  23. package/dist/types/api/users.d.ts +7 -0
  24. package/dist/types/api/users.d.ts.map +1 -0
  25. package/dist/types/api/webhooks/coordination.d.ts +7 -3
  26. package/dist/types/api/webhooks/coordination.d.ts.map +1 -1
  27. package/dist/types/auth-do.d.ts +37 -0
  28. package/dist/types/auth-do.d.ts.map +1 -0
  29. package/dist/types/brain-runner-do.d.ts +29 -2
  30. package/dist/types/brain-runner-do.d.ts.map +1 -1
  31. package/dist/types/event-loader.d.ts +25 -0
  32. package/dist/types/event-loader.d.ts.map +1 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/types/monitor-do.d.ts +1 -0
  36. package/dist/types/monitor-do.d.ts.map +1 -1
  37. package/dist/types/signal-provider.d.ts +11 -0
  38. package/dist/types/signal-provider.d.ts.map +1 -0
  39. package/dist/types/sqlite-adapter.d.ts +6 -3
  40. package/dist/types/sqlite-adapter.d.ts.map +1 -1
  41. package/package.json +5 -4
@@ -0,0 +1,475 @@
1
+ function _array_like_to_array(arr, len) {
2
+ if (len == null || len > arr.length) len = arr.length;
3
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4
+ return arr2;
5
+ }
6
+ function _array_with_holes(arr) {
7
+ if (Array.isArray(arr)) return arr;
8
+ }
9
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
10
+ try {
11
+ var info = gen[key](arg);
12
+ var value = info.value;
13
+ } catch (error) {
14
+ reject(error);
15
+ return;
16
+ }
17
+ if (info.done) {
18
+ resolve(value);
19
+ } else {
20
+ Promise.resolve(value).then(_next, _throw);
21
+ }
22
+ }
23
+ function _async_to_generator(fn) {
24
+ return function() {
25
+ var self = this, args = arguments;
26
+ return new Promise(function(resolve, reject) {
27
+ var gen = fn.apply(self, args);
28
+ function _next(value) {
29
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
30
+ }
31
+ function _throw(err) {
32
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
33
+ }
34
+ _next(undefined);
35
+ });
36
+ };
37
+ }
38
+ function _instanceof(left, right) {
39
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
40
+ return !!right[Symbol.hasInstance](left);
41
+ } else {
42
+ return left instanceof right;
43
+ }
44
+ }
45
+ function _iterable_to_array_limit(arr, i) {
46
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
47
+ if (_i == null) return;
48
+ var _arr = [];
49
+ var _n = true;
50
+ var _d = false;
51
+ var _s, _e;
52
+ try {
53
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
54
+ _arr.push(_s.value);
55
+ if (i && _arr.length === i) break;
56
+ }
57
+ } catch (err) {
58
+ _d = true;
59
+ _e = err;
60
+ } finally{
61
+ try {
62
+ if (!_n && _i["return"] != null) _i["return"]();
63
+ } finally{
64
+ if (_d) throw _e;
65
+ }
66
+ }
67
+ return _arr;
68
+ }
69
+ function _non_iterable_rest() {
70
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
71
+ }
72
+ function _sliced_to_array(arr, i) {
73
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
74
+ }
75
+ function _unsupported_iterable_to_array(o, minLen) {
76
+ if (!o) return;
77
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
78
+ var n = Object.prototype.toString.call(o).slice(8, -1);
79
+ if (n === "Object" && o.constructor) n = o.constructor.name;
80
+ if (n === "Map" || n === "Set") return Array.from(n);
81
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
82
+ }
83
+ function _ts_generator(thisArg, body) {
84
+ var f, y, t, _ = {
85
+ label: 0,
86
+ sent: function() {
87
+ if (t[0] & 1) throw t[1];
88
+ return t[1];
89
+ },
90
+ trys: [],
91
+ ops: []
92
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
93
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
94
+ return this;
95
+ }), g;
96
+ function verb(n) {
97
+ return function(v) {
98
+ return step([
99
+ n,
100
+ v
101
+ ]);
102
+ };
103
+ }
104
+ function step(op) {
105
+ if (f) throw new TypeError("Generator is already executing.");
106
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
107
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
108
+ if (y = 0, t) op = [
109
+ op[0] & 2,
110
+ t.value
111
+ ];
112
+ switch(op[0]){
113
+ case 0:
114
+ case 1:
115
+ t = op;
116
+ break;
117
+ case 4:
118
+ _.label++;
119
+ return {
120
+ value: op[1],
121
+ done: false
122
+ };
123
+ case 5:
124
+ _.label++;
125
+ y = op[1];
126
+ op = [
127
+ 0
128
+ ];
129
+ continue;
130
+ case 7:
131
+ op = _.ops.pop();
132
+ _.trys.pop();
133
+ continue;
134
+ default:
135
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
136
+ _ = 0;
137
+ continue;
138
+ }
139
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
140
+ _.label = op[1];
141
+ break;
142
+ }
143
+ if (op[0] === 6 && _.label < t[1]) {
144
+ _.label = t[1];
145
+ t = op;
146
+ break;
147
+ }
148
+ if (t && _.label < t[2]) {
149
+ _.label = t[2];
150
+ _.ops.push(op);
151
+ break;
152
+ }
153
+ if (t[2]) _.ops.pop();
154
+ _.trys.pop();
155
+ continue;
156
+ }
157
+ op = body.call(thisArg, _);
158
+ } catch (e) {
159
+ op = [
160
+ 6,
161
+ e
162
+ ];
163
+ y = 0;
164
+ } finally{
165
+ f = t = 0;
166
+ }
167
+ if (op[0] & 5) throw op[1];
168
+ return {
169
+ value: op[0] ? op[1] : void 0,
170
+ done: true
171
+ };
172
+ }
173
+ }
174
+ import { parseRequestSignature } from '@misskey-dev/node-http-message-signatures';
175
+ /**
176
+ * Get the algorithm parameters for SubtleCrypto based on JWK key type
177
+ */ function getAlgorithmForJwk(jwk) {
178
+ if (jwk.kty === 'RSA') {
179
+ return {
180
+ name: 'RSASSA-PKCS1-v1_5',
181
+ hash: 'SHA-256'
182
+ };
183
+ } else if (jwk.kty === 'EC') {
184
+ return {
185
+ name: 'ECDSA',
186
+ namedCurve: jwk.crv || 'P-256'
187
+ };
188
+ } else if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') {
189
+ return {
190
+ name: 'Ed25519'
191
+ };
192
+ }
193
+ throw new Error("Unsupported key type: ".concat(jwk.kty));
194
+ }
195
+ /**
196
+ * Get the algorithm parameters for signature verification
197
+ */ function getVerifyAlgorithm(jwk) {
198
+ if (jwk.kty === 'RSA') {
199
+ return {
200
+ name: 'RSASSA-PKCS1-v1_5',
201
+ hash: 'SHA-256'
202
+ };
203
+ } else if (jwk.kty === 'EC') {
204
+ return {
205
+ name: 'ECDSA',
206
+ hash: 'SHA-256'
207
+ };
208
+ } else if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519') {
209
+ return {
210
+ name: 'Ed25519'
211
+ };
212
+ }
213
+ throw new Error("Unsupported key type: ".concat(jwk.kty));
214
+ }
215
+ /**
216
+ * Convert a JWK to a CryptoKey for signature verification
217
+ */ function jwkToCryptoKey(jwkString) {
218
+ return _async_to_generator(function() {
219
+ var jwk, algorithm;
220
+ return _ts_generator(this, function(_state) {
221
+ jwk = JSON.parse(jwkString);
222
+ algorithm = getAlgorithmForJwk(jwk);
223
+ return [
224
+ 2,
225
+ crypto.subtle.importKey('jwk', jwk, algorithm, true, [
226
+ 'verify'
227
+ ])
228
+ ];
229
+ });
230
+ })();
231
+ }
232
+ /**
233
+ * Verify a signature using Web Crypto API
234
+ */ function verifySignatureWithKey(signatureBase, signatureB64, cryptoKey, jwk) {
235
+ return _async_to_generator(function() {
236
+ var encoder, data, signatureBytes, algorithm;
237
+ return _ts_generator(this, function(_state) {
238
+ encoder = new TextEncoder();
239
+ data = encoder.encode(signatureBase);
240
+ signatureBytes = Uint8Array.from(atob(signatureB64), function(c) {
241
+ return c.charCodeAt(0);
242
+ });
243
+ algorithm = getVerifyAlgorithm(jwk);
244
+ return [
245
+ 2,
246
+ crypto.subtle.verify(algorithm, cryptoKey, signatureBytes, data)
247
+ ];
248
+ });
249
+ })();
250
+ }
251
+ /**
252
+ * Extract keyId and signature info from parsed signature
253
+ * Handles both draft and RFC9421 formats
254
+ */ function extractSignatureInfo(parsed) {
255
+ if (parsed.version === 'draft') {
256
+ return {
257
+ keyId: parsed.value.keyId,
258
+ signature: parsed.value.params.signature,
259
+ base: parsed.value.signingString
260
+ };
261
+ } else if (parsed.version === 'rfc9421') {
262
+ // RFC9421 returns an array of [label, value] tuples
263
+ var signatures = parsed.value;
264
+ if (signatures.length === 0) return null;
265
+ // Use the first signature (usually 'sig1')
266
+ var _signatures_ = _sliced_to_array(signatures[0], 2), sigValue = _signatures_[1];
267
+ return {
268
+ keyId: sigValue.keyid,
269
+ signature: sigValue.signature,
270
+ base: sigValue.base
271
+ };
272
+ }
273
+ return null;
274
+ }
275
+ /**
276
+ * Authentication middleware for the Positronic API
277
+ * Verifies HTTP message signatures (RFC 9421) using @misskey-dev/node-http-message-signatures for parsing
278
+ */ export function authMiddleware() {
279
+ return function(c, next) {
280
+ return _async_to_generator(function() {
281
+ var signatureHeader, signatureInputHeader, parsedSignature, requestForParsing, errorMessage, sigInfo, keyId, signature, base, authDoId, authDo, userKey, jwk, cryptoKey, isValid, error, errorMessage1, jwk1, cryptoKey1, isValid1, error1, errorMessage2;
282
+ return _ts_generator(this, function(_state) {
283
+ switch(_state.label){
284
+ case 0:
285
+ // Skip auth in development mode
286
+ if (c.env.NODE_ENV === 'development') {
287
+ c.set('auth', {
288
+ userId: null,
289
+ isRoot: true
290
+ });
291
+ return [
292
+ 2,
293
+ next()
294
+ ];
295
+ }
296
+ // Get signature headers
297
+ signatureHeader = c.req.header('Signature');
298
+ signatureInputHeader = c.req.header('Signature-Input');
299
+ // If no signature headers, return 401
300
+ if (!signatureHeader || !signatureInputHeader) {
301
+ return [
302
+ 2,
303
+ c.json({
304
+ error: 'Authentication required'
305
+ }, 401)
306
+ ];
307
+ }
308
+ try {
309
+ // Build a request-like object for the library
310
+ requestForParsing = {
311
+ method: c.req.method,
312
+ url: c.req.url,
313
+ headers: Object.fromEntries(c.req.raw.headers.entries())
314
+ };
315
+ parsedSignature = parseRequestSignature(requestForParsing, {
316
+ clockSkew: {
317
+ now: new Date(),
318
+ forward: 300000,
319
+ delay: 300000
320
+ }
321
+ });
322
+ } catch (error) {
323
+ // Log error type only - avoid logging request details that could contain sensitive data
324
+ errorMessage = _instanceof(error, Error) ? error.message : 'Unknown error';
325
+ console.error('Failed to parse signature:', errorMessage);
326
+ return [
327
+ 2,
328
+ c.json({
329
+ error: 'Invalid signature format'
330
+ }, 401)
331
+ ];
332
+ }
333
+ // Extract signature info from parsed result
334
+ sigInfo = extractSignatureInfo(parsedSignature);
335
+ if (!sigInfo) {
336
+ return [
337
+ 2,
338
+ c.json({
339
+ error: 'No valid signature found'
340
+ }, 401)
341
+ ];
342
+ }
343
+ keyId = sigInfo.keyId, signature = sigInfo.signature, base = sigInfo.base;
344
+ // Try to find the key in the auth database
345
+ authDoId = c.env.AUTH_DO.idFromName('auth');
346
+ authDo = c.env.AUTH_DO.get(authDoId);
347
+ return [
348
+ 4,
349
+ authDo.getKeyByFingerprint(keyId)
350
+ ];
351
+ case 1:
352
+ userKey = _state.sent();
353
+ if (!userKey) return [
354
+ 3,
355
+ 6
356
+ ];
357
+ _state.label = 2;
358
+ case 2:
359
+ _state.trys.push([
360
+ 2,
361
+ 5,
362
+ ,
363
+ 6
364
+ ]);
365
+ jwk = JSON.parse(userKey.jwk);
366
+ return [
367
+ 4,
368
+ jwkToCryptoKey(userKey.jwk)
369
+ ];
370
+ case 3:
371
+ cryptoKey = _state.sent();
372
+ return [
373
+ 4,
374
+ verifySignatureWithKey(base, signature, cryptoKey, jwk)
375
+ ];
376
+ case 4:
377
+ isValid = _state.sent();
378
+ if (!isValid) {
379
+ return [
380
+ 2,
381
+ c.json({
382
+ error: 'Invalid signature'
383
+ }, 401)
384
+ ];
385
+ }
386
+ c.set('auth', {
387
+ userId: userKey.userId,
388
+ isRoot: false
389
+ });
390
+ return [
391
+ 2,
392
+ next()
393
+ ];
394
+ case 5:
395
+ error = _state.sent();
396
+ // Log error type only - avoid logging key material or signature data
397
+ errorMessage1 = _instanceof(error, Error) ? error.message : 'Unknown error';
398
+ console.error('Signature verification failed:', errorMessage1);
399
+ return [
400
+ 2,
401
+ c.json({
402
+ error: 'Signature verification failed'
403
+ }, 401)
404
+ ];
405
+ case 6:
406
+ if (!c.env.ROOT_PUBLIC_KEY) return [
407
+ 3,
408
+ 11
409
+ ];
410
+ _state.label = 7;
411
+ case 7:
412
+ _state.trys.push([
413
+ 7,
414
+ 10,
415
+ ,
416
+ 11
417
+ ]);
418
+ jwk1 = JSON.parse(c.env.ROOT_PUBLIC_KEY);
419
+ return [
420
+ 4,
421
+ jwkToCryptoKey(c.env.ROOT_PUBLIC_KEY)
422
+ ];
423
+ case 8:
424
+ cryptoKey1 = _state.sent();
425
+ return [
426
+ 4,
427
+ verifySignatureWithKey(base, signature, cryptoKey1, jwk1)
428
+ ];
429
+ case 9:
430
+ isValid1 = _state.sent();
431
+ if (isValid1) {
432
+ c.set('auth', {
433
+ userId: null,
434
+ isRoot: true
435
+ });
436
+ return [
437
+ 2,
438
+ next()
439
+ ];
440
+ }
441
+ return [
442
+ 3,
443
+ 11
444
+ ];
445
+ case 10:
446
+ error1 = _state.sent();
447
+ // Log error type only - avoid logging key material
448
+ errorMessage2 = _instanceof(error1, Error) ? error1.message : 'Unknown error';
449
+ console.error('Root key verification failed:', errorMessage2);
450
+ return [
451
+ 3,
452
+ 11
453
+ ];
454
+ case 11:
455
+ // No matching key found
456
+ // Check if ROOT_PUBLIC_KEY is configured - if not, return specific error
457
+ if (!c.env.ROOT_PUBLIC_KEY) {
458
+ return [
459
+ 2,
460
+ c.json({
461
+ error: 'ROOT_KEY_NOT_CONFIGURED'
462
+ }, 401)
463
+ ];
464
+ }
465
+ return [
466
+ 2,
467
+ c.json({
468
+ error: 'Unknown key'
469
+ }, 401)
470
+ ];
471
+ }
472
+ });
473
+ })();
474
+ };
475
+ }
@@ -157,6 +157,7 @@ import { Hono } from 'hono';
157
157
  import { v4 as uuidv4 } from 'uuid';
158
158
  import { parseCronExpression } from 'cron-schedule';
159
159
  import Fuse from 'fuse.js';
160
+ import { isSignalValid, brainMachineDefinition } from '@positronic/core';
160
161
  import { getManifest } from '../brain-runner-do.js';
161
162
  var brains = new Hono();
162
163
  brains.post('/runs', function(context) {
@@ -478,6 +479,165 @@ brains.delete('/runs/:runId', function(context) {
478
479
  });
479
480
  })();
480
481
  });
482
+ // Signal endpoint - queue KILL, PAUSE, USER_MESSAGE, RESUME, or WEBHOOK_RESPONSE signals
483
+ brains.post('/runs/:runId/signals', function(context) {
484
+ return _async_to_generator(function() {
485
+ var runId, body, monitorId, monitorStub, run, validation, namespace, doId, stub, signal;
486
+ return _ts_generator(this, function(_state) {
487
+ switch(_state.label){
488
+ case 0:
489
+ runId = context.req.param('runId');
490
+ return [
491
+ 4,
492
+ context.req.json()
493
+ ];
494
+ case 1:
495
+ body = _state.sent();
496
+ // Validate signal type
497
+ if (![
498
+ 'KILL',
499
+ 'PAUSE',
500
+ 'USER_MESSAGE',
501
+ 'RESUME',
502
+ 'WEBHOOK_RESPONSE'
503
+ ].includes(body.type)) {
504
+ return [
505
+ 2,
506
+ context.json({
507
+ error: 'Invalid signal type'
508
+ }, 400)
509
+ ];
510
+ }
511
+ // Check if the run exists in MonitorDO
512
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
513
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
514
+ return [
515
+ 4,
516
+ monitorStub.getRun(runId)
517
+ ];
518
+ case 2:
519
+ run = _state.sent();
520
+ if (!run) {
521
+ return [
522
+ 2,
523
+ context.json({
524
+ error: 'Brain run not found'
525
+ }, 404)
526
+ ];
527
+ }
528
+ // Validate control signals against current brain state using state machine definition
529
+ // USER_MESSAGE is a data signal that gets queued and processed during agent execution,
530
+ // so it doesn't need state validation - it can always be queued
531
+ if (body.type !== 'USER_MESSAGE') {
532
+ validation = isSignalValid(brainMachineDefinition, run.status, body.type);
533
+ if (!validation.valid) {
534
+ return [
535
+ 2,
536
+ context.json({
537
+ error: validation.reason
538
+ }, 409)
539
+ ];
540
+ }
541
+ }
542
+ // Get BrainRunnerDO stub and queue the signal
543
+ namespace = context.env.BRAIN_RUNNER_DO;
544
+ doId = namespace.idFromName(runId);
545
+ stub = namespace.get(doId);
546
+ return [
547
+ 4,
548
+ stub.queueSignal(body)
549
+ ];
550
+ case 3:
551
+ signal = _state.sent();
552
+ if (!(body.type === 'RESUME')) return [
553
+ 3,
554
+ 5
555
+ ];
556
+ return [
557
+ 4,
558
+ stub.wakeUp(runId)
559
+ ];
560
+ case 4:
561
+ _state.sent();
562
+ _state.label = 5;
563
+ case 5:
564
+ return [
565
+ 2,
566
+ context.json({
567
+ success: true,
568
+ signal: {
569
+ type: signal.type,
570
+ queuedAt: signal.queuedAt
571
+ }
572
+ }, 202)
573
+ ];
574
+ }
575
+ });
576
+ })();
577
+ });
578
+ // Resume endpoint - resume a paused brain using signal-based approach
579
+ brains.post('/runs/:runId/resume', function(context) {
580
+ return _async_to_generator(function() {
581
+ var runId, monitorId, monitorStub, run, namespace, doId, stub;
582
+ return _ts_generator(this, function(_state) {
583
+ switch(_state.label){
584
+ case 0:
585
+ runId = context.req.param('runId');
586
+ // Check if the run exists and is paused via MonitorDO
587
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
588
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
589
+ return [
590
+ 4,
591
+ monitorStub.getRun(runId)
592
+ ];
593
+ case 1:
594
+ run = _state.sent();
595
+ if (!run) {
596
+ return [
597
+ 2,
598
+ context.json({
599
+ error: 'Brain run not found'
600
+ }, 404)
601
+ ];
602
+ }
603
+ if (run.status !== 'paused') {
604
+ return [
605
+ 2,
606
+ context.json({
607
+ error: "Cannot resume brain in '".concat(run.status, "' state. Only paused brains can be resumed.")
608
+ }, 409)
609
+ ];
610
+ }
611
+ // Queue RESUME signal and wake up the brain
612
+ namespace = context.env.BRAIN_RUNNER_DO;
613
+ doId = namespace.idFromName(runId);
614
+ stub = namespace.get(doId);
615
+ // Queue the RESUME signal first, then wake up the brain
616
+ return [
617
+ 4,
618
+ stub.queueSignal({
619
+ type: 'RESUME'
620
+ })
621
+ ];
622
+ case 2:
623
+ _state.sent();
624
+ return [
625
+ 4,
626
+ stub.wakeUp(runId)
627
+ ];
628
+ case 3:
629
+ _state.sent();
630
+ return [
631
+ 2,
632
+ context.json({
633
+ success: true,
634
+ action: 'resumed'
635
+ }, 202)
636
+ ];
637
+ }
638
+ });
639
+ })();
640
+ });
481
641
  brains.get('/:identifier/history', function(context) {
482
642
  return _async_to_generator(function() {
483
643
  var identifier, limit, manifest, resolution, brain, brainTitle, monitorId, monitorStub, runs;