@vercel/node#VercelResponse TypeScript Examples

The following examples show how to use @vercel/node#VercelResponse. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From views with MIT License 7 votes vote down vote up
setReadTime = (
  req: VercelRequest,
  res: VercelResponse,
  key: string,
): void => {
  if (onRead(req, key)) return
  if (res.writableEnded || !req.query.unique) return
  res.setHeader(
    'Set-Cookie',
    `${key}=1;expires=${new Date(Date.now() + 50000).toUTCString()};httpOnly`,
  )
}
Example #2
Source File: utils.ts    From discord-ifttt with MIT License 6 votes vote down vote up
function handleError(error: AxiosError, response: VercelResponse): void {
	if (error.response) {
		response.status(error.response.status).send(error.response.data)
	} else {
		response.status(400).send({error: error.message})
	}
}
Example #3
Source File: utils.ts    From views with MIT License 6 votes vote down vote up
ok = (req: VercelRequest, res: VercelResponse, count: number = 0): void => {
  if (req.query.json) {
    res.status(200).send({ count })
  } else {
    res.status(200).send(makeSvg(req, res, count))
  }
}
Example #4
Source File: utils.ts    From views with MIT License 6 votes vote down vote up
setContentType = (req: VercelRequest, res: VercelResponse): void => {
  const contentType = req.query.json ? 'application/json' : 'image/svg+xml'
  res.setHeader('Content-Type', contentType)
}
Example #5
Source File: utils.ts    From views with MIT License 6 votes vote down vote up
setAllowOrigin = (req: VercelRequest, res: VercelResponse): void => {
  if (req.query.json && req.headers.origin) {
    res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
  }
}
Example #6
Source File: utils.ts    From views with MIT License 6 votes vote down vote up
setViewsStatus = (res: VercelResponse, status: string): void => {
  res.setHeader('x-view-status', status)
}
Example #7
Source File: views.ts    From views with MIT License 6 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  _.setAllowOrigin(req, res)
  _.setContentType(req, res)
  _.setViewsStatus(res, 'bad')
  if (!req.headers.referer || !req.query.key) return _.ok(req, res)

  try {
    const currentView = _.getViewsKeys(req)
    const { viewId, key } = currentView
    const { hasPage, count } = await findPageByMD5Key(viewId, key)
    _.setReadTime(req, res, key)
    _.setViewsStatus(res, 'ok')

    if (_.onRead(req, key) || req.query.readonly) return _.ok(req, res, count)

    if (!hasPage) {
      const { limitExceeded } = await createPageByViewId(currentView)
      if (limitExceeded) {
        _.setViewsStatus(res, 'limit-exceeded')
      }
      return _.ok(req, res, 1)
    }
    _.ok(req, res, count)

    await updatePageByMD5Key(key)
  } catch (e) {
    console.log(`referer: ${req.headers.referer}, key: ${req.query.key}\n`, e)
    if (res.writableEnded) return
    return _.ok(req, res)
  }
}
Example #8
Source File: wrapExpressHandler.ts    From octane with Apache License 2.0 6 votes vote down vote up
wrapExpressHandler = function (handler: RequestHandler): VercelApiHandler {
    return function (request: VercelRequest, response: VercelResponse): Promise<void> {
        return new Promise<void>(function (resolve, reject) {
            handler(request as any, response as any, function (error?: any) {
                if (error) {
                    reject(error);
                } else {
                    resolve();
                }
            });
        });
    };
}
Example #9
Source File: ratelimit.ts    From vercel-badge with MIT License 6 votes vote down vote up
export default function handler(req: VercelRequest, res: VercelResponse) {
  axios
    .get(`https://api.github.com/rate_limit`, {
      headers: {
        Authorization: `Basic ${Buffer.from(
          `${process.env.ID}:${process.env.SECRET}`
        ).toString("base64")}`,
      },
    })
    .then((response) => {
      return res.status(200).json(response.data);
    })
    .catch((error) => {
      return res.status(400).json(error.response.data);
    });
}
Example #10
Source File: reminder.ts    From telegram-standup-bot with MIT License 6 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  if (
    process.env.NODE_ENV === 'production' &&
    req.query.key !== process.env.TELEGRAM_API_KEY
  ) {
    return res.status(401).json({ status: 'invalid api key' });
  }

  const { db } = await connectToDatabase();
  const users = await db.collection('users').find({}).toArray();

  const reminders = [];
  users
    .filter((u) => !!u.groups.length)
    .forEach((user: Member) => {
      const winners = user.groups.filter(g => !!g).filter((g: StandupGroup) => g.winner);

      if (winners.length) {
        const winnerTitles = winners.map((g) => g.title);

        const message = user.submitted
          ? SUBMITTED_MESSAGE(winnerTitles)
          : NOT_SUBMITTED_MESSAGE(winnerTitles);

        reminders.push(sendMsg(message, user.userId));
      }
    });

  await Promise.all(reminders);

  return res.status(200).json({ status: 'ok', sendCount: reminders.length });
};
Example #11
Source File: groups.ts    From telegram-standup-bot with MIT License 6 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  const isValid = checkSignature(req?.body || {});

  if (!isValid && process.env.NODE_ENV === 'production') {
    return res.status(401).json({ status: 'Unauthorized' });
  }

  const { db } = await connectToDatabase();
  const user = await db.collection('users').findOne({ userId: req.body.id });

  if (!user) {
    return res.status(404).json({ statusText: 'User not found' });
  }

  return res
    .status(200)
    .json(user.groups.filter((g) => !!g).map((g) => g.title));
};
Example #12
Source File: getFile.ts    From telegram-standup-bot with MIT License 6 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  let file_path = '';
  if (!req.query.file_id) {
    return res.status(400).json({ statusText: 'Bad Request' });
  }

  var download_url = `https://api.telegram.org/bot${process.env.TELEGRAM_API_KEY}/getFile?file_id=${req.query.file_id}`;
  const file = await fetch(download_url);
  const json = await file.json();
  if (json?.ok) {
    file_path = `https://api.telegram.org/file/bot${process.env.TELEGRAM_API_KEY}/${json?.result?.file_path}`;
  }

  var tmp = json?.result?.file_path.split('/');
  const response = await fetch(file_path);

  res.setHeader('content-disposition', `attachment; filename=${tmp.pop()}`);

  // @ts-ignore - pipeline weird issue
  await pipeline(response.body, res);
};
Example #13
Source File: standup.ts    From telegram-standup-bot with MIT License 5 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  if (req.query.key !== process.env.TELEGRAM_API_KEY) {
    return res.status(401).json({ status: 'invalid api key' });
  }

  const { body } = req;

  let message = body?.message || body?.edited_message;
  const { chat, entities, text, message_id, from } = message || {};

  // Don't try to parse this message if missing info
  if (!message || !Object.keys(message).some((a) => telegramTypes[a])) {
    console.log('Quitting early', message, body);
    // This has to be a 200 or else Telegram will try to resend it
    return res.status(200).json({ status: 'invalid' });
  }

  // Between you and the bot in a public group
  const inGroup = chat?.type === 'group' || chat?.type === 'supergroup';
  const isBotCommand = entities?.[0]?.type === 'bot_command';
  const isGroupCommand = inGroup && isBotCommand;
  const isMembersCommand = isGroupCommand && text?.includes('/members');
  const isSubscribeCommand =
    (isGroupCommand && text?.includes('/subscribe')) || text?.includes('/join');
  const isUnsubscribeCommand = isGroupCommand && text?.includes('/unsubscribe');

  // Between you and the bot in a private chat
  const isPrivateMessage = chat?.type === 'private';
  const isPrivateCommand = isBotCommand && isPrivateMessage;
  const isStartCommand = isPrivateCommand && text?.includes('/start');

  if (isStartCommand) {
    await startBot(from.id);
    const r = await sendMsg(START_MESSAGE, chat.id, message_id);
    return res.json({ status: r.status });
  }

  // We only accept start command as a private command
  if (isPrivateCommand) {
    const r = await sendMsg(INVALID_PRIVATE_MESSAGE, chat.id, message_id);
    return res.json({ status: r.status });
  }

  // Private to the bot, must be a standup update so lets save it
  if (isPrivateMessage) {
    const r = await submitStandup(chat.id, from.id, message_id, body);
    const status = r?.status || 200;
    return res.json({ status });
  }

  // In a group
  if (isSubscribeCommand) {
    const r = await addToStandupGroup(
      chat.id,
      from.id,
      chat.title,
      from,
      message_id
    );
    return res.json({ status: r.status });
  }

  // In a group
  if (isMembersCommand) {
    const r = await getMembers(chat.id, from.id, chat.title, from, message_id);
    return res.json({ status: r.status });
  }

  // In a group
  if (isUnsubscribeCommand) {
    const r = await leaveStandupGroup(chat.id, from.id, message_id);
    return res.json({ status: r.status });
  }

  return res.status(200).json({ status: 'invalid command' });
};
Example #14
Source File: updates.ts    From telegram-standup-bot with MIT License 5 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  const isValid = checkSignature(req?.body || {});

  if (!isValid && process.env.NODE_ENV === 'production') {
    return res.status(401).json({ statusText: 'Unauthorized' });
  }

  const { db } = await connectToDatabase();
  const { value: user } = await db.collection('users').findOneAndUpdate(
    { userId: req.body.id },
    {
      $set: {
        about: req?.body,
      },
    }
  );

  if (!user) {
    return res.status(404).json({ statusText: 'User not found' });
  }

  // Get updates for one user
  if (req.query.userId) {
    const page = req.query.page || 1;
    const userId = req.query.userId;
    const updates = await db
      .collection('users')
      .find({
        userId: Number(userId),
        // To make sure they're allowed to query this user ID
        'groups.chatId': {
          $in: user?.groups?.map((g) => g?.chatId).filter((g) => !!g) || [],
        },
      })
      .project({ updateArchive: { $slice: -10 } })
      .toArray();

    if (updates && Array.isArray(updates)) {
      let response = [];
      updates.forEach((r) => transformUpdate(r, response));

      return res.status(200).json(response);
    }

    return res.status(404).json({ statusText: 'User not found' });
  }

  const groupUpdates = await db
    .collection('users')
    .find({
      'groups.chatId': {
        $in: user?.groups?.map((g) => g?.chatId).filter((g) => !!g) || [],
      },
    })
    .project({ updateArchive: { $slice: -10 } })
    .toArray();

  let response = [];
  groupUpdates.map((r) => transformUpdate(r, response));

  return res.status(200).json(response);
};
Example #15
Source File: index.ts    From vercel-badge with MIT License 5 votes vote down vote up
export default function handler(req: VercelRequest, res: VercelResponse) {
  res.json({
    message:
      "Use /[owner]/[repo] to get a Vercel deployment badge for your github repository!",
  });
}
Example #16
Source File: blockhash.ts    From octane with Apache License 2.0 5 votes vote down vote up
// Endpoint to get the most recent blockhash seen by Octane's RPC node
export default async function (request: VercelRequest, response: VercelResponse) {
    await rateLimit(request, response);

    const blockhash = await connection.getRecentBlockhash();

    response.status(200).send({ blockhash });
}
Example #17
Source File: index.ts    From octane with Apache License 2.0 5 votes vote down vote up
// Endpoint to get Octane's configuration
export default async function (request: VercelRequest, response: VercelResponse) {
    await rateLimit(request, response);

    response.status(200).send(body);
}
Example #18
Source File: transfer.ts    From octane with Apache License 2.0 5 votes vote down vote up
// Endpoint to pay for transactions with an SPL token transfer
export default async function (request: VercelRequest, response: VercelResponse) {
    await cors(request, response);
    await rateLimit(request, response);

    // Deserialize a base58 wire-encoded transaction from the request
    const serialized = request.body?.transaction;
    if (typeof serialized !== 'string') throw new Error('invalid transaction');
    const transaction = Transaction.from(base58.decode(serialized));

    // Prevent simple duplicate transactions using a hash of the message
    let key = `transaction/${base58.encode(sha256(transaction.serializeMessage()))}`;
    if (await cache.get(key)) throw new Error('duplicate transaction');
    await cache.set(key, true);

    // Check that the transaction is basically valid, sign it, and serialize it, verifying the signatures
    const { signature, rawTransaction } = await validateTransaction(transaction);

    // Check that the transaction contains a valid transfer to Octane's token account
    const transfer = await validateTransfer(transaction);

    /*
       An attacker could make multiple signing requests before the transaction is confirmed. If the source token account
       has the minimum fee balance, validation and simulation of all these requests may succeed. All but the first
       confirmed transaction will fail because the account will be empty afterward. To prevent this race condition,
       simulation abuse, or similar attacks, we implement a simple lockout for the source token account until the
       transaction succeeds or fails.
     */
    key = `transfer/${transfer.keys.source.pubkey.toBase58()}`;
    if (await cache.get(key)) throw new Error('duplicate transfer');
    await cache.set(key, true);

    try {
        // Simulate, send, and confirm the transaction
        await simulateRawTransaction(rawTransaction);
        await sendAndConfirmRawTransaction(connection, rawTransaction, { commitment: 'confirmed' });
    } finally {
        await cache.del(key);
    }

    // Respond with the confirmed transaction signature
    response.status(200).send({ signature });
}
Example #19
Source File: discord.ts    From linear-discord-serverless with MIT License 5 votes vote down vote up
export default async function handler(
	req: VercelRequest,
	res: VercelResponse,
): Promise<void> {
	if (!req.method || req.method.toUpperCase() !== 'POST') {
		return void res.status(405).json({
			success: false,
			message: `Cannot ${req.method} this endpoint. Must be POST`,
		});
	}

	const {id, token} = req.query as {
		id: string;
		token: string;
	};

	const body = req.body as Partial<IncomingLinearWebhookPayload> | undefined;

	if (!body || !body.type || !body.action || !body.data) {
		return void res.status(422).json({
			success: false,
			message: 'No body sent',
		});
	}

	if (!['create', 'update'].includes(body.action)) {
		return void res.json({
			success: false,
			message: 'This is for creation or update of issues only!',
		});
	}

	if (!body.url) {
		return void res.json({
			success: false,
			message: 'No Issue URL was sent',
		});
	}

	const options = [
		{action: body.action, url: body.url},
		{id, token},
	] as const;

	try {
		if (body.type === 'Issue') {
			await sendIssue(body.data, ...options);
		} else if (body.type === 'Comment') {
			await sendComment(body.data, ...options);
		} else {
			return void res.json({
				success: false,
				message: 'You ',
			});
		}

		return void res.json({
			success: true,
			message: 'Success, webhook has been sent.',
		});
	} catch (e) {
		const url = `https://discord.com/api/webhooks/${id}/${token}`;
		await exec(
			url,
			error(e instanceof Error ? e.message : 'something went wrong'),
		);

		return void res.status(500).json({
			success: false,
			message: `Something went wrong: ${
				e instanceof Error ? e.message : 'unknown errors'
			}`,
		});
	}
}
Example #20
Source File: ApolloServer.ts    From apollo-server-vercel with MIT License 5 votes vote down vote up
async createGraphQLServerOptions(req: VercelRequest, res: VercelResponse): Promise<GraphQLOptions> {
    return super.graphQLServerOptions({ req, res });
  }
Example #21
Source File: webhooks.ts    From discord-ifttt with MIT License 5 votes vote down vote up
webhooks = async (request: VercelRequest, response: VercelResponse) => {
	if (request.method !== 'POST') {
		response.status(405).send('this route supports POST only!')
		return
	}

	const {id, token, wait, thread_id} = request.query
	const parameters = new URLSearchParams()
	if (wait) {
		parameters.append('wait', String(wait))
	}

	if (thread_id) {
		parameters.append('thread_id', String(thread_id))
	}

	const url = new URL(`https://discord.com/api/webhooks/${id}/${token}?${parameters}`).toString()

	const contentType = request.headers['content-type']!.split(';')[0]

	switch (contentType) {
		case 'application/json': {
			try {
				const {body} = request

				await dynamicSleep(`${id}-${token}`)

				axios
					.post(url, body)
					.then(res => {
						response.status(res.status).send(res.data)
					})
					.catch(error => {
						handleError(error, response)
					})
			} catch (error: any) {
				response
					.status(400)
					.send({error: error.message})
			}

			break
		}

		case 'text/plain': {
			const body: string = request.body.trim().slice(0, 2000)
			if (body.length === 0) {
				response.status(400).send({error: 'empty body'})
				return
			}

			await dynamicSleep(`${id}-${token}`)

			axios
				.post(url, {content: body})
				.then(res => {
					response.status(res.status).send(res.data)
				})
				.catch(error => {
					handleError(error, response)
				})
			break
		}

		default: {
			response.status(415).send({error: 'This Content-Type is not supported! Use "application/json" or "text/plain".'})
			break
		}
	}
}
Example #22
Source File: [repo].ts    From vercel-badge with MIT License 4 votes vote down vote up
export default function handler(req: VercelRequest, res: VercelResponse) {
  const { owner, repo } = req.query;

  if (!owner || typeof owner !== "string") {
    res.statusCode = 400;
    return res.json({ message: "Please input the repository owner!" });
  }

  if (!repo || typeof repo !== "string") {
    res.statusCode = 400;
    return res.json({ message: "Please input the repository name!" });
  }

  let style;
  if (!req.query.style) style = "flat";
  else if (
    req.query.style === "flat" ||
    req.query.style === "flat-square" ||
    req.query.style === "for-the-badge" ||
    req.query.style === "plastic"
  )
    style = req.query.style;

  axios
    .get(`https://api.github.com/repos/${owner}/${repo}/deployments`, {
      headers: {
        Authorization: `Basic ${Buffer.from(
          `${process.env.ID}:${process.env.SECRET}`
        ).toString("base64")}`,
      },
    })
    .then((response) => {
      if (response.data.length <= 0) {
        res.setHeader("Content-Type", "image/svg+xml");
        return fs
          .createReadStream(
            path.join(__dirname, `../../assets/${style}/none.svg`)
          )
          .pipe(res);
      }

      const vercelDeployments = response.data.filter(
        (deployment) =>
          deployment.creator.login === "vercel[bot]" &&
          deployment.creator.html_url === "https://github.com/apps/vercel" &&
          deployment.creator.type === "Bot"
      );

      if (vercelDeployments.length <= 0) {
        res.setHeader("Content-Type", "image/svg+xml");
        return fs
          .createReadStream(
            path.join(__dirname, `../../assets/${style}/none.svg`)
          )
          .pipe(res);
      }

      const latest = vercelDeployments[0];

      axios
        .get(latest.statuses_url, {
          headers: {
            Authorization: `Basic ${Buffer.from(
              `${process.env.ID}:${process.env.SECRET}`
            ).toString("base64")}`,
          },
        })
        .then((response) => {
          res.setHeader("Content-Type", "image/svg+xml");
          if (response.data[0].state === "success")
            return fs
              .createReadStream(
                path.join(__dirname, `../../assets/${style}/passing.svg`)
              )
              .pipe(res);
          else if (response.data[0].state === "failure")
            return fs
              .createReadStream(
                path.join(__dirname, `../../assets/${style}/failed.svg`)
              )
              .pipe(res);
          else if (response.data[0].state === "pending")
            return fs
              .createReadStream(
                path.join(__dirname, `../../assets/${style}/pending.svg`)
              )
              .pipe(res);
        });
    })
    .catch((error) => {
      res.setHeader("Content-Type", "image/svg+xml");
      return fs
        .createReadStream(
          path.join(__dirname, `../../assets/${style}/error.svg`)
        )
        .pipe(res);
    });
}
Example #23
Source File: send.ts    From telegram-standup-bot with MIT License 4 votes vote down vote up
module.exports = async (req: VercelRequest, res: VercelResponse) => {
  if (
    process.env.NODE_ENV === 'production' &&
    req.query.key !== process.env.TELEGRAM_API_KEY
  ) {
    return res.status(401).json({ status: 'invalid api key' });
  }

  const { previousSubmitTimestamp, nextSubmitTimestamp } = getSubmissionDates();

  const { db } = await connectToDatabase();

  const markAllSent = async () => {
    console.log('Marking as sent');

    const response = await db.collection('users').updateMany(
      {
        'updateArchive.sent': false,
      },
      { $set: { 'updateArchive.$[elem].sent': true, submitted: false } },
      {
        arrayFilters: [
          {
            'elem.sent': false,
          },
        ],
        multi: true,
      }
    );

    console.log(response);
  };

  let groupUpdates = [];

  groupUpdates = await db
    .collection('users')
    .aggregate([
      {
        $project: { updateArchive: 1, groups: 1, about: 1 },
      },
      {
        $unwind: '$updateArchive',
      },
      {
        $match: {
          'updateArchive.sent': false,
        },
      },
      {
        $group: {
          _id: '$about.id',
          about: { $first: '$about' },
          groups: { $first: '$groups' },
          updateArchive: { $push: '$updateArchive' },
        },
      },
    ])
    .toArray();

  const sent = {};
  const sendUpdatePromises = [];

  const totalMedia = {};

  groupUpdates
    .filter((g: Member) => !!g.groups.length && !!g.updateArchive)
    .forEach((user: Member) => {
      user.updateArchive.forEach((update: UpdateArchive) => {
        const id =
          update.body?.message?.media_group_id ||
          update.body?.message?.message_id;

        if (
          Array.isArray(totalMedia[user.about.id]) &&
          totalMedia[user.about.id].includes(id)
        )
          return;

        totalMedia[user.about.id] = Array.isArray(totalMedia[user.about.id])
          ? [...totalMedia[user.about.id], id]
          : [id];
      });
    });

  groupUpdates
    .filter((g: Member) => !!g.groups.length && !!g.updateArchive)
    .forEach((user: Member) => {
      user.groups
        .filter((g) => !!g)
        .forEach((group: StandupGroup) => {
          // only send update to this group if the user won for this group!
          if (!group || !group?.winner) {
            return;
          }

          const chat_id = group.chatId;
          let total = user.updateArchive.length;
          let prefixTotal = 1;

          user.updateArchive.forEach((update: UpdateArchive) => {
            total = totalMedia[user.about.id].length;

            const body = update?.body || {};
            const groupId = body?.message?.media_group_id;
            const type = groupId ? 'group' : update?.type || 'text';

            if (
              Array.isArray(sent[chat_id]) &&
              sent[chat_id].includes(groupId)
            ) {
              console.log(groupId, 'already sent');
              return true;
            }

            if (type === 'group') {
              sent[chat_id] = Array.isArray(sent[chat_id])
                ? [...sent[chat_id], groupId]
                : [groupId];
            }

            const prefix =
              total > 1
                ? `${prefixTotal}/${total}: ${user.about.first_name}`
                : `- ${user.about.first_name}`;

            sendUpdatePromises.push(
              sendMsg(
                prefix,
                group.chatId,
                null,
                true,
                update,
                user.updateArchive
              )
            );

            prefixTotal += 1;
          });
        });
    });

  await Promise.all(sendUpdatePromises);

  if (sendUpdatePromises.length) {
    await markAllSent();
  } else {
    console.log('nothing to send');
  }

  // Next round of users getting chosen!
  await setWinners();

  return res.status(200).json({ status: 'ok' });
};
Example #24
Source File: ApolloServer.ts    From apollo-server-vercel with MIT License 4 votes vote down vote up
public createHandler({ cors, onHealthCheck }: CreateHandlerOptions = {}): VercelApiHandler {
    const corsHeaders = new Map();

    if (cors) {
      if (cors.methods) {
        if (typeof cors.methods === `string`) {
          corsHeaders.set(`access-control-allow-methods`, cors.methods);
        } else if (Array.isArray(cors.methods)) {
          corsHeaders.set(`access-control-allow-methods`, cors.methods.join(`,`));
        }
      }

      if (cors.allowedHeaders) {
        if (typeof cors.allowedHeaders === `string`) {
          corsHeaders.set(`access-control-allow-headers`, cors.allowedHeaders);
        } else if (Array.isArray(cors.allowedHeaders)) {
          corsHeaders.set(`access-control-allow-headers`, cors.allowedHeaders.join(`,`));
        }
      }

      if (cors.exposedHeaders) {
        if (typeof cors.exposedHeaders === `string`) {
          corsHeaders.set(`access-control-expose-headers`, cors.exposedHeaders);
        } else if (Array.isArray(cors.exposedHeaders)) {
          corsHeaders.set(`access-control-expose-headers`, cors.exposedHeaders.join(`,`));
        }
      }

      if (cors.credentials) {
        corsHeaders.set(`access-control-allow-credentials`, `true`);
      }
      if (typeof cors.maxAge === `number`) {
        corsHeaders.set(`access-control-max-age`, cors.maxAge.toString());
      }
    }

    return async (req: VercelRequest, res: VercelResponse): Promise<void> => {
      const willStart = this.willStart();
      const requestCorsHeaders = new Map(corsHeaders);

      if (cors?.origin) {
        const requestOrigin = req.headers.origin;
        if (typeof cors.origin === `string`) {
          requestCorsHeaders.set(`access-control-allow-origin`, cors.origin);
        } else if (
          requestOrigin &&
          (typeof cors.origin === `boolean` ||
            (Array.isArray(cors.origin) && requestOrigin && cors.origin.includes(requestOrigin)))
        ) {
          requestCorsHeaders.set(`access-control-allow-origin`, requestOrigin);
        }

        const requestAccessControlRequestHeaders = req.headers[`access-control-request-headers`];
        if (!cors.allowedHeaders && requestAccessControlRequestHeaders) {
          requestCorsHeaders.set(`access-control-allow-headers`, requestAccessControlRequestHeaders);
        }
      }

      const requestCorsHeadersObject = Array.from(requestCorsHeaders).reduce<Record<string, string>>(
        (headersObject, [key, value]) => {
          headersObject[key] = value;
          return headersObject;
        },
        {}
      );

      if (req.method === `OPTIONS`) {
        setHeaders(res, requestCorsHeadersObject);
        res.status(204).send(``);
        return;
      }

      if (req.url === `/.well-known/apollo/server-health`) {
        const successfulResponse = (): VercelResponse => {
          setHeaders(res, {
            "Content-Type": `application/json`,
            ...requestCorsHeadersObject
          });
          return res.status(200).json({ status: `pass` });
        };
        if (onHealthCheck) {
          try {
            void onHealthCheck(req);
            successfulResponse();
          } catch {
            setHeaders(res, {
              "Content-Type": `application/json`,
              ...requestCorsHeadersObject
            });
            res.status(503).json({ status: `fail` });
            return;
          }
        } else {
          successfulResponse();
          return;
        }
      }

      if (this.playgroundOptions && req.method === `GET`) {
        const acceptHeader = req.headers.Accept ?? req.headers.accept;
        if (acceptHeader?.includes(`text/html`)) {
          const path = req.url ?? `/`;
          const playgroundRenderPageOptions: PlaygroundRenderPageOptions = {
            endpoint: path,
            ...this.playgroundOptions
          };

          setHeaders(res, {
            "Content-Type": `text/html`,
            ...requestCorsHeadersObject
          });
          res.status(200).send(renderPlaygroundPage(playgroundRenderPageOptions));
          return;
        }
      }

      type NextFunction = () => Promise<void>;

      const fileUploadHandler = async (next: NextFunction): Promise<void> => {
        const contentType = req.headers[`content-type`] ?? req.headers[`Content-Type`];
        if (
          contentType &&
          (contentType as string).startsWith(`multipart/form-data`) &&
          typeof processFileUploads === `function`
        ) {
          try {
            // eslint-disable-next-line require-atomic-updates
            req.body = await processFileUploads(req, res, this.uploadsConfig ?? {});
            await next();
          } catch (error: unknown) {
            if (error instanceof Error) {
              // eslint-disable-next-line @typescript-eslint/no-throw-literal
              throw formatApolloErrors([error], {
                formatter: this.requestOptions.formatError,
                debug: this.requestOptions.debug
              });
            }
          }
        } else {
          await next();
        }
      };

      const handleGraphQLRequest = async (): Promise<void> => {
        await willStart;
        if (cors) {
          setHeaders(res, {
            ...requestCorsHeadersObject
          });
        }
        const options = await this.createGraphQLServerOptions(req, res);
        graphqlVercel(options)(req, res);
      };

      await fileUploadHandler(handleGraphQLRequest);
    };
  }