@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,427 @@
1
+ /**
2
+ * Orchestrator - Manager of EntityManagers
3
+ *
4
+ * Central registry that creates and distributes EntityManagers.
5
+ * Uses a factory function provided by the consuming application.
6
+ * Entity configs can be declared by modules via registry.addEntity().
7
+ *
8
+ * Usage:
9
+ * ```js
10
+ * // Dashboard provides a factory that receives (name, config)
11
+ * const entityFactory = (entityName, entityConfig) => {
12
+ * // entityConfig comes from registry.addEntity() or is undefined
13
+ * if (entityConfig instanceof EntityManager) {
14
+ * return entityConfig // Module provided a custom manager
15
+ * }
16
+ * return new EntityManager({
17
+ * name: entityName,
18
+ * storage: new ApiStorage({
19
+ * endpoint: entityConfig?.endpoint || `/${entityName}`,
20
+ * client
21
+ * })
22
+ * })
23
+ * }
24
+ *
25
+ * const orchestrator = new Orchestrator({ entityFactory })
26
+ *
27
+ * // Get managers (created lazily)
28
+ * const usersManager = orchestrator.get('users')
29
+ * ```
30
+ */
31
+ import { getEntityConfig } from '../module/moduleRegistry'
32
+ import type { EntityManager, EntityManagerOptions } from '../entity/EntityManager'
33
+ import type { EntityRecord } from '../types'
34
+ import type { SignalBus } from '../kernel/SignalBus'
35
+ import type { HookRegistry } from '../hooks/HookRegistry'
36
+ import type { EntityAuthAdapter } from '../entity/auth/EntityAuthAdapter'
37
+
38
+ /**
39
+ * DeferredRegistry interface (minimal for Orchestrator needs)
40
+ */
41
+ export interface DeferredRegistry {
42
+ has(key: string): boolean
43
+ await(key: string): Promise<unknown>
44
+ queue<T>(key: string, fn: () => Promise<T>): Promise<T>
45
+ }
46
+
47
+ /**
48
+ * Entity factory function type
49
+ */
50
+ export type EntityFactory = (
51
+ entityName: string,
52
+ entityConfig: EntityManagerOptions | EntityManager | undefined
53
+ ) => EntityManager | null
54
+
55
+ /**
56
+ * Toast options
57
+ */
58
+ export interface ToastOptions {
59
+ life?: number
60
+ emitter?: string
61
+ }
62
+
63
+ /**
64
+ * Toast config for default life durations
65
+ */
66
+ export interface ToastConfig {
67
+ success?: number
68
+ error?: number
69
+ warn?: number
70
+ info?: number
71
+ }
72
+
73
+ /**
74
+ * Toast helper interface
75
+ */
76
+ export interface ToastHelper {
77
+ success(summary: string, detail?: string, options?: string | ToastOptions): void
78
+ error(summary: string, detail?: string, options?: string | ToastOptions): void
79
+ warn(summary: string, detail?: string, options?: string | ToastOptions): void
80
+ info(summary: string, detail?: string, options?: string | ToastOptions): void
81
+ }
82
+
83
+ /**
84
+ * Orchestrator constructor options
85
+ */
86
+ export interface OrchestratorOptions {
87
+ entityFactory?: EntityFactory | null
88
+ managers?: Record<string, EntityManager>
89
+ signals?: SignalBus | null
90
+ hooks?: HookRegistry | null
91
+ deferred?: DeferredRegistry | null
92
+ entityAuthAdapter?: EntityAuthAdapter | null
93
+ }
94
+
95
+ export class Orchestrator {
96
+ private _entityFactory: EntityFactory | null
97
+ private _managers: Map<string, EntityManager>
98
+ private _signals: SignalBus | null
99
+ private _hooks: HookRegistry | null
100
+ private _deferred: DeferredRegistry | null
101
+ private _entityAuthAdapter: EntityAuthAdapter | null
102
+ private _toastConfig: ToastConfig = {}
103
+ private _toastHelper: ToastHelper | null = null
104
+
105
+ // Kernel options (set by Kernel after construction, avoids circular reference)
106
+ kernelOptions?: {
107
+ defaultEntityCacheTtlMs?: number
108
+ }
109
+
110
+ constructor(options: OrchestratorOptions = {}) {
111
+ const {
112
+ entityFactory = null,
113
+ // Optional: pre-registered managers (for special cases)
114
+ managers = {},
115
+ // SignalBus instance for event-driven communication
116
+ signals = null,
117
+ // HookRegistry instance for lifecycle hooks
118
+ hooks = null,
119
+ // DeferredRegistry instance for async warmup
120
+ deferred = null,
121
+ // Optional: AuthAdapter for entity permission checks (scope/silo)
122
+ entityAuthAdapter = null,
123
+ } = options
124
+
125
+ this._entityFactory = entityFactory
126
+ this._managers = new Map()
127
+ this._signals = signals
128
+ this._hooks = hooks
129
+ this._deferred = deferred
130
+ this._entityAuthAdapter = entityAuthAdapter
131
+
132
+ // Register pre-provided managers
133
+ for (const [name, manager] of Object.entries(managers)) {
134
+ this.register(name, manager)
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Set the SignalBus instance
140
+ */
141
+ setSignals(signals: SignalBus): void {
142
+ this._signals = signals
143
+ }
144
+
145
+ /**
146
+ * Get the SignalBus instance
147
+ */
148
+ get signals(): SignalBus | null {
149
+ return this._signals
150
+ }
151
+
152
+ /**
153
+ * Set toast configuration (life defaults per severity)
154
+ */
155
+ setToastConfig(config: ToastConfig): void {
156
+ this._toastConfig = { ...this._toastConfig, ...config }
157
+ this._toastHelper = null // Reset helper to pick up new config
158
+ }
159
+
160
+ /**
161
+ * Toast helper - wraps signal-based toasts
162
+ *
163
+ * Usage:
164
+ * orchestrator.toast.success('Saved', 'Item saved successfully')
165
+ * orchestrator.toast.error('Error', 'Failed to save', 'MyComponent')
166
+ * orchestrator.toast.warn('Warning', 'Check your input', { life: 10000, emitter: 'Custom' })
167
+ *
168
+ * Third param can be:
169
+ * - string: treated as emitter
170
+ * - object: { life, emitter }
171
+ */
172
+ get toast(): ToastHelper {
173
+ if (!this._toastHelper) {
174
+ // Default life values per severity (can be overridden via setToastConfig)
175
+ const defaults: Required<ToastConfig> = {
176
+ success: 3000,
177
+ error: 5000,
178
+ warn: 5000,
179
+ info: 3000,
180
+ ...this._toastConfig,
181
+ }
182
+
183
+ const emit = (
184
+ severity: keyof ToastConfig,
185
+ summary: string,
186
+ detail?: string,
187
+ options?: string | ToastOptions
188
+ ): void => {
189
+ if (this._signals) {
190
+ // Options can be string (emitter) or object { life, emitter }
191
+ const opts: ToastOptions =
192
+ typeof options === 'string' ? { emitter: options } : options || {}
193
+ this._signals.emit(`toast:${severity}`, {
194
+ summary,
195
+ detail,
196
+ life: opts.life ?? defaults[severity],
197
+ emitter: opts.emitter,
198
+ })
199
+ }
200
+ }
201
+
202
+ this._toastHelper = {
203
+ success: (summary, detail, options) => emit('success', summary, detail, options),
204
+ error: (summary, detail, options) => emit('error', summary, detail, options),
205
+ warn: (summary, detail, options) => emit('warn', summary, detail, options),
206
+ info: (summary, detail, options) => emit('info', summary, detail, options),
207
+ }
208
+ }
209
+ return this._toastHelper
210
+ }
211
+
212
+ /**
213
+ * Set the entity AuthAdapter for permission checks
214
+ * This adapter will be injected into all newly registered managers
215
+ * (unless they already have their own adapter)
216
+ */
217
+ setEntityAuthAdapter(adapter: EntityAuthAdapter): void {
218
+ this._entityAuthAdapter = adapter
219
+ }
220
+
221
+ /**
222
+ * Get the entity AuthAdapter
223
+ */
224
+ get entityAuthAdapter(): EntityAuthAdapter | null {
225
+ return this._entityAuthAdapter
226
+ }
227
+
228
+ /**
229
+ * Set the HookRegistry instance
230
+ */
231
+ setHooks(hooks: HookRegistry): void {
232
+ this._hooks = hooks
233
+ }
234
+
235
+ /**
236
+ * Get the HookRegistry instance
237
+ */
238
+ get hooks(): HookRegistry | null {
239
+ return this._hooks
240
+ }
241
+
242
+ /**
243
+ * Set the DeferredRegistry instance
244
+ */
245
+ setDeferred(deferred: DeferredRegistry): void {
246
+ this._deferred = deferred
247
+ }
248
+
249
+ /**
250
+ * Get the DeferredRegistry instance
251
+ */
252
+ get deferred(): DeferredRegistry | null {
253
+ return this._deferred
254
+ }
255
+
256
+ /**
257
+ * Set the entity factory
258
+ */
259
+ setFactory(factory: EntityFactory): void {
260
+ this._entityFactory = factory
261
+ }
262
+
263
+ /**
264
+ * Register an EntityManager manually
265
+ * Use this for special managers that don't follow the factory pattern
266
+ */
267
+ register(name: string, manager: EntityManager): void {
268
+ this._managers.set(name, manager)
269
+ // Pass signals reference to manager for event emission
270
+ if (this._signals && manager.setSignals) {
271
+ manager.setSignals(this._signals)
272
+ }
273
+ // Pass hooks reference to manager for lifecycle hooks
274
+ if (this._hooks && manager.setHooks) {
275
+ manager.setHooks(this._hooks)
276
+ }
277
+ // Inject entityAuthAdapter if provided and manager doesn't have one
278
+ // Manager's own adapter takes precedence (allows per-entity customization)
279
+ const managerWithAuth = manager as EntityManager & { _authAdapter?: unknown }
280
+ if (this._entityAuthAdapter && !managerWithAuth._authAdapter) {
281
+ manager.authAdapter = this._entityAuthAdapter
282
+ }
283
+ if (manager.onRegister) {
284
+ manager.onRegister(this)
285
+ }
286
+ }
287
+
288
+ /**
289
+ * Check if a manager exists (registered or can be created via factory)
290
+ */
291
+ has(name: string): boolean {
292
+ return this._managers.has(name) || !!this._entityFactory
293
+ }
294
+
295
+ /**
296
+ * Check if a manager is actually registered (not just creatable)
297
+ * Use this to check if ctx.entity() was called for this entity
298
+ */
299
+ isRegistered(name: string): boolean {
300
+ return this._managers.has(name)
301
+ }
302
+
303
+ /**
304
+ * Get an EntityManager by name
305
+ * Creates it via factory if not already registered
306
+ */
307
+ get<T extends EntityRecord = EntityRecord>(name: string): EntityManager<T> | undefined {
308
+ // Return existing manager
309
+ if (this._managers.has(name)) {
310
+ return this._managers.get(name) as unknown as EntityManager<T>
311
+ }
312
+
313
+ // Get entity config from module registry (if declared)
314
+ const entityConfig = getEntityConfig(name) as
315
+ | EntityManagerOptions
316
+ | EntityManager
317
+ | undefined
318
+
319
+ // If config is already an EntityManager, use it directly
320
+ if (entityConfig && typeof (entityConfig as EntityManager).get === 'function') {
321
+ this.register(name, entityConfig as EntityManager)
322
+ return entityConfig as unknown as EntityManager<T>
323
+ }
324
+
325
+ // Create via factory
326
+ if (this._entityFactory) {
327
+ const manager = this._entityFactory(name, entityConfig)
328
+ if (manager) {
329
+ this.register(name, manager)
330
+ return manager as unknown as EntityManager<T>
331
+ }
332
+ }
333
+
334
+ // Build helpful error message
335
+ const registered = this.getRegisteredNames()
336
+ const hint =
337
+ registered.length > 0
338
+ ? `\nRegistered entities: ${registered.join(', ')}\n`
339
+ : '\nNo entities registered yet.\n'
340
+
341
+ const suggestion = `
342
+ Possible causes:
343
+ 1. Entity "${name}" not declared in any module (ctx.entity('${name}', {...}))
344
+ 2. Module not loaded (check moduleDefs in config/modules.js)
345
+ 3. Typo in entity name
346
+
347
+ Example fix in your module:
348
+ ctx.entity('${name}', {
349
+ name: '${name}',
350
+ labelField: 'name',
351
+ fields: { ... },
352
+ storage: yourStorage
353
+ })`
354
+
355
+ throw new Error(`[Orchestrator] No manager for entity "${name}"${hint}${suggestion}`)
356
+ }
357
+
358
+ /**
359
+ * Get all registered manager names
360
+ */
361
+ getRegisteredNames(): string[] {
362
+ return Array.from(this._managers.keys())
363
+ }
364
+
365
+ /**
366
+ * Fire warmup for all managers (fire-and-forget)
367
+ *
368
+ * Triggers cache preloading for all managers with warmupEnabled.
369
+ * Each manager registers its warmup in the DeferredRegistry, allowing
370
+ * pages to await specific entities before rendering.
371
+ *
372
+ * IMPORTANT: This is fire-and-forget by design. Don't await this method.
373
+ * Components await what they need via DeferredRegistry:
374
+ * `await deferred.await('entity:books:cache')`
375
+ *
376
+ * @returns For debugging/logging only
377
+ *
378
+ * @example
379
+ * ```js
380
+ * // At boot (fire-and-forget)
381
+ * orchestrator.fireWarmups()
382
+ *
383
+ * // In component - await specific entity cache
384
+ * await deferred.await('entity:books:cache')
385
+ * const { items } = await booksManager.list() // Uses local cache
386
+ * ```
387
+ */
388
+ fireWarmups(): Map<string, boolean | Error | null> {
389
+ const results = new Map<string, boolean | Error | null>()
390
+
391
+ for (const [name, manager] of this._managers) {
392
+ if (manager.warmup && manager.warmupEnabled) {
393
+ // Fire each warmup - they register themselves in DeferredRegistry
394
+ manager
395
+ .warmup()
396
+ .then((result) => {
397
+ results.set(name, result)
398
+ })
399
+ .catch((error: Error) => {
400
+ console.warn(`[Orchestrator] Warmup failed for ${name}:`, error.message)
401
+ results.set(name, error)
402
+ })
403
+ }
404
+ }
405
+
406
+ return results
407
+ }
408
+
409
+ /**
410
+ * Dispose all managers
411
+ */
412
+ dispose(): void {
413
+ for (const [, manager] of this._managers) {
414
+ if (manager.onDispose) {
415
+ manager.onDispose()
416
+ }
417
+ }
418
+ this._managers.clear()
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Factory function to create an Orchestrator
424
+ */
425
+ export function createOrchestrator(options?: OrchestratorOptions): Orchestrator {
426
+ return new Orchestrator(options)
427
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Orchestrator Module
3
+ *
4
+ * Manager of EntityManagers - central registry for entity access.
5
+ */
6
+
7
+ export { Orchestrator, createOrchestrator, type OrchestratorOptions } from './Orchestrator'
8
+ export { useOrchestrator, useEntity, type UseOrchestratorReturn } from './useOrchestrator'
@@ -0,0 +1,80 @@
1
+ /**
2
+ * useOrchestrator - Composable to access the Orchestrator
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * const { orchestrator, getManager } = useOrchestrator()
7
+ *
8
+ * // Get a specific manager
9
+ * const usersManager = getManager('users')
10
+ *
11
+ * // Use it
12
+ * const { items } = await usersManager.list({ page: 1 })
13
+ * ```
14
+ */
15
+ import { inject } from 'vue'
16
+ import type { Orchestrator } from './Orchestrator'
17
+ import type { EntityManager } from '../entity/EntityManager'
18
+ import type { EntityRecord } from '../types'
19
+
20
+ /**
21
+ * Return type for useOrchestrator
22
+ */
23
+ export interface UseOrchestratorReturn {
24
+ orchestrator: Orchestrator
25
+ getManager: <T extends EntityRecord = EntityRecord>(name: string) => EntityManager<T>
26
+ hasManager: (name: string) => boolean
27
+ }
28
+
29
+ export function useOrchestrator(): UseOrchestratorReturn {
30
+ const injectedOrchestrator = inject<Orchestrator | undefined>('qdadmOrchestrator')
31
+
32
+ if (!injectedOrchestrator) {
33
+ throw new Error(
34
+ '[qdadm] Orchestrator not provided.\n' +
35
+ 'Possible causes:\n' +
36
+ '1. Kernel not initialized - ensure createKernel().createApp() is called before mounting\n' +
37
+ '2. Component used outside of qdadm app context\n' +
38
+ '3. Missing entityFactory in Kernel options'
39
+ )
40
+ }
41
+
42
+ // Capture after null check for closure
43
+ const orchestrator = injectedOrchestrator
44
+
45
+ /**
46
+ * Get an EntityManager by name
47
+ * @param name - Entity name
48
+ */
49
+ function getManager<T extends EntityRecord = EntityRecord>(name: string): EntityManager<T> {
50
+ return orchestrator.get(name) as EntityManager<T>
51
+ }
52
+
53
+ /**
54
+ * Check if a manager exists
55
+ * @param name - Entity name
56
+ */
57
+ function hasManager(name: string): boolean {
58
+ return orchestrator.has(name)
59
+ }
60
+
61
+ return {
62
+ orchestrator,
63
+ getManager,
64
+ hasManager
65
+ }
66
+ }
67
+
68
+ /**
69
+ * useEntity - Shorthand composable to get a specific EntityManager
70
+ *
71
+ * Usage:
72
+ * ```ts
73
+ * const users = useEntity('users')
74
+ * const { items } = await users.list()
75
+ * ```
76
+ */
77
+ export function useEntity<T extends EntityRecord = EntityRecord>(name: string): EntityManager<T> {
78
+ const { getManager } = useOrchestrator()
79
+ return getManager<T>(name)
80
+ }