@server/next 0.40.4 → 0.41.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/index.d.ts +141 -88
- package/index.js +102 -56
- package/package.json +5 -2
package/index.d.ts
CHANGED
|
@@ -41,10 +41,14 @@ declare const redirect: (...args: Params<"redirect">) => Response;
|
|
|
41
41
|
|
|
42
42
|
type Reply = ReturnType<typeof status>;
|
|
43
43
|
type Method = "get" | "post" | "put" | "patch" | "delete" | "head" | "options" | "socket";
|
|
44
|
-
type
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
type ContextTypes = {
|
|
45
|
+
session?: any;
|
|
46
|
+
user?: any;
|
|
47
|
+
params?: any;
|
|
48
|
+
query?: any;
|
|
49
|
+
body?: any;
|
|
47
50
|
};
|
|
51
|
+
type Field<C, K extends keyof ContextTypes, Fallback> = K extends keyof C ? SchemaOutput<C[K], C[K]> : Fallback;
|
|
48
52
|
declare namespace JSX {
|
|
49
53
|
interface Element {
|
|
50
54
|
type: any;
|
|
@@ -55,16 +59,49 @@ declare namespace JSX {
|
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
61
|
type BodyMode = "parse" | "raw" | "stream";
|
|
58
|
-
type
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
type StandardIssue = {
|
|
63
|
+
readonly message: string;
|
|
64
|
+
readonly path?: readonly (PropertyKey | {
|
|
65
|
+
readonly key: PropertyKey;
|
|
66
|
+
})[];
|
|
61
67
|
};
|
|
68
|
+
interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
69
|
+
readonly "~standard": {
|
|
70
|
+
readonly version: 1;
|
|
71
|
+
readonly vendor: string;
|
|
72
|
+
readonly validate: (value: unknown) => {
|
|
73
|
+
value: Output;
|
|
74
|
+
issues?: undefined;
|
|
75
|
+
} | {
|
|
76
|
+
issues: readonly StandardIssue[];
|
|
77
|
+
} | Promise<{
|
|
78
|
+
value: Output;
|
|
79
|
+
issues?: undefined;
|
|
80
|
+
} | {
|
|
81
|
+
issues: readonly StandardIssue[];
|
|
82
|
+
}>;
|
|
83
|
+
readonly types?: {
|
|
84
|
+
readonly input: Input;
|
|
85
|
+
readonly output: Output;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
type SchemaOutput<S, Fallback> = [S] extends [
|
|
90
|
+
StandardSchemaV1<any, infer Output>
|
|
91
|
+
] ? Output : Fallback;
|
|
62
92
|
type CacheOption = string | number | false;
|
|
63
|
-
type
|
|
93
|
+
type RouteSchema = {
|
|
64
94
|
tags?: string | string[];
|
|
65
95
|
title?: string;
|
|
66
96
|
description?: string;
|
|
67
|
-
|
|
97
|
+
};
|
|
98
|
+
type RouteOptions = {
|
|
99
|
+
schema?: RouteSchema;
|
|
100
|
+
parser?: BodyMode;
|
|
101
|
+
body?: StandardSchemaV1<any, any>;
|
|
102
|
+
query?: StandardSchemaV1<any, any>;
|
|
103
|
+
params?: StandardSchemaV1<any, any>;
|
|
104
|
+
response?: StandardSchemaV1<any, any>;
|
|
68
105
|
cache?: CacheOption;
|
|
69
106
|
};
|
|
70
107
|
type Route = {
|
|
@@ -197,6 +234,7 @@ type SecurityOptions = {
|
|
|
197
234
|
hsts?: boolean | string;
|
|
198
235
|
xssProtection?: boolean;
|
|
199
236
|
traversalProtection?: boolean;
|
|
237
|
+
maxBody?: number | string | false;
|
|
200
238
|
csp?: boolean | string;
|
|
201
239
|
coop?: boolean | string;
|
|
202
240
|
corp?: boolean | string;
|
|
@@ -205,6 +243,7 @@ type SecurityOptions = {
|
|
|
205
243
|
type SecuritySettings = {
|
|
206
244
|
trustProxy: boolean;
|
|
207
245
|
traversalProtection: boolean;
|
|
246
|
+
maxBody: number;
|
|
208
247
|
headers: Record<string, string>;
|
|
209
248
|
hsts: string | null;
|
|
210
249
|
};
|
|
@@ -227,7 +266,7 @@ type Options = {
|
|
|
227
266
|
log?: LogLevel | boolean;
|
|
228
267
|
favicon?: string | BucketFile;
|
|
229
268
|
security?: boolean | SecurityOptions;
|
|
230
|
-
|
|
269
|
+
parser?: BodyMode;
|
|
231
270
|
cache?: CacheOption;
|
|
232
271
|
};
|
|
233
272
|
type Settings = {
|
|
@@ -249,7 +288,7 @@ type Settings = {
|
|
|
249
288
|
log: Logger;
|
|
250
289
|
favicon?: string | BucketFile;
|
|
251
290
|
security: SecuritySettings;
|
|
252
|
-
|
|
291
|
+
parser: BodyMode;
|
|
253
292
|
cache?: CacheOption;
|
|
254
293
|
};
|
|
255
294
|
type Time = {
|
|
@@ -280,27 +319,23 @@ type BunEnv = Record<string, string> & {
|
|
|
280
319
|
};
|
|
281
320
|
interface ContextExtension {
|
|
282
321
|
}
|
|
283
|
-
type Context<
|
|
322
|
+
type Context<C extends ContextTypes = {}> = {
|
|
284
323
|
method: Method;
|
|
285
324
|
ip: string;
|
|
286
325
|
headers: Record<string, string | string[]>;
|
|
287
326
|
cookies: Record<string, string>;
|
|
288
|
-
body?: SerializableValue | Buffer | ReadableStream
|
|
327
|
+
body?: Field<C, "body", SerializableValue | Buffer | ReadableStream>;
|
|
289
328
|
url: URL & {
|
|
290
|
-
params:
|
|
291
|
-
query: Record<string,
|
|
329
|
+
params: Field<C, "params", Record<string, any>>;
|
|
330
|
+
query: Field<C, "query", Record<string, any>>;
|
|
292
331
|
};
|
|
293
332
|
options: Settings;
|
|
294
333
|
platform: Platform;
|
|
295
334
|
time?: Time;
|
|
296
335
|
socket?: WebSocket;
|
|
297
336
|
sockets?: WebSocket[];
|
|
298
|
-
session:
|
|
299
|
-
|
|
300
|
-
} ? S extends Record<"Session", infer Inner> ? Inner : Record<string, any> : Record<string, any>;
|
|
301
|
-
user?: O extends {
|
|
302
|
-
User?: infer U;
|
|
303
|
-
} ? U extends Record<"User", infer Inner> ? Inner : AuthUser : AuthUser;
|
|
337
|
+
session: Field<C, "session", Record<string, any>>;
|
|
338
|
+
user?: Field<C, "user", Record<string, any>>;
|
|
304
339
|
init: number;
|
|
305
340
|
req?: Request;
|
|
306
341
|
res?: Response & {
|
|
@@ -313,7 +348,7 @@ type InlineReply = Response | Reply | BucketFile | {
|
|
|
313
348
|
headers?: Headers;
|
|
314
349
|
} | SerializableValue | JSX.Element | Buffer | ReadableStream;
|
|
315
350
|
type Body = InlineReply;
|
|
316
|
-
type Middleware<
|
|
351
|
+
type Middleware<C extends ContextTypes = {}> = (ctx: Context<C>) => InlineReply | Promise<InlineReply> | void | Promise<void>;
|
|
317
352
|
|
|
318
353
|
type Variables = Record<string, string | string[]>;
|
|
319
354
|
type ExtendError = string | {
|
|
@@ -336,50 +371,68 @@ declare global {
|
|
|
336
371
|
var env: Record<string, any>;
|
|
337
372
|
}
|
|
338
373
|
|
|
339
|
-
type
|
|
340
|
-
|
|
374
|
+
type Fn<C extends ContextTypes> = (ctx: Context<C>) => ReturnType<Middleware>;
|
|
375
|
+
type RouteCtx<C extends ContextTypes, RO extends RouteOptions, Params> = Omit<C, "params" | "query" | "body"> & {
|
|
376
|
+
params: [RO["params"]] extends [StandardSchemaV1<any, any>] ? RO["params"] : Params;
|
|
377
|
+
} & Pick<RO, keyof RO & ("query" | "body")>;
|
|
378
|
+
type Mids<C extends ContextTypes, Path extends string, RO extends RouteOptions = {}> = Fn<RouteCtx<C, RO, PathToParams<Path>>>[];
|
|
379
|
+
type Exact<RO> = RouteOptions & {
|
|
380
|
+
[K in Exclude<keyof RO, keyof RouteOptions>]: never;
|
|
381
|
+
};
|
|
382
|
+
declare class Router<C extends ContextTypes = {}> {
|
|
341
383
|
middleware: Middleware[];
|
|
342
384
|
handlers: Record<Method, Route[]>;
|
|
343
385
|
self(): this;
|
|
344
386
|
handle(method: Method, pathOrFn?: any, ...rest: any[]): this;
|
|
345
|
-
socket<Path extends string>(path: Path, ...middleware: Mids<
|
|
346
|
-
socket
|
|
347
|
-
socket(...middleware:
|
|
348
|
-
socket(options:
|
|
349
|
-
get<Path extends string>(path: Path, ...middleware: Mids<
|
|
350
|
-
get
|
|
351
|
-
get(...middleware:
|
|
352
|
-
get(options:
|
|
353
|
-
head<Path extends string>(path: Path, ...middleware: Mids<
|
|
354
|
-
head
|
|
355
|
-
head(...middleware:
|
|
356
|
-
head(options:
|
|
357
|
-
post<Path extends string>(path: Path, ...middleware: Mids<
|
|
358
|
-
post
|
|
359
|
-
post(...middleware:
|
|
360
|
-
post(options:
|
|
361
|
-
put<Path extends string>(path: Path, ...middleware: Mids<
|
|
362
|
-
put
|
|
363
|
-
put(...middleware:
|
|
364
|
-
put(options:
|
|
365
|
-
patch<Path extends string>(path: Path, ...middleware: Mids<
|
|
366
|
-
patch
|
|
367
|
-
patch(...middleware:
|
|
368
|
-
patch(options:
|
|
369
|
-
delete<Path extends string>(path: Path, ...middleware: Mids<
|
|
370
|
-
delete
|
|
371
|
-
delete(...middleware:
|
|
372
|
-
delete(options:
|
|
373
|
-
options<Path extends string>(path: Path, ...middleware: Mids<
|
|
374
|
-
options
|
|
375
|
-
options(...middleware:
|
|
376
|
-
options(options:
|
|
377
|
-
use(...middleware:
|
|
378
|
-
use(router: Router): this;
|
|
387
|
+
socket<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
388
|
+
socket(...middleware: Fn<C>[]): this;
|
|
389
|
+
socket<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
390
|
+
socket<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
391
|
+
get<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
392
|
+
get(...middleware: Fn<C>[]): this;
|
|
393
|
+
get<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
394
|
+
get<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
395
|
+
head<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
396
|
+
head(...middleware: Fn<C>[]): this;
|
|
397
|
+
head<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
398
|
+
head<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
399
|
+
post<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
400
|
+
post(...middleware: Fn<C>[]): this;
|
|
401
|
+
post<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
402
|
+
post<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
403
|
+
put<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
404
|
+
put(...middleware: Fn<C>[]): this;
|
|
405
|
+
put<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
406
|
+
put<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
407
|
+
patch<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
408
|
+
patch(...middleware: Fn<C>[]): this;
|
|
409
|
+
patch<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
410
|
+
patch<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
411
|
+
delete<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
412
|
+
delete(...middleware: Fn<C>[]): this;
|
|
413
|
+
delete<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
414
|
+
delete<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...middleware: Mids<C, Path, RO>): this;
|
|
415
|
+
options<Path extends string>(path: Path, ...middleware: Mids<C, Path>): this;
|
|
416
|
+
options(...middleware: Fn<C>[]): this;
|
|
417
|
+
options<RO extends Exact<RO>>(options: RO, ...middleware: Fn<RouteCtx<C, RO, Record<string, string>>>[]): this;
|
|
418
|
+
options<Path extends string, RO extends Exact<RO>>(path: Path, options: RO, ...mid: Mids<C, Path, RO>): this;
|
|
419
|
+
use(...middleware: Fn<C>[]): this;
|
|
420
|
+
use(router: Router<any>): this;
|
|
421
|
+
}
|
|
422
|
+
declare function router<C extends ContextTypes = {}>(): Router<C>;
|
|
423
|
+
|
|
424
|
+
declare class StatusError extends Error {
|
|
425
|
+
status: number;
|
|
426
|
+
constructor(msg: string, status?: number);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
declare class ValidationError extends StatusError {
|
|
430
|
+
source: "body" | "query" | "params" | "response";
|
|
431
|
+
issues: readonly StandardIssue[];
|
|
432
|
+
constructor(source: "body" | "query" | "params" | "response", issues: readonly StandardIssue[]);
|
|
379
433
|
}
|
|
380
|
-
declare function router(): Router;
|
|
381
434
|
|
|
382
|
-
declare class Server<
|
|
435
|
+
declare class Server<C extends ContextTypes = {}> extends Router<C> {
|
|
383
436
|
settings: Settings;
|
|
384
437
|
platform: Platform;
|
|
385
438
|
sockets: any[];
|
|
@@ -397,111 +450,111 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
397
450
|
callback(request: Request, context: unknown): Promise<Response>;
|
|
398
451
|
test(): {
|
|
399
452
|
get: (path: string, options?: {
|
|
453
|
+
method?: string;
|
|
454
|
+
headers?: HeadersInit;
|
|
400
455
|
cache?: RequestCache;
|
|
456
|
+
redirect?: RequestRedirect;
|
|
401
457
|
credentials?: RequestCredentials;
|
|
402
|
-
headers?: HeadersInit;
|
|
403
458
|
integrity?: string;
|
|
404
459
|
keepalive?: boolean;
|
|
405
|
-
method?: string;
|
|
406
460
|
mode?: RequestMode;
|
|
407
461
|
priority?: RequestPriority;
|
|
408
|
-
redirect?: RequestRedirect;
|
|
409
462
|
referrer?: string;
|
|
410
463
|
referrerPolicy?: ReferrerPolicy;
|
|
411
464
|
signal?: AbortSignal | null;
|
|
412
465
|
window?: null;
|
|
413
466
|
}) => Promise<Response>;
|
|
414
467
|
head: (path: string, options?: {
|
|
468
|
+
method?: string;
|
|
469
|
+
headers?: HeadersInit;
|
|
415
470
|
cache?: RequestCache;
|
|
471
|
+
redirect?: RequestRedirect;
|
|
416
472
|
credentials?: RequestCredentials;
|
|
417
|
-
headers?: HeadersInit;
|
|
418
473
|
integrity?: string;
|
|
419
474
|
keepalive?: boolean;
|
|
420
|
-
method?: string;
|
|
421
475
|
mode?: RequestMode;
|
|
422
476
|
priority?: RequestPriority;
|
|
423
|
-
redirect?: RequestRedirect;
|
|
424
477
|
referrer?: string;
|
|
425
478
|
referrerPolicy?: ReferrerPolicy;
|
|
426
479
|
signal?: AbortSignal | null;
|
|
427
480
|
window?: null;
|
|
428
481
|
}) => Promise<Response>;
|
|
429
|
-
post: (path: string, body?: string | number | boolean | ArrayBuffer |
|
|
482
|
+
post: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
430
483
|
[key: string]: SerializableValue;
|
|
431
|
-
} | SerializableValue[], options?: {
|
|
484
|
+
} | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
|
|
485
|
+
method?: string;
|
|
486
|
+
headers?: HeadersInit;
|
|
432
487
|
cache?: RequestCache;
|
|
488
|
+
redirect?: RequestRedirect;
|
|
433
489
|
credentials?: RequestCredentials;
|
|
434
|
-
headers?: HeadersInit;
|
|
435
490
|
integrity?: string;
|
|
436
491
|
keepalive?: boolean;
|
|
437
|
-
method?: string;
|
|
438
492
|
mode?: RequestMode;
|
|
439
493
|
priority?: RequestPriority;
|
|
440
|
-
redirect?: RequestRedirect;
|
|
441
494
|
referrer?: string;
|
|
442
495
|
referrerPolicy?: ReferrerPolicy;
|
|
443
496
|
signal?: AbortSignal | null;
|
|
444
497
|
window?: null;
|
|
445
498
|
}) => Promise<Response>;
|
|
446
|
-
put: (path: string, body?: string | number | boolean | ArrayBuffer |
|
|
499
|
+
put: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
447
500
|
[key: string]: SerializableValue;
|
|
448
|
-
} | SerializableValue[], options?: {
|
|
501
|
+
} | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
|
|
502
|
+
method?: string;
|
|
503
|
+
headers?: HeadersInit;
|
|
449
504
|
cache?: RequestCache;
|
|
505
|
+
redirect?: RequestRedirect;
|
|
450
506
|
credentials?: RequestCredentials;
|
|
451
|
-
headers?: HeadersInit;
|
|
452
507
|
integrity?: string;
|
|
453
508
|
keepalive?: boolean;
|
|
454
|
-
method?: string;
|
|
455
509
|
mode?: RequestMode;
|
|
456
510
|
priority?: RequestPriority;
|
|
457
|
-
redirect?: RequestRedirect;
|
|
458
511
|
referrer?: string;
|
|
459
512
|
referrerPolicy?: ReferrerPolicy;
|
|
460
513
|
signal?: AbortSignal | null;
|
|
461
514
|
window?: null;
|
|
462
515
|
}) => Promise<Response>;
|
|
463
|
-
patch: (path: string, body?: string | number | boolean | ArrayBuffer |
|
|
516
|
+
patch: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
464
517
|
[key: string]: SerializableValue;
|
|
465
|
-
} | SerializableValue[], options?: {
|
|
518
|
+
} | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
|
|
519
|
+
method?: string;
|
|
520
|
+
headers?: HeadersInit;
|
|
466
521
|
cache?: RequestCache;
|
|
522
|
+
redirect?: RequestRedirect;
|
|
467
523
|
credentials?: RequestCredentials;
|
|
468
|
-
headers?: HeadersInit;
|
|
469
524
|
integrity?: string;
|
|
470
525
|
keepalive?: boolean;
|
|
471
|
-
method?: string;
|
|
472
526
|
mode?: RequestMode;
|
|
473
527
|
priority?: RequestPriority;
|
|
474
|
-
redirect?: RequestRedirect;
|
|
475
528
|
referrer?: string;
|
|
476
529
|
referrerPolicy?: ReferrerPolicy;
|
|
477
530
|
signal?: AbortSignal | null;
|
|
478
531
|
window?: null;
|
|
479
532
|
}) => Promise<Response>;
|
|
480
533
|
delete: (path: string, options?: {
|
|
534
|
+
method?: string;
|
|
535
|
+
headers?: HeadersInit;
|
|
481
536
|
cache?: RequestCache;
|
|
537
|
+
redirect?: RequestRedirect;
|
|
482
538
|
credentials?: RequestCredentials;
|
|
483
|
-
headers?: HeadersInit;
|
|
484
539
|
integrity?: string;
|
|
485
540
|
keepalive?: boolean;
|
|
486
|
-
method?: string;
|
|
487
541
|
mode?: RequestMode;
|
|
488
542
|
priority?: RequestPriority;
|
|
489
|
-
redirect?: RequestRedirect;
|
|
490
543
|
referrer?: string;
|
|
491
544
|
referrerPolicy?: ReferrerPolicy;
|
|
492
545
|
signal?: AbortSignal | null;
|
|
493
546
|
window?: null;
|
|
494
547
|
}) => Promise<Response>;
|
|
495
548
|
options: (path: string, options?: {
|
|
549
|
+
method?: string;
|
|
550
|
+
headers?: HeadersInit;
|
|
496
551
|
cache?: RequestCache;
|
|
552
|
+
redirect?: RequestRedirect;
|
|
497
553
|
credentials?: RequestCredentials;
|
|
498
|
-
headers?: HeadersInit;
|
|
499
554
|
integrity?: string;
|
|
500
555
|
keepalive?: boolean;
|
|
501
|
-
method?: string;
|
|
502
556
|
mode?: RequestMode;
|
|
503
557
|
priority?: RequestPriority;
|
|
504
|
-
redirect?: RequestRedirect;
|
|
505
558
|
referrer?: string;
|
|
506
559
|
referrerPolicy?: ReferrerPolicy;
|
|
507
560
|
signal?: AbortSignal | null;
|
|
@@ -509,6 +562,6 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
509
562
|
}) => Promise<Response>;
|
|
510
563
|
};
|
|
511
564
|
}
|
|
512
|
-
declare function server<
|
|
565
|
+
declare function server<C extends ContextTypes = {}>(options?: Options): Server<C>;
|
|
513
566
|
|
|
514
|
-
export { type AuthOption, type AuthSession, type AuthSettings, type AuthUser, type BasicValue, type Body, type BodyMode, type
|
|
567
|
+
export { type AuthOption, type AuthSession, type AuthSettings, type AuthUser, type BasicValue, type Body, type BodyMode, type Bucket, type BucketFile, type BunEnv, type CacheOption, type Context, type ContextExtension, type ContextTypes, type Cookie, type CorsSettings, type ExtractPathParams, type FileInfo, type InferParamType, type InlineReply, type KVStore, type LogLevel, type Logger, type Method, type Middleware, type Options, type ParamTypeMap, type ParamsToObject, type PathToParams, type Platform, type ProfileUser, type Provider, type Route, type RouteOptions, type RouteSchema, type RouterMethod, type SchemaOutput, type SecurityOptions, type SecuritySettings, type SerializableValue, Server, TypedServerError as ServerError, type Settings, type StandardIssue, type StandardSchemaV1, type StoreSource, type Strategy, type Time, type UploadOptions, type UploadedFile, ValidationError, cache, cookies, server as default, download, file, headers, json, redirect, router, send, status, type };
|
package/index.js
CHANGED
|
@@ -220,7 +220,7 @@ function human(bytes) {
|
|
|
220
220
|
return `${rounded}${UNITS[i]}`;
|
|
221
221
|
}
|
|
222
222
|
var tooLarge = (max) => new StatusError(
|
|
223
|
-
`Request body exceeds the ${human(max)} limit. Raise it with
|
|
223
|
+
`Request body exceeds the ${human(max)} limit. Raise it with security: { maxBody: '10mb' }, or maxBody: false to disable it.`,
|
|
224
224
|
413
|
|
225
225
|
);
|
|
226
226
|
|
|
@@ -577,11 +577,9 @@ var sources = /* @__PURE__ */ new WeakMap();
|
|
|
577
577
|
function setBodySource(ctx, source) {
|
|
578
578
|
sources.set(ctx, source);
|
|
579
579
|
}
|
|
580
|
-
async function resolveBody(ctx,
|
|
580
|
+
async function resolveBody(ctx, mode = "parse", max = resolveMax(void 0)) {
|
|
581
581
|
const source = sources.get(ctx);
|
|
582
582
|
if (!source) return void 0;
|
|
583
|
-
const mode = typeof body === "string" ? body : body?.mode ?? "parse";
|
|
584
|
-
const max = resolveMax(typeof body === "object" ? body?.max : void 0);
|
|
585
583
|
const contentType = String(ctx.headers["content-type"] || "");
|
|
586
584
|
const isMultipart = /multipart\/form-data/i.test(contentType);
|
|
587
585
|
const declared = Number(ctx.headers["content-length"]);
|
|
@@ -1631,6 +1629,9 @@ function resolveSecurity(security) {
|
|
|
1631
1629
|
return {
|
|
1632
1630
|
trustProxy: o.trustProxy ?? true,
|
|
1633
1631
|
traversalProtection: off ? false : o.traversalProtection !== false,
|
|
1632
|
+
// Cap on the bytes buffered per request (see bodyLimit). `false` (or
|
|
1633
|
+
// turning security off entirely) resolves to Infinity, meaning no limit.
|
|
1634
|
+
maxBody: off ? INF : resolveMax(o.maxBody),
|
|
1634
1635
|
headers: headers2,
|
|
1635
1636
|
hsts: off ? null : val(o.hsts, "max-age=15552000; includeSubDomains")
|
|
1636
1637
|
};
|
|
@@ -1661,6 +1662,19 @@ function applySecurity(res, ctx) {
|
|
|
1661
1662
|
// src/helpers/config.ts
|
|
1662
1663
|
function config(options = {}) {
|
|
1663
1664
|
const env2 = globalThis.env;
|
|
1665
|
+
const opts = options;
|
|
1666
|
+
if (typeof opts.body === "string") {
|
|
1667
|
+
throw new Error(
|
|
1668
|
+
`The root \`body: '${opts.body}'\` option is now \`parser: '${opts.body}'\`.`
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
for (const key of ["body", "query", "params", "response"]) {
|
|
1672
|
+
if (opts[key] !== void 0) {
|
|
1673
|
+
throw new Error(
|
|
1674
|
+
`\`${key}\` is a route option, not a root one; pass it per route, like .post('/', { ${key} }, handler).`
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1664
1678
|
const raw = options.log ?? env2.LOG_LEVEL;
|
|
1665
1679
|
const level = raw === true ? "info" : raw === false ? void 0 : raw;
|
|
1666
1680
|
const log = createLogger(level);
|
|
@@ -1670,7 +1684,7 @@ function config(options = {}) {
|
|
|
1670
1684
|
log,
|
|
1671
1685
|
// How request bodies are read: parsed into ctx.body by default; `raw` keeps
|
|
1672
1686
|
// the Buffer, `stream` hands the handler the unread web ReadableStream.
|
|
1673
|
-
|
|
1687
|
+
parser: options.parser ?? "parse",
|
|
1674
1688
|
// Secure-by-default response headers + trustProxy for ctx.ip. `false` turns
|
|
1675
1689
|
// the added headers off; see resolveSecurity for the defaults.
|
|
1676
1690
|
security: resolveSecurity(options.security)
|
|
@@ -1808,7 +1822,7 @@ function applyCors(res, ctx) {
|
|
|
1808
1822
|
|
|
1809
1823
|
// src/helpers/createWebsocket.ts
|
|
1810
1824
|
function createWebsocket(sockets, handlers) {
|
|
1811
|
-
const
|
|
1825
|
+
const run2 = (event, socket, body) => {
|
|
1812
1826
|
const routes = handlers.socket?.filter((r2) => r2.path === event) ?? [];
|
|
1813
1827
|
const user = socket.user ?? socket.data?.user;
|
|
1814
1828
|
for (const route of routes) {
|
|
@@ -1818,14 +1832,14 @@ function createWebsocket(sockets, handlers) {
|
|
|
1818
1832
|
}
|
|
1819
1833
|
};
|
|
1820
1834
|
return {
|
|
1821
|
-
message: (socket, body) =>
|
|
1835
|
+
message: (socket, body) => run2("message", socket, body),
|
|
1822
1836
|
open: (socket) => {
|
|
1823
1837
|
sockets.push(socket);
|
|
1824
|
-
|
|
1838
|
+
run2("open", socket);
|
|
1825
1839
|
},
|
|
1826
1840
|
close: (socket) => {
|
|
1827
1841
|
sockets.splice(sockets.indexOf(socket), 1);
|
|
1828
|
-
|
|
1842
|
+
run2("close", socket);
|
|
1829
1843
|
}
|
|
1830
1844
|
};
|
|
1831
1845
|
}
|
|
@@ -2009,36 +2023,48 @@ function pathPattern(pattern, path) {
|
|
|
2009
2023
|
return null;
|
|
2010
2024
|
}
|
|
2011
2025
|
|
|
2012
|
-
// src/
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
if (
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
if (typeof schema?.body?.parse === "function") {
|
|
2022
|
-
base = "body";
|
|
2023
|
-
schema.body.parse(ctx.body || {});
|
|
2024
|
-
}
|
|
2025
|
-
if (typeof schema?.query === "function") {
|
|
2026
|
-
base = "query";
|
|
2027
|
-
schema.query(ctx.url.query || {});
|
|
2028
|
-
}
|
|
2029
|
-
if (typeof schema?.query?.parse === "function") {
|
|
2030
|
-
base = "query";
|
|
2031
|
-
schema.query.parse(ctx.url.query || {});
|
|
2032
|
-
}
|
|
2033
|
-
} catch (error) {
|
|
2034
|
-
if (error.name === "ZodError" || error.constructor.name === "ZodError") {
|
|
2035
|
-
const message = error.issues.map(
|
|
2036
|
-
({ path, message: message2 }) => `[${base}.${path.join(".")}]: ${message2}`
|
|
2037
|
-
).sort().join("\n");
|
|
2038
|
-
throw new StatusError(message, 422);
|
|
2026
|
+
// src/errors/ValidationError.ts
|
|
2027
|
+
var ValidationError = class extends StatusError {
|
|
2028
|
+
source;
|
|
2029
|
+
issues;
|
|
2030
|
+
constructor(source, issues) {
|
|
2031
|
+
if (source === "response") {
|
|
2032
|
+
super("Server Error", 500);
|
|
2033
|
+
} else {
|
|
2034
|
+
super(`Invalid request ${source}`, 422);
|
|
2039
2035
|
}
|
|
2040
|
-
|
|
2036
|
+
this.source = source;
|
|
2037
|
+
this.issues = issues;
|
|
2041
2038
|
}
|
|
2039
|
+
};
|
|
2040
|
+
|
|
2041
|
+
// src/helpers/validate.ts
|
|
2042
|
+
async function run(schema, value, source) {
|
|
2043
|
+
const result = await schema["~standard"].validate(value);
|
|
2044
|
+
if (result.issues) throw new ValidationError(source, result.issues);
|
|
2045
|
+
return result.value;
|
|
2046
|
+
}
|
|
2047
|
+
async function validateRequest(ctx, options) {
|
|
2048
|
+
if (options.body) {
|
|
2049
|
+
ctx.body = await run(options.body, ctx.body ?? {}, "body");
|
|
2050
|
+
}
|
|
2051
|
+
if (options.query) {
|
|
2052
|
+
const query = await run(options.query, ctx.url.query || {}, "query");
|
|
2053
|
+
replace2(ctx.url.query, query);
|
|
2054
|
+
}
|
|
2055
|
+
if (options.params) {
|
|
2056
|
+
const params = await run(options.params, ctx.url.params || {}, "params");
|
|
2057
|
+
replace2(ctx.url.params, params);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
async function validateResponse(out, options) {
|
|
2061
|
+
if (!options.response) return out;
|
|
2062
|
+
if (out?.constructor !== Object && !Array.isArray(out)) return out;
|
|
2063
|
+
return await run(options.response, out, "response");
|
|
2064
|
+
}
|
|
2065
|
+
function replace2(target, values) {
|
|
2066
|
+
for (const key of Object.keys(target)) delete target[key];
|
|
2067
|
+
Object.assign(target, values);
|
|
2042
2068
|
}
|
|
2043
2069
|
|
|
2044
2070
|
// src/helpers/handleRequest.ts
|
|
@@ -2063,20 +2089,28 @@ async function getResponse(app, ctx) {
|
|
|
2063
2089
|
ctx.options = { ...app.settings, ...route.options };
|
|
2064
2090
|
}
|
|
2065
2091
|
checkTraversal(params, ctx);
|
|
2066
|
-
ctx.body = await resolveBody(
|
|
2092
|
+
ctx.body = await resolveBody(
|
|
2093
|
+
ctx,
|
|
2094
|
+
ctx.options.parser,
|
|
2095
|
+
ctx.options.security.maxBody
|
|
2096
|
+
);
|
|
2097
|
+
await validateRequest(ctx, route.options);
|
|
2067
2098
|
for (const cb of route.fns) {
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
}
|
|
2099
|
+
const res = await cb(ctx);
|
|
2100
|
+
const out = await parseResponse(
|
|
2101
|
+
await validateResponse(res, route.options),
|
|
2102
|
+
ctx
|
|
2103
|
+
);
|
|
2104
|
+
if (out) return out;
|
|
2075
2105
|
}
|
|
2076
2106
|
break;
|
|
2077
2107
|
}
|
|
2078
2108
|
if (!matched) {
|
|
2079
|
-
ctx.body = await resolveBody(
|
|
2109
|
+
ctx.body = await resolveBody(
|
|
2110
|
+
ctx,
|
|
2111
|
+
ctx.options.parser,
|
|
2112
|
+
ctx.options.security.maxBody
|
|
2113
|
+
);
|
|
2080
2114
|
for (const mw of app.middleware) {
|
|
2081
2115
|
const out = await parseResponse(await mw(ctx), ctx);
|
|
2082
2116
|
if (out) return out;
|
|
@@ -2541,8 +2575,8 @@ var generateOpenApiPaths = (handlers) => {
|
|
|
2541
2575
|
for (const route of routes) {
|
|
2542
2576
|
const path = route.path;
|
|
2543
2577
|
const fn = route.fns.find((p) => typeof p === "function");
|
|
2544
|
-
const meta = route.
|
|
2545
|
-
const config2 = getConfig(route.options);
|
|
2578
|
+
const meta = route.options ?? {};
|
|
2579
|
+
const config2 = getConfig(route.options?.schema);
|
|
2546
2580
|
if (typeof path !== "string" || path === "*" || path === "/docs" || !fn) {
|
|
2547
2581
|
continue;
|
|
2548
2582
|
}
|
|
@@ -2595,7 +2629,7 @@ var generateOpenApiPaths = (handlers) => {
|
|
|
2595
2629
|
paths[normalizedPath][method] = {
|
|
2596
2630
|
tags: config2.tags,
|
|
2597
2631
|
summary: config2.title || getTag("@title", fn) || `${method.toUpperCase()} ${normalizedPath}`,
|
|
2598
|
-
description: getTitle(fn) || getDescription(fn),
|
|
2632
|
+
description: config2.description || getTitle(fn) || getDescription(fn),
|
|
2599
2633
|
requestBody,
|
|
2600
2634
|
parameters,
|
|
2601
2635
|
responses
|
|
@@ -3052,6 +3086,14 @@ var Netlify = async (app, request, context) => {
|
|
|
3052
3086
|
};
|
|
3053
3087
|
|
|
3054
3088
|
// src/router.ts
|
|
3089
|
+
function checkParserConflict(options, globalParser) {
|
|
3090
|
+
const parser = options.parser ?? globalParser ?? "parse";
|
|
3091
|
+
if (options.body && parser !== "parse") {
|
|
3092
|
+
throw new Error(
|
|
3093
|
+
`A \`parser: '${parser}'\` route never parses the body, so its \`body\` schema cannot run. Remove one, or set \`parser: 'parse'\` on the route.`
|
|
3094
|
+
);
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3055
3097
|
var Router = class _Router {
|
|
3056
3098
|
// Cross-cutting middleware added with .use(); they run on every request
|
|
3057
3099
|
middleware = [];
|
|
@@ -3085,6 +3127,7 @@ var Router = class _Router {
|
|
|
3085
3127
|
if (rest[0] != null && typeof rest[0] !== "function") {
|
|
3086
3128
|
options = rest.shift();
|
|
3087
3129
|
}
|
|
3130
|
+
checkParserConflict(options, this.settings?.parser);
|
|
3088
3131
|
const base = method === "socket" ? [] : this.middleware;
|
|
3089
3132
|
const fns = [...base, ...rest].filter((fn) => fn != null);
|
|
3090
3133
|
this.handlers[method].push({ path, options, fns });
|
|
@@ -3119,6 +3162,7 @@ var Router = class _Router {
|
|
|
3119
3162
|
if (arg instanceof _Router) {
|
|
3120
3163
|
for (const m of Object.keys(arg.handlers)) {
|
|
3121
3164
|
for (const route of arg.handlers[m]) {
|
|
3165
|
+
checkParserConflict(route.options, this.settings?.parser);
|
|
3122
3166
|
const base = m === "socket" ? [] : this.middleware;
|
|
3123
3167
|
this.handlers[m].push({
|
|
3124
3168
|
path: route.path,
|
|
@@ -3208,16 +3252,17 @@ var Server = class extends Router {
|
|
|
3208
3252
|
} else if (this.platform.runtime === "bun") {
|
|
3209
3253
|
this.settings.log.start(`http://localhost:${this.settings.port}/`);
|
|
3210
3254
|
}
|
|
3211
|
-
this
|
|
3212
|
-
|
|
3213
|
-
this.use(
|
|
3214
|
-
|
|
3215
|
-
this.
|
|
3255
|
+
const app = this;
|
|
3256
|
+
app.use(timer);
|
|
3257
|
+
if (this.settings.cors) app.use(preflight);
|
|
3258
|
+
app.use(assets);
|
|
3259
|
+
if (this.settings.favicon) app.get("/favicon.ico", favicon);
|
|
3260
|
+
app.use(session);
|
|
3216
3261
|
if (this.settings.auth) {
|
|
3217
|
-
auth(
|
|
3262
|
+
auth(app);
|
|
3218
3263
|
}
|
|
3219
3264
|
if (this.settings.openapi) {
|
|
3220
|
-
|
|
3265
|
+
app.get(this.settings.openapi.path || "/docs", openapi_default);
|
|
3221
3266
|
}
|
|
3222
3267
|
}
|
|
3223
3268
|
self() {
|
|
@@ -3252,6 +3297,7 @@ function server(options) {
|
|
|
3252
3297
|
export {
|
|
3253
3298
|
Server,
|
|
3254
3299
|
ServerError_default as ServerError,
|
|
3300
|
+
ValidationError,
|
|
3255
3301
|
default3 as bucket,
|
|
3256
3302
|
cache,
|
|
3257
3303
|
cookies,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "A fully-fledged web server with routing, file uploads, sessions, static files, schema validation, websockets, testing, etc.",
|
|
5
5
|
"homepage": "https://server-js.com/",
|
|
6
6
|
"repository": "github:franciscop/server-next",
|
|
@@ -70,9 +70,12 @@
|
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/bun": "^1.3.0",
|
|
72
72
|
"@types/node": "^24.10.0",
|
|
73
|
+
"arktype": "^2.2.3",
|
|
73
74
|
"bun": "^1.3.13",
|
|
74
75
|
"check-dts": "^0.8.2",
|
|
75
76
|
"tsup": "^8.5.1",
|
|
76
|
-
"typescript": "^6.0.2"
|
|
77
|
+
"typescript": "^6.0.2",
|
|
78
|
+
"valibot": "^1.4.2",
|
|
79
|
+
"zod": "^4.4.3"
|
|
77
80
|
}
|
|
78
81
|
}
|