-
Notifications
You must be signed in to change notification settings - Fork 27.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add forbidden and unauthorized APIs #72785
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Tests Passed |
Stats from current PRDefault Build (Increase detected
|
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
buildDuration | 19.3s | 16.8s | N/A |
buildDurationCached | 15.4s | 15.5s | N/A |
nodeModulesSize | 405 MB | 405 MB | |
nextStartRea..uration (ms) | 468ms | 487ms | N/A |
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
0b69cffb-HASH.js gzip | 52.6 kB | 52.6 kB | N/A |
1924.HASH.js gzip | 169 B | 169 B | ✓ |
195-HASH.js gzip | 48.4 kB | 48.8 kB | |
8589-HASH.js gzip | 5.27 kB | 5.28 kB | N/A |
framework-HASH.js gzip | 57.4 kB | 57.4 kB | N/A |
main-app-HASH.js gzip | 232 B | 230 B | N/A |
main-HASH.js gzip | 33.1 kB | 33.1 kB | N/A |
webpack-HASH.js gzip | 1.71 kB | 1.71 kB | N/A |
Overall change | 48.5 kB | 49 kB |
Legacy Client Bundles (polyfills)
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 39.4 kB | 39.4 kB | ✓ |
Overall change | 39.4 kB | 39.4 kB | ✓ |
Client Pages
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
_app-HASH.js gzip | 193 B | 193 B | ✓ |
_error-HASH.js gzip | 192 B | 190 B | N/A |
amp-HASH.js gzip | 510 B | 510 B | ✓ |
css-HASH.js gzip | 341 B | 343 B | N/A |
dynamic-HASH.js gzip | 1.84 kB | 1.84 kB | N/A |
edge-ssr-HASH.js gzip | 266 B | 266 B | ✓ |
head-HASH.js gzip | 362 B | 364 B | N/A |
hooks-HASH.js gzip | 393 B | 392 B | N/A |
image-HASH.js gzip | 4.42 kB | 4.42 kB | N/A |
index-HASH.js gzip | 268 B | 268 B | ✓ |
link-HASH.js gzip | 2.34 kB | 2.35 kB | N/A |
routerDirect..HASH.js gzip | 328 B | 327 B | N/A |
script-HASH.js gzip | 398 B | 396 B | N/A |
withRouter-HASH.js gzip | 325 B | 322 B | N/A |
1afbb74e6ecf..834.css gzip | 106 B | 106 B | ✓ |
Overall change | 1.34 kB | 1.34 kB | ✓ |
Client Build Manifests
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
_buildManifest.js gzip | 748 B | 749 B | N/A |
Overall change | 0 B | 0 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
index.html gzip | 522 B | 523 B | N/A |
link.html gzip | 537 B | 537 B | ✓ |
withRouter.html gzip | 519 B | 518 B | N/A |
Overall change | 537 B | 537 B | ✓ |
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
edge-ssr.js gzip | 128 kB | 128 kB | N/A |
page.js gzip | 199 kB | 200 kB | |
Overall change | 199 kB | 200 kB |
Middleware size
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
middleware-b..fest.js gzip | 670 B | 668 B | N/A |
middleware-r..fest.js gzip | 156 B | 155 B | N/A |
middleware.js gzip | 30.9 kB | 31 kB | N/A |
edge-runtime..pack.js gzip | 844 B | 844 B | ✓ |
Overall change | 844 B | 844 B | ✓ |
Next Runtimes Overall increase ⚠️
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
732-experime...dev.js gzip | 322 B | 322 B | ✓ |
732.runtime.dev.js gzip | 314 B | 314 B | ✓ |
app-page-exp...dev.js gzip | 322 kB | 323 kB | |
app-page-exp..prod.js gzip | 125 kB | 125 kB | |
app-page-tur..prod.js gzip | 138 kB | 138 kB | |
app-page-tur..prod.js gzip | 133 kB | 133 kB | |
app-page.run...dev.js gzip | 313 kB | 314 kB | |
app-page.run..prod.js gzip | 121 kB | 121 kB | |
app-route-ex...dev.js gzip | 36 kB | 36.1 kB | N/A |
app-route-ex..prod.js gzip | 24.4 kB | 24.4 kB | N/A |
app-route-tu..prod.js gzip | 24.4 kB | 24.4 kB | N/A |
app-route-tu..prod.js gzip | 24.2 kB | 24.2 kB | N/A |
app-route.ru...dev.js gzip | 37.6 kB | 37.7 kB | N/A |
app-route.ru..prod.js gzip | 24.2 kB | 24.2 kB | N/A |
pages-api-tu..prod.js gzip | 9.57 kB | 9.57 kB | ✓ |
pages-api.ru...dev.js gzip | 11.4 kB | 11.4 kB | ✓ |
pages-api.ru..prod.js gzip | 9.56 kB | 9.56 kB | ✓ |
pages-turbo...prod.js gzip | 21 kB | 21 kB | ✓ |
pages.runtim...dev.js gzip | 26.6 kB | 26.6 kB | ✓ |
pages.runtim..prod.js gzip | 21 kB | 21 kB | ✓ |
server.runti..prod.js gzip | 916 kB | 916 kB | N/A |
Overall change | 1.25 MB | 1.25 MB |
build cache Overall increase ⚠️
vercel/next.js canary | vercel/next.js 11-13-pick_up_conventions | Change | |
---|---|---|---|
0.pack gzip | 2.01 MB | 2.03 MB | |
index.pack gzip | 147 kB | 148 kB | |
Overall change | 2.16 MB | 2.17 MB |
Diff details
Diff for page.js
Diff too large to display
Diff for middleware.js
Diff too large to display
Diff for edge-ssr.js
Diff too large to display
Diff for image-HASH.js
@@ -1,7 +1,7 @@
(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
[2983],
{
- /***/ 6745: /***/ (
+ /***/ 7391: /***/ (
__unused_webpack_module,
__unused_webpack_exports,
__webpack_require__
@@ -9,7 +9,7 @@
(window.__NEXT_P = window.__NEXT_P || []).push([
"/image",
function () {
- return __webpack_require__(5675);
+ return __webpack_require__(1489);
},
]);
if (false) {
@@ -18,7 +18,7 @@
/***/
},
- /***/ 9053: /***/ (module, exports, __webpack_require__) => {
+ /***/ 9313: /***/ (module, exports, __webpack_require__) => {
"use strict";
/* __next_internal_client_entry_do_not_use__ cjs */
Object.defineProperty(exports, "__esModule", {
@@ -40,17 +40,17 @@
__webpack_require__(6093)
);
const _head = /*#__PURE__*/ _interop_require_default._(
- __webpack_require__(8808)
+ __webpack_require__(7964)
);
- const _getimgprops = __webpack_require__(1945);
- const _imageconfig = __webpack_require__(7668);
- const _imageconfigcontextsharedruntime = __webpack_require__(1694);
- const _warnonce = __webpack_require__(1876);
- const _routercontextsharedruntime = __webpack_require__(5575);
+ const _getimgprops = __webpack_require__(8821);
+ const _imageconfig = __webpack_require__(664);
+ const _imageconfigcontextsharedruntime = __webpack_require__(6418);
+ const _warnonce = __webpack_require__(7360);
+ const _routercontextsharedruntime = __webpack_require__(4203);
const _imageloader = /*#__PURE__*/ _interop_require_default._(
- __webpack_require__(3589)
+ __webpack_require__(2489)
);
- const _usemergedref = __webpack_require__(6746);
+ const _usemergedref = __webpack_require__(2454);
// This is replaced by webpack define plugin
const configEnv = {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
@@ -371,7 +371,7 @@
/***/
},
- /***/ 6746: /***/ (module, exports, __webpack_require__) => {
+ /***/ 2454: /***/ (module, exports, __webpack_require__) => {
"use strict";
Object.defineProperty(exports, "__esModule", {
@@ -432,7 +432,7 @@
/***/
},
- /***/ 1945: /***/ (
+ /***/ 8821: /***/ (
__unused_webpack_module,
exports,
__webpack_require__
@@ -448,9 +448,9 @@
return getImgProps;
},
});
- const _warnonce = __webpack_require__(1876);
- const _imageblursvg = __webpack_require__(6704);
- const _imageconfig = __webpack_require__(7668);
+ const _warnonce = __webpack_require__(7360);
+ const _imageblursvg = __webpack_require__(5884);
+ const _imageconfig = __webpack_require__(664);
const VALID_LOADING_VALUES =
/* unused pure expression or super */ null && [
"lazy",
@@ -824,7 +824,7 @@
/***/
},
- /***/ 6704: /***/ (__unused_webpack_module, exports) => {
+ /***/ 5884: /***/ (__unused_webpack_module, exports) => {
"use strict";
/**
* A shared function, used on both client and server, to generate a SVG blur placeholder.
@@ -879,7 +879,7 @@
/***/
},
- /***/ 965: /***/ (
+ /***/ 9345: /***/ (
__unused_webpack_module,
exports,
__webpack_require__
@@ -906,10 +906,10 @@
},
});
const _interop_require_default = __webpack_require__(1739);
- const _getimgprops = __webpack_require__(1945);
- const _imagecomponent = __webpack_require__(9053);
+ const _getimgprops = __webpack_require__(8821);
+ const _imagecomponent = __webpack_require__(9313);
const _imageloader = /*#__PURE__*/ _interop_require_default._(
- __webpack_require__(3589)
+ __webpack_require__(2489)
);
function getImageProps(imgProps) {
const { props } = (0, _getimgprops.getImgProps)(imgProps, {
@@ -941,7 +941,7 @@
/***/
},
- /***/ 3589: /***/ (__unused_webpack_module, exports) => {
+ /***/ 2489: /***/ (__unused_webpack_module, exports) => {
"use strict";
Object.defineProperty(exports, "__esModule", {
@@ -976,7 +976,7 @@
/***/
},
- /***/ 5675: /***/ (
+ /***/ 1489: /***/ (
__unused_webpack_module,
__webpack_exports__,
__webpack_require__
@@ -993,8 +993,8 @@
// EXTERNAL MODULE: ./node_modules/.pnpm/react@19.0.0-rc-380f5d67-20241113/node_modules/react/jsx-runtime.js
var jsx_runtime = __webpack_require__(6322);
- // EXTERNAL MODULE: ./node_modules/.pnpm/next@file+..+main-repo+packages+next+next-packed.tgz_react-dom@19.0.0-rc-380f5d67-20241113_re_d7fg766ptstyt4prarg74ol27i/node_modules/next/image.js
- var next_image = __webpack_require__(1695);
+ // EXTERNAL MODULE: ./node_modules/.pnpm/next@file+..+diff-repo+packages+next+next-packed.tgz_react-dom@19.0.0-rc-380f5d67-20241113_re_k6jswiqskvoeqe45yhuljotqne/node_modules/next/image.js
+ var next_image = __webpack_require__(8106);
var image_default = /*#__PURE__*/ __webpack_require__.n(next_image); // ./pages/nextjs.png
/* harmony default export */ const nextjs = {
src: "/_next/static/media/nextjs.cae0b805.png",
@@ -1024,12 +1024,12 @@
/***/
},
- /***/ 1695: /***/ (
+ /***/ 8106: /***/ (
module,
__unused_webpack_exports,
__webpack_require__
) => {
- module.exports = __webpack_require__(965);
+ module.exports = __webpack_require__(9345);
/***/
},
@@ -1039,7 +1039,7 @@
/******/ var __webpack_exec__ = (moduleId) =>
__webpack_require__((__webpack_require__.s = moduleId));
/******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
- __webpack_exec__(6745)
+ __webpack_exec__(7391)
);
/******/ var __webpack_exports__ = __webpack_require__.O();
/******/ _N_E = __webpack_exports__;
Diff for 195-HASH.js
Diff too large to display
Diff for app-page-exp..ntime.dev.js
failed to diff
Diff for app-page-exp..time.prod.js
Diff too large to display
Diff for app-page-tur..time.prod.js
Diff too large to display
Diff for app-page-tur..time.prod.js
Diff too large to display
Diff for app-page.runtime.dev.js
Diff too large to display
Diff for app-page.runtime.prod.js
Diff too large to display
Diff for app-route-ex..ntime.dev.js
Diff too large to display
Diff for app-route-ex..time.prod.js
Diff too large to display
Diff for app-route-tu..time.prod.js
Diff too large to display
Diff for app-route-tu..time.prod.js
Diff too large to display
Diff for app-route.runtime.dev.js
Diff too large to display
Diff for app-route.ru..time.prod.js
Diff too large to display
Diff for server.runtime.prod.js
Diff too large to display
1890a53
to
d99a6ec
Compare
I'm very happy this is happening. Two notes:
Footnotes
|
d247e63
to
e5ec2de
Compare
4f76a06
to
80a143c
Compare
f6caf88
to
35e1233
Compare
@simoncave I can answer the 2n question now. Our goal is not trying to mirror the HTTP status codes as APIs, it's providing the semantic actions that act as communication channels between the different parts of the system or the different libraries composability, similar concept to The set is limited rather than infinite, we're not going to add different boundaries for each HTTP code. These two are the ones coming up so far which are useful after the application is started and allow you to show the restrictions to the resources you're trying to access. On the application side or library side you just learn the curated sets that framework picked for you. The distinction is valuable. E.g. |
917b0bf
to
91c6b0d
Compare
388f020
to
f8437f1
Compare
cab2e9d
to
671a3f4
Compare
fix test fixture improve test handle no matched boundary case test: reorganize the default test update metadata error convention (#72834) add element validation and remove unused boundaries use flag pass down flag everywhere
671a3f4
to
64c3d67
Compare
packages/next/src/client/components/http-access-fallback/error-boundary.tsx
Outdated
Show resolved
Hide resolved
packages/next/src/client/components/http-access-fallback/error-boundary.tsx
Outdated
Show resolved
Hide resolved
**Do not merge until #72785 lands in canary.** Closes: - https://linear.app/vercel/issue/DOC-3820/[unstable]-forbidden-and-forbiddenjs - https://linear.app/vercel/issue/DOC-3849/[unstable]-unauthorized-and-unauthorizedjs - https://linear.app/vercel/issue/DOC-3860/[experimental]-authinterrupts-config-option
**Do not merge until #72785 lands in canary.** Closes: - https://linear.app/vercel/issue/DOC-3820/[unstable]-forbidden-and-forbiddenjs - https://linear.app/vercel/issue/DOC-3849/[unstable]-unauthorized-and-unauthorizedjs - https://linear.app/vercel/issue/DOC-3860/[experimental]-authinterrupts-config-option
What
Support the
forbidden.js
andunauthorized.js
convention from the app directory and expose two experimental APIforbidden()
andunauthorized()
in thenext/navigation
. Add restriction that it's only working on canary for now.Why
Providing these 2 new APIs and error boundaries to fill more missing pieces of the navigation story in Next.js.
Our goal is not trying to mirror the HTTP status codes as APIs, it's providing the semantic actions that act as communication channels between the different parts of the system or the different libraries composability, similar concept to
Suspense
in React.The set is limited rather than infinite, we're not going to add different boundaries for each HTTP code. These two are the ones coming up so far which are useful after the application is started and allow you to show the restrictions to the resources you're trying to access. On the application side or library side you just learn the curated sets that framework picked for you.
The distinction is valuable. E.g.
unauthorized()
would likely take you to a login screen, where asforbidden()
might be caught but a child boundary and just indicate that part of the screen isn't available to this user. This also gives library flexibility to just call the abstract API and the upper parent or application side can implement the boundary to handle these errors, instead of deletgating everything to the library to decide what to do.Example
Closes NDX-298