@nextrush/types 3.0.6 → 4.0.0-beta.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/README.md +309 -321
- package/dist/index.d.ts +756 -92
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.d.ts
CHANGED
|
@@ -222,12 +222,17 @@ interface BodySource {
|
|
|
222
222
|
*/
|
|
223
223
|
text(): Promise<string>;
|
|
224
224
|
/**
|
|
225
|
-
* Read the body as a Uint8Array buffer
|
|
225
|
+
* Read the body as a Uint8Array buffer.
|
|
226
226
|
*
|
|
227
|
+
* @param limit - Optional per-read byte limit. When provided, it is the value
|
|
228
|
+
* enforced for both the Content-Length pre-check and the incremental
|
|
229
|
+
* streaming check (taking precedence over the source's construction-time
|
|
230
|
+
* limit); when omitted, the construction-time limit governs. See
|
|
231
|
+
* docs/RFC/request-data/017-body-source-limit-propagation.md.
|
|
227
232
|
* @returns Promise resolving to the body as Uint8Array
|
|
228
233
|
* @throws Error if body has already been consumed
|
|
229
234
|
*/
|
|
230
|
-
buffer(): Promise<Uint8Array>;
|
|
235
|
+
buffer(limit?: number): Promise<Uint8Array>;
|
|
231
236
|
/**
|
|
232
237
|
* Read the body as JSON
|
|
233
238
|
*
|
|
@@ -279,6 +284,130 @@ interface BodySourceOptions {
|
|
|
279
284
|
encoding?: 'utf-8' | 'utf8' | 'ascii' | 'latin1' | 'iso-8859-1' | 'utf-16le' | 'utf-16be';
|
|
280
285
|
}
|
|
281
286
|
|
|
287
|
+
/**
|
|
288
|
+
* @nextrush/types - Response Streaming Contracts
|
|
289
|
+
*
|
|
290
|
+
* Pure type contracts for runtime-agnostic response streaming (text/SSE/NDJSON).
|
|
291
|
+
* The implementation lives in `@nextrush/stream`; these interfaces live here so
|
|
292
|
+
* the `Context` interface can reference them without `@nextrush/types` depending
|
|
293
|
+
* on any higher-tier package.
|
|
294
|
+
*
|
|
295
|
+
* See `docs/RFC/request-data/003-stream.md`.
|
|
296
|
+
*
|
|
297
|
+
* @packageDocumentation
|
|
298
|
+
*/
|
|
299
|
+
/**
|
|
300
|
+
* A single Server-Sent Event.
|
|
301
|
+
*
|
|
302
|
+
* @remarks
|
|
303
|
+
* `data` is the only required field. Objects are serialized with `JSON.stringify`;
|
|
304
|
+
* strings are sent verbatim. The framework handles all wire-format framing
|
|
305
|
+
* (multi-line `data:` escaping, `event:`/`id:`/`retry:` fields, terminating blank line).
|
|
306
|
+
*/
|
|
307
|
+
interface SSEEvent {
|
|
308
|
+
/** Event payload. Objects are JSON-serialized; strings are sent as-is. */
|
|
309
|
+
data: unknown;
|
|
310
|
+
/** SSE `event:` field — lets the client dispatch to a named listener. */
|
|
311
|
+
event?: string;
|
|
312
|
+
/** SSE `id:` field — enables client auto-reconnect from the last-seen id. */
|
|
313
|
+
id?: string;
|
|
314
|
+
/** SSE `retry:` field, in milliseconds — client reconnection delay hint. */
|
|
315
|
+
retry?: number;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Capabilities shared by every response-stream writer, regardless of protocol.
|
|
319
|
+
*
|
|
320
|
+
* @remarks
|
|
321
|
+
* Concrete writers ({@link TextStreamWriter}, {@link SSEStreamWriter},
|
|
322
|
+
* {@link NDJSONStreamWriter}) add a protocol-specific `write()` on top of this.
|
|
323
|
+
*/
|
|
324
|
+
interface BaseStreamWriter {
|
|
325
|
+
/**
|
|
326
|
+
* `true` once the client has disconnected.
|
|
327
|
+
*
|
|
328
|
+
* @remarks
|
|
329
|
+
* Use as a loop guard for long-running streams. Writing after this is `true`
|
|
330
|
+
* throws `StreamAbortedError`.
|
|
331
|
+
*/
|
|
332
|
+
readonly aborted: boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Fires when the client disconnects.
|
|
335
|
+
*
|
|
336
|
+
* @remarks
|
|
337
|
+
* Pass this straight into an upstream SDK's own abort option
|
|
338
|
+
* (e.g. `{ signal: writer.signal }`) so the upstream call is cancelled the
|
|
339
|
+
* instant the client goes away.
|
|
340
|
+
*/
|
|
341
|
+
readonly signal: AbortSignal;
|
|
342
|
+
/**
|
|
343
|
+
* Register a cleanup callback invoked once when the client disconnects.
|
|
344
|
+
*
|
|
345
|
+
* @param fn - Cleanup callback (e.g. abort an upstream request, release a resource).
|
|
346
|
+
*/
|
|
347
|
+
onAbort(fn: () => void): void;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Source shapes accepted by a writer's `consume()` method.
|
|
351
|
+
*
|
|
352
|
+
* @remarks
|
|
353
|
+
* Normalized internally to a single async-iterator path — callers never branch
|
|
354
|
+
* on the concrete shape.
|
|
355
|
+
*/
|
|
356
|
+
type StreamSource<T> = AsyncIterable<T> | ReadableStream<T>;
|
|
357
|
+
/**
|
|
358
|
+
* Writer for a raw text/byte stream (`ctx.stream()`).
|
|
359
|
+
*/
|
|
360
|
+
interface TextStreamWriter extends BaseStreamWriter {
|
|
361
|
+
/**
|
|
362
|
+
* Write text or bytes.
|
|
363
|
+
* @throws StreamAbortedError if the client has already disconnected.
|
|
364
|
+
*/
|
|
365
|
+
write(chunk: string | Uint8Array): Promise<void>;
|
|
366
|
+
/**
|
|
367
|
+
* Consume an existing producer as this response's body.
|
|
368
|
+
* @param source - An `AsyncIterable` or Web `ReadableStream` of strings/bytes.
|
|
369
|
+
* @throws StreamAbortedError if the client disconnects mid-consume.
|
|
370
|
+
*/
|
|
371
|
+
consume(source: StreamSource<string | Uint8Array>): Promise<void>;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Writer for a Server-Sent Events stream (`ctx.sse()`).
|
|
375
|
+
*/
|
|
376
|
+
interface SSEStreamWriter extends BaseStreamWriter {
|
|
377
|
+
/**
|
|
378
|
+
* Write one Server-Sent Event. The framework handles all wire-format framing.
|
|
379
|
+
* @throws StreamAbortedError if the client has already disconnected.
|
|
380
|
+
*/
|
|
381
|
+
write(event: SSEEvent): Promise<void>;
|
|
382
|
+
/**
|
|
383
|
+
* Consume an existing producer; each yielded chunk is sent as `{ data: chunk }`.
|
|
384
|
+
* @throws StreamAbortedError if the client disconnects mid-consume.
|
|
385
|
+
*/
|
|
386
|
+
consume(source: StreamSource<string | Uint8Array>): Promise<void>;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Writer for a newline-delimited JSON stream (`ctx.ndjson()`).
|
|
390
|
+
*/
|
|
391
|
+
interface NDJSONStreamWriter extends BaseStreamWriter {
|
|
392
|
+
/**
|
|
393
|
+
* Write one JSON-serializable value as a single NDJSON line.
|
|
394
|
+
* @throws StreamAbortedError if the client has already disconnected.
|
|
395
|
+
*/
|
|
396
|
+
write(value: unknown): Promise<void>;
|
|
397
|
+
/**
|
|
398
|
+
* Consume an existing producer of JSON-serializable values, one line each.
|
|
399
|
+
* @throws StreamAbortedError if the client disconnects mid-consume.
|
|
400
|
+
*/
|
|
401
|
+
consume(source: StreamSource<unknown>): Promise<void>;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* A streaming callback that receives a protocol-specific writer.
|
|
405
|
+
*
|
|
406
|
+
* @remarks
|
|
407
|
+
* The connection auto-closes when this callback resolves.
|
|
408
|
+
*/
|
|
409
|
+
type StreamRun<W extends BaseStreamWriter> = (writer: W) => Promise<void>;
|
|
410
|
+
|
|
282
411
|
/**
|
|
283
412
|
* @nextrush/types - Context Type Definitions
|
|
284
413
|
*
|
|
@@ -600,6 +729,72 @@ interface Context {
|
|
|
600
729
|
* ```
|
|
601
730
|
*/
|
|
602
731
|
readonly bodySource: BodySource;
|
|
732
|
+
/**
|
|
733
|
+
* Abort signal that fires when the client disconnects mid-response.
|
|
734
|
+
*
|
|
735
|
+
* @internal
|
|
736
|
+
* @remarks
|
|
737
|
+
* Adapter-level primitive consumed by `@nextrush/stream`. Handlers should use
|
|
738
|
+
* `writer.signal` inside `ctx.stream()`/`ctx.sse()`/`ctx.ndjson()` instead of
|
|
739
|
+
* accessing this directly. Synthesized on Node from response `close`/request
|
|
740
|
+
* `aborted`; passed through natively on Bun/Deno/Edge from `Request.signal`.
|
|
741
|
+
*/
|
|
742
|
+
readonly signal: AbortSignal;
|
|
743
|
+
/**
|
|
744
|
+
* Send a raw byte stream as the response body.
|
|
745
|
+
*
|
|
746
|
+
* @internal
|
|
747
|
+
* @remarks
|
|
748
|
+
* Adapter-level transport primitive consumed by `@nextrush/stream`. Not
|
|
749
|
+
* intended for direct handler use — use `ctx.stream()`/`ctx.sse()`/
|
|
750
|
+
* `ctx.ndjson()`. Resolves when the stream is fully flushed (Node) or once the
|
|
751
|
+
* response body is wired (Bun/Deno/Edge).
|
|
752
|
+
*
|
|
753
|
+
* @param source - A Web `ReadableStream` of bytes to stream to the client.
|
|
754
|
+
*/
|
|
755
|
+
sendStream(source: ReadableStream<Uint8Array>): Promise<void>;
|
|
756
|
+
/**
|
|
757
|
+
* Stream a raw text/byte response. The connection closes automatically when
|
|
758
|
+
* the callback resolves.
|
|
759
|
+
*
|
|
760
|
+
* @param run - Callback that receives a {@link TextStreamWriter}.
|
|
761
|
+
*
|
|
762
|
+
* @example
|
|
763
|
+
* ```typescript
|
|
764
|
+
* await ctx.stream(async (writer) => {
|
|
765
|
+
* await writer.write('Loading...\n');
|
|
766
|
+
* await writer.write('Done.\n');
|
|
767
|
+
* });
|
|
768
|
+
* ```
|
|
769
|
+
*/
|
|
770
|
+
stream(run: StreamRun<TextStreamWriter>): Promise<void>;
|
|
771
|
+
/**
|
|
772
|
+
* Stream a Server-Sent Events (`text/event-stream`) response.
|
|
773
|
+
*
|
|
774
|
+
* @param run - Callback that receives an {@link SSEStreamWriter}.
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* ```typescript
|
|
778
|
+
* await ctx.sse(async (writer) => {
|
|
779
|
+
* for await (const token of llm) await writer.write({ data: token });
|
|
780
|
+
* });
|
|
781
|
+
* ```
|
|
782
|
+
*/
|
|
783
|
+
sse(run: StreamRun<SSEStreamWriter>): Promise<void>;
|
|
784
|
+
/**
|
|
785
|
+
* Stream a newline-delimited JSON (`application/x-ndjson`) response.
|
|
786
|
+
*
|
|
787
|
+
* @param run - Callback that receives an {@link NDJSONStreamWriter}.
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
* ```typescript
|
|
791
|
+
* await ctx.ndjson(async (writer) => {
|
|
792
|
+
* await writer.write({ step: 'search' });
|
|
793
|
+
* await writer.write({ step: 'done' });
|
|
794
|
+
* });
|
|
795
|
+
* ```
|
|
796
|
+
*/
|
|
797
|
+
ndjson(run: StreamRun<NDJSONStreamWriter>): Promise<void>;
|
|
603
798
|
}
|
|
604
799
|
/**
|
|
605
800
|
* Next function type (traditional Koa-style)
|
|
@@ -645,133 +840,579 @@ interface ContextOptions {
|
|
|
645
840
|
}
|
|
646
841
|
|
|
647
842
|
/**
|
|
648
|
-
* @nextrush/types -
|
|
843
|
+
* @nextrush/types - Adapter Context Contracts (F-13)
|
|
844
|
+
*
|
|
845
|
+
* The concrete adapter context classes expose transport/lifecycle primitives
|
|
846
|
+
* that are not part of the runtime-neutral {@link Context} contract:
|
|
847
|
+
* `markResponded()` (all adapters), and `getResponse()` / `waitUntil()` / `env`
|
|
848
|
+
* (the Web/fetch adapters). Consumers typed as `Context` cannot see these, so
|
|
849
|
+
* `@nextrush/stream` and the adapters resort to structural access.
|
|
649
850
|
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
851
|
+
* These interfaces model that surface **additively** — they extend `Context`,
|
|
852
|
+
* they never weaken it. Adapters (and `@nextrush/stream`) can depend on these
|
|
853
|
+
* instead of coupling to the concrete context classes.
|
|
652
854
|
*
|
|
653
855
|
* @packageDocumentation
|
|
654
856
|
*/
|
|
655
857
|
|
|
656
858
|
/**
|
|
657
|
-
*
|
|
658
|
-
*
|
|
859
|
+
* A {@link Context} plus the lifecycle primitive every adapter exposes.
|
|
860
|
+
*
|
|
861
|
+
* @remarks
|
|
862
|
+
* `markResponded()` lets the transport/streaming layer flag that a response has
|
|
863
|
+
* been committed out-of-band (e.g. after wiring a stream), so the adapter's
|
|
864
|
+
* "not responded" fallback path is skipped.
|
|
659
865
|
*/
|
|
660
|
-
interface
|
|
866
|
+
interface AdapterContext extends Context {
|
|
661
867
|
/**
|
|
662
|
-
*
|
|
868
|
+
* Mark the response as already sent.
|
|
869
|
+
*
|
|
870
|
+
* @remarks
|
|
871
|
+
* Used by streaming and adapter transport code when a response is committed
|
|
872
|
+
* without going through `json()`/`send()`/`html()`/`redirect()`.
|
|
663
873
|
*/
|
|
664
|
-
|
|
874
|
+
markResponded(): void;
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* An {@link AdapterContext} for Web/fetch runtimes (Bun, Deno, Edge).
|
|
878
|
+
*
|
|
879
|
+
* @remarks
|
|
880
|
+
* Adds the fetch-specific surface: `getResponse()` (materialize the built
|
|
881
|
+
* `Response`), and the optional edge primitives `waitUntil()` and `env`
|
|
882
|
+
* (platform bindings — reachable only on runtimes that provide them, e.g.
|
|
883
|
+
* Cloudflare Workers).
|
|
884
|
+
*/
|
|
885
|
+
interface FetchContext extends AdapterContext {
|
|
665
886
|
/**
|
|
666
|
-
*
|
|
887
|
+
* Build and return the Web `Response` accumulated by the context.
|
|
888
|
+
*
|
|
889
|
+
* @returns The `Response` to hand back to the runtime.
|
|
667
890
|
*/
|
|
668
|
-
|
|
891
|
+
getResponse(): Response;
|
|
892
|
+
/**
|
|
893
|
+
* Extend the request's lifetime for fire-and-forget work (logging,
|
|
894
|
+
* analytics, cache writes). Only present on runtimes that expose an
|
|
895
|
+
* execution context (e.g. Cloudflare Workers, Vercel Edge).
|
|
896
|
+
*
|
|
897
|
+
* @param promise - Work that should outlive the response.
|
|
898
|
+
*/
|
|
899
|
+
waitUntil?(promise: Promise<unknown>): void;
|
|
900
|
+
/**
|
|
901
|
+
* Platform bindings passed by the runtime (e.g. Cloudflare `env`: KV, D1, R2,
|
|
902
|
+
* Durable Objects, secrets). Typed as `unknown` at the contract level; a
|
|
903
|
+
* concrete adapter may narrow it via a generic.
|
|
904
|
+
*/
|
|
905
|
+
env?: unknown;
|
|
669
906
|
}
|
|
670
907
|
/**
|
|
671
|
-
*
|
|
908
|
+
* The shape of an adapter's context factory.
|
|
672
909
|
*
|
|
673
|
-
*
|
|
674
|
-
* -
|
|
675
|
-
* -
|
|
676
|
-
*
|
|
910
|
+
* @remarks
|
|
911
|
+
* Every adapter builds the per-request context through a factory that takes
|
|
912
|
+
* platform-specific inputs (e.g. Node's `(req, res, options)`, a fetch runtime's
|
|
913
|
+
* `(request, options)`) and returns an {@link AdapterContext} over the shared
|
|
914
|
+
* {@link Context} contract. This type formalizes that invariant — "adapters build
|
|
915
|
+
* `Context` via a factory and run `app.callback()`" — at the type level, generic
|
|
916
|
+
* over the platform input tuple so server- and fetch-style factories both conform.
|
|
917
|
+
*
|
|
918
|
+
* @typeParam Args - The platform-specific factory argument tuple.
|
|
919
|
+
* @typeParam Ctx - The concrete {@link AdapterContext} the factory returns.
|
|
677
920
|
*
|
|
678
921
|
* @example
|
|
679
922
|
* ```typescript
|
|
680
|
-
*
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
* app.use(async (ctx, next) => {
|
|
686
|
-
* const start = Date.now();
|
|
687
|
-
* await next();
|
|
688
|
-
* console.log(`${ctx.method} ${ctx.path} - ${Date.now() - start}ms`);
|
|
689
|
-
* });
|
|
690
|
-
* }
|
|
691
|
-
* }
|
|
923
|
+
* // Node adapter
|
|
924
|
+
* const _factory = createNodeContext satisfies AdapterContextFactory<
|
|
925
|
+
* [IncomingMessage, ServerResponse, NodeContextOptions?],
|
|
926
|
+
* NodeContext
|
|
927
|
+
* >;
|
|
692
928
|
* ```
|
|
693
929
|
*/
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
930
|
+
type AdapterContextFactory<Args extends readonly unknown[], Ctx extends AdapterContext = AdapterContext> = (...args: Args) => Ctx;
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* @nextrush/types - Logger contract
|
|
934
|
+
*
|
|
935
|
+
* The structured logging interface shared by the application, adapters, and
|
|
936
|
+
* extensions. Lives here (the lowest package) so any layer can depend on the
|
|
937
|
+
* contract without depending on `@nextrush/core`.
|
|
938
|
+
*
|
|
939
|
+
* @packageDocumentation
|
|
940
|
+
*/
|
|
941
|
+
/**
|
|
942
|
+
* Pluggable logger interface.
|
|
943
|
+
*
|
|
944
|
+
* Pass `console` for quick development logging, or a structured logger
|
|
945
|
+
* (pino, winston, `@nextrush/logger`) in production.
|
|
946
|
+
*/
|
|
947
|
+
interface Logger {
|
|
948
|
+
error(...args: unknown[]): void;
|
|
949
|
+
warn(...args: unknown[]): void;
|
|
950
|
+
info(...args: unknown[]): void;
|
|
951
|
+
debug(...args: unknown[]): void;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* @nextrush/types - Adapter Conformance Contract (F-01)
|
|
956
|
+
*
|
|
957
|
+
* A light, additive compile-time contract that server- and fetch-style adapters
|
|
958
|
+
* `satisfies` at export time, so the *shape* of `serve`/`createHandler`/
|
|
959
|
+
* `createFetchHandler` and the `ServerHandle` cannot drift silently across
|
|
960
|
+
* adapters. This is the cheap secondary guard; a shared behavioral conformance
|
|
961
|
+
* suite is the primary one (see the audit's Adapter Conformance Specification).
|
|
962
|
+
*
|
|
963
|
+
* The contract is generic over the concrete application type because
|
|
964
|
+
* `@nextrush/types` sits below `@nextrush/core` in the package hierarchy and
|
|
965
|
+
* must not import `Application`. Adapters bind `App = Application` when they
|
|
966
|
+
* `satisfies` these shapes.
|
|
967
|
+
*
|
|
968
|
+
* @packageDocumentation
|
|
969
|
+
*/
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* The single canonical network address a server adapter binds to.
|
|
973
|
+
*
|
|
974
|
+
* @remarks
|
|
975
|
+
* Replaces the per-adapter `{ port, host }` vs `{ port, hostname }` divergence
|
|
976
|
+
* (audit F-05). `host` is the canonical key; adapters normalize internally.
|
|
977
|
+
*/
|
|
978
|
+
interface ServerAddress {
|
|
979
|
+
/** Port the server is listening on. */
|
|
980
|
+
readonly port: number;
|
|
981
|
+
/** Host/address the server is bound to (canonical key). */
|
|
982
|
+
readonly host: string;
|
|
705
983
|
/**
|
|
706
|
-
*
|
|
707
|
-
* Called when app.plugin() is invoked
|
|
984
|
+
* Host alias.
|
|
708
985
|
*
|
|
709
|
-
* @
|
|
986
|
+
* @deprecated Use {@link ServerAddress.host}. Retained so Bun/Deno, which
|
|
987
|
+
* historically returned `{ port, hostname }`, keep working during migration.
|
|
710
988
|
*/
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Cleanup when application shuts down (optional)
|
|
714
|
-
* Called during graceful shutdown
|
|
715
|
-
*/
|
|
716
|
-
destroy?(): void | Promise<void>;
|
|
989
|
+
readonly hostname?: string;
|
|
717
990
|
}
|
|
718
991
|
/**
|
|
719
|
-
*
|
|
720
|
-
*
|
|
992
|
+
* Options common to server-style handler factories (node/bun/deno).
|
|
993
|
+
*
|
|
994
|
+
* @remarks
|
|
995
|
+
* Intentionally light. Individual adapters may accept a superset; this pins the
|
|
996
|
+
* shared, portable subset.
|
|
997
|
+
*/
|
|
998
|
+
interface HandlerOptions {
|
|
999
|
+
/** Logger for adapter diagnostics. Defaults to the application logger. */
|
|
1000
|
+
logger?: Logger;
|
|
1001
|
+
/** Per-request timeout in milliseconds. */
|
|
1002
|
+
timeout?: number;
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Options for fetch-style handler factories (edge).
|
|
721
1006
|
*/
|
|
722
|
-
interface
|
|
1007
|
+
interface FetchHandlerOptions {
|
|
723
1008
|
/**
|
|
724
|
-
*
|
|
1009
|
+
* Per-request timeout in milliseconds. Individual adapters may apply their
|
|
1010
|
+
* own default when omitted (e.g. the edge adapter's `DEFAULT_EDGE_TIMEOUT_MS`,
|
|
1011
|
+
* F-07/ADR-0010) rather than leaving the timeout unenforced — this shared
|
|
1012
|
+
* type only pins the option's shape, not a specific default.
|
|
725
1013
|
*/
|
|
726
|
-
|
|
1014
|
+
timeout?: number;
|
|
727
1015
|
/**
|
|
728
|
-
*
|
|
1016
|
+
* Custom error handler. Receives the error and the fetch context and returns
|
|
1017
|
+
* the `Response` to send.
|
|
729
1018
|
*/
|
|
730
|
-
|
|
1019
|
+
onError?: (error: Error, ctx: FetchContext) => Response | Promise<Response>;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* A running server instance with one canonical address shape and async close.
|
|
1023
|
+
*
|
|
1024
|
+
* @remarks
|
|
1025
|
+
* The canonical handle every server adapter's `serve()` resolves to. Concrete
|
|
1026
|
+
* adapters may expose additional fields (e.g. the raw `server`) on a subtype.
|
|
1027
|
+
*/
|
|
1028
|
+
interface ServerHandle {
|
|
1029
|
+
/** The address the server is bound to. */
|
|
1030
|
+
address(): ServerAddress;
|
|
1031
|
+
/** Stop the server, draining in-flight requests. */
|
|
1032
|
+
close(): Promise<void>;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* A fetch handler: maps a Web `Request` (plus an optional runtime execution
|
|
1036
|
+
* context) to a `Response`.
|
|
1037
|
+
*
|
|
1038
|
+
* @typeParam Exec - The runtime execution-context type (e.g. an edge
|
|
1039
|
+
* `waitUntil` context). Defaults to `unknown`.
|
|
1040
|
+
*/
|
|
1041
|
+
type FetchHandler<Exec = unknown> = (request: Request, executionContext?: Exec) => Response | Promise<Response>;
|
|
1042
|
+
/**
|
|
1043
|
+
* Contract for server-style adapters (node/bun/deno).
|
|
1044
|
+
*
|
|
1045
|
+
* @typeParam App - The application type (adapters bind `Application`).
|
|
1046
|
+
* @typeParam Opts - The adapter's `serve` options type.
|
|
1047
|
+
* @typeParam Instance - The `serve` return type (a {@link ServerHandle} subtype).
|
|
1048
|
+
*/
|
|
1049
|
+
interface ServerAdapter<App = unknown, Opts = unknown, Instance extends ServerHandle = ServerHandle> {
|
|
1050
|
+
/** Start a server for the application. */
|
|
1051
|
+
serve(app: App, options?: Opts): Promise<Instance>;
|
|
1052
|
+
/** Build a request handler for the application without owning the server. */
|
|
1053
|
+
createHandler(app: App, options?: HandlerOptions): unknown;
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Contract for fetch-style adapters (edge).
|
|
1057
|
+
*
|
|
1058
|
+
* @typeParam App - The application type (adapters bind `Application`).
|
|
1059
|
+
*/
|
|
1060
|
+
interface FetchAdapter<App = unknown, Exec = unknown> {
|
|
1061
|
+
/** Build a fetch handler for the application. */
|
|
1062
|
+
createFetchHandler(app: App, options?: FetchHandlerOptions): FetchHandler<Exec>;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* @nextrush/types - Dependency Injection contract
|
|
1067
|
+
*
|
|
1068
|
+
* The container contract shared by `@nextrush/di` (implementation),
|
|
1069
|
+
* `@nextrush/core` (each app owns one), and consumers. Lives here (the lowest
|
|
1070
|
+
* package) so any layer can reference the contract without depending on `di`.
|
|
1071
|
+
*
|
|
1072
|
+
* @packageDocumentation
|
|
1073
|
+
*/
|
|
1074
|
+
/** Constructor type for class-based tokens. */
|
|
1075
|
+
type Constructor<T = unknown> = new (...args: unknown[]) => T;
|
|
1076
|
+
/** Token used to identify a dependency — a class, string, or symbol. */
|
|
1077
|
+
type Token<T = unknown> = Constructor<T> | string | symbol;
|
|
1078
|
+
/** Provider that uses a class constructor. */
|
|
1079
|
+
interface ClassProvider<T> {
|
|
1080
|
+
useClass: Constructor<T>;
|
|
1081
|
+
}
|
|
1082
|
+
/** Provider that uses a factory function (optionally with injected deps). */
|
|
1083
|
+
interface FactoryProvider<T> {
|
|
1084
|
+
useFactory: (...args: unknown[]) => T | Promise<T>;
|
|
1085
|
+
inject?: Token[];
|
|
1086
|
+
}
|
|
1087
|
+
/** Provider that uses a constant value. */
|
|
1088
|
+
interface ValueProvider<T> {
|
|
1089
|
+
useValue: T;
|
|
1090
|
+
}
|
|
1091
|
+
/** Union of all provider kinds. */
|
|
1092
|
+
type Provider<T> = ClassProvider<T> | FactoryProvider<T> | ValueProvider<T>;
|
|
1093
|
+
/**
|
|
1094
|
+
* Lifecycle scope for registered services.
|
|
1095
|
+
*
|
|
1096
|
+
* - `'singleton'` — one shared instance for the process lifetime.
|
|
1097
|
+
* - `'transient'` — a fresh instance on every resolve.
|
|
1098
|
+
* - `'request'` — one instance per request, shared within that request. Backed
|
|
1099
|
+
* by a per-request child container; see RFC-NEXTRUSH-REQUEST-SCOPE.
|
|
1100
|
+
*/
|
|
1101
|
+
type Scope = 'singleton' | 'transient' | 'request';
|
|
1102
|
+
/** Options for service registration. */
|
|
1103
|
+
interface ServiceOptions {
|
|
1104
|
+
scope?: Scope;
|
|
1105
|
+
}
|
|
1106
|
+
/** Registration options for `Container.register()`. */
|
|
1107
|
+
interface RegisterOptions {
|
|
1108
|
+
/** Lifecycle scope — defaults to 'transient' if not specified. */
|
|
1109
|
+
scope?: Scope;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Dependency injection container contract.
|
|
1113
|
+
*
|
|
1114
|
+
* Each NextRush {@link Application} may own one (per-app, not a global
|
|
1115
|
+
* singleton). `@nextrush/di` provides the implementation.
|
|
1116
|
+
*/
|
|
1117
|
+
interface Container {
|
|
1118
|
+
/** Register a dependency. */
|
|
1119
|
+
register<T>(token: Token<T>, provider: Provider<T>, options?: RegisterOptions): void;
|
|
1120
|
+
/** Resolve a dependency synchronously. */
|
|
1121
|
+
resolve<T>(token: Token<T>): T;
|
|
1122
|
+
/** Resolve a dependency that may have been registered with an async factory. */
|
|
1123
|
+
resolveAsync<T>(token: Token<T>): Promise<T>;
|
|
1124
|
+
/** Bootstrap all factory providers (awaits async factories, caches results). */
|
|
1125
|
+
bootstrap(): Promise<void>;
|
|
1126
|
+
/** Resolve all dependencies registered under a token. */
|
|
1127
|
+
resolveAll<T>(token: Token<T>): T[];
|
|
1128
|
+
/** Check if a token is registered. */
|
|
1129
|
+
isRegistered<T>(token: Token<T>): boolean;
|
|
1130
|
+
/** Clear all registered instances (testing). */
|
|
1131
|
+
clearInstances(): void;
|
|
1132
|
+
/** Reset the container completely (testing). */
|
|
1133
|
+
reset(): void;
|
|
1134
|
+
/** Create a child container with isolated scope. */
|
|
1135
|
+
createChild(): Container;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* @nextrush/types - Extension contract
|
|
1140
|
+
*
|
|
1141
|
+
* Extensions are the rare (~0.1%) long-lived runtime services that must attach
|
|
1142
|
+
* state to the app, run async boot, and/or tear down on shutdown — an event bus,
|
|
1143
|
+
* a database pool, a websocket attach. Most framework features are **middleware**
|
|
1144
|
+
* (`app.use`) or plain **registrar** functions, not Extensions.
|
|
1145
|
+
*
|
|
1146
|
+
* See docs/RFC/class-runtime/005-plugin-system.md.
|
|
1147
|
+
*
|
|
1148
|
+
* @packageDocumentation
|
|
1149
|
+
*/
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* The subset of `Application` an {@link Extension} may use during `setup()`.
|
|
1153
|
+
*
|
|
1154
|
+
* Kept structural (not the concrete `Application`) so {@link ExtensionContext}
|
|
1155
|
+
* can live in `@nextrush/types` without importing `@nextrush/core`. The
|
|
1156
|
+
* `Application` class implements this interface. Routing methods are added here
|
|
1157
|
+
* when the app-owned router lands (RFC §11.1).
|
|
1158
|
+
*/
|
|
1159
|
+
interface ExtensionHost {
|
|
1160
|
+
/** Register middleware on the application. */
|
|
1161
|
+
use(middleware: Middleware): this;
|
|
1162
|
+
/** Whether a decoration already occupies `name`. */
|
|
1163
|
+
hasDecorator(name: string): boolean;
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* The argument passed to {@link Extension.setup}.
|
|
1167
|
+
*
|
|
1168
|
+
* A context object rather than the bare app, so future fields (`runtime`,
|
|
1169
|
+
* `container`, `config`, …) are **additive** and never break existing
|
|
1170
|
+
* extensions — the same reason VS Code uses `activate(context)`.
|
|
1171
|
+
*/
|
|
1172
|
+
interface ExtensionContext {
|
|
1173
|
+
/** The application instance — add middleware, read decorations. */
|
|
1174
|
+
readonly app: ExtensionHost;
|
|
1175
|
+
/** The app logger (structured, pluggable). */
|
|
1176
|
+
readonly logger: Logger;
|
|
731
1177
|
/**
|
|
732
|
-
*
|
|
1178
|
+
* The app's DI container, if one was configured (per-app, not a global
|
|
1179
|
+
* singleton). Present when the app was created via `nextrush/class` or with
|
|
1180
|
+
* `createApp({ container })`; `undefined` for functional, DI-free apps.
|
|
733
1181
|
*/
|
|
734
|
-
|
|
1182
|
+
readonly container?: Container;
|
|
1183
|
+
/** Environment mode. */
|
|
1184
|
+
readonly env: 'development' | 'production' | 'test';
|
|
1185
|
+
/** This extension's own name (for scoped diagnostics). */
|
|
1186
|
+
readonly name: string;
|
|
735
1187
|
/**
|
|
736
|
-
*
|
|
737
|
-
*
|
|
1188
|
+
* Attach a value to the app under `name`. The extension-author primitive for
|
|
1189
|
+
* exposing app-level surface (e.g. `app.events`). Throws if `name` is already
|
|
1190
|
+
* decorated or collides with a core `Application` member.
|
|
738
1191
|
*/
|
|
739
|
-
|
|
1192
|
+
decorate(name: string, value: unknown): void;
|
|
740
1193
|
}
|
|
741
1194
|
/**
|
|
742
|
-
*
|
|
743
|
-
*
|
|
1195
|
+
* A NextRush Extension.
|
|
1196
|
+
*
|
|
1197
|
+
* Registered via `app.extend()` (queues) and booted once at `app.ready()`
|
|
1198
|
+
* (runs `setup` in registration order). Torn down at `app.close()`.
|
|
744
1199
|
*
|
|
745
1200
|
* @example
|
|
746
1201
|
* ```typescript
|
|
747
|
-
*
|
|
748
|
-
*
|
|
1202
|
+
* export function events(): Extension {
|
|
1203
|
+
* const emitter = new EventEmitter();
|
|
1204
|
+
* return {
|
|
1205
|
+
* name: 'events',
|
|
1206
|
+
* setup(ctx) { ctx.decorate('events', emitter); },
|
|
1207
|
+
* destroy() { emitter.clear(); },
|
|
1208
|
+
* };
|
|
1209
|
+
* }
|
|
749
1210
|
* ```
|
|
750
1211
|
*/
|
|
751
|
-
type PluginFactory<TOptions = unknown> = (options?: TOptions) => Plugin;
|
|
752
1212
|
/**
|
|
753
|
-
*
|
|
1213
|
+
* @template TDecorated - Shape decorated onto the app by this extension's
|
|
1214
|
+
* `setup()`. Phantom — never read at runtime, only carried through the type
|
|
1215
|
+
* system so `Application.extend()` can return `this & TDecorated`, giving
|
|
1216
|
+
* `app.<decoratedProperty>` static inference with zero `declare module`
|
|
1217
|
+
* augmentation. Defaults to `{}` so plain, untyped `Extension` usages
|
|
1218
|
+
* (the common case for internal/test extensions) are unaffected.
|
|
1219
|
+
*
|
|
1220
|
+
* @remarks
|
|
1221
|
+
* Two things to know before relying on this:
|
|
1222
|
+
*
|
|
1223
|
+
* - **TypeScript trusts `TDecorated`, it never verifies it.** Nothing checks
|
|
1224
|
+
* that the declared shape actually matches what `setup()` calls
|
|
1225
|
+
* `ctx.decorate()` with — `Extension<{ foo: Foo }>` whose `setup()` never
|
|
1226
|
+
* decorates `foo` still typechecks, and `app.foo` will be `undefined` at
|
|
1227
|
+
* runtime with no warning. Keep the generic and the `decorate()` call in
|
|
1228
|
+
* sync by hand.
|
|
1229
|
+
* - **The inferred type is lost on `let` reassignment.** Chain in one
|
|
1230
|
+
* expression (`const app = createApp().extend(x)`), not
|
|
1231
|
+
* `let app = createApp(); app = app.extend(x);` — TypeScript widens the
|
|
1232
|
+
* reassignment to the `let` binding's originally-inferred type, silently
|
|
1233
|
+
* dropping `TDecorated`. Every example below chains for this reason.
|
|
1234
|
+
*
|
|
1235
|
+
* @example
|
|
1236
|
+
* ```typescript
|
|
1237
|
+
* function events<T extends EventMap>(): Extension<{ events: EventEmitter<T> }> {
|
|
1238
|
+
* return {
|
|
1239
|
+
* name: 'events',
|
|
1240
|
+
* setup(ctx) { ctx.decorate('events', new EventEmitter<T>()); },
|
|
1241
|
+
* };
|
|
1242
|
+
* }
|
|
1243
|
+
*
|
|
1244
|
+
* const app = createApp().extend(events<MyEvents>());
|
|
1245
|
+
* app.events.emit('user:created', { id: '1' }); // inferred, no cast
|
|
1246
|
+
* ```
|
|
754
1247
|
*/
|
|
755
|
-
interface
|
|
756
|
-
/**
|
|
757
|
-
name: string;
|
|
758
|
-
/**
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
1248
|
+
interface Extension<TDecorated = Record<string, never>> {
|
|
1249
|
+
/** Unique name — used for collision detection, dependency assertion, diagnostics. */
|
|
1250
|
+
readonly name: string;
|
|
1251
|
+
/**
|
|
1252
|
+
* Names of other extensions that MUST already be registered before this one.
|
|
1253
|
+
* Asserted at `app.ready()` in registration order — not auto-sorted.
|
|
1254
|
+
*/
|
|
1255
|
+
readonly needs?: readonly string[];
|
|
1256
|
+
/** Set up the extension. Runs once, at `app.ready()`, in registration order. */
|
|
1257
|
+
setup(ctx: ExtensionContext): void | Promise<void>;
|
|
1258
|
+
/** Tear down on `app.close()`. Runs in reverse registration order. */
|
|
1259
|
+
destroy?(): void | Promise<void>;
|
|
1260
|
+
/**
|
|
1261
|
+
* Phantom marker carrying `TDecorated` through the type system. Never set
|
|
1262
|
+
* at runtime — `TDecorated` has no inhabitant, so no implementation ever
|
|
1263
|
+
* assigns this. Purely what lets `extend()` infer its return type.
|
|
1264
|
+
*/
|
|
1265
|
+
readonly __decorated?: TDecorated;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
/**
|
|
1269
|
+
* @nextrush/types - Standard Schema Contract
|
|
1270
|
+
*
|
|
1271
|
+
* Structural copy of the `@standard-schema/spec` v1 interface
|
|
1272
|
+
* (https://github.com/standard-schema/standard-schema, MIT licensed), vendored
|
|
1273
|
+
* as a type so NextRush stays dependency-free. It lives in `@nextrush/types`
|
|
1274
|
+
* (not in any single consumer) because it is now a shared contract: request
|
|
1275
|
+
* validation, route metadata, and OpenAPI generation all reference it.
|
|
1276
|
+
*
|
|
1277
|
+
* Because TypeScript is structural, any schema implementing Standard Schema —
|
|
1278
|
+
* Zod 3.24+, Valibot 1.0+, ArkType 2.0+, and others — satisfies this interface
|
|
1279
|
+
* without an adapter.
|
|
1280
|
+
*
|
|
1281
|
+
* @packageDocumentation
|
|
1282
|
+
*/
|
|
1283
|
+
/**
|
|
1284
|
+
* A schema that exposes the Standard Schema v1 contract on its `~standard`
|
|
1285
|
+
* property. This is the only surface NextRush depends on.
|
|
1286
|
+
*/
|
|
1287
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
1288
|
+
readonly '~standard': StandardSchemaProps<Input, Output>;
|
|
1289
|
+
}
|
|
1290
|
+
/** The `~standard` property contract. */
|
|
1291
|
+
interface StandardSchemaProps<Input = unknown, Output = Input> {
|
|
1292
|
+
/** Spec version — always `1`. */
|
|
1293
|
+
readonly version: 1;
|
|
1294
|
+
/** Identifier of the schema library (e.g. `'zod'`, `'valibot'`). */
|
|
1295
|
+
readonly vendor: string;
|
|
1296
|
+
/** Validates and (optionally) coerces `value`; may be sync or async. */
|
|
1297
|
+
readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
1298
|
+
/** Phantom types for input/output inference; never present at runtime. */
|
|
1299
|
+
readonly types?: {
|
|
1300
|
+
readonly input: Input;
|
|
1301
|
+
readonly output: Output;
|
|
1302
|
+
} | undefined;
|
|
1303
|
+
}
|
|
1304
|
+
/** Result of a validation: either a success carrying `value`, or a failure carrying `issues`. */
|
|
1305
|
+
type StandardSchemaResult<Output> = {
|
|
1306
|
+
readonly value: Output;
|
|
1307
|
+
readonly issues?: undefined;
|
|
1308
|
+
} | {
|
|
1309
|
+
readonly issues: readonly StandardSchemaIssue[];
|
|
1310
|
+
};
|
|
1311
|
+
/** A single validation issue reported by a schema. */
|
|
1312
|
+
interface StandardSchemaIssue {
|
|
1313
|
+
/** Human-readable message. */
|
|
1314
|
+
readonly message: string;
|
|
1315
|
+
/** Path to the offending value; segments are keys or `{ key }` objects. */
|
|
1316
|
+
readonly path?: readonly (PropertyKey | StandardSchemaPathSegment)[] | undefined;
|
|
1317
|
+
}
|
|
1318
|
+
/** A structured path segment. */
|
|
1319
|
+
interface StandardSchemaPathSegment {
|
|
1320
|
+
readonly key: PropertyKey;
|
|
1321
|
+
}
|
|
1322
|
+
/** Infer the validated output type of a Standard Schema. */
|
|
1323
|
+
type InferOutput<S extends StandardSchemaV1> = NonNullable<S['~standard']['types']>['output'];
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* @nextrush/types - Route Metadata Contracts
|
|
1327
|
+
*
|
|
1328
|
+
* `RouteDefinition` is the single source of truth for what a route *is and
|
|
1329
|
+
* means*. The router collects it once at registration; renderers
|
|
1330
|
+
* (`@nextrush/openapi`, and later SDK/Postman/RPC generators) read it. The
|
|
1331
|
+
* router itself is renderer-agnostic — it stores raw schemas and generic
|
|
1332
|
+
* metadata, never OpenAPI shapes.
|
|
1333
|
+
*
|
|
1334
|
+
* See docs/RFC/request-data/002-route-metadata.md.
|
|
1335
|
+
*
|
|
1336
|
+
* @packageDocumentation
|
|
1337
|
+
*/
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Well-known symbol by which anything — a middleware function (e.g. `validate()`)
|
|
1341
|
+
* or a pure marker (e.g. `endpoint()`) — contributes metadata to the route it is
|
|
1342
|
+
* registered on. The router reads this symbol off every route entry at
|
|
1343
|
+
* registration and merges the contributions.
|
|
1344
|
+
*
|
|
1345
|
+
* `Symbol.for` (global registry) is used so the identity holds even across
|
|
1346
|
+
* duplicate package instances.
|
|
1347
|
+
*/
|
|
1348
|
+
declare const ROUTE_METADATA: unique symbol;
|
|
1349
|
+
/** A partial metadata contribution; contributions merge in registration order. */
|
|
1350
|
+
type MetadataContribution = Partial<RouteMetadata>;
|
|
1351
|
+
/**
|
|
1352
|
+
* A pure-metadata marker carried in a route's argument list. Not a middleware —
|
|
1353
|
+
* it has no runtime behavior and never enters the executed chain.
|
|
1354
|
+
*/
|
|
1355
|
+
interface RouteMetaMarker {
|
|
1356
|
+
readonly [ROUTE_METADATA]: MetadataContribution;
|
|
1357
|
+
}
|
|
1358
|
+
/** An entry in a route's argument list: behavior (`Middleware`) or pure metadata (a marker). */
|
|
1359
|
+
type RouteEntry = Middleware | RouteMetaMarker;
|
|
1360
|
+
/**
|
|
1361
|
+
* Generic, renderer-agnostic description of a route's request/response shapes
|
|
1362
|
+
* and documentation facts. Every field is a fact any renderer needs; no
|
|
1363
|
+
* renderer-specific artifacts (e.g. OpenAPI `operationId`) live here.
|
|
1364
|
+
*/
|
|
1365
|
+
interface RouteMetadata {
|
|
1366
|
+
/** Request shapes — contributed by `validate()`; never hand-written on the golden path. */
|
|
1367
|
+
readonly request?: {
|
|
1368
|
+
readonly body?: StandardSchemaV1;
|
|
1369
|
+
readonly query?: StandardSchemaV1;
|
|
1370
|
+
readonly params?: StandardSchemaV1;
|
|
1371
|
+
};
|
|
1372
|
+
/** Response shapes by numeric status — contributed by `endpoint()`. */
|
|
1373
|
+
readonly responses?: Readonly<Record<number, StandardSchemaV1>>;
|
|
1374
|
+
readonly summary?: string;
|
|
1375
|
+
readonly description?: string;
|
|
1376
|
+
readonly tags?: readonly string[];
|
|
1377
|
+
readonly deprecated?: boolean;
|
|
1378
|
+
/** Cross-renderer intent — an `'internal'` route is excluded from public specs/SDKs. */
|
|
1379
|
+
readonly visibility?: 'public' | 'internal';
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* The canonical description of a registered endpoint, produced by the router
|
|
1383
|
+
* and consumed by renderers.
|
|
1384
|
+
*/
|
|
1385
|
+
interface RouteDefinition {
|
|
1386
|
+
/**
|
|
1387
|
+
* Canonical route key — `${METHOD} ${pathPattern}` (e.g. `"GET /users/:id"`),
|
|
1388
|
+
* the key the router uses internally. Deterministic and stable across
|
|
1389
|
+
* restarts, but it encodes the path, so it changes if the path or a param
|
|
1390
|
+
* name changes — a key, not a rename-stable opaque id.
|
|
1391
|
+
*/
|
|
1392
|
+
readonly key: string;
|
|
1393
|
+
readonly method: HttpMethod;
|
|
1394
|
+
/** Full, mount/prefix-resolved path pattern. */
|
|
1395
|
+
readonly path: string;
|
|
1396
|
+
readonly metadata?: RouteMetadata;
|
|
1397
|
+
/**
|
|
1398
|
+
* `true` when this entry represents an any-method route (registered via
|
|
1399
|
+
* `router.all()` / `@All()`), matching every standard HTTP method under a
|
|
1400
|
+
* single introspection row rather than one row per method (T016). `method`
|
|
1401
|
+
* is still a real `HttpMethod` value for structural compatibility with
|
|
1402
|
+
* existing consumers that read `.method` unconditionally — check this flag
|
|
1403
|
+
* first when the distinction matters (e.g. an OpenAPI renderer expanding
|
|
1404
|
+
* one row into per-verb operations). Absent (`undefined`) for every
|
|
1405
|
+
* ordinary single-method route.
|
|
1406
|
+
*/
|
|
1407
|
+
readonly isAnyMethod?: boolean;
|
|
768
1408
|
}
|
|
769
1409
|
|
|
770
1410
|
/**
|
|
771
1411
|
* @nextrush/types - Router Type Definitions
|
|
772
1412
|
*
|
|
773
1413
|
* Types for the NextRush router system.
|
|
774
|
-
* The router
|
|
1414
|
+
* The router matches routes with a segment trie keyed by whole path segments,
|
|
1415
|
+
* giving O(k) lookups where k is the number of path segments.
|
|
775
1416
|
*
|
|
776
1417
|
* @packageDocumentation
|
|
777
1418
|
*/
|
|
@@ -820,43 +1461,53 @@ interface Router {
|
|
|
820
1461
|
/**
|
|
821
1462
|
* Register a GET route
|
|
822
1463
|
*/
|
|
823
|
-
get(path: string, ...
|
|
1464
|
+
get(path: string, ...entries: RouteEntry[]): this;
|
|
824
1465
|
/**
|
|
825
1466
|
* Register a POST route
|
|
826
1467
|
*/
|
|
827
|
-
post(path: string, ...
|
|
1468
|
+
post(path: string, ...entries: RouteEntry[]): this;
|
|
828
1469
|
/**
|
|
829
1470
|
* Register a PUT route
|
|
830
1471
|
*/
|
|
831
|
-
put(path: string, ...
|
|
1472
|
+
put(path: string, ...entries: RouteEntry[]): this;
|
|
832
1473
|
/**
|
|
833
1474
|
* Register a DELETE route
|
|
834
1475
|
*/
|
|
835
|
-
delete(path: string, ...
|
|
1476
|
+
delete(path: string, ...entries: RouteEntry[]): this;
|
|
836
1477
|
/**
|
|
837
1478
|
* Register a PATCH route
|
|
838
1479
|
*/
|
|
839
|
-
patch(path: string, ...
|
|
1480
|
+
patch(path: string, ...entries: RouteEntry[]): this;
|
|
840
1481
|
/**
|
|
841
1482
|
* Register a HEAD route
|
|
842
1483
|
*/
|
|
843
|
-
head(path: string, ...
|
|
1484
|
+
head(path: string, ...entries: RouteEntry[]): this;
|
|
844
1485
|
/**
|
|
845
1486
|
* Register an OPTIONS route
|
|
846
1487
|
*/
|
|
847
|
-
options(path: string, ...
|
|
1488
|
+
options(path: string, ...entries: RouteEntry[]): this;
|
|
848
1489
|
/**
|
|
849
1490
|
* Register a route for any HTTP method
|
|
850
1491
|
*/
|
|
851
|
-
all(path: string, ...
|
|
1492
|
+
all(path: string, ...entries: RouteEntry[]): this;
|
|
852
1493
|
/**
|
|
853
1494
|
* Register a route for specific method
|
|
854
1495
|
*/
|
|
855
|
-
route(method: HttpMethod, path: string, ...
|
|
1496
|
+
route(method: HttpMethod, path: string, ...entries: RouteEntry[]): this;
|
|
856
1497
|
/**
|
|
857
1498
|
* Mount router middleware
|
|
858
1499
|
*/
|
|
859
|
-
|
|
1500
|
+
/**
|
|
1501
|
+
* Mount middleware.
|
|
1502
|
+
*
|
|
1503
|
+
* @remarks
|
|
1504
|
+
* Sub-router mounting (`router.use(path, subRouter)`) is a concrete
|
|
1505
|
+
* `@nextrush/router` `Router` capability, not part of this structural
|
|
1506
|
+
* interface — mounting needs internal tree access
|
|
1507
|
+
* (`Router.mount()`/the concrete class's own `use()` overload provide it).
|
|
1508
|
+
* Cross-package router composition goes through `Application.route()`
|
|
1509
|
+
* (`Routable`, `routes()`-only) instead.
|
|
1510
|
+
*/
|
|
860
1511
|
use(middleware: Middleware): this;
|
|
861
1512
|
/**
|
|
862
1513
|
* Register a redirect from one path to another
|
|
@@ -871,6 +1522,12 @@ interface Router {
|
|
|
871
1522
|
* Mount this on the application
|
|
872
1523
|
*/
|
|
873
1524
|
routes(): Middleware;
|
|
1525
|
+
/**
|
|
1526
|
+
* Return every registered route as a read-only list of RouteDefinitions.
|
|
1527
|
+
* Consumed by renderers (`@nextrush/openapi`, SDK/Postman generators).
|
|
1528
|
+
* Doc-generation-time projection — never called on the request hot path.
|
|
1529
|
+
*/
|
|
1530
|
+
getRoutes(): readonly RouteDefinition[];
|
|
874
1531
|
/**
|
|
875
1532
|
* Match a route
|
|
876
1533
|
*/
|
|
@@ -895,6 +1552,13 @@ interface RouterOptions {
|
|
|
895
1552
|
* @default false
|
|
896
1553
|
*/
|
|
897
1554
|
strict?: boolean;
|
|
1555
|
+
/**
|
|
1556
|
+
* Whether to percent-decode extracted param and wildcard values
|
|
1557
|
+
* (via `decodeURIComponent`). Malformed encoding falls back to the raw value
|
|
1558
|
+
* and never throws. Set to `false` to receive raw, undecoded values.
|
|
1559
|
+
* @default true
|
|
1560
|
+
*/
|
|
1561
|
+
decode?: boolean;
|
|
898
1562
|
}
|
|
899
1563
|
/**
|
|
900
1564
|
* Supported route pattern types
|
|
@@ -912,4 +1576,4 @@ interface RouteParam {
|
|
|
912
1576
|
pattern?: RegExp;
|
|
913
1577
|
}
|
|
914
1578
|
|
|
915
|
-
export { type
|
|
1579
|
+
export { type AdapterContext, type AdapterContextFactory, type BaseStreamWriter, type BodySource, type BodySourceOptions, type ClassProvider, type CommonHttpMethod, type Constructor, type Container, ContentType, type ContentTypeValue, type Context, type ContextOptions, type ContextState, type Extension, type ExtensionContext, type ExtensionHost, type FactoryProvider, type FetchAdapter, type FetchContext, type FetchHandler, type FetchHandlerOptions, HTTP_METHODS, type HandlerOptions, type HttpMethod, HttpStatus, type HttpStatusCode, type IncomingHeaders, type InferOutput, type Logger, type MetadataContribution, type Middleware, type NDJSONStreamWriter, type Next, type NodeStreamLike, type OutgoingHeaders, type ParsedBody, type Provider, type QueryParams, ROUTE_METADATA, type RawHttp, type RegisterOptions, type ResponseBody, type Route, type RouteDefinition, type RouteEntry, type RouteHandler, type RouteMatch, type RouteMetaMarker, type RouteMetadata, type RouteParam, type RouteParams, type RoutePattern, type Router, type RouterOptions, type Runtime, type RuntimeCapabilities, type RuntimeInfo, type SSEEvent, type SSEStreamWriter, type Scope, type ServerAdapter, type ServerAddress, type ServerHandle, type ServiceOptions, type StandardSchemaIssue, type StandardSchemaPathSegment, type StandardSchemaProps, type StandardSchemaResult, type StandardSchemaV1, type StreamRun, type StreamSource, type TextStreamWriter, type Token, type ValueProvider, type WebStreamLike };
|