@strapi/content-type-builder 0.0.0 → 5.0.0-beta.6

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 (316) hide show
  1. package/README.md +1 -1
  2. package/dist/_chunks/ListView-BG19KtnI.js +963 -0
  3. package/dist/_chunks/ListView-BG19KtnI.js.map +1 -0
  4. package/dist/_chunks/ListView-C-9-V_FI.mjs +957 -0
  5. package/dist/_chunks/ListView-C-9-V_FI.mjs.map +1 -0
  6. package/dist/_chunks/ar-BYDB75EB.mjs +51 -0
  7. package/dist/_chunks/ar-BYDB75EB.mjs.map +1 -0
  8. package/dist/_chunks/ar-OCxhAFUy.js +51 -0
  9. package/dist/_chunks/ar-OCxhAFUy.js.map +1 -0
  10. package/dist/_chunks/cs-ChL4LaFY.mjs +139 -0
  11. package/dist/_chunks/cs-ChL4LaFY.mjs.map +1 -0
  12. package/dist/_chunks/cs-Ci3js5EC.js +139 -0
  13. package/dist/_chunks/cs-Ci3js5EC.js.map +1 -0
  14. package/dist/_chunks/de-DnlblIOh.js +193 -0
  15. package/dist/_chunks/de-DnlblIOh.js.map +1 -0
  16. package/dist/_chunks/de-DsHQNzp2.mjs +193 -0
  17. package/dist/_chunks/de-DsHQNzp2.mjs.map +1 -0
  18. package/dist/_chunks/dk-BC7NAQR2.mjs +183 -0
  19. package/dist/_chunks/dk-BC7NAQR2.mjs.map +1 -0
  20. package/dist/_chunks/dk-D3XnOjYz.js +183 -0
  21. package/dist/_chunks/dk-D3XnOjYz.js.map +1 -0
  22. package/dist/_chunks/en-BbczxQBr.mjs +216 -0
  23. package/dist/_chunks/en-BbczxQBr.mjs.map +1 -0
  24. package/dist/_chunks/en-BnToboMV.js +216 -0
  25. package/dist/_chunks/en-BnToboMV.js.map +1 -0
  26. package/dist/_chunks/es-BE_zx2_w.mjs +183 -0
  27. package/dist/_chunks/es-BE_zx2_w.mjs.map +1 -0
  28. package/dist/_chunks/es-DL8lez9W.js +183 -0
  29. package/dist/_chunks/es-DL8lez9W.js.map +1 -0
  30. package/dist/_chunks/fr-DnTxugIo.js +75 -0
  31. package/dist/_chunks/fr-DnTxugIo.js.map +1 -0
  32. package/dist/_chunks/fr-lU_OMJma.mjs +75 -0
  33. package/dist/_chunks/fr-lU_OMJma.mjs.map +1 -0
  34. package/dist/_chunks/id-DYuTgqcc.js +166 -0
  35. package/dist/_chunks/id-DYuTgqcc.js.map +1 -0
  36. package/dist/_chunks/id-W1sKBFEw.mjs +166 -0
  37. package/dist/_chunks/id-W1sKBFEw.mjs.map +1 -0
  38. package/dist/_chunks/index-BfUcwV-B.js +1211 -0
  39. package/dist/_chunks/index-BfUcwV-B.js.map +1 -0
  40. package/dist/_chunks/index-BtxPpV-M.mjs +6843 -0
  41. package/dist/_chunks/index-BtxPpV-M.mjs.map +1 -0
  42. package/dist/_chunks/index-CBlX4byY.mjs +1185 -0
  43. package/dist/_chunks/index-CBlX4byY.mjs.map +1 -0
  44. package/dist/_chunks/index-ClkMXXk0.js +6881 -0
  45. package/dist/_chunks/index-ClkMXXk0.js.map +1 -0
  46. package/dist/_chunks/it-D04lb2Wc.mjs +167 -0
  47. package/dist/_chunks/it-D04lb2Wc.mjs.map +1 -0
  48. package/dist/_chunks/it-DS4sM3km.js +167 -0
  49. package/dist/_chunks/it-DS4sM3km.js.map +1 -0
  50. package/dist/_chunks/ja-BHLK_2_g.mjs +50 -0
  51. package/dist/_chunks/ja-BHLK_2_g.mjs.map +1 -0
  52. package/dist/_chunks/ja-BjouJgZf.js +50 -0
  53. package/dist/_chunks/ja-BjouJgZf.js.map +1 -0
  54. package/dist/_chunks/ko-D_71Pdfn.js +183 -0
  55. package/dist/_chunks/ko-D_71Pdfn.js.map +1 -0
  56. package/dist/_chunks/ko-DoNsXHXA.mjs +183 -0
  57. package/dist/_chunks/ko-DoNsXHXA.mjs.map +1 -0
  58. package/dist/_chunks/ms-BtGFDB9t.mjs +163 -0
  59. package/dist/_chunks/ms-BtGFDB9t.mjs.map +1 -0
  60. package/dist/_chunks/ms-Re1pSHmx.js +163 -0
  61. package/dist/_chunks/ms-Re1pSHmx.js.map +1 -0
  62. package/dist/_chunks/nl-BaTAuelQ.mjs +156 -0
  63. package/dist/_chunks/nl-BaTAuelQ.mjs.map +1 -0
  64. package/dist/_chunks/nl-DQjrDEw0.js +156 -0
  65. package/dist/_chunks/nl-DQjrDEw0.js.map +1 -0
  66. package/dist/_chunks/pl-BGwXgwH7.js +193 -0
  67. package/dist/_chunks/pl-BGwXgwH7.js.map +1 -0
  68. package/dist/_chunks/pl-CP2Zgp01.mjs +193 -0
  69. package/dist/_chunks/pl-CP2Zgp01.mjs.map +1 -0
  70. package/dist/_chunks/pt-BR-CCQGwXs0.mjs +193 -0
  71. package/dist/_chunks/pt-BR-CCQGwXs0.mjs.map +1 -0
  72. package/dist/_chunks/pt-BR-DPd5nRnl.js +193 -0
  73. package/dist/_chunks/pt-BR-DPd5nRnl.js.map +1 -0
  74. package/dist/_chunks/pt-CJoUDTHQ.js +51 -0
  75. package/dist/_chunks/pt-CJoUDTHQ.js.map +1 -0
  76. package/dist/_chunks/pt-DMeTMW2x.mjs +51 -0
  77. package/dist/_chunks/pt-DMeTMW2x.mjs.map +1 -0
  78. package/dist/_chunks/ru-C8A_4j0w.js +168 -0
  79. package/dist/_chunks/ru-C8A_4j0w.js.map +1 -0
  80. package/dist/_chunks/ru-DGSjru5m.mjs +168 -0
  81. package/dist/_chunks/ru-DGSjru5m.mjs.map +1 -0
  82. package/dist/_chunks/sk-DVK4HfSC.mjs +167 -0
  83. package/dist/_chunks/sk-DVK4HfSC.mjs.map +1 -0
  84. package/dist/_chunks/sk-raWRcmPT.js +167 -0
  85. package/dist/_chunks/sk-raWRcmPT.js.map +1 -0
  86. package/dist/_chunks/sv-BGb12eW3.mjs +202 -0
  87. package/dist/_chunks/sv-BGb12eW3.mjs.map +1 -0
  88. package/dist/_chunks/sv-BNN71SFE.js +202 -0
  89. package/dist/_chunks/sv-BNN71SFE.js.map +1 -0
  90. package/dist/_chunks/th--u3VqsON.mjs +164 -0
  91. package/dist/_chunks/th--u3VqsON.mjs.map +1 -0
  92. package/dist/_chunks/th-C83Bb_kR.js +164 -0
  93. package/dist/_chunks/th-C83Bb_kR.js.map +1 -0
  94. package/dist/_chunks/tr-BW20CfcO.js +179 -0
  95. package/dist/_chunks/tr-BW20CfcO.js.map +1 -0
  96. package/dist/_chunks/tr-DsUerr-c.mjs +179 -0
  97. package/dist/_chunks/tr-DsUerr-c.mjs.map +1 -0
  98. package/dist/_chunks/uk-Bx5IlOKX.mjs +164 -0
  99. package/dist/_chunks/uk-Bx5IlOKX.mjs.map +1 -0
  100. package/dist/_chunks/uk-VwB0oiuV.js +164 -0
  101. package/dist/_chunks/uk-VwB0oiuV.js.map +1 -0
  102. package/dist/_chunks/zh-BiOCwPJu.js +202 -0
  103. package/dist/_chunks/zh-BiOCwPJu.js.map +1 -0
  104. package/dist/_chunks/zh-CsUDN13W.mjs +202 -0
  105. package/dist/_chunks/zh-CsUDN13W.mjs.map +1 -0
  106. package/dist/_chunks/zh-Hans-CLTLm_nt.js +147 -0
  107. package/dist/_chunks/zh-Hans-CLTLm_nt.js.map +1 -0
  108. package/dist/_chunks/zh-Hans-Cc0M5PXr.mjs +147 -0
  109. package/dist/_chunks/zh-Hans-Cc0M5PXr.mjs.map +1 -0
  110. package/dist/admin/index.js +4 -0
  111. package/dist/admin/index.js.map +1 -0
  112. package/dist/admin/index.mjs +5 -0
  113. package/dist/admin/index.mjs.map +1 -0
  114. package/dist/admin/src/components/AllowedTypesSelect.d.ts +9 -0
  115. package/dist/admin/src/components/AttributeIcon.d.ts +9 -0
  116. package/dist/admin/src/components/AttributeOptions/AttributeList.d.ts +6 -0
  117. package/dist/admin/src/components/AttributeOptions/AttributeOption.d.ts +11 -0
  118. package/dist/admin/src/components/AttributeOptions/AttributeOptions.d.ts +13 -0
  119. package/dist/admin/src/components/AttributeOptions/CustomFieldOption.d.ts +22 -0
  120. package/dist/admin/src/components/AttributeOptions/CustomFieldsList.d.ts +1 -0
  121. package/dist/admin/src/components/AttributeOptions/EmptyAttributes.d.ts +2 -0
  122. package/dist/admin/src/components/AttributeOptions/OptionBoxWrapper.d.ts +1 -0
  123. package/dist/admin/src/components/AutoReloadOverlayBlocker.d.ts +25 -0
  124. package/dist/admin/src/components/BooleanDefaultValueSelect.d.ts +20 -0
  125. package/dist/admin/src/components/BooleanRadioGroup.d.ts +8 -0
  126. package/dist/admin/src/components/BoxWrapper.d.ts +1 -0
  127. package/dist/admin/src/components/CheckboxWithNumberField.d.ts +11 -0
  128. package/dist/admin/src/components/ComponentCard/ComponentCard.d.ts +10 -0
  129. package/dist/admin/src/components/ComponentCard/ComponentIcon/ComponentIcon.d.ts +7 -0
  130. package/dist/admin/src/components/ComponentCard/ComponentIcon/index.d.ts +1 -0
  131. package/dist/admin/src/components/ComponentCard/index.d.ts +1 -0
  132. package/dist/admin/src/components/ComponentList.d.ts +10 -0
  133. package/dist/admin/src/components/ContentTypeBuilderNav/ContentTypeBuilderNav.d.ts +1 -0
  134. package/dist/admin/src/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.d.ts +18 -0
  135. package/dist/admin/src/components/ContentTypeRadioGroup.d.ts +15 -0
  136. package/dist/admin/src/components/CustomRadioGroup/CustomRadioGroup.d.ts +15 -0
  137. package/dist/admin/src/components/CustomRadioGroup/Styles.d.ts +2 -0
  138. package/dist/admin/src/components/CustomRadioGroup/index.d.ts +1 -0
  139. package/dist/admin/src/components/DataManagerProvider/DataManagerProvider.d.ts +6 -0
  140. package/dist/admin/src/components/DataManagerProvider/constants.d.ts +17 -0
  141. package/dist/admin/src/components/DataManagerProvider/reducer.d.ts +12 -0
  142. package/dist/admin/src/components/DataManagerProvider/selectors.d.ts +17 -0
  143. package/dist/admin/src/components/DataManagerProvider/utils/cleanData.d.ts +23 -0
  144. package/dist/admin/src/components/DataManagerProvider/utils/createDataObject.d.ts +2 -0
  145. package/dist/admin/src/components/DataManagerProvider/utils/createModifiedDataSchema.d.ts +6 -0
  146. package/dist/admin/src/components/DataManagerProvider/utils/formatSchemas.d.ts +6 -0
  147. package/dist/admin/src/components/DataManagerProvider/utils/retrieveComponentsFromSchema.d.ts +4 -0
  148. package/dist/admin/src/components/DataManagerProvider/utils/retrieveComponentsThatHaveComponents.d.ts +4 -0
  149. package/dist/admin/src/components/DataManagerProvider/utils/retrieveNestedComponents.d.ts +1 -0
  150. package/dist/admin/src/components/DataManagerProvider/utils/retrieveSpecificInfoFromComponents.d.ts +1 -0
  151. package/dist/admin/src/components/DataManagerProvider/utils/serverRestartWatcher.d.ts +6 -0
  152. package/dist/admin/src/components/DataManagerProvider/utils/validateSchema.d.ts +1 -0
  153. package/dist/admin/src/components/DisplayedType.d.ts +7 -0
  154. package/dist/admin/src/components/DraftAndPublishToggle.d.ts +27 -0
  155. package/dist/admin/src/components/DynamicZoneList.d.ts +10 -0
  156. package/dist/admin/src/components/FormModal/FormModal.d.ts +1 -0
  157. package/dist/admin/src/components/FormModal/attributes/advancedForm.d.ts +416 -0
  158. package/dist/admin/src/components/FormModal/attributes/attributeOptions.d.ts +90 -0
  159. package/dist/admin/src/components/FormModal/attributes/baseForm.d.ts +376 -0
  160. package/dist/admin/src/components/FormModal/attributes/commonBaseForm.d.ts +17 -0
  161. package/dist/admin/src/components/FormModal/attributes/form.d.ts +792 -0
  162. package/dist/admin/src/components/FormModal/attributes/nameField.d.ts +12 -0
  163. package/dist/admin/src/components/FormModal/attributes/types.d.ts +325 -0
  164. package/dist/admin/src/components/FormModal/attributes/validation/common.d.ts +29 -0
  165. package/dist/admin/src/components/FormModal/category/createCategorySchema.d.ts +5 -0
  166. package/dist/admin/src/components/FormModal/category/form.d.ts +20 -0
  167. package/dist/admin/src/components/FormModal/category/regex.d.ts +1 -0
  168. package/dist/admin/src/components/FormModal/component/componentField.d.ts +20 -0
  169. package/dist/admin/src/components/FormModal/component/componentForm.d.ts +25 -0
  170. package/dist/admin/src/components/FormModal/component/createComponentSchema.d.ts +10 -0
  171. package/dist/admin/src/components/FormModal/constants.d.ts +12 -0
  172. package/dist/admin/src/components/FormModal/contentType/contentTypeForm.d.ts +116 -0
  173. package/dist/admin/src/components/FormModal/contentType/createContentTypeSchema.d.ts +24 -0
  174. package/dist/admin/src/components/FormModal/dynamiczoneForm.d.ts +68 -0
  175. package/dist/admin/src/components/FormModal/forms/forms.d.ts +207 -0
  176. package/dist/admin/src/components/FormModal/forms/utils/addItemsToFormSection.d.ts +38 -0
  177. package/dist/admin/src/components/FormModal/forms/utils/createCollectionName.d.ts +2 -0
  178. package/dist/admin/src/components/FormModal/forms/utils/getUsedAttributeNames.d.ts +11 -0
  179. package/dist/admin/src/components/FormModal/reducer.d.ts +4 -0
  180. package/dist/admin/src/components/FormModal/selectors.d.ts +16 -0
  181. package/dist/admin/src/components/FormModal/utils/canEditContentType.d.ts +18 -0
  182. package/dist/admin/src/components/FormModal/utils/createUid.d.ts +4 -0
  183. package/dist/admin/src/components/FormModal/utils/customFieldDefaultOptionsReducer.d.ts +1 -0
  184. package/dist/admin/src/components/FormModal/utils/getAttributesToDisplay.d.ts +3 -0
  185. package/dist/admin/src/components/FormModal/utils/getFormInputNames.d.ts +1 -0
  186. package/dist/admin/src/components/FormModal/utils/relations.d.ts +4 -0
  187. package/dist/admin/src/components/FormModalEndActions.d.ts +42 -0
  188. package/dist/admin/src/components/FormModalHeader.d.ts +18 -0
  189. package/dist/admin/src/components/FormModalNavigationProvider/FormModalNavigationProvider.d.ts +22 -0
  190. package/dist/admin/src/components/FormModalNavigationProvider/constants.d.ts +16 -0
  191. package/dist/admin/src/components/FormModalSubHeader.d.ts +22 -0
  192. package/dist/admin/src/components/GenericInputs.d.ts +57 -0
  193. package/dist/admin/src/components/IconPicker/IconPicker.d.ts +13 -0
  194. package/dist/admin/src/components/IconPicker/constants.d.ts +5 -0
  195. package/dist/admin/src/components/IconPicker/index.d.ts +1 -0
  196. package/dist/admin/src/components/List.d.ts +18 -0
  197. package/dist/admin/src/components/ListRow.d.ts +20 -0
  198. package/dist/admin/src/components/NestedFooter.d.ts +9 -0
  199. package/dist/admin/src/components/PluginIcon.d.ts +1 -0
  200. package/dist/admin/src/components/PluralName.d.ts +22 -0
  201. package/dist/admin/src/components/Relation/Relation.d.ts +9 -0
  202. package/dist/admin/src/components/Relation/RelationField/RelationField.d.ts +13 -0
  203. package/dist/admin/src/components/Relation/RelationField/RelationTargetPicker/RelationTargetPicker.d.ts +6 -0
  204. package/dist/admin/src/components/Relation/RelationNaturePicker/Components.d.ts +48 -0
  205. package/dist/admin/src/components/Relation/RelationNaturePicker/RelationNaturePicker.d.ts +8 -0
  206. package/dist/admin/src/components/SelectCategory.d.ts +19 -0
  207. package/dist/admin/src/components/SelectComponent.d.ts +19 -0
  208. package/dist/admin/src/components/SelectComponents.d.ts +19 -0
  209. package/dist/admin/src/components/SelectDateType.d.ts +38 -0
  210. package/dist/admin/src/components/SelectNumber.d.ts +42 -0
  211. package/dist/admin/src/components/SingularName.d.ts +17 -0
  212. package/dist/admin/src/components/TabForm.d.ts +9 -0
  213. package/dist/admin/src/components/TextareaEnum.d.ts +20 -0
  214. package/dist/admin/src/components/Tr.d.ts +6 -0
  215. package/dist/admin/src/components/UpperFirst.d.ts +3 -0
  216. package/dist/admin/src/constants.d.ts +6 -0
  217. package/dist/admin/src/contexts/DataManagerContext.d.ts +41 -0
  218. package/dist/admin/src/contexts/FormModalNavigationContext.d.ts +38 -0
  219. package/dist/admin/src/hooks/useDataManager.d.ts +1 -0
  220. package/dist/admin/src/hooks/useFormModalNavigation.d.ts +1 -0
  221. package/dist/admin/src/icons/Curve.d.ts +5 -0
  222. package/dist/admin/src/index.d.ts +16 -0
  223. package/dist/admin/src/pages/App/index.d.ts +2 -0
  224. package/dist/admin/src/pages/ListView/LinkToCMSettingsView.d.ts +10 -0
  225. package/dist/admin/src/pages/ListView/ListView.d.ts +2 -0
  226. package/dist/admin/src/pages/RecursivePath/RecursivePath.d.ts +1 -0
  227. package/dist/admin/src/pluginId.d.ts +1 -0
  228. package/dist/admin/src/reducers.d.ts +3 -0
  229. package/dist/admin/src/types.d.ts +57 -0
  230. package/dist/admin/src/utils/findAttribute.d.ts +2 -0
  231. package/dist/admin/src/utils/formAPI.d.ts +1 -0
  232. package/dist/admin/src/utils/getAttributeDisplayedType.d.ts +1 -0
  233. package/dist/admin/src/utils/getRelationType.d.ts +6 -0
  234. package/dist/admin/src/utils/getTrad.d.ts +1 -0
  235. package/dist/admin/src/utils/getYupInnerErrors.d.ts +7 -0
  236. package/dist/admin/src/utils/index.d.ts +2 -0
  237. package/dist/admin/src/utils/isAllowedContentTypesForRelations.d.ts +2 -0
  238. package/dist/admin/src/utils/makeUnique.d.ts +2 -0
  239. package/dist/admin/src/utils/nameToSlug.d.ts +1 -0
  240. package/dist/admin/src/utils/prefixPluginTranslations.d.ts +3 -0
  241. package/dist/admin/src/utils/startsWithANumber.d.ts +1 -0
  242. package/dist/admin/src/utils/toRegressedEnumValue.d.ts +1 -0
  243. package/dist/server/index.js +2312 -0
  244. package/dist/server/index.js.map +1 -0
  245. package/dist/server/index.mjs +2291 -0
  246. package/dist/server/index.mjs.map +1 -0
  247. package/dist/server/src/bootstrap.d.ts +6 -0
  248. package/dist/server/src/bootstrap.d.ts.map +1 -0
  249. package/dist/server/src/config.d.ts +6 -0
  250. package/dist/server/src/config.d.ts.map +1 -0
  251. package/dist/server/src/controllers/builder.d.ts +6 -0
  252. package/dist/server/src/controllers/builder.d.ts.map +1 -0
  253. package/dist/server/src/controllers/component-categories.d.ts +7 -0
  254. package/dist/server/src/controllers/component-categories.d.ts.map +1 -0
  255. package/dist/server/src/controllers/components.d.ts +38 -0
  256. package/dist/server/src/controllers/components.d.ts.map +1 -0
  257. package/dist/server/src/controllers/content-types.d.ts +10 -0
  258. package/dist/server/src/controllers/content-types.d.ts.map +1 -0
  259. package/dist/server/src/controllers/index.d.ts +25 -0
  260. package/dist/server/src/controllers/index.d.ts.map +1 -0
  261. package/dist/server/src/controllers/validation/common.d.ts +25 -0
  262. package/dist/server/src/controllers/validation/common.d.ts.map +1 -0
  263. package/dist/server/src/controllers/validation/component-category.d.ts +5 -0
  264. package/dist/server/src/controllers/validation/component-category.d.ts.map +1 -0
  265. package/dist/server/src/controllers/validation/component.d.ts +25 -0
  266. package/dist/server/src/controllers/validation/component.d.ts.map +1 -0
  267. package/dist/server/src/controllers/validation/content-type.d.ts +36 -0
  268. package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -0
  269. package/dist/server/src/controllers/validation/data-transform.d.ts +4 -0
  270. package/dist/server/src/controllers/validation/data-transform.d.ts.map +1 -0
  271. package/dist/server/src/controllers/validation/model-schema.d.ts +12 -0
  272. package/dist/server/src/controllers/validation/model-schema.d.ts.map +1 -0
  273. package/dist/server/src/controllers/validation/relations.d.ts +16 -0
  274. package/dist/server/src/controllers/validation/relations.d.ts.map +1 -0
  275. package/dist/server/src/controllers/validation/types.d.ts +9 -0
  276. package/dist/server/src/controllers/validation/types.d.ts.map +1 -0
  277. package/dist/server/src/index.d.ts +68 -0
  278. package/dist/server/src/index.d.ts.map +1 -0
  279. package/dist/server/src/routes/admin.d.ts +18 -0
  280. package/dist/server/src/routes/admin.d.ts.map +1 -0
  281. package/dist/server/src/routes/content-api.d.ts +10 -0
  282. package/dist/server/src/routes/content-api.d.ts.map +1 -0
  283. package/dist/server/src/routes/index.d.ts +28 -0
  284. package/dist/server/src/routes/index.d.ts.map +1 -0
  285. package/dist/server/src/services/api-handler.d.ts +15 -0
  286. package/dist/server/src/services/api-handler.d.ts.map +1 -0
  287. package/dist/server/src/services/builder.d.ts +5 -0
  288. package/dist/server/src/services/builder.d.ts.map +1 -0
  289. package/dist/server/src/services/component-categories.d.ts +13 -0
  290. package/dist/server/src/services/component-categories.d.ts.map +1 -0
  291. package/dist/server/src/services/components.d.ts +54 -0
  292. package/dist/server/src/services/components.d.ts.map +1 -0
  293. package/dist/server/src/services/constants.d.ts +19 -0
  294. package/dist/server/src/services/constants.d.ts.map +1 -0
  295. package/dist/server/src/services/content-types.d.ts +60 -0
  296. package/dist/server/src/services/content-types.d.ts.map +1 -0
  297. package/dist/server/src/services/index.d.ts +14 -0
  298. package/dist/server/src/services/index.d.ts.map +1 -0
  299. package/dist/server/src/services/schema-builder/component-builder.d.ts +39 -0
  300. package/dist/server/src/services/schema-builder/component-builder.d.ts.map +1 -0
  301. package/dist/server/src/services/schema-builder/content-type-builder.d.ts +38 -0
  302. package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -0
  303. package/dist/server/src/services/schema-builder/index.d.ts +78 -0
  304. package/dist/server/src/services/schema-builder/index.d.ts.map +1 -0
  305. package/dist/server/src/services/schema-builder/schema-handler.d.ts +36 -0
  306. package/dist/server/src/services/schema-builder/schema-handler.d.ts.map +1 -0
  307. package/dist/server/src/utils/attributes.d.ts +192 -0
  308. package/dist/server/src/utils/attributes.d.ts.map +1 -0
  309. package/dist/server/src/utils/helpers.d.ts +3 -0
  310. package/dist/server/src/utils/helpers.d.ts.map +1 -0
  311. package/dist/server/src/utils/index.d.ts +15 -0
  312. package/dist/server/src/utils/index.d.ts.map +1 -0
  313. package/dist/server/src/utils/typeguards.d.ts +3 -0
  314. package/dist/server/src/utils/typeguards.d.ts.map +1 -0
  315. package/package.json +91 -3
  316. package/strapi-server.js +3 -0
@@ -0,0 +1,2312 @@
1
+ "use strict";
2
+ const _ = require("lodash");
3
+ const fp = require("lodash/fp");
4
+ const utils = require("@strapi/utils");
5
+ const path = require("path");
6
+ const fse = require("fs-extra");
7
+ const pluralize = require("pluralize");
8
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule)
11
+ return e;
12
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
13
+ if (e) {
14
+ for (const k in e) {
15
+ if (k !== "default") {
16
+ const d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: () => e[k]
20
+ });
21
+ }
22
+ }
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+ const ___default = /* @__PURE__ */ _interopDefault(_);
28
+ const utils__default = /* @__PURE__ */ _interopDefault(utils);
29
+ const path__namespace = /* @__PURE__ */ _interopNamespace(path);
30
+ const fse__namespace = /* @__PURE__ */ _interopNamespace(fse);
31
+ const pluralize__default = /* @__PURE__ */ _interopDefault(pluralize);
32
+ const config = {
33
+ default: {},
34
+ validator() {
35
+ }
36
+ };
37
+ const bootstrap = async ({ strapi: strapi2 }) => {
38
+ const actions = [
39
+ {
40
+ section: "plugins",
41
+ displayName: "Read",
42
+ uid: "read",
43
+ pluginName: "content-type-builder"
44
+ }
45
+ ];
46
+ await strapi2.service("admin::permission").actionProvider.registerMany(actions);
47
+ };
48
+ const { ApplicationError: ApplicationError$3 } = utils.errors;
49
+ const hasComponent = (model) => {
50
+ const compoKeys = Object.keys(model.attributes || {}).filter((key) => {
51
+ return model.attributes[key].type === "component";
52
+ });
53
+ return compoKeys.length > 0;
54
+ };
55
+ const isConfigurable = (attribute) => ___default.default.get(attribute, "configurable", true);
56
+ const isRelation = (attribute) => attribute.type === "relation";
57
+ const formatAttributes = (model) => {
58
+ const { getVisibleAttributes } = utils__default.default.contentTypes;
59
+ return getVisibleAttributes(model).reduce((acc, key) => {
60
+ acc[key] = formatAttribute(model.attributes[key]);
61
+ return acc;
62
+ }, {});
63
+ };
64
+ const formatAttribute = (attribute) => {
65
+ const { configurable, required, autoPopulate, pluginOptions } = attribute;
66
+ if (attribute.type === "media") {
67
+ return {
68
+ type: "media",
69
+ multiple: !!attribute.multiple,
70
+ required: !!required,
71
+ configurable: configurable === false ? false : void 0,
72
+ private: !!attribute.private,
73
+ allowedTypes: attribute.allowedTypes,
74
+ pluginOptions
75
+ };
76
+ }
77
+ if (attribute.type === "relation") {
78
+ return {
79
+ ...attribute,
80
+ type: "relation",
81
+ target: attribute.target,
82
+ targetAttribute: attribute.inversedBy || attribute.mappedBy || null,
83
+ configurable: configurable === false ? false : void 0,
84
+ private: !!attribute.private,
85
+ pluginOptions,
86
+ // TODO: remove
87
+ autoPopulate
88
+ };
89
+ }
90
+ return attribute;
91
+ };
92
+ const replaceTemporaryUIDs = (uidMap) => (schema) => {
93
+ return {
94
+ ...schema,
95
+ attributes: Object.keys(schema.attributes).reduce((acc, key) => {
96
+ const attr = schema.attributes[key];
97
+ if (attr.type === "component") {
98
+ if (___default.default.has(uidMap, attr.component)) {
99
+ acc[key] = {
100
+ ...attr,
101
+ component: uidMap[attr.component]
102
+ };
103
+ return acc;
104
+ }
105
+ if (!___default.default.has(strapi.components, attr.component)) {
106
+ throw new ApplicationError$3("component.notFound");
107
+ }
108
+ }
109
+ if (attr.type === "dynamiczone" && ___default.default.intersection(attr.components, Object.keys(uidMap)).length > 0) {
110
+ acc[key] = {
111
+ ...attr,
112
+ components: attr.components.map((value) => {
113
+ if (___default.default.has(uidMap, value))
114
+ return uidMap[value];
115
+ if (!___default.default.has(strapi.components, value)) {
116
+ throw new ApplicationError$3("component.notFound");
117
+ }
118
+ return value;
119
+ })
120
+ };
121
+ return acc;
122
+ }
123
+ acc[key] = attr;
124
+ return acc;
125
+ }, {})
126
+ };
127
+ };
128
+ function createSchemaHandler(infos) {
129
+ const { category, modelName, plugin, uid, dir, filename, schema } = infos;
130
+ const initialState = {
131
+ modelName,
132
+ plugin,
133
+ category,
134
+ uid,
135
+ dir,
136
+ filename,
137
+ schema: schema || {
138
+ info: {},
139
+ options: {},
140
+ attributes: {}
141
+ }
142
+ };
143
+ const state = ___default.default.cloneDeep(initialState);
144
+ Object.freeze(initialState.schema);
145
+ let modified = false;
146
+ let deleted = false;
147
+ return {
148
+ get modelName() {
149
+ return initialState.modelName;
150
+ },
151
+ get plugin() {
152
+ return initialState.plugin;
153
+ },
154
+ get category() {
155
+ return initialState.category;
156
+ },
157
+ get kind() {
158
+ return ___default.default.get(state.schema, "kind", "collectionType");
159
+ },
160
+ get uid() {
161
+ return state.uid;
162
+ },
163
+ get writable() {
164
+ return ___default.default.get(state, "plugin") !== "admin";
165
+ },
166
+ setUID(val) {
167
+ modified = true;
168
+ state.uid = val;
169
+ return this;
170
+ },
171
+ setDir(val) {
172
+ modified = true;
173
+ state.dir = val;
174
+ return this;
175
+ },
176
+ get schema() {
177
+ return ___default.default.cloneDeep(state.schema);
178
+ },
179
+ setSchema(val) {
180
+ modified = true;
181
+ state.schema = ___default.default.cloneDeep(val);
182
+ return this;
183
+ },
184
+ // get a particular path inside the schema
185
+ get(path2) {
186
+ return ___default.default.get(state.schema, path2);
187
+ },
188
+ // set a particular path inside the schema
189
+ set(path2, val) {
190
+ if (!state.schema)
191
+ return this;
192
+ modified = true;
193
+ const value = ___default.default.defaultTo(val, ___default.default.get(state.schema, path2));
194
+ ___default.default.set(state.schema, path2, value);
195
+ return this;
196
+ },
197
+ // delete a particular path inside the schema
198
+ unset(path2) {
199
+ modified = true;
200
+ ___default.default.unset(state.schema, path2);
201
+ return this;
202
+ },
203
+ delete() {
204
+ deleted = true;
205
+ return this;
206
+ },
207
+ getAttribute(key) {
208
+ return this.get(["attributes", key]);
209
+ },
210
+ setAttribute(key, attribute) {
211
+ return this.set(["attributes", key], attribute);
212
+ },
213
+ deleteAttribute(key) {
214
+ return this.unset(["attributes", key]);
215
+ },
216
+ setAttributes(newAttributes) {
217
+ if (!this.schema)
218
+ return this;
219
+ for (const key in this.schema.attributes) {
220
+ if (isConfigurable(this.schema.attributes[key])) {
221
+ this.deleteAttribute(key);
222
+ }
223
+ }
224
+ for (const key of Object.keys(newAttributes)) {
225
+ this.setAttribute(key, newAttributes[key]);
226
+ }
227
+ return this;
228
+ },
229
+ removeContentType(uid2) {
230
+ if (!state.schema)
231
+ return this;
232
+ const attributes = state.schema.attributes;
233
+ Object.keys(attributes).forEach((key) => {
234
+ const attribute = attributes[key];
235
+ if (attribute.target === uid2) {
236
+ this.deleteAttribute(key);
237
+ }
238
+ });
239
+ return this;
240
+ },
241
+ // utils
242
+ removeComponent(uid2) {
243
+ if (!state.schema)
244
+ return this;
245
+ const attributes = state.schema.attributes;
246
+ Object.keys(attributes).forEach((key) => {
247
+ const attr = attributes[key];
248
+ if (attr.type === "component" && attr.component === uid2) {
249
+ this.deleteAttribute(key);
250
+ }
251
+ if (attr.type === "dynamiczone" && Array.isArray(attr.components) && attr.components.includes(uid2)) {
252
+ const updatedComponentList = attributes[key].components.filter(
253
+ (val) => val !== uid2
254
+ );
255
+ this.set(["attributes", key, "components"], updatedComponentList);
256
+ }
257
+ });
258
+ return this;
259
+ },
260
+ updateComponent(uid2, newUID) {
261
+ if (!state.schema)
262
+ return this;
263
+ const attributes = state.schema.attributes;
264
+ Object.keys(attributes).forEach((key) => {
265
+ const attr = attributes[key];
266
+ if (attr.type === "component" && attr.component === uid2) {
267
+ this.set(["attributes", key, "component"], newUID);
268
+ }
269
+ if (attr.type === "dynamiczone" && Array.isArray(attr.components) && attr.components.includes(uid2)) {
270
+ const updatedComponentList = attr.components.map(
271
+ (val) => val === uid2 ? newUID : val
272
+ );
273
+ this.set(["attributes", key, "components"], updatedComponentList);
274
+ }
275
+ });
276
+ return this;
277
+ },
278
+ // save the schema to disk
279
+ async flush() {
280
+ if (!this.writable) {
281
+ return;
282
+ }
283
+ const initialPath = path__namespace.default.join(initialState.dir, initialState.filename);
284
+ const filePath = path__namespace.default.join(state.dir, state.filename);
285
+ if (deleted) {
286
+ await fse__namespace.default.remove(initialPath);
287
+ const list = await fse__namespace.default.readdir(initialState.dir);
288
+ if (list.length === 0) {
289
+ await fse__namespace.default.remove(initialState.dir);
290
+ }
291
+ return;
292
+ }
293
+ if (modified) {
294
+ if (!state.schema)
295
+ return Promise.resolve();
296
+ await fse__namespace.default.ensureFile(filePath);
297
+ await fse__namespace.default.writeJSON(
298
+ filePath,
299
+ {
300
+ kind: state.schema.kind,
301
+ collectionName: state.schema.collectionName,
302
+ info: state.schema.info,
303
+ options: state.schema.options,
304
+ pluginOptions: state.schema.pluginOptions,
305
+ attributes: state.schema.attributes,
306
+ config: state.schema.config
307
+ },
308
+ { spaces: 2 }
309
+ );
310
+ if (initialPath !== filePath) {
311
+ await fse__namespace.default.remove(initialPath);
312
+ const list = await fse__namespace.default.readdir(initialState.dir);
313
+ if (list.length === 0) {
314
+ await fse__namespace.default.remove(initialState.dir);
315
+ }
316
+ }
317
+ return;
318
+ }
319
+ return Promise.resolve();
320
+ },
321
+ // reset the schema to its initial value
322
+ async rollback() {
323
+ if (!this.writable) {
324
+ return;
325
+ }
326
+ const initialPath = path__namespace.default.join(initialState.dir, initialState.filename);
327
+ const filePath = path__namespace.default.join(state.dir, state.filename);
328
+ if (!initialState.uid) {
329
+ await fse__namespace.default.remove(filePath);
330
+ const list = await fse__namespace.default.readdir(state.dir);
331
+ if (list.length === 0) {
332
+ await fse__namespace.default.remove(state.dir);
333
+ }
334
+ return;
335
+ }
336
+ if (modified || deleted) {
337
+ await fse__namespace.default.ensureFile(initialPath);
338
+ await fse__namespace.default.writeJSON(initialPath, initialState.schema, { spaces: 2 });
339
+ if (initialPath !== filePath) {
340
+ await fse__namespace.default.remove(filePath);
341
+ const list = await fse__namespace.default.readdir(state.dir);
342
+ if (list.length === 0) {
343
+ await fse__namespace.default.remove(state.dir);
344
+ }
345
+ }
346
+ }
347
+ return Promise.resolve();
348
+ }
349
+ };
350
+ }
351
+ const { ApplicationError: ApplicationError$2 } = utils.errors;
352
+ function createComponentBuilder$1() {
353
+ return {
354
+ createComponentUID({ category, displayName }) {
355
+ return `${utils.strings.nameToSlug(category)}.${utils.strings.nameToSlug(displayName)}`;
356
+ },
357
+ createNewComponentUIDMap(components2) {
358
+ return components2.reduce((uidMap, component) => {
359
+ uidMap[component.tmpUID] = this.createComponentUID(component);
360
+ return uidMap;
361
+ }, {});
362
+ },
363
+ /**
364
+ * create a component in the tmpComponent map
365
+ */
366
+ createComponent(infos) {
367
+ const uid = this.createComponentUID(infos);
368
+ if (this.components.has(uid)) {
369
+ throw new ApplicationError$2("component.alreadyExists");
370
+ }
371
+ const handler = createSchemaHandler({
372
+ dir: path__namespace.default.join(strapi.dirs.app.components, utils.strings.nameToSlug(infos.category)),
373
+ filename: `${utils.strings.nameToSlug(infos.displayName)}.json`
374
+ });
375
+ const collectionName = `components_${utils.strings.nameToCollectionName(
376
+ infos.category
377
+ )}_${utils.strings.nameToCollectionName(pluralize__default.default(infos.displayName))}`;
378
+ this.components.forEach((compo) => {
379
+ if (compo.schema.collectionName === collectionName) {
380
+ throw new ApplicationError$2("component.alreadyExists");
381
+ }
382
+ });
383
+ handler.setUID(uid).set("collectionName", collectionName).set(["info", "displayName"], infos.displayName).set(["info", "icon"], infos.icon).set(["info", "description"], infos.description).set("pluginOptions", infos.pluginOptions).set("config", infos.config).setAttributes(this.convertAttributes(infos.attributes));
384
+ if (this.components.size === 0) {
385
+ strapi.telemetry.send("didCreateFirstComponent");
386
+ } else {
387
+ strapi.telemetry.send("didCreateComponent");
388
+ }
389
+ this.components.set(uid, handler);
390
+ return handler;
391
+ },
392
+ /**
393
+ * create a component in the tmpComponent map
394
+ */
395
+ editComponent(infos) {
396
+ const { uid } = infos;
397
+ if (!this.components.has(uid)) {
398
+ throw new utils.errors.ApplicationError("component.notFound");
399
+ }
400
+ const component = this.components.get(uid);
401
+ const [, nameUID] = uid.split(".");
402
+ const newCategory = utils.strings.nameToSlug(infos.category);
403
+ const newUID = `${newCategory}.${nameUID}`;
404
+ if (newUID !== uid && this.components.has(newUID)) {
405
+ throw new utils.errors.ApplicationError("component.edit.alreadyExists");
406
+ }
407
+ const newDir = path__namespace.default.join(strapi.dirs.app.components, newCategory);
408
+ const oldAttributes = component.schema.attributes;
409
+ const newAttributes = ___default.default.omitBy(infos.attributes, (attr, key) => {
410
+ return ___default.default.has(oldAttributes, key) && !isConfigurable(oldAttributes[key]);
411
+ });
412
+ component.setUID(newUID).setDir(newDir).set(["info", "displayName"], infos.displayName).set(["info", "icon"], infos.icon).set(["info", "description"], infos.description).set("pluginOptions", infos.pluginOptions).setAttributes(this.convertAttributes(newAttributes));
413
+ if (newUID !== uid) {
414
+ this.components.forEach((compo) => {
415
+ compo.updateComponent(uid, newUID);
416
+ });
417
+ this.contentTypes.forEach((ct) => {
418
+ ct.updateComponent(uid, newUID);
419
+ });
420
+ }
421
+ return component;
422
+ },
423
+ deleteComponent(uid) {
424
+ if (!this.components.has(uid)) {
425
+ throw new utils.errors.ApplicationError("component.notFound");
426
+ }
427
+ this.components.forEach((compo) => {
428
+ compo.removeComponent(uid);
429
+ });
430
+ this.contentTypes.forEach((ct) => {
431
+ ct.removeComponent(uid);
432
+ });
433
+ return this.components.get(uid).delete();
434
+ }
435
+ };
436
+ }
437
+ const modelTypes = {
438
+ CONTENT_TYPE: "CONTENT_TYPE",
439
+ COMPONENT: "COMPONENT"
440
+ };
441
+ const typeKinds = {
442
+ SINGLE_TYPE: "singleType",
443
+ COLLECTION_TYPE: "collectionType"
444
+ };
445
+ const DEFAULT_TYPES = [
446
+ // advanced types
447
+ "media",
448
+ // scalar types
449
+ "string",
450
+ "text",
451
+ "richtext",
452
+ "blocks",
453
+ "json",
454
+ "enumeration",
455
+ "password",
456
+ "email",
457
+ "integer",
458
+ "biginteger",
459
+ "float",
460
+ "decimal",
461
+ "date",
462
+ "time",
463
+ "datetime",
464
+ "timestamp",
465
+ "boolean",
466
+ "relation"
467
+ ];
468
+ const VALID_UID_TARGETS = ["string", "text"];
469
+ const FORBIDDEN_ATTRIBUTE_NAMES = ["__component", "__contentType"];
470
+ const coreUids = {
471
+ STRAPI_USER: "admin::user",
472
+ PREFIX: "strapi::"
473
+ };
474
+ const pluginsUids = {
475
+ UPLOAD_FILE: "plugin::upload.file"
476
+ };
477
+ const { ApplicationError: ApplicationError$1 } = utils.errors;
478
+ const reuseUnsetPreviousProperties = (newAttribute, oldAttribute) => {
479
+ ___default.default.defaults(
480
+ newAttribute,
481
+ ___default.default.omit(oldAttribute, [
482
+ "configurable",
483
+ "required",
484
+ "private",
485
+ "unique",
486
+ "pluginOptions",
487
+ "inversedBy",
488
+ "mappedBy"
489
+ ])
490
+ );
491
+ };
492
+ function createComponentBuilder() {
493
+ return {
494
+ setRelation({ key, uid, attribute }) {
495
+ if (!___default.default.has(attribute, "target")) {
496
+ return;
497
+ }
498
+ const targetCT = this.contentTypes.get(attribute.target);
499
+ const targetAttribute = targetCT.getAttribute(attribute.targetAttribute);
500
+ if (!attribute.targetAttribute) {
501
+ return;
502
+ }
503
+ targetCT.setAttribute(
504
+ attribute.targetAttribute,
505
+ generateRelation({ key, attribute, uid, targetAttribute })
506
+ );
507
+ },
508
+ unsetRelation(attribute) {
509
+ if (!___default.default.has(attribute, "target")) {
510
+ return;
511
+ }
512
+ const targetCT = this.contentTypes.get(attribute.target);
513
+ const targetAttributeName = attribute.inversedBy || attribute.mappedBy;
514
+ const targetAttribute = targetCT.getAttribute(targetAttributeName);
515
+ if (!targetAttribute)
516
+ return;
517
+ return targetCT.deleteAttribute(targetAttributeName);
518
+ },
519
+ /**
520
+ * Creates a content type in memory to be written to files later on
521
+ */
522
+ createContentType(infos) {
523
+ const uid = createContentTypeUID(infos);
524
+ if (this.contentTypes.has(uid)) {
525
+ throw new ApplicationError$1("contentType.alreadyExists");
526
+ }
527
+ const contentType = createSchemaHandler({
528
+ modelName: infos.singularName,
529
+ dir: path__namespace.default.join(
530
+ strapi.dirs.app.api,
531
+ infos.singularName,
532
+ "content-types",
533
+ infos.singularName
534
+ ),
535
+ filename: `schema.json`
536
+ });
537
+ this.contentTypes.set(uid, contentType);
538
+ Object.keys(infos.attributes).forEach((key) => {
539
+ const { target } = infos.attributes[key];
540
+ if (target === "__self__") {
541
+ infos.attributes[key].target = uid;
542
+ }
543
+ });
544
+ contentType.setUID(uid).set("kind", infos.kind || typeKinds.COLLECTION_TYPE).set(
545
+ "collectionName",
546
+ infos.collectionName || utils.strings.nameToCollectionName(infos.pluralName)
547
+ ).set("info", {
548
+ singularName: infos.singularName,
549
+ pluralName: infos.pluralName,
550
+ displayName: infos.displayName,
551
+ description: infos.description
552
+ }).set("options", {
553
+ ...infos.options ?? {},
554
+ draftAndPublish: infos.draftAndPublish
555
+ }).set("pluginOptions", infos.pluginOptions).set("config", infos.config).setAttributes(this.convertAttributes(infos.attributes));
556
+ Object.keys(infos.attributes).forEach((key) => {
557
+ const attribute = infos.attributes[key];
558
+ if (isRelation(attribute)) {
559
+ if (["manyToMany", "oneToOne"].includes(attribute.relation)) {
560
+ attribute.dominant = true;
561
+ }
562
+ this.setRelation({
563
+ key,
564
+ uid,
565
+ attribute
566
+ });
567
+ }
568
+ });
569
+ return contentType;
570
+ },
571
+ editContentType(infos) {
572
+ const { uid } = infos;
573
+ if (!this.contentTypes.has(uid)) {
574
+ throw new ApplicationError$1("contentType.notFound");
575
+ }
576
+ const contentType = this.contentTypes.get(uid);
577
+ const oldAttributes = contentType.schema.attributes;
578
+ const newAttributes = ___default.default.omitBy(infos.attributes, (attr, key) => {
579
+ return ___default.default.has(oldAttributes, key) && !isConfigurable(oldAttributes[key]);
580
+ });
581
+ const newKeys = ___default.default.difference(Object.keys(newAttributes), Object.keys(oldAttributes));
582
+ const deletedKeys = ___default.default.difference(Object.keys(oldAttributes), Object.keys(newAttributes));
583
+ const remainingKeys = ___default.default.intersection(Object.keys(oldAttributes), Object.keys(newAttributes));
584
+ deletedKeys.forEach((key) => {
585
+ const attribute = oldAttributes[key];
586
+ const targetAttributeName = attribute.inversedBy || attribute.mappedBy;
587
+ if (isConfigurable(attribute) && isRelation(attribute) && !___default.default.isNil(targetAttributeName)) {
588
+ this.unsetRelation(attribute);
589
+ }
590
+ });
591
+ remainingKeys.forEach((key) => {
592
+ const oldAttribute = oldAttributes[key];
593
+ const newAttribute = newAttributes[key];
594
+ if (!isRelation(oldAttribute) && isRelation(newAttribute)) {
595
+ return this.setRelation({
596
+ key,
597
+ uid,
598
+ attribute: newAttributes[key]
599
+ });
600
+ }
601
+ if (isRelation(oldAttribute) && !isRelation(newAttribute)) {
602
+ return this.unsetRelation(oldAttribute);
603
+ }
604
+ if (isRelation(oldAttribute) && isRelation(newAttribute)) {
605
+ const oldTargetAttributeName = oldAttribute.inversedBy || oldAttribute.mappedBy;
606
+ const sameRelation = oldAttribute.relation === newAttribute.relation;
607
+ const targetAttributeHasChanged = oldTargetAttributeName !== newAttribute.targetAttribute;
608
+ if (!sameRelation || targetAttributeHasChanged) {
609
+ this.unsetRelation(oldAttribute);
610
+ }
611
+ reuseUnsetPreviousProperties(newAttribute, oldAttribute);
612
+ if (oldAttribute.inversedBy) {
613
+ newAttribute.dominant = true;
614
+ } else if (oldAttribute.mappedBy) {
615
+ newAttribute.dominant = false;
616
+ }
617
+ return this.setRelation({
618
+ key,
619
+ uid,
620
+ attribute: newAttribute
621
+ });
622
+ }
623
+ });
624
+ newKeys.forEach((key) => {
625
+ const attribute = newAttributes[key];
626
+ if (isRelation(attribute)) {
627
+ if (["manyToMany", "oneToOne"].includes(attribute.relation)) {
628
+ attribute.dominant = true;
629
+ }
630
+ this.setRelation({
631
+ key,
632
+ uid,
633
+ attribute
634
+ });
635
+ }
636
+ });
637
+ contentType.set("kind", infos.kind || contentType.schema.kind).set(["info", "displayName"], infos.displayName).set(["info", "description"], infos.description).set("options", {
638
+ ...infos.options ?? {},
639
+ draftAndPublish: infos.draftAndPublish
640
+ }).set("pluginOptions", infos.pluginOptions).setAttributes(this.convertAttributes(newAttributes));
641
+ return contentType;
642
+ },
643
+ deleteContentType(uid) {
644
+ if (!this.contentTypes.has(uid)) {
645
+ throw new ApplicationError$1("contentType.notFound");
646
+ }
647
+ this.components.forEach((compo) => {
648
+ compo.removeContentType(uid);
649
+ });
650
+ this.contentTypes.forEach((ct) => {
651
+ ct.removeContentType(uid);
652
+ });
653
+ return this.contentTypes.get(uid).delete();
654
+ }
655
+ };
656
+ }
657
+ const createContentTypeUID = ({
658
+ singularName
659
+ }) => `api::${singularName}.${singularName}`;
660
+ const generateRelation = ({ key, attribute, uid, targetAttribute = {} }) => {
661
+ const opts = {
662
+ type: "relation",
663
+ target: uid,
664
+ autoPopulate: targetAttribute.autoPopulate,
665
+ private: targetAttribute.private || void 0,
666
+ pluginOptions: targetAttribute.pluginOptions || void 0
667
+ };
668
+ switch (attribute.relation) {
669
+ case "oneToOne": {
670
+ opts.relation = "oneToOne";
671
+ if (attribute.dominant) {
672
+ opts.mappedBy = key;
673
+ } else {
674
+ opts.inversedBy = key;
675
+ }
676
+ break;
677
+ }
678
+ case "oneToMany": {
679
+ opts.relation = "manyToOne";
680
+ opts.inversedBy = key;
681
+ break;
682
+ }
683
+ case "manyToOne": {
684
+ opts.relation = "oneToMany";
685
+ opts.mappedBy = key;
686
+ break;
687
+ }
688
+ case "manyToMany": {
689
+ opts.relation = "manyToMany";
690
+ if (attribute.dominant) {
691
+ opts.mappedBy = key;
692
+ } else {
693
+ opts.inversedBy = key;
694
+ }
695
+ break;
696
+ }
697
+ }
698
+ const { type, relation, target, ...restOptions } = opts;
699
+ return {
700
+ type,
701
+ relation,
702
+ target,
703
+ ...restOptions
704
+ };
705
+ };
706
+ function createBuilder() {
707
+ const components2 = Object.values(strapi.components).map((componentInput) => ({
708
+ category: componentInput.category,
709
+ modelName: componentInput.modelName,
710
+ plugin: componentInput.modelName,
711
+ uid: componentInput.uid,
712
+ filename: componentInput.__filename__,
713
+ dir: path.join(strapi.dirs.app.components, componentInput.category),
714
+ schema: componentInput.__schema__,
715
+ config: componentInput.config
716
+ }));
717
+ const contentTypes2 = Object.values(strapi.contentTypes).map((contentTypeInput) => {
718
+ const dir = contentTypeInput.plugin ? path.join(
719
+ strapi.dirs.app.extensions,
720
+ contentTypeInput.plugin,
721
+ "content-types",
722
+ contentTypeInput.info.singularName
723
+ ) : path.join(
724
+ strapi.dirs.app.api,
725
+ contentTypeInput.apiName,
726
+ "content-types",
727
+ contentTypeInput.info.singularName
728
+ );
729
+ return {
730
+ modelName: contentTypeInput.modelName,
731
+ plugin: contentTypeInput.plugin,
732
+ uid: contentTypeInput.uid,
733
+ filename: "schema.json",
734
+ dir,
735
+ schema: contentTypeInput.__schema__,
736
+ config: contentTypeInput.config
737
+ };
738
+ });
739
+ return createSchemaBuilder({
740
+ components: components2,
741
+ contentTypes: contentTypes2
742
+ });
743
+ }
744
+ function createSchemaBuilder({ components: components2, contentTypes: contentTypes2 }) {
745
+ const tmpComponents = /* @__PURE__ */ new Map();
746
+ const tmpContentTypes = /* @__PURE__ */ new Map();
747
+ Object.keys(contentTypes2).forEach((key) => {
748
+ tmpContentTypes.set(contentTypes2[key].uid, createSchemaHandler(contentTypes2[key]));
749
+ });
750
+ Object.keys(components2).forEach((key) => {
751
+ tmpComponents.set(components2[key].uid, createSchemaHandler(components2[key]));
752
+ });
753
+ return {
754
+ get components() {
755
+ return tmpComponents;
756
+ },
757
+ get contentTypes() {
758
+ return tmpContentTypes;
759
+ },
760
+ /**
761
+ * Convert Attributes received from the API to the right syntax
762
+ */
763
+ convertAttributes(attributes) {
764
+ return Object.keys(attributes).reduce(
765
+ (acc, key) => {
766
+ const attribute = attributes[key];
767
+ const { configurable, private: isPrivate } = attribute;
768
+ const baseProperties = {
769
+ private: isPrivate === true ? true : void 0,
770
+ configurable: configurable === false ? false : void 0
771
+ };
772
+ if (attribute.type === "relation") {
773
+ const { target, relation, targetAttribute, dominant, ...restOfProperties } = attribute;
774
+ const attr = {
775
+ type: "relation",
776
+ relation,
777
+ target,
778
+ ...restOfProperties,
779
+ ...baseProperties
780
+ };
781
+ acc[key] = attr;
782
+ if (target && !this.contentTypes.has(target)) {
783
+ throw new utils.errors.ApplicationError(`target: ${target} does not exist`);
784
+ }
785
+ if (___default.default.isNil(targetAttribute)) {
786
+ return acc;
787
+ }
788
+ if (["oneToOne", "manyToMany"].includes(relation) && dominant === true) {
789
+ attr.inversedBy = targetAttribute;
790
+ } else if (["oneToOne", "manyToMany"].includes(relation) && dominant === false) {
791
+ attr.mappedBy = targetAttribute;
792
+ } else if (["oneToOne", "manyToOne", "manyToMany"].includes(relation)) {
793
+ attr.inversedBy = targetAttribute;
794
+ } else if (["oneToMany"].includes(relation)) {
795
+ attr.mappedBy = targetAttribute;
796
+ }
797
+ return acc;
798
+ }
799
+ acc[key] = {
800
+ ...attribute,
801
+ ...baseProperties
802
+ };
803
+ return acc;
804
+ },
805
+ {}
806
+ );
807
+ },
808
+ ...createComponentBuilder$1(),
809
+ ...createComponentBuilder(),
810
+ /**
811
+ * Write all type to files
812
+ */
813
+ writeFiles() {
814
+ const schemas = [
815
+ ...Array.from(tmpComponents.values()),
816
+ ...Array.from(tmpContentTypes.values())
817
+ ];
818
+ return Promise.all(schemas.map((schema) => schema.flush())).catch((error) => {
819
+ strapi.log.error("Error writing schema files");
820
+ strapi.log.error(error);
821
+ return this.rollback();
822
+ }).catch((error) => {
823
+ strapi.log.error(
824
+ "Error rolling back schema files. You might need to fix your files manually"
825
+ );
826
+ strapi.log.error(error);
827
+ throw new utils.errors.ApplicationError("Invalid schema edition");
828
+ });
829
+ },
830
+ /**
831
+ * rollback all files
832
+ */
833
+ rollback() {
834
+ return Promise.all(
835
+ [...Array.from(tmpComponents.values()), ...Array.from(tmpContentTypes.values())].map(
836
+ (schema) => schema.rollback()
837
+ )
838
+ );
839
+ }
840
+ };
841
+ }
842
+ const { ApplicationError } = utils.errors;
843
+ const isContentTypeVisible = (model) => fp.getOr(true, "pluginOptions.content-type-builder.visible", model) === true;
844
+ const getRestrictRelationsTo = (contentType) => {
845
+ const { uid } = contentType;
846
+ if (uid === coreUids.STRAPI_USER) {
847
+ return ["oneWay", "manyWay"];
848
+ }
849
+ if (uid.startsWith(coreUids.PREFIX) || uid === pluginsUids.UPLOAD_FILE || !isContentTypeVisible(contentType)) {
850
+ return [];
851
+ }
852
+ return null;
853
+ };
854
+ const formatContentType = (contentType) => {
855
+ const { uid, kind, modelName, plugin, collectionName, info } = contentType;
856
+ return {
857
+ uid,
858
+ plugin,
859
+ apiID: modelName,
860
+ schema: {
861
+ ...utils.contentTypes.getOptions(contentType),
862
+ displayName: info.displayName,
863
+ singularName: info.singularName,
864
+ pluralName: info.pluralName,
865
+ description: ___default.default.get(info, "description", ""),
866
+ pluginOptions: contentType.pluginOptions,
867
+ kind: kind || "collectionType",
868
+ collectionName,
869
+ attributes: formatAttributes(contentType),
870
+ visible: isContentTypeVisible(contentType),
871
+ restrictRelationsTo: getRestrictRelationsTo(contentType)
872
+ }
873
+ };
874
+ };
875
+ const createContentTypes = async (contentTypes2) => {
876
+ const builder2 = createBuilder();
877
+ const createdContentTypes = [];
878
+ for (const contentType of contentTypes2) {
879
+ createdContentTypes.push(await createContentType(contentType, { defaultBuilder: builder2 }));
880
+ }
881
+ await builder2.writeFiles();
882
+ return createdContentTypes;
883
+ };
884
+ const createContentType = async ({ contentType, components: components2 }, options = {}) => {
885
+ const builder2 = options.defaultBuilder || createBuilder();
886
+ const uidMap = builder2.createNewComponentUIDMap(components2 || []);
887
+ const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
888
+ const newContentType = builder2.createContentType(replaceTmpUIDs(contentType));
889
+ const targetContentType = (infos) => {
890
+ Object.keys(infos.attributes).forEach((key) => {
891
+ const { target } = infos.attributes[key];
892
+ if (target === "__contentType__") {
893
+ infos.attributes[key].target = newContentType.uid;
894
+ }
895
+ });
896
+ return infos;
897
+ };
898
+ components2?.forEach((component) => {
899
+ const options2 = replaceTmpUIDs(targetContentType(component));
900
+ if (!___default.default.has(component, "uid")) {
901
+ return builder2.createComponent(options2);
902
+ }
903
+ return builder2.editComponent(options2);
904
+ });
905
+ await generateAPI({
906
+ displayName: contentType.displayName || contentType.info.displayName,
907
+ singularName: contentType.singularName,
908
+ pluralName: contentType.pluralName,
909
+ kind: contentType.kind
910
+ });
911
+ if (!options.defaultBuilder) {
912
+ await builder2.writeFiles();
913
+ }
914
+ strapi.eventHub.emit("content-type.create", { contentType: newContentType });
915
+ return newContentType;
916
+ };
917
+ const generateAPI = ({
918
+ singularName,
919
+ kind = "collectionType",
920
+ pluralName,
921
+ displayName
922
+ }) => {
923
+ const strapiGenerators = require("@strapi/generators");
924
+ return strapiGenerators.generate(
925
+ "content-type",
926
+ {
927
+ kind,
928
+ singularName,
929
+ id: singularName,
930
+ pluralName,
931
+ displayName,
932
+ destination: "new",
933
+ bootstrapApi: true,
934
+ attributes: []
935
+ },
936
+ { dir: strapi.dirs.app.root }
937
+ );
938
+ };
939
+ const editContentType = async (uid, { contentType, components: components2 = [] }) => {
940
+ const builder2 = createBuilder();
941
+ const previousSchema = builder2.contentTypes.get(uid).schema;
942
+ const previousKind = previousSchema.kind;
943
+ const newKind = contentType.kind || previousKind;
944
+ const previousAttributes = previousSchema.attributes;
945
+ const prevNonVisibleAttributes = utils.contentTypes.getNonVisibleAttributes(previousSchema).reduce((acc, key) => {
946
+ if (key in previousAttributes) {
947
+ acc[key] = previousAttributes[key];
948
+ }
949
+ return acc;
950
+ }, {});
951
+ contentType.attributes = ___default.default.merge(prevNonVisibleAttributes, contentType.attributes);
952
+ if (newKind !== previousKind && newKind === "singleType") {
953
+ const entryCount = await strapi.db.query(uid).count();
954
+ if (entryCount > 1) {
955
+ throw new ApplicationError(
956
+ "You cannot convert a collectionType to a singleType when having multiple entries in DB"
957
+ );
958
+ }
959
+ }
960
+ const uidMap = builder2.createNewComponentUIDMap(components2);
961
+ const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
962
+ const updatedContentType = builder2.editContentType({
963
+ uid,
964
+ ...replaceTmpUIDs(contentType)
965
+ });
966
+ components2.forEach((component) => {
967
+ if (!___default.default.has(component, "uid")) {
968
+ return builder2.createComponent(replaceTmpUIDs(component));
969
+ }
970
+ return builder2.editComponent(replaceTmpUIDs(component));
971
+ });
972
+ if (newKind !== previousKind) {
973
+ const apiHandler2 = strapi.plugin("content-type-builder").service("api-handler");
974
+ await apiHandler2.backup(uid);
975
+ try {
976
+ await apiHandler2.clear(uid);
977
+ await generateAPI({
978
+ displayName: updatedContentType.schema.info.displayName,
979
+ singularName: updatedContentType.schema.info.singularName,
980
+ pluralName: updatedContentType.schema.info.pluralName,
981
+ kind: updatedContentType.schema.kind
982
+ });
983
+ await builder2.writeFiles();
984
+ } catch (error) {
985
+ strapi.log.error(error);
986
+ await apiHandler2.rollback(uid);
987
+ }
988
+ return updatedContentType;
989
+ }
990
+ await builder2.writeFiles();
991
+ strapi.eventHub.emit("content-type.update", { contentType: updatedContentType });
992
+ return updatedContentType;
993
+ };
994
+ const deleteContentTypes = async (uids) => {
995
+ const builder2 = createBuilder();
996
+ const apiHandler2 = strapi.plugin("content-type-builder").service("api-handler");
997
+ for (const uid of uids) {
998
+ await deleteContentType(uid, builder2);
999
+ }
1000
+ await builder2.writeFiles();
1001
+ for (const uid of uids) {
1002
+ try {
1003
+ await apiHandler2.clear(uid);
1004
+ } catch (error) {
1005
+ strapi.log.error(error);
1006
+ await apiHandler2.rollback(uid);
1007
+ }
1008
+ }
1009
+ };
1010
+ const deleteContentType = async (uid, defaultBuilder = void 0) => {
1011
+ const builder2 = defaultBuilder || createBuilder();
1012
+ const apiHandler2 = strapi.plugin("content-type-builder").service("api-handler");
1013
+ await apiHandler2.backup(uid);
1014
+ const contentType = builder2.deleteContentType(uid);
1015
+ if (!defaultBuilder) {
1016
+ try {
1017
+ await builder2.writeFiles();
1018
+ await apiHandler2.clear(uid);
1019
+ } catch (error) {
1020
+ await apiHandler2.rollback(uid);
1021
+ }
1022
+ }
1023
+ strapi.eventHub.emit("content-type.delete", { contentType });
1024
+ return contentType;
1025
+ };
1026
+ const contentTypes$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1027
+ __proto__: null,
1028
+ createContentType,
1029
+ createContentTypes,
1030
+ deleteContentType,
1031
+ deleteContentTypes,
1032
+ editContentType,
1033
+ formatContentType,
1034
+ generateAPI,
1035
+ getRestrictRelationsTo,
1036
+ isContentTypeVisible
1037
+ }, Symbol.toStringTag, { value: "Module" }));
1038
+ const formatComponent = (component) => {
1039
+ const { uid, modelName, connection, collectionName, info, category } = component;
1040
+ return {
1041
+ uid,
1042
+ category,
1043
+ apiId: modelName,
1044
+ schema: {
1045
+ displayName: _.get(info, "displayName"),
1046
+ description: _.get(info, "description", ""),
1047
+ icon: _.get(info, "icon"),
1048
+ connection,
1049
+ collectionName,
1050
+ pluginOptions: component.pluginOptions,
1051
+ attributes: formatAttributes(component)
1052
+ }
1053
+ };
1054
+ };
1055
+ const createComponent = async ({ component, components: components2 = [] }) => {
1056
+ const builder2 = createBuilder();
1057
+ const uidMap = builder2.createNewComponentUIDMap(components2);
1058
+ const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
1059
+ const newComponent = builder2.createComponent(replaceTmpUIDs(component));
1060
+ components2.forEach((component2) => {
1061
+ if (!_.has(component2, "uid")) {
1062
+ return builder2.createComponent(replaceTmpUIDs(component2));
1063
+ }
1064
+ return builder2.editComponent(replaceTmpUIDs(component2));
1065
+ });
1066
+ await builder2.writeFiles();
1067
+ strapi.eventHub.emit("component.create", { component: newComponent });
1068
+ return newComponent;
1069
+ };
1070
+ const editComponent = async (uid, { component, components: components2 = [] }) => {
1071
+ const builder2 = createBuilder();
1072
+ const uidMap = builder2.createNewComponentUIDMap(components2);
1073
+ const replaceTmpUIDs = replaceTemporaryUIDs(uidMap);
1074
+ const updatedComponent = builder2.editComponent({
1075
+ uid,
1076
+ ...replaceTmpUIDs(component)
1077
+ });
1078
+ components2.forEach((component2) => {
1079
+ if (!_.has(component2, "uid")) {
1080
+ return builder2.createComponent(replaceTmpUIDs(component2));
1081
+ }
1082
+ return builder2.editComponent(replaceTmpUIDs(component2));
1083
+ });
1084
+ await builder2.writeFiles();
1085
+ strapi.eventHub.emit("component.update", { component: updatedComponent });
1086
+ return updatedComponent;
1087
+ };
1088
+ const deleteComponent = async (uid) => {
1089
+ const builder2 = createBuilder();
1090
+ const deletedComponent = builder2.deleteComponent(uid);
1091
+ await builder2.writeFiles();
1092
+ strapi.eventHub.emit("component.delete", { component: deletedComponent });
1093
+ return deletedComponent;
1094
+ };
1095
+ const components$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1096
+ __proto__: null,
1097
+ createComponent,
1098
+ deleteComponent,
1099
+ editComponent,
1100
+ formatComponent
1101
+ }, Symbol.toStringTag, { value: "Module" }));
1102
+ const editCategory = async (name, infos) => {
1103
+ const newName = utils.strings.nameToSlug(infos.name);
1104
+ if (name === newName)
1105
+ return;
1106
+ if (!categoryExists(name)) {
1107
+ throw new utils.errors.ApplicationError("category not found");
1108
+ }
1109
+ if (categoryExists(newName)) {
1110
+ throw new utils.errors.ApplicationError("Name already taken");
1111
+ }
1112
+ const builder2 = createBuilder();
1113
+ builder2.components.forEach((component) => {
1114
+ const oldUID = component.uid;
1115
+ const newUID = `${newName}.${component.modelName}`;
1116
+ if (component.category !== name)
1117
+ return;
1118
+ component.setUID(newUID).setDir(path.join(strapi.dirs.app.components, newName));
1119
+ builder2.components.forEach((compo) => {
1120
+ compo.updateComponent(oldUID, newUID);
1121
+ });
1122
+ builder2.contentTypes.forEach((ct) => {
1123
+ ct.updateComponent(oldUID, newUID);
1124
+ });
1125
+ });
1126
+ await builder2.writeFiles();
1127
+ return newName;
1128
+ };
1129
+ const deleteCategory = async (name) => {
1130
+ if (!categoryExists(name)) {
1131
+ throw new utils.errors.ApplicationError("category not found");
1132
+ }
1133
+ const builder2 = createBuilder();
1134
+ builder2.components.forEach((component) => {
1135
+ if (component.category === name) {
1136
+ builder2.deleteComponent(component.uid);
1137
+ }
1138
+ });
1139
+ await builder2.writeFiles();
1140
+ };
1141
+ const categoryExists = (name) => {
1142
+ const matchingIndex = Object.values(strapi.components).findIndex(
1143
+ (component) => component.category === name
1144
+ );
1145
+ return matchingIndex > -1;
1146
+ };
1147
+ const componentCategories$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1148
+ __proto__: null,
1149
+ deleteCategory,
1150
+ editCategory
1151
+ }, Symbol.toStringTag, { value: "Module" }));
1152
+ const getReservedNames = () => {
1153
+ return {
1154
+ // use kebab case everywhere since singularName and pluralName are validated that way
1155
+ models: [
1156
+ "boolean",
1157
+ "date",
1158
+ "date-time",
1159
+ "time",
1160
+ "upload",
1161
+ "document",
1162
+ "then"
1163
+ // no longer an issue but still restricting for being a javascript keyword
1164
+ ],
1165
+ // attributes are compared with snake_case(name), so only snake_case is needed here and camelCase + UPPER_CASE matches will still be caught
1166
+ attributes: [
1167
+ // TODO: these need to come from a centralized place so we don't break things accidentally in the future and can share them outside the CTB, for example on Strapi bootstrap prior to schema db sync
1168
+ // ID fields
1169
+ "id",
1170
+ "document_id",
1171
+ // Creator fields
1172
+ "created_at",
1173
+ "updated_at",
1174
+ "published_at",
1175
+ "created_by_id",
1176
+ "updated_by_id",
1177
+ // does not actually conflict because the fields are called *_by_id but we'll leave it to avoid confusion
1178
+ "created_by",
1179
+ "updated_by",
1180
+ // Used for Strapi functionality
1181
+ "entry_id",
1182
+ "status",
1183
+ "localizations",
1184
+ "meta",
1185
+ "locale",
1186
+ // TODO: remove these in favor of restricting the strapi_ prefix
1187
+ "strapi",
1188
+ "strapi_stage",
1189
+ "strapi_assignee"
1190
+ ]
1191
+ };
1192
+ };
1193
+ const builder$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1194
+ __proto__: null,
1195
+ getReservedNames
1196
+ }, Symbol.toStringTag, { value: "Module" }));
1197
+ async function clear(uid) {
1198
+ const { apiName, modelName } = strapi.contentTypes[uid];
1199
+ const apiFolder = path__namespace.join(strapi.dirs.app.api, apiName);
1200
+ await recursiveRemoveFiles(apiFolder, createDeleteApiFunction(modelName));
1201
+ await deleteBackup(uid);
1202
+ }
1203
+ async function backup(uid) {
1204
+ const { apiName } = strapi.contentTypes[uid];
1205
+ const apiFolder = path__namespace.join(strapi.dirs.app.api, apiName);
1206
+ const backupFolder = path__namespace.join(strapi.dirs.app.api, ".backup", apiName);
1207
+ await fse__namespace.copy(apiFolder, backupFolder);
1208
+ }
1209
+ async function deleteBackup(uid) {
1210
+ const { apiName } = strapi.contentTypes[uid];
1211
+ const backupFolder = path__namespace.join(strapi.dirs.app.api, ".backup");
1212
+ const apiBackupFolder = path__namespace.join(strapi.dirs.app.api, ".backup", apiName);
1213
+ await fse__namespace.remove(apiBackupFolder);
1214
+ const list = await fse__namespace.readdir(backupFolder);
1215
+ if (list.length === 0) {
1216
+ await fse__namespace.remove(backupFolder);
1217
+ }
1218
+ }
1219
+ async function rollback(uid) {
1220
+ const { apiName } = strapi.contentTypes[uid];
1221
+ const apiFolder = path__namespace.join(strapi.dirs.app.api, apiName);
1222
+ const backupFolder = path__namespace.join(strapi.dirs.app.api, ".backup", apiName);
1223
+ try {
1224
+ await fse__namespace.access(backupFolder);
1225
+ } catch {
1226
+ throw new Error("Cannot rollback api that was not backed up");
1227
+ }
1228
+ await fse__namespace.remove(apiFolder);
1229
+ await fse__namespace.copy(backupFolder, apiFolder);
1230
+ await deleteBackup(uid);
1231
+ }
1232
+ const createDeleteApiFunction = (baseName) => {
1233
+ return async (filePath) => {
1234
+ const fileName = path__namespace.basename(filePath, path__namespace.extname(filePath));
1235
+ const isSchemaFile = filePath.endsWith(`${baseName}/schema.json`);
1236
+ if (fileName === baseName || isSchemaFile) {
1237
+ return fse__namespace.remove(filePath);
1238
+ }
1239
+ };
1240
+ };
1241
+ const recursiveRemoveFiles = async (folder, deleteFn) => {
1242
+ const filesName = await fse__namespace.readdir(folder);
1243
+ for (const fileName of filesName) {
1244
+ const filePath = path__namespace.join(folder, fileName);
1245
+ const stat = await fse__namespace.stat(filePath);
1246
+ if (stat.isDirectory()) {
1247
+ await recursiveRemoveFiles(filePath, deleteFn);
1248
+ } else {
1249
+ await deleteFn(filePath);
1250
+ }
1251
+ }
1252
+ const files = await fse__namespace.readdir(folder);
1253
+ if (files.length === 0) {
1254
+ await fse__namespace.remove(folder);
1255
+ }
1256
+ };
1257
+ const apiHandler = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
1258
+ __proto__: null,
1259
+ backup,
1260
+ clear,
1261
+ rollback
1262
+ }, Symbol.toStringTag, { value: "Module" }));
1263
+ const services = {
1264
+ "content-types": contentTypes$1,
1265
+ components: components$1,
1266
+ "component-categories": componentCategories$1,
1267
+ builder: builder$1,
1268
+ "api-handler": apiHandler
1269
+ };
1270
+ function getService(name) {
1271
+ return strapi.plugin("content-type-builder").service(name);
1272
+ }
1273
+ const builder = {
1274
+ getReservedNames(ctx) {
1275
+ ctx.body = getService("builder").getReservedNames();
1276
+ }
1277
+ };
1278
+ const validators = {
1279
+ required: utils.yup.boolean(),
1280
+ unique: utils.yup.boolean(),
1281
+ minLength: utils.yup.number().integer().positive(),
1282
+ maxLength: utils.yup.number().integer().positive()
1283
+ };
1284
+ const NAME_REGEX = /^[A-Za-z][_0-9A-Za-z]*$/;
1285
+ const COLLECTION_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;
1286
+ const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;
1287
+ const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;
1288
+ const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
1289
+ const isValidName = {
1290
+ name: "isValidName",
1291
+ message: `\${path} must match the following regex: ${NAME_REGEX}`,
1292
+ test: (val) => val === "" || NAME_REGEX.test(val)
1293
+ };
1294
+ const isValidIcon = {
1295
+ name: "isValidIcon",
1296
+ message: `\${path} is not a valid icon name. Make sure your icon name starts with an alphanumeric character and only includes alphanumeric characters or dashes.`,
1297
+ test: (val) => val === "" || ICON_REGEX.test(val)
1298
+ };
1299
+ const isValidUID = {
1300
+ name: "isValidUID",
1301
+ message: `\${path} must match the following regex: ${UID_REGEX}`,
1302
+ test: (val) => val === "" || UID_REGEX.test(val)
1303
+ };
1304
+ const isValidCategoryName = {
1305
+ name: "isValidCategoryName",
1306
+ message: `\${path} must match the following regex: ${CATEGORY_NAME_REGEX}`,
1307
+ test: (val) => val === "" || CATEGORY_NAME_REGEX.test(val)
1308
+ };
1309
+ const isValidCollectionName = {
1310
+ name: "isValidCollectionName",
1311
+ message: `\${path} must match the following regex: ${COLLECTION_NAME_REGEX}`,
1312
+ test: (val) => val === "" || COLLECTION_NAME_REGEX.test(val)
1313
+ };
1314
+ const isValidKey = (key) => ({
1315
+ name: "isValidKey",
1316
+ message: `Attribute name '${key}' must match the following regex: ${NAME_REGEX}`,
1317
+ test: () => NAME_REGEX.test(key)
1318
+ });
1319
+ const isValidEnum = {
1320
+ name: "isValidEnum",
1321
+ message: "${path} should not start with number",
1322
+ test: (val) => val === "" || !utils.strings.startsWithANumber(val)
1323
+ };
1324
+ const areEnumValuesUnique = {
1325
+ name: "areEnumValuesUnique",
1326
+ message: "${path} cannot contain duplicate values",
1327
+ test(values) {
1328
+ const filtered = [...new Set(values)];
1329
+ return filtered.length === values.length;
1330
+ }
1331
+ };
1332
+ const isValidRegExpPattern = {
1333
+ name: "isValidRegExpPattern",
1334
+ message: "${path} must be a valid RexExp pattern string",
1335
+ test: (val) => val === "" || !!new RegExp(val)
1336
+ };
1337
+ const isValidDefaultJSON = {
1338
+ name: "isValidDefaultJSON",
1339
+ message: "${path} is not a valid JSON",
1340
+ test(val) {
1341
+ if (val === void 0) {
1342
+ return true;
1343
+ }
1344
+ if (___default.default.isNumber(val) || ___default.default.isNull(val) || ___default.default.isObject(val) || ___default.default.isArray(val)) {
1345
+ return true;
1346
+ }
1347
+ try {
1348
+ JSON.parse(val);
1349
+ return true;
1350
+ } catch (err) {
1351
+ return false;
1352
+ }
1353
+ }
1354
+ };
1355
+ const componentCategorySchema = utils.yup.object({
1356
+ name: utils.yup.string().min(3).test(isValidCategoryName).required("name.required")
1357
+ }).noUnknown();
1358
+ const validateComponentCategory = utils.validateYupSchema(componentCategorySchema);
1359
+ const componentCategories = {
1360
+ async editCategory(ctx) {
1361
+ const body = ctx.request.body;
1362
+ try {
1363
+ await validateComponentCategory(body);
1364
+ } catch (error) {
1365
+ return ctx.send({ error }, 400);
1366
+ }
1367
+ const { name } = ctx.params;
1368
+ strapi.reload.isWatching = false;
1369
+ const componentCategoryService = getService("component-categories");
1370
+ const newName = await componentCategoryService.editCategory(name, body);
1371
+ setImmediate(() => strapi.reload());
1372
+ ctx.send({ name: newName });
1373
+ },
1374
+ async deleteCategory(ctx) {
1375
+ const { name } = ctx.params;
1376
+ strapi.reload.isWatching = false;
1377
+ const componentCategoryService = getService("component-categories");
1378
+ await componentCategoryService.deleteCategory(name);
1379
+ setImmediate(() => strapi.reload());
1380
+ ctx.send({ name });
1381
+ }
1382
+ };
1383
+ const maxLengthIsGreaterThanOrEqualToMinLength = {
1384
+ name: "isGreaterThanMin",
1385
+ message: "maxLength must be greater or equal to minLength",
1386
+ test(value) {
1387
+ const { minLength } = this.parent;
1388
+ return !(!___default.default.isUndefined(minLength) && !___default.default.isUndefined(value) && value < minLength);
1389
+ }
1390
+ };
1391
+ const getTypeValidator = (attribute, { types, modelType, attributes }) => {
1392
+ return utils.yup.object({
1393
+ type: utils.yup.string().oneOf([...types]).required(),
1394
+ configurable: utils.yup.boolean().nullable(),
1395
+ private: utils.yup.boolean().nullable(),
1396
+ pluginOptions: utils.yup.object(),
1397
+ ...getTypeShape(attribute, { modelType, attributes })
1398
+ });
1399
+ };
1400
+ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
1401
+ switch (attribute.type) {
1402
+ case "media": {
1403
+ return {
1404
+ multiple: utils.yup.boolean(),
1405
+ required: validators.required,
1406
+ allowedTypes: utils.yup.array().of(utils.yup.string().oneOf(["images", "videos", "files", "audios"])).min(1)
1407
+ };
1408
+ }
1409
+ case "uid": {
1410
+ return {
1411
+ required: validators.required,
1412
+ targetField: utils.yup.string().oneOf(
1413
+ Object.keys(attributes).filter(
1414
+ (key) => VALID_UID_TARGETS.includes(___default.default.get(attributes[key], "type"))
1415
+ )
1416
+ ).nullable(),
1417
+ default: utils.yup.string().test(
1418
+ "isValidDefaultUID",
1419
+ "cannot define a default UID if the targetField is set",
1420
+ function(value) {
1421
+ const { targetField } = this.parent;
1422
+ return !!(___default.default.isNil(targetField) || ___default.default.isNil(value));
1423
+ }
1424
+ ).test(isValidUID),
1425
+ minLength: validators.minLength,
1426
+ maxLength: validators.maxLength.max(256).test(maxLengthIsGreaterThanOrEqualToMinLength),
1427
+ options: utils.yup.object().shape({
1428
+ separator: utils.yup.string(),
1429
+ lowercase: utils.yup.boolean(),
1430
+ decamelize: utils.yup.boolean(),
1431
+ customReplacements: utils.yup.array().of(utils.yup.array().of(utils.yup.string()).min(2).max(2)),
1432
+ preserveLeadingUnderscore: utils.yup.boolean()
1433
+ })
1434
+ };
1435
+ }
1436
+ case "string":
1437
+ case "text": {
1438
+ return {
1439
+ default: utils.yup.string(),
1440
+ required: validators.required,
1441
+ unique: validators.unique,
1442
+ minLength: validators.minLength,
1443
+ maxLength: validators.maxLength,
1444
+ regex: utils.yup.string().test(isValidRegExpPattern)
1445
+ };
1446
+ }
1447
+ case "richtext": {
1448
+ return {
1449
+ default: utils.yup.string(),
1450
+ required: validators.required,
1451
+ minLength: validators.minLength,
1452
+ maxLength: validators.maxLength
1453
+ };
1454
+ }
1455
+ case "blocks": {
1456
+ return {
1457
+ required: validators.required
1458
+ };
1459
+ }
1460
+ case "json": {
1461
+ return {
1462
+ default: utils.yup.mixed().test(isValidDefaultJSON),
1463
+ required: validators.required
1464
+ };
1465
+ }
1466
+ case "enumeration": {
1467
+ return {
1468
+ enum: utils.yup.array().of(utils.yup.string().test(isValidEnum).required()).min(1).test(areEnumValuesUnique).required(),
1469
+ default: utils.yup.string().when("enum", (enumVal) => utils.yup.string().oneOf(enumVal)),
1470
+ enumName: utils.yup.string().test(isValidName),
1471
+ required: validators.required
1472
+ };
1473
+ }
1474
+ case "password": {
1475
+ return {
1476
+ required: validators.required,
1477
+ minLength: validators.minLength,
1478
+ maxLength: validators.maxLength
1479
+ };
1480
+ }
1481
+ case "email": {
1482
+ return {
1483
+ default: utils.yup.string().email(),
1484
+ required: validators.required,
1485
+ unique: validators.unique,
1486
+ minLength: validators.minLength,
1487
+ maxLength: validators.maxLength
1488
+ };
1489
+ }
1490
+ case "integer": {
1491
+ return {
1492
+ default: utils.yup.number().integer(),
1493
+ required: validators.required,
1494
+ unique: validators.unique,
1495
+ min: utils.yup.number().integer(),
1496
+ max: utils.yup.number().integer()
1497
+ };
1498
+ }
1499
+ case "biginteger": {
1500
+ return {
1501
+ default: utils.yup.string().nullable().matches(/^\d*$/),
1502
+ required: validators.required,
1503
+ unique: validators.unique,
1504
+ min: utils.yup.string().nullable().matches(/^\d*$/),
1505
+ max: utils.yup.string().nullable().matches(/^\d*$/)
1506
+ };
1507
+ }
1508
+ case "float": {
1509
+ return {
1510
+ default: utils.yup.number(),
1511
+ required: validators.required,
1512
+ unique: validators.unique,
1513
+ min: utils.yup.number(),
1514
+ max: utils.yup.number()
1515
+ };
1516
+ }
1517
+ case "decimal": {
1518
+ return {
1519
+ default: utils.yup.number(),
1520
+ required: validators.required,
1521
+ unique: validators.unique,
1522
+ min: utils.yup.number(),
1523
+ max: utils.yup.number()
1524
+ };
1525
+ }
1526
+ case "time":
1527
+ case "datetime":
1528
+ case "date": {
1529
+ return {
1530
+ default: utils.yup.string(),
1531
+ required: validators.required,
1532
+ unique: validators.unique
1533
+ };
1534
+ }
1535
+ case "boolean": {
1536
+ return {
1537
+ default: utils.yup.boolean(),
1538
+ required: validators.required
1539
+ };
1540
+ }
1541
+ case "component": {
1542
+ return {
1543
+ required: validators.required,
1544
+ repeatable: utils.yup.boolean(),
1545
+ component: utils.yup.string().test({
1546
+ name: "Check max component nesting is 1 lvl",
1547
+ test(compoUID) {
1548
+ const targetCompo = strapi.components[compoUID];
1549
+ if (!targetCompo)
1550
+ return true;
1551
+ if (modelType === modelTypes.COMPONENT && hasComponent(targetCompo)) {
1552
+ return this.createError({
1553
+ path: this.path,
1554
+ message: `${targetCompo.modelName} already is a nested component. You cannot have more than one level of nesting inside your components.`
1555
+ });
1556
+ }
1557
+ return true;
1558
+ }
1559
+ }).required(),
1560
+ min: utils.yup.number(),
1561
+ max: utils.yup.number()
1562
+ };
1563
+ }
1564
+ case "dynamiczone": {
1565
+ return {
1566
+ required: validators.required,
1567
+ components: utils.yup.array().of(utils.yup.string().required()).test("isArray", "${path} must be an array", (value) => Array.isArray(value)).min(1),
1568
+ min: utils.yup.number(),
1569
+ max: utils.yup.number()
1570
+ };
1571
+ }
1572
+ default: {
1573
+ return {};
1574
+ }
1575
+ }
1576
+ };
1577
+ const STRAPI_USER_RELATIONS = ["oneToOne", "oneToMany"];
1578
+ const isValidRelation = (validNatures) => function(value) {
1579
+ if (value === void 0) {
1580
+ return true;
1581
+ }
1582
+ if (this.parent.target === coreUids.STRAPI_USER) {
1583
+ if (!validNatures.includes(value) || !fp.isUndefined(this.parent.targetAttribute)) {
1584
+ return this.createError({
1585
+ path: this.path,
1586
+ message: `must be one of the following values: ${STRAPI_USER_RELATIONS.join(", ")}`
1587
+ });
1588
+ }
1589
+ }
1590
+ return validNatures.includes(value) ? true : this.createError({
1591
+ path: this.path,
1592
+ message: `must be one of the following values: ${validNatures.join(", ")}`
1593
+ });
1594
+ };
1595
+ const getRelationValidator = (attribute, allowedRelations) => {
1596
+ const contentTypesUIDs = Object.keys(strapi.contentTypes).filter((key) => strapi.contentTypes[key].kind === typeKinds.COLLECTION_TYPE).filter((key) => !key.startsWith(coreUids.PREFIX) || key === coreUids.STRAPI_USER).concat(["__self__", "__contentType__"]);
1597
+ const base = {
1598
+ type: utils.yup.string().oneOf(["relation"]).required(),
1599
+ relation: utils.yup.string().test("isValidRelation", isValidRelation(allowedRelations)).required(),
1600
+ configurable: utils.yup.boolean().nullable(),
1601
+ private: utils.yup.boolean().nullable(),
1602
+ pluginOptions: utils.yup.object()
1603
+ };
1604
+ switch (attribute.relation) {
1605
+ case "oneToOne":
1606
+ case "oneToMany":
1607
+ case "manyToOne":
1608
+ case "manyToMany":
1609
+ case "morphOne":
1610
+ case "morphMany": {
1611
+ return utils.yup.object({
1612
+ ...base,
1613
+ target: utils.yup.string().oneOf(contentTypesUIDs).required(),
1614
+ targetAttribute: utils.yup.string().test(isValidName).nullable()
1615
+ });
1616
+ }
1617
+ case "morphToOne":
1618
+ case "morphToMany":
1619
+ default: {
1620
+ return utils.yup.object({ ...base });
1621
+ }
1622
+ }
1623
+ };
1624
+ const createSchema = (types, relations, { modelType } = {}) => {
1625
+ const shape = {
1626
+ description: utils.yup.string(),
1627
+ options: utils.yup.object(),
1628
+ pluginOptions: utils.yup.object(),
1629
+ collectionName: utils.yup.string().nullable().test(isValidCollectionName),
1630
+ attributes: createAttributesValidator({ types, relations, modelType }),
1631
+ reviewWorkflows: utils.yup.boolean(),
1632
+ draftAndPublish: utils.yup.boolean()
1633
+ };
1634
+ if (modelType === modelTypes.CONTENT_TYPE) {
1635
+ shape.kind = utils.yup.string().oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]).nullable();
1636
+ }
1637
+ return utils.yup.object(shape).noUnknown();
1638
+ };
1639
+ const createAttributesValidator = ({ types, modelType, relations }) => {
1640
+ return utils.yup.lazy((attributes) => {
1641
+ return utils.yup.object().shape(
1642
+ ___default.default.mapValues(attributes, (attribute, key) => {
1643
+ if (isForbiddenKey(key)) {
1644
+ return forbiddenValidator();
1645
+ }
1646
+ if (isConflictingKey(key, attributes)) {
1647
+ return conflictingKeysValidator(key);
1648
+ }
1649
+ if (attribute.type === "relation") {
1650
+ return getRelationValidator(attribute, relations).test(isValidKey(key));
1651
+ }
1652
+ if (___default.default.has(attribute, "type")) {
1653
+ return getTypeValidator(attribute, { types, modelType, attributes }).test(
1654
+ isValidKey(key)
1655
+ );
1656
+ }
1657
+ return typeOrRelationValidator;
1658
+ })
1659
+ ).required("attributes.required");
1660
+ });
1661
+ };
1662
+ const isConflictingKey = (key, attributes) => {
1663
+ const snakeCaseKey = fp.snakeCase(key);
1664
+ return Object.keys(attributes).some((existingKey) => {
1665
+ if (existingKey === key)
1666
+ return false;
1667
+ return fp.snakeCase(existingKey) === snakeCaseKey;
1668
+ });
1669
+ };
1670
+ const isForbiddenKey = (key) => {
1671
+ const snakeCaseKey = fp.snakeCase(key);
1672
+ const reservedNames = [
1673
+ ...FORBIDDEN_ATTRIBUTE_NAMES,
1674
+ ...getService("builder").getReservedNames().attributes
1675
+ ];
1676
+ return reservedNames.some((reserved) => {
1677
+ return fp.snakeCase(reserved) === snakeCaseKey;
1678
+ });
1679
+ };
1680
+ const forbiddenValidator = () => {
1681
+ const reservedNames = [
1682
+ ...FORBIDDEN_ATTRIBUTE_NAMES,
1683
+ ...getService("builder").getReservedNames().attributes
1684
+ ];
1685
+ return utils.yup.mixed().test({
1686
+ name: "forbiddenKeys",
1687
+ message: `Attribute keys cannot be one of ${reservedNames.join(", ")}`,
1688
+ test: () => false
1689
+ });
1690
+ };
1691
+ const conflictingKeysValidator = (key) => {
1692
+ return utils.yup.mixed().test({
1693
+ name: "conflictingKeys",
1694
+ message: `Attribute ${key} conflicts with an existing key`,
1695
+ test: () => false
1696
+ });
1697
+ };
1698
+ const typeOrRelationValidator = utils.yup.object().test({
1699
+ name: "mustHaveTypeOrTarget",
1700
+ message: "Attribute must have either a type or a target",
1701
+ test: () => false
1702
+ });
1703
+ const hasDefaultAttribute = (attribute) => {
1704
+ return "default" in attribute;
1705
+ };
1706
+ const removeEmptyDefaults = (data) => {
1707
+ const { attributes } = data || {};
1708
+ Object.keys(attributes).forEach((attributeName) => {
1709
+ const attribute = attributes[attributeName];
1710
+ if (hasDefaultAttribute(attribute) && attribute.default === "") {
1711
+ attribute.default = void 0;
1712
+ }
1713
+ });
1714
+ };
1715
+ const removeDeletedUIDTargetFields = (data) => {
1716
+ if (___default.default.has(data, "attributes")) {
1717
+ Object.values(data.attributes).forEach((attribute) => {
1718
+ if (attribute.type === "uid" && !___default.default.isUndefined(attribute.targetField) && !___default.default.has(data.attributes, attribute.targetField)) {
1719
+ attribute.targetField = void 0;
1720
+ }
1721
+ });
1722
+ }
1723
+ };
1724
+ const VALID_RELATIONS$1 = ["oneToOne", "oneToMany"];
1725
+ const VALID_TYPES$1 = [...DEFAULT_TYPES, "component", "customField"];
1726
+ const componentSchema = createSchema(VALID_TYPES$1, VALID_RELATIONS$1, {
1727
+ modelType: modelTypes.COMPONENT
1728
+ }).shape({
1729
+ displayName: utils.yup.string().min(1).required("displayName.required"),
1730
+ icon: utils.yup.string().nullable().test(isValidIcon),
1731
+ category: utils.yup.string().nullable().test(isValidCategoryName).required("category.required")
1732
+ }).required().noUnknown();
1733
+ const nestedComponentSchema = utils.yup.array().of(
1734
+ componentSchema.shape({
1735
+ uid: utils.yup.string(),
1736
+ tmpUID: utils.yup.string()
1737
+ }).test({
1738
+ name: "mustHaveUIDOrTmpUID",
1739
+ message: "Component must have a uid or a tmpUID",
1740
+ test(attr) {
1741
+ if (___default.default.has(attr, "uid") && ___default.default.has(attr, "tmpUID"))
1742
+ return false;
1743
+ if (!___default.default.has(attr, "uid") && !___default.default.has(attr, "tmpUID"))
1744
+ return false;
1745
+ return true;
1746
+ }
1747
+ }).required().noUnknown()
1748
+ );
1749
+ const componentInputSchema = utils.yup.object({
1750
+ component: componentSchema,
1751
+ components: nestedComponentSchema
1752
+ }).noUnknown();
1753
+ const validateComponentInput = utils.validateYupSchema(componentInputSchema);
1754
+ const updateComponentInputSchema = utils.yup.object({
1755
+ component: componentSchema,
1756
+ components: nestedComponentSchema
1757
+ }).noUnknown();
1758
+ const validateUpdateComponentInput = (data) => {
1759
+ if (___default.default.has(data, "component") && data.component) {
1760
+ removeEmptyDefaults(data.component);
1761
+ }
1762
+ if (___default.default.has(data, "components") && Array.isArray(data.components)) {
1763
+ data.components.forEach((data2) => {
1764
+ if (___default.default.has(data2, "uid")) {
1765
+ removeEmptyDefaults(data2);
1766
+ }
1767
+ });
1768
+ }
1769
+ return utils.validateYupSchema(updateComponentInputSchema)(data);
1770
+ };
1771
+ const components = {
1772
+ /**
1773
+ * GET /components handler
1774
+ * Returns a list of available components
1775
+ * @param {Object} ctx - koa context
1776
+ */
1777
+ async getComponents(ctx) {
1778
+ const componentService = getService("components");
1779
+ const componentUIDs = Object.keys(strapi.components);
1780
+ const data = componentUIDs.map((uid) => {
1781
+ return componentService.formatComponent(strapi.components[uid]);
1782
+ });
1783
+ ctx.send({ data });
1784
+ },
1785
+ /**
1786
+ * GET /components/:uid
1787
+ * Returns a specific component
1788
+ * @param {Object} ctx - koa context
1789
+ */
1790
+ async getComponent(ctx) {
1791
+ const { uid } = ctx.params;
1792
+ const component = strapi.components[uid];
1793
+ if (!component) {
1794
+ return ctx.send({ error: "component.notFound" }, 404);
1795
+ }
1796
+ const componentService = getService("components");
1797
+ ctx.send({ data: componentService.formatComponent(component) });
1798
+ },
1799
+ /**
1800
+ * POST /components
1801
+ * Creates a component and returns its infos
1802
+ * @param {Object} ctx - koa context
1803
+ */
1804
+ async createComponent(ctx) {
1805
+ const body = ctx.request.body;
1806
+ try {
1807
+ await validateComponentInput(body);
1808
+ } catch (error) {
1809
+ return ctx.send({ error }, 400);
1810
+ }
1811
+ try {
1812
+ strapi.reload.isWatching = false;
1813
+ const componentService = getService("components");
1814
+ const component = await componentService.createComponent({
1815
+ component: body.component,
1816
+ components: body.components
1817
+ });
1818
+ setImmediate(() => strapi.reload());
1819
+ ctx.send({ data: { uid: component.uid } }, 201);
1820
+ } catch (error) {
1821
+ strapi.log.error(error);
1822
+ ctx.send({ error: error?.message || "Unknown error" }, 400);
1823
+ }
1824
+ },
1825
+ /**
1826
+ * PUT /components/:uid
1827
+ * Updates a component and return its infos
1828
+ * @param {Object} ctx - koa context - enhanced koa context
1829
+ */
1830
+ async updateComponent(ctx) {
1831
+ const { uid } = ctx.params;
1832
+ const body = ctx.request.body;
1833
+ if (!___default.default.has(strapi.components, uid)) {
1834
+ return ctx.send({ error: "component.notFound" }, 404);
1835
+ }
1836
+ try {
1837
+ await validateUpdateComponentInput(body);
1838
+ } catch (error) {
1839
+ return ctx.send({ error }, 400);
1840
+ }
1841
+ try {
1842
+ strapi.reload.isWatching = false;
1843
+ const componentService = getService("components");
1844
+ const component = await componentService.editComponent(uid, {
1845
+ component: body.component,
1846
+ components: body.components
1847
+ });
1848
+ setImmediate(() => strapi.reload());
1849
+ ctx.send({ data: { uid: component.uid } });
1850
+ } catch (error) {
1851
+ strapi.log.error(error);
1852
+ ctx.send({ error: error?.message || "Unknown error" }, 400);
1853
+ }
1854
+ },
1855
+ /**
1856
+ * DELETE /components/:uid
1857
+ * Deletes a components and returns its old infos
1858
+ * @param {Object} ctx - koa context
1859
+ */
1860
+ async deleteComponent(ctx) {
1861
+ const { uid } = ctx.params;
1862
+ if (!___default.default.has(strapi.components, uid)) {
1863
+ return ctx.send({ error: "component.notFound" }, 404);
1864
+ }
1865
+ try {
1866
+ strapi.reload.isWatching = false;
1867
+ const componentService = getService("components");
1868
+ const component = await componentService.deleteComponent(uid);
1869
+ setImmediate(() => strapi.reload());
1870
+ ctx.send({ data: { uid: component.uid } });
1871
+ } catch (error) {
1872
+ strapi.log.error(error);
1873
+ ctx.send({ error: error?.message || "Unknown error" }, 400);
1874
+ }
1875
+ }
1876
+ };
1877
+ const VALID_RELATIONS = {
1878
+ [typeKinds.SINGLE_TYPE]: [
1879
+ "oneToOne",
1880
+ "oneToMany",
1881
+ "morphOne",
1882
+ "morphMany",
1883
+ "morphToOne",
1884
+ "morphToMany"
1885
+ ],
1886
+ [typeKinds.COLLECTION_TYPE]: [
1887
+ "oneToOne",
1888
+ "oneToMany",
1889
+ "manyToOne",
1890
+ "manyToMany",
1891
+ "morphOne",
1892
+ "morphMany",
1893
+ "morphToOne",
1894
+ "morphToMany"
1895
+ ]
1896
+ };
1897
+ const VALID_TYPES = [...DEFAULT_TYPES, "uid", "component", "dynamiczone", "customField"];
1898
+ const createContentTypeSchema = (data, { isEdition = false } = {}) => {
1899
+ const kind = fp.getOr(
1900
+ typeKinds.COLLECTION_TYPE,
1901
+ "contentType.kind",
1902
+ data
1903
+ );
1904
+ const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS[kind] || [], {
1905
+ modelType: modelTypes.CONTENT_TYPE
1906
+ }).shape({
1907
+ displayName: utils.yup.string().min(1).required(),
1908
+ singularName: utils.yup.string().min(1).test(nameIsAvailable(isEdition)).test(forbiddenContentTypeNameValidator()).isKebabCase().required(),
1909
+ pluralName: utils.yup.string().min(1).test(nameIsAvailable(isEdition)).test(nameIsNotExistingCollectionName(isEdition)).test(forbiddenContentTypeNameValidator()).isKebabCase().required()
1910
+ }).test(
1911
+ "singularName-not-equal-pluralName",
1912
+ "${path}: singularName and pluralName should be different",
1913
+ (value) => value.singularName !== value.pluralName
1914
+ );
1915
+ return utils.yup.object({
1916
+ // FIXME .noUnknown(false) will strip off the unwanted properties without throwing an error
1917
+ // Why not having .noUnknown() ? Because we want to be able to add options relatable to EE features
1918
+ // without having any reference to them in CE.
1919
+ // Why not handle an "options" object in the content-type ? The admin panel needs lots of rework
1920
+ // to be able to send this options object instead of top-level attributes.
1921
+ // @nathan-pichon 20/02/2023
1922
+ contentType: contentTypeSchema.required().noUnknown(false),
1923
+ components: nestedComponentSchema
1924
+ }).noUnknown();
1925
+ };
1926
+ const validateContentTypeInput = (data) => {
1927
+ return utils.validateYupSchema(createContentTypeSchema(data))(data);
1928
+ };
1929
+ const validateUpdateContentTypeInput = (data) => {
1930
+ if (fp.has("contentType", data)) {
1931
+ removeEmptyDefaults(data.contentType);
1932
+ removeDeletedUIDTargetFields(data.contentType);
1933
+ }
1934
+ if (fp.has("components", data) && Array.isArray(data.components)) {
1935
+ data.components.forEach((comp) => {
1936
+ if (fp.has("uid", comp)) {
1937
+ removeEmptyDefaults(comp);
1938
+ }
1939
+ });
1940
+ }
1941
+ return utils.validateYupSchema(createContentTypeSchema(data, { isEdition: true }))(data);
1942
+ };
1943
+ const forbiddenContentTypeNameValidator = () => {
1944
+ const reservedNames = getService("builder").getReservedNames().models;
1945
+ return {
1946
+ name: "forbiddenContentTypeName",
1947
+ message: `Content Type name cannot be one of ${reservedNames.join(", ")}`,
1948
+ test(value) {
1949
+ if (typeof value !== "string") {
1950
+ return true;
1951
+ }
1952
+ return reservedNames.every((reservedName) => fp.snakeCase(reservedName) !== fp.snakeCase(value));
1953
+ }
1954
+ };
1955
+ };
1956
+ const nameIsAvailable = (isEdition) => {
1957
+ const usedNames = fp.flatMap((ct) => {
1958
+ return [ct.info?.singularName, ct.info?.pluralName];
1959
+ })(strapi.contentTypes);
1960
+ return {
1961
+ name: "nameAlreadyUsed",
1962
+ message: "contentType: name `${value}` is already being used by another content type.",
1963
+ test(value) {
1964
+ if (isEdition)
1965
+ return true;
1966
+ if (typeof value !== "string") {
1967
+ return true;
1968
+ }
1969
+ return usedNames.every((usedName) => fp.snakeCase(usedName) !== fp.snakeCase(value));
1970
+ }
1971
+ };
1972
+ };
1973
+ const nameIsNotExistingCollectionName = (isEdition) => {
1974
+ const usedNames = Object.keys(strapi.contentTypes).map(
1975
+ (key) => strapi.contentTypes[key].collectionName
1976
+ );
1977
+ return {
1978
+ name: "nameAlreadyUsed",
1979
+ message: "contentType: name `${value}` is already being used by another content type.",
1980
+ test(value) {
1981
+ if (isEdition)
1982
+ return true;
1983
+ if (typeof value !== "string") {
1984
+ return true;
1985
+ }
1986
+ return usedNames.every((usedName) => fp.snakeCase(usedName) !== fp.snakeCase(value));
1987
+ }
1988
+ };
1989
+ };
1990
+ const kindSchema = utils.yup.string().oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]);
1991
+ const validateKind = utils.validateYupSchema(kindSchema);
1992
+ const contentTypes = {
1993
+ async getContentTypes(ctx) {
1994
+ const { kind } = ctx.query;
1995
+ try {
1996
+ await validateKind(kind);
1997
+ } catch (error) {
1998
+ return ctx.send({ error }, 400);
1999
+ }
2000
+ const contentTypeService = getService("content-types");
2001
+ const contentTypes2 = Object.keys(strapi.contentTypes).filter(
2002
+ (uid) => !kind || ___default.default.get(strapi.contentTypes[uid], "kind", "collectionType") === kind
2003
+ ).map(
2004
+ (uid) => contentTypeService.formatContentType(strapi.contentTypes[uid])
2005
+ );
2006
+ ctx.send({
2007
+ data: contentTypes2
2008
+ });
2009
+ },
2010
+ getContentType(ctx) {
2011
+ const { uid } = ctx.params;
2012
+ const contentType = strapi.contentTypes[uid];
2013
+ if (!contentType) {
2014
+ return ctx.send({ error: "contentType.notFound" }, 404);
2015
+ }
2016
+ const contentTypeService = getService("content-types");
2017
+ ctx.send({ data: contentTypeService.formatContentType(contentType) });
2018
+ },
2019
+ async createContentType(ctx) {
2020
+ const body = ctx.request.body;
2021
+ try {
2022
+ await validateContentTypeInput(body);
2023
+ } catch (error) {
2024
+ return ctx.send({ error }, 400);
2025
+ }
2026
+ try {
2027
+ strapi.reload.isWatching = false;
2028
+ const contentTypeService = getService("content-types");
2029
+ const contentType = await contentTypeService.createContentType({
2030
+ contentType: body.contentType,
2031
+ components: body.components
2032
+ });
2033
+ const metricsPayload = {
2034
+ eventProperties: {
2035
+ kind: contentType.kind
2036
+ }
2037
+ };
2038
+ if (___default.default.isEmpty(strapi.apis)) {
2039
+ await strapi.telemetry.send("didCreateFirstContentType", metricsPayload);
2040
+ } else {
2041
+ await strapi.telemetry.send("didCreateContentType", metricsPayload);
2042
+ }
2043
+ setImmediate(() => strapi.reload());
2044
+ ctx.send({ data: { uid: contentType.uid } }, 201);
2045
+ } catch (err) {
2046
+ strapi.log.error(err);
2047
+ await strapi.telemetry.send("didNotCreateContentType", {
2048
+ eventProperties: { error: err.message || err }
2049
+ });
2050
+ ctx.send({ error: err.message || "Unknown error" }, 400);
2051
+ }
2052
+ },
2053
+ async updateContentType(ctx) {
2054
+ const { uid } = ctx.params;
2055
+ const body = ctx.request.body;
2056
+ if (!___default.default.has(strapi.contentTypes, uid)) {
2057
+ return ctx.send({ error: "contentType.notFound" }, 404);
2058
+ }
2059
+ try {
2060
+ await validateUpdateContentTypeInput(body);
2061
+ } catch (error) {
2062
+ return ctx.send({ error }, 400);
2063
+ }
2064
+ try {
2065
+ strapi.reload.isWatching = false;
2066
+ const contentTypeService = getService("content-types");
2067
+ const component = await contentTypeService.editContentType(uid, {
2068
+ contentType: body.contentType,
2069
+ components: body.components
2070
+ });
2071
+ setImmediate(() => strapi.reload());
2072
+ ctx.send({ data: { uid: component.uid } }, 201);
2073
+ } catch (error) {
2074
+ strapi.log.error(error);
2075
+ ctx.send({ error: error?.message || "Unknown error" }, 400);
2076
+ }
2077
+ },
2078
+ async deleteContentType(ctx) {
2079
+ const { uid } = ctx.params;
2080
+ if (!___default.default.has(strapi.contentTypes, uid)) {
2081
+ return ctx.send({ error: "contentType.notFound" }, 404);
2082
+ }
2083
+ try {
2084
+ strapi.reload.isWatching = false;
2085
+ const contentTypeService = getService("content-types");
2086
+ const component = await contentTypeService.deleteContentType(uid);
2087
+ setImmediate(() => strapi.reload());
2088
+ ctx.send({ data: { uid: component.uid } });
2089
+ } catch (error) {
2090
+ strapi.log.error(error);
2091
+ ctx.send({ error: error?.message || "Unknown error" }, 400);
2092
+ }
2093
+ }
2094
+ };
2095
+ const exportObject = {
2096
+ builder,
2097
+ "component-categories": componentCategories,
2098
+ components,
2099
+ "content-types": contentTypes
2100
+ };
2101
+ const admin = {
2102
+ type: "admin",
2103
+ routes: [
2104
+ {
2105
+ method: "GET",
2106
+ path: "/reserved-names",
2107
+ handler: "builder.getReservedNames",
2108
+ config: {
2109
+ policies: [
2110
+ {
2111
+ name: "admin::hasPermissions",
2112
+ config: { actions: ["plugin::content-type-builder.read"] }
2113
+ }
2114
+ ]
2115
+ }
2116
+ },
2117
+ {
2118
+ method: "GET",
2119
+ path: "/content-types",
2120
+ handler: "content-types.getContentTypes",
2121
+ config: {
2122
+ policies: [
2123
+ {
2124
+ name: "admin::hasPermissions",
2125
+ config: { actions: ["plugin::content-type-builder.read"] }
2126
+ }
2127
+ ]
2128
+ }
2129
+ },
2130
+ {
2131
+ method: "GET",
2132
+ path: "/content-types/:uid",
2133
+ handler: "content-types.getContentType",
2134
+ config: {
2135
+ policies: [
2136
+ {
2137
+ name: "admin::hasPermissions",
2138
+ config: { actions: ["plugin::content-type-builder.read"] }
2139
+ }
2140
+ ]
2141
+ }
2142
+ },
2143
+ {
2144
+ method: "POST",
2145
+ path: "/content-types",
2146
+ handler: "content-types.createContentType",
2147
+ config: {
2148
+ policies: [
2149
+ {
2150
+ name: "admin::hasPermissions",
2151
+ config: { actions: ["plugin::content-type-builder.read"] }
2152
+ }
2153
+ ]
2154
+ }
2155
+ },
2156
+ {
2157
+ method: "PUT",
2158
+ path: "/content-types/:uid",
2159
+ handler: "content-types.updateContentType",
2160
+ config: {
2161
+ policies: [
2162
+ {
2163
+ name: "admin::hasPermissions",
2164
+ config: { actions: ["plugin::content-type-builder.read"] }
2165
+ }
2166
+ ]
2167
+ }
2168
+ },
2169
+ {
2170
+ method: "DELETE",
2171
+ path: "/content-types/:uid",
2172
+ handler: "content-types.deleteContentType",
2173
+ config: {
2174
+ policies: [
2175
+ {
2176
+ name: "admin::hasPermissions",
2177
+ config: { actions: ["plugin::content-type-builder.read"] }
2178
+ }
2179
+ ]
2180
+ }
2181
+ },
2182
+ {
2183
+ method: "GET",
2184
+ path: "/components",
2185
+ handler: "components.getComponents",
2186
+ config: {
2187
+ policies: [
2188
+ {
2189
+ name: "admin::hasPermissions",
2190
+ config: { actions: ["plugin::content-type-builder.read"] }
2191
+ }
2192
+ ]
2193
+ }
2194
+ },
2195
+ {
2196
+ method: "GET",
2197
+ path: "/components/:uid",
2198
+ handler: "components.getComponent",
2199
+ config: {
2200
+ policies: [
2201
+ {
2202
+ name: "admin::hasPermissions",
2203
+ config: { actions: ["plugin::content-type-builder.read"] }
2204
+ }
2205
+ ]
2206
+ }
2207
+ },
2208
+ {
2209
+ method: "POST",
2210
+ path: "/components",
2211
+ handler: "components.createComponent",
2212
+ config: {
2213
+ policies: [
2214
+ {
2215
+ name: "admin::hasPermissions",
2216
+ config: { actions: ["plugin::content-type-builder.read"] }
2217
+ }
2218
+ ]
2219
+ }
2220
+ },
2221
+ {
2222
+ method: "PUT",
2223
+ path: "/components/:uid",
2224
+ handler: "components.updateComponent",
2225
+ config: {
2226
+ policies: [
2227
+ {
2228
+ name: "admin::hasPermissions",
2229
+ config: { actions: ["plugin::content-type-builder.read"] }
2230
+ }
2231
+ ]
2232
+ }
2233
+ },
2234
+ {
2235
+ method: "DELETE",
2236
+ path: "/components/:uid",
2237
+ handler: "components.deleteComponent",
2238
+ config: {
2239
+ policies: [
2240
+ {
2241
+ name: "admin::hasPermissions",
2242
+ config: { actions: ["plugin::content-type-builder.read"] }
2243
+ }
2244
+ ]
2245
+ }
2246
+ },
2247
+ {
2248
+ method: "PUT",
2249
+ path: "/component-categories/:name",
2250
+ handler: "component-categories.editCategory",
2251
+ config: {
2252
+ policies: [
2253
+ {
2254
+ name: "admin::hasPermissions",
2255
+ config: { actions: ["plugin::content-type-builder.read"] }
2256
+ }
2257
+ ]
2258
+ }
2259
+ },
2260
+ {
2261
+ method: "DELETE",
2262
+ path: "/component-categories/:name",
2263
+ handler: "component-categories.deleteCategory",
2264
+ config: {
2265
+ policies: [
2266
+ {
2267
+ name: "admin::hasPermissions",
2268
+ config: { actions: ["plugin::content-type-builder.read"] }
2269
+ }
2270
+ ]
2271
+ }
2272
+ }
2273
+ ]
2274
+ };
2275
+ const contentApi = {
2276
+ type: "content-api",
2277
+ routes: [
2278
+ {
2279
+ method: "GET",
2280
+ path: "/content-types",
2281
+ handler: "content-types.getContentTypes"
2282
+ },
2283
+ {
2284
+ method: "GET",
2285
+ path: "/content-types/:uid",
2286
+ handler: "content-types.getContentType"
2287
+ },
2288
+ {
2289
+ method: "GET",
2290
+ path: "/components",
2291
+ handler: "components.getComponents"
2292
+ },
2293
+ {
2294
+ method: "GET",
2295
+ path: "/components/:uid",
2296
+ handler: "components.getComponent"
2297
+ }
2298
+ ]
2299
+ };
2300
+ const routes = {
2301
+ admin,
2302
+ "content-api": contentApi
2303
+ };
2304
+ const index = () => ({
2305
+ config,
2306
+ bootstrap,
2307
+ services,
2308
+ controllers: exportObject,
2309
+ routes
2310
+ });
2311
+ module.exports = index;
2312
+ //# sourceMappingURL=index.js.map