@payloadcms/next 3.89.0 → 3.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/elements/DocumentHeader/Tabs/Tab/index.d.ts +2 -1
- package/dist/elements/DocumentHeader/Tabs/Tab/index.d.ts.map +1 -1
- package/dist/elements/DocumentHeader/Tabs/Tab/index.js +3 -2
- package/dist/elements/DocumentHeader/Tabs/Tab/index.js.map +1 -1
- package/dist/elements/DocumentHeader/Tabs/index.d.ts +2 -1
- package/dist/elements/DocumentHeader/Tabs/index.d.ts.map +1 -1
- package/dist/elements/DocumentHeader/Tabs/index.js +5 -3
- package/dist/elements/DocumentHeader/Tabs/index.js.map +1 -1
- package/dist/elements/DocumentHeader/index.d.ts +2 -1
- package/dist/elements/DocumentHeader/index.d.ts.map +1 -1
- package/dist/elements/DocumentHeader/index.js +4 -2
- package/dist/elements/DocumentHeader/index.js.map +1 -1
- package/dist/layouts/Root/index.js +6 -5
- package/dist/layouts/Root/index.js.map +1 -1
- package/dist/prod/styles.css +1 -1
- package/dist/utilities/handleServerFunctions.d.ts.map +1 -1
- package/dist/utilities/handleServerFunctions.js +4 -2
- package/dist/utilities/handleServerFunctions.js.map +1 -1
- package/dist/utilities/initReq.d.ts.map +1 -1
- package/dist/utilities/initReq.js +35 -2
- package/dist/utilities/initReq.js.map +1 -1
- package/dist/utilities/initReq.spec.js +240 -0
- package/dist/utilities/initReq.spec.js.map +1 -0
- package/dist/utilities/isPublicAdminRoute.d.ts.map +1 -1
- package/dist/utilities/isPublicAdminRoute.js +11 -9
- package/dist/utilities/isPublicAdminRoute.js.map +1 -1
- package/dist/utilities/isPublicAdminRoute.spec.js +34 -0
- package/dist/utilities/isPublicAdminRoute.spec.js.map +1 -0
- package/dist/views/Account/index.d.ts +1 -1
- package/dist/views/Account/index.d.ts.map +1 -1
- package/dist/views/Account/index.js +10 -7
- package/dist/views/Account/index.js.map +1 -1
- package/dist/views/BrowseByFolder/buildView.js +4 -4
- package/dist/views/BrowseByFolder/buildView.js.map +1 -1
- package/dist/views/CollectionFolders/buildView.js +4 -4
- package/dist/views/CollectionFolders/buildView.js.map +1 -1
- package/dist/views/Dashboard/Default/ModularDashboard/index.d.ts.map +1 -1
- package/dist/views/Dashboard/Default/ModularDashboard/index.js +1 -0
- package/dist/views/Dashboard/Default/ModularDashboard/index.js.map +1 -1
- package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.d.ts.map +1 -1
- package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js +3 -1
- package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js.map +1 -1
- package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.d.ts.map +1 -1
- package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js +2 -0
- package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js.map +1 -1
- package/dist/views/Dashboard/index.js +5 -3
- package/dist/views/Dashboard/index.js.map +1 -1
- package/dist/views/Document/handleServerFunction.d.ts.map +1 -1
- package/dist/views/Document/handleServerFunction.js +2 -0
- package/dist/views/Document/handleServerFunction.js.map +1 -1
- package/dist/views/Document/index.d.ts +1 -1
- package/dist/views/Document/index.d.ts.map +1 -1
- package/dist/views/Document/index.js +9 -4
- package/dist/views/Document/index.js.map +1 -1
- package/dist/views/Document/renderDocumentSlots.d.ts +1 -0
- package/dist/views/Document/renderDocumentSlots.d.ts.map +1 -1
- package/dist/views/Document/renderDocumentSlots.js +7 -4
- package/dist/views/Document/renderDocumentSlots.js.map +1 -1
- package/dist/views/ForgotPassword/ForgotPasswordForm/index.d.ts +1 -0
- package/dist/views/ForgotPassword/ForgotPasswordForm/index.d.ts.map +1 -1
- package/dist/views/ForgotPassword/ForgotPasswordForm/index.js +212 -159
- package/dist/views/ForgotPassword/ForgotPasswordForm/index.js.map +1 -1
- package/dist/views/ForgotPassword/index.d.ts.map +1 -1
- package/dist/views/ForgotPassword/index.js +3 -11
- package/dist/views/ForgotPassword/index.js.map +1 -1
- package/dist/views/List/handleServerFunction.d.ts.map +1 -1
- package/dist/views/List/handleServerFunction.js +4 -2
- package/dist/views/List/handleServerFunction.js.map +1 -1
- package/dist/views/List/index.d.ts.map +1 -1
- package/dist/views/List/index.js +2 -1
- package/dist/views/List/index.js.map +1 -1
- package/dist/views/NotFound/index.d.ts.map +1 -1
- package/dist/views/NotFound/index.js +3 -2
- package/dist/views/NotFound/index.js.map +1 -1
- package/dist/views/Root/index.d.ts.map +1 -1
- package/dist/views/Root/index.js +6 -4
- package/dist/views/Root/index.js.map +1 -1
- package/dist/views/Verify/index.d.ts +1 -1
- package/dist/views/Verify/index.d.ts.map +1 -1
- package/dist/views/Verify/index.js +4 -4
- package/dist/views/Verify/index.js.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleServerFunctions.d.ts","sourceRoot":"","sources":["../../src/utilities/handleServerFunctions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA6C,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAmC/F,eAAO,MAAM,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"handleServerFunctions.d.ts","sourceRoot":"","sources":["../../src/utilities/handleServerFunctions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA6C,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAmC/F,eAAO,MAAM,qBAAqB,EAAE,qBAgCnC,CAAA"}
|
|
@@ -37,7 +37,8 @@ export const handleServerFunctions = async args => {
|
|
|
37
37
|
cookies,
|
|
38
38
|
locale,
|
|
39
39
|
permissions,
|
|
40
|
-
req
|
|
40
|
+
req,
|
|
41
|
+
user
|
|
41
42
|
} = await initReq({
|
|
42
43
|
configPromise,
|
|
43
44
|
importMap,
|
|
@@ -49,7 +50,8 @@ export const handleServerFunctions = async args => {
|
|
|
49
50
|
importMap,
|
|
50
51
|
locale,
|
|
51
52
|
permissions,
|
|
52
|
-
req
|
|
53
|
+
req,
|
|
54
|
+
user
|
|
53
55
|
};
|
|
54
56
|
const fn = extraServerFunctions?.[fnKey] || baseServerFunctions[fnKey];
|
|
55
57
|
if (!fn) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleServerFunctions.js","names":["_internal_renderFieldHandler","copyDataFromLocaleHandler","buildFormStateHandler","buildTableStateHandler","getFolderResultsComponentAndDataHandler","getUpcomingScheduledPublishHandler","schedulePublishHandler","getDefaultLayoutHandler","renderWidgetHandler","renderDocumentHandler","renderDocumentSlotsHandler","renderListHandler","initReq","slugifyHandler","baseServerFunctions","slugify","handleServerFunctions","args","name","fnKey","fnArgs","config","configPromise","importMap","serverFunctions","extraServerFunctions","cookies","locale","permissions","req","key","augmentedArgs","fn","Error"],"sources":["../../src/utilities/handleServerFunctions.ts"],"sourcesContent":["import type { DefaultServerFunctionArgs, ServerFunction, ServerFunctionHandler } from 'payload'\n\nimport { _internal_renderFieldHandler, copyDataFromLocaleHandler } from '@payloadcms/ui/rsc'\nimport { buildFormStateHandler } from '@payloadcms/ui/utilities/buildFormState'\nimport { buildTableStateHandler } from '@payloadcms/ui/utilities/buildTableState'\nimport { getFolderResultsComponentAndDataHandler } from '@payloadcms/ui/utilities/getFolderResultsComponentAndData'\nimport {\n getUpcomingScheduledPublishHandler,\n schedulePublishHandler,\n} from '@payloadcms/ui/utilities/schedulePublishHandler'\n\nimport { getDefaultLayoutHandler } from '../views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js'\nimport { renderWidgetHandler } from '../views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js'\nimport { renderDocumentHandler } from '../views/Document/handleServerFunction.js'\nimport { renderDocumentSlotsHandler } from '../views/Document/renderDocumentSlots.js'\nimport { renderListHandler } from '../views/List/handleServerFunction.js'\nimport { initReq } from './initReq.js'\nimport { slugifyHandler } from './slugify.js'\n\nconst baseServerFunctions: Record<string, ServerFunction<any, any>> = {\n 'copy-data-from-locale': copyDataFromLocaleHandler,\n 'form-state': buildFormStateHandler,\n 'get-default-layout': getDefaultLayoutHandler,\n 'get-folder-results-component-and-data': getFolderResultsComponentAndDataHandler,\n 'get-upcoming-scheduled-publish': getUpcomingScheduledPublishHandler,\n 'render-document': renderDocumentHandler,\n 'render-document-slots': renderDocumentSlotsHandler,\n 'render-field': _internal_renderFieldHandler,\n 'render-list': renderListHandler,\n 'render-widget': renderWidgetHandler,\n 'schedule-publish': schedulePublishHandler,\n slugify: slugifyHandler,\n 'table-state': buildTableStateHandler,\n}\n\nexport const handleServerFunctions: ServerFunctionHandler = async (args) => {\n const {\n name: fnKey,\n args: fnArgs,\n config: configPromise,\n importMap,\n serverFunctions: extraServerFunctions,\n } = args\n\n const { cookies, locale, permissions, req } = await initReq({\n configPromise,\n importMap,\n key: 'RootLayout',\n })\n\n const augmentedArgs: DefaultServerFunctionArgs = {\n ...fnArgs,\n cookies,\n importMap,\n locale,\n permissions,\n req,\n }\n\n const fn = extraServerFunctions?.[fnKey] || baseServerFunctions[fnKey]\n\n if (!fn) {\n throw new Error(`Unknown Server Function: ${fnKey}`)\n }\n\n return fn(augmentedArgs)\n}\n"],"mappings":"AAEA,SAASA,4BAA4B,EAAEC,yBAAyB,QAAQ;AACxE,SAASC,qBAAqB,QAAQ;AACtC,SAASC,sBAAsB,QAAQ;AACvC,SAASC,uCAAuC,QAAQ;AACxD,SACEC,kCAAkC,EAClCC,sBAAsB,QACjB;AAEP,SAASC,uBAAuB,QAAQ;AACxC,SAASC,mBAAmB,QAAQ;AACpC,SAASC,qBAAqB,QAAQ;AACtC,SAASC,0BAA0B,QAAQ;AAC3C,SAASC,iBAAiB,QAAQ;AAClC,SAASC,OAAO,QAAQ;AACxB,SAASC,cAAc,QAAQ;AAE/B,MAAMC,mBAAA,GAAgE;EACpE,yBAAyBb,yBAAA;EACzB,cAAcC,qBAAA;EACd,sBAAsBK,uBAAA;EACtB,yCAAyCH,uCAAA;EACzC,kCAAkCC,kCAAA;EAClC,mBAAmBI,qBAAA;EACnB,yBAAyBC,0BAAA;EACzB,gBAAgBV,4BAAA;EAChB,eAAeW,iBAAA;EACf,iBAAiBH,mBAAA;EACjB,oBAAoBF,sBAAA;EACpBS,OAAA,EAASF,cAAA;EACT,eAAeV;AACjB;AAEA,OAAO,MAAMa,qBAAA,GAA+C,MAAOC,IAAA;EACjE,MAAM;IACJC,IAAA,EAAMC,KAAK;IACXF,IAAA,EAAMG,MAAM;IACZC,MAAA,EAAQC,aAAa;IACrBC,SAAS;IACTC,eAAA,EAAiBC;EAAoB,CACtC,GAAGR,IAAA;EAEJ,MAAM;IAAES,OAAO;IAAEC,MAAM;IAAEC,WAAW;IAAEC;
|
|
1
|
+
{"version":3,"file":"handleServerFunctions.js","names":["_internal_renderFieldHandler","copyDataFromLocaleHandler","buildFormStateHandler","buildTableStateHandler","getFolderResultsComponentAndDataHandler","getUpcomingScheduledPublishHandler","schedulePublishHandler","getDefaultLayoutHandler","renderWidgetHandler","renderDocumentHandler","renderDocumentSlotsHandler","renderListHandler","initReq","slugifyHandler","baseServerFunctions","slugify","handleServerFunctions","args","name","fnKey","fnArgs","config","configPromise","importMap","serverFunctions","extraServerFunctions","cookies","locale","permissions","req","user","key","augmentedArgs","fn","Error"],"sources":["../../src/utilities/handleServerFunctions.ts"],"sourcesContent":["import type { DefaultServerFunctionArgs, ServerFunction, ServerFunctionHandler } from 'payload'\n\nimport { _internal_renderFieldHandler, copyDataFromLocaleHandler } from '@payloadcms/ui/rsc'\nimport { buildFormStateHandler } from '@payloadcms/ui/utilities/buildFormState'\nimport { buildTableStateHandler } from '@payloadcms/ui/utilities/buildTableState'\nimport { getFolderResultsComponentAndDataHandler } from '@payloadcms/ui/utilities/getFolderResultsComponentAndData'\nimport {\n getUpcomingScheduledPublishHandler,\n schedulePublishHandler,\n} from '@payloadcms/ui/utilities/schedulePublishHandler'\n\nimport { getDefaultLayoutHandler } from '../views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js'\nimport { renderWidgetHandler } from '../views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js'\nimport { renderDocumentHandler } from '../views/Document/handleServerFunction.js'\nimport { renderDocumentSlotsHandler } from '../views/Document/renderDocumentSlots.js'\nimport { renderListHandler } from '../views/List/handleServerFunction.js'\nimport { initReq } from './initReq.js'\nimport { slugifyHandler } from './slugify.js'\n\nconst baseServerFunctions: Record<string, ServerFunction<any, any>> = {\n 'copy-data-from-locale': copyDataFromLocaleHandler,\n 'form-state': buildFormStateHandler,\n 'get-default-layout': getDefaultLayoutHandler,\n 'get-folder-results-component-and-data': getFolderResultsComponentAndDataHandler,\n 'get-upcoming-scheduled-publish': getUpcomingScheduledPublishHandler,\n 'render-document': renderDocumentHandler,\n 'render-document-slots': renderDocumentSlotsHandler,\n 'render-field': _internal_renderFieldHandler,\n 'render-list': renderListHandler,\n 'render-widget': renderWidgetHandler,\n 'schedule-publish': schedulePublishHandler,\n slugify: slugifyHandler,\n 'table-state': buildTableStateHandler,\n}\n\nexport const handleServerFunctions: ServerFunctionHandler = async (args) => {\n const {\n name: fnKey,\n args: fnArgs,\n config: configPromise,\n importMap,\n serverFunctions: extraServerFunctions,\n } = args\n\n const { cookies, locale, permissions, req, user } = await initReq({\n configPromise,\n importMap,\n key: 'RootLayout',\n })\n\n const augmentedArgs: DefaultServerFunctionArgs = {\n ...fnArgs,\n cookies,\n importMap,\n locale,\n permissions,\n req,\n user,\n }\n\n const fn = extraServerFunctions?.[fnKey] || baseServerFunctions[fnKey]\n\n if (!fn) {\n throw new Error(`Unknown Server Function: ${fnKey}`)\n }\n\n return fn(augmentedArgs)\n}\n"],"mappings":"AAEA,SAASA,4BAA4B,EAAEC,yBAAyB,QAAQ;AACxE,SAASC,qBAAqB,QAAQ;AACtC,SAASC,sBAAsB,QAAQ;AACvC,SAASC,uCAAuC,QAAQ;AACxD,SACEC,kCAAkC,EAClCC,sBAAsB,QACjB;AAEP,SAASC,uBAAuB,QAAQ;AACxC,SAASC,mBAAmB,QAAQ;AACpC,SAASC,qBAAqB,QAAQ;AACtC,SAASC,0BAA0B,QAAQ;AAC3C,SAASC,iBAAiB,QAAQ;AAClC,SAASC,OAAO,QAAQ;AACxB,SAASC,cAAc,QAAQ;AAE/B,MAAMC,mBAAA,GAAgE;EACpE,yBAAyBb,yBAAA;EACzB,cAAcC,qBAAA;EACd,sBAAsBK,uBAAA;EACtB,yCAAyCH,uCAAA;EACzC,kCAAkCC,kCAAA;EAClC,mBAAmBI,qBAAA;EACnB,yBAAyBC,0BAAA;EACzB,gBAAgBV,4BAAA;EAChB,eAAeW,iBAAA;EACf,iBAAiBH,mBAAA;EACjB,oBAAoBF,sBAAA;EACpBS,OAAA,EAASF,cAAA;EACT,eAAeV;AACjB;AAEA,OAAO,MAAMa,qBAAA,GAA+C,MAAOC,IAAA;EACjE,MAAM;IACJC,IAAA,EAAMC,KAAK;IACXF,IAAA,EAAMG,MAAM;IACZC,MAAA,EAAQC,aAAa;IACrBC,SAAS;IACTC,eAAA,EAAiBC;EAAoB,CACtC,GAAGR,IAAA;EAEJ,MAAM;IAAES,OAAO;IAAEC,MAAM;IAAEC,WAAW;IAAEC,GAAG;IAAEC;EAAI,CAAE,GAAG,MAAMlB,OAAA,CAAQ;IAChEU,aAAA;IACAC,SAAA;IACAQ,GAAA,EAAK;EACP;EAEA,MAAMC,aAAA,GAA2C;IAC/C,GAAGZ,MAAM;IACTM,OAAA;IACAH,SAAA;IACAI,MAAA;IACAC,WAAA;IACAC,GAAA;IACAC;EACF;EAEA,MAAMG,EAAA,GAAKR,oBAAA,GAAuBN,KAAA,CAAM,IAAIL,mBAAmB,CAACK,KAAA,CAAM;EAEtE,IAAI,CAACc,EAAA,EAAI;IACP,MAAM,IAAIC,KAAA,CAAM,4BAA4Bf,KAAA,EAAO;EACrD;EAEA,OAAOc,EAAA,CAAGD,aAAA;AACZ","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initReq.d.ts","sourceRoot":"","sources":["../../src/utilities/initReq.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAA;AAIxF,OAAO,EACL,cAAc,EAMf,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"initReq.d.ts","sourceRoot":"","sources":["../../src/utilities/initReq.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAA;AAIxF,OAAO,EACL,cAAc,EAMf,MAAM,SAAS,CAAA;AAehB;;;GAGG;AACH,eAAO,MAAM,OAAO,iEAMjB;IACD,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAAA;IACzD,SAAS,EAAE,SAAS,CAAA;IACpB,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;CACjD,KAAG,OAAO,CAAC,aAAa,CA8HxB,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { initI18n } from '@payloadcms/translations';
|
|
2
2
|
import { headers as getHeaders } from 'next/headers.js';
|
|
3
3
|
import { createLocalReq, executeAuthStrategies, getAccessResults, getPayload, getRequestLanguage, parseCookies } from 'payload';
|
|
4
|
+
import { applyUserReadAccess } from 'payload/internal';
|
|
4
5
|
import { getRequestLocale } from './getRequestLocale.js';
|
|
5
6
|
import { selectiveCache } from './selectiveCache.js';
|
|
6
7
|
// Create cache instances for different parts of our application
|
|
@@ -64,6 +65,10 @@ export const initReq = async function ({
|
|
|
64
65
|
req: reqOverrides,
|
|
65
66
|
...optionsOverrides
|
|
66
67
|
} = overrides || {};
|
|
68
|
+
const hasOptionsUserOverride = Object.hasOwn(optionsOverrides, 'user');
|
|
69
|
+
const hasReqUserOverride = Object.hasOwn(reqOverrides ?? {}, 'user');
|
|
70
|
+
const hasUserOverride = hasOptionsUserOverride || hasReqUserOverride;
|
|
71
|
+
const userOverride = hasOptionsUserOverride ? optionsOverrides.user : reqOverrides?.user;
|
|
67
72
|
const req = await createLocalReq({
|
|
68
73
|
req: {
|
|
69
74
|
headers,
|
|
@@ -75,10 +80,37 @@ export const initReq = async function ({
|
|
|
75
80
|
},
|
|
76
81
|
...(optionsOverrides || {})
|
|
77
82
|
}, payload);
|
|
83
|
+
if (hasUserOverride && userOverride == null) {
|
|
84
|
+
req.user = null;
|
|
85
|
+
}
|
|
86
|
+
let userWithReadAccess = req.user;
|
|
78
87
|
const locale = await getRequestLocale({
|
|
79
88
|
req
|
|
80
89
|
});
|
|
81
90
|
req.locale = locale?.code;
|
|
91
|
+
if (!hasUserOverride && req.user) {
|
|
92
|
+
try {
|
|
93
|
+
const collectionSlug = req.user.collection ?? payload.config.admin.user;
|
|
94
|
+
const collection = payload.collections[collectionSlug];
|
|
95
|
+
if (!collection?.config.auth) {
|
|
96
|
+
throw new Error('Authenticated user collection not found');
|
|
97
|
+
}
|
|
98
|
+
userWithReadAccess = await applyUserReadAccess({
|
|
99
|
+
collection: collection.config,
|
|
100
|
+
depth: collection.config.auth.depth,
|
|
101
|
+
overrideAccess: false,
|
|
102
|
+
req,
|
|
103
|
+
showHiddenFields: false,
|
|
104
|
+
user: req.user
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
payload.logger.error({
|
|
108
|
+
err: error
|
|
109
|
+
});
|
|
110
|
+
req.user = null;
|
|
111
|
+
userWithReadAccess = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
82
114
|
const permissions = await getAccessResults({
|
|
83
115
|
req
|
|
84
116
|
});
|
|
@@ -88,9 +120,10 @@ export const initReq = async function ({
|
|
|
88
120
|
languageCode,
|
|
89
121
|
locale,
|
|
90
122
|
permissions,
|
|
91
|
-
req
|
|
123
|
+
req,
|
|
124
|
+
user: userWithReadAccess
|
|
92
125
|
};
|
|
93
|
-
}, key).then(result => {
|
|
126
|
+
}, key, overrides).then(result => {
|
|
94
127
|
// CRITICAL: Create a shallow copy of req before returning to prevent
|
|
95
128
|
// mutations from propagating to the cached req object.
|
|
96
129
|
// This ensures parallel operations using the same cache key don't affect each other.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initReq.js","names":["initI18n","headers","getHeaders","createLocalReq","executeAuthStrategies","getAccessResults","getPayload","getRequestLanguage","parseCookies","getRequestLocale","selectiveCache","partialReqCache","reqCache","initReq","canSetHeaders","configPromise","importMap","key","overrides","cookies","partialResult","get","config","payload","cron","languageCode","i18n","context","language","responseHeaders","user","req","reqOverrides","optionsOverrides","host","locale","code","permissions","then","result"],"sources":["../../src/utilities/initReq.ts"],"sourcesContent":["import type { I18n, I18nClient } from '@payloadcms/translations'\nimport type { ImportMap, InitReqResult, PayloadRequest, SanitizedConfig } from 'payload'\n\nimport { initI18n } from '@payloadcms/translations'\nimport { headers as getHeaders } from 'next/headers.js'\nimport {\n createLocalReq,\n executeAuthStrategies,\n getAccessResults,\n getPayload,\n getRequestLanguage,\n parseCookies,\n} from 'payload'\n\nimport { getRequestLocale } from './getRequestLocale.js'\nimport { selectiveCache } from './selectiveCache.js'\n\ntype PartialResult = {\n i18n: I18nClient\n} & Pick<InitReqResult, 'languageCode'> &\n Pick<PayloadRequest, 'payload' | 'responseHeaders' | 'user'>\n\n// Create cache instances for different parts of our application\nconst partialReqCache = selectiveCache<PartialResult>('partialReq')\nconst reqCache = selectiveCache<InitReqResult>('req')\n\n/**\n * Initializes a full request object, including the `req` object and access control.\n * As access control and getting the request locale is dependent on the current URL and\n */\nexport const initReq = async function ({\n canSetHeaders,\n configPromise,\n importMap,\n key,\n overrides,\n}: {\n canSetHeaders?: boolean\n configPromise: Promise<SanitizedConfig> | SanitizedConfig\n importMap: ImportMap\n key: string\n overrides?: Parameters<typeof createLocalReq>[0]\n}): Promise<InitReqResult> {\n const headers = await getHeaders()\n const cookies = parseCookies(headers)\n\n const partialResult = await partialReqCache.get(async () => {\n const config = await configPromise\n const payload = await getPayload({ config, cron: true, importMap })\n const languageCode = getRequestLanguage({\n config,\n cookies,\n headers,\n })\n\n const i18n: I18nClient = await initI18n({\n config: config.i18n,\n context: 'client',\n language: languageCode,\n })\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers,\n payload,\n })\n\n return {\n i18n,\n languageCode,\n payload,\n responseHeaders,\n user,\n }\n }, 'global')\n\n return reqCache\n .get(async () => {\n
|
|
1
|
+
{"version":3,"file":"initReq.js","names":["initI18n","headers","getHeaders","createLocalReq","executeAuthStrategies","getAccessResults","getPayload","getRequestLanguage","parseCookies","applyUserReadAccess","getRequestLocale","selectiveCache","partialReqCache","reqCache","initReq","canSetHeaders","configPromise","importMap","key","overrides","cookies","partialResult","get","config","payload","cron","languageCode","i18n","context","language","responseHeaders","user","req","reqOverrides","optionsOverrides","hasOptionsUserOverride","Object","hasOwn","hasReqUserOverride","hasUserOverride","userOverride","host","userWithReadAccess","locale","code","collectionSlug","collection","admin","collections","auth","Error","depth","overrideAccess","showHiddenFields","error","logger","err","permissions","then","result"],"sources":["../../src/utilities/initReq.ts"],"sourcesContent":["import type { I18n, I18nClient } from '@payloadcms/translations'\nimport type { ImportMap, InitReqResult, PayloadRequest, SanitizedConfig } from 'payload'\n\nimport { initI18n } from '@payloadcms/translations'\nimport { headers as getHeaders } from 'next/headers.js'\nimport {\n createLocalReq,\n executeAuthStrategies,\n getAccessResults,\n getPayload,\n getRequestLanguage,\n parseCookies,\n} from 'payload'\nimport { applyUserReadAccess } from 'payload/internal'\n\nimport { getRequestLocale } from './getRequestLocale.js'\nimport { selectiveCache } from './selectiveCache.js'\n\ntype PartialResult = {\n i18n: I18nClient\n} & Pick<InitReqResult, 'languageCode'> &\n Pick<PayloadRequest, 'payload' | 'responseHeaders' | 'user'>\n\n// Create cache instances for different parts of our application\nconst partialReqCache = selectiveCache<PartialResult>('partialReq')\nconst reqCache = selectiveCache<InitReqResult>('req')\n\n/**\n * Initializes a full request object, including the `req` object and access control.\n * As access control and getting the request locale is dependent on the current URL and\n */\nexport const initReq = async function ({\n canSetHeaders,\n configPromise,\n importMap,\n key,\n overrides,\n}: {\n canSetHeaders?: boolean\n configPromise: Promise<SanitizedConfig> | SanitizedConfig\n importMap: ImportMap\n key: string\n overrides?: Parameters<typeof createLocalReq>[0]\n}): Promise<InitReqResult> {\n const headers = await getHeaders()\n const cookies = parseCookies(headers)\n\n const partialResult = await partialReqCache.get(async () => {\n const config = await configPromise\n const payload = await getPayload({ config, cron: true, importMap })\n const languageCode = getRequestLanguage({\n config,\n cookies,\n headers,\n })\n\n const i18n: I18nClient = await initI18n({\n config: config.i18n,\n context: 'client',\n language: languageCode,\n })\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers,\n payload,\n })\n\n return {\n i18n,\n languageCode,\n payload,\n responseHeaders,\n user,\n }\n }, 'global')\n\n return reqCache\n .get(\n async () => {\n const { i18n, languageCode, payload, responseHeaders, user } = partialResult\n\n const { req: reqOverrides, ...optionsOverrides } = overrides || {}\n const hasOptionsUserOverride = Object.hasOwn(optionsOverrides, 'user')\n const hasReqUserOverride = Object.hasOwn(reqOverrides ?? {}, 'user')\n const hasUserOverride = hasOptionsUserOverride || hasReqUserOverride\n const userOverride = hasOptionsUserOverride ? optionsOverrides.user : reqOverrides?.user\n\n const req = await createLocalReq(\n {\n req: {\n headers,\n host: headers.get('host'),\n i18n: i18n as I18n,\n responseHeaders,\n user,\n ...(reqOverrides || {}),\n },\n ...(optionsOverrides || {}),\n },\n payload,\n )\n\n if (hasUserOverride && userOverride == null) {\n req.user = null\n }\n\n let userWithReadAccess = req.user\n\n const locale = await getRequestLocale({ req })\n req.locale = locale?.code\n\n if (!hasUserOverride && req.user) {\n try {\n const collectionSlug = req.user.collection ?? payload.config.admin.user\n const collection = payload.collections[collectionSlug]\n\n if (!collection?.config.auth) {\n throw new Error('Authenticated user collection not found')\n }\n\n userWithReadAccess = await applyUserReadAccess({\n collection: collection.config,\n depth: collection.config.auth.depth,\n overrideAccess: false,\n req,\n showHiddenFields: false,\n user: req.user,\n })\n } catch (error) {\n payload.logger.error({ err: error })\n req.user = null\n userWithReadAccess = null\n }\n }\n\n const permissions = await getAccessResults({\n req,\n })\n\n return {\n cookies,\n headers,\n languageCode,\n locale,\n permissions,\n req,\n user: userWithReadAccess,\n }\n },\n key,\n overrides,\n )\n .then((result) => {\n // CRITICAL: Create a shallow copy of req before returning to prevent\n // mutations from propagating to the cached req object.\n // This ensures parallel operations using the same cache key don't affect each other.\n return {\n ...result,\n req: {\n ...result.req,\n ...(result.req?.context\n ? {\n context: { ...result.req.context },\n }\n : {}),\n },\n }\n })\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { getAccessResults } from 'payload';
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
const mocks = vi.hoisted(() => ({
|
|
4
|
+
applyUserReadAccess: vi.fn(async ({
|
|
5
|
+
req,
|
|
6
|
+
user
|
|
7
|
+
}) => {
|
|
8
|
+
mocks.readAccessCalls += 1;
|
|
9
|
+
if (!mocks.readAccessSucceeds) {
|
|
10
|
+
throw new Error('User read access failed');
|
|
11
|
+
}
|
|
12
|
+
const userWithReadAccess = {
|
|
13
|
+
...user,
|
|
14
|
+
requestLocale: req.locale
|
|
15
|
+
};
|
|
16
|
+
delete userWithReadAccess.authorizationRole;
|
|
17
|
+
return userWithReadAccess;
|
|
18
|
+
}),
|
|
19
|
+
authenticationSucceeds: true,
|
|
20
|
+
cacheStores: new Map(),
|
|
21
|
+
executeAuthStrategies: vi.fn(async () => ({
|
|
22
|
+
responseHeaders: new Headers({
|
|
23
|
+
'x-auth': 'authenticated'
|
|
24
|
+
}),
|
|
25
|
+
user: mocks.authenticationSucceeds ? {
|
|
26
|
+
authorizationRole: 'admin',
|
|
27
|
+
collection: 'users',
|
|
28
|
+
id: 'user-id'
|
|
29
|
+
} : null
|
|
30
|
+
})),
|
|
31
|
+
readAccessCalls: 0,
|
|
32
|
+
readAccessSucceeds: true
|
|
33
|
+
}));
|
|
34
|
+
vi.mock('@payloadcms/translations', () => ({
|
|
35
|
+
initI18n: vi.fn(async () => ({
|
|
36
|
+
dateFNSKey: 'en-US',
|
|
37
|
+
fallbackLanguage: 'en',
|
|
38
|
+
language: 'en',
|
|
39
|
+
t: key => key,
|
|
40
|
+
translations: {}
|
|
41
|
+
}))
|
|
42
|
+
}));
|
|
43
|
+
vi.mock('next/headers.js', () => ({
|
|
44
|
+
headers: vi.fn(async () => new Headers())
|
|
45
|
+
}));
|
|
46
|
+
vi.mock('payload', async importOriginal => {
|
|
47
|
+
const payloadModule = await importOriginal();
|
|
48
|
+
return {
|
|
49
|
+
...payloadModule,
|
|
50
|
+
createLocalReq: vi.fn(async (options, payload) => {
|
|
51
|
+
const request = options.req ?? {};
|
|
52
|
+
const url = new URL(options.urlSuffix ?? '/', 'http://localhost');
|
|
53
|
+
const user = options.user ?? request.user ?? null;
|
|
54
|
+
return {
|
|
55
|
+
...request,
|
|
56
|
+
context: options.context ?? request.context ?? {},
|
|
57
|
+
fallbackLocale: options.fallbackLocale,
|
|
58
|
+
headers: request.headers ?? new Headers(),
|
|
59
|
+
locale: options.locale ?? request.locale ?? request.query?.locale ?? 'en',
|
|
60
|
+
pathname: request.pathname ?? url.pathname,
|
|
61
|
+
payload,
|
|
62
|
+
query: request.query ?? {},
|
|
63
|
+
responseHeaders: request.responseHeaders ?? new Headers(),
|
|
64
|
+
url: request.url ?? url.href,
|
|
65
|
+
user: user && !user.collection ? {
|
|
66
|
+
...user,
|
|
67
|
+
collection: payload.config.admin.user
|
|
68
|
+
} : user
|
|
69
|
+
};
|
|
70
|
+
}),
|
|
71
|
+
executeAuthStrategies: mocks.executeAuthStrategies,
|
|
72
|
+
getAccessResults: vi.fn(async ({
|
|
73
|
+
req
|
|
74
|
+
}) => ({
|
|
75
|
+
canAccessAdmin: req.user?.authorizationRole === 'admin'
|
|
76
|
+
})),
|
|
77
|
+
getPayload: vi.fn(async () => ({
|
|
78
|
+
collections: {
|
|
79
|
+
users: {
|
|
80
|
+
config: {
|
|
81
|
+
auth: {
|
|
82
|
+
depth: 0
|
|
83
|
+
},
|
|
84
|
+
slug: 'users'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
config: {
|
|
89
|
+
admin: {
|
|
90
|
+
user: 'users'
|
|
91
|
+
},
|
|
92
|
+
i18n: {
|
|
93
|
+
fallbackLanguage: 'en',
|
|
94
|
+
supportedLanguages: {
|
|
95
|
+
en: {}
|
|
96
|
+
},
|
|
97
|
+
translations: {}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
logger: {
|
|
101
|
+
error: vi.fn()
|
|
102
|
+
}
|
|
103
|
+
})),
|
|
104
|
+
getRequestLanguage: vi.fn(() => 'en')
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
vi.mock('payload/internal', () => ({
|
|
108
|
+
applyUserReadAccess: mocks.applyUserReadAccess
|
|
109
|
+
}));
|
|
110
|
+
vi.mock('./getRequestLocale.js', () => ({
|
|
111
|
+
getRequestLocale: vi.fn(async ({
|
|
112
|
+
req
|
|
113
|
+
}) => ({
|
|
114
|
+
code: req.locale ?? 'en'
|
|
115
|
+
}))
|
|
116
|
+
}));
|
|
117
|
+
vi.mock('./selectiveCache.js', () => ({
|
|
118
|
+
selectiveCache: namespace => ({
|
|
119
|
+
get: async (factory, ...args) => {
|
|
120
|
+
let cacheEntry = mocks.cacheStores.get(namespace);
|
|
121
|
+
if (!cacheEntry) {
|
|
122
|
+
cacheEntry = {
|
|
123
|
+
children: new Map()
|
|
124
|
+
};
|
|
125
|
+
mocks.cacheStores.set(namespace, cacheEntry);
|
|
126
|
+
}
|
|
127
|
+
for (const arg of args) {
|
|
128
|
+
let child = cacheEntry.children.get(arg);
|
|
129
|
+
if (!child) {
|
|
130
|
+
child = {
|
|
131
|
+
children: new Map()
|
|
132
|
+
};
|
|
133
|
+
cacheEntry.children.set(arg, child);
|
|
134
|
+
}
|
|
135
|
+
cacheEntry = child;
|
|
136
|
+
}
|
|
137
|
+
if (!('value' in cacheEntry)) {
|
|
138
|
+
cacheEntry.value = await factory();
|
|
139
|
+
}
|
|
140
|
+
return cacheEntry.value;
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
}));
|
|
144
|
+
import { initReq } from './initReq.js';
|
|
145
|
+
describe('initReq', () => {
|
|
146
|
+
beforeEach(() => {
|
|
147
|
+
mocks.authenticationSucceeds = true;
|
|
148
|
+
mocks.applyUserReadAccess.mockClear();
|
|
149
|
+
mocks.cacheStores.clear();
|
|
150
|
+
mocks.executeAuthStrategies.mockClear();
|
|
151
|
+
mocks.readAccessCalls = 0;
|
|
152
|
+
mocks.readAccessSucceeds = true;
|
|
153
|
+
});
|
|
154
|
+
it('should authenticate once and apply user read access for each request shape', async () => {
|
|
155
|
+
const first = await initReq({
|
|
156
|
+
configPromise: {},
|
|
157
|
+
importMap: {},
|
|
158
|
+
key: 'shared-request',
|
|
159
|
+
overrides: {
|
|
160
|
+
locale: 'en'
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const second = await initReq({
|
|
164
|
+
configPromise: {},
|
|
165
|
+
importMap: {},
|
|
166
|
+
key: 'shared-request',
|
|
167
|
+
overrides: {
|
|
168
|
+
locale: 'fr'
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
expect(mocks.executeAuthStrategies).toHaveBeenCalledOnce();
|
|
172
|
+
expect(mocks.readAccessCalls).toBe(2);
|
|
173
|
+
expect(first.user).toMatchObject({
|
|
174
|
+
requestLocale: 'en'
|
|
175
|
+
});
|
|
176
|
+
expect(second.user).toMatchObject({
|
|
177
|
+
requestLocale: 'fr'
|
|
178
|
+
});
|
|
179
|
+
expect(first.req.user).toHaveProperty('authorizationRole', 'admin');
|
|
180
|
+
expect(second.req.user).toHaveProperty('authorizationRole', 'admin');
|
|
181
|
+
});
|
|
182
|
+
it('should preserve complete fields for subsequent access checks', async () => {
|
|
183
|
+
const result = await initReq({
|
|
184
|
+
configPromise: {},
|
|
185
|
+
importMap: {},
|
|
186
|
+
key: 'subsequent-access'
|
|
187
|
+
});
|
|
188
|
+
const subsequentPermissions = await getAccessResults({
|
|
189
|
+
req: result.req
|
|
190
|
+
});
|
|
191
|
+
expect(result.req.user).toHaveProperty('authorizationRole', 'admin');
|
|
192
|
+
expect(result.user).not.toHaveProperty('authorizationRole');
|
|
193
|
+
expect(subsequentPermissions.canAccessAdmin).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
it('should clear authentication when client user processing fails', async () => {
|
|
196
|
+
mocks.readAccessSucceeds = false;
|
|
197
|
+
const result = await initReq({
|
|
198
|
+
configPromise: {},
|
|
199
|
+
importMap: {},
|
|
200
|
+
key: 'failed-user-read'
|
|
201
|
+
});
|
|
202
|
+
expect(result.user).toBeNull();
|
|
203
|
+
expect(result.req.user).toBeNull();
|
|
204
|
+
expect(result.permissions.canAccessAdmin).toBe(false);
|
|
205
|
+
});
|
|
206
|
+
it('should preserve an explicit user override without applying read access', async () => {
|
|
207
|
+
const user = {
|
|
208
|
+
authorizationRole: 'admin',
|
|
209
|
+
collection: 'users',
|
|
210
|
+
id: 'override-user'
|
|
211
|
+
};
|
|
212
|
+
const result = await initReq({
|
|
213
|
+
configPromise: {},
|
|
214
|
+
importMap: {},
|
|
215
|
+
key: 'user-override',
|
|
216
|
+
overrides: {
|
|
217
|
+
user
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
expect(mocks.applyUserReadAccess).not.toHaveBeenCalled();
|
|
221
|
+
expect(result.user).toBe(user);
|
|
222
|
+
expect(result.req.user).toBe(user);
|
|
223
|
+
expect(result.permissions.canAccessAdmin).toBe(true);
|
|
224
|
+
});
|
|
225
|
+
it('should preserve an explicit top-level null user override', async () => {
|
|
226
|
+
const result = await initReq({
|
|
227
|
+
configPromise: {},
|
|
228
|
+
importMap: {},
|
|
229
|
+
key: 'top-level-null-user-override',
|
|
230
|
+
overrides: {
|
|
231
|
+
user: null
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
expect(mocks.applyUserReadAccess).not.toHaveBeenCalled();
|
|
235
|
+
expect(result.user).toBeNull();
|
|
236
|
+
expect(result.req.user).toBeNull();
|
|
237
|
+
expect(result.permissions.canAccessAdmin).toBe(false);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
//# sourceMappingURL=initReq.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initReq.spec.js","names":["getAccessResults","beforeEach","describe","expect","it","vi","mocks","hoisted","applyUserReadAccess","fn","req","user","readAccessCalls","readAccessSucceeds","Error","userWithReadAccess","requestLocale","locale","authorizationRole","authenticationSucceeds","cacheStores","Map","executeAuthStrategies","responseHeaders","Headers","collection","id","mock","initI18n","dateFNSKey","fallbackLanguage","language","t","key","translations","headers","importOriginal","payloadModule","createLocalReq","options","payload","request","url","URL","urlSuffix","context","fallbackLocale","query","pathname","href","config","admin","canAccessAdmin","getPayload","collections","users","auth","depth","slug","i18n","supportedLanguages","en","logger","error","getRequestLanguage","getRequestLocale","code","selectiveCache","namespace","get","factory","args","cacheEntry","children","set","arg","child","value","initReq","mockClear","clear","first","configPromise","importMap","overrides","second","toHaveBeenCalledOnce","toBe","toMatchObject","toHaveProperty","result","subsequentPermissions","not","toBeNull","permissions","toHaveBeenCalled"],"sources":["../../src/utilities/initReq.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { getAccessResults } from 'payload'\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\ntype CacheEntry = {\n children: Map<unknown, CacheEntry>\n value?: object\n}\n\nconst mocks = vi.hoisted(() => ({\n applyUserReadAccess: vi.fn(\n async ({ req, user }: { req: PayloadRequest; user: NonNullable<PayloadRequest['user']> }) => {\n mocks.readAccessCalls += 1\n\n if (!mocks.readAccessSucceeds) {\n throw new Error('User read access failed')\n }\n\n const userWithReadAccess = {\n ...user,\n requestLocale: req.locale,\n }\n\n delete userWithReadAccess.authorizationRole\n\n return userWithReadAccess\n },\n ),\n authenticationSucceeds: true,\n cacheStores: new Map<string, CacheEntry>(),\n executeAuthStrategies: vi.fn(async () => ({\n responseHeaders: new Headers({ 'x-auth': 'authenticated' }),\n user: mocks.authenticationSucceeds\n ? {\n authorizationRole: 'admin',\n collection: 'users',\n id: 'user-id',\n }\n : null,\n })),\n readAccessCalls: 0,\n readAccessSucceeds: true,\n}))\n\nvi.mock('@payloadcms/translations', () => ({\n initI18n: vi.fn(async () => ({\n dateFNSKey: 'en-US',\n fallbackLanguage: 'en',\n language: 'en',\n t: (key: string) => key,\n translations: {},\n })),\n}))\n\nvi.mock('next/headers.js', () => ({\n headers: vi.fn(async () => new Headers()),\n}))\n\nvi.mock('payload', async (importOriginal) => {\n const payloadModule = await importOriginal<typeof import('payload')>()\n\n return {\n ...payloadModule,\n createLocalReq: vi.fn(async (options, payload) => {\n const request = options.req ?? {}\n const url = new URL(options.urlSuffix ?? '/', 'http://localhost')\n const user = options.user ?? request.user ?? null\n\n return {\n ...request,\n context: options.context ?? request.context ?? {},\n fallbackLocale: options.fallbackLocale,\n headers: request.headers ?? new Headers(),\n locale: options.locale ?? request.locale ?? request.query?.locale ?? 'en',\n pathname: request.pathname ?? url.pathname,\n payload,\n query: request.query ?? {},\n responseHeaders: request.responseHeaders ?? new Headers(),\n url: request.url ?? url.href,\n user: user && !user.collection ? { ...user, collection: payload.config.admin.user } : user,\n }\n }),\n executeAuthStrategies: mocks.executeAuthStrategies,\n getAccessResults: vi.fn(async ({ req }: { req: PayloadRequest }) => ({\n canAccessAdmin: req.user?.authorizationRole === 'admin',\n })),\n getPayload: vi.fn(async () => ({\n collections: {\n users: {\n config: {\n auth: { depth: 0 },\n slug: 'users',\n },\n },\n },\n config: {\n admin: { user: 'users' },\n i18n: {\n fallbackLanguage: 'en',\n supportedLanguages: { en: {} },\n translations: {},\n },\n },\n logger: { error: vi.fn() },\n })),\n getRequestLanguage: vi.fn(() => 'en'),\n }\n})\n\nvi.mock('payload/internal', () => ({\n applyUserReadAccess: mocks.applyUserReadAccess,\n}))\n\nvi.mock('./getRequestLocale.js', () => ({\n getRequestLocale: vi.fn(async ({ req }: { req: PayloadRequest }) => ({\n code: req.locale ?? 'en',\n })),\n}))\n\nvi.mock('./selectiveCache.js', () => ({\n selectiveCache: (namespace: string) => ({\n get: async (factory: () => Promise<object>, ...args: unknown[]) => {\n let cacheEntry = mocks.cacheStores.get(namespace)\n\n if (!cacheEntry) {\n cacheEntry = { children: new Map() }\n mocks.cacheStores.set(namespace, cacheEntry)\n }\n\n for (const arg of args) {\n let child = cacheEntry.children.get(arg)\n\n if (!child) {\n child = { children: new Map() }\n cacheEntry.children.set(arg, child)\n }\n\n cacheEntry = child\n }\n\n if (!('value' in cacheEntry)) {\n cacheEntry.value = await factory()\n }\n\n return cacheEntry.value\n },\n }),\n}))\n\nimport { initReq } from './initReq.js'\n\ndescribe('initReq', () => {\n beforeEach(() => {\n mocks.authenticationSucceeds = true\n mocks.applyUserReadAccess.mockClear()\n mocks.cacheStores.clear()\n mocks.executeAuthStrategies.mockClear()\n mocks.readAccessCalls = 0\n mocks.readAccessSucceeds = true\n })\n\n it('should authenticate once and apply user read access for each request shape', async () => {\n const first = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'shared-request',\n overrides: { locale: 'en' },\n })\n const second = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'shared-request',\n overrides: { locale: 'fr' },\n })\n\n expect(mocks.executeAuthStrategies).toHaveBeenCalledOnce()\n expect(mocks.readAccessCalls).toBe(2)\n expect(first.user).toMatchObject({ requestLocale: 'en' })\n expect(second.user).toMatchObject({ requestLocale: 'fr' })\n expect(first.req.user).toHaveProperty('authorizationRole', 'admin')\n expect(second.req.user).toHaveProperty('authorizationRole', 'admin')\n })\n\n it('should preserve complete fields for subsequent access checks', async () => {\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'subsequent-access',\n })\n\n const subsequentPermissions = await getAccessResults({ req: result.req })\n\n expect(result.req.user).toHaveProperty('authorizationRole', 'admin')\n expect(result.user).not.toHaveProperty('authorizationRole')\n expect(subsequentPermissions.canAccessAdmin).toBe(true)\n })\n\n it('should clear authentication when client user processing fails', async () => {\n mocks.readAccessSucceeds = false\n\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'failed-user-read',\n })\n\n expect(result.user).toBeNull()\n expect(result.req.user).toBeNull()\n expect(result.permissions.canAccessAdmin).toBe(false)\n })\n\n it('should preserve an explicit user override without applying read access', async () => {\n const user = { authorizationRole: 'admin', collection: 'users', id: 'override-user' }\n\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'user-override',\n overrides: { user },\n })\n\n expect(mocks.applyUserReadAccess).not.toHaveBeenCalled()\n expect(result.user).toBe(user)\n expect(result.req.user).toBe(user)\n expect(result.permissions.canAccessAdmin).toBe(true)\n })\n\n it('should preserve an explicit top-level null user override', async () => {\n const result = await initReq({\n configPromise: {} as never,\n importMap: {},\n key: 'top-level-null-user-override',\n overrides: { user: null },\n })\n\n expect(mocks.applyUserReadAccess).not.toHaveBeenCalled()\n expect(result.user).toBeNull()\n expect(result.req.user).toBeNull()\n expect(result.permissions.canAccessAdmin).toBe(false)\n })\n})\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isPublicAdminRoute.d.ts","sourceRoot":"","sources":["../../src/utilities/isPublicAdminRoute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAmB9C,eAAO,MAAM,kBAAkB,mCAI5B;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd,KAAG,
|
|
1
|
+
{"version":3,"file":"isPublicAdminRoute.d.ts","sourceRoot":"","sources":["../../src/utilities/isPublicAdminRoute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAmB9C,eAAO,MAAM,kBAAkB,mCAI5B;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,eAAe,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd,KAAG,OAuBH,CAAA"}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { getRouteWithoutAdmin } from './getRouteWithoutAdmin.js';
|
|
2
|
-
// Routes that
|
|
2
|
+
// Routes that are accessible without admin authentication
|
|
3
3
|
const publicAdminRoutes = ['createFirstUser', 'forgot', 'login', 'logout', 'forgot', 'inactivity', 'unauthorized', 'reset'];
|
|
4
4
|
export const isPublicAdminRoute = ({
|
|
5
5
|
adminRoute,
|
|
6
6
|
config,
|
|
7
7
|
route
|
|
8
8
|
}) => {
|
|
9
|
-
const
|
|
9
|
+
const routeWithoutAdmin = getRouteWithoutAdmin({
|
|
10
|
+
adminRoute,
|
|
11
|
+
route
|
|
12
|
+
});
|
|
13
|
+
const routeSegments = routeWithoutAdmin.split('/').filter(Boolean);
|
|
14
|
+
const isVerifyRoute = routeSegments.length === 3 && routeSegments[1] === 'verify' && config.collections.some(collection => collection.slug === routeSegments[0] && Boolean(collection.auth));
|
|
15
|
+
if (isVerifyRoute) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
return publicAdminRoutes.some(routeSegment => {
|
|
10
19
|
const segment = config.admin?.routes?.[routeSegment] || routeSegment;
|
|
11
|
-
const routeWithoutAdmin = getRouteWithoutAdmin({
|
|
12
|
-
adminRoute,
|
|
13
|
-
route
|
|
14
|
-
});
|
|
15
20
|
if (routeWithoutAdmin.startsWith(segment)) {
|
|
16
21
|
return true;
|
|
17
|
-
} else if (routeWithoutAdmin.includes('/verify/')) {
|
|
18
|
-
return true;
|
|
19
22
|
} else {
|
|
20
23
|
return false;
|
|
21
24
|
}
|
|
22
25
|
});
|
|
23
|
-
return isPublicAdminRoute;
|
|
24
26
|
};
|
|
25
27
|
//# sourceMappingURL=isPublicAdminRoute.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isPublicAdminRoute.js","names":["getRouteWithoutAdmin","publicAdminRoutes","isPublicAdminRoute","adminRoute","config","route","some","
|
|
1
|
+
{"version":3,"file":"isPublicAdminRoute.js","names":["getRouteWithoutAdmin","publicAdminRoutes","isPublicAdminRoute","adminRoute","config","route","routeWithoutAdmin","routeSegments","split","filter","Boolean","isVerifyRoute","length","collections","some","collection","slug","auth","routeSegment","segment","admin","routes","startsWith"],"sources":["../../src/utilities/isPublicAdminRoute.ts"],"sourcesContent":["import type { SanitizedConfig } from 'payload'\n\nimport { getRouteWithoutAdmin } from './getRouteWithoutAdmin.js'\n\n// Routes that are accessible without admin authentication\nconst publicAdminRoutes: (keyof Pick<\n SanitizedConfig['admin']['routes'],\n 'createFirstUser' | 'forgot' | 'inactivity' | 'login' | 'logout' | 'reset' | 'unauthorized'\n>)[] = [\n 'createFirstUser',\n 'forgot',\n 'login',\n 'logout',\n 'forgot',\n 'inactivity',\n 'unauthorized',\n 'reset',\n]\n\nexport const isPublicAdminRoute = ({\n adminRoute,\n config,\n route,\n}: {\n adminRoute: string\n config: SanitizedConfig\n route: string\n}): boolean => {\n const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })\n const routeSegments = routeWithoutAdmin.split('/').filter(Boolean)\n const isVerifyRoute =\n routeSegments.length === 3 &&\n routeSegments[1] === 'verify' &&\n config.collections.some(\n (collection) => collection.slug === routeSegments[0] && Boolean(collection.auth),\n )\n\n if (isVerifyRoute) {\n return true\n }\n\n return publicAdminRoutes.some((routeSegment) => {\n const segment = config.admin?.routes?.[routeSegment] || routeSegment\n\n if (routeWithoutAdmin.startsWith(segment)) {\n return true\n } else {\n return false\n }\n })\n}\n"],"mappings":"AAEA,SAASA,oBAAoB,QAAQ;AAErC;AACA,MAAMC,iBAAA,GAGC,CACL,mBACA,UACA,SACA,UACA,UACA,cACA,gBACA,QACD;AAED,OAAO,MAAMC,kBAAA,GAAqBA,CAAC;EACjCC,UAAU;EACVC,MAAM;EACNC;AAAK,CAKN;EACC,MAAMC,iBAAA,GAAoBN,oBAAA,CAAqB;IAAEG,UAAA;IAAYE;EAAM;EACnE,MAAME,aAAA,GAAgBD,iBAAA,CAAkBE,KAAK,CAAC,KAAKC,MAAM,CAACC,OAAA;EAC1D,MAAMC,aAAA,GACJJ,aAAA,CAAcK,MAAM,KAAK,KACzBL,aAAa,CAAC,EAAE,KAAK,YACrBH,MAAA,CAAOS,WAAW,CAACC,IAAI,CACpBC,UAAA,IAAeA,UAAA,CAAWC,IAAI,KAAKT,aAAa,CAAC,EAAE,IAAIG,OAAA,CAAQK,UAAA,CAAWE,IAAI;EAGnF,IAAIN,aAAA,EAAe;IACjB,OAAO;EACT;EAEA,OAAOV,iBAAA,CAAkBa,IAAI,CAAEI,YAAA;IAC7B,MAAMC,OAAA,GAAUf,MAAA,CAAOgB,KAAK,EAAEC,MAAA,GAASH,YAAA,CAAa,IAAIA,YAAA;IAExD,IAAIZ,iBAAA,CAAkBgB,UAAU,CAACH,OAAA,GAAU;MACzC,OAAO;IACT,OAAO;MACL,OAAO;IACT;EACF;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { isPublicAdminRoute } from './isPublicAdminRoute.js';
|
|
3
|
+
describe('isPublicAdminRoute', () => {
|
|
4
|
+
const config = {
|
|
5
|
+
collections: [{
|
|
6
|
+
auth: true,
|
|
7
|
+
slug: 'users'
|
|
8
|
+
}, {
|
|
9
|
+
slug: 'pages'
|
|
10
|
+
}]
|
|
11
|
+
};
|
|
12
|
+
it('should allow collection verification routes', () => {
|
|
13
|
+
expect(isPublicAdminRoute({
|
|
14
|
+
adminRoute: '/admin',
|
|
15
|
+
config,
|
|
16
|
+
route: '/admin/users/verify/token'
|
|
17
|
+
})).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('should not allow verification routes for collections without auth', () => {
|
|
20
|
+
expect(isPublicAdminRoute({
|
|
21
|
+
adminRoute: '/admin',
|
|
22
|
+
config,
|
|
23
|
+
route: '/admin/pages/verify/token'
|
|
24
|
+
})).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
it('should not allow unrelated routes containing the verification segment', () => {
|
|
27
|
+
expect(isPublicAdminRoute({
|
|
28
|
+
adminRoute: '/admin',
|
|
29
|
+
config,
|
|
30
|
+
route: '/admin/custom/verify/dashboard'
|
|
31
|
+
})).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=isPublicAdminRoute.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isPublicAdminRoute.spec.js","names":["describe","expect","it","isPublicAdminRoute","config","collections","auth","slug","adminRoute","route","toBe"],"sources":["../../src/utilities/isPublicAdminRoute.spec.ts"],"sourcesContent":["import type { SanitizedConfig } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { isPublicAdminRoute } from './isPublicAdminRoute.js'\n\ndescribe('isPublicAdminRoute', () => {\n const config = {\n collections: [{ auth: true, slug: 'users' }, { slug: 'pages' }],\n } as unknown as SanitizedConfig\n\n it('should allow collection verification routes', () => {\n expect(\n isPublicAdminRoute({\n adminRoute: '/admin',\n config,\n route: '/admin/users/verify/token',\n }),\n ).toBe(true)\n })\n\n it('should not allow verification routes for collections without auth', () => {\n expect(\n isPublicAdminRoute({\n adminRoute: '/admin',\n config,\n route: '/admin/pages/verify/token',\n }),\n ).toBe(false)\n })\n\n it('should not allow unrelated routes containing the verification segment', () => {\n expect(\n isPublicAdminRoute({\n adminRoute: '/admin',\n config,\n route: '/admin/custom/verify/dashboard',\n }),\n ).toBe(false)\n })\n})\n"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ;AAErC,SAASC,kBAAkB,QAAQ;AAEnCH,QAAA,CAAS,sBAAsB;EAC7B,MAAMI,MAAA,GAAS;IACbC,WAAA,EAAa,CAAC;MAAEC,IAAA,EAAM;MAAMC,IAAA,EAAM;IAAQ,GAAG;MAAEA,IAAA,EAAM;IAAQ;EAC/D;EAEAL,EAAA,CAAG,+CAA+C;IAChDD,MAAA,CACEE,kBAAA,CAAmB;MACjBK,UAAA,EAAY;MACZJ,MAAA;MACAK,KAAA,EAAO;IACT,IACAC,IAAI,CAAC;EACT;EAEAR,EAAA,CAAG,qEAAqE;IACtED,MAAA,CACEE,kBAAA,CAAmB;MACjBK,UAAA,EAAY;MACZJ,MAAA;MACAK,KAAA,EAAO;IACT,IACAC,IAAI,CAAC;EACT;EAEAR,EAAA,CAAG,yEAAyE;IAC1ED,MAAA,CACEE,kBAAA,CAAmB;MACjBK,UAAA,EAAY;MACZJ,MAAA;MACAK,KAAA,EAAO;IACT,IACAC,IAAI,CAAC;EACT;AACF","ignoreList":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { AdminViewServerProps } from 'payload';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
export declare function AccountView({ initPageResult, params, searchParams }: AdminViewServerProps): Promise<React.JSX.Element>;
|
|
3
|
+
export declare function AccountView({ initPageResult, params, searchParams, user: userWithReadAccess, }: AdminViewServerProps): Promise<React.JSX.Element>;
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/views/Account/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAA+B,MAAM,SAAS,CAAA;AAOhF,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,wBAAsB,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/views/Account/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAA+B,MAAM,SAAS,CAAA;AAOhF,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,wBAAsB,WAAW,CAAC,EAChC,cAAc,EACd,MAAM,EACN,YAAY,EACZ,IAAI,EAAE,kBAAkB,GACzB,EAAE,oBAAoB,8BAkKtB"}
|
|
@@ -17,7 +17,8 @@ import { Settings } from './Settings/index.js';
|
|
|
17
17
|
export async function AccountView({
|
|
18
18
|
initPageResult,
|
|
19
19
|
params,
|
|
20
|
-
searchParams
|
|
20
|
+
searchParams,
|
|
21
|
+
user: userWithReadAccess
|
|
21
22
|
}) {
|
|
22
23
|
const {
|
|
23
24
|
languageOptions,
|
|
@@ -91,7 +92,8 @@ export async function AccountView({
|
|
|
91
92
|
renderAllFields: true,
|
|
92
93
|
req,
|
|
93
94
|
schemaPath: collectionConfig.slug,
|
|
94
|
-
skipValidation: true
|
|
95
|
+
skipValidation: true,
|
|
96
|
+
user: userWithReadAccess
|
|
95
97
|
});
|
|
96
98
|
// Fetch document lock state
|
|
97
99
|
const {
|
|
@@ -125,11 +127,11 @@ export async function AccountView({
|
|
|
125
127
|
languageOptions: languageOptions,
|
|
126
128
|
payload: payload,
|
|
127
129
|
theme: theme,
|
|
128
|
-
user:
|
|
130
|
+
user: userWithReadAccess
|
|
129
131
|
}),
|
|
130
132
|
apiURL: formatAdminURL({
|
|
131
133
|
apiRoute: api,
|
|
132
|
-
path: `/${userSlug}
|
|
134
|
+
path: `/${userSlug}/${user.id}`
|
|
133
135
|
}),
|
|
134
136
|
collectionSlug: userSlug,
|
|
135
137
|
currentEditor: currentEditor,
|
|
@@ -139,7 +141,7 @@ export async function AccountView({
|
|
|
139
141
|
hasPublishPermission: hasPublishPermission,
|
|
140
142
|
hasSavePermission: hasSavePermission,
|
|
141
143
|
hasTrashPermission: hasTrashPermission,
|
|
142
|
-
id: user
|
|
144
|
+
id: user.id,
|
|
143
145
|
initialData: data,
|
|
144
146
|
initialState: formState,
|
|
145
147
|
isEditing: true,
|
|
@@ -153,7 +155,8 @@ export async function AccountView({
|
|
|
153
155
|
collectionConfig: collectionConfig,
|
|
154
156
|
hideTabs: true,
|
|
155
157
|
permissions: permissions,
|
|
156
|
-
req: req
|
|
158
|
+
req: req,
|
|
159
|
+
user: userWithReadAccess
|
|
157
160
|
}), /*#__PURE__*/_jsx(HydrateAuthProvider, {
|
|
158
161
|
permissions: permissions
|
|
159
162
|
}), RenderServerComponent({
|
|
@@ -171,7 +174,7 @@ export async function AccountView({
|
|
|
171
174
|
permissions,
|
|
172
175
|
routeSegments: [],
|
|
173
176
|
searchParams,
|
|
174
|
-
user
|
|
177
|
+
user: userWithReadAccess
|
|
175
178
|
}
|
|
176
179
|
}), /*#__PURE__*/_jsx(AccountClient, {})]
|
|
177
180
|
})
|