@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,353 @@
1
+ /**
2
+ * DeferredRegistry - Named promise registry for loose coupling
3
+ *
4
+ * Enables async dependencies between services/components:
5
+ * - Services queue work during warmup
6
+ * - Components await dependencies without tight coupling
7
+ * - External signals (SSE) can resolve promises
8
+ *
9
+ * Key insight: await() can be called BEFORE queue() - the promise
10
+ * is created on first access and resolved when the task completes.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * // During app boot - queue lazy services
15
+ * deferred.queue('users-service', () => usersService.init())
16
+ * deferred.queue('config', () => configService.load())
17
+ *
18
+ * // In component - await dependencies (can be called before queue!)
19
+ * const config = await deferred.await('config')
20
+ *
21
+ * // Wait for multiple with Promise.all
22
+ * const [users, config] = await Promise.all([
23
+ * deferred.await('users-service'),
24
+ * deferred.await('config')
25
+ * ])
26
+ *
27
+ * // External resolution (SSE, webhooks)
28
+ * deferred.resolve('job-123', { status: 'done', data: result })
29
+ * deferred.reject('job-456', new Error('Failed'))
30
+ * ```
31
+ */
32
+
33
+ /**
34
+ * Status of a deferred entry
35
+ */
36
+ export type DeferredStatus = 'pending' | 'running' | 'completed' | 'failed'
37
+
38
+ /**
39
+ * Deferred entry stored in the registry
40
+ */
41
+ export interface DeferredEntry<T = unknown> {
42
+ promise: Promise<T>
43
+ resolve: (value: T) => void
44
+ reject: (error: Error) => void
45
+ status: DeferredStatus
46
+ value: T | Error | undefined
47
+ timestamp: number
48
+ }
49
+
50
+ /**
51
+ * Kernel interface for event emission
52
+ */
53
+ export interface DeferredKernel {
54
+ emit: (event: string, data: unknown) => void
55
+ }
56
+
57
+ /**
58
+ * DeferredRegistry options
59
+ */
60
+ export interface DeferredRegistryOptions {
61
+ kernel?: DeferredKernel | null
62
+ debug?: boolean
63
+ }
64
+
65
+ /**
66
+ * Entry info returned by entries()
67
+ */
68
+ export interface DeferredEntryInfo {
69
+ key: string
70
+ status: DeferredStatus
71
+ timestamp: number
72
+ }
73
+
74
+ export class DeferredRegistry {
75
+ private _entries: Map<string, DeferredEntry>
76
+ private _kernel: DeferredKernel | null
77
+ private _debug: boolean
78
+
79
+ /**
80
+ * @param options - Registry options
81
+ */
82
+ constructor(options: DeferredRegistryOptions = {}) {
83
+ this._entries = new Map()
84
+ this._kernel = options.kernel || null
85
+ this._debug = options.debug || false
86
+ }
87
+
88
+ /**
89
+ * Get or create a deferred entry for a key
90
+ * @param key - Unique identifier
91
+ * @returns Deferred entry
92
+ */
93
+ private _getOrCreate<T = unknown>(key: string): DeferredEntry<T> {
94
+ if (!this._entries.has(key)) {
95
+ let resolve!: (value: T) => void
96
+ let reject!: (error: Error) => void
97
+ const promise = new Promise<T>((res, rej) => {
98
+ resolve = res
99
+ reject = rej
100
+ })
101
+
102
+ const entry: DeferredEntry<T> = {
103
+ promise,
104
+ resolve,
105
+ reject,
106
+ status: 'pending',
107
+ value: undefined,
108
+ timestamp: Date.now(),
109
+ }
110
+
111
+ this._entries.set(key, entry as DeferredEntry)
112
+
113
+ if (this._debug) {
114
+ console.debug(`[deferred] Created entry: ${key}`)
115
+ }
116
+ }
117
+
118
+ return this._entries.get(key) as DeferredEntry<T>
119
+ }
120
+
121
+ /**
122
+ * Get the promise for a key (creates if doesn't exist)
123
+ * Can be called BEFORE queue() - promise resolves when task completes
124
+ *
125
+ * @param key - Unique identifier
126
+ * @returns Promise that resolves when the deferred completes
127
+ */
128
+ await<T = unknown>(key: string): Promise<T> {
129
+ return this._getOrCreate<T>(key).promise
130
+ }
131
+
132
+ /**
133
+ * Queue a task for execution
134
+ * If already running/completed, returns existing promise (deduplication)
135
+ *
136
+ * @param key - Unique identifier
137
+ * @param executor - Async function to execute
138
+ * @returns Promise that resolves with task result
139
+ */
140
+ queue<T = unknown>(key: string, executor: () => Promise<T> | T): Promise<T> {
141
+ const entry = this._getOrCreate<T>(key)
142
+
143
+ // Already started - return existing promise (idempotent)
144
+ if (entry.status !== 'pending') {
145
+ if (this._debug) {
146
+ console.debug(`[deferred] Already ${entry.status}: ${key}`)
147
+ }
148
+ return entry.promise
149
+ }
150
+
151
+ entry.status = 'running'
152
+ this._emit('deferred:started', { key })
153
+
154
+ if (this._debug) {
155
+ console.debug(`[deferred] Started: ${key}`)
156
+ }
157
+
158
+ // Execute and handle result
159
+ Promise.resolve()
160
+ .then(() => executor())
161
+ .then((value) => {
162
+ entry.status = 'completed'
163
+ entry.value = value
164
+ entry.resolve(value)
165
+ this._emit('deferred:completed', { key, value })
166
+
167
+ if (this._debug) {
168
+ console.debug(`[deferred] Completed: ${key}`)
169
+ }
170
+ })
171
+ .catch((error: Error) => {
172
+ entry.status = 'failed'
173
+ entry.value = error
174
+ entry.reject(error)
175
+ this._emit('deferred:failed', { key, error })
176
+
177
+ if (this._debug) {
178
+ console.debug(`[deferred] Failed: ${key}`, error)
179
+ }
180
+ })
181
+
182
+ return entry.promise
183
+ }
184
+
185
+ /**
186
+ * Resolve a deferred externally (for SSE, webhooks, etc.)
187
+ * No-op if already completed/failed
188
+ *
189
+ * @param key - Unique identifier
190
+ * @param value - Value to resolve with
191
+ * @returns True if resolved, false if already settled
192
+ */
193
+ resolve<T = unknown>(key: string, value: T): boolean {
194
+ const entry = this._getOrCreate<T>(key)
195
+
196
+ if (entry.status === 'completed' || entry.status === 'failed') {
197
+ if (this._debug) {
198
+ console.debug(`[deferred] Cannot resolve (already ${entry.status}): ${key}`)
199
+ }
200
+ return false
201
+ }
202
+
203
+ entry.status = 'completed'
204
+ entry.value = value
205
+ entry.resolve(value)
206
+ this._emit('deferred:completed', { key, value })
207
+
208
+ if (this._debug) {
209
+ console.debug(`[deferred] Resolved externally: ${key}`)
210
+ }
211
+
212
+ return true
213
+ }
214
+
215
+ /**
216
+ * Reject a deferred externally (for SSE, webhooks, etc.)
217
+ * No-op if already completed/failed
218
+ *
219
+ * @param key - Unique identifier
220
+ * @param error - Error to reject with
221
+ * @returns True if rejected, false if already settled
222
+ */
223
+ reject(key: string, error: Error): boolean {
224
+ const entry = this._getOrCreate(key)
225
+
226
+ if (entry.status === 'completed' || entry.status === 'failed') {
227
+ if (this._debug) {
228
+ console.debug(`[deferred] Cannot reject (already ${entry.status}): ${key}`)
229
+ }
230
+ return false
231
+ }
232
+
233
+ entry.status = 'failed'
234
+ entry.value = error
235
+ entry.reject(error)
236
+ this._emit('deferred:failed', { key, error })
237
+
238
+ if (this._debug) {
239
+ console.debug(`[deferred] Rejected externally: ${key}`)
240
+ }
241
+
242
+ return true
243
+ }
244
+
245
+ /**
246
+ * Check if a key exists in the registry
247
+ * @param key - Unique identifier
248
+ * @returns True if entry exists
249
+ */
250
+ has(key: string): boolean {
251
+ return this._entries.has(key)
252
+ }
253
+
254
+ /**
255
+ * Get the status of a deferred
256
+ * @param key - Unique identifier
257
+ * @returns Status or null if not found
258
+ */
259
+ status(key: string): DeferredStatus | null {
260
+ return this._entries.get(key)?.status || null
261
+ }
262
+
263
+ /**
264
+ * Get the resolved value (only if completed)
265
+ * @param key - Unique identifier
266
+ * @returns Value or undefined
267
+ */
268
+ value<T = unknown>(key: string): T | undefined {
269
+ const entry = this._entries.get(key)
270
+ return entry?.status === 'completed' ? (entry.value as T) : undefined
271
+ }
272
+
273
+ /**
274
+ * Check if a deferred is settled (completed or failed)
275
+ * @param key - Unique identifier
276
+ * @returns True if settled
277
+ */
278
+ isSettled(key: string): boolean {
279
+ const status = this.status(key)
280
+ return status === 'completed' || status === 'failed'
281
+ }
282
+
283
+ /**
284
+ * Get all keys in the registry
285
+ * @returns Array of keys
286
+ */
287
+ keys(): string[] {
288
+ return Array.from(this._entries.keys())
289
+ }
290
+
291
+ /**
292
+ * Get all entries with their status
293
+ * @returns Array of entry info
294
+ */
295
+ entries(): DeferredEntryInfo[] {
296
+ return Array.from(this._entries.entries()).map(([key, entry]) => ({
297
+ key,
298
+ status: entry.status,
299
+ timestamp: entry.timestamp,
300
+ }))
301
+ }
302
+
303
+ /**
304
+ * Clear a specific entry (for cleanup/retry)
305
+ * @param key - Unique identifier
306
+ * @returns True if cleared
307
+ */
308
+ clear(key: string): boolean {
309
+ return this._entries.delete(key)
310
+ }
311
+
312
+ /**
313
+ * Clear all entries
314
+ */
315
+ clearAll(): void {
316
+ this._entries.clear()
317
+ }
318
+
319
+ /**
320
+ * Emit event via kernel (if provided)
321
+ * @private
322
+ */
323
+ private _emit(event: string, data: unknown): void {
324
+ if (this._kernel) {
325
+ this._kernel.emit(event, data)
326
+ }
327
+ }
328
+
329
+ /**
330
+ * Set kernel for event emission
331
+ * @param kernel - Kernel instance with emit method
332
+ */
333
+ setKernel(kernel: DeferredKernel): void {
334
+ this._kernel = kernel
335
+ }
336
+
337
+ /**
338
+ * Enable/disable debug mode
339
+ * @param enabled - Debug mode flag
340
+ */
341
+ debug(enabled: boolean): void {
342
+ this._debug = enabled
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Factory function
348
+ * @param options - Registry options
349
+ * @returns New DeferredRegistry instance
350
+ */
351
+ export function createDeferredRegistry(options: DeferredRegistryOptions = {}): DeferredRegistry {
352
+ return new DeferredRegistry(options)
353
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Deferred Module
3
+ *
4
+ * Named promise registry for loose async coupling between services and components.
5
+ */
6
+
7
+ export {
8
+ DeferredRegistry,
9
+ createDeferredRegistry,
10
+ type DeferredStatus,
11
+ type DeferredEntry,
12
+ type DeferredKernel,
13
+ type DeferredRegistryOptions,
14
+ type DeferredEntryInfo,
15
+ } from './DeferredRegistry'
@@ -0,0 +1,12 @@
1
+ /**
2
+ * qdadm/editors - Optional editors that require vanilla-jsoneditor
3
+ *
4
+ * Import from '@quazardous/qdadm/editors' only if you need VanillaJsonEditor.
5
+ * This keeps vanilla-jsoneditor out of the main bundle.
6
+ *
7
+ * Usage:
8
+ * import { VanillaJsonEditor, JsonStructuredField } from '@quazardous/qdadm/editors'
9
+ */
10
+
11
+ export { default as VanillaJsonEditor } from '../components/editors/VanillaJsonEditor.vue'
12
+ export { default as JsonStructuredField } from '../components/editors/JsonStructuredField.vue'