astro-routify 1.0.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 +160 -36
- package/dist/core/RouterBuilder.d.ts +114 -3
- package/dist/core/RouterBuilder.js +133 -6
- package/dist/core/defineGroup.d.ts +87 -0
- package/dist/core/defineGroup.js +111 -0
- package/dist/core/defineHandler.d.ts +23 -0
- package/dist/core/defineHandler.js +40 -0
- package/dist/core/defineRoute.d.ts +32 -0
- package/dist/core/defineRoute.js +14 -1
- package/dist/core/defineRouter.d.ts +33 -1
- package/dist/core/defineRouter.js +32 -3
- package/dist/core/internal/createJsonStreamRoute.d.ts +64 -0
- package/dist/core/internal/createJsonStreamRoute.js +92 -0
- package/dist/core/responseHelpers.d.ts +63 -1
- package/dist/core/responseHelpers.js +68 -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 +512 -6
- package/dist/index.js +4 -0
- package/package.json +13 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as astro from 'astro';
|
|
2
2
|
import { APIContext, APIRoute } from 'astro';
|
|
3
|
-
import { HeadersInit } from 'undici';
|
|
3
|
+
import { HeadersInit, BodyInit } from 'undici';
|
|
4
4
|
|
|
5
5
|
declare enum HttpMethod {
|
|
6
6
|
GET = "GET",
|
|
@@ -16,40 +16,275 @@ 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
|
+
*/
|
|
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
|
+
*/
|
|
34
96
|
declare function toAstroResponse(result: ResultResponse | undefined): Response;
|
|
35
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
|
+
*/
|
|
36
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
|
+
*/
|
|
37
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
|
+
*/
|
|
122
|
+
declare function isReadableStream(value: unknown): value is ReadableStream<Uint8Array>;
|
|
38
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Represents a single route definition.
|
|
126
|
+
*/
|
|
39
127
|
interface Route {
|
|
128
|
+
/**
|
|
129
|
+
* HTTP method to match (GET, POST, PUT, etc.).
|
|
130
|
+
*/
|
|
40
131
|
method: HttpMethod;
|
|
132
|
+
/**
|
|
133
|
+
* Path pattern, starting with `/`, supporting static or param segments (e.g., `/users/:id`).
|
|
134
|
+
*/
|
|
41
135
|
path: string;
|
|
136
|
+
/**
|
|
137
|
+
* The function that handles the request when matched.
|
|
138
|
+
*/
|
|
42
139
|
handler: Handler;
|
|
43
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
|
+
*/
|
|
44
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
|
+
*/
|
|
45
162
|
declare function defineRoute(method: HttpMethod, path: string, handler: Handler): Route;
|
|
46
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Optional configuration for the router instance.
|
|
166
|
+
*/
|
|
47
167
|
interface RouterOptions {
|
|
48
|
-
/**
|
|
168
|
+
/**
|
|
169
|
+
* A base path to strip from the incoming request path (default: `/api`).
|
|
170
|
+
* Only routes beneath this prefix will be matched.
|
|
171
|
+
*/
|
|
172
|
+
basePath?: string;
|
|
173
|
+
/**
|
|
174
|
+
* Custom handler to return when no route is matched (404).
|
|
175
|
+
*/
|
|
49
176
|
onNotFound?: () => ReturnType<typeof notFound>;
|
|
50
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
|
+
*/
|
|
51
200
|
declare function defineRouter(routes: Route[], options?: RouterOptions): APIRoute;
|
|
52
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Represents a group of routes under a shared base path.
|
|
204
|
+
*
|
|
205
|
+
* Use this class to organize related endpoints, applying a consistent prefix
|
|
206
|
+
* and reducing duplication when defining similar routes.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* const users = new RouteGroup('/users')
|
|
210
|
+
* .addGet('/:id', handler)
|
|
211
|
+
* .addPost('/', createUser);
|
|
212
|
+
*/
|
|
213
|
+
declare class RouteGroup {
|
|
214
|
+
private basePath;
|
|
215
|
+
private routes;
|
|
216
|
+
/**
|
|
217
|
+
* Creates a new route group with the specified base path.
|
|
218
|
+
* Trailing slashes are automatically removed.
|
|
219
|
+
*
|
|
220
|
+
* @param basePath - The common prefix for all routes in the group (e.g. "/users")
|
|
221
|
+
*/
|
|
222
|
+
constructor(basePath: string);
|
|
223
|
+
/**
|
|
224
|
+
* Returns the normalized base path used by the group.
|
|
225
|
+
*/
|
|
226
|
+
getBasePath(): string;
|
|
227
|
+
/**
|
|
228
|
+
* Registers a GET route under the group's base path.
|
|
229
|
+
*
|
|
230
|
+
* @param path - Path relative to the base path (e.g. "/:id")
|
|
231
|
+
* @param handler - The handler function for this route
|
|
232
|
+
*/
|
|
233
|
+
addGet(path: string, handler: Handler): this;
|
|
234
|
+
/**
|
|
235
|
+
* Registers a POST route under the group's base path.
|
|
236
|
+
*
|
|
237
|
+
* @param path - Path relative to the base path
|
|
238
|
+
* @param handler - The handler function for this route
|
|
239
|
+
*/
|
|
240
|
+
addPost(path: string, handler: Handler): this;
|
|
241
|
+
/**
|
|
242
|
+
* Registers a PUT route under the group's base path.
|
|
243
|
+
*
|
|
244
|
+
* @param path - Path relative to the base path
|
|
245
|
+
* @param handler - The handler function for this route
|
|
246
|
+
*/
|
|
247
|
+
addPut(path: string, handler: Handler): this;
|
|
248
|
+
/**
|
|
249
|
+
* Registers a DELETE route under the group's base path.
|
|
250
|
+
*
|
|
251
|
+
* @param path - Path relative to the base path
|
|
252
|
+
* @param handler - The handler function for this route
|
|
253
|
+
*/
|
|
254
|
+
addDelete(path: string, handler: Handler): this;
|
|
255
|
+
/**
|
|
256
|
+
* Registers a PATCH route under the group's base path.
|
|
257
|
+
*
|
|
258
|
+
* @param path - Path relative to the base path
|
|
259
|
+
* @param handler - The handler function for this route
|
|
260
|
+
*/
|
|
261
|
+
addPatch(path: string, handler: Handler): this;
|
|
262
|
+
/**
|
|
263
|
+
* Internal method to register a route under the group with any HTTP method.
|
|
264
|
+
*
|
|
265
|
+
* @param method - HTTP verb
|
|
266
|
+
* @param subPath - Route path relative to the base
|
|
267
|
+
* @param handler - The handler function for this route
|
|
268
|
+
*/
|
|
269
|
+
private add;
|
|
270
|
+
/**
|
|
271
|
+
* Returns all the registered routes in the group.
|
|
272
|
+
*/
|
|
273
|
+
getRoutes(): Route[];
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Helper to define a `RouteGroup` with optional inline configuration.
|
|
277
|
+
*
|
|
278
|
+
* @param basePath - The base path prefix for all routes
|
|
279
|
+
* @param configure - Optional callback to configure the group inline
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* const users = defineGroup('/users', (group) => {
|
|
283
|
+
* group.addGet('/:id', handler);
|
|
284
|
+
* });
|
|
285
|
+
*/
|
|
286
|
+
declare function defineGroup(basePath: string, configure?: (group: RouteGroup) => void): RouteGroup;
|
|
287
|
+
|
|
53
288
|
interface RouteMatch {
|
|
54
289
|
handler: Handler | null;
|
|
55
290
|
allowed?: HttpMethod[];
|
|
@@ -62,12 +297,283 @@ declare class RouteTrie {
|
|
|
62
297
|
private segmentize;
|
|
63
298
|
}
|
|
64
299
|
|
|
300
|
+
/**
|
|
301
|
+
* A fluent builder for creating and composing API routes in Astro.
|
|
302
|
+
*
|
|
303
|
+
* `RouterBuilder` supports both simple method-based additions (`addGet`, `addPost`, etc.)
|
|
304
|
+
* and organized groups via `defineGroup()` + `addGroup()` for scalable applications.
|
|
305
|
+
*
|
|
306
|
+
* @example Basic usage:
|
|
307
|
+
* ```ts
|
|
308
|
+
* const router = new RouterBuilder()
|
|
309
|
+
* .addGet('/ping', () => ok('pong'))
|
|
310
|
+
* .addPost('/submit', handler);
|
|
311
|
+
*
|
|
312
|
+
* export const ALL = router.build();
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* @example Using groups:
|
|
316
|
+
* ```ts
|
|
317
|
+
* const users = defineGroup('/users')
|
|
318
|
+
* .addGet('/:id', userHandler);
|
|
319
|
+
*
|
|
320
|
+
* const router = new RouterBuilder({ basePath: '/api' })
|
|
321
|
+
* .addGroup(users);
|
|
322
|
+
*
|
|
323
|
+
* export const GET = router.build();
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
65
326
|
declare class RouterBuilder {
|
|
66
|
-
private
|
|
327
|
+
private _options;
|
|
328
|
+
private _routes;
|
|
329
|
+
private static _registerWarned;
|
|
330
|
+
constructor(options?: RouterOptions);
|
|
331
|
+
/**
|
|
332
|
+
* @deprecated Prefer `addGroup()` or `addRoute()` for structured routing.
|
|
333
|
+
*
|
|
334
|
+
* Registers a single route manually.
|
|
335
|
+
*
|
|
336
|
+
* This method is deprecated in favor of a more scalable and organized approach using
|
|
337
|
+
* `defineGroup()` + `addGroup()` or `addRoute()` for ad-hoc additions.
|
|
338
|
+
*
|
|
339
|
+
* @param route A single `Route` object to register.
|
|
340
|
+
*/
|
|
67
341
|
register(route: Route): void;
|
|
342
|
+
/**
|
|
343
|
+
* @deprecated Prefer `addGroup()` or `addRoute()` for structured routing.
|
|
344
|
+
*
|
|
345
|
+
* Registers multiple routes at once.
|
|
346
|
+
*
|
|
347
|
+
* This method is deprecated and discouraged for larger codebases in favor of group-based composition.
|
|
348
|
+
*
|
|
349
|
+
* @param routes An array of `Route` objects to register.
|
|
350
|
+
*/
|
|
68
351
|
register(routes: Route[]): void;
|
|
69
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Adds a single route to the router.
|
|
354
|
+
*
|
|
355
|
+
* @param route The route to add.
|
|
356
|
+
* @returns The current builder instance (for chaining).
|
|
357
|
+
*/
|
|
358
|
+
addRoute(route: Route): this;
|
|
359
|
+
/**
|
|
360
|
+
* Adds a group of pre-defined routes (from `defineGroup()`).
|
|
361
|
+
*
|
|
362
|
+
* @param group A `RouteGroup` instance.
|
|
363
|
+
* @returns The current builder instance (for chaining).
|
|
364
|
+
*/
|
|
365
|
+
addGroup(group: RouteGroup): this;
|
|
366
|
+
/**
|
|
367
|
+
* Adds a GET route.
|
|
368
|
+
* @param path Route path (e.g., `/items/:id`)
|
|
369
|
+
* @param handler Request handler function.
|
|
370
|
+
*/
|
|
371
|
+
addGet(path: string, handler: Handler): this;
|
|
372
|
+
/**
|
|
373
|
+
* Adds a POST route.
|
|
374
|
+
* @param path Route path.
|
|
375
|
+
* @param handler Request handler function.
|
|
376
|
+
*/
|
|
377
|
+
addPost(path: string, handler: Handler): this;
|
|
378
|
+
/**
|
|
379
|
+
* Adds a PUT route.
|
|
380
|
+
* @param path Route path.
|
|
381
|
+
* @param handler Request handler function.
|
|
382
|
+
*/
|
|
383
|
+
addPut(path: string, handler: Handler): this;
|
|
384
|
+
/**
|
|
385
|
+
* Adds a DELETE route.
|
|
386
|
+
* @param path Route path.
|
|
387
|
+
* @param handler Request handler function.
|
|
388
|
+
*/
|
|
389
|
+
addDelete(path: string, handler: Handler): this;
|
|
390
|
+
/**
|
|
391
|
+
* Adds a PATCH route.
|
|
392
|
+
* @param path Route path.
|
|
393
|
+
* @param handler Request handler function.
|
|
394
|
+
*/
|
|
395
|
+
addPatch(path: string, handler: Handler): this;
|
|
396
|
+
/**
|
|
397
|
+
* Internal helper to add a route with any HTTP method.
|
|
398
|
+
*
|
|
399
|
+
* @param method The HTTP method.
|
|
400
|
+
* @param subPath Path segment (can be relative or absolute).
|
|
401
|
+
* @param handler Request handler.
|
|
402
|
+
* @returns The current builder instance (for chaining).
|
|
403
|
+
*/
|
|
404
|
+
private add;
|
|
405
|
+
/**
|
|
406
|
+
* Finalizes the router and returns an Astro-compatible route handler.
|
|
407
|
+
*
|
|
408
|
+
* This function should be used to export a method like `GET`, `POST`, or `ALL`
|
|
409
|
+
* inside Astro API endpoints.
|
|
410
|
+
*
|
|
411
|
+
* @returns A fully resolved Astro route handler.
|
|
412
|
+
*/
|
|
413
|
+
build(): astro.APIRoute;
|
|
414
|
+
}
|
|
415
|
+
|
|
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;
|
|
70
517
|
}
|
|
71
518
|
|
|
72
|
-
|
|
73
|
-
|
|
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
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export * from './core/defineRoute';
|
|
2
2
|
export * from './core/defineRouter';
|
|
3
3
|
export * from './core/defineHandler';
|
|
4
|
+
export * from './core/defineGroup';
|
|
4
5
|
export * from './core/RouteTrie';
|
|
5
6
|
export * from './core/HttpMethod';
|
|
6
7
|
export * from './core/responseHelpers';
|
|
7
8
|
export * from './core/RouterBuilder';
|
|
9
|
+
export * from './core/stream';
|
|
10
|
+
export * from './core/streamJsonND';
|
|
11
|
+
export * from './core/streamJsonArray';
|
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",
|
|
@@ -31,10 +37,10 @@
|
|
|
31
37
|
},
|
|
32
38
|
"devDependencies": {
|
|
33
39
|
"rimraf": "^6.0.1",
|
|
34
|
-
"rollup": "^4.
|
|
40
|
+
"rollup": "^4.46.2",
|
|
35
41
|
"rollup-plugin-dts": "^6.2.1",
|
|
36
42
|
"typescript": "^5.3.3",
|
|
37
|
-
"undici": "^7.
|
|
43
|
+
"undici": "^7.13.0",
|
|
38
44
|
"vitest": "^3.2.4"
|
|
39
45
|
},
|
|
40
46
|
"engines": {
|