@positronic/cloudflare 0.0.63 → 0.0.65
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/index.js +7 -0
- package/dist/src/api/webhooks/coordination.js +26 -97
- package/dist/src/api/webhooks/index.js +43 -7
- package/dist/src/api/webhooks/system.js +22 -3
- package/dist/src/brain-runner-do.js +93 -9
- package/dist/src/monitor-do.js +17 -5
- package/dist/src/timeout-adapter.js +205 -0
- package/dist/src/webhook-adapter.js +1 -1
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/webhooks/coordination.d.ts +2 -8
- package/dist/types/api/webhooks/coordination.d.ts.map +1 -1
- package/dist/types/api/webhooks/index.d.ts.map +1 -1
- package/dist/types/api/webhooks/system.d.ts.map +1 -1
- package/dist/types/brain-runner-do.d.ts +8 -0
- package/dist/types/brain-runner-do.d.ts.map +1 -1
- package/dist/types/monitor-do.d.ts +6 -3
- package/dist/types/monitor-do.d.ts.map +1 -1
- package/dist/types/timeout-adapter.d.ts +13 -0
- package/dist/types/timeout-adapter.d.ts.map +1 -0
- package/dist/types/webhook-adapter.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/src/api/index.js
CHANGED
|
@@ -169,6 +169,13 @@ app.use('*', function(c, next) {
|
|
|
169
169
|
next()
|
|
170
170
|
];
|
|
171
171
|
}
|
|
172
|
+
// Ignore favicon requests (browsers auto-request this when loading pages)
|
|
173
|
+
if (c.req.path === '/favicon.ico') {
|
|
174
|
+
return [
|
|
175
|
+
2,
|
|
176
|
+
c.body(null, 204)
|
|
177
|
+
];
|
|
178
|
+
}
|
|
172
179
|
// Skip auth for viewing pages (GET /pages/:slug but not GET /pages/ or /pages/:slug/meta)
|
|
173
180
|
if (c.req.method === 'GET' && c.req.path.startsWith('/pages/') && !c.req.path.endsWith('/meta')) {
|
|
174
181
|
return [
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
function _array_like_to_array(arr, len) {
|
|
2
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
3
|
-
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
4
|
-
return arr2;
|
|
5
|
-
}
|
|
6
|
-
function _array_with_holes(arr) {
|
|
7
|
-
if (Array.isArray(arr)) return arr;
|
|
8
|
-
}
|
|
9
1
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
10
2
|
try {
|
|
11
3
|
var info = gen[key](arg);
|
|
@@ -35,44 +27,6 @@ function _async_to_generator(fn) {
|
|
|
35
27
|
});
|
|
36
28
|
};
|
|
37
29
|
}
|
|
38
|
-
function _iterable_to_array_limit(arr, i) {
|
|
39
|
-
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
40
|
-
if (_i == null) return;
|
|
41
|
-
var _arr = [];
|
|
42
|
-
var _n = true;
|
|
43
|
-
var _d = false;
|
|
44
|
-
var _s, _e;
|
|
45
|
-
try {
|
|
46
|
-
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
47
|
-
_arr.push(_s.value);
|
|
48
|
-
if (i && _arr.length === i) break;
|
|
49
|
-
}
|
|
50
|
-
} catch (err) {
|
|
51
|
-
_d = true;
|
|
52
|
-
_e = err;
|
|
53
|
-
} finally{
|
|
54
|
-
try {
|
|
55
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
|
56
|
-
} finally{
|
|
57
|
-
if (_d) throw _e;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return _arr;
|
|
61
|
-
}
|
|
62
|
-
function _non_iterable_rest() {
|
|
63
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
64
|
-
}
|
|
65
|
-
function _sliced_to_array(arr, i) {
|
|
66
|
-
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
67
|
-
}
|
|
68
|
-
function _unsupported_iterable_to_array(o, minLen) {
|
|
69
|
-
if (!o) return;
|
|
70
|
-
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
71
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
72
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
73
|
-
if (n === "Map" || n === "Set") return Array.from(n);
|
|
74
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
75
|
-
}
|
|
76
30
|
function _ts_generator(thisArg, body) {
|
|
77
31
|
var f, y, t, _ = {
|
|
78
32
|
label: 0,
|
|
@@ -164,16 +118,16 @@ function _ts_generator(thisArg, body) {
|
|
|
164
118
|
};
|
|
165
119
|
}
|
|
166
120
|
}
|
|
167
|
-
import { isSignalValid, brainMachineDefinition } from '@positronic/core';
|
|
121
|
+
import { isSignalValid, brainMachineDefinition, validateWebhookToken } from '@positronic/core';
|
|
168
122
|
/**
|
|
169
123
|
* Find a brain waiting for a webhook, queue the WEBHOOK_RESPONSE signal, and wake it up.
|
|
170
124
|
* Returns a JSON response object suitable for returning from a webhook endpoint.
|
|
171
125
|
*
|
|
172
126
|
* This is the signal-based approach: webhook response data flows through the signal queue
|
|
173
127
|
* rather than being passed directly to the resume method.
|
|
174
|
-
*/ export function queueWebhookAndWakeUp(context, slug, identifier, response) {
|
|
128
|
+
*/ export function queueWebhookAndWakeUp(context, slug, identifier, response, submittedToken) {
|
|
175
129
|
return _async_to_generator(function() {
|
|
176
|
-
var monitorId, monitorStub, brainRunId, run, validation, namespace, doId, stub;
|
|
130
|
+
var monitorId, monitorStub, result, brainRunId, expectedToken, tokenValidation, run, validation, namespace, doId, stub;
|
|
177
131
|
return _ts_generator(this, function(_state) {
|
|
178
132
|
switch(_state.label){
|
|
179
133
|
case 0:
|
|
@@ -184,11 +138,30 @@ import { isSignalValid, brainMachineDefinition } from '@positronic/core';
|
|
|
184
138
|
monitorStub.findWaitingBrain(slug, identifier)
|
|
185
139
|
];
|
|
186
140
|
case 1:
|
|
187
|
-
|
|
188
|
-
if (!
|
|
141
|
+
result = _state.sent();
|
|
142
|
+
if (!result) return [
|
|
189
143
|
3,
|
|
190
144
|
5
|
|
191
145
|
];
|
|
146
|
+
brainRunId = result.brainRunId, expectedToken = result.token;
|
|
147
|
+
// Validate CSRF token
|
|
148
|
+
tokenValidation = validateWebhookToken(expectedToken, submittedToken);
|
|
149
|
+
if (!tokenValidation.valid) {
|
|
150
|
+
return [
|
|
151
|
+
2,
|
|
152
|
+
{
|
|
153
|
+
received: true,
|
|
154
|
+
action: 'ignored',
|
|
155
|
+
identifier: identifier,
|
|
156
|
+
brainRunId: brainRunId,
|
|
157
|
+
reason: tokenValidation.reason
|
|
158
|
+
}
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
// Warn in dev mode when no token is present — may indicate an unprotected form
|
|
162
|
+
if (!expectedToken && !submittedToken && context.env.NODE_ENV === 'development') {
|
|
163
|
+
console.warn('[positronic] Webhook "'.concat(slug, '" received without a CSRF token. ') + "This is fine if you validate the request in your webhook handler, " + "but if this webhook receives form submissions from a page, consider " + "adding a token with generateFormToken(). See the docs for details.");
|
|
164
|
+
}
|
|
192
165
|
return [
|
|
193
166
|
4,
|
|
194
167
|
monitorStub.getRun(brainRunId)
|
|
@@ -254,49 +227,5 @@ import { isSignalValid, brainMachineDefinition } from '@positronic/core';
|
|
|
254
227
|
});
|
|
255
228
|
})();
|
|
256
229
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
* Supports:
|
|
260
|
-
* - name[] syntax for explicit arrays
|
|
261
|
-
* - Multiple values with same key (converted to array)
|
|
262
|
-
*/ export function parseFormData(formData) {
|
|
263
|
-
var result = {};
|
|
264
|
-
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
265
|
-
try {
|
|
266
|
-
for(var _iterator = formData.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
267
|
-
var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], value = _step_value[1];
|
|
268
|
-
// Handle array fields (e.g., name[] for multi-select)
|
|
269
|
-
if (key.endsWith('[]')) {
|
|
270
|
-
var baseKey = key.slice(0, -2);
|
|
271
|
-
if (!result[baseKey]) {
|
|
272
|
-
result[baseKey] = [];
|
|
273
|
-
}
|
|
274
|
-
result[baseKey].push(value);
|
|
275
|
-
} else if (result[key] !== undefined) {
|
|
276
|
-
// Convert to array if same key appears multiple times
|
|
277
|
-
if (!Array.isArray(result[key])) {
|
|
278
|
-
result[key] = [
|
|
279
|
-
result[key]
|
|
280
|
-
];
|
|
281
|
-
}
|
|
282
|
-
result[key].push(value);
|
|
283
|
-
} else {
|
|
284
|
-
result[key] = value;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
} catch (err) {
|
|
288
|
-
_didIteratorError = true;
|
|
289
|
-
_iteratorError = err;
|
|
290
|
-
} finally{
|
|
291
|
-
try {
|
|
292
|
-
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
293
|
-
_iterator.return();
|
|
294
|
-
}
|
|
295
|
-
} finally{
|
|
296
|
-
if (_didIteratorError) {
|
|
297
|
-
throw _iteratorError;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
return result;
|
|
302
|
-
}
|
|
230
|
+
// Re-export parseFormData from core for backwards compatibility
|
|
231
|
+
export { parseFormData } from '@positronic/core';
|
|
@@ -197,7 +197,7 @@ webhooks.get('/', function(context) {
|
|
|
197
197
|
// Receive incoming webhook from external service (user-defined webhooks)
|
|
198
198
|
webhooks.post('/:slug', function(context) {
|
|
199
199
|
return _async_to_generator(function() {
|
|
200
|
-
var slug, webhookManifest, webhook, handlerResult, result, error;
|
|
200
|
+
var slug, webhookManifest, webhook, clonedReq, handlerResult, submittedToken, contentType, formData, e, result, error;
|
|
201
201
|
return _ts_generator(this, function(_state) {
|
|
202
202
|
switch(_state.label){
|
|
203
203
|
case 0:
|
|
@@ -216,10 +216,13 @@ webhooks.post('/:slug', function(context) {
|
|
|
216
216
|
case 1:
|
|
217
217
|
_state.trys.push([
|
|
218
218
|
1,
|
|
219
|
-
|
|
219
|
+
8,
|
|
220
220
|
,
|
|
221
|
-
|
|
221
|
+
9
|
|
222
222
|
]);
|
|
223
|
+
// Clone the request so we can extract the CSRF token separately
|
|
224
|
+
// without consuming the body that the user's handler needs
|
|
225
|
+
clonedReq = context.req.raw.clone();
|
|
223
226
|
return [
|
|
224
227
|
4,
|
|
225
228
|
webhook.handler(context.req.raw)
|
|
@@ -235,11 +238,44 @@ webhooks.post('/:slug', function(context) {
|
|
|
235
238
|
})
|
|
236
239
|
];
|
|
237
240
|
}
|
|
241
|
+
// Extract CSRF token from form submissions
|
|
242
|
+
submittedToken = null;
|
|
243
|
+
contentType = clonedReq.headers.get('content-type') || '';
|
|
244
|
+
if (!(contentType.includes('form-urlencoded') || contentType.includes('form-data'))) return [
|
|
245
|
+
3,
|
|
246
|
+
6
|
|
247
|
+
];
|
|
248
|
+
_state.label = 3;
|
|
249
|
+
case 3:
|
|
250
|
+
_state.trys.push([
|
|
251
|
+
3,
|
|
252
|
+
5,
|
|
253
|
+
,
|
|
254
|
+
6
|
|
255
|
+
]);
|
|
238
256
|
return [
|
|
239
257
|
4,
|
|
240
|
-
|
|
258
|
+
clonedReq.formData()
|
|
241
259
|
];
|
|
242
|
-
case
|
|
260
|
+
case 4:
|
|
261
|
+
formData = _state.sent();
|
|
262
|
+
submittedToken = formData.get('__positronic_token');
|
|
263
|
+
return [
|
|
264
|
+
3,
|
|
265
|
+
6
|
|
266
|
+
];
|
|
267
|
+
case 5:
|
|
268
|
+
e = _state.sent();
|
|
269
|
+
return [
|
|
270
|
+
3,
|
|
271
|
+
6
|
|
272
|
+
];
|
|
273
|
+
case 6:
|
|
274
|
+
return [
|
|
275
|
+
4,
|
|
276
|
+
queueWebhookAndWakeUp(context, slug, handlerResult.identifier, handlerResult.response, submittedToken)
|
|
277
|
+
];
|
|
278
|
+
case 7:
|
|
243
279
|
result = _state.sent();
|
|
244
280
|
// For user webhooks, return 'queued' instead of 'not_found' when no brain is waiting
|
|
245
281
|
// This allows webhooks to be received even when no brain is actively waiting
|
|
@@ -257,7 +293,7 @@ webhooks.post('/:slug', function(context) {
|
|
|
257
293
|
2,
|
|
258
294
|
context.json(result)
|
|
259
295
|
];
|
|
260
|
-
case
|
|
296
|
+
case 8:
|
|
261
297
|
error = _state.sent();
|
|
262
298
|
console.error("Error receiving webhook ".concat(slug, ":"), error);
|
|
263
299
|
return [
|
|
@@ -266,7 +302,7 @@ webhooks.post('/:slug', function(context) {
|
|
|
266
302
|
error: 'Failed to process webhook'
|
|
267
303
|
}, 500)
|
|
268
304
|
];
|
|
269
|
-
case
|
|
305
|
+
case 9:
|
|
270
306
|
return [
|
|
271
307
|
2
|
|
272
308
|
];
|
|
@@ -181,7 +181,7 @@ var system = new Hono();
|
|
|
181
181
|
* Content-Type: application/x-www-form-urlencoded or multipart/form-data
|
|
182
182
|
*/ system.post('/ui-form', function(context) {
|
|
183
183
|
return _async_to_generator(function() {
|
|
184
|
-
var identifier, formData, response, result, error;
|
|
184
|
+
var identifier, formData, _parseFormData, response, token, result, error;
|
|
185
185
|
return _ts_generator(this, function(_state) {
|
|
186
186
|
switch(_state.label){
|
|
187
187
|
case 0:
|
|
@@ -208,13 +208,32 @@ var system = new Hono();
|
|
|
208
208
|
];
|
|
209
209
|
case 2:
|
|
210
210
|
formData = _state.sent();
|
|
211
|
-
|
|
211
|
+
_parseFormData = parseFormData(formData), response = _parseFormData.data, token = _parseFormData.token;
|
|
212
|
+
// System ui-form endpoint always requires a CSRF token
|
|
213
|
+
if (!token) {
|
|
214
|
+
return [
|
|
215
|
+
2,
|
|
216
|
+
context.json({
|
|
217
|
+
received: false,
|
|
218
|
+
action: 'ignored',
|
|
219
|
+
identifier: identifier,
|
|
220
|
+
reason: 'Missing form token'
|
|
221
|
+
}, 403)
|
|
222
|
+
];
|
|
223
|
+
}
|
|
212
224
|
return [
|
|
213
225
|
4,
|
|
214
|
-
queueWebhookAndWakeUp(context, 'ui-form', identifier, response)
|
|
226
|
+
queueWebhookAndWakeUp(context, 'ui-form', identifier, response, token)
|
|
215
227
|
];
|
|
216
228
|
case 3:
|
|
217
229
|
result = _state.sent();
|
|
230
|
+
// Return 403 if token mismatch
|
|
231
|
+
if (result.action === 'ignored' && result.reason === 'Invalid form token') {
|
|
232
|
+
return [
|
|
233
|
+
2,
|
|
234
|
+
context.json(result, 403)
|
|
235
|
+
];
|
|
236
|
+
}
|
|
218
237
|
// Return 404 if no brain was waiting
|
|
219
238
|
if (result.action === 'not_found') {
|
|
220
239
|
return [
|
|
@@ -294,6 +294,7 @@ import { DurableObject } from 'cloudflare:workers';
|
|
|
294
294
|
import { CloudflareSignalProvider } from './signal-provider.js';
|
|
295
295
|
import { BrainRunSQLiteAdapter } from './sqlite-adapter.js';
|
|
296
296
|
import { WebhookAdapter } from './webhook-adapter.js';
|
|
297
|
+
import { TimeoutAdapter } from './timeout-adapter.js';
|
|
297
298
|
import { PageAdapter } from './page-adapter.js';
|
|
298
299
|
import { EventLoader } from './event-loader.js';
|
|
299
300
|
import { createPagesService } from './pages-service.js';
|
|
@@ -504,6 +505,8 @@ var ScheduleAdapter = /*#__PURE__*/ function() {
|
|
|
504
505
|
}();
|
|
505
506
|
// SQL to initialize the signals table
|
|
506
507
|
var signalsTableSQL = "\nCREATE TABLE IF NOT EXISTS brain_signals (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n signal_type TEXT NOT NULL,\n content TEXT,\n queued_at INTEGER NOT NULL\n);\n";
|
|
508
|
+
// SQL to initialize the wait timeout table
|
|
509
|
+
var waitTimeoutTableSQL = "\nCREATE TABLE IF NOT EXISTS wait_timeout (\n brain_run_id TEXT PRIMARY KEY,\n timeout_at INTEGER NOT NULL\n);\n";
|
|
507
510
|
export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
508
511
|
"use strict";
|
|
509
512
|
_inherits(BrainRunnerDO, DurableObject);
|
|
@@ -513,7 +516,7 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
513
516
|
_this = _call_super(this, BrainRunnerDO, [
|
|
514
517
|
state,
|
|
515
518
|
env
|
|
516
|
-
]), _define_property(_this, "sql", void 0), _define_property(_this, "brainRunId", void 0), _define_property(_this, "eventStreamAdapter", new EventStreamAdapter()), _define_property(_this, "abortController", null), _define_property(_this, "pageAdapter", null), _define_property(_this, "signalsTableInitialized", false);
|
|
519
|
+
]), _define_property(_this, "sql", void 0), _define_property(_this, "brainRunId", void 0), _define_property(_this, "eventStreamAdapter", new EventStreamAdapter()), _define_property(_this, "abortController", null), _define_property(_this, "pageAdapter", null), _define_property(_this, "signalsTableInitialized", false), _define_property(_this, "waitTimeoutTableInitialized", false);
|
|
517
520
|
_this.sql = state.storage.sql;
|
|
518
521
|
_this.brainRunId = state.id.toString();
|
|
519
522
|
_this.env = env;
|
|
@@ -529,6 +532,41 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
529
532
|
}
|
|
530
533
|
}
|
|
531
534
|
},
|
|
535
|
+
{
|
|
536
|
+
key: "initializeWaitTimeoutTable",
|
|
537
|
+
value: function initializeWaitTimeoutTable() {
|
|
538
|
+
if (!this.waitTimeoutTableInitialized) {
|
|
539
|
+
this.sql.exec(waitTimeoutTableSQL);
|
|
540
|
+
this.waitTimeoutTableInitialized = true;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
key: "storeWaitTimeout",
|
|
546
|
+
value: function storeWaitTimeout(brainRunId, timeoutAt) {
|
|
547
|
+
this.initializeWaitTimeoutTable();
|
|
548
|
+
this.sql.exec("INSERT OR REPLACE INTO wait_timeout (brain_run_id, timeout_at) VALUES (?, ?)", brainRunId, timeoutAt);
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
key: "clearWaitTimeout",
|
|
553
|
+
value: function clearWaitTimeout(brainRunId) {
|
|
554
|
+
this.initializeWaitTimeoutTable();
|
|
555
|
+
this.sql.exec("DELETE FROM wait_timeout WHERE brain_run_id = ?", brainRunId);
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
key: "getWaitTimeout",
|
|
560
|
+
value: function getWaitTimeout() {
|
|
561
|
+
this.initializeWaitTimeoutTable();
|
|
562
|
+
var results = this.sql.exec("SELECT brain_run_id, timeout_at FROM wait_timeout LIMIT 1").toArray();
|
|
563
|
+
if (results.length === 0) return null;
|
|
564
|
+
return {
|
|
565
|
+
brainRunId: results[0].brain_run_id,
|
|
566
|
+
timeoutAt: results[0].timeout_at
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
},
|
|
532
570
|
{
|
|
533
571
|
key: "queueSignal",
|
|
534
572
|
value: /**
|
|
@@ -928,14 +966,31 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
928
966
|
key: "alarm",
|
|
929
967
|
value: function alarm() {
|
|
930
968
|
return _async_to_generator(function() {
|
|
969
|
+
var timeout;
|
|
931
970
|
return _ts_generator(this, function(_state) {
|
|
932
971
|
switch(_state.label){
|
|
933
972
|
case 0:
|
|
973
|
+
timeout = this.getWaitTimeout();
|
|
974
|
+
if (!(timeout && Date.now() >= timeout.timeoutAt)) return [
|
|
975
|
+
3,
|
|
976
|
+
2
|
|
977
|
+
];
|
|
978
|
+
this.clearWaitTimeout(timeout.brainRunId);
|
|
934
979
|
return [
|
|
935
980
|
4,
|
|
936
|
-
this.
|
|
981
|
+
this.queueSignal({
|
|
982
|
+
type: 'KILL'
|
|
983
|
+
})
|
|
937
984
|
];
|
|
938
985
|
case 1:
|
|
986
|
+
_state.sent();
|
|
987
|
+
_state.label = 2;
|
|
988
|
+
case 2:
|
|
989
|
+
return [
|
|
990
|
+
4,
|
|
991
|
+
this.wakeUp(this.brainRunId)
|
|
992
|
+
];
|
|
993
|
+
case 3:
|
|
939
994
|
_state.sent();
|
|
940
995
|
return [
|
|
941
996
|
2
|
|
@@ -949,7 +1004,7 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
949
1004
|
key: "start",
|
|
950
1005
|
value: function start(brainTitle, brainRunId, initialData) {
|
|
951
1006
|
return _async_to_generator(function() {
|
|
952
|
-
var _this, sql, resolution, brainToRun, sqliteAdapter, eventStreamAdapter, monitorDOStub, monitorAdapter, scheduleAdapter, webhookAdapter, env, pagesService, r2Resources, runnerWithResources, signalProvider, options, initialState, batchChunkAdapter;
|
|
1007
|
+
var _this, sql, resolution, brainToRun, sqliteAdapter, eventStreamAdapter, monitorDOStub, monitorAdapter, scheduleAdapter, webhookAdapter, env, pagesService, r2Resources, runnerWithResources, signalProvider, options, initialState, batchChunkAdapter, timeoutAdapter;
|
|
953
1008
|
return _ts_generator(this, function(_state) {
|
|
954
1009
|
switch(_state.label){
|
|
955
1010
|
case 0:
|
|
@@ -1016,6 +1071,11 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1016
1071
|
}, function(time) {
|
|
1017
1072
|
return _this.ctx.storage.setAlarm(time);
|
|
1018
1073
|
});
|
|
1074
|
+
timeoutAdapter = new TimeoutAdapter(function(brainRunId, timeoutAt) {
|
|
1075
|
+
return _this.storeWaitTimeout(brainRunId, timeoutAt);
|
|
1076
|
+
}, function(time) {
|
|
1077
|
+
return _this.ctx.storage.setAlarm(time);
|
|
1078
|
+
});
|
|
1019
1079
|
runnerWithResources.withAdapters([
|
|
1020
1080
|
sqliteAdapter,
|
|
1021
1081
|
eventStreamAdapter,
|
|
@@ -1023,7 +1083,8 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1023
1083
|
scheduleAdapter,
|
|
1024
1084
|
webhookAdapter,
|
|
1025
1085
|
this.pageAdapter,
|
|
1026
|
-
batchChunkAdapter
|
|
1086
|
+
batchChunkAdapter,
|
|
1087
|
+
timeoutAdapter
|
|
1027
1088
|
]).run(brainToRun, _object_spread_props(_object_spread({
|
|
1028
1089
|
initialState: initialState,
|
|
1029
1090
|
brainRunId: brainRunId
|
|
@@ -1054,12 +1115,29 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1054
1115
|
* This method reconstructs state and calls BrainRunner.resume().
|
|
1055
1116
|
*/ function wakeUp(brainRunId) {
|
|
1056
1117
|
return _async_to_generator(function() {
|
|
1057
|
-
var _this, sql, eventLoader, startEvent, brainTitle, initialState, originalBrainRunId, resolution, brainToRun, allEvents, machine, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, event, sqliteAdapter, eventStreamAdapter, monitorDOStub, monitorAdapter, scheduleAdapter, webhookAdapter, env, pagesService, r2Resources, runnerWithResources, signalProvider, batchChunkAdapter;
|
|
1118
|
+
var _this, sql, pendingTimeout, eventLoader, startEvent, brainTitle, initialState, originalBrainRunId, resolution, brainToRun, allEvents, machine, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, event, sqliteAdapter, eventStreamAdapter, monitorDOStub, monitorAdapter, scheduleAdapter, webhookAdapter, env, pagesService, r2Resources, runnerWithResources, signalProvider, batchChunkAdapter, timeoutAdapter;
|
|
1058
1119
|
return _ts_generator(this, function(_state) {
|
|
1059
1120
|
switch(_state.label){
|
|
1060
1121
|
case 0:
|
|
1061
1122
|
_this = this;
|
|
1062
1123
|
sql = this.sql;
|
|
1124
|
+
// Clear any pending timeout and cancel the alarm to prevent spurious alarm
|
|
1125
|
+
// fires after explicit resume. Safe because wakeUp() is only called when a
|
|
1126
|
+
// brain is suspended (waiting/paused), never during active batch execution.
|
|
1127
|
+
pendingTimeout = this.getWaitTimeout();
|
|
1128
|
+
if (!pendingTimeout) return [
|
|
1129
|
+
3,
|
|
1130
|
+
2
|
|
1131
|
+
];
|
|
1132
|
+
this.clearWaitTimeout(pendingTimeout.brainRunId);
|
|
1133
|
+
return [
|
|
1134
|
+
4,
|
|
1135
|
+
this.ctx.storage.deleteAlarm()
|
|
1136
|
+
];
|
|
1137
|
+
case 1:
|
|
1138
|
+
_state.sent();
|
|
1139
|
+
_state.label = 2;
|
|
1140
|
+
case 2:
|
|
1063
1141
|
if (!manifest) {
|
|
1064
1142
|
throw new Error('Runtime manifest not initialized');
|
|
1065
1143
|
}
|
|
@@ -1069,7 +1147,7 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1069
1147
|
4,
|
|
1070
1148
|
eventLoader.loadEventByType(BRAIN_EVENTS.START, 'ASC')
|
|
1071
1149
|
];
|
|
1072
|
-
case
|
|
1150
|
+
case 3:
|
|
1073
1151
|
startEvent = _state.sent();
|
|
1074
1152
|
if (!startEvent) {
|
|
1075
1153
|
throw new Error("No START event found for brain run ".concat(brainRunId));
|
|
@@ -1102,7 +1180,7 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1102
1180
|
4,
|
|
1103
1181
|
eventLoader.loadAllEvents()
|
|
1104
1182
|
];
|
|
1105
|
-
case
|
|
1183
|
+
case 4:
|
|
1106
1184
|
allEvents = _state.sent();
|
|
1107
1185
|
// Create state machine and feed all historical events to reconstruct execution state
|
|
1108
1186
|
machine = createBrainExecutionMachine({
|
|
@@ -1146,7 +1224,7 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1146
1224
|
4,
|
|
1147
1225
|
this.loadResourcesFromR2()
|
|
1148
1226
|
];
|
|
1149
|
-
case
|
|
1227
|
+
case 5:
|
|
1150
1228
|
r2Resources = _state.sent();
|
|
1151
1229
|
runnerWithResources = brainRunner;
|
|
1152
1230
|
if (r2Resources) {
|
|
@@ -1167,6 +1245,11 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1167
1245
|
}, function(time) {
|
|
1168
1246
|
return _this.ctx.storage.setAlarm(time);
|
|
1169
1247
|
});
|
|
1248
|
+
timeoutAdapter = new TimeoutAdapter(function(brainRunId, timeoutAt) {
|
|
1249
|
+
return _this.storeWaitTimeout(brainRunId, timeoutAt);
|
|
1250
|
+
}, function(time) {
|
|
1251
|
+
return _this.ctx.storage.setAlarm(time);
|
|
1252
|
+
});
|
|
1170
1253
|
runnerWithResources.withAdapters([
|
|
1171
1254
|
sqliteAdapter,
|
|
1172
1255
|
eventStreamAdapter,
|
|
@@ -1174,7 +1257,8 @@ export var BrainRunnerDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
1174
1257
|
scheduleAdapter,
|
|
1175
1258
|
webhookAdapter,
|
|
1176
1259
|
this.pageAdapter,
|
|
1177
|
-
batchChunkAdapter
|
|
1260
|
+
batchChunkAdapter,
|
|
1261
|
+
timeoutAdapter
|
|
1178
1262
|
]).resume(brainToRun, {
|
|
1179
1263
|
machine: machine,
|
|
1180
1264
|
brainRunId: originalBrainRunId,
|
package/dist/src/monitor-do.js
CHANGED
|
@@ -259,6 +259,12 @@ export var MonitorDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
259
259
|
_this.storage = state.storage.sql;
|
|
260
260
|
// Update table schema and indexes
|
|
261
261
|
_this.storage.exec("\n CREATE TABLE IF NOT EXISTS brain_runs (\n run_id TEXT PRIMARY KEY,\n brain_title TEXT NOT NULL,\n brain_description TEXT,\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 TABLE IF NOT EXISTS brain_events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n run_id TEXT NOT NULL,\n event_type TEXT NOT NULL,\n event_data TEXT NOT NULL,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_brain_events_run\n ON brain_events(run_id, id);\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\n CREATE TABLE IF NOT EXISTS page_registrations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n slug TEXT NOT NULL UNIQUE,\n brain_run_id TEXT NOT NULL,\n persist INTEGER NOT NULL DEFAULT 0,\n created_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_page_brain_run\n ON page_registrations(brain_run_id);\n\n CREATE INDEX IF NOT EXISTS idx_page_persist\n ON page_registrations(persist);\n ");
|
|
262
|
+
// Migration: add token column to webhook_registrations
|
|
263
|
+
try {
|
|
264
|
+
_this.storage.exec("ALTER TABLE webhook_registrations ADD COLUMN token TEXT");
|
|
265
|
+
} catch (e) {
|
|
266
|
+
// Column already exists
|
|
267
|
+
}
|
|
262
268
|
return _this;
|
|
263
269
|
}
|
|
264
270
|
_create_class(MonitorDO, [
|
|
@@ -476,18 +482,24 @@ export var MonitorDO = /*#__PURE__*/ function(DurableObject) {
|
|
|
476
482
|
* Register a webhook to wait for
|
|
477
483
|
* Called when a brain emits a WEBHOOK event
|
|
478
484
|
*/ key: "registerWebhook",
|
|
479
|
-
value: function registerWebhook(slug, identifier, brainRunId) {
|
|
480
|
-
this.storage.exec("\n INSERT INTO webhook_registrations (slug, identifier, brain_run_id, created_at)\n VALUES (?, ?, ?, ?)\n ", slug, identifier, brainRunId, Date.now());
|
|
485
|
+
value: function registerWebhook(slug, identifier, brainRunId, token) {
|
|
486
|
+
this.storage.exec("\n INSERT INTO webhook_registrations (slug, identifier, brain_run_id, token, created_at)\n VALUES (?, ?, ?, ?, ?)\n ", slug, identifier, brainRunId, token !== null && token !== void 0 ? token : null, Date.now());
|
|
481
487
|
}
|
|
482
488
|
},
|
|
483
489
|
{
|
|
484
490
|
/**
|
|
485
491
|
* Find a brain waiting for this webhook
|
|
486
|
-
* Returns the brain_run_id if found, null otherwise
|
|
492
|
+
* Returns the brain_run_id and token if found, null otherwise
|
|
487
493
|
*/ key: "findWaitingBrain",
|
|
488
494
|
value: function findWaitingBrain(slug, identifier) {
|
|
489
|
-
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();
|
|
490
|
-
|
|
495
|
+
var results = this.storage.exec("\n SELECT brain_run_id as brainRunId, token\n FROM webhook_registrations\n WHERE slug = ? AND identifier = ?\n LIMIT 1\n ", slug, identifier).toArray();
|
|
496
|
+
if (results.length === 0) return null;
|
|
497
|
+
var row = results[0];
|
|
498
|
+
var _row_token;
|
|
499
|
+
return {
|
|
500
|
+
brainRunId: row.brainRunId,
|
|
501
|
+
token: (_row_token = row.token) !== null && _row_token !== void 0 ? _row_token : null
|
|
502
|
+
};
|
|
491
503
|
}
|
|
492
504
|
},
|
|
493
505
|
{
|
|
@@ -0,0 +1,205 @@
|
|
|
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 with a timeout by storing the
|
|
156
|
+
* timeout and scheduling a DO alarm. When the alarm fires and the
|
|
157
|
+
* brain is still waiting, it queues a KILL signal to cancel the brain.
|
|
158
|
+
*/ export var TimeoutAdapter = /*#__PURE__*/ function() {
|
|
159
|
+
"use strict";
|
|
160
|
+
function TimeoutAdapter(storeTimeout, setAlarm) {
|
|
161
|
+
_class_call_check(this, TimeoutAdapter);
|
|
162
|
+
_define_property(this, "storeTimeout", void 0);
|
|
163
|
+
_define_property(this, "setAlarm", void 0);
|
|
164
|
+
this.storeTimeout = storeTimeout;
|
|
165
|
+
this.setAlarm = setAlarm;
|
|
166
|
+
}
|
|
167
|
+
_create_class(TimeoutAdapter, [
|
|
168
|
+
{
|
|
169
|
+
key: "dispatch",
|
|
170
|
+
value: function dispatch(event) {
|
|
171
|
+
return _async_to_generator(function() {
|
|
172
|
+
var timeout, timeoutAt;
|
|
173
|
+
return _ts_generator(this, function(_state) {
|
|
174
|
+
switch(_state.label){
|
|
175
|
+
case 0:
|
|
176
|
+
if (event.type !== BRAIN_EVENTS.WEBHOOK) {
|
|
177
|
+
return [
|
|
178
|
+
2
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
timeout = event.timeout;
|
|
182
|
+
if (timeout === undefined) {
|
|
183
|
+
return [
|
|
184
|
+
2
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
timeoutAt = Date.now() + timeout;
|
|
188
|
+
this.storeTimeout(event.brainRunId, timeoutAt);
|
|
189
|
+
return [
|
|
190
|
+
4,
|
|
191
|
+
this.setAlarm(timeoutAt)
|
|
192
|
+
];
|
|
193
|
+
case 1:
|
|
194
|
+
_state.sent();
|
|
195
|
+
return [
|
|
196
|
+
2
|
|
197
|
+
];
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}).call(this);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
]);
|
|
204
|
+
return TimeoutAdapter;
|
|
205
|
+
}();
|
|
@@ -195,7 +195,7 @@ import { BRAIN_EVENTS } from '@positronic/core';
|
|
|
195
195
|
registration = _step.value;
|
|
196
196
|
return [
|
|
197
197
|
4,
|
|
198
|
-
this.monitorStub.registerWebhook(registration.slug, registration.identifier, event.brainRunId)
|
|
198
|
+
this.monitorStub.registerWebhook(registration.slug, registration.identifier, event.brainRunId, registration.token)
|
|
199
199
|
];
|
|
200
200
|
case 3:
|
|
201
201
|
_state.sent();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAU3C,QAAA,MAAM,GAAG;cAAwB,QAAQ;yCAAK,CAAC;AAiE/C,eAAe,GAAG,CAAC;AAGnB,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -18,7 +18,7 @@ export type WebhookHandlerResult = {
|
|
|
18
18
|
* This is the signal-based approach: webhook response data flows through the signal queue
|
|
19
19
|
* rather than being passed directly to the resume method.
|
|
20
20
|
*/
|
|
21
|
-
export declare function queueWebhookAndWakeUp(context: Context, slug: string, identifier: string, response: Record<string, unknown
|
|
21
|
+
export declare function queueWebhookAndWakeUp(context: Context, slug: string, identifier: string, response: Record<string, unknown>, submittedToken?: string | null): Promise<{
|
|
22
22
|
received: boolean;
|
|
23
23
|
action: 'resumed' | 'not_found' | 'queued' | 'ignored';
|
|
24
24
|
identifier: string;
|
|
@@ -26,11 +26,5 @@ export declare function queueWebhookAndWakeUp(context: Context, slug: string, id
|
|
|
26
26
|
message?: string;
|
|
27
27
|
reason?: string;
|
|
28
28
|
}>;
|
|
29
|
-
|
|
30
|
-
* Parse form data into a plain object, handling array fields.
|
|
31
|
-
* Supports:
|
|
32
|
-
* - name[] syntax for explicit arrays
|
|
33
|
-
* - Multiple values with same key (converted to array)
|
|
34
|
-
*/
|
|
35
|
-
export declare function parseFormData(formData: FormData): Record<string, unknown>;
|
|
29
|
+
export { parseFormData } from '@positronic/core';
|
|
36
30
|
//# sourceMappingURL=coordination.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../../../src/api/webhooks/coordination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEhF;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../../../src/api/webhooks/coordination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAEhF;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAC7B,OAAO,CAAC;IACT,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAoED;AAGD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,QAAA,MAAM,QAAQ;cAAwB,QAAQ;yCAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/webhooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,QAAA,MAAM,QAAQ;cAAwB,QAAQ;yCAAK,CAAC;AAiFpD,eAAe,QAAQ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../../src/api/webhooks/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,QAAA,MAAM,MAAM;cAAwB,QAAQ;yCAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../../src/api/webhooks/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,QAAA,MAAM,MAAM;cAAwB,QAAQ;yCAAK,CAAC;AAoDlD,eAAe,MAAM,CAAC"}
|
|
@@ -23,8 +23,16 @@ export declare class BrainRunnerDO extends DurableObject<Env> {
|
|
|
23
23
|
private abortController;
|
|
24
24
|
private pageAdapter;
|
|
25
25
|
private signalsTableInitialized;
|
|
26
|
+
private waitTimeoutTableInitialized;
|
|
26
27
|
constructor(state: DurableObjectState, env: Env);
|
|
27
28
|
private initializeSignalsTable;
|
|
29
|
+
private initializeWaitTimeoutTable;
|
|
30
|
+
storeWaitTimeout(brainRunId: string, timeoutAt: number): void;
|
|
31
|
+
clearWaitTimeout(brainRunId: string): void;
|
|
32
|
+
getWaitTimeout(): {
|
|
33
|
+
brainRunId: string;
|
|
34
|
+
timeoutAt: number;
|
|
35
|
+
} | null;
|
|
28
36
|
/**
|
|
29
37
|
* Queue a signal for this brain run.
|
|
30
38
|
* Returns the queued signal with timestamp.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brain-runner-do.d.ts","sourceRoot":"","sources":["../../src/brain-runner-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiG,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAChK,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"brain-runner-do.d.ts","sourceRoot":"","sources":["../../src/brain-runner-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiG,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAChK,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAUnD,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,CAExD;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;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsGD,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;IACvD,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,uBAAuB,CAAS;IACxC,OAAO,CAAC,2BAA2B,CAAS;gBAEhC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;IAO/C,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,0BAA0B;IAOlC,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAStD,gBAAgB,CAAC,UAAU,EAAE,MAAM;IAQnC,cAAc,IAAI;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAWlE;;;;OAIG;IACG,WAAW,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAmB9I;;;;OAIG;IACH,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,WAAW,EAAE;YA+C5D,mBAAmB;IAqEjC;;;OAGG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;;;;;OAQG;IACG,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IA0E9F,KAAK;IASL,KAAK,CACT,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAyHnC;;;;OAIG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM;IAyJzB,KAAK,CAAC,OAAO,EAAE,OAAO;CAkE7B"}
|
|
@@ -22,12 +22,15 @@ export declare class MonitorDO extends DurableObject<Env> {
|
|
|
22
22
|
* Register a webhook to wait for
|
|
23
23
|
* Called when a brain emits a WEBHOOK event
|
|
24
24
|
*/
|
|
25
|
-
registerWebhook(slug: string, identifier: string, brainRunId: string): void;
|
|
25
|
+
registerWebhook(slug: string, identifier: string, brainRunId: string, token?: string): void;
|
|
26
26
|
/**
|
|
27
27
|
* Find a brain waiting for this webhook
|
|
28
|
-
* Returns the brain_run_id if found, null otherwise
|
|
28
|
+
* Returns the brain_run_id and token if found, null otherwise
|
|
29
29
|
*/
|
|
30
|
-
findWaitingBrain(slug: string, identifier: string):
|
|
30
|
+
findWaitingBrain(slug: string, identifier: string): {
|
|
31
|
+
brainRunId: string;
|
|
32
|
+
token: string | null;
|
|
33
|
+
} | null;
|
|
31
34
|
/**
|
|
32
35
|
* Clear all webhook registrations for a brain run
|
|
33
36
|
* Called when brain completes, errors, or is cancelled
|
|
@@ -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;AAQnD,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;IAEtD,OAAO,CAAC,QAAQ,CAAwC;gBAE5C,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;
|
|
1
|
+
{"version":3,"file":"monitor-do.d.ts","sourceRoot":"","sources":["../../src/monitor-do.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAQnD,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;IAEtD,OAAO,CAAC,QAAQ,CAAwC;gBAE5C,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG;IAyE/C,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC;YAmHzB,sBAAsB;IA4B9B,KAAK,CAAC,OAAO,EAAE,OAAO;IAmE5B,YAAY,CAAC,UAAU,EAAE,MAAM;IAa/B;;;OAGG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM;IAqCzB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW;IA6B9C,UAAU,CAAC,UAAU,EAAE,MAAM;IA2B7B;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAcpF;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAmBvG;;;OAGG;IACH,yBAAyB,CAAC,UAAU,EAAE,MAAM;IAU5C;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAgB/D;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM;IAU3B;;;OAGG;IACH,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAezD;;;OAGG;IACH,sBAAsB,CAAC,UAAU,EAAE,MAAM;CAU1C"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Adapter, BrainEvent } from '@positronic/core';
|
|
2
|
+
/**
|
|
3
|
+
* Adapter that handles WEBHOOK events with a timeout by storing the
|
|
4
|
+
* timeout and scheduling a DO alarm. When the alarm fires and the
|
|
5
|
+
* brain is still waiting, it queues a KILL signal to cancel the brain.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TimeoutAdapter implements Adapter {
|
|
8
|
+
private storeTimeout;
|
|
9
|
+
private setAlarm;
|
|
10
|
+
constructor(storeTimeout: (brainRunId: string, timeoutAt: number) => void, setAlarm: (time: number) => Promise<void>);
|
|
11
|
+
dispatch(event: BrainEvent): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=timeout-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeout-adapter.d.ts","sourceRoot":"","sources":["../../src/timeout-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG5D;;;;GAIG;AACH,qBAAa,cAAe,YAAW,OAAO;IAE1C,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,QAAQ;gBADR,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,EAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;IAG7C,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAcjD"}
|
|
@@ -1 +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;
|
|
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;CAgBjD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@positronic/cloudflare",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.65",
|
|
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.
|
|
35
|
-
"@positronic/spec": "^0.0.
|
|
36
|
-
"@positronic/template-new-project": "^0.0.
|
|
34
|
+
"@positronic/core": "^0.0.65",
|
|
35
|
+
"@positronic/spec": "^0.0.65",
|
|
36
|
+
"@positronic/template-new-project": "^0.0.65",
|
|
37
37
|
"aws4fetch": "^1.0.18",
|
|
38
38
|
"caz": "^2.0.0",
|
|
39
39
|
"cron-schedule": "^5.0.4",
|