next.js/packages/next/src/server/lib/postponed-request-body.ts
postponed-request-body.ts62 lines1.8 KB
import {
  DEFAULT_MAX_POSTPONED_STATE_SIZE,
  parseMaxPostponedStateSize,
} from '../../shared/lib/size-limit'
import type { SizeLimit } from '../../types'

const INVALID_MAX_POSTPONED_STATE_SIZE_ERROR_MESSAGE =
  'maxPostponedStateSize must be a valid number (bytes) or filesize format string (e.g., "5mb")'

export type PostponedRequestBodyChunk = Buffer | Uint8Array | string

export function getMaxPostponedStateSize(
  configuredMaxPostponedStateSize: SizeLimit | undefined
): {
  maxPostponedStateSize: SizeLimit
  maxPostponedStateSizeBytes: number
} {
  const maxPostponedStateSize =
    configuredMaxPostponedStateSize ?? DEFAULT_MAX_POSTPONED_STATE_SIZE
  const maxPostponedStateSizeBytes = parseMaxPostponedStateSize(
    configuredMaxPostponedStateSize
  )

  if (maxPostponedStateSizeBytes === undefined) {
    throw new Error(INVALID_MAX_POSTPONED_STATE_SIZE_ERROR_MESSAGE)
  }

  return { maxPostponedStateSize, maxPostponedStateSizeBytes }
}

export function getPostponedStateExceededErrorMessage(
  maxPostponedStateSize: SizeLimit
): string {
  return (
    `Postponed state exceeded ${maxPostponedStateSize} limit. ` +
    `To configure the limit, see: https://nextjs.org/docs/app/api-reference/config/next-config-js/max-postponed-state-size`
  )
}

function toBuffer(chunk: PostponedRequestBodyChunk): Buffer {
  return Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
}

export async function readBodyWithSizeLimit(
  body: AsyncIterable<PostponedRequestBodyChunk>,
  maxBodySizeBytes: number
): Promise<Buffer | null> {
  const chunks: Array<Buffer> = []
  let size = 0

  for await (const chunk of body) {
    const buffer = toBuffer(chunk)
    size += buffer.byteLength
    if (size > maxBodySizeBytes) {
      return null
    }
    chunks.push(buffer)
  }

  return Buffer.concat(chunks)
}
Quest for Codev2.0.0
/
SIGN IN