effect-start 0.10.0 → 0.11.0
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/package.json +5 -3
- package/src/FileHttpRouter.test.ts +4 -4
- package/src/FileHttpRouter.ts +6 -8
- package/src/FileRouter.ts +4 -6
- package/src/FileRouterCodegen.test.ts +2 -2
- package/src/HttpAppExtra.test.ts +84 -0
- package/src/HttpAppExtra.ts +399 -47
- package/src/Route.test.ts +59 -33
- package/src/Route.ts +59 -49
- package/src/RouteRender.ts +6 -4
- package/src/Router.test.ts +416 -0
- package/src/Router.ts +279 -0
- package/src/RouterPattern.test.ts +29 -3
- package/src/RouterPattern.ts +30 -5
- package/src/TestHttpClient.test.ts +29 -0
- package/src/TestHttpClient.ts +122 -73
- package/src/assets.d.ts +39 -0
- package/src/bun/BunHttpServer.test.ts +74 -0
- package/src/bun/BunHttpServer.ts +22 -9
- package/src/bun/BunRoute.test.ts +307 -134
- package/src/bun/BunRoute.ts +240 -139
- package/src/bun/BunRoute_bundles.test.ts +181 -181
- package/src/index.ts +14 -14
- package/src/middlewares/BasicAuthMiddleware.test.ts +74 -0
- package/src/middlewares/BasicAuthMiddleware.ts +36 -0
package/src/bun/BunRoute.ts
CHANGED
|
@@ -2,34 +2,119 @@ import * as HttpApp from "@effect/platform/HttpApp"
|
|
|
2
2
|
import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
|
|
3
3
|
import * as HttpServerResponse from "@effect/platform/HttpServerResponse"
|
|
4
4
|
import type * as Bun from "bun"
|
|
5
|
+
import * as Array from "effect/Array"
|
|
5
6
|
import * as Effect from "effect/Effect"
|
|
6
|
-
|
|
7
7
|
import * as Function from "effect/Function"
|
|
8
|
+
import * as Option from "effect/Option"
|
|
8
9
|
import * as Predicate from "effect/Predicate"
|
|
9
10
|
import type * as Runtime from "effect/Runtime"
|
|
11
|
+
import * as HttpAppExtra from "../HttpAppExtra.ts"
|
|
10
12
|
import * as HttpUtils from "../HttpUtils.ts"
|
|
13
|
+
import * as HyperHtml from "../HyperHtml.ts"
|
|
11
14
|
import * as Random from "../Random.ts"
|
|
12
15
|
import * as Route from "../Route.ts"
|
|
13
16
|
import * as Router from "../Router.ts"
|
|
14
17
|
import * as RouteRender from "../RouteRender.ts"
|
|
15
18
|
import * as RouterPattern from "../RouterPattern.ts"
|
|
19
|
+
import * as BunHttpServer from "./BunHttpServer.ts"
|
|
16
20
|
|
|
17
21
|
const TypeId: unique symbol = Symbol.for("effect-start/BunRoute")
|
|
18
22
|
|
|
23
|
+
const INTERNAL_FETCH_HEADER = "x-effect-start-internal-fetch"
|
|
24
|
+
|
|
19
25
|
export type BunRoute =
|
|
20
26
|
& Route.Route
|
|
21
27
|
& {
|
|
22
28
|
[TypeId]: typeof TypeId
|
|
29
|
+
// Prefix because Bun.serve routes ignore everything after `*` in wildcard patterns.
|
|
30
|
+
// A suffix like `/*~internal` would match the same as `/*`, shadowing the internal route.
|
|
31
|
+
internalPathPrefix: string
|
|
23
32
|
load: () => Promise<Bun.HTMLBundle>
|
|
24
33
|
}
|
|
25
34
|
|
|
26
|
-
export function
|
|
35
|
+
export function html(
|
|
27
36
|
load: () => Promise<Bun.HTMLBundle | { default: Bun.HTMLBundle }>,
|
|
28
37
|
): BunRoute {
|
|
38
|
+
const internalPathPrefix = `/.BunRoute-${Random.token(6)}`
|
|
39
|
+
|
|
40
|
+
const handler: Route.RouteHandler<
|
|
41
|
+
HttpServerResponse.HttpServerResponse,
|
|
42
|
+
Router.RouterError,
|
|
43
|
+
BunHttpServer.BunServer
|
|
44
|
+
> = (context) =>
|
|
45
|
+
Effect.gen(function*() {
|
|
46
|
+
const originalRequest = context.request.source as Request
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
originalRequest.headers.get(INTERNAL_FETCH_HEADER) === "true"
|
|
50
|
+
) {
|
|
51
|
+
return yield* Effect.fail(
|
|
52
|
+
new Router.RouterError({
|
|
53
|
+
reason: "ProxyError",
|
|
54
|
+
pattern: context.url.pathname,
|
|
55
|
+
message:
|
|
56
|
+
"Request to internal Bun server was caught by BunRoute handler. This should not happen. Please report a bug.",
|
|
57
|
+
}),
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const bunServer = yield* BunHttpServer.BunServer
|
|
62
|
+
const internalPath = `${internalPathPrefix}${context.url.pathname}`
|
|
63
|
+
const internalUrl = new URL(internalPath, bunServer.server.url)
|
|
64
|
+
|
|
65
|
+
const headers = new Headers(originalRequest.headers)
|
|
66
|
+
headers.set(INTERNAL_FETCH_HEADER, "true")
|
|
67
|
+
|
|
68
|
+
const proxyRequest = new Request(internalUrl, {
|
|
69
|
+
method: originalRequest.method,
|
|
70
|
+
headers,
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const response = yield* Effect.tryPromise({
|
|
74
|
+
try: () => fetch(proxyRequest),
|
|
75
|
+
catch: (error) =>
|
|
76
|
+
new Router.RouterError({
|
|
77
|
+
reason: "ProxyError",
|
|
78
|
+
pattern: internalPath,
|
|
79
|
+
message: `Failed to fetch internal HTML bundle: ${String(error)}`,
|
|
80
|
+
}),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
let html = yield* Effect.tryPromise({
|
|
84
|
+
try: () => response.text(),
|
|
85
|
+
catch: (error) =>
|
|
86
|
+
new Router.RouterError({
|
|
87
|
+
reason: "ProxyError",
|
|
88
|
+
pattern: internalPath,
|
|
89
|
+
message: String(error),
|
|
90
|
+
}),
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const children = yield* context.next<Router.RouterError, never>()
|
|
94
|
+
let childrenHtml = ""
|
|
95
|
+
if (children != null) {
|
|
96
|
+
if (HttpServerResponse.isServerResponse(children)) {
|
|
97
|
+
const webResponse = HttpServerResponse.toWeb(children)
|
|
98
|
+
childrenHtml = yield* Effect.promise(() => webResponse.text())
|
|
99
|
+
} else if (Route.isGenericJsxObject(children)) {
|
|
100
|
+
childrenHtml = HyperHtml.renderToString(children)
|
|
101
|
+
} else {
|
|
102
|
+
childrenHtml = String(children)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
html = html.replace(/%yield%/g, childrenHtml)
|
|
107
|
+
html = html.replace(/%slots\.(\w+)%/g, (_, name) =>
|
|
108
|
+
context.slots[name] ?? "")
|
|
109
|
+
|
|
110
|
+
return HttpServerResponse
|
|
111
|
+
.html(html)
|
|
112
|
+
})
|
|
113
|
+
|
|
29
114
|
const route = Route.make({
|
|
30
|
-
method: "
|
|
115
|
+
method: "*",
|
|
31
116
|
media: "text/html",
|
|
32
|
-
handler
|
|
117
|
+
handler,
|
|
33
118
|
schemas: {},
|
|
34
119
|
})
|
|
35
120
|
|
|
@@ -37,11 +122,13 @@ export function loadBundle(
|
|
|
37
122
|
Object.create(route),
|
|
38
123
|
{
|
|
39
124
|
[TypeId]: TypeId,
|
|
125
|
+
internalPathPrefix,
|
|
40
126
|
load: () => load().then(mod => "default" in mod ? mod.default : mod),
|
|
127
|
+
set: [],
|
|
41
128
|
},
|
|
42
129
|
)
|
|
43
130
|
|
|
44
|
-
bunRoute.set
|
|
131
|
+
bunRoute.set.push(bunRoute)
|
|
45
132
|
|
|
46
133
|
return bunRoute
|
|
47
134
|
}
|
|
@@ -50,41 +137,47 @@ export function isBunRoute(input: unknown): input is BunRoute {
|
|
|
50
137
|
return Predicate.hasProperty(input, TypeId)
|
|
51
138
|
}
|
|
52
139
|
|
|
53
|
-
function
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const matchingRoutes: Route.Route.Default[] = []
|
|
58
|
-
for (const layer of layers) {
|
|
59
|
-
for (const layerRoute of layer.set) {
|
|
60
|
-
if (Route.matches(layerRoute, route)) {
|
|
61
|
-
matchingRoutes.push(layerRoute)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return matchingRoutes
|
|
66
|
-
}
|
|
140
|
+
function makeHandler(routes: Route.Route.Default[]) {
|
|
141
|
+
return Effect.gen(function*() {
|
|
142
|
+
const request = yield* HttpServerRequest.HttpServerRequest
|
|
143
|
+
const accept = request.headers.accept ?? ""
|
|
67
144
|
|
|
68
|
-
|
|
69
|
-
innerRoute: Route.Route.Default,
|
|
70
|
-
layerRoute: Route.Route.Default,
|
|
71
|
-
): Route.Route.Default {
|
|
72
|
-
const handler: Route.RouteHandler = (context) => {
|
|
73
|
-
const innerNext = () => innerRoute.handler(context)
|
|
145
|
+
let selectedRoute: Route.Route.Default | undefined
|
|
74
146
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
147
|
+
if (accept.includes("application/json")) {
|
|
148
|
+
selectedRoute = routes.find((r) => r.media === "application/json")
|
|
149
|
+
}
|
|
150
|
+
if (!selectedRoute && accept.includes("text/plain")) {
|
|
151
|
+
selectedRoute = routes.find((r) => r.media === "text/plain")
|
|
152
|
+
}
|
|
153
|
+
if (
|
|
154
|
+
!selectedRoute
|
|
155
|
+
&& (accept.includes("text/html")
|
|
156
|
+
|| accept.includes("*/*")
|
|
157
|
+
|| !accept)
|
|
158
|
+
) {
|
|
159
|
+
selectedRoute = routes.find((r) => r.media === "text/html")
|
|
160
|
+
}
|
|
161
|
+
if (!selectedRoute) {
|
|
162
|
+
selectedRoute = routes[0]
|
|
78
163
|
}
|
|
79
164
|
|
|
80
|
-
|
|
81
|
-
|
|
165
|
+
if (!selectedRoute) {
|
|
166
|
+
return HttpServerResponse.empty({ status: 406 })
|
|
167
|
+
}
|
|
82
168
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
169
|
+
const context: Route.RouteContext = {
|
|
170
|
+
request,
|
|
171
|
+
get url() {
|
|
172
|
+
return HttpUtils.makeUrlFromRequest(request)
|
|
173
|
+
},
|
|
174
|
+
slots: {},
|
|
175
|
+
next: () => Effect.void,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return yield* RouteRender.render(selectedRoute, context).pipe(
|
|
179
|
+
Effect.catchAllCause((cause) => HttpAppExtra.renderError(cause, accept)),
|
|
180
|
+
)
|
|
88
181
|
})
|
|
89
182
|
}
|
|
90
183
|
|
|
@@ -126,9 +219,12 @@ export function bundlesFromRouter(
|
|
|
126
219
|
([path, route]) =>
|
|
127
220
|
Effect.promise(() =>
|
|
128
221
|
route.load().then((bundle) => {
|
|
129
|
-
const httpPath = RouterPattern.
|
|
222
|
+
const httpPath = RouterPattern.toBun(path)
|
|
130
223
|
|
|
131
|
-
return [
|
|
224
|
+
return [
|
|
225
|
+
httpPath,
|
|
226
|
+
bundle,
|
|
227
|
+
] as const
|
|
132
228
|
})
|
|
133
229
|
),
|
|
134
230
|
{ concurrency: "unbounded" },
|
|
@@ -161,7 +257,54 @@ function isMethodHandlers(value: unknown): value is MethodHandlers {
|
|
|
161
257
|
}
|
|
162
258
|
|
|
163
259
|
/**
|
|
164
|
-
*
|
|
260
|
+
* Validates that a route pattern can be implemented with Bun.serve routes.
|
|
261
|
+
*
|
|
262
|
+
* Supported patterns (native or via multiple routes):
|
|
263
|
+
* - /exact - Exact match
|
|
264
|
+
* - /users/:id - Full-segment named param
|
|
265
|
+
* - /path/* - Directory wildcard
|
|
266
|
+
* - /* - Catch-all
|
|
267
|
+
* - /[[id]] - Optional param (implemented via `/` and `/:id`)
|
|
268
|
+
* - /[[...rest]] - Optional rest param (implemented via `/` and `/*`)
|
|
269
|
+
*
|
|
270
|
+
* Unsupported patterns (cannot be implemented in Bun):
|
|
271
|
+
* - /pk_[id] - Prefix before param
|
|
272
|
+
* - /[id]_sfx - Suffix after param
|
|
273
|
+
* - /[id].json - Suffix with dot
|
|
274
|
+
* - /[id]~test - Suffix with tilde
|
|
275
|
+
* - /hello-* - Inline prefix wildcard
|
|
276
|
+
*/
|
|
277
|
+
|
|
278
|
+
export function validateBunPattern(
|
|
279
|
+
pattern: string,
|
|
280
|
+
): Option.Option<Router.RouterError> {
|
|
281
|
+
const segments = RouterPattern.parse(pattern)
|
|
282
|
+
|
|
283
|
+
const unsupported = Array.findFirst(segments, (seg) => {
|
|
284
|
+
if (seg._tag === "ParamSegment") {
|
|
285
|
+
return seg.prefix !== undefined || seg.suffix !== undefined
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return false
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
if (Option.isSome(unsupported)) {
|
|
292
|
+
return Option.some(
|
|
293
|
+
new Router.RouterError({
|
|
294
|
+
reason: "UnsupportedPattern",
|
|
295
|
+
pattern,
|
|
296
|
+
message:
|
|
297
|
+
`Pattern "${pattern}" uses prefixed/suffixed params (prefix_[param] or [param]_suffix) `
|
|
298
|
+
+ `which cannot be implemented in Bun.serve.`,
|
|
299
|
+
}),
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return Option.none()
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Converts a RouterBuilder into Bun-compatible routes passed to {@link Bun.serve}.
|
|
165
308
|
*
|
|
166
309
|
* For BunRoutes (HtmlBundle), creates two routes:
|
|
167
310
|
* - An internal route at `${path}~BunRoute-${nonce}:${path}` holding the actual HtmlBundle
|
|
@@ -171,129 +314,87 @@ function isMethodHandlers(value: unknown): value is MethodHandlers {
|
|
|
171
314
|
* the HtmlBundle natively on the internal route.
|
|
172
315
|
*/
|
|
173
316
|
export function routesFromRouter(
|
|
174
|
-
router: Router.
|
|
175
|
-
runtime?: Runtime.Runtime<
|
|
176
|
-
): Effect.Effect<BunRoutes> {
|
|
317
|
+
router: Router.RouterBuilder.Any,
|
|
318
|
+
runtime?: Runtime.Runtime<BunHttpServer.BunServer>,
|
|
319
|
+
): Effect.Effect<BunRoutes, Router.RouterError, BunHttpServer.BunServer> {
|
|
177
320
|
return Effect.gen(function*() {
|
|
178
|
-
const rt = runtime ?? (yield* Effect.runtime<
|
|
179
|
-
const nonce = Random.token(6)
|
|
180
|
-
|
|
181
|
-
const loadedRoutes = yield* Effect.forEach(
|
|
182
|
-
router.routes,
|
|
183
|
-
(mod) =>
|
|
184
|
-
Effect.gen(function*() {
|
|
185
|
-
const routeModule = yield* Effect.promise(() => mod.load())
|
|
186
|
-
|
|
187
|
-
const layerModules = mod.layers
|
|
188
|
-
? yield* Effect.forEach(
|
|
189
|
-
mod.layers,
|
|
190
|
-
(layerLoad) => Effect.promise(() => layerLoad()),
|
|
191
|
-
)
|
|
192
|
-
: []
|
|
193
|
-
|
|
194
|
-
const layers = layerModules
|
|
195
|
-
.map((m: any) => m.default)
|
|
196
|
-
.filter(Route.isRouteLayer)
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
path: mod.path,
|
|
200
|
-
exported: routeModule.default,
|
|
201
|
-
layers,
|
|
202
|
-
}
|
|
203
|
-
}),
|
|
204
|
-
)
|
|
205
|
-
|
|
321
|
+
const rt = runtime ?? (yield* Effect.runtime<BunHttpServer.BunServer>())
|
|
206
322
|
const result: BunRoutes = {}
|
|
207
323
|
|
|
208
|
-
for (const
|
|
209
|
-
const
|
|
324
|
+
for (const entry of router.entries) {
|
|
325
|
+
const { path, route: routeSet, layers } = entry
|
|
210
326
|
|
|
211
|
-
const
|
|
212
|
-
|
|
327
|
+
const validationError = validateBunPattern(path)
|
|
328
|
+
if (Option.isSome(validationError)) {
|
|
329
|
+
return yield* Effect.fail(validationError.value)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
for (const route of routeSet.set) {
|
|
213
333
|
if (isBunRoute(route)) {
|
|
214
334
|
const bundle = yield* Effect.promise(() => route.load())
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const proxyHandler: BunServerFetchHandler = (request) => {
|
|
220
|
-
const url = new URL(internalPath, request.url)
|
|
221
|
-
return fetch(new Request(url, request))
|
|
335
|
+
const bunPaths = RouterPattern.toBun(path)
|
|
336
|
+
for (const bunPath of bunPaths) {
|
|
337
|
+
const internalPath = `${route.internalPathPrefix}${bunPath}`
|
|
338
|
+
result[internalPath] = bundle
|
|
222
339
|
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
223
342
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
343
|
+
for (const layer of layers) {
|
|
344
|
+
for (const route of layer.set) {
|
|
345
|
+
if (isBunRoute(route)) {
|
|
346
|
+
const bundle = yield* Effect.promise(() => route.load())
|
|
347
|
+
const bunPaths = RouterPattern.toBun(path)
|
|
348
|
+
for (const bunPath of bunPaths) {
|
|
349
|
+
const internalPath = `${route.internalPathPrefix}${bunPath}`
|
|
350
|
+
result[internalPath] = bundle
|
|
227
351
|
}
|
|
228
352
|
}
|
|
229
|
-
} else {
|
|
230
|
-
const existing = byMethod.get(route.method) ?? []
|
|
231
|
-
existing.push(route)
|
|
232
|
-
byMethod.set(route.method, existing)
|
|
233
353
|
}
|
|
234
354
|
}
|
|
355
|
+
}
|
|
235
356
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const request = yield* HttpServerRequest.HttpServerRequest
|
|
239
|
-
const accept = request.headers.accept ?? ""
|
|
240
|
-
|
|
241
|
-
let selectedRoute: Route.Route.Default | undefined
|
|
242
|
-
|
|
243
|
-
if (accept.includes("application/json")) {
|
|
244
|
-
selectedRoute = routes.find((r) => r.media === "application/json")
|
|
245
|
-
}
|
|
246
|
-
if (!selectedRoute && accept.includes("text/plain")) {
|
|
247
|
-
selectedRoute = routes.find((r) => r.media === "text/plain")
|
|
248
|
-
}
|
|
249
|
-
if (
|
|
250
|
-
!selectedRoute
|
|
251
|
-
&& (accept.includes("text/html")
|
|
252
|
-
|| accept.includes("*/*")
|
|
253
|
-
|| !accept)
|
|
254
|
-
) {
|
|
255
|
-
selectedRoute = routes.find((r) => r.media === "text/html")
|
|
256
|
-
}
|
|
257
|
-
if (!selectedRoute) {
|
|
258
|
-
selectedRoute = routes[0]
|
|
259
|
-
}
|
|
357
|
+
for (const path of Object.keys(router.mounts)) {
|
|
358
|
+
const routeSet = router.mounts[path]
|
|
260
359
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
360
|
+
const validationError = validateBunPattern(path)
|
|
361
|
+
if (Option.isSome(validationError)) {
|
|
362
|
+
continue
|
|
363
|
+
}
|
|
264
364
|
|
|
265
|
-
|
|
266
|
-
selectedRoute,
|
|
267
|
-
layers,
|
|
268
|
-
)
|
|
269
|
-
let wrappedRoute = selectedRoute
|
|
270
|
-
for (const layerRoute of matchingLayerRoutes.reverse()) {
|
|
271
|
-
wrappedRoute = wrapWithLayerRoute(wrappedRoute, layerRoute)
|
|
272
|
-
}
|
|
365
|
+
const httpPaths = RouterPattern.toBun(path as Route.RoutePattern)
|
|
273
366
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
next: () => Effect.void,
|
|
281
|
-
}
|
|
367
|
+
const byMethod = new Map<Route.RouteMethod, Route.Route.Default[]>()
|
|
368
|
+
for (const route of routeSet.set) {
|
|
369
|
+
const existing = byMethod.get(route.method) ?? []
|
|
370
|
+
existing.push(route)
|
|
371
|
+
byMethod.set(route.method, existing)
|
|
372
|
+
}
|
|
282
373
|
|
|
283
|
-
|
|
284
|
-
|
|
374
|
+
const entry = router.entries.find((e) => e.path === path)
|
|
375
|
+
const allMiddleware = (entry?.layers ?? [])
|
|
376
|
+
.map((layer) => layer.httpMiddleware)
|
|
377
|
+
.filter((m): m is Route.HttpMiddlewareFunction => m !== undefined)
|
|
285
378
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
.filter((m): m is Route.HttpMiddlewareFunction => m !== undefined)
|
|
379
|
+
for (const [method, routes] of byMethod) {
|
|
380
|
+
let httpApp: HttpApp.Default<any, any> = makeHandler(routes)
|
|
289
381
|
|
|
290
|
-
let finalHandler = httpApp
|
|
291
382
|
for (const middleware of allMiddleware) {
|
|
292
|
-
|
|
383
|
+
httpApp = middleware(httpApp)
|
|
293
384
|
}
|
|
294
385
|
|
|
295
|
-
const webHandler = HttpApp.toWebHandlerRuntime(rt)(
|
|
296
|
-
const handler: BunServerFetchHandler = (request) =>
|
|
386
|
+
const webHandler = HttpApp.toWebHandlerRuntime(rt)(httpApp)
|
|
387
|
+
const handler: BunServerFetchHandler = (request) => {
|
|
388
|
+
const url = new URL(request.url)
|
|
389
|
+
if (url.pathname.startsWith("/.BunRoute-")) {
|
|
390
|
+
return new Response(
|
|
391
|
+
"Internal routing error: BunRoute internal path was not matched. "
|
|
392
|
+
+ "This indicates the HTMLBundle route was not registered. Please report a bug.",
|
|
393
|
+
{ status: 500 },
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
return webHandler(request)
|
|
397
|
+
}
|
|
297
398
|
|
|
298
399
|
for (const httpPath of httpPaths) {
|
|
299
400
|
if (method === "*") {
|