payload 4.0.0-internal.2fddfc0 → 4.0.0-internal.3aa3d85

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 (262) hide show
  1. package/LICENSE.md +1 -1
  2. package/bin.js +11 -0
  3. package/dist/admin/RichText.d.ts +1 -21
  4. package/dist/admin/RichText.d.ts.map +1 -1
  5. package/dist/admin/RichText.js.map +1 -1
  6. package/dist/admin/forms/Field.d.ts +2 -2
  7. package/dist/admin/forms/Field.d.ts.map +1 -1
  8. package/dist/admin/forms/Field.js.map +1 -1
  9. package/dist/admin/forms/Form.d.ts +0 -29
  10. package/dist/admin/forms/Form.d.ts.map +1 -1
  11. package/dist/admin/forms/Form.js.map +1 -1
  12. package/dist/admin/functions/index.d.ts +1 -1
  13. package/dist/admin/functions/index.js.map +1 -1
  14. package/dist/admin/types.d.ts +1 -0
  15. package/dist/admin/types.d.ts.map +1 -1
  16. package/dist/admin/types.js.map +1 -1
  17. package/dist/auth/operations/auth.d.ts +2 -2
  18. package/dist/auth/operations/auth.d.ts.map +1 -1
  19. package/dist/auth/operations/auth.js.map +1 -1
  20. package/dist/auth/operations/login.d.ts +2 -1
  21. package/dist/auth/operations/login.d.ts.map +1 -1
  22. package/dist/auth/operations/login.js.map +1 -1
  23. package/dist/auth/operations/me.js.map +1 -1
  24. package/dist/auth/operations/refresh.d.ts.map +1 -1
  25. package/dist/auth/operations/refresh.js +9 -3
  26. package/dist/auth/operations/refresh.js.map +1 -1
  27. package/dist/auth/operations/resetPassword.d.ts.map +1 -1
  28. package/dist/auth/operations/resetPassword.js.map +1 -1
  29. package/dist/auth/sendVerificationEmail.d.ts +2 -2
  30. package/dist/auth/sendVerificationEmail.d.ts.map +1 -1
  31. package/dist/auth/sendVerificationEmail.js +1 -1
  32. package/dist/auth/sendVerificationEmail.js.map +1 -1
  33. package/dist/auth/sessions.d.ts +4 -5
  34. package/dist/auth/sessions.d.ts.map +1 -1
  35. package/dist/auth/sessions.js +5 -3
  36. package/dist/auth/sessions.js.map +1 -1
  37. package/dist/auth/strategies/apiKey.js.map +1 -1
  38. package/dist/auth/strategies/local/incrementLoginAttempts.d.ts +2 -2
  39. package/dist/auth/strategies/local/incrementLoginAttempts.d.ts.map +1 -1
  40. package/dist/auth/strategies/local/incrementLoginAttempts.js +1 -1
  41. package/dist/auth/strategies/local/incrementLoginAttempts.js.map +1 -1
  42. package/dist/auth/types.d.ts +28 -21
  43. package/dist/auth/types.d.ts.map +1 -1
  44. package/dist/auth/types.js.map +1 -1
  45. package/dist/bin/generateImportMap/iterateCollections.d.ts.map +1 -1
  46. package/dist/bin/generateImportMap/iterateCollections.js +10 -0
  47. package/dist/bin/generateImportMap/iterateCollections.js.map +1 -1
  48. package/dist/bin/generateImportMap/utilities/resolveImportMapFilePath.d.ts.map +1 -1
  49. package/dist/bin/generateImportMap/utilities/resolveImportMapFilePath.js +11 -3
  50. package/dist/bin/generateImportMap/utilities/resolveImportMapFilePath.js.map +1 -1
  51. package/dist/collections/config/client.d.ts +1 -1
  52. package/dist/collections/config/client.d.ts.map +1 -1
  53. package/dist/collections/config/client.js +1 -0
  54. package/dist/collections/config/client.js.map +1 -1
  55. package/dist/collections/config/defaults.d.ts +0 -4
  56. package/dist/collections/config/defaults.d.ts.map +1 -1
  57. package/dist/collections/config/defaults.js +0 -15
  58. package/dist/collections/config/defaults.js.map +1 -1
  59. package/dist/collections/config/types.d.ts +6 -0
  60. package/dist/collections/config/types.d.ts.map +1 -1
  61. package/dist/collections/config/types.js.map +1 -1
  62. package/dist/collections/operations/findDistinct.d.ts.map +1 -1
  63. package/dist/collections/operations/findDistinct.js +1 -0
  64. package/dist/collections/operations/findDistinct.js.map +1 -1
  65. package/dist/collections/operations/local/count.d.ts +3 -3
  66. package/dist/collections/operations/local/count.d.ts.map +1 -1
  67. package/dist/collections/operations/local/count.js.map +1 -1
  68. package/dist/collections/operations/local/countVersions.d.ts +3 -3
  69. package/dist/collections/operations/local/countVersions.d.ts.map +1 -1
  70. package/dist/collections/operations/local/countVersions.js.map +1 -1
  71. package/dist/collections/operations/local/create.d.ts +3 -3
  72. package/dist/collections/operations/local/create.d.ts.map +1 -1
  73. package/dist/collections/operations/local/create.js.map +1 -1
  74. package/dist/collections/operations/local/delete.d.ts +3 -3
  75. package/dist/collections/operations/local/delete.d.ts.map +1 -1
  76. package/dist/collections/operations/local/delete.js.map +1 -1
  77. package/dist/collections/operations/local/duplicate.d.ts +3 -3
  78. package/dist/collections/operations/local/duplicate.d.ts.map +1 -1
  79. package/dist/collections/operations/local/duplicate.js.map +1 -1
  80. package/dist/collections/operations/local/find.d.ts +3 -3
  81. package/dist/collections/operations/local/find.d.ts.map +1 -1
  82. package/dist/collections/operations/local/find.js.map +1 -1
  83. package/dist/collections/operations/local/findByID.d.ts +3 -3
  84. package/dist/collections/operations/local/findByID.d.ts.map +1 -1
  85. package/dist/collections/operations/local/findByID.js.map +1 -1
  86. package/dist/collections/operations/local/findDistinct.d.ts +2 -2
  87. package/dist/collections/operations/local/findDistinct.d.ts.map +1 -1
  88. package/dist/collections/operations/local/findDistinct.js.map +1 -1
  89. package/dist/collections/operations/local/findVersionByID.d.ts +3 -3
  90. package/dist/collections/operations/local/findVersionByID.d.ts.map +1 -1
  91. package/dist/collections/operations/local/findVersionByID.js.map +1 -1
  92. package/dist/collections/operations/local/findVersions.d.ts +3 -3
  93. package/dist/collections/operations/local/findVersions.d.ts.map +1 -1
  94. package/dist/collections/operations/local/findVersions.js.map +1 -1
  95. package/dist/collections/operations/local/restoreVersion.d.ts +3 -3
  96. package/dist/collections/operations/local/restoreVersion.d.ts.map +1 -1
  97. package/dist/collections/operations/local/restoreVersion.js.map +1 -1
  98. package/dist/collections/operations/local/update.d.ts +3 -3
  99. package/dist/collections/operations/local/update.d.ts.map +1 -1
  100. package/dist/collections/operations/local/update.js.map +1 -1
  101. package/dist/collections/operations/utilities/types.d.ts +0 -9
  102. package/dist/collections/operations/utilities/types.d.ts.map +1 -1
  103. package/dist/collections/operations/utilities/types.js.map +1 -1
  104. package/dist/config/client.d.ts +2 -2
  105. package/dist/config/client.d.ts.map +1 -1
  106. package/dist/config/client.js.map +1 -1
  107. package/dist/config/defaults.d.ts +0 -4
  108. package/dist/config/defaults.d.ts.map +1 -1
  109. package/dist/config/defaults.js +0 -78
  110. package/dist/config/defaults.js.map +1 -1
  111. package/dist/config/definePlugin.d.ts +10 -10
  112. package/dist/config/definePlugin.d.ts.map +1 -1
  113. package/dist/config/definePlugin.js +7 -11
  114. package/dist/config/definePlugin.js.map +1 -1
  115. package/dist/config/sanitize.d.ts.map +1 -1
  116. package/dist/config/sanitize.js +137 -13
  117. package/dist/config/sanitize.js.map +1 -1
  118. package/dist/config/types.d.ts +35 -3
  119. package/dist/config/types.d.ts.map +1 -1
  120. package/dist/config/types.js.map +1 -1
  121. package/dist/exports/internal.d.ts +1 -0
  122. package/dist/exports/internal.d.ts.map +1 -1
  123. package/dist/exports/internal.js +1 -0
  124. package/dist/exports/internal.js.map +1 -1
  125. package/dist/exports/shared.d.ts +3 -2
  126. package/dist/exports/shared.d.ts.map +1 -1
  127. package/dist/exports/shared.js +2 -1
  128. package/dist/exports/shared.js.map +1 -1
  129. package/dist/fields/baseFields/slug/countVersions.d.ts.map +1 -1
  130. package/dist/fields/baseFields/slug/countVersions.js +6 -8
  131. package/dist/fields/baseFields/slug/countVersions.js.map +1 -1
  132. package/dist/fields/baseFields/slug/generateSlug.d.ts +14 -7
  133. package/dist/fields/baseFields/slug/generateSlug.d.ts.map +1 -1
  134. package/dist/fields/baseFields/slug/generateSlug.js +53 -73
  135. package/dist/fields/baseFields/slug/generateSlug.js.map +1 -1
  136. package/dist/fields/baseFields/slug/types.d.ts +14 -0
  137. package/dist/fields/baseFields/slug/types.d.ts.map +1 -0
  138. package/dist/fields/baseFields/slug/types.js +6 -0
  139. package/dist/fields/baseFields/slug/types.js.map +1 -0
  140. package/dist/fields/config/client.d.ts +1 -1
  141. package/dist/fields/config/client.d.ts.map +1 -1
  142. package/dist/fields/config/client.js +2 -1
  143. package/dist/fields/config/client.js.map +1 -1
  144. package/dist/fields/config/sanitize.d.ts.map +1 -1
  145. package/dist/fields/config/sanitize.js +39 -0
  146. package/dist/fields/config/sanitize.js.map +1 -1
  147. package/dist/fields/config/types.d.ts +44 -8
  148. package/dist/fields/config/types.d.ts.map +1 -1
  149. package/dist/fields/config/types.js.map +1 -1
  150. package/dist/fields/hooks/afterRead/promise.d.ts.map +1 -1
  151. package/dist/fields/hooks/afterRead/promise.js +11 -1
  152. package/dist/fields/hooks/afterRead/promise.js.map +1 -1
  153. package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
  154. package/dist/fields/hooks/beforeValidate/promise.js +10 -1
  155. package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
  156. package/dist/fields/setDefaultBeforeDuplicate.js +1 -0
  157. package/dist/fields/setDefaultBeforeDuplicate.js.map +1 -1
  158. package/dist/fields/sortableFieldTypes.d.ts.map +1 -1
  159. package/dist/fields/sortableFieldTypes.js +1 -0
  160. package/dist/fields/sortableFieldTypes.js.map +1 -1
  161. package/dist/fields/validations.d.ts +4 -1
  162. package/dist/fields/validations.d.ts.map +1 -1
  163. package/dist/fields/validations.js +7 -0
  164. package/dist/fields/validations.js.map +1 -1
  165. package/dist/globals/operations/local/countVersions.d.ts +3 -3
  166. package/dist/globals/operations/local/countVersions.d.ts.map +1 -1
  167. package/dist/globals/operations/local/countVersions.js.map +1 -1
  168. package/dist/globals/operations/local/findOne.d.ts +3 -3
  169. package/dist/globals/operations/local/findOne.d.ts.map +1 -1
  170. package/dist/globals/operations/local/findOne.js.map +1 -1
  171. package/dist/globals/operations/local/findVersionByID.d.ts +3 -3
  172. package/dist/globals/operations/local/findVersionByID.d.ts.map +1 -1
  173. package/dist/globals/operations/local/findVersionByID.js.map +1 -1
  174. package/dist/globals/operations/local/findVersions.d.ts +3 -3
  175. package/dist/globals/operations/local/findVersions.d.ts.map +1 -1
  176. package/dist/globals/operations/local/findVersions.js.map +1 -1
  177. package/dist/globals/operations/local/restoreVersion.d.ts +3 -3
  178. package/dist/globals/operations/local/restoreVersion.d.ts.map +1 -1
  179. package/dist/globals/operations/local/restoreVersion.js.map +1 -1
  180. package/dist/globals/operations/local/update.d.ts +3 -3
  181. package/dist/globals/operations/local/update.d.ts.map +1 -1
  182. package/dist/globals/operations/local/update.js.map +1 -1
  183. package/dist/index.bundled.d.ts +365 -300
  184. package/dist/index.d.ts +59 -15
  185. package/dist/index.d.ts.map +1 -1
  186. package/dist/index.js +1 -2
  187. package/dist/index.js.map +1 -1
  188. package/dist/preferences/keys.d.ts +4 -0
  189. package/dist/preferences/keys.d.ts.map +1 -1
  190. package/dist/preferences/keys.js +4 -1
  191. package/dist/preferences/keys.js.map +1 -1
  192. package/dist/preferences/types.d.ts +15 -0
  193. package/dist/preferences/types.d.ts.map +1 -1
  194. package/dist/preferences/types.js +3 -1
  195. package/dist/preferences/types.js.map +1 -1
  196. package/dist/types/index.d.ts +8 -3
  197. package/dist/types/index.d.ts.map +1 -1
  198. package/dist/types/index.js.map +1 -1
  199. package/dist/uploads/fetchAPI-multipart/processMultipart.d.ts.map +1 -1
  200. package/dist/uploads/fetchAPI-multipart/processMultipart.js +1 -14
  201. package/dist/uploads/fetchAPI-multipart/processMultipart.js.map +1 -1
  202. package/dist/uploads/matchMimeType.d.ts +8 -0
  203. package/dist/uploads/matchMimeType.d.ts.map +1 -0
  204. package/dist/uploads/matchMimeType.js +19 -0
  205. package/dist/uploads/matchMimeType.js.map +1 -0
  206. package/dist/uploads/matchMimeType.spec.js +66 -0
  207. package/dist/uploads/matchMimeType.spec.js.map +1 -0
  208. package/dist/uploads/types.d.ts +21 -0
  209. package/dist/uploads/types.d.ts.map +1 -1
  210. package/dist/uploads/types.js.map +1 -1
  211. package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
  212. package/dist/utilities/addDataAndFileToRequest.js +6 -0
  213. package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
  214. package/dist/utilities/configToJSONSchema.d.ts +13 -4
  215. package/dist/utilities/configToJSONSchema.d.ts.map +1 -1
  216. package/dist/utilities/configToJSONSchema.js +139 -61
  217. package/dist/utilities/configToJSONSchema.js.map +1 -1
  218. package/dist/utilities/configToJSONSchema.spec.js +319 -0
  219. package/dist/utilities/configToJSONSchema.spec.js.map +1 -1
  220. package/dist/utilities/createLocalReq.d.ts +2 -2
  221. package/dist/utilities/createLocalReq.d.ts.map +1 -1
  222. package/dist/utilities/createLocalReq.js.map +1 -1
  223. package/dist/utilities/createPayloadRequest.d.ts.map +1 -1
  224. package/dist/utilities/createPayloadRequest.js +1 -0
  225. package/dist/utilities/createPayloadRequest.js.map +1 -1
  226. package/dist/utilities/getEntityPermissions/getEntityPermissions.d.ts.map +1 -1
  227. package/dist/utilities/getEntityPermissions/getEntityPermissions.js +2 -0
  228. package/dist/utilities/getEntityPermissions/getEntityPermissions.js.map +1 -1
  229. package/dist/utilities/getEntityPermissions/populateFieldPermissions.d.ts +7 -1
  230. package/dist/utilities/getEntityPermissions/populateFieldPermissions.d.ts.map +1 -1
  231. package/dist/utilities/getEntityPermissions/populateFieldPermissions.js +19 -2
  232. package/dist/utilities/getEntityPermissions/populateFieldPermissions.js.map +1 -1
  233. package/dist/utilities/isURLAllowed.d.ts.map +1 -1
  234. package/dist/utilities/isURLAllowed.js +9 -3
  235. package/dist/utilities/isURLAllowed.js.map +1 -1
  236. package/dist/utilities/isURLAllowed.spec.js +78 -0
  237. package/dist/utilities/isURLAllowed.spec.js.map +1 -0
  238. package/dist/utilities/telemetry/conf/envPaths.d.ts.map +1 -1
  239. package/dist/utilities/telemetry/conf/envPaths.js +40 -31
  240. package/dist/utilities/telemetry/conf/envPaths.js.map +1 -1
  241. package/dist/utilities/telemetry/events/adminInit.d.ts.map +1 -1
  242. package/dist/utilities/telemetry/events/adminInit.js +2 -3
  243. package/dist/utilities/telemetry/events/adminInit.js.map +1 -1
  244. package/dist/utilities/telemetry/events/serverInit.d.ts.map +1 -1
  245. package/dist/utilities/telemetry/events/serverInit.js +2 -3
  246. package/dist/utilities/telemetry/events/serverInit.js.map +1 -1
  247. package/dist/utilities/telemetry/index.d.ts +14 -3
  248. package/dist/utilities/telemetry/index.d.ts.map +1 -1
  249. package/dist/utilities/telemetry/index.js +6 -1
  250. package/dist/utilities/telemetry/index.js.map +1 -1
  251. package/dist/utilities/telemetry/index.spec.js +43 -0
  252. package/dist/utilities/telemetry/index.spec.js.map +1 -0
  253. package/dist/versions/schedule/job.js.map +1 -1
  254. package/package.json +3 -3
  255. package/dist/fields/baseFields/slug/index.d.ts +0 -89
  256. package/dist/fields/baseFields/slug/index.d.ts.map +0 -1
  257. package/dist/fields/baseFields/slug/index.js +0 -81
  258. package/dist/fields/baseFields/slug/index.js.map +0 -1
  259. package/dist/utilities/isRSCEnabled.d.ts +0 -12
  260. package/dist/utilities/isRSCEnabled.d.ts.map +0 -1
  261. package/dist/utilities/isRSCEnabled.js +0 -14
  262. package/dist/utilities/isRSCEnabled.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/createPayloadRequest.ts"],"sourcesContent":["import { initI18n } from '@payloadcms/translations'\nimport * as qs from 'qs-esm'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { TypedFallbackLocale } from '../index.js'\nimport type { CustomPayloadRequestProperties, PayloadRequest } from '../types/index.js'\n\nimport { executeAuthStrategies } from '../auth/executeAuthStrategies.js'\nimport { getDataLoader } from '../collections/dataloader.js'\nimport { getPayload } from '../index.js'\nimport { sanitizeLocales } from './addLocalesToRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { getRequestLanguage } from './getRequestLanguage.js'\nimport { parseCookies } from './parseCookies.js'\n\ntype Args = {\n canSetHeaders?: boolean\n config: Promise<SanitizedConfig> | SanitizedConfig\n params?: {\n collection: string\n }\n payloadInstanceCacheKey?: string\n request: Request\n}\n\nexport const createPayloadRequest = async ({\n canSetHeaders,\n config: configPromise,\n params,\n payloadInstanceCacheKey,\n request,\n}: Args): Promise<PayloadRequest> => {\n const cookies = parseCookies(request.headers)\n const payload = await getPayload({\n config: configPromise,\n cron: true,\n key: payloadInstanceCacheKey,\n })\n\n const { config } = payload\n const localization = config.localization\n\n const urlProperties = new URL(request.url)\n const { pathname, searchParams } = urlProperties\n\n const isGraphQL =\n !config.graphQL.disable &&\n pathname ===\n formatAdminURL({\n apiRoute: config.routes.api,\n path: config.routes.graphQL as `/${string}`,\n })\n\n const language = getRequestLanguage({\n config,\n cookies,\n headers: request.headers,\n })\n\n const i18n = await initI18n({\n config: config.i18n,\n context: 'api',\n language,\n })\n\n let locale = searchParams.get('locale')\n\n const { search: queryToParse } = urlProperties\n\n const query = queryToParse\n ? qs.parse(queryToParse, {\n arrayLimit: 1000,\n depth: 10,\n ignoreQueryPrefix: true,\n })\n : {}\n\n const fallbackFromRequest = (query.fallbackLocale ||\n searchParams.get('fallback-locale') ||\n searchParams.get('fallbackLocale')) as TypedFallbackLocale\n\n let fallbackLocale = fallbackFromRequest\n\n if (localization) {\n const locales = sanitizeLocales({\n fallbackLocale: fallbackLocale!,\n locale: locale!,\n localization,\n })\n\n fallbackLocale = locales.fallbackLocale!\n locale = locales.locale!\n }\n\n const customRequest: CustomPayloadRequestProperties = {\n context: {},\n fallbackLocale: fallbackLocale!,\n hash: urlProperties.hash,\n host: urlProperties.host,\n href: urlProperties.href,\n i18n,\n locale,\n origin: urlProperties.origin,\n pathname: urlProperties.pathname,\n payload,\n payloadAPI: isGraphQL ? 'GraphQL' : 'REST',\n payloadDataLoader: undefined!,\n payloadUploadSizes: {},\n port: urlProperties.port,\n protocol: urlProperties.protocol,\n query,\n routeParams: params || {},\n search: urlProperties.search,\n searchParams: urlProperties.searchParams,\n t: i18n.t,\n transactionID: undefined,\n user: null,\n }\n\n const req: PayloadRequest = Object.assign(request, customRequest)\n\n req.payloadDataLoader = getDataLoader(req)\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers: req.headers,\n isGraphQL,\n payload,\n })\n\n req.user = user\n\n if (responseHeaders) {\n req.responseHeaders = responseHeaders\n }\n\n return req\n}\n"],"names":["initI18n","qs","executeAuthStrategies","getDataLoader","getPayload","sanitizeLocales","formatAdminURL","getRequestLanguage","parseCookies","createPayloadRequest","canSetHeaders","config","configPromise","params","payloadInstanceCacheKey","request","cookies","headers","payload","cron","key","localization","urlProperties","URL","url","pathname","searchParams","isGraphQL","graphQL","disable","apiRoute","routes","api","path","language","i18n","context","locale","get","search","queryToParse","query","parse","arrayLimit","depth","ignoreQueryPrefix","fallbackFromRequest","fallbackLocale","locales","customRequest","hash","host","href","origin","payloadAPI","payloadDataLoader","undefined","payloadUploadSizes","port","protocol","routeParams","t","transactionID","user","req","Object","assign","responseHeaders"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utilities/createPayloadRequest.ts"],"sourcesContent":["import { initI18n } from '@payloadcms/translations'\nimport * as qs from 'qs-esm'\n\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { TypedFallbackLocale } from '../index.js'\nimport type { CustomPayloadRequestProperties, PayloadRequest } from '../types/index.js'\n\nimport { executeAuthStrategies } from '../auth/executeAuthStrategies.js'\nimport { getDataLoader } from '../collections/dataloader.js'\nimport { getPayload } from '../index.js'\nimport { sanitizeLocales } from './addLocalesToRequest.js'\nimport { formatAdminURL } from './formatAdminURL.js'\nimport { getRequestLanguage } from './getRequestLanguage.js'\nimport { parseCookies } from './parseCookies.js'\n\ntype Args = {\n canSetHeaders?: boolean\n config: Promise<SanitizedConfig> | SanitizedConfig\n params?: {\n collection: string\n }\n payloadInstanceCacheKey?: string\n request: Request\n}\n\nexport const createPayloadRequest = async ({\n canSetHeaders,\n config: configPromise,\n params,\n payloadInstanceCacheKey,\n request,\n}: Args): Promise<PayloadRequest> => {\n const cookies = parseCookies(request.headers)\n const payload = await getPayload({\n config: configPromise,\n cron: true,\n key: payloadInstanceCacheKey,\n })\n\n const { config } = payload\n const localization = config.localization\n\n const urlProperties = new URL(request.url)\n const { pathname, searchParams } = urlProperties\n\n const isGraphQL =\n !config.graphQL.disable &&\n pathname ===\n formatAdminURL({\n apiRoute: config.routes.api,\n path: config.routes.graphQL as `/${string}`,\n })\n\n const language = getRequestLanguage({\n config,\n cookies,\n headers: request.headers,\n })\n\n const i18n = await initI18n({\n config: config.i18n,\n context: 'api',\n language,\n })\n\n let locale = searchParams.get('locale')\n\n const { search: queryToParse } = urlProperties\n\n const query = queryToParse\n ? qs.parse(queryToParse, {\n allowEmptyArrays: true,\n arrayLimit: 1000,\n depth: 10,\n ignoreQueryPrefix: true,\n })\n : {}\n\n const fallbackFromRequest = (query.fallbackLocale ||\n searchParams.get('fallback-locale') ||\n searchParams.get('fallbackLocale')) as TypedFallbackLocale\n\n let fallbackLocale = fallbackFromRequest\n\n if (localization) {\n const locales = sanitizeLocales({\n fallbackLocale: fallbackLocale!,\n locale: locale!,\n localization,\n })\n\n fallbackLocale = locales.fallbackLocale!\n locale = locales.locale!\n }\n\n const customRequest: CustomPayloadRequestProperties = {\n context: {},\n fallbackLocale: fallbackLocale!,\n hash: urlProperties.hash,\n host: urlProperties.host,\n href: urlProperties.href,\n i18n,\n locale,\n origin: urlProperties.origin,\n pathname: urlProperties.pathname,\n payload,\n payloadAPI: isGraphQL ? 'GraphQL' : 'REST',\n payloadDataLoader: undefined!,\n payloadUploadSizes: {},\n port: urlProperties.port,\n protocol: urlProperties.protocol,\n query,\n routeParams: params || {},\n search: urlProperties.search,\n searchParams: urlProperties.searchParams,\n t: i18n.t,\n transactionID: undefined,\n user: null,\n }\n\n const req: PayloadRequest = Object.assign(request, customRequest)\n\n req.payloadDataLoader = getDataLoader(req)\n\n const { responseHeaders, user } = await executeAuthStrategies({\n canSetHeaders,\n headers: req.headers,\n isGraphQL,\n payload,\n })\n\n req.user = user\n\n if (responseHeaders) {\n req.responseHeaders = responseHeaders\n }\n\n return req\n}\n"],"names":["initI18n","qs","executeAuthStrategies","getDataLoader","getPayload","sanitizeLocales","formatAdminURL","getRequestLanguage","parseCookies","createPayloadRequest","canSetHeaders","config","configPromise","params","payloadInstanceCacheKey","request","cookies","headers","payload","cron","key","localization","urlProperties","URL","url","pathname","searchParams","isGraphQL","graphQL","disable","apiRoute","routes","api","path","language","i18n","context","locale","get","search","queryToParse","query","parse","allowEmptyArrays","arrayLimit","depth","ignoreQueryPrefix","fallbackFromRequest","fallbackLocale","locales","customRequest","hash","host","href","origin","payloadAPI","payloadDataLoader","undefined","payloadUploadSizes","port","protocol","routeParams","t","transactionID","user","req","Object","assign","responseHeaders"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"getEntityPermissions.d.ts","sourceRoot":"","sources":["../../../src/utilities/getEntityPermissions/getEntityPermissions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EAEpB,gBAAgB,EAEjB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAC9F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAS,MAAM,sBAAsB,CAAA;AAO5F,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAC7C,SAAS,EACT,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,UAAU,CAAA;AAE/C,KAAK,UAAU,CAAC,WAAW,SAAS,YAAY,GAAG,QAAQ,IAAI,WAAW,SAAS,QAAQ,GACvF,gBAAgB,GAChB,oBAAoB,CAAA;AAExB,KAAK,IAAI,CAAC,WAAW,SAAS,YAAY,GAAG,QAAQ,IAAI;IACvD,0BAA0B,EAAE,0BAA0B,CAAA;IACtD;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,WAAW,SAAS,YAAY,GAAG,yBAAyB,GAAG,qBAAqB,CAAA;IAC5F,UAAU,EAAE,WAAW,CAAA;IACvB;;OAEG;IACH,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,GAAG,EAAE,cAAc,CAAA;CACpB,GAAG,CACA;IACE,SAAS,EAAE,KAAK,CAAA;IAChB,EAAE,CAAC,EAAE,KAAK,CAAA;CACX,GACD;IACE,SAAS,EAAE,IAAI,CAAA;IACf,EAAE,EAAE,WAAW,SAAS,YAAY,GAAG,qBAAqB,GAAG,SAAS,CAAA;CACzE,CACJ,CAAA;AAYD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,SAAS,YAAY,GAAG,QAAQ,EACpF,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,GACtB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAwJlC"}
1
+ {"version":3,"file":"getEntityPermissions.d.ts","sourceRoot":"","sources":["../../../src/utilities/getEntityPermissions/getEntityPermissions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EAEpB,gBAAgB,EAEjB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAC9F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAS,MAAM,sBAAsB,CAAA;AAO5F,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAC7C,SAAS,EACT,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAC7C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,UAAU,CAAA;AAE/C,KAAK,UAAU,CAAC,WAAW,SAAS,YAAY,GAAG,QAAQ,IAAI,WAAW,SAAS,QAAQ,GACvF,gBAAgB,GAChB,oBAAoB,CAAA;AAExB,KAAK,IAAI,CAAC,WAAW,SAAS,YAAY,GAAG,QAAQ,IAAI;IACvD,0BAA0B,EAAE,0BAA0B,CAAA;IACtD;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,WAAW,SAAS,YAAY,GAAG,yBAAyB,GAAG,qBAAqB,CAAA;IAC5F,UAAU,EAAE,WAAW,CAAA;IACvB;;OAEG;IACH,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,GAAG,EAAE,cAAc,CAAA;CACpB,GAAG,CACA;IACE,SAAS,EAAE,KAAK,CAAA;IAChB,EAAE,CAAC,EAAE,KAAK,CAAA;CACX,GACD;IACE,SAAS,EAAE,IAAI,CAAA;IACf,EAAE,EAAE,WAAW,SAAS,YAAY,GAAG,qBAAqB,GAAG,SAAS,CAAA;CACzE,CACJ,CAAA;AAYD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,SAAS,YAAY,GAAG,QAAQ,EACpF,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,GACtB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CA0JlC"}
@@ -127,8 +127,10 @@ const topLevelGlobalPermissions = [
127
127
  await Promise.all(wherePromises);
128
128
  populateFieldPermissions({
129
129
  blockReferencesPermissions,
130
+ collection: entityType === 'collection' ? entity : null,
130
131
  data,
131
132
  fields: entity.fields,
133
+ global: entityType === 'global' ? entity : null,
132
134
  operations,
133
135
  parentPermissionsObject: entityPermissions,
134
136
  permissionsObject: fieldsPermissions,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utilities/getEntityPermissions/getEntityPermissions.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'util'\n\nimport type {\n BlockPermissions,\n CollectionPermission,\n FieldsPermissions,\n GlobalPermission,\n Permission,\n} from '../../auth/types.js'\nimport type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'\nimport type { SanitizedGlobalConfig } from '../../globals/config/types.js'\nimport type { BlockSlug, DefaultDocumentIDType } from '../../index.js'\nimport type { AllOperations, JsonObject, PayloadRequest, Where } from '../../types/index.js'\n\nimport { entityDocExists } from './entityDocExists.js'\nimport { populateFieldPermissions } from './populateFieldPermissions.js'\n\ntype WhereQueryCache = { result: Promise<boolean>; where: Where }[]\n\nexport type BlockReferencesPermissions = Record<\n BlockSlug,\n BlockPermissions | Promise<BlockPermissions>\n>\n\nexport type EntityDoc = JsonObject | TypeWithID\n\ntype ReturnType<TEntityType extends 'collection' | 'global'> = TEntityType extends 'global'\n ? GlobalPermission\n : CollectionPermission\n\ntype Args<TEntityType extends 'collection' | 'global'> = {\n blockReferencesPermissions: BlockReferencesPermissions\n /**\n * If the document data is passed, it will be used to check access instead of fetching the document from the database.\n */\n data?: JsonObject\n entity: TEntityType extends 'collection' ? SanitizedCollectionConfig : SanitizedGlobalConfig\n entityType: TEntityType\n /**\n * Operations to check access for\n */\n operations: AllOperations[]\n req: PayloadRequest\n} & (\n | {\n fetchData: false\n id?: never\n }\n | {\n fetchData: true\n id: TEntityType extends 'collection' ? DefaultDocumentIDType : undefined\n }\n)\n\nconst topLevelCollectionPermissions = [\n 'create',\n 'delete',\n 'read',\n 'readVersions',\n 'update',\n 'unlock',\n]\nconst topLevelGlobalPermissions = ['read', 'readVersions', 'update']\n\n/**\n * Build up permissions object for an entity (collection or global).\n * This is not run during any update and reflects the current state of the entity data => doc and data is the same.\n *\n * When `fetchData` is false:\n * - returned `Where` are not run and evaluated as \"does not have permission\".\n * - If req.data is passed: `data` and `doc` is passed to access functions.\n * - If req.data is not passed: `data` and `doc` is not passed to access functions.\n *\n * When `fetchData` is true:\n * - `Where` are run and evaluated as \"has permission\" or \"does not have permission\".\n * - `data` and `doc` are always passed to access functions.\n * - Error is thrown if `entityType` is 'collection' and `id` is not passed.\n *\n * In both cases:\n * We cannot include siblingData or blockData here, as we do not have siblingData available once we reach block or array\n * rows, as we're calculating schema permissions, which do not include individual rows.\n * For consistency, it's thus better to never include the siblingData and blockData\n *\n * @internal\n */\nexport async function getEntityPermissions<TEntityType extends 'collection' | 'global'>(\n args: Args<TEntityType>,\n): Promise<ReturnType<TEntityType>> {\n const {\n id,\n blockReferencesPermissions,\n data: _data,\n entity,\n entityType,\n fetchData,\n operations,\n req,\n } = args\n const { locale: _locale, user } = req\n\n const locale = _locale ? _locale : undefined\n\n if (fetchData && entityType === 'collection' && !id) {\n throw new Error('ID is required when fetching data for a collection')\n }\n\n const hasData = _data && Object.keys(_data).length > 0\n const data: JsonObject | undefined = hasData\n ? _data\n : fetchData\n ? await (async () => {\n if (entityType === 'global') {\n return req.payload.findGlobal({\n slug: entity.slug,\n depth: 0,\n fallbackLocale: null,\n locale,\n overrideAccess: true,\n req,\n })\n }\n\n if (entityType === 'collection') {\n return req.payload.findByID({\n id: id!,\n collection: entity.slug,\n depth: 0,\n fallbackLocale: null,\n locale,\n overrideAccess: true,\n req,\n trash: true,\n })\n }\n })()\n : undefined\n\n const isLoggedIn = !!user\n\n const fieldsPermissions: FieldsPermissions = {}\n\n const entityPermissions: ReturnType<TEntityType> = {\n fields: fieldsPermissions,\n } as ReturnType<TEntityType>\n\n const promises: Promise<void>[] = []\n\n // Phase 1: Resolve all access functions to get where queries\n const accessResults: {\n operation: keyof typeof entity.access\n result: Promise<boolean | Where>\n }[] = []\n\n for (const _operation of operations) {\n const operation = _operation as keyof typeof entity.access\n const accessFunction = entity.access[operation]\n\n if (\n (entityType === 'collection' && topLevelCollectionPermissions.includes(operation)) ||\n (entityType === 'global' && topLevelGlobalPermissions.includes(operation))\n ) {\n if (typeof accessFunction === 'function') {\n accessResults.push({\n operation,\n result: Promise.resolve(accessFunction({ id, data, req })) as Promise<boolean | Where>,\n })\n } else {\n entityPermissions[operation] = {\n permission: isLoggedIn,\n }\n }\n }\n }\n\n // Await all access functions in parallel\n const resolvedAccessResults = await Promise.all(\n accessResults.map(async (item) => ({\n operation: item.operation,\n result: await item.result,\n })),\n )\n\n // Phase 2: Process where queries with cache and resolve in parallel\n const whereQueryCache: WhereQueryCache = []\n const wherePromises: Promise<void>[] = []\n\n for (const { operation, result: accessResult } of resolvedAccessResults) {\n if (typeof accessResult === 'object') {\n processWhereQuery({\n id,\n slug: entity.slug,\n accessResult,\n entityPermissions,\n entityType,\n fetchData,\n locale,\n operation,\n req,\n wherePromises,\n whereQueryCache,\n })\n } else if (entityPermissions[operation]?.permission !== false) {\n entityPermissions[operation] = { permission: !!accessResult }\n }\n }\n\n // Await all where query DB calls in parallel\n await Promise.all(wherePromises)\n\n populateFieldPermissions({\n blockReferencesPermissions,\n data,\n fields: entity.fields,\n operations,\n parentPermissionsObject: entityPermissions,\n permissionsObject: fieldsPermissions,\n promises,\n req,\n })\n\n /**\n * Await all promises in parallel.\n * A promise can add more promises to the promises array (group of fields calls populateFieldPermissions again in their own promise), which will not be\n * awaited in the first run.\n * This is why we need to loop again to process the new promises, until there are no more promises left.\n */\n let iterations = 0\n while (promises.length > 0) {\n const currentPromises = promises.splice(0, promises.length)\n\n await Promise.all(currentPromises)\n\n iterations++\n if (iterations >= 100) {\n throw new Error('Infinite getEntityPermissions promise loop detected.')\n }\n }\n\n return entityPermissions\n}\n\nconst processWhereQuery = ({\n id,\n slug,\n accessResult,\n entityPermissions,\n entityType,\n fetchData,\n locale,\n operation,\n req,\n wherePromises,\n whereQueryCache,\n}: {\n accessResult: Where\n entityPermissions: CollectionPermission | GlobalPermission\n entityType: 'collection' | 'global'\n fetchData: boolean\n id?: DefaultDocumentIDType\n locale?: string\n operation: Extract<keyof (CollectionPermission | GlobalPermission), AllOperations>\n req: PayloadRequest\n slug: string\n wherePromises: Promise<void>[]\n whereQueryCache: WhereQueryCache\n}): void => {\n if (fetchData) {\n // Check cache for identical where query using deep comparison\n let cached = whereQueryCache.find((entry) => isDeepStrictEqual(entry.where, accessResult))\n\n if (!cached) {\n // Cache miss - start DB query (don't await)\n cached = {\n result: entityDocExists({\n id,\n slug,\n entityType,\n locale,\n operation,\n req,\n where: accessResult,\n }),\n where: accessResult,\n }\n whereQueryCache.push(cached)\n }\n\n // Defer resolution to Promise.all (cache hits reuse same promise)\n wherePromises.push(\n cached.result.then((hasPermission) => {\n entityPermissions[operation] = {\n permission: hasPermission,\n where: accessResult,\n } as Permission\n }),\n )\n } else {\n // TODO: 4.0: Investigate defaulting to `false` here, if where query is returned but ignored as we don't\n // have the document data available. This seems more secure.\n // Alternatively, we could set permission to a third state, like 'unknown'.\n // Even after calling sanitizePermissions, the permissions will still be true if the where query is returned but ignored as we don't have the document data available.\n entityPermissions[operation] = { permission: true, where: accessResult } as Permission\n }\n}\n"],"names":["isDeepStrictEqual","entityDocExists","populateFieldPermissions","topLevelCollectionPermissions","topLevelGlobalPermissions","getEntityPermissions","args","id","blockReferencesPermissions","data","_data","entity","entityType","fetchData","operations","req","locale","_locale","user","undefined","Error","hasData","Object","keys","length","payload","findGlobal","slug","depth","fallbackLocale","overrideAccess","findByID","collection","trash","isLoggedIn","fieldsPermissions","entityPermissions","fields","promises","accessResults","_operation","operation","accessFunction","access","includes","push","result","Promise","resolve","permission","resolvedAccessResults","all","map","item","whereQueryCache","wherePromises","accessResult","processWhereQuery","parentPermissionsObject","permissionsObject","iterations","currentPromises","splice","cached","find","entry","where","then","hasPermission"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/utilities/getEntityPermissions/getEntityPermissions.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'util'\n\nimport type {\n BlockPermissions,\n CollectionPermission,\n FieldsPermissions,\n GlobalPermission,\n Permission,\n} from '../../auth/types.js'\nimport type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types.js'\nimport type { SanitizedGlobalConfig } from '../../globals/config/types.js'\nimport type { BlockSlug, DefaultDocumentIDType } from '../../index.js'\nimport type { AllOperations, JsonObject, PayloadRequest, Where } from '../../types/index.js'\n\nimport { entityDocExists } from './entityDocExists.js'\nimport { populateFieldPermissions } from './populateFieldPermissions.js'\n\ntype WhereQueryCache = { result: Promise<boolean>; where: Where }[]\n\nexport type BlockReferencesPermissions = Record<\n BlockSlug,\n BlockPermissions | Promise<BlockPermissions>\n>\n\nexport type EntityDoc = JsonObject | TypeWithID\n\ntype ReturnType<TEntityType extends 'collection' | 'global'> = TEntityType extends 'global'\n ? GlobalPermission\n : CollectionPermission\n\ntype Args<TEntityType extends 'collection' | 'global'> = {\n blockReferencesPermissions: BlockReferencesPermissions\n /**\n * If the document data is passed, it will be used to check access instead of fetching the document from the database.\n */\n data?: JsonObject\n entity: TEntityType extends 'collection' ? SanitizedCollectionConfig : SanitizedGlobalConfig\n entityType: TEntityType\n /**\n * Operations to check access for\n */\n operations: AllOperations[]\n req: PayloadRequest\n} & (\n | {\n fetchData: false\n id?: never\n }\n | {\n fetchData: true\n id: TEntityType extends 'collection' ? DefaultDocumentIDType : undefined\n }\n)\n\nconst topLevelCollectionPermissions = [\n 'create',\n 'delete',\n 'read',\n 'readVersions',\n 'update',\n 'unlock',\n]\nconst topLevelGlobalPermissions = ['read', 'readVersions', 'update']\n\n/**\n * Build up permissions object for an entity (collection or global).\n * This is not run during any update and reflects the current state of the entity data => doc and data is the same.\n *\n * When `fetchData` is false:\n * - returned `Where` are not run and evaluated as \"does not have permission\".\n * - If req.data is passed: `data` and `doc` is passed to access functions.\n * - If req.data is not passed: `data` and `doc` is not passed to access functions.\n *\n * When `fetchData` is true:\n * - `Where` are run and evaluated as \"has permission\" or \"does not have permission\".\n * - `data` and `doc` are always passed to access functions.\n * - Error is thrown if `entityType` is 'collection' and `id` is not passed.\n *\n * In both cases:\n * We cannot include siblingData or blockData here, as we do not have siblingData available once we reach block or array\n * rows, as we're calculating schema permissions, which do not include individual rows.\n * For consistency, it's thus better to never include the siblingData and blockData\n *\n * @internal\n */\nexport async function getEntityPermissions<TEntityType extends 'collection' | 'global'>(\n args: Args<TEntityType>,\n): Promise<ReturnType<TEntityType>> {\n const {\n id,\n blockReferencesPermissions,\n data: _data,\n entity,\n entityType,\n fetchData,\n operations,\n req,\n } = args\n const { locale: _locale, user } = req\n\n const locale = _locale ? _locale : undefined\n\n if (fetchData && entityType === 'collection' && !id) {\n throw new Error('ID is required when fetching data for a collection')\n }\n\n const hasData = _data && Object.keys(_data).length > 0\n const data: JsonObject | undefined = hasData\n ? _data\n : fetchData\n ? await (async () => {\n if (entityType === 'global') {\n return req.payload.findGlobal({\n slug: entity.slug,\n depth: 0,\n fallbackLocale: null,\n locale,\n overrideAccess: true,\n req,\n })\n }\n\n if (entityType === 'collection') {\n return req.payload.findByID({\n id: id!,\n collection: entity.slug,\n depth: 0,\n fallbackLocale: null,\n locale,\n overrideAccess: true,\n req,\n trash: true,\n })\n }\n })()\n : undefined\n\n const isLoggedIn = !!user\n\n const fieldsPermissions: FieldsPermissions = {}\n\n const entityPermissions: ReturnType<TEntityType> = {\n fields: fieldsPermissions,\n } as ReturnType<TEntityType>\n\n const promises: Promise<void>[] = []\n\n // Phase 1: Resolve all access functions to get where queries\n const accessResults: {\n operation: keyof typeof entity.access\n result: Promise<boolean | Where>\n }[] = []\n\n for (const _operation of operations) {\n const operation = _operation as keyof typeof entity.access\n const accessFunction = entity.access[operation]\n\n if (\n (entityType === 'collection' && topLevelCollectionPermissions.includes(operation)) ||\n (entityType === 'global' && topLevelGlobalPermissions.includes(operation))\n ) {\n if (typeof accessFunction === 'function') {\n accessResults.push({\n operation,\n result: Promise.resolve(accessFunction({ id, data, req })) as Promise<boolean | Where>,\n })\n } else {\n entityPermissions[operation] = {\n permission: isLoggedIn,\n }\n }\n }\n }\n\n // Await all access functions in parallel\n const resolvedAccessResults = await Promise.all(\n accessResults.map(async (item) => ({\n operation: item.operation,\n result: await item.result,\n })),\n )\n\n // Phase 2: Process where queries with cache and resolve in parallel\n const whereQueryCache: WhereQueryCache = []\n const wherePromises: Promise<void>[] = []\n\n for (const { operation, result: accessResult } of resolvedAccessResults) {\n if (typeof accessResult === 'object') {\n processWhereQuery({\n id,\n slug: entity.slug,\n accessResult,\n entityPermissions,\n entityType,\n fetchData,\n locale,\n operation,\n req,\n wherePromises,\n whereQueryCache,\n })\n } else if (entityPermissions[operation]?.permission !== false) {\n entityPermissions[operation] = { permission: !!accessResult }\n }\n }\n\n // Await all where query DB calls in parallel\n await Promise.all(wherePromises)\n\n populateFieldPermissions({\n blockReferencesPermissions,\n collection: entityType === 'collection' ? (entity as SanitizedCollectionConfig) : null,\n data,\n fields: entity.fields,\n global: entityType === 'global' ? (entity as SanitizedGlobalConfig) : null,\n operations,\n parentPermissionsObject: entityPermissions,\n permissionsObject: fieldsPermissions,\n promises,\n req,\n })\n\n /**\n * Await all promises in parallel.\n * A promise can add more promises to the promises array (group of fields calls populateFieldPermissions again in their own promise), which will not be\n * awaited in the first run.\n * This is why we need to loop again to process the new promises, until there are no more promises left.\n */\n let iterations = 0\n while (promises.length > 0) {\n const currentPromises = promises.splice(0, promises.length)\n\n await Promise.all(currentPromises)\n\n iterations++\n if (iterations >= 100) {\n throw new Error('Infinite getEntityPermissions promise loop detected.')\n }\n }\n\n return entityPermissions\n}\n\nconst processWhereQuery = ({\n id,\n slug,\n accessResult,\n entityPermissions,\n entityType,\n fetchData,\n locale,\n operation,\n req,\n wherePromises,\n whereQueryCache,\n}: {\n accessResult: Where\n entityPermissions: CollectionPermission | GlobalPermission\n entityType: 'collection' | 'global'\n fetchData: boolean\n id?: DefaultDocumentIDType\n locale?: string\n operation: Extract<keyof (CollectionPermission | GlobalPermission), AllOperations>\n req: PayloadRequest\n slug: string\n wherePromises: Promise<void>[]\n whereQueryCache: WhereQueryCache\n}): void => {\n if (fetchData) {\n // Check cache for identical where query using deep comparison\n let cached = whereQueryCache.find((entry) => isDeepStrictEqual(entry.where, accessResult))\n\n if (!cached) {\n // Cache miss - start DB query (don't await)\n cached = {\n result: entityDocExists({\n id,\n slug,\n entityType,\n locale,\n operation,\n req,\n where: accessResult,\n }),\n where: accessResult,\n }\n whereQueryCache.push(cached)\n }\n\n // Defer resolution to Promise.all (cache hits reuse same promise)\n wherePromises.push(\n cached.result.then((hasPermission) => {\n entityPermissions[operation] = {\n permission: hasPermission,\n where: accessResult,\n } as Permission\n }),\n )\n } else {\n // TODO: 4.0: Investigate defaulting to `false` here, if where query is returned but ignored as we don't\n // have the document data available. This seems more secure.\n // Alternatively, we could set permission to a third state, like 'unknown'.\n // Even after calling sanitizePermissions, the permissions will still be true if the where query is returned but ignored as we don't have the document data available.\n entityPermissions[operation] = { permission: true, where: accessResult } as Permission\n }\n}\n"],"names":["isDeepStrictEqual","entityDocExists","populateFieldPermissions","topLevelCollectionPermissions","topLevelGlobalPermissions","getEntityPermissions","args","id","blockReferencesPermissions","data","_data","entity","entityType","fetchData","operations","req","locale","_locale","user","undefined","Error","hasData","Object","keys","length","payload","findGlobal","slug","depth","fallbackLocale","overrideAccess","findByID","collection","trash","isLoggedIn","fieldsPermissions","entityPermissions","fields","promises","accessResults","_operation","operation","accessFunction","access","includes","push","result","Promise","resolve","permission","resolvedAccessResults","all","map","item","whereQueryCache","wherePromises","accessResult","processWhereQuery","global","parentPermissionsObject","permissionsObject","iterations","currentPromises","splice","cached","find","entry","where","then","hasPermission"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import type { CollectionPermission, FieldPermissions, FieldsPermissions, GlobalPermission } from '../../auth/types.js';
2
+ import type { SanitizedCollectionConfig } from '../../collections/config/types.js';
3
+ import type { SanitizedGlobalConfig } from '../../globals/config/types.js';
2
4
  import type { DefaultDocumentIDType } from '../../index.js';
3
5
  import type { AllOperations, JsonObject, PayloadRequest } from '../../types/index.js';
4
6
  import type { BlockReferencesPermissions } from './getEntityPermissions.js';
@@ -7,10 +9,14 @@ import { type Field } from '../../fields/config/types.js';
7
9
  * Build up permissions object and run access functions for each field of an entity
8
10
  * This function is synchronous and collects all async work into the promises array
9
11
  */
10
- export declare const populateFieldPermissions: ({ id, blockReferencesPermissions, data, fields, operations, parentPermissionsObject, permissionsObject, promises, req, }: {
12
+ export declare const populateFieldPermissions: ({ id, blockReferencesPermissions, collection, data, fields, global, operations, parentPermissionsObject, permissionsObject, promises, req, }: {
11
13
  blockReferencesPermissions: BlockReferencesPermissions;
14
+ /** The collection which the fields belong to. If the fields belong to a global, this will be null. */
15
+ collection: null | SanitizedCollectionConfig;
12
16
  data: JsonObject | undefined;
13
17
  fields: Field[];
18
+ /** The global which the fields belong to. If the fields belong to a collection, this will be null. */
19
+ global: null | SanitizedGlobalConfig;
14
20
  id?: DefaultDocumentIDType;
15
21
  /**
16
22
  * Operations to check access for
@@ -1 +1 @@
1
- {"version":3,"file":"populateFieldPermissions.d.ts","sourceRoot":"","sources":["../../../src/utilities/getEntityPermissions/populateFieldPermissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAA;AAE3E,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,8BAA8B,CAAA;AAkCrE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,0HAUtC;IACD,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;IAC5B,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,EAAE,CAAC,EAAE,qBAAqB,CAAA;IAC1B;;OAEG;IACH,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,uBAAuB,EAAE,oBAAoB,GAAG,gBAAgB,GAAG,gBAAgB,CAAA;IACnF,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAA;IACzB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,IAmPH,CAAA"}
1
+ {"version":3,"file":"populateFieldPermissions.d.ts","sourceRoot":"","sources":["../../../src/utilities/getEntityPermissions/populateFieldPermissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAEjB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAA;AAC1E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAA;AAE3E,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,8BAA8B,CAAA;AAkCrE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,8IAYtC;IACD,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,sGAAsG;IACtG,UAAU,EAAE,IAAI,GAAG,yBAAyB,CAAA;IAC5C,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;IAC5B,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,sGAAsG;IACtG,MAAM,EAAE,IAAI,GAAG,qBAAqB,CAAA;IACpC,EAAE,CAAC,EAAE,qBAAqB,CAAA;IAC1B;;OAEG;IACH,UAAU,EAAE,aAAa,EAAE,CAAA;IAC3B,uBAAuB,EAAE,oBAAoB,GAAG,gBAAgB,GAAG,gBAAgB,CAAA;IACnF,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAA;IACzB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,IA2QH,CAAA"}
@@ -27,7 +27,7 @@ target, operation, value, promises)=>{
27
27
  /**
28
28
  * Build up permissions object and run access functions for each field of an entity
29
29
  * This function is synchronous and collects all async work into the promises array
30
- */ export const populateFieldPermissions = ({ id, blockReferencesPermissions, data, fields, operations, parentPermissionsObject, permissionsObject, promises, req })=>{
30
+ */ export const populateFieldPermissions = ({ id, blockReferencesPermissions, collection, data, fields, global, operations, parentPermissionsObject, permissionsObject, promises, req })=>{
31
31
  for (const field of fields){
32
32
  // Set up permissions for all operations
33
33
  for (const operation of operations){
@@ -42,11 +42,18 @@ target, operation, value, promises)=>{
42
42
  }
43
43
  const fieldPermissions = permissionsObject[field.name];
44
44
  if ('access' in field && field.access && typeof field.access[operation] === 'function') {
45
- const accessResult = field.access[operation]({
45
+ const accessResult = field.access[operation](collection ? {
46
46
  id,
47
+ collection,
47
48
  data,
48
49
  doc: data,
49
50
  req
51
+ } : {
52
+ id,
53
+ data,
54
+ doc: data,
55
+ global: global,
56
+ req
50
57
  });
51
58
  // Handle both sync and async access results
52
59
  if (isThenable(accessResult)) {
@@ -71,8 +78,10 @@ target, operation, value, promises)=>{
71
78
  populateFieldPermissions({
72
79
  id,
73
80
  blockReferencesPermissions,
81
+ collection,
74
82
  data,
75
83
  fields: field.fields,
84
+ global,
76
85
  operations,
77
86
  parentPermissionsObject: fieldPermissions,
78
87
  permissionsObject: fieldPermissions.fields,
@@ -145,8 +154,10 @@ target, operation, value, promises)=>{
145
154
  populateFieldPermissions({
146
155
  id,
147
156
  blockReferencesPermissions,
157
+ collection,
148
158
  data,
149
159
  fields: block.fields,
160
+ global,
150
161
  operations,
151
162
  parentPermissionsObject: blockPermission,
152
163
  permissionsObject: blockPermission.fields,
@@ -161,8 +172,10 @@ target, operation, value, promises)=>{
161
172
  // Field does not have a name => same parentPermissionsObject
162
173
  populateFieldPermissions({
163
174
  id,
175
+ collection,
164
176
  data,
165
177
  fields: field.fields,
178
+ global,
166
179
  operations,
167
180
  // Field does not have a name here => use parent permissions object
168
181
  blockReferencesPermissions,
@@ -205,8 +218,10 @@ target, operation, value, promises)=>{
205
218
  populateFieldPermissions({
206
219
  id,
207
220
  blockReferencesPermissions,
221
+ collection,
208
222
  data,
209
223
  fields: tab.fields,
224
+ global,
210
225
  operations,
211
226
  parentPermissionsObject: tabPermissions,
212
227
  permissionsObject: tabPermissions.fields,
@@ -217,8 +232,10 @@ target, operation, value, promises)=>{
217
232
  // Tab does not have a name => same parentPermissionsObject
218
233
  populateFieldPermissions({
219
234
  id,
235
+ collection,
220
236
  data,
221
237
  fields: tab.fields,
238
+ global,
222
239
  operations,
223
240
  // Tab does not have a name here => use parent permissions object
224
241
  blockReferencesPermissions,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utilities/getEntityPermissions/populateFieldPermissions.ts"],"sourcesContent":["import type {\n BlockPermissions,\n BlocksPermissions,\n CollectionPermission,\n FieldPermissions,\n FieldsPermissions,\n GlobalPermission,\n Permission,\n} from '../../auth/types.js'\nimport type { DefaultDocumentIDType } from '../../index.js'\nimport type { AllOperations, JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { BlockReferencesPermissions } from './getEntityPermissions.js'\n\nimport { type Field, tabHasName } from '../../fields/config/types.js'\n\nconst isThenable = (value: unknown): value is Promise<unknown> =>\n value != null && typeof (value as { then?: unknown }).then === 'function'\n\n/**\n * Helper to set a permission value that might be a promise.\n * If it's a promise, creates a chained promise that resolves to update the target,\n * stores the promise temporarily, and adds it to the promises array for later resolution.\n */\nconst setPermission = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n target: any,\n operation: AllOperations,\n value: boolean | Promise<boolean> | undefined,\n promises: Promise<void>[],\n): void => {\n if (isThenable(value)) {\n // Create a single permission object that will be mutated in place\n // This ensures all references (including cached blocks) see the resolved value\n const permissionObj = { permission: value as any }\n target[operation] = permissionObj\n\n const permissionPromise = value.then((result) => {\n // Mutate the permission property in place so all references see the update\n permissionObj.permission = result\n })\n\n promises.push(permissionPromise)\n } else {\n target[operation] = { permission: value }\n }\n}\n\n/**\n * Build up permissions object and run access functions for each field of an entity\n * This function is synchronous and collects all async work into the promises array\n */\nexport const populateFieldPermissions = ({\n id,\n blockReferencesPermissions,\n data,\n fields,\n operations,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n}: {\n blockReferencesPermissions: BlockReferencesPermissions\n data: JsonObject | undefined\n fields: Field[]\n id?: DefaultDocumentIDType\n /**\n * Operations to check access for\n */\n operations: AllOperations[]\n parentPermissionsObject: CollectionPermission | FieldPermissions | GlobalPermission\n permissionsObject: FieldsPermissions\n promises: Promise<void>[]\n req: PayloadRequest\n}): void => {\n for (const field of fields) {\n // Set up permissions for all operations\n for (const operation of operations) {\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n if ('name' in field && field.name) {\n if (!permissionsObject[field.name]) {\n permissionsObject[field.name] = {} as FieldPermissions\n }\n const fieldPermissions: FieldPermissions = permissionsObject[field.name]!\n\n if ('access' in field && field.access && typeof field.access[operation] === 'function') {\n const accessResult = field.access[operation]({\n id,\n data,\n doc: data,\n req,\n // We cannot include siblingData or blockData here, as we do not have siblingData/blockData available once we reach block or array\n // rows, as we're calculating schema permissions, which do not include individual rows.\n // For consistency, it's thus better to never include the siblingData and blockData\n })\n\n // Handle both sync and async access results\n if (isThenable(accessResult)) {\n const booleanPromise = accessResult.then((result) => Boolean(result))\n setPermission(fieldPermissions, operation, booleanPromise, promises)\n } else {\n setPermission(fieldPermissions, operation, Boolean(accessResult), promises)\n }\n } else {\n // Inherit from parent (which might be a promise)\n setPermission(fieldPermissions, operation, parentPermissionForOperation, promises)\n }\n }\n }\n\n // Handle named fields with nested content\n if ('name' in field && field.name) {\n const fieldPermissions: FieldPermissions = permissionsObject[field.name]!\n\n if ('fields' in field && field.fields) {\n if (!fieldPermissions.fields) {\n fieldPermissions.fields = {}\n }\n\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: field.fields,\n operations,\n parentPermissionsObject: fieldPermissions,\n permissionsObject: fieldPermissions.fields,\n promises,\n req,\n })\n }\n\n if ('blocks' in field && field.blocks?.length) {\n if (!fieldPermissions.blocks) {\n fieldPermissions.blocks = {}\n }\n const blocksPermissions: BlocksPermissions = fieldPermissions.blocks\n\n // Set up permissions for all operations for all blocks\n for (const operation of operations) {\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n for (const _block of field.blocks) {\n const block = typeof _block === 'string' ? req.payload.blocks[_block] : _block\n\n // Skip if block doesn't exist (invalid block reference)\n if (!block) {\n continue\n }\n\n // Handle block references - check if we've seen this block before\n if (typeof _block === 'string') {\n const blockReferencePermissions = blockReferencesPermissions[_block]\n if (blockReferencePermissions) {\n // Reference the cached permissions (may be a promise or resolved object)\n blocksPermissions[block.slug] = blockReferencePermissions as BlockPermissions\n continue\n }\n }\n\n // Initialize block permissions object if needed\n if (!blocksPermissions[block.slug]) {\n blocksPermissions[block.slug] = {} as BlockPermissions\n }\n\n const blockPermission = blocksPermissions[block.slug]!\n\n // Set permission for this operation\n if (!blockPermission[operation]) {\n const fieldPermission =\n fieldPermissions[operation]?.permission ?? parentPermissionForOperation\n\n // Inherit from field permission (which might be a promise)\n setPermission(blockPermission, operation, fieldPermission, promises)\n }\n }\n }\n\n // Process nested content for each unique block (once per block, not once per operation)\n const processedBlocks = new Set<string>()\n for (const _block of field.blocks) {\n const block = typeof _block === 'string' ? req.payload.blocks[_block] : _block\n\n // Skip if block doesn't exist (invalid block reference)\n if (!block || processedBlocks.has(block.slug)) {\n continue\n }\n processedBlocks.add(block.slug)\n\n const blockPermission = blocksPermissions[block.slug]\n if (!blockPermission) {\n continue\n }\n\n if (!blockPermission.fields) {\n blockPermission.fields = {}\n }\n\n // Handle block references with caching - store as promise that will be resolved later\n if (typeof _block === 'string' && !blockReferencesPermissions[_block]) {\n // Mark this block as being processed by storing a reference\n blockReferencesPermissions[_block] = blockPermission\n }\n\n // Recursively process block fields synchronously\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: block.fields,\n operations,\n parentPermissionsObject: blockPermission,\n permissionsObject: blockPermission.fields,\n promises,\n req,\n })\n }\n }\n }\n\n // Handle unnamed group fields\n if ('fields' in field && field.fields && !('name' in field && field.name)) {\n // Field does not have a name => same parentPermissionsObject\n populateFieldPermissions({\n id,\n data,\n fields: field.fields,\n operations,\n // Field does not have a name here => use parent permissions object\n blockReferencesPermissions,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n })\n }\n\n // Handle tabs fields\n if (field.type === 'tabs') {\n // Process tabs for all operations\n for (const operation of operations) {\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n for (const tab of field.tabs) {\n if (tabHasName(tab)) {\n if (!permissionsObject[tab.name]) {\n permissionsObject[tab.name] = { fields: {} } as FieldPermissions\n }\n\n const tabPermissions = permissionsObject[tab.name]!\n if (!tabPermissions[operation]) {\n // Inherit from parent (which might be a promise)\n setPermission(tabPermissions, operation, parentPermissionForOperation, promises)\n }\n }\n }\n }\n\n for (const tab of field.tabs) {\n if (tabHasName(tab)) {\n const tabPermissions: FieldPermissions = permissionsObject[tab.name]!\n\n if (!tabPermissions.fields) {\n tabPermissions.fields = {}\n }\n\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n data,\n fields: tab.fields,\n operations,\n parentPermissionsObject: tabPermissions,\n permissionsObject: tabPermissions.fields,\n promises,\n req,\n })\n } else {\n // Tab does not have a name => same parentPermissionsObject\n populateFieldPermissions({\n id,\n data,\n fields: tab.fields,\n operations,\n // Tab does not have a name here => use parent permissions object\n blockReferencesPermissions,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n })\n }\n }\n }\n }\n}\n"],"names":["tabHasName","isThenable","value","then","setPermission","target","operation","promises","permissionObj","permission","permissionPromise","result","push","populateFieldPermissions","id","blockReferencesPermissions","data","fields","operations","parentPermissionsObject","permissionsObject","req","field","parentPermissionForOperation","name","fieldPermissions","access","accessResult","doc","booleanPromise","Boolean","blocks","length","blocksPermissions","_block","block","payload","blockReferencePermissions","slug","blockPermission","fieldPermission","processedBlocks","Set","has","add","type","tab","tabs","tabPermissions"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/utilities/getEntityPermissions/populateFieldPermissions.ts"],"sourcesContent":["import type {\n BlockPermissions,\n BlocksPermissions,\n CollectionPermission,\n FieldPermissions,\n FieldsPermissions,\n GlobalPermission,\n Permission,\n} from '../../auth/types.js'\nimport type { SanitizedCollectionConfig } from '../../collections/config/types.js'\nimport type { SanitizedGlobalConfig } from '../../globals/config/types.js'\nimport type { DefaultDocumentIDType } from '../../index.js'\nimport type { AllOperations, JsonObject, PayloadRequest } from '../../types/index.js'\nimport type { BlockReferencesPermissions } from './getEntityPermissions.js'\n\nimport { type Field, tabHasName } from '../../fields/config/types.js'\n\nconst isThenable = (value: unknown): value is Promise<unknown> =>\n value != null && typeof (value as { then?: unknown }).then === 'function'\n\n/**\n * Helper to set a permission value that might be a promise.\n * If it's a promise, creates a chained promise that resolves to update the target,\n * stores the promise temporarily, and adds it to the promises array for later resolution.\n */\nconst setPermission = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n target: any,\n operation: AllOperations,\n value: boolean | Promise<boolean> | undefined,\n promises: Promise<void>[],\n): void => {\n if (isThenable(value)) {\n // Create a single permission object that will be mutated in place\n // This ensures all references (including cached blocks) see the resolved value\n const permissionObj = { permission: value as any }\n target[operation] = permissionObj\n\n const permissionPromise = value.then((result) => {\n // Mutate the permission property in place so all references see the update\n permissionObj.permission = result\n })\n\n promises.push(permissionPromise)\n } else {\n target[operation] = { permission: value }\n }\n}\n\n/**\n * Build up permissions object and run access functions for each field of an entity\n * This function is synchronous and collects all async work into the promises array\n */\nexport const populateFieldPermissions = ({\n id,\n blockReferencesPermissions,\n collection,\n data,\n fields,\n global,\n operations,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n}: {\n blockReferencesPermissions: BlockReferencesPermissions\n /** The collection which the fields belong to. If the fields belong to a global, this will be null. */\n collection: null | SanitizedCollectionConfig\n data: JsonObject | undefined\n fields: Field[]\n /** The global which the fields belong to. If the fields belong to a collection, this will be null. */\n global: null | SanitizedGlobalConfig\n id?: DefaultDocumentIDType\n /**\n * Operations to check access for\n */\n operations: AllOperations[]\n parentPermissionsObject: CollectionPermission | FieldPermissions | GlobalPermission\n permissionsObject: FieldsPermissions\n promises: Promise<void>[]\n req: PayloadRequest\n}): void => {\n for (const field of fields) {\n // Set up permissions for all operations\n for (const operation of operations) {\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n if ('name' in field && field.name) {\n if (!permissionsObject[field.name]) {\n permissionsObject[field.name] = {} as FieldPermissions\n }\n const fieldPermissions: FieldPermissions = permissionsObject[field.name]!\n\n if ('access' in field && field.access && typeof field.access[operation] === 'function') {\n const accessResult = field.access[operation](\n collection\n ? {\n id,\n collection,\n data,\n doc: data,\n req,\n // We cannot include siblingData or blockData here, as we do not have siblingData/blockData available once we reach block or array\n // rows, as we're calculating schema permissions, which do not include individual rows.\n // For consistency, it's thus better to never include the siblingData and blockData\n }\n : {\n id,\n data,\n doc: data,\n global: global!,\n req,\n // We cannot include siblingData or blockData here, as we do not have siblingData/blockData available once we reach block or array\n // rows, as we're calculating schema permissions, which do not include individual rows.\n // For consistency, it's thus better to never include the siblingData and blockData\n },\n )\n\n // Handle both sync and async access results\n if (isThenable(accessResult)) {\n const booleanPromise = accessResult.then((result) => Boolean(result))\n setPermission(fieldPermissions, operation, booleanPromise, promises)\n } else {\n setPermission(fieldPermissions, operation, Boolean(accessResult), promises)\n }\n } else {\n // Inherit from parent (which might be a promise)\n setPermission(fieldPermissions, operation, parentPermissionForOperation, promises)\n }\n }\n }\n\n // Handle named fields with nested content\n if ('name' in field && field.name) {\n const fieldPermissions: FieldPermissions = permissionsObject[field.name]!\n\n if ('fields' in field && field.fields) {\n if (!fieldPermissions.fields) {\n fieldPermissions.fields = {}\n }\n\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n collection,\n data,\n fields: field.fields,\n global,\n operations,\n parentPermissionsObject: fieldPermissions,\n permissionsObject: fieldPermissions.fields,\n promises,\n req,\n })\n }\n\n if ('blocks' in field && field.blocks?.length) {\n if (!fieldPermissions.blocks) {\n fieldPermissions.blocks = {}\n }\n const blocksPermissions: BlocksPermissions = fieldPermissions.blocks\n\n // Set up permissions for all operations for all blocks\n for (const operation of operations) {\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n for (const _block of field.blocks) {\n const block = typeof _block === 'string' ? req.payload.blocks[_block] : _block\n\n // Skip if block doesn't exist (invalid block reference)\n if (!block) {\n continue\n }\n\n // Handle block references - check if we've seen this block before\n if (typeof _block === 'string') {\n const blockReferencePermissions = blockReferencesPermissions[_block]\n if (blockReferencePermissions) {\n // Reference the cached permissions (may be a promise or resolved object)\n blocksPermissions[block.slug] = blockReferencePermissions as BlockPermissions\n continue\n }\n }\n\n // Initialize block permissions object if needed\n if (!blocksPermissions[block.slug]) {\n blocksPermissions[block.slug] = {} as BlockPermissions\n }\n\n const blockPermission = blocksPermissions[block.slug]!\n\n // Set permission for this operation\n if (!blockPermission[operation]) {\n const fieldPermission =\n fieldPermissions[operation]?.permission ?? parentPermissionForOperation\n\n // Inherit from field permission (which might be a promise)\n setPermission(blockPermission, operation, fieldPermission, promises)\n }\n }\n }\n\n // Process nested content for each unique block (once per block, not once per operation)\n const processedBlocks = new Set<string>()\n for (const _block of field.blocks) {\n const block = typeof _block === 'string' ? req.payload.blocks[_block] : _block\n\n // Skip if block doesn't exist (invalid block reference)\n if (!block || processedBlocks.has(block.slug)) {\n continue\n }\n processedBlocks.add(block.slug)\n\n const blockPermission = blocksPermissions[block.slug]\n if (!blockPermission) {\n continue\n }\n\n if (!blockPermission.fields) {\n blockPermission.fields = {}\n }\n\n // Handle block references with caching - store as promise that will be resolved later\n if (typeof _block === 'string' && !blockReferencesPermissions[_block]) {\n // Mark this block as being processed by storing a reference\n blockReferencesPermissions[_block] = blockPermission\n }\n\n // Recursively process block fields synchronously\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n collection,\n data,\n fields: block.fields,\n global,\n operations,\n parentPermissionsObject: blockPermission,\n permissionsObject: blockPermission.fields,\n promises,\n req,\n })\n }\n }\n }\n\n // Handle unnamed group fields\n if ('fields' in field && field.fields && !('name' in field && field.name)) {\n // Field does not have a name => same parentPermissionsObject\n populateFieldPermissions({\n id,\n collection,\n data,\n fields: field.fields,\n global,\n operations,\n // Field does not have a name here => use parent permissions object\n blockReferencesPermissions,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n })\n }\n\n // Handle tabs fields\n if (field.type === 'tabs') {\n // Process tabs for all operations\n for (const operation of operations) {\n // Fields don't have all operations of a collection\n if (operation === 'delete' || operation === 'readVersions' || operation === 'unlock') {\n continue\n }\n\n const parentPermissionForOperation = (\n parentPermissionsObject[operation as keyof typeof parentPermissionsObject] as Permission\n )?.permission\n\n for (const tab of field.tabs) {\n if (tabHasName(tab)) {\n if (!permissionsObject[tab.name]) {\n permissionsObject[tab.name] = { fields: {} } as FieldPermissions\n }\n\n const tabPermissions = permissionsObject[tab.name]!\n if (!tabPermissions[operation]) {\n // Inherit from parent (which might be a promise)\n setPermission(tabPermissions, operation, parentPermissionForOperation, promises)\n }\n }\n }\n }\n\n for (const tab of field.tabs) {\n if (tabHasName(tab)) {\n const tabPermissions: FieldPermissions = permissionsObject[tab.name]!\n\n if (!tabPermissions.fields) {\n tabPermissions.fields = {}\n }\n\n populateFieldPermissions({\n id,\n blockReferencesPermissions,\n collection,\n data,\n fields: tab.fields,\n global,\n operations,\n parentPermissionsObject: tabPermissions,\n permissionsObject: tabPermissions.fields,\n promises,\n req,\n })\n } else {\n // Tab does not have a name => same parentPermissionsObject\n populateFieldPermissions({\n id,\n collection,\n data,\n fields: tab.fields,\n global,\n operations,\n // Tab does not have a name here => use parent permissions object\n blockReferencesPermissions,\n parentPermissionsObject,\n permissionsObject,\n promises,\n req,\n })\n }\n }\n }\n }\n}\n"],"names":["tabHasName","isThenable","value","then","setPermission","target","operation","promises","permissionObj","permission","permissionPromise","result","push","populateFieldPermissions","id","blockReferencesPermissions","collection","data","fields","global","operations","parentPermissionsObject","permissionsObject","req","field","parentPermissionForOperation","name","fieldPermissions","access","accessResult","doc","booleanPromise","Boolean","blocks","length","blocksPermissions","_block","block","payload","blockReferencePermissions","slug","blockPermission","fieldPermission","processedBlocks","Set","has","add","type","tab","tabs","tabPermissions"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"isURLAllowed.d.ts","sourceRoot":"","sources":["../../src/utilities/isURLAllowed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAEpD,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,EAAE,WAAW,SAAS,KAAG,OAgChE,CAAA"}
1
+ {"version":3,"file":"isURLAllowed.d.ts","sourceRoot":"","sources":["../../src/utilities/isURLAllowed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAIpD,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,EAAE,WAAW,SAAS,KAAG,OAqChE,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { escapeRegExp } from './escapeRegExp.js';
1
2
  export const isURLAllowed = (url, allowList)=>{
2
3
  try {
3
4
  const parsedUrl = new URL(url);
@@ -12,9 +13,14 @@ export const isURLAllowed = (url, allowList)=>{
12
13
  return typeof value === 'string' && parsedUrl.protocol === `${value}:`;
13
14
  }
14
15
  if (key === 'pathname') {
15
- // Convert wildcards to a regex
16
- const regexPattern = value.replace(/\*\*/g, '.*') // Match any path
17
- .replace(/\*/g, '[^/]*') // Match any part of a path segment
16
+ // Translate a small glob syntax to a regex. The pattern is escaped
17
+ // first so that metacharacters in the configured value (e.g. `.`)
18
+ // match literally and cannot broaden what the allow-list accepts.
19
+ // Wildcards become `\*` once escaped, so they are restored afterwards
20
+ // — translating `**` before `*` is safe because the resulting `.*`
21
+ // no longer contains an escaped `\*` for the next replace to match.
22
+ const regexPattern = escapeRegExp(value).replace(/\\\*\\\*/g, '.*') // `**` → match any path
23
+ .replace(/\\\*/g, '[^/]*') // `*` → match any part of a path segment
18
24
  .replace(/\/$/, '(/)?') // Allow optional trailing slash
19
25
  ;
20
26
  const regex = new RegExp(`^${regexPattern}$`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utilities/isURLAllowed.ts"],"sourcesContent":["import type { AllowList } from '../uploads/types.js'\n\nexport const isURLAllowed = (url: string, allowList: AllowList): boolean => {\n try {\n const parsedUrl = new URL(url)\n\n return allowList.some((allowItem) => {\n return Object.entries(allowItem).every(([key, value]) => {\n // Skip undefined or null values\n if (!value) {\n return true\n }\n // Compare protocol with colon\n if (key === 'protocol') {\n return typeof value === 'string' && parsedUrl.protocol === `${value}:`\n }\n\n if (key === 'pathname') {\n // Convert wildcards to a regex\n const regexPattern = value\n .replace(/\\*\\*/g, '.*') // Match any path\n .replace(/\\*/g, '[^/]*') // Match any part of a path segment\n .replace(/\\/$/, '(/)?') // Allow optional trailing slash\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(parsedUrl.pathname)\n }\n\n // Default comparison for all other properties (hostname, port, search)\n return parsedUrl[key as keyof URL] === value\n })\n })\n } catch {\n return false // If the URL is invalid, deny by default\n }\n}\n"],"names":["isURLAllowed","url","allowList","parsedUrl","URL","some","allowItem","Object","entries","every","key","value","protocol","regexPattern","replace","regex","RegExp","test","pathname"],"mappings":"AAEA,OAAO,MAAMA,eAAe,CAACC,KAAaC;IACxC,IAAI;QACF,MAAMC,YAAY,IAAIC,IAAIH;QAE1B,OAAOC,UAAUG,IAAI,CAAC,CAACC;YACrB,OAAOC,OAAOC,OAAO,CAACF,WAAWG,KAAK,CAAC,CAAC,CAACC,KAAKC,MAAM;gBAClD,gCAAgC;gBAChC,IAAI,CAACA,OAAO;oBACV,OAAO;gBACT;gBACA,8BAA8B;gBAC9B,IAAID,QAAQ,YAAY;oBACtB,OAAO,OAAOC,UAAU,YAAYR,UAAUS,QAAQ,KAAK,GAAGD,MAAM,CAAC,CAAC;gBACxE;gBAEA,IAAID,QAAQ,YAAY;oBACtB,+BAA+B;oBAC/B,MAAMG,eAAeF,MAClBG,OAAO,CAAC,SAAS,MAAM,iBAAiB;qBACxCA,OAAO,CAAC,OAAO,SAAS,mCAAmC;qBAC3DA,OAAO,CAAC,OAAO,QAAQ,gCAAgC;;oBAC1D,MAAMC,QAAQ,IAAIC,OAAO,CAAC,CAAC,EAAEH,aAAa,CAAC,CAAC;oBAC5C,OAAOE,MAAME,IAAI,CAACd,UAAUe,QAAQ;gBACtC;gBAEA,uEAAuE;gBACvE,OAAOf,SAAS,CAACO,IAAiB,KAAKC;YACzC;QACF;IACF,EAAE,OAAM;QACN,OAAO,MAAM,yCAAyC;;IACxD;AACF,EAAC"}
1
+ {"version":3,"sources":["../../src/utilities/isURLAllowed.ts"],"sourcesContent":["import type { AllowList } from '../uploads/types.js'\n\nimport { escapeRegExp } from './escapeRegExp.js'\n\nexport const isURLAllowed = (url: string, allowList: AllowList): boolean => {\n try {\n const parsedUrl = new URL(url)\n\n return allowList.some((allowItem) => {\n return Object.entries(allowItem).every(([key, value]) => {\n // Skip undefined or null values\n if (!value) {\n return true\n }\n // Compare protocol with colon\n if (key === 'protocol') {\n return typeof value === 'string' && parsedUrl.protocol === `${value}:`\n }\n\n if (key === 'pathname') {\n // Translate a small glob syntax to a regex. The pattern is escaped\n // first so that metacharacters in the configured value (e.g. `.`)\n // match literally and cannot broaden what the allow-list accepts.\n // Wildcards become `\\*` once escaped, so they are restored afterwards\n // — translating `**` before `*` is safe because the resulting `.*`\n // no longer contains an escaped `\\*` for the next replace to match.\n const regexPattern = escapeRegExp(value)\n .replace(/\\\\\\*\\\\\\*/g, '.*') // `**` → match any path\n .replace(/\\\\\\*/g, '[^/]*') // `*` → match any part of a path segment\n .replace(/\\/$/, '(/)?') // Allow optional trailing slash\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(parsedUrl.pathname)\n }\n\n // Default comparison for all other properties (hostname, port, search)\n return parsedUrl[key as keyof URL] === value\n })\n })\n } catch {\n return false // If the URL is invalid, deny by default\n }\n}\n"],"names":["escapeRegExp","isURLAllowed","url","allowList","parsedUrl","URL","some","allowItem","Object","entries","every","key","value","protocol","regexPattern","replace","regex","RegExp","test","pathname"],"mappings":"AAEA,SAASA,YAAY,QAAQ,oBAAmB;AAEhD,OAAO,MAAMC,eAAe,CAACC,KAAaC;IACxC,IAAI;QACF,MAAMC,YAAY,IAAIC,IAAIH;QAE1B,OAAOC,UAAUG,IAAI,CAAC,CAACC;YACrB,OAAOC,OAAOC,OAAO,CAACF,WAAWG,KAAK,CAAC,CAAC,CAACC,KAAKC,MAAM;gBAClD,gCAAgC;gBAChC,IAAI,CAACA,OAAO;oBACV,OAAO;gBACT;gBACA,8BAA8B;gBAC9B,IAAID,QAAQ,YAAY;oBACtB,OAAO,OAAOC,UAAU,YAAYR,UAAUS,QAAQ,KAAK,GAAGD,MAAM,CAAC,CAAC;gBACxE;gBAEA,IAAID,QAAQ,YAAY;oBACtB,mEAAmE;oBACnE,kEAAkE;oBAClE,kEAAkE;oBAClE,sEAAsE;oBACtE,mEAAmE;oBACnE,oEAAoE;oBACpE,MAAMG,eAAed,aAAaY,OAC/BG,OAAO,CAAC,aAAa,MAAM,wBAAwB;qBACnDA,OAAO,CAAC,SAAS,SAAS,yCAAyC;qBACnEA,OAAO,CAAC,OAAO,QAAQ,gCAAgC;;oBAC1D,MAAMC,QAAQ,IAAIC,OAAO,CAAC,CAAC,EAAEH,aAAa,CAAC,CAAC;oBAC5C,OAAOE,MAAME,IAAI,CAACd,UAAUe,QAAQ;gBACtC;gBAEA,uEAAuE;gBACvE,OAAOf,SAAS,CAACO,IAAiB,KAAKC;YACzC;QACF;IACF,EAAE,OAAM;QACN,OAAO,MAAM,yCAAyC;;IACxD;AACF,EAAC"}
@@ -0,0 +1,78 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { isURLAllowed } from './isURLAllowed.js';
3
+ describe('isURLAllowed', ()=>{
4
+ describe('hostname matching', ()=>{
5
+ const allowList = [
6
+ {
7
+ hostname: 'cdn.example.com'
8
+ }
9
+ ];
10
+ it('should allow an exactly matching hostname', ()=>{
11
+ expect(isURLAllowed('https://cdn.example.com/file.png', allowList)).toBe(true);
12
+ });
13
+ it('should deny a different hostname', ()=>{
14
+ expect(isURLAllowed('https://attacker.com/file.png', allowList)).toBe(false);
15
+ });
16
+ it('should deny a userinfo `@` trick (hostname is the real authority)', ()=>{
17
+ expect(isURLAllowed('https://cdn.example.com@attacker.com/file.png', allowList)).toBe(false);
18
+ });
19
+ it('should deny an invalid URL', ()=>{
20
+ expect(isURLAllowed('not a url', allowList)).toBe(false);
21
+ });
22
+ });
23
+ describe('pathname matching', ()=>{
24
+ it('should treat a literal dot as a literal, not a wildcard', ()=>{
25
+ const allowList = [
26
+ {
27
+ hostname: 'cdn.example.com',
28
+ pathname: '/files/report.json'
29
+ }
30
+ ];
31
+ expect(isURLAllowed('https://cdn.example.com/files/report.json', allowList)).toBe(true);
32
+ // Previously the unescaped `.` matched any character, widening the allow-list.
33
+ expect(isURLAllowed('https://cdn.example.com/files/reportXjson', allowList)).toBe(false);
34
+ });
35
+ it('should not let other regex metacharacters broaden the match', ()=>{
36
+ const allowList = [
37
+ {
38
+ hostname: 'cdn.example.com',
39
+ pathname: '/a+b/(c)'
40
+ }
41
+ ];
42
+ expect(isURLAllowed('https://cdn.example.com/a+b/(c)', allowList)).toBe(true);
43
+ expect(isURLAllowed('https://cdn.example.com/aaab/c', allowList)).toBe(false);
44
+ });
45
+ it('should match a single segment with `*` but not across slashes', ()=>{
46
+ const allowList = [
47
+ {
48
+ hostname: 'cdn.example.com',
49
+ pathname: '/uploads/*'
50
+ }
51
+ ];
52
+ expect(isURLAllowed('https://cdn.example.com/uploads/photo.png', allowList)).toBe(true);
53
+ expect(isURLAllowed('https://cdn.example.com/uploads/nested/photo.png', allowList)).toBe(false);
54
+ });
55
+ it('should match across slashes with `**`', ()=>{
56
+ const allowList = [
57
+ {
58
+ hostname: 'cdn.example.com',
59
+ pathname: '/uploads/**'
60
+ }
61
+ ];
62
+ expect(isURLAllowed('https://cdn.example.com/uploads/photo.png', allowList)).toBe(true);
63
+ expect(isURLAllowed('https://cdn.example.com/uploads/nested/photo.png', allowList)).toBe(true);
64
+ });
65
+ it('should allow an optional trailing slash', ()=>{
66
+ const allowList = [
67
+ {
68
+ hostname: 'cdn.example.com',
69
+ pathname: '/assets/'
70
+ }
71
+ ];
72
+ expect(isURLAllowed('https://cdn.example.com/assets', allowList)).toBe(true);
73
+ expect(isURLAllowed('https://cdn.example.com/assets/', allowList)).toBe(true);
74
+ });
75
+ });
76
+ });
77
+
78
+ //# sourceMappingURL=isURLAllowed.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utilities/isURLAllowed.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport type { AllowList } from '../uploads/types.js'\n\nimport { isURLAllowed } from './isURLAllowed.js'\n\ndescribe('isURLAllowed', () => {\n describe('hostname matching', () => {\n const allowList: AllowList = [{ hostname: 'cdn.example.com' }]\n\n it('should allow an exactly matching hostname', () => {\n expect(isURLAllowed('https://cdn.example.com/file.png', allowList)).toBe(true)\n })\n\n it('should deny a different hostname', () => {\n expect(isURLAllowed('https://attacker.com/file.png', allowList)).toBe(false)\n })\n\n it('should deny a userinfo `@` trick (hostname is the real authority)', () => {\n expect(isURLAllowed('https://cdn.example.com@attacker.com/file.png', allowList)).toBe(false)\n })\n\n it('should deny an invalid URL', () => {\n expect(isURLAllowed('not a url', allowList)).toBe(false)\n })\n })\n\n describe('pathname matching', () => {\n it('should treat a literal dot as a literal, not a wildcard', () => {\n const allowList: AllowList = [{ hostname: 'cdn.example.com', pathname: '/files/report.json' }]\n\n expect(isURLAllowed('https://cdn.example.com/files/report.json', allowList)).toBe(true)\n // Previously the unescaped `.` matched any character, widening the allow-list.\n expect(isURLAllowed('https://cdn.example.com/files/reportXjson', allowList)).toBe(false)\n })\n\n it('should not let other regex metacharacters broaden the match', () => {\n const allowList: AllowList = [{ hostname: 'cdn.example.com', pathname: '/a+b/(c)' }]\n\n expect(isURLAllowed('https://cdn.example.com/a+b/(c)', allowList)).toBe(true)\n expect(isURLAllowed('https://cdn.example.com/aaab/c', allowList)).toBe(false)\n })\n\n it('should match a single segment with `*` but not across slashes', () => {\n const allowList: AllowList = [{ hostname: 'cdn.example.com', pathname: '/uploads/*' }]\n\n expect(isURLAllowed('https://cdn.example.com/uploads/photo.png', allowList)).toBe(true)\n expect(isURLAllowed('https://cdn.example.com/uploads/nested/photo.png', allowList)).toBe(\n false,\n )\n })\n\n it('should match across slashes with `**`', () => {\n const allowList: AllowList = [{ hostname: 'cdn.example.com', pathname: '/uploads/**' }]\n\n expect(isURLAllowed('https://cdn.example.com/uploads/photo.png', allowList)).toBe(true)\n expect(isURLAllowed('https://cdn.example.com/uploads/nested/photo.png', allowList)).toBe(true)\n })\n\n it('should allow an optional trailing slash', () => {\n const allowList: AllowList = [{ hostname: 'cdn.example.com', pathname: '/assets/' }]\n\n expect(isURLAllowed('https://cdn.example.com/assets', allowList)).toBe(true)\n expect(isURLAllowed('https://cdn.example.com/assets/', allowList)).toBe(true)\n })\n })\n})\n"],"names":["describe","expect","it","isURLAllowed","allowList","hostname","toBe","pathname"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAI7C,SAASC,YAAY,QAAQ,oBAAmB;AAEhDH,SAAS,gBAAgB;IACvBA,SAAS,qBAAqB;QAC5B,MAAMI,YAAuB;YAAC;gBAAEC,UAAU;YAAkB;SAAE;QAE9DH,GAAG,6CAA6C;YAC9CD,OAAOE,aAAa,oCAAoCC,YAAYE,IAAI,CAAC;QAC3E;QAEAJ,GAAG,oCAAoC;YACrCD,OAAOE,aAAa,iCAAiCC,YAAYE,IAAI,CAAC;QACxE;QAEAJ,GAAG,qEAAqE;YACtED,OAAOE,aAAa,iDAAiDC,YAAYE,IAAI,CAAC;QACxF;QAEAJ,GAAG,8BAA8B;YAC/BD,OAAOE,aAAa,aAAaC,YAAYE,IAAI,CAAC;QACpD;IACF;IAEAN,SAAS,qBAAqB;QAC5BE,GAAG,2DAA2D;YAC5D,MAAME,YAAuB;gBAAC;oBAAEC,UAAU;oBAAmBE,UAAU;gBAAqB;aAAE;YAE9FN,OAAOE,aAAa,6CAA6CC,YAAYE,IAAI,CAAC;YAClF,+EAA+E;YAC/EL,OAAOE,aAAa,6CAA6CC,YAAYE,IAAI,CAAC;QACpF;QAEAJ,GAAG,+DAA+D;YAChE,MAAME,YAAuB;gBAAC;oBAAEC,UAAU;oBAAmBE,UAAU;gBAAW;aAAE;YAEpFN,OAAOE,aAAa,mCAAmCC,YAAYE,IAAI,CAAC;YACxEL,OAAOE,aAAa,kCAAkCC,YAAYE,IAAI,CAAC;QACzE;QAEAJ,GAAG,iEAAiE;YAClE,MAAME,YAAuB;gBAAC;oBAAEC,UAAU;oBAAmBE,UAAU;gBAAa;aAAE;YAEtFN,OAAOE,aAAa,6CAA6CC,YAAYE,IAAI,CAAC;YAClFL,OAAOE,aAAa,oDAAoDC,YAAYE,IAAI,CACtF;QAEJ;QAEAJ,GAAG,yCAAyC;YAC1C,MAAME,YAAuB;gBAAC;oBAAEC,UAAU;oBAAmBE,UAAU;gBAAc;aAAE;YAEvFN,OAAOE,aAAa,6CAA6CC,YAAYE,IAAI,CAAC;YAClFL,OAAOE,aAAa,oDAAoDC,YAAYE,IAAI,CAAC;QAC3F;QAEAJ,GAAG,2CAA2C;YAC5C,MAAME,YAAuB;gBAAC;oBAAEC,UAAU;oBAAmBE,UAAU;gBAAW;aAAE;YAEpFN,OAAOE,aAAa,kCAAkCC,YAAYE,IAAI,CAAC;YACvEL,OAAOE,aAAa,mCAAmCC,YAAYE,IAAI,CAAC;QAC1E;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"envPaths.d.ts","sourceRoot":"","sources":["../../../../src/utilities/telemetry/conf/envPaths.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AAMH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAiB,EAAE;;CAAK;;;;;;EAgDhE"}
1
+ {"version":3,"file":"envPaths.d.ts","sourceRoot":"","sources":["../../../../src/utilities/telemetry/conf/envPaths.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AAkDH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAiB,EAAE;;CAAK;;;;;;EAmBhE"}
@@ -14,6 +14,43 @@
14
14
  */ import os from 'node:os';
15
15
  import path from 'node:path';
16
16
  import process from 'node:process';
17
+ const homedir = os.homedir();
18
+ const tmpdir = os.tmpdir();
19
+ const { env } = process;
20
+ const macos = (name)=>{
21
+ const library = path.join(homedir, 'Library');
22
+ return {
23
+ cache: path.join(library, 'Caches', name),
24
+ config: path.join(library, 'Preferences', name),
25
+ data: path.join(library, 'Application Support', name),
26
+ log: path.join(library, 'Logs', name),
27
+ temp: path.join(tmpdir, name)
28
+ };
29
+ };
30
+ const windows = (name)=>{
31
+ const appData = env.APPDATA || path.join(homedir, 'AppData', 'Roaming');
32
+ const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
33
+ return {
34
+ // Data/config/cache/log are invented by me as Windows isn't opinionated about this
35
+ cache: path.join(localAppData, name, 'Cache'),
36
+ config: path.join(appData, name, 'Config'),
37
+ data: path.join(localAppData, name, 'Data'),
38
+ log: path.join(localAppData, name, 'Log'),
39
+ temp: path.join(tmpdir, name)
40
+ };
41
+ };
42
+ // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
43
+ const linux = (name)=>{
44
+ const username = path.basename(homedir);
45
+ return {
46
+ cache: path.join(env.XDG_CACHE_HOME || path.join(homedir, '.cache'), name),
47
+ config: path.join(env.XDG_CONFIG_HOME || path.join(homedir, '.config'), name),
48
+ data: path.join(env.XDG_DATA_HOME || path.join(homedir, '.local', 'share'), name),
49
+ // https://wiki.debian.org/XDGBaseDirectorySpecification#state
50
+ log: path.join(env.XDG_STATE_HOME || path.join(homedir, '.local', 'state'), name),
51
+ temp: path.join(tmpdir, username, name)
52
+ };
53
+ };
17
54
  export function envPaths(name, { suffix = 'nodejs' } = {}) {
18
55
  if (typeof name !== 'string') {
19
56
  throw new TypeError(`Expected a string, got ${typeof name}`);
@@ -22,41 +59,13 @@ export function envPaths(name, { suffix = 'nodejs' } = {}) {
22
59
  // Add suffix to prevent possible conflict with native apps
23
60
  name += `-${suffix}`;
24
61
  }
25
- const homedir = os.homedir();
26
- const tmpdir = os.tmpdir();
27
- const { env } = process;
28
62
  if (process.platform === 'darwin') {
29
- const library = path.join(homedir, 'Library');
30
- return {
31
- cache: path.join(library, 'Caches', name),
32
- config: path.join(library, 'Preferences', name),
33
- data: path.join(library, 'Application Support', name),
34
- log: path.join(library, 'Logs', name),
35
- temp: path.join(tmpdir, name)
36
- };
63
+ return macos(name);
37
64
  }
38
65
  if (process.platform === 'win32') {
39
- const appData = env.APPDATA || path.join(homedir, 'AppData', 'Roaming');
40
- const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
41
- return {
42
- // Data/config/cache/log are invented by me as Windows isn't opinionated about this
43
- cache: path.join(localAppData, name, 'Cache'),
44
- config: path.join(appData, name, 'Config'),
45
- data: path.join(localAppData, name, 'Data'),
46
- log: path.join(localAppData, name, 'Log'),
47
- temp: path.join(tmpdir, name)
48
- };
66
+ return windows(name);
49
67
  }
50
- // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
51
- const username = path.basename(homedir);
52
- return {
53
- cache: path.join(env.XDG_CACHE_HOME || path.join(homedir, '.cache'), name),
54
- config: path.join(env.XDG_CONFIG_HOME || path.join(homedir, '.config'), name),
55
- data: path.join(env.XDG_DATA_HOME || path.join(homedir, '.local', 'share'), name),
56
- // https://wiki.debian.org/XDGBaseDirectorySpecification#state
57
- log: path.join(env.XDG_STATE_HOME || path.join(homedir, '.local', 'state'), name),
58
- temp: path.join(tmpdir, username, name)
59
- };
68
+ return linux(name);
60
69
  }
61
70
 
62
71
  //# sourceMappingURL=envPaths.js.map