• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yiminghe / next-compose-middlewares / 12483800089

24 Dec 2024 03:57PM UTC coverage: 66.935% (+0.1%) from 66.83%
12483800089

push

github

yiminghe
error on cookie

61 of 133 branches covered (45.86%)

Branch coverage included in aggregate %.

8 of 9 new or added lines in 3 files covered. (88.89%)

354 of 487 relevant lines covered (72.69%)

3.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.76
/source/next-context.ts
1
import type {
2
  NextContext,
3
  CookieAttributes,
4
  NextContextResponseInternal,
5
  ClientCookieAttributes,
6
} from './types';
7
import type { NextRequest } from 'next/server';
8
import { cookies as getCookies, headers as getHeaders } from 'next/headers';
9
import {
10
  NEXT_URL_HEADER,
11
  FORWARDED_URI_HEADER,
12
  FORWARDED_PROTO_HEADER,
13
  FORWARDED_HOST_HEADER,
14
  FORWARDED_FOR_HEADER,
15
  NEXT_BASE_PATH_HEADER,
16
  INIT_TOKEN,
17
} from './constants';
18
import { NextURL } from 'next/dist/server/web/next-url';
19

20
async function transformCookiesToObject(): Promise<any> {
21
  const originals = (await getCookies()).getAll();
5✔
22
  const cookies: any = {};
5✔
23
  for (const h of originals) {
5✔
24
    cookies[h.name] = h.value;
6✔
25
  }
26
  return cookies;
5✔
27
}
28

29
async function transformHeadersToObject(): Promise<any> {
30
  const originals = await getHeaders();
5✔
31
  const headers: any = {};
5✔
32
  for (const h of Array.from(originals.keys())) {
5✔
33
    headers[h] = originals.get(h);
75✔
34
  }
35
  return headers;
5✔
36
}
37

38
function buildResponse(): NextContextResponseInternal {
39
  const p: NextContextResponseInternal['_private'] = {
5✔
40
    status: 200,
41
    headers: {},
42
  };
43
  const res = {
5✔
44
    _private: p,
45
    async clearCookie(name: string, options?: CookieAttributes) {
46
      (await getCookies()).set(name, '', {
×
47
        ...options,
48
        maxAge: 0,
49
      });
50
    },
51
    async cookie(name: string, value: string, options?: CookieAttributes) {
52
      (await getCookies()).set(name, value, options);
6✔
53
    },
54
    append(k: string, v: string) {
55
      p.headers[k] = p.headers[k] ?? '';
×
56
      p.headers[k] += v;
×
57
    },
58
    set(...args: any) {
59
      const [k, v] = args;
3✔
60
      if (typeof k === 'string') {
3!
61
        p.headers[k] = v;
3✔
62
        return;
3✔
63
      }
64
      Object.assign(p.headers, k);
×
65
    },
66
    get(k: string) {
67
      return p.headers[k];
×
68
    },
69
    status(s: number) {
70
      p.status = s;
×
71
    },
72
    json(j: any) {
73
      p.json = j;
3✔
74
    },
75
    redirect(r: string) {
76
      p.redirectUrl = r;
×
77
    },
78
  };
79
  return res;
5✔
80
}
81

82
async function buildRequest() {
83
  const headers = await transformHeadersToObject();
5✔
84
  function get(k: string) {
85
    return headers[k];
×
86
  }
87
  if (!headers[FORWARDED_URI_HEADER]) {
5!
88
    throw new Error('must setup middleware!');
×
89
  }
90
  const stringUrl = `${headers[FORWARDED_PROTO_HEADER]}://${headers[FORWARDED_HOST_HEADER]}${headers[FORWARDED_URI_HEADER]}`;
5✔
91
  const url = new URL(stringUrl);
5✔
92
  const searchParams: Record<string, any> = {};
5✔
93
  for (const [k, v] of Array.from(url.searchParams.entries())) {
5✔
94
    searchParams[k] = v;
×
95
  }
96
  const protocol = url.protocol.slice(0, -1);
5✔
97
  const nextUrl = new NextURL(headers[NEXT_URL_HEADER]);
5✔
98
  nextUrl.basePath = headers[NEXT_BASE_PATH_HEADER];
5✔
99
  nextUrl.pathname = nextUrl.pathname.slice(nextUrl.basePath.length);
5✔
100
  return {
5✔
101
    params: {},
102
    method: 'GET',
103
    cookies: await transformCookiesToObject(),
104
    text: () =>
105
      new Promise<string>((r) => {
×
106
        r('');
×
107
      }),
108
    json: () =>
109
      new Promise<any>((r) => {
×
110
        r({});
×
111
      }),
112
    host: url.host,
113
    secure: protocol === 'https',
114
    url: url.toString(),
115
    nextUrl,
116
    path: url.pathname,
117
    query: searchParams,
118
    protocol,
119
    ip: headers[FORWARDED_FOR_HEADER],
120
    headers,
121
    get,
122
    header: get,
123
  };
124
}
125

126
export function buildPageResponse() {
127
  const res = buildResponse();
1✔
128
  function cookie(name: string, value: string, options_?: CookieAttributes) {
129
    const private_ = res._private;
3✔
130
    if (private_.cookieSent) {
3!
NEW
131
      throw new Error('only can set cookie inside middleware and entry page!');
×
132
    }
133
    const { maxAge, expires, ...clientOptions_ } = options_ || {};
3!
134
    let clientOptions: ClientCookieAttributes = clientOptions_;
3✔
135
    if (expires) {
3✔
136
      clientOptions.expires = +expires;
1✔
137
    } else if (typeof maxAge === 'number') {
2✔
138
      clientOptions.expires = Date.now() + maxAge * 1000;
1✔
139
    }
140
    private_.cookies = private_.cookies || {};
3✔
141
    private_.cookies[name] = { options: clientOptions, value };
3✔
142
  }
143
  return {
1✔
144
    ...res,
145
    cookie,
146
    clearCookie(name: string, options_?: CookieAttributes) {
147
      cookie(name, '', { ...options_, expires: new Date(0) });
×
148
    },
149
  };
150
}
151

152
export function createNextContextFromPage() {
153
  const context: NextContext = {
1✔
154
    type: 'page',
155
    req: null as any,
156
    res: buildPageResponse(),
157
  };
158
  (context as any)[INIT_TOKEN] = (async () => {
1✔
159
    context.req = await buildRequest();
1✔
160
    delete (context as any)[INIT_TOKEN];
1✔
161
  })();
162
  return context;
1✔
163
}
164

165
export async function createNextContextFromAction() {
166
  const res = buildResponse();
1✔
167
  const context: NextContext = {
1✔
168
    type: 'action',
169
    req: {
170
      ...(await buildRequest()),
171
      method: 'POST',
172
    },
173
    res,
174
  };
175
  return context;
1✔
176
}
177

178
export async function createNextContextFromRoute(req: NextRequest) {
179
  const context: NextContext = {
180
    type: 'route',
181
    res: buildResponse(),
182
    req: {
183
      ...(await buildRequest()),
184
      text: () => req.text(),
×
185
      json: () => req.json(),
×
186
      method: req.method,
187
    },
188
  };
189
  return context;
3✔
190
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc