2022-02-17 19:21:40 +01:00
import type { HtmlProps } from './html-context'
2021-07-21 18:12:33 +02:00
import type { ComponentType } from 'react'
import type { DomainLocale } from '../../server/config'
import type { Env } from '@next/env'
import type { IncomingMessage , ServerResponse } from 'http'
import type { NextRouter } from './router/router'
import type { ParsedUrlQuery } from 'querystring'
import type { PreviewData } from 'next/types'
2022-08-12 15:01:19 +02:00
import { COMPILER_NAMES } from './constants'
2019-04-22 19:55:03 +02:00
2019-05-23 21:31:22 +02:00
export type NextComponentType <
C extends BaseContext = NextPageContext ,
IP = { } ,
P = { }
> = ComponentType < P > & {
2019-12-03 19:35:20 +01:00
/ * *
* Used for initial page load data population . Data returned from ` getInitialProps ` is serialized when server rendered .
* Make sure to return plain ` Object ` without using ` Date ` , ` Map ` , ` Set ` .
* @param ctx Context of ` page `
* /
2019-07-07 20:52:59 +02:00
getInitialProps ? ( context : C ) : IP | Promise < IP >
2019-04-22 19:55:03 +02:00
}
2019-05-23 21:31:22 +02:00
export type DocumentType = NextComponentType <
DocumentContext ,
DocumentInitialProps ,
DocumentProps
2021-08-13 05:36:54 +02:00
>
2019-04-22 19:55:03 +02:00
2022-09-09 22:32:58 +02:00
export type AppType < P = {} > = NextComponentType <
2019-05-23 21:31:22 +02:00
AppContextType ,
2022-09-09 22:32:58 +02:00
P ,
AppPropsType < any , P >
2019-05-23 21:31:22 +02:00
>
2019-04-22 19:55:03 +02:00
2019-09-09 18:23:34 +02:00
export type AppTreeType = ComponentType <
AppInitialProps & { [ name : string ] : any }
>
2020-07-03 05:36:13 +02:00
/ * *
* Web vitals provided to _app . reportWebVitals by Core Web Vitals plugin developed by Google Chrome team .
* https : //nextjs.org/blog/next-9-4#integrated-web-vitals-reporting
* /
add attribution to web vitals (#39368)
This commit implements the main proposal presented in
https://github.com/vercel/next.js/issues/39241
to add attribution to web vitals.
Attribution adds more specific debugging info to web vitals,
for example in the case of Cumulative Layout Shift (CLS),
we might want to know
> What's the first element that shifted when the single largest layout shift occurred?
on in the case of Largest Contentful Paint (LCP),
> What's the element corresponding to the LCP for the page?
> If it is an image, what's the URL of the image resource?
Attribution is *disabled* by default because it could potentially
generate a lot data and overwhelm the RUM backend.
It is enabled *per metric* (LCP, FCP, CLS, etc)
As part of this change, `web-vitals` has been upgraded to v3.0.0
This version contains minor bug fixes, please see changelog at
https://github.com/GoogleChrome/web-vitals/commit/9fe3cc02c875cb70ac0f1803f5e11b428e7a4014
Fixes #39241
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] 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 by running `pnpm lint`
- [x] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
2022-10-04 02:17:30 +02:00
export const WEB_VITALS = [ 'CLS' , 'FCP' , 'FID' , 'INP' , 'LCP' , 'TTFB' ] as const
2020-07-03 05:36:13 +02:00
export type NextWebVitalsMetric = {
id : string
startTime : number
value : number
add attribution to web vitals (#39368)
This commit implements the main proposal presented in
https://github.com/vercel/next.js/issues/39241
to add attribution to web vitals.
Attribution adds more specific debugging info to web vitals,
for example in the case of Cumulative Layout Shift (CLS),
we might want to know
> What's the first element that shifted when the single largest layout shift occurred?
on in the case of Largest Contentful Paint (LCP),
> What's the element corresponding to the LCP for the page?
> If it is an image, what's the URL of the image resource?
Attribution is *disabled* by default because it could potentially
generate a lot data and overwhelm the RUM backend.
It is enabled *per metric* (LCP, FCP, CLS, etc)
As part of this change, `web-vitals` has been upgraded to v3.0.0
This version contains minor bug fixes, please see changelog at
https://github.com/GoogleChrome/web-vitals/commit/9fe3cc02c875cb70ac0f1803f5e11b428e7a4014
Fixes #39241
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] 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 by running `pnpm lint`
- [x] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
2022-10-04 02:17:30 +02:00
attribution ? : { [ key : string ] : unknown }
2021-07-20 03:39:24 +02:00
} & (
| {
label : 'web-vital'
add attribution to web vitals (#39368)
This commit implements the main proposal presented in
https://github.com/vercel/next.js/issues/39241
to add attribution to web vitals.
Attribution adds more specific debugging info to web vitals,
for example in the case of Cumulative Layout Shift (CLS),
we might want to know
> What's the first element that shifted when the single largest layout shift occurred?
on in the case of Largest Contentful Paint (LCP),
> What's the element corresponding to the LCP for the page?
> If it is an image, what's the URL of the image resource?
Attribution is *disabled* by default because it could potentially
generate a lot data and overwhelm the RUM backend.
It is enabled *per metric* (LCP, FCP, CLS, etc)
As part of this change, `web-vitals` has been upgraded to v3.0.0
This version contains minor bug fixes, please see changelog at
https://github.com/GoogleChrome/web-vitals/commit/9fe3cc02c875cb70ac0f1803f5e11b428e7a4014
Fixes #39241
## Bug
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
## Feature
- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] 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 by running `pnpm lint`
- [x] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
2022-10-04 02:17:30 +02:00
name : typeof WEB_VITALS [ number ]
2021-07-20 03:39:24 +02:00
}
| {
label : 'custom'
name :
| 'Next.js-hydration'
| 'Next.js-route-change-to-render'
| 'Next.js-render'
}
)
2020-07-03 05:36:13 +02:00
2019-04-22 19:55:03 +02:00
export type Enhancer < C > = ( Component : C ) = > C
export type ComponentsEnhancer =
2019-05-23 21:31:22 +02:00
| {
enhanceApp? : Enhancer < AppType >
2019-05-29 13:57:26 +02:00
enhanceComponent? : Enhancer < NextComponentType >
2019-05-23 21:31:22 +02:00
}
2019-04-22 19:55:03 +02:00
| Enhancer < NextComponentType >
2019-05-23 21:31:22 +02:00
export type RenderPageResult = {
html : string
head? : Array < JSX.Element | null >
}
2019-04-22 19:55:03 +02:00
2019-05-23 21:31:22 +02:00
export type RenderPage = (
2019-05-29 13:57:26 +02:00
options? : ComponentsEnhancer
2021-09-09 10:13:50 +02:00
) = > DocumentInitialProps | Promise < DocumentInitialProps >
2019-04-22 19:55:03 +02:00
2019-04-26 09:37:57 +02:00
export type BaseContext = {
2019-04-22 19:55:03 +02:00
res? : ServerResponse
2019-05-29 13:57:26 +02:00
[ k : string ] : any
2019-04-22 19:55:03 +02:00
}
2019-05-06 23:42:04 +02:00
export type NEXT_DATA = {
2020-08-14 00:19:06 +02:00
props : Record < string , any >
2019-04-22 19:55:03 +02:00
page : string
query : ParsedUrlQuery
buildId : string
assetPrefix? : string
runtimeConfig ? : { [ key : string ] : any }
nextExport? : boolean
2019-09-15 20:35:14 +02:00
autoExport? : boolean
2020-02-07 14:09:06 +01:00
isFallback? : boolean
2021-04-21 13:18:05 +02:00
dynamicIds ? : ( string | number ) [ ]
2022-08-12 15:01:19 +02:00
err? : Error & {
statusCode? : number
source? : typeof COMPILER_NAMES . server | typeof COMPILER_NAMES . edgeServer
}
2020-03-03 19:39:08 +01:00
gsp? : boolean
gssp? : boolean
2020-03-06 17:14:39 +01:00
customServer? : boolean
2020-04-13 11:59:49 +02:00
gip? : boolean
appGip? : boolean
2020-10-07 23:11:01 +02:00
locale? : string
locales? : string [ ]
2020-10-08 13:12:17 +02:00
defaultLocale? : string
2021-07-21 18:12:33 +02:00
domainLocales? : DomainLocale [ ]
2021-03-02 20:17:33 +01:00
scriptLoader? : any [ ]
2021-02-18 19:34:33 +01:00
isPreview? : boolean
2022-02-16 19:53:48 +01:00
notFoundSrcPage? : string
2019-04-22 19:55:03 +02:00
}
2019-05-23 21:31:22 +02:00
/ * *
* ` Next ` context
* /
2019-05-06 23:42:04 +02:00
export interface NextPageContext {
2019-05-23 21:31:22 +02:00
/ * *
* Error object if encountered during rendering
* /
2019-11-11 04:24:53 +01:00
err ? : ( Error & { statusCode? : number } ) | null
2019-05-23 21:31:22 +02:00
/ * *
* ` HTTP ` request object .
* /
2019-04-22 19:55:03 +02:00
req? : IncomingMessage
2019-05-23 21:31:22 +02:00
/ * *
* ` HTTP ` response object .
* /
2019-04-22 19:55:03 +02:00
res? : ServerResponse
2019-05-23 21:31:22 +02:00
/ * *
* Path section of ` URL ` .
* /
2019-04-22 19:55:03 +02:00
pathname : string
2019-05-23 21:31:22 +02:00
/ * *
* Query string section of ` URL ` parsed as an object .
* /
2019-04-22 19:55:03 +02:00
query : ParsedUrlQuery
2019-05-23 21:31:22 +02:00
/ * *
* ` String ` of the actual path including query .
* /
2019-04-22 19:55:03 +02:00
asPath? : string
2021-05-22 18:35:57 +02:00
/ * *
* The currently active locale
* /
locale? : string
/ * *
* All configured locales
* /
locales? : string [ ]
/ * *
* The configured default locale
* /
defaultLocale? : string
2019-08-13 11:33:48 +02:00
/ * *
* ` Component ` the tree of the App to use if needing to render separately
* /
2019-09-09 18:23:34 +02:00
AppTree : AppTreeType
2019-04-22 19:55:03 +02:00
}
2019-07-11 19:35:39 +02:00
export type AppContextType < R extends NextRouter = NextRouter > = {
2019-05-06 23:42:04 +02:00
Component : NextComponentType < NextPageContext >
2019-09-09 18:23:34 +02:00
AppTree : AppTreeType
2019-05-29 13:57:26 +02:00
ctx : NextPageContext
2019-07-30 20:00:19 +02:00
router : R
2019-04-22 19:55:03 +02:00
}
2022-08-26 03:10:11 +02:00
export type AppInitialProps < P = any > = {
pageProps : P
2019-04-22 19:55:03 +02:00
}
2019-05-23 21:31:22 +02:00
export type AppPropsType <
2019-07-11 19:35:39 +02:00
R extends NextRouter = NextRouter ,
2019-05-23 21:31:22 +02:00
P = { }
2022-08-26 03:10:11 +02:00
> = AppInitialProps < P > & {
Component : NextComponentType < NextPageContext , any , any >
2019-05-29 13:57:26 +02:00
router : R
2020-03-06 05:15:10 +01:00
__N_SSG? : boolean
__N_SSP? : boolean
2019-04-22 19:55:03 +02:00
}
2019-05-06 23:42:04 +02:00
export type DocumentContext = NextPageContext & {
2019-05-29 13:57:26 +02:00
renderPage : RenderPage
2022-04-19 14:37:57 +02:00
defaultGetInitialProps (
ctx : DocumentContext ,
options ? : { nonce? : string }
) : Promise < DocumentInitialProps >
2019-04-22 19:55:03 +02:00
}
2019-04-26 09:37:57 +02:00
export type DocumentInitialProps = RenderPageResult & {
2022-05-23 06:00:36 +02:00
styles? : React.ReactElement [ ] | React . ReactFragment | JSX . Element
2019-04-22 19:55:03 +02:00
}
2021-08-13 05:36:54 +02:00
export type DocumentProps = DocumentInitialProps & HtmlProps
2019-04-22 19:55:03 +02:00
/ * *
2019-06-05 13:22:09 +02:00
* Next ` API ` route request
* /
2020-05-07 00:04:24 +02:00
export interface NextApiRequest extends IncomingMessage {
2019-06-05 13:22:09 +02:00
/ * *
* Object of ` query ` values from url
* /
fix NextApiRequestCookies and NextApiRequestQuery types (#25532)
Hello! Thanks for making next.js so great.
## Bug
Right now, these types give false confidence. These `key`s are treated as though [a value is defined for _every_ string](https://dev.to/sarioglu/avoiding-unintended-undefined-values-while-using-typescript-record-4igo). However, given an arbitrary request, a particular cookie or query param could be `undefined`.
For example, when building an `/api` endpoint, the code might look like this:
```ts
import type { NextApiRequest, NextApiResponse } from "next"
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// According to the old types, `value` is a string
const value = req.cookies.value
// Type-checking passes but leads to a runtime error when no `value` cookie is provided in the request
// Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
value.toLowerCause()
// ...
}
```
By using `Partial`, TypeScript now knows that these objects don't have values defined for every `key` and accessing a given `key` might resolve to `undefined`.
---
The only obvious error this caused within this repo was on line 333 of the same file. For better or worse, I ended up casting that cookie value to a `string`. There's a series of `if` statements before it that, I guess, are guaranteeing that it's truly a string. Potentially, that stretch could be refactored such that TypeScript _knows_ it's a string.
Also, I tried to follow the contributing guidelines. However, running `yarn types` kicked out a bunch of errors about overwriting files:
```
$ yarn types
yarn run v1.22.10
$ lerna run types --stream
lerna notice cli v4.0.0
lerna info Executing command in 2 packages: "yarn run types"
@next/env: $ tsc index.ts --declaration --emitDeclarationOnly --declarationDir types --esModuleInterop
next: $ tsc --declaration --emitDeclarationOnly --declarationDir dist
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/index.d.ts' because it would overwrite input file.
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/webpack/plugins/build-manifest-plugin.d.ts' because it would overwrite input file.
...
...
...
```
Let me know if there's anything I can improve here! Thanks again.
2022-05-23 02:48:26 +02:00
query : Partial < {
2019-06-05 13:22:09 +02:00
[ key : string ] : string | string [ ]
fix NextApiRequestCookies and NextApiRequestQuery types (#25532)
Hello! Thanks for making next.js so great.
## Bug
Right now, these types give false confidence. These `key`s are treated as though [a value is defined for _every_ string](https://dev.to/sarioglu/avoiding-unintended-undefined-values-while-using-typescript-record-4igo). However, given an arbitrary request, a particular cookie or query param could be `undefined`.
For example, when building an `/api` endpoint, the code might look like this:
```ts
import type { NextApiRequest, NextApiResponse } from "next"
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// According to the old types, `value` is a string
const value = req.cookies.value
// Type-checking passes but leads to a runtime error when no `value` cookie is provided in the request
// Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
value.toLowerCause()
// ...
}
```
By using `Partial`, TypeScript now knows that these objects don't have values defined for every `key` and accessing a given `key` might resolve to `undefined`.
---
The only obvious error this caused within this repo was on line 333 of the same file. For better or worse, I ended up casting that cookie value to a `string`. There's a series of `if` statements before it that, I guess, are guaranteeing that it's truly a string. Potentially, that stretch could be refactored such that TypeScript _knows_ it's a string.
Also, I tried to follow the contributing guidelines. However, running `yarn types` kicked out a bunch of errors about overwriting files:
```
$ yarn types
yarn run v1.22.10
$ lerna run types --stream
lerna notice cli v4.0.0
lerna info Executing command in 2 packages: "yarn run types"
@next/env: $ tsc index.ts --declaration --emitDeclarationOnly --declarationDir types --esModuleInterop
next: $ tsc --declaration --emitDeclarationOnly --declarationDir dist
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/index.d.ts' because it would overwrite input file.
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/webpack/plugins/build-manifest-plugin.d.ts' because it would overwrite input file.
...
...
...
```
Let me know if there's anything I can improve here! Thanks again.
2022-05-23 02:48:26 +02:00
} >
2019-06-05 13:22:09 +02:00
/ * *
* Object of ` cookies ` from header
* /
fix NextApiRequestCookies and NextApiRequestQuery types (#25532)
Hello! Thanks for making next.js so great.
## Bug
Right now, these types give false confidence. These `key`s are treated as though [a value is defined for _every_ string](https://dev.to/sarioglu/avoiding-unintended-undefined-values-while-using-typescript-record-4igo). However, given an arbitrary request, a particular cookie or query param could be `undefined`.
For example, when building an `/api` endpoint, the code might look like this:
```ts
import type { NextApiRequest, NextApiResponse } from "next"
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// According to the old types, `value` is a string
const value = req.cookies.value
// Type-checking passes but leads to a runtime error when no `value` cookie is provided in the request
// Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
value.toLowerCause()
// ...
}
```
By using `Partial`, TypeScript now knows that these objects don't have values defined for every `key` and accessing a given `key` might resolve to `undefined`.
---
The only obvious error this caused within this repo was on line 333 of the same file. For better or worse, I ended up casting that cookie value to a `string`. There's a series of `if` statements before it that, I guess, are guaranteeing that it's truly a string. Potentially, that stretch could be refactored such that TypeScript _knows_ it's a string.
Also, I tried to follow the contributing guidelines. However, running `yarn types` kicked out a bunch of errors about overwriting files:
```
$ yarn types
yarn run v1.22.10
$ lerna run types --stream
lerna notice cli v4.0.0
lerna info Executing command in 2 packages: "yarn run types"
@next/env: $ tsc index.ts --declaration --emitDeclarationOnly --declarationDir types --esModuleInterop
next: $ tsc --declaration --emitDeclarationOnly --declarationDir dist
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/index.d.ts' because it would overwrite input file.
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/webpack/plugins/build-manifest-plugin.d.ts' because it would overwrite input file.
...
...
...
```
Let me know if there's anything I can improve here! Thanks again.
2022-05-23 02:48:26 +02:00
cookies : Partial < {
2019-06-05 13:22:09 +02:00
[ key : string ] : string
fix NextApiRequestCookies and NextApiRequestQuery types (#25532)
Hello! Thanks for making next.js so great.
## Bug
Right now, these types give false confidence. These `key`s are treated as though [a value is defined for _every_ string](https://dev.to/sarioglu/avoiding-unintended-undefined-values-while-using-typescript-record-4igo). However, given an arbitrary request, a particular cookie or query param could be `undefined`.
For example, when building an `/api` endpoint, the code might look like this:
```ts
import type { NextApiRequest, NextApiResponse } from "next"
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// According to the old types, `value` is a string
const value = req.cookies.value
// Type-checking passes but leads to a runtime error when no `value` cookie is provided in the request
// Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
value.toLowerCause()
// ...
}
```
By using `Partial`, TypeScript now knows that these objects don't have values defined for every `key` and accessing a given `key` might resolve to `undefined`.
---
The only obvious error this caused within this repo was on line 333 of the same file. For better or worse, I ended up casting that cookie value to a `string`. There's a series of `if` statements before it that, I guess, are guaranteeing that it's truly a string. Potentially, that stretch could be refactored such that TypeScript _knows_ it's a string.
Also, I tried to follow the contributing guidelines. However, running `yarn types` kicked out a bunch of errors about overwriting files:
```
$ yarn types
yarn run v1.22.10
$ lerna run types --stream
lerna notice cli v4.0.0
lerna info Executing command in 2 packages: "yarn run types"
@next/env: $ tsc index.ts --declaration --emitDeclarationOnly --declarationDir types --esModuleInterop
next: $ tsc --declaration --emitDeclarationOnly --declarationDir dist
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/index.d.ts' because it would overwrite input file.
next: error TS5055: Cannot write file '/Users/mbrandly/code/next.js/packages/next/dist/build/webpack/plugins/build-manifest-plugin.d.ts' because it would overwrite input file.
...
...
...
```
Let me know if there's anything I can improve here! Thanks again.
2022-05-23 02:48:26 +02:00
} >
2019-06-05 13:22:09 +02:00
body : any
2020-03-26 13:32:41 +01:00
env : Env
2020-07-07 05:41:16 +02:00
preview? : boolean
/ * *
* Preview data set on the request , if any
* * /
2021-04-20 20:13:48 +02:00
previewData? : PreviewData
2019-06-05 13:22:09 +02:00
}
/ * *
* Send body of response
2019-04-22 19:55:03 +02:00
* /
2019-07-09 19:02:46 +02:00
type Send < T > = ( body : T ) = > void
2019-04-22 19:55:03 +02:00
2019-06-05 13:22:09 +02:00
/ * *
* Next ` API ` route response
* /
2019-07-09 19:02:46 +02:00
export type NextApiResponse < T = any > = ServerResponse & {
2019-06-05 13:22:09 +02:00
/ * *
2019-07-10 16:43:04 +02:00
* Send data ` any ` data in response
2019-06-05 13:22:09 +02:00
* /
2019-07-09 19:02:46 +02:00
send : Send < T >
2019-06-05 13:22:09 +02:00
/ * *
2019-07-10 16:43:04 +02:00
* Send data ` json ` data in response
2019-06-05 13:22:09 +02:00
* /
2019-07-09 19:02:46 +02:00
json : Send < T >
status : ( statusCode : number ) = > NextApiResponse < T >
2020-07-29 09:01:21 +02:00
redirect ( url : string ) : NextApiResponse < T >
redirect ( status : number , url : string ) : NextApiResponse < T >
2020-02-12 02:16:42 +01:00
/ * *
* Set preview data for Next . js ' prerender mode
* /
setPreviewData : (
data : object | string ,
options ? : {
/ * *
* Specifies the number ( in seconds ) for the preview session to last for .
* The given number will be converted to an integer by rounding down .
* By default , no maximum age is set and the preview session finishes
* when the client shuts down ( browser is closed ) .
* /
maxAge? : number
2022-08-08 03:45:30 +02:00
/ * *
* Specifies the path for the preview session to work under . By default ,
* the path is considered the "default path" , i . e . , any pages under "/" .
* /
path? : string
2020-02-12 02:16:42 +01:00
}
) = > NextApiResponse < T >
2022-09-05 22:37:08 +02:00
/ * *
* Clear preview data for Next . js ' prerender mode
* /
clearPreviewData : ( options ? : { path? : string } ) = > NextApiResponse < T >
2022-02-08 04:50:23 +01:00
2022-06-27 21:28:41 +02:00
/ * *
* @deprecated ` unstable_revalidate ` has been renamed to ` revalidate `
* /
unstable_revalidate : ( ) = > void
2022-06-24 23:59:23 +02:00
revalidate : (
2022-04-13 18:56:58 +02:00
urlPath : string ,
opts ? : {
unstable_onlyGenerated? : boolean
}
) = > Promise < void >
2019-06-05 13:22:09 +02:00
}
2020-02-19 04:57:31 +01:00
/ * *
* Next ` API ` route handler
* /
export type NextApiHandler < T = any > = (
req : NextApiRequest ,
res : NextApiResponse < T >
2022-04-16 06:00:52 +02:00
) = > unknown | Promise < unknown >
2020-02-19 04:57:31 +01:00
2019-06-05 13:22:09 +02:00
/ * *
* Utils
* /
2020-04-06 17:59:44 +02:00
export function execOnce < T extends ( ...args : any [ ] ) = > ReturnType < T > > (
fn : T
) : T {
2019-04-22 19:55:03 +02:00
let used = false
2020-04-06 17:59:44 +02:00
let result : ReturnType < T >
2019-11-01 20:13:13 +01:00
2020-04-06 17:59:44 +02:00
return ( ( . . . args : any [ ] ) = > {
2019-04-22 19:55:03 +02:00
if ( ! used ) {
used = true
2020-04-06 17:59:44 +02:00
result = fn ( . . . args )
2019-04-22 19:55:03 +02:00
}
2019-11-01 20:13:13 +01:00
return result
2020-04-06 17:59:44 +02:00
} ) as T
2019-04-22 19:55:03 +02:00
}
2022-05-22 18:43:48 +02:00
// Scheme: https://tools.ietf.org/html/rfc3986#section-3.1
// Absolute URL: https://tools.ietf.org/html/rfc3986#section-4.3
const ABSOLUTE_URL_REGEX = /^[a-zA-Z][a-zA-Z\d+\-.]*?:/
export const isAbsoluteUrl = ( url : string ) = > ABSOLUTE_URL_REGEX . test ( url )
2019-04-22 19:55:03 +02:00
export function getLocationOrigin() {
const { protocol , hostname , port } = window . location
return ` ${ protocol } // ${ hostname } ${ port ? ':' + port : '' } `
}
export function getURL() {
const { href } = window . location
const origin = getLocationOrigin ( )
return href . substring ( origin . length )
}
2020-04-06 17:59:44 +02:00
export function getDisplayName < P > ( Component : ComponentType < P > ) {
2019-05-23 21:31:22 +02:00
return typeof Component === 'string'
? Component
: Component . displayName || Component . name || 'Unknown'
2019-04-22 19:55:03 +02:00
}
export function isResSent ( res : ServerResponse ) {
return res . finished || res . headersSent
}
2021-08-03 17:06:26 +02:00
export function normalizeRepeatedSlashes ( url : string ) {
const urlParts = url . split ( '?' )
const urlNoQuery = urlParts [ 0 ]
return (
urlNoQuery
// first we replace any non-encoded backslashes with forward
// then normalize repeated forward slashes
. replace ( /\\/g , '/' )
. replace ( /\/\/+/g , '/' ) +
( urlParts [ 1 ] ? ` ? ${ urlParts . slice ( 1 ) . join ( '?' ) } ` : '' )
)
}
2019-05-23 21:31:22 +02:00
export async function loadGetInitialProps <
C extends BaseContext ,
IP = { } ,
P = { }
2019-11-02 16:00:55 +01:00
> ( App : NextComponentType < C , IP , P > , ctx : C ) : Promise < IP > {
2019-04-22 19:55:03 +02:00
if ( process . env . NODE_ENV !== 'production' ) {
2020-01-08 17:30:53 +01:00
if ( App . prototype ? . getInitialProps ) {
2019-05-23 21:31:22 +02:00
const message = ` " ${ getDisplayName (
2019-11-02 16:00:55 +01:00
App
2021-03-29 10:25:00 +02:00
) } . getInitialProps ( ) " is defined as an instance method - visit https : //nextjs.org/docs/messages/get-initial-props-as-an-instance-method for more information.`
2019-04-22 19:55:03 +02:00
throw new Error ( message )
}
}
2019-04-30 23:28:25 +02:00
// when called from _app `ctx` is nested in `ctx`
const res = ctx . res || ( ctx . ctx && ctx . ctx . res )
2019-04-22 19:55:03 +02:00
2019-11-02 16:00:55 +01:00
if ( ! App . getInitialProps ) {
if ( ctx . ctx && ctx . Component ) {
// @ts-ignore pageProps default
return {
pageProps : await loadGetInitialProps ( ctx . Component , ctx . ctx ) ,
}
}
2020-04-06 17:59:44 +02:00
return { } as IP
2019-04-25 10:11:05 +02:00
}
2019-04-22 19:55:03 +02:00
2019-11-02 16:00:55 +01:00
const props = await App . getInitialProps ( ctx )
2019-04-22 19:55:03 +02:00
2019-04-30 23:28:25 +02:00
if ( res && isResSent ( res ) ) {
2019-04-22 19:55:03 +02:00
return props
}
if ( ! props ) {
2019-05-23 21:31:22 +02:00
const message = ` " ${ getDisplayName (
2019-11-02 16:00:55 +01:00
App
2019-05-23 21:31:22 +02:00
) } . getInitialProps ( ) " should resolve to an object. But found " $ { props } " instead . `
2019-04-22 19:55:03 +02:00
throw new Error ( message )
}
2019-08-22 19:06:30 +02:00
if ( process . env . NODE_ENV !== 'production' ) {
if ( Object . keys ( props ) . length === 0 && ! ctx . ctx ) {
console . warn (
` ${ getDisplayName (
2019-11-02 16:00:55 +01:00
App
2021-03-29 10:25:00 +02:00
) } returned an empty object from \ ` getInitialProps \` . This de-optimizes and prevents automatic static optimization. https://nextjs.org/docs/messages/empty-object-getInitialProps `
2019-08-22 19:06:30 +02:00
)
}
}
2019-04-22 19:55:03 +02:00
return props
}
2022-02-28 23:39:51 +01:00
let warnOnce = ( _ : string ) = > { }
if ( process . env . NODE_ENV !== 'production' ) {
const warnings = new Set < string > ( )
warnOnce = ( msg : string ) = > {
if ( ! warnings . has ( msg ) ) {
console . warn ( msg )
}
warnings . add ( msg )
}
}
export { warnOnce }
2020-01-04 21:53:33 +01:00
export const SP = typeof performance !== 'undefined'
export const ST =
SP &&
2022-06-30 18:06:53 +02:00
( [ 'mark' , 'measure' , 'getEntriesByName' ] as const ) . every (
( method ) = > typeof performance [ method ] === 'function'
)
2021-07-05 18:31:32 +02:00
export class DecodeError extends Error { }
2022-05-01 11:23:06 +02:00
export class NormalizeError extends Error { }
2022-06-06 20:35:26 +02:00
export class PageNotFoundError extends Error {
code : string
constructor ( page : string ) {
super ( )
this . code = 'ENOENT'
this . message = ` Cannot find module for page: ${ page } `
}
}
2021-08-13 05:36:54 +02:00
2022-06-27 21:15:09 +02:00
export class MissingStaticPage extends Error {
constructor ( page : string , message : string ) {
super ( )
this . message = ` Failed to load static file for page: ${ page } ${ message } `
}
}
2022-06-24 20:50:49 +02:00
export class MiddlewareNotFoundError extends Error {
code : string
constructor ( ) {
super ( )
this . code = 'ENOENT'
this . message = ` Cannot find the middleware module `
}
}
2021-12-17 23:56:26 +01:00
export interface CacheFs {
readFile ( f : string ) : Promise < string >
readFileSync ( f : string ) : string
writeFile ( f : string , d : any ) : Promise < void >
2022-01-04 16:35:32 +01:00
mkdir ( dir : string ) : Promise < void | string >
2021-12-17 23:56:26 +01:00
stat ( f : string ) : Promise < { mtime : Date } >
}