@quazardous/qdadm 1.19.3

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 (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/package.json +101 -0
  4. package/src/assets/logo.svg +6 -0
  5. package/src/auth/SessionAuthAdapter.ts +459 -0
  6. package/src/auth/index.ts +15 -0
  7. package/src/chain/ActiveStack.ts +154 -0
  8. package/src/chain/StackHydrator.ts +292 -0
  9. package/src/chain/index.ts +25 -0
  10. package/src/chain/useActiveStack.ts +120 -0
  11. package/src/chain/useStackHydrator.ts +155 -0
  12. package/src/components/BoolCell.vue +34 -0
  13. package/src/components/InfoBanner.vue +73 -0
  14. package/src/components/QdadmRoot.vue +52 -0
  15. package/src/components/SeverityTag.vue +86 -0
  16. package/src/components/dialogs/BulkStatusDialog.vue +60 -0
  17. package/src/components/dialogs/MultiStepDialog.vue +331 -0
  18. package/src/components/dialogs/SimpleDialog.vue +122 -0
  19. package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
  20. package/src/components/display/BannerZone.vue +65 -0
  21. package/src/components/display/CardsGrid.vue +72 -0
  22. package/src/components/display/CopyableId.vue +84 -0
  23. package/src/components/display/EmptyState.vue +62 -0
  24. package/src/components/display/IntensityBar.vue +190 -0
  25. package/src/components/display/RichCardsGrid.vue +101 -0
  26. package/src/components/edit/FormActions.vue +78 -0
  27. package/src/components/edit/FormField.vue +82 -0
  28. package/src/components/edit/FormInput.vue +158 -0
  29. package/src/components/edit/FormPage.vue +260 -0
  30. package/src/components/edit/FormTab.vue +217 -0
  31. package/src/components/edit/FormTabs.vue +120 -0
  32. package/src/components/edit/LookupField.vue +406 -0
  33. package/src/components/edit/LookupPickerDialog.vue +230 -0
  34. package/src/components/editors/JsonEditorFoldable.vue +470 -0
  35. package/src/components/editors/JsonStructuredField.vue +264 -0
  36. package/src/components/editors/JsonViewer.vue +51 -0
  37. package/src/components/editors/KeyValueEditor.vue +314 -0
  38. package/src/components/editors/LanguageEditor.vue +259 -0
  39. package/src/components/editors/PermissionEditor.vue +558 -0
  40. package/src/components/editors/ScopeEditor.vue +372 -0
  41. package/src/components/editors/VanillaJsonEditor.vue +183 -0
  42. package/src/components/index.ts +83 -0
  43. package/src/components/item/FieldGroups.vue +392 -0
  44. package/src/components/layout/AppLayout.vue +1032 -0
  45. package/src/components/layout/BaseLayout.vue +190 -0
  46. package/src/components/layout/Breadcrumb.vue +55 -0
  47. package/src/components/layout/DashboardLayout.vue +104 -0
  48. package/src/components/layout/FormLayout.vue +256 -0
  49. package/src/components/layout/ListLayout.vue +278 -0
  50. package/src/components/layout/PageHeader.vue +156 -0
  51. package/src/components/layout/PageLayout.vue +126 -0
  52. package/src/components/layout/PageNav.vue +192 -0
  53. package/src/components/layout/SidebarBox.vue +87 -0
  54. package/src/components/layout/Zone.vue +182 -0
  55. package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
  56. package/src/components/layout/defaults/DefaultFooter.vue +89 -0
  57. package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
  58. package/src/components/layout/defaults/DefaultHeader.vue +78 -0
  59. package/src/components/layout/defaults/DefaultMenu.vue +188 -0
  60. package/src/components/layout/defaults/DefaultPagination.vue +75 -0
  61. package/src/components/layout/defaults/DefaultTable.vue +137 -0
  62. package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
  63. package/src/components/layout/defaults/index.ts +16 -0
  64. package/src/components/lists/ActionButtons.vue +49 -0
  65. package/src/components/lists/ActionColumn.vue +40 -0
  66. package/src/components/lists/FilterBar.vue +54 -0
  67. package/src/components/lists/ListPage.vue +467 -0
  68. package/src/components/pages/LoginPage.vue +334 -0
  69. package/src/components/pages/NotFoundPage.vue +98 -0
  70. package/src/components/show/ShowDisplay.vue +343 -0
  71. package/src/components/show/ShowField.vue +67 -0
  72. package/src/components/show/ShowPage.vue +431 -0
  73. package/src/composables/index.ts +155 -0
  74. package/src/composables/useApp.ts +67 -0
  75. package/src/composables/useAuth.ts +98 -0
  76. package/src/composables/useBareForm.ts +319 -0
  77. package/src/composables/useBreadcrumb.ts +252 -0
  78. package/src/composables/useChildPage.ts +113 -0
  79. package/src/composables/useCurrentEntity.ts +60 -0
  80. package/src/composables/useDeferred.ts +94 -0
  81. package/src/composables/useDirtyState.ts +138 -0
  82. package/src/composables/useEntityItemFormPage.ts +942 -0
  83. package/src/composables/useEntityItemFormPage.types.ts +451 -0
  84. package/src/composables/useEntityItemPage.ts +438 -0
  85. package/src/composables/useEntityItemShowPage.ts +722 -0
  86. package/src/composables/useFieldManager.ts +692 -0
  87. package/src/composables/useForm.ts +544 -0
  88. package/src/composables/useGuardStore.ts +53 -0
  89. package/src/composables/useHooks.ts +56 -0
  90. package/src/composables/useInfoBanner.ts +217 -0
  91. package/src/composables/useJsonSyntax.ts +122 -0
  92. package/src/composables/useLayoutResolver.ts +329 -0
  93. package/src/composables/useListPage.ts +1535 -0
  94. package/src/composables/useListPage.types.ts +437 -0
  95. package/src/composables/useListPage.utils.ts +101 -0
  96. package/src/composables/useNavContext.ts +439 -0
  97. package/src/composables/useNavigation.ts +216 -0
  98. package/src/composables/useOptionsLookup.ts +323 -0
  99. package/src/composables/usePageTitle.ts +84 -0
  100. package/src/composables/useSSEBridge.ts +142 -0
  101. package/src/composables/useSemanticBreadcrumb.ts +222 -0
  102. package/src/composables/useSidebarState.ts +24 -0
  103. package/src/composables/useSignals.ts +52 -0
  104. package/src/composables/useUnsavedChangesGuard.ts +155 -0
  105. package/src/composables/useUserImpersonator.ts +317 -0
  106. package/src/composables/useZoneRegistry.ts +252 -0
  107. package/src/core/bundles.ts +558 -0
  108. package/src/core/decorator.ts +420 -0
  109. package/src/core/extension.ts +470 -0
  110. package/src/core/index.ts +59 -0
  111. package/src/deferred/DeferredRegistry.ts +353 -0
  112. package/src/deferred/index.ts +15 -0
  113. package/src/editors/index.ts +12 -0
  114. package/src/entity/EntityManager.cache.ts +530 -0
  115. package/src/entity/EntityManager.crud.ts +615 -0
  116. package/src/entity/EntityManager.interface.ts +78 -0
  117. package/src/entity/EntityManager.query.ts +221 -0
  118. package/src/entity/EntityManager.relations.ts +151 -0
  119. package/src/entity/EntityManager.ts +944 -0
  120. package/src/entity/EntityManager.types.ts +288 -0
  121. package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
  122. package/src/entity/auth/EntityAuthAdapter.ts +119 -0
  123. package/src/entity/auth/PermissiveAdapter.ts +43 -0
  124. package/src/entity/auth/RoleHierarchy.ts +128 -0
  125. package/src/entity/auth/SecurityChecker.ts +202 -0
  126. package/src/entity/auth/factory.ts +203 -0
  127. package/src/entity/auth/index.ts +47 -0
  128. package/src/entity/factory.test.js +189 -0
  129. package/src/entity/factory.ts +146 -0
  130. package/src/entity/index.ts +49 -0
  131. package/src/entity/storage/ApiStorage.ts +228 -0
  132. package/src/entity/storage/IStorage.ts +100 -0
  133. package/src/entity/storage/LocalStorage.ts +200 -0
  134. package/src/entity/storage/MemoryStorage.ts +184 -0
  135. package/src/entity/storage/MockApiStorage.ts +318 -0
  136. package/src/entity/storage/SdkStorage.ts +377 -0
  137. package/src/entity/storage/factory.test.js +159 -0
  138. package/src/entity/storage/factory.ts +209 -0
  139. package/src/entity/storage/index.ts +75 -0
  140. package/src/gen/FieldMapper.ts +122 -0
  141. package/src/gen/StorageProfileFactory.ts +93 -0
  142. package/src/gen/connectors/BaseConnector.ts +150 -0
  143. package/src/gen/connectors/ManualConnector.test.js +499 -0
  144. package/src/gen/connectors/ManualConnector.ts +414 -0
  145. package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
  146. package/src/gen/connectors/OpenAPIConnector.ts +693 -0
  147. package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
  148. package/src/gen/connectors/index.ts +27 -0
  149. package/src/gen/createManagers.ts +245 -0
  150. package/src/gen/decorators.ts +134 -0
  151. package/src/gen/generateManagers.test.js +540 -0
  152. package/src/gen/generateManagers.ts +398 -0
  153. package/src/gen/index.ts +66 -0
  154. package/src/gen/schema.ts +248 -0
  155. package/src/gen/vite-plugin.ts +114 -0
  156. package/src/generated/managers/testManager.js +45 -0
  157. package/src/generated/managers/testManager.ts +46 -0
  158. package/src/hooks/HookRegistry.ts +16 -0
  159. package/src/hooks/index.ts +15 -0
  160. package/src/i18n/I18n.ts +344 -0
  161. package/src/i18n/IncrementalDomainProvider.ts +153 -0
  162. package/src/i18n/InlineTranslationProvider.ts +4 -0
  163. package/src/i18n/LazyTranslationProvider.ts +102 -0
  164. package/src/i18n/MessagesRegistry.ts +4 -0
  165. package/src/i18n/Resolver.ts +4 -0
  166. package/src/i18n/__tests__/I18n.test.ts +169 -0
  167. package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
  168. package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
  169. package/src/i18n/__tests__/Resolver.test.ts +271 -0
  170. package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
  171. package/src/i18n/defaults/core.en.yml +55 -0
  172. package/src/i18n/defaults/core.fr.yml +55 -0
  173. package/src/i18n/index.ts +55 -0
  174. package/src/i18n/loaders/raw-modules.d.ts +15 -0
  175. package/src/i18n/loaders/yaml.ts +35 -0
  176. package/src/i18n/strategies.ts +4 -0
  177. package/src/i18n/types.ts +34 -0
  178. package/src/i18n/useI18n.ts +34 -0
  179. package/src/index.ts +453 -0
  180. package/src/kernel/EventRouter.ts +23 -0
  181. package/src/kernel/Kernel.api.ts +79 -0
  182. package/src/kernel/Kernel.auth.ts +120 -0
  183. package/src/kernel/Kernel.i18n.ts +29 -0
  184. package/src/kernel/Kernel.modules.ts +170 -0
  185. package/src/kernel/Kernel.registries.ts +237 -0
  186. package/src/kernel/Kernel.routing.ts +334 -0
  187. package/src/kernel/Kernel.ts +460 -0
  188. package/src/kernel/Kernel.types.ts +263 -0
  189. package/src/kernel/Kernel.vue.ts +304 -0
  190. package/src/kernel/KernelContext.entities.ts +80 -0
  191. package/src/kernel/KernelContext.events.ts +57 -0
  192. package/src/kernel/KernelContext.i18n.ts +37 -0
  193. package/src/kernel/KernelContext.permissions.ts +38 -0
  194. package/src/kernel/KernelContext.routing.ts +280 -0
  195. package/src/kernel/KernelContext.ts +252 -0
  196. package/src/kernel/KernelContext.types.ts +173 -0
  197. package/src/kernel/KernelContext.zones.ts +54 -0
  198. package/src/kernel/Module.ts +169 -0
  199. package/src/kernel/ModuleLoader.ts +645 -0
  200. package/src/kernel/SSEBridge.ts +11 -0
  201. package/src/kernel/SignalBus.ts +48 -0
  202. package/src/kernel/index.ts +56 -0
  203. package/src/module/index.ts +33 -0
  204. package/src/module/moduleRegistry.ts +492 -0
  205. package/src/modules/debug/AuthCollector.ts +501 -0
  206. package/src/modules/debug/Collector.ts +20 -0
  207. package/src/modules/debug/DebugBridge.ts +14 -0
  208. package/src/modules/debug/DebugModule.ts +220 -0
  209. package/src/modules/debug/EntitiesCollector.ts +839 -0
  210. package/src/modules/debug/ErrorCollector.ts +4 -0
  211. package/src/modules/debug/I18nCollector.ts +9 -0
  212. package/src/modules/debug/LocalStorageAdapter.ts +7 -0
  213. package/src/modules/debug/RouterCollector.ts +449 -0
  214. package/src/modules/debug/SignalCollector.ts +4 -0
  215. package/src/modules/debug/ToastCollector.ts +4 -0
  216. package/src/modules/debug/ZonesCollector.ts +447 -0
  217. package/src/modules/debug/components/DebugBar.vue +31 -0
  218. package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
  219. package/src/modules/debug/components/index.ts +9 -0
  220. package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
  221. package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
  222. package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
  223. package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
  224. package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
  225. package/src/modules/debug/components/panels/index.ts +16 -0
  226. package/src/modules/debug/index.ts +58 -0
  227. package/src/modules/debug/styles.scss +2671 -0
  228. package/src/notifications/NotificationBadge.vue +35 -0
  229. package/src/notifications/NotificationListener.vue +71 -0
  230. package/src/notifications/NotificationModule.ts +76 -0
  231. package/src/notifications/NotificationPanel.vue +478 -0
  232. package/src/notifications/NotificationStore.ts +288 -0
  233. package/src/notifications/index.ts +42 -0
  234. package/src/notifications/styles.scss +32 -0
  235. package/src/orchestrator/Orchestrator.ts +427 -0
  236. package/src/orchestrator/index.ts +8 -0
  237. package/src/orchestrator/useOrchestrator.ts +80 -0
  238. package/src/plugin.ts +251 -0
  239. package/src/query/FilterQuery.ts +306 -0
  240. package/src/query/QueryExecutor.ts +341 -0
  241. package/src/query/index.ts +16 -0
  242. package/src/security/EntityRolesProvider.ts +385 -0
  243. package/src/security/PermissionMatcher.ts +152 -0
  244. package/src/security/PermissionRegistry.ts +273 -0
  245. package/src/security/PersistableRolesProvider.ts +584 -0
  246. package/src/security/RolesManager.ts +136 -0
  247. package/src/security/RolesProvider.ts +167 -0
  248. package/src/security/RolesProviderStorage.ts +211 -0
  249. package/src/security/SecurityModule.ts +94 -0
  250. package/src/security/StaticRolesProvider.ts +117 -0
  251. package/src/security/UsersManager.ts +163 -0
  252. package/src/security/index.ts +77 -0
  253. package/src/security/pages/RoleForm.vue +276 -0
  254. package/src/security/pages/RoleList.vue +123 -0
  255. package/src/styles/_alerts.scss +95 -0
  256. package/src/styles/_buttons.scss +391 -0
  257. package/src/styles/_cards.scss +241 -0
  258. package/src/styles/_code.scss +78 -0
  259. package/src/styles/_dialogs.scss +55 -0
  260. package/src/styles/_filter-bar.scss +70 -0
  261. package/src/styles/_forms.scss +434 -0
  262. package/src/styles/_helpers.scss +153 -0
  263. package/src/styles/_lists.scss +225 -0
  264. package/src/styles/_main.scss +356 -0
  265. package/src/styles/_markdown.scss +88 -0
  266. package/src/styles/_responsive.scss +255 -0
  267. package/src/styles/_show-pages.scss +186 -0
  268. package/src/styles/_sidebar.scss +380 -0
  269. package/src/styles/_states.scss +115 -0
  270. package/src/styles/_stats.scss +47 -0
  271. package/src/styles/_variables.scss +224 -0
  272. package/src/styles/index.scss +38 -0
  273. package/src/styles/theme/_components.scss +331 -0
  274. package/src/styles/theme/_index.scss +10 -0
  275. package/src/styles/theme/_tokens.scss +147 -0
  276. package/src/styles/theme/_utilities.scss +175 -0
  277. package/src/toast/ToastBridgeModule.ts +68 -0
  278. package/src/toast/ToastListener.vue +55 -0
  279. package/src/toast/index.ts +26 -0
  280. package/src/toast/useSignalToast.ts +154 -0
  281. package/src/types/index.ts +285 -0
  282. package/src/types/pluralize.d.ts +19 -0
  283. package/src/types/quarkernel.d.ts +50 -0
  284. package/src/utils/formatters.ts +174 -0
  285. package/src/utils/index.ts +35 -0
  286. package/src/utils/transformers.ts +131 -0
  287. package/src/vite/qdadmDebugPlugin.ts +401 -0
  288. package/src/vite-env.d.ts +50 -0
  289. package/src/zones/ZoneRegistry.ts +934 -0
  290. package/src/zones/index.ts +29 -0
  291. package/src/zones/zones.ts +191 -0
@@ -0,0 +1,414 @@
1
+ /**
2
+ * Manual Connector
3
+ *
4
+ * Parses inline entity/field definitions into UnifiedEntitySchema format.
5
+ * Used when schemas are defined directly in configuration rather than
6
+ * extracted from OpenAPI specs or other sources.
7
+ *
8
+ * @module gen/connectors/ManualConnector
9
+ */
10
+
11
+ import { BaseConnector, type ConnectorOptions, type ParseResult, type ParseWarning } from './BaseConnector'
12
+ import {
13
+ UNIFIED_FIELD_TYPES,
14
+ isValidFieldType,
15
+ type UnifiedEntitySchema,
16
+ type UnifiedFieldSchema,
17
+ type UnifiedFieldReference,
18
+ type UnifiedFieldType,
19
+ } from '../schema'
20
+
21
+ /**
22
+ * Manual field definition input
23
+ */
24
+ export interface ManualFieldInput {
25
+ /** Field name (required) */
26
+ name: string
27
+ /** Field type (required, must be valid UnifiedFieldType) */
28
+ type: string
29
+ /** Human-readable label */
30
+ label?: string
31
+ /** Whether field is required */
32
+ required?: boolean
33
+ /** Whether field is read-only */
34
+ readOnly?: boolean
35
+ /** Whether field should be hidden in UI */
36
+ hidden?: boolean
37
+ /** Original format hint */
38
+ format?: string
39
+ /** Allowed values for enumeration */
40
+ enum?: string[]
41
+ /** Default value */
42
+ default?: unknown
43
+ /** Relation to another entity */
44
+ reference?: UnifiedFieldReference
45
+ /** Project-specific extensions */
46
+ extensions?: Record<string, unknown>
47
+ }
48
+
49
+ /**
50
+ * Manual entity definition input
51
+ */
52
+ export interface ManualEntityInput {
53
+ /** Entity name (required) */
54
+ name: string
55
+ /** API endpoint path (required) */
56
+ endpoint: string
57
+ /** Human-readable singular label */
58
+ label?: string
59
+ /** Human-readable plural label */
60
+ labelPlural?: string
61
+ /** Field used as display label */
62
+ labelField?: string
63
+ /** Route prefix for admin UI */
64
+ routePrefix?: string
65
+ /** Primary key field name */
66
+ idField?: string
67
+ /** Whether entity is read-only */
68
+ readOnly?: boolean
69
+ /** Field definitions */
70
+ fields?: Record<string, ManualFieldInput>
71
+ /** Project-specific extensions */
72
+ extensions?: Record<string, unknown>
73
+ }
74
+
75
+ /**
76
+ * Manual source input - array of entities or single entity
77
+ */
78
+ export type ManualSourceInput =
79
+ | ManualEntityInput[]
80
+ | ManualEntityInput
81
+ | { entities: ManualEntityInput[] }
82
+
83
+ /**
84
+ * Manual Connector for parsing inline entity/field definitions.
85
+ *
86
+ * Accepts entity definitions in various formats:
87
+ * - Single entity object
88
+ * - Array of entity objects
89
+ * - Object with `entities` array
90
+ *
91
+ * @extends BaseConnector
92
+ *
93
+ * @example
94
+ * // Parse a single entity
95
+ * const connector = new ManualConnector()
96
+ * const schemas = connector.parse({
97
+ * name: 'users',
98
+ * endpoint: '/api/users',
99
+ * fields: {
100
+ * id: { name: 'id', type: 'number', readOnly: true },
101
+ * email: { name: 'email', type: 'email', required: true }
102
+ * }
103
+ * })
104
+ *
105
+ * @example
106
+ * // Parse multiple entities
107
+ * const schemas = connector.parse([
108
+ * { name: 'users', endpoint: '/api/users', fields: { ... } },
109
+ * { name: 'posts', endpoint: '/api/posts', fields: { ... } }
110
+ * ])
111
+ *
112
+ * @example
113
+ * // Strict mode throws on validation errors
114
+ * const connector = new ManualConnector({ strict: true })
115
+ * connector.parse({ name: 'users' }) // throws: missing 'endpoint'
116
+ */
117
+ export class ManualConnector extends BaseConnector {
118
+ constructor(options: ConnectorOptions = {}) {
119
+ super(options)
120
+ }
121
+
122
+ /**
123
+ * Parse manual entity definitions into UnifiedEntitySchema format
124
+ *
125
+ * @param source - Manual entity definitions
126
+ * @returns Parsed entity schemas
127
+ * @throws If validation fails (always in strict mode, on critical errors otherwise)
128
+ */
129
+ parse(source: ManualSourceInput): UnifiedEntitySchema[] {
130
+ const entities = this._normalizeSource(source)
131
+ const results: UnifiedEntitySchema[] = []
132
+
133
+ for (const entity of entities) {
134
+ const validated = this._validateEntity(entity)
135
+ if (validated) {
136
+ results.push(this._transformEntity(validated))
137
+ }
138
+ }
139
+
140
+ return results
141
+ }
142
+
143
+ /**
144
+ * Parse with detailed result including warnings
145
+ *
146
+ * @param source - Manual entity definitions
147
+ * @returns Schemas and warnings
148
+ */
149
+ parseWithWarnings(source: ManualSourceInput): ParseResult {
150
+ const warnings: ParseWarning[] = []
151
+ const entities = this._normalizeSource(source)
152
+ const results: UnifiedEntitySchema[] = []
153
+
154
+ for (const entity of entities) {
155
+ const entityWarnings = this._collectWarnings(entity)
156
+ warnings.push(...entityWarnings)
157
+
158
+ const validated = this._validateEntity(entity)
159
+ if (validated) {
160
+ results.push(this._transformEntity(validated))
161
+ }
162
+ }
163
+
164
+ return { schemas: results, warnings }
165
+ }
166
+
167
+ /**
168
+ * Normalize various source formats into entity array
169
+ *
170
+ * @private
171
+ * @param source - Source in any supported format
172
+ * @returns Normalized entity array
173
+ */
174
+ private _normalizeSource(source: ManualSourceInput): ManualEntityInput[] {
175
+ if (!source) {
176
+ return []
177
+ }
178
+
179
+ // Array of entities
180
+ if (Array.isArray(source)) {
181
+ return source
182
+ }
183
+
184
+ // Object with entities array
185
+ if ('entities' in source && Array.isArray(source.entities)) {
186
+ return source.entities
187
+ }
188
+
189
+ // Single entity object (may be missing name - validation will catch it)
190
+ if (typeof source === 'object') {
191
+ return [source as ManualEntityInput]
192
+ }
193
+
194
+ return []
195
+ }
196
+
197
+ /**
198
+ * Validate entity definition
199
+ *
200
+ * @private
201
+ * @param entity - Entity to validate
202
+ * @returns Validated entity or null if invalid
203
+ * @throws In strict mode, throws on validation error
204
+ */
205
+ private _validateEntity(entity: ManualEntityInput): ManualEntityInput | null {
206
+ const entityName = entity.name || '(unnamed)'
207
+
208
+ // Validate entity.name
209
+ if (!entity.name || typeof entity.name !== 'string' || entity.name.trim() === '') {
210
+ const message = `ManualConnector: entity ${entityName} missing required field 'name'`
211
+ if (this.strict) {
212
+ throw new Error(message)
213
+ }
214
+ return null
215
+ }
216
+
217
+ // Validate entity.endpoint
218
+ if (!entity.endpoint || typeof entity.endpoint !== 'string' || entity.endpoint.trim() === '') {
219
+ const message = `ManualConnector: entity '${entity.name}' missing required field 'endpoint'`
220
+ if (this.strict) {
221
+ throw new Error(message)
222
+ }
223
+ return null
224
+ }
225
+
226
+ // Validate fields if present
227
+ if (entity.fields) {
228
+ for (const [fieldKey, field] of Object.entries(entity.fields)) {
229
+ if (!this._validateField(entity.name, fieldKey, field)) {
230
+ if (this.strict) {
231
+ // Error already thrown in strict mode by _validateField
232
+ return null
233
+ }
234
+ // In non-strict mode, skip invalid fields by not adding them
235
+ }
236
+ }
237
+ }
238
+
239
+ return entity
240
+ }
241
+
242
+ /**
243
+ * Validate field definition
244
+ *
245
+ * @private
246
+ * @param entityName - Parent entity name for error context
247
+ * @param fieldKey - Field key in fields object
248
+ * @param field - Field to validate
249
+ * @returns True if valid
250
+ * @throws In strict mode, throws on validation error
251
+ */
252
+ private _validateField(entityName: string, fieldKey: string, field: ManualFieldInput): boolean {
253
+ // Validate field.name
254
+ if (!field.name || typeof field.name !== 'string' || field.name.trim() === '') {
255
+ const message = `ManualConnector: entity '${entityName}' field '${fieldKey}' missing required property 'name'`
256
+ if (this.strict) {
257
+ throw new Error(message)
258
+ }
259
+ return false
260
+ }
261
+
262
+ // Validate field.type exists
263
+ if (!field.type || typeof field.type !== 'string' || field.type.trim() === '') {
264
+ const message = `ManualConnector: entity '${entityName}' field '${field.name}' missing required property 'type'`
265
+ if (this.strict) {
266
+ throw new Error(message)
267
+ }
268
+ return false
269
+ }
270
+
271
+ // Validate field.type is valid UnifiedFieldType
272
+ if (!isValidFieldType(field.type)) {
273
+ const validTypes = UNIFIED_FIELD_TYPES.join(', ')
274
+ const message = `ManualConnector: entity '${entityName}' field '${field.name}' has invalid type '${field.type}'. Valid types: ${validTypes}`
275
+ if (this.strict) {
276
+ throw new Error(message)
277
+ }
278
+ return false
279
+ }
280
+
281
+ return true
282
+ }
283
+
284
+ /**
285
+ * Collect warnings for an entity without throwing
286
+ *
287
+ * @private
288
+ * @param entity - Entity to check
289
+ * @returns Collected warnings
290
+ */
291
+ private _collectWarnings(entity: ManualEntityInput): ParseWarning[] {
292
+ const warnings: ParseWarning[] = []
293
+ const entityName = entity.name || '(unnamed)'
294
+
295
+ if (!entity.name || typeof entity.name !== 'string' || entity.name.trim() === '') {
296
+ warnings.push({
297
+ path: entityName,
298
+ message: "Entity missing required field 'name'",
299
+ code: 'MISSING_ENTITY_NAME',
300
+ })
301
+ return warnings // Can't validate further without name
302
+ }
303
+
304
+ if (!entity.endpoint || typeof entity.endpoint !== 'string' || entity.endpoint.trim() === '') {
305
+ warnings.push({
306
+ path: entity.name,
307
+ message: "Entity missing required field 'endpoint'",
308
+ code: 'MISSING_ENTITY_ENDPOINT',
309
+ })
310
+ }
311
+
312
+ if (entity.fields) {
313
+ for (const [fieldKey, field] of Object.entries(entity.fields)) {
314
+ if (!field.name || typeof field.name !== 'string' || field.name.trim() === '') {
315
+ warnings.push({
316
+ path: `${entity.name}.fields.${fieldKey}`,
317
+ message: "Field missing required property 'name'",
318
+ code: 'MISSING_FIELD_NAME',
319
+ })
320
+ continue
321
+ }
322
+
323
+ if (!field.type || typeof field.type !== 'string' || field.type.trim() === '') {
324
+ warnings.push({
325
+ path: `${entity.name}.fields.${field.name}`,
326
+ message: "Field missing required property 'type'",
327
+ code: 'MISSING_FIELD_TYPE',
328
+ })
329
+ } else if (!isValidFieldType(field.type)) {
330
+ warnings.push({
331
+ path: `${entity.name}.fields.${field.name}`,
332
+ message: `Invalid field type '${field.type}'`,
333
+ code: 'INVALID_FIELD_TYPE',
334
+ })
335
+ }
336
+ }
337
+ }
338
+
339
+ return warnings
340
+ }
341
+
342
+ /**
343
+ * Transform validated entity input into UnifiedEntitySchema
344
+ *
345
+ * @private
346
+ * @param entity - Validated entity input
347
+ * @returns Transformed entity schema
348
+ */
349
+ private _transformEntity(entity: ManualEntityInput): UnifiedEntitySchema {
350
+ const transformedFields: Record<string, UnifiedFieldSchema> = {}
351
+
352
+ if (entity.fields) {
353
+ for (const [fieldKey, field] of Object.entries(entity.fields)) {
354
+ // Skip invalid fields in non-strict mode
355
+ if (!this._validateField(entity.name, fieldKey, field)) {
356
+ continue
357
+ }
358
+ transformedFields[fieldKey] = this._transformField(field)
359
+ }
360
+ }
361
+
362
+ const schema: UnifiedEntitySchema = {
363
+ name: entity.name,
364
+ endpoint: entity.endpoint,
365
+ fields: transformedFields,
366
+ }
367
+
368
+ // Add optional properties if provided
369
+ if (entity.label !== undefined) schema.label = entity.label
370
+ if (entity.labelPlural !== undefined) schema.labelPlural = entity.labelPlural
371
+ if (entity.labelField !== undefined) schema.labelField = entity.labelField
372
+ if (entity.routePrefix !== undefined) schema.routePrefix = entity.routePrefix
373
+ if (entity.idField !== undefined) schema.idField = entity.idField
374
+ if (entity.readOnly !== undefined) schema.readOnly = entity.readOnly
375
+
376
+ // Merge extensions from connector options and entity
377
+ if (this.extensions && Object.keys(this.extensions).length > 0) {
378
+ schema.extensions = { ...this.extensions, ...entity.extensions }
379
+ } else if (entity.extensions) {
380
+ schema.extensions = entity.extensions
381
+ }
382
+
383
+ return schema
384
+ }
385
+
386
+ /**
387
+ * Transform field input into UnifiedFieldSchema
388
+ *
389
+ * @private
390
+ * @param field - Field input
391
+ * @returns Transformed field schema
392
+ */
393
+ private _transformField(field: ManualFieldInput): UnifiedFieldSchema {
394
+ const schema: UnifiedFieldSchema = {
395
+ name: field.name,
396
+ type: field.type as UnifiedFieldType,
397
+ }
398
+
399
+ // Add optional properties if provided
400
+ if (field.label !== undefined) schema.label = field.label
401
+ if (field.required !== undefined) schema.required = field.required
402
+ if (field.readOnly !== undefined) schema.readOnly = field.readOnly
403
+ if (field.hidden !== undefined) schema.hidden = field.hidden
404
+ if (field.format !== undefined) schema.format = field.format
405
+ if (field.enum !== undefined) schema.enum = field.enum
406
+ if (field.default !== undefined) schema.default = field.default
407
+ if (field.reference !== undefined) schema.reference = field.reference
408
+ if (field.extensions !== undefined) schema.extensions = field.extensions
409
+
410
+ return schema
411
+ }
412
+ }
413
+
414
+ export default ManualConnector