-
Notifications
You must be signed in to change notification settings - Fork 26.1k
/
cookies.ts
115 lines (97 loc) · 2.98 KB
/
cookies.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import cookie from 'next/dist/compiled/cookie'
import { CookieSerializeOptions } from '../types'
const normalizeCookieOptions = (options: CookieSerializeOptions) => {
options = Object.assign({}, options)
if (options.maxAge) {
options.expires = new Date(Date.now() + options.maxAge * 1000)
}
if (options.path == null) {
options.path = '/'
}
return options
}
const serializeValue = (value: unknown) =>
typeof value === 'object' ? `j:${JSON.stringify(value)}` : String(value)
const serializeExpiredCookie = (
key: string,
options: CookieSerializeOptions = {}
) =>
cookie.serialize(key, '', {
expires: new Date(0),
path: '/',
...options,
})
const deserializeCookie = (input: Request | Response): string[] => {
const value = input.headers.get('set-cookie')
return value !== undefined && value !== null ? value.split(', ') : []
}
const serializeCookie = (input: string[]) => input.join(', ')
export class Cookies extends Map<string, any> {
constructor(input?: string | null) {
const parsedInput = typeof input === 'string' ? cookie.parse(input) : {}
super(Object.entries(parsedInput))
}
set(key: string, value: unknown, options: CookieSerializeOptions = {}) {
return super.set(
key,
cookie.serialize(
key,
serializeValue(value),
normalizeCookieOptions(options)
)
)
}
}
export class NextCookies extends Cookies {
response: Request | Response
constructor(response: Request | Response) {
super(response.headers.get('cookie'))
this.response = response
}
set(...args: Parameters<Cookies['set']>) {
const isAlreadyAdded = super.has(args[0])
const store = super.set(...args)
if (isAlreadyAdded) {
const setCookie = serializeCookie(
deserializeCookie(this.response).filter(
(value) => !value.startsWith(`${args[0]}=`)
)
)
if (setCookie) {
this.response.headers.set(
'set-cookie',
[store.get(args[0]), setCookie].join(', ')
)
} else {
this.response.headers.set('set-cookie', store.get(args[0]))
}
} else {
this.response.headers.append('set-cookie', store.get(args[0]))
}
return store
}
delete(key: any, options: CookieSerializeOptions = {}) {
const isDeleted = super.delete(key)
if (isDeleted) {
const setCookie = serializeCookie(
deserializeCookie(this.response).filter(
(value) => !value.startsWith(`${key}=`)
)
)
const expiredCookie = serializeExpiredCookie(key, options)
this.response.headers.set(
'set-cookie',
[expiredCookie, setCookie].join(', ')
)
}
return isDeleted
}
clear(options: CookieSerializeOptions = {}) {
const expiredCookies = Array.from(super.keys())
.map((key) => serializeExpiredCookie(key, options))
.join(', ')
if (expiredCookies) this.response.headers.set('set-cookie', expiredCookies)
return super.clear()
}
}
export { CookieSerializeOptions }