@server/next 0.40.3 → 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 +144 -89
- 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 = {
|
|
@@ -278,40 +317,38 @@ type BunEnv = Record<string, string> & {
|
|
|
278
317
|
data?: any;
|
|
279
318
|
}) => boolean;
|
|
280
319
|
};
|
|
281
|
-
|
|
320
|
+
interface ContextExtension {
|
|
321
|
+
}
|
|
322
|
+
type Context<C extends ContextTypes = {}> = {
|
|
282
323
|
method: Method;
|
|
283
324
|
ip: string;
|
|
284
325
|
headers: Record<string, string | string[]>;
|
|
285
326
|
cookies: Record<string, string>;
|
|
286
|
-
body?: SerializableValue | Buffer | ReadableStream
|
|
327
|
+
body?: Field<C, "body", SerializableValue | Buffer | ReadableStream>;
|
|
287
328
|
url: URL & {
|
|
288
|
-
params:
|
|
289
|
-
query: Record<string,
|
|
329
|
+
params: Field<C, "params", Record<string, any>>;
|
|
330
|
+
query: Field<C, "query", Record<string, any>>;
|
|
290
331
|
};
|
|
291
332
|
options: Settings;
|
|
292
333
|
platform: Platform;
|
|
293
334
|
time?: Time;
|
|
294
335
|
socket?: WebSocket;
|
|
295
336
|
sockets?: WebSocket[];
|
|
296
|
-
session:
|
|
297
|
-
|
|
298
|
-
} ? S extends Record<"Session", infer Inner> ? Inner : Record<string, any> : Record<string, any>;
|
|
299
|
-
user?: O extends {
|
|
300
|
-
User?: infer U;
|
|
301
|
-
} ? 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>>;
|
|
302
339
|
init: number;
|
|
303
340
|
req?: Request;
|
|
304
341
|
res?: Response & {
|
|
305
342
|
cookies?: Record<string, string>;
|
|
306
343
|
};
|
|
307
344
|
app: Server;
|
|
308
|
-
};
|
|
345
|
+
} & ContextExtension;
|
|
309
346
|
type InlineReply = Response | Reply | BucketFile | {
|
|
310
347
|
body: string;
|
|
311
348
|
headers?: Headers;
|
|
312
349
|
} | SerializableValue | JSX.Element | Buffer | ReadableStream;
|
|
313
350
|
type Body = InlineReply;
|
|
314
|
-
type Middleware<
|
|
351
|
+
type Middleware<C extends ContextTypes = {}> = (ctx: Context<C>) => InlineReply | Promise<InlineReply> | void | Promise<void>;
|
|
315
352
|
|
|
316
353
|
type Variables = Record<string, string | string[]>;
|
|
317
354
|
type ExtendError = string | {
|
|
@@ -334,50 +371,68 @@ declare global {
|
|
|
334
371
|
var env: Record<string, any>;
|
|
335
372
|
}
|
|
336
373
|
|
|
337
|
-
type
|
|
338
|
-
|
|
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 = {}> {
|
|
339
383
|
middleware: Middleware[];
|
|
340
384
|
handlers: Record<Method, Route[]>;
|
|
341
385
|
self(): this;
|
|
342
386
|
handle(method: Method, pathOrFn?: any, ...rest: any[]): this;
|
|
343
|
-
socket<Path extends string>(path: Path, ...middleware: Mids<
|
|
344
|
-
socket
|
|
345
|
-
socket(...middleware:
|
|
346
|
-
socket(options:
|
|
347
|
-
get<Path extends string>(path: Path, ...middleware: Mids<
|
|
348
|
-
get
|
|
349
|
-
get(...middleware:
|
|
350
|
-
get(options:
|
|
351
|
-
head<Path extends string>(path: Path, ...middleware: Mids<
|
|
352
|
-
head
|
|
353
|
-
head(...middleware:
|
|
354
|
-
head(options:
|
|
355
|
-
post<Path extends string>(path: Path, ...middleware: Mids<
|
|
356
|
-
post
|
|
357
|
-
post(...middleware:
|
|
358
|
-
post(options:
|
|
359
|
-
put<Path extends string>(path: Path, ...middleware: Mids<
|
|
360
|
-
put
|
|
361
|
-
put(...middleware:
|
|
362
|
-
put(options:
|
|
363
|
-
patch<Path extends string>(path: Path, ...middleware: Mids<
|
|
364
|
-
patch
|
|
365
|
-
patch(...middleware:
|
|
366
|
-
patch(options:
|
|
367
|
-
delete<Path extends string>(path: Path, ...middleware: Mids<
|
|
368
|
-
delete
|
|
369
|
-
delete(...middleware:
|
|
370
|
-
delete(options:
|
|
371
|
-
options<Path extends string>(path: Path, ...middleware: Mids<
|
|
372
|
-
options
|
|
373
|
-
options(...middleware:
|
|
374
|
-
options(options:
|
|
375
|
-
use(...middleware:
|
|
376
|
-
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);
|
|
377
427
|
}
|
|
378
|
-
declare function router(): Router;
|
|
379
428
|
|
|
380
|
-
declare class
|
|
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[]);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
declare class Server<C extends ContextTypes = {}> extends Router<C> {
|
|
381
436
|
settings: Settings;
|
|
382
437
|
platform: Platform;
|
|
383
438
|
sockets: any[];
|
|
@@ -395,111 +450,111 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
395
450
|
callback(request: Request, context: unknown): Promise<Response>;
|
|
396
451
|
test(): {
|
|
397
452
|
get: (path: string, options?: {
|
|
453
|
+
method?: string;
|
|
454
|
+
headers?: HeadersInit;
|
|
398
455
|
cache?: RequestCache;
|
|
456
|
+
redirect?: RequestRedirect;
|
|
399
457
|
credentials?: RequestCredentials;
|
|
400
|
-
headers?: HeadersInit;
|
|
401
458
|
integrity?: string;
|
|
402
459
|
keepalive?: boolean;
|
|
403
|
-
method?: string;
|
|
404
460
|
mode?: RequestMode;
|
|
405
461
|
priority?: RequestPriority;
|
|
406
|
-
redirect?: RequestRedirect;
|
|
407
462
|
referrer?: string;
|
|
408
463
|
referrerPolicy?: ReferrerPolicy;
|
|
409
464
|
signal?: AbortSignal | null;
|
|
410
465
|
window?: null;
|
|
411
466
|
}) => Promise<Response>;
|
|
412
467
|
head: (path: string, options?: {
|
|
468
|
+
method?: string;
|
|
469
|
+
headers?: HeadersInit;
|
|
413
470
|
cache?: RequestCache;
|
|
471
|
+
redirect?: RequestRedirect;
|
|
414
472
|
credentials?: RequestCredentials;
|
|
415
|
-
headers?: HeadersInit;
|
|
416
473
|
integrity?: string;
|
|
417
474
|
keepalive?: boolean;
|
|
418
|
-
method?: string;
|
|
419
475
|
mode?: RequestMode;
|
|
420
476
|
priority?: RequestPriority;
|
|
421
|
-
redirect?: RequestRedirect;
|
|
422
477
|
referrer?: string;
|
|
423
478
|
referrerPolicy?: ReferrerPolicy;
|
|
424
479
|
signal?: AbortSignal | null;
|
|
425
480
|
window?: null;
|
|
426
481
|
}) => Promise<Response>;
|
|
427
|
-
post: (path: string, body?: string | number | boolean | ArrayBuffer |
|
|
482
|
+
post: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
428
483
|
[key: string]: SerializableValue;
|
|
429
|
-
} | SerializableValue[], options?: {
|
|
484
|
+
} | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
|
|
485
|
+
method?: string;
|
|
486
|
+
headers?: HeadersInit;
|
|
430
487
|
cache?: RequestCache;
|
|
488
|
+
redirect?: RequestRedirect;
|
|
431
489
|
credentials?: RequestCredentials;
|
|
432
|
-
headers?: HeadersInit;
|
|
433
490
|
integrity?: string;
|
|
434
491
|
keepalive?: boolean;
|
|
435
|
-
method?: string;
|
|
436
492
|
mode?: RequestMode;
|
|
437
493
|
priority?: RequestPriority;
|
|
438
|
-
redirect?: RequestRedirect;
|
|
439
494
|
referrer?: string;
|
|
440
495
|
referrerPolicy?: ReferrerPolicy;
|
|
441
496
|
signal?: AbortSignal | null;
|
|
442
497
|
window?: null;
|
|
443
498
|
}) => Promise<Response>;
|
|
444
|
-
put: (path: string, body?: string | number | boolean | ArrayBuffer |
|
|
499
|
+
put: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
445
500
|
[key: string]: SerializableValue;
|
|
446
|
-
} | SerializableValue[], options?: {
|
|
501
|
+
} | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
|
|
502
|
+
method?: string;
|
|
503
|
+
headers?: HeadersInit;
|
|
447
504
|
cache?: RequestCache;
|
|
505
|
+
redirect?: RequestRedirect;
|
|
448
506
|
credentials?: RequestCredentials;
|
|
449
|
-
headers?: HeadersInit;
|
|
450
507
|
integrity?: string;
|
|
451
508
|
keepalive?: boolean;
|
|
452
|
-
method?: string;
|
|
453
509
|
mode?: RequestMode;
|
|
454
510
|
priority?: RequestPriority;
|
|
455
|
-
redirect?: RequestRedirect;
|
|
456
511
|
referrer?: string;
|
|
457
512
|
referrerPolicy?: ReferrerPolicy;
|
|
458
513
|
signal?: AbortSignal | null;
|
|
459
514
|
window?: null;
|
|
460
515
|
}) => Promise<Response>;
|
|
461
|
-
patch: (path: string, body?: string | number | boolean | ArrayBuffer |
|
|
516
|
+
patch: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
462
517
|
[key: string]: SerializableValue;
|
|
463
|
-
} | SerializableValue[], options?: {
|
|
518
|
+
} | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
|
|
519
|
+
method?: string;
|
|
520
|
+
headers?: HeadersInit;
|
|
464
521
|
cache?: RequestCache;
|
|
522
|
+
redirect?: RequestRedirect;
|
|
465
523
|
credentials?: RequestCredentials;
|
|
466
|
-
headers?: HeadersInit;
|
|
467
524
|
integrity?: string;
|
|
468
525
|
keepalive?: boolean;
|
|
469
|
-
method?: string;
|
|
470
526
|
mode?: RequestMode;
|
|
471
527
|
priority?: RequestPriority;
|
|
472
|
-
redirect?: RequestRedirect;
|
|
473
528
|
referrer?: string;
|
|
474
529
|
referrerPolicy?: ReferrerPolicy;
|
|
475
530
|
signal?: AbortSignal | null;
|
|
476
531
|
window?: null;
|
|
477
532
|
}) => Promise<Response>;
|
|
478
533
|
delete: (path: string, options?: {
|
|
534
|
+
method?: string;
|
|
535
|
+
headers?: HeadersInit;
|
|
479
536
|
cache?: RequestCache;
|
|
537
|
+
redirect?: RequestRedirect;
|
|
480
538
|
credentials?: RequestCredentials;
|
|
481
|
-
headers?: HeadersInit;
|
|
482
539
|
integrity?: string;
|
|
483
540
|
keepalive?: boolean;
|
|
484
|
-
method?: string;
|
|
485
541
|
mode?: RequestMode;
|
|
486
542
|
priority?: RequestPriority;
|
|
487
|
-
redirect?: RequestRedirect;
|
|
488
543
|
referrer?: string;
|
|
489
544
|
referrerPolicy?: ReferrerPolicy;
|
|
490
545
|
signal?: AbortSignal | null;
|
|
491
546
|
window?: null;
|
|
492
547
|
}) => Promise<Response>;
|
|
493
548
|
options: (path: string, options?: {
|
|
549
|
+
method?: string;
|
|
550
|
+
headers?: HeadersInit;
|
|
494
551
|
cache?: RequestCache;
|
|
552
|
+
redirect?: RequestRedirect;
|
|
495
553
|
credentials?: RequestCredentials;
|
|
496
|
-
headers?: HeadersInit;
|
|
497
554
|
integrity?: string;
|
|
498
555
|
keepalive?: boolean;
|
|
499
|
-
method?: string;
|
|
500
556
|
mode?: RequestMode;
|
|
501
557
|
priority?: RequestPriority;
|
|
502
|
-
redirect?: RequestRedirect;
|
|
503
558
|
referrer?: string;
|
|
504
559
|
referrerPolicy?: ReferrerPolicy;
|
|
505
560
|
signal?: AbortSignal | null;
|
|
@@ -507,6 +562,6 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
507
562
|
}) => Promise<Response>;
|
|
508
563
|
};
|
|
509
564
|
}
|
|
510
|
-
declare function server<
|
|
565
|
+
declare function server<C extends ContextTypes = {}>(options?: Options): Server<C>;
|
|
511
566
|
|
|
512
|
-
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
|
}
|