@positronic/cloudflare 0.0.76 → 0.0.78

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 (41) hide show
  1. package/dist/src/api/brains.js +90 -195
  2. package/dist/src/api/files.js +178 -0
  3. package/dist/src/api/index.js +9 -0
  4. package/dist/src/api/webhooks/coordination.js +0 -2
  5. package/dist/src/api/webhooks/index.js +43 -36
  6. package/dist/src/api/webhooks/system.js +23 -21
  7. package/dist/src/brain-runner-do.js +113 -173
  8. package/dist/src/content-type.js +6 -0
  9. package/dist/src/dev-server.js +128 -18
  10. package/dist/src/file-utils.js +7 -0
  11. package/dist/src/files-service.js +465 -0
  12. package/dist/src/manifest.js +13 -8
  13. package/dist/src/monitor-do.js +17 -0
  14. package/dist/src/schedule-do.js +5 -19
  15. package/dist/src/zip-builder.js +507 -0
  16. package/dist/types/api/brains.d.ts.map +1 -1
  17. package/dist/types/api/files.d.ts +7 -0
  18. package/dist/types/api/files.d.ts.map +1 -0
  19. package/dist/types/api/index.d.ts.map +1 -1
  20. package/dist/types/api/webhooks/coordination.d.ts +0 -1
  21. package/dist/types/api/webhooks/coordination.d.ts.map +1 -1
  22. package/dist/types/api/webhooks/index.d.ts.map +1 -1
  23. package/dist/types/api/webhooks/system.d.ts.map +1 -1
  24. package/dist/types/brain-runner-do.d.ts +13 -7
  25. package/dist/types/brain-runner-do.d.ts.map +1 -1
  26. package/dist/types/content-type.d.ts +2 -0
  27. package/dist/types/content-type.d.ts.map +1 -0
  28. package/dist/types/dev-server.d.ts +1 -0
  29. package/dist/types/dev-server.d.ts.map +1 -1
  30. package/dist/types/file-utils.d.ts +3 -0
  31. package/dist/types/file-utils.d.ts.map +1 -0
  32. package/dist/types/files-service.d.ts +4 -0
  33. package/dist/types/files-service.d.ts.map +1 -0
  34. package/dist/types/manifest.d.ts.map +1 -1
  35. package/dist/types/monitor-do.d.ts +6 -0
  36. package/dist/types/monitor-do.d.ts.map +1 -1
  37. package/dist/types/schedule-do.d.ts +0 -1
  38. package/dist/types/schedule-do.d.ts.map +1 -1
  39. package/dist/types/zip-builder.d.ts +4 -0
  40. package/dist/types/zip-builder.d.ts.map +1 -0
  41. package/package.json +5 -4
@@ -154,13 +154,43 @@ function _ts_generator(thisArg, body) {
154
154
  }
155
155
  }
156
156
  import { Hono } from 'hono';
157
- import { v4 as uuidv4 } from 'uuid';
158
157
  import { Cron } from 'croner';
159
158
  import Fuse from 'fuse.js';
160
159
  import { isSignalValid, brainMachineDefinition } from '@positronic/core';
161
160
  import { zodToJsonSchema } from 'zod-to-json-schema';
162
- import { getManifest } from '../brain-runner-do.js';
161
+ import { getManifest, startBrainRun } from '../brain-runner-do.js';
163
162
  var brains = new Hono();
163
+ /**
164
+ * Resolve a brain identifier from the manifest. Returns the brain and title
165
+ * on success, or an HTTP error Response on failure.
166
+ */ function resolveBrain(context, identifier) {
167
+ var multipleMatchStatus = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 300;
168
+ var manifest = getManifest();
169
+ if (!manifest) {
170
+ return context.json({
171
+ error: 'Manifest not initialized'
172
+ }, 500);
173
+ }
174
+ var resolution = manifest.resolve(identifier);
175
+ if (resolution.matchType === 'none') {
176
+ return context.json({
177
+ error: "Brain '".concat(identifier, "' not found")
178
+ }, 404);
179
+ }
180
+ if (resolution.matchType === 'multiple') {
181
+ return context.json({
182
+ error: 'Multiple brains match the identifier',
183
+ matchType: 'multiple',
184
+ candidates: resolution.candidates
185
+ }, multipleMatchStatus);
186
+ }
187
+ var brain = resolution.brain;
188
+ var brainTitle = brain.title || identifier;
189
+ return {
190
+ brain: brain,
191
+ brainTitle: brainTitle
192
+ };
193
+ }
164
194
  /**
165
195
  * Get the userName for ownership filtering from the auth context.
166
196
  * Root users get null (no filter — sees everything).
@@ -172,7 +202,7 @@ var brains = new Hono();
172
202
  }
173
203
  brains.post('/runs', function(context) {
174
204
  return _async_to_generator(function() {
175
- var requestBody, options, initialState, identifier, manifest, resolution, brain, brainRunId, namespace, doId, stub, auth, currentUser, initialData, brainTitle, response;
205
+ var requestBody, options, initialState, identifier, result, brain, auth, currentUser, initialData, brainRunId, response;
176
206
  return _ts_generator(this, function(_state) {
177
207
  switch(_state.label){
178
208
  case 0:
@@ -194,40 +224,12 @@ brains.post('/runs', function(context) {
194
224
  ];
195
225
  }
196
226
  // Validate that the brain exists before starting it
197
- manifest = getManifest();
198
- if (!manifest) {
199
- return [
200
- 2,
201
- context.json({
202
- error: 'Manifest not initialized'
203
- }, 500)
204
- ];
205
- }
206
- // Resolve the identifier to find the brain
207
- resolution = manifest.resolve(identifier);
208
- if (resolution.matchType === 'none') {
209
- return [
210
- 2,
211
- context.json({
212
- error: "Brain '".concat(identifier, "' not found")
213
- }, 404)
214
- ];
215
- }
216
- if (resolution.matchType === 'multiple') {
217
- return [
218
- 2,
219
- context.json({
220
- error: 'Multiple brains match the identifier',
221
- matchType: 'multiple',
222
- candidates: resolution.candidates
223
- }, 409)
224
- ];
225
- }
226
- brain = resolution.brain;
227
- brainRunId = uuidv4();
228
- namespace = context.env.BRAIN_RUNNER_DO;
229
- doId = namespace.idFromName(brainRunId);
230
- stub = namespace.get(doId);
227
+ result = resolveBrain(context, identifier, 409);
228
+ if (!('brain' in result)) return [
229
+ 2,
230
+ result
231
+ ];
232
+ brain = result.brain;
231
233
  // Read auth context for currentUser (every brain run must have an owner)
232
234
  auth = context.get('auth');
233
235
  if (!(auth === null || auth === void 0 ? void 0 : auth.userName) && !(auth === null || auth === void 0 ? void 0 : auth.isRoot)) {
@@ -247,14 +249,12 @@ brains.post('/runs', function(context) {
247
249
  }, initialState && {
248
250
  initialState: initialState
249
251
  }) : undefined;
250
- // Get the actual brain title from the resolved brain
251
- brainTitle = brain.title || identifier;
252
252
  return [
253
253
  4,
254
- stub.start(brainTitle, brainRunId, currentUser, initialData)
254
+ startBrainRun(context.env.BRAIN_RUNNER_DO, result.brainTitle, currentUser, initialData)
255
255
  ];
256
256
  case 2:
257
- _state.sent();
257
+ brainRunId = _state.sent();
258
258
  response = {
259
259
  brainRunId: brainRunId
260
260
  };
@@ -321,21 +321,27 @@ brains.post('/runs/rerun', function(context) {
321
321
  case 3:
322
322
  _state.trys.push([
323
323
  3,
324
- 5,
324
+ 6,
325
325
  ,
326
- 6
326
+ 7
327
327
  ]);
328
328
  return [
329
329
  4,
330
- stub.rerun(startsAt)
330
+ monitorStub.prepareForRerun(runId)
331
331
  ];
332
332
  case 4:
333
333
  _state.sent();
334
334
  return [
335
- 3,
336
- 6
335
+ 4,
336
+ stub.rerun(startsAt)
337
337
  ];
338
338
  case 5:
339
+ _state.sent();
340
+ return [
341
+ 3,
342
+ 7
343
+ ];
344
+ case 6:
339
345
  error = _state.sent();
340
346
  return [
341
347
  2,
@@ -343,7 +349,7 @@ brains.post('/runs/rerun', function(context) {
343
349
  error: error.message || 'Rerun failed'
344
350
  }, 500)
345
351
  ];
346
- case 6:
352
+ case 7:
347
353
  return [
348
354
  2,
349
355
  context.json({
@@ -486,7 +492,7 @@ brains.delete('/runs/:runId', function(context) {
486
492
  });
487
493
  })();
488
494
  });
489
- // Signal endpoint - queue KILL, PAUSE, USER_MESSAGE, RESUME, or WEBHOOK_RESPONSE signals
495
+ // Signal endpoint - queue KILL, PAUSE, RESUME, or WEBHOOK_RESPONSE signals
490
496
  brains.post('/runs/:runId/signals', function(context) {
491
497
  return _async_to_generator(function() {
492
498
  var runId, body, monitorId, monitorStub, run, validation, namespace, doId, stub, signal;
@@ -504,7 +510,6 @@ brains.post('/runs/:runId/signals', function(context) {
504
510
  if (![
505
511
  'KILL',
506
512
  'PAUSE',
507
- 'USER_MESSAGE',
508
513
  'RESUME',
509
514
  'WEBHOOK_RESPONSE'
510
515
  ].includes(body.type)) {
@@ -533,18 +538,14 @@ brains.post('/runs/:runId/signals', function(context) {
533
538
  ];
534
539
  }
535
540
  // Validate control signals against current brain state using state machine definition
536
- // USER_MESSAGE is a data signal that gets queued and processed during agent execution,
537
- // so it doesn't need state validation - it can always be queued
538
- if (body.type !== 'USER_MESSAGE') {
539
- validation = isSignalValid(brainMachineDefinition, run.status, body.type);
540
- if (!validation.valid) {
541
- return [
542
- 2,
543
- context.json({
544
- error: validation.reason
545
- }, 409)
546
- ];
547
- }
541
+ validation = isSignalValid(brainMachineDefinition, run.status, body.type);
542
+ if (!validation.valid) {
543
+ return [
544
+ 2,
545
+ context.json({
546
+ error: validation.reason
547
+ }, 409)
548
+ ];
548
549
  }
549
550
  // Get BrainRunnerDO stub and queue the signal
550
551
  namespace = context.env.BRAIN_RUNNER_DO;
@@ -647,51 +648,23 @@ brains.post('/runs/:runId/resume', function(context) {
647
648
  });
648
649
  brains.get('/:identifier/history', function(context) {
649
650
  return _async_to_generator(function() {
650
- var identifier, limit, manifest, resolution, brain, brainTitle, monitorId, monitorStub, userName, runs;
651
+ var identifier, limit, result, monitorId, monitorStub, userName, runs;
651
652
  return _ts_generator(this, function(_state) {
652
653
  switch(_state.label){
653
654
  case 0:
654
655
  identifier = context.req.param('identifier');
655
656
  limit = Number(context.req.query('limit') || '10');
656
- // Resolve the identifier to get the actual brain title
657
- manifest = getManifest();
658
- if (!manifest) {
659
- return [
660
- 2,
661
- context.json({
662
- error: 'Manifest not initialized'
663
- }, 500)
664
- ];
665
- }
666
- resolution = manifest.resolve(identifier);
667
- if (resolution.matchType === 'none') {
668
- return [
669
- 2,
670
- context.json({
671
- error: "Brain '".concat(identifier, "' not found")
672
- }, 404)
673
- ];
674
- }
675
- if (resolution.matchType === 'multiple') {
676
- return [
677
- 2,
678
- context.json({
679
- error: 'Multiple brains match the identifier',
680
- matchType: 'multiple',
681
- candidates: resolution.candidates
682
- }, 300)
683
- ];
684
- }
685
- // Get the actual brain title
686
- brain = resolution.brain;
687
- brainTitle = brain.title || identifier;
688
- // Get the monitor singleton instance
657
+ result = resolveBrain(context, identifier);
658
+ if (!('brain' in result)) return [
659
+ 2,
660
+ result
661
+ ];
689
662
  monitorId = context.env.MONITOR_DO.idFromName('singleton');
690
663
  monitorStub = context.env.MONITOR_DO.get(monitorId);
691
664
  userName = scopeUserName(context);
692
665
  return [
693
666
  4,
694
- monitorStub.history(brainTitle, limit, userName)
667
+ monitorStub.history(result.brainTitle, limit, userName)
695
668
  ];
696
669
  case 1:
697
670
  runs = _state.sent();
@@ -707,50 +680,22 @@ brains.get('/:identifier/history', function(context) {
707
680
  });
708
681
  brains.get('/:identifier/active-runs', function(context) {
709
682
  return _async_to_generator(function() {
710
- var identifier, manifest, resolution, brain, brainTitle, monitorId, monitorStub, userName, runs;
683
+ var identifier, result, monitorId, monitorStub, userName, runs;
711
684
  return _ts_generator(this, function(_state) {
712
685
  switch(_state.label){
713
686
  case 0:
714
687
  identifier = context.req.param('identifier');
715
- // Resolve the identifier to get the actual brain title
716
- manifest = getManifest();
717
- if (!manifest) {
718
- return [
719
- 2,
720
- context.json({
721
- error: 'Manifest not initialized'
722
- }, 500)
723
- ];
724
- }
725
- resolution = manifest.resolve(identifier);
726
- if (resolution.matchType === 'none') {
727
- return [
728
- 2,
729
- context.json({
730
- error: "Brain '".concat(identifier, "' not found")
731
- }, 404)
732
- ];
733
- }
734
- if (resolution.matchType === 'multiple') {
735
- return [
736
- 2,
737
- context.json({
738
- error: 'Multiple brains match the identifier',
739
- matchType: 'multiple',
740
- candidates: resolution.candidates
741
- }, 300)
742
- ];
743
- }
744
- // Get the actual brain title
745
- brain = resolution.brain;
746
- brainTitle = brain.title || identifier;
747
- // Get the monitor singleton instance
688
+ result = resolveBrain(context, identifier);
689
+ if (!('brain' in result)) return [
690
+ 2,
691
+ result
692
+ ];
748
693
  monitorId = context.env.MONITOR_DO.idFromName('singleton');
749
694
  monitorStub = context.env.MONITOR_DO.get(monitorId);
750
695
  userName = scopeUserName(context);
751
696
  return [
752
697
  4,
753
- monitorStub.activeRuns(brainTitle, userName)
698
+ monitorStub.activeRuns(result.brainTitle, userName)
754
699
  ];
755
700
  case 1:
756
701
  runs = _state.sent();
@@ -931,7 +876,7 @@ brains.get('/', function(context) {
931
876
  // Create a new schedule
932
877
  brains.post('/schedules', function(context) {
933
878
  return _async_to_generator(function() {
934
- var body, cronExpression, identifier, manifest, resolution, brain, brainTitle, scheduleDoId, scheduleStub, auth, runAsUserName, timezone, schedule, error, errorMessage;
879
+ var body, cronExpression, identifier, result, brainTitle, scheduleDoId, scheduleStub, auth, runAsUserName, timezone, schedule, error, errorMessage;
935
880
  return _ts_generator(this, function(_state) {
936
881
  switch(_state.label){
937
882
  case 0:
@@ -978,37 +923,12 @@ brains.post('/schedules', function(context) {
978
923
  ];
979
924
  }
980
925
  // Resolve the identifier to get the actual brain title
981
- manifest = getManifest();
982
- if (!manifest) {
983
- return [
984
- 2,
985
- context.json({
986
- error: 'Manifest not initialized'
987
- }, 500)
988
- ];
989
- }
990
- resolution = manifest.resolve(identifier);
991
- if (resolution.matchType === 'none') {
992
- return [
993
- 2,
994
- context.json({
995
- error: "Brain '".concat(identifier, "' not found")
996
- }, 404)
997
- ];
998
- }
999
- if (resolution.matchType === 'multiple') {
1000
- return [
1001
- 2,
1002
- context.json({
1003
- error: 'Multiple brains match the identifier',
1004
- matchType: 'multiple',
1005
- candidates: resolution.candidates
1006
- }, 409)
1007
- ];
1008
- }
1009
- // Get the actual brain title
1010
- brain = resolution.brain;
1011
- brainTitle = brain.title || identifier;
926
+ result = resolveBrain(context, identifier, 409);
927
+ if (!('brain' in result)) return [
928
+ 2,
929
+ result
930
+ ];
931
+ brainTitle = result.brainTitle;
1012
932
  // Get the schedule singleton instance
1013
933
  scheduleDoId = context.env.SCHEDULE_DO.idFromName('singleton');
1014
934
  scheduleStub = context.env.SCHEDULE_DO.get(scheduleDoId);
@@ -1241,40 +1161,15 @@ brains.delete('/schedules/:scheduleId', function(context) {
1241
1161
  });
1242
1162
  brains.get('/:identifier', function(context) {
1243
1163
  return _async_to_generator(function() {
1244
- var identifier, manifest, resolution, brain, structure;
1164
+ var identifier, result, brain, structure;
1245
1165
  return _ts_generator(this, function(_state) {
1246
1166
  identifier = context.req.param('identifier');
1247
- manifest = getManifest();
1248
- if (!manifest) {
1249
- return [
1250
- 2,
1251
- context.json({
1252
- error: 'Manifest not initialized'
1253
- }, 500)
1254
- ];
1255
- }
1256
- // Resolve the identifier to find the brain
1257
- resolution = manifest.resolve(identifier);
1258
- if (resolution.matchType === 'none') {
1259
- return [
1260
- 2,
1261
- context.json({
1262
- error: "Brain '".concat(identifier, "' not found")
1263
- }, 404)
1264
- ];
1265
- }
1266
- if (resolution.matchType === 'multiple') {
1267
- return [
1268
- 2,
1269
- context.json({
1270
- error: 'Multiple brains match the identifier',
1271
- matchType: 'multiple',
1272
- candidates: resolution.candidates
1273
- }, 300)
1274
- ];
1275
- }
1276
- brain = resolution.brain;
1277
- // Get the brain structure
1167
+ result = resolveBrain(context, identifier);
1168
+ if (!('brain' in result)) return [
1169
+ 2,
1170
+ result
1171
+ ];
1172
+ brain = result.brain;
1278
1173
  structure = brain.structure;
1279
1174
  return [
1280
1175
  2,
@@ -0,0 +1,178 @@
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 _ts_generator(thisArg, body) {
31
+ var f, y, t, _ = {
32
+ label: 0,
33
+ sent: function() {
34
+ if (t[0] & 1) throw t[1];
35
+ return t[1];
36
+ },
37
+ trys: [],
38
+ ops: []
39
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
40
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
41
+ return this;
42
+ }), g;
43
+ function verb(n) {
44
+ return function(v) {
45
+ return step([
46
+ n,
47
+ v
48
+ ]);
49
+ };
50
+ }
51
+ function step(op) {
52
+ if (f) throw new TypeError("Generator is already executing.");
53
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
54
+ 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;
55
+ if (y = 0, t) op = [
56
+ op[0] & 2,
57
+ t.value
58
+ ];
59
+ switch(op[0]){
60
+ case 0:
61
+ case 1:
62
+ t = op;
63
+ break;
64
+ case 4:
65
+ _.label++;
66
+ return {
67
+ value: op[1],
68
+ done: false
69
+ };
70
+ case 5:
71
+ _.label++;
72
+ y = op[1];
73
+ op = [
74
+ 0
75
+ ];
76
+ continue;
77
+ case 7:
78
+ op = _.ops.pop();
79
+ _.trys.pop();
80
+ continue;
81
+ default:
82
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
83
+ _ = 0;
84
+ continue;
85
+ }
86
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
87
+ _.label = op[1];
88
+ break;
89
+ }
90
+ if (op[0] === 6 && _.label < t[1]) {
91
+ _.label = t[1];
92
+ t = op;
93
+ break;
94
+ }
95
+ if (t && _.label < t[2]) {
96
+ _.label = t[2];
97
+ _.ops.push(op);
98
+ break;
99
+ }
100
+ if (t[2]) _.ops.pop();
101
+ _.trys.pop();
102
+ continue;
103
+ }
104
+ op = body.call(thisArg, _);
105
+ } catch (e) {
106
+ op = [
107
+ 6,
108
+ e
109
+ ];
110
+ y = 0;
111
+ } finally{
112
+ f = t = 0;
113
+ }
114
+ if (op[0] & 5) throw op[1];
115
+ return {
116
+ value: op[0] ? op[1] : void 0,
117
+ done: true
118
+ };
119
+ }
120
+ }
121
+ import { Hono } from 'hono';
122
+ import { guessContentType } from '../content-type.js';
123
+ var files = new Hono();
124
+ /**
125
+ * GET /files/* — serves file content from R2.
126
+ * URL path is /files/user/{userName}/{brainTitle}/{name}
127
+ * R2 key is files/user/{userName}/{brainTitle}/{name} (prepend "files/" prefix)
128
+ * Public endpoint (no auth) so download URLs work in browsers.
129
+ */ files.get('/*', function(context) {
130
+ return _async_to_generator(function() {
131
+ var path, key, bucket, object, headers;
132
+ return _ts_generator(this, function(_state) {
133
+ switch(_state.label){
134
+ case 0:
135
+ path = context.req.path.replace(/^\/files\//, '');
136
+ if (!path) {
137
+ return [
138
+ 2,
139
+ context.json({
140
+ error: 'File path is required'
141
+ }, 400)
142
+ ];
143
+ }
144
+ // Reconstruct the R2 key by adding the "files/" namespace prefix
145
+ key = "files/".concat(path);
146
+ bucket = context.env.RESOURCES_BUCKET;
147
+ return [
148
+ 4,
149
+ bucket.get(key)
150
+ ];
151
+ case 1:
152
+ object = _state.sent();
153
+ if (!object) {
154
+ return [
155
+ 2,
156
+ context.json({
157
+ error: 'File not found'
158
+ }, 404)
159
+ ];
160
+ }
161
+ headers = new Headers();
162
+ object.writeHttpMetadata(headers);
163
+ // If no content-type was stored, infer from the key
164
+ if (!headers.get('content-type')) {
165
+ headers.set('content-type', guessContentType(key));
166
+ }
167
+ headers.set('etag', object.httpEtag);
168
+ return [
169
+ 2,
170
+ new Response(object.body, {
171
+ headers: headers
172
+ })
173
+ ];
174
+ }
175
+ });
176
+ })();
177
+ });
178
+ export default files;
@@ -127,6 +127,7 @@ import secrets from './secrets.js';
127
127
  import bundle from './bundle.js';
128
128
  import users from './users.js';
129
129
  import store from './store.js';
130
+ import files from './files.js';
130
131
  import { authMiddleware } from './auth-middleware.js';
131
132
  var app = new Hono();
132
133
  // Health check endpoint (no auth required)
@@ -191,6 +192,13 @@ app.use('*', function(c, next) {
191
192
  next()
192
193
  ];
193
194
  }
195
+ // Skip auth for files (download URLs are public)
196
+ if (c.req.method === 'GET' && c.req.path.startsWith('/files/')) {
197
+ return [
198
+ 2,
199
+ next()
200
+ ];
201
+ }
194
202
  // Skip auth for all webhook POST requests (external services and browser forms can't send JWT)
195
203
  if (c.req.method === 'POST' && c.req.path.startsWith('/webhooks/')) {
196
204
  return [
@@ -239,4 +247,5 @@ app.route('/secrets', secrets);
239
247
  app.route('/bundle', bundle);
240
248
  app.route('/users', users);
241
249
  app.route('/store', store);
250
+ app.route('/files', files);
242
251
  export default app;
@@ -227,5 +227,3 @@ import { isSignalValid, brainMachineDefinition, validateWebhookToken } from '@po
227
227
  });
228
228
  })();
229
229
  }
230
- // Re-export parseFormData from core for backwards compatibility
231
- export { parseFormData } from '@positronic/core';