adminizer 4.7.0-build.224 → 5.0.0-build.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/Readme.md +2 -1
  2. package/assets/add-De0wyF0A.js +1 -0
  3. package/assets/add-group-CMWybgIR.js +1 -0
  4. package/assets/add-user-BxP23daH.js +1 -0
  5. package/assets/app-CtWuWD5N.css +1 -0
  6. package/assets/app-layout-GYMU2HO1.js +1 -0
  7. package/assets/app.js +45 -50
  8. package/assets/catalog-tImW1BnS.js +6 -0
  9. package/assets/controls/chunks/_commonjsHelpers-C6fGbg64.js +6 -0
  10. package/assets/controls/chunks/index-CjiZ2FIa.js +93 -0
  11. package/assets/controls/chunks/jsx-runtime-jIxVPx5o.js +31 -0
  12. package/assets/controls/chunks/use-appearance-CFLOwiSX.js +38 -0
  13. package/assets/controls/chunks/use-window-size-BXgBKW65.js +19 -0
  14. package/assets/controls/chunks/vanilla-picker-Dg97NL4h.js +529 -0
  15. package/assets/controls/ckeditor.es.js +83683 -0
  16. package/assets/controls/handsontable.css +1 -0
  17. package/assets/controls/handsontable.es.js +70585 -0
  18. package/assets/controls/jsoneditor.css +1 -0
  19. package/assets/controls/jsoneditor.es.js +42082 -0
  20. package/assets/controls/leaflet.css +1 -0
  21. package/assets/controls/leaflet.es.js +10299 -0
  22. package/assets/controls/monaco.es.js +618 -0
  23. package/assets/controls/toast-ui.css +1 -0
  24. package/assets/controls/toast-ui.es.js +41797 -0
  25. package/assets/dashboard-CQ4atH3N.js +3 -0
  26. package/assets/debounce-BMmXVQ06.js +1 -0
  27. package/assets/history-BileQPEi.js +1 -0
  28. package/assets/init-user-8aUohVDq.js +1 -0
  29. package/assets/list-Pz_5mfSq.js +4 -0
  30. package/assets/login-CO4laf6m.js +1 -0
  31. package/assets/manifest.json +66 -602
  32. package/assets/media-manager-BDbpSSjH.js +6 -0
  33. package/assets/media-manager-BZPjl98I.css +1 -0
  34. package/assets/module-CQiOdgZN.js +1 -0
  35. package/assets/notification-BIyv1smE.js +20 -0
  36. package/assets/register-DBYIMXGQ.js +1 -0
  37. package/assets/ru-rYKdQbWF.js +1 -0
  38. package/assets/use-appearance-_EbbjHTh.js +1 -0
  39. package/assets/user-filters-list-Aq8CvCeh.js +1 -0
  40. package/assets/welcome-DxhWYzUL.js +1 -0
  41. package/controllers/add.d.ts +1 -1
  42. package/controllers/addGroup.js +3 -3
  43. package/controllers/addUser.js +3 -3
  44. package/controllers/catalog/Catalog.d.ts +1 -1
  45. package/controllers/catalog/Catalog.js +2 -1
  46. package/controllers/catalog/FrontendCatalogAdapter.d.ts +2 -12
  47. package/controllers/catalog/FrontendCatalogAdapter.js +3 -16
  48. package/controllers/catalog/FrontentCatalogAdapter.d.ts +2 -12
  49. package/controllers/catalog/FrontentCatalogAdapter.js +0 -16
  50. package/controllers/edit.js +6 -11
  51. package/controllers/editGroup.d.ts +1 -1
  52. package/controllers/editGroup.js +3 -3
  53. package/controllers/editUser.d.ts +1 -1
  54. package/controllers/editUser.js +3 -3
  55. package/controllers/feed.js +1 -1
  56. package/controllers/filter-fields/columns.js +1 -1
  57. package/controllers/filter-fields/getAllUserFilters.js +2 -2
  58. package/controllers/filter-fields/groups.js +2 -2
  59. package/controllers/filter-fields/savedFilters.js +1 -1
  60. package/controllers/history-actions/HistoryController.js +1 -1
  61. package/controllers/initUser.js +2 -2
  62. package/controllers/list.d.ts +1 -1
  63. package/controllers/login.d.ts +1 -1
  64. package/controllers/login.js +3 -3
  65. package/controllers/media-manager/ThumbController.js +2 -2
  66. package/controllers/media-manager/mediaManagerApi.js +13 -15
  67. package/controllers/register.d.ts +1 -1
  68. package/controllers/register.js +5 -5
  69. package/controllers/remove.d.ts +1 -1
  70. package/controllers/userApiKey.js +2 -2
  71. package/controllers/view.d.ts +1 -1
  72. package/controllers/view.js +5 -5
  73. package/controllers/widgets/Action.js +5 -2
  74. package/controllers/widgets/filterInfo.js +1 -1
  75. package/files/favicon.png +0 -0
  76. package/helpers/accessRightsHelper.d.ts +6 -4
  77. package/helpers/accessRightsHelper.js +13 -0
  78. package/helpers/diffHelpers.js +1 -1
  79. package/helpers/fieldsHelper.d.ts +1 -1
  80. package/helpers/fieldsHelper.js +8 -4
  81. package/helpers/filterDatetimeHelper.d.ts +1 -1
  82. package/helpers/inertiaAddHelper.d.ts +6 -5
  83. package/helpers/inertiaAddHelper.js +45 -37
  84. package/helpers/inertiaAutHelper.js +5 -5
  85. package/helpers/inertiaGroupHelper.d.ts +4 -4
  86. package/helpers/inertiaMenuHelper.js +1 -1
  87. package/helpers/inertiaUserHelper.d.ts +3 -3
  88. package/helpers/inertiaUserHelper.js +1 -1
  89. package/helpers/menuHelper.d.ts +2 -2
  90. package/index.d.ts +19 -6
  91. package/index.js +19 -6
  92. package/interfaces/adminpanelConfig.d.ts +10 -33
  93. package/interfaces/global.d.ts +10 -15
  94. package/interfaces/listQueryBuilder.d.ts +1 -1
  95. package/lib/Adminizer.d.ts +25 -2
  96. package/lib/Adminizer.js +124 -50
  97. package/lib/DataAccessor.d.ts +9 -5
  98. package/lib/DataAccessor.js +89 -42
  99. package/lib/access-rights/AccessRightsHandler.d.ts +17 -0
  100. package/lib/access-rights/AccessRightsHandler.js +63 -0
  101. package/lib/ai-assistant/AbstractAiModelService.d.ts +5 -8
  102. package/lib/ai-assistant/AbstractAiModelService.js +3 -14
  103. package/lib/ai-assistant/AiAssistantHandler.d.ts +2 -2
  104. package/lib/app-manager/AdminizerApp.d.ts +228 -0
  105. package/lib/app-manager/AdminizerApp.js +17 -0
  106. package/lib/app-manager/AppManager.d.ts +18 -0
  107. package/lib/app-manager/AppManager.js +537 -0
  108. package/lib/app-manager/AssetHandler.d.ts +17 -0
  109. package/lib/app-manager/AssetHandler.js +67 -0
  110. package/lib/app-manager/ConfigLayerHandler.d.ts +18 -0
  111. package/lib/app-manager/ConfigLayerHandler.js +119 -0
  112. package/lib/app-manager/ControllerHandler.d.ts +25 -0
  113. package/lib/app-manager/ControllerHandler.js +140 -0
  114. package/lib/catalog/AbstractCatalog.d.ts +28 -19
  115. package/lib/catalog/AbstractCatalog.js +41 -10
  116. package/lib/catalog/CatalogHandler.d.ts +13 -0
  117. package/lib/catalog/CatalogHandler.js +48 -2
  118. package/lib/catalog/CatalogTemplateComponentHandler.d.ts +23 -0
  119. package/lib/catalog/CatalogTemplateComponentHandler.js +59 -0
  120. package/lib/controls/Control.d.ts +17 -0
  121. package/lib/controls/Control.js +1 -0
  122. package/lib/controls/ControlsHandler.d.ts +5 -6
  123. package/lib/controls/ControlsHandler.js +0 -13
  124. package/lib/controls/codeEditor/MonacoEditor.d.ts +3 -4
  125. package/lib/controls/codeEditor/MonacoEditor.js +13 -8
  126. package/lib/controls/geojsoneditor/GeoEditor.d.ts +3 -4
  127. package/lib/controls/geojsoneditor/GeoEditor.js +14 -9
  128. package/lib/controls/jsoneditor/JsonEditor.d.ts +5 -6
  129. package/lib/controls/jsoneditor/JsonEditor.js +14 -13
  130. package/lib/controls/markdown/ToastUiEditor.d.ts +5 -6
  131. package/lib/controls/markdown/ToastUiEditor.js +14 -13
  132. package/lib/controls/table/Handsontable.d.ts +5 -6
  133. package/lib/controls/table/Handsontable.js +14 -13
  134. package/lib/controls/wysiwyg/CKeditor.d.ts +5 -6
  135. package/lib/controls/wysiwyg/CKeditor.js +14 -13
  136. package/lib/filters/ConditionValidator.d.ts +1 -1
  137. package/lib/filters/FilterService.d.ts +18 -18
  138. package/lib/filters/FilterService.js +11 -11
  139. package/lib/history-actions/AbstractHistoryAdapter.d.ts +14 -14
  140. package/lib/history-actions/AbstractHistoryAdapter.js +5 -6
  141. package/lib/history-actions/DefaultHistoryAdapter.d.ts +7 -7
  142. package/lib/history-actions/DefaultHistoryAdapter.js +2 -2
  143. package/lib/list-query-builder/ListQueryBuilder.d.ts +1 -1
  144. package/lib/media-manager/AbstractMediaManager.d.ts +14 -3
  145. package/lib/media-manager/AbstractMediaManager.js +16 -5
  146. package/lib/media-manager/MediaManagerHandler.d.ts +3 -0
  147. package/lib/media-manager/MediaManagerHandler.js +30 -5
  148. package/lib/media-manager/Thumb.js +7 -13
  149. package/lib/media-manager/helpers/MediaManagerHelper.d.ts +6 -4
  150. package/lib/media-manager/helpers/MediaManagerHelper.js +18 -18
  151. package/lib/model/AbstractModel.d.ts +9 -5
  152. package/lib/model/AbstractModel.js +9 -13
  153. package/lib/model/InternalModelAccessFactory.js +9 -10
  154. package/lib/model/ModelHandler.d.ts +45 -7
  155. package/lib/model/ModelHandler.js +168 -11
  156. package/lib/model/adapter/sequelize.d.ts +2 -4
  157. package/lib/model/adapter/sequelize.js +16 -193
  158. package/lib/model/adapter/typeorm.d.ts +2 -4
  159. package/lib/model/adapter/typeorm.js +2 -35
  160. package/lib/notifications/AbstractNotificationService.d.ts +9 -9
  161. package/lib/notifications/AbstractNotificationService.js +8 -8
  162. package/lib/notifications/GeneralNotificationService.js +1 -1
  163. package/lib/notifications/SystemNotificationService.js +1 -1
  164. package/lib/ui-i18n/uiTranslationKeys.d.ts +1 -1
  165. package/lib/ui-i18n/uiTranslationKeys.js +1 -0
  166. package/lib/widgets/abstractCustom.d.ts +5 -2
  167. package/lib/widgets/abstractCustom.js +4 -0
  168. package/lib/widgets/widgetHandler.d.ts +5 -2
  169. package/lib/widgets/widgetHandler.js +60 -14
  170. package/models/{FilterAP.d.ts → Filter.d.ts} +4 -70
  171. package/models/Filter.js +1 -0
  172. package/models/FilterColumn.d.ts +10 -0
  173. package/models/FilterColumn.js +1 -0
  174. package/models/Group.d.ts +8 -0
  175. package/models/Group.js +1 -0
  176. package/models/HistoryActions.d.ts +14 -0
  177. package/models/HistoryActions.js +1 -0
  178. package/models/MediaManagerAP.d.ts +2 -54
  179. package/models/MediaManagerAP.js +1 -51
  180. package/models/MediaManagerAssociationsAP.d.ts +1 -35
  181. package/models/MediaManagerAssociationsAP.js +1 -33
  182. package/models/MediaManagerMetaAP.d.ts +2 -30
  183. package/models/MediaManagerMetaAP.js +1 -27
  184. package/models/Notification.d.ts +13 -0
  185. package/models/Notification.js +1 -0
  186. package/models/User.d.ts +23 -0
  187. package/models/User.js +1 -0
  188. package/models/UserNotification.d.ts +7 -0
  189. package/models/UserNotification.js +1 -0
  190. package/package.json +25 -30
  191. package/services/FeedService.d.ts +5 -5
  192. package/services/FeedService.js +1 -1
  193. package/system/Router.js +2 -10
  194. package/system/bindAccessRights.js +1 -1
  195. package/system/bindAuthorization.js +2 -2
  196. package/system/bindControls.js +7 -6
  197. package/system/bindDashboardWidgets.js +3 -2
  198. package/system/bindDev.js +1 -1
  199. package/system/bindHistory.d.ts +1 -1
  200. package/system/bindHistory.js +1 -1
  201. package/system/bindInertia.js +0 -6
  202. package/system/bindMediaManager.js +4 -17
  203. package/system/bindNotifications.d.ts +1 -1
  204. package/system/bindNotifications.js +1 -1
  205. package/system/bindReqFunctions.d.ts +1 -0
  206. package/system/bindReqFunctions.js +20 -3
  207. package/system/buildInternalModelAccess.js +2 -15
  208. package/system/defaults.js +5 -10
  209. package/system/systemModelContracts.d.ts +22 -0
  210. package/system/systemModelContracts.js +155 -0
  211. package/system/validateSystemModels.d.ts +2 -0
  212. package/system/validateSystemModels.js +101 -0
  213. package/translations/ar.json +2 -1
  214. package/translations/cn.json +2 -1
  215. package/translations/de.json +2 -1
  216. package/translations/en.json +1 -0
  217. package/translations/es.json +2 -1
  218. package/translations/fr.json +2 -1
  219. package/translations/hi.json +2 -1
  220. package/translations/jp.json +2 -1
  221. package/translations/ko.json +2 -1
  222. package/translations/pt.json +2 -1
  223. package/translations/ru.json +2 -1
  224. package/translations/ua.json +2 -1
  225. package/translations/uz.json +2 -1
  226. package/translations/vi.json +2 -1
  227. package/assets/RelationDialogStack-DhThUMep.js +0 -20
  228. package/assets/add-group-L8lMigab.js +0 -1
  229. package/assets/add-group-form-o7F6t6qW.js +0 -1
  230. package/assets/add-user-BE4-TNJw.js +0 -1
  231. package/assets/add-user-form-BP_8TjxN.js +0 -1
  232. package/assets/add-w398ZkhF.js +0 -1
  233. package/assets/app-C7J5ccrI.css +0 -1
  234. package/assets/app-layout-Bg455MIY.js +0 -1
  235. package/assets/app-shell-BT2kF0We.js +0 -1
  236. package/assets/app-sidebar-CZfPUXck.js +0 -1
  237. package/assets/app-sidebar-header-UVcKhNm6.js +0 -1
  238. package/assets/breadcrumbs-CrqIBT84.js +0 -1
  239. package/assets/catalog-btkCCwiv.js +0 -6
  240. package/assets/dashboard-Bvasc1cr.js +0 -3
  241. package/assets/date-picker-kxQWOxHk.js +0 -1
  242. package/assets/del-modal-C39LR5aQ.js +0 -1
  243. package/assets/dynamic-controls-DyPP5sTC.js +0 -1
  244. package/assets/geo-json-CGNQFl6J.js +0 -1
  245. package/assets/handsontable-Dv59QFH5.js +0 -336
  246. package/assets/history-DwKR8MPu.js +0 -1
  247. package/assets/home-BrtAkCRj.js +0 -2
  248. package/assets/icon-DpUVVHmK.js +0 -1
  249. package/assets/init-user-8PiKR1zX.js +0 -1
  250. package/assets/input-error-Cbt-Y3Fj.js +0 -1
  251. package/assets/jsoneditor-CiPXPMho.js +0 -3869
  252. package/assets/list-DGsL_qii.js +0 -4
  253. package/assets/login-Br_FcBU_.js +0 -1
  254. package/assets/material-icon-DOkM71fv.js +0 -1
  255. package/assets/module-EgfgIEhF.js +0 -1
  256. package/assets/monaco-ompgKQ3_.js +0 -11
  257. package/assets/nav-footer-DzLwfBAE.js +0 -1
  258. package/assets/nav-main-CSEbjYgs.js +0 -1
  259. package/assets/nav-user-DJ0hfhfH.js +0 -1
  260. package/assets/notification-B19ZLro7.js +0 -20
  261. package/assets/pagination-render-8GvJxq55.js +0 -1
  262. package/assets/register-CZzIeT2G.js +0 -1
  263. package/assets/ru-1NdRIQNV.js +0 -1
  264. package/assets/theme-switcher-CBbEj1u-.js +0 -1
  265. package/assets/toast-editor-DwVqd1rz.js +0 -668
  266. package/assets/user-filters-list-7Im79QyS.js +0 -1
  267. package/assets/user-info-YiU17Mmy.js +0 -1
  268. package/assets/user-menu-content-gdpNF5-8.js +0 -1
  269. package/assets/vanilla-picker-B3LgXoKV.js +0 -2
  270. package/assets/vendor-l0sNRNKZ.js +0 -1
  271. package/assets/welcome-nT0eFWHb.js +0 -1
  272. package/controllers/navigation/edit.d.ts +0 -1
  273. package/controllers/navigation/edit.js +0 -8
  274. package/lib/ai-assistant/DummyAiModelService.d.ts +0 -8
  275. package/lib/ai-assistant/DummyAiModelService.js +0 -14
  276. package/lib/ai-assistant/OpenAiModelService.d.ts +0 -24
  277. package/lib/ai-assistant/OpenAiModelService.js +0 -184
  278. package/lib/catalog/Navigation.d.ts +0 -49
  279. package/lib/catalog/Navigation.js +0 -492
  280. package/lib/controls/AbstractControls.d.ts +0 -30
  281. package/lib/controls/AbstractControls.js +0 -14
  282. package/lib/media-manager/DefaultMediaManager.d.ts +0 -20
  283. package/lib/media-manager/DefaultMediaManager.js +0 -127
  284. package/lib/media-manager/Items.d.ts +0 -50
  285. package/lib/media-manager/Items.js +0 -296
  286. package/models/FilterAP.js +0 -68
  287. package/models/FilterColumnAP.d.ts +0 -32
  288. package/models/FilterColumnAP.js +0 -21
  289. package/models/GroupAP.d.ts +0 -31
  290. package/models/GroupAP.js +0 -22
  291. package/models/HistoryActionsAP.d.ts +0 -56
  292. package/models/HistoryActionsAP.js +0 -42
  293. package/models/NavigationAP.d.ts +0 -22
  294. package/models/NavigationAP.js +0 -16
  295. package/models/NotificationAP.d.ts +0 -44
  296. package/models/NotificationAP.js +0 -30
  297. package/models/UserAP.d.ts +0 -81
  298. package/models/UserAP.js +0 -57
  299. package/models/UserNotificationAP.d.ts +0 -26
  300. package/models/UserNotificationAP.js +0 -18
  301. package/system/bindAiAssistant.d.ts +0 -2
  302. package/system/bindAiAssistant.js +0 -30
  303. package/system/bindModels.d.ts +0 -2
  304. package/system/bindModels.js +0 -48
  305. package/system/bindNavigation.d.ts +0 -2
  306. package/system/bindNavigation.js +0 -38
  307. /package/assets/{RelationDialogStack-B00Ot5qS.css → controls/ckeditor.css} +0 -0
@@ -47,14 +47,29 @@ export class DataAccessor {
47
47
  this.actionVerb = getTokenAction(this.action);
48
48
  }
49
49
  getModelConfig(modelName) {
50
+ const resolvedModelName = this.adminizer.modelHandler.resolveModelName(modelName);
50
51
  const entry = Object.entries(this.adminizer.config.models)
51
- .find(([key]) => key.toLowerCase() === modelName.toLowerCase());
52
+ .find(([key, config]) => {
53
+ if (key.toLowerCase() === resolvedModelName.toLowerCase()) {
54
+ return true;
55
+ }
56
+ if (!isObject(config)) {
57
+ return false;
58
+ }
59
+ return config.model?.toLowerCase() === resolvedModelName.toLowerCase();
60
+ });
52
61
  const config = entry ? entry[1] : undefined;
53
62
  return isObject(config) ? config : undefined;
54
63
  }
55
64
  accessRelationModel(modelName) {
56
65
  return this.adminizer.modelHandler.internal("data-accessor").get(modelName);
57
66
  }
67
+ resolveRelationTarget(modelName) {
68
+ if (!modelName) {
69
+ return undefined;
70
+ }
71
+ return this.adminizer.modelHandler.resolveModelName(modelName).toLowerCase();
72
+ }
58
73
  /**
59
74
  * Retrieves the fields for the given ModelResource based on action type,
60
75
  * taking into account access rights and configuration settings.
@@ -116,21 +131,22 @@ export class DataAccessor {
116
131
  let populatedModelFieldsConfig = {};
117
132
  if (modelField.type === "association" || modelField.type === "association-many") {
118
133
  const modelName = modelField.model || modelField.collection;
119
- const tokenId = `read-${modelName}-${MODEL_TOKEN_SUFFIX}`;
120
- if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
121
- Adminizer.log.silly(`No access rights to model: ${this.modelResource.model.modelname}`);
122
- return undefined;
123
- }
124
- if (modelName) {
134
+ const resolvedModelName = modelName ? this.adminizer.modelHandler.resolveModelName(modelName) : undefined;
135
+ if (modelName && resolvedModelName) {
136
+ const tokenId = `read-${resolvedModelName}-${MODEL_TOKEN_SUFFIX}`;
137
+ if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
138
+ Adminizer.log.silly(`No access rights to model: ${this.modelResource.model.modelname}`);
139
+ return undefined;
140
+ }
125
141
  const model = this.adminizer.modelHandler.model.get(modelName);
126
142
  if (model) {
127
- populatedModelFieldsConfig = this.getAssociatedFieldsConfig(modelName);
128
- const modelCfg = this.getModelConfig(modelName);
143
+ populatedModelFieldsConfig = this.getAssociatedFieldsConfig(resolvedModelName);
144
+ const modelCfg = this.getModelConfig(resolvedModelName);
129
145
  if (modelCfg) {
130
146
  associatedModelConfig = modelCfg;
131
147
  }
132
148
  else {
133
- Adminizer.log.error(`DataAccessor > getFieldsConfig > Model config not found: ${modelName}`);
149
+ Adminizer.log.error(`DataAccessor > getFieldsConfig > Model config not found: ${resolvedModelName}`);
134
150
  }
135
151
  }
136
152
  else {
@@ -167,15 +183,16 @@ export class DataAccessor {
167
183
  return orderedFields;
168
184
  }
169
185
  getAssociatedFieldsConfig(modelName) {
170
- const model = this.adminizer.modelHandler.model.get(modelName);
171
- const modelConfig = this.getModelConfig(modelName);
186
+ const resolvedModelName = this.adminizer.modelHandler.resolveModelName(modelName);
187
+ const model = this.adminizer.modelHandler.model.get(resolvedModelName);
188
+ const modelConfig = this.getModelConfig(resolvedModelName);
172
189
  if (!model || !modelConfig) {
173
190
  return undefined;
174
191
  }
175
192
  // Check if user has access to the associated model
176
- const tokenId = `read-${modelName}-${MODEL_TOKEN_SUFFIX}`;
193
+ const tokenId = `read-${resolvedModelName}-${MODEL_TOKEN_SUFFIX}`;
177
194
  if (!this.adminizer.accessRightsHelper.hasPermission(tokenId, this.user)) {
178
- Adminizer.log.debug(`getAssociatedFieldsConfig > No access rights to ${this.actionVerb} model: ${modelName}`);
195
+ Adminizer.log.debug(`getAssociatedFieldsConfig > No access rights to ${this.actionVerb} model: ${resolvedModelName}`);
179
196
  return undefined;
180
197
  }
181
198
  const associatedFields = {};
@@ -248,10 +265,28 @@ export class DataAccessor {
248
265
  return !userGroups || !userGroups.includes(this.adminizer.config.registration?.defaultUserGroup);
249
266
  }
250
267
  }
268
+ getSelectedFields(select) {
269
+ if (!select) {
270
+ return undefined;
271
+ }
272
+ if (Array.isArray(select)) {
273
+ return new Set(select);
274
+ }
275
+ return new Set(Object.entries(select)
276
+ .filter(([, enabled]) => enabled)
277
+ .map(([field]) => field));
278
+ }
279
+ getPopulateCriteria(criteria, fieldKey) {
280
+ const populateConfig = criteria?.populate?.[fieldKey];
281
+ return populateConfig && populateConfig !== true ? populateConfig : undefined;
282
+ }
283
+ canUseSelectedFieldFallback() {
284
+ return this.user.isAdministrator || this.adminizer.config.auth?.enable === false;
285
+ }
251
286
  /**
252
287
  * Returns filtered record applying config from this.fields on this record
253
288
  * @data - record from a specific model */
254
- process(record) {
289
+ process(record, criteria) {
255
290
  // Initialize fields configuration, if it was not already set
256
291
  if (!this.fields) {
257
292
  this.fields = this.getFieldsConfig();
@@ -269,6 +304,8 @@ export class DataAccessor {
269
304
  // Check access to the field
270
305
  if (this.checkFieldAccess(fieldKey, fieldConfig.config)) {
271
306
  const fieldType = fieldConfig.config.type;
307
+ const populateCriteria = this.getPopulateCriteria(criteria, fieldKey);
308
+ const selectedAssociatedFields = this.getSelectedFields(populateCriteria?.select);
272
309
  // Handle fields that are not associations
273
310
  if (fieldType !== 'association' && fieldType !== 'association-many') {
274
311
  filteredRecord[fieldKey] = fieldValue;
@@ -278,7 +315,7 @@ export class DataAccessor {
278
315
  if (Array.isArray(fieldValue)) {
279
316
  // If the field value is an array of objects
280
317
  filteredRecord[fieldKey] = (fieldValue.every(item => typeof item === 'object')
281
- ? fieldValue.map(associatedRecord => this.filterAssociatedRecord(associatedRecord, fieldConfig.populated))
318
+ ? fieldValue.map(associatedRecord => this.filterAssociatedRecord(associatedRecord, fieldConfig.populated, selectedAssociatedFields))
282
319
  : fieldValue); // If the array contains IDs, pass them as is (it can contain ids, because this function also can be called before saving something)
283
320
  }
284
321
  else {
@@ -290,7 +327,7 @@ export class DataAccessor {
290
327
  else if (fieldType === 'association') {
291
328
  if (fieldValue && typeof fieldValue === 'object') {
292
329
  // If the field value is an object
293
- filteredRecord[fieldKey] = this.filterAssociatedRecord(fieldValue, fieldConfig.populated);
330
+ filteredRecord[fieldKey] = this.filterAssociatedRecord(fieldValue, fieldConfig.populated, selectedAssociatedFields);
294
331
  }
295
332
  else {
296
333
  // If the field value is an ID or null, pass it as is (it can contain id, because this function also can be called before saving something)
@@ -310,23 +347,30 @@ export class DataAccessor {
310
347
  return filteredRecord;
311
348
  }
312
349
  /** Filters associated records (simplified process() function) */
313
- filterAssociatedRecord(associatedRecord, associatedFieldsConfig) {
314
- if (!associatedFieldsConfig) {
350
+ filterAssociatedRecord(associatedRecord, associatedFieldsConfig, selectedFields) {
351
+ if (!associatedFieldsConfig && !selectedFields) {
315
352
  return {};
316
353
  }
317
354
  const filteredAssociatedRecord = {};
318
355
  for (const assocFieldKey in associatedRecord) {
319
- const assocFieldConfig = associatedFieldsConfig[assocFieldKey];
356
+ if (selectedFields && !selectedFields.has(assocFieldKey)) {
357
+ continue;
358
+ }
359
+ const assocFieldConfig = associatedFieldsConfig?.[assocFieldKey];
320
360
  const assocFieldValue = associatedRecord[assocFieldKey];
321
361
  if (assocFieldConfig && this.checkFieldAccess(assocFieldKey, assocFieldConfig.config)) {
322
362
  filteredAssociatedRecord[assocFieldKey] = assocFieldValue;
363
+ continue;
364
+ }
365
+ if (selectedFields && this.canUseSelectedFieldFallback()) {
366
+ filteredAssociatedRecord[assocFieldKey] = assocFieldValue;
323
367
  }
324
368
  }
325
369
  return filteredAssociatedRecord;
326
370
  }
327
371
  /** Process for an array of records */
328
- processMany(records) {
329
- return records.map(record => this.process(record));
372
+ processMany(records, criteria) {
373
+ return records.map(record => this.process(record, criteria));
330
374
  }
331
375
  async sanitizeUserRelationAccess(criteria = {}) {
332
376
  let sanitizedCriteria = {};
@@ -341,33 +385,35 @@ export class DataAccessor {
341
385
  const userAccessRelation = modelConfig.userAccessRelation;
342
386
  if (typeof userAccessRelation === 'string') {
343
387
  let accessField = userAccessRelation;
344
- // Check if the relation points to `UserAP` or `GroupAP` in the model's attributes
388
+ // Check if the relation points to `User` or `Group` in the model's attributes
345
389
  const modelAttributes = this.modelResource.model.attributes;
346
390
  const relation = modelAttributes[accessField];
347
- if (!relation || !['userap', 'groupap'].includes(relation.model.toLowerCase() || relation.collection.toLowerCase())) {
391
+ const relationModel = this.resolveRelationTarget(relation?.model);
392
+ const relationCollection = this.resolveRelationTarget(relation?.collection);
393
+ if (!relation || !['user', 'group'].includes(relationModel ?? relationCollection ?? "")) {
348
394
  throw new Error(`Invalid userAccessRelation configuration for model ${modelName}`);
349
395
  }
350
396
  // Determine if the current user matches the access criteria
351
- if (relation.model) {
352
- if (relation.model.toLowerCase() === 'userap') {
353
- // Filter by the user's ID if related to UserAP as a model
397
+ if (relationModel) {
398
+ if (relationModel === 'user') {
399
+ // Filter by the user's ID if related to User as a model
354
400
  sanitizedCriteria = { ...sanitizedCriteria, [accessField]: this.user.id };
355
401
  }
356
- else if (relation.model.toLowerCase() === 'groupap') {
357
- // Filter by user's group membership if related to GroupAP as a model
402
+ else if (relationModel === 'group') {
403
+ // Filter by user's group membership if related to Group as a model
358
404
  const userGroups = this.user.groups?.map((group) => group.id);
359
405
  sanitizedCriteria = { ...sanitizedCriteria, [accessField]: { in: userGroups } };
360
406
  }
361
407
  }
362
408
  /** Warning: collection relation access is not supported and needs adapter-level processing */
363
- if (relation.collection) {
409
+ if (relationCollection) {
364
410
  Adminizer.log.warn(`Collection relation is not supported and was not tested. You may have an error here: ${JSON.stringify(relation, null, 2)}`);
365
- if (relation.collection.toLowerCase() === 'userap') {
366
- // Ensure user's ID is part of the associated collection to UserAP
411
+ if (relationCollection === 'user') {
412
+ // Ensure user's ID is part of the associated collection to User
367
413
  sanitizedCriteria = { ...sanitizedCriteria, [accessField]: { contains: this.user.id } };
368
414
  }
369
- else if (relation.collection.toLowerCase() === 'groupap') {
370
- // Ensure user's groups intersect with the collection to GroupAP
415
+ else if (relationCollection === 'group') {
416
+ // Ensure user's groups intersect with the collection to Group
371
417
  const userGroups = this.user.groups?.map((group) => group.id);
372
418
  sanitizedCriteria = { ...sanitizedCriteria, [accessField]: { intersects: userGroups } };
373
419
  }
@@ -390,9 +436,9 @@ export class DataAccessor {
390
436
  // Validate the `via` field in the intermediate model
391
437
  const intermediateAttributes = intermediateModel.attributes;
392
438
  const viaRelation = intermediateAttributes[via];
393
- if (!viaRelation || viaRelation.model.toLowerCase() !== 'userap') {
439
+ if (!viaRelation || this.resolveRelationTarget(viaRelation.model) !== 'user') {
394
440
  throw new Error(`Unsupported or invalid via field "${via}" in intermediate model "${intermediateRelation.model}". ` +
395
- `Currently, only relations to "userap" are supported`);
441
+ `Currently, only relations to "User" are supported`);
396
442
  }
397
443
  // Fetch all intermediate records associated with the user
398
444
  const intermediateRecords = await this.accessRelationModel(intermediateRelation.model).find({ where: { [via]: this.user.id } });
@@ -418,16 +464,17 @@ export class DataAccessor {
418
464
  if (updatedRecord[accessField] && !this.user.isAdministrator) {
419
465
  delete updatedRecord[accessField];
420
466
  }
421
- // Check if the relation points to `UserAP` or `GroupAP` in the model's attributes
467
+ // Check if the relation points to `User` or `Group` in the model's attributes
422
468
  const modelAttributes = this.modelResource.model.attributes;
423
469
  const relation = modelAttributes[accessField];
424
- if (relation && ['userap', 'groupap'].includes(relation.model.toLowerCase())) {
425
- if (relation.model.toLowerCase() === 'userap') {
470
+ const relationModel = this.resolveRelationTarget(relation?.model);
471
+ if (relation && ['user', 'group'].includes(relationModel ?? "")) {
472
+ if (relationModel === 'user') {
426
473
  if (!this.user.isAdministrator) {
427
474
  updatedRecord[accessField] = this.user.id;
428
475
  }
429
476
  }
430
- else if (relation.model.toLowerCase() === 'groupap') {
477
+ else if (relationModel === 'group') {
431
478
  const userGroups = this.user.groups || [];
432
479
  if (userGroups.length === 1) {
433
480
  updatedRecord[accessField] = userGroups[0].id;
@@ -458,9 +505,9 @@ export class DataAccessor {
458
505
  // Validate the `via` field in the intermediate model
459
506
  const intermediateAttributes = intermediateModel.attributes;
460
507
  const viaRelation = intermediateAttributes[via];
461
- if (!viaRelation || !viaRelation.model || viaRelation.model.toLowerCase() !== 'userap') {
508
+ if (!viaRelation || this.resolveRelationTarget(viaRelation.model) !== 'user') {
462
509
  throw new Error(`Unsupported or invalid via field "${via}" in intermediate model "${intermediateRelation.model}". ` +
463
- `Currently, only relations to "userap" are supported`);
510
+ `Currently, only relations to "User" are supported`);
464
511
  }
465
512
  const intermediatePk = (intermediateModel.primaryKey ?? 'id');
466
513
  const chosenId = typeof updatedRecord[field] === 'object'
@@ -0,0 +1,17 @@
1
+ import type { AccessRightsToken } from "../../interfaces/types";
2
+ import type { Adminizer } from "../Adminizer";
3
+ export interface AccessRightsRecord {
4
+ id: string;
5
+ appName: string;
6
+ token: AccessRightsToken;
7
+ }
8
+ export declare class AccessRightsHandler {
9
+ private adminizer;
10
+ private records;
11
+ constructor(adminizer: Adminizer);
12
+ register(appName: string, token: AccessRightsToken): string;
13
+ unregister(id: string): void;
14
+ getByApp(appName: string): AccessRightsRecord[];
15
+ private getRecordId;
16
+ private getTokenOwner;
17
+ }
@@ -0,0 +1,63 @@
1
+ export class AccessRightsHandler {
2
+ adminizer;
3
+ records = new Map();
4
+ constructor(adminizer) {
5
+ this.adminizer = adminizer;
6
+ }
7
+ register(appName, token) {
8
+ const normalizedToken = {
9
+ ...token,
10
+ id: token.id.toLowerCase(),
11
+ };
12
+ const id = this.getRecordId(appName, normalizedToken.id);
13
+ if (this.records.has(id)) {
14
+ throw new Error(`Access rights token "${normalizedToken.id}" is already registered for app "${appName}"`);
15
+ }
16
+ const existingOwner = this.getTokenOwner(normalizedToken.id);
17
+ if (existingOwner && existingOwner !== appName) {
18
+ throw new Error(`Access rights token "${normalizedToken.id}" is already registered by app "${existingOwner}"`);
19
+ }
20
+ if (!existingOwner && this.adminizer.accessRightsHelper.hasToken(normalizedToken.id)) {
21
+ throw new Error(`Access rights token "${normalizedToken.id}" is already registered`);
22
+ }
23
+ this.adminizer.accessRightsHelper.registerToken(normalizedToken);
24
+ this.records.set(id, {
25
+ id,
26
+ appName,
27
+ token: normalizedToken,
28
+ });
29
+ this.adminizer.emitter.emit("app:access-right:registered", {
30
+ appName,
31
+ resourceId: id,
32
+ tokenId: normalizedToken.id,
33
+ });
34
+ return id;
35
+ }
36
+ unregister(id) {
37
+ const record = this.records.get(id);
38
+ if (!record) {
39
+ return;
40
+ }
41
+ this.adminizer.accessRightsHelper.unregisterToken(record.token.id);
42
+ this.records.delete(id);
43
+ this.adminizer.emitter.emit("app:access-right:unregistered", {
44
+ appName: record.appName,
45
+ resourceId: id,
46
+ tokenId: record.token.id,
47
+ });
48
+ }
49
+ getByApp(appName) {
50
+ return Array.from(this.records.values()).filter((record) => record.appName === appName);
51
+ }
52
+ getRecordId(appName, tokenId) {
53
+ return `${appName}:${tokenId}`;
54
+ }
55
+ getTokenOwner(tokenId) {
56
+ for (const record of this.records.values()) {
57
+ if (record.token.id === tokenId) {
58
+ return record.appName;
59
+ }
60
+ }
61
+ return undefined;
62
+ }
63
+ }
@@ -1,17 +1,14 @@
1
- import { Adminizer } from '../Adminizer';
2
1
  import { AiAssistantMessage, AiAssistantModelInfo } from '../../interfaces/types';
3
- import { UserAP } from '../../models/UserAP';
2
+ import { User } from '../../models/User';
4
3
  /**
5
- * Base class for AI assistant models. It is responsible for registering
6
- * access rights for the model and providing metadata for the front-end.
4
+ * Base class for AI assistant models. App modules register access rights
5
+ * and expose model metadata through this service.
7
6
  */
8
7
  export declare abstract class AbstractAiModelService {
9
- protected readonly adminizer: Adminizer;
10
8
  readonly id: string;
11
9
  readonly name: string;
12
10
  readonly description?: string;
13
- protected constructor(adminizer: Adminizer, metadata: AiAssistantModelInfo);
14
- protected registerAccessRight(): void;
11
+ protected constructor(metadata: AiAssistantModelInfo);
15
12
  getMetadata(): AiAssistantModelInfo;
16
- abstract generateReply(prompt: string, history: AiAssistantMessage[], user: UserAP): Promise<string>;
13
+ abstract generateReply(prompt: string, history: AiAssistantMessage[], user: User): Promise<string>;
17
14
  }
@@ -1,26 +1,15 @@
1
1
  /**
2
- * Base class for AI assistant models. It is responsible for registering
3
- * access rights for the model and providing metadata for the front-end.
2
+ * Base class for AI assistant models. App modules register access rights
3
+ * and expose model metadata through this service.
4
4
  */
5
5
  export class AbstractAiModelService {
6
- adminizer;
7
6
  id;
8
7
  name;
9
8
  description;
10
- constructor(adminizer, metadata) {
11
- this.adminizer = adminizer;
9
+ constructor(metadata) {
12
10
  this.id = metadata.id;
13
11
  this.name = metadata.name;
14
12
  this.description = metadata.description;
15
- this.registerAccessRight();
16
- }
17
- registerAccessRight() {
18
- this.adminizer.accessRightsHelper.registerToken({
19
- id: `ai-assistant-${this.id}`,
20
- name: this.name,
21
- description: `Access to AI assistant model ${this.name}`,
22
- department: 'AI Assistant',
23
- });
24
13
  }
25
14
  getMetadata() {
26
15
  return {
@@ -1,7 +1,7 @@
1
1
  import { Adminizer } from '../Adminizer';
2
2
  import { AbstractAiModelService } from './AbstractAiModelService';
3
3
  import { AiAssistantMessage, AiAssistantModelInfo } from '../../interfaces/types';
4
- import { UserAP } from '../../models/UserAP';
4
+ import { User } from '../../models/User';
5
5
  export declare class AiAssistantHandler {
6
6
  private readonly adminizer;
7
7
  private readonly models;
@@ -12,7 +12,7 @@ export declare class AiAssistantHandler {
12
12
  getModels(): AiAssistantModelInfo[];
13
13
  getHistory(userId: number, modelId: string): AiAssistantMessage[];
14
14
  resetHistory(userId: number, modelId: string): void;
15
- sendMessage(user: UserAP, modelId: string, prompt: string): Promise<{
15
+ sendMessage(user: User, modelId: string, prompt: string): Promise<{
16
16
  history: AiAssistantMessage[];
17
17
  }>;
18
18
  private getSessionKey;
@@ -0,0 +1,228 @@
1
+ import type { ActionType, AdminpanelConfig, AdminpanelIcon, ModelConfig } from "../../interfaces/adminpanelConfig";
2
+ import type { AccessRightsToken, INotification, ModelResource } from "../../interfaces/types";
3
+ import type { AbstractCatalog } from "../catalog/AbstractCatalog";
4
+ import type { CatalogTemplateComponentResource } from "../catalog/CatalogTemplateComponentHandler";
5
+ import type { AppModelAccess } from "../model/ModelHandler";
6
+ import type { AbstractMediaManager } from "../media-manager/AbstractMediaManager";
7
+ import type { Config, ControlType } from "../controls/Control";
8
+ import type { User } from "../../models/User";
9
+ import type { DataAccessor } from "../DataAccessor";
10
+ import type { AbstractAiModelService } from "../ai-assistant/AbstractAiModelService";
11
+ export type AppDisposer = () => void | Promise<void>;
12
+ export type AppEventName = string | symbol;
13
+ export type AppEventHandler<TPayload = any> = (payload: TPayload, runtime: AppRuntime) => void | Promise<void>;
14
+ export type AppControllerMethod = "get" | "post" | "put" | "patch" | "delete" | "all";
15
+ export type AppControllerPolicyMode = "ui" | "api";
16
+ export type AppControllerPolicy = {
17
+ type: "auth";
18
+ mode?: AppControllerPolicyMode;
19
+ } | {
20
+ type: "auth-enabled";
21
+ } | {
22
+ type: "admin";
23
+ mode?: AppControllerPolicyMode;
24
+ } | {
25
+ type: "permission";
26
+ token: string;
27
+ mode?: AppControllerPolicyMode;
28
+ } | {
29
+ type: "any-permission";
30
+ tokens: string[];
31
+ mode?: AppControllerPolicyMode;
32
+ };
33
+ export type AppConfigPatch = {
34
+ [K in keyof AdminpanelConfig]?: AdminpanelConfig[K] extends (...args: any[]) => any ? AdminpanelConfig[K] : AdminpanelConfig[K] extends Array<infer U> ? U[] : AdminpanelConfig[K] extends object ? Partial<AdminpanelConfig[K]> : AdminpanelConfig[K];
35
+ };
36
+ /**
37
+ * A controller owned by an Adminizer app.
38
+ *
39
+ * Before the middleware runs, ControllerHandler assigns an AppRuntime scoped
40
+ * to the owning app to `req.runtime`. App controllers must use that runtime
41
+ * instead of reading `req.adminizer`.
42
+ */
43
+ export interface AppController {
44
+ id?: string;
45
+ route: string;
46
+ method: AppControllerMethod;
47
+ middleware: MiddlewareType;
48
+ policies?: AppControllerPolicy[];
49
+ }
50
+ export interface AppAsset {
51
+ id: string;
52
+ filePath: string;
53
+ route?: string;
54
+ devUrl?: string;
55
+ }
56
+ export interface AppControlResource {
57
+ id?: string;
58
+ type: ControlType;
59
+ name: string;
60
+ config?: Config;
61
+ component: AppAsset;
62
+ stylesheet?: AppAsset;
63
+ }
64
+ export interface AppWidgetBaseResource {
65
+ id: string;
66
+ name: string;
67
+ description: string;
68
+ icon?: AdminpanelIcon | string;
69
+ department: string;
70
+ backgroundCSS?: string | null;
71
+ size?: {
72
+ h: number;
73
+ w: number;
74
+ } | null;
75
+ accessRightsToken?: string;
76
+ group?: string;
77
+ }
78
+ export interface AppWidgetContext {
79
+ runtime: AppRuntime;
80
+ }
81
+ export interface AppWidgetInfoContext extends AppWidgetContext {
82
+ user?: ReqType["user"];
83
+ }
84
+ export interface AppInfoWidgetResource extends AppWidgetBaseResource {
85
+ type: "info";
86
+ link?: string;
87
+ linkType?: "self" | "blank";
88
+ getInfo(context: AppWidgetInfoContext): Promise<string> | string;
89
+ }
90
+ export interface AppActionWidgetResource extends AppWidgetBaseResource {
91
+ type: "action";
92
+ action(context: AppWidgetContext): Promise<unknown> | unknown;
93
+ }
94
+ export interface AppSwitchWidgetResource extends AppWidgetBaseResource {
95
+ type: "switcher";
96
+ getState(context: AppWidgetContext): Promise<boolean> | boolean;
97
+ switchIt(context: AppWidgetContext): Promise<boolean> | boolean;
98
+ }
99
+ export interface AppLinkWidgetLink {
100
+ name: string;
101
+ description: string;
102
+ icon?: AdminpanelIcon | string;
103
+ link: string;
104
+ linkType: "self" | "blank";
105
+ backgroundCSS?: string | null;
106
+ }
107
+ export interface AppLinkWidgetResource extends AppWidgetBaseResource {
108
+ type: "link";
109
+ links: AppLinkWidgetLink[];
110
+ }
111
+ export interface AppCustomWidgetResource extends AppWidgetBaseResource {
112
+ type: "custom";
113
+ component: AppAsset;
114
+ }
115
+ export type AppWidgetResource = AppInfoWidgetResource | AppActionWidgetResource | AppSwitchWidgetResource | AppLinkWidgetResource | AppCustomWidgetResource;
116
+ /**
117
+ * Public capabilities available to an Adminizer app at runtime.
118
+ *
119
+ * The runtime is scoped to the app that registered the resource. In
120
+ * particular, `models` exposes only models declared through
121
+ * `AppSetupContext.modelAccess()`.
122
+ *
123
+ * App code must not retain or depend on the Adminizer instance. Controllers
124
+ * receive this object through `req.runtime`; catalog factories and event
125
+ * listeners receive it as an argument.
126
+ */
127
+ export interface AppRuntime {
128
+ models: AppModelAccess;
129
+ config: AppRuntimeConfig;
130
+ notifications: AppRuntimeNotifications;
131
+ apps: AppRuntimeApps;
132
+ }
133
+ export interface AppRuntimeConfig {
134
+ readonly routePrefix: string;
135
+ getModelConfig(modelName: string): ModelConfig | undefined;
136
+ }
137
+ export type AppRuntimeAppState = "registered" | "enabled" | "disabled" | "unregistered" | "failed";
138
+ export interface AppRuntimeApp {
139
+ readonly name: string;
140
+ readonly version: string;
141
+ readonly state: AppRuntimeAppState;
142
+ }
143
+ export interface AppRuntimeApps {
144
+ list(): AppRuntimeApp[];
145
+ get(name: string): AppRuntimeApp | undefined;
146
+ enable(name: string): Promise<void>;
147
+ disable(name: string): Promise<void>;
148
+ unregister(name: string): Promise<void>;
149
+ }
150
+ export interface AppRuntimeNotifications {
151
+ send(notification: Omit<INotification, "id" | "createdAt" | "icon">): Promise<boolean>;
152
+ }
153
+ export interface AppModelAccessResource {
154
+ id?: string;
155
+ models: string[];
156
+ }
157
+ export interface AppModelResource {
158
+ name: string;
159
+ adapter?: string;
160
+ }
161
+ export interface AppCatalogFactoryResource {
162
+ id: string;
163
+ templates?: CatalogTemplateComponentResource[];
164
+ factory: (runtime: AppRuntime) => AbstractCatalog | Promise<AbstractCatalog>;
165
+ }
166
+ export interface AppMediaManagerResource {
167
+ factory: (runtime: AppRuntime) => AbstractMediaManager | Promise<AbstractMediaManager>;
168
+ }
169
+ export interface AppAiAssistantContext {
170
+ runtime: AppRuntime;
171
+ routePrefix: string;
172
+ getModelResources(): ModelResource[];
173
+ resolveModelResource(modelName: string): ModelResource | undefined;
174
+ hasPermission(token: string, user: User): boolean;
175
+ createDataAccessor(modelResource: ModelResource, user: User, action: ActionType): DataAccessor;
176
+ }
177
+ export interface AppAiAssistantResource {
178
+ models: Array<(context: AppAiAssistantContext) => AbstractAiModelService | Promise<AbstractAiModelService>>;
179
+ }
180
+ /**
181
+ * Resource registration API provided while an app is being enabled.
182
+ *
183
+ * Apps use this context to declare everything they own. They must not accept
184
+ * an Adminizer instance in their constructor or setup method. This keeps app
185
+ * lifecycle, resource cleanup, model permissions, and runtime capabilities
186
+ * under AppManager control.
187
+ */
188
+ export interface AppSetupContext {
189
+ asset(asset: AppAsset): string;
190
+ control(control: AppControlResource): void;
191
+ widget(widget: AppWidgetResource): void;
192
+ controller(controller: AppController): string;
193
+ config(config: AppConfigPatch, id?: string): void;
194
+ accessRight(token: AccessRightsToken): void;
195
+ catalog(catalog: AppCatalogFactoryResource): void;
196
+ mediaManager(resource: AppMediaManagerResource): void;
197
+ model(model: AppModelResource): void;
198
+ modelAccess(access: AppModelAccessResource): void;
199
+ aiAssistant(resource: AppAiAssistantResource): void;
200
+ listener(event: AppEventName, handler: AppEventHandler): void;
201
+ }
202
+ /**
203
+ * Base contract for an Adminizer app.
204
+ *
205
+ * An app is created from its own configuration and optional app-level
206
+ * dependencies, then enabled with `adminizer.appManager.enable(app)`.
207
+ * The Adminizer instance belongs to the host application and must not be
208
+ * passed into or stored by the app.
209
+ *
210
+ * Use `setup(ctx)` for resource registration. At runtime, use:
211
+ * - `req.runtime` in app controllers;
212
+ * - the `runtime` factory argument in catalogs;
213
+ * - the `runtime` handler argument in event listeners.
214
+ */
215
+ export declare abstract class AbstractAdminizerApp<TConfig = unknown> {
216
+ abstract readonly name: string;
217
+ abstract readonly version: string;
218
+ readonly config?: TConfig;
219
+ protected constructor();
220
+ /**
221
+ * Declares resources owned by the app.
222
+ *
223
+ * Do not add an Adminizer parameter. Runtime access is intentionally
224
+ * provided through registered controller requests, factories, and
225
+ * listeners.
226
+ */
227
+ abstract setup(ctx: AppSetupContext): void | Promise<void>;
228
+ }