payload 3.79.0 → 3.79.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 (93) hide show
  1. package/dist/auth/endpoints/forgotPassword.d.ts.map +1 -1
  2. package/dist/auth/endpoints/forgotPassword.js +0 -2
  3. package/dist/auth/endpoints/forgotPassword.js.map +1 -1
  4. package/dist/auth/extractJWT.d.ts.map +1 -1
  5. package/dist/auth/extractJWT.js +18 -4
  6. package/dist/auth/extractJWT.js.map +1 -1
  7. package/dist/auth/operations/forgotPassword.d.ts.map +1 -1
  8. package/dist/auth/operations/forgotPassword.js +5 -4
  9. package/dist/auth/operations/forgotPassword.js.map +1 -1
  10. package/dist/auth/operations/me.js +5 -5
  11. package/dist/auth/operations/me.js.map +1 -1
  12. package/dist/auth/sendVerificationEmail.d.ts.map +1 -1
  13. package/dist/auth/sendVerificationEmail.js +5 -4
  14. package/dist/auth/sendVerificationEmail.js.map +1 -1
  15. package/dist/config/orderable/index.d.ts +2 -2
  16. package/dist/config/orderable/index.d.ts.map +1 -1
  17. package/dist/config/orderable/index.js +60 -34
  18. package/dist/config/orderable/index.js.map +1 -1
  19. package/dist/config/orderable/utils/buildJoinScopeWhere.d.ts +10 -0
  20. package/dist/config/orderable/utils/buildJoinScopeWhere.d.ts.map +1 -0
  21. package/dist/config/orderable/utils/buildJoinScopeWhere.js +43 -0
  22. package/dist/config/orderable/utils/buildJoinScopeWhere.js.map +1 -0
  23. package/dist/config/orderable/utils/getJoinScopeContext.d.ts +16 -0
  24. package/dist/config/orderable/utils/getJoinScopeContext.d.ts.map +1 -0
  25. package/dist/config/orderable/utils/getJoinScopeContext.js +42 -0
  26. package/dist/config/orderable/utils/getJoinScopeContext.js.map +1 -0
  27. package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.d.ts +12 -0
  28. package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.d.ts.map +1 -0
  29. package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.js +18 -0
  30. package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.js.map +1 -0
  31. package/dist/config/orderable/utils/getValueAtPath.d.ts +5 -0
  32. package/dist/config/orderable/utils/getValueAtPath.d.ts.map +1 -0
  33. package/dist/config/orderable/utils/getValueAtPath.js +18 -0
  34. package/dist/config/orderable/utils/getValueAtPath.js.map +1 -0
  35. package/dist/config/orderable/utils/resolvePendingTargetKey.d.ts +13 -0
  36. package/dist/config/orderable/utils/resolvePendingTargetKey.d.ts.map +1 -0
  37. package/dist/config/orderable/utils/resolvePendingTargetKey.js +24 -0
  38. package/dist/config/orderable/utils/resolvePendingTargetKey.js.map +1 -0
  39. package/dist/config/types.d.ts +1 -1
  40. package/dist/config/types.js.map +1 -1
  41. package/dist/database/getLocalizedPaths.d.ts.map +1 -1
  42. package/dist/database/getLocalizedPaths.js +2 -1
  43. package/dist/database/getLocalizedPaths.js.map +1 -1
  44. package/dist/database/queryValidation/validateQueryPaths.js +1 -1
  45. package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
  46. package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
  47. package/dist/database/queryValidation/validateSearchParams.js +2 -1
  48. package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
  49. package/dist/database/sanitizeJoinQuery.d.ts.map +1 -1
  50. package/dist/database/sanitizeJoinQuery.js +6 -0
  51. package/dist/database/sanitizeJoinQuery.js.map +1 -1
  52. package/dist/exports/shared.d.ts +1 -0
  53. package/dist/exports/shared.d.ts.map +1 -1
  54. package/dist/exports/shared.js +1 -0
  55. package/dist/exports/shared.js.map +1 -1
  56. package/dist/fields/validations.js +1 -1
  57. package/dist/fields/validations.js.map +1 -1
  58. package/dist/fields/validations.spec.js +25 -0
  59. package/dist/fields/validations.spec.js.map +1 -1
  60. package/dist/index.bundled.d.ts +8 -5
  61. package/dist/types/constants.d.ts +5 -0
  62. package/dist/types/constants.d.ts.map +1 -1
  63. package/dist/types/constants.js +4 -0
  64. package/dist/types/constants.js.map +1 -1
  65. package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
  66. package/dist/uploads/endpoints/getFile.js +7 -1
  67. package/dist/uploads/endpoints/getFile.js.map +1 -1
  68. package/dist/uploads/endpoints/getFileFromURL.d.ts.map +1 -1
  69. package/dist/uploads/endpoints/getFileFromURL.js +67 -28
  70. package/dist/uploads/endpoints/getFileFromURL.js.map +1 -1
  71. package/dist/uploads/getExternalFile.d.ts.map +1 -1
  72. package/dist/uploads/getExternalFile.js +3 -0
  73. package/dist/uploads/getExternalFile.js.map +1 -1
  74. package/dist/uploads/safeFetch.d.ts +1 -1
  75. package/dist/uploads/safeFetch.d.ts.map +1 -1
  76. package/dist/uploads/safeFetch.js.map +1 -1
  77. package/dist/utilities/configToJSONSchema.d.ts +7 -3
  78. package/dist/utilities/configToJSONSchema.d.ts.map +1 -1
  79. package/dist/utilities/configToJSONSchema.js +23 -33
  80. package/dist/utilities/configToJSONSchema.js.map +1 -1
  81. package/dist/utilities/configToJSONSchema.spec.js +75 -1
  82. package/dist/utilities/configToJSONSchema.spec.js.map +1 -1
  83. package/dist/utilities/getRequestOrigin.d.ts +10 -0
  84. package/dist/utilities/getRequestOrigin.d.ts.map +1 -0
  85. package/dist/utilities/getRequestOrigin.js +50 -0
  86. package/dist/utilities/getRequestOrigin.js.map +1 -0
  87. package/dist/utilities/getRequestOrigin.spec.js +151 -0
  88. package/dist/utilities/getRequestOrigin.spec.js.map +1 -0
  89. package/dist/utilities/sanitizeUrl.d.ts +7 -0
  90. package/dist/utilities/sanitizeUrl.d.ts.map +1 -0
  91. package/dist/utilities/sanitizeUrl.js +28 -0
  92. package/dist/utilities/sanitizeUrl.js.map +1 -0
  93. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/endpoints/forgotPassword.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAM3D,eAAO,MAAM,qBAAqB,EAAE,cAkCnC,CAAA"}
1
+ {"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/endpoints/forgotPassword.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAM3D,eAAO,MAAM,qBAAqB,EAAE,cAgCnC,CAAA"}
@@ -14,8 +14,6 @@ export const forgotPasswordHandler = async (req)=>{
14
14
  await forgotPasswordOperation({
15
15
  collection,
16
16
  data: authData,
17
- disableEmail: Boolean(req.data?.disableEmail),
18
- expiration: typeof req.data?.expiration === 'number' ? req.data.expiration : undefined,
19
17
  req
20
18
  });
21
19
  return Response.json({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/auth/endpoints/forgotPassword.ts"],"sourcesContent":["import { status as httpStatus } from 'http-status'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\nimport { forgotPasswordOperation } from '../operations/forgotPassword.js'\n\nexport const forgotPasswordHandler: PayloadHandler = async (req) => {\n const { t } = req\n\n const collection = getRequestCollection(req)\n\n const authData = collection.config.auth?.loginWithUsername\n ? {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n username: typeof req.data?.username === 'string' ? req.data.username : '',\n }\n : {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n }\n\n await forgotPasswordOperation({\n collection,\n data: authData,\n disableEmail: Boolean(req.data?.disableEmail),\n expiration: typeof req.data?.expiration === 'number' ? req.data.expiration : undefined,\n req,\n })\n\n return Response.json(\n {\n message: t('general:success'),\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.OK,\n },\n )\n}\n"],"names":["status","httpStatus","getRequestCollection","headersWithCors","forgotPasswordOperation","forgotPasswordHandler","req","t","collection","authData","config","auth","loginWithUsername","email","data","username","disableEmail","Boolean","expiration","undefined","Response","json","message","headers","Headers","OK"],"mappings":"AAAA,SAASA,UAAUC,UAAU,QAAQ,cAAa;AAIlD,SAASC,oBAAoB,QAAQ,sCAAqC;AAC1E,SAASC,eAAe,QAAQ,qCAAoC;AACpE,SAASC,uBAAuB,QAAQ,kCAAiC;AAEzE,OAAO,MAAMC,wBAAwC,OAAOC;IAC1D,MAAM,EAAEC,CAAC,EAAE,GAAGD;IAEd,MAAME,aAAaN,qBAAqBI;IAExC,MAAMG,WAAWD,WAAWE,MAAM,CAACC,IAAI,EAAEC,oBACrC;QACEC,OAAO,OAAOP,IAAIQ,IAAI,EAAED,UAAU,WAAWP,IAAIQ,IAAI,CAACD,KAAK,GAAG;QAC9DE,UAAU,OAAOT,IAAIQ,IAAI,EAAEC,aAAa,WAAWT,IAAIQ,IAAI,CAACC,QAAQ,GAAG;IACzE,IACA;QACEF,OAAO,OAAOP,IAAIQ,IAAI,EAAED,UAAU,WAAWP,IAAIQ,IAAI,CAACD,KAAK,GAAG;IAChE;IAEJ,MAAMT,wBAAwB;QAC5BI;QACAM,MAAML;QACNO,cAAcC,QAAQX,IAAIQ,IAAI,EAAEE;QAChCE,YAAY,OAAOZ,IAAIQ,IAAI,EAAEI,eAAe,WAAWZ,IAAIQ,IAAI,CAACI,UAAU,GAAGC;QAC7Eb;IACF;IAEA,OAAOc,SAASC,IAAI,CAClB;QACEC,SAASf,EAAE;IACb,GACA;QACEgB,SAASpB,gBAAgB;YACvBoB,SAAS,IAAIC;YACblB;QACF;QACAN,QAAQC,WAAWwB,EAAE;IACvB;AAEJ,EAAC"}
1
+ {"version":3,"sources":["../../../src/auth/endpoints/forgotPassword.ts"],"sourcesContent":["import { status as httpStatus } from 'http-status'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\nimport { forgotPasswordOperation } from '../operations/forgotPassword.js'\n\nexport const forgotPasswordHandler: PayloadHandler = async (req) => {\n const { t } = req\n\n const collection = getRequestCollection(req)\n\n const authData = collection.config.auth?.loginWithUsername\n ? {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n username: typeof req.data?.username === 'string' ? req.data.username : '',\n }\n : {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n }\n\n await forgotPasswordOperation({\n collection,\n data: authData,\n req,\n })\n\n return Response.json(\n {\n message: t('general:success'),\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.OK,\n },\n )\n}\n"],"names":["status","httpStatus","getRequestCollection","headersWithCors","forgotPasswordOperation","forgotPasswordHandler","req","t","collection","authData","config","auth","loginWithUsername","email","data","username","Response","json","message","headers","Headers","OK"],"mappings":"AAAA,SAASA,UAAUC,UAAU,QAAQ,cAAa;AAIlD,SAASC,oBAAoB,QAAQ,sCAAqC;AAC1E,SAASC,eAAe,QAAQ,qCAAoC;AACpE,SAASC,uBAAuB,QAAQ,kCAAiC;AAEzE,OAAO,MAAMC,wBAAwC,OAAOC;IAC1D,MAAM,EAAEC,CAAC,EAAE,GAAGD;IAEd,MAAME,aAAaN,qBAAqBI;IAExC,MAAMG,WAAWD,WAAWE,MAAM,CAACC,IAAI,EAAEC,oBACrC;QACEC,OAAO,OAAOP,IAAIQ,IAAI,EAAED,UAAU,WAAWP,IAAIQ,IAAI,CAACD,KAAK,GAAG;QAC9DE,UAAU,OAAOT,IAAIQ,IAAI,EAAEC,aAAa,WAAWT,IAAIQ,IAAI,CAACC,QAAQ,GAAG;IACzE,IACA;QACEF,OAAO,OAAOP,IAAIQ,IAAI,EAAED,UAAU,WAAWP,IAAIQ,IAAI,CAACD,KAAK,GAAG;IAChE;IAEJ,MAAMT,wBAAwB;QAC5BI;QACAM,MAAML;QACNH;IACF;IAEA,OAAOU,SAASC,IAAI,CAClB;QACEC,SAASX,EAAE;IACb,GACA;QACEY,SAAShB,gBAAgB;YACvBgB,SAAS,IAAIC;YACbd;QACF;QACAN,QAAQC,WAAWoB,EAAE;IACvB;AAEJ,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"extractJWT.d.ts","sourceRoot":"","sources":["../../src/auth/extractJWT.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AA6C1D,eAAO,MAAM,UAAU,SAAU,IAAI,CAAC,wBAAwB,EAAE,cAAc,CAAC,KAAG,IAAI,GAAG,MAcxF,CAAA"}
1
+ {"version":3,"file":"extractJWT.d.ts","sourceRoot":"","sources":["../../src/auth/extractJWT.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AA+D1D,eAAO,MAAM,UAAU,SAAU,IAAI,CAAC,wBAAwB,EAAE,cAAc,CAAC,KAAG,IAAI,GAAG,MAcxF,CAAA"}
@@ -2,24 +2,38 @@ import { parseCookies } from '../utilities/parseCookies.js';
2
2
  const extractionMethods = {
3
3
  Bearer: ({ headers })=>{
4
4
  const jwtFromHeader = headers.get('Authorization');
5
- // allow RFC6750 OAuth 2.0 compliant Bearer tokens
6
- // in addition to the payload default JWT format
5
+ // RFC6750 OAuth 2.0 Bearer token
7
6
  if (jwtFromHeader?.startsWith('Bearer ')) {
8
7
  return jwtFromHeader.replace('Bearer ', '');
9
8
  }
10
9
  return null;
11
10
  },
12
11
  cookie: ({ headers, payload })=>{
13
- const origin = headers.get('Origin');
14
12
  const cookies = parseCookies(headers);
15
13
  const tokenCookieName = `${payload.config.cookiePrefix}-token`;
16
14
  const cookieToken = cookies.get(tokenCookieName);
17
15
  if (!cookieToken) {
18
16
  return null;
19
17
  }
20
- if (!origin || payload.config.csrf.length === 0 || payload.config.csrf.indexOf(origin) > -1) {
18
+ const origin = headers.get('Origin');
19
+ // Origin present — validate against csrf allowlist
20
+ if (origin) {
21
+ if (payload.config.csrf.length === 0 || payload.config.csrf.includes(origin)) {
22
+ return cookieToken;
23
+ }
24
+ return null;
25
+ }
26
+ // No Origin and no csrf configured — no allowlist to enforce
27
+ if (payload.config.csrf.length === 0) {
28
+ return cookieToken;
29
+ }
30
+ // No Origin with csrf configured — fall back to Sec-Fetch-Site
31
+ const secFetchSite = headers.get('Sec-Fetch-Site');
32
+ // Allow same-origin, same-site, and direct navigations (none)
33
+ if (secFetchSite === 'same-origin' || secFetchSite === 'same-site' || secFetchSite === 'none') {
21
34
  return cookieToken;
22
35
  }
36
+ // Reject cross-site requests and missing header (non-browser clients)
23
37
  return null;
24
38
  },
25
39
  JWT: ({ headers })=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/extractJWT.ts"],"sourcesContent":["import type { BasePayload } from '../index.js'\nimport type { AuthStrategyFunctionArgs } from './index.js'\n\nimport { parseCookies } from '../utilities/parseCookies.js'\n\ntype ExtractionMethod = (args: { headers: Headers; payload: BasePayload }) => null | string\n\nconst extractionMethods: Record<string, ExtractionMethod> = {\n Bearer: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n // allow RFC6750 OAuth 2.0 compliant Bearer tokens\n // in addition to the payload default JWT format\n if (jwtFromHeader?.startsWith('Bearer ')) {\n return jwtFromHeader.replace('Bearer ', '')\n }\n\n return null\n },\n cookie: ({ headers, payload }) => {\n const origin = headers.get('Origin')\n const cookies = parseCookies(headers)\n const tokenCookieName = `${payload.config.cookiePrefix}-token`\n const cookieToken = cookies.get(tokenCookieName)\n\n if (!cookieToken) {\n return null\n }\n\n if (!origin || payload.config.csrf.length === 0 || payload.config.csrf.indexOf(origin) > -1) {\n return cookieToken\n }\n\n return null\n },\n JWT: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n if (jwtFromHeader?.startsWith('JWT ')) {\n return jwtFromHeader.replace('JWT ', '')\n }\n\n return null\n },\n}\n\nexport const extractJWT = (args: Omit<AuthStrategyFunctionArgs, 'strategyName'>): null | string => {\n const { headers, payload } = args\n\n const extractionOrder = payload.config.auth.jwtOrder\n\n for (const extractionStrategy of extractionOrder) {\n const result = extractionMethods[extractionStrategy]!({ headers, payload })\n\n if (result) {\n return result\n }\n }\n\n return null\n}\n"],"names":["parseCookies","extractionMethods","Bearer","headers","jwtFromHeader","get","startsWith","replace","cookie","payload","origin","cookies","tokenCookieName","config","cookiePrefix","cookieToken","csrf","length","indexOf","JWT","extractJWT","args","extractionOrder","auth","jwtOrder","extractionStrategy","result"],"mappings":"AAGA,SAASA,YAAY,QAAQ,+BAA8B;AAI3D,MAAMC,oBAAsD;IAC1DC,QAAQ,CAAC,EAAEC,OAAO,EAAE;QAClB,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC;QAElC,kDAAkD;QAClD,gDAAgD;QAChD,IAAID,eAAeE,WAAW,YAAY;YACxC,OAAOF,cAAcG,OAAO,CAAC,WAAW;QAC1C;QAEA,OAAO;IACT;IACAC,QAAQ,CAAC,EAAEL,OAAO,EAAEM,OAAO,EAAE;QAC3B,MAAMC,SAASP,QAAQE,GAAG,CAAC;QAC3B,MAAMM,UAAUX,aAAaG;QAC7B,MAAMS,kBAAkB,GAAGH,QAAQI,MAAM,CAACC,YAAY,CAAC,MAAM,CAAC;QAC9D,MAAMC,cAAcJ,QAAQN,GAAG,CAACO;QAEhC,IAAI,CAACG,aAAa;YAChB,OAAO;QACT;QAEA,IAAI,CAACL,UAAUD,QAAQI,MAAM,CAACG,IAAI,CAACC,MAAM,KAAK,KAAKR,QAAQI,MAAM,CAACG,IAAI,CAACE,OAAO,CAACR,UAAU,CAAC,GAAG;YAC3F,OAAOK;QACT;QAEA,OAAO;IACT;IACAI,KAAK,CAAC,EAAEhB,OAAO,EAAE;QACf,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC;QAElC,IAAID,eAAeE,WAAW,SAAS;YACrC,OAAOF,cAAcG,OAAO,CAAC,QAAQ;QACvC;QAEA,OAAO;IACT;AACF;AAEA,OAAO,MAAMa,aAAa,CAACC;IACzB,MAAM,EAAElB,OAAO,EAAEM,OAAO,EAAE,GAAGY;IAE7B,MAAMC,kBAAkBb,QAAQI,MAAM,CAACU,IAAI,CAACC,QAAQ;IAEpD,KAAK,MAAMC,sBAAsBH,gBAAiB;QAChD,MAAMI,SAASzB,iBAAiB,CAACwB,mBAAmB,CAAE;YAAEtB;YAASM;QAAQ;QAEzE,IAAIiB,QAAQ;YACV,OAAOA;QACT;IACF;IAEA,OAAO;AACT,EAAC"}
1
+ {"version":3,"sources":["../../src/auth/extractJWT.ts"],"sourcesContent":["import type { BasePayload } from '../index.js'\nimport type { AuthStrategyFunctionArgs } from './index.js'\n\nimport { parseCookies } from '../utilities/parseCookies.js'\n\ntype ExtractionMethod = (args: { headers: Headers; payload: BasePayload }) => null | string\n\nconst extractionMethods: Record<string, ExtractionMethod> = {\n Bearer: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n // RFC6750 OAuth 2.0 Bearer token\n if (jwtFromHeader?.startsWith('Bearer ')) {\n return jwtFromHeader.replace('Bearer ', '')\n }\n\n return null\n },\n cookie: ({ headers, payload }) => {\n const cookies = parseCookies(headers)\n const tokenCookieName = `${payload.config.cookiePrefix}-token`\n const cookieToken = cookies.get(tokenCookieName)\n\n if (!cookieToken) {\n return null\n }\n\n const origin = headers.get('Origin')\n\n // Origin present — validate against csrf allowlist\n if (origin) {\n if (payload.config.csrf.length === 0 || payload.config.csrf.includes(origin)) {\n return cookieToken\n }\n return null\n }\n\n // No Origin and no csrf configured — no allowlist to enforce\n if (payload.config.csrf.length === 0) {\n return cookieToken\n }\n\n // No Origin with csrf configured — fall back to Sec-Fetch-Site\n const secFetchSite = headers.get('Sec-Fetch-Site')\n\n // Allow same-origin, same-site, and direct navigations (none)\n if (secFetchSite === 'same-origin' || secFetchSite === 'same-site' || secFetchSite === 'none') {\n return cookieToken\n }\n\n // Reject cross-site requests and missing header (non-browser clients)\n return null\n },\n JWT: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n if (jwtFromHeader?.startsWith('JWT ')) {\n return jwtFromHeader.replace('JWT ', '')\n }\n\n return null\n },\n}\n\nexport const extractJWT = (args: Omit<AuthStrategyFunctionArgs, 'strategyName'>): null | string => {\n const { headers, payload } = args\n\n const extractionOrder = payload.config.auth.jwtOrder\n\n for (const extractionStrategy of extractionOrder) {\n const result = extractionMethods[extractionStrategy]!({ headers, payload })\n\n if (result) {\n return result\n }\n }\n\n return null\n}\n"],"names":["parseCookies","extractionMethods","Bearer","headers","jwtFromHeader","get","startsWith","replace","cookie","payload","cookies","tokenCookieName","config","cookiePrefix","cookieToken","origin","csrf","length","includes","secFetchSite","JWT","extractJWT","args","extractionOrder","auth","jwtOrder","extractionStrategy","result"],"mappings":"AAGA,SAASA,YAAY,QAAQ,+BAA8B;AAI3D,MAAMC,oBAAsD;IAC1DC,QAAQ,CAAC,EAAEC,OAAO,EAAE;QAClB,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC;QAElC,iCAAiC;QACjC,IAAID,eAAeE,WAAW,YAAY;YACxC,OAAOF,cAAcG,OAAO,CAAC,WAAW;QAC1C;QAEA,OAAO;IACT;IACAC,QAAQ,CAAC,EAAEL,OAAO,EAAEM,OAAO,EAAE;QAC3B,MAAMC,UAAUV,aAAaG;QAC7B,MAAMQ,kBAAkB,GAAGF,QAAQG,MAAM,CAACC,YAAY,CAAC,MAAM,CAAC;QAC9D,MAAMC,cAAcJ,QAAQL,GAAG,CAACM;QAEhC,IAAI,CAACG,aAAa;YAChB,OAAO;QACT;QAEA,MAAMC,SAASZ,QAAQE,GAAG,CAAC;QAE3B,mDAAmD;QACnD,IAAIU,QAAQ;YACV,IAAIN,QAAQG,MAAM,CAACI,IAAI,CAACC,MAAM,KAAK,KAAKR,QAAQG,MAAM,CAACI,IAAI,CAACE,QAAQ,CAACH,SAAS;gBAC5E,OAAOD;YACT;YACA,OAAO;QACT;QAEA,6DAA6D;QAC7D,IAAIL,QAAQG,MAAM,CAACI,IAAI,CAACC,MAAM,KAAK,GAAG;YACpC,OAAOH;QACT;QAEA,+DAA+D;QAC/D,MAAMK,eAAehB,QAAQE,GAAG,CAAC;QAEjC,8DAA8D;QAC9D,IAAIc,iBAAiB,iBAAiBA,iBAAiB,eAAeA,iBAAiB,QAAQ;YAC7F,OAAOL;QACT;QAEA,sEAAsE;QACtE,OAAO;IACT;IACAM,KAAK,CAAC,EAAEjB,OAAO,EAAE;QACf,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC;QAElC,IAAID,eAAeE,WAAW,SAAS;YACrC,OAAOF,cAAcG,OAAO,CAAC,QAAQ;QACvC;QAEA,OAAO;IACT;AACF;AAEA,OAAO,MAAMc,aAAa,CAACC;IACzB,MAAM,EAAEnB,OAAO,EAAEM,OAAO,EAAE,GAAGa;IAE7B,MAAMC,kBAAkBd,QAAQG,MAAM,CAACY,IAAI,CAACC,QAAQ;IAEpD,KAAK,MAAMC,sBAAsBH,gBAAiB;QAChD,MAAMI,SAAS1B,iBAAiB,CAACyB,mBAAmB,CAAE;YAAEvB;YAASM;QAAQ;QAEzE,IAAIkB,QAAQ;YACV,OAAOA;QACT;IACF;IAEA,OAAO;AACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/operations/forgotPassword.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gCAAgC,EAChC,UAAU,EACX,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAS,MAAM,sBAAsB,CAAA;AAajE,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,kBAAkB,IAAI;IACxD,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE;QACJ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,GAAG,gCAAgC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAA;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,MAAM,CAAA;AAE3B,eAAO,MAAM,uBAAuB,GAAU,KAAK,SAAS,kBAAkB,gBAC9D,SAAS,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,IAAI,GAAG,MAAM,CA+LvB,CAAA"}
1
+ {"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/operations/forgotPassword.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gCAAgC,EAChC,UAAU,EACX,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAS,MAAM,sBAAsB,CAAA;AAcjE,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,kBAAkB,IAAI;IACxD,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE;QACJ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,GAAG,gCAAgC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAA;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,MAAM,CAAA;AAE3B,eAAO,MAAM,uBAAuB,GAAU,KAAK,SAAS,kBAAkB,gBAC9D,SAAS,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,IAAI,GAAG,MAAM,CA2LvB,CAAA"}
@@ -1,6 +1,5 @@
1
1
  import crypto from 'crypto';
2
2
  import { status as httpStatus } from 'http-status';
3
- import { URL } from 'url';
4
3
  import { buildAfterOperation } from '../../collections/operations/utilities/buildAfterOperation.js';
5
4
  import { buildBeforeOperation } from '../../collections/operations/utilities/buildBeforeOperation.js';
6
5
  import { APIError } from '../../errors/index.js';
@@ -8,6 +7,7 @@ import { Forbidden } from '../../index.js';
8
7
  import { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js';
9
8
  import { commitTransaction } from '../../utilities/commitTransaction.js';
10
9
  import { formatAdminURL } from '../../utilities/formatAdminURL.js';
10
+ import { getRequestOrigin } from '../../utilities/getRequestOrigin.js';
11
11
  import { initTransaction } from '../../utilities/initTransaction.js';
12
12
  import { killTransaction } from '../../utilities/killTransaction.js';
13
13
  import { getLoginOptions } from '../getLoginOptions.js';
@@ -86,9 +86,10 @@ export const forgotPasswordOperation = async (incomingArgs)=>{
86
86
  req
87
87
  });
88
88
  if (!disableEmail && user.email) {
89
- const protocol = new URL(req.url).protocol // includes the final :
90
- ;
91
- const serverURL = config.serverURL !== null && config.serverURL !== '' ? config.serverURL : `${protocol}//${req.headers.get('host')}`;
89
+ const serverURL = getRequestOrigin({
90
+ config,
91
+ req
92
+ });
92
93
  const forgotURL = formatAdminURL({
93
94
  adminRoute: config.routes.admin,
94
95
  path: `${config.admin.routes.reset}/${token}`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/auth/operations/forgotPassword.ts"],"sourcesContent":["import crypto from 'crypto'\nimport { status as httpStatus } from 'http-status'\nimport { URL } from 'url'\n\nimport type {\n AuthOperationsFromCollectionSlug,\n Collection,\n} from '../../collections/config/types.js'\nimport type { AuthCollectionSlug } from '../../index.js'\nimport type { PayloadRequest, Where } from '../../types/index.js'\n\nimport { buildAfterOperation } from '../../collections/operations/utilities/buildAfterOperation.js'\nimport { buildBeforeOperation } from '../../collections/operations/utilities/buildBeforeOperation.js'\nimport { APIError } from '../../errors/index.js'\nimport { Forbidden } from '../../index.js'\nimport { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js'\nimport { commitTransaction } from '../../utilities/commitTransaction.js'\nimport { formatAdminURL } from '../../utilities/formatAdminURL.js'\nimport { initTransaction } from '../../utilities/initTransaction.js'\nimport { killTransaction } from '../../utilities/killTransaction.js'\nimport { getLoginOptions } from '../getLoginOptions.js'\n\nexport type Arguments<TSlug extends AuthCollectionSlug> = {\n collection: Collection\n data: {\n [key: string]: unknown\n } & AuthOperationsFromCollectionSlug<TSlug>['forgotPassword']\n disableEmail?: boolean\n expiration?: number\n overrideAccess?: boolean\n req: PayloadRequest\n}\n\nexport type Result = string\n\nexport const forgotPasswordOperation = async <TSlug extends AuthCollectionSlug>(\n incomingArgs: Arguments<TSlug>,\n): Promise<null | string> => {\n const loginWithUsername = incomingArgs.collection.config.auth.loginWithUsername\n const { data, overrideAccess } = incomingArgs\n\n const { canLoginWithEmail, canLoginWithUsername } = getLoginOptions(loginWithUsername)\n\n const sanitizedEmail =\n (canLoginWithEmail && (incomingArgs.data.email || '').toLowerCase().trim()) || null\n const sanitizedUsername =\n 'username' in data && typeof data?.username === 'string'\n ? data.username.toLowerCase().trim()\n : null\n\n let args = incomingArgs\n\n if (incomingArgs.collection.config.auth.disableLocalStrategy) {\n throw new Forbidden(incomingArgs.req.t)\n }\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n try {\n const shouldCommit = await initTransaction(args.req)\n\n // /////////////////////////////////////\n // beforeOperation - Collection\n // /////////////////////////////////////\n args = await buildBeforeOperation({\n args,\n collection: args.collection.config,\n operation: 'forgotPassword',\n overrideAccess,\n })\n\n const {\n collection: { config: collectionConfig },\n disableEmail,\n expiration,\n req: {\n payload: { config, email },\n payload,\n },\n req,\n } = args\n\n // /////////////////////////////////////\n // Forget password\n // /////////////////////////////////////\n\n let token: string = crypto.randomBytes(20).toString('hex')\n type UserDoc = {\n email?: string\n id: number | string\n resetPasswordExpiration?: string\n resetPasswordToken?: string\n }\n\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n let whereConstraint: Where = {}\n\n if (canLoginWithEmail && sanitizedEmail) {\n whereConstraint = {\n email: {\n equals: sanitizedEmail,\n },\n }\n } else if (canLoginWithUsername && sanitizedUsername) {\n whereConstraint = {\n username: {\n equals: sanitizedUsername,\n },\n }\n }\n\n // Exclude trashed users unless `trash: true`\n whereConstraint = appendNonTrashedFilter({\n enableTrash: collectionConfig.trash,\n trash: false,\n where: whereConstraint,\n })\n\n let user = await payload.db.findOne<UserDoc>({\n collection: collectionConfig.slug,\n req,\n where: whereConstraint,\n })\n\n // We don't want to indicate specifically that an email was not found,\n // as doing so could lead to the exposure of registered emails.\n // Therefore, we prefer to fail silently.\n if (!user) {\n await commitTransaction(args.req)\n return null\n }\n\n const resetPasswordExpiration = new Date(\n Date.now() + (collectionConfig.auth?.forgotPassword?.expiration ?? expiration ?? 3600000),\n ).toISOString()\n\n user = await payload.update({\n id: user.id,\n collection: collectionConfig.slug,\n data: {\n resetPasswordExpiration,\n resetPasswordToken: token,\n },\n req,\n })\n\n if (!disableEmail && user.email) {\n const protocol = new URL(req.url!).protocol // includes the final :\n const serverURL =\n config.serverURL !== null && config.serverURL !== ''\n ? config.serverURL\n : `${protocol}//${req.headers.get('host')}`\n const forgotURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `${config.admin.routes.reset}/${token}`,\n serverURL,\n })\n let html = `${req.t('authentication:youAreReceivingResetPassword')}\n <a href=\"${forgotURL}\">${forgotURL}</a>\n ${req.t('authentication:youDidNotRequestPassword')}`\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailHTML === 'function') {\n html = await collectionConfig.auth.forgotPassword.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:resetYourPassword')\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailSubject === 'function') {\n subject = await collectionConfig.auth.forgotPassword.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n\n // /////////////////////////////////////\n // afterForgotPassword - Collection\n // /////////////////////////////////////\n\n if (collectionConfig.hooks?.afterForgotPassword?.length) {\n for (const hook of collectionConfig.hooks.afterForgotPassword) {\n await hook({ args, collection: args.collection?.config, context: req.context })\n }\n }\n\n // /////////////////////////////////////\n // afterOperation - Collection\n // /////////////////////////////////////\n\n token = await buildAfterOperation({\n args,\n collection: args.collection?.config,\n operation: 'forgotPassword',\n overrideAccess,\n result: token,\n })\n\n if (shouldCommit) {\n await commitTransaction(req)\n }\n\n return token\n } catch (error: unknown) {\n await killTransaction(args.req)\n throw error\n }\n}\n"],"names":["crypto","status","httpStatus","URL","buildAfterOperation","buildBeforeOperation","APIError","Forbidden","appendNonTrashedFilter","commitTransaction","formatAdminURL","initTransaction","killTransaction","getLoginOptions","forgotPasswordOperation","incomingArgs","loginWithUsername","collection","config","auth","data","overrideAccess","canLoginWithEmail","canLoginWithUsername","sanitizedEmail","email","toLowerCase","trim","sanitizedUsername","username","args","disableLocalStrategy","req","t","BAD_REQUEST","shouldCommit","operation","collectionConfig","disableEmail","expiration","payload","token","randomBytes","toString","whereConstraint","equals","enableTrash","trash","where","user","db","findOne","slug","resetPasswordExpiration","Date","now","forgotPassword","toISOString","update","id","resetPasswordToken","protocol","url","serverURL","headers","get","forgotURL","adminRoute","routes","admin","path","reset","html","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to","hooks","afterForgotPassword","length","hook","context","result","error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/auth/operations/forgotPassword.ts"],"sourcesContent":["import crypto from 'crypto'\nimport { status as httpStatus } from 'http-status'\n\nimport type {\n AuthOperationsFromCollectionSlug,\n Collection,\n} from '../../collections/config/types.js'\nimport type { AuthCollectionSlug } from '../../index.js'\nimport type { PayloadRequest, Where } from '../../types/index.js'\n\nimport { buildAfterOperation } from '../../collections/operations/utilities/buildAfterOperation.js'\nimport { buildBeforeOperation } from '../../collections/operations/utilities/buildBeforeOperation.js'\nimport { APIError } from '../../errors/index.js'\nimport { Forbidden } from '../../index.js'\nimport { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js'\nimport { commitTransaction } from '../../utilities/commitTransaction.js'\nimport { formatAdminURL } from '../../utilities/formatAdminURL.js'\nimport { getRequestOrigin } from '../../utilities/getRequestOrigin.js'\nimport { initTransaction } from '../../utilities/initTransaction.js'\nimport { killTransaction } from '../../utilities/killTransaction.js'\nimport { getLoginOptions } from '../getLoginOptions.js'\n\nexport type Arguments<TSlug extends AuthCollectionSlug> = {\n collection: Collection\n data: {\n [key: string]: unknown\n } & AuthOperationsFromCollectionSlug<TSlug>['forgotPassword']\n disableEmail?: boolean\n expiration?: number\n overrideAccess?: boolean\n req: PayloadRequest\n}\n\nexport type Result = string\n\nexport const forgotPasswordOperation = async <TSlug extends AuthCollectionSlug>(\n incomingArgs: Arguments<TSlug>,\n): Promise<null | string> => {\n const loginWithUsername = incomingArgs.collection.config.auth.loginWithUsername\n const { data, overrideAccess } = incomingArgs\n\n const { canLoginWithEmail, canLoginWithUsername } = getLoginOptions(loginWithUsername)\n\n const sanitizedEmail =\n (canLoginWithEmail && (incomingArgs.data.email || '').toLowerCase().trim()) || null\n const sanitizedUsername =\n 'username' in data && typeof data?.username === 'string'\n ? data.username.toLowerCase().trim()\n : null\n\n let args = incomingArgs\n\n if (incomingArgs.collection.config.auth.disableLocalStrategy) {\n throw new Forbidden(incomingArgs.req.t)\n }\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n try {\n const shouldCommit = await initTransaction(args.req)\n\n // /////////////////////////////////////\n // beforeOperation - Collection\n // /////////////////////////////////////\n args = await buildBeforeOperation({\n args,\n collection: args.collection.config,\n operation: 'forgotPassword',\n overrideAccess,\n })\n\n const {\n collection: { config: collectionConfig },\n disableEmail,\n expiration,\n req: {\n payload: { config, email },\n payload,\n },\n req,\n } = args\n\n // /////////////////////////////////////\n // Forget password\n // /////////////////////////////////////\n\n let token: string = crypto.randomBytes(20).toString('hex')\n type UserDoc = {\n email?: string\n id: number | string\n resetPasswordExpiration?: string\n resetPasswordToken?: string\n }\n\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n let whereConstraint: Where = {}\n\n if (canLoginWithEmail && sanitizedEmail) {\n whereConstraint = {\n email: {\n equals: sanitizedEmail,\n },\n }\n } else if (canLoginWithUsername && sanitizedUsername) {\n whereConstraint = {\n username: {\n equals: sanitizedUsername,\n },\n }\n }\n\n // Exclude trashed users unless `trash: true`\n whereConstraint = appendNonTrashedFilter({\n enableTrash: collectionConfig.trash,\n trash: false,\n where: whereConstraint,\n })\n\n let user = await payload.db.findOne<UserDoc>({\n collection: collectionConfig.slug,\n req,\n where: whereConstraint,\n })\n\n // We don't want to indicate specifically that an email was not found,\n // as doing so could lead to the exposure of registered emails.\n // Therefore, we prefer to fail silently.\n if (!user) {\n await commitTransaction(args.req)\n return null\n }\n\n const resetPasswordExpiration = new Date(\n Date.now() + (collectionConfig.auth?.forgotPassword?.expiration ?? expiration ?? 3600000),\n ).toISOString()\n\n user = await payload.update({\n id: user.id,\n collection: collectionConfig.slug,\n data: {\n resetPasswordExpiration,\n resetPasswordToken: token,\n },\n req,\n })\n\n if (!disableEmail && user.email) {\n const serverURL = getRequestOrigin({ config, req })\n const forgotURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `${config.admin.routes.reset}/${token}`,\n serverURL,\n })\n let html = `${req.t('authentication:youAreReceivingResetPassword')}\n <a href=\"${forgotURL}\">${forgotURL}</a>\n ${req.t('authentication:youDidNotRequestPassword')}`\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailHTML === 'function') {\n html = await collectionConfig.auth.forgotPassword.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:resetYourPassword')\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailSubject === 'function') {\n subject = await collectionConfig.auth.forgotPassword.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n\n // /////////////////////////////////////\n // afterForgotPassword - Collection\n // /////////////////////////////////////\n\n if (collectionConfig.hooks?.afterForgotPassword?.length) {\n for (const hook of collectionConfig.hooks.afterForgotPassword) {\n await hook({ args, collection: args.collection?.config, context: req.context })\n }\n }\n\n // /////////////////////////////////////\n // afterOperation - Collection\n // /////////////////////////////////////\n\n token = await buildAfterOperation({\n args,\n collection: args.collection?.config,\n operation: 'forgotPassword',\n overrideAccess,\n result: token,\n })\n\n if (shouldCommit) {\n await commitTransaction(req)\n }\n\n return token\n } catch (error: unknown) {\n await killTransaction(args.req)\n throw error\n }\n}\n"],"names":["crypto","status","httpStatus","buildAfterOperation","buildBeforeOperation","APIError","Forbidden","appendNonTrashedFilter","commitTransaction","formatAdminURL","getRequestOrigin","initTransaction","killTransaction","getLoginOptions","forgotPasswordOperation","incomingArgs","loginWithUsername","collection","config","auth","data","overrideAccess","canLoginWithEmail","canLoginWithUsername","sanitizedEmail","email","toLowerCase","trim","sanitizedUsername","username","args","disableLocalStrategy","req","t","BAD_REQUEST","shouldCommit","operation","collectionConfig","disableEmail","expiration","payload","token","randomBytes","toString","whereConstraint","equals","enableTrash","trash","where","user","db","findOne","slug","resetPasswordExpiration","Date","now","forgotPassword","toISOString","update","id","resetPasswordToken","serverURL","forgotURL","adminRoute","routes","admin","path","reset","html","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to","hooks","afterForgotPassword","length","hook","context","result","error"],"mappings":"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"}
@@ -5,6 +5,11 @@ export const meOperation = async (args)=>{
5
5
  user: null
6
6
  };
7
7
  if (req.user) {
8
+ if (req.user.collection !== collection.config.slug) {
9
+ return {
10
+ user: null
11
+ };
12
+ }
8
13
  const { pathname } = req;
9
14
  const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`;
10
15
  const user = await req.payload.findByID({
@@ -23,11 +28,6 @@ export const meOperation = async (args)=>{
23
28
  user.collection = collection.config.slug;
24
29
  user._strategy = req.user._strategy;
25
30
  }
26
- if (req.user.collection !== collection.config.slug) {
27
- return {
28
- user: null
29
- };
30
- }
31
31
  // /////////////////////////////////////
32
32
  // me hook - Collection
33
33
  // /////////////////////////////////////
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/auth/operations/me.ts"],"sourcesContent":["import { decodeJwt } from 'jose'\n\nimport type { Collection } from '../../collections/config/types.js'\nimport type { TypedUser } from '../../index.js'\nimport type { JoinQuery, PayloadRequest, PopulateType, SelectType } from '../../types/index.js'\nimport type { ClientUser } from '../types.js'\n\nexport type MeOperationResult = {\n collection?: string\n exp?: number\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n strategy?: string\n token?: string\n user?: ClientUser\n}\n\nexport type Arguments = {\n collection: Collection\n currentToken?: string\n depth?: number\n draft?: boolean\n joins?: JoinQuery\n populate?: PopulateType\n req: PayloadRequest\n select?: SelectType\n}\n\nexport const meOperation = async (args: Arguments): Promise<MeOperationResult> => {\n const { collection, currentToken, depth, draft, joins, populate, req, select } = args\n\n let result: MeOperationResult = {\n user: null!,\n }\n\n if (req.user) {\n const { pathname } = req\n const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`\n\n const user = (await req.payload.findByID({\n id: req.user.id,\n collection: collection.config.slug,\n depth: isGraphQL ? 0 : (depth ?? collection.config.auth.depth),\n draft,\n joins,\n overrideAccess: false,\n populate,\n req,\n select,\n showHiddenFields: false,\n })) as TypedUser\n\n if (user) {\n user.collection = collection.config.slug\n user._strategy = req.user._strategy\n }\n\n if (req.user.collection !== collection.config.slug) {\n return {\n user: null!,\n }\n }\n\n // /////////////////////////////////////\n // me hook - Collection\n // /////////////////////////////////////\n\n for (const meHook of collection.config.hooks.me) {\n const hookResult = await meHook({ args, user })\n\n if (hookResult) {\n result.user = hookResult.user\n result.exp = hookResult.exp\n\n break\n }\n }\n\n result.collection = req.user.collection\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n result.strategy = req.user._strategy\n\n if (!result.user) {\n result.user = user\n\n if (currentToken) {\n const decoded = decodeJwt(currentToken)\n if (decoded) {\n result.exp = decoded.exp\n }\n if (!collection.config.auth.removeTokenFromResponses) {\n result.token = currentToken\n }\n }\n }\n }\n\n // /////////////////////////////////////\n // After Me - Collection\n // /////////////////////////////////////\n\n if (collection.config.hooks?.afterMe?.length) {\n for (const hook of collection.config.hooks.afterMe) {\n result =\n (await hook({\n collection: collection?.config,\n context: req.context,\n req,\n response: result,\n })) || result\n }\n }\n\n return result\n}\n"],"names":["decodeJwt","meOperation","args","collection","currentToken","depth","draft","joins","populate","req","select","result","user","pathname","isGraphQL","payload","config","routes","graphQL","findByID","id","slug","auth","overrideAccess","showHiddenFields","_strategy","meHook","hooks","me","hookResult","exp","strategy","decoded","removeTokenFromResponses","token","afterMe","length","hook","context","response"],"mappings":"AAAA,SAASA,SAAS,QAAQ,OAAM;AAgChC,OAAO,MAAMC,cAAc,OAAOC;IAChC,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAEC,KAAK,EAAEC,KAAK,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,MAAM,EAAE,GAAGR;IAEjF,IAAIS,SAA4B;QAC9BC,MAAM;IACR;IAEA,IAAIH,IAAIG,IAAI,EAAE;QACZ,MAAM,EAAEC,QAAQ,EAAE,GAAGJ;QACrB,MAAMK,YAAYD,aAAa,CAAC,IAAI,EAAEJ,IAAIM,OAAO,CAACC,MAAM,CAACC,MAAM,CAACC,OAAO,EAAE;QAEzE,MAAMN,OAAQ,MAAMH,IAAIM,OAAO,CAACI,QAAQ,CAAC;YACvCC,IAAIX,IAAIG,IAAI,CAACQ,EAAE;YACfjB,YAAYA,WAAWa,MAAM,CAACK,IAAI;YAClChB,OAAOS,YAAY,IAAKT,SAASF,WAAWa,MAAM,CAACM,IAAI,CAACjB,KAAK;YAC7DC;YACAC;YACAgB,gBAAgB;YAChBf;YACAC;YACAC;YACAc,kBAAkB;QACpB;QAEA,IAAIZ,MAAM;YACRA,KAAKT,UAAU,GAAGA,WAAWa,MAAM,CAACK,IAAI;YACxCT,KAAKa,SAAS,GAAGhB,IAAIG,IAAI,CAACa,SAAS;QACrC;QAEA,IAAIhB,IAAIG,IAAI,CAACT,UAAU,KAAKA,WAAWa,MAAM,CAACK,IAAI,EAAE;YAClD,OAAO;gBACLT,MAAM;YACR;QACF;QAEA,wCAAwC;QACxC,uBAAuB;QACvB,wCAAwC;QAExC,KAAK,MAAMc,UAAUvB,WAAWa,MAAM,CAACW,KAAK,CAACC,EAAE,CAAE;YAC/C,MAAMC,aAAa,MAAMH,OAAO;gBAAExB;gBAAMU;YAAK;YAE7C,IAAIiB,YAAY;gBACdlB,OAAOC,IAAI,GAAGiB,WAAWjB,IAAI;gBAC7BD,OAAOmB,GAAG,GAAGD,WAAWC,GAAG;gBAE3B;YACF;QACF;QAEAnB,OAAOR,UAAU,GAAGM,IAAIG,IAAI,CAACT,UAAU;QACvC;;;;;KAKC,GACDQ,OAAOoB,QAAQ,GAAGtB,IAAIG,IAAI,CAACa,SAAS;QAEpC,IAAI,CAACd,OAAOC,IAAI,EAAE;YAChBD,OAAOC,IAAI,GAAGA;YAEd,IAAIR,cAAc;gBAChB,MAAM4B,UAAUhC,UAAUI;gBAC1B,IAAI4B,SAAS;oBACXrB,OAAOmB,GAAG,GAAGE,QAAQF,GAAG;gBAC1B;gBACA,IAAI,CAAC3B,WAAWa,MAAM,CAACM,IAAI,CAACW,wBAAwB,EAAE;oBACpDtB,OAAOuB,KAAK,GAAG9B;gBACjB;YACF;QACF;IACF;IAEA,wCAAwC;IACxC,wBAAwB;IACxB,wCAAwC;IAExC,IAAID,WAAWa,MAAM,CAACW,KAAK,EAAEQ,SAASC,QAAQ;QAC5C,KAAK,MAAMC,QAAQlC,WAAWa,MAAM,CAACW,KAAK,CAACQ,OAAO,CAAE;YAClDxB,SACE,AAAC,MAAM0B,KAAK;gBACVlC,YAAYA,YAAYa;gBACxBsB,SAAS7B,IAAI6B,OAAO;gBACpB7B;gBACA8B,UAAU5B;YACZ,MAAOA;QACX;IACF;IAEA,OAAOA;AACT,EAAC"}
1
+ {"version":3,"sources":["../../../src/auth/operations/me.ts"],"sourcesContent":["import { decodeJwt } from 'jose'\n\nimport type { Collection } from '../../collections/config/types.js'\nimport type { TypedUser } from '../../index.js'\nimport type { JoinQuery, PayloadRequest, PopulateType, SelectType } from '../../types/index.js'\nimport type { ClientUser } from '../types.js'\n\nexport type MeOperationResult = {\n collection?: string\n exp?: number\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n strategy?: string\n token?: string\n user?: ClientUser\n}\n\nexport type Arguments = {\n collection: Collection\n currentToken?: string\n depth?: number\n draft?: boolean\n joins?: JoinQuery\n populate?: PopulateType\n req: PayloadRequest\n select?: SelectType\n}\n\nexport const meOperation = async (args: Arguments): Promise<MeOperationResult> => {\n const { collection, currentToken, depth, draft, joins, populate, req, select } = args\n\n let result: MeOperationResult = {\n user: null!,\n }\n\n if (req.user) {\n if (req.user.collection !== collection.config.slug) {\n return {\n user: null!,\n }\n }\n\n const { pathname } = req\n const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`\n\n const user = (await req.payload.findByID({\n id: req.user.id,\n collection: collection.config.slug,\n depth: isGraphQL ? 0 : (depth ?? collection.config.auth.depth),\n draft,\n joins,\n overrideAccess: false,\n populate,\n req,\n select,\n showHiddenFields: false,\n })) as TypedUser\n\n if (user) {\n user.collection = collection.config.slug\n user._strategy = req.user._strategy\n }\n\n // /////////////////////////////////////\n // me hook - Collection\n // /////////////////////////////////////\n\n for (const meHook of collection.config.hooks.me) {\n const hookResult = await meHook({ args, user })\n\n if (hookResult) {\n result.user = hookResult.user\n result.exp = hookResult.exp\n\n break\n }\n }\n\n result.collection = req.user.collection\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n result.strategy = req.user._strategy\n\n if (!result.user) {\n result.user = user\n\n if (currentToken) {\n const decoded = decodeJwt(currentToken)\n if (decoded) {\n result.exp = decoded.exp\n }\n if (!collection.config.auth.removeTokenFromResponses) {\n result.token = currentToken\n }\n }\n }\n }\n\n // /////////////////////////////////////\n // After Me - Collection\n // /////////////////////////////////////\n\n if (collection.config.hooks?.afterMe?.length) {\n for (const hook of collection.config.hooks.afterMe) {\n result =\n (await hook({\n collection: collection?.config,\n context: req.context,\n req,\n response: result,\n })) || result\n }\n }\n\n return result\n}\n"],"names":["decodeJwt","meOperation","args","collection","currentToken","depth","draft","joins","populate","req","select","result","user","config","slug","pathname","isGraphQL","payload","routes","graphQL","findByID","id","auth","overrideAccess","showHiddenFields","_strategy","meHook","hooks","me","hookResult","exp","strategy","decoded","removeTokenFromResponses","token","afterMe","length","hook","context","response"],"mappings":"AAAA,SAASA,SAAS,QAAQ,OAAM;AAgChC,OAAO,MAAMC,cAAc,OAAOC;IAChC,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAEC,KAAK,EAAEC,KAAK,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,MAAM,EAAE,GAAGR;IAEjF,IAAIS,SAA4B;QAC9BC,MAAM;IACR;IAEA,IAAIH,IAAIG,IAAI,EAAE;QACZ,IAAIH,IAAIG,IAAI,CAACT,UAAU,KAAKA,WAAWU,MAAM,CAACC,IAAI,EAAE;YAClD,OAAO;gBACLF,MAAM;YACR;QACF;QAEA,MAAM,EAAEG,QAAQ,EAAE,GAAGN;QACrB,MAAMO,YAAYD,aAAa,CAAC,IAAI,EAAEN,IAAIQ,OAAO,CAACJ,MAAM,CAACK,MAAM,CAACC,OAAO,EAAE;QAEzE,MAAMP,OAAQ,MAAMH,IAAIQ,OAAO,CAACG,QAAQ,CAAC;YACvCC,IAAIZ,IAAIG,IAAI,CAACS,EAAE;YACflB,YAAYA,WAAWU,MAAM,CAACC,IAAI;YAClCT,OAAOW,YAAY,IAAKX,SAASF,WAAWU,MAAM,CAACS,IAAI,CAACjB,KAAK;YAC7DC;YACAC;YACAgB,gBAAgB;YAChBf;YACAC;YACAC;YACAc,kBAAkB;QACpB;QAEA,IAAIZ,MAAM;YACRA,KAAKT,UAAU,GAAGA,WAAWU,MAAM,CAACC,IAAI;YACxCF,KAAKa,SAAS,GAAGhB,IAAIG,IAAI,CAACa,SAAS;QACrC;QAEA,wCAAwC;QACxC,uBAAuB;QACvB,wCAAwC;QAExC,KAAK,MAAMC,UAAUvB,WAAWU,MAAM,CAACc,KAAK,CAACC,EAAE,CAAE;YAC/C,MAAMC,aAAa,MAAMH,OAAO;gBAAExB;gBAAMU;YAAK;YAE7C,IAAIiB,YAAY;gBACdlB,OAAOC,IAAI,GAAGiB,WAAWjB,IAAI;gBAC7BD,OAAOmB,GAAG,GAAGD,WAAWC,GAAG;gBAE3B;YACF;QACF;QAEAnB,OAAOR,UAAU,GAAGM,IAAIG,IAAI,CAACT,UAAU;QACvC;;;;;KAKC,GACDQ,OAAOoB,QAAQ,GAAGtB,IAAIG,IAAI,CAACa,SAAS;QAEpC,IAAI,CAACd,OAAOC,IAAI,EAAE;YAChBD,OAAOC,IAAI,GAAGA;YAEd,IAAIR,cAAc;gBAChB,MAAM4B,UAAUhC,UAAUI;gBAC1B,IAAI4B,SAAS;oBACXrB,OAAOmB,GAAG,GAAGE,QAAQF,GAAG;gBAC1B;gBACA,IAAI,CAAC3B,WAAWU,MAAM,CAACS,IAAI,CAACW,wBAAwB,EAAE;oBACpDtB,OAAOuB,KAAK,GAAG9B;gBACjB;YACF;QACF;IACF;IAEA,wCAAwC;IACxC,wBAAwB;IACxB,wCAAwC;IAExC,IAAID,WAAWU,MAAM,CAACc,KAAK,EAAEQ,SAASC,QAAQ;QAC5C,KAAK,MAAMC,QAAQlC,WAAWU,MAAM,CAACc,KAAK,CAACQ,OAAO,CAAE;YAClDxB,SACE,AAAC,MAAM0B,KAAK;gBACVlC,YAAYA,YAAYU;gBACxByB,SAAS7B,IAAI6B,OAAO;gBACpB7B;gBACA8B,UAAU5B;YACZ,MAAOA;QACX;IACF;IAEA,OAAOA;AACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sendVerificationEmail.d.ts","sourceRoot":"","sources":["../../src/auth/sendVerificationEmail.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAKvD,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,YAAY,EAAE,OAAO,CAAA;IACrB,KAAK,EAAE,uBAAuB,CAAA;IAC9B,GAAG,EAAE,cAAc,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,SAAS,CAAA;CAChB,CAAA;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DrE"}
1
+ {"version":3,"file":"sendVerificationEmail.d.ts","sourceRoot":"","sources":["../../src/auth/sendVerificationEmail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAMvD,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,YAAY,EAAE,OAAO,CAAA;IACrB,KAAK,EAAE,uBAAuB,CAAA;IAC9B,GAAG,EAAE,cAAc,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,SAAS,CAAA;CAChB,CAAA;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDrE"}
@@ -1,12 +1,13 @@
1
- import { URL } from 'url';
2
1
  import { formatAdminURL } from '../utilities/formatAdminURL.js';
2
+ import { getRequestOrigin } from '../utilities/getRequestOrigin.js';
3
3
  export async function sendVerificationEmail(args) {
4
4
  // Verify token from e-mail
5
5
  const { collection: { config: collectionConfig }, config, disableEmail, email, req, token, user } = args;
6
6
  if (!disableEmail) {
7
- const protocol = new URL(req.url).protocol // includes the final :
8
- ;
9
- const serverURL = config.serverURL !== null && config.serverURL !== '' ? config.serverURL : `${protocol}//${req.headers.get('host')}`;
7
+ const serverURL = getRequestOrigin({
8
+ config,
9
+ req
10
+ });
10
11
  const verificationURL = formatAdminURL({
11
12
  adminRoute: config.routes.admin,
12
13
  path: `/${collectionConfig.slug}/verify/${token}`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/sendVerificationEmail.ts"],"sourcesContent":["import { URL } from 'url'\n\nimport type { Collection } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { InitializedEmailAdapter } from '../email/types.js'\nimport type { TypedUser } from '../index.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { VerifyConfig } from './types.js'\n\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\n\ntype Args = {\n collection: Collection\n config: SanitizedConfig\n disableEmail: boolean\n email: InitializedEmailAdapter\n req: PayloadRequest\n token: string\n user: TypedUser\n}\n\nexport async function sendVerificationEmail(args: Args): Promise<void> {\n // Verify token from e-mail\n const {\n collection: { config: collectionConfig },\n config,\n disableEmail,\n email,\n req,\n token,\n user,\n } = args\n\n if (!disableEmail) {\n const protocol = new URL(req.url!).protocol // includes the final :\n const serverURL =\n config.serverURL !== null && config.serverURL !== ''\n ? config.serverURL\n : `${protocol}//${req.headers.get('host')}`\n\n const verificationURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/${collectionConfig.slug}/verify/${token}`,\n serverURL,\n })\n\n let html = `${req.t('authentication:newAccountCreated', {\n serverURL: config.serverURL,\n verificationURL,\n })}`\n\n const verify = collectionConfig.auth.verify as VerifyConfig\n\n // Allow config to override email content\n if (typeof verify.generateEmailHTML === 'function') {\n html = await verify.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:verifyYourEmail')\n\n // Allow config to override email subject\n if (typeof verify.generateEmailSubject === 'function') {\n subject = await verify.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n}\n"],"names":["URL","formatAdminURL","sendVerificationEmail","args","collection","config","collectionConfig","disableEmail","email","req","token","user","protocol","url","serverURL","headers","get","verificationURL","adminRoute","routes","admin","path","slug","html","t","verify","auth","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to"],"mappings":"AAAA,SAASA,GAAG,QAAQ,MAAK;AASzB,SAASC,cAAc,QAAQ,iCAAgC;AAY/D,OAAO,eAAeC,sBAAsBC,IAAU;IACpD,2BAA2B;IAC3B,MAAM,EACJC,YAAY,EAAEC,QAAQC,gBAAgB,EAAE,EACxCD,MAAM,EACNE,YAAY,EACZC,KAAK,EACLC,GAAG,EACHC,KAAK,EACLC,IAAI,EACL,GAAGR;IAEJ,IAAI,CAACI,cAAc;QACjB,MAAMK,WAAW,IAAIZ,IAAIS,IAAII,GAAG,EAAGD,QAAQ,CAAC,uBAAuB;;QACnE,MAAME,YACJT,OAAOS,SAAS,KAAK,QAAQT,OAAOS,SAAS,KAAK,KAC9CT,OAAOS,SAAS,GAChB,GAAGF,SAAS,EAAE,EAAEH,IAAIM,OAAO,CAACC,GAAG,CAAC,SAAS;QAE/C,MAAMC,kBAAkBhB,eAAe;YACrCiB,YAAYb,OAAOc,MAAM,CAACC,KAAK;YAC/BC,MAAM,CAAC,CAAC,EAAEf,iBAAiBgB,IAAI,CAAC,QAAQ,EAAEZ,OAAO;YACjDI;QACF;QAEA,IAAIS,OAAO,GAAGd,IAAIe,CAAC,CAAC,oCAAoC;YACtDV,WAAWT,OAAOS,SAAS;YAC3BG;QACF,IAAI;QAEJ,MAAMQ,SAASnB,iBAAiBoB,IAAI,CAACD,MAAM;QAE3C,yCAAyC;QACzC,IAAI,OAAOA,OAAOE,iBAAiB,KAAK,YAAY;YAClDJ,OAAO,MAAME,OAAOE,iBAAiB,CAAC;gBACpClB;gBACAC;gBACAC;YACF;QACF;QAEA,IAAIiB,UAAUnB,IAAIe,CAAC,CAAC;QAEpB,yCAAyC;QACzC,IAAI,OAAOC,OAAOI,oBAAoB,KAAK,YAAY;YACrDD,UAAU,MAAMH,OAAOI,oBAAoB,CAAC;gBAC1CpB;gBACAC;gBACAC;YACF;QACF;QAEA,MAAMH,MAAMsB,SAAS,CAAC;YACpBC,MAAM,CAAC,CAAC,EAAEvB,MAAMwB,eAAe,CAAC,GAAG,EAAExB,MAAMyB,kBAAkB,CAAC,CAAC,CAAC;YAChEV;YACAK;YACAM,IAAIvB,KAAKH,KAAK;QAChB;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/auth/sendVerificationEmail.ts"],"sourcesContent":["import type { Collection } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { InitializedEmailAdapter } from '../email/types.js'\nimport type { TypedUser } from '../index.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { VerifyConfig } from './types.js'\n\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\nimport { getRequestOrigin } from '../utilities/getRequestOrigin.js'\n\ntype Args = {\n collection: Collection\n config: SanitizedConfig\n disableEmail: boolean\n email: InitializedEmailAdapter\n req: PayloadRequest\n token: string\n user: TypedUser\n}\n\nexport async function sendVerificationEmail(args: Args): Promise<void> {\n // Verify token from e-mail\n const {\n collection: { config: collectionConfig },\n config,\n disableEmail,\n email,\n req,\n token,\n user,\n } = args\n\n if (!disableEmail) {\n const serverURL = getRequestOrigin({ config, req })\n\n const verificationURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/${collectionConfig.slug}/verify/${token}`,\n serverURL,\n })\n\n let html = `${req.t('authentication:newAccountCreated', {\n serverURL: config.serverURL,\n verificationURL,\n })}`\n\n const verify = collectionConfig.auth.verify as VerifyConfig\n\n // Allow config to override email content\n if (typeof verify.generateEmailHTML === 'function') {\n html = await verify.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:verifyYourEmail')\n\n // Allow config to override email subject\n if (typeof verify.generateEmailSubject === 'function') {\n subject = await verify.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n}\n"],"names":["formatAdminURL","getRequestOrigin","sendVerificationEmail","args","collection","config","collectionConfig","disableEmail","email","req","token","user","serverURL","verificationURL","adminRoute","routes","admin","path","slug","html","t","verify","auth","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to"],"mappings":"AAOA,SAASA,cAAc,QAAQ,iCAAgC;AAC/D,SAASC,gBAAgB,QAAQ,mCAAkC;AAYnE,OAAO,eAAeC,sBAAsBC,IAAU;IACpD,2BAA2B;IAC3B,MAAM,EACJC,YAAY,EAAEC,QAAQC,gBAAgB,EAAE,EACxCD,MAAM,EACNE,YAAY,EACZC,KAAK,EACLC,GAAG,EACHC,KAAK,EACLC,IAAI,EACL,GAAGR;IAEJ,IAAI,CAACI,cAAc;QACjB,MAAMK,YAAYX,iBAAiB;YAAEI;YAAQI;QAAI;QAEjD,MAAMI,kBAAkBb,eAAe;YACrCc,YAAYT,OAAOU,MAAM,CAACC,KAAK;YAC/BC,MAAM,CAAC,CAAC,EAAEX,iBAAiBY,IAAI,CAAC,QAAQ,EAAER,OAAO;YACjDE;QACF;QAEA,IAAIO,OAAO,GAAGV,IAAIW,CAAC,CAAC,oCAAoC;YACtDR,WAAWP,OAAOO,SAAS;YAC3BC;QACF,IAAI;QAEJ,MAAMQ,SAASf,iBAAiBgB,IAAI,CAACD,MAAM;QAE3C,yCAAyC;QACzC,IAAI,OAAOA,OAAOE,iBAAiB,KAAK,YAAY;YAClDJ,OAAO,MAAME,OAAOE,iBAAiB,CAAC;gBACpCd;gBACAC;gBACAC;YACF;QACF;QAEA,IAAIa,UAAUf,IAAIW,CAAC,CAAC;QAEpB,yCAAyC;QACzC,IAAI,OAAOC,OAAOI,oBAAoB,KAAK,YAAY;YACrDD,UAAU,MAAMH,OAAOI,oBAAoB,CAAC;gBAC1ChB;gBACAC;gBACAC;YACF;QACF;QAEA,MAAMH,MAAMkB,SAAS,CAAC;YACpBC,MAAM,CAAC,CAAC,EAAEnB,MAAMoB,eAAe,CAAC,GAAG,EAAEpB,MAAMqB,kBAAkB,CAAC,CAAC,CAAC;YAChEV;YACAK;YACAM,IAAInB,KAAKH,KAAK;QAChB;IACF;AACF"}
@@ -9,7 +9,7 @@ import type { SanitizedConfig } from '../types.js';
9
9
  * Also, if collection.defaultSort or joinField.defaultSort is not set, it will be set to the orderable field.
10
10
  */
11
11
  export declare const setupOrderable: (config: SanitizedConfig) => void;
12
- export declare const addOrderableFieldsAndHook: (collection: CollectionConfig, orderableFieldNames: string[]) => void;
12
+ export declare const addOrderableFieldsAndHook: (collection: CollectionConfig, orderableFieldNames: string[], joinFieldPathsByCollection?: Map<string, Map<string, string>>) => void;
13
13
  /**
14
14
  * The body of the reorder endpoint.
15
15
  * @internal
@@ -24,5 +24,5 @@ export type OrderableEndpointBody = {
24
24
  key: string;
25
25
  };
26
26
  };
27
- export declare const addOrderableEndpoint: (config: SanitizedConfig) => void;
27
+ export declare const addOrderableEndpoint: (config: SanitizedConfig, joinFieldPathsByCollection: Map<string, Map<string, string>>) => void;
28
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/orderable/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,mCAAmC,CAAA;AAE3F,OAAO,KAAK,EAA4B,eAAe,EAAE,MAAM,aAAa,CAAA;AAU5E;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WAAY,eAAe,SAuDrD,CAAA;AAED,eAAO,MAAM,yBAAyB,eACxB,gBAAgB,uBACP,MAAM,EAAE,SAgE9B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,MAAM,CAAA;IAChC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAA;QACV,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;CACF,CAAA;AAED,eAAO,MAAM,oBAAoB,WAAY,eAAe,SAkL3D,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/orderable/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,mCAAmC,CAAA;AAE3F,OAAO,KAAK,EAA4B,eAAe,EAAE,MAAM,aAAa,CAAA;AAc5E;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WAAY,eAAe,SA2DrD,CAAA;AAED,eAAO,MAAM,yBAAyB,eACxB,gBAAgB,uBACP,MAAM,EAAE,+BACA,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,SA2E9D,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,MAAM,CAAA;IAChC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAA;QACV,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;CACF,CAAA;AAED,eAAO,MAAM,oBAAoB,WACvB,eAAe,8BACK,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,SA4L7D,CAAA"}
@@ -1,11 +1,15 @@
1
1
  import { status as httpStatus } from 'http-status';
2
2
  import { executeAccess } from '../../auth/executeAccess.js';
3
3
  import { APIError } from '../../errors/index.js';
4
+ import { combineWhereConstraints } from '../../utilities/combineWhereConstraints.js';
4
5
  import { commitTransaction } from '../../utilities/commitTransaction.js';
5
6
  import { initTransaction } from '../../utilities/initTransaction.js';
6
7
  import { killTransaction } from '../../utilities/killTransaction.js';
7
8
  import { traverseFields } from '../../utilities/traverseFields.js';
8
9
  import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.js';
10
+ import { getJoinScopeContext } from './utils/getJoinScopeContext.js';
11
+ import { getJoinScopeWhereFromDocData } from './utils/getJoinScopeWhereFromDocData.js';
12
+ import { resolvePendingTargetKey } from './utils/resolvePendingTargetKey.js';
9
13
  /**
10
14
  * This function creates:
11
15
  * - N fields per collection, named `_order` or `_<collection>_<joinField>_order`
@@ -15,6 +19,7 @@ import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.
15
19
  * Also, if collection.defaultSort or joinField.defaultSort is not set, it will be set to the orderable field.
16
20
  */ export const setupOrderable = (config)=>{
17
21
  const fieldsToAdd = new Map();
22
+ const joinFieldPathsByCollection = new Map();
18
23
  config.collections.forEach((collection)=>{
19
24
  if (collection.orderable) {
20
25
  const currentFields = fieldsToAdd.get(collection) || [];
@@ -47,23 +52,27 @@ import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.
47
52
  const currentFields = fieldsToAdd.get(relationshipCollection) || [];
48
53
  // @ts-expect-error ref is untyped
49
54
  const prefix = parentRef?.prefix ? `${parentRef.prefix}_` : '';
55
+ const joinOrderableFieldName = `_${field.collection}_${prefix}${field.name}_order`;
50
56
  fieldsToAdd.set(relationshipCollection, [
51
57
  ...currentFields,
52
- `_${field.collection}_${prefix}${field.name}_order`
58
+ joinOrderableFieldName
53
59
  ]);
60
+ const currentJoinFieldPaths = joinFieldPathsByCollection.get(relationshipCollection.slug) || new Map();
61
+ currentJoinFieldPaths.set(joinOrderableFieldName, field.on);
62
+ joinFieldPathsByCollection.set(relationshipCollection.slug, currentJoinFieldPaths);
54
63
  }
55
64
  },
56
65
  fields: collection.fields
57
66
  });
58
67
  });
59
68
  Array.from(fieldsToAdd.entries()).forEach(([collection, orderableFields])=>{
60
- addOrderableFieldsAndHook(collection, orderableFields);
69
+ addOrderableFieldsAndHook(collection, orderableFields, joinFieldPathsByCollection);
61
70
  });
62
71
  if (fieldsToAdd.size > 0) {
63
- addOrderableEndpoint(config);
72
+ addOrderableEndpoint(config, joinFieldPathsByCollection);
64
73
  }
65
74
  };
66
- export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
75
+ export const addOrderableFieldsAndHook = (collection, orderableFieldNames, joinFieldPathsByCollection)=>{
67
76
  // 1. Add field
68
77
  orderableFieldNames.forEach((orderableFieldName)=>{
69
78
  const orderField = {
@@ -99,6 +108,13 @@ export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
99
108
  const orderBeforeChangeHook = async ({ data, originalDoc, req })=>{
100
109
  for (const orderableFieldName of orderableFieldNames){
101
110
  if (!data[orderableFieldName] && !originalDoc?.[orderableFieldName]) {
111
+ const joinScopeWhere = getJoinScopeWhereFromDocData({
112
+ collectionSlug: collection.slug,
113
+ data,
114
+ joinFieldPathsByCollection,
115
+ orderableFieldName,
116
+ originalDoc
117
+ });
102
118
  const lastDoc = await req.payload.find({
103
119
  collection: collection.slug,
104
120
  depth: 0,
@@ -109,11 +125,14 @@ export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
109
125
  [orderableFieldName]: true
110
126
  },
111
127
  sort: `-${orderableFieldName}`,
112
- where: {
113
- [orderableFieldName]: {
114
- exists: true
115
- }
116
- }
128
+ where: combineWhereConstraints([
129
+ {
130
+ [orderableFieldName]: {
131
+ exists: true
132
+ }
133
+ },
134
+ joinScopeWhere ?? undefined
135
+ ])
117
136
  });
118
137
  const lastOrderValue = lastDoc.docs[0]?.[orderableFieldName] || null;
119
138
  data[orderableFieldName] = generateKeyBetween(lastOrderValue, null);
@@ -123,7 +142,7 @@ export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
123
142
  };
124
143
  collection.hooks.beforeChange.push(orderBeforeChangeHook);
125
144
  };
126
- export const addOrderableEndpoint = (config)=>{
145
+ export const addOrderableEndpoint = (config, joinFieldPathsByCollection)=>{
127
146
  // 3. Add endpoint
128
147
  const reorderHandler = async (req)=>{
129
148
  const body = await req.json?.();
@@ -169,6 +188,13 @@ export const addOrderableEndpoint = (config)=>{
169
188
  status: 400
170
189
  });
171
190
  }
191
+ const { joinScopeWhere, targetDoc } = await getJoinScopeContext({
192
+ collectionSlug: collection.slug,
193
+ joinFieldPathsByCollection,
194
+ orderableFieldName,
195
+ req,
196
+ target
197
+ });
172
198
  // Prevent reordering if user doesn't have editing permissions
173
199
  if (collection.access?.update) {
174
200
  await executeAccess({
@@ -196,11 +222,14 @@ export const addOrderableEndpoint = (config)=>{
196
222
  select: {
197
223
  [orderableFieldName]: true
198
224
  },
199
- where: {
200
- [orderableFieldName]: {
201
- exists: false
202
- }
203
- }
225
+ where: combineWhereConstraints([
226
+ {
227
+ [orderableFieldName]: {
228
+ exists: false
229
+ }
230
+ },
231
+ joinScopeWhere ?? undefined
232
+ ])
204
233
  });
205
234
  await initTransaction(req);
206
235
  // We cannot update all documents in a single operation with `payload.update`,
@@ -244,20 +273,14 @@ export const addOrderableEndpoint = (config)=>{
244
273
  });
245
274
  }
246
275
  const targetId = target.id;
247
- let targetKey = target.key;
248
- // If targetKey = pending, we need to find its current key.
249
- // This can only happen if the user reorders rows quickly with a slow connection.
250
- if (targetKey === 'pending') {
251
- const beforeDoc = await req.payload.findByID({
252
- id: targetId,
253
- collection: collection.slug,
254
- depth: 0,
255
- select: {
256
- [orderableFieldName]: true
257
- }
258
- });
259
- targetKey = beforeDoc?.[orderableFieldName] || null;
260
- }
276
+ const targetKey = await resolvePendingTargetKey({
277
+ collectionSlug: collection.slug,
278
+ orderableFieldName,
279
+ req,
280
+ targetDoc,
281
+ targetID: targetId,
282
+ targetKey: target.key
283
+ });
261
284
  // The reason the endpoint does not receive this docId as an argument is that there
262
285
  // are situations where the user may not see or know what the next or previous one is. For
263
286
  // example, access control restrictions, if docBefore is the last one on the page, etc.
@@ -270,11 +293,14 @@ export const addOrderableEndpoint = (config)=>{
270
293
  [orderableFieldName]: true
271
294
  },
272
295
  sort: newKeyWillBe === 'greater' ? orderableFieldName : `-${orderableFieldName}`,
273
- where: {
274
- [orderableFieldName]: {
275
- [newKeyWillBe === 'greater' ? 'greater_than' : 'less_than']: targetKey
276
- }
277
- }
296
+ where: combineWhereConstraints([
297
+ {
298
+ [orderableFieldName]: {
299
+ [newKeyWillBe === 'greater' ? 'greater_than' : 'less_than']: targetKey
300
+ }
301
+ },
302
+ joinScopeWhere ?? undefined
303
+ ])
278
304
  });
279
305
  const adjacentDocKey = adjacentDoc.docs?.[0]?.[orderableFieldName] || null;
280
306
  // Currently N (= docsToMove.length) is always 1. Maybe in the future we will