payload 3.80.0-internal-debug.cd99b1f → 3.80.0-internal.21e9c47

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 (259) hide show
  1. package/dist/admin/elements/Nav.d.ts +10 -0
  2. package/dist/admin/elements/Nav.d.ts.map +1 -1
  3. package/dist/admin/elements/Nav.js.map +1 -1
  4. package/dist/admin/functions/index.d.ts +1 -38
  5. package/dist/admin/functions/index.d.ts.map +1 -1
  6. package/dist/admin/functions/index.js.map +1 -1
  7. package/dist/admin/types.d.ts +5 -4
  8. package/dist/admin/types.d.ts.map +1 -1
  9. package/dist/admin/types.js.map +1 -1
  10. package/dist/admin/views/hierarchyList.d.ts +9 -0
  11. package/dist/admin/views/hierarchyList.d.ts.map +1 -0
  12. package/dist/admin/views/hierarchyList.js +3 -0
  13. package/dist/admin/views/hierarchyList.js.map +1 -0
  14. package/dist/admin/views/index.d.ts +1 -3
  15. package/dist/admin/views/index.d.ts.map +1 -1
  16. package/dist/admin/views/index.js.map +1 -1
  17. package/dist/admin/views/list.d.ts +37 -1
  18. package/dist/admin/views/list.d.ts.map +1 -1
  19. package/dist/admin/views/list.js.map +1 -1
  20. package/dist/auth/operations/me.js +5 -5
  21. package/dist/auth/operations/me.js.map +1 -1
  22. package/dist/bin/generateImportMap/iterateCollections.d.ts.map +1 -1
  23. package/dist/bin/generateImportMap/iterateCollections.js +1 -0
  24. package/dist/bin/generateImportMap/iterateCollections.js.map +1 -1
  25. package/dist/bin/generateImportMap/iterateConfig.d.ts.map +1 -1
  26. package/dist/bin/generateImportMap/iterateConfig.js +7 -0
  27. package/dist/bin/generateImportMap/iterateConfig.js.map +1 -1
  28. package/dist/collections/config/client.d.ts +3 -1
  29. package/dist/collections/config/client.d.ts.map +1 -1
  30. package/dist/collections/config/client.js +11 -0
  31. package/dist/collections/config/client.js.map +1 -1
  32. package/dist/collections/config/defaults.js +1 -1
  33. package/dist/collections/config/defaults.js.map +1 -1
  34. package/dist/collections/config/sanitize.d.ts.map +1 -1
  35. package/dist/collections/config/sanitize.js +3 -7
  36. package/dist/collections/config/sanitize.js.map +1 -1
  37. package/dist/collections/config/types.d.ts +29 -7
  38. package/dist/collections/config/types.d.ts.map +1 -1
  39. package/dist/collections/config/types.js.map +1 -1
  40. package/dist/collections/operations/create.js +17 -17
  41. package/dist/collections/operations/create.js.map +1 -1
  42. package/dist/collections/operations/findByID.js +3 -3
  43. package/dist/collections/operations/findByID.js.map +1 -1
  44. package/dist/collections/operations/utilities/update.d.ts.map +1 -1
  45. package/dist/collections/operations/utilities/update.js +5 -4
  46. package/dist/collections/operations/utilities/update.js.map +1 -1
  47. package/dist/config/client.d.ts.map +1 -1
  48. package/dist/config/client.js +0 -10
  49. package/dist/config/client.js.map +1 -1
  50. package/dist/config/defaults.d.ts.map +1 -1
  51. package/dist/config/defaults.js +0 -15
  52. package/dist/config/defaults.js.map +1 -1
  53. package/dist/config/sanitize.d.ts.map +1 -1
  54. package/dist/config/sanitize.js +3 -26
  55. package/dist/config/sanitize.js.map +1 -1
  56. package/dist/config/types.d.ts +26 -12
  57. package/dist/config/types.d.ts.map +1 -1
  58. package/dist/config/types.js.map +1 -1
  59. package/dist/exports/shared.d.ts +2 -3
  60. package/dist/exports/shared.d.ts.map +1 -1
  61. package/dist/exports/shared.js +1 -2
  62. package/dist/exports/shared.js.map +1 -1
  63. package/dist/fields/config/sanitize.d.ts.map +1 -1
  64. package/dist/fields/config/sanitize.js +4 -0
  65. package/dist/fields/config/sanitize.js.map +1 -1
  66. package/dist/fields/config/sanitizeJoinField.d.ts.map +1 -1
  67. package/dist/fields/config/sanitizeJoinField.js +3 -0
  68. package/dist/fields/config/sanitizeJoinField.js.map +1 -1
  69. package/dist/globals/config/types.d.ts +4 -0
  70. package/dist/globals/config/types.d.ts.map +1 -1
  71. package/dist/globals/config/types.js.map +1 -1
  72. package/dist/hierarchy/addHierarchyToCollection.d.ts +8 -0
  73. package/dist/hierarchy/addHierarchyToCollection.d.ts.map +1 -0
  74. package/dist/hierarchy/addHierarchyToCollection.js +62 -0
  75. package/dist/hierarchy/addHierarchyToCollection.js.map +1 -0
  76. package/dist/hierarchy/buildParentField.d.ts +11 -0
  77. package/dist/hierarchy/buildParentField.d.ts.map +1 -0
  78. package/dist/hierarchy/buildParentField.js +42 -0
  79. package/dist/hierarchy/buildParentField.js.map +1 -0
  80. package/dist/hierarchy/constants.d.ts +15 -0
  81. package/dist/hierarchy/constants.d.ts.map +1 -0
  82. package/dist/hierarchy/constants.js +11 -0
  83. package/dist/hierarchy/constants.js.map +1 -0
  84. package/dist/hierarchy/createFolderField.d.ts +39 -0
  85. package/dist/hierarchy/createFolderField.d.ts.map +1 -0
  86. package/dist/hierarchy/createFolderField.js +54 -0
  87. package/dist/hierarchy/createFolderField.js.map +1 -0
  88. package/dist/hierarchy/createFoldersCollection.d.ts +57 -0
  89. package/dist/hierarchy/createFoldersCollection.d.ts.map +1 -0
  90. package/dist/hierarchy/createFoldersCollection.js +63 -0
  91. package/dist/hierarchy/createFoldersCollection.js.map +1 -0
  92. package/dist/hierarchy/createTagField.d.ts +44 -0
  93. package/dist/hierarchy/createTagField.d.ts.map +1 -0
  94. package/dist/hierarchy/createTagField.js +48 -0
  95. package/dist/hierarchy/createTagField.js.map +1 -0
  96. package/dist/hierarchy/createTagsCollection.d.ts +54 -0
  97. package/dist/hierarchy/createTagsCollection.d.ts.map +1 -0
  98. package/dist/hierarchy/createTagsCollection.js +56 -0
  99. package/dist/hierarchy/createTagsCollection.js.map +1 -0
  100. package/dist/hierarchy/endpoints/findRelated.d.ts +7 -0
  101. package/dist/hierarchy/endpoints/findRelated.d.ts.map +1 -0
  102. package/dist/hierarchy/endpoints/findRelated.js +36 -0
  103. package/dist/hierarchy/endpoints/findRelated.js.map +1 -0
  104. package/dist/hierarchy/getInitialTreeData.d.ts +24 -0
  105. package/dist/hierarchy/getInitialTreeData.d.ts.map +1 -0
  106. package/dist/hierarchy/getInitialTreeData.js +120 -0
  107. package/dist/hierarchy/getInitialTreeData.js.map +1 -0
  108. package/dist/hierarchy/hooks/collectionAfterDelete.d.ts +14 -0
  109. package/dist/hierarchy/hooks/collectionAfterDelete.d.ts.map +1 -0
  110. package/dist/hierarchy/hooks/collectionAfterDelete.js +21 -0
  111. package/dist/hierarchy/hooks/collectionAfterDelete.js.map +1 -0
  112. package/dist/hierarchy/hooks/collectionAfterRead.d.ts +27 -0
  113. package/dist/hierarchy/hooks/collectionAfterRead.d.ts.map +1 -0
  114. package/dist/hierarchy/hooks/collectionAfterRead.js +64 -0
  115. package/dist/hierarchy/hooks/collectionAfterRead.js.map +1 -0
  116. package/dist/hierarchy/hooks/collectionBeforeChange.d.ts +19 -0
  117. package/dist/hierarchy/hooks/collectionBeforeChange.d.ts.map +1 -0
  118. package/dist/hierarchy/hooks/collectionBeforeChange.js +90 -0
  119. package/dist/hierarchy/hooks/collectionBeforeChange.js.map +1 -0
  120. package/dist/hierarchy/hooks/collectionBeforeDelete.d.ts +15 -0
  121. package/dist/hierarchy/hooks/collectionBeforeDelete.d.ts.map +1 -0
  122. package/dist/hierarchy/hooks/collectionBeforeDelete.js +20 -0
  123. package/dist/hierarchy/hooks/collectionBeforeDelete.js.map +1 -0
  124. package/dist/hierarchy/hooks/ensureSafeCollectionsChange.d.ts +8 -0
  125. package/dist/hierarchy/hooks/ensureSafeCollectionsChange.d.ts.map +1 -0
  126. package/dist/hierarchy/hooks/ensureSafeCollectionsChange.js +108 -0
  127. package/dist/hierarchy/hooks/ensureSafeCollectionsChange.js.map +1 -0
  128. package/dist/hierarchy/injectHierarchyButton.d.ts +14 -0
  129. package/dist/hierarchy/injectHierarchyButton.d.ts.map +1 -0
  130. package/dist/hierarchy/injectHierarchyButton.js +37 -0
  131. package/dist/hierarchy/injectHierarchyButton.js.map +1 -0
  132. package/dist/hierarchy/operations/findRelatedDocuments.d.ts +24 -0
  133. package/dist/hierarchy/operations/findRelatedDocuments.d.ts.map +1 -0
  134. package/dist/hierarchy/operations/findRelatedDocuments.js +73 -0
  135. package/dist/hierarchy/operations/findRelatedDocuments.js.map +1 -0
  136. package/dist/hierarchy/operations/index.d.ts +2 -0
  137. package/dist/hierarchy/operations/index.d.ts.map +1 -0
  138. package/dist/hierarchy/operations/index.js +3 -0
  139. package/dist/hierarchy/operations/index.js.map +1 -0
  140. package/dist/hierarchy/resolveHierarchyCollections.d.ts +23 -0
  141. package/dist/hierarchy/resolveHierarchyCollections.d.ts.map +1 -0
  142. package/dist/hierarchy/resolveHierarchyCollections.js +312 -0
  143. package/dist/hierarchy/resolveHierarchyCollections.js.map +1 -0
  144. package/dist/hierarchy/sanitizeHierarchyCollection.d.ts +14 -0
  145. package/dist/hierarchy/sanitizeHierarchyCollection.d.ts.map +1 -0
  146. package/dist/hierarchy/sanitizeHierarchyCollection.js +125 -0
  147. package/dist/hierarchy/sanitizeHierarchyCollection.js.map +1 -0
  148. package/dist/hierarchy/types.d.ts +137 -0
  149. package/dist/hierarchy/types.d.ts.map +1 -0
  150. package/dist/hierarchy/types.js +6 -0
  151. package/dist/hierarchy/types.js.map +1 -0
  152. package/dist/hierarchy/utils/buildLocalizedHierarchyPaths.d.ts +71 -0
  153. package/dist/hierarchy/utils/buildLocalizedHierarchyPaths.d.ts.map +1 -0
  154. package/dist/hierarchy/utils/buildLocalizedHierarchyPaths.js +65 -0
  155. package/dist/hierarchy/utils/buildLocalizedHierarchyPaths.js.map +1 -0
  156. package/dist/hierarchy/utils/computePaths.d.ts +31 -0
  157. package/dist/hierarchy/utils/computePaths.d.ts.map +1 -0
  158. package/dist/hierarchy/utils/computePaths.js +371 -0
  159. package/dist/hierarchy/utils/computePaths.js.map +1 -0
  160. package/dist/hierarchy/utils/findUseAsTitle.d.ts +6 -0
  161. package/dist/hierarchy/utils/findUseAsTitle.d.ts.map +1 -0
  162. package/dist/hierarchy/utils/findUseAsTitle.js +72 -0
  163. package/dist/hierarchy/utils/findUseAsTitle.js.map +1 -0
  164. package/dist/hierarchy/utils/getAncestors.d.ts +34 -0
  165. package/dist/hierarchy/utils/getAncestors.d.ts.map +1 -0
  166. package/dist/hierarchy/utils/getAncestors.js +94 -0
  167. package/dist/hierarchy/utils/getAncestors.js.map +1 -0
  168. package/dist/hierarchy/utils/getLocalizedValue.d.ts +30 -0
  169. package/dist/hierarchy/utils/getLocalizedValue.d.ts.map +1 -0
  170. package/dist/hierarchy/utils/getLocalizedValue.js +46 -0
  171. package/dist/hierarchy/utils/getLocalizedValue.js.map +1 -0
  172. package/dist/hierarchy/utils/getLocalizedValue.spec.js +250 -0
  173. package/dist/hierarchy/utils/getLocalizedValue.spec.js.map +1 -0
  174. package/dist/index.bundled.d.ts +567 -280
  175. package/dist/index.d.ts +23 -9
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +13 -5
  178. package/dist/index.js.map +1 -1
  179. package/dist/preferences/keys.d.ts +8 -4
  180. package/dist/preferences/keys.d.ts.map +1 -1
  181. package/dist/preferences/keys.js +7 -4
  182. package/dist/preferences/keys.js.map +1 -1
  183. package/dist/types/index.d.ts +1 -0
  184. package/dist/types/index.d.ts.map +1 -1
  185. package/dist/types/index.js.map +1 -1
  186. package/dist/utilities/extractID.js +1 -1
  187. package/dist/utilities/extractID.js.map +1 -1
  188. package/dist/utilities/formatAdminURL.d.ts +13 -2
  189. package/dist/utilities/formatAdminURL.d.ts.map +1 -1
  190. package/dist/utilities/formatAdminURL.js.map +1 -1
  191. package/package.json +2 -2
  192. package/dist/admin/views/folderList.d.ts +0 -56
  193. package/dist/admin/views/folderList.d.ts.map +0 -1
  194. package/dist/admin/views/folderList.js +0 -3
  195. package/dist/admin/views/folderList.js.map +0 -1
  196. package/dist/folders/addFolderCollection.d.ts +0 -10
  197. package/dist/folders/addFolderCollection.d.ts.map +0 -1
  198. package/dist/folders/addFolderCollection.js +0 -26
  199. package/dist/folders/addFolderCollection.js.map +0 -1
  200. package/dist/folders/addFolderFieldToCollection.d.ts +0 -8
  201. package/dist/folders/addFolderFieldToCollection.d.ts.map +0 -1
  202. package/dist/folders/addFolderFieldToCollection.js +0 -20
  203. package/dist/folders/addFolderFieldToCollection.js.map +0 -1
  204. package/dist/folders/buildFolderField.d.ts +0 -8
  205. package/dist/folders/buildFolderField.d.ts.map +0 -1
  206. package/dist/folders/buildFolderField.js +0 -87
  207. package/dist/folders/buildFolderField.js.map +0 -1
  208. package/dist/folders/constants.d.ts +0 -3
  209. package/dist/folders/constants.d.ts.map +0 -1
  210. package/dist/folders/constants.js +0 -4
  211. package/dist/folders/constants.js.map +0 -1
  212. package/dist/folders/createFolderCollection.d.ts +0 -11
  213. package/dist/folders/createFolderCollection.d.ts.map +0 -1
  214. package/dist/folders/createFolderCollection.js +0 -115
  215. package/dist/folders/createFolderCollection.js.map +0 -1
  216. package/dist/folders/hooks/deleteSubfoldersAfterDelete.d.ts +0 -8
  217. package/dist/folders/hooks/deleteSubfoldersAfterDelete.d.ts.map +0 -1
  218. package/dist/folders/hooks/deleteSubfoldersAfterDelete.js +0 -15
  219. package/dist/folders/hooks/deleteSubfoldersAfterDelete.js.map +0 -1
  220. package/dist/folders/hooks/dissasociateAfterDelete.d.ts +0 -8
  221. package/dist/folders/hooks/dissasociateAfterDelete.d.ts.map +0 -1
  222. package/dist/folders/hooks/dissasociateAfterDelete.js +0 -20
  223. package/dist/folders/hooks/dissasociateAfterDelete.js.map +0 -1
  224. package/dist/folders/hooks/ensureSafeCollectionsChange.d.ts +0 -5
  225. package/dist/folders/hooks/ensureSafeCollectionsChange.d.ts.map +0 -1
  226. package/dist/folders/hooks/ensureSafeCollectionsChange.js +0 -107
  227. package/dist/folders/hooks/ensureSafeCollectionsChange.js.map +0 -1
  228. package/dist/folders/hooks/reparentChildFolder.d.ts +0 -24
  229. package/dist/folders/hooks/reparentChildFolder.d.ts.map +0 -1
  230. package/dist/folders/hooks/reparentChildFolder.js +0 -72
  231. package/dist/folders/hooks/reparentChildFolder.js.map +0 -1
  232. package/dist/folders/types.d.ts +0 -118
  233. package/dist/folders/types.d.ts.map +0 -1
  234. package/dist/folders/types.js +0 -3
  235. package/dist/folders/types.js.map +0 -1
  236. package/dist/folders/utils/buildFolderWhereConstraints.d.ts +0 -13
  237. package/dist/folders/utils/buildFolderWhereConstraints.d.ts.map +0 -1
  238. package/dist/folders/utils/buildFolderWhereConstraints.js +0 -45
  239. package/dist/folders/utils/buildFolderWhereConstraints.js.map +0 -1
  240. package/dist/folders/utils/formatFolderOrDocumentItem.d.ts +0 -12
  241. package/dist/folders/utils/formatFolderOrDocumentItem.d.ts.map +0 -1
  242. package/dist/folders/utils/formatFolderOrDocumentItem.js +0 -30
  243. package/dist/folders/utils/formatFolderOrDocumentItem.js.map +0 -1
  244. package/dist/folders/utils/getFolderBreadcrumbs.d.ts +0 -14
  245. package/dist/folders/utils/getFolderBreadcrumbs.d.ts.map +0 -1
  246. package/dist/folders/utils/getFolderBreadcrumbs.js +0 -45
  247. package/dist/folders/utils/getFolderBreadcrumbs.js.map +0 -1
  248. package/dist/folders/utils/getFolderData.d.ts +0 -33
  249. package/dist/folders/utils/getFolderData.d.ts.map +0 -1
  250. package/dist/folders/utils/getFolderData.js +0 -88
  251. package/dist/folders/utils/getFolderData.js.map +0 -1
  252. package/dist/folders/utils/getFoldersAndDocumentsFromJoin.d.ts +0 -24
  253. package/dist/folders/utils/getFoldersAndDocumentsFromJoin.d.ts.map +0 -1
  254. package/dist/folders/utils/getFoldersAndDocumentsFromJoin.js +0 -66
  255. package/dist/folders/utils/getFoldersAndDocumentsFromJoin.js.map +0 -1
  256. package/dist/folders/utils/getOrphanedDocs.d.ts +0 -15
  257. package/dist/folders/utils/getOrphanedDocs.d.ts.map +0 -1
  258. package/dist/folders/utils/getOrphanedDocs.js +0 -40
  259. package/dist/folders/utils/getOrphanedDocs.js.map +0 -1
@@ -0,0 +1,21 @@
1
+ /**
2
+ * afterDelete Hook Responsibilities:
3
+ * - Clear folder references from related documents when folder is deleted
4
+ */ export const hierarchyCollectionAfterDelete = ({ relatedCollections })=>async ({ id, req })=>{
5
+ for (const [collectionSlug, fieldName] of Object.entries(relatedCollections)){
6
+ await req.payload.update({
7
+ collection: collectionSlug,
8
+ data: {
9
+ [fieldName]: null
10
+ },
11
+ req,
12
+ where: {
13
+ [fieldName]: {
14
+ equals: id
15
+ }
16
+ }
17
+ });
18
+ }
19
+ };
20
+
21
+ //# sourceMappingURL=collectionAfterDelete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hierarchy/hooks/collectionAfterDelete.ts"],"sourcesContent":["/**\n * afterDelete Hook Responsibilities:\n * - Clear folder references from related documents when folder is deleted\n */\n\nimport type { CollectionAfterDeleteHook } from '../../index.js'\n\ntype Args = {\n /**\n * Map of collection slugs to their field names\n */\n relatedCollections: Record<string, string>\n}\n\nexport const hierarchyCollectionAfterDelete =\n ({ relatedCollections }: Args): CollectionAfterDeleteHook =>\n async ({ id, req }) => {\n for (const [collectionSlug, fieldName] of Object.entries(relatedCollections)) {\n await req.payload.update({\n collection: collectionSlug,\n data: {\n [fieldName]: null,\n },\n req,\n where: {\n [fieldName]: {\n equals: id,\n },\n },\n })\n }\n }\n"],"names":["hierarchyCollectionAfterDelete","relatedCollections","id","req","collectionSlug","fieldName","Object","entries","payload","update","collection","data","where","equals"],"mappings":"AAAA;;;CAGC,GAWD,OAAO,MAAMA,iCACX,CAAC,EAAEC,kBAAkB,EAAQ,GAC7B,OAAO,EAAEC,EAAE,EAAEC,GAAG,EAAE;QAChB,KAAK,MAAM,CAACC,gBAAgBC,UAAU,IAAIC,OAAOC,OAAO,CAACN,oBAAqB;YAC5E,MAAME,IAAIK,OAAO,CAACC,MAAM,CAAC;gBACvBC,YAAYN;gBACZO,MAAM;oBACJ,CAACN,UAAU,EAAE;gBACf;gBACAF;gBACAS,OAAO;oBACL,CAACP,UAAU,EAAE;wBACXQ,QAAQX;oBACV;gBACF;YACF;QACF;IACF,EAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * afterRead Hook Responsibilities:
3
+ * - Automatically compute and attach _h_slugPath and _h_titlePath to documents
4
+ * - Use cached ancestors to optimize queries when reading multiple documents
5
+ * - Only computes when explicitly requested via:
6
+ * 1. context.computeHierarchyPaths flag
7
+ * 2. ?computeHierarchyPaths=true query param
8
+ * 3. Selecting path fields in query (select parameter)
9
+ */
10
+ import type { CollectionAfterReadHook } from '../../index.js';
11
+ type Args = {
12
+ /**
13
+ * The name of the field that contains the parent document ID
14
+ */
15
+ parentFieldName: string;
16
+ /**
17
+ * The name of the field to populate with the slug-based path
18
+ */
19
+ slugPathFieldName: string;
20
+ /**
21
+ * The name of the field to populate with the title-based path
22
+ */
23
+ titlePathFieldName: string;
24
+ };
25
+ export declare const hierarchyCollectionAfterRead: ({ parentFieldName, slugPathFieldName, titlePathFieldName }: Args) => CollectionAfterReadHook;
26
+ export {};
27
+ //# sourceMappingURL=collectionAfterRead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionAfterRead.d.ts","sourceRoot":"","sources":["../../../src/hierarchy/hooks/collectionAfterRead.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAkB,MAAM,gBAAgB,CAAA;AAgC7E,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,eAAe,EAAE,MAAM,CAAA;IACvB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB;;OAEG;IACH,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,eAAO,MAAM,4BAA4B,+DACsB,IAAI,KAAG,uBA8CnE,CAAA"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * afterRead Hook Responsibilities:
3
+ * - Automatically compute and attach _h_slugPath and _h_titlePath to documents
4
+ * - Use cached ancestors to optimize queries when reading multiple documents
5
+ * - Only computes when explicitly requested via:
6
+ * 1. context.computeHierarchyPaths flag
7
+ * 2. ?computeHierarchyPaths=true query param
8
+ * 3. Selecting path fields in query (select parameter)
9
+ */ import { computePaths } from '../utils/computePaths.js';
10
+ import { findUseAsTitleField } from '../utils/findUseAsTitle.js';
11
+ /**
12
+ * Checks if path fields are being selected in the query
13
+ */ function isPathFieldSelected(req, slugPathFieldName, titlePathFieldName) {
14
+ // Check query.select parameter (REST API)
15
+ const selectParam = req.query?.select;
16
+ if (selectParam) {
17
+ if (typeof selectParam === 'string') {
18
+ const selectedFields = selectParam.split(',').map((f)=>f.trim());
19
+ return selectedFields.includes(slugPathFieldName) || selectedFields.includes(titlePathFieldName);
20
+ }
21
+ // Could be an array or object depending on query parser
22
+ if (Array.isArray(selectParam)) {
23
+ return selectParam.includes(slugPathFieldName) || selectParam.includes(titlePathFieldName);
24
+ }
25
+ }
26
+ return false;
27
+ }
28
+ export const hierarchyCollectionAfterRead = ({ parentFieldName, slugPathFieldName, titlePathFieldName })=>async ({ collection, context, doc, req })=>{
29
+ // Skip if deleting
30
+ if (context?.isDeleting) {
31
+ return doc;
32
+ }
33
+ // Determine if paths should be computed
34
+ const shouldComputePaths = context?.computeHierarchyPaths === true || // Explicit flag
35
+ req.query?.computeHierarchyPaths === 'true' || // Query parameter
36
+ isPathFieldSelected(req, slugPathFieldName, titlePathFieldName) // Field selection detection
37
+ ;
38
+ if (!shouldComputePaths) {
39
+ return doc;
40
+ }
41
+ try {
42
+ const { localized: isTitleLocalized } = findUseAsTitleField(collection);
43
+ const { slugPath, titlePath } = await computePaths({
44
+ collection,
45
+ doc,
46
+ draft: doc._status === 'draft',
47
+ locale: isTitleLocalized && req.locale === 'all' ? 'all' : req.locale === 'all' ? undefined : req.locale || undefined,
48
+ parentFieldName,
49
+ req,
50
+ slugPathFieldName,
51
+ titlePathFieldName
52
+ });
53
+ // Attach computed paths to document using configured field names
54
+ doc[slugPathFieldName] = slugPath;
55
+ doc[titlePathFieldName] = titlePath;
56
+ } catch (error) {
57
+ // If path computation fails, log but don't break the document read
58
+ // eslint-disable-next-line no-console
59
+ console.error(`Failed to compute hierarchy paths for document ${doc.id}:`, error);
60
+ }
61
+ return doc;
62
+ };
63
+
64
+ //# sourceMappingURL=collectionAfterRead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hierarchy/hooks/collectionAfterRead.ts"],"sourcesContent":["/**\n * afterRead Hook Responsibilities:\n * - Automatically compute and attach _h_slugPath and _h_titlePath to documents\n * - Use cached ancestors to optimize queries when reading multiple documents\n * - Only computes when explicitly requested via:\n * 1. context.computeHierarchyPaths flag\n * 2. ?computeHierarchyPaths=true query param\n * 3. Selecting path fields in query (select parameter)\n */\n\nimport type { CollectionAfterReadHook, PayloadRequest } from '../../index.js'\n\nimport { computePaths } from '../utils/computePaths.js'\nimport { findUseAsTitleField } from '../utils/findUseAsTitle.js'\n\n/**\n * Checks if path fields are being selected in the query\n */\nfunction isPathFieldSelected(\n req: PayloadRequest,\n slugPathFieldName: string,\n titlePathFieldName: string,\n): boolean {\n // Check query.select parameter (REST API)\n const selectParam = req.query?.select\n\n if (selectParam) {\n if (typeof selectParam === 'string') {\n const selectedFields = selectParam.split(',').map((f) => f.trim())\n return (\n selectedFields.includes(slugPathFieldName) || selectedFields.includes(titlePathFieldName)\n )\n }\n // Could be an array or object depending on query parser\n if (Array.isArray(selectParam)) {\n return selectParam.includes(slugPathFieldName) || selectParam.includes(titlePathFieldName)\n }\n }\n\n return false\n}\n\ntype Args = {\n /**\n * The name of the field that contains the parent document ID\n */\n parentFieldName: string\n /**\n * The name of the field to populate with the slug-based path\n */\n slugPathFieldName: string\n /**\n * The name of the field to populate with the title-based path\n */\n titlePathFieldName: string\n}\n\nexport const hierarchyCollectionAfterRead =\n ({ parentFieldName, slugPathFieldName, titlePathFieldName }: Args): CollectionAfterReadHook =>\n async ({ collection, context, doc, req }) => {\n // Skip if deleting\n if (context?.isDeleting) {\n return doc\n }\n\n // Determine if paths should be computed\n const shouldComputePaths =\n context?.computeHierarchyPaths === true || // Explicit flag\n req.query?.computeHierarchyPaths === 'true' || // Query parameter\n isPathFieldSelected(req, slugPathFieldName, titlePathFieldName) // Field selection detection\n\n if (!shouldComputePaths) {\n return doc\n }\n\n try {\n const { localized: isTitleLocalized } = findUseAsTitleField(collection)\n\n const { slugPath, titlePath } = await computePaths({\n collection,\n doc,\n draft: doc._status === 'draft',\n locale:\n isTitleLocalized && req.locale === 'all'\n ? 'all'\n : req.locale === 'all'\n ? undefined\n : req.locale || undefined,\n parentFieldName,\n req,\n slugPathFieldName,\n titlePathFieldName,\n })\n\n // Attach computed paths to document using configured field names\n doc[slugPathFieldName] = slugPath\n doc[titlePathFieldName] = titlePath\n } catch (error) {\n // If path computation fails, log but don't break the document read\n // eslint-disable-next-line no-console\n console.error(`Failed to compute hierarchy paths for document ${doc.id}:`, error)\n }\n\n return doc\n }\n"],"names":["computePaths","findUseAsTitleField","isPathFieldSelected","req","slugPathFieldName","titlePathFieldName","selectParam","query","select","selectedFields","split","map","f","trim","includes","Array","isArray","hierarchyCollectionAfterRead","parentFieldName","collection","context","doc","isDeleting","shouldComputePaths","computeHierarchyPaths","localized","isTitleLocalized","slugPath","titlePath","draft","_status","locale","undefined","error","console","id"],"mappings":"AAAA;;;;;;;;CAQC,GAID,SAASA,YAAY,QAAQ,2BAA0B;AACvD,SAASC,mBAAmB,QAAQ,6BAA4B;AAEhE;;CAEC,GACD,SAASC,oBACPC,GAAmB,EACnBC,iBAAyB,EACzBC,kBAA0B;IAE1B,0CAA0C;IAC1C,MAAMC,cAAcH,IAAII,KAAK,EAAEC;IAE/B,IAAIF,aAAa;QACf,IAAI,OAAOA,gBAAgB,UAAU;YACnC,MAAMG,iBAAiBH,YAAYI,KAAK,CAAC,KAAKC,GAAG,CAAC,CAACC,IAAMA,EAAEC,IAAI;YAC/D,OACEJ,eAAeK,QAAQ,CAACV,sBAAsBK,eAAeK,QAAQ,CAACT;QAE1E;QACA,wDAAwD;QACxD,IAAIU,MAAMC,OAAO,CAACV,cAAc;YAC9B,OAAOA,YAAYQ,QAAQ,CAACV,sBAAsBE,YAAYQ,QAAQ,CAACT;QACzE;IACF;IAEA,OAAO;AACT;AAiBA,OAAO,MAAMY,+BACX,CAAC,EAAEC,eAAe,EAAEd,iBAAiB,EAAEC,kBAAkB,EAAQ,GACjE,OAAO,EAAEc,UAAU,EAAEC,OAAO,EAAEC,GAAG,EAAElB,GAAG,EAAE;QACtC,mBAAmB;QACnB,IAAIiB,SAASE,YAAY;YACvB,OAAOD;QACT;QAEA,wCAAwC;QACxC,MAAME,qBACJH,SAASI,0BAA0B,QAAQ,gBAAgB;QAC3DrB,IAAII,KAAK,EAAEiB,0BAA0B,UAAU,kBAAkB;QACjEtB,oBAAoBC,KAAKC,mBAAmBC,oBAAoB,4BAA4B;;QAE9F,IAAI,CAACkB,oBAAoB;YACvB,OAAOF;QACT;QAEA,IAAI;YACF,MAAM,EAAEI,WAAWC,gBAAgB,EAAE,GAAGzB,oBAAoBkB;YAE5D,MAAM,EAAEQ,QAAQ,EAAEC,SAAS,EAAE,GAAG,MAAM5B,aAAa;gBACjDmB;gBACAE;gBACAQ,OAAOR,IAAIS,OAAO,KAAK;gBACvBC,QACEL,oBAAoBvB,IAAI4B,MAAM,KAAK,QAC/B,QACA5B,IAAI4B,MAAM,KAAK,QACbC,YACA7B,IAAI4B,MAAM,IAAIC;gBACtBd;gBACAf;gBACAC;gBACAC;YACF;YAEA,iEAAiE;YACjEgB,GAAG,CAACjB,kBAAkB,GAAGuB;YACzBN,GAAG,CAAChB,mBAAmB,GAAGuB;QAC5B,EAAE,OAAOK,OAAO;YACd,mEAAmE;YACnE,sCAAsC;YACtCC,QAAQD,KAAK,CAAC,CAAC,+CAA+C,EAAEZ,IAAIc,EAAE,CAAC,CAAC,CAAC,EAAEF;QAC7E;QAEA,OAAOZ;IACT,EAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * beforeChange Hook Responsibilities:
3
+ * - Validate circular references when parent changes
4
+ * - Prevent moving a folder into its own subfolder
5
+ *
6
+ * Does NOT handle:
7
+ * - Tree structure (no stored tree anymore)
8
+ * - Path computation (done in afterRead)
9
+ */
10
+ import type { CollectionBeforeChangeHook } from '../../index.js';
11
+ type Args = {
12
+ /**
13
+ * The name of the field that contains the parent document ID
14
+ */
15
+ parentFieldName: string;
16
+ };
17
+ export declare const hierarchyCollectionBeforeChange: ({ parentFieldName }: Args) => CollectionBeforeChangeHook;
18
+ export {};
19
+ //# sourceMappingURL=collectionBeforeChange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionBeforeChange.d.ts","sourceRoot":"","sources":["../../../src/hierarchy/hooks/collectionBeforeChange.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,0BAA0B,EAI3B,MAAM,gBAAgB,CAAA;AAEvB,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,eAAO,MAAM,+BAA+B,wBACpB,IAAI,KAAG,0BAgC5B,CAAA"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * beforeChange Hook Responsibilities:
3
+ * - Validate circular references when parent changes
4
+ * - Prevent moving a folder into its own subfolder
5
+ *
6
+ * Does NOT handle:
7
+ * - Tree structure (no stored tree anymore)
8
+ * - Path computation (done in afterRead)
9
+ */ export const hierarchyCollectionBeforeChange = ({ parentFieldName })=>async ({ collection, data, operation, originalDoc, req })=>{
10
+ // Determine the new parent ID
11
+ const newParentID = data[parentFieldName] !== undefined ? data[parentFieldName] : originalDoc?.[parentFieldName];
12
+ const parentChanged = operation === 'update' && data[parentFieldName] !== undefined && data[parentFieldName] !== originalDoc?.[parentFieldName];
13
+ // Validate circular references when parent is changing
14
+ if (parentChanged && newParentID) {
15
+ // Extract parent ID (could be plain ID or populated object with id)
16
+ const parentId = typeof newParentID === 'object' && 'id' in newParentID ? newParentID.id : newParentID;
17
+ // Prevent self-referential parent
18
+ if (parentId === (originalDoc?.id || data.id)) {
19
+ throw new Error('Document cannot be its own parent');
20
+ }
21
+ // Check for true circular references (loops in the chain), but allow
22
+ // moving into a child - that will be handled by afterChange reparenting
23
+ await validateNoCircularReference({
24
+ collection,
25
+ currentDocId: originalDoc?.id,
26
+ parentId,
27
+ req
28
+ });
29
+ }
30
+ return data;
31
+ };
32
+ /**
33
+ * Walks up the parent chain to detect true circular references (loops).
34
+ * Does NOT throw when moving into a child - that case is handled by afterChange
35
+ * which will automatically reparent the child.
36
+ */ async function validateNoCircularReference({ collection, currentDocId, parentId, req }) {
37
+ const parentFieldName = collection.hierarchy && collection.hierarchy !== true ? collection.hierarchy.parentFieldName : undefined;
38
+ if (!parentFieldName) {
39
+ return;
40
+ }
41
+ const fieldName = parentFieldName;
42
+ async function checkAncestor(ancestorId, visitedNodes = new Set()) {
43
+ // Create unique key for this node
44
+ const nodeKey = `${collection.slug}:${ancestorId}`;
45
+ // Check if we've visited this node before (true loop in the chain)
46
+ if (visitedNodes.has(nodeKey)) {
47
+ throw new Error(`Circular reference detected: the parent chain contains a loop`);
48
+ }
49
+ // If we've reached the current document, this means we're trying to move into a child
50
+ if (ancestorId === currentDocId) {
51
+ throw new Error('Cannot move folder into its own subfolder');
52
+ }
53
+ // Add this node to visited set
54
+ visitedNodes.add(nodeKey);
55
+ try {
56
+ const ancestor = await req.payload.findByID({
57
+ id: ancestorId,
58
+ collection: collection.slug,
59
+ depth: 0,
60
+ req,
61
+ select: {
62
+ [fieldName]: true
63
+ }
64
+ });
65
+ const nextParent = ancestor?.[fieldName];
66
+ if (!nextParent) {
67
+ return; // No parent, end of chain
68
+ }
69
+ // Extract next parent ID (could be plain ID or populated object)
70
+ let nextParentId = nextParent;
71
+ if (typeof nextParent === 'object' && 'id' in nextParent) {
72
+ nextParentId = nextParent.id;
73
+ }
74
+ // Continue traversal if parent exists
75
+ if (nextParentId !== null && nextParentId !== undefined && (typeof nextParentId === 'string' || typeof nextParentId === 'number')) {
76
+ return checkAncestor(nextParentId, visitedNodes);
77
+ }
78
+ } catch (error) {
79
+ // If it's our validation error, re-throw it
80
+ if (error instanceof Error && error.message?.includes('Circular reference detected')) {
81
+ throw error;
82
+ }
83
+ // Non-existent parent can't create a circular reference
84
+ return;
85
+ }
86
+ }
87
+ await checkAncestor(parentId);
88
+ }
89
+
90
+ //# sourceMappingURL=collectionBeforeChange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hierarchy/hooks/collectionBeforeChange.ts"],"sourcesContent":["/**\n * beforeChange Hook Responsibilities:\n * - Validate circular references when parent changes\n * - Prevent moving a folder into its own subfolder\n *\n * Does NOT handle:\n * - Tree structure (no stored tree anymore)\n * - Path computation (done in afterRead)\n */\n\nimport type {\n CollectionBeforeChangeHook,\n CollectionConfig,\n JsonObject,\n PayloadRequest,\n} from '../../index.js'\n\ntype Args = {\n /**\n * The name of the field that contains the parent document ID\n */\n parentFieldName: string\n}\n\nexport const hierarchyCollectionBeforeChange =\n ({ parentFieldName }: Args): CollectionBeforeChangeHook =>\n async ({ collection, data, operation, originalDoc, req }) => {\n // Determine the new parent ID\n const newParentID =\n data[parentFieldName] !== undefined ? data[parentFieldName] : originalDoc?.[parentFieldName]\n const parentChanged =\n operation === 'update' &&\n data[parentFieldName] !== undefined &&\n data[parentFieldName] !== originalDoc?.[parentFieldName]\n\n // Validate circular references when parent is changing\n if (parentChanged && newParentID) {\n // Extract parent ID (could be plain ID or populated object with id)\n const parentId =\n typeof newParentID === 'object' && 'id' in newParentID ? newParentID.id : newParentID\n\n // Prevent self-referential parent\n if (parentId === (originalDoc?.id || data.id)) {\n throw new Error('Document cannot be its own parent')\n }\n\n // Check for true circular references (loops in the chain), but allow\n // moving into a child - that will be handled by afterChange reparenting\n await validateNoCircularReference({\n collection,\n currentDocId: originalDoc?.id,\n parentId,\n req,\n })\n }\n\n return data\n }\n\n/**\n * Walks up the parent chain to detect true circular references (loops).\n * Does NOT throw when moving into a child - that case is handled by afterChange\n * which will automatically reparent the child.\n */\nasync function validateNoCircularReference({\n collection,\n currentDocId,\n parentId,\n req,\n}: {\n collection: CollectionConfig\n currentDocId: number | string\n parentId: number | string\n req: PayloadRequest\n}) {\n const parentFieldName =\n collection.hierarchy && collection.hierarchy !== true\n ? collection.hierarchy.parentFieldName\n : undefined\n\n if (!parentFieldName) {\n return\n }\n\n const fieldName = parentFieldName\n\n async function checkAncestor(\n ancestorId: number | string,\n visitedNodes: Set<string> = new Set(),\n ): Promise<void> {\n // Create unique key for this node\n const nodeKey = `${collection.slug}:${ancestorId}`\n\n // Check if we've visited this node before (true loop in the chain)\n if (visitedNodes.has(nodeKey)) {\n throw new Error(`Circular reference detected: the parent chain contains a loop`)\n }\n\n // If we've reached the current document, this means we're trying to move into a child\n if (ancestorId === currentDocId) {\n throw new Error('Cannot move folder into its own subfolder')\n }\n\n // Add this node to visited set\n visitedNodes.add(nodeKey)\n\n try {\n const ancestor = (await req.payload.findByID({\n id: ancestorId,\n collection: collection.slug,\n depth: 0,\n req,\n select: {\n [fieldName]: true,\n },\n })) as JsonObject\n\n const nextParent = ancestor?.[fieldName]\n\n if (!nextParent) {\n return // No parent, end of chain\n }\n\n // Extract next parent ID (could be plain ID or populated object)\n let nextParentId = nextParent\n if (typeof nextParent === 'object' && 'id' in nextParent) {\n nextParentId = nextParent.id\n }\n\n // Continue traversal if parent exists\n if (\n nextParentId !== null &&\n nextParentId !== undefined &&\n (typeof nextParentId === 'string' || typeof nextParentId === 'number')\n ) {\n return checkAncestor(nextParentId, visitedNodes)\n }\n } catch (error) {\n // If it's our validation error, re-throw it\n if (error instanceof Error && error.message?.includes('Circular reference detected')) {\n throw error\n }\n // Non-existent parent can't create a circular reference\n return\n }\n }\n\n await checkAncestor(parentId)\n}\n"],"names":["hierarchyCollectionBeforeChange","parentFieldName","collection","data","operation","originalDoc","req","newParentID","undefined","parentChanged","parentId","id","Error","validateNoCircularReference","currentDocId","hierarchy","fieldName","checkAncestor","ancestorId","visitedNodes","Set","nodeKey","slug","has","add","ancestor","payload","findByID","depth","select","nextParent","nextParentId","error","message","includes"],"mappings":"AAAA;;;;;;;;CAQC,GAgBD,OAAO,MAAMA,kCACX,CAAC,EAAEC,eAAe,EAAQ,GAC1B,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,SAAS,EAAEC,WAAW,EAAEC,GAAG,EAAE;QACtD,8BAA8B;QAC9B,MAAMC,cACJJ,IAAI,CAACF,gBAAgB,KAAKO,YAAYL,IAAI,CAACF,gBAAgB,GAAGI,aAAa,CAACJ,gBAAgB;QAC9F,MAAMQ,gBACJL,cAAc,YACdD,IAAI,CAACF,gBAAgB,KAAKO,aAC1BL,IAAI,CAACF,gBAAgB,KAAKI,aAAa,CAACJ,gBAAgB;QAE1D,uDAAuD;QACvD,IAAIQ,iBAAiBF,aAAa;YAChC,oEAAoE;YACpE,MAAMG,WACJ,OAAOH,gBAAgB,YAAY,QAAQA,cAAcA,YAAYI,EAAE,GAAGJ;YAE5E,kCAAkC;YAClC,IAAIG,aAAcL,CAAAA,aAAaM,MAAMR,KAAKQ,EAAE,AAAD,GAAI;gBAC7C,MAAM,IAAIC,MAAM;YAClB;YAEA,qEAAqE;YACrE,wEAAwE;YACxE,MAAMC,4BAA4B;gBAChCX;gBACAY,cAAcT,aAAaM;gBAC3BD;gBACAJ;YACF;QACF;QAEA,OAAOH;IACT,EAAC;AAEH;;;;CAIC,GACD,eAAeU,4BAA4B,EACzCX,UAAU,EACVY,YAAY,EACZJ,QAAQ,EACRJ,GAAG,EAMJ;IACC,MAAML,kBACJC,WAAWa,SAAS,IAAIb,WAAWa,SAAS,KAAK,OAC7Cb,WAAWa,SAAS,CAACd,eAAe,GACpCO;IAEN,IAAI,CAACP,iBAAiB;QACpB;IACF;IAEA,MAAMe,YAAYf;IAElB,eAAegB,cACbC,UAA2B,EAC3BC,eAA4B,IAAIC,KAAK;QAErC,kCAAkC;QAClC,MAAMC,UAAU,GAAGnB,WAAWoB,IAAI,CAAC,CAAC,EAAEJ,YAAY;QAElD,mEAAmE;QACnE,IAAIC,aAAaI,GAAG,CAACF,UAAU;YAC7B,MAAM,IAAIT,MAAM,CAAC,6DAA6D,CAAC;QACjF;QAEA,sFAAsF;QACtF,IAAIM,eAAeJ,cAAc;YAC/B,MAAM,IAAIF,MAAM;QAClB;QAEA,+BAA+B;QAC/BO,aAAaK,GAAG,CAACH;QAEjB,IAAI;YACF,MAAMI,WAAY,MAAMnB,IAAIoB,OAAO,CAACC,QAAQ,CAAC;gBAC3ChB,IAAIO;gBACJhB,YAAYA,WAAWoB,IAAI;gBAC3BM,OAAO;gBACPtB;gBACAuB,QAAQ;oBACN,CAACb,UAAU,EAAE;gBACf;YACF;YAEA,MAAMc,aAAaL,UAAU,CAACT,UAAU;YAExC,IAAI,CAACc,YAAY;gBACf,QAAO,0BAA0B;YACnC;YAEA,iEAAiE;YACjE,IAAIC,eAAeD;YACnB,IAAI,OAAOA,eAAe,YAAY,QAAQA,YAAY;gBACxDC,eAAeD,WAAWnB,EAAE;YAC9B;YAEA,sCAAsC;YACtC,IACEoB,iBAAiB,QACjBA,iBAAiBvB,aAChB,CAAA,OAAOuB,iBAAiB,YAAY,OAAOA,iBAAiB,QAAO,GACpE;gBACA,OAAOd,cAAcc,cAAcZ;YACrC;QACF,EAAE,OAAOa,OAAO;YACd,4CAA4C;YAC5C,IAAIA,iBAAiBpB,SAASoB,MAAMC,OAAO,EAAEC,SAAS,gCAAgC;gBACpF,MAAMF;YACR;YACA,wDAAwD;YACxD;QACF;IACF;IAEA,MAAMf,cAAcP;AACtB"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * beforeDelete Hook Responsibilities:
3
+ * - Delete child folders when parent is deleted (cascade delete)
4
+ * - Set context flag for deletion tracking
5
+ */
6
+ import type { CollectionBeforeDeleteHook } from '../../index.js';
7
+ type Args = {
8
+ /**
9
+ * The name of the field that contains the parent document ID
10
+ */
11
+ parentFieldName: string;
12
+ };
13
+ export declare const hierarchyCollectionBeforeDelete: ({ parentFieldName }: Args) => CollectionBeforeDeleteHook;
14
+ export {};
15
+ //# sourceMappingURL=collectionBeforeDelete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionBeforeDelete.d.ts","sourceRoot":"","sources":["../../../src/hierarchy/hooks/collectionBeforeDelete.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAA;AAEhE,KAAK,IAAI,GAAG;IACV;;OAEG;IACH,eAAe,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,eAAO,MAAM,+BAA+B,wBACpB,IAAI,KAAG,0BAe5B,CAAA"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * beforeDelete Hook Responsibilities:
3
+ * - Delete child folders when parent is deleted (cascade delete)
4
+ * - Set context flag for deletion tracking
5
+ */ export const hierarchyCollectionBeforeDelete = ({ parentFieldName })=>async ({ id, collection, req })=>{
6
+ req.context = req.context || {};
7
+ req.context.isDeleting = true;
8
+ // Delete all child folders (cascade delete)
9
+ await req.payload.delete({
10
+ collection: collection.slug,
11
+ req,
12
+ where: {
13
+ [parentFieldName]: {
14
+ equals: id
15
+ }
16
+ }
17
+ });
18
+ };
19
+
20
+ //# sourceMappingURL=collectionBeforeDelete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hierarchy/hooks/collectionBeforeDelete.ts"],"sourcesContent":["/**\n * beforeDelete Hook Responsibilities:\n * - Delete child folders when parent is deleted (cascade delete)\n * - Set context flag for deletion tracking\n */\n\nimport type { CollectionBeforeDeleteHook } from '../../index.js'\n\ntype Args = {\n /**\n * The name of the field that contains the parent document ID\n */\n parentFieldName: string\n}\n\nexport const hierarchyCollectionBeforeDelete =\n ({ parentFieldName }: Args): CollectionBeforeDeleteHook =>\n async ({ id, collection, req }) => {\n req.context = req.context || {}\n req.context.isDeleting = true\n\n // Delete all child folders (cascade delete)\n await req.payload.delete({\n collection: collection.slug,\n req,\n where: {\n [parentFieldName]: {\n equals: id,\n },\n },\n })\n }\n"],"names":["hierarchyCollectionBeforeDelete","parentFieldName","id","collection","req","context","isDeleting","payload","delete","slug","where","equals"],"mappings":"AAAA;;;;CAIC,GAWD,OAAO,MAAMA,kCACX,CAAC,EAAEC,eAAe,EAAQ,GAC1B,OAAO,EAAEC,EAAE,EAAEC,UAAU,EAAEC,GAAG,EAAE;QAC5BA,IAAIC,OAAO,GAAGD,IAAIC,OAAO,IAAI,CAAC;QAC9BD,IAAIC,OAAO,CAACC,UAAU,GAAG;QAEzB,4CAA4C;QAC5C,MAAMF,IAAIG,OAAO,CAACC,MAAM,CAAC;YACvBL,YAAYA,WAAWM,IAAI;YAC3BL;YACAM,OAAO;gBACL,CAACT,gBAAgB,EAAE;oBACjBU,QAAQT;gBACV;YACF;QACF;IACF,EAAC"}
@@ -0,0 +1,8 @@
1
+ import { type CollectionBeforeValidateHook, type CollectionSlug } from '../../index.js';
2
+ export declare const ensureSafeCollectionsChange: ({ folderFieldName, foldersSlug, parentFieldName, typeFieldName, }: {
3
+ folderFieldName: string;
4
+ foldersSlug: CollectionSlug;
5
+ parentFieldName?: string;
6
+ typeFieldName?: string;
7
+ }) => CollectionBeforeValidateHook;
8
+ //# sourceMappingURL=ensureSafeCollectionsChange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensureSafeCollectionsChange.d.ts","sourceRoot":"","sources":["../../../src/hierarchy/hooks/ensureSafeCollectionsChange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,4BAA4B,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAIjG,eAAO,MAAM,2BAA2B,sEAMnC;IACD,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,cAAc,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,KAAG,4BAmIH,CAAA"}
@@ -0,0 +1,108 @@
1
+ import { APIError } from '../../index.js';
2
+ import { extractID } from '../../utilities/extractID.js';
3
+ import { getTranslatedLabel } from '../../utilities/getTranslatedLabel.js';
4
+ export const ensureSafeCollectionsChange = ({ folderFieldName, foldersSlug, parentFieldName = 'folder', typeFieldName = 'hierarchyType' })=>async ({ data, originalDoc, req })=>{
5
+ const currentFolderID = extractID(originalDoc || {});
6
+ const parentFolderID = extractID(data?.[parentFieldName] || originalDoc?.[parentFieldName] || {});
7
+ if (Array.isArray(data?.[typeFieldName]) && data[typeFieldName].length > 0) {
8
+ const typeFieldValue = data[typeFieldName];
9
+ const currentlyAssignedCollections = Array.isArray(originalDoc?.[typeFieldName]) && originalDoc[typeFieldName].length > 0 ? originalDoc[typeFieldName] : undefined;
10
+ /**
11
+ * Check if the assigned collections have changed.
12
+ * example:
13
+ * - originalAssignedCollections: ['posts', 'pages']
14
+ * - folderType: ['posts']
15
+ *
16
+ * The user is narrowing the types of documents that can be associated with this folder.
17
+ * If the user is only expanding the types of documents that can be associated with this folder,
18
+ * we do not need to do anything.
19
+ */ const newCollections = currentlyAssignedCollections ? currentlyAssignedCollections.filter((c)=>!typeFieldValue.includes(c)) : typeFieldValue;
20
+ if (newCollections && newCollections.length > 0) {
21
+ let dependentCollection = null;
22
+ if (typeof currentFolderID === 'string' || typeof currentFolderID === 'number') {
23
+ // Check each collection being removed for dependent documents
24
+ for (const collectionSlug of newCollections){
25
+ const result = await req.payload.find({
26
+ collection: collectionSlug,
27
+ limit: 1,
28
+ overrideAccess: true,
29
+ req,
30
+ where: {
31
+ [folderFieldName]: {
32
+ equals: currentFolderID
33
+ }
34
+ }
35
+ });
36
+ if (result.totalDocs > 0) {
37
+ dependentCollection = collectionSlug;
38
+ break;
39
+ }
40
+ }
41
+ // Also check for child folders with these types
42
+ if (!dependentCollection) {
43
+ const childFoldersResult = await req.payload.find({
44
+ collection: foldersSlug,
45
+ limit: 1,
46
+ overrideAccess: true,
47
+ req,
48
+ where: {
49
+ and: [
50
+ {
51
+ [typeFieldName]: {
52
+ in: newCollections
53
+ }
54
+ },
55
+ {
56
+ [parentFieldName]: {
57
+ equals: currentFolderID
58
+ }
59
+ }
60
+ ]
61
+ }
62
+ });
63
+ if (childFoldersResult.totalDocs > 0) {
64
+ dependentCollection = foldersSlug;
65
+ }
66
+ }
67
+ }
68
+ if (dependentCollection) {
69
+ const translatedLabels = newCollections.map((collectionSlug)=>{
70
+ if (req.payload.collections[collectionSlug]?.config.labels.singular) {
71
+ return getTranslatedLabel(req.payload.collections[collectionSlug]?.config.labels.plural, req.i18n);
72
+ }
73
+ return collectionSlug;
74
+ });
75
+ const isFolder = dependentCollection === foldersSlug;
76
+ throw new APIError(`The folder "${data.name || originalDoc.name}" contains ${isFolder ? 'folders' : 'documents'} that still belong to the following collections: ${translatedLabels.join(', ')}`, 400);
77
+ }
78
+ return data;
79
+ }
80
+ } else if ((data?.[typeFieldName] === null || Array.isArray(data?.[typeFieldName]) && data?.[typeFieldName].length === 0) && parentFolderID) {
81
+ // attempting to set the type to catch-all, so we need to ensure that the parent allows this
82
+ let parentFolder;
83
+ if (typeof parentFolderID === 'string' || typeof parentFolderID === 'number') {
84
+ try {
85
+ parentFolder = await req.payload.findByID({
86
+ id: parentFolderID,
87
+ collection: foldersSlug,
88
+ overrideAccess: true,
89
+ req,
90
+ select: {
91
+ name: true,
92
+ [typeFieldName]: true
93
+ },
94
+ user: req.user
95
+ });
96
+ } catch (_) {
97
+ // parent folder does not exist
98
+ }
99
+ }
100
+ const parentTypeValue = parentFolder?.[typeFieldName];
101
+ if (parentFolder && parentTypeValue && Array.isArray(parentTypeValue) && parentTypeValue.length > 0) {
102
+ throw new APIError(`The folder "${data?.name || originalDoc.name}" must have folder-type set since its parent folder ${parentFolder?.name ? `"${parentFolder?.name}" ` : ''}has a folder-type set.`, 400);
103
+ }
104
+ }
105
+ return data;
106
+ };
107
+
108
+ //# sourceMappingURL=ensureSafeCollectionsChange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/hierarchy/hooks/ensureSafeCollectionsChange.ts"],"sourcesContent":["import { APIError, type CollectionBeforeValidateHook, type CollectionSlug } from '../../index.js'\nimport { extractID } from '../../utilities/extractID.js'\nimport { getTranslatedLabel } from '../../utilities/getTranslatedLabel.js'\n\nexport const ensureSafeCollectionsChange =\n ({\n folderFieldName,\n foldersSlug,\n parentFieldName = 'folder',\n typeFieldName = 'hierarchyType',\n }: {\n folderFieldName: string\n foldersSlug: CollectionSlug\n parentFieldName?: string\n typeFieldName?: string\n }): CollectionBeforeValidateHook =>\n async ({ data, originalDoc, req }) => {\n const currentFolderID = extractID(originalDoc || {})\n const parentFolderID = extractID(\n data?.[parentFieldName] || originalDoc?.[parentFieldName] || {},\n )\n if (Array.isArray(data?.[typeFieldName]) && data[typeFieldName].length > 0) {\n const typeFieldValue = data[typeFieldName] as string[]\n const currentlyAssignedCollections: string[] | undefined =\n Array.isArray(originalDoc?.[typeFieldName]) && originalDoc[typeFieldName].length > 0\n ? originalDoc[typeFieldName]\n : undefined\n /**\n * Check if the assigned collections have changed.\n * example:\n * - originalAssignedCollections: ['posts', 'pages']\n * - folderType: ['posts']\n *\n * The user is narrowing the types of documents that can be associated with this folder.\n * If the user is only expanding the types of documents that can be associated with this folder,\n * we do not need to do anything.\n */\n const newCollections = currentlyAssignedCollections\n ? // user is narrowing the current scope of the folder\n currentlyAssignedCollections.filter((c) => !typeFieldValue.includes(c))\n : // user is adding a scope to the folder\n typeFieldValue\n\n if (newCollections && newCollections.length > 0) {\n let dependentCollection: null | string = null\n\n if (typeof currentFolderID === 'string' || typeof currentFolderID === 'number') {\n // Check each collection being removed for dependent documents\n for (const collectionSlug of newCollections) {\n const result = await req.payload.find({\n collection: collectionSlug,\n limit: 1,\n overrideAccess: true,\n req,\n where: {\n [folderFieldName]: { equals: currentFolderID },\n },\n })\n\n if (result.totalDocs > 0) {\n dependentCollection = collectionSlug\n break\n }\n }\n\n // Also check for child folders with these types\n if (!dependentCollection) {\n const childFoldersResult = await req.payload.find({\n collection: foldersSlug,\n limit: 1,\n overrideAccess: true,\n req,\n where: {\n and: [\n { [typeFieldName]: { in: newCollections } },\n { [parentFieldName]: { equals: currentFolderID } },\n ],\n },\n })\n\n if (childFoldersResult.totalDocs > 0) {\n dependentCollection = foldersSlug\n }\n }\n }\n\n if (dependentCollection) {\n const translatedLabels = newCollections.map((collectionSlug) => {\n if (req.payload.collections[collectionSlug]?.config.labels.singular) {\n return getTranslatedLabel(\n req.payload.collections[collectionSlug]?.config.labels.plural,\n req.i18n,\n )\n }\n return collectionSlug\n })\n\n const isFolder = dependentCollection === foldersSlug\n throw new APIError(\n `The folder \"${data.name || originalDoc.name}\" contains ${isFolder ? 'folders' : 'documents'} that still belong to the following collections: ${translatedLabels.join(', ')}`,\n 400,\n )\n }\n\n return data\n }\n } else if (\n (data?.[typeFieldName] === null ||\n (Array.isArray(data?.[typeFieldName]) && data?.[typeFieldName].length === 0)) &&\n parentFolderID\n ) {\n // attempting to set the type to catch-all, so we need to ensure that the parent allows this\n let parentFolder\n if (typeof parentFolderID === 'string' || typeof parentFolderID === 'number') {\n try {\n parentFolder = await req.payload.findByID({\n id: parentFolderID,\n collection: foldersSlug,\n overrideAccess: true,\n req,\n select: {\n name: true,\n [typeFieldName]: true,\n },\n user: req.user,\n })\n } catch (_) {\n // parent folder does not exist\n }\n }\n\n const parentTypeValue = parentFolder?.[typeFieldName]\n if (\n parentFolder &&\n parentTypeValue &&\n Array.isArray(parentTypeValue) &&\n parentTypeValue.length > 0\n ) {\n throw new APIError(\n `The folder \"${data?.name || originalDoc.name}\" must have folder-type set since its parent folder ${parentFolder?.name ? `\"${parentFolder?.name}\" ` : ''}has a folder-type set.`,\n 400,\n )\n }\n }\n\n return data\n }\n"],"names":["APIError","extractID","getTranslatedLabel","ensureSafeCollectionsChange","folderFieldName","foldersSlug","parentFieldName","typeFieldName","data","originalDoc","req","currentFolderID","parentFolderID","Array","isArray","length","typeFieldValue","currentlyAssignedCollections","undefined","newCollections","filter","c","includes","dependentCollection","collectionSlug","result","payload","find","collection","limit","overrideAccess","where","equals","totalDocs","childFoldersResult","and","in","translatedLabels","map","collections","config","labels","singular","plural","i18n","isFolder","name","join","parentFolder","findByID","id","select","user","_","parentTypeValue"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { CollectionConfig } from '../collections/config/types.js';
2
+ /**
3
+ * Injects the HierarchyButton component into a collection's BeforeDocumentMeta slot.
4
+ *
5
+ * The HierarchyButton provides a header UI for selecting parent hierarchy items
6
+ * via miller columns, replacing the standard relationship field input.
7
+ */
8
+ export declare const injectHierarchyButton: ({ collection, fieldName, hierarchyCollectionSlug, parentFieldName, }: {
9
+ collection: CollectionConfig;
10
+ fieldName: string;
11
+ hierarchyCollectionSlug: string;
12
+ parentFieldName: string;
13
+ }) => void;
14
+ //# sourceMappingURL=injectHierarchyButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injectHierarchyButton.d.ts","sourceRoot":"","sources":["../../src/hierarchy/injectHierarchyButton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,yEAK/B;IACD,UAAU,EAAE,gBAAgB,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,eAAe,EAAE,MAAM,CAAA;CACxB,KAAG,IAiCH,CAAA"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Injects the HierarchyButton component into a collection's BeforeDocumentMeta slot.
3
+ *
4
+ * The HierarchyButton provides a header UI for selecting parent hierarchy items
5
+ * via miller columns, replacing the standard relationship field input.
6
+ */ export const injectHierarchyButton = ({ collection, fieldName, hierarchyCollectionSlug, parentFieldName })=>{
7
+ collection.admin = collection.admin || {};
8
+ collection.admin.components = collection.admin.components || {};
9
+ collection.admin.components.edit = collection.admin.components.edit || {};
10
+ const hierarchyComponent = {
11
+ path: '@payloadcms/ui/rsc#HierarchyButton',
12
+ serverProps: {
13
+ fieldName,
14
+ hierarchyCollectionSlug,
15
+ parentFieldName
16
+ }
17
+ };
18
+ const existingComponents = collection.admin.components.edit.BeforeDocumentMeta || [];
19
+ const componentPath = '@payloadcms/ui/rsc#HierarchyButton';
20
+ const alreadyInjected = existingComponents.some((c)=>{
21
+ if (typeof c === 'string') {
22
+ return c === componentPath;
23
+ }
24
+ if (c && typeof c === 'object' && 'path' in c) {
25
+ return c.path === componentPath;
26
+ }
27
+ return false;
28
+ });
29
+ if (!alreadyInjected) {
30
+ collection.admin.components.edit.BeforeDocumentMeta = [
31
+ hierarchyComponent,
32
+ ...existingComponents
33
+ ];
34
+ }
35
+ };
36
+
37
+ //# sourceMappingURL=injectHierarchyButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hierarchy/injectHierarchyButton.ts"],"sourcesContent":["import type { CollectionConfig } from '../collections/config/types.js'\n\n/**\n * Injects the HierarchyButton component into a collection's BeforeDocumentMeta slot.\n *\n * The HierarchyButton provides a header UI for selecting parent hierarchy items\n * via miller columns, replacing the standard relationship field input.\n */\nexport const injectHierarchyButton = ({\n collection,\n fieldName,\n hierarchyCollectionSlug,\n parentFieldName,\n}: {\n collection: CollectionConfig\n fieldName: string\n hierarchyCollectionSlug: string\n parentFieldName: string\n}): void => {\n collection.admin = collection.admin || {}\n collection.admin.components = collection.admin.components || {}\n collection.admin.components.edit = collection.admin.components.edit || {}\n\n const hierarchyComponent = {\n path: '@payloadcms/ui/rsc#HierarchyButton',\n serverProps: {\n fieldName,\n hierarchyCollectionSlug,\n parentFieldName,\n },\n }\n\n const existingComponents = collection.admin.components.edit.BeforeDocumentMeta || []\n const componentPath = '@payloadcms/ui/rsc#HierarchyButton'\n\n const alreadyInjected = existingComponents.some((c) => {\n if (typeof c === 'string') {\n return c === componentPath\n }\n if (c && typeof c === 'object' && 'path' in c) {\n return c.path === componentPath\n }\n return false\n })\n\n if (!alreadyInjected) {\n collection.admin.components.edit.BeforeDocumentMeta = [\n hierarchyComponent,\n ...existingComponents,\n ]\n }\n}\n"],"names":["injectHierarchyButton","collection","fieldName","hierarchyCollectionSlug","parentFieldName","admin","components","edit","hierarchyComponent","path","serverProps","existingComponents","BeforeDocumentMeta","componentPath","alreadyInjected","some","c"],"mappings":"AAEA;;;;;CAKC,GACD,OAAO,MAAMA,wBAAwB,CAAC,EACpCC,UAAU,EACVC,SAAS,EACTC,uBAAuB,EACvBC,eAAe,EAMhB;IACCH,WAAWI,KAAK,GAAGJ,WAAWI,KAAK,IAAI,CAAC;IACxCJ,WAAWI,KAAK,CAACC,UAAU,GAAGL,WAAWI,KAAK,CAACC,UAAU,IAAI,CAAC;IAC9DL,WAAWI,KAAK,CAACC,UAAU,CAACC,IAAI,GAAGN,WAAWI,KAAK,CAACC,UAAU,CAACC,IAAI,IAAI,CAAC;IAExE,MAAMC,qBAAqB;QACzBC,MAAM;QACNC,aAAa;YACXR;YACAC;YACAC;QACF;IACF;IAEA,MAAMO,qBAAqBV,WAAWI,KAAK,CAACC,UAAU,CAACC,IAAI,CAACK,kBAAkB,IAAI,EAAE;IACpF,MAAMC,gBAAgB;IAEtB,MAAMC,kBAAkBH,mBAAmBI,IAAI,CAAC,CAACC;QAC/C,IAAI,OAAOA,MAAM,UAAU;YACzB,OAAOA,MAAMH;QACf;QACA,IAAIG,KAAK,OAAOA,MAAM,YAAY,UAAUA,GAAG;YAC7C,OAAOA,EAAEP,IAAI,KAAKI;QACpB;QACA,OAAO;IACT;IAEA,IAAI,CAACC,iBAAiB;QACpBb,WAAWI,KAAK,CAACC,UAAU,CAACC,IAAI,CAACK,kBAAkB,GAAG;YACpDJ;eACGG;SACJ;IACH;AACF,EAAC"}
@@ -0,0 +1,24 @@
1
+ import type { PaginatedDocs, PayloadRequest, SanitizedCollectionConfig } from '../../index.js';
2
+ type RelatedDocumentsResult = {
3
+ [collectionSlug: string]: PaginatedDocs;
4
+ };
5
+ type Args = {
6
+ collection: SanitizedCollectionConfig;
7
+ depth?: number;
8
+ id: number | string;
9
+ limit?: number;
10
+ page?: number;
11
+ req: PayloadRequest;
12
+ };
13
+ /**
14
+ * Find all documents across collections that reference a hierarchy item
15
+ *
16
+ * This operation:
17
+ * 1. Finds child hierarchy items (same collection with matching parent)
18
+ * 2. Uses pre-computed relatedCollections from sanitized hierarchy config
19
+ * 3. Queries each related collection for documents referencing this hierarchy item
20
+ * 4. Returns grouped results by collection slug
21
+ */
22
+ export declare function findRelatedDocuments({ id, collection, depth, limit, page, req, }: Args): Promise<RelatedDocumentsResult>;
23
+ export {};
24
+ //# sourceMappingURL=findRelatedDocuments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findRelatedDocuments.d.ts","sourceRoot":"","sources":["../../../src/hierarchy/operations/findRelatedDocuments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,yBAAyB,EAE1B,MAAM,gBAAgB,CAAA;AAEvB,KAAK,sBAAsB,GAAG;IAC5B,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,CAAA;CACxC,CAAA;AAED,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,yBAAyB,CAAA;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,EAAE,EACF,UAAU,EACV,KAAS,EACT,KAAU,EACV,IAAQ,EACR,GAAG,GACJ,EAAE,IAAI,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAuExC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Find all documents across collections that reference a hierarchy item
3
+ *
4
+ * This operation:
5
+ * 1. Finds child hierarchy items (same collection with matching parent)
6
+ * 2. Uses pre-computed relatedCollections from sanitized hierarchy config
7
+ * 3. Queries each related collection for documents referencing this hierarchy item
8
+ * 4. Returns grouped results by collection slug
9
+ */ export async function findRelatedDocuments({ id, collection, depth = 0, limit = 50, page = 1, req }) {
10
+ const { payload } = req;
11
+ const results = {};
12
+ // Get the parent field name from hierarchy config
13
+ const hierarchyConfig = collection.hierarchy;
14
+ const parentFieldName = hierarchyConfig && typeof hierarchyConfig === 'object' ? hierarchyConfig.parentFieldName : undefined;
15
+ if (!parentFieldName) {
16
+ return results;
17
+ }
18
+ // 1. Query child hierarchy items (same collection)
19
+ results[collection.slug] = await payload.find({
20
+ collection: collection.slug,
21
+ depth,
22
+ limit,
23
+ overrideAccess: false,
24
+ page,
25
+ req,
26
+ user: req.user,
27
+ where: {
28
+ [parentFieldName]: {
29
+ equals: id
30
+ }
31
+ }
32
+ });
33
+ // 2. Use pre-computed relatedCollections from sanitized hierarchy config
34
+ const relatedCollectionsConfig = (hierarchyConfig && typeof hierarchyConfig === 'object' ? hierarchyConfig.relatedCollections : undefined) || {};
35
+ // 3. Query each related collection
36
+ for (const [relatedSlug, fieldInfo] of Object.entries(relatedCollectionsConfig)){
37
+ const relatedCollection = payload.config.collections.find((c)=>c.slug === relatedSlug);
38
+ if (!relatedCollection) {
39
+ continue;
40
+ }
41
+ const { fieldName, hasMany } = fieldInfo;
42
+ // Build where clause using pre-computed field info
43
+ const where = {
44
+ [fieldName]: hasMany ? {
45
+ in: [
46
+ id
47
+ ]
48
+ } : {
49
+ equals: id
50
+ }
51
+ };
52
+ try {
53
+ results[relatedSlug] = await payload.find({
54
+ collection: relatedSlug,
55
+ depth,
56
+ limit,
57
+ overrideAccess: false,
58
+ page,
59
+ req,
60
+ user: req.user,
61
+ where
62
+ });
63
+ } catch (error) {
64
+ req.payload.logger.warn({
65
+ err: error,
66
+ msg: `Failed to query ${relatedSlug} for hierarchy ${collection.slug}:${id}`
67
+ });
68
+ }
69
+ }
70
+ return results;
71
+ }
72
+
73
+ //# sourceMappingURL=findRelatedDocuments.js.map