rsnext/packages/next/server/web/spec-compliant/response.ts
Javi Velasco a815ba9f79
Implement Middleware RFC (#30081)
This PR adds support for [Middleware as per RFC ](https://github.com/vercel/next.js/discussions/29750). 

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes
2021-10-20 17:52:11 +00:00

113 lines
2.5 KiB
TypeScript

import { Body, BodyInit, cloneBody, extractContentType } from './body'
import { NextURL } from '../next-url'
const INTERNALS = Symbol('internal response')
const REDIRECTS = new Set([301, 302, 303, 307, 308])
class BaseResponse extends Body implements Response {
[INTERNALS]: {
headers: Headers
status: number
statusText: string
type: 'default' | 'error'
url?: NextURL
}
constructor(body?: BodyInit | null, init?: ResponseInit) {
super(body)
this[INTERNALS] = {
headers: new Headers(init?.headers),
status: init?.status || 200,
statusText: init?.statusText || '',
type: 'default',
url: init?.url ? new NextURL(init.url) : undefined,
}
if (this[INTERNALS].status < 200 || this[INTERNALS].status > 599) {
throw new RangeError(
`Responses may only be constructed with status codes in the range 200 to 599, inclusive.`
)
}
if (body !== null && !this[INTERNALS].headers.has('Content-Type')) {
const contentType = extractContentType(this)
if (contentType) {
this[INTERNALS].headers.append('Content-Type', contentType)
}
}
}
static redirect(url: string, status = 302) {
if (!REDIRECTS.has(status)) {
throw new RangeError(
'Failed to execute "redirect" on "response": Invalid status code'
)
}
return new Response(null, {
headers: { Location: url },
status,
})
}
static error() {
const response = new BaseResponse(null, { status: 0, statusText: '' })
response[INTERNALS].type = 'error'
return response
}
get url() {
return this[INTERNALS].url?.toString() || ''
}
get ok() {
return this[INTERNALS].status >= 200 && this[INTERNALS].status < 300
}
get status() {
return this[INTERNALS].status
}
get statusText() {
return this[INTERNALS].statusText
}
get headers() {
return this[INTERNALS].headers
}
get redirected() {
return (
this[INTERNALS].status > 299 &&
this[INTERNALS].status < 400 &&
this[INTERNALS].headers.has('Location')
)
}
get type() {
return this[INTERNALS].type
}
clone() {
return new BaseResponse(cloneBody(this), {
headers: this.headers,
status: this.status,
statusText: this.statusText,
url: this.url,
})
}
get [Symbol.toStringTag]() {
return 'Response'
}
}
export interface ResponseInit {
headers?: HeadersInit
status?: number
statusText?: string
url?: string
}
export { BaseResponse as Response }