sevok 0.0.2

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.
@@ -0,0 +1,732 @@
1
+ import { i as extractParams, n as compilePath, o as normalizePathname, r as extractKeys, t as canonicalizePath } from "./_shared-38k_JIsU.mjs";
2
+ import { t as _color_default } from "./_color-B42q-MpL.mjs";
3
+ import { EventDispatcher } from "@hornjs/evt";
4
+ //#region \0rolldown/runtime.js
5
+ var __defProp = Object.defineProperty;
6
+ var __exportAll = (all, no_symbols) => {
7
+ let target = {};
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ return target;
14
+ };
15
+ //#endregion
16
+ //#region src/_plugins.ts
17
+ /**
18
+ * Wrap the request pipeline with the user-provided error handler.
19
+ *
20
+ * The plugin inserts a middleware at the front of the stack so both thrown
21
+ * exceptions and rejected downstream promises are normalized through
22
+ * `server.options.error`.
23
+ */
24
+ const errorPlugin = (server) => {
25
+ const errorHandler = server.options.error;
26
+ if (!errorHandler) return;
27
+ server.options.middleware.unshift((ctx, next) => {
28
+ try {
29
+ const res = next(ctx);
30
+ return res instanceof Promise ? res.catch((error) => errorHandler(error)) : res;
31
+ } catch (error) {
32
+ return errorHandler(error);
33
+ }
34
+ });
35
+ };
36
+ /**
37
+ * Register process signal handlers that close the server gracefully.
38
+ *
39
+ * The first `SIGINT` / `SIGTERM` starts a graceful shutdown countdown. A second
40
+ * `SIGINT` forces active connections to close immediately.
41
+ */
42
+ const gracefulShutdownPlugin = (server) => {
43
+ const config = server.options?.gracefulShutdown;
44
+ if (!globalThis.process?.on || config === false || config === void 0 && (process.env.CI || process.env.TEST)) return;
45
+ const gracefulTimeout = config === true || !config?.gracefulTimeout ? Number.parseInt(process.env.SERVER_SHUTDOWN_TIMEOUT || "") || 5 : config.gracefulTimeout;
46
+ let isClosing = false;
47
+ let isClosed = false;
48
+ const write = server.options.silent ? () => {} : process.stderr.write.bind(process.stderr);
49
+ /**
50
+ * Forcefully close active connections once graceful shutdown times out or the
51
+ * user presses Ctrl+C again.
52
+ */
53
+ const forceClose = async () => {
54
+ if (isClosed) return;
55
+ write(_color_default.red("\x1B[2K\rForcibly closing connections...\n"));
56
+ isClosed = true;
57
+ await server.close(true);
58
+ };
59
+ /**
60
+ * Attempt to close the server cleanly while printing countdown updates.
61
+ */
62
+ const shutdown = async () => {
63
+ if (isClosing || isClosed) return;
64
+ setTimeout(() => {
65
+ globalThis.process.once("SIGINT", forceClose);
66
+ }, 100);
67
+ isClosing = true;
68
+ const closePromise = server.close();
69
+ for (let remaining = gracefulTimeout; remaining > 0; remaining--) {
70
+ write(_color_default.gray(`\rStopping server gracefully (${remaining}s)... Press ${_color_default.bold("Ctrl+C")} again to force close.`));
71
+ if (await Promise.race([closePromise.then(() => true), new Promise((r) => setTimeout(() => r(false), 1e3))])) {
72
+ write("\x1B[2K\r" + _color_default.green("Server closed successfully.\n"));
73
+ isClosed = true;
74
+ return;
75
+ }
76
+ }
77
+ write("\x1B[2K\rGraceful shutdown timed out.\n");
78
+ await forceClose();
79
+ };
80
+ for (const sig of ["SIGINT", "SIGTERM"]) globalThis.process.on(sig, shutdown);
81
+ };
82
+ //#endregion
83
+ //#region src/core.ts
84
+ var core_exports = /* @__PURE__ */ __exportAll({
85
+ InvocationContext: () => InvocationContext,
86
+ Server: () => Server,
87
+ ServerCloseEvent: () => ServerCloseEvent,
88
+ ServerErrorEvent: () => ServerErrorEvent,
89
+ ServerServeEvent: () => ServerServeEvent,
90
+ createContextKey: () => createContextKey,
91
+ createWaitUntil: () => createWaitUntil,
92
+ isServerHandlerObject: () => isServerHandlerObject,
93
+ loadServerAdapter: () => loadServerAdapter,
94
+ raceRequestAbort: () => raceRequestAbort,
95
+ runMiddleware: () => runMiddleware,
96
+ serve: () => serve,
97
+ toServerHandlerObject: () => toServerHandlerObject,
98
+ unstable_buildRouteTree: () => unstable_buildRouteTree,
99
+ unstable_convertRoutesToHandler: () => unstable_convertRoutesToHandler,
100
+ unstable_match: () => unstable_match,
101
+ wrapFetch: () => wrapFetch
102
+ });
103
+ /**
104
+ * Create an invocation context key with an optional default value.
105
+ *
106
+ * When a default value is provided, `InvocationContext#get()` can always
107
+ * return a value for that key even if nothing has been explicitly written yet.
108
+ *
109
+ * @param defaultValue The default value for the context key
110
+ * @returns The new context key
111
+ */
112
+ function createContextKey(defaultValue) {
113
+ return { defaultValue };
114
+ }
115
+ /**
116
+ * A context object that contains information about the current invocation.
117
+ * Each handler and middleware receives its own context instance, which may be
118
+ * derived from a parent context via `with()`.
119
+ *
120
+ * Context values are immutable - use `with()` to create a modified copy.
121
+ */
122
+ var InvocationContext = class InvocationContext {
123
+ /**
124
+ * The original request that was dispatched to the router.
125
+ *
126
+ * Note: The request body may already have been consumed by middleware
127
+ * (available as `context.get(FormData)`). Use `context.with({ request })`
128
+ * if you need to pass a modified request downstream.
129
+ */
130
+ request;
131
+ /**
132
+ * Cached parsed URL for middleware and handlers that need repeated URL access.
133
+ */
134
+ url;
135
+ /**
136
+ * Runtime specific invocation context.
137
+ */
138
+ capabilities;
139
+ /**
140
+ * The current route parameters for this request.
141
+ *
142
+ * This reflects the active matched route and returns an empty object before
143
+ * routing has resolved a match.
144
+ */
145
+ params;
146
+ /**
147
+ * Tell the runtime about an ongoing operation that shouldn't close until the
148
+ * promise resolves.
149
+ *
150
+ * This mirrors service-worker-style `waitUntil()` semantics and is wired into
151
+ * `Server.close()`.
152
+ */
153
+ waitUntil;
154
+ #contextMap;
155
+ constructor(init) {
156
+ this.request = init.request;
157
+ this.capabilities = init.capabilities;
158
+ this.params = init.params ?? emptyRouteParams;
159
+ this.waitUntil = init.waitUntil;
160
+ this.#contextMap = /* @__PURE__ */ new Map();
161
+ }
162
+ /**
163
+ * Create a derived context with optional overrides.
164
+ * Copies all context values to the new instance.
165
+ */
166
+ with(overrides) {
167
+ const child = new InvocationContext({
168
+ request: overrides.request ?? this.request,
169
+ capabilities: overrides.capabilities ?? this.capabilities,
170
+ params: overrides.params ?? this.params,
171
+ waitUntil: overrides.waitUntil ?? this.waitUntil
172
+ });
173
+ for (const [key, value] of this.#contextMap) child.#contextMap.set(key, value);
174
+ return child;
175
+ }
176
+ /**
177
+ * Get a value from invocation context.
178
+ *
179
+ * @param TKey The key to read
180
+ * @returns The value for the given key
181
+ */
182
+ get(key) {
183
+ if (this.#contextMap.has(key)) return this.#contextMap.get(key);
184
+ const contextKey = key;
185
+ if (contextKey.defaultValue === void 0) throw new Error(`Missing default value in context for key ${key}`);
186
+ return contextKey.defaultValue;
187
+ }
188
+ /**
189
+ * Check whether a value exists in invocation context.
190
+ *
191
+ * @param TKey The key to check
192
+ * @returns `true` if a value has been set for the key
193
+ */
194
+ has(key) {
195
+ return this.#contextMap.has(key);
196
+ }
197
+ /**
198
+ * Set a value in invocation context.
199
+ *
200
+ * @param key The key to write
201
+ * @param value The value to write
202
+ */
203
+ set(key, value) {
204
+ this.#contextMap.set(key, value);
205
+ }
206
+ };
207
+ /**
208
+ * Reject when the request abort signal fires before the promise settles.
209
+ *
210
+ * This keeps long-running async work aligned with fetch semantics: once the
211
+ * request has been aborted, downstream work should stop surfacing successful
212
+ * results for it.
213
+ */
214
+ function raceRequestAbort(promise, request) {
215
+ let signal = request.signal;
216
+ if (signal.aborted) throw signal.reason;
217
+ return new Promise((resolve, reject) => {
218
+ let onAbort = () => reject(signal.reason);
219
+ signal.addEventListener("abort", onAbort, { once: true });
220
+ promise.then((value) => {
221
+ signal.removeEventListener("abort", onAbort);
222
+ resolve(value);
223
+ }, (error) => {
224
+ signal.removeEventListener("abort", onAbort);
225
+ reject(error);
226
+ });
227
+ });
228
+ }
229
+ /**
230
+ * Create a `waitUntil()` registry that keeps track of pending background work.
231
+ *
232
+ * Rejected tasks are logged and removed from the registry so shutdown can
233
+ * continue cleanly.
234
+ */
235
+ function createWaitUntil() {
236
+ const promises = /* @__PURE__ */ new Set();
237
+ return {
238
+ waitUntil: (promise) => {
239
+ if (typeof promise?.then !== "function") return;
240
+ let tracked;
241
+ tracked = Promise.resolve(promise).catch(console.error).finally(() => promises.delete(tracked));
242
+ promises.add(tracked);
243
+ },
244
+ wait: () => {
245
+ return Promise.all(promises);
246
+ }
247
+ };
248
+ }
249
+ /**
250
+ * Normalize handlers so middleware runners can treat function and object forms
251
+ * uniformly.
252
+ *
253
+ * A bare handler becomes `{ handleRequest }`, while object handlers are returned
254
+ * unchanged.
255
+ */
256
+ function toServerHandlerObject(handler) {
257
+ if (typeof handler === "function") return { handleRequest: handler };
258
+ return handler;
259
+ }
260
+ /**
261
+ * Type guard to check if a value conforms to the `ServerHandlerObject` shape.
262
+ *
263
+ * This is used to distinguish between a bare `ServerHandler` function and an
264
+ * object wrapper that may also carry per-route middleware.
265
+ */
266
+ function isServerHandlerObject(value) {
267
+ return value != null && !Array.isArray(value) && typeof value === "object" && "handleRequest" in value && typeof value.handleRequest === "function";
268
+ }
269
+ /**
270
+ * Execute middleware in sequence and then hand off to the terminal handler.
271
+ *
272
+ * Middleware may:
273
+ * - return a `Response` to short-circuit downstream execution
274
+ * - call `next()` and return its result
275
+ * - call `next()` without returning it, in which case the downstream response
276
+ * is still used
277
+ *
278
+ * If the terminal handler is a `ServerHandlerObject`, its own `middleware`
279
+ * array is executed after the outer middleware chain completes.
280
+ */
281
+ function runMiddleware(context, middleware, terminal) {
282
+ let index = -1;
283
+ const dispatch = async (context, i) => {
284
+ if (i <= index) throw new Error("next() called multiple times");
285
+ index = i;
286
+ if (context.request.signal.aborted) throw context.request.signal.reason;
287
+ const fn = middleware[i];
288
+ if (!fn) {
289
+ const { middleware, handleRequest } = toServerHandlerObject(terminal);
290
+ if (middleware?.length) return runMiddleware(context, middleware, { handleRequest });
291
+ return await raceRequestAbort(Promise.resolve(handleRequest(context)), context.request);
292
+ }
293
+ let nextPromise;
294
+ let next = (nextContext) => {
295
+ nextPromise = dispatch(nextContext, i + 1);
296
+ return nextPromise;
297
+ };
298
+ let response = await raceRequestAbort(Promise.resolve(fn(context, next)), context.request);
299
+ if (response instanceof Response) return response;
300
+ if (nextPromise != null) return nextPromise;
301
+ return next(context);
302
+ };
303
+ return dispatch(context, 0);
304
+ }
305
+ function resolveRouteHandler(route, method) {
306
+ if (typeof route === "function" || isServerHandlerObject(route)) return route;
307
+ if (method && route[method]) return route[method];
308
+ if (method === "HEAD" && route.GET) return route.GET;
309
+ }
310
+ function resolveRouteMethods(route) {
311
+ if (typeof route === "function" || isServerHandlerObject(route)) return [];
312
+ const methods = Object.keys(route);
313
+ if (methods.includes("GET") && !methods.includes("HEAD")) methods.push("HEAD");
314
+ return methods;
315
+ }
316
+ function resolveRouteInput(input) {
317
+ if (typeof input === "string") try {
318
+ return { pathname: new URL(input).pathname };
319
+ } catch {
320
+ return { pathname: input };
321
+ }
322
+ if (input instanceof URL) return { pathname: input.pathname };
323
+ if (input instanceof Request) return {
324
+ pathname: new URL(input.url).pathname,
325
+ method: input.method
326
+ };
327
+ return {
328
+ pathname: typeof input.url === "string" ? new URL(input.url).pathname : input.url.pathname,
329
+ method: input.method
330
+ };
331
+ }
332
+ /**
333
+ * Compile a declarative `ServerRoutes` table into precedence buckets for fast
334
+ * request matching.
335
+ *
336
+ * The build step also rejects conflicting route shapes such as duplicate exact
337
+ * routes or parameter routes that collapse to the same canonical pattern.
338
+ */
339
+ function unstable_buildRouteTree(routes) {
340
+ const tree = {
341
+ exact: /* @__PURE__ */ new Map(),
342
+ param: [],
343
+ wildcard: []
344
+ };
345
+ const seen = /* @__PURE__ */ new Map();
346
+ for (const [path, route] of Object.entries(routes)) {
347
+ const normalized = normalizePathname(path);
348
+ const canonical = canonicalizePath(normalized);
349
+ const previous = seen.get(canonical);
350
+ if (previous) throw new Error(`Conflicting routes: "${previous}" and "${path}" both resolve to "${canonical}".`);
351
+ seen.set(canonical, path);
352
+ const compiled = {
353
+ path: normalized,
354
+ route,
355
+ regexp: compilePath(normalized),
356
+ keys: extractKeys(normalized)
357
+ };
358
+ if (normalized === "/*") {
359
+ tree.catchAll = compiled;
360
+ continue;
361
+ }
362
+ if (normalized.includes("*")) {
363
+ tree.wildcard.push(compiled);
364
+ continue;
365
+ }
366
+ if (normalized.includes(":")) {
367
+ tree.param.push(compiled);
368
+ continue;
369
+ }
370
+ tree.exact.set(normalized, route);
371
+ }
372
+ return tree;
373
+ }
374
+ /**
375
+ * Match a request-like input against a compiled route tree.
376
+ *
377
+ * `all` contains every pathname candidate in precedence order, while
378
+ * `matched` further filters that list by HTTP method and resolves the concrete
379
+ * handler that would run.
380
+ */
381
+ function unstable_match(tree, input) {
382
+ const all = [];
383
+ const { pathname, method } = resolveRouteInput(input);
384
+ const normalized = normalizePathname(pathname);
385
+ const exact = tree.exact.get(normalized);
386
+ if (exact) all.push({
387
+ path: normalized,
388
+ route: exact,
389
+ params: {}
390
+ });
391
+ for (const compiled of tree.param) {
392
+ const result = compiled.regexp.exec(normalized);
393
+ if (!result) continue;
394
+ all.push({
395
+ path: compiled.path,
396
+ route: compiled.route,
397
+ params: extractParams(compiled.keys, result)
398
+ });
399
+ }
400
+ for (const compiled of tree.wildcard) {
401
+ if (!compiled.regexp.test(normalized)) continue;
402
+ all.push({
403
+ path: compiled.path,
404
+ route: compiled.route,
405
+ params: {}
406
+ });
407
+ }
408
+ if (tree.catchAll && tree.catchAll.regexp.test(normalized)) all.push({
409
+ path: tree.catchAll.path,
410
+ route: tree.catchAll.route,
411
+ params: {}
412
+ });
413
+ return {
414
+ all,
415
+ matched: all.flatMap((candidate) => {
416
+ const handler = resolveRouteHandler(candidate.route, method);
417
+ if (!handler) return [];
418
+ return [{
419
+ ...candidate,
420
+ handler,
421
+ method
422
+ }];
423
+ })
424
+ };
425
+ }
426
+ /**
427
+ * Turn a precompiled route tree into a `ServerHandler`.
428
+ *
429
+ * Pathname matches are resolved using Bun-style precedence. When a pathname
430
+ * matches but the method does not, the returned handler responds with `405`
431
+ * and an `Allow` header. If no route matches, `fallback` is used when
432
+ * provided; otherwise a `404` response is returned.
433
+ */
434
+ function unstable_convertRoutesToHandler({ input, fallback, runRouteMiddleware }) {
435
+ return async (context) => {
436
+ const result = unstable_match(input, context.request);
437
+ const route = result.matched[0];
438
+ if (route) {
439
+ context = context.with({ params: route.params });
440
+ if (typeof route.handler === "function") return route.handler(context);
441
+ if (!route.handler.middleware?.length) return route.handler.handleRequest(context);
442
+ if (!runRouteMiddleware) throw new Error("Route handler middleware requires `runRouteMiddleware`.");
443
+ return runRouteMiddleware(context, route.handler.middleware, route.handler);
444
+ }
445
+ if (result.all.length > 0) {
446
+ const allow = /* @__PURE__ */ new Set();
447
+ for (const candidate of result.all) for (const method of resolveRouteMethods(candidate.route)) allow.add(method);
448
+ const headers = allow.size > 0 ? { Allow: [...allow].join(", ") } : void 0;
449
+ return new Response("Method Not Allowed", {
450
+ status: 405,
451
+ headers
452
+ });
453
+ }
454
+ if (fallback) return fallback(context);
455
+ return new Response("Not Found", { status: 404 });
456
+ };
457
+ }
458
+ const emptyRouteParams = Object.freeze({});
459
+ /**
460
+ * Resolve the runtime adapter for the current process.
461
+ *
462
+ * The adapter is chosen lazily so the package can stay portable across Bun,
463
+ * Deno, and Node without importing runtime-specific code up front.
464
+ */
465
+ async function loadServerAdapter() {
466
+ if (process.versions.bun) {
467
+ const { BunRuntimeAdapter } = await import("./bun.mjs");
468
+ return new BunRuntimeAdapter();
469
+ } else if (process.versions.deno) {
470
+ const { DenoRuntimeAdapter } = await import("./deno.mjs");
471
+ return new DenoRuntimeAdapter();
472
+ } else {
473
+ const { NodeRuntimeAdapter } = await import("./node.mjs");
474
+ return new NodeRuntimeAdapter();
475
+ }
476
+ }
477
+ /**
478
+ * Temporary adapter that rejects server operations until the real runtime
479
+ * adapter has been resolved asynchronously.
480
+ */
481
+ var PlaceholderRuntimeAdapter = class {
482
+ #callback;
483
+ constructor(callback) {
484
+ this.#callback = callback;
485
+ }
486
+ get capabilities() {
487
+ throw new Error("Server runtime adapter is still initializing.");
488
+ }
489
+ setup() {
490
+ loadServerAdapter().then((adapter) => this.#callback(null, adapter), (error) => this.#callback(error, null));
491
+ }
492
+ async serve() {
493
+ throw new Error("Server runtime adapter is still initializing.");
494
+ }
495
+ async close() {}
496
+ };
497
+ /**
498
+ * Emitted after the server starts accepting requests.
499
+ */
500
+ var ServerServeEvent = class extends Event {
501
+ constructor() {
502
+ super("serve");
503
+ }
504
+ };
505
+ /**
506
+ * Emitted after the server has fully closed.
507
+ */
508
+ var ServerCloseEvent = class extends Event {
509
+ constructor() {
510
+ super("close");
511
+ }
512
+ };
513
+ /**
514
+ * Emitted when server startup or runtime handling raises an error.
515
+ */
516
+ var ServerErrorEvent = class extends Event {
517
+ error;
518
+ constructor(error) {
519
+ super("error");
520
+ this.error = error;
521
+ }
522
+ };
523
+ /**
524
+ * Convenience factory for creating a `Server` without `new`.
525
+ */
526
+ function serve(init) {
527
+ return new Server(init);
528
+ }
529
+ /**
530
+ * Runtime-agnostic fetch server.
531
+ *
532
+ * `Server` owns middleware composition, per-invocation context setup, background
533
+ * task tracking, and runtime lifecycle coordination. Concrete adapters handle
534
+ * the host-specific details of listening for requests.
535
+ */
536
+ var Server = class extends EventDispatcher {
537
+ /**
538
+ * Server options.
539
+ */
540
+ options;
541
+ /**
542
+ * Register a background task that the server should await before closing.
543
+ *
544
+ * Same as `request.waitUntil` but available at the server level for use
545
+ * outside of request handlers.
546
+ */
547
+ waitUntil;
548
+ #wait;
549
+ #kernel;
550
+ #adapter;
551
+ #url;
552
+ #adapterPromise;
553
+ #rejectAdapter;
554
+ #readyPromise;
555
+ #rejectReady;
556
+ #closePromise;
557
+ /**
558
+ * Create a server, apply plugins, prepare the runtime adapter, and optionally
559
+ * start listening immediately.
560
+ */
561
+ constructor({ middleware = [], plugins = [], adapter, ...options }) {
562
+ super();
563
+ this.options = {
564
+ ...options,
565
+ middleware: [...middleware]
566
+ };
567
+ for (const plugin of plugins) plugin(this);
568
+ errorPlugin(this);
569
+ if (!this.options.fetch) {
570
+ if (!this.options.routes || !this.options.routes["/*"]) throw new Error("Server requires either `fetch` or a `routes` table with `/*`.");
571
+ }
572
+ this.#wait = createWaitUntil();
573
+ this.waitUntil = this.#wait.waitUntil;
574
+ this.#kernel = () => {
575
+ throw new Error("Server request handler is not ready until the runtime adapter finishes initializing.");
576
+ };
577
+ const initializeAdapter = (adapter, resolve) => {
578
+ if (adapter.graceful) gracefulShutdownPlugin(this);
579
+ const kernel = wrapFetch(this);
580
+ adapter.setup(this);
581
+ this.#adapter = adapter;
582
+ this.#kernel = kernel;
583
+ if (!options.manual) this.#startServing();
584
+ resolve?.();
585
+ };
586
+ if (adapter) {
587
+ this.#adapter = adapter;
588
+ initializeAdapter(adapter);
589
+ return;
590
+ }
591
+ const { promise, resolve, reject } = Promise.withResolvers();
592
+ this.#adapterPromise = promise;
593
+ this.#rejectAdapter = reject;
594
+ promise.catch(() => {}).finally(() => {
595
+ this.#adapterPromise = void 0;
596
+ this.#rejectAdapter = void 0;
597
+ });
598
+ this.#adapter = new PlaceholderRuntimeAdapter((error, adapter) => {
599
+ if (adapter != null) initializeAdapter(adapter, resolve);
600
+ else {
601
+ reject(error);
602
+ if (!(error instanceof Error) || error.name !== "AbortError") this.dispatchEvent(new ServerErrorEvent(error));
603
+ }
604
+ });
605
+ this.#adapter.setup(this);
606
+ }
607
+ /**
608
+ * Listener URL reported by the runtime adapter after `serve()` succeeds.
609
+ */
610
+ get url() {
611
+ return this.#url;
612
+ }
613
+ /**
614
+ * Create a `InvocationContext` view over an arbitrary `Request`.
615
+ *
616
+ * This preserves the upstream request object and pairs it with sevok
617
+ * invocation state such as runtime capabilities, `waitUntil`, and `params`.
618
+ */
619
+ createContext(request, params) {
620
+ return new InvocationContext({
621
+ request,
622
+ capabilities: this.#adapter.capabilities,
623
+ waitUntil: this.#wait?.waitUntil,
624
+ params
625
+ });
626
+ }
627
+ /**
628
+ * Invoke the composed request pipeline directly.
629
+ */
630
+ handle(context) {
631
+ if (this.#adapterPromise) return this.#adapterPromise.then(() => this.#kernel(context));
632
+ return this.#kernel(context);
633
+ }
634
+ /**
635
+ * Adapt an arbitrary `Request` into an `InvocationContext` and invoke the handler pipeline.
636
+ */
637
+ async fetch(request) {
638
+ if (this.#adapterPromise) await this.#adapterPromise;
639
+ return await this.handle(this.createContext(request));
640
+ }
641
+ #startServing() {
642
+ if (this.#readyPromise) return;
643
+ const { promise, resolve, reject } = Promise.withResolvers();
644
+ this.#readyPromise = promise;
645
+ this.#rejectReady = reject;
646
+ this.#url = void 0;
647
+ this.#adapter.serve(this).then((info) => {
648
+ this.#url = info?.url;
649
+ this.dispatchEvent(new ServerServeEvent());
650
+ resolve();
651
+ }, reject);
652
+ }
653
+ /**
654
+ * Start the runtime adapter if it has not been started already.
655
+ *
656
+ * The returned promise resolves once the adapter reports the final listener
657
+ * URL. Repeated calls reuse the same in-flight startup.
658
+ */
659
+ async serve() {
660
+ if (this.#readyPromise) return;
661
+ if (this.#adapterPromise) await this.#adapterPromise;
662
+ this.#startServing();
663
+ }
664
+ /**
665
+ * Wait until the server has completed startup and then return the instance.
666
+ *
667
+ * This is mainly a convenience for fluent startup code.
668
+ */
669
+ async ready() {
670
+ if (this.#adapterPromise) await this.#adapterPromise;
671
+ if (!this.#readyPromise) throw new Error("Server has not been started. Call serve() first.");
672
+ return Promise.resolve(this.#readyPromise).then(() => this);
673
+ }
674
+ /**
675
+ * Close the runtime adapter and wait for outstanding `waitUntil()` tasks.
676
+ *
677
+ * If startup was still in progress, `ready()` is rejected with an
678
+ * `AbortError`.
679
+ */
680
+ async close(closeActiveConnections = false) {
681
+ if (this.#closePromise) return this.#closePromise;
682
+ const finalizeClose = async () => {
683
+ try {
684
+ if (this.#rejectAdapter) {
685
+ const error = /* @__PURE__ */ new Error("Server closed before adapter initialization completed.");
686
+ error.name = "AbortError";
687
+ this.#rejectAdapter(error);
688
+ }
689
+ await Promise.all([this.#adapter.close(closeActiveConnections), this.#wait?.wait()]);
690
+ } finally {
691
+ if (this.#rejectReady) {
692
+ const error = /* @__PURE__ */ new Error("Server closed before becoming ready.");
693
+ error.name = "AbortError";
694
+ this.#rejectReady(error);
695
+ this.#rejectReady = void 0;
696
+ }
697
+ this.dispatchEvent(new ServerCloseEvent());
698
+ }
699
+ };
700
+ this.#closePromise = finalizeClose().finally(() => {
701
+ this.#readyPromise = void 0;
702
+ this.#closePromise = void 0;
703
+ });
704
+ return this.#closePromise;
705
+ }
706
+ };
707
+ /**
708
+ * Compose fetch handler, middleware, and optional error handling into the
709
+ * single request kernel used by `Server`.
710
+ */
711
+ function wrapFetch(server) {
712
+ const fetchHandler = server.options.fetch;
713
+ const routes = server.options.routes;
714
+ const middleware = server.options.middleware || [];
715
+ let handler;
716
+ if (!routes) {
717
+ if (!fetchHandler) throw new Error("Server requires either `routes` or `fetch`.");
718
+ handler = fetchHandler;
719
+ } else {
720
+ if (!routes["/*"]) {
721
+ if (!fetchHandler) throw new Error("Route tables without `/*` require a fallback `fetch` handler.");
722
+ }
723
+ handler = unstable_convertRoutesToHandler({
724
+ input: unstable_buildRouteTree(routes),
725
+ fallback: fetchHandler,
726
+ runRouteMiddleware: runMiddleware
727
+ });
728
+ }
729
+ return middleware.length === 0 ? handler : (context) => runMiddleware(context, middleware, handler);
730
+ }
731
+ //#endregion
732
+ export { unstable_match as _, ServerServeEvent as a, createWaitUntil as c, raceRequestAbort as d, runMiddleware as f, unstable_convertRoutesToHandler as g, unstable_buildRouteTree as h, ServerErrorEvent as i, isServerHandlerObject as l, toServerHandlerObject as m, Server as n, core_exports as o, serve as p, ServerCloseEvent as r, createContextKey as s, InvocationContext as t, loadServerAdapter as u, wrapFetch as v };