qdadm 1.13.0 → 1.19.2
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/package.json +8 -4
- package/src/chain/ActiveStack.ts +79 -98
- package/src/chain/StackHydrator.ts +3 -2
- package/src/chain/index.ts +7 -1
- package/src/components/QdadmRoot.vue +52 -0
- package/src/components/edit/FormActions.vue +9 -6
- package/src/components/edit/LookupPickerDialog.vue +6 -3
- package/src/components/index.ts +6 -0
- package/src/composables/useEntityItemFormPage.ts +1 -0
- package/src/composables/useEntityItemShowPage.ts +1 -0
- package/src/composables/useFieldManager.ts +100 -3
- package/src/composables/useListPage.ts +50 -59
- package/src/composables/useListPage.utils.ts +101 -0
- package/src/composables/useNavigation.ts +26 -3
- package/src/composables/useOptionsLookup.ts +5 -1
- package/src/gen/generateManagers.test.js +27 -0
- package/src/gen/generateManagers.ts +12 -0
- package/src/hooks/HookRegistry.ts +14 -435
- 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 +37 -0
- package/src/kernel/EventRouter.ts +17 -300
- package/src/kernel/Kernel.i18n.ts +29 -0
- package/src/kernel/Kernel.modules.ts +6 -0
- package/src/kernel/Kernel.registries.ts +10 -2
- package/src/kernel/Kernel.routing.ts +43 -1
- package/src/kernel/Kernel.ts +43 -0
- package/src/kernel/Kernel.types.ts +52 -1
- package/src/kernel/Kernel.vue.ts +121 -15
- 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 +125 -834
- package/src/kernel/KernelContext.types.ts +173 -0
- package/src/kernel/KernelContext.zones.ts +54 -0
- package/src/kernel/SSEBridge.ts +7 -362
- package/src/kernel/SignalBus.ts +24 -148
- package/src/modules/debug/AuthCollector.ts +48 -1
- package/src/modules/debug/Collector.ts +16 -302
- package/src/modules/debug/DebugBridge.ts +10 -171
- package/src/modules/debug/DebugModule.ts +35 -5
- package/src/modules/debug/EntitiesCollector.ts +97 -1
- package/src/modules/debug/ErrorCollector.ts +2 -77
- package/src/modules/debug/I18nCollector.ts +9 -0
- package/src/modules/debug/LocalStorageAdapter.ts +3 -147
- package/src/modules/debug/RouterCollector.ts +101 -1
- package/src/modules/debug/SignalCollector.ts +2 -150
- package/src/modules/debug/ToastCollector.ts +2 -91
- package/src/modules/debug/ZonesCollector.ts +93 -1
- package/src/modules/debug/components/DebugBar.vue +19 -775
- package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
- package/src/modules/debug/components/index.ts +4 -3
- package/src/modules/debug/components/panels/AuthPanel.vue +1 -1
- package/src/modules/debug/components/panels/EntitiesPanel.vue +5 -5
- package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
- package/src/modules/debug/components/panels/RouterPanel.vue +1 -1
- package/src/modules/debug/components/panels/index.ts +10 -4
- package/src/modules/debug/index.ts +15 -0
- package/src/modules/debug/styles.scss +22 -18
- package/src/utils/index.ts +0 -3
- package/src/vite/qdadmDebugPlugin.ts +401 -0
- package/src/vite-env.d.ts +16 -0
- package/src/modules/debug/components/ObjectTree.vue +0 -123
- package/src/modules/debug/components/panels/EntriesPanel.vue +0 -100
- package/src/modules/debug/components/panels/SignalsPanel.vue +0 -188
- package/src/modules/debug/components/panels/ToastsPanel.vue +0 -45
- package/src/utils/debugInjector.ts +0 -306
|
@@ -1,437 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HookRegistry
|
|
2
|
+
* HookRegistry — qdadm re-export.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* // Register lifecycle hook (fire-and-forget)
|
|
18
|
-
* // Handlers receive QuarKernel event - context is in event.data
|
|
19
|
-
* hooks.register('entity:presave', async (event) => {
|
|
20
|
-
* event.data.entity.updated_at = Date.now()
|
|
21
|
-
* }, { priority: 10 })
|
|
22
|
-
*
|
|
23
|
-
* // Register alter hook (transform chain)
|
|
24
|
-
* hooks.register('list:alter', (config) => {
|
|
25
|
-
* config.columns.push({ field: 'custom' })
|
|
26
|
-
* return config
|
|
27
|
-
* })
|
|
28
|
-
*
|
|
29
|
-
* // Invoke lifecycle hook
|
|
30
|
-
* await hooks.invoke('entity:presave', { entity, manager })
|
|
31
|
-
*
|
|
32
|
-
* // Invoke alter hook
|
|
33
|
-
* const alteredConfig = await hooks.alter('list:alter', baseConfig)
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
import { createKernel, type QuarKernel, type ListenerOptions } from '@quazardous/quarkernel'
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Default priority for hooks (middle of range)
|
|
40
|
-
*/
|
|
41
|
-
const DEFAULT_PRIORITY = 50
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Priority constants for common use cases
|
|
45
|
-
*/
|
|
46
|
-
export const HOOK_PRIORITY = {
|
|
47
|
-
FIRST: 100,
|
|
48
|
-
HIGH: 75,
|
|
49
|
-
NORMAL: 50,
|
|
50
|
-
LOW: 25,
|
|
51
|
-
LAST: 0,
|
|
52
|
-
} as const
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Hook handler function type
|
|
56
|
-
*/
|
|
57
|
-
export type HookHandler<T = unknown> = (data: T) => T | void | Promise<T | void>
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Hook registration options
|
|
61
|
-
*/
|
|
62
|
-
export interface HookRegistrationOptions {
|
|
63
|
-
priority?: number
|
|
64
|
-
id?: string
|
|
65
|
-
after?: string | string[]
|
|
66
|
-
once?: boolean
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Hook entry for internal tracking
|
|
71
|
-
*/
|
|
72
|
-
interface HookEntry {
|
|
73
|
-
handler: HookHandler
|
|
74
|
-
priority: number
|
|
75
|
-
id?: string
|
|
76
|
-
after?: string | string[]
|
|
77
|
-
once: boolean
|
|
78
|
-
unbind: () => void
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Hook entry with normalized dependencies
|
|
83
|
-
*/
|
|
84
|
-
interface HookEntryWithDeps extends HookEntry {
|
|
85
|
-
afterArray: string[]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* HookRegistry constructor options
|
|
90
|
-
*/
|
|
91
|
-
export interface HookRegistryOptions {
|
|
92
|
-
kernel?: QuarKernel
|
|
93
|
-
debug?: boolean
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Invoke options
|
|
98
|
-
*/
|
|
99
|
-
export interface InvokeOptions {
|
|
100
|
-
throwOnError?: boolean
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Alter options
|
|
105
|
-
*/
|
|
106
|
-
export interface AlterOptions {
|
|
107
|
-
immutable?: boolean
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* HookRegistry class - wraps QuarKernel for Drupal-inspired hook API
|
|
112
|
-
*/
|
|
113
|
-
export class HookRegistry {
|
|
114
|
-
private _kernel: QuarKernel
|
|
115
|
-
private _hooks: Map<string, HookEntry[]>
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Create a HookRegistry instance
|
|
119
|
-
*
|
|
120
|
-
* @param options - Configuration options
|
|
121
|
-
*/
|
|
122
|
-
constructor(options: HookRegistryOptions = {}) {
|
|
123
|
-
this._kernel =
|
|
124
|
-
options.kernel ??
|
|
125
|
-
createKernel({
|
|
126
|
-
delimiter: ':',
|
|
127
|
-
wildcard: true,
|
|
128
|
-
errorBoundary: true,
|
|
129
|
-
debug: options.debug ?? false,
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
// Track registered hooks for introspection
|
|
133
|
-
this._hooks = new Map()
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Register a hook handler
|
|
138
|
-
*
|
|
139
|
-
* @param name - Hook name (colon-delimited, e.g., 'entity:presave')
|
|
140
|
-
* @param handler - Handler function
|
|
141
|
-
* @param options - Registration options
|
|
142
|
-
* @returns Unbind function to remove this handler
|
|
143
|
-
*/
|
|
144
|
-
register(name: string, handler: HookHandler, options: HookRegistrationOptions = {}): () => void {
|
|
145
|
-
const { priority = DEFAULT_PRIORITY, id, after, once = false } = options
|
|
146
|
-
|
|
147
|
-
// Build QuarKernel options
|
|
148
|
-
const kernelOptions: ListenerOptions = {
|
|
149
|
-
priority,
|
|
150
|
-
once,
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (id) {
|
|
154
|
-
kernelOptions.id = id
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (after) {
|
|
158
|
-
kernelOptions.after = after
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Register with QuarKernel
|
|
162
|
-
const unbind = this._kernel.on(name, handler as never, kernelOptions)
|
|
163
|
-
|
|
164
|
-
// Track for introspection
|
|
165
|
-
if (!this._hooks.has(name)) {
|
|
166
|
-
this._hooks.set(name, [])
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const hookEntry: HookEntry = {
|
|
170
|
-
handler,
|
|
171
|
-
priority,
|
|
172
|
-
id,
|
|
173
|
-
after,
|
|
174
|
-
once,
|
|
175
|
-
unbind,
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
this._hooks.get(name)!.push(hookEntry)
|
|
179
|
-
|
|
180
|
-
// Return enhanced unbind that also cleans up tracking
|
|
181
|
-
return () => {
|
|
182
|
-
unbind()
|
|
183
|
-
const hooks = this._hooks.get(name)
|
|
184
|
-
if (hooks) {
|
|
185
|
-
const idx = hooks.indexOf(hookEntry)
|
|
186
|
-
if (idx !== -1) {
|
|
187
|
-
hooks.splice(idx, 1)
|
|
188
|
-
}
|
|
189
|
-
if (hooks.length === 0) {
|
|
190
|
-
this._hooks.delete(name)
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Invoke a lifecycle hook (fire-and-forget)
|
|
198
|
-
*
|
|
199
|
-
* All registered handlers are called with the context in priority/dependency order.
|
|
200
|
-
* Handlers are executed sequentially (serial) to ensure predictable mutation order.
|
|
201
|
-
* Handlers may be async; all are awaited before returning.
|
|
202
|
-
* No return value is expected from handlers.
|
|
203
|
-
*
|
|
204
|
-
* @param name - Hook name
|
|
205
|
-
* @param context - Context object passed to all handlers (can be mutated)
|
|
206
|
-
* @param options - Invocation options
|
|
207
|
-
* @throws AggregateError if throwOnError is true and any handlers threw errors
|
|
208
|
-
*/
|
|
209
|
-
async invoke(name: string, context: unknown = {}, options: InvokeOptions = {}): Promise<void> {
|
|
210
|
-
const { throwOnError = false } = options
|
|
211
|
-
|
|
212
|
-
// Clear any previous execution errors
|
|
213
|
-
this._kernel.clearExecutionErrors()
|
|
214
|
-
|
|
215
|
-
// Use emitSerial for guaranteed sequential execution (predictable mutation order)
|
|
216
|
-
// QuarKernel's errorBoundary: true continues on errors, collecting them
|
|
217
|
-
await this._kernel.emitSerial(name, context)
|
|
218
|
-
|
|
219
|
-
// If requested, rethrow collected errors after all handlers have run
|
|
220
|
-
if (throwOnError) {
|
|
221
|
-
const errors = this._kernel.getExecutionErrors()
|
|
222
|
-
if (errors.length > 0) {
|
|
223
|
-
const errorMessages = errors.map(
|
|
224
|
-
(e: { listenerId: string; error: Error }) => `[${e.listenerId}] ${e.error.message}`
|
|
225
|
-
)
|
|
226
|
-
throw new AggregateError(
|
|
227
|
-
errors.map((e: { error: Error }) => e.error),
|
|
228
|
-
`Hook "${name}" handlers failed:\n ${errorMessages.join('\n ')}`
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Invoke an alter hook (chained transforms)
|
|
236
|
-
*
|
|
237
|
-
* Each handler receives the current data and returns the transformed data.
|
|
238
|
-
* Handlers are chained: each receives the output of the previous handler (reduce pattern).
|
|
239
|
-
* Respects priority ordering (higher priority runs first) and `after` dependencies.
|
|
240
|
-
*
|
|
241
|
-
* @param name - Hook name
|
|
242
|
-
* @param data - Initial data to transform
|
|
243
|
-
* @param options - Alter options
|
|
244
|
-
* @returns Transformed data after all handlers
|
|
245
|
-
*
|
|
246
|
-
* @example
|
|
247
|
-
* // Register handlers
|
|
248
|
-
* hooks.register('list:alter', (config) => {
|
|
249
|
-
* config.columns.push({ field: 'custom' })
|
|
250
|
-
* return config // MUST return
|
|
251
|
-
* }, { priority: HOOK_PRIORITY.NORMAL })
|
|
252
|
-
*
|
|
253
|
-
* // Invoke alter hook
|
|
254
|
-
* const config = await hooks.alter('list:alter', baseConfig)
|
|
255
|
-
*
|
|
256
|
-
* // With immutability (each handler gets a fresh clone)
|
|
257
|
-
* const config = await hooks.alter('list:alter', baseConfig, { immutable: true })
|
|
258
|
-
*/
|
|
259
|
-
async alter<T>(name: string, data: T, options: AlterOptions = {}): Promise<T> {
|
|
260
|
-
const { immutable = false } = options
|
|
261
|
-
|
|
262
|
-
// No handlers? Return data unchanged
|
|
263
|
-
if (!this.hasHook(name)) {
|
|
264
|
-
return data
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Get our tracked handlers (they have priority and dependency info)
|
|
268
|
-
const handlers = this._hooks.get(name) || []
|
|
269
|
-
|
|
270
|
-
// Sort by dependencies and priority using the same algorithm as QuarKernel
|
|
271
|
-
const sortedHandlers = this._sortByDependencies(handlers)
|
|
272
|
-
|
|
273
|
-
// Chain through handlers: each receives previous output (reduce pattern)
|
|
274
|
-
let result: T = data
|
|
275
|
-
for (const entry of sortedHandlers) {
|
|
276
|
-
// Clone data if immutability is enabled
|
|
277
|
-
const input = immutable ? this._cloneData(result) : result
|
|
278
|
-
const handlerResult = await entry.handler(input)
|
|
279
|
-
|
|
280
|
-
// If handler returns something, use it; otherwise keep current
|
|
281
|
-
if (handlerResult !== undefined) {
|
|
282
|
-
result = handlerResult as T
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return result
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Clone data for immutability support
|
|
291
|
-
*/
|
|
292
|
-
private _cloneData<T>(val: T): T {
|
|
293
|
-
if (val === null || val === undefined) {
|
|
294
|
-
return val
|
|
295
|
-
}
|
|
296
|
-
if (typeof val !== 'object') {
|
|
297
|
-
return val
|
|
298
|
-
}
|
|
299
|
-
// Use structuredClone for deep copy (available in Node 17+)
|
|
300
|
-
return structuredClone(val)
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Sort handlers by dependencies and priority
|
|
305
|
-
* Uses topological sort for dependency resolution (after option)
|
|
306
|
-
*/
|
|
307
|
-
private _sortByDependencies(handlers: HookEntry[]): HookEntryWithDeps[] {
|
|
308
|
-
// If no dependencies, just return sorted by priority
|
|
309
|
-
const hasDependencies = handlers.some(
|
|
310
|
-
(h) => h.after && (typeof h.after === 'string' || (Array.isArray(h.after) && h.after.length > 0))
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
const entriesWithDeps: HookEntryWithDeps[] = handlers.map((h) => ({
|
|
314
|
-
...h,
|
|
315
|
-
afterArray: h.after ? (Array.isArray(h.after) ? h.after : [h.after]) : [],
|
|
316
|
-
}))
|
|
317
|
-
|
|
318
|
-
if (!hasDependencies) {
|
|
319
|
-
return entriesWithDeps.sort((a, b) => b.priority - a.priority)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Build ID set for validation
|
|
323
|
-
const handlerIds = new Set(entriesWithDeps.filter((e) => e.id).map((e) => e.id))
|
|
324
|
-
|
|
325
|
-
// Filter dependencies to only those that exist in this hook
|
|
326
|
-
for (const entry of entriesWithDeps) {
|
|
327
|
-
entry.afterArray = entry.afterArray.filter((dep) => handlerIds.has(dep))
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Assign dependency levels
|
|
331
|
-
const levelMap = new Map<HookEntryWithDeps, number>()
|
|
332
|
-
const assignLevel = (entry: HookEntryWithDeps, visited: Set<HookEntryWithDeps> = new Set()): number => {
|
|
333
|
-
if (levelMap.has(entry)) {
|
|
334
|
-
return levelMap.get(entry)!
|
|
335
|
-
}
|
|
336
|
-
if (visited.has(entry)) {
|
|
337
|
-
// Circular dependency - treat as level 0
|
|
338
|
-
return 0
|
|
339
|
-
}
|
|
340
|
-
visited.add(entry)
|
|
341
|
-
|
|
342
|
-
if (entry.afterArray.length === 0) {
|
|
343
|
-
levelMap.set(entry, 0)
|
|
344
|
-
return 0
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Find max level of dependencies
|
|
348
|
-
let maxDepLevel = 0
|
|
349
|
-
for (const depId of entry.afterArray) {
|
|
350
|
-
const depEntry = entriesWithDeps.find((e) => e.id === depId)
|
|
351
|
-
if (depEntry) {
|
|
352
|
-
const depLevel = assignLevel(depEntry, new Set(visited))
|
|
353
|
-
maxDepLevel = Math.max(maxDepLevel, depLevel)
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const level = maxDepLevel + 1
|
|
358
|
-
levelMap.set(entry, level)
|
|
359
|
-
return level
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Assign levels to all entries
|
|
363
|
-
entriesWithDeps.forEach((e) => assignLevel(e))
|
|
364
|
-
|
|
365
|
-
// Sort by level, then by priority within level
|
|
366
|
-
return [...entriesWithDeps].sort((a, b) => {
|
|
367
|
-
const levelA = levelMap.get(a) ?? 0
|
|
368
|
-
const levelB = levelMap.get(b) ?? 0
|
|
369
|
-
if (levelA !== levelB) {
|
|
370
|
-
return levelA - levelB // Lower level first (dependencies run first)
|
|
371
|
-
}
|
|
372
|
-
return b.priority - a.priority // Higher priority first within same level
|
|
373
|
-
})
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Get all registered hook names
|
|
378
|
-
*/
|
|
379
|
-
getRegisteredHooks(): string[] {
|
|
380
|
-
return Array.from(this._hooks.keys())
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Get handler count for a hook
|
|
385
|
-
*
|
|
386
|
-
* @param name - Hook name (optional, total if omitted)
|
|
387
|
-
*/
|
|
388
|
-
getHandlerCount(name?: string): number {
|
|
389
|
-
if (name) {
|
|
390
|
-
return this._hooks.get(name)?.length ?? 0
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
let total = 0
|
|
394
|
-
for (const handlers of this._hooks.values()) {
|
|
395
|
-
total += handlers.length
|
|
396
|
-
}
|
|
397
|
-
return total
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Check if a hook has any registered handlers
|
|
402
|
-
*/
|
|
403
|
-
hasHook(name: string): boolean {
|
|
404
|
-
return this._hooks.has(name) && this._hooks.get(name)!.length > 0
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Clean up all registered hooks
|
|
409
|
-
*
|
|
410
|
-
* Removes all handlers and clears internal state.
|
|
411
|
-
*/
|
|
412
|
-
dispose(): void {
|
|
413
|
-
// Unbind all handlers
|
|
414
|
-
for (const handlers of this._hooks.values()) {
|
|
415
|
-
for (const entry of handlers) {
|
|
416
|
-
entry.unbind()
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Clear tracking
|
|
421
|
-
this._hooks.clear()
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Enable/disable debug mode
|
|
426
|
-
*/
|
|
427
|
-
debug(enabled: boolean): void {
|
|
428
|
-
this._kernel.debug(enabled)
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Factory function to create a HookRegistry instance
|
|
434
|
-
*/
|
|
435
|
-
export function createHookRegistry(options: HookRegistryOptions = {}): HookRegistry {
|
|
436
|
-
return new HookRegistry(options)
|
|
437
|
-
}
|
|
4
|
+
* The actual implementation now lives in `@quazardous/qdcore` so it can be
|
|
5
|
+
* shared with qdcms. This module re-exports the public API to preserve
|
|
6
|
+
* existing qdadm imports (`from '../hooks/HookRegistry'`).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { HookRegistry, createHookRegistry, HOOK_PRIORITY } from '@quazardous/qdcore'
|
|
10
|
+
export type {
|
|
11
|
+
HookHandler,
|
|
12
|
+
HookRegistrationOptions,
|
|
13
|
+
HookRegistryOptions,
|
|
14
|
+
InvokeOptions,
|
|
15
|
+
AlterOptions,
|
|
16
|
+
} from '@quazardous/qdcore'
|