astro-routify 1.1.0 → 1.2.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 +110 -58
- package/dist/core/defineHandler.d.ts +22 -0
- package/dist/core/defineHandler.js +25 -1
- package/dist/core/defineRoute.d.ts +32 -0
- package/dist/core/defineRoute.js +14 -1
- package/dist/core/defineRouter.d.ts +32 -1
- package/dist/core/defineRouter.js +25 -1
- package/dist/core/internal/createJsonStreamRoute.d.ts +64 -0
- package/dist/core/internal/createJsonStreamRoute.js +92 -0
- package/dist/core/responseHelpers.d.ts +62 -1
- package/dist/core/responseHelpers.js +54 -0
- package/dist/core/stream.d.ts +75 -0
- package/dist/core/stream.js +91 -0
- package/dist/core/streamJsonArray.d.ts +31 -0
- package/dist/core/streamJsonArray.js +30 -0
- package/dist/core/streamJsonND.d.ts +34 -0
- package/dist/core/streamJsonND.js +33 -0
- package/dist/index.d.ts +311 -3
- package/dist/index.js +3 -0
- package/package.json +11 -5
package/dist/index.d.ts
CHANGED
|
@@ -16,41 +16,187 @@ declare const ALLOWED_HTTP_METHODS: Set<string>;
|
|
|
16
16
|
*/
|
|
17
17
|
declare function normalizeMethod(method: string): HttpMethod;
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* A standardized shape for internal route result objects.
|
|
21
|
+
* These are later converted into native `Response` instances.
|
|
22
|
+
*/
|
|
19
23
|
interface ResultResponse<T = unknown> {
|
|
24
|
+
/**
|
|
25
|
+
* Optional body content (can be a string, object, or binary).
|
|
26
|
+
*/
|
|
20
27
|
body?: T;
|
|
28
|
+
/**
|
|
29
|
+
* HTTP status code (e.g. 200, 404, 500).
|
|
30
|
+
*/
|
|
21
31
|
status: number;
|
|
32
|
+
/**
|
|
33
|
+
* Optional response headers.
|
|
34
|
+
*/
|
|
22
35
|
headers?: HeadersInit;
|
|
23
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* 200 OK
|
|
39
|
+
*/
|
|
24
40
|
declare const ok: <T>(body: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
41
|
+
/**
|
|
42
|
+
* 201 Created
|
|
43
|
+
*/
|
|
25
44
|
declare const created: <T>(body: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
45
|
+
/**
|
|
46
|
+
* 204 No Content
|
|
47
|
+
*/
|
|
26
48
|
declare const noContent: (headers?: HeadersInit) => ResultResponse<undefined>;
|
|
49
|
+
/**
|
|
50
|
+
* 304 Not Modified
|
|
51
|
+
*/
|
|
27
52
|
declare const notModified: (headers?: HeadersInit) => ResultResponse<undefined>;
|
|
53
|
+
/**
|
|
54
|
+
* 400 Bad Request
|
|
55
|
+
*/
|
|
28
56
|
declare const badRequest: <T = string>(body?: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
57
|
+
/**
|
|
58
|
+
* 401 Unauthorized
|
|
59
|
+
*/
|
|
29
60
|
declare const unauthorized: <T = string>(body?: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
61
|
+
/**
|
|
62
|
+
* 403 Forbidden
|
|
63
|
+
*/
|
|
30
64
|
declare const forbidden: <T = string>(body?: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
65
|
+
/**
|
|
66
|
+
* 404 Not Found
|
|
67
|
+
*/
|
|
31
68
|
declare const notFound: <T = string>(body?: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
69
|
+
/**
|
|
70
|
+
* 405 Method Not Allowed
|
|
71
|
+
*/
|
|
32
72
|
declare const methodNotAllowed: <T = string>(body?: T, headers?: HeadersInit) => ResultResponse<T>;
|
|
73
|
+
/**
|
|
74
|
+
* 500 Internal Server Error
|
|
75
|
+
*/
|
|
33
76
|
declare const internalError: (err: unknown, headers?: HeadersInit) => ResultResponse<string>;
|
|
77
|
+
/**
|
|
78
|
+
* Sends a binary or stream-based file response with optional content-disposition.
|
|
79
|
+
*
|
|
80
|
+
* @param content - The file data (Blob, ArrayBuffer, or stream)
|
|
81
|
+
* @param contentType - MIME type of the file
|
|
82
|
+
* @param fileName - Optional download filename
|
|
83
|
+
* @param headers - Optional extra headers
|
|
84
|
+
* @returns A ResultResponse for download-ready content
|
|
85
|
+
*/
|
|
34
86
|
declare const fileResponse: (content: Blob | ArrayBuffer | ReadableStream<Uint8Array>, contentType: string, fileName?: string, headers?: HeadersInit) => ResultResponse<BodyInit>;
|
|
87
|
+
/**
|
|
88
|
+
* Converts an internal `ResultResponse` into a native `Response` object
|
|
89
|
+
* for use inside Astro API routes.
|
|
90
|
+
*
|
|
91
|
+
* Automatically applies `Content-Type: application/json` for object bodies.
|
|
92
|
+
*
|
|
93
|
+
* @param result - A ResultResponse returned from route handler
|
|
94
|
+
* @returns A native Response
|
|
95
|
+
*/
|
|
35
96
|
declare function toAstroResponse(result: ResultResponse | undefined): Response;
|
|
36
97
|
|
|
98
|
+
/**
|
|
99
|
+
* A flexible route handler that can return:
|
|
100
|
+
* - a native `Response` object,
|
|
101
|
+
* - a structured `ResultResponse` object,
|
|
102
|
+
* - or a file stream (Blob, ArrayBuffer, or ReadableStream).
|
|
103
|
+
*/
|
|
37
104
|
type Handler = (ctx: APIContext) => Promise<ResultResponse | Response> | ResultResponse | Response;
|
|
105
|
+
/**
|
|
106
|
+
* Wraps a `Handler` function into an `APIRoute` that:
|
|
107
|
+
* - logs requests and responses,
|
|
108
|
+
* - supports all valid `ResultResponse` return formats,
|
|
109
|
+
* - auto-converts structured responses into Astro `Response`s,
|
|
110
|
+
* - handles errors with standardized 500 output.
|
|
111
|
+
*
|
|
112
|
+
* @param handler - A handler function returning a `Response` or `ResultResponse`
|
|
113
|
+
* @returns An Astro-compatible `APIRoute` function
|
|
114
|
+
*/
|
|
38
115
|
declare function defineHandler(handler: Handler): APIRoute;
|
|
116
|
+
/**
|
|
117
|
+
* Type guard to detect ReadableStreams, used for streamed/binary responses.
|
|
118
|
+
*
|
|
119
|
+
* @param value - Any value to test
|
|
120
|
+
* @returns True if it looks like a ReadableStream
|
|
121
|
+
*/
|
|
39
122
|
declare function isReadableStream(value: unknown): value is ReadableStream<Uint8Array>;
|
|
40
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Represents a single route definition.
|
|
126
|
+
*/
|
|
41
127
|
interface Route {
|
|
128
|
+
/**
|
|
129
|
+
* HTTP method to match (GET, POST, PUT, etc.).
|
|
130
|
+
*/
|
|
42
131
|
method: HttpMethod;
|
|
132
|
+
/**
|
|
133
|
+
* Path pattern, starting with `/`, supporting static or param segments (e.g., `/users/:id`).
|
|
134
|
+
*/
|
|
43
135
|
path: string;
|
|
136
|
+
/**
|
|
137
|
+
* The function that handles the request when matched.
|
|
138
|
+
*/
|
|
44
139
|
handler: Handler;
|
|
45
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Defines a route using a `Route` object.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* defineRoute({ method: 'GET', path: '/users', handler });
|
|
146
|
+
*
|
|
147
|
+
* @param route - A fully constructed route object
|
|
148
|
+
* @returns The validated Route object
|
|
149
|
+
*/
|
|
46
150
|
declare function defineRoute(route: Route): Route;
|
|
151
|
+
/**
|
|
152
|
+
* Defines a route by specifying its method, path, and handler explicitly.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* defineRoute('POST', '/login', handler);
|
|
156
|
+
*
|
|
157
|
+
* @param method - HTTP method to match
|
|
158
|
+
* @param path - Route path (must start with `/`)
|
|
159
|
+
* @param handler - Function to handle the matched request
|
|
160
|
+
* @returns The validated Route object
|
|
161
|
+
*/
|
|
47
162
|
declare function defineRoute(method: HttpMethod, path: string, handler: Handler): Route;
|
|
48
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Optional configuration for the router instance.
|
|
166
|
+
*/
|
|
49
167
|
interface RouterOptions {
|
|
168
|
+
/**
|
|
169
|
+
* A base path to strip from the incoming request path (default: `/api`).
|
|
170
|
+
* Only routes beneath this prefix will be matched.
|
|
171
|
+
*/
|
|
50
172
|
basePath?: string;
|
|
51
|
-
/**
|
|
173
|
+
/**
|
|
174
|
+
* Custom handler to return when no route is matched (404).
|
|
175
|
+
*/
|
|
52
176
|
onNotFound?: () => ReturnType<typeof notFound>;
|
|
53
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Defines a router that dynamically matches registered routes based on method and path.
|
|
180
|
+
*
|
|
181
|
+
* This allows building a clean, centralized API routing system with features like:
|
|
182
|
+
* - Trie-based fast route lookup
|
|
183
|
+
* - Per-method matching with 405 fallback
|
|
184
|
+
* - Parameter extraction (e.g. `/users/:id`)
|
|
185
|
+
* - Customizable basePath and 404 behavior
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* defineRouter([
|
|
189
|
+
* defineRoute('GET', '/users', handler),
|
|
190
|
+
* defineRoute('POST', '/login', loginHandler),
|
|
191
|
+
* ], {
|
|
192
|
+
* basePath: '/api',
|
|
193
|
+
* onNotFound: () => notFound('No such route')
|
|
194
|
+
* });
|
|
195
|
+
*
|
|
196
|
+
* @param routes - An array of route definitions (see `defineRoute`)
|
|
197
|
+
* @param options - Optional router config (basePath, custom 404)
|
|
198
|
+
* @returns An Astro-compatible APIRoute handler
|
|
199
|
+
*/
|
|
54
200
|
declare function defineRouter(routes: Route[], options?: RouterOptions): APIRoute;
|
|
55
201
|
|
|
56
202
|
/**
|
|
@@ -267,5 +413,167 @@ declare class RouterBuilder {
|
|
|
267
413
|
build(): astro.APIRoute;
|
|
268
414
|
}
|
|
269
415
|
|
|
270
|
-
|
|
271
|
-
|
|
416
|
+
/**
|
|
417
|
+
* A writer for streaming raw data to the response body.
|
|
418
|
+
*
|
|
419
|
+
* This is used inside the `stream()` route handler to emit bytes
|
|
420
|
+
* or strings directly to the client with backpressure awareness.
|
|
421
|
+
*/
|
|
422
|
+
interface StreamWriter {
|
|
423
|
+
/**
|
|
424
|
+
* Write a string or Uint8Array chunk to the response stream.
|
|
425
|
+
* @param chunk - Text or byte chunk to emit
|
|
426
|
+
*/
|
|
427
|
+
write: (chunk: string | Uint8Array) => void;
|
|
428
|
+
/**
|
|
429
|
+
* Close the stream and signal end-of-response to the client.
|
|
430
|
+
*/
|
|
431
|
+
close: () => void;
|
|
432
|
+
/**
|
|
433
|
+
* Dynamically change the Content-Type header.
|
|
434
|
+
* Should be called before the first `write()` to take effect.
|
|
435
|
+
* @param type - MIME type (e.g., `text/html`, `application/json`)
|
|
436
|
+
*/
|
|
437
|
+
setContentType: (type: string) => void;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Configuration options for the `stream()` route helper.
|
|
441
|
+
*/
|
|
442
|
+
interface StreamOptions {
|
|
443
|
+
/**
|
|
444
|
+
* HTTP method (defaults to GET).
|
|
445
|
+
*/
|
|
446
|
+
method?: HttpMethod;
|
|
447
|
+
/**
|
|
448
|
+
* Content-Type header (defaults to `text/event-stream`).
|
|
449
|
+
*/
|
|
450
|
+
contentType?: string;
|
|
451
|
+
/**
|
|
452
|
+
* Additional custom headers.
|
|
453
|
+
*/
|
|
454
|
+
headers?: HeadersInit;
|
|
455
|
+
/**
|
|
456
|
+
* Enable SSE keep-alive headers (defaults to true for SSE).
|
|
457
|
+
*/
|
|
458
|
+
keepAlive?: boolean;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Defines a generic streaming route that can write raw chunks of data
|
|
462
|
+
* to the response in real time using a `ReadableStream`.
|
|
463
|
+
*
|
|
464
|
+
* Suitable for Server-Sent Events (SSE), long-polling, streamed HTML,
|
|
465
|
+
* logs, LLM output, or NDJSON responses.
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
* stream('/clock', async ({ response }) => {
|
|
469
|
+
* const timer = setInterval(() => {
|
|
470
|
+
* response.write(`data: ${new Date().toISOString()}\n\n`);
|
|
471
|
+
* }, 1000);
|
|
472
|
+
*
|
|
473
|
+
* setTimeout(() => {
|
|
474
|
+
* clearInterval(timer);
|
|
475
|
+
* response.close();
|
|
476
|
+
* }, 5000);
|
|
477
|
+
* });
|
|
478
|
+
*
|
|
479
|
+
* @param path - The route path (e.g. `/clock`)
|
|
480
|
+
* @param handler - Handler that receives the API context and response writer
|
|
481
|
+
* @param options - Optional stream configuration
|
|
482
|
+
* @returns A Route object ready to be used in `defineRouter()`
|
|
483
|
+
*/
|
|
484
|
+
declare function stream(path: string, handler: (ctx: APIContext & {
|
|
485
|
+
response: StreamWriter;
|
|
486
|
+
}) => void | Promise<void>, options?: StreamOptions): Route;
|
|
487
|
+
|
|
488
|
+
type JsonValue = any;
|
|
489
|
+
/**
|
|
490
|
+
* A writer interface for streaming JSON data to the response body.
|
|
491
|
+
* Supports both NDJSON and array formats.
|
|
492
|
+
*/
|
|
493
|
+
interface JsonStreamWriter {
|
|
494
|
+
/**
|
|
495
|
+
* Send a JSON-serializable value to the response stream.
|
|
496
|
+
* - In `ndjson` mode: appends a newline after each object.
|
|
497
|
+
* - In `array` mode: adds commas and wraps with brackets.
|
|
498
|
+
* @param value - Any serializable object or array item
|
|
499
|
+
*/
|
|
500
|
+
send: (value: JsonValue) => void;
|
|
501
|
+
/**
|
|
502
|
+
* Write raw text or bytes to the stream.
|
|
503
|
+
* Used for low-level control if needed.
|
|
504
|
+
*/
|
|
505
|
+
write: (chunk: string | Uint8Array) => void;
|
|
506
|
+
/**
|
|
507
|
+
* Close the stream. In `array` mode, it writes the closing `]`.
|
|
508
|
+
*/
|
|
509
|
+
close: () => void;
|
|
510
|
+
/**
|
|
511
|
+
* Override response headers dynamically before the response is sent.
|
|
512
|
+
* Only safe before the first write.
|
|
513
|
+
* @param key - Header name
|
|
514
|
+
* @param value - Header value
|
|
515
|
+
*/
|
|
516
|
+
setHeader: (key: string, value: string) => void;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Defines a JSON streaming route using NDJSON (Newline Delimited JSON) format.
|
|
521
|
+
*
|
|
522
|
+
* This helper streams individual JSON objects separated by newlines (`\n`)
|
|
523
|
+
* instead of a single JSON array. It sets the `Content-Type` to
|
|
524
|
+
* `application/x-ndjson` and disables buffering to allow low-latency
|
|
525
|
+
* delivery of each item.
|
|
526
|
+
*
|
|
527
|
+
* Ideal for real-time updates, event logs, progressive loading, or
|
|
528
|
+
* integrations with LLMs or dashboards where each object can be processed
|
|
529
|
+
* as soon as it's received.
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* streamJsonND('/events', async ({ response }) => {
|
|
533
|
+
* response.send({ type: 'start' });
|
|
534
|
+
* await delay(100);
|
|
535
|
+
* response.send({ type: 'progress', percent: 25 });
|
|
536
|
+
* response.close();
|
|
537
|
+
* });
|
|
538
|
+
*
|
|
539
|
+
* @param path - The route path (e.g. `/events`)
|
|
540
|
+
* @param handler - A function that receives `ctx` and a JSON stream writer
|
|
541
|
+
* @param options - Optional HTTP method override (default is GET)
|
|
542
|
+
* @returns A Route object ready to be registered with `defineRouter`
|
|
543
|
+
*/
|
|
544
|
+
declare function streamJsonND(path: string, handler: (ctx: APIContext & {
|
|
545
|
+
response: JsonStreamWriter;
|
|
546
|
+
}) => void | Promise<void>, options?: {
|
|
547
|
+
method?: HttpMethod;
|
|
548
|
+
}): Route;
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Defines a JSON streaming route that emits a valid JSON array.
|
|
552
|
+
*
|
|
553
|
+
* This helper returns a valid `application/json` response containing
|
|
554
|
+
* a streamable array of JSON values. Useful for large data exports
|
|
555
|
+
* or APIs where the full array can be streamed as it's generated.
|
|
556
|
+
*
|
|
557
|
+
* Unlike `streamJsonND()`, this wraps all values in `[` and `]`
|
|
558
|
+
* and separates them with commas.
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* streamJsonArray('/users', async ({ response }) => {
|
|
562
|
+
* response.send({ id: 1 });
|
|
563
|
+
* response.send({ id: 2 });
|
|
564
|
+
* response.close();
|
|
565
|
+
* });
|
|
566
|
+
*
|
|
567
|
+
* @param path - The route path (e.g. `/users`)
|
|
568
|
+
* @param handler - A function that receives `ctx` and a JSON stream writer
|
|
569
|
+
* @param options - Optional HTTP method override (default is GET)
|
|
570
|
+
* @returns A Route object ready to be registered with `defineRouter`
|
|
571
|
+
*/
|
|
572
|
+
declare function streamJsonArray(path: string, handler: (ctx: APIContext & {
|
|
573
|
+
response: JsonStreamWriter;
|
|
574
|
+
}) => void | Promise<void>, options?: {
|
|
575
|
+
method?: HttpMethod;
|
|
576
|
+
}): Route;
|
|
577
|
+
|
|
578
|
+
export { ALLOWED_HTTP_METHODS, HttpMethod, RouteGroup, RouteTrie, RouterBuilder, badRequest, created, defineGroup, defineHandler, defineRoute, defineRouter, fileResponse, forbidden, internalError, isReadableStream, methodNotAllowed, noContent, normalizeMethod, notFound, notModified, ok, stream, streamJsonArray, streamJsonND, toAstroResponse, unauthorized };
|
|
579
|
+
export type { Handler, JsonStreamWriter, ResultResponse, Route, RouterOptions, StreamOptions, StreamWriter };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-routify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A high-performance API router for Astro using a Trie-based matcher.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,13 +16,19 @@
|
|
|
16
16
|
],
|
|
17
17
|
"keywords": [
|
|
18
18
|
"astro",
|
|
19
|
-
"
|
|
19
|
+
"astrojs",
|
|
20
20
|
"api-router",
|
|
21
|
-
"
|
|
21
|
+
"router",
|
|
22
22
|
"routing",
|
|
23
|
-
"
|
|
23
|
+
"typescript",
|
|
24
24
|
"esm",
|
|
25
|
-
"trie"
|
|
25
|
+
"trie",
|
|
26
|
+
"streaming",
|
|
27
|
+
"sse",
|
|
28
|
+
"ndjson",
|
|
29
|
+
"json-stream",
|
|
30
|
+
"response-helpers",
|
|
31
|
+
"astro-api"
|
|
26
32
|
],
|
|
27
33
|
"author": "Alex Mora",
|
|
28
34
|
"license": "MIT",
|