@positronic/cloudflare 0.0.3 → 0.0.5

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 (52) hide show
  1. package/dist/src/api.js +1270 -0
  2. package/dist/src/brain-runner-do.js +654 -0
  3. package/dist/src/dev-server.js +1357 -0
  4. package/{src/index.ts → dist/src/index.js} +1 -6
  5. package/dist/src/manifest.js +278 -0
  6. package/dist/src/monitor-do.js +408 -0
  7. package/{src/node-index.ts → dist/src/node-index.js} +3 -7
  8. package/dist/src/r2-loader.js +207 -0
  9. package/dist/src/schedule-do.js +705 -0
  10. package/dist/src/sqlite-adapter.js +69 -0
  11. package/dist/types/api.d.ts +21 -0
  12. package/dist/types/api.d.ts.map +1 -0
  13. package/dist/types/brain-runner-do.d.ts +25 -0
  14. package/dist/types/brain-runner-do.d.ts.map +1 -0
  15. package/dist/types/dev-server.d.ts +45 -0
  16. package/dist/types/dev-server.d.ts.map +1 -0
  17. package/dist/types/index.d.ts +7 -0
  18. package/dist/types/index.d.ts.map +1 -0
  19. package/dist/types/manifest.d.ts +11 -0
  20. package/dist/types/manifest.d.ts.map +1 -0
  21. package/dist/types/monitor-do.d.ts +16 -0
  22. package/dist/types/monitor-do.d.ts.map +1 -0
  23. package/dist/types/node-index.d.ts +10 -0
  24. package/dist/types/node-index.d.ts.map +1 -0
  25. package/dist/types/r2-loader.d.ts +10 -0
  26. package/dist/types/r2-loader.d.ts.map +1 -0
  27. package/dist/types/schedule-do.d.ts +47 -0
  28. package/dist/types/schedule-do.d.ts.map +1 -0
  29. package/dist/types/sqlite-adapter.d.ts +10 -0
  30. package/dist/types/sqlite-adapter.d.ts.map +1 -0
  31. package/package.json +5 -1
  32. package/src/api.ts +0 -579
  33. package/src/brain-runner-do.ts +0 -309
  34. package/src/dev-server.ts +0 -776
  35. package/src/manifest.ts +0 -69
  36. package/src/monitor-do.ts +0 -268
  37. package/src/r2-loader.ts +0 -27
  38. package/src/schedule-do.ts +0 -377
  39. package/src/sqlite-adapter.ts +0 -50
  40. package/test-project/package-lock.json +0 -3010
  41. package/test-project/package.json +0 -21
  42. package/test-project/src/index.ts +0 -70
  43. package/test-project/src/runner.ts +0 -24
  44. package/test-project/tests/api.test.ts +0 -1005
  45. package/test-project/tests/r2loader.test.ts +0 -73
  46. package/test-project/tests/resources-api.test.ts +0 -671
  47. package/test-project/tests/spec.test.ts +0 -135
  48. package/test-project/tests/tsconfig.json +0 -7
  49. package/test-project/tsconfig.json +0 -20
  50. package/test-project/vitest.config.ts +0 -12
  51. package/test-project/wrangler.jsonc +0 -53
  52. package/tsconfig.json +0 -11
@@ -0,0 +1,705 @@
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_without_holes(arr) {
7
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
8
+ }
9
+ function _assert_this_initialized(self) {
10
+ if (self === void 0) {
11
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
12
+ }
13
+ return self;
14
+ }
15
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
16
+ try {
17
+ var info = gen[key](arg);
18
+ var value = info.value;
19
+ } catch (error) {
20
+ reject(error);
21
+ return;
22
+ }
23
+ if (info.done) {
24
+ resolve(value);
25
+ } else {
26
+ Promise.resolve(value).then(_next, _throw);
27
+ }
28
+ }
29
+ function _async_to_generator(fn) {
30
+ return function() {
31
+ var self = this, args = arguments;
32
+ return new Promise(function(resolve, reject) {
33
+ var gen = fn.apply(self, args);
34
+ function _next(value) {
35
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
36
+ }
37
+ function _throw(err) {
38
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
39
+ }
40
+ _next(undefined);
41
+ });
42
+ };
43
+ }
44
+ function _call_super(_this, derived, args) {
45
+ derived = _get_prototype_of(derived);
46
+ return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
47
+ }
48
+ function _class_call_check(instance, Constructor) {
49
+ if (!(instance instanceof Constructor)) {
50
+ throw new TypeError("Cannot call a class as a function");
51
+ }
52
+ }
53
+ function _defineProperties(target, props) {
54
+ for(var i = 0; i < props.length; i++){
55
+ var descriptor = props[i];
56
+ descriptor.enumerable = descriptor.enumerable || false;
57
+ descriptor.configurable = true;
58
+ if ("value" in descriptor) descriptor.writable = true;
59
+ Object.defineProperty(target, descriptor.key, descriptor);
60
+ }
61
+ }
62
+ function _create_class(Constructor, protoProps, staticProps) {
63
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
64
+ if (staticProps) _defineProperties(Constructor, staticProps);
65
+ return Constructor;
66
+ }
67
+ function _define_property(obj, key, value) {
68
+ if (key in obj) {
69
+ Object.defineProperty(obj, key, {
70
+ value: value,
71
+ enumerable: true,
72
+ configurable: true,
73
+ writable: true
74
+ });
75
+ } else {
76
+ obj[key] = value;
77
+ }
78
+ return obj;
79
+ }
80
+ function _get_prototype_of(o) {
81
+ _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
82
+ return o.__proto__ || Object.getPrototypeOf(o);
83
+ };
84
+ return _get_prototype_of(o);
85
+ }
86
+ function _inherits(subClass, superClass) {
87
+ if (typeof superClass !== "function" && superClass !== null) {
88
+ throw new TypeError("Super expression must either be null or a function");
89
+ }
90
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
91
+ constructor: {
92
+ value: subClass,
93
+ writable: true,
94
+ configurable: true
95
+ }
96
+ });
97
+ if (superClass) _set_prototype_of(subClass, superClass);
98
+ }
99
+ function _instanceof(left, right) {
100
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
101
+ return !!right[Symbol.hasInstance](left);
102
+ } else {
103
+ return left instanceof right;
104
+ }
105
+ }
106
+ function _iterable_to_array(iter) {
107
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
108
+ }
109
+ function _non_iterable_spread() {
110
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
111
+ }
112
+ function _possible_constructor_return(self, call) {
113
+ if (call && (_type_of(call) === "object" || typeof call === "function")) {
114
+ return call;
115
+ }
116
+ return _assert_this_initialized(self);
117
+ }
118
+ function _set_prototype_of(o, p) {
119
+ _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
120
+ o.__proto__ = p;
121
+ return o;
122
+ };
123
+ return _set_prototype_of(o, p);
124
+ }
125
+ function _to_consumable_array(arr) {
126
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
127
+ }
128
+ function _type_of(obj) {
129
+ "@swc/helpers - typeof";
130
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
131
+ }
132
+ function _unsupported_iterable_to_array(o, minLen) {
133
+ if (!o) return;
134
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
135
+ var n = Object.prototype.toString.call(o).slice(8, -1);
136
+ if (n === "Object" && o.constructor) n = o.constructor.name;
137
+ if (n === "Map" || n === "Set") return Array.from(n);
138
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
139
+ }
140
+ function _is_native_reflect_construct() {
141
+ try {
142
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
143
+ } catch (_) {}
144
+ return (_is_native_reflect_construct = function() {
145
+ return !!result;
146
+ })();
147
+ }
148
+ function _ts_generator(thisArg, body) {
149
+ var f, y, t, _ = {
150
+ label: 0,
151
+ sent: function() {
152
+ if (t[0] & 1) throw t[1];
153
+ return t[1];
154
+ },
155
+ trys: [],
156
+ ops: []
157
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
158
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
159
+ return this;
160
+ }), g;
161
+ function verb(n) {
162
+ return function(v) {
163
+ return step([
164
+ n,
165
+ v
166
+ ]);
167
+ };
168
+ }
169
+ function step(op) {
170
+ if (f) throw new TypeError("Generator is already executing.");
171
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
172
+ 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;
173
+ if (y = 0, t) op = [
174
+ op[0] & 2,
175
+ t.value
176
+ ];
177
+ switch(op[0]){
178
+ case 0:
179
+ case 1:
180
+ t = op;
181
+ break;
182
+ case 4:
183
+ _.label++;
184
+ return {
185
+ value: op[1],
186
+ done: false
187
+ };
188
+ case 5:
189
+ _.label++;
190
+ y = op[1];
191
+ op = [
192
+ 0
193
+ ];
194
+ continue;
195
+ case 7:
196
+ op = _.ops.pop();
197
+ _.trys.pop();
198
+ continue;
199
+ default:
200
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
201
+ _ = 0;
202
+ continue;
203
+ }
204
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
205
+ _.label = op[1];
206
+ break;
207
+ }
208
+ if (op[0] === 6 && _.label < t[1]) {
209
+ _.label = t[1];
210
+ t = op;
211
+ break;
212
+ }
213
+ if (t && _.label < t[2]) {
214
+ _.label = t[2];
215
+ _.ops.push(op);
216
+ break;
217
+ }
218
+ if (t[2]) _.ops.pop();
219
+ _.trys.pop();
220
+ continue;
221
+ }
222
+ op = body.call(thisArg, _);
223
+ } catch (e) {
224
+ op = [
225
+ 6,
226
+ e
227
+ ];
228
+ y = 0;
229
+ } finally{
230
+ f = t = 0;
231
+ }
232
+ if (op[0] & 5) throw op[1];
233
+ return {
234
+ value: op[0] ? op[1] : void 0,
235
+ done: true
236
+ };
237
+ }
238
+ }
239
+ import { DurableObject } from 'cloudflare:workers';
240
+ import { v4 as uuidv4 } from 'uuid';
241
+ import { parseCronExpression } from 'cron-schedule';
242
+ import { BRAIN_EVENTS } from '@positronic/core';
243
+ var ALARM_INTERVAL = 60 * 1000;
244
+ export var ScheduleDO = /*#__PURE__*/ function(DurableObject) {
245
+ "use strict";
246
+ _inherits(ScheduleDO, DurableObject);
247
+ function ScheduleDO(state, env) {
248
+ _class_call_check(this, ScheduleDO);
249
+ var _this;
250
+ _this = _call_super(this, ScheduleDO, [
251
+ state,
252
+ env
253
+ ]), _define_property(_this, "storage", void 0);
254
+ _this.storage = state.storage.sql;
255
+ // Initialize database schema
256
+ _this.storage.exec("\n CREATE TABLE IF NOT EXISTS schedules (\n id TEXT PRIMARY KEY,\n brain_name TEXT NOT NULL,\n cron_expression TEXT NOT NULL,\n enabled INTEGER NOT NULL DEFAULT 1,\n created_at INTEGER NOT NULL,\n next_run_at INTEGER\n );\n\n CREATE INDEX IF NOT EXISTS idx_schedules_brain\n ON schedules(brain_name);\n\n CREATE INDEX IF NOT EXISTS idx_schedules_enabled\n ON schedules(enabled);\n\n CREATE TABLE IF NOT EXISTS scheduled_runs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n schedule_id TEXT NOT NULL,\n brain_run_id TEXT UNIQUE,\n status TEXT NOT NULL CHECK(status IN ('triggered', 'failed', 'complete')),\n ran_at INTEGER NOT NULL,\n completed_at INTEGER,\n error TEXT,\n FOREIGN KEY (schedule_id) REFERENCES schedules(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_runs_schedule\n ON scheduled_runs(schedule_id, ran_at DESC);\n ");
257
+ return _this;
258
+ }
259
+ _create_class(ScheduleDO, [
260
+ {
261
+ key: "createSchedule",
262
+ value: function createSchedule(brainName, cronExpression) {
263
+ return _async_to_generator(function() {
264
+ var id, createdAt, alarm, cron, nextRunAt;
265
+ return _ts_generator(this, function(_state) {
266
+ switch(_state.label){
267
+ case 0:
268
+ id = uuidv4();
269
+ createdAt = Date.now();
270
+ if (!(this.env.IS_TEST !== 'true')) return [
271
+ 3,
272
+ 3
273
+ ];
274
+ return [
275
+ 4,
276
+ this.ctx.storage.getAlarm()
277
+ ];
278
+ case 1:
279
+ alarm = _state.sent();
280
+ if (!!alarm) return [
281
+ 3,
282
+ 3
283
+ ];
284
+ return [
285
+ 4,
286
+ this.ctx.storage.setAlarm(Date.now() + ALARM_INTERVAL)
287
+ ];
288
+ case 2:
289
+ _state.sent();
290
+ _state.label = 3;
291
+ case 3:
292
+ // Note: Cron expression is validated at the API level before calling this method
293
+ // Calculate next run time
294
+ cron = parseCronExpression(cronExpression);
295
+ nextRunAt = this.calculateNextRunTime(cron, createdAt);
296
+ this.storage.exec("INSERT INTO schedules (id, brain_name, cron_expression, enabled, created_at, next_run_at)\n VALUES (?, ?, ?, 1, ?, ?)", id, brainName, cronExpression, createdAt, nextRunAt);
297
+ return [
298
+ 2,
299
+ {
300
+ id: id,
301
+ brainName: brainName,
302
+ cronExpression: cronExpression,
303
+ enabled: true,
304
+ createdAt: createdAt,
305
+ nextRunAt: nextRunAt
306
+ }
307
+ ];
308
+ }
309
+ });
310
+ }).call(this);
311
+ }
312
+ },
313
+ {
314
+ key: "getSchedule",
315
+ value: function getSchedule(scheduleId) {
316
+ return _async_to_generator(function() {
317
+ var results, result;
318
+ return _ts_generator(this, function(_state) {
319
+ results = this.storage.exec("SELECT id, brain_name, cron_expression, enabled, created_at, next_run_at\n FROM schedules WHERE id = ?", scheduleId).toArray();
320
+ if (results.length === 0) {
321
+ return [
322
+ 2,
323
+ null
324
+ ];
325
+ }
326
+ result = results[0];
327
+ return [
328
+ 2,
329
+ {
330
+ id: result.id,
331
+ brainName: result.brain_name,
332
+ cronExpression: result.cron_expression,
333
+ enabled: result.enabled === 1,
334
+ createdAt: result.created_at,
335
+ nextRunAt: result.next_run_at
336
+ }
337
+ ];
338
+ });
339
+ }).call(this);
340
+ }
341
+ },
342
+ {
343
+ key: "deleteSchedule",
344
+ value: function deleteSchedule(scheduleId) {
345
+ return _async_to_generator(function() {
346
+ var existing;
347
+ return _ts_generator(this, function(_state) {
348
+ switch(_state.label){
349
+ case 0:
350
+ return [
351
+ 4,
352
+ this.getSchedule(scheduleId)
353
+ ];
354
+ case 1:
355
+ existing = _state.sent();
356
+ if (!existing) {
357
+ return [
358
+ 2,
359
+ false
360
+ ];
361
+ }
362
+ this.storage.exec("DELETE FROM schedules WHERE id = ?", scheduleId);
363
+ return [
364
+ 2,
365
+ true
366
+ ];
367
+ }
368
+ });
369
+ }).call(this);
370
+ }
371
+ },
372
+ {
373
+ key: "listSchedules",
374
+ value: function listSchedules() {
375
+ return _async_to_generator(function() {
376
+ var alarm, schedules;
377
+ return _ts_generator(this, function(_state) {
378
+ switch(_state.label){
379
+ case 0:
380
+ if (!(this.env.NODE_ENV === 'development')) return [
381
+ 3,
382
+ 4
383
+ ];
384
+ console.log('[ScheduleDO] Checking alarm');
385
+ return [
386
+ 4,
387
+ this.ctx.storage.getAlarm()
388
+ ];
389
+ case 1:
390
+ alarm = _state.sent();
391
+ if (!alarm) return [
392
+ 3,
393
+ 4
394
+ ];
395
+ console.log('[ScheduleDO] Deleting alarm');
396
+ return [
397
+ 4,
398
+ this.ctx.storage.deleteAlarm()
399
+ ];
400
+ case 2:
401
+ _state.sent();
402
+ console.log('[ScheduleDO] Running alarm handler');
403
+ return [
404
+ 4,
405
+ this.alarm()
406
+ ];
407
+ case 3:
408
+ _state.sent();
409
+ _state.label = 4;
410
+ case 4:
411
+ schedules = this.storage.exec("SELECT id, brain_name, cron_expression, enabled, created_at, next_run_at\n FROM schedules\n ORDER BY created_at DESC").toArray().map(function(row) {
412
+ return {
413
+ id: row.id,
414
+ brainName: row.brain_name,
415
+ cronExpression: row.cron_expression,
416
+ enabled: row.enabled === 1,
417
+ createdAt: row.created_at,
418
+ nextRunAt: row.next_run_at
419
+ };
420
+ });
421
+ return [
422
+ 2,
423
+ {
424
+ schedules: schedules,
425
+ count: schedules.length
426
+ }
427
+ ];
428
+ }
429
+ });
430
+ }).call(this);
431
+ }
432
+ },
433
+ {
434
+ key: "getAllRuns",
435
+ value: function getAllRuns(scheduleId) {
436
+ var limit = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 100;
437
+ return _async_to_generator(function() {
438
+ var _this_storage, _this_storage1, query, params, runs, countQuery, countParams, countResult, count;
439
+ return _ts_generator(this, function(_state) {
440
+ query = "\n SELECT id, schedule_id, brain_run_id, status, ran_at, completed_at, error\n FROM scheduled_runs\n ";
441
+ params = [];
442
+ if (scheduleId) {
443
+ query += " WHERE schedule_id = ?";
444
+ params.push(scheduleId);
445
+ }
446
+ query += " ORDER BY ran_at DESC LIMIT ?";
447
+ params.push(limit);
448
+ runs = (_this_storage = this.storage).exec.apply(_this_storage, [
449
+ query
450
+ ].concat(_to_consumable_array(params))).toArray().map(function(row) {
451
+ return {
452
+ id: row.id,
453
+ scheduleId: row.schedule_id,
454
+ brainRunId: row.brain_run_id,
455
+ status: row.status,
456
+ ranAt: row.ran_at,
457
+ completedAt: row.completed_at,
458
+ error: row.error
459
+ };
460
+ });
461
+ // Get total count
462
+ countQuery = "SELECT COUNT(*) as count FROM scheduled_runs";
463
+ countParams = [];
464
+ if (scheduleId) {
465
+ countQuery += " WHERE schedule_id = ?";
466
+ countParams.push(scheduleId);
467
+ }
468
+ countResult = (_this_storage1 = this.storage).exec.apply(_this_storage1, [
469
+ countQuery
470
+ ].concat(_to_consumable_array(countParams))).one();
471
+ count = (countResult === null || countResult === void 0 ? void 0 : countResult.count) || 0;
472
+ return [
473
+ 2,
474
+ {
475
+ runs: runs,
476
+ count: count
477
+ }
478
+ ];
479
+ });
480
+ }).call(this);
481
+ }
482
+ },
483
+ {
484
+ key: "alarm",
485
+ value: // Handle the alarm trigger - runs every minute in a perpetual cycle
486
+ function alarm() {
487
+ return _async_to_generator(function() {
488
+ var now, dueSchedules, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, schedule, scheduleId, brainName, cronExpression, brainRunId, error, errorMessage, cron, nextRunAt, err;
489
+ return _ts_generator(this, function(_state) {
490
+ switch(_state.label){
491
+ case 0:
492
+ _state.trys.push([
493
+ 0,
494
+ ,
495
+ 12,
496
+ 15
497
+ ]);
498
+ // This alarm runs every minute to check for schedules that need to be executed.
499
+ // Since cron expressions have minute-level granularity at most (e.g., * * * * *),
500
+ // checking every minute ensures we never miss a scheduled run.
501
+ // Get all enabled schedules that are due
502
+ now = Date.now();
503
+ dueSchedules = this.storage.exec("SELECT id, brain_name, cron_expression\n FROM schedules\n WHERE enabled = 1 AND next_run_at <= ?", now).toArray();
504
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
505
+ _state.label = 1;
506
+ case 1:
507
+ _state.trys.push([
508
+ 1,
509
+ 9,
510
+ 10,
511
+ 11
512
+ ]);
513
+ _iterator = dueSchedules[Symbol.iterator]();
514
+ _state.label = 2;
515
+ case 2:
516
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
517
+ 3,
518
+ 8
519
+ ];
520
+ schedule = _step.value;
521
+ scheduleId = schedule.id;
522
+ brainName = schedule.brain_name;
523
+ cronExpression = schedule.cron_expression;
524
+ _state.label = 3;
525
+ case 3:
526
+ _state.trys.push([
527
+ 3,
528
+ 5,
529
+ ,
530
+ 6
531
+ ]);
532
+ return [
533
+ 4,
534
+ this.triggerBrainRun(brainName)
535
+ ];
536
+ case 4:
537
+ brainRunId = _state.sent();
538
+ // Record successful run
539
+ this.storage.exec("INSERT INTO scheduled_runs (schedule_id, brain_run_id, status, ran_at)\n VALUES (?, ?, 'triggered', ?)", scheduleId, brainRunId, now);
540
+ return [
541
+ 3,
542
+ 6
543
+ ];
544
+ case 5:
545
+ error = _state.sent();
546
+ // Record failed run
547
+ errorMessage = _instanceof(error, Error) ? error.message : 'Unknown error';
548
+ this.storage.exec("INSERT INTO scheduled_runs (schedule_id, status, ran_at, error)\n VALUES (?, 'failed', ?, ?)", scheduleId, now, errorMessage);
549
+ console.error("[ScheduleDO] Failed to trigger brain ".concat(brainName, ":"), error);
550
+ return [
551
+ 3,
552
+ 6
553
+ ];
554
+ case 6:
555
+ // Calculate and update next run time
556
+ cron = parseCronExpression(cronExpression);
557
+ nextRunAt = this.calculateNextRunTime(cron, now);
558
+ this.storage.exec("UPDATE schedules SET next_run_at = ? WHERE id = ?", nextRunAt, scheduleId);
559
+ _state.label = 7;
560
+ case 7:
561
+ _iteratorNormalCompletion = true;
562
+ return [
563
+ 3,
564
+ 2
565
+ ];
566
+ case 8:
567
+ return [
568
+ 3,
569
+ 11
570
+ ];
571
+ case 9:
572
+ err = _state.sent();
573
+ _didIteratorError = true;
574
+ _iteratorError = err;
575
+ return [
576
+ 3,
577
+ 11
578
+ ];
579
+ case 10:
580
+ try {
581
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
582
+ _iterator.return();
583
+ }
584
+ } finally{
585
+ if (_didIteratorError) {
586
+ throw _iteratorError;
587
+ }
588
+ }
589
+ return [
590
+ 7
591
+ ];
592
+ case 11:
593
+ return [
594
+ 3,
595
+ 15
596
+ ];
597
+ case 12:
598
+ if (!(this.env.IS_TEST !== 'true')) return [
599
+ 3,
600
+ 14
601
+ ];
602
+ return [
603
+ 4,
604
+ this.ctx.storage.setAlarm(Date.now() + ALARM_INTERVAL)
605
+ ];
606
+ case 13:
607
+ _state.sent();
608
+ _state.label = 14;
609
+ case 14:
610
+ return [
611
+ 7
612
+ ];
613
+ case 15:
614
+ return [
615
+ 2
616
+ ];
617
+ }
618
+ });
619
+ }).call(this);
620
+ }
621
+ },
622
+ {
623
+ key: "triggerBrainRun",
624
+ value: function triggerBrainRun(brainName) {
625
+ return _async_to_generator(function() {
626
+ var brainRunId, namespace, doId, stub;
627
+ return _ts_generator(this, function(_state) {
628
+ switch(_state.label){
629
+ case 0:
630
+ brainRunId = uuidv4();
631
+ namespace = this.env.BRAIN_RUNNER_DO;
632
+ doId = namespace.idFromName(brainRunId);
633
+ stub = namespace.get(doId);
634
+ console.log("[ScheduleDO] Triggering brain run ".concat(brainName, " with id ").concat(brainRunId));
635
+ return [
636
+ 4,
637
+ stub.start(brainName, brainRunId)
638
+ ];
639
+ case 1:
640
+ _state.sent();
641
+ return [
642
+ 2,
643
+ brainRunId
644
+ ];
645
+ }
646
+ });
647
+ }).call(this);
648
+ }
649
+ },
650
+ {
651
+ key: "handleBrainEvent",
652
+ value: // Called by ScheduleAdapter when brain events occur
653
+ function handleBrainEvent(event) {
654
+ return _async_to_generator(function() {
655
+ var result, scheduledRun, completedAt, status, error;
656
+ return _ts_generator(this, function(_state) {
657
+ // We only care about completion events for scheduled runs
658
+ if (event.type !== BRAIN_EVENTS.COMPLETE && event.type !== BRAIN_EVENTS.ERROR) {
659
+ return [
660
+ 2
661
+ ];
662
+ }
663
+ // Check if this brain run was triggered by a schedule
664
+ result = this.storage.exec("SELECT id FROM scheduled_runs WHERE brain_run_id = ?", event.brainRunId).toArray();
665
+ if (result.length === 0) {
666
+ // This brain run wasn't triggered by a schedule, ignore it
667
+ return [
668
+ 2
669
+ ];
670
+ }
671
+ scheduledRun = result[0];
672
+ completedAt = Date.now();
673
+ status = event.type === BRAIN_EVENTS.COMPLETE ? 'complete' : 'failed';
674
+ error = event.type === BRAIN_EVENTS.ERROR ? event.error ? JSON.stringify(event.error) : 'Unknown error' : null;
675
+ // Update the scheduled run record
676
+ this.storage.exec("UPDATE scheduled_runs\n SET status = ?, completed_at = ?, error = ?\n WHERE brain_run_id = ?", status, completedAt, error, event.brainRunId);
677
+ return [
678
+ 2
679
+ ];
680
+ });
681
+ }).call(this);
682
+ }
683
+ },
684
+ {
685
+ key: "isValidCronExpression",
686
+ value: function isValidCronExpression(expression) {
687
+ try {
688
+ // Try to parse the expression - if it throws, it's invalid
689
+ parseCronExpression(expression);
690
+ return true;
691
+ } catch (error) {
692
+ return false;
693
+ }
694
+ }
695
+ },
696
+ {
697
+ key: "calculateNextRunTime",
698
+ value: function calculateNextRunTime(cron, afterTime) {
699
+ var nextDate = cron.getNextDate(new Date(afterTime));
700
+ return nextDate.getTime();
701
+ }
702
+ }
703
+ ]);
704
+ return ScheduleDO;
705
+ }(DurableObject);