@positronic/cloudflare 0.0.51 → 0.0.53

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 (42) hide show
  1. package/dist/src/api/brains.js +1003 -0
  2. package/dist/src/api/bundle.js +204 -0
  3. package/dist/src/api/index.js +149 -0
  4. package/dist/src/api/pages.js +681 -0
  5. package/dist/src/api/resources.js +778 -0
  6. package/dist/src/api/secrets.js +707 -0
  7. package/dist/src/api/types.js +1 -0
  8. package/dist/src/api/webhooks/coordination.js +267 -0
  9. package/dist/src/api/webhooks/index.js +277 -0
  10. package/dist/src/api/webhooks/system.js +248 -0
  11. package/dist/src/brain-runner-do.js +5 -5
  12. package/dist/src/dev-server.js +206 -10
  13. package/dist/src/index.js +2 -4
  14. package/dist/src/monitor-do.js +23 -7
  15. package/dist/types/api/brains.d.ts +7 -0
  16. package/dist/types/api/brains.d.ts.map +1 -0
  17. package/dist/types/api/bundle.d.ts +7 -0
  18. package/dist/types/api/bundle.d.ts.map +1 -0
  19. package/dist/types/api/index.d.ts +8 -0
  20. package/dist/types/api/index.d.ts.map +1 -0
  21. package/dist/types/api/pages.d.ts +7 -0
  22. package/dist/types/api/pages.d.ts.map +1 -0
  23. package/dist/types/api/resources.d.ts +7 -0
  24. package/dist/types/api/resources.d.ts.map +1 -0
  25. package/dist/types/api/secrets.d.ts +7 -0
  26. package/dist/types/api/secrets.d.ts.map +1 -0
  27. package/dist/types/{api.d.ts → api/types.d.ts} +15 -9
  28. package/dist/types/api/types.d.ts.map +1 -0
  29. package/dist/types/api/webhooks/coordination.d.ts +32 -0
  30. package/dist/types/api/webhooks/coordination.d.ts.map +1 -0
  31. package/dist/types/api/webhooks/index.d.ts +7 -0
  32. package/dist/types/api/webhooks/index.d.ts.map +1 -0
  33. package/dist/types/api/webhooks/system.d.ts +7 -0
  34. package/dist/types/api/webhooks/system.d.ts.map +1 -0
  35. package/dist/types/dev-server.d.ts +5 -0
  36. package/dist/types/dev-server.d.ts.map +1 -1
  37. package/dist/types/index.d.ts +3 -5
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/types/monitor-do.d.ts.map +1 -1
  40. package/package.json +4 -4
  41. package/dist/src/api.js +0 -2839
  42. package/dist/types/api.d.ts.map +0 -1
@@ -0,0 +1,1003 @@
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 _define_property(obj, key, value) {
31
+ if (key in obj) {
32
+ Object.defineProperty(obj, key, {
33
+ value: value,
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true
37
+ });
38
+ } else {
39
+ obj[key] = value;
40
+ }
41
+ return obj;
42
+ }
43
+ function _instanceof(left, right) {
44
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
45
+ return !!right[Symbol.hasInstance](left);
46
+ } else {
47
+ return left instanceof right;
48
+ }
49
+ }
50
+ function _object_spread(target) {
51
+ for(var i = 1; i < arguments.length; i++){
52
+ var source = arguments[i] != null ? arguments[i] : {};
53
+ var ownKeys = Object.keys(source);
54
+ if (typeof Object.getOwnPropertySymbols === "function") {
55
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
56
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
57
+ }));
58
+ }
59
+ ownKeys.forEach(function(key) {
60
+ _define_property(target, key, source[key]);
61
+ });
62
+ }
63
+ return target;
64
+ }
65
+ function _ts_generator(thisArg, body) {
66
+ var f, y, t, _ = {
67
+ label: 0,
68
+ sent: function() {
69
+ if (t[0] & 1) throw t[1];
70
+ return t[1];
71
+ },
72
+ trys: [],
73
+ ops: []
74
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
75
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
76
+ return this;
77
+ }), g;
78
+ function verb(n) {
79
+ return function(v) {
80
+ return step([
81
+ n,
82
+ v
83
+ ]);
84
+ };
85
+ }
86
+ function step(op) {
87
+ if (f) throw new TypeError("Generator is already executing.");
88
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
89
+ 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;
90
+ if (y = 0, t) op = [
91
+ op[0] & 2,
92
+ t.value
93
+ ];
94
+ switch(op[0]){
95
+ case 0:
96
+ case 1:
97
+ t = op;
98
+ break;
99
+ case 4:
100
+ _.label++;
101
+ return {
102
+ value: op[1],
103
+ done: false
104
+ };
105
+ case 5:
106
+ _.label++;
107
+ y = op[1];
108
+ op = [
109
+ 0
110
+ ];
111
+ continue;
112
+ case 7:
113
+ op = _.ops.pop();
114
+ _.trys.pop();
115
+ continue;
116
+ default:
117
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
118
+ _ = 0;
119
+ continue;
120
+ }
121
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
122
+ _.label = op[1];
123
+ break;
124
+ }
125
+ if (op[0] === 6 && _.label < t[1]) {
126
+ _.label = t[1];
127
+ t = op;
128
+ break;
129
+ }
130
+ if (t && _.label < t[2]) {
131
+ _.label = t[2];
132
+ _.ops.push(op);
133
+ break;
134
+ }
135
+ if (t[2]) _.ops.pop();
136
+ _.trys.pop();
137
+ continue;
138
+ }
139
+ op = body.call(thisArg, _);
140
+ } catch (e) {
141
+ op = [
142
+ 6,
143
+ e
144
+ ];
145
+ y = 0;
146
+ } finally{
147
+ f = t = 0;
148
+ }
149
+ if (op[0] & 5) throw op[1];
150
+ return {
151
+ value: op[0] ? op[1] : void 0,
152
+ done: true
153
+ };
154
+ }
155
+ }
156
+ import { Hono } from 'hono';
157
+ import { v4 as uuidv4 } from 'uuid';
158
+ import { parseCronExpression } from 'cron-schedule';
159
+ import Fuse from 'fuse.js';
160
+ import { getManifest } from '../brain-runner-do.js';
161
+ var brains = new Hono();
162
+ brains.post('/runs', function(context) {
163
+ return _async_to_generator(function() {
164
+ var requestBody, options, identifier, manifest, resolution, brain, brainRunId, namespace, doId, stub, initialData, brainTitle, response;
165
+ return _ts_generator(this, function(_state) {
166
+ switch(_state.label){
167
+ case 0:
168
+ return [
169
+ 4,
170
+ context.req.json()
171
+ ];
172
+ case 1:
173
+ requestBody = _state.sent();
174
+ options = requestBody.options;
175
+ // Support both identifier and brainTitle for backward compatibility
176
+ identifier = requestBody.identifier || requestBody.brainTitle;
177
+ if (!identifier) {
178
+ return [
179
+ 2,
180
+ context.json({
181
+ error: 'Missing identifier or brainTitle in request body'
182
+ }, 400)
183
+ ];
184
+ }
185
+ // Validate that the brain exists before starting it
186
+ manifest = getManifest();
187
+ if (!manifest) {
188
+ return [
189
+ 2,
190
+ context.json({
191
+ error: 'Manifest not initialized'
192
+ }, 500)
193
+ ];
194
+ }
195
+ // Resolve the identifier to find the brain
196
+ resolution = manifest.resolve(identifier);
197
+ if (resolution.matchType === 'none') {
198
+ return [
199
+ 2,
200
+ context.json({
201
+ error: "Brain '".concat(identifier, "' not found")
202
+ }, 404)
203
+ ];
204
+ }
205
+ if (resolution.matchType === 'multiple') {
206
+ return [
207
+ 2,
208
+ context.json({
209
+ error: 'Multiple brains match the identifier',
210
+ matchType: 'multiple',
211
+ candidates: resolution.candidates
212
+ }, 409)
213
+ ];
214
+ }
215
+ brain = resolution.brain;
216
+ brainRunId = uuidv4();
217
+ namespace = context.env.BRAIN_RUNNER_DO;
218
+ doId = namespace.idFromName(brainRunId);
219
+ stub = namespace.get(doId);
220
+ // Pass options to the brain runner if provided
221
+ initialData = options ? {
222
+ options: options
223
+ } : undefined;
224
+ // Get the actual brain title from the resolved brain
225
+ brainTitle = brain.title || identifier;
226
+ return [
227
+ 4,
228
+ stub.start(brainTitle, brainRunId, initialData)
229
+ ];
230
+ case 2:
231
+ _state.sent();
232
+ response = {
233
+ brainRunId: brainRunId
234
+ };
235
+ return [
236
+ 2,
237
+ context.json(response, 201)
238
+ ];
239
+ }
240
+ });
241
+ })();
242
+ });
243
+ brains.post('/runs/rerun', function(context) {
244
+ return _async_to_generator(function() {
245
+ var requestBody, runId, startsAt, stopsAfter, identifier, manifest, resolution, brain, monitorId, monitorStub, existingRun, newBrainRunId, namespace, doId, stub, rerunOptions, brainTitle, response;
246
+ return _ts_generator(this, function(_state) {
247
+ switch(_state.label){
248
+ case 0:
249
+ return [
250
+ 4,
251
+ context.req.json()
252
+ ];
253
+ case 1:
254
+ requestBody = _state.sent();
255
+ runId = requestBody.runId, startsAt = requestBody.startsAt, stopsAfter = requestBody.stopsAfter;
256
+ // Support both identifier and brainTitle for backward compatibility
257
+ identifier = requestBody.identifier || requestBody.brainTitle;
258
+ if (!identifier) {
259
+ return [
260
+ 2,
261
+ context.json({
262
+ error: 'Missing identifier or brainTitle in request body'
263
+ }, 400)
264
+ ];
265
+ }
266
+ // Validate that the brain exists
267
+ manifest = getManifest();
268
+ if (!manifest) {
269
+ return [
270
+ 2,
271
+ context.json({
272
+ error: 'Manifest not initialized'
273
+ }, 500)
274
+ ];
275
+ }
276
+ // Resolve the identifier to find the brain
277
+ resolution = manifest.resolve(identifier);
278
+ if (resolution.matchType === 'none') {
279
+ return [
280
+ 2,
281
+ context.json({
282
+ error: "Brain '".concat(identifier, "' not found")
283
+ }, 404)
284
+ ];
285
+ }
286
+ if (resolution.matchType === 'multiple') {
287
+ return [
288
+ 2,
289
+ context.json({
290
+ error: 'Multiple brains match the identifier',
291
+ matchType: 'multiple',
292
+ candidates: resolution.candidates
293
+ }, 409)
294
+ ];
295
+ }
296
+ brain = resolution.brain;
297
+ if (!runId) return [
298
+ 3,
299
+ 3
300
+ ];
301
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
302
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
303
+ return [
304
+ 4,
305
+ monitorStub.getLastEvent(runId)
306
+ ];
307
+ case 2:
308
+ existingRun = _state.sent();
309
+ if (!existingRun) {
310
+ return [
311
+ 2,
312
+ context.json({
313
+ error: "Brain run '".concat(runId, "' not found")
314
+ }, 404)
315
+ ];
316
+ }
317
+ _state.label = 3;
318
+ case 3:
319
+ // Create a new brain run with rerun parameters
320
+ newBrainRunId = uuidv4();
321
+ namespace = context.env.BRAIN_RUNNER_DO;
322
+ doId = namespace.idFromName(newBrainRunId);
323
+ stub = namespace.get(doId);
324
+ // Start the brain with rerun options
325
+ rerunOptions = _object_spread({}, runId && {
326
+ originalRunId: runId
327
+ }, startsAt !== undefined && {
328
+ startsAt: startsAt
329
+ }, stopsAfter !== undefined && {
330
+ stopsAfter: stopsAfter
331
+ });
332
+ // Get the actual brain title from the resolved brain
333
+ brainTitle = brain.title || identifier;
334
+ return [
335
+ 4,
336
+ stub.start(brainTitle, newBrainRunId, rerunOptions)
337
+ ];
338
+ case 4:
339
+ _state.sent();
340
+ response = {
341
+ brainRunId: newBrainRunId
342
+ };
343
+ return [
344
+ 2,
345
+ context.json(response, 201)
346
+ ];
347
+ }
348
+ });
349
+ })();
350
+ });
351
+ brains.get('/runs/:runId/watch', function(context) {
352
+ return _async_to_generator(function() {
353
+ var runId, namespace, doId, stub, response;
354
+ return _ts_generator(this, function(_state) {
355
+ switch(_state.label){
356
+ case 0:
357
+ runId = context.req.param('runId');
358
+ namespace = context.env.BRAIN_RUNNER_DO;
359
+ doId = namespace.idFromName(runId);
360
+ stub = namespace.get(doId);
361
+ return [
362
+ 4,
363
+ stub.fetch(new Request("http://do/watch"))
364
+ ];
365
+ case 1:
366
+ response = _state.sent();
367
+ return [
368
+ 2,
369
+ response
370
+ ];
371
+ }
372
+ });
373
+ })();
374
+ });
375
+ brains.get('/runs/:runId', function(context) {
376
+ return _async_to_generator(function() {
377
+ var runId, monitorId, monitorStub, run;
378
+ return _ts_generator(this, function(_state) {
379
+ switch(_state.label){
380
+ case 0:
381
+ runId = context.req.param('runId');
382
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
383
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
384
+ return [
385
+ 4,
386
+ monitorStub.getRun(runId)
387
+ ];
388
+ case 1:
389
+ run = _state.sent();
390
+ if (!run) {
391
+ return [
392
+ 2,
393
+ context.json({
394
+ error: "Brain run '".concat(runId, "' not found")
395
+ }, 404)
396
+ ];
397
+ }
398
+ return [
399
+ 2,
400
+ context.json(run)
401
+ ];
402
+ }
403
+ });
404
+ })();
405
+ });
406
+ brains.delete('/runs/:runId', function(context) {
407
+ return _async_to_generator(function() {
408
+ var runId, monitorId, monitorStub, existingRun, namespace, doId, stub, result, error;
409
+ return _ts_generator(this, function(_state) {
410
+ switch(_state.label){
411
+ case 0:
412
+ runId = context.req.param('runId');
413
+ // First check if the run exists in the monitor
414
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
415
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
416
+ return [
417
+ 4,
418
+ monitorStub.getLastEvent(runId)
419
+ ];
420
+ case 1:
421
+ existingRun = _state.sent();
422
+ if (!existingRun) {
423
+ return [
424
+ 2,
425
+ context.json({
426
+ error: "Brain run '".concat(runId, "' not found")
427
+ }, 404)
428
+ ];
429
+ }
430
+ // Now try to kill it - pass runId and brainTitle as fallbacks in case
431
+ // the DO's SQLite state is missing (zombie brain scenario)
432
+ namespace = context.env.BRAIN_RUNNER_DO;
433
+ doId = namespace.idFromName(runId);
434
+ stub = namespace.get(doId);
435
+ _state.label = 2;
436
+ case 2:
437
+ _state.trys.push([
438
+ 2,
439
+ 4,
440
+ ,
441
+ 5
442
+ ]);
443
+ return [
444
+ 4,
445
+ stub.kill(runId, existingRun.brain_title)
446
+ ];
447
+ case 3:
448
+ result = _state.sent();
449
+ if (!result.success) {
450
+ return [
451
+ 2,
452
+ context.json({
453
+ error: result.message
454
+ }, 409)
455
+ ];
456
+ }
457
+ // Return 204 No Content on success
458
+ return [
459
+ 2,
460
+ new Response(null, {
461
+ status: 204
462
+ })
463
+ ];
464
+ case 4:
465
+ error = _state.sent();
466
+ console.error("Error killing brain run ".concat(runId, ":"), error);
467
+ return [
468
+ 2,
469
+ context.json({
470
+ error: 'Failed to kill brain run'
471
+ }, 500)
472
+ ];
473
+ case 5:
474
+ return [
475
+ 2
476
+ ];
477
+ }
478
+ });
479
+ })();
480
+ });
481
+ brains.get('/:identifier/history', function(context) {
482
+ return _async_to_generator(function() {
483
+ var identifier, limit, manifest, resolution, brain, brainTitle, monitorId, monitorStub, runs;
484
+ return _ts_generator(this, function(_state) {
485
+ switch(_state.label){
486
+ case 0:
487
+ identifier = context.req.param('identifier');
488
+ limit = Number(context.req.query('limit') || '10');
489
+ // Resolve the identifier to get the actual brain title
490
+ manifest = getManifest();
491
+ if (!manifest) {
492
+ return [
493
+ 2,
494
+ context.json({
495
+ error: 'Manifest not initialized'
496
+ }, 500)
497
+ ];
498
+ }
499
+ resolution = manifest.resolve(identifier);
500
+ if (resolution.matchType === 'none') {
501
+ return [
502
+ 2,
503
+ context.json({
504
+ error: "Brain '".concat(identifier, "' not found")
505
+ }, 404)
506
+ ];
507
+ }
508
+ if (resolution.matchType === 'multiple') {
509
+ return [
510
+ 2,
511
+ context.json({
512
+ error: 'Multiple brains match the identifier',
513
+ matchType: 'multiple',
514
+ candidates: resolution.candidates
515
+ }, 300)
516
+ ];
517
+ }
518
+ // Get the actual brain title
519
+ brain = resolution.brain;
520
+ brainTitle = brain.title || identifier;
521
+ // Get the monitor singleton instance
522
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
523
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
524
+ return [
525
+ 4,
526
+ monitorStub.history(brainTitle, limit)
527
+ ];
528
+ case 1:
529
+ runs = _state.sent();
530
+ return [
531
+ 2,
532
+ context.json({
533
+ runs: runs
534
+ })
535
+ ];
536
+ }
537
+ });
538
+ })();
539
+ });
540
+ brains.get('/:identifier/active-runs', function(context) {
541
+ return _async_to_generator(function() {
542
+ var identifier, manifest, resolution, brain, brainTitle, monitorId, monitorStub, runs;
543
+ return _ts_generator(this, function(_state) {
544
+ switch(_state.label){
545
+ case 0:
546
+ identifier = context.req.param('identifier');
547
+ // Resolve the identifier to get the actual brain title
548
+ manifest = getManifest();
549
+ if (!manifest) {
550
+ return [
551
+ 2,
552
+ context.json({
553
+ error: 'Manifest not initialized'
554
+ }, 500)
555
+ ];
556
+ }
557
+ resolution = manifest.resolve(identifier);
558
+ if (resolution.matchType === 'none') {
559
+ return [
560
+ 2,
561
+ context.json({
562
+ error: "Brain '".concat(identifier, "' not found")
563
+ }, 404)
564
+ ];
565
+ }
566
+ if (resolution.matchType === 'multiple') {
567
+ return [
568
+ 2,
569
+ context.json({
570
+ error: 'Multiple brains match the identifier',
571
+ matchType: 'multiple',
572
+ candidates: resolution.candidates
573
+ }, 300)
574
+ ];
575
+ }
576
+ // Get the actual brain title
577
+ brain = resolution.brain;
578
+ brainTitle = brain.title || identifier;
579
+ // Get the monitor singleton instance
580
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
581
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
582
+ return [
583
+ 4,
584
+ monitorStub.activeRuns(brainTitle)
585
+ ];
586
+ case 1:
587
+ runs = _state.sent();
588
+ return [
589
+ 2,
590
+ context.json({
591
+ runs: runs
592
+ })
593
+ ];
594
+ }
595
+ });
596
+ })();
597
+ });
598
+ brains.get('/watch', function(context) {
599
+ return _async_to_generator(function() {
600
+ var monitorId, monitorStub, response;
601
+ return _ts_generator(this, function(_state) {
602
+ switch(_state.label){
603
+ case 0:
604
+ monitorId = context.env.MONITOR_DO.idFromName('singleton');
605
+ monitorStub = context.env.MONITOR_DO.get(monitorId);
606
+ return [
607
+ 4,
608
+ monitorStub.fetch(new Request("http://do/watch"))
609
+ ];
610
+ case 1:
611
+ response = _state.sent();
612
+ return [
613
+ 2,
614
+ response
615
+ ];
616
+ }
617
+ });
618
+ })();
619
+ });
620
+ brains.get('/', function(context) {
621
+ return _async_to_generator(function() {
622
+ var _context_req_query, manifest, query, brainFilenames, brainList, validBrains, queryLower, exactMatch, fuse, results;
623
+ return _ts_generator(this, function(_state) {
624
+ switch(_state.label){
625
+ case 0:
626
+ manifest = getManifest();
627
+ if (!manifest) {
628
+ return [
629
+ 2,
630
+ context.json({
631
+ error: 'Manifest not initialized'
632
+ }, 500)
633
+ ];
634
+ }
635
+ query = (_context_req_query = context.req.query('q')) === null || _context_req_query === void 0 ? void 0 : _context_req_query.trim();
636
+ brainFilenames = manifest.list();
637
+ return [
638
+ 4,
639
+ Promise.all(brainFilenames.map(function(filename) {
640
+ return _async_to_generator(function() {
641
+ var brain, structure;
642
+ return _ts_generator(this, function(_state) {
643
+ switch(_state.label){
644
+ case 0:
645
+ return [
646
+ 4,
647
+ manifest.import(filename)
648
+ ];
649
+ case 1:
650
+ brain = _state.sent();
651
+ if (!brain) {
652
+ return [
653
+ 2,
654
+ null
655
+ ];
656
+ }
657
+ structure = brain.structure;
658
+ return [
659
+ 2,
660
+ {
661
+ filename: filename,
662
+ title: structure.title,
663
+ description: structure.description || "".concat(structure.title, " brain")
664
+ }
665
+ ];
666
+ }
667
+ });
668
+ })();
669
+ }))
670
+ ];
671
+ case 1:
672
+ brainList = _state.sent();
673
+ // Filter out any null entries
674
+ validBrains = brainList.filter(function(brain) {
675
+ return brain !== null;
676
+ });
677
+ // If no query, return all brains
678
+ if (!query) {
679
+ return [
680
+ 2,
681
+ context.json({
682
+ brains: validBrains,
683
+ count: validBrains.length
684
+ })
685
+ ];
686
+ }
687
+ // Check for exact match on title or filename first
688
+ queryLower = query.toLowerCase();
689
+ exactMatch = validBrains.find(function(brain) {
690
+ return brain.title.toLowerCase() === queryLower || brain.filename.toLowerCase() === queryLower;
691
+ });
692
+ if (exactMatch) {
693
+ return [
694
+ 2,
695
+ context.json({
696
+ brains: [
697
+ exactMatch
698
+ ],
699
+ count: 1
700
+ })
701
+ ];
702
+ }
703
+ // Use fuse.js for fuzzy matching with weighted keys
704
+ fuse = new Fuse(validBrains, {
705
+ keys: [
706
+ {
707
+ name: 'title',
708
+ weight: 2
709
+ },
710
+ {
711
+ name: 'filename',
712
+ weight: 2
713
+ },
714
+ {
715
+ name: 'description',
716
+ weight: 0.5
717
+ }
718
+ ],
719
+ includeScore: true,
720
+ threshold: 0.4,
721
+ ignoreLocation: true
722
+ });
723
+ results = fuse.search(query);
724
+ // If no results, return empty
725
+ if (results.length === 0) {
726
+ return [
727
+ 2,
728
+ context.json({
729
+ brains: [],
730
+ count: 0
731
+ })
732
+ ];
733
+ }
734
+ // If top result is significantly better than others (score difference > 0.2),
735
+ // or there's only one result, return just that one
736
+ if (results.length === 1 || results.length > 1 && results[1].score - results[0].score > 0.2) {
737
+ return [
738
+ 2,
739
+ context.json({
740
+ brains: [
741
+ results[0].item
742
+ ],
743
+ count: 1
744
+ })
745
+ ];
746
+ }
747
+ // Return all matching results, sorted by score (best first)
748
+ return [
749
+ 2,
750
+ context.json({
751
+ brains: results.map(function(r) {
752
+ return r.item;
753
+ }),
754
+ count: results.length
755
+ })
756
+ ];
757
+ }
758
+ });
759
+ })();
760
+ });
761
+ // Schedule endpoints
762
+ // Create a new schedule
763
+ brains.post('/schedules', function(context) {
764
+ return _async_to_generator(function() {
765
+ var body, cronExpression, identifier, manifest, resolution, brain, brainTitle, scheduleId, scheduleStub, schedule, error, errorMessage;
766
+ return _ts_generator(this, function(_state) {
767
+ switch(_state.label){
768
+ case 0:
769
+ _state.trys.push([
770
+ 0,
771
+ 3,
772
+ ,
773
+ 4
774
+ ]);
775
+ return [
776
+ 4,
777
+ context.req.json()
778
+ ];
779
+ case 1:
780
+ body = _state.sent();
781
+ cronExpression = body.cronExpression;
782
+ // Support both identifier and brainTitle for backward compatibility
783
+ identifier = body.identifier || body.brainTitle;
784
+ if (!identifier) {
785
+ return [
786
+ 2,
787
+ context.json({
788
+ error: 'Missing required field "identifier" or "brainTitle"'
789
+ }, 400)
790
+ ];
791
+ }
792
+ if (!cronExpression) {
793
+ return [
794
+ 2,
795
+ context.json({
796
+ error: 'Missing required field "cronExpression"'
797
+ }, 400)
798
+ ];
799
+ }
800
+ // Validate cron expression before calling DO
801
+ try {
802
+ parseCronExpression(cronExpression);
803
+ } catch (e) {
804
+ return [
805
+ 2,
806
+ context.json({
807
+ error: "Invalid cron expression: ".concat(cronExpression)
808
+ }, 400)
809
+ ];
810
+ }
811
+ // Resolve the identifier to get the actual brain title
812
+ manifest = getManifest();
813
+ if (!manifest) {
814
+ return [
815
+ 2,
816
+ context.json({
817
+ error: 'Manifest not initialized'
818
+ }, 500)
819
+ ];
820
+ }
821
+ resolution = manifest.resolve(identifier);
822
+ if (resolution.matchType === 'none') {
823
+ return [
824
+ 2,
825
+ context.json({
826
+ error: "Brain '".concat(identifier, "' not found")
827
+ }, 404)
828
+ ];
829
+ }
830
+ if (resolution.matchType === 'multiple') {
831
+ return [
832
+ 2,
833
+ context.json({
834
+ error: 'Multiple brains match the identifier',
835
+ matchType: 'multiple',
836
+ candidates: resolution.candidates
837
+ }, 409)
838
+ ];
839
+ }
840
+ // Get the actual brain title
841
+ brain = resolution.brain;
842
+ brainTitle = brain.title || identifier;
843
+ // Get the schedule singleton instance
844
+ scheduleId = context.env.SCHEDULE_DO.idFromName('singleton');
845
+ scheduleStub = context.env.SCHEDULE_DO.get(scheduleId);
846
+ return [
847
+ 4,
848
+ scheduleStub.createSchedule(brainTitle, cronExpression)
849
+ ];
850
+ case 2:
851
+ schedule = _state.sent();
852
+ return [
853
+ 2,
854
+ context.json(schedule, 201)
855
+ ];
856
+ case 3:
857
+ error = _state.sent();
858
+ errorMessage = _instanceof(error, Error) ? error.message : 'Failed to create schedule';
859
+ return [
860
+ 2,
861
+ context.json({
862
+ error: errorMessage
863
+ }, 400)
864
+ ];
865
+ case 4:
866
+ return [
867
+ 2
868
+ ];
869
+ }
870
+ });
871
+ })();
872
+ });
873
+ // List all schedules
874
+ brains.get('/schedules', function(context) {
875
+ return _async_to_generator(function() {
876
+ var scheduleId, scheduleStub, result;
877
+ return _ts_generator(this, function(_state) {
878
+ switch(_state.label){
879
+ case 0:
880
+ scheduleId = context.env.SCHEDULE_DO.idFromName('singleton');
881
+ scheduleStub = context.env.SCHEDULE_DO.get(scheduleId);
882
+ return [
883
+ 4,
884
+ scheduleStub.listSchedules()
885
+ ];
886
+ case 1:
887
+ result = _state.sent();
888
+ return [
889
+ 2,
890
+ context.json(result)
891
+ ];
892
+ }
893
+ });
894
+ })();
895
+ });
896
+ // Get scheduled run history - MUST be before :scheduleId route
897
+ brains.get('/schedules/runs', function(context) {
898
+ return _async_to_generator(function() {
899
+ var scheduleIdParam, limit, scheduleDoId, scheduleStub, result;
900
+ return _ts_generator(this, function(_state) {
901
+ switch(_state.label){
902
+ case 0:
903
+ scheduleIdParam = context.req.query('scheduleId');
904
+ limit = Number(context.req.query('limit') || '100');
905
+ scheduleDoId = context.env.SCHEDULE_DO.idFromName('singleton');
906
+ scheduleStub = context.env.SCHEDULE_DO.get(scheduleDoId);
907
+ return [
908
+ 4,
909
+ scheduleStub.getAllRuns(scheduleIdParam, limit)
910
+ ];
911
+ case 1:
912
+ result = _state.sent();
913
+ return [
914
+ 2,
915
+ context.json(result)
916
+ ];
917
+ }
918
+ });
919
+ })();
920
+ });
921
+ // Delete a schedule
922
+ brains.delete('/schedules/:scheduleId', function(context) {
923
+ return _async_to_generator(function() {
924
+ var scheduleIdParam, scheduleDoId, scheduleStub, deleted;
925
+ return _ts_generator(this, function(_state) {
926
+ switch(_state.label){
927
+ case 0:
928
+ scheduleIdParam = context.req.param('scheduleId');
929
+ scheduleDoId = context.env.SCHEDULE_DO.idFromName('singleton');
930
+ scheduleStub = context.env.SCHEDULE_DO.get(scheduleDoId);
931
+ return [
932
+ 4,
933
+ scheduleStub.deleteSchedule(scheduleIdParam)
934
+ ];
935
+ case 1:
936
+ deleted = _state.sent();
937
+ if (!deleted) {
938
+ return [
939
+ 2,
940
+ context.json({
941
+ error: 'Schedule not found'
942
+ }, 404)
943
+ ];
944
+ }
945
+ return [
946
+ 2,
947
+ new Response(null, {
948
+ status: 204
949
+ })
950
+ ];
951
+ }
952
+ });
953
+ })();
954
+ });
955
+ brains.get('/:identifier', function(context) {
956
+ return _async_to_generator(function() {
957
+ var identifier, manifest, resolution, brain, structure;
958
+ return _ts_generator(this, function(_state) {
959
+ identifier = context.req.param('identifier');
960
+ manifest = getManifest();
961
+ if (!manifest) {
962
+ return [
963
+ 2,
964
+ context.json({
965
+ error: 'Manifest not initialized'
966
+ }, 500)
967
+ ];
968
+ }
969
+ // Resolve the identifier to find the brain
970
+ resolution = manifest.resolve(identifier);
971
+ if (resolution.matchType === 'none') {
972
+ return [
973
+ 2,
974
+ context.json({
975
+ error: "Brain '".concat(identifier, "' not found")
976
+ }, 404)
977
+ ];
978
+ }
979
+ if (resolution.matchType === 'multiple') {
980
+ return [
981
+ 2,
982
+ context.json({
983
+ error: 'Multiple brains match the identifier',
984
+ matchType: 'multiple',
985
+ candidates: resolution.candidates
986
+ }, 300)
987
+ ];
988
+ }
989
+ brain = resolution.brain;
990
+ // Get the brain structure
991
+ structure = brain.structure;
992
+ return [
993
+ 2,
994
+ context.json({
995
+ title: structure.title,
996
+ description: structure.description || "".concat(structure.title, " brain"),
997
+ steps: structure.steps
998
+ })
999
+ ];
1000
+ });
1001
+ })();
1002
+ });
1003
+ export default brains;