@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.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/package.json +101 -0
- package/src/assets/logo.svg +6 -0
- package/src/auth/SessionAuthAdapter.ts +459 -0
- package/src/auth/index.ts +15 -0
- package/src/chain/ActiveStack.ts +154 -0
- package/src/chain/StackHydrator.ts +292 -0
- package/src/chain/index.ts +25 -0
- package/src/chain/useActiveStack.ts +120 -0
- package/src/chain/useStackHydrator.ts +155 -0
- package/src/components/BoolCell.vue +34 -0
- package/src/components/InfoBanner.vue +73 -0
- package/src/components/QdadmRoot.vue +52 -0
- package/src/components/SeverityTag.vue +86 -0
- package/src/components/dialogs/BulkStatusDialog.vue +60 -0
- package/src/components/dialogs/MultiStepDialog.vue +331 -0
- package/src/components/dialogs/SimpleDialog.vue +122 -0
- package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
- package/src/components/display/BannerZone.vue +65 -0
- package/src/components/display/CardsGrid.vue +72 -0
- package/src/components/display/CopyableId.vue +84 -0
- package/src/components/display/EmptyState.vue +62 -0
- package/src/components/display/IntensityBar.vue +190 -0
- package/src/components/display/RichCardsGrid.vue +101 -0
- package/src/components/edit/FormActions.vue +78 -0
- package/src/components/edit/FormField.vue +82 -0
- package/src/components/edit/FormInput.vue +158 -0
- package/src/components/edit/FormPage.vue +260 -0
- package/src/components/edit/FormTab.vue +217 -0
- package/src/components/edit/FormTabs.vue +120 -0
- package/src/components/edit/LookupField.vue +406 -0
- package/src/components/edit/LookupPickerDialog.vue +230 -0
- package/src/components/editors/JsonEditorFoldable.vue +470 -0
- package/src/components/editors/JsonStructuredField.vue +264 -0
- package/src/components/editors/JsonViewer.vue +51 -0
- package/src/components/editors/KeyValueEditor.vue +314 -0
- package/src/components/editors/LanguageEditor.vue +259 -0
- package/src/components/editors/PermissionEditor.vue +558 -0
- package/src/components/editors/ScopeEditor.vue +372 -0
- package/src/components/editors/VanillaJsonEditor.vue +183 -0
- package/src/components/index.ts +83 -0
- package/src/components/item/FieldGroups.vue +392 -0
- package/src/components/layout/AppLayout.vue +1032 -0
- package/src/components/layout/BaseLayout.vue +190 -0
- package/src/components/layout/Breadcrumb.vue +55 -0
- package/src/components/layout/DashboardLayout.vue +104 -0
- package/src/components/layout/FormLayout.vue +256 -0
- package/src/components/layout/ListLayout.vue +278 -0
- package/src/components/layout/PageHeader.vue +156 -0
- package/src/components/layout/PageLayout.vue +126 -0
- package/src/components/layout/PageNav.vue +192 -0
- package/src/components/layout/SidebarBox.vue +87 -0
- package/src/components/layout/Zone.vue +182 -0
- package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
- package/src/components/layout/defaults/DefaultFooter.vue +89 -0
- package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
- package/src/components/layout/defaults/DefaultHeader.vue +78 -0
- package/src/components/layout/defaults/DefaultMenu.vue +188 -0
- package/src/components/layout/defaults/DefaultPagination.vue +75 -0
- package/src/components/layout/defaults/DefaultTable.vue +137 -0
- package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
- package/src/components/layout/defaults/index.ts +16 -0
- package/src/components/lists/ActionButtons.vue +49 -0
- package/src/components/lists/ActionColumn.vue +40 -0
- package/src/components/lists/FilterBar.vue +54 -0
- package/src/components/lists/ListPage.vue +467 -0
- package/src/components/pages/LoginPage.vue +334 -0
- package/src/components/pages/NotFoundPage.vue +98 -0
- package/src/components/show/ShowDisplay.vue +343 -0
- package/src/components/show/ShowField.vue +67 -0
- package/src/components/show/ShowPage.vue +431 -0
- package/src/composables/index.ts +155 -0
- package/src/composables/useApp.ts +67 -0
- package/src/composables/useAuth.ts +98 -0
- package/src/composables/useBareForm.ts +319 -0
- package/src/composables/useBreadcrumb.ts +252 -0
- package/src/composables/useChildPage.ts +113 -0
- package/src/composables/useCurrentEntity.ts +60 -0
- package/src/composables/useDeferred.ts +94 -0
- package/src/composables/useDirtyState.ts +138 -0
- package/src/composables/useEntityItemFormPage.ts +942 -0
- package/src/composables/useEntityItemFormPage.types.ts +451 -0
- package/src/composables/useEntityItemPage.ts +438 -0
- package/src/composables/useEntityItemShowPage.ts +722 -0
- package/src/composables/useFieldManager.ts +692 -0
- package/src/composables/useForm.ts +544 -0
- package/src/composables/useGuardStore.ts +53 -0
- package/src/composables/useHooks.ts +56 -0
- package/src/composables/useInfoBanner.ts +217 -0
- package/src/composables/useJsonSyntax.ts +122 -0
- package/src/composables/useLayoutResolver.ts +329 -0
- package/src/composables/useListPage.ts +1535 -0
- package/src/composables/useListPage.types.ts +437 -0
- package/src/composables/useListPage.utils.ts +101 -0
- package/src/composables/useNavContext.ts +439 -0
- package/src/composables/useNavigation.ts +216 -0
- package/src/composables/useOptionsLookup.ts +323 -0
- package/src/composables/usePageTitle.ts +84 -0
- package/src/composables/useSSEBridge.ts +142 -0
- package/src/composables/useSemanticBreadcrumb.ts +222 -0
- package/src/composables/useSidebarState.ts +24 -0
- package/src/composables/useSignals.ts +52 -0
- package/src/composables/useUnsavedChangesGuard.ts +155 -0
- package/src/composables/useUserImpersonator.ts +317 -0
- package/src/composables/useZoneRegistry.ts +252 -0
- package/src/core/bundles.ts +558 -0
- package/src/core/decorator.ts +420 -0
- package/src/core/extension.ts +470 -0
- package/src/core/index.ts +59 -0
- package/src/deferred/DeferredRegistry.ts +353 -0
- package/src/deferred/index.ts +15 -0
- package/src/editors/index.ts +12 -0
- package/src/entity/EntityManager.cache.ts +530 -0
- package/src/entity/EntityManager.crud.ts +615 -0
- package/src/entity/EntityManager.interface.ts +78 -0
- package/src/entity/EntityManager.query.ts +221 -0
- package/src/entity/EntityManager.relations.ts +151 -0
- package/src/entity/EntityManager.ts +944 -0
- package/src/entity/EntityManager.types.ts +288 -0
- package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
- package/src/entity/auth/EntityAuthAdapter.ts +119 -0
- package/src/entity/auth/PermissiveAdapter.ts +43 -0
- package/src/entity/auth/RoleHierarchy.ts +128 -0
- package/src/entity/auth/SecurityChecker.ts +202 -0
- package/src/entity/auth/factory.ts +203 -0
- package/src/entity/auth/index.ts +47 -0
- package/src/entity/factory.test.js +189 -0
- package/src/entity/factory.ts +146 -0
- package/src/entity/index.ts +49 -0
- package/src/entity/storage/ApiStorage.ts +228 -0
- package/src/entity/storage/IStorage.ts +100 -0
- package/src/entity/storage/LocalStorage.ts +200 -0
- package/src/entity/storage/MemoryStorage.ts +184 -0
- package/src/entity/storage/MockApiStorage.ts +318 -0
- package/src/entity/storage/SdkStorage.ts +377 -0
- package/src/entity/storage/factory.test.js +159 -0
- package/src/entity/storage/factory.ts +209 -0
- package/src/entity/storage/index.ts +75 -0
- package/src/gen/FieldMapper.ts +122 -0
- package/src/gen/StorageProfileFactory.ts +93 -0
- package/src/gen/connectors/BaseConnector.ts +150 -0
- package/src/gen/connectors/ManualConnector.test.js +499 -0
- package/src/gen/connectors/ManualConnector.ts +414 -0
- package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
- package/src/gen/connectors/OpenAPIConnector.ts +693 -0
- package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
- package/src/gen/connectors/index.ts +27 -0
- package/src/gen/createManagers.ts +245 -0
- package/src/gen/decorators.ts +134 -0
- package/src/gen/generateManagers.test.js +540 -0
- package/src/gen/generateManagers.ts +398 -0
- package/src/gen/index.ts +66 -0
- package/src/gen/schema.ts +248 -0
- package/src/gen/vite-plugin.ts +114 -0
- package/src/generated/managers/testManager.js +45 -0
- package/src/generated/managers/testManager.ts +46 -0
- package/src/hooks/HookRegistry.ts +16 -0
- package/src/hooks/index.ts +15 -0
- package/src/i18n/I18n.ts +344 -0
- package/src/i18n/IncrementalDomainProvider.ts +153 -0
- package/src/i18n/InlineTranslationProvider.ts +4 -0
- package/src/i18n/LazyTranslationProvider.ts +102 -0
- package/src/i18n/MessagesRegistry.ts +4 -0
- package/src/i18n/Resolver.ts +4 -0
- package/src/i18n/__tests__/I18n.test.ts +169 -0
- package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
- package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
- package/src/i18n/__tests__/Resolver.test.ts +271 -0
- package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
- package/src/i18n/defaults/core.en.yml +55 -0
- package/src/i18n/defaults/core.fr.yml +55 -0
- package/src/i18n/index.ts +55 -0
- package/src/i18n/loaders/raw-modules.d.ts +15 -0
- package/src/i18n/loaders/yaml.ts +35 -0
- package/src/i18n/strategies.ts +4 -0
- package/src/i18n/types.ts +34 -0
- package/src/i18n/useI18n.ts +34 -0
- package/src/index.ts +453 -0
- package/src/kernel/EventRouter.ts +23 -0
- package/src/kernel/Kernel.api.ts +79 -0
- package/src/kernel/Kernel.auth.ts +120 -0
- package/src/kernel/Kernel.i18n.ts +29 -0
- package/src/kernel/Kernel.modules.ts +170 -0
- package/src/kernel/Kernel.registries.ts +237 -0
- package/src/kernel/Kernel.routing.ts +334 -0
- package/src/kernel/Kernel.ts +460 -0
- package/src/kernel/Kernel.types.ts +263 -0
- package/src/kernel/Kernel.vue.ts +304 -0
- package/src/kernel/KernelContext.entities.ts +80 -0
- package/src/kernel/KernelContext.events.ts +57 -0
- package/src/kernel/KernelContext.i18n.ts +37 -0
- package/src/kernel/KernelContext.permissions.ts +38 -0
- package/src/kernel/KernelContext.routing.ts +280 -0
- package/src/kernel/KernelContext.ts +252 -0
- package/src/kernel/KernelContext.types.ts +173 -0
- package/src/kernel/KernelContext.zones.ts +54 -0
- package/src/kernel/Module.ts +169 -0
- package/src/kernel/ModuleLoader.ts +645 -0
- package/src/kernel/SSEBridge.ts +11 -0
- package/src/kernel/SignalBus.ts +48 -0
- package/src/kernel/index.ts +56 -0
- package/src/module/index.ts +33 -0
- package/src/module/moduleRegistry.ts +492 -0
- package/src/modules/debug/AuthCollector.ts +501 -0
- package/src/modules/debug/Collector.ts +20 -0
- package/src/modules/debug/DebugBridge.ts +14 -0
- package/src/modules/debug/DebugModule.ts +220 -0
- package/src/modules/debug/EntitiesCollector.ts +839 -0
- package/src/modules/debug/ErrorCollector.ts +4 -0
- package/src/modules/debug/I18nCollector.ts +9 -0
- package/src/modules/debug/LocalStorageAdapter.ts +7 -0
- package/src/modules/debug/RouterCollector.ts +449 -0
- package/src/modules/debug/SignalCollector.ts +4 -0
- package/src/modules/debug/ToastCollector.ts +4 -0
- package/src/modules/debug/ZonesCollector.ts +447 -0
- package/src/modules/debug/components/DebugBar.vue +31 -0
- package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
- package/src/modules/debug/components/index.ts +9 -0
- package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
- package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
- package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
- package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
- package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
- package/src/modules/debug/components/panels/index.ts +16 -0
- package/src/modules/debug/index.ts +58 -0
- package/src/modules/debug/styles.scss +2671 -0
- package/src/notifications/NotificationBadge.vue +35 -0
- package/src/notifications/NotificationListener.vue +71 -0
- package/src/notifications/NotificationModule.ts +76 -0
- package/src/notifications/NotificationPanel.vue +478 -0
- package/src/notifications/NotificationStore.ts +288 -0
- package/src/notifications/index.ts +42 -0
- package/src/notifications/styles.scss +32 -0
- package/src/orchestrator/Orchestrator.ts +427 -0
- package/src/orchestrator/index.ts +8 -0
- package/src/orchestrator/useOrchestrator.ts +80 -0
- package/src/plugin.ts +251 -0
- package/src/query/FilterQuery.ts +306 -0
- package/src/query/QueryExecutor.ts +341 -0
- package/src/query/index.ts +16 -0
- package/src/security/EntityRolesProvider.ts +385 -0
- package/src/security/PermissionMatcher.ts +152 -0
- package/src/security/PermissionRegistry.ts +273 -0
- package/src/security/PersistableRolesProvider.ts +584 -0
- package/src/security/RolesManager.ts +136 -0
- package/src/security/RolesProvider.ts +167 -0
- package/src/security/RolesProviderStorage.ts +211 -0
- package/src/security/SecurityModule.ts +94 -0
- package/src/security/StaticRolesProvider.ts +117 -0
- package/src/security/UsersManager.ts +163 -0
- package/src/security/index.ts +77 -0
- package/src/security/pages/RoleForm.vue +276 -0
- package/src/security/pages/RoleList.vue +123 -0
- package/src/styles/_alerts.scss +95 -0
- package/src/styles/_buttons.scss +391 -0
- package/src/styles/_cards.scss +241 -0
- package/src/styles/_code.scss +78 -0
- package/src/styles/_dialogs.scss +55 -0
- package/src/styles/_filter-bar.scss +70 -0
- package/src/styles/_forms.scss +434 -0
- package/src/styles/_helpers.scss +153 -0
- package/src/styles/_lists.scss +225 -0
- package/src/styles/_main.scss +356 -0
- package/src/styles/_markdown.scss +88 -0
- package/src/styles/_responsive.scss +255 -0
- package/src/styles/_show-pages.scss +186 -0
- package/src/styles/_sidebar.scss +380 -0
- package/src/styles/_states.scss +115 -0
- package/src/styles/_stats.scss +47 -0
- package/src/styles/_variables.scss +224 -0
- package/src/styles/index.scss +38 -0
- package/src/styles/theme/_components.scss +331 -0
- package/src/styles/theme/_index.scss +10 -0
- package/src/styles/theme/_tokens.scss +147 -0
- package/src/styles/theme/_utilities.scss +175 -0
- package/src/toast/ToastBridgeModule.ts +68 -0
- package/src/toast/ToastListener.vue +55 -0
- package/src/toast/index.ts +26 -0
- package/src/toast/useSignalToast.ts +154 -0
- package/src/types/index.ts +285 -0
- package/src/types/pluralize.d.ts +19 -0
- package/src/types/quarkernel.d.ts +50 -0
- package/src/utils/formatters.ts +174 -0
- package/src/utils/index.ts +35 -0
- package/src/utils/transformers.ts +131 -0
- package/src/vite/qdadmDebugPlugin.ts +401 -0
- package/src/vite-env.d.ts +50 -0
- package/src/zones/ZoneRegistry.ts +934 -0
- package/src/zones/index.ts +29 -0
- 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'
|