-
Notifications
You must be signed in to change notification settings - Fork 0
/
httpresponse.ts
96 lines (81 loc) · 3.05 KB
/
httpresponse.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2023-2024 the Sequoia authors. All rights reserved. MIT license.
import { HTTPStatus } from './status.ts'
import { CookieStorage } from './cookie.ts'
import { convertToBody, type Writeable } from './util.ts'
import { ContentType } from './media.ts'
export type ResponseBody = string | number | bigint | boolean | symbol | object | null | undefined
export type ResponseBodyFunction = () => ResponseBody | Promise<ResponseBody>
export interface HTTPResponseOptions {
body: ResponseBody | ResponseBodyFunction
headers?: Headers
type?: string
status?: HTTPStatus
}
export type HTTPResponseInit =
| string
| number
| bigint
| boolean
| symbol
| ResponseBodyFunction
| HTTPResponseOptions
export function isStatusNullBody(status: HTTPStatus): boolean {
return (
status === HTTPStatus.SWITCHING_PROTOCOLS ||
status === HTTPStatus.NO_CONTENT ||
status === HTTPStatus.RESET_CONTENT ||
status === HTTPStatus.NOT_MODIFIED
)
}
export class HTTPResponse {
readonly body: ResponseBody = null
readonly headers: Headers = new Headers()
readonly status: HTTPStatus = HTTPStatus.SUCCESS
readonly type?: string
constructor(initializer: HTTPResponseInit) {
if (['string', 'number', 'bigint', 'boolean', 'symbol'].includes(typeof initializer)) {
this.body = initializer
} else if (typeof initializer === 'function') {
this.body = initializer()
} else {
const options = initializer as HTTPResponseOptions
this.body = typeof options.body === 'function'
? (options.body as ResponseBodyFunction)()
: options.body
if (typeof options.body === 'object' && !options.type) this.type = ContentType.JSON
else this.type = options.type
this.status = options.status ?? HTTPStatus.SUCCESS
if (options.headers) this.headers = options.headers
}
}
transform = (): Response => {
const body: BodyInit | null = isStatusNullBody(this.status)
? null
: convertToBody(this.body)
const headers = new Headers()
const status = this.status
if (this.headers) {
for (const [key, val] of this.headers.entries()) {
if (typeof val === 'string' && val) {
headers.append(key, val)
}
}
}
if (this.type) headers.set('Content-Type', this.type)
return new Response(body, { status, headers })
}
empty = (): boolean => {
let headers = 0
for (const _ of this.headers.keys()) headers++
return (headers === 0 && !this.body)
}
applyCookies = (storage: CookieStorage): void => {
if (storage.size()) {
const cookies = storage.entries().filter((entry) => entry[1].overwrite)
for (const cookie of cookies) {
this.headers.append('Set-Cookie', cookie[1].toString())
}
}
}
}
export type HTTPContextResponse = Writeable<HTTPResponse>