@positronic/cloudflare 0.0.18 → 0.0.20

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/dist/src/api.js CHANGED
@@ -1,3 +1,11 @@
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
+ }
1
9
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
10
  try {
3
11
  var info = gen[key](arg);
@@ -47,6 +55,33 @@ function _instanceof(left, right) {
47
55
  return left instanceof right;
48
56
  }
49
57
  }
58
+ function _iterable_to_array_limit(arr, i) {
59
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
60
+ if (_i == null) return;
61
+ var _arr = [];
62
+ var _n = true;
63
+ var _d = false;
64
+ var _s, _e;
65
+ try {
66
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
67
+ _arr.push(_s.value);
68
+ if (i && _arr.length === i) break;
69
+ }
70
+ } catch (err) {
71
+ _d = true;
72
+ _e = err;
73
+ } finally{
74
+ try {
75
+ if (!_n && _i["return"] != null) _i["return"]();
76
+ } finally{
77
+ if (_d) throw _e;
78
+ }
79
+ }
80
+ return _arr;
81
+ }
82
+ function _non_iterable_rest() {
83
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
84
+ }
50
85
  function _object_spread(target) {
51
86
  for(var i = 1; i < arguments.length; i++){
52
87
  var source = arguments[i] != null ? arguments[i] : {};
@@ -86,6 +121,17 @@ function _object_spread_props(target, source) {
86
121
  }
87
122
  return target;
88
123
  }
124
+ function _sliced_to_array(arr, i) {
125
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
126
+ }
127
+ function _unsupported_iterable_to_array(o, minLen) {
128
+ if (!o) return;
129
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
130
+ var n = Object.prototype.toString.call(o).slice(8, -1);
131
+ if (n === "Object" && o.constructor) n = o.constructor.name;
132
+ if (n === "Map" || n === "Set") return Array.from(n);
133
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
134
+ }
89
135
  function _ts_generator(thisArg, body) {
90
136
  var f, y, t, _ = {
91
137
  label: 0,
@@ -181,7 +227,7 @@ import { Hono } from 'hono';
181
227
  import { v4 as uuidv4 } from 'uuid';
182
228
  import { AwsClient } from 'aws4fetch';
183
229
  import { parseCronExpression } from 'cron-schedule';
184
- import { getManifest } from './brain-runner-do.js';
230
+ import { getManifest, getWebhookManifest } from './brain-runner-do.js';
185
231
  import { RESOURCE_TYPES } from '@positronic/core';
186
232
  var app = new Hono();
187
233
  app.post('/brains/runs', function(context) {
@@ -397,6 +443,81 @@ app.get('/brains/runs/:runId/watch', function(context) {
397
443
  });
398
444
  })();
399
445
  });
446
+ app.delete('/brains/runs/:runId', function(context) {
447
+ return _async_to_generator(function() {
448
+ var runId, monitorId, monitorStub, existingRun, namespace, doId, stub, result, error;
449
+ return _ts_generator(this, function(_state) {
450
+ switch(_state.label){
451
+ case 0:
452
+ runId = context.req.param('runId');
453
+ // First check if the run exists in the monitor
454
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
455
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
456
+ return [
457
+ 4,
458
+ monitorStub.getLastEvent(runId)
459
+ ];
460
+ case 1:
461
+ existingRun = _state.sent();
462
+ if (!existingRun) {
463
+ return [
464
+ 2,
465
+ context.json({
466
+ error: "Brain run '".concat(runId, "' not found")
467
+ }, 404)
468
+ ];
469
+ }
470
+ // Now try to kill it
471
+ namespace = context.env.BRAIN_RUNNER_DO;
472
+ doId = namespace.idFromName(runId);
473
+ stub = namespace.get(doId);
474
+ _state.label = 2;
475
+ case 2:
476
+ _state.trys.push([
477
+ 2,
478
+ 4,
479
+ ,
480
+ 5
481
+ ]);
482
+ return [
483
+ 4,
484
+ stub.kill()
485
+ ];
486
+ case 3:
487
+ result = _state.sent();
488
+ if (!result.success) {
489
+ // Brain run is not active or already completed
490
+ return [
491
+ 2,
492
+ context.json({
493
+ error: result.message
494
+ }, 409)
495
+ ];
496
+ }
497
+ // Return 204 No Content on success
498
+ return [
499
+ 2,
500
+ new Response(null, {
501
+ status: 204
502
+ })
503
+ ];
504
+ case 4:
505
+ error = _state.sent();
506
+ console.error("Error killing brain run ".concat(runId, ":"), error);
507
+ return [
508
+ 2,
509
+ context.json({
510
+ error: 'Failed to kill brain run'
511
+ }, 500)
512
+ ];
513
+ case 5:
514
+ return [
515
+ 2
516
+ ];
517
+ }
518
+ });
519
+ })();
520
+ });
400
521
  app.get('/brains/:identifier/history', function(context) {
401
522
  return _async_to_generator(function() {
402
523
  var identifier, limit, manifest, resolution, brain, brainTitle, monitorId, monitorStub, runs;
@@ -1397,4 +1518,137 @@ app.post('/resources/presigned-link', function(context) {
1397
1518
  });
1398
1519
  })();
1399
1520
  });
1521
+ // Webhook endpoints
1522
+ // List all webhooks
1523
+ app.get('/webhooks', function(context) {
1524
+ return _async_to_generator(function() {
1525
+ var webhookManifest, webhooks;
1526
+ return _ts_generator(this, function(_state) {
1527
+ webhookManifest = getWebhookManifest();
1528
+ if (!webhookManifest) {
1529
+ return [
1530
+ 2,
1531
+ context.json({
1532
+ webhooks: [],
1533
+ count: 0
1534
+ })
1535
+ ];
1536
+ }
1537
+ webhooks = Object.entries(webhookManifest).map(function(param) {
1538
+ var _param = _sliced_to_array(param, 2), slug = _param[0], webhook = _param[1];
1539
+ return {
1540
+ slug: slug,
1541
+ description: webhook.description
1542
+ };
1543
+ });
1544
+ return [
1545
+ 2,
1546
+ context.json({
1547
+ webhooks: webhooks,
1548
+ count: webhooks.length
1549
+ })
1550
+ ];
1551
+ });
1552
+ })();
1553
+ });
1554
+ // Receive incoming webhook from external service
1555
+ app.post('/webhooks/:slug', function(context) {
1556
+ return _async_to_generator(function() {
1557
+ var slug, webhookManifest, webhook, result, monitorId, monitorStub, brainRunId, namespace, doId, stub, error;
1558
+ return _ts_generator(this, function(_state) {
1559
+ switch(_state.label){
1560
+ case 0:
1561
+ slug = context.req.param('slug');
1562
+ webhookManifest = getWebhookManifest();
1563
+ if (!webhookManifest) {
1564
+ return [
1565
+ 2,
1566
+ context.json({
1567
+ error: 'Webhook manifest not initialized'
1568
+ }, 500)
1569
+ ];
1570
+ }
1571
+ webhook = webhookManifest[slug];
1572
+ if (!webhook) {
1573
+ return [
1574
+ 2,
1575
+ context.json({
1576
+ error: "Webhook '".concat(slug, "' not found")
1577
+ }, 404)
1578
+ ];
1579
+ }
1580
+ _state.label = 1;
1581
+ case 1:
1582
+ _state.trys.push([
1583
+ 1,
1584
+ 6,
1585
+ ,
1586
+ 7
1587
+ ]);
1588
+ return [
1589
+ 4,
1590
+ webhook.handler(context.req.raw)
1591
+ ];
1592
+ case 2:
1593
+ result = _state.sent();
1594
+ // Check if there's a brain waiting for this webhook
1595
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
1596
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
1597
+ return [
1598
+ 4,
1599
+ monitorStub.findWaitingBrain(slug, result.identifier)
1600
+ ];
1601
+ case 3:
1602
+ brainRunId = _state.sent();
1603
+ if (!brainRunId) return [
1604
+ 3,
1605
+ 5
1606
+ ];
1607
+ // Found a brain waiting for this webhook - resume it
1608
+ namespace = context.env.BRAIN_RUNNER_DO;
1609
+ doId = namespace.idFromName(brainRunId);
1610
+ stub = namespace.get(doId);
1611
+ // Resume the brain with the webhook response
1612
+ return [
1613
+ 4,
1614
+ stub.resume(brainRunId, result.response)
1615
+ ];
1616
+ case 4:
1617
+ _state.sent();
1618
+ return [
1619
+ 2,
1620
+ context.json({
1621
+ received: true,
1622
+ action: 'resumed',
1623
+ identifier: result.identifier,
1624
+ brainRunId: brainRunId
1625
+ })
1626
+ ];
1627
+ case 5:
1628
+ // No brain waiting for this webhook
1629
+ return [
1630
+ 2,
1631
+ context.json({
1632
+ received: true,
1633
+ action: 'queued',
1634
+ identifier: result.identifier
1635
+ })
1636
+ ];
1637
+ case 6:
1638
+ error = _state.sent();
1639
+ console.error("Error receiving webhook ".concat(slug, ":"), error);
1640
+ return [
1641
+ 2,
1642
+ context.json({
1643
+ error: 'Failed to process webhook'
1644
+ }, 500)
1645
+ ];
1646
+ case 7:
1647
+ return [
1648
+ 2
1649
+ ];
1650
+ }
1651
+ });
1652
+ })();
1653
+ });
1400
1654
  export default app;
@@ -103,6 +103,30 @@ function _object_spread(target) {
103
103
  }
104
104
  return target;
105
105
  }
106
+ function ownKeys(object, enumerableOnly) {
107
+ var keys = Object.keys(object);
108
+ if (Object.getOwnPropertySymbols) {
109
+ var symbols = Object.getOwnPropertySymbols(object);
110
+ if (enumerableOnly) {
111
+ symbols = symbols.filter(function(sym) {
112
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
113
+ });
114
+ }
115
+ keys.push.apply(keys, symbols);
116
+ }
117
+ return keys;
118
+ }
119
+ function _object_spread_props(target, source) {
120
+ source = source != null ? source : {};
121
+ if (Object.getOwnPropertyDescriptors) {
122
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
123
+ } else {
124
+ ownKeys(Object(source)).forEach(function(key) {
125
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
126
+ });
127
+ }
128
+ return target;
129
+ }
106
130
  function _possible_constructor_return(self, call) {
107
131
  if (call && (_type_of(call) === "object" || typeof call === "function")) {
108
132
  return call;
@@ -219,8 +243,10 @@ function _ts_generator(thisArg, body) {
219
243
  };
220
244
  }
221
245
  }
246
+ import { STATUS, BRAIN_EVENTS } from '@positronic/core';
222
247
  import { DurableObject } from 'cloudflare:workers';
223
248
  import { BrainRunSQLiteAdapter } from './sqlite-adapter.js';
249
+ import { WebhookAdapter } from './webhook-adapter.js';
224
250
  import { CloudflareR2Loader } from './r2-loader.js';
225
251
  import { createResources } from '@positronic/core';
226
252
  var manifest = null;
@@ -234,6 +260,13 @@ var brainRunner = null;
234
260
  export function setBrainRunner(runner) {
235
261
  brainRunner = runner;
236
262
  }
263
+ var webhookManifest = null;
264
+ export function setWebhookManifest(manifest) {
265
+ webhookManifest = manifest;
266
+ }
267
+ export function getWebhookManifest() {
268
+ return webhookManifest;
269
+ }
237
270
  var EventStreamAdapter = /*#__PURE__*/ function() {
238
271
  "use strict";
239
272
  function EventStreamAdapter() {
@@ -364,7 +397,7 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
364
397
  _this = _call_super(this, BrainRunnerDO, [
365
398
  state,
366
399
  env
367
- ]), _define_property(_this, "sql", void 0), _define_property(_this, "brainRunId", void 0), _define_property(_this, "eventStreamAdapter", new EventStreamAdapter());
400
+ ]), _define_property(_this, "sql", void 0), _define_property(_this, "brainRunId", void 0), _define_property(_this, "eventStreamAdapter", new EventStreamAdapter()), _define_property(_this, "abortController", null);
368
401
  _this.sql = state.storage.sql;
369
402
  _this.brainRunId = state.id.toString();
370
403
  _this.env = env;
@@ -502,14 +535,45 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
502
535
  }).call(this);
503
536
  }
504
537
  },
538
+ {
539
+ key: "kill",
540
+ value: function kill() {
541
+ return _async_to_generator(function() {
542
+ return _ts_generator(this, function(_state) {
543
+ if (this.abortController && !this.abortController.signal.aborted) {
544
+ this.abortController.abort();
545
+ return [
546
+ 2,
547
+ {
548
+ success: true,
549
+ message: 'Brain run kill signal sent'
550
+ }
551
+ ];
552
+ } else {
553
+ return [
554
+ 2,
555
+ {
556
+ success: false,
557
+ message: 'Brain run is not active or already completed'
558
+ }
559
+ ];
560
+ }
561
+ return [
562
+ 2
563
+ ];
564
+ });
565
+ }).call(this);
566
+ }
567
+ },
505
568
  {
506
569
  key: "start",
507
570
  value: function start(brainTitle, brainRunId, initialData) {
508
571
  return _async_to_generator(function() {
509
- var sql, resolution, brainToRun, sqliteAdapter, eventStreamAdapter, monitorAdapter, scheduleAdapter, r2Resources, runnerWithResources, options, initialState;
572
+ var _this, sql, resolution, brainToRun, sqliteAdapter, eventStreamAdapter, monitorDOStub, monitorAdapter, scheduleAdapter, webhookAdapter, r2Resources, runnerWithResources, options, initialState;
510
573
  return _ts_generator(this, function(_state) {
511
574
  switch(_state.label){
512
575
  case 0:
576
+ _this = this;
513
577
  sql = this.sql;
514
578
  if (!manifest) {
515
579
  throw new Error('Runtime manifest not initialized');
@@ -531,8 +595,10 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
531
595
  }
532
596
  sqliteAdapter = new BrainRunSQLiteAdapter(sql);
533
597
  eventStreamAdapter = this.eventStreamAdapter;
534
- monitorAdapter = new MonitorAdapter(this.env.MONITOR_DO.get(this.env.MONITOR_DO.idFromName('singleton')));
598
+ monitorDOStub = this.env.MONITOR_DO.get(this.env.MONITOR_DO.idFromName('singleton'));
599
+ monitorAdapter = new MonitorAdapter(monitorDOStub);
535
600
  scheduleAdapter = new ScheduleAdapter(this.env.SCHEDULE_DO.get(this.env.SCHEDULE_DO.idFromName('singleton')));
601
+ webhookAdapter = new WebhookAdapter(monitorDOStub);
536
602
  if (!brainRunner) {
537
603
  throw new Error('BrainRunner not initialized');
538
604
  }
@@ -551,18 +617,123 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
551
617
  // Extract options from initialData if present
552
618
  options = initialData === null || initialData === void 0 ? void 0 : initialData.options;
553
619
  initialState = initialData && !initialData.options ? initialData : {};
620
+ // Create abort controller for this run
621
+ this.abortController = new AbortController();
554
622
  runnerWithResources.withAdapters([
555
623
  sqliteAdapter,
556
624
  eventStreamAdapter,
557
625
  monitorAdapter,
558
- scheduleAdapter
559
- ]).run(brainToRun, _object_spread({
626
+ scheduleAdapter,
627
+ webhookAdapter
628
+ ]).run(brainToRun, _object_spread_props(_object_spread({
560
629
  initialState: initialState,
561
630
  brainRunId: brainRunId
562
631
  }, options && {
563
632
  options: options
633
+ }), {
634
+ signal: this.abortController.signal
564
635
  })).catch(function(err) {
565
636
  console.error("[DO ".concat(brainRunId, "] BrainRunner run failed:"), err);
637
+ throw err; // Re-throw to ensure proper error propagation
638
+ }).finally(function() {
639
+ // Clean up abort controller when run completes
640
+ _this.abortController = null;
641
+ });
642
+ return [
643
+ 2
644
+ ];
645
+ }
646
+ });
647
+ }).call(this);
648
+ }
649
+ },
650
+ {
651
+ key: "resume",
652
+ value: function resume(brainRunId, webhookResponse) {
653
+ return _async_to_generator(function() {
654
+ var _this, sql, startEventResult, startEvent, brainTitle, initialState, resolution, brainToRun, eventsResult, initialCompletedSteps, sqliteAdapter, eventStreamAdapter, monitorDOStub, monitorAdapter, scheduleAdapter, webhookAdapter, r2Resources, runnerWithResources;
655
+ return _ts_generator(this, function(_state) {
656
+ switch(_state.label){
657
+ case 0:
658
+ _this = this;
659
+ sql = this.sql;
660
+ if (!manifest) {
661
+ throw new Error('Runtime manifest not initialized');
662
+ }
663
+ // Get the initial state and brain title by loading the START or RESTART event
664
+ startEventResult = sql.exec("SELECT serialized_event FROM brain_events WHERE event_type IN (?, ?) ORDER BY event_id DESC LIMIT 1", BRAIN_EVENTS.START, BRAIN_EVENTS.RESTART).toArray();
665
+ if (startEventResult.length === 0) {
666
+ throw new Error("No START or RESTART event found for brain run ".concat(brainRunId));
667
+ }
668
+ startEvent = JSON.parse(startEventResult[0].serialized_event);
669
+ brainTitle = startEvent.brainTitle;
670
+ initialState = startEvent.initialState || {};
671
+ if (!brainTitle) {
672
+ throw new Error("Brain title not found in START/RESTART event for brain run ".concat(brainRunId));
673
+ }
674
+ // Resolve the brain using the title
675
+ resolution = manifest.resolve(brainTitle);
676
+ if (resolution.matchType === 'none') {
677
+ console.error("[DO ".concat(brainRunId, "] Brain ").concat(brainTitle, " not found in manifest."));
678
+ throw new Error("Brain ".concat(brainTitle, " not found"));
679
+ }
680
+ if (resolution.matchType === 'multiple') {
681
+ console.error("[DO ".concat(brainRunId, "] Multiple brains match identifier ").concat(brainTitle), resolution.candidates);
682
+ throw new Error("Multiple brains match identifier ".concat(brainTitle));
683
+ }
684
+ brainToRun = resolution.brain;
685
+ if (!brainToRun) {
686
+ throw new Error("Brain ".concat(brainTitle, " resolved but brain object is missing"));
687
+ }
688
+ // Load completed steps from SQLite
689
+ eventsResult = sql.exec("SELECT serialized_event FROM brain_events WHERE event_type = ? ORDER BY event_id ASC", BRAIN_EVENTS.STEP_COMPLETE).toArray();
690
+ initialCompletedSteps = eventsResult.map(function(row) {
691
+ var event = JSON.parse(row.serialized_event);
692
+ return {
693
+ id: event.stepId,
694
+ title: event.stepTitle,
695
+ status: STATUS.COMPLETE,
696
+ patch: event.patch
697
+ };
698
+ });
699
+ sqliteAdapter = new BrainRunSQLiteAdapter(sql);
700
+ eventStreamAdapter = this.eventStreamAdapter;
701
+ monitorDOStub = this.env.MONITOR_DO.get(this.env.MONITOR_DO.idFromName('singleton'));
702
+ monitorAdapter = new MonitorAdapter(monitorDOStub);
703
+ scheduleAdapter = new ScheduleAdapter(this.env.SCHEDULE_DO.get(this.env.SCHEDULE_DO.idFromName('singleton')));
704
+ webhookAdapter = new WebhookAdapter(monitorDOStub);
705
+ if (!brainRunner) {
706
+ throw new Error('BrainRunner not initialized');
707
+ }
708
+ return [
709
+ 4,
710
+ this.loadResourcesFromR2()
711
+ ];
712
+ case 1:
713
+ r2Resources = _state.sent();
714
+ runnerWithResources = brainRunner;
715
+ if (r2Resources) {
716
+ runnerWithResources = brainRunner.withResources(r2Resources);
717
+ }
718
+ // Create abort controller for this run
719
+ this.abortController = new AbortController();
720
+ runnerWithResources.withAdapters([
721
+ sqliteAdapter,
722
+ eventStreamAdapter,
723
+ monitorAdapter,
724
+ scheduleAdapter,
725
+ webhookAdapter
726
+ ]).run(brainToRun, {
727
+ initialState: initialState,
728
+ initialCompletedSteps: initialCompletedSteps,
729
+ brainRunId: brainRunId,
730
+ response: webhookResponse,
731
+ signal: this.abortController.signal
732
+ }).catch(function(err) {
733
+ console.error("[DO ".concat(brainRunId, "] BrainRunner resume failed:"), err);
734
+ throw err;
735
+ }).finally(function() {
736
+ _this.abortController = null;
566
737
  });
567
738
  return [
568
739
  2
@@ -456,7 +456,8 @@ function generateProject(projectName, projectDir, onSuccess) {
456
456
  name: projectName,
457
457
  backend: 'cloudflare',
458
458
  install: true,
459
- pm: 'npm'
459
+ pm: 'npm',
460
+ claudemd: false
460
461
  };
461
462
  return [
462
463
  4,
package/dist/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { BrainRunnerDO, setBrainRunner, setManifest, getManifest } from './brain-runner-do.js';
1
+ export { BrainRunnerDO, setBrainRunner, setManifest, getManifest, setWebhookManifest } from './brain-runner-do.js';
2
2
  export { MonitorDO } from './monitor-do.js';
3
3
  export { ScheduleDO } from './schedule-do.js';
4
4
  export { PositronicManifest } from './manifest.js';
@@ -218,20 +218,24 @@ export var MonitorDO = /*#__PURE__*/ function(DurableObject) {
218
218
  ]), _define_property(_this, "storage", void 0), _define_property(_this, "eventStreamHandler", new EventStreamHandler());
219
219
  _this.storage = state.storage.sql;
220
220
  // Update table schema and indexes
221
- _this.storage.exec("\n CREATE TABLE IF NOT EXISTS brain_runs (\n run_id TEXT PRIMARY KEY,\n brain_title TEXT NOT NULL, -- Renamed column\n brain_description TEXT, -- Renamed column\n type TEXT NOT NULL,\n status TEXT NOT NULL,\n options TEXT,\n error TEXT,\n created_at INTEGER NOT NULL,\n started_at INTEGER,\n completed_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_brain_status -- Renamed index\n ON brain_runs(brain_title, status);\n\n CREATE INDEX IF NOT EXISTS idx_brain_time -- Renamed index\n ON brain_runs(created_at DESC);\n ");
221
+ _this.storage.exec("\n CREATE TABLE IF NOT EXISTS brain_runs (\n run_id TEXT PRIMARY KEY,\n brain_title TEXT NOT NULL, -- Renamed column\n brain_description TEXT, -- Renamed column\n type TEXT NOT NULL,\n status TEXT NOT NULL,\n options TEXT,\n error TEXT,\n created_at INTEGER NOT NULL,\n started_at INTEGER,\n completed_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_brain_status -- Renamed index\n ON brain_runs(brain_title, status);\n\n CREATE INDEX IF NOT EXISTS idx_brain_time -- Renamed index\n ON brain_runs(created_at DESC);\n\n CREATE TABLE IF NOT EXISTS webhook_registrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n slug TEXT NOT NULL,\n identifier TEXT NOT NULL,\n brain_run_id TEXT NOT NULL,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_webhook_lookup\n ON webhook_registrations(slug, identifier);\n\n CREATE INDEX IF NOT EXISTS idx_webhook_brain_run\n ON webhook_registrations(brain_run_id);\n ");
222
222
  return _this;
223
223
  }
224
224
  _create_class(MonitorDO, [
225
225
  {
226
226
  key: "handleBrainEvent",
227
227
  value: function handleBrainEvent(event) {
228
- if (event.type === BRAIN_EVENTS.START || event.type === BRAIN_EVENTS.RESTART || event.type === BRAIN_EVENTS.COMPLETE || event.type === BRAIN_EVENTS.ERROR) {
228
+ if (event.type === BRAIN_EVENTS.START || event.type === BRAIN_EVENTS.RESTART || event.type === BRAIN_EVENTS.COMPLETE || event.type === BRAIN_EVENTS.ERROR || event.type === BRAIN_EVENTS.CANCELLED) {
229
229
  var currentTime = Date.now();
230
230
  var startTime = event.type === BRAIN_EVENTS.START || event.type === BRAIN_EVENTS.RESTART ? currentTime : null;
231
- var completeTime = event.type === BRAIN_EVENTS.COMPLETE || event.type === BRAIN_EVENTS.ERROR ? currentTime : null;
231
+ var completeTime = event.type === BRAIN_EVENTS.COMPLETE || event.type === BRAIN_EVENTS.ERROR || event.type === BRAIN_EVENTS.CANCELLED ? currentTime : null;
232
232
  var error = event.type === BRAIN_EVENTS.ERROR ? JSON.stringify(event.error) : null;
233
233
  // Update SQL insert/update with new column names, read from existing event fields
234
234
  this.storage.exec("\n INSERT INTO brain_runs (\n run_id, brain_title, brain_description, type, status,\n options, error, created_at, started_at, completed_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(run_id) DO UPDATE SET\n type = excluded.type,\n status = excluded.status,\n error = excluded.error,\n completed_at = excluded.completed_at\n ", event.brainRunId, event.brainTitle, event.brainDescription || null, event.type, event.status, JSON.stringify(event.options || {}), error, currentTime, startTime, completeTime);
235
+ // Clean up webhook registrations when brain terminates
236
+ if (event.type === BRAIN_EVENTS.COMPLETE || event.type === BRAIN_EVENTS.ERROR || event.type === BRAIN_EVENTS.CANCELLED) {
237
+ this.clearWebhookRegistrations(event.brainRunId);
238
+ }
235
239
  this.broadcastRunningBrains();
236
240
  }
237
241
  }
@@ -341,10 +345,10 @@ export var MonitorDO = /*#__PURE__*/ function(DurableObject) {
341
345
  }
342
346
  },
343
347
  {
344
- // No changes needed for getLastEvent, uses run_id
345
348
  key: "getLastEvent",
346
349
  value: function getLastEvent(brainRunId) {
347
- return this.storage.exec("\n SELECT * FROM brain_runs WHERE run_id = ?\n ", brainRunId).one();
350
+ var results = this.storage.exec("\n SELECT * FROM brain_runs WHERE run_id = ?\n ", brainRunId).toArray();
351
+ return results.length > 0 ? results[0] : null;
348
352
  }
349
353
  },
350
354
  {
@@ -363,6 +367,34 @@ export var MonitorDO = /*#__PURE__*/ function(DurableObject) {
363
367
  value: function activeRuns(brainTitle) {
364
368
  return this.storage.exec("\n SELECT\n run_id as brainRunId,\n brain_title as brainTitle,\n brain_description as brainDescription,\n type,\n status,\n options,\n error,\n created_at as createdAt,\n started_at as startedAt,\n completed_at as completedAt\n FROM brain_runs\n WHERE brain_title = ? AND status = ?\n ORDER BY created_at DESC\n ", brainTitle, STATUS.RUNNING).toArray();
365
369
  }
370
+ },
371
+ {
372
+ /**
373
+ * Register a webhook to wait for
374
+ * Called when a brain emits a WEBHOOK event
375
+ */ key: "registerWebhook",
376
+ value: function registerWebhook(slug, identifier, brainRunId) {
377
+ this.storage.exec("\n INSERT INTO webhook_registrations (slug, identifier, brain_run_id, created_at)\n VALUES (?, ?, ?, ?)\n ", slug, identifier, brainRunId, Date.now());
378
+ }
379
+ },
380
+ {
381
+ /**
382
+ * Find a brain waiting for this webhook
383
+ * Returns the brain_run_id if found, null otherwise
384
+ */ key: "findWaitingBrain",
385
+ value: function findWaitingBrain(slug, identifier) {
386
+ var results = this.storage.exec("\n SELECT brain_run_id as brainRunId\n FROM webhook_registrations\n WHERE slug = ? AND identifier = ?\n LIMIT 1\n ", slug, identifier).toArray();
387
+ return results.length > 0 ? results[0].brainRunId : null;
388
+ }
389
+ },
390
+ {
391
+ /**
392
+ * Clear all webhook registrations for a brain run
393
+ * Called when brain completes, errors, or is cancelled
394
+ */ key: "clearWebhookRegistrations",
395
+ value: function clearWebhookRegistrations(brainRunId) {
396
+ this.storage.exec("\n DELETE FROM webhook_registrations\n WHERE brain_run_id = ?\n ", brainRunId);
397
+ }
366
398
  }
367
399
  ]);
368
400
  return MonitorDO;
@@ -0,0 +1,246 @@
1
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
+ try {
3
+ var info = gen[key](arg);
4
+ var value = info.value;
5
+ } catch (error) {
6
+ reject(error);
7
+ return;
8
+ }
9
+ if (info.done) {
10
+ resolve(value);
11
+ } else {
12
+ Promise.resolve(value).then(_next, _throw);
13
+ }
14
+ }
15
+ function _async_to_generator(fn) {
16
+ return function() {
17
+ var self = this, args = arguments;
18
+ return new Promise(function(resolve, reject) {
19
+ var gen = fn.apply(self, args);
20
+ function _next(value) {
21
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
22
+ }
23
+ function _throw(err) {
24
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
25
+ }
26
+ _next(undefined);
27
+ });
28
+ };
29
+ }
30
+ function _class_call_check(instance, Constructor) {
31
+ if (!(instance instanceof Constructor)) {
32
+ throw new TypeError("Cannot call a class as a function");
33
+ }
34
+ }
35
+ function _defineProperties(target, props) {
36
+ for(var i = 0; i < props.length; i++){
37
+ var descriptor = props[i];
38
+ descriptor.enumerable = descriptor.enumerable || false;
39
+ descriptor.configurable = true;
40
+ if ("value" in descriptor) descriptor.writable = true;
41
+ Object.defineProperty(target, descriptor.key, descriptor);
42
+ }
43
+ }
44
+ function _create_class(Constructor, protoProps, staticProps) {
45
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
46
+ if (staticProps) _defineProperties(Constructor, staticProps);
47
+ return Constructor;
48
+ }
49
+ function _define_property(obj, key, value) {
50
+ if (key in obj) {
51
+ Object.defineProperty(obj, key, {
52
+ value: value,
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true
56
+ });
57
+ } else {
58
+ obj[key] = value;
59
+ }
60
+ return obj;
61
+ }
62
+ function _ts_generator(thisArg, body) {
63
+ var f, y, t, _ = {
64
+ label: 0,
65
+ sent: function() {
66
+ if (t[0] & 1) throw t[1];
67
+ return t[1];
68
+ },
69
+ trys: [],
70
+ ops: []
71
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
72
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
73
+ return this;
74
+ }), g;
75
+ function verb(n) {
76
+ return function(v) {
77
+ return step([
78
+ n,
79
+ v
80
+ ]);
81
+ };
82
+ }
83
+ function step(op) {
84
+ if (f) throw new TypeError("Generator is already executing.");
85
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
86
+ 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;
87
+ if (y = 0, t) op = [
88
+ op[0] & 2,
89
+ t.value
90
+ ];
91
+ switch(op[0]){
92
+ case 0:
93
+ case 1:
94
+ t = op;
95
+ break;
96
+ case 4:
97
+ _.label++;
98
+ return {
99
+ value: op[1],
100
+ done: false
101
+ };
102
+ case 5:
103
+ _.label++;
104
+ y = op[1];
105
+ op = [
106
+ 0
107
+ ];
108
+ continue;
109
+ case 7:
110
+ op = _.ops.pop();
111
+ _.trys.pop();
112
+ continue;
113
+ default:
114
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
115
+ _ = 0;
116
+ continue;
117
+ }
118
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
119
+ _.label = op[1];
120
+ break;
121
+ }
122
+ if (op[0] === 6 && _.label < t[1]) {
123
+ _.label = t[1];
124
+ t = op;
125
+ break;
126
+ }
127
+ if (t && _.label < t[2]) {
128
+ _.label = t[2];
129
+ _.ops.push(op);
130
+ break;
131
+ }
132
+ if (t[2]) _.ops.pop();
133
+ _.trys.pop();
134
+ continue;
135
+ }
136
+ op = body.call(thisArg, _);
137
+ } catch (e) {
138
+ op = [
139
+ 6,
140
+ e
141
+ ];
142
+ y = 0;
143
+ } finally{
144
+ f = t = 0;
145
+ }
146
+ if (op[0] & 5) throw op[1];
147
+ return {
148
+ value: op[0] ? op[1] : void 0,
149
+ done: true
150
+ };
151
+ }
152
+ }
153
+ import { BRAIN_EVENTS } from '@positronic/core';
154
+ /**
155
+ * Adapter that handles WEBHOOK events by registering webhooks
156
+ * with the MonitorDO for brain resumption
157
+ */ export var WebhookAdapter = /*#__PURE__*/ function() {
158
+ "use strict";
159
+ function WebhookAdapter(monitorStub) {
160
+ _class_call_check(this, WebhookAdapter);
161
+ _define_property(this, "monitorStub", void 0);
162
+ this.monitorStub = monitorStub;
163
+ }
164
+ _create_class(WebhookAdapter, [
165
+ {
166
+ key: "dispatch",
167
+ value: function dispatch(event) {
168
+ return _async_to_generator(function() {
169
+ var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, registration, err;
170
+ return _ts_generator(this, function(_state) {
171
+ switch(_state.label){
172
+ case 0:
173
+ // Only handle WEBHOOK events
174
+ if (event.type !== BRAIN_EVENTS.WEBHOOK) {
175
+ return [
176
+ 2
177
+ ];
178
+ }
179
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
180
+ _state.label = 1;
181
+ case 1:
182
+ _state.trys.push([
183
+ 1,
184
+ 6,
185
+ 7,
186
+ 8
187
+ ]);
188
+ _iterator = event.waitFor[Symbol.iterator]();
189
+ _state.label = 2;
190
+ case 2:
191
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
192
+ 3,
193
+ 5
194
+ ];
195
+ registration = _step.value;
196
+ return [
197
+ 4,
198
+ this.monitorStub.registerWebhook(registration.slug, registration.identifier, event.brainRunId)
199
+ ];
200
+ case 3:
201
+ _state.sent();
202
+ _state.label = 4;
203
+ case 4:
204
+ _iteratorNormalCompletion = true;
205
+ return [
206
+ 3,
207
+ 2
208
+ ];
209
+ case 5:
210
+ return [
211
+ 3,
212
+ 8
213
+ ];
214
+ case 6:
215
+ err = _state.sent();
216
+ _didIteratorError = true;
217
+ _iteratorError = err;
218
+ return [
219
+ 3,
220
+ 8
221
+ ];
222
+ case 7:
223
+ try {
224
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
225
+ _iterator.return();
226
+ }
227
+ } finally{
228
+ if (_didIteratorError) {
229
+ throw _iteratorError;
230
+ }
231
+ }
232
+ return [
233
+ 7
234
+ ];
235
+ case 8:
236
+ return [
237
+ 2
238
+ ];
239
+ }
240
+ });
241
+ }).call(this);
242
+ }
243
+ }
244
+ ]);
245
+ return WebhookAdapter;
246
+ }();
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAI1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,2BAA2B,CAAC;AAGpE,KAAK,QAAQ,GAAG;IACd,eAAe,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC;IACvD,UAAU,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC9C,WAAW,EAAE,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAChD,gBAAgB,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAmBF,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;AAupB/C,eAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAI1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,2BAA2B,CAAC;AAGpE,KAAK,QAAQ,GAAG;IACd,eAAe,EAAE,sBAAsB,CAAC,aAAa,CAAC,CAAC;IACvD,UAAU,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC9C,WAAW,EAAE,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAChD,gBAAgB,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAmBF,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;AAmwB/C,eAAe,GAAG,CAAC"}
@@ -7,6 +7,8 @@ import type { R2Bucket } from '@cloudflare/workers-types';
7
7
  export declare function setManifest(generatedManifest: PositronicManifest): void;
8
8
  export declare function getManifest(): PositronicManifest | null;
9
9
  export declare function setBrainRunner(runner: BrainRunner): void;
10
+ export declare function setWebhookManifest(manifest: Record<string, any>): void;
11
+ export declare function getWebhookManifest(): Record<string, any> | null;
10
12
  export interface Env {
11
13
  BRAIN_RUNNER_DO: DurableObjectNamespace;
12
14
  MONITOR_DO: DurableObjectNamespace<MonitorDO>;
@@ -17,9 +19,15 @@ export declare class BrainRunnerDO extends DurableObject<Env> {
17
19
  private sql;
18
20
  private brainRunId;
19
21
  private eventStreamAdapter;
22
+ private abortController;
20
23
  constructor(state: DurableObjectState, env: Env);
21
24
  private loadResourcesFromR2;
25
+ kill(): Promise<{
26
+ success: boolean;
27
+ message: string;
28
+ }>;
22
29
  start(brainTitle: string, brainRunId: string, initialData?: Record<string, any>): Promise<void>;
30
+ resume(brainRunId: string, webhookResponse: Record<string, any>): Promise<void>;
23
31
  fetch(request: Request): Promise<Response>;
24
32
  }
25
33
  //# sourceMappingURL=brain-runner-do.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"brain-runner-do.d.ts","sourceRoot":"","sources":["../../src/brain-runner-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAG1D,wBAAgB,WAAW,CAAC,iBAAiB,EAAE,kBAAkB,QAEhE;AAED,wBAAgB,WAAW,IAAI,kBAAkB,GAAG,IAAI,CAEvD;AAGD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,QAEjD;AAED,MAAM,WAAW,GAAG;IAClB,eAAe,EAAE,sBAAsB,CAAC;IACxC,UAAU,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC9C,WAAW,EAAE,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAChD,gBAAgB,EAAE,QAAQ,CAAC;CAC5B;AAwDD,qBAAa,aAAc,SAAQ,aAAa,CAAC,GAAG,CAAC;IACnD,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,kBAAkB,CAA4B;gBAE1C,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;YAOjC,mBAAmB;IA0E3B,KAAK,CACT,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IA2E7B,KAAK,CAAC,OAAO,EAAE,OAAO;CA4E7B"}
1
+ {"version":3,"file":"brain-runner-do.d.ts","sourceRoot":"","sources":["../../src/brain-runner-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAwC,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAG1D,wBAAgB,WAAW,CAAC,iBAAiB,EAAE,kBAAkB,QAEhE;AAED,wBAAgB,WAAW,IAAI,kBAAkB,GAAG,IAAI,CAEvD;AAGD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,QAEjD;AAGD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAE/D;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAE/D;AAED,MAAM,WAAW,GAAG;IAClB,eAAe,EAAE,sBAAsB,CAAC;IACxC,UAAU,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC9C,WAAW,EAAE,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAChD,gBAAgB,EAAE,QAAQ,CAAC;CAC5B;AAwDD,qBAAa,aAAc,SAAQ,aAAa,CAAC,GAAG,CAAC;IACnD,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,kBAAkB,CAA4B;IACtD,OAAO,CAAC,eAAe,CAAgC;gBAE3C,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;YAOjC,mBAAmB;IA0E3B,IAAI,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAStD,KAAK,CACT,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAuF7B,MAAM,CACV,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAuHhC,KAAK,CAAC,OAAO,EAAE,OAAO;CA4E7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/dev-server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA0M1E,qBAAa,mBAAoB,YAAW,mBAAmB;IAyB1C,cAAc,EAAE,MAAM;IAjBzC;;;;;;;;;;;OAWG;IAEH,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,gBAAgB,CAAwC;gBAE7C,cAAc,EAAE,MAAM;IAEnC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAiB7B,qBAAqB;YA4DrB,wBAAwB;YAqBxB,yBAAyB;YAQzB,2BAA2B;IAuBzC,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,wBAAwB;YASlB,0BAA0B;IA4BxC,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,gBAAgB;IA4BlB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkD3C,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GACjC,OAAO,CAAC,IAAI,CAAC;IAUV,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E7B,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIhD,OAAO,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIlD,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9C,WAAW,IAAI,OAAO,CAC1B,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,IAAI,CAAA;KAAE,CAAC,CAC5D;IAwCK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CrD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuC5C,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA0DnD"}
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../../src/dev-server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AA4M1E,qBAAa,mBAAoB,YAAW,mBAAmB;IAyB1C,cAAc,EAAE,MAAM;IAjBzC;;;;;;;;;;;OAWG;IAEH,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,cAAc,CAAwC;IAC9D,OAAO,CAAC,gBAAgB,CAAwC;gBAE7C,cAAc,EAAE,MAAM;IAEnC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAiB7B,qBAAqB;YA4DrB,wBAAwB;YAqBxB,yBAAyB;YAQzB,2BAA2B;IAuBzC,OAAO,CAAC,oBAAoB;IAU5B,OAAO,CAAC,wBAAwB;YASlB,0BAA0B;IA4BxC,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,gBAAgB;IA4BlB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkD3C,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GACjC,OAAO,CAAC,IAAI,CAAC;IAUV,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E7B,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIhD,OAAO,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAIlD,SAAS,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9C,WAAW,IAAI,OAAO,CAC1B,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,IAAI,CAAC;QAAC,SAAS,CAAC,EAAE,IAAI,CAAA;KAAE,CAAC,CAC5D;IAwCK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CrD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuC5C,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA0DnD"}
@@ -1,4 +1,4 @@
1
- export { BrainRunnerDO, setBrainRunner, setManifest, getManifest, } from './brain-runner-do.js';
1
+ export { BrainRunnerDO, setBrainRunner, setManifest, getManifest, setWebhookManifest, } from './brain-runner-do.js';
2
2
  export { MonitorDO } from './monitor-do.js';
3
3
  export { ScheduleDO } from './schedule-do.js';
4
4
  export { PositronicManifest, type BrainMetadata, type ResolutionResult } from './manifest.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,EACX,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -9,8 +9,23 @@ export declare class MonitorDO extends DurableObject<Env> {
9
9
  handleBrainEvent(event: BrainEvent<any>): void;
10
10
  private broadcastRunningBrains;
11
11
  fetch(request: Request): Promise<Response>;
12
- getLastEvent(brainRunId: string): Record<string, SqlStorageValue>;
12
+ getLastEvent(brainRunId: string): Record<string, SqlStorageValue> | null;
13
13
  history(brainTitle: string, limit?: number): Record<string, SqlStorageValue>[];
14
14
  activeRuns(brainTitle: string): Record<string, SqlStorageValue>[];
15
+ /**
16
+ * Register a webhook to wait for
17
+ * Called when a brain emits a WEBHOOK event
18
+ */
19
+ registerWebhook(slug: string, identifier: string, brainRunId: string): void;
20
+ /**
21
+ * Find a brain waiting for this webhook
22
+ * Returns the brain_run_id if found, null otherwise
23
+ */
24
+ findWaitingBrain(slug: string, identifier: string): string | null;
25
+ /**
26
+ * Clear all webhook registrations for a brain run
27
+ * Called when brain completes, errors, or is cancelled
28
+ */
29
+ clearWebhookRegistrations(brainRunId: string): void;
15
30
  }
16
31
  //# sourceMappingURL=monitor-do.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"monitor-do.d.ts","sourceRoot":"","sources":["../../src/monitor-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,GAAG;CAEnB;AAED,qBAAa,SAAU,SAAQ,aAAa,CAAC,GAAG,CAAC;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,kBAAkB,CAA4B;gBAE1C,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;IA2B/C,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC;YAiDzB,sBAAsB;IA0B9B,KAAK,CAAC,OAAO,EAAE,OAAO;IA2D5B,YAAY,CAAC,UAAU,EAAE,MAAM;IAY/B,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;IA6B9C,UAAU,CAAC,UAAU,EAAE,MAAM;CAwB9B"}
1
+ {"version":3,"file":"monitor-do.d.ts","sourceRoot":"","sources":["../../src/monitor-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,GAAG;CAEnB;AAED,qBAAa,SAAU,SAAQ,aAAa,CAAC,GAAG,CAAC;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,kBAAkB,CAA4B;gBAE1C,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;IAyC/C,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC;YA4DzB,sBAAsB;IA0B9B,KAAK,CAAC,OAAO,EAAE,OAAO;IA0D5B,YAAY,CAAC,UAAU,EAAE,MAAM;IAc/B,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;IA6B9C,UAAU,CAAC,UAAU,EAAE,MAAM;IAyB7B;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAapE;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAiBjE;;;OAGG;IACH,yBAAyB,CAAC,UAAU,EAAE,MAAM;CAS7C"}
@@ -0,0 +1,14 @@
1
+ import type { Adapter, BrainEvent } from '@positronic/core';
2
+ import type { MonitorDO } from './monitor-do.js';
3
+ /**
4
+ * Adapter that handles WEBHOOK events by registering webhooks
5
+ * with the MonitorDO for brain resumption
6
+ */
7
+ export declare class WebhookAdapter implements Adapter {
8
+ private monitorStub;
9
+ constructor(monitorStub: {
10
+ registerWebhook: MonitorDO['registerWebhook'];
11
+ });
12
+ dispatch(event: BrainEvent): Promise<void>;
13
+ }
14
+ //# sourceMappingURL=webhook-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-adapter.d.ts","sourceRoot":"","sources":["../../src/webhook-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;GAGG;AACH,qBAAa,cAAe,YAAW,OAAO;IAChC,OAAO,CAAC,WAAW;gBAAX,WAAW,EAAE;QAAE,eAAe,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAA;KAAE;IAE5E,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAejD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@positronic/cloudflare",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -31,9 +31,9 @@
31
31
  "clean": "rm -rf tsconfig.tsbuildinfo dist"
32
32
  },
33
33
  "dependencies": {
34
- "@positronic/core": "^0.0.18",
35
- "@positronic/spec": "^0.0.18",
36
- "@positronic/template-new-project": "^0.0.18",
34
+ "@positronic/core": "^0.0.20",
35
+ "@positronic/spec": "^0.0.20",
36
+ "@positronic/template-new-project": "^0.0.20",
37
37
  "aws4fetch": "^1.0.18",
38
38
  "caz": "^2.0.0",
39
39
  "cron-schedule": "^5.0.4",