@vistagenic/vista 0.3.2 → 0.3.4
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/bin/vista.js +79 -109
- package/dist/ai/embeddings.d.ts +11 -11
- package/dist/ai/embeddings.js +71 -71
- package/dist/ai/index.d.ts +10 -10
- package/dist/ai/index.js +26 -26
- package/dist/ai/providers/base.js +85 -85
- package/dist/ai/react/react-server.d.ts +1 -1
- package/dist/ai/react/react-server.js +17 -17
- package/dist/ai/react/use-agent.js +138 -138
- package/dist/auth/core.d.ts +140 -140
- package/dist/auth/core.js +165 -165
- package/dist/auth/index.d.ts +20 -20
- package/dist/auth/index.js +369 -369
- package/dist/auth/react-server.d.ts +1 -1
- package/dist/auth/react-server.js +10 -10
- package/dist/auth/react.d.ts +18 -18
- package/dist/auth/react.js +71 -71
- package/dist/bin/build-rsc-flashpack.js +6 -0
- package/dist/bin/build-rsc.js +555 -492
- package/dist/bin/build.js +365 -353
- package/dist/bin/generate.js +513 -510
- package/dist/bin/webpack.config.d.ts +3 -1
- package/dist/bin/webpack.config.js +7 -4
- package/dist/build/manifest.d.ts +169 -169
- package/dist/build/manifest.js +423 -423
- package/dist/build/rsc/client-manifest.d.ts +62 -62
- package/dist/build/rsc/client-manifest.js +295 -295
- package/dist/build/rsc/compiler.d.ts +3 -1
- package/dist/build/rsc/compiler.js +12 -7
- package/dist/build/rsc/native-scanner.d.ts +135 -135
- package/dist/build/rsc/native-scanner.js +203 -203
- package/dist/build/rsc/react-client-reference-manifest.d.ts +35 -28
- package/dist/build/rsc/react-client-reference-manifest.js +366 -240
- package/dist/build/standalone.js +260 -254
- package/dist/client/dynamic.react-server.d.ts +2 -2
- package/dist/client/dynamic.react-server.js +23 -23
- package/dist/client/link.js +1 -1
- package/dist/client/link.react-server.d.ts +2 -2
- package/dist/client/link.react-server.js +11 -11
- package/dist/client/navigation.js +2 -2
- package/dist/client/navigation.react-server.d.ts +1 -1
- package/dist/client/navigation.react-server.js +17 -17
- package/dist/client/router.react-server.d.ts +1 -1
- package/dist/client/router.react-server.js +17 -17
- package/dist/client/rsc-router.d.ts +1 -3
- package/dist/client/rsc-router.js +98 -45
- package/dist/client/rsc-router.react-server.d.ts +1 -1
- package/dist/client/rsc-router.react-server.js +17 -17
- package/dist/client/script.react-server.d.ts +2 -2
- package/dist/client/script.react-server.js +23 -23
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -7
- package/dist/deploy/adapters/cloudflare.js +42 -41
- package/dist/deploy/adapters/docker.d.ts +1 -0
- package/dist/deploy/adapters/docker.js +5 -4
- package/dist/deploy/adapters/netlify.js +60 -27
- package/dist/deploy/adapters/vercel.js +80 -50
- package/dist/deploy/preflight.js +4 -3
- package/dist/deploy/runtime-pack.d.ts +11 -0
- package/dist/deploy/runtime-pack.js +300 -0
- package/dist/deploy/utils.d.ts +7 -1
- package/dist/deploy/utils.js +95 -3
- package/dist/flashpack/command.js +1 -0
- package/dist/flashpack/runtime.js +2 -1
- package/dist/image/get-img-props.js +21 -11
- package/dist/image/image-config.d.ts +2 -0
- package/dist/image/image-config.js +17 -0
- package/dist/image/index.d.ts +18 -3
- package/dist/image/index.js +1 -1
- package/dist/image/react-server.d.ts +1 -2
- package/dist/image/react-server.js +1 -1
- package/dist/index.d.ts +23 -23
- package/dist/index.js +61 -61
- package/dist/server/app-dir.d.ts +22 -0
- package/dist/server/app-dir.js +77 -0
- package/dist/server/app-router-runtime.d.ts +1 -0
- package/dist/server/app-router-runtime.js +34 -9
- package/dist/server/cookie-parse.d.ts +4 -4
- package/dist/server/cookie-parse.js +14 -14
- package/dist/server/engine.js +5 -5
- package/dist/server/hydration-chunks.d.ts +7 -0
- package/dist/server/hydration-chunks.js +49 -0
- package/dist/server/image-optimizer.js +2 -1
- package/dist/server/index.d.ts +109 -109
- package/dist/server/index.js +315 -315
- package/dist/server/middleware-runner.d.ts +125 -125
- package/dist/server/middleware-runner.js +607 -615
- package/dist/server/middleware-security.d.ts +36 -36
- package/dist/server/middleware-security.js +183 -183
- package/dist/server/module-compile-hook.js +706 -695
- package/dist/server/root-resolver.js +6 -5
- package/dist/server/rsc-engine-flashpack.d.ts +3 -1
- package/dist/server/rsc-engine-flashpack.js +12 -1
- package/dist/server/rsc-engine.d.ts +6 -1
- package/dist/server/rsc-engine.js +217 -280
- package/dist/server/rsc-upstream.js +900 -892
- package/dist/server/ssr-webpack-shim.d.ts +6 -0
- package/dist/server/ssr-webpack-shim.js +29 -0
- package/dist/server/static-generator.d.ts +2 -0
- package/dist/server/static-generator.js +33 -32
- package/dist/server/structure-validator.js +2 -1
- package/dist/server/structure-watch.js +2 -0
- package/dist/server/typed-api-runtime.js +639 -635
- package/dist/server/vista-import-map.js +134 -134
- package/dist/stack/index.d.ts +34 -34
- package/dist/stack/index.js +49 -49
- package/dist/stack/server/caller.d.ts +13 -13
- package/dist/stack/server/caller.js +42 -42
- package/dist/stack/server/executor.d.ts +40 -40
- package/dist/stack/server/executor.js +222 -222
- package/dist/stack/server/index.d.ts +11 -11
- package/dist/stack/server/index.js +24 -24
- package/dist/stack/server/procedure.d.ts +20 -20
- package/dist/stack/server/procedure.js +66 -66
- package/dist/stack/server/types.d.ts +113 -113
- package/dist/theme/react-server.d.ts +10 -10
- package/dist/theme/react-server.js +16 -16
- package/package.json +1 -1
|
@@ -1,635 +1,639 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.resolveLegacyApiRoutePath = resolveLegacyApiRoutePath;
|
|
7
|
-
exports.resolveRouteHandlerMatch = resolveRouteHandlerMatch;
|
|
8
|
-
exports.resolveLegacyRouteHandlerPath = resolveLegacyRouteHandlerPath;
|
|
9
|
-
exports.runLegacyApiRoute = runLegacyApiRoute;
|
|
10
|
-
exports.runTypedApiRoute = runTypedApiRoute;
|
|
11
|
-
const fs_1 = __importDefault(require("fs"));
|
|
12
|
-
const path_1 = __importDefault(require("path"));
|
|
13
|
-
const node_stream_1 = require("node:stream");
|
|
14
|
-
const server_1 = require("../stack/server");
|
|
15
|
-
const segment_config_1 = require("./segment-config");
|
|
16
|
-
const request_context_1 = require("./request-context");
|
|
17
|
-
const route_handler_registry_1 = require("./route-handler-registry");
|
|
18
|
-
const cookie_parse_1 = require("./cookie-parse");
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
path_1.default.join('
|
|
23
|
-
path_1.default.join('
|
|
24
|
-
path_1.default.join('
|
|
25
|
-
path_1.default.join('
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{ requestPath: '/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
mod?.
|
|
68
|
-
mod?.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
typeof res.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
return
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
//
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
res
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
if (
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
const
|
|
541
|
-
if (!
|
|
542
|
-
return false;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const
|
|
564
|
-
const
|
|
565
|
-
const
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
return
|
|
581
|
-
}
|
|
582
|
-
if (
|
|
583
|
-
res.
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if (typedError instanceof
|
|
597
|
-
typedError
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveLegacyApiRoutePath = resolveLegacyApiRoutePath;
|
|
7
|
+
exports.resolveRouteHandlerMatch = resolveRouteHandlerMatch;
|
|
8
|
+
exports.resolveLegacyRouteHandlerPath = resolveLegacyRouteHandlerPath;
|
|
9
|
+
exports.runLegacyApiRoute = runLegacyApiRoute;
|
|
10
|
+
exports.runTypedApiRoute = runTypedApiRoute;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const node_stream_1 = require("node:stream");
|
|
14
|
+
const server_1 = require("../stack/server");
|
|
15
|
+
const segment_config_1 = require("./segment-config");
|
|
16
|
+
const request_context_1 = require("./request-context");
|
|
17
|
+
const route_handler_registry_1 = require("./route-handler-registry");
|
|
18
|
+
const cookie_parse_1 = require("./cookie-parse");
|
|
19
|
+
const app_dir_1 = require("./app-dir");
|
|
20
|
+
// Relative to the resolved app directory (supports both app/ and src/app layouts).
|
|
21
|
+
const TYPED_API_ENTRYPOINTS = [
|
|
22
|
+
path_1.default.join('api', 'typed.ts'),
|
|
23
|
+
path_1.default.join('api', 'typed.tsx'),
|
|
24
|
+
path_1.default.join('api', 'typed.js'),
|
|
25
|
+
path_1.default.join('api', 'typed.jsx'),
|
|
26
|
+
'typed-api.ts',
|
|
27
|
+
'typed-api.tsx',
|
|
28
|
+
'typed-api.js',
|
|
29
|
+
'typed-api.jsx',
|
|
30
|
+
];
|
|
31
|
+
const METADATA_ROUTE_MAPPINGS = [
|
|
32
|
+
{ requestPath: '/robots.txt', stem: 'robots' },
|
|
33
|
+
{ requestPath: '/sitemap.xml', stem: 'sitemap' },
|
|
34
|
+
{ requestPath: '/manifest.webmanifest', stem: 'manifest' },
|
|
35
|
+
];
|
|
36
|
+
const ROUTE_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'];
|
|
37
|
+
class BodyLimitError extends Error {
|
|
38
|
+
status = 413;
|
|
39
|
+
constructor(limitBytes) {
|
|
40
|
+
super(`Request body exceeds configured limit (${limitBytes} bytes)`);
|
|
41
|
+
this.name = 'BodyLimitError';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
class BodyParseError extends Error {
|
|
45
|
+
status = 400;
|
|
46
|
+
constructor(message) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = 'BodyParseError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const DEFAULT_ROUTE_BODY_LIMIT_BYTES = 1024 * 1024;
|
|
52
|
+
function isWebResponse(value) {
|
|
53
|
+
return typeof Response !== 'undefined' && value instanceof Response;
|
|
54
|
+
}
|
|
55
|
+
function isStackRouterLike(value) {
|
|
56
|
+
if (!value || typeof value !== 'object') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const candidate = value;
|
|
60
|
+
return (!!candidate.procedures &&
|
|
61
|
+
!!candidate.routes &&
|
|
62
|
+
!!candidate.metadata &&
|
|
63
|
+
typeof candidate.resolve === 'function');
|
|
64
|
+
}
|
|
65
|
+
function resolveTypedRouterFromModule(mod) {
|
|
66
|
+
const candidates = [
|
|
67
|
+
mod?.default,
|
|
68
|
+
mod?.router,
|
|
69
|
+
mod?.typedRouter,
|
|
70
|
+
mod?.api,
|
|
71
|
+
typeof mod?.createRouter === 'function' ? mod.createRouter() : null,
|
|
72
|
+
typeof mod?.createTypedRouter === 'function' ? mod.createTypedRouter() : null,
|
|
73
|
+
];
|
|
74
|
+
for (const candidate of candidates) {
|
|
75
|
+
if (isStackRouterLike(candidate)) {
|
|
76
|
+
return candidate;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function normalizeApiPath(pathname) {
|
|
82
|
+
if (!pathname.startsWith('/api')) {
|
|
83
|
+
return pathname || '/';
|
|
84
|
+
}
|
|
85
|
+
const stripped = pathname.slice('/api'.length);
|
|
86
|
+
return stripped ? stripped : '/';
|
|
87
|
+
}
|
|
88
|
+
function buildPathCandidates(pathname) {
|
|
89
|
+
const normalized = pathname || '/';
|
|
90
|
+
const apiNormalized = normalizeApiPath(normalized);
|
|
91
|
+
const dedup = new Set([normalized, apiNormalized]);
|
|
92
|
+
return Array.from(dedup);
|
|
93
|
+
}
|
|
94
|
+
function normalizeRouteRequestPath(requestPath) {
|
|
95
|
+
const normalized = String(requestPath || '/').split('?')[0].replace(/\\/g, '/');
|
|
96
|
+
if (normalized === '/' || normalized === '') {
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
return normalized.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
100
|
+
}
|
|
101
|
+
function isRouteGroupDirectory(name) {
|
|
102
|
+
return /^\([\w-]+\)$/.test(name);
|
|
103
|
+
}
|
|
104
|
+
function resolveMetadataRoutePath(cwd, stem) {
|
|
105
|
+
const appDir = (0, app_dir_1.resolveAppDir)(cwd);
|
|
106
|
+
const tryStemInDirectory = (dir) => {
|
|
107
|
+
for (const extension of ROUTE_FILE_EXTENSIONS) {
|
|
108
|
+
const candidate = path_1.default.join(dir, `${stem}${extension}`);
|
|
109
|
+
if (fs_1.default.existsSync(candidate)) {
|
|
110
|
+
return candidate;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
};
|
|
115
|
+
const directMatch = tryStemInDirectory(appDir);
|
|
116
|
+
if (directMatch) {
|
|
117
|
+
return directMatch;
|
|
118
|
+
}
|
|
119
|
+
const searchGroupDirectories = (dir) => {
|
|
120
|
+
const entries = fs_1.default
|
|
121
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
122
|
+
.filter((entry) => entry.isDirectory() && isRouteGroupDirectory(entry.name))
|
|
123
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
const groupDir = path_1.default.join(dir, entry.name);
|
|
126
|
+
const match = tryStemInDirectory(groupDir);
|
|
127
|
+
if (match) {
|
|
128
|
+
return match;
|
|
129
|
+
}
|
|
130
|
+
const nestedMatch = searchGroupDirectories(groupDir);
|
|
131
|
+
if (nestedMatch) {
|
|
132
|
+
return nestedMatch;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
};
|
|
137
|
+
return searchGroupDirectories(appDir);
|
|
138
|
+
}
|
|
139
|
+
function hasMethodMatch(router, pathname, method) {
|
|
140
|
+
const normalized = method.toLowerCase();
|
|
141
|
+
return router.resolve(pathname, normalized) !== null;
|
|
142
|
+
}
|
|
143
|
+
function hasRouteForAnyMethod(router, pathname) {
|
|
144
|
+
return hasMethodMatch(router, pathname, 'get') || hasMethodMatch(router, pathname, 'post');
|
|
145
|
+
}
|
|
146
|
+
async function parseRequestBody(req, bodySizeLimitBytes) {
|
|
147
|
+
if (req.method === 'GET' || req.method === 'HEAD') {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
const chunks = [];
|
|
151
|
+
let size = 0;
|
|
152
|
+
for await (const chunk of req) {
|
|
153
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
154
|
+
size += buffer.length;
|
|
155
|
+
if (size > bodySizeLimitBytes) {
|
|
156
|
+
throw new BodyLimitError(bodySizeLimitBytes);
|
|
157
|
+
}
|
|
158
|
+
chunks.push(buffer);
|
|
159
|
+
}
|
|
160
|
+
if (chunks.length === 0) {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
const raw = Buffer.concat(chunks);
|
|
164
|
+
const contentType = String(req.headers['content-type'] || '')
|
|
165
|
+
.split(';')[0]
|
|
166
|
+
.trim()
|
|
167
|
+
.toLowerCase();
|
|
168
|
+
if (!contentType || contentType === 'application/json' || contentType.endsWith('+json')) {
|
|
169
|
+
try {
|
|
170
|
+
return JSON.parse(raw.toString('utf-8'));
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
throw new BodyParseError('Invalid JSON body for typed API request.');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (contentType === 'application/x-www-form-urlencoded') {
|
|
177
|
+
return Object.fromEntries(new URLSearchParams(raw.toString('utf-8')).entries());
|
|
178
|
+
}
|
|
179
|
+
if (contentType.startsWith('text/')) {
|
|
180
|
+
return raw.toString('utf-8');
|
|
181
|
+
}
|
|
182
|
+
return raw;
|
|
183
|
+
}
|
|
184
|
+
async function sendFetchResponse(res, response) {
|
|
185
|
+
response.headers.forEach((value, key) => {
|
|
186
|
+
res.setHeader(key, value);
|
|
187
|
+
});
|
|
188
|
+
const method = String(res.req?.method || '').toUpperCase();
|
|
189
|
+
res.status(response.status);
|
|
190
|
+
if (method === 'HEAD' || !response.body) {
|
|
191
|
+
res.end();
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const canPipe = typeof res.once === 'function' &&
|
|
195
|
+
typeof res.on === 'function' &&
|
|
196
|
+
typeof res.write === 'function' &&
|
|
197
|
+
typeof res.end === 'function';
|
|
198
|
+
if (canPipe && typeof node_stream_1.Readable.fromWeb === 'function') {
|
|
199
|
+
try {
|
|
200
|
+
const nodeStream = node_stream_1.Readable.fromWeb(response.body);
|
|
201
|
+
await new Promise((resolve, reject) => {
|
|
202
|
+
const fail = (error) => reject(error);
|
|
203
|
+
nodeStream.once('error', fail);
|
|
204
|
+
res.once('error', fail);
|
|
205
|
+
res.once('finish', () => resolve());
|
|
206
|
+
nodeStream.pipe(res);
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Fall through to buffering when the web stream cannot be piped.
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const arrayBuffer = await new Response(response.body).arrayBuffer();
|
|
215
|
+
const body = Buffer.from(arrayBuffer);
|
|
216
|
+
if (typeof res.send === 'function') {
|
|
217
|
+
res.send(body);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
res.end(body);
|
|
221
|
+
}
|
|
222
|
+
function applyRuntimeTraceHeaders(res, segmentConfig, mode) {
|
|
223
|
+
res.setHeader('X-Vista-Route-Runtime', segmentConfig.runtime);
|
|
224
|
+
res.setHeader('X-Vista-Advanced-Runtime', mode);
|
|
225
|
+
}
|
|
226
|
+
function createReadonlyCookieStore(header) {
|
|
227
|
+
const cookieMap = new Map();
|
|
228
|
+
if (header) {
|
|
229
|
+
for (const segment of header.split(';')) {
|
|
230
|
+
const [rawName, ...valueParts] = segment.split('=');
|
|
231
|
+
const name = rawName?.trim();
|
|
232
|
+
if (!name)
|
|
233
|
+
continue;
|
|
234
|
+
cookieMap.set(name, (0, cookie_parse_1.safeDecodeURIComponent)(valueParts.join('=').trim()));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
get(name) {
|
|
239
|
+
const value = cookieMap.get(name);
|
|
240
|
+
return value === undefined ? undefined : { name, value };
|
|
241
|
+
},
|
|
242
|
+
getAll() {
|
|
243
|
+
return Array.from(cookieMap.entries()).map(([name, value]) => ({ name, value }));
|
|
244
|
+
},
|
|
245
|
+
has(name) {
|
|
246
|
+
return cookieMap.has(name);
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function bufferFromParsedBody(body) {
|
|
251
|
+
if (body === undefined || body === null) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
if (Buffer.isBuffer(body)) {
|
|
255
|
+
return body;
|
|
256
|
+
}
|
|
257
|
+
if (typeof body === 'string') {
|
|
258
|
+
return Buffer.from(body);
|
|
259
|
+
}
|
|
260
|
+
if (typeof body === 'object') {
|
|
261
|
+
return Buffer.from(JSON.stringify(body));
|
|
262
|
+
}
|
|
263
|
+
return Buffer.from(String(body));
|
|
264
|
+
}
|
|
265
|
+
async function readRouteRequestBody(req, bodySizeLimitBytes = DEFAULT_ROUTE_BODY_LIMIT_BYTES) {
|
|
266
|
+
if (req.method === 'GET' || req.method === 'HEAD') {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
const hasParsedBody = Object.prototype.hasOwnProperty.call(req, 'body') && req.body !== undefined;
|
|
270
|
+
const streamEnded = req.readableEnded === true || req.complete === true;
|
|
271
|
+
if (hasParsedBody && streamEnded) {
|
|
272
|
+
const parsed = bufferFromParsedBody(req.body);
|
|
273
|
+
if (parsed && parsed.length > bodySizeLimitBytes) {
|
|
274
|
+
throw new BodyLimitError(bodySizeLimitBytes);
|
|
275
|
+
}
|
|
276
|
+
return parsed;
|
|
277
|
+
}
|
|
278
|
+
const chunks = [];
|
|
279
|
+
let size = 0;
|
|
280
|
+
for await (const chunk of req) {
|
|
281
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
282
|
+
size += buffer.length;
|
|
283
|
+
if (size > bodySizeLimitBytes) {
|
|
284
|
+
throw new BodyLimitError(bodySizeLimitBytes);
|
|
285
|
+
}
|
|
286
|
+
chunks.push(buffer);
|
|
287
|
+
}
|
|
288
|
+
if (chunks.length === 0) {
|
|
289
|
+
if (hasParsedBody) {
|
|
290
|
+
const parsed = bufferFromParsedBody(req.body);
|
|
291
|
+
if (parsed && parsed.length > bodySizeLimitBytes) {
|
|
292
|
+
throw new BodyLimitError(bodySizeLimitBytes);
|
|
293
|
+
}
|
|
294
|
+
return parsed;
|
|
295
|
+
}
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
return Buffer.concat(chunks);
|
|
299
|
+
}
|
|
300
|
+
function buildRequestUrl(req) {
|
|
301
|
+
const protocol = req.protocol || 'http';
|
|
302
|
+
const host = req.get('host') || 'localhost';
|
|
303
|
+
return new URL(req.originalUrl || req.url || req.path || '/', `${protocol}://${host}`);
|
|
304
|
+
}
|
|
305
|
+
function createRouteRequest(req, body) {
|
|
306
|
+
const requestUrl = buildRequestUrl(req);
|
|
307
|
+
const headers = new Headers();
|
|
308
|
+
for (const [key, value] of Object.entries(req.headers || {})) {
|
|
309
|
+
if (Array.isArray(value)) {
|
|
310
|
+
for (const entry of value) {
|
|
311
|
+
headers.append(key, String(entry));
|
|
312
|
+
}
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (value !== undefined) {
|
|
316
|
+
headers.set(key, String(value));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const requestInit = {
|
|
320
|
+
method: req.method,
|
|
321
|
+
headers,
|
|
322
|
+
};
|
|
323
|
+
if (body !== undefined) {
|
|
324
|
+
requestInit.body = new Uint8Array(body);
|
|
325
|
+
}
|
|
326
|
+
const request = new Request(requestUrl.toString(), requestInit);
|
|
327
|
+
Object.defineProperty(request, 'nextUrl', {
|
|
328
|
+
configurable: true,
|
|
329
|
+
enumerable: true,
|
|
330
|
+
value: {
|
|
331
|
+
pathname: requestUrl.pathname,
|
|
332
|
+
searchParams: requestUrl.searchParams,
|
|
333
|
+
href: requestUrl.href,
|
|
334
|
+
origin: requestUrl.origin,
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
Object.defineProperty(request, 'cookies', {
|
|
338
|
+
configurable: true,
|
|
339
|
+
enumerable: true,
|
|
340
|
+
value: createReadonlyCookieStore(headers.get('cookie')),
|
|
341
|
+
});
|
|
342
|
+
return request;
|
|
343
|
+
}
|
|
344
|
+
function resolveRouteSegmentRuntime(apiPath, apiModule) {
|
|
345
|
+
let parsedSourceConfig = {};
|
|
346
|
+
try {
|
|
347
|
+
const source = fs_1.default.readFileSync(apiPath, 'utf-8');
|
|
348
|
+
parsedSourceConfig = (0, segment_config_1.parseSegmentConfig)(source, apiPath).config;
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
parsedSourceConfig = {};
|
|
352
|
+
}
|
|
353
|
+
const runtimeValue = typeof apiModule?.runtime === 'string' ? apiModule.runtime : parsedSourceConfig.runtime;
|
|
354
|
+
return (0, segment_config_1.mergeSegmentConfigs)([
|
|
355
|
+
{
|
|
356
|
+
absolutePath: apiPath,
|
|
357
|
+
segmentConfig: {
|
|
358
|
+
...parsedSourceConfig,
|
|
359
|
+
...(runtimeValue ? { runtime: runtimeValue } : {}),
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
]);
|
|
363
|
+
}
|
|
364
|
+
function isEdgeRuntime(runtime) {
|
|
365
|
+
return runtime === 'edge' || runtime === 'experimental-edge';
|
|
366
|
+
}
|
|
367
|
+
function getTypedApiEntrypoint(cwd) {
|
|
368
|
+
const appDir = (0, app_dir_1.resolveAppDir)(cwd);
|
|
369
|
+
for (const relativePath of TYPED_API_ENTRYPOINTS) {
|
|
370
|
+
const absolutePath = path_1.default.join(appDir, relativePath);
|
|
371
|
+
if (fs_1.default.existsSync(absolutePath)) {
|
|
372
|
+
return absolutePath;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
async function executeTypedRoute(router, options) {
|
|
378
|
+
const pathCandidates = buildPathCandidates(options.req.path);
|
|
379
|
+
const method = options.method.toLowerCase();
|
|
380
|
+
let selectedPath = null;
|
|
381
|
+
let routeExistsForDifferentMethod = false;
|
|
382
|
+
for (const candidate of pathCandidates) {
|
|
383
|
+
if (hasMethodMatch(router, candidate, method)) {
|
|
384
|
+
selectedPath = candidate;
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
if (hasRouteForAnyMethod(router, candidate)) {
|
|
388
|
+
routeExistsForDifferentMethod = true;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (!selectedPath) {
|
|
392
|
+
if (routeExistsForDifferentMethod) {
|
|
393
|
+
return {
|
|
394
|
+
kind: 'method-not-allowed',
|
|
395
|
+
status: 405,
|
|
396
|
+
error: `Method ${method.toUpperCase()} not allowed`,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
return { kind: 'not-found' };
|
|
400
|
+
}
|
|
401
|
+
const result = await (0, server_1.executeRoute)(router, {
|
|
402
|
+
path: selectedPath,
|
|
403
|
+
method,
|
|
404
|
+
req: {
|
|
405
|
+
method,
|
|
406
|
+
path: selectedPath,
|
|
407
|
+
query: options.query,
|
|
408
|
+
body: options.body,
|
|
409
|
+
headers: options.req.headers,
|
|
410
|
+
originalUrl: options.req.originalUrl,
|
|
411
|
+
url: options.req.url,
|
|
412
|
+
cookies: createReadonlyCookieStore(typeof options.req.headers?.cookie === 'string' ? options.req.headers.cookie : null),
|
|
413
|
+
},
|
|
414
|
+
ctx: options.context,
|
|
415
|
+
env: options.env,
|
|
416
|
+
serialization: options.serialization,
|
|
417
|
+
});
|
|
418
|
+
return {
|
|
419
|
+
kind: 'handled',
|
|
420
|
+
status: isWebResponse(result.data) ? result.data.status : 200,
|
|
421
|
+
payload: isWebResponse(result.data) ? result.data : result.serializedData,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function resolveLegacyApiRoutePath(cwd, requestPath) {
|
|
425
|
+
if (!requestPath.startsWith('/api/')) {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
return resolveLegacyRouteHandlerPath(cwd, requestPath);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Resolve a request path to a route handler file plus its dynamic params.
|
|
432
|
+
*
|
|
433
|
+
* Static routes are answered by a direct filesystem probe, which keeps the common
|
|
434
|
+
* case free of any directory walk. Only when that misses do we consult the discovered
|
|
435
|
+
* route table, which is what makes `app/api/users/[id]/route.ts` reachable.
|
|
436
|
+
*/
|
|
437
|
+
function resolveRouteHandlerMatch(cwd, requestPath, options = {}) {
|
|
438
|
+
const literalPath = resolveLegacyRouteHandlerPath(cwd, requestPath);
|
|
439
|
+
if (literalPath) {
|
|
440
|
+
return { filePath: literalPath, params: {} };
|
|
441
|
+
}
|
|
442
|
+
const dynamicMatch = (0, route_handler_registry_1.resolveRouteHandler)((0, app_dir_1.resolveAppDir)(cwd), requestPath, options);
|
|
443
|
+
if (dynamicMatch) {
|
|
444
|
+
return { filePath: dynamicMatch.filePath, params: dynamicMatch.params };
|
|
445
|
+
}
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
function resolveLegacyRouteHandlerPath(cwd, requestPath) {
|
|
449
|
+
const normalized = normalizeRouteRequestPath(requestPath);
|
|
450
|
+
const appDir = (0, app_dir_1.resolveAppDir)(cwd);
|
|
451
|
+
const routeCandidates = [];
|
|
452
|
+
const metadataRoute = METADATA_ROUTE_MAPPINGS.find((entry) => entry.requestPath === String(requestPath || '').split('?')[0]);
|
|
453
|
+
if (metadataRoute) {
|
|
454
|
+
const resolvedMetadataPath = resolveMetadataRoutePath(cwd, metadataRoute.stem);
|
|
455
|
+
if (resolvedMetadataPath) {
|
|
456
|
+
routeCandidates.push(resolvedMetadataPath);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
if (normalized.startsWith('api/')) {
|
|
460
|
+
const apiRoute = normalized.slice('api/'.length);
|
|
461
|
+
routeCandidates.push(path_1.default.join(appDir, 'api', apiRoute, 'route.ts'), path_1.default.join(appDir, 'api', apiRoute, 'route.tsx'), path_1.default.join(appDir, 'api', apiRoute, 'route.js'), path_1.default.join(appDir, 'api', apiRoute, 'route.jsx'), path_1.default.join(appDir, 'api', `${apiRoute}.ts`), path_1.default.join(appDir, 'api', `${apiRoute}.tsx`), path_1.default.join(appDir, 'api', `${apiRoute}.js`), path_1.default.join(appDir, 'api', `${apiRoute}.jsx`));
|
|
462
|
+
}
|
|
463
|
+
routeCandidates.push(path_1.default.join(appDir, normalized, 'route.ts'), path_1.default.join(appDir, normalized, 'route.tsx'), path_1.default.join(appDir, normalized, 'route.js'), path_1.default.join(appDir, normalized, 'route.jsx'));
|
|
464
|
+
for (const routePath of routeCandidates) {
|
|
465
|
+
if (fs_1.default.existsSync(routePath)) {
|
|
466
|
+
return routePath;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
/** HTTP methods a module actually exports, in canonical order. */
|
|
472
|
+
function getExportedRouteMethods(apiModule) {
|
|
473
|
+
return route_handler_registry_1.ROUTE_HANDLER_METHODS.filter((method) => typeof apiModule?.[method] === 'function');
|
|
474
|
+
}
|
|
475
|
+
async function runLegacyApiRoute(options) {
|
|
476
|
+
const { req, res, apiPath, isDev } = options;
|
|
477
|
+
const params = options.params || {};
|
|
478
|
+
if (isDev) {
|
|
479
|
+
delete require.cache[require.resolve(apiPath)];
|
|
480
|
+
}
|
|
481
|
+
const apiModule = require(apiPath);
|
|
482
|
+
const resolvedSegmentConfig = resolveRouteSegmentRuntime(apiPath, apiModule);
|
|
483
|
+
(0, request_context_1.setCurrentSegmentConfig)(resolvedSegmentConfig);
|
|
484
|
+
const runtime = resolvedSegmentConfig.runtime;
|
|
485
|
+
applyRuntimeTraceHeaders(res, resolvedSegmentConfig, 'route-handler');
|
|
486
|
+
const method = req.method?.toUpperCase() || 'GET';
|
|
487
|
+
const exportedMethods = getExportedRouteMethods(apiModule);
|
|
488
|
+
// HEAD falls back to GET, per RFC 9110: same headers, response body dropped by
|
|
489
|
+
// Express because the request method is HEAD.
|
|
490
|
+
const methodHandler = apiModule[method] || (method === 'HEAD' ? apiModule.GET : undefined);
|
|
491
|
+
// An unhandled OPTIONS request is answered from the exported method list rather
|
|
492
|
+
// than 405, so CORS preflight works without every route writing a handler.
|
|
493
|
+
if (method === 'OPTIONS' && typeof methodHandler !== 'function' && exportedMethods.length > 0) {
|
|
494
|
+
const allow = [...new Set([...exportedMethods, 'OPTIONS'])].join(', ');
|
|
495
|
+
res.status(204).setHeader('Allow', allow);
|
|
496
|
+
res.end();
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (typeof methodHandler === 'function') {
|
|
500
|
+
try {
|
|
501
|
+
const requestBody = await readRouteRequestBody(req);
|
|
502
|
+
const request = createRouteRequest(req, requestBody);
|
|
503
|
+
const result = await methodHandler(request, { params });
|
|
504
|
+
if (result instanceof Response) {
|
|
505
|
+
res.req = res.req || req;
|
|
506
|
+
await sendFetchResponse(res, result);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (result !== undefined) {
|
|
510
|
+
res.status(200).json(result);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
res.status(204).end();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
catch (error) {
|
|
517
|
+
if (error instanceof BodyLimitError) {
|
|
518
|
+
res.status(error.status).json({ error: error.message });
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
throw error;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (isEdgeRuntime(runtime) && typeof apiModule.default === 'function') {
|
|
525
|
+
res.status(500).json({
|
|
526
|
+
error: 'Edge runtime route handlers must export HTTP method functions instead of a default Express handler.',
|
|
527
|
+
});
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (typeof apiModule.default === 'function') {
|
|
531
|
+
apiModule.default(req, res);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
if (exportedMethods.length > 0) {
|
|
535
|
+
res.setHeader('Allow', [...new Set([...exportedMethods, 'OPTIONS'])].join(', '));
|
|
536
|
+
}
|
|
537
|
+
res.status(405).json({ error: `Method ${method} not allowed` });
|
|
538
|
+
}
|
|
539
|
+
async function runTypedApiRoute(options) {
|
|
540
|
+
const { req, res, cwd, isDev, config } = options;
|
|
541
|
+
if (!config.enabled) {
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
544
|
+
const entrypoint = getTypedApiEntrypoint(cwd);
|
|
545
|
+
if (!entrypoint) {
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
try {
|
|
549
|
+
if (isDev) {
|
|
550
|
+
delete require.cache[require.resolve(entrypoint)];
|
|
551
|
+
}
|
|
552
|
+
const typedModule = require(entrypoint);
|
|
553
|
+
const router = resolveTypedRouterFromModule(typedModule);
|
|
554
|
+
const resolvedSegmentConfig = resolveRouteSegmentRuntime(entrypoint, typedModule);
|
|
555
|
+
(0, request_context_1.setCurrentSegmentConfig)(resolvedSegmentConfig);
|
|
556
|
+
applyRuntimeTraceHeaders(res, resolvedSegmentConfig, 'typed-api');
|
|
557
|
+
if (!router) {
|
|
558
|
+
res.status(500).json({
|
|
559
|
+
error: `Typed API entrypoint "${path_1.default.relative(cwd, entrypoint)}" does not export a valid stack router.`,
|
|
560
|
+
});
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
const method = (req.method || 'GET').toUpperCase();
|
|
564
|
+
const body = await parseRequestBody(req, config.bodySizeLimitBytes);
|
|
565
|
+
const query = (req.query ?? {});
|
|
566
|
+
const contextFactory = typeof typedModule.createContext === 'function' ? typedModule.createContext : null;
|
|
567
|
+
const envFactory = typeof typedModule.createEnv === 'function' ? typedModule.createEnv : null;
|
|
568
|
+
const context = contextFactory ? await contextFactory({ req, res }) : {};
|
|
569
|
+
const env = envFactory ? await envFactory({ req, res }) : {};
|
|
570
|
+
const routeResult = await executeTypedRoute(router, {
|
|
571
|
+
req,
|
|
572
|
+
method,
|
|
573
|
+
query,
|
|
574
|
+
body,
|
|
575
|
+
serialization: config.serialization,
|
|
576
|
+
context: context ?? {},
|
|
577
|
+
env,
|
|
578
|
+
});
|
|
579
|
+
if (routeResult.kind === 'not-found') {
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
if (routeResult.kind === 'method-not-allowed') {
|
|
583
|
+
res.status(routeResult.status).json({ error: routeResult.error });
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
if (isWebResponse(routeResult.payload)) {
|
|
587
|
+
res.req = res.req || req;
|
|
588
|
+
await sendFetchResponse(res, routeResult.payload);
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
res.status(routeResult.status).json(routeResult.payload);
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
catch (error) {
|
|
595
|
+
const typedError = error;
|
|
596
|
+
if (typedError instanceof BodyLimitError || typedError instanceof BodyParseError) {
|
|
597
|
+
res.status(typedError.status).json({ error: typedError.message });
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
if (typedError instanceof server_1.StackValidationError ||
|
|
601
|
+
typedError instanceof server_1.StackMethodNotAllowedError) {
|
|
602
|
+
const status = typeof typedError.status === 'number' ? typedError.status : 400;
|
|
603
|
+
res.status(status).json({ error: typedError.message });
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
if (typedError instanceof server_1.StackRouteNotFoundError) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
// Router-level error handler gets first chance.
|
|
610
|
+
try {
|
|
611
|
+
const entrypoint = getTypedApiEntrypoint(cwd);
|
|
612
|
+
if (entrypoint) {
|
|
613
|
+
if (isDev) {
|
|
614
|
+
delete require.cache[require.resolve(entrypoint)];
|
|
615
|
+
}
|
|
616
|
+
const typedModule = require(entrypoint);
|
|
617
|
+
const router = resolveTypedRouterFromModule(typedModule);
|
|
618
|
+
const errorHandler = router?.metadata?.errorHandler;
|
|
619
|
+
if (typeof errorHandler === 'function') {
|
|
620
|
+
const response = errorHandler(error, {
|
|
621
|
+
method: req.method,
|
|
622
|
+
path: req.path,
|
|
623
|
+
query: (req.query ?? {}),
|
|
624
|
+
headers: req.headers,
|
|
625
|
+
});
|
|
626
|
+
if (response instanceof Response) {
|
|
627
|
+
await sendFetchResponse(res, response);
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
catch {
|
|
634
|
+
// Ignore fallback handler errors and use generic 500 response below.
|
|
635
|
+
}
|
|
636
|
+
res.status(500).json({ error: 'Internal Server Error in Typed API' });
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
}
|