@payloadcms/next 3.89.0 → 3.90.1

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.
Files changed (82) hide show
  1. package/dist/elements/DocumentHeader/Tabs/Tab/index.d.ts +2 -1
  2. package/dist/elements/DocumentHeader/Tabs/Tab/index.d.ts.map +1 -1
  3. package/dist/elements/DocumentHeader/Tabs/Tab/index.js +3 -2
  4. package/dist/elements/DocumentHeader/Tabs/Tab/index.js.map +1 -1
  5. package/dist/elements/DocumentHeader/Tabs/index.d.ts +2 -1
  6. package/dist/elements/DocumentHeader/Tabs/index.d.ts.map +1 -1
  7. package/dist/elements/DocumentHeader/Tabs/index.js +5 -3
  8. package/dist/elements/DocumentHeader/Tabs/index.js.map +1 -1
  9. package/dist/elements/DocumentHeader/index.d.ts +2 -1
  10. package/dist/elements/DocumentHeader/index.d.ts.map +1 -1
  11. package/dist/elements/DocumentHeader/index.js +4 -2
  12. package/dist/elements/DocumentHeader/index.js.map +1 -1
  13. package/dist/layouts/Root/index.js +6 -5
  14. package/dist/layouts/Root/index.js.map +1 -1
  15. package/dist/prod/styles.css +1 -1
  16. package/dist/utilities/handleServerFunctions.d.ts.map +1 -1
  17. package/dist/utilities/handleServerFunctions.js +4 -2
  18. package/dist/utilities/handleServerFunctions.js.map +1 -1
  19. package/dist/utilities/initReq.d.ts.map +1 -1
  20. package/dist/utilities/initReq.js +35 -2
  21. package/dist/utilities/initReq.js.map +1 -1
  22. package/dist/utilities/initReq.spec.js +240 -0
  23. package/dist/utilities/initReq.spec.js.map +1 -0
  24. package/dist/utilities/isPublicAdminRoute.d.ts.map +1 -1
  25. package/dist/utilities/isPublicAdminRoute.js +11 -9
  26. package/dist/utilities/isPublicAdminRoute.js.map +1 -1
  27. package/dist/utilities/isPublicAdminRoute.spec.js +34 -0
  28. package/dist/utilities/isPublicAdminRoute.spec.js.map +1 -0
  29. package/dist/views/Account/index.d.ts +1 -1
  30. package/dist/views/Account/index.d.ts.map +1 -1
  31. package/dist/views/Account/index.js +10 -7
  32. package/dist/views/Account/index.js.map +1 -1
  33. package/dist/views/BrowseByFolder/buildView.js +4 -4
  34. package/dist/views/BrowseByFolder/buildView.js.map +1 -1
  35. package/dist/views/CollectionFolders/buildView.js +4 -4
  36. package/dist/views/CollectionFolders/buildView.js.map +1 -1
  37. package/dist/views/Dashboard/Default/ModularDashboard/index.d.ts.map +1 -1
  38. package/dist/views/Dashboard/Default/ModularDashboard/index.js +1 -0
  39. package/dist/views/Dashboard/Default/ModularDashboard/index.js.map +1 -1
  40. package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.d.ts.map +1 -1
  41. package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js +3 -1
  42. package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js.map +1 -1
  43. package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.d.ts.map +1 -1
  44. package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js +2 -0
  45. package/dist/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js.map +1 -1
  46. package/dist/views/Dashboard/index.js +5 -3
  47. package/dist/views/Dashboard/index.js.map +1 -1
  48. package/dist/views/Document/handleServerFunction.d.ts.map +1 -1
  49. package/dist/views/Document/handleServerFunction.js +2 -0
  50. package/dist/views/Document/handleServerFunction.js.map +1 -1
  51. package/dist/views/Document/index.d.ts +1 -1
  52. package/dist/views/Document/index.d.ts.map +1 -1
  53. package/dist/views/Document/index.js +9 -4
  54. package/dist/views/Document/index.js.map +1 -1
  55. package/dist/views/Document/renderDocumentSlots.d.ts +1 -0
  56. package/dist/views/Document/renderDocumentSlots.d.ts.map +1 -1
  57. package/dist/views/Document/renderDocumentSlots.js +7 -4
  58. package/dist/views/Document/renderDocumentSlots.js.map +1 -1
  59. package/dist/views/ForgotPassword/ForgotPasswordForm/index.d.ts +1 -0
  60. package/dist/views/ForgotPassword/ForgotPasswordForm/index.d.ts.map +1 -1
  61. package/dist/views/ForgotPassword/ForgotPasswordForm/index.js +212 -159
  62. package/dist/views/ForgotPassword/ForgotPasswordForm/index.js.map +1 -1
  63. package/dist/views/ForgotPassword/index.d.ts.map +1 -1
  64. package/dist/views/ForgotPassword/index.js +3 -11
  65. package/dist/views/ForgotPassword/index.js.map +1 -1
  66. package/dist/views/List/handleServerFunction.d.ts.map +1 -1
  67. package/dist/views/List/handleServerFunction.js +4 -2
  68. package/dist/views/List/handleServerFunction.js.map +1 -1
  69. package/dist/views/List/index.d.ts.map +1 -1
  70. package/dist/views/List/index.js +2 -1
  71. package/dist/views/List/index.js.map +1 -1
  72. package/dist/views/NotFound/index.d.ts.map +1 -1
  73. package/dist/views/NotFound/index.js +3 -2
  74. package/dist/views/NotFound/index.js.map +1 -1
  75. package/dist/views/Root/index.d.ts.map +1 -1
  76. package/dist/views/Root/index.js +6 -4
  77. package/dist/views/Root/index.js.map +1 -1
  78. package/dist/views/Verify/index.d.ts +1 -1
  79. package/dist/views/Verify/index.d.ts.map +1 -1
  80. package/dist/views/Verify/index.js +4 -4
  81. package/dist/views/Verify/index.js.map +1 -1
  82. 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,qBA+BnC,CAAA"}
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;EAAG,CAAE,GAAG,MAAMjB,OAAA,CAAQ;IAC1DU,aAAA;IACAC,SAAA;IACAO,GAAA,EAAK;EACP;EAEA,MAAMC,aAAA,GAA2C;IAC/C,GAAGX,MAAM;IACTM,OAAA;IACAH,SAAA;IACAI,MAAA;IACAC,WAAA;IACAC;EACF;EAEA,MAAMG,EAAA,GAAKP,oBAAA,GAAuBN,KAAA,CAAM,IAAIL,mBAAmB,CAACK,KAAA,CAAM;EAEtE,IAAI,CAACa,EAAA,EAAI;IACP,MAAM,IAAIC,KAAA,CAAM,4BAA4Bd,KAAA,EAAO;EACrD;EAEA,OAAOa,EAAA,CAAGD,aAAA;AACZ","ignoreList":[]}
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;AAchB;;;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,CA0FxB,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 const { i18n, languageCode, payload, responseHeaders, user } = partialResult\n\n const { req: reqOverrides, ...optionsOverrides } = overrides || {}\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 const locale = await getRequestLocale({\n req,\n })\n\n req.locale = locale?.code\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 }\n }, key)\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":"AAGA,SAASA,QAAQ,QAAQ;AACzB,SAASC,OAAA,IAAWC,UAAU,QAAQ;AACtC,SACEC,cAAc,EACdC,qBAAqB,EACrBC,gBAAgB,EAChBC,UAAU,EACVC,kBAAkB,EAClBC,YAAY,QACP;AAEP,SAASC,gBAAgB,QAAQ;AACjC,SAASC,cAAc,QAAQ;AAO/B;AACA,MAAMC,eAAA,GAAkBD,cAAA,CAA8B;AACtD,MAAME,QAAA,GAAWF,cAAA,CAA8B;AAE/C;;;;AAIA,OAAO,MAAMG,OAAA,GAAU,eAAAA,CAAgB;EACrCC,aAAa;EACbC,aAAa;EACbC,SAAS;EACTC,GAAG;EACHC;AAAS,CAOV;EACC,MAAMjB,OAAA,GAAU,MAAMC,UAAA;EACtB,MAAMiB,OAAA,GAAUX,YAAA,CAAaP,OAAA;EAE7B,MAAMmB,aAAA,GAAgB,MAAMT,eAAA,CAAgBU,GAAG,CAAC;IAC9C,MAAMC,MAAA,GAAS,MAAMP,aAAA;IACrB,MAAMQ,OAAA,GAAU,MAAMjB,UAAA,CAAW;MAAEgB,MAAA;MAAQE,IAAA,EAAM;MAAMR;IAAU;IACjE,MAAMS,YAAA,GAAelB,kBAAA,CAAmB;MACtCe,MAAA;MACAH,OAAA;MACAlB;IACF;IAEA,MAAMyB,IAAA,GAAmB,MAAM1B,QAAA,CAAS;MACtCsB,MAAA,EAAQA,MAAA,CAAOI,IAAI;MACnBC,OAAA,EAAS;MACTC,QAAA,EAAUH;IACZ;IAEA,MAAM;MAAEI,eAAe;MAAEC;IAAI,CAAE,GAAG,MAAM1B,qBAAA,CAAsB;MAC5DU,aAAA;MACAb,OAAA;MACAsB;IACF;IAEA,OAAO;MACLG,IAAA;MACAD,YAAA;MACAF,OAAA;MACAM,eAAA;MACAC;IACF;EACF,GAAG;EAEH,OAAOlB,QAAA,CACJS,GAAG,CAAC;IACH,MAAM;MAAEK,IAAI;MAAED,YAAY;MAAEF,OAAO;MAAEM,eAAe;MAAEC;IAAI,CAAE,GAAGV,aAAA;IAE/D,MAAM;MAAEW,GAAA,EAAKC,YAAY;MAAE,GAAGC;IAAA,CAAkB,GAAGf,SAAA,IAAa,CAAC;IAEjE,MAAMa,GAAA,GAAM,MAAM5B,cAAA,CAChB;MACE4B,GAAA,EAAK;QACH9B,OAAA;QACAiC,IAAA,EAAMjC,OAAA,CAAQoB,GAAG,CAAC;QAClBK,IAAA,EAAMA,IAAA;QACNG,eAAA;QACAC,IAAA;QACA,IAAIE,YAAA,IAAgB,CAAC,CAAC;MACxB;MACA,IAAIC,gBAAA,IAAoB,CAAC,CAAC;IAC5B,GACAV,OAAA;IAGF,MAAMY,MAAA,GAAS,MAAM1B,gBAAA,CAAiB;MACpCsB;IACF;IAEAA,GAAA,CAAII,MAAM,GAAGA,MAAA,EAAQC,IAAA;IAErB,MAAMC,WAAA,GAAc,MAAMhC,gBAAA,CAAiB;MACzC0B;IACF;IAEA,OAAO;MACLZ,OAAA;MACAlB,OAAA;MACAwB,YAAA;MACAU,MAAA;MACAE,WAAA;MACAN;IACF;EACF,GAAGd,GAAA,EACFqB,IAAI,CAAEC,MAAA;IACL;IACA;IACA;IACA,OAAO;MACL,GAAGA,MAAM;MACTR,GAAA,EAAK;QACH,GAAGQ,MAAA,CAAOR,GAAG;QACb,IAAIQ,MAAA,CAAOR,GAAG,EAAEJ,OAAA,GACZ;UACEA,OAAA,EAAS;YAAE,GAAGY,MAAA,CAAOR,GAAG,CAACJ;UAAQ;QACnC,IACA,CAAC,CAAC;MACR;IACF;EACF;AACJ","ignoreList":[]}
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,OAeH,CAAA"}
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 require admin authentication
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 isPublicAdminRoute = publicAdminRoutes.some(routeSegment => {
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","routeSegment","segment","admin","routes","routeWithoutAdmin","startsWith","includes"],"sources":["../../src/utilities/isPublicAdminRoute.ts"],"sourcesContent":["import type { SanitizedConfig } from 'payload'\n\nimport { getRouteWithoutAdmin } from './getRouteWithoutAdmin.js'\n\n// Routes that require 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 isPublicAdminRoute = publicAdminRoutes.some((routeSegment) => {\n const segment = config.admin?.routes?.[routeSegment] || routeSegment\n const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })\n\n if (routeWithoutAdmin.startsWith(segment)) {\n return true\n } else if (routeWithoutAdmin.includes('/verify/')) {\n return true\n } else {\n return false\n }\n })\n\n return isPublicAdminRoute\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,MAAMH,kBAAA,GAAqBD,iBAAA,CAAkBK,IAAI,CAAEC,YAAA;IACjD,MAAMC,OAAA,GAAUJ,MAAA,CAAOK,KAAK,EAAEC,MAAA,GAASH,YAAA,CAAa,IAAIA,YAAA;IACxD,MAAMI,iBAAA,GAAoBX,oBAAA,CAAqB;MAAEG,UAAA;MAAYE;IAAM;IAEnE,IAAIM,iBAAA,CAAkBC,UAAU,CAACJ,OAAA,GAAU;MACzC,OAAO;IACT,OAAO,IAAIG,iBAAA,CAAkBE,QAAQ,CAAC,aAAa;MACjD,OAAO;IACT,OAAO;MACL,OAAO;IACT;EACF;EAEA,OAAOX,kBAAA;AACT","ignoreList":[]}
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,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,oBAAoB,8BAgK/F"}
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: user
130
+ user: userWithReadAccess
129
131
  }),
130
132
  apiURL: formatAdminURL({
131
133
  apiRoute: api,
132
- path: `/${userSlug}${user?.id ? `/${user.id}` : ''}`
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?.id,
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
  })