@positronic/cloudflare 0.0.56 → 0.0.57

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 (39) hide show
  1. package/dist/src/api/auth-middleware.js +466 -0
  2. package/dist/src/api/brains.js +160 -0
  3. package/dist/src/api/index.js +22 -1
  4. package/dist/src/api/users.js +582 -0
  5. package/dist/src/api/webhooks/coordination.js +43 -8
  6. package/dist/src/api/webhooks/index.js +2 -2
  7. package/dist/src/api/webhooks/system.js +2 -2
  8. package/dist/src/auth-do.js +455 -0
  9. package/dist/src/brain-runner-do.js +255 -97
  10. package/dist/src/event-loader.js +301 -0
  11. package/dist/src/index.js +1 -0
  12. package/dist/src/monitor-do.js +39 -19
  13. package/dist/src/signal-provider.js +179 -0
  14. package/dist/src/sqlite-adapter.js +196 -13
  15. package/dist/types/api/auth-middleware.d.ts +19 -0
  16. package/dist/types/api/auth-middleware.d.ts.map +1 -0
  17. package/dist/types/api/brains.d.ts.map +1 -1
  18. package/dist/types/api/index.d.ts.map +1 -1
  19. package/dist/types/api/types.d.ts +3 -0
  20. package/dist/types/api/types.d.ts.map +1 -1
  21. package/dist/types/api/users.d.ts +7 -0
  22. package/dist/types/api/users.d.ts.map +1 -0
  23. package/dist/types/api/webhooks/coordination.d.ts +7 -3
  24. package/dist/types/api/webhooks/coordination.d.ts.map +1 -1
  25. package/dist/types/auth-do.d.ts +37 -0
  26. package/dist/types/auth-do.d.ts.map +1 -0
  27. package/dist/types/brain-runner-do.d.ts +29 -2
  28. package/dist/types/brain-runner-do.d.ts.map +1 -1
  29. package/dist/types/event-loader.d.ts +25 -0
  30. package/dist/types/event-loader.d.ts.map +1 -0
  31. package/dist/types/index.d.ts +1 -0
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/types/monitor-do.d.ts +1 -0
  34. package/dist/types/monitor-do.d.ts.map +1 -1
  35. package/dist/types/signal-provider.d.ts +11 -0
  36. package/dist/types/signal-provider.d.ts.map +1 -0
  37. package/dist/types/sqlite-adapter.d.ts +6 -3
  38. package/dist/types/sqlite-adapter.d.ts.map +1 -1
  39. package/package.json +5 -4
@@ -0,0 +1,582 @@
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 _type_of(obj) {
31
+ "@swc/helpers - typeof";
32
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
33
+ }
34
+ function _ts_generator(thisArg, body) {
35
+ var f, y, t, _ = {
36
+ label: 0,
37
+ sent: function() {
38
+ if (t[0] & 1) throw t[1];
39
+ return t[1];
40
+ },
41
+ trys: [],
42
+ ops: []
43
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
44
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
45
+ return this;
46
+ }), g;
47
+ function verb(n) {
48
+ return function(v) {
49
+ return step([
50
+ n,
51
+ v
52
+ ]);
53
+ };
54
+ }
55
+ function step(op) {
56
+ if (f) throw new TypeError("Generator is already executing.");
57
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
58
+ 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;
59
+ if (y = 0, t) op = [
60
+ op[0] & 2,
61
+ t.value
62
+ ];
63
+ switch(op[0]){
64
+ case 0:
65
+ case 1:
66
+ t = op;
67
+ break;
68
+ case 4:
69
+ _.label++;
70
+ return {
71
+ value: op[1],
72
+ done: false
73
+ };
74
+ case 5:
75
+ _.label++;
76
+ y = op[1];
77
+ op = [
78
+ 0
79
+ ];
80
+ continue;
81
+ case 7:
82
+ op = _.ops.pop();
83
+ _.trys.pop();
84
+ continue;
85
+ default:
86
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
87
+ _ = 0;
88
+ continue;
89
+ }
90
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
91
+ _.label = op[1];
92
+ break;
93
+ }
94
+ if (op[0] === 6 && _.label < t[1]) {
95
+ _.label = t[1];
96
+ t = op;
97
+ break;
98
+ }
99
+ if (t && _.label < t[2]) {
100
+ _.label = t[2];
101
+ _.ops.push(op);
102
+ break;
103
+ }
104
+ if (t[2]) _.ops.pop();
105
+ _.trys.pop();
106
+ continue;
107
+ }
108
+ op = body.call(thisArg, _);
109
+ } catch (e) {
110
+ op = [
111
+ 6,
112
+ e
113
+ ];
114
+ y = 0;
115
+ } finally{
116
+ f = t = 0;
117
+ }
118
+ if (op[0] & 5) throw op[1];
119
+ return {
120
+ value: op[0] ? op[1] : void 0,
121
+ done: true
122
+ };
123
+ }
124
+ }
125
+ import { Hono } from 'hono';
126
+ var app = new Hono();
127
+ // Validation constants
128
+ var MAX_USERNAME_LENGTH = 64;
129
+ var USERNAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
130
+ /**
131
+ * Validate a username
132
+ * @returns null if valid, error message if invalid
133
+ */ function validateUsername(name) {
134
+ if (!name || typeof name !== 'string') {
135
+ return 'Name is required';
136
+ }
137
+ if (name.length === 0) {
138
+ return 'Name cannot be empty';
139
+ }
140
+ if (name.length > MAX_USERNAME_LENGTH) {
141
+ return "Name cannot exceed ".concat(MAX_USERNAME_LENGTH, " characters");
142
+ }
143
+ if (!USERNAME_PATTERN.test(name)) {
144
+ return 'Name can only contain letters, numbers, hyphens, and underscores';
145
+ }
146
+ return null;
147
+ }
148
+ // POST /users - Create a new user
149
+ app.post('/', function(c) {
150
+ return _async_to_generator(function() {
151
+ var body, validationError, authDoId, authDo, existing, user, error;
152
+ return _ts_generator(this, function(_state) {
153
+ switch(_state.label){
154
+ case 0:
155
+ _state.trys.push([
156
+ 0,
157
+ 4,
158
+ ,
159
+ 5
160
+ ]);
161
+ return [
162
+ 4,
163
+ c.req.json()
164
+ ];
165
+ case 1:
166
+ body = _state.sent();
167
+ validationError = validateUsername(body.name);
168
+ if (validationError) {
169
+ return [
170
+ 2,
171
+ c.json({
172
+ error: validationError
173
+ }, 400)
174
+ ];
175
+ }
176
+ authDoId = c.env.AUTH_DO.idFromName('auth');
177
+ authDo = c.env.AUTH_DO.get(authDoId);
178
+ return [
179
+ 4,
180
+ authDo.getUserByName(body.name)
181
+ ];
182
+ case 2:
183
+ existing = _state.sent();
184
+ if (existing) {
185
+ return [
186
+ 2,
187
+ c.json({
188
+ error: "User '".concat(body.name, "' already exists")
189
+ }, 409)
190
+ ];
191
+ }
192
+ return [
193
+ 4,
194
+ authDo.createUser(body.name)
195
+ ];
196
+ case 3:
197
+ user = _state.sent();
198
+ return [
199
+ 2,
200
+ c.json(user, 201)
201
+ ];
202
+ case 4:
203
+ error = _state.sent();
204
+ console.error('Error creating user:', error);
205
+ return [
206
+ 2,
207
+ c.json({
208
+ error: 'Failed to create user'
209
+ }, 500)
210
+ ];
211
+ case 5:
212
+ return [
213
+ 2
214
+ ];
215
+ }
216
+ });
217
+ })();
218
+ });
219
+ // GET /users - List all users
220
+ app.get('/', function(c) {
221
+ return _async_to_generator(function() {
222
+ var authDoId, authDo, result, error;
223
+ return _ts_generator(this, function(_state) {
224
+ switch(_state.label){
225
+ case 0:
226
+ _state.trys.push([
227
+ 0,
228
+ 2,
229
+ ,
230
+ 3
231
+ ]);
232
+ authDoId = c.env.AUTH_DO.idFromName('auth');
233
+ authDo = c.env.AUTH_DO.get(authDoId);
234
+ return [
235
+ 4,
236
+ authDo.listUsers()
237
+ ];
238
+ case 1:
239
+ result = _state.sent();
240
+ return [
241
+ 2,
242
+ c.json(result)
243
+ ];
244
+ case 2:
245
+ error = _state.sent();
246
+ console.error('Error listing users:', error);
247
+ return [
248
+ 2,
249
+ c.json({
250
+ error: 'Failed to list users'
251
+ }, 500)
252
+ ];
253
+ case 3:
254
+ return [
255
+ 2
256
+ ];
257
+ }
258
+ });
259
+ })();
260
+ });
261
+ // GET /users/:id - Get a specific user
262
+ app.get('/:id', function(c) {
263
+ return _async_to_generator(function() {
264
+ var userId, authDoId, authDo, user, error;
265
+ return _ts_generator(this, function(_state) {
266
+ switch(_state.label){
267
+ case 0:
268
+ _state.trys.push([
269
+ 0,
270
+ 2,
271
+ ,
272
+ 3
273
+ ]);
274
+ userId = c.req.param('id');
275
+ authDoId = c.env.AUTH_DO.idFromName('auth');
276
+ authDo = c.env.AUTH_DO.get(authDoId);
277
+ return [
278
+ 4,
279
+ authDo.getUser(userId)
280
+ ];
281
+ case 1:
282
+ user = _state.sent();
283
+ if (!user) {
284
+ return [
285
+ 2,
286
+ c.json({
287
+ error: "User '".concat(userId, "' not found")
288
+ }, 404)
289
+ ];
290
+ }
291
+ return [
292
+ 2,
293
+ c.json(user)
294
+ ];
295
+ case 2:
296
+ error = _state.sent();
297
+ console.error('Error getting user:', error);
298
+ return [
299
+ 2,
300
+ c.json({
301
+ error: 'Failed to get user'
302
+ }, 500)
303
+ ];
304
+ case 3:
305
+ return [
306
+ 2
307
+ ];
308
+ }
309
+ });
310
+ })();
311
+ });
312
+ // DELETE /users/:id - Delete a user
313
+ app.delete('/:id', function(c) {
314
+ return _async_to_generator(function() {
315
+ var userId, authDoId, authDo, deleted, error;
316
+ return _ts_generator(this, function(_state) {
317
+ switch(_state.label){
318
+ case 0:
319
+ _state.trys.push([
320
+ 0,
321
+ 2,
322
+ ,
323
+ 3
324
+ ]);
325
+ userId = c.req.param('id');
326
+ authDoId = c.env.AUTH_DO.idFromName('auth');
327
+ authDo = c.env.AUTH_DO.get(authDoId);
328
+ return [
329
+ 4,
330
+ authDo.deleteUser(userId)
331
+ ];
332
+ case 1:
333
+ deleted = _state.sent();
334
+ if (!deleted) {
335
+ return [
336
+ 2,
337
+ c.json({
338
+ error: "User '".concat(userId, "' not found")
339
+ }, 404)
340
+ ];
341
+ }
342
+ return [
343
+ 2,
344
+ c.body(null, 204)
345
+ ];
346
+ case 2:
347
+ error = _state.sent();
348
+ console.error('Error deleting user:', error);
349
+ return [
350
+ 2,
351
+ c.json({
352
+ error: 'Failed to delete user'
353
+ }, 500)
354
+ ];
355
+ case 3:
356
+ return [
357
+ 2
358
+ ];
359
+ }
360
+ });
361
+ })();
362
+ });
363
+ // POST /users/:id/keys - Add a key to a user
364
+ app.post('/:id/keys', function(c) {
365
+ return _async_to_generator(function() {
366
+ var userId, body, authDoId, authDo, user, existingKey, key, error;
367
+ return _ts_generator(this, function(_state) {
368
+ switch(_state.label){
369
+ case 0:
370
+ _state.trys.push([
371
+ 0,
372
+ 5,
373
+ ,
374
+ 6
375
+ ]);
376
+ userId = c.req.param('id');
377
+ return [
378
+ 4,
379
+ c.req.json()
380
+ ];
381
+ case 1:
382
+ body = _state.sent();
383
+ if (!body.jwk || _type_of(body.jwk) !== 'object') {
384
+ return [
385
+ 2,
386
+ c.json({
387
+ error: 'JWK is required'
388
+ }, 400)
389
+ ];
390
+ }
391
+ if (!body.fingerprint || typeof body.fingerprint !== 'string') {
392
+ return [
393
+ 2,
394
+ c.json({
395
+ error: 'Fingerprint is required'
396
+ }, 400)
397
+ ];
398
+ }
399
+ authDoId = c.env.AUTH_DO.idFromName('auth');
400
+ authDo = c.env.AUTH_DO.get(authDoId);
401
+ return [
402
+ 4,
403
+ authDo.getUser(userId)
404
+ ];
405
+ case 2:
406
+ user = _state.sent();
407
+ if (!user) {
408
+ return [
409
+ 2,
410
+ c.json({
411
+ error: "User '".concat(userId, "' not found")
412
+ }, 404)
413
+ ];
414
+ }
415
+ return [
416
+ 4,
417
+ authDo.getKeyByFingerprint(body.fingerprint)
418
+ ];
419
+ case 3:
420
+ existingKey = _state.sent();
421
+ if (existingKey) {
422
+ return [
423
+ 2,
424
+ c.json({
425
+ error: 'Key already exists'
426
+ }, 409)
427
+ ];
428
+ }
429
+ return [
430
+ 4,
431
+ authDo.addKey(userId, body.fingerprint, JSON.stringify(body.jwk), body.label || '')
432
+ ];
433
+ case 4:
434
+ key = _state.sent();
435
+ // Return key without the jwk for security
436
+ return [
437
+ 2,
438
+ c.json({
439
+ fingerprint: key.fingerprint,
440
+ userId: key.userId,
441
+ label: key.label,
442
+ addedAt: key.addedAt
443
+ }, 201)
444
+ ];
445
+ case 5:
446
+ error = _state.sent();
447
+ console.error('Error adding key:', error);
448
+ return [
449
+ 2,
450
+ c.json({
451
+ error: 'Failed to add key'
452
+ }, 500)
453
+ ];
454
+ case 6:
455
+ return [
456
+ 2
457
+ ];
458
+ }
459
+ });
460
+ })();
461
+ });
462
+ // GET /users/:id/keys - List keys for a user
463
+ app.get('/:id/keys', function(c) {
464
+ return _async_to_generator(function() {
465
+ var userId, authDoId, authDo, user, result, error;
466
+ return _ts_generator(this, function(_state) {
467
+ switch(_state.label){
468
+ case 0:
469
+ _state.trys.push([
470
+ 0,
471
+ 3,
472
+ ,
473
+ 4
474
+ ]);
475
+ userId = c.req.param('id');
476
+ authDoId = c.env.AUTH_DO.idFromName('auth');
477
+ authDo = c.env.AUTH_DO.get(authDoId);
478
+ return [
479
+ 4,
480
+ authDo.getUser(userId)
481
+ ];
482
+ case 1:
483
+ user = _state.sent();
484
+ if (!user) {
485
+ return [
486
+ 2,
487
+ c.json({
488
+ error: "User '".concat(userId, "' not found")
489
+ }, 404)
490
+ ];
491
+ }
492
+ return [
493
+ 4,
494
+ authDo.listKeys(userId)
495
+ ];
496
+ case 2:
497
+ result = _state.sent();
498
+ // Return keys without the jwk for security
499
+ return [
500
+ 2,
501
+ c.json({
502
+ keys: result.keys.map(function(key) {
503
+ return {
504
+ fingerprint: key.fingerprint,
505
+ userId: key.userId,
506
+ label: key.label,
507
+ addedAt: key.addedAt
508
+ };
509
+ }),
510
+ count: result.count
511
+ })
512
+ ];
513
+ case 3:
514
+ error = _state.sent();
515
+ console.error('Error listing keys:', error);
516
+ return [
517
+ 2,
518
+ c.json({
519
+ error: 'Failed to list keys'
520
+ }, 500)
521
+ ];
522
+ case 4:
523
+ return [
524
+ 2
525
+ ];
526
+ }
527
+ });
528
+ })();
529
+ });
530
+ // DELETE /users/:id/keys/:fingerprint - Remove a key from a user
531
+ app.delete('/:id/keys/:fingerprint', function(c) {
532
+ return _async_to_generator(function() {
533
+ var userId, fingerprint, authDoId, authDo, deleted, error;
534
+ return _ts_generator(this, function(_state) {
535
+ switch(_state.label){
536
+ case 0:
537
+ _state.trys.push([
538
+ 0,
539
+ 2,
540
+ ,
541
+ 3
542
+ ]);
543
+ userId = c.req.param('id');
544
+ fingerprint = decodeURIComponent(c.req.param('fingerprint'));
545
+ authDoId = c.env.AUTH_DO.idFromName('auth');
546
+ authDo = c.env.AUTH_DO.get(authDoId);
547
+ return [
548
+ 4,
549
+ authDo.removeKey(userId, fingerprint)
550
+ ];
551
+ case 1:
552
+ deleted = _state.sent();
553
+ if (!deleted) {
554
+ return [
555
+ 2,
556
+ c.json({
557
+ error: "Key not found"
558
+ }, 404)
559
+ ];
560
+ }
561
+ return [
562
+ 2,
563
+ c.body(null, 204)
564
+ ];
565
+ case 2:
566
+ error = _state.sent();
567
+ console.error('Error removing key:', error);
568
+ return [
569
+ 2,
570
+ c.json({
571
+ error: 'Failed to remove key'
572
+ }, 500)
573
+ ];
574
+ case 3:
575
+ return [
576
+ 2
577
+ ];
578
+ }
579
+ });
580
+ })();
581
+ });
582
+ export default app;
@@ -164,12 +164,16 @@ function _ts_generator(thisArg, body) {
164
164
  };
165
165
  }
166
166
  }
167
+ import { isSignalValid, brainMachineDefinition } from '@positronic/core';
167
168
  /**
168
- * Find a brain waiting for a webhook and resume it if found.
169
+ * Find a brain waiting for a webhook, queue the WEBHOOK_RESPONSE signal, and wake it up.
169
170
  * Returns a JSON response object suitable for returning from a webhook endpoint.
170
- */ export function findAndResumeBrain(context, slug, identifier, response) {
171
+ *
172
+ * This is the signal-based approach: webhook response data flows through the signal queue
173
+ * rather than being passed directly to the resume method.
174
+ */ export function queueWebhookAndWakeUp(context, slug, identifier, response) {
171
175
  return _async_to_generator(function() {
172
- var monitorId, monitorStub, brainRunId, namespace, doId, stub;
176
+ var monitorId, monitorStub, brainRunId, run, validation, namespace, doId, stub;
173
177
  return _ts_generator(this, function(_state) {
174
178
  switch(_state.label){
175
179
  case 0:
@@ -183,17 +187,48 @@ function _ts_generator(thisArg, body) {
183
187
  brainRunId = _state.sent();
184
188
  if (!brainRunId) return [
185
189
  3,
186
- 3
190
+ 5
187
191
  ];
188
- // Found a brain waiting - resume it
192
+ return [
193
+ 4,
194
+ monitorStub.getRun(brainRunId)
195
+ ];
196
+ case 2:
197
+ run = _state.sent();
198
+ if (run) {
199
+ validation = isSignalValid(brainMachineDefinition, run.status, 'WEBHOOK_RESPONSE');
200
+ if (!validation.valid) {
201
+ return [
202
+ 2,
203
+ {
204
+ received: true,
205
+ action: 'ignored',
206
+ identifier: identifier,
207
+ brainRunId: brainRunId,
208
+ reason: validation.reason
209
+ }
210
+ ];
211
+ }
212
+ }
213
+ // Queue WEBHOOK_RESPONSE signal and wake up the brain
189
214
  namespace = context.env.BRAIN_RUNNER_DO;
190
215
  doId = namespace.idFromName(brainRunId);
191
216
  stub = namespace.get(doId);
217
+ // Queue the signal first, then wake up the brain
192
218
  return [
193
219
  4,
194
- stub.resume(brainRunId, response)
220
+ stub.queueSignal({
221
+ type: 'WEBHOOK_RESPONSE',
222
+ response: response
223
+ })
195
224
  ];
196
- case 2:
225
+ case 3:
226
+ _state.sent();
227
+ return [
228
+ 4,
229
+ stub.wakeUp(brainRunId)
230
+ ];
231
+ case 4:
197
232
  _state.sent();
198
233
  return [
199
234
  2,
@@ -204,7 +239,7 @@ function _ts_generator(thisArg, body) {
204
239
  brainRunId: brainRunId
205
240
  }
206
241
  ];
207
- case 3:
242
+ case 5:
208
243
  // No brain waiting for this webhook
209
244
  return [
210
245
  2,
@@ -166,7 +166,7 @@ function _ts_generator(thisArg, body) {
166
166
  }
167
167
  import { Hono } from 'hono';
168
168
  import { getWebhookManifest } from '../../brain-runner-do.js';
169
- import { findAndResumeBrain } from './coordination.js';
169
+ import { queueWebhookAndWakeUp } from './coordination.js';
170
170
  import system from './system.js';
171
171
  var webhooks = new Hono();
172
172
  // Mount system webhooks at /webhooks/system/*
@@ -237,7 +237,7 @@ webhooks.post('/:slug', function(context) {
237
237
  }
238
238
  return [
239
239
  4,
240
- findAndResumeBrain(context, slug, handlerResult.identifier, handlerResult.response)
240
+ queueWebhookAndWakeUp(context, slug, handlerResult.identifier, handlerResult.response)
241
241
  ];
242
242
  case 3:
243
243
  result = _state.sent();
@@ -171,7 +171,7 @@ function _ts_generator(thisArg, body) {
171
171
  }
172
172
  }
173
173
  import { Hono } from 'hono';
174
- import { findAndResumeBrain, parseFormData } from './coordination.js';
174
+ import { queueWebhookAndWakeUp, parseFormData } from './coordination.js';
175
175
  var system = new Hono();
176
176
  /**
177
177
  * Built-in webhook for UI form submissions.
@@ -211,7 +211,7 @@ var system = new Hono();
211
211
  response = parseFormData(formData);
212
212
  return [
213
213
  4,
214
- findAndResumeBrain(context, 'ui-form', identifier, response)
214
+ queueWebhookAndWakeUp(context, 'ui-form', identifier, response)
215
215
  ];
216
216
  case 3:
217
217
  result = _state.sent();