@acorex-platform/framework-client 0.0.10

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 (112) hide show
  1. package/README.md +7 -0
  2. package/auth/README.md +3 -0
  3. package/common/README.md +3 -0
  4. package/core/README.md +4 -0
  5. package/fesm2022/acorex-platform-framework-client-auth.mjs +1383 -0
  6. package/fesm2022/acorex-platform-framework-client-auth.mjs.map +1 -0
  7. package/fesm2022/acorex-platform-framework-client-common-common-settings.provider-CbzOYCnI.mjs +190 -0
  8. package/fesm2022/acorex-platform-framework-client-common-common-settings.provider-CbzOYCnI.mjs.map +1 -0
  9. package/fesm2022/acorex-platform-framework-client-common.mjs +9467 -0
  10. package/fesm2022/acorex-platform-framework-client-common.mjs.map +1 -0
  11. package/fesm2022/acorex-platform-framework-client-core.mjs +4655 -0
  12. package/fesm2022/acorex-platform-framework-client-core.mjs.map +1 -0
  13. package/fesm2022/acorex-platform-framework-client-domain.mjs +3189 -0
  14. package/fesm2022/acorex-platform-framework-client-domain.mjs.map +1 -0
  15. package/fesm2022/acorex-platform-framework-client-layout-builder.mjs +3439 -0
  16. package/fesm2022/acorex-platform-framework-client-layout-builder.mjs.map +1 -0
  17. package/fesm2022/acorex-platform-framework-client-layout-components-binding-expression-editor-popup.component-CWVU3wXL.mjs +134 -0
  18. package/fesm2022/acorex-platform-framework-client-layout-components-binding-expression-editor-popup.component-CWVU3wXL.mjs.map +1 -0
  19. package/fesm2022/acorex-platform-framework-client-layout-components.mjs +9777 -0
  20. package/fesm2022/acorex-platform-framework-client-layout-components.mjs.map +1 -0
  21. package/fesm2022/acorex-platform-framework-client-layout-designer.mjs +2799 -0
  22. package/fesm2022/acorex-platform-framework-client-layout-designer.mjs.map +1 -0
  23. package/fesm2022/acorex-platform-framework-client-layout-entity-attachments-page.component-CxBxxpmA.mjs +376 -0
  24. package/fesm2022/acorex-platform-framework-client-layout-entity-attachments-page.component-CxBxxpmA.mjs.map +1 -0
  25. package/fesm2022/acorex-platform-framework-client-layout-entity-file-list-popup.component-l0JAHKIH.mjs +100 -0
  26. package/fesm2022/acorex-platform-framework-client-layout-entity-file-list-popup.component-l0JAHKIH.mjs.map +1 -0
  27. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs +26299 -0
  28. package/fesm2022/acorex-platform-framework-client-layout-entity.mjs.map +1 -0
  29. package/fesm2022/acorex-platform-framework-client-layout-views.mjs +2960 -0
  30. package/fesm2022/acorex-platform-framework-client-layout-views.mjs.map +1 -0
  31. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs +4711 -0
  32. package/fesm2022/acorex-platform-framework-client-layout-widget-core.mjs.map +1 -0
  33. package/fesm2022/acorex-platform-framework-client-layout-widgets-button-widget-designer.component-CpkWwygb.mjs +72 -0
  34. package/fesm2022/acorex-platform-framework-client-layout-widgets-button-widget-designer.component-CpkWwygb.mjs.map +1 -0
  35. package/fesm2022/acorex-platform-framework-client-layout-widgets-image-preview.popup-C_EPAvCU.mjs +29 -0
  36. package/fesm2022/acorex-platform-framework-client-layout-widgets-image-preview.popup-C_EPAvCU.mjs.map +1 -0
  37. package/fesm2022/acorex-platform-framework-client-layout-widgets-page-widget-designer.component-CmtTq2Mt.mjs +172 -0
  38. package/fesm2022/acorex-platform-framework-client-layout-widgets-page-widget-designer.component-CmtTq2Mt.mjs.map +1 -0
  39. package/fesm2022/acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-DSx0E3NV.mjs +513 -0
  40. package/fesm2022/acorex-platform-framework-client-layout-widgets-repeater-widget-column.component-DSx0E3NV.mjs.map +1 -0
  41. package/fesm2022/acorex-platform-framework-client-layout-widgets-tabular-data-edit-popup.component-DdfcGV1C.mjs +274 -0
  42. package/fesm2022/acorex-platform-framework-client-layout-widgets-tabular-data-edit-popup.component-DdfcGV1C.mjs.map +1 -0
  43. package/fesm2022/acorex-platform-framework-client-layout-widgets-tabular-data-view-popup.component-CntopmDS.mjs +64 -0
  44. package/fesm2022/acorex-platform-framework-client-layout-widgets-tabular-data-view-popup.component-CntopmDS.mjs.map +1 -0
  45. package/fesm2022/acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-B5kSWxGk.mjs +34 -0
  46. package/fesm2022/acorex-platform-framework-client-layout-widgets-text-block-widget-designer.component-B5kSWxGk.mjs.map +1 -0
  47. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs +28553 -0
  48. package/fesm2022/acorex-platform-framework-client-layout-widgets.mjs.map +1 -0
  49. package/fesm2022/acorex-platform-framework-client-native.mjs +155 -0
  50. package/fesm2022/acorex-platform-framework-client-native.mjs.map +1 -0
  51. package/fesm2022/acorex-platform-framework-client-runtime.mjs +911 -0
  52. package/fesm2022/acorex-platform-framework-client-runtime.mjs.map +1 -0
  53. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-create-view.component-DnTHwsDJ.mjs +160 -0
  54. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-create-view.component-DnTHwsDJ.mjs.map +1 -0
  55. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-modify-view.component-BpR9g6QS.mjs +121 -0
  56. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-modify-view.component-BpR9g6QS.mjs.map +1 -0
  57. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-single-view.component-D1a7UI71.mjs +236 -0
  58. package/fesm2022/acorex-platform-framework-client-themes-default-entity-master-single-view.component-D1a7UI71.mjs.map +1 -0
  59. package/fesm2022/acorex-platform-framework-client-themes-default-error-401.component-D--_MIar.mjs +48 -0
  60. package/fesm2022/acorex-platform-framework-client-themes-default-error-401.component-D--_MIar.mjs.map +1 -0
  61. package/fesm2022/acorex-platform-framework-client-themes-default-error-404.component-Byyqk8pH.mjs +42 -0
  62. package/fesm2022/acorex-platform-framework-client-themes-default-error-404.component-Byyqk8pH.mjs.map +1 -0
  63. package/fesm2022/acorex-platform-framework-client-themes-default-error-offline.component-DR6G8gPC.mjs +19 -0
  64. package/fesm2022/acorex-platform-framework-client-themes-default-error-offline.component-DR6G8gPC.mjs.map +1 -0
  65. package/fesm2022/acorex-platform-framework-client-themes-default.mjs +4160 -0
  66. package/fesm2022/acorex-platform-framework-client-themes-default.mjs.map +1 -0
  67. package/fesm2022/acorex-platform-framework-client-themes-shared-icon-chooser-column.component-CXSGiTCK.mjs +55 -0
  68. package/fesm2022/acorex-platform-framework-client-themes-shared-icon-chooser-column.component-CXSGiTCK.mjs.map +1 -0
  69. package/fesm2022/acorex-platform-framework-client-themes-shared-icon-chooser-view.component-BY5clQ1J.mjs +57 -0
  70. package/fesm2022/acorex-platform-framework-client-themes-shared-icon-chooser-view.component-BY5clQ1J.mjs.map +1 -0
  71. package/fesm2022/acorex-platform-framework-client-themes-shared-settings.provider-DEL2YOTP.mjs +234 -0
  72. package/fesm2022/acorex-platform-framework-client-themes-shared-settings.provider-DEL2YOTP.mjs.map +1 -0
  73. package/fesm2022/acorex-platform-framework-client-themes-shared-theme-color-chooser-column.component-BXl8u4Yp.mjs +94 -0
  74. package/fesm2022/acorex-platform-framework-client-themes-shared-theme-color-chooser-column.component-BXl8u4Yp.mjs.map +1 -0
  75. package/fesm2022/acorex-platform-framework-client-themes-shared-theme-color-chooser-view.component-i2sOOkVj.mjs +86 -0
  76. package/fesm2022/acorex-platform-framework-client-themes-shared-theme-color-chooser-view.component-i2sOOkVj.mjs.map +1 -0
  77. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs +2375 -0
  78. package/fesm2022/acorex-platform-framework-client-themes-shared.mjs.map +1 -0
  79. package/fesm2022/acorex-platform-framework-client-workflow.mjs +2836 -0
  80. package/fesm2022/acorex-platform-framework-client-workflow.mjs.map +1 -0
  81. package/fesm2022/acorex-platform-framework-client.mjs +6 -0
  82. package/fesm2022/acorex-platform-framework-client.mjs.map +1 -0
  83. package/layout/builder/README.md +1578 -0
  84. package/layout/components/README.md +3 -0
  85. package/layout/designer/README.md +4 -0
  86. package/layout/entity/README.md +4 -0
  87. package/layout/views/README.md +3 -0
  88. package/layout/widget-core/README.md +4 -0
  89. package/layout/widgets/README.md +3 -0
  90. package/native/README.md +4 -0
  91. package/package.json +98 -0
  92. package/runtime/README.md +3 -0
  93. package/themes/default/README.md +3 -0
  94. package/themes/shared/README.md +3 -0
  95. package/types/acorex-platform-framework-client-auth.d.ts +690 -0
  96. package/types/acorex-platform-framework-client-common.d.ts +3287 -0
  97. package/types/acorex-platform-framework-client-core.d.ts +1849 -0
  98. package/types/acorex-platform-framework-client-domain.d.ts +1968 -0
  99. package/types/acorex-platform-framework-client-layout-builder.d.ts +1058 -0
  100. package/types/acorex-platform-framework-client-layout-components.d.ts +3362 -0
  101. package/types/acorex-platform-framework-client-layout-designer.d.ts +501 -0
  102. package/types/acorex-platform-framework-client-layout-entity.d.ts +4374 -0
  103. package/types/acorex-platform-framework-client-layout-views.d.ts +975 -0
  104. package/types/acorex-platform-framework-client-layout-widget-core.d.ts +1080 -0
  105. package/types/acorex-platform-framework-client-layout-widgets.d.ts +5263 -0
  106. package/types/acorex-platform-framework-client-native.d.ts +28 -0
  107. package/types/acorex-platform-framework-client-runtime.d.ts +301 -0
  108. package/types/acorex-platform-framework-client-themes-default.d.ts +889 -0
  109. package/types/acorex-platform-framework-client-themes-shared.d.ts +202 -0
  110. package/types/acorex-platform-framework-client-workflow.d.ts +1345 -0
  111. package/types/acorex-platform-framework-client.d.ts +2 -0
  112. package/workflow/README.md +4 -0
@@ -0,0 +1,3189 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, NgModule, Injectable, makeEnvironmentProviders } from '@angular/core';
3
+ import { AXPRuntimeModule } from '@acorex-platform/framework-client/runtime';
4
+ import { AXPEntityType, AXPRelationshipCardinality, AXPRelationshipKind } from '@acorex-platform/framework-shared/domain';
5
+
6
+ /**
7
+ * Token for entity CRUD setup. Consumed by AXPDomainModule.
8
+ * The actual provider is provideEntity() from @acorex-platform/framework-client/layout/entity
9
+ * to avoid circular dependency (domain must not depend on layout/entity).
10
+ */
11
+ const AXP_ENTITY_CRUD_SETUP = new InjectionToken('AXP_ENTITY_CRUD_SETUP');
12
+
13
+ //#endregion
14
+ //#region ---- Injection Token ----
15
+ const AXP_ENTITY_DEFINITION_CRUD_SERVICE = new InjectionToken('AXP_ENTITY_DEFINITION_CRUD_SERVICE', {
16
+ providedIn: null,
17
+ factory: () => null,
18
+ });
19
+ //#endregion
20
+
21
+ //#region ---- Dependency Injection Tokens ----
22
+ /**
23
+ * Targeted middleware extension (name or regex) for property resolution.
24
+ */
25
+ const AXP_PROPERTY_EXTENSION = new InjectionToken('AXP_PROPERTY_EXTENSION');
26
+ /**
27
+ * Bootstrap hook: register property definitions known at build time.
28
+ */
29
+ const AXP_PROPERTY_SETUP = new InjectionToken('AXP_PROPERTY_SETUP');
30
+ /**
31
+ * Bootstrap hook: register global middleware for every property resolution.
32
+ */
33
+ const AXP_PROPERTY_MIDDLEWARE_SETUP = new InjectionToken('AXP_PROPERTY_MIDDLEWARE_SETUP');
34
+ /**
35
+ * Bootstrap hook: register on-demand property loaders.
36
+ */
37
+ const AXP_PROPERTY_LOADER_SETUP = new InjectionToken('AXP_PROPERTY_LOADER_SETUP');
38
+ //#endregion
39
+
40
+ //#region ---- Dependency Injection Tokens ----
41
+ /**
42
+ * Injection token for schema-specific middleware extensions.
43
+ *
44
+ * Used for targeted middleware that applies only to schemas matching
45
+ * specific patterns (name or regex). This enables fine-grained control
46
+ * over which schemas receive which middleware.
47
+ */
48
+ const AXP_DOMAIN_EXTENSION = new InjectionToken('AXP_DOMAIN_EXTENSION');
49
+ /**
50
+ * Injection token for schema setup initialization.
51
+ *
52
+ * Used during application bootstrap to register schemas that are
53
+ * known at build time. Multiple providers can use this token to
54
+ * contribute schemas to the registry.
55
+ */
56
+ const AXP_DOMAIN_SETUP = new InjectionToken('AXP_DOMAIN_SETUP');
57
+ /**
58
+ * Injection token for schema middleware setup initialization.
59
+ *
60
+ * Used during application bootstrap to register global middleware
61
+ * that applies to all schema resolutions. This enables centralized
62
+ * schema processing logic.
63
+ */
64
+ const AXP_DOMAIN_MIDDLEWARE_SETUP = new InjectionToken('AXP_DOMAIN_MIDDLEWARE_SETUP');
65
+ /**
66
+ * Injection token for schema loader setup initialization.
67
+ *
68
+ * Used during application bootstrap to register schema loaders
69
+ * that can provide schemas on-demand when they're not found in
70
+ * the registry.
71
+ */
72
+ const AXP_DOMAIN_LOADER_SETUP = new InjectionToken('AXP_DOMAIN_LOADER_SETUP');
73
+ //#endregion
74
+
75
+ class AXPDomainModule {
76
+ constructor() {
77
+ this._commandSetup = inject(AXP_ENTITY_CRUD_SETUP, { optional: true });
78
+ /**
79
+ * Optional bootstrap hooks for registered property definitions (see {@link AXP_PROPERTY_SETUP} and related tokens).
80
+ */
81
+ this._propertySetup = inject(AXP_PROPERTY_SETUP, { optional: true });
82
+ this._propertyMiddlewareSetup = inject(AXP_PROPERTY_MIDDLEWARE_SETUP, { optional: true });
83
+ this._propertyLoaderSetup = inject(AXP_PROPERTY_LOADER_SETUP, { optional: true });
84
+ /**
85
+ * Injection token for domain loader setup initialization.
86
+ *
87
+ * Used during application bootstrap to register domain loaders
88
+ * that can provide domain definitions on-demand when they're not found in
89
+ * the registry.
90
+ */
91
+ this._domainLoaderSetup = inject(AXP_DOMAIN_LOADER_SETUP, { optional: true });
92
+ this._domainMiddlewareSetup = inject(AXP_DOMAIN_MIDDLEWARE_SETUP, { optional: true });
93
+ this._domainSetup = inject(AXP_DOMAIN_SETUP, { optional: true });
94
+ }
95
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
96
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainModule, imports: [AXPRuntimeModule] }); }
97
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainModule, imports: [AXPRuntimeModule] }); }
98
+ }
99
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainModule, decorators: [{
100
+ type: NgModule,
101
+ args: [{
102
+ imports: [
103
+ AXPRuntimeModule
104
+ ]
105
+ }]
106
+ }] });
107
+
108
+ //#region ---- AXPAggregateModel ----
109
+ /**
110
+ * Simple runtime model for aggregate definitions with parent references and navigation helpers.
111
+ * Relations are stored in a separate collection; join when needed.
112
+ */
113
+ class AXPAggregateModel {
114
+ constructor(definition, parent) {
115
+ this.name = definition.name;
116
+ this.title = definition.title;
117
+ this.validations = definition.validations || [];
118
+ this.actions = definition.actions || [];
119
+ this.parent = parent;
120
+ // Extract entity references - convert all formats to simple string map
121
+ this.entityReferences = this.extractEntityReferences(definition.entities);
122
+ }
123
+ //#endregion
124
+ //#region ---- Entity Reference Extraction ----
125
+ /**
126
+ * Extract entity references from various entity definition formats
127
+ * and convert to simple string map
128
+ */
129
+ extractEntityReferences(entities) {
130
+ if (!entities) {
131
+ return {};
132
+ }
133
+ if (Array.isArray(entities)) {
134
+ // Format 1: Array of entity definitions - convert to self-references
135
+ const references = {};
136
+ for (const entity of entities) {
137
+ if (entity.name) {
138
+ // Self-reference format: module.aggregate.entity
139
+ references[entity.name] = `${this.parent.name}.${this.name}.${entity.name}`;
140
+ }
141
+ }
142
+ return references;
143
+ }
144
+ if (typeof entities === 'object') {
145
+ // Format 2: Object with string references - use as-is
146
+ return { ...entities };
147
+ }
148
+ return {};
149
+ }
150
+ //#endregion
151
+ //#region ---- Navigation Helpers ----
152
+ /**
153
+ * Get entity reference by name
154
+ *
155
+ * @param entityName Name of the entity
156
+ * @returns Entity reference string or undefined if not found
157
+ */
158
+ getEntityReference(entityName) {
159
+ return this.entityReferences[entityName];
160
+ }
161
+ /**
162
+ * Get full path for an entity in this aggregate
163
+ *
164
+ * @param entityName Name of the entity
165
+ * @returns Full entity path
166
+ */
167
+ getEntityPath(entityName) {
168
+ return `${this.parent.name}.${this.name}.${entityName}`;
169
+ }
170
+ /**
171
+ * Get all available entity names
172
+ *
173
+ * @returns Array of entity names
174
+ */
175
+ getEntityNames() {
176
+ return Object.keys(this.entityReferences);
177
+ }
178
+ /**
179
+ * Check if entity exists in this aggregate
180
+ *
181
+ * @param entityName Name of the entity
182
+ * @returns True if entity exists
183
+ */
184
+ hasEntity(entityName) {
185
+ return entityName in this.entityReferences;
186
+ }
187
+ //#endregion
188
+ //#region ---- Parent Navigation ----
189
+ /**
190
+ * Get parent module
191
+ *
192
+ * @returns Parent module model
193
+ */
194
+ getModule() {
195
+ return this.parent;
196
+ }
197
+ /**
198
+ * Get full aggregate path (module.aggregate)
199
+ *
200
+ * @returns Full path string
201
+ */
202
+ getPath() {
203
+ return `${this.parent.name}.${this.name}`;
204
+ }
205
+ //#endregion
206
+ //#region ---- Utility Methods ----
207
+ /**
208
+ * Get aggregate statistics
209
+ *
210
+ * @returns Statistics object
211
+ */
212
+ getStatistics() {
213
+ return {
214
+ entityCount: Object.keys(this.entityReferences).length,
215
+ actionCount: this.actions.length,
216
+ validationCount: this.validations.length
217
+ };
218
+ }
219
+ /**
220
+ * Convert back to interface definition
221
+ *
222
+ * @returns Aggregate definition
223
+ */
224
+ toDefinition() {
225
+ return {
226
+ name: this.name,
227
+ title: this.title,
228
+ entities: this.entityReferences, // Return as reference map
229
+ validations: this.validations,
230
+ actions: this.actions
231
+ };
232
+ }
233
+ //#endregion
234
+ //#region ---- Validation Methods ----
235
+ /**
236
+ * Validate the aggregate structure (synchronous validation only)
237
+ *
238
+ * @returns Array of validation errors
239
+ */
240
+ validate() {
241
+ const errors = [];
242
+ // Validate aggregate structure
243
+ if (!this.name)
244
+ errors.push('Aggregate name is required');
245
+ if (!this.title)
246
+ errors.push('Aggregate title is required');
247
+ // Validate entity references
248
+ for (const [entityName, entityRef] of Object.entries(this.entityReferences)) {
249
+ if (!entityRef || typeof entityRef !== 'string') {
250
+ errors.push(`Invalid entity reference for '${entityName}': must be a non-empty string`);
251
+ }
252
+ }
253
+ return errors;
254
+ }
255
+ }
256
+ //#endregion
257
+
258
+ //#region ---- AXPModuleModel ----
259
+ /**
260
+ * Simple runtime model for module definitions with navigation helpers.
261
+ *
262
+ * This model is a pure data structure that provides:
263
+ * - Access to module properties and metadata
264
+ * - Navigation helpers for finding aggregates
265
+ * - Hierarchy navigation and path generation
266
+ *
267
+ * All loading and resolution logic has been moved to AXPDomainRegistry.
268
+ */
269
+ class AXPModuleModel {
270
+ constructor(definition) {
271
+ this.aggregates = [];
272
+ this.name = definition.name;
273
+ this.title = definition.title;
274
+ // Initialize aggregates with parent reference (simplified constructor)
275
+ this.aggregates = (definition.aggregates || []).map(aggDef => new AXPAggregateModel(aggDef, this));
276
+ }
277
+ //#endregion
278
+ //#region ---- Navigation Helpers ----
279
+ /**
280
+ * Find aggregate by name
281
+ *
282
+ * @param name Aggregate name
283
+ * @returns Aggregate model or undefined if not found
284
+ */
285
+ findAggregate(name) {
286
+ return this.aggregates.find(agg => agg.name === name);
287
+ }
288
+ /**
289
+ * Get all aggregates
290
+ *
291
+ * @returns Array of all aggregate models
292
+ */
293
+ getAllAggregates() {
294
+ return [...this.aggregates];
295
+ }
296
+ /**
297
+ * Check if aggregate exists in this module
298
+ *
299
+ * @param name Aggregate name
300
+ * @returns True if aggregate exists
301
+ */
302
+ hasAggregate(name) {
303
+ return this.aggregates.some(agg => agg.name === name);
304
+ }
305
+ /**
306
+ * Get all aggregate names
307
+ *
308
+ * @returns Array of aggregate names
309
+ */
310
+ getAggregateNames() {
311
+ return this.aggregates.map(agg => agg.name);
312
+ }
313
+ /**
314
+ * Find entity reference across all aggregates
315
+ *
316
+ * @param entityName Entity name to search for
317
+ * @returns Object with aggregate and entity reference, or undefined if not found
318
+ */
319
+ findEntityReference(entityName) {
320
+ for (const aggregate of this.aggregates) {
321
+ const entityReference = aggregate.getEntityReference(entityName);
322
+ if (entityReference) {
323
+ return { aggregate, entityReference };
324
+ }
325
+ }
326
+ return undefined;
327
+ }
328
+ /**
329
+ * Get entity path for a specific entity in a specific aggregate
330
+ *
331
+ * @param aggregateName Aggregate name
332
+ * @param entityName Entity name
333
+ * @returns Full entity path
334
+ */
335
+ getEntityPath(aggregateName, entityName) {
336
+ return `${this.name}.${aggregateName}.${entityName}`;
337
+ }
338
+ /**
339
+ * Get aggregate path
340
+ *
341
+ * @param aggregateName Aggregate name
342
+ * @returns Full aggregate path
343
+ */
344
+ getAggregatePath(aggregateName) {
345
+ return `${this.name}.${aggregateName}`;
346
+ }
347
+ //#endregion
348
+ //#region ---- Query Methods ----
349
+ /**
350
+ * Get all entity references across all aggregates
351
+ *
352
+ * @returns Map of entity name to full path
353
+ */
354
+ getAllEntityReferences() {
355
+ const allReferences = {};
356
+ for (const aggregate of this.aggregates) {
357
+ const aggregateReferences = aggregate.entityReferences;
358
+ for (const [entityName, entityRef] of Object.entries(aggregateReferences)) {
359
+ // Use full path as key to avoid conflicts
360
+ const fullKey = `${aggregate.name}.${entityName}`;
361
+ allReferences[fullKey] = entityRef;
362
+ }
363
+ }
364
+ return allReferences;
365
+ }
366
+ /**
367
+ * Relations are stored in a separate collection. Use relation queries for join when needed.
368
+ * @deprecated Relations are no longer nested in aggregates.
369
+ */
370
+ getAllRelations() {
371
+ return [];
372
+ }
373
+ //#endregion
374
+ //#region ---- Validation Methods ----
375
+ /**
376
+ * Validate the module structure (synchronous validation only)
377
+ *
378
+ * @returns Array of validation errors
379
+ */
380
+ validate() {
381
+ const errors = [];
382
+ // Validate module structure
383
+ if (!this.name)
384
+ errors.push('Module name is required');
385
+ if (!this.title)
386
+ errors.push('Module title is required');
387
+ // Check for duplicate aggregate names
388
+ const aggregateNames = this.aggregates.map(agg => agg.name);
389
+ const duplicateNames = aggregateNames.filter((name, index) => aggregateNames.indexOf(name) !== index);
390
+ if (duplicateNames.length > 0) {
391
+ errors.push(`Duplicate aggregate names: ${duplicateNames.join(', ')}`);
392
+ }
393
+ // Validate aggregates
394
+ for (const aggregate of this.aggregates) {
395
+ const aggErrors = aggregate.validate();
396
+ if (aggErrors.length > 0) {
397
+ errors.push(...aggErrors.map((err) => `${aggregate.name}: ${err}`));
398
+ }
399
+ }
400
+ return errors;
401
+ }
402
+ //#endregion
403
+ //#region ---- Utility Methods ----
404
+ /**
405
+ * Get module statistics
406
+ *
407
+ * @returns Statistics object
408
+ */
409
+ getStatistics() {
410
+ const aggregateStats = this.aggregates.map(agg => agg.getStatistics());
411
+ return {
412
+ aggregateCount: this.aggregates.length,
413
+ entityCount: aggregateStats.reduce((sum, stat) => sum + stat.entityCount, 0),
414
+ actionCount: aggregateStats.reduce((sum, stat) => sum + stat.actionCount, 0),
415
+ validationCount: aggregateStats.reduce((sum, stat) => sum + stat.validationCount, 0)
416
+ };
417
+ }
418
+ /**
419
+ * Convert back to interface definition
420
+ *
421
+ * @returns Module definition
422
+ */
423
+ toDefinition() {
424
+ return {
425
+ name: this.name,
426
+ title: this.title,
427
+ aggregates: this.aggregates.map(agg => agg.toDefinition())
428
+ };
429
+ }
430
+ }
431
+ //#endregion
432
+
433
+ //#region ---- AXPPropertyModel ----
434
+ /**
435
+ * Runtime model for a {@link AXPPropertyDefinition} with helper methods.
436
+ */
437
+ class AXPPropertyModel {
438
+ constructor(definition) {
439
+ this.name = definition.name;
440
+ this.title = definition.title;
441
+ this.interface = definition.interface;
442
+ this.disabled = definition.disabled;
443
+ this.dataType = definition.dataType ?? 'string';
444
+ this.validations = definition.validations ?? [];
445
+ this.features = definition.features ?? {};
446
+ this.metadata = definition.metadata;
447
+ this.description = definition.description;
448
+ this.icon = definition.icon;
449
+ this.defaultValue = definition.defaultValue;
450
+ }
451
+ //#endregion
452
+ /**
453
+ * Get widget options
454
+ */
455
+ getWidgetOptions() {
456
+ return this.interface.options;
457
+ }
458
+ /**
459
+ * Check if the property is disabled
460
+ */
461
+ isDisabled() {
462
+ return this.disabled ?? false;
463
+ }
464
+ //#endregion
465
+ //#region ---- Feature Methods ----
466
+ /**
467
+ * Check if searchable
468
+ */
469
+ isSearchable() {
470
+ return this.features.searchable?.enabled ?? false;
471
+ }
472
+ /**
473
+ * Check if full text searchable
474
+ */
475
+ isFullTextSearchable() {
476
+ return this.features.searchable?.fullText ?? false;
477
+ }
478
+ /**
479
+ * Check if filterable
480
+ */
481
+ isFilterable() {
482
+ return this.features.filterable?.enabled ?? false;
483
+ }
484
+ /**
485
+ * Check if inline filterable
486
+ */
487
+ isInlineFilterable() {
488
+ return this.features.filterable?.inline ?? false;
489
+ }
490
+ /**
491
+ * Check if sortable
492
+ */
493
+ isSortable() {
494
+ return this.features.sortable?.enabled ?? false;
495
+ }
496
+ /**
497
+ * Check if auditable
498
+ */
499
+ isAuditable() {
500
+ return this.features.auditable?.enabled ?? false;
501
+ }
502
+ //#endregion
503
+ //#region ---- Validation Methods ----
504
+ /**
505
+ * Validate the property definition structure
506
+ */
507
+ async validate() {
508
+ const errors = [];
509
+ // Validate interface
510
+ if (!this.interface.name) {
511
+ errors.push('Widget type is required');
512
+ }
513
+ return errors;
514
+ }
515
+ //#endregion
516
+ //#region ---- Utility Methods ----
517
+ /**
518
+ * Get property capabilities
519
+ */
520
+ getCapabilities() {
521
+ return {
522
+ searchable: this.isSearchable(),
523
+ fullTextSearchable: this.isFullTextSearchable(),
524
+ filterable: this.isFilterable(),
525
+ inlineFilterable: this.isInlineFilterable(),
526
+ sortable: this.isSortable(),
527
+ auditable: this.isAuditable(),
528
+ disabled: this.isDisabled()
529
+ };
530
+ }
531
+ /**
532
+ * Get property summary
533
+ */
534
+ getSummary() {
535
+ const capabilities = this.getCapabilities();
536
+ const capabilityCount = Object.values(capabilities).filter(Boolean).length;
537
+ return {
538
+ widget: this.interface.name,
539
+ hasOptions: !!this.interface.options,
540
+ hasMetadata: !!this.metadata,
541
+ hasValidations: !!this.validations && this.validations.length > 0,
542
+ capabilityCount
543
+ };
544
+ }
545
+ /**
546
+ * Convert back to interface definition
547
+ */
548
+ toDefinition() {
549
+ return {
550
+ name: this.name,
551
+ title: this.title,
552
+ description: this.description,
553
+ icon: this.icon,
554
+ dataType: this.dataType,
555
+ defaultValue: this.defaultValue,
556
+ disabled: this.disabled,
557
+ interface: this.interface,
558
+ validations: this.validations,
559
+ features: this.features,
560
+ metadata: this.metadata
561
+ };
562
+ }
563
+ }
564
+
565
+ //#region ---- Property definition helpers ----
566
+ /**
567
+ * Strips entity-only fields so the payload matches {@link AXPPropertyDefinition}.
568
+ */
569
+ function toPropertyDefinition(def) {
570
+ const { actions, fieldFeatures, ...propertyDefinition } = def;
571
+ return propertyDefinition;
572
+ }
573
+ //#endregion
574
+ //#region ---- AXPEntityFieldModel ----
575
+ /**
576
+ * Runtime model for entity field definitions with parent references and helper methods
577
+ */
578
+ class AXPEntityFieldModel {
579
+ constructor(definition, parent, propertyService) {
580
+ this.entityPropertyDefinition = definition;
581
+ this.name = definition.name;
582
+ this.title = definition.title;
583
+ this.description = definition.description;
584
+ this.validations = definition.validations;
585
+ this.actions = definition.actions;
586
+ this.fieldFeatures = definition.fieldFeatures;
587
+ this.defaultValue = definition.defaultValue;
588
+ this.parent = parent;
589
+ this.propertyService = propertyService;
590
+ this.property = new AXPPropertyModel(toPropertyDefinition(definition));
591
+ this.propertyName = definition.name;
592
+ }
593
+ //#region ---- Feature Check Methods ----
594
+ /**
595
+ * Check if field is nullable
596
+ */
597
+ isNullable() {
598
+ return this.fieldFeatures?.nullable ?? false;
599
+ }
600
+ /**
601
+ * Check if field is readonly
602
+ */
603
+ isReadonly() {
604
+ return this.fieldFeatures?.readOnly ?? false;
605
+ }
606
+ /**
607
+ * Check if field is required (has required validation)
608
+ */
609
+ isRequired() {
610
+ return this.validations?.some((validation) => validation.rule === "required") ?? false;
611
+ }
612
+ /**
613
+ * Check if field is searchable
614
+ */
615
+ isSearchable() {
616
+ return this.property.features?.searchable?.enabled ?? false;
617
+ }
618
+ /**
619
+ * Check if field supports full text search
620
+ */
621
+ isFullTextSearchable() {
622
+ return this.property.features?.searchable?.fullText ?? false;
623
+ }
624
+ /**
625
+ * Check if field is filterable
626
+ */
627
+ isFilterable() {
628
+ return this.property.features?.filterable?.enabled ?? false;
629
+ }
630
+ /**
631
+ * Check if field has inline filtering
632
+ */
633
+ hasInlineFiltering() {
634
+ return this.property.features?.filterable?.inline ?? false;
635
+ }
636
+ /**
637
+ * Check if field is sortable
638
+ */
639
+ isSortable() {
640
+ return this.property.features?.sortable?.enabled ?? false;
641
+ }
642
+ /**
643
+ * Check if field is auditable
644
+ */
645
+ isAuditable() {
646
+ return this.property.features?.auditable?.enabled ?? false;
647
+ }
648
+ //#endregion
649
+ //#region ---- Property info ----
650
+ /**
651
+ * Registered property name (same as entity field name in the embedded model).
652
+ */
653
+ getPropertyName() {
654
+ return this.propertyName;
655
+ }
656
+ /**
657
+ * Registration metadata when this field's definition name is registered; otherwise embedded summary.
658
+ */
659
+ getPropertyInfo() {
660
+ if (this.propertyService.isRegistered(this.property.name)) {
661
+ return this.propertyService.getRegisteredProperty(this.property.name);
662
+ }
663
+ return this.property.getSummary();
664
+ }
665
+ /**
666
+ * Rebuild the property model from embedded definition (e.g. after definition updates).
667
+ */
668
+ refreshProperty() {
669
+ this.property = new AXPPropertyModel(toPropertyDefinition(this.entityPropertyDefinition));
670
+ }
671
+ //#endregion
672
+ //#region ---- Navigation Methods ----
673
+ /**
674
+ * Get parent entity
675
+ */
676
+ getEntity() {
677
+ return this.parent;
678
+ }
679
+ /**
680
+ * Get parent aggregate
681
+ */
682
+ getAggregate() {
683
+ return this.parent?.parent;
684
+ }
685
+ /**
686
+ * Get parent module
687
+ */
688
+ getModule() {
689
+ return this.parent?.parent?.parent;
690
+ }
691
+ /**
692
+ * Get full path (module.aggregate.entity.field)
693
+ */
694
+ getPath() {
695
+ return `${this.parent.parent.parent.name}.${this.parent.parent.name}.${this.parent.name}.${this.name}`;
696
+ }
697
+ //#endregion
698
+ //#region ---- Validation Methods ----
699
+ /**
700
+ * Validate the field structure
701
+ */
702
+ async validate() {
703
+ const errors = [];
704
+ if (!this.name)
705
+ errors.push("Field name is required");
706
+ if (!this.title)
707
+ errors.push("Field title is required");
708
+ if (!this.property.interface?.name) {
709
+ errors.push("Widget type (interface.name) is required");
710
+ }
711
+ if (this.property) {
712
+ const propertyErrors = await this.property.validate();
713
+ if (propertyErrors.length > 0) {
714
+ errors.push(...propertyErrors.map((err) => `Property: ${err}`));
715
+ }
716
+ }
717
+ return errors;
718
+ }
719
+ //#endregion
720
+ //#region ---- Utility Methods ----
721
+ /**
722
+ * Get field statistics
723
+ */
724
+ getStatistics() {
725
+ return {
726
+ hasValidations: !!this.validations && this.validations.length > 0,
727
+ hasActions: !!this.actions && this.actions.length > 0,
728
+ hasFieldFeatures: !!this.fieldFeatures,
729
+ hasDefaultValue: this.defaultValue !== undefined,
730
+ validationCount: this.validations?.length ?? 0,
731
+ actionCount: this.actions?.length ?? 0,
732
+ };
733
+ }
734
+ /**
735
+ * Get field capabilities
736
+ */
737
+ getCapabilities() {
738
+ return {
739
+ searchable: this.isSearchable(),
740
+ filterable: this.isFilterable(),
741
+ sortable: this.isSortable(),
742
+ auditable: this.isAuditable(),
743
+ nullable: this.isNullable(),
744
+ readonly: this.isReadonly(),
745
+ required: this.isRequired(),
746
+ };
747
+ }
748
+ /**
749
+ * Convert back to interface definition
750
+ */
751
+ toDefinition() {
752
+ return {
753
+ ...this.property.toDefinition(),
754
+ actions: this.actions,
755
+ fieldFeatures: this.fieldFeatures,
756
+ };
757
+ }
758
+ }
759
+ //#endregion
760
+
761
+ //#region ---- AXPEntityModel ----
762
+ /**
763
+ * Runtime model for entity definitions with parent references and helper methods
764
+ */
765
+ class AXPEntityModel {
766
+ constructor(definition, parent, propertyService) {
767
+ this.fields = [];
768
+ this.name = definition.name;
769
+ this.title = definition.title;
770
+ this.type = definition.type;
771
+ this.parent = parent;
772
+ this.propertyService = propertyService;
773
+ // Initialize fields with parent reference and property service
774
+ this.fields = definition.fields.map(fieldDef => new AXPEntityFieldModel(fieldDef, this, propertyService));
775
+ }
776
+ //#endregion
777
+ //#region ---- Query Methods ----
778
+ /**
779
+ * Find field by name
780
+ */
781
+ findField(name) {
782
+ return this.fields.find(field => field.name === name);
783
+ }
784
+ /**
785
+ * Get all fields
786
+ */
787
+ getAllFields() {
788
+ return [...this.fields];
789
+ }
790
+ /**
791
+ * Get required fields
792
+ */
793
+ getRequiredFields() {
794
+ return this.fields.filter(field => field.isRequired());
795
+ }
796
+ /**
797
+ * Get readonly fields
798
+ */
799
+ getReadonlyFields() {
800
+ return this.fields.filter(field => field.isReadonly());
801
+ }
802
+ /**
803
+ * Get searchable fields
804
+ */
805
+ getSearchableFields() {
806
+ return this.fields.filter(field => field.isSearchable());
807
+ }
808
+ /**
809
+ * Get filterable fields
810
+ */
811
+ getFilterableFields() {
812
+ return this.fields.filter(field => field.isFilterable());
813
+ }
814
+ /**
815
+ * Get sortable fields
816
+ */
817
+ getSortableFields() {
818
+ return this.fields.filter(field => field.isSortable());
819
+ }
820
+ //#endregion
821
+ //#region ---- Type Checking Methods ----
822
+ /**
823
+ * Check if this entity is an aggregate root
824
+ */
825
+ isAggregateRoot() {
826
+ return this.type === AXPEntityType.AggregateRoot;
827
+ }
828
+ /**
829
+ * Check if this entity is a regular entity
830
+ */
831
+ isEntity() {
832
+ return this.type === AXPEntityType.Entity;
833
+ }
834
+ /**
835
+ * Check if this entity is a value object
836
+ */
837
+ isValueObject() {
838
+ return this.type === AXPEntityType.ValueObject;
839
+ }
840
+ //#endregion
841
+ //#region ---- Navigation Methods ----
842
+ /**
843
+ * Get parent aggregate
844
+ */
845
+ getAggregate() {
846
+ return this.parent;
847
+ }
848
+ /**
849
+ * Get parent module
850
+ */
851
+ getModule() {
852
+ return this.parent?.parent;
853
+ }
854
+ /**
855
+ * Get full path (module.aggregate.entity)
856
+ */
857
+ getPath() {
858
+ return `${this.parent.parent.name}.${this.parent.name}.${this.name}`;
859
+ }
860
+ //#endregion
861
+ //#region ---- Validation Methods ----
862
+ /**
863
+ * Validate the entity structure
864
+ */
865
+ async validate() {
866
+ const errors = [];
867
+ // Validate entity structure
868
+ if (!this.name)
869
+ errors.push('Entity name is required');
870
+ if (!this.title)
871
+ errors.push('Entity title is required');
872
+ // Validate fields
873
+ for (const field of this.fields) {
874
+ const fieldErrors = await field.validate();
875
+ if (fieldErrors.length > 0) {
876
+ errors.push(...fieldErrors.map(err => `${field.name}: ${err}`));
877
+ }
878
+ }
879
+ return errors;
880
+ }
881
+ //#endregion
882
+ //#region ---- Utility Methods ----
883
+ /**
884
+ * Get entity statistics
885
+ */
886
+ getStatistics() {
887
+ return {
888
+ fieldCount: this.fields.length,
889
+ requiredFieldCount: this.getRequiredFields().length,
890
+ readonlyFieldCount: this.getReadonlyFields().length,
891
+ searchableFieldCount: this.getSearchableFields().length,
892
+ filterableFieldCount: this.getFilterableFields().length,
893
+ sortableFieldCount: this.getSortableFields().length
894
+ };
895
+ }
896
+ /**
897
+ * Convert back to interface definition
898
+ */
899
+ toDefinition() {
900
+ return {
901
+ name: this.name,
902
+ title: this.title,
903
+ fields: this.fields.map(field => field.toDefinition()),
904
+ type: this.type
905
+ };
906
+ }
907
+ }
908
+
909
+ //#region ---- AXPRelationModel ----
910
+ /**
911
+ * Runtime model for standalone relation definitions.
912
+ * Relations live in their own collection; join when needed.
913
+ */
914
+ class AXPRelationModel {
915
+ constructor(definition, parent) {
916
+ this.type = definition.type;
917
+ this.kind = definition.kind;
918
+ this.target = { ...definition.target };
919
+ this.source = { ...definition.source };
920
+ this.isRequired = definition.isRequired;
921
+ this.parent = parent;
922
+ }
923
+ //#endregion
924
+ //#region ---- Cardinality Methods ----
925
+ /**
926
+ * Check if relation is one-to-one
927
+ */
928
+ isOneToOne() {
929
+ return this.type === AXPRelationshipCardinality.OneToOne;
930
+ }
931
+ /**
932
+ * Check if relation is one-to-many
933
+ */
934
+ isOneToMany() {
935
+ return this.type === AXPRelationshipCardinality.OneToMany;
936
+ }
937
+ /**
938
+ * Check if relation is many-to-many
939
+ */
940
+ isManyToMany() {
941
+ return this.type === AXPRelationshipCardinality.ManyToMany;
942
+ }
943
+ //#endregion
944
+ //#region ---- Kind Methods ----
945
+ /**
946
+ * Check if relation is association
947
+ */
948
+ isAssociation() {
949
+ return this.kind === AXPRelationshipKind.Association;
950
+ }
951
+ /**
952
+ * Check if relation is composition
953
+ */
954
+ isComposition() {
955
+ return this.kind === AXPRelationshipKind.Composition;
956
+ }
957
+ /**
958
+ * Check if relation is aggregation
959
+ */
960
+ isAggregation() {
961
+ return this.kind === AXPRelationshipKind.Aggregation;
962
+ }
963
+ //#endregion
964
+ //#region ---- Navigation Methods ----
965
+ /**
966
+ * Get parent aggregate
967
+ */
968
+ getAggregate() {
969
+ return this.parent;
970
+ }
971
+ /**
972
+ * Get parent module
973
+ */
974
+ getModule() {
975
+ return this.parent?.parent;
976
+ }
977
+ /**
978
+ * Get full path (module.aggregate.relation)
979
+ */
980
+ getPath() {
981
+ return `${this.parent.parent.name}.${this.parent.name}.${this.source.entity}->${this.target.entity}`;
982
+ }
983
+ //#endregion
984
+ //#region ---- Query Methods ----
985
+ /**
986
+ * Get relation description
987
+ */
988
+ getDescription() {
989
+ const cardinalityDesc = this.getCardinalityDescription();
990
+ const kindDesc = this.getKindDescription();
991
+ const requiredDesc = this.isRequired ? 'required' : 'optional';
992
+ return `${cardinalityDesc} ${kindDesc} (${requiredDesc})`;
993
+ }
994
+ /**
995
+ * Get cardinality description
996
+ */
997
+ getCardinalityDescription() {
998
+ switch (this.type) {
999
+ case AXPRelationshipCardinality.OneToOne:
1000
+ return 'one-to-one';
1001
+ case AXPRelationshipCardinality.OneToMany:
1002
+ return 'one-to-many';
1003
+ case AXPRelationshipCardinality.ManyToMany:
1004
+ return 'many-to-many';
1005
+ default:
1006
+ return 'unknown';
1007
+ }
1008
+ }
1009
+ /**
1010
+ * Get kind description
1011
+ */
1012
+ getKindDescription() {
1013
+ switch (this.kind) {
1014
+ case AXPRelationshipKind.Association:
1015
+ return 'association';
1016
+ case AXPRelationshipKind.Composition:
1017
+ return 'composition';
1018
+ case AXPRelationshipKind.Aggregation:
1019
+ return 'aggregation';
1020
+ default:
1021
+ return 'unknown';
1022
+ }
1023
+ }
1024
+ /**
1025
+ * Get relation summary
1026
+ */
1027
+ getSummary() {
1028
+ return `${this.source.entity}.${this.source.key} -> ${this.target.aggregate}.${this.target.entity}.${this.target.key}`;
1029
+ }
1030
+ //#endregion
1031
+ //#region ---- Validation Methods ----
1032
+ /**
1033
+ * Validate the relation structure
1034
+ */
1035
+ validate() {
1036
+ const errors = [];
1037
+ // Validate source
1038
+ if (!this.source.entity)
1039
+ errors.push('Source entity is required');
1040
+ if (!this.source.key)
1041
+ errors.push('Source key is required');
1042
+ // Validate target
1043
+ if (!this.target.aggregate)
1044
+ errors.push('Target aggregate is required');
1045
+ if (!this.target.entity)
1046
+ errors.push('Target entity is required');
1047
+ if (!this.target.key)
1048
+ errors.push('Target key is required');
1049
+ return errors;
1050
+ }
1051
+ //#endregion
1052
+ //#region ---- Utility Methods ----
1053
+ /**
1054
+ * Get relation characteristics
1055
+ */
1056
+ getCharacteristics() {
1057
+ return {
1058
+ type: this.getCardinalityDescription(),
1059
+ kind: this.getKindDescription(),
1060
+ required: this.isRequired,
1061
+ isOwning: this.isComposition(),
1062
+ isNavigable: !this.isComposition() || this.isOneToOne()
1063
+ };
1064
+ }
1065
+ /**
1066
+ * Check if relation involves entity
1067
+ */
1068
+ involvesEntity(entityName) {
1069
+ return this.source.entity === entityName || this.target.entity === entityName;
1070
+ }
1071
+ /**
1072
+ * Check if relation targets aggregate
1073
+ */
1074
+ targetsAggregate(aggregateName) {
1075
+ return this.target.aggregate === aggregateName;
1076
+ }
1077
+ /**
1078
+ * Get the other entity in the relation
1079
+ */
1080
+ getOtherEntity(entityName) {
1081
+ if (this.source.entity === entityName) {
1082
+ return this.target.entity;
1083
+ }
1084
+ else if (this.target.entity === entityName) {
1085
+ return this.source.entity;
1086
+ }
1087
+ return null;
1088
+ }
1089
+ /**
1090
+ * Convert back to interface definition (AXPRelationDefinition with full source/target)
1091
+ */
1092
+ toDefinition() {
1093
+ return {
1094
+ type: this.type,
1095
+ kind: this.kind,
1096
+ target: { ...this.target },
1097
+ source: { ...this.source },
1098
+ isRequired: this.isRequired
1099
+ };
1100
+ }
1101
+ }
1102
+
1103
+ //#region ---- AXPModuleHelper ----
1104
+ /**
1105
+ * Helper utility class for working with module models
1106
+ *
1107
+ * @deprecated This helper class is deprecated and will be updated to work with the new domain registry system.
1108
+ * Use AXPDomainService for domain operations instead.
1109
+ *
1110
+ * TODO: Update this helper to work with the new simplified models and domain registry system.
1111
+ */
1112
+ class AXPModuleHelper {
1113
+ //#endregion
1114
+ //#region ---- Deprecated Methods - To Be Updated ----
1115
+ /**
1116
+ * @deprecated Use AXPDomainService.findEntitiesByName() instead
1117
+ */
1118
+ static findEntitiesByName(module, name) {
1119
+ console.warn('AXPModuleHelper.findEntitiesByName is deprecated. Use AXPDomainService instead.');
1120
+ return [];
1121
+ }
1122
+ /**
1123
+ * @deprecated Use AXPDomainService with entity field queries instead
1124
+ */
1125
+ static findFieldsByName(module, fieldName) {
1126
+ console.warn('AXPModuleHelper.findFieldsByName is deprecated. Use AXPDomainService instead.');
1127
+ return [];
1128
+ }
1129
+ /**
1130
+ * @deprecated Use AXPDomainService with entity type queries instead
1131
+ */
1132
+ static findEntitiesByType(module, type) {
1133
+ console.warn('AXPModuleHelper.findEntitiesByType is deprecated. Use AXPDomainService instead.');
1134
+ return [];
1135
+ }
1136
+ /**
1137
+ * @deprecated Use AXPDomainService with field validation queries instead
1138
+ */
1139
+ static findFieldsWithValidation(module, validationRule) {
1140
+ console.warn('AXPModuleHelper.findFieldsWithValidation is deprecated. Use AXPDomainService instead.');
1141
+ return [];
1142
+ }
1143
+ /**
1144
+ * @deprecated Use AXPDomainService with field queries instead
1145
+ */
1146
+ static findFieldsByDataType(module, dataType) {
1147
+ console.warn('AXPModuleHelper.findFieldsByDataType is deprecated. Use AXPDomainService instead.');
1148
+ return [];
1149
+ }
1150
+ /**
1151
+ * @deprecated Use AXPDomainService with required field queries instead
1152
+ */
1153
+ static findRequiredFields(module) {
1154
+ console.warn('AXPModuleHelper.findRequiredFields is deprecated. Use AXPDomainService instead.');
1155
+ return [];
1156
+ }
1157
+ /**
1158
+ * @deprecated Use AXPDomainService with nullable field queries instead
1159
+ */
1160
+ static findNullableFields(module) {
1161
+ console.warn('AXPModuleHelper.findNullableFields is deprecated. Use AXPDomainService instead.');
1162
+ return [];
1163
+ }
1164
+ /**
1165
+ * @deprecated Use AXPDomainService with default value queries instead
1166
+ */
1167
+ static findFieldsWithDefaultValues(module) {
1168
+ console.warn('AXPModuleHelper.findFieldsWithDefaultValues is deprecated. Use AXPDomainService instead.');
1169
+ return [];
1170
+ }
1171
+ /**
1172
+ * @deprecated Use AXPDomainService with registered property name queries instead
1173
+ */
1174
+ static findFieldsByRegisteredPropertyName(module, propertyName) {
1175
+ console.warn('AXPModuleHelper.findFieldsByRegisteredPropertyName is deprecated. Use AXPDomainService instead.');
1176
+ return [];
1177
+ }
1178
+ /**
1179
+ * @deprecated Use module.validate() method instead
1180
+ */
1181
+ static validateModule(module) {
1182
+ return module.validate();
1183
+ }
1184
+ /**
1185
+ * @deprecated Use aggregate relation queries instead
1186
+ */
1187
+ static findRelationsByType(module, relationType) {
1188
+ console.warn('AXPModuleHelper.findRelationsByType is deprecated. Use relation queries instead.');
1189
+ return [];
1190
+ }
1191
+ /**
1192
+ * @deprecated Use AXPDomainService with entity dependency queries instead
1193
+ */
1194
+ static findEntityDependencies(module, entityName) {
1195
+ console.warn('AXPModuleHelper.findEntityDependencies is deprecated. Use AXPDomainService instead.');
1196
+ return [];
1197
+ }
1198
+ /**
1199
+ * @deprecated Use module.getStatistics() method instead
1200
+ */
1201
+ static getModuleStatistics(module) {
1202
+ return module.getStatistics();
1203
+ }
1204
+ /**
1205
+ * @deprecated Use AXPDomainService with entity queries instead
1206
+ */
1207
+ static getAllEntities(module) {
1208
+ console.warn('AXPModuleHelper.getAllEntities is deprecated. Use AXPDomainService instead.');
1209
+ return [];
1210
+ }
1211
+ /**
1212
+ * @deprecated Use AXPDomainService with field queries instead
1213
+ */
1214
+ static getAllFields(module) {
1215
+ console.warn('AXPModuleHelper.getAllFields is deprecated. Use AXPDomainService instead.');
1216
+ return [];
1217
+ }
1218
+ }
1219
+
1220
+ //#region ---- Schema Middleware Context ----
1221
+ /**
1222
+ * Context class for schema middleware operations providing a fluent API for schema manipulation.
1223
+ *
1224
+ * This class serves as the interface between middleware functions and schema definitions,
1225
+ * offering methods to modify various aspects of a schema including:
1226
+ * - Widget configuration and options
1227
+ * - Validation rules
1228
+ * - Feature flags (searchable, filterable, sortable)
1229
+ * - Metadata and custom properties
1230
+ * - UI behavior (visibility, readonly state)
1231
+ *
1232
+ * All methods return `this` to enable fluent method chaining.
1233
+ *
1234
+ * @example
1235
+ * ```typescript
1236
+ * // Example middleware using the context
1237
+ * (context) => {
1238
+ * context
1239
+ * .addValidation({ rule: 'required' })
1240
+ * .searchable(true)
1241
+ * .withDefaultValue('default text')
1242
+ * .readonly(false);
1243
+ * }
1244
+ * ```
1245
+ */
1246
+ class AXPPropertyMiddlewareContext {
1247
+ constructor(definition) {
1248
+ // Deep clone to avoid mutating the original definition
1249
+ this._definition = JSON.parse(JSON.stringify(definition));
1250
+ }
1251
+ //#region ---- Schema Access Properties ----
1252
+ /**
1253
+ * Get the current schema definition (readonly access)
1254
+ */
1255
+ get definition() {
1256
+ return this._definition;
1257
+ }
1258
+ /**
1259
+ * Get the schema name for conditional logic
1260
+ */
1261
+ get name() {
1262
+ return this._definition.name;
1263
+ }
1264
+ //#endregion
1265
+ //#region ---- Default Value Management ----
1266
+ /**
1267
+ * Set a default value for the widget
1268
+ * @param defaultValue The default value to set
1269
+ */
1270
+ withDefaultValue(defaultValue) {
1271
+ if (!this._definition.interface.options) {
1272
+ this._definition.interface.options = {};
1273
+ }
1274
+ this._definition.interface.options['defaultValue'] = defaultValue;
1275
+ return this;
1276
+ }
1277
+ /**
1278
+ * Remove the default value from the widget
1279
+ */
1280
+ removeDefaultValue() {
1281
+ if (this._definition.interface.options) {
1282
+ delete this._definition.interface.options['defaultValue'];
1283
+ }
1284
+ return this;
1285
+ }
1286
+ //#endregion
1287
+ //#region ---- Validation Management ----
1288
+ /**
1289
+ * Add multiple validation rules to the schema
1290
+ * @param rules Array of validation rules to add
1291
+ */
1292
+ withValidation(rules) {
1293
+ if (!this._definition.validations) {
1294
+ this._definition.validations = [];
1295
+ }
1296
+ this._definition.validations.push(...rules);
1297
+ return this;
1298
+ }
1299
+ /**
1300
+ * Add a single validation rule to the schema
1301
+ * @param rule The validation rule to add
1302
+ */
1303
+ addValidation(rule) {
1304
+ if (!this._definition.validations) {
1305
+ this._definition.validations = [];
1306
+ }
1307
+ this._definition.validations.push(rule);
1308
+ return this;
1309
+ }
1310
+ /**
1311
+ * Add a single validation rule (alias for addValidation for backward compatibility)
1312
+ * @param rule The validation rule to add
1313
+ */
1314
+ withValidationRule(rule) {
1315
+ return this.addValidation(rule);
1316
+ }
1317
+ /**
1318
+ * Remove all validation rules from the schema
1319
+ */
1320
+ clearValidations() {
1321
+ this._definition.validations = [];
1322
+ return this;
1323
+ }
1324
+ /**
1325
+ * Remove a specific validation rule by its rule name
1326
+ * @param ruleName The name of the rule to remove (e.g., 'required', 'email')
1327
+ */
1328
+ removeValidation(ruleName) {
1329
+ if (this._definition.validations) {
1330
+ this._definition.validations = this._definition.validations.filter((v) => v.rule !== ruleName);
1331
+ }
1332
+ return this;
1333
+ }
1334
+ //#endregion
1335
+ //#region ---- Widget Configuration ----
1336
+ /**
1337
+ * Set or merge widget options
1338
+ * @param options Object containing widget-specific options to merge
1339
+ */
1340
+ withWidgetOptions(options) {
1341
+ const current = this._definition.interface.options ?? {};
1342
+ this._definition.interface.options = {
1343
+ ...current,
1344
+ ...options
1345
+ };
1346
+ return this;
1347
+ }
1348
+ /**
1349
+ * Remove a specific widget option by key
1350
+ * @param optionKey The key of the option to remove
1351
+ */
1352
+ removeWidgetOption(optionKey) {
1353
+ if (this._definition.interface.options) {
1354
+ delete this._definition.interface.options[optionKey];
1355
+ }
1356
+ return this;
1357
+ }
1358
+ /**
1359
+ * Change the widget type for this schema
1360
+ * @param widgetType The new widget type identifier
1361
+ */
1362
+ withWidgetType(widgetType) {
1363
+ this._definition.interface.name = widgetType;
1364
+ return this;
1365
+ }
1366
+ //#endregion
1367
+ //#region ---- Feature Configuration ----
1368
+ /**
1369
+ * Configure general features using an object
1370
+ * @param features Object containing feature configurations to merge
1371
+ */
1372
+ withFeatures(features) {
1373
+ this._definition.features = {
1374
+ ...this._definition.features,
1375
+ ...features
1376
+ };
1377
+ return this;
1378
+ }
1379
+ /**
1380
+ * Configure searchable feature with fine-grained control
1381
+ * @param enabled Whether searching is enabled
1382
+ * @param fullText Whether full-text search is enabled
1383
+ */
1384
+ searchable(enabled = true, fullText = false) {
1385
+ if (!this._definition.features) {
1386
+ this._definition.features = {};
1387
+ }
1388
+ this._definition.features.searchable = { enabled, fullText };
1389
+ return this;
1390
+ }
1391
+ /**
1392
+ * Configure filterable feature with inline filter support
1393
+ * @param enabled Whether filtering is enabled
1394
+ * @param inline Whether inline filtering is supported
1395
+ */
1396
+ filterable(enabled = true, inline = false) {
1397
+ if (!this._definition.features) {
1398
+ this._definition.features = {};
1399
+ }
1400
+ this._definition.features.filterable = { enabled, inline };
1401
+ return this;
1402
+ }
1403
+ /**
1404
+ * Configure sortable feature
1405
+ * @param enabled Whether sorting is enabled
1406
+ */
1407
+ sortable(enabled = true) {
1408
+ if (!this._definition.features) {
1409
+ this._definition.features = {};
1410
+ }
1411
+ this._definition.features.sortable = { enabled };
1412
+ return this;
1413
+ }
1414
+ //#endregion
1415
+ //#region ---- Metadata Management ----
1416
+ /**
1417
+ * Add or merge metadata to the schema
1418
+ * @param metadata Object containing metadata to merge
1419
+ */
1420
+ withMetadata(metadata) {
1421
+ this._definition.metadata = {
1422
+ ...this._definition.metadata,
1423
+ ...metadata
1424
+ };
1425
+ return this;
1426
+ }
1427
+ /**
1428
+ * Remove a specific metadata property by key
1429
+ * @param key The metadata key to remove
1430
+ */
1431
+ removeMetadata(key) {
1432
+ if (this._definition.metadata) {
1433
+ delete this._definition.metadata[key];
1434
+ }
1435
+ return this;
1436
+ }
1437
+ //#endregion
1438
+ //#region ---- UI State Management ----
1439
+ /**
1440
+ * Set the disabled state of the widget
1441
+ * @param isDisabled Whether the widget should be disabled
1442
+ */
1443
+ disabled(isDisabled = true) {
1444
+ this._definition.disabled = isDisabled;
1445
+ return this;
1446
+ }
1447
+ /**
1448
+ * Set the visibility of the widget
1449
+ * @param visible Whether the widget should be visible
1450
+ */
1451
+ withVisibility(visible) {
1452
+ if (!this._definition.interface.options) {
1453
+ this._definition.interface.options = {};
1454
+ }
1455
+ this._definition.interface.options['visible'] = visible;
1456
+ return this;
1457
+ }
1458
+ /**
1459
+ * Set the readonly state of the widget
1460
+ * @param isReadonly Whether the widget should be readonly
1461
+ */
1462
+ readonly(isReadonly = true) {
1463
+ if (!this._definition.interface.options) {
1464
+ this._definition.interface.options = {};
1465
+ }
1466
+ this._definition.interface.options['readonly'] = isReadonly;
1467
+ return this;
1468
+ }
1469
+ }
1470
+ //#endregion
1471
+ //#region ---- Builder-Based Middleware Types ----
1472
+
1473
+ //#endregion
1474
+ //#region ---- Schema Registry Service ----
1475
+ /**
1476
+ * Central registry for managing schema definitions, middleware, and dynamic loading.
1477
+ *
1478
+ * Provides:
1479
+ * - Schema registration and retrieval
1480
+ * - Middleware processing pipeline
1481
+ * - On-demand schema loading
1482
+ * - Caching and performance optimization
1483
+ */
1484
+ class AXPPropertyRegistry {
1485
+ constructor() {
1486
+ this._registrations = new Map();
1487
+ this._globalMiddleware = [];
1488
+ this._modelCache = new Map();
1489
+ this._loaders = null;
1490
+ }
1491
+ //#region ---- Registration Methods ----
1492
+ /**
1493
+ * Register a schema definition with optional metadata and middleware
1494
+ */
1495
+ register(definition, options = {}) {
1496
+ if (!definition.name || definition.name.trim() === '') {
1497
+ throw new Error('Property name is required and cannot be empty');
1498
+ }
1499
+ const registered = {
1500
+ name: definition.name,
1501
+ definition,
1502
+ options,
1503
+ registeredAt: new Date()
1504
+ };
1505
+ this._registrations.set(definition.name, registered);
1506
+ this.invalidateCache(definition.name);
1507
+ }
1508
+ /**
1509
+ * Register multiple schemas at once for batch operations
1510
+ */
1511
+ registerBatch(entries) {
1512
+ for (const entry of entries) {
1513
+ this.register(entry.definition, entry.options || {});
1514
+ }
1515
+ }
1516
+ /**
1517
+ * Remove a schema from the registry
1518
+ */
1519
+ unregister(name) {
1520
+ const removed = this._registrations.delete(name);
1521
+ if (removed) {
1522
+ this.invalidateCache(name);
1523
+ }
1524
+ return removed;
1525
+ }
1526
+ /**
1527
+ * Check if a schema is currently registered
1528
+ */
1529
+ isRegistered(name) {
1530
+ return this._registrations.has(name);
1531
+ }
1532
+ //#endregion
1533
+ //#region ---- Resolution Methods ----
1534
+ /**
1535
+ * Resolve a schema by name with full middleware processing and caching.
1536
+ * Supports on-demand loading if schema is not registered.
1537
+ */
1538
+ async resolve(name) {
1539
+ // Check cache first for performance
1540
+ if (this._modelCache.has(name)) {
1541
+ return this._modelCache.get(name);
1542
+ }
1543
+ // Try to get from registered schemas first
1544
+ let registered = this._registrations.get(name);
1545
+ // If not found, attempt on-demand loading
1546
+ if (!registered) {
1547
+ const definition = await this.loadFromLoaders(name);
1548
+ if (definition) {
1549
+ registered = {
1550
+ name,
1551
+ definition,
1552
+ options: {},
1553
+ registeredAt: new Date()
1554
+ };
1555
+ this._registrations.set(name, registered);
1556
+ }
1557
+ else {
1558
+ throw new Error(`Property '${name}' is not registered and no loader can provide it`);
1559
+ }
1560
+ }
1561
+ // Clone and process through middleware pipeline
1562
+ const definition = this.cloneDefinition(registered.definition);
1563
+ const context = new AXPPropertyMiddlewareContext(definition);
1564
+ // Apply global middleware first
1565
+ for (const middleware of this._globalMiddleware) {
1566
+ await middleware(context);
1567
+ }
1568
+ // Apply registration-specific middleware
1569
+ if (registered.options.middleware) {
1570
+ for (const middleware of registered.options.middleware) {
1571
+ await middleware(context);
1572
+ }
1573
+ }
1574
+ // Create final model and cache it
1575
+ const model = new AXPPropertyModel(context.definition);
1576
+ this._modelCache.set(name, model);
1577
+ return model;
1578
+ }
1579
+ /**
1580
+ * Synchronous resolution without middleware processing.
1581
+ * Use only when middleware is not needed for performance.
1582
+ */
1583
+ resolveSync(name) {
1584
+ const registered = this._registrations.get(name);
1585
+ if (!registered) {
1586
+ throw new Error(`Property '${name}' is not registered`);
1587
+ }
1588
+ return new AXPPropertyModel(this.cloneDefinition(registered.definition));
1589
+ }
1590
+ //#endregion
1591
+ //#region ---- Middleware Management ----
1592
+ /**
1593
+ * Add global middleware that applies to all schema resolutions
1594
+ */
1595
+ addGlobalMiddleware(middleware) {
1596
+ if (typeof middleware !== 'function') {
1597
+ throw new Error('Middleware must be a function');
1598
+ }
1599
+ this._globalMiddleware.push(middleware);
1600
+ }
1601
+ /**
1602
+ * Remove specific global middleware
1603
+ */
1604
+ removeGlobalMiddleware(middleware) {
1605
+ const index = this._globalMiddleware.indexOf(middleware);
1606
+ if (index > -1) {
1607
+ this._globalMiddleware.splice(index, 1);
1608
+ return true;
1609
+ }
1610
+ return false;
1611
+ }
1612
+ /**
1613
+ * Clear all global middleware
1614
+ */
1615
+ clearGlobalMiddleware() {
1616
+ this._globalMiddleware.length = 0;
1617
+ }
1618
+ //#endregion
1619
+ //#region ---- Loader Management ----
1620
+ /**
1621
+ * Add a schema loader for on-demand loading
1622
+ */
1623
+ addLoader(loader) {
1624
+ if (this._loaders === null) {
1625
+ this._loaders = [];
1626
+ }
1627
+ this._loaders.push(new loader());
1628
+ }
1629
+ //#endregion
1630
+ //#region ---- Query Methods ----
1631
+ /**
1632
+ * Get all registered schema names
1633
+ */
1634
+ getRegisteredNames() {
1635
+ return Array.from(this._registrations.keys());
1636
+ }
1637
+ /**
1638
+ * Get detailed registration information for a schema
1639
+ */
1640
+ getRegisteredProperty(name) {
1641
+ return this._registrations.get(name);
1642
+ }
1643
+ /**
1644
+ * Get all registered properties with their metadata
1645
+ */
1646
+ getAllRegisteredProperties() {
1647
+ return Array.from(this._registrations.values());
1648
+ }
1649
+ /**
1650
+ * Find registered properties by tag for categorization
1651
+ */
1652
+ findByTag(tag) {
1653
+ return Array.from(this._registrations.values()).filter((registration) => registration.options.tags?.includes(tag));
1654
+ }
1655
+ /**
1656
+ * Find registered properties by widget type for widget-specific operations
1657
+ */
1658
+ findByWidget(widgetType) {
1659
+ return Array.from(this._registrations.values()).filter((registration) => registration.definition.interface.name === widgetType);
1660
+ }
1661
+ /**
1662
+ * Get comprehensive registry statistics
1663
+ */
1664
+ getStatistics() {
1665
+ const propertiesByWidget = {};
1666
+ const propertiesByTag = {};
1667
+ for (const registration of this._registrations.values()) {
1668
+ const widget = registration.definition.interface.name;
1669
+ propertiesByWidget[widget] = (propertiesByWidget[widget] || 0) + 1;
1670
+ if (registration.options.tags) {
1671
+ for (const tag of registration.options.tags) {
1672
+ propertiesByTag[tag] = (propertiesByTag[tag] || 0) + 1;
1673
+ }
1674
+ }
1675
+ }
1676
+ return {
1677
+ propertyCount: this._registrations.size,
1678
+ globalMiddlewareCount: this._globalMiddleware.length,
1679
+ propertiesByWidget,
1680
+ propertiesByTag
1681
+ };
1682
+ }
1683
+ //#endregion
1684
+ //#region ---- Cache Management ----
1685
+ /**
1686
+ * Clear all cached models (useful when schemas need to be reloaded)
1687
+ */
1688
+ clearCache() {
1689
+ this._modelCache.clear();
1690
+ }
1691
+ /**
1692
+ * Invalidate cache for a specific schema
1693
+ */
1694
+ invalidateCache(name) {
1695
+ this._modelCache.delete(name);
1696
+ }
1697
+ /**
1698
+ * Clear all registered schemas, middleware, and cached models
1699
+ */
1700
+ clear() {
1701
+ this._registrations.clear();
1702
+ this._globalMiddleware.length = 0;
1703
+ this._modelCache.clear();
1704
+ this._loaders = null;
1705
+ }
1706
+ //#endregion
1707
+ //#region ---- Private Helper Methods ----
1708
+ /**
1709
+ * Attempt to load schema from registered loaders
1710
+ */
1711
+ async loadFromLoaders(name) {
1712
+ const loaders = this.getLoaders();
1713
+ for (const loader of loaders) {
1714
+ if (loader.canLoad(name)) {
1715
+ try {
1716
+ const definition = await loader.load(name);
1717
+ if (definition) {
1718
+ console.log(`Property '${name}' loaded from ${loader.constructor.name}`);
1719
+ return definition;
1720
+ }
1721
+ }
1722
+ catch (error) {
1723
+ console.warn(`Loader ${loader.constructor.name} failed to load '${name}':`, error);
1724
+ }
1725
+ }
1726
+ }
1727
+ return null;
1728
+ }
1729
+ /**
1730
+ * Get loaders sorted by priority (lazy initialization)
1731
+ */
1732
+ getLoaders() {
1733
+ if (this._loaders === null) {
1734
+ try {
1735
+ this._loaders = [];
1736
+ // Sort by priority (higher priority first)
1737
+ this._loaders.sort((a, b) => {
1738
+ const priorityA = a.priority ?? 0;
1739
+ const priorityB = b.priority ?? 0;
1740
+ return priorityB - priorityA;
1741
+ });
1742
+ }
1743
+ catch (error) {
1744
+ console.warn('Failed to initialize property loaders:', error);
1745
+ this._loaders = [];
1746
+ }
1747
+ }
1748
+ return this._loaders;
1749
+ }
1750
+ /**
1751
+ * Create a deep clone of a schema definition to prevent mutations
1752
+ */
1753
+ cloneDefinition(definition) {
1754
+ return JSON.parse(JSON.stringify(definition));
1755
+ }
1756
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPropertyRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1757
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPropertyRegistry, providedIn: 'root' }); }
1758
+ }
1759
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPropertyRegistry, decorators: [{
1760
+ type: Injectable,
1761
+ args: [{ providedIn: 'root' }]
1762
+ }], ctorParameters: () => [] });
1763
+
1764
+ //#region ---- Property Service ----
1765
+ /**
1766
+ * High-level facade for registered property definitions ({@link AXPPropertyDefinition}).
1767
+ *
1768
+ * Wraps {@link AXPPropertyRegistry} with convenience methods for resolution and discovery.
1769
+ */
1770
+ class AXPPropertyService {
1771
+ constructor() {
1772
+ this.registry = inject(AXPPropertyRegistry);
1773
+ }
1774
+ //#region ---- Registration ----
1775
+ /**
1776
+ * Register a property definition with optional configuration
1777
+ */
1778
+ register(definition, options) {
1779
+ this.registry.register(definition, options);
1780
+ }
1781
+ /**
1782
+ * Register multiple property definitions at once
1783
+ */
1784
+ registerBatch(entries) {
1785
+ this.registry.registerBatch(entries);
1786
+ }
1787
+ /**
1788
+ * Remove a property definition from the registry
1789
+ */
1790
+ unregister(name) {
1791
+ return this.registry.unregister(name);
1792
+ }
1793
+ /**
1794
+ * Check if a property definition is registered by name
1795
+ */
1796
+ isRegistered(name) {
1797
+ return this.registry.isRegistered(name);
1798
+ }
1799
+ /**
1800
+ * Get all registered property names
1801
+ */
1802
+ getRegisteredNames() {
1803
+ return this.registry.getRegisteredNames();
1804
+ }
1805
+ /**
1806
+ * Clear all registrations and reset the registry
1807
+ */
1808
+ clear() {
1809
+ this.registry.clear();
1810
+ }
1811
+ //#endregion
1812
+ //#region ---- Resolution ----
1813
+ /**
1814
+ * Resolve a registered property by name with full middleware processing
1815
+ */
1816
+ async resolve(name) {
1817
+ return this.registry.resolve(name);
1818
+ }
1819
+ /**
1820
+ * Resolve synchronously without middleware (for performance)
1821
+ */
1822
+ resolveSync(name) {
1823
+ return this.registry.resolveSync(name);
1824
+ }
1825
+ /**
1826
+ * Resolve multiple registered properties for form building and batch operations
1827
+ */
1828
+ async resolveMultiple(fieldConfigs) {
1829
+ const resolvedFields = await Promise.all(fieldConfigs.map(async (config) => ({
1830
+ name: config.name,
1831
+ property: await this.resolve(config.propertyName),
1832
+ })));
1833
+ return resolvedFields;
1834
+ }
1835
+ //#endregion
1836
+ //#region ---- Middleware Management ----
1837
+ /**
1838
+ * Add global middleware that applies to all property resolutions
1839
+ */
1840
+ addGlobalMiddleware(middleware) {
1841
+ this.registry.addGlobalMiddleware(middleware);
1842
+ }
1843
+ /**
1844
+ * Remove specific global middleware
1845
+ */
1846
+ removeGlobalMiddleware(middleware) {
1847
+ return this.registry.removeGlobalMiddleware(middleware);
1848
+ }
1849
+ /**
1850
+ * Clear all global middleware
1851
+ */
1852
+ clearGlobalMiddleware() {
1853
+ this.registry.clearGlobalMiddleware();
1854
+ }
1855
+ //#endregion
1856
+ //#region ---- Query and Discovery ----
1857
+ /**
1858
+ * Get detailed information about a registered property definition
1859
+ */
1860
+ getRegisteredProperty(name) {
1861
+ return this.registry.getRegisteredProperty(name);
1862
+ }
1863
+ /**
1864
+ * Get all registered property definitions with their metadata
1865
+ */
1866
+ getAllRegisteredProperties() {
1867
+ return this.registry.getAllRegisteredProperties();
1868
+ }
1869
+ /**
1870
+ * Find registered properties by tag for categorization and grouping
1871
+ */
1872
+ findByTag(tag) {
1873
+ return this.registry.findByTag(tag);
1874
+ }
1875
+ /**
1876
+ * Find registered properties by widget type for widget-specific operations
1877
+ */
1878
+ findByWidget(widgetType) {
1879
+ return this.registry.findByWidget(widgetType);
1880
+ }
1881
+ /**
1882
+ * Get comprehensive registry statistics and analytics
1883
+ */
1884
+ getStatistics() {
1885
+ const stats = this.registry.getStatistics();
1886
+ // Enhance with top-used analytics
1887
+ const mostUsedWidgets = Object.entries(stats.propertiesByWidget)
1888
+ .sort(([, a], [, b]) => b - a)
1889
+ .slice(0, 5)
1890
+ .map(([widget]) => widget);
1891
+ const mostUsedTags = Object.entries(stats.propertiesByTag)
1892
+ .sort(([, a], [, b]) => b - a)
1893
+ .slice(0, 5)
1894
+ .map(([tag]) => tag);
1895
+ return {
1896
+ ...stats,
1897
+ mostUsedWidgets,
1898
+ mostUsedTags
1899
+ };
1900
+ }
1901
+ //#endregion
1902
+ //#region ---- Validation and Analysis ----
1903
+ /**
1904
+ * Validate that all referenced property names exist in the registry
1905
+ */
1906
+ validatePropertyReferences(propertyNames) {
1907
+ const missingPropertyNames = [];
1908
+ for (const propertyName of propertyNames) {
1909
+ if (!this.isRegistered(propertyName)) {
1910
+ missingPropertyNames.push(propertyName);
1911
+ }
1912
+ }
1913
+ return {
1914
+ valid: missingPropertyNames.length === 0,
1915
+ missingPropertyNames,
1916
+ };
1917
+ }
1918
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPropertyService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1919
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPropertyService, providedIn: 'root' }); }
1920
+ }
1921
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPPropertyService, decorators: [{
1922
+ type: Injectable,
1923
+ args: [{ providedIn: 'root' }]
1924
+ }] });
1925
+
1926
+ //#endregion
1927
+
1928
+ //#endregion
1929
+ //#region ---- Provider Functions ----
1930
+ /**
1931
+ * Provide schema loaders for on-demand schema loading.
1932
+ *
1933
+ * Schema loaders enable the registry to load schemas that are not registered
1934
+ * at build time. This is useful for:
1935
+ * - Loading schemas from external APIs
1936
+ * - Dynamic schema generation
1937
+ * - Lazy loading of large schema sets
1938
+ * - Development-time schema hot-reloading
1939
+ *
1940
+ * @param loaders Array of loader classes or loader configurations
1941
+ * @returns Environment providers for dependency injection
1942
+ *
1943
+ * @example
1944
+ * ```typescript
1945
+ * // Simple loader registration
1946
+ * providePropertyLoaders([
1947
+ * HttpSchemaLoader,
1948
+ * FileSystemSchemaLoader
1949
+ * ])
1950
+ *
1951
+ * // With priority configuration
1952
+ * providePropertyLoaders([
1953
+ * { loader: HttpSchemaLoader, priority: 10 },
1954
+ * { loader: FileSystemSchemaLoader, priority: 5 }
1955
+ * ])
1956
+ * ```
1957
+ */
1958
+ function providePropertyLoaders(loaders) {
1959
+ return makeEnvironmentProviders([
1960
+ {
1961
+ provide: AXP_PROPERTY_LOADER_SETUP,
1962
+ useFactory: async () => {
1963
+ const registry = inject(AXPPropertyRegistry);
1964
+ // Register each loader with the registry
1965
+ for (const loader of loaders) {
1966
+ const loaderClass = typeof loader === 'function' ? loader : loader.loader;
1967
+ registry.addLoader(loaderClass);
1968
+ }
1969
+ return true;
1970
+ },
1971
+ multi: true
1972
+ }
1973
+ ]);
1974
+ }
1975
+ //#endregion
1976
+
1977
+ //#endregion
1978
+ //#region ---- Provider Functions ----
1979
+ /**
1980
+ * Provide schema setups for registration during application bootstrap.
1981
+ *
1982
+ * This is the primary way to register schemas that are known at build time.
1983
+ * Schemas registered this way are immediately available in the registry.
1984
+ *
1985
+ * @param schemas Array of schema entries to register
1986
+ * @returns Environment providers for dependency injection
1987
+ *
1988
+ * @example
1989
+ * ```typescript
1990
+ * providePropertySetups([
1991
+ * {
1992
+ * definition: emailSchema,
1993
+ * options: {
1994
+ * tags: ['user', 'contact'],
1995
+ * description: 'Email field schema'
1996
+ * }
1997
+ * },
1998
+ * {
1999
+ * definition: phoneSchema,
2000
+ * options: { tags: ['contact'] }
2001
+ * }
2002
+ * ])
2003
+ * ```
2004
+ */
2005
+ function providePropertySetups(entries) {
2006
+ return makeEnvironmentProviders([
2007
+ {
2008
+ provide: AXP_PROPERTY_SETUP,
2009
+ useFactory: () => {
2010
+ const registry = inject(AXPPropertyRegistry);
2011
+ for (const entry of entries) {
2012
+ registry.register(entry.definition, entry.options);
2013
+ }
2014
+ return true;
2015
+ },
2016
+ multi: true
2017
+ }
2018
+ ]);
2019
+ }
2020
+ /**
2021
+ * Convenience function to provide a single schema setup.
2022
+ *
2023
+ * Useful when you need to register just one schema or want to keep
2024
+ * schema registrations separate for organizational purposes.
2025
+ *
2026
+ * @param definition The schema definition to register
2027
+ * @param options Optional registration options and metadata
2028
+ * @returns Environment providers for dependency injection
2029
+ *
2030
+ * @example
2031
+ * ```typescript
2032
+ * provideProperty(emailSchema, {
2033
+ * tags: ['user', 'contact'],
2034
+ * description: 'User email field'
2035
+ * })
2036
+ * ```
2037
+ */
2038
+ function provideProperty(definition, options) {
2039
+ return providePropertySetups([{ definition, options }]);
2040
+ }
2041
+ /**
2042
+ * Provide schema setups from a factory function for dynamic registration.
2043
+ *
2044
+ * Useful when schemas need to be generated at runtime, loaded from external
2045
+ * sources, or depend on configuration that's not available at build time.
2046
+ *
2047
+ * @param schemaFactory Factory function that returns schema entries
2048
+ * @returns Environment providers for dependency injection
2049
+ *
2050
+ * @example
2051
+ * ```typescript
2052
+ * providePropertiesFromFactory(async () => {
2053
+ * const config = await loadConfiguration();
2054
+ * return config.schemas.map(schema => ({
2055
+ * definition: schema,
2056
+ * options: { tags: ['dynamic'] }
2057
+ * }));
2058
+ * })
2059
+ * ```
2060
+ */
2061
+ function providePropertiesFromFactory(factory) {
2062
+ return makeEnvironmentProviders([
2063
+ {
2064
+ provide: AXP_PROPERTY_SETUP,
2065
+ useFactory: async () => {
2066
+ const registry = inject(AXPPropertyRegistry);
2067
+ const entries = await factory();
2068
+ for (const entry of entries) {
2069
+ registry.register(entry.definition, entry.options);
2070
+ }
2071
+ return true;
2072
+ },
2073
+ multi: true
2074
+ }
2075
+ ]);
2076
+ }
2077
+ //#endregion
2078
+
2079
+ //#endregion
2080
+ //#region ---- Provider Functions ----
2081
+ /**
2082
+ * Provide schema middleware for registration in the application.
2083
+ *
2084
+ * Supports both global middleware (applies to all schemas) and targeted middleware
2085
+ * (applies only to schemas matching specific patterns).
2086
+ *
2087
+ * @param middleware Array of middleware entries to register
2088
+ * @returns Environment providers for dependency injection
2089
+ *
2090
+ * @example
2091
+ * ```typescript
2092
+ * // Global middleware
2093
+ * providePropertyMiddleware([
2094
+ * (context) => {
2095
+ * if (context.definition.dataType === 'string') {
2096
+ * context.searchable(true);
2097
+ * }
2098
+ * }
2099
+ * ])
2100
+ *
2101
+ * // Targeted middleware
2102
+ * providePropertyMiddleware([
2103
+ * {
2104
+ * target: /^user_/,
2105
+ * middleware: (context) => context.withMetadata({ category: 'user' })
2106
+ * }
2107
+ * ])
2108
+ * ```
2109
+ */
2110
+ function providePropertyMiddleware(middleware) {
2111
+ const global = [];
2112
+ const targeted = [];
2113
+ // Separate global and targeted middleware for different processing
2114
+ for (const entry of middleware) {
2115
+ if (typeof entry === 'function') {
2116
+ global.push(entry);
2117
+ }
2118
+ else {
2119
+ targeted.push(entry);
2120
+ }
2121
+ }
2122
+ return makeEnvironmentProviders([
2123
+ // Setup global middleware that applies to all schemas
2124
+ ...(global.length > 0 ? [{
2125
+ provide: AXP_PROPERTY_MIDDLEWARE_SETUP,
2126
+ useFactory: () => {
2127
+ const registry = inject(AXPPropertyRegistry);
2128
+ for (const mw of global) {
2129
+ registry.addGlobalMiddleware(mw);
2130
+ }
2131
+ return true;
2132
+ },
2133
+ multi: true
2134
+ }] : []),
2135
+ // Register targeted middleware entries for future extension support
2136
+ ...targeted.map(entry => ({
2137
+ provide: AXP_PROPERTY_EXTENSION,
2138
+ useValue: entry,
2139
+ multi: true
2140
+ }))
2141
+ ]);
2142
+ }
2143
+ //#endregion
2144
+
2145
+ //#region ---- Property registry core ----
2146
+ //#endregion
2147
+
2148
+ //#region ---- Domain Middleware Context ----
2149
+ /**
2150
+ * Context class for domain middleware operations providing a fluent API for domain definition manipulation.
2151
+ *
2152
+ * This class serves as the interface between middleware functions and domain definitions,
2153
+ * offering methods to modify various aspects of a domain definition including:
2154
+ * - Metadata and custom properties
2155
+ * - Validation rules
2156
+ * - Feature flags and configuration
2157
+ * - Transformations and augmentations
2158
+ *
2159
+ * All methods return `this` to enable fluent method chaining.
2160
+ */
2161
+ class AXPDomainMiddlewareContext {
2162
+ constructor(definition, type) {
2163
+ // Deep clone to avoid mutating the original definition
2164
+ this._definition = JSON.parse(JSON.stringify(definition));
2165
+ this._type = type;
2166
+ }
2167
+ /**
2168
+ * Get the current definition (read-only access)
2169
+ */
2170
+ get definition() {
2171
+ return this._definition;
2172
+ }
2173
+ /**
2174
+ * Get the type of domain object being processed
2175
+ */
2176
+ get type() {
2177
+ return this._type;
2178
+ }
2179
+ /**
2180
+ * Set metadata for the domain definition
2181
+ */
2182
+ setMetadata(key, value) {
2183
+ const def = this._definition;
2184
+ if (!def.metadata) {
2185
+ def.metadata = {};
2186
+ }
2187
+ def.metadata[key] = value;
2188
+ return this;
2189
+ }
2190
+ /**
2191
+ * Get metadata value
2192
+ */
2193
+ getMetadata(key) {
2194
+ const def = this._definition;
2195
+ return def.metadata?.[key];
2196
+ }
2197
+ /**
2198
+ * Add validation rule to the definition (for entities and aggregates)
2199
+ */
2200
+ addValidation(rule) {
2201
+ if ('validations' in this._definition) {
2202
+ this._definition.validations = this._definition.validations || [];
2203
+ this._definition.validations.push(rule);
2204
+ }
2205
+ return this;
2206
+ }
2207
+ /**
2208
+ * Transform fields (for entities)
2209
+ */
2210
+ transformFields(transformer) {
2211
+ if ('fields' in this._definition && this._definition.fields) {
2212
+ this._definition.fields = this._definition.fields.map(transformer);
2213
+ }
2214
+ return this;
2215
+ }
2216
+ /**
2217
+ * Add field to entity definition
2218
+ */
2219
+ addField(field) {
2220
+ if ('fields' in this._definition) {
2221
+ this._definition.fields = this._definition.fields || [];
2222
+ this._definition.fields.push(field);
2223
+ }
2224
+ return this;
2225
+ }
2226
+ /**
2227
+ * Set title with transformation
2228
+ */
2229
+ setTitle(title) {
2230
+ this._definition.title = title;
2231
+ return this;
2232
+ }
2233
+ /**
2234
+ * Apply conditional logic
2235
+ */
2236
+ when(condition, callback) {
2237
+ if (condition) {
2238
+ callback(this);
2239
+ }
2240
+ return this;
2241
+ }
2242
+ /**
2243
+ * Replace the entire definition
2244
+ */
2245
+ replaceDefinition(newDefinition) {
2246
+ this._definition = JSON.parse(JSON.stringify(newDefinition));
2247
+ return this;
2248
+ }
2249
+ }
2250
+ //#endregion
2251
+
2252
+ //#region ---- Domain Registry Service ----
2253
+ /**
2254
+ * Central registry for managing domain definitions, middleware, and dynamic loading.
2255
+ *
2256
+ * Provides:
2257
+ * - Path-based domain resolution (module.aggregate.entity)
2258
+ * - Definition-level caching with fresh model creation
2259
+ * - Type-specific middleware processing
2260
+ * - On-demand domain loading with first-wins strategy
2261
+ * - Model creation and dependency injection
2262
+ */
2263
+ class AXPDomainRegistry {
2264
+ constructor() {
2265
+ // Cache definitions (before middleware), not models
2266
+ this._definitionCache = new Map();
2267
+ // Type-specific middleware collections
2268
+ this._moduleMiddleware = [];
2269
+ this._aggregateMiddleware = [];
2270
+ this._entityMiddleware = [];
2271
+ // Registered loaders for on-demand loading
2272
+ this._loaders = [];
2273
+ // Injected dependencies
2274
+ this.propertyService = inject(AXPPropertyService);
2275
+ }
2276
+ //#region ---- Main Resolution Method ----
2277
+ /**
2278
+ * Resolve a domain object by path with full middleware processing.
2279
+ * Supports definition-level caching with fresh model creation.
2280
+ *
2281
+ * @param path Domain path (e.g., "user-management.user-aggregate.user")
2282
+ * @returns Promise that resolves to the domain model
2283
+ */
2284
+ async resolve(path) {
2285
+ const pathInfo = this.parsePath(path);
2286
+ // Check definition cache first
2287
+ let definition = this._definitionCache.get(path);
2288
+ if (!definition) {
2289
+ // Load from first available loader
2290
+ definition = await this.loadFromLoaders(path, pathInfo.type);
2291
+ if (!definition) {
2292
+ throw new Error(`Cannot resolve domain path: ${path}`);
2293
+ }
2294
+ // Cache the raw definition
2295
+ this._definitionCache.set(path, definition);
2296
+ }
2297
+ // Apply type-specific middleware (creates new processed definition)
2298
+ const processedDefinition = await this.applyTypeMiddleware(definition, pathInfo.type, path);
2299
+ // Create and return fresh model instance (not cached)
2300
+ return this.createModel(processedDefinition, pathInfo);
2301
+ }
2302
+ //#endregion
2303
+ //#region ---- Path Parsing ----
2304
+ /**
2305
+ * Parse domain path string into structured information
2306
+ *
2307
+ * @param path Domain path to parse
2308
+ * @returns Parsed path information
2309
+ */
2310
+ parsePath(path) {
2311
+ const parts = path.split('.');
2312
+ if (parts.length === 1) {
2313
+ return {
2314
+ module: parts[0],
2315
+ type: 'module',
2316
+ fullPath: path
2317
+ };
2318
+ }
2319
+ else if (parts.length === 2) {
2320
+ return {
2321
+ module: parts[0],
2322
+ aggregate: parts[1],
2323
+ type: 'aggregate',
2324
+ fullPath: path
2325
+ };
2326
+ }
2327
+ else if (parts.length === 3) {
2328
+ return {
2329
+ module: parts[0],
2330
+ aggregate: parts[1],
2331
+ entity: parts[2],
2332
+ type: 'entity',
2333
+ fullPath: path
2334
+ };
2335
+ }
2336
+ throw new Error(`Invalid domain path format: ${path}. Expected: module, module.aggregate, or module.aggregate.entity`);
2337
+ }
2338
+ //#endregion
2339
+ //#region ---- Loader Management ----
2340
+ /**
2341
+ * Register a domain loader for on-demand loading
2342
+ *
2343
+ * @param loader The loader instance to register
2344
+ */
2345
+ addLoader(loader) {
2346
+ this._loaders.push(loader);
2347
+ // Sort by priority (highest first) after adding
2348
+ this._loaders.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
2349
+ }
2350
+ /**
2351
+ * Load definition from registered loaders using first-wins strategy
2352
+ *
2353
+ * @param path Domain path to load
2354
+ * @param type Type of domain object
2355
+ * @returns Promise that resolves to definition or undefined
2356
+ */
2357
+ async loadFromLoaders(path, type) {
2358
+ for (const loader of this._loaders) {
2359
+ if (loader.canLoad(path, type)) {
2360
+ try {
2361
+ const definition = await loader.load(path, type);
2362
+ if (definition) {
2363
+ console.log(`✓ Loaded ${path} from ${loader.constructor.name}`);
2364
+ return definition; // Return first successful result
2365
+ }
2366
+ }
2367
+ catch (error) {
2368
+ console.warn(`⚠ Loader ${loader.constructor.name} failed for ${path}:`, error);
2369
+ // Continue to next loader instead of throwing
2370
+ }
2371
+ }
2372
+ }
2373
+ return undefined; // No loader could provide the definition
2374
+ }
2375
+ //#endregion
2376
+ //#region ---- Middleware Management ----
2377
+ /**
2378
+ * Add middleware for module processing
2379
+ */
2380
+ addModuleMiddleware(middleware) {
2381
+ this._moduleMiddleware.push(middleware);
2382
+ }
2383
+ /**
2384
+ * Add middleware for aggregate processing
2385
+ */
2386
+ addAggregateMiddleware(middleware) {
2387
+ this._aggregateMiddleware.push(middleware);
2388
+ }
2389
+ /**
2390
+ * Add middleware for entity processing
2391
+ */
2392
+ addEntityMiddleware(middleware) {
2393
+ this._entityMiddleware.push(middleware);
2394
+ }
2395
+ /**
2396
+ * Apply type-specific middleware to definition
2397
+ *
2398
+ * @param definition Raw definition from cache or loader
2399
+ * @param type Type of domain object
2400
+ * @param path Original path for context
2401
+ * @returns Processed definition
2402
+ */
2403
+ async applyTypeMiddleware(definition, type, path) {
2404
+ const middleware = this.getMiddlewareForType(type);
2405
+ if (middleware.length === 0) {
2406
+ return definition; // No middleware to apply
2407
+ }
2408
+ const context = new AXPDomainMiddlewareContext(definition, type);
2409
+ // Apply all middleware for this type
2410
+ for (const mw of middleware) {
2411
+ await mw(context);
2412
+ }
2413
+ return context.definition;
2414
+ }
2415
+ /**
2416
+ * Get middleware collection for specific type
2417
+ *
2418
+ * @param type Domain object type
2419
+ * @returns Array of middleware functions
2420
+ */
2421
+ getMiddlewareForType(type) {
2422
+ switch (type) {
2423
+ case 'module': return this._moduleMiddleware;
2424
+ case 'aggregate': return this._aggregateMiddleware;
2425
+ case 'entity': return this._entityMiddleware;
2426
+ default: return [];
2427
+ }
2428
+ }
2429
+ //#endregion
2430
+ //#region ---- Model Creation ----
2431
+ /**
2432
+ * Create domain model from processed definition
2433
+ *
2434
+ * @param definition Processed definition (after middleware)
2435
+ * @param pathInfo Parsed path information
2436
+ * @returns Created domain model
2437
+ */
2438
+ createModel(definition, pathInfo) {
2439
+ switch (pathInfo.type) {
2440
+ case 'module':
2441
+ return new AXPModuleModel(definition);
2442
+ case 'aggregate':
2443
+ // For aggregate, we need to resolve parent module first
2444
+ // This will be simplified when we refactor the models
2445
+ const moduleDefinition = {
2446
+ name: pathInfo.module,
2447
+ title: pathInfo.module,
2448
+ aggregates: [definition]
2449
+ };
2450
+ const parentModule = new AXPModuleModel(moduleDefinition);
2451
+ return new AXPAggregateModel(definition, parentModule);
2452
+ case 'entity':
2453
+ // For entity, we need both module and aggregate parents
2454
+ // This will be simplified when we refactor the models
2455
+ const entityAggregateDefinition = {
2456
+ name: pathInfo.aggregate,
2457
+ title: pathInfo.aggregate || '',
2458
+ entities: [definition],
2459
+ validations: [],
2460
+ actions: []
2461
+ };
2462
+ const entityModuleDefinition = {
2463
+ name: pathInfo.module,
2464
+ title: pathInfo.module,
2465
+ aggregates: [entityAggregateDefinition]
2466
+ };
2467
+ const entityModule = new AXPModuleModel(entityModuleDefinition);
2468
+ const entityAggregate = new AXPAggregateModel(entityAggregateDefinition, entityModule);
2469
+ return new AXPEntityModel(definition, entityAggregate, this.propertyService);
2470
+ default:
2471
+ throw new Error(`Unknown domain type: ${pathInfo.type}`);
2472
+ }
2473
+ }
2474
+ //#endregion
2475
+ //#region ---- Cache Management ----
2476
+ /**
2477
+ * Clear definition cache for a specific path
2478
+ *
2479
+ * @param path Path to clear from cache
2480
+ */
2481
+ invalidateCache(path) {
2482
+ this._definitionCache.delete(path);
2483
+ }
2484
+ /**
2485
+ * Clear all cached definitions
2486
+ */
2487
+ clearCache() {
2488
+ this._definitionCache.clear();
2489
+ }
2490
+ /**
2491
+ * Get cache statistics
2492
+ */
2493
+ getCacheStats() {
2494
+ return {
2495
+ size: this._definitionCache.size,
2496
+ paths: Array.from(this._definitionCache.keys())
2497
+ };
2498
+ }
2499
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2500
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainRegistry, providedIn: 'root' }); }
2501
+ }
2502
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainRegistry, decorators: [{
2503
+ type: Injectable,
2504
+ args: [{ providedIn: 'root' }]
2505
+ }] });
2506
+
2507
+ //#region ---- Domain Service ----
2508
+ /**
2509
+ * High-level facade service for domain operations.
2510
+ *
2511
+ * Provides simplified interfaces to the domain registry with additional
2512
+ * business logic and convenience methods for common operations.
2513
+ *
2514
+ * This service acts as the main entry point for domain model resolution
2515
+ * and provides a clean API for consuming applications.
2516
+ */
2517
+ class AXPDomainService {
2518
+ constructor() {
2519
+ // Injected dependencies
2520
+ this.registry = inject(AXPDomainRegistry);
2521
+ }
2522
+ //#region ---- Module Operations ----
2523
+ /**
2524
+ * Get module by name
2525
+ *
2526
+ * @param name Module name
2527
+ * @returns Promise that resolves to module model
2528
+ */
2529
+ async getModule(name) {
2530
+ return this.registry.resolve(name);
2531
+ }
2532
+ /**
2533
+ * Check if module exists
2534
+ *
2535
+ * @param name Module name
2536
+ * @returns Promise that resolves to boolean
2537
+ */
2538
+ async moduleExists(name) {
2539
+ try {
2540
+ await this.getModule(name);
2541
+ return true;
2542
+ }
2543
+ catch {
2544
+ return false;
2545
+ }
2546
+ }
2547
+ //#endregion
2548
+ //#region ---- Aggregate Operations ----
2549
+ /**
2550
+ * Get aggregate by module and aggregate names
2551
+ *
2552
+ * @param moduleName Module name
2553
+ * @param aggregateName Aggregate name
2554
+ * @returns Promise that resolves to aggregate model
2555
+ */
2556
+ async getAggregate(moduleName, aggregateName) {
2557
+ const path = `${moduleName}.${aggregateName}`;
2558
+ return this.registry.resolve(path);
2559
+ }
2560
+ /**
2561
+ * Get aggregate by path
2562
+ *
2563
+ * @param path Aggregate path (module.aggregate)
2564
+ * @returns Promise that resolves to aggregate model
2565
+ */
2566
+ async getAggregateByPath(path) {
2567
+ return this.registry.resolve(path);
2568
+ }
2569
+ /**
2570
+ * Check if aggregate exists
2571
+ *
2572
+ * @param moduleName Module name
2573
+ * @param aggregateName Aggregate name
2574
+ * @returns Promise that resolves to boolean
2575
+ */
2576
+ async aggregateExists(moduleName, aggregateName) {
2577
+ try {
2578
+ await this.getAggregate(moduleName, aggregateName);
2579
+ return true;
2580
+ }
2581
+ catch {
2582
+ return false;
2583
+ }
2584
+ }
2585
+ //#endregion
2586
+ //#region ---- Entity Operations ----
2587
+ /**
2588
+ * Get entity by full path
2589
+ *
2590
+ * @param path Full entity path (module.aggregate.entity)
2591
+ * @returns Promise that resolves to entity model
2592
+ */
2593
+ async getEntity(path) {
2594
+ return this.registry.resolve(path);
2595
+ }
2596
+ /**
2597
+ * Get entity by component parts
2598
+ *
2599
+ * @param moduleName Module name
2600
+ * @param aggregateName Aggregate name
2601
+ * @param entityName Entity name
2602
+ * @returns Promise that resolves to entity model
2603
+ */
2604
+ async getEntityByParts(moduleName, aggregateName, entityName) {
2605
+ const path = `${moduleName}.${aggregateName}.${entityName}`;
2606
+ return this.getEntity(path);
2607
+ }
2608
+ /**
2609
+ * Check if entity exists
2610
+ *
2611
+ * @param path Full entity path
2612
+ * @returns Promise that resolves to boolean
2613
+ */
2614
+ async entityExists(path) {
2615
+ try {
2616
+ await this.getEntity(path);
2617
+ return true;
2618
+ }
2619
+ catch {
2620
+ return false;
2621
+ }
2622
+ }
2623
+ //#endregion
2624
+ //#region ---- Batch Operations ----
2625
+ /**
2626
+ * Get multiple modules in parallel
2627
+ *
2628
+ * @param moduleNames Array of module names
2629
+ * @returns Promise that resolves to array of module models
2630
+ */
2631
+ async getModules(moduleNames) {
2632
+ return Promise.all(moduleNames.map(name => this.getModule(name)));
2633
+ }
2634
+ /**
2635
+ * Get multiple aggregates in parallel
2636
+ *
2637
+ * @param aggregatePaths Array of aggregate paths
2638
+ * @returns Promise that resolves to array of aggregate models
2639
+ */
2640
+ async getAggregates(aggregatePaths) {
2641
+ return Promise.all(aggregatePaths.map(path => this.getAggregateByPath(path)));
2642
+ }
2643
+ /**
2644
+ * Get multiple entities in parallel
2645
+ *
2646
+ * @param entityPaths Array of entity paths
2647
+ * @returns Promise that resolves to array of entity models
2648
+ */
2649
+ async getEntities(entityPaths) {
2650
+ return Promise.all(entityPaths.map(path => this.getEntity(path)));
2651
+ }
2652
+ //#endregion
2653
+ //#region ---- Search and Discovery ----
2654
+ /**
2655
+ * Find entities by name across all loaded modules
2656
+ *
2657
+ * @param entityName Entity name to search for
2658
+ * @returns Promise that resolves to array of matching entity paths
2659
+ */
2660
+ async findEntitiesByName(entityName) {
2661
+ // This would require additional registry functionality
2662
+ // For now, return empty array as placeholder
2663
+ return [];
2664
+ }
2665
+ /**
2666
+ * Get all aggregates for a module
2667
+ *
2668
+ * @param moduleName Module name
2669
+ * @returns Promise that resolves to array of aggregate models
2670
+ */
2671
+ async getModuleAggregates(moduleName) {
2672
+ const module = await this.getModule(moduleName);
2673
+ return module.getAllAggregates();
2674
+ }
2675
+ /**
2676
+ * Get all entity references for an aggregate
2677
+ *
2678
+ * @param moduleName Module name
2679
+ * @param aggregateName Aggregate name
2680
+ * @returns Promise that resolves to entity references map
2681
+ */
2682
+ async getAggregateEntityReferences(moduleName, aggregateName) {
2683
+ const aggregate = await this.getAggregate(moduleName, aggregateName);
2684
+ return aggregate.entityReferences;
2685
+ }
2686
+ //#endregion
2687
+ //#region ---- Validation Operations ----
2688
+ /**
2689
+ * Validate module and all its components
2690
+ *
2691
+ * @param moduleName Module name
2692
+ * @returns Promise that resolves to validation errors array
2693
+ */
2694
+ async validateModule(moduleName) {
2695
+ try {
2696
+ const module = await this.getModule(moduleName);
2697
+ return module.validate();
2698
+ }
2699
+ catch (error) {
2700
+ return [`Failed to load module '${moduleName}': ${error instanceof Error ? error.message : 'Unknown error'}`];
2701
+ }
2702
+ }
2703
+ /**
2704
+ * Validate aggregate and its components
2705
+ *
2706
+ * @param moduleName Module name
2707
+ * @param aggregateName Aggregate name
2708
+ * @returns Promise that resolves to validation errors array
2709
+ */
2710
+ async validateAggregate(moduleName, aggregateName) {
2711
+ try {
2712
+ const aggregate = await this.getAggregate(moduleName, aggregateName);
2713
+ return aggregate.validate();
2714
+ }
2715
+ catch (error) {
2716
+ return [`Failed to load aggregate '${moduleName}.${aggregateName}': ${error instanceof Error ? error.message : 'Unknown error'}`];
2717
+ }
2718
+ }
2719
+ //#endregion
2720
+ //#region ---- Utility Operations ----
2721
+ /**
2722
+ * Get statistics for a module
2723
+ *
2724
+ * @param moduleName Module name
2725
+ * @returns Promise that resolves to module statistics
2726
+ */
2727
+ async getModuleStatistics(moduleName) {
2728
+ const module = await this.getModule(moduleName);
2729
+ return module.getStatistics();
2730
+ }
2731
+ /**
2732
+ * Get statistics for an aggregate
2733
+ *
2734
+ * @param moduleName Module name
2735
+ * @param aggregateName Aggregate name
2736
+ * @returns Promise that resolves to aggregate statistics
2737
+ */
2738
+ async getAggregateStatistics(moduleName, aggregateName) {
2739
+ const aggregate = await this.getAggregate(moduleName, aggregateName);
2740
+ return aggregate.getStatistics();
2741
+ }
2742
+ /**
2743
+ * Clear registry cache
2744
+ */
2745
+ clearCache() {
2746
+ this.registry.clearCache();
2747
+ }
2748
+ /**
2749
+ * Get cache statistics
2750
+ *
2751
+ * @returns Cache statistics object
2752
+ */
2753
+ getCacheStatistics() {
2754
+ return this.registry.getCacheStats();
2755
+ }
2756
+ /**
2757
+ * Invalidate cache for specific path
2758
+ *
2759
+ * @param path Domain path to invalidate
2760
+ */
2761
+ invalidateCache(path) {
2762
+ this.registry.invalidateCache(path);
2763
+ }
2764
+ //#endregion
2765
+ //#region ---- Helper Methods ----
2766
+ /**
2767
+ * Parse domain path into components
2768
+ *
2769
+ * @param path Domain path to parse
2770
+ * @returns Parsed path components
2771
+ */
2772
+ parsePath(path) {
2773
+ const parts = path.split('.');
2774
+ if (parts.length === 1) {
2775
+ return { module: parts[0], type: 'module' };
2776
+ }
2777
+ else if (parts.length === 2) {
2778
+ return { module: parts[0], aggregate: parts[1], type: 'aggregate' };
2779
+ }
2780
+ else if (parts.length === 3) {
2781
+ return { module: parts[0], aggregate: parts[1], entity: parts[2], type: 'entity' };
2782
+ }
2783
+ throw new Error(`Invalid domain path format: ${path}`);
2784
+ }
2785
+ /**
2786
+ * Build path from components
2787
+ *
2788
+ * @param module Module name
2789
+ * @param aggregate Aggregate name (optional)
2790
+ * @param entity Entity name (optional)
2791
+ * @returns Built path string
2792
+ */
2793
+ buildPath(module, aggregate, entity) {
2794
+ if (entity && aggregate) {
2795
+ return `${module}.${aggregate}.${entity}`;
2796
+ }
2797
+ else if (aggregate) {
2798
+ return `${module}.${aggregate}`;
2799
+ }
2800
+ else {
2801
+ return module;
2802
+ }
2803
+ }
2804
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2805
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainService, providedIn: 'root' }); }
2806
+ }
2807
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: AXPDomainService, decorators: [{
2808
+ type: Injectable,
2809
+ args: [{ providedIn: 'root' }]
2810
+ }] });
2811
+
2812
+ //#endregion
2813
+
2814
+ //#endregion
2815
+ //#region ---- Provider Functions ----
2816
+ /**
2817
+ * Provide domain loaders for on-demand domain loading.
2818
+ *
2819
+ * Domain loaders enable the registry to load domain definitions that are not registered
2820
+ * at build time. This is useful for:
2821
+ * - Loading domain definitions from external APIs
2822
+ * - Dynamic domain generation
2823
+ * - Lazy loading of large domain sets
2824
+ * - Development-time domain hot-reloading
2825
+ *
2826
+ * @param loaders Array of loader classes, instances, or loader configurations
2827
+ * @returns Environment providers for dependency injection
2828
+ *
2829
+ * @example
2830
+ * ```typescript
2831
+ * // Simple loader registration
2832
+ * provideDomainLoaders([
2833
+ * HttpDomainLoader,
2834
+ * FileSystemDomainLoader,
2835
+ * new MemoryDomainLoader()
2836
+ * ])
2837
+ *
2838
+ * // With priority configuration
2839
+ * provideDomainLoaders([
2840
+ * { loader: HttpDomainLoader, priority: 10 },
2841
+ * { loader: FileSystemDomainLoader, priority: 5 },
2842
+ * { loader: new MemoryDomainLoader(), priority: 15 }
2843
+ * ])
2844
+ * ```
2845
+ */
2846
+ function provideDomainLoaders(loaders) {
2847
+ return makeEnvironmentProviders([
2848
+ {
2849
+ provide: AXP_DOMAIN_LOADER_SETUP,
2850
+ useFactory: async () => {
2851
+ const registry = inject(AXPDomainRegistry);
2852
+ if (!registry) {
2853
+ console.warn('Domain registry not available during loader setup');
2854
+ return false;
2855
+ }
2856
+ // Register each loader with the registry
2857
+ for (const loaderConfig of loaders) {
2858
+ try {
2859
+ let loaderInstance;
2860
+ let priority;
2861
+ if (typeof loaderConfig === 'function') {
2862
+ // Type<AXPDomainLoader>
2863
+ loaderInstance = new loaderConfig();
2864
+ priority = loaderInstance.priority;
2865
+ }
2866
+ else if (typeof loaderConfig === 'object' && 'canLoad' in loaderConfig) {
2867
+ // AXPDomainLoader instance
2868
+ loaderInstance = loaderConfig;
2869
+ priority = loaderInstance.priority;
2870
+ }
2871
+ else if (typeof loaderConfig === 'object' && 'loader' in loaderConfig) {
2872
+ // AXPDomainLoaderConfig
2873
+ if (typeof loaderConfig.loader === 'function') {
2874
+ loaderInstance = new loaderConfig.loader();
2875
+ }
2876
+ else {
2877
+ loaderInstance = loaderConfig.loader;
2878
+ }
2879
+ priority = loaderConfig.priority ?? loaderInstance.priority;
2880
+ }
2881
+ else {
2882
+ console.warn('Invalid loader configuration:', loaderConfig);
2883
+ continue;
2884
+ }
2885
+ // Apply custom priority if specified
2886
+ if (priority !== undefined && priority !== loaderInstance.priority) {
2887
+ loaderInstance.priority = priority;
2888
+ }
2889
+ registry.addLoader(loaderInstance);
2890
+ console.log(`✓ Registered domain loader: ${loaderInstance.constructor.name} (priority: ${loaderInstance.priority ?? 0})`);
2891
+ }
2892
+ catch (error) {
2893
+ console.error('Failed to register domain loader:', error);
2894
+ }
2895
+ }
2896
+ return true;
2897
+ },
2898
+ multi: true
2899
+ }
2900
+ ]);
2901
+ }
2902
+ /**
2903
+ * Provide a single domain loader for convenience
2904
+ *
2905
+ * @param loader Loader class, instance, or configuration
2906
+ * @returns Environment providers for dependency injection
2907
+ */
2908
+ function provideDomainLoader(loader) {
2909
+ return provideDomainLoaders([loader]);
2910
+ }
2911
+ //#endregion
2912
+
2913
+ //#region ---- Injection Tokens ----
2914
+ /**
2915
+ * Injection tokens for type-specific middleware setup
2916
+ */
2917
+ const AXP_MODULE_MIDDLEWARE_SETUP = 'AXP_MODULE_MIDDLEWARE_SETUP';
2918
+ const AXP_AGGREGATE_MIDDLEWARE_SETUP = 'AXP_AGGREGATE_MIDDLEWARE_SETUP';
2919
+ const AXP_ENTITY_MIDDLEWARE_SETUP = 'AXP_ENTITY_MIDDLEWARE_SETUP';
2920
+ //#endregion
2921
+ //#region ---- Provider Functions ----
2922
+ /**
2923
+ * Provide middleware for module processing.
2924
+ *
2925
+ * Module middleware is applied when resolving module definitions and can:
2926
+ * - Add metadata and custom properties
2927
+ * - Validate module structure
2928
+ * - Transform module definitions
2929
+ * - Add computed properties
2930
+ *
2931
+ * @param middleware Array of middleware functions to register
2932
+ * @returns Environment providers for dependency injection
2933
+ *
2934
+ * @example
2935
+ * ```typescript
2936
+ * provideModuleMiddleware([
2937
+ * (context) => {
2938
+ * // Add common module metadata
2939
+ * context.setMetadata('loadedAt', new Date());
2940
+ * context.setMetadata('version', '1.0.0');
2941
+ * },
2942
+ * (context) => {
2943
+ * // Add namespace prefix if not present
2944
+ * if (!context.definition.name.includes('.')) {
2945
+ * context.definition.name = `app.${context.definition.name}`;
2946
+ * }
2947
+ * }
2948
+ * ])
2949
+ * ```
2950
+ */
2951
+ function provideModuleMiddleware(middleware) {
2952
+ return makeEnvironmentProviders([
2953
+ {
2954
+ provide: AXP_MODULE_MIDDLEWARE_SETUP,
2955
+ useFactory: () => {
2956
+ // Access registry through DI when available
2957
+ const registry = globalThis.__domainRegistry__;
2958
+ if (!registry) {
2959
+ console.warn('Domain registry not available during module middleware setup');
2960
+ return false;
2961
+ }
2962
+ // Register all module middleware
2963
+ for (const mw of middleware) {
2964
+ registry.addModuleMiddleware(mw);
2965
+ }
2966
+ console.log(`✓ Registered ${middleware.length} module middleware functions`);
2967
+ return true;
2968
+ },
2969
+ multi: true
2970
+ }
2971
+ ]);
2972
+ }
2973
+ /**
2974
+ * Provide middleware for aggregate processing.
2975
+ *
2976
+ * Aggregate middleware is applied when resolving aggregate definitions and can:
2977
+ * - Add metadata and custom properties
2978
+ * - Validate aggregate structure
2979
+ * - Transform entity references
2980
+ * - Add computed relations
2981
+ *
2982
+ * @param middleware Array of middleware functions to register
2983
+ * @returns Environment providers for dependency injection
2984
+ *
2985
+ * @example
2986
+ * ```typescript
2987
+ * provideAggregateMiddleware([
2988
+ * (context) => {
2989
+ * // Add aggregate metadata
2990
+ * context.setMetadata('type', 'business-aggregate');
2991
+ * },
2992
+ * (context) => {
2993
+ * // Validate entity references
2994
+ * const entities = context.definition.entities;
2995
+ * if (Object.keys(entities).length === 0) {
2996
+ * throw new Error('Aggregate must have at least one entity');
2997
+ * }
2998
+ * }
2999
+ * ])
3000
+ * ```
3001
+ */
3002
+ function provideAggregateMiddleware(middleware) {
3003
+ return makeEnvironmentProviders([
3004
+ {
3005
+ provide: AXP_AGGREGATE_MIDDLEWARE_SETUP,
3006
+ useFactory: () => {
3007
+ // Access registry through DI when available
3008
+ const registry = globalThis.__domainRegistry__;
3009
+ if (!registry) {
3010
+ console.warn('Domain registry not available during aggregate middleware setup');
3011
+ return false;
3012
+ }
3013
+ // Register all aggregate middleware
3014
+ for (const mw of middleware) {
3015
+ registry.addAggregateMiddleware(mw);
3016
+ }
3017
+ console.log(`✓ Registered ${middleware.length} aggregate middleware functions`);
3018
+ return true;
3019
+ },
3020
+ multi: true
3021
+ }
3022
+ ]);
3023
+ }
3024
+ /**
3025
+ * Provide middleware for entity processing.
3026
+ *
3027
+ * Entity middleware is applied when resolving entity definitions and can:
3028
+ * - Add auto-generated fields (id, timestamps)
3029
+ * - Apply field transformations
3030
+ * - Add validation rules
3031
+ * - Set default values
3032
+ *
3033
+ * @param middleware Array of middleware functions to register
3034
+ * @returns Environment providers for dependency injection
3035
+ *
3036
+ * @example
3037
+ * ```typescript
3038
+ * provideEntityMiddleware([
3039
+ * (context) => {
3040
+ * // Add auto-generated ID field if not present
3041
+ * if (!context.definition.fields.some(f => f.name === 'id')) {
3042
+ * context.addField({
3043
+ * name: 'id',
3044
+ * type: 'uuid',
3045
+ * required: true,
3046
+ * generated: true
3047
+ * });
3048
+ * }
3049
+ * },
3050
+ * (context) => {
3051
+ * // Add timestamp fields
3052
+ * context.addField({
3053
+ * name: 'createdAt',
3054
+ * type: 'datetime',
3055
+ * required: true,
3056
+ * generated: true
3057
+ * });
3058
+ * context.addField({
3059
+ * name: 'updatedAt',
3060
+ * type: 'datetime',
3061
+ * required: true,
3062
+ * generated: true
3063
+ * });
3064
+ * }
3065
+ * ])
3066
+ * ```
3067
+ */
3068
+ function provideEntityMiddleware(middleware) {
3069
+ return makeEnvironmentProviders([
3070
+ {
3071
+ provide: AXP_ENTITY_MIDDLEWARE_SETUP,
3072
+ useFactory: () => {
3073
+ // Access registry through DI when available
3074
+ const registry = globalThis.__domainRegistry__;
3075
+ if (!registry) {
3076
+ console.warn('Domain registry not available during entity middleware setup');
3077
+ return false;
3078
+ }
3079
+ // Register all entity middleware
3080
+ for (const mw of middleware) {
3081
+ registry.addEntityMiddleware(mw);
3082
+ }
3083
+ console.log(`✓ Registered ${middleware.length} entity middleware functions`);
3084
+ return true;
3085
+ },
3086
+ multi: true
3087
+ }
3088
+ ]);
3089
+ }
3090
+ /**
3091
+ * Provide combined middleware for all domain types.
3092
+ *
3093
+ * This is a convenience function that allows registering middleware for multiple
3094
+ * domain types in a single call.
3095
+ *
3096
+ * @param config Configuration object with middleware for each type
3097
+ * @returns Environment providers for dependency injection
3098
+ *
3099
+ * @example
3100
+ * ```typescript
3101
+ * provideDomainMiddleware({
3102
+ * modules: [
3103
+ * (context) => context.setMetadata('loadedAt', new Date())
3104
+ * ],
3105
+ * aggregates: [
3106
+ * (context) => context.setMetadata('type', 'business-aggregate')
3107
+ * ],
3108
+ * entities: [
3109
+ * (context) => {
3110
+ * if (!context.definition.fields.some(f => f.name === 'id')) {
3111
+ * context.addField({ name: 'id', type: 'uuid', required: true });
3112
+ * }
3113
+ * }
3114
+ * ]
3115
+ * })
3116
+ * ```
3117
+ */
3118
+ function provideDomainMiddleware(config) {
3119
+ const allProviders = [];
3120
+ // Add module middleware providers
3121
+ if (config.modules && config.modules.length > 0) {
3122
+ allProviders.push({
3123
+ provide: AXP_MODULE_MIDDLEWARE_SETUP,
3124
+ useFactory: () => {
3125
+ const registry = globalThis.__domainRegistry__;
3126
+ if (!registry) {
3127
+ console.warn('Domain registry not available during module middleware setup');
3128
+ return false;
3129
+ }
3130
+ for (const mw of config.modules) {
3131
+ registry.addModuleMiddleware(mw);
3132
+ }
3133
+ return true;
3134
+ },
3135
+ multi: true
3136
+ });
3137
+ }
3138
+ // Add aggregate middleware providers
3139
+ if (config.aggregates && config.aggregates.length > 0) {
3140
+ allProviders.push({
3141
+ provide: AXP_AGGREGATE_MIDDLEWARE_SETUP,
3142
+ useFactory: () => {
3143
+ const registry = globalThis.__domainRegistry__;
3144
+ if (!registry) {
3145
+ console.warn('Domain registry not available during aggregate middleware setup');
3146
+ return false;
3147
+ }
3148
+ for (const mw of config.aggregates) {
3149
+ registry.addAggregateMiddleware(mw);
3150
+ }
3151
+ return true;
3152
+ },
3153
+ multi: true
3154
+ });
3155
+ }
3156
+ // Add entity middleware providers
3157
+ if (config.entities && config.entities.length > 0) {
3158
+ allProviders.push({
3159
+ provide: AXP_ENTITY_MIDDLEWARE_SETUP,
3160
+ useFactory: () => {
3161
+ const registry = globalThis.__domainRegistry__;
3162
+ if (!registry) {
3163
+ console.warn('Domain registry not available during entity middleware setup');
3164
+ return false;
3165
+ }
3166
+ for (const mw of config.entities) {
3167
+ registry.addEntityMiddleware(mw);
3168
+ }
3169
+ return true;
3170
+ },
3171
+ multi: true
3172
+ });
3173
+ }
3174
+ return makeEnvironmentProviders(allProviders);
3175
+ }
3176
+ //#endregion
3177
+
3178
+ //#region ---- Core Registry System ----
3179
+ // Main registry and service
3180
+ //#endregion
3181
+
3182
+ //#endregion
3183
+
3184
+ /**
3185
+ * Generated bundle index. Do not edit.
3186
+ */
3187
+
3188
+ export { AXPAggregateModel, AXPDomainMiddlewareContext, AXPDomainModule, AXPDomainRegistry, AXPDomainService, AXPEntityFieldModel, AXPEntityModel, AXPModuleHelper, AXPModuleModel, AXPPropertyMiddlewareContext, AXPPropertyModel, AXPPropertyRegistry, AXPPropertyService, AXPRelationModel, AXP_AGGREGATE_MIDDLEWARE_SETUP, AXP_ENTITY_CRUD_SETUP, AXP_ENTITY_DEFINITION_CRUD_SERVICE, AXP_ENTITY_MIDDLEWARE_SETUP, AXP_MODULE_MIDDLEWARE_SETUP, AXP_PROPERTY_EXTENSION, AXP_PROPERTY_LOADER_SETUP, AXP_PROPERTY_MIDDLEWARE_SETUP, AXP_PROPERTY_SETUP, provideAggregateMiddleware, provideDomainLoader, provideDomainLoaders, provideDomainMiddleware, provideEntityMiddleware, provideModuleMiddleware, providePropertiesFromFactory, provideProperty, providePropertyLoaders, providePropertyMiddleware, providePropertySetups, toPropertyDefinition };
3189
+ //# sourceMappingURL=acorex-platform-framework-client-domain.mjs.map