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.
Files changed (86) hide show
  1. package/package.json +8 -4
  2. package/src/chain/ActiveStack.ts +79 -98
  3. package/src/chain/StackHydrator.ts +3 -2
  4. package/src/chain/index.ts +7 -1
  5. package/src/components/QdadmRoot.vue +52 -0
  6. package/src/components/edit/FormActions.vue +9 -6
  7. package/src/components/edit/LookupPickerDialog.vue +6 -3
  8. package/src/components/index.ts +6 -0
  9. package/src/composables/useEntityItemFormPage.ts +1 -0
  10. package/src/composables/useEntityItemShowPage.ts +1 -0
  11. package/src/composables/useFieldManager.ts +100 -3
  12. package/src/composables/useListPage.ts +50 -59
  13. package/src/composables/useListPage.utils.ts +101 -0
  14. package/src/composables/useNavigation.ts +26 -3
  15. package/src/composables/useOptionsLookup.ts +5 -1
  16. package/src/gen/generateManagers.test.js +27 -0
  17. package/src/gen/generateManagers.ts +12 -0
  18. package/src/hooks/HookRegistry.ts +14 -435
  19. package/src/i18n/I18n.ts +344 -0
  20. package/src/i18n/IncrementalDomainProvider.ts +153 -0
  21. package/src/i18n/InlineTranslationProvider.ts +4 -0
  22. package/src/i18n/LazyTranslationProvider.ts +102 -0
  23. package/src/i18n/MessagesRegistry.ts +4 -0
  24. package/src/i18n/Resolver.ts +4 -0
  25. package/src/i18n/__tests__/I18n.test.ts +169 -0
  26. package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
  27. package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
  28. package/src/i18n/__tests__/Resolver.test.ts +271 -0
  29. package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
  30. package/src/i18n/defaults/core.en.yml +55 -0
  31. package/src/i18n/defaults/core.fr.yml +55 -0
  32. package/src/i18n/index.ts +55 -0
  33. package/src/i18n/loaders/raw-modules.d.ts +15 -0
  34. package/src/i18n/loaders/yaml.ts +35 -0
  35. package/src/i18n/strategies.ts +4 -0
  36. package/src/i18n/types.ts +34 -0
  37. package/src/i18n/useI18n.ts +34 -0
  38. package/src/index.ts +37 -0
  39. package/src/kernel/EventRouter.ts +17 -300
  40. package/src/kernel/Kernel.i18n.ts +29 -0
  41. package/src/kernel/Kernel.modules.ts +6 -0
  42. package/src/kernel/Kernel.registries.ts +10 -2
  43. package/src/kernel/Kernel.routing.ts +43 -1
  44. package/src/kernel/Kernel.ts +43 -0
  45. package/src/kernel/Kernel.types.ts +52 -1
  46. package/src/kernel/Kernel.vue.ts +121 -15
  47. package/src/kernel/KernelContext.entities.ts +80 -0
  48. package/src/kernel/KernelContext.events.ts +57 -0
  49. package/src/kernel/KernelContext.i18n.ts +37 -0
  50. package/src/kernel/KernelContext.permissions.ts +38 -0
  51. package/src/kernel/KernelContext.routing.ts +280 -0
  52. package/src/kernel/KernelContext.ts +125 -834
  53. package/src/kernel/KernelContext.types.ts +173 -0
  54. package/src/kernel/KernelContext.zones.ts +54 -0
  55. package/src/kernel/SSEBridge.ts +7 -362
  56. package/src/kernel/SignalBus.ts +24 -148
  57. package/src/modules/debug/AuthCollector.ts +48 -1
  58. package/src/modules/debug/Collector.ts +16 -302
  59. package/src/modules/debug/DebugBridge.ts +10 -171
  60. package/src/modules/debug/DebugModule.ts +35 -5
  61. package/src/modules/debug/EntitiesCollector.ts +97 -1
  62. package/src/modules/debug/ErrorCollector.ts +2 -77
  63. package/src/modules/debug/I18nCollector.ts +9 -0
  64. package/src/modules/debug/LocalStorageAdapter.ts +3 -147
  65. package/src/modules/debug/RouterCollector.ts +101 -1
  66. package/src/modules/debug/SignalCollector.ts +2 -150
  67. package/src/modules/debug/ToastCollector.ts +2 -91
  68. package/src/modules/debug/ZonesCollector.ts +93 -1
  69. package/src/modules/debug/components/DebugBar.vue +19 -775
  70. package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
  71. package/src/modules/debug/components/index.ts +4 -3
  72. package/src/modules/debug/components/panels/AuthPanel.vue +1 -1
  73. package/src/modules/debug/components/panels/EntitiesPanel.vue +5 -5
  74. package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
  75. package/src/modules/debug/components/panels/RouterPanel.vue +1 -1
  76. package/src/modules/debug/components/panels/index.ts +10 -4
  77. package/src/modules/debug/index.ts +15 -0
  78. package/src/modules/debug/styles.scss +22 -18
  79. package/src/utils/index.ts +0 -3
  80. package/src/vite/qdadmDebugPlugin.ts +401 -0
  81. package/src/vite-env.d.ts +16 -0
  82. package/src/modules/debug/components/ObjectTree.vue +0 -123
  83. package/src/modules/debug/components/panels/EntriesPanel.vue +0 -100
  84. package/src/modules/debug/components/panels/SignalsPanel.vue +0 -188
  85. package/src/modules/debug/components/panels/ToastsPanel.vue +0 -45
  86. package/src/utils/debugInjector.ts +0 -306
@@ -0,0 +1,173 @@
1
+ /**
2
+ * KernelContext types - shared between the class shell and the prototype-patch
3
+ * modules (KernelContext.{entities,routing,zones,events,permissions,i18n}.ts).
4
+ *
5
+ * Internal types (ModuleWithCleanup, AuthAdapter, KernelOptions,
6
+ * KernelInterface, function types) stay un-exported by KernelContext.ts so
7
+ * they remain private to qdadm internals; the public types (NavItem,
8
+ * ZoneOptions, …) are re-exported from KernelContext.ts to preserve the
9
+ * existing barrel API.
10
+ */
11
+
12
+ import type { App, Component } from 'vue'
13
+ import type { Router } from 'vue-router'
14
+ import type { UsersManagerOptions } from '../security/UsersManager'
15
+ import type { SignalBus } from './SignalBus'
16
+ import type { Orchestrator } from '../orchestrator/Orchestrator'
17
+ import type { HookRegistry } from '../hooks/HookRegistry'
18
+ import type { ZoneRegistry } from '../zones/ZoneRegistry'
19
+ import type { DeferredRegistry } from '../deferred/DeferredRegistry.js'
20
+ import type { SecurityChecker } from '../entity/auth/SecurityChecker'
21
+ import type { PermissionRegistry } from '../security/PermissionRegistry'
22
+ import type { I18n } from '../i18n/I18n'
23
+
24
+ // ─────────────────────────────────────────────────────────────────────────────
25
+ // Internal types — shared across patch modules, not exposed by index.ts
26
+ // ─────────────────────────────────────────────────────────────────────────────
27
+
28
+ /** Extended Module interface with internal cleanup method */
29
+ export interface ModuleWithCleanup {
30
+ constructor?: { name?: string }
31
+ _addSignalCleanup?: (cleanup: () => void) => void
32
+ }
33
+
34
+ /** Auth adapter interface */
35
+ export interface AuthAdapter {
36
+ getUser(): unknown
37
+ [key: string]: unknown
38
+ }
39
+
40
+ /** Kernel options interface */
41
+ export interface KernelOptions {
42
+ debug?: boolean
43
+ authAdapter?: AuthAdapter | null
44
+ storageResolver?: unknown
45
+ managerResolver?: unknown
46
+ managerRegistry?: Record<string, unknown>
47
+ [key: string]: unknown
48
+ }
49
+
50
+ /** Kernel interface for type safety inside KernelContext */
51
+ export interface KernelInterface {
52
+ vueApp: App | null
53
+ router: Router | null
54
+ signals: SignalBus | null
55
+ orchestrator: Orchestrator | null
56
+ zoneRegistry: ZoneRegistry | null
57
+ hookRegistry: HookRegistry | null
58
+ deferred: DeferredRegistry | null
59
+ securityChecker: SecurityChecker | null
60
+ permissionRegistry: PermissionRegistry | null
61
+ activeStack: unknown
62
+ stackHydrator: unknown
63
+ options: KernelOptions
64
+ i18nInstance: I18n | null
65
+ _pendingProvides: Map<string | symbol, unknown>
66
+ _pendingComponents: Map<string, Component>
67
+ }
68
+
69
+ /** Signal handler function type */
70
+ export type SignalHandler = (event: { data: unknown; [key: string]: unknown }) => void
71
+
72
+ /** Hook handler function type */
73
+ export type HookHandler = (context: unknown) => unknown | Promise<unknown>
74
+
75
+ /** Deferred factory function type */
76
+ export type DeferredFactory = () => Promise<void>
77
+
78
+ // ─────────────────────────────────────────────────────────────────────────────
79
+ // Public types — re-exported by KernelContext.ts (and ultimately by index.ts)
80
+ // ─────────────────────────────────────────────────────────────────────────────
81
+
82
+ /** Navigation item configuration */
83
+ export interface NavItem {
84
+ section: string
85
+ route: string
86
+ label: string
87
+ icon?: string
88
+ exact?: boolean
89
+ entity?: string
90
+ }
91
+
92
+ /** Zone configuration */
93
+ export interface ZoneOptions {
94
+ default?: Component
95
+ }
96
+
97
+ /** Block configuration */
98
+ export interface BlockConfig {
99
+ component: Component
100
+ weight?: number
101
+ props?: Record<string, unknown>
102
+ id?: string
103
+ operation?: 'add' | 'replace' | 'extend' | 'wrap'
104
+ /** Block ID to replace (required if operation='replace') */
105
+ replaces?: string
106
+ /** Block ID to insert before (for operation='extend') */
107
+ before?: string
108
+ /** Block ID to insert after (for operation='extend') */
109
+ after?: string
110
+ /** Block ID to wrap (required if operation='wrap') */
111
+ wraps?: string
112
+ }
113
+
114
+ /** Route options */
115
+ export interface RouteOptions {
116
+ entity?: string
117
+ parent?: ParentConfig
118
+ label?: string
119
+ layout?: string
120
+ }
121
+
122
+ /** Parent route configuration */
123
+ export interface ParentConfig {
124
+ entity: string
125
+ param: string
126
+ foreignKey?: string
127
+ }
128
+
129
+ /** CRUD page components */
130
+ export interface CrudPages {
131
+ list?: () => Promise<{ default: Component }>
132
+ show?: () => Promise<{ default: Component }>
133
+ form?: () => Promise<{ default: Component }>
134
+ create?: () => Promise<{ default: Component }>
135
+ edit?: () => Promise<{ default: Component }>
136
+ }
137
+
138
+ /** CRUD options */
139
+ export interface CrudOptions {
140
+ nav?: {
141
+ section: string
142
+ icon?: string
143
+ label?: string
144
+ }
145
+ routePrefix?: string
146
+ /** Override the URL path segment (defaults to entity name). Useful for camelCase entities like 'jobTasks' → 'tasks'. */
147
+ pathSegment?: string
148
+ parentRoute?: string
149
+ foreignKey?: string
150
+ label?: string
151
+ }
152
+
153
+ /** Child page options for non-entity child routes */
154
+ export interface ChildPageOptions {
155
+ component: () => Promise<{ default: Component }>
156
+ label?: string
157
+ icon?: string
158
+ meta?: Record<string, unknown>
159
+ }
160
+
161
+ /** User entity options */
162
+ export type UserEntityOptions = UsersManagerOptions
163
+
164
+ /** Permission metadata */
165
+ export interface PermissionMeta {
166
+ label: string
167
+ description?: string
168
+ }
169
+
170
+ /** Permission options */
171
+ export interface PermissionOptions {
172
+ isEntity?: boolean
173
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Patch KernelContext prototype with UI extensibility methods:
3
+ * - zone(name, options) — define a zone slot
4
+ * - block(zoneName, config) — register a block in a zone
5
+ * - provide(key, value) — Vue dependency injection
6
+ * - component(name, component) — global Vue component registration
7
+ *
8
+ * provide/component fall back to the kernel's _pendingProvides /
9
+ * _pendingComponents maps when the Vue app isn't created yet, so modules can
10
+ * call them during connect().
11
+ */
12
+
13
+ import type { Component } from 'vue'
14
+ import type { BlockConfig, ZoneOptions } from './KernelContext.types'
15
+
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ type Self = any
18
+
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ export function applyZoneMethods(KernelContextClass: { prototype: any }): void {
21
+ const proto = KernelContextClass.prototype as Self
22
+
23
+ proto.zone = function (this: Self, name: string, options: ZoneOptions = {}): Self {
24
+ if (this._kernel.zoneRegistry) {
25
+ this._kernel.zoneRegistry.defineZone(name, options)
26
+ }
27
+ return this
28
+ }
29
+
30
+ proto.block = function (this: Self, zoneName: string, config: BlockConfig): Self {
31
+ if (this._kernel.zoneRegistry) {
32
+ this._kernel.zoneRegistry.registerBlock(zoneName, config)
33
+ }
34
+ return this
35
+ }
36
+
37
+ proto.provide = function (this: Self, key: string | symbol, value: unknown): Self {
38
+ if (this._kernel.vueApp) {
39
+ this._kernel.vueApp.provide(key, value)
40
+ } else {
41
+ this._kernel._pendingProvides.set(key, value)
42
+ }
43
+ return this
44
+ }
45
+
46
+ proto.component = function (this: Self, name: string, component: Component): Self {
47
+ if (this._kernel.vueApp) {
48
+ this._kernel.vueApp.component(name, component)
49
+ } else {
50
+ this._kernel._pendingComponents.set(name, component)
51
+ }
52
+ return this
53
+ }
54
+ }
@@ -1,366 +1,11 @@
1
1
  /**
2
- * SSEBridge - Server-Sent Events to SignalBus bridge
2
+ * SSEBridge qdadm re-export.
3
3
  *
4
- * Manages a single SSE connection and emits all events to SignalBus.
5
- * Components subscribe via signals.on('sse:eventName', handler) instead of
6
- * managing their own EventSource connections.
7
- *
8
- * Benefits:
9
- * - Single SSE connection per app (vs. one per component)
10
- * - Decoupled event handling via SignalBus
11
- * - Automatic reconnection with configurable delay
12
- * - Connection status available via signals
13
- *
14
- * Signal naming:
15
- * - `sse:connected` - Emitted when connection established
16
- * - `sse:disconnected` - Emitted when connection lost
17
- * - `sse:error` - Emitted on connection error
18
- * - `sse:{eventName}` - SSE event forwarded (e.g., sse:task:completed)
19
- *
20
- * Usage in Kernel:
21
- * ```js
22
- * new Kernel({
23
- * sse: {
24
- * url: '/api/events',
25
- * reconnectDelay: 5000,
26
- * signalPrefix: 'sse',
27
- * autoConnect: true
28
- * }
29
- * })
30
- * ```
31
- *
32
- * Usage in components:
33
- * ```js
34
- * const signals = inject('qdadmSignals')
35
- *
36
- * // Subscribe to specific SSE events
37
- * signals.on('sse:task:completed', ({ data }) => {
38
- * console.log('Task completed:', data)
39
- * })
40
- *
41
- * // Subscribe to all SSE events via wildcard
42
- * signals.on('sse:*', ({ event, data }) => {
43
- * console.log(`SSE event ${event}:`, data)
44
- * })
45
- * ```
46
- */
47
-
48
- import type { SignalBus } from './SignalBus'
49
-
50
- export const SSE_SIGNALS = {
51
- CONNECTED: 'sse:connected',
52
- DISCONNECTED: 'sse:disconnected',
53
- ERROR: 'sse:error',
54
- MESSAGE: 'sse:message',
55
- } as const
56
-
57
- /**
58
- * SSEBridge options
4
+ * The actual implementation now lives in `@quazardous/qdcore` so it can be
5
+ * shared with qdcms. The auth-aware connect/disconnect behaviour is now
6
+ * configurable via `connectOnSignal` / `disconnectOnSignal` options; defaults
7
+ * remain `'auth:login'` / `'auth:logout'` for backwards compatibility.
59
8
  */
60
- export interface SSEBridgeOptions {
61
- /** SignalBus instance */
62
- signals: SignalBus
63
- /** SSE endpoint URL */
64
- url: string
65
- /** Delay before reconnect (ms), 0 to disable */
66
- reconnectDelay?: number
67
- /** Prefix for emitted signals (default: 'sse') */
68
- signalPrefix?: string
69
- /** Connect immediately (default: false, waits for auth:login) */
70
- autoConnect?: boolean
71
- /** Include credentials in request */
72
- withCredentials?: boolean
73
- /** Query param name for auth token */
74
- tokenParam?: string
75
- /** Function to get auth token */
76
- getToken?: (() => string | null) | null
77
- /** Enable debug logging */
78
- debug?: boolean
79
- }
80
-
81
- export class SSEBridge {
82
- private _signals: SignalBus
83
- private _url: string
84
- private _reconnectDelay: number
85
- private _signalPrefix: string
86
- private _withCredentials: boolean
87
- private _tokenParam: string
88
- private _getToken: (() => string | null) | null
89
- private _debug: boolean
90
-
91
- private _eventSource: EventSource | null = null
92
- private _reconnectTimer: ReturnType<typeof setTimeout> | null = null
93
- private _connected = false
94
- private _reconnecting = false
95
-
96
- constructor(options: SSEBridgeOptions) {
97
- const {
98
- signals,
99
- url,
100
- reconnectDelay = 5000,
101
- signalPrefix = 'sse',
102
- autoConnect = false,
103
- withCredentials = false,
104
- tokenParam = 'token',
105
- getToken = null,
106
- debug = false,
107
- } = options
108
-
109
- if (!signals) {
110
- throw new Error('[SSEBridge] signals (SignalBus) is required')
111
- }
112
- if (!url) {
113
- throw new Error('[SSEBridge] url is required')
114
- }
115
-
116
- this._signals = signals
117
- this._url = url
118
- this._reconnectDelay = reconnectDelay
119
- this._signalPrefix = signalPrefix
120
- this._withCredentials = withCredentials
121
- this._tokenParam = tokenParam
122
- this._getToken = getToken
123
- this._debug = debug
124
-
125
- // Auto-connect or wait for auth:login
126
- if (autoConnect) {
127
- this.connect()
128
- } else {
129
- // Wait for auth:login signal to connect
130
- this._signals.once('auth:login', () => {
131
- this._log('Received auth:login, connecting SSE')
132
- this.connect()
133
- })
134
- }
135
-
136
- // Disconnect on auth:logout
137
- this._signals.on('auth:logout', () => {
138
- this._log('Received auth:logout, disconnecting SSE')
139
- this.disconnect()
140
- })
141
- }
142
-
143
- /**
144
- * Build signal name with prefix
145
- */
146
- private _buildSignal(eventName: string): string {
147
- return `${this._signalPrefix}:${eventName}`
148
- }
149
-
150
- /**
151
- * Debug logging
152
- */
153
- private _log(...args: unknown[]): void {
154
- if (this._debug) {
155
- console.debug('[SSEBridge]', ...args)
156
- }
157
- }
158
-
159
- /**
160
- * Build SSE URL with auth token
161
- */
162
- private _buildUrl(): string {
163
- const token = this._getToken?.()
164
- const sseUrl = new URL(this._url, window.location.origin)
165
-
166
- if (token && this._tokenParam) {
167
- sseUrl.searchParams.set(this._tokenParam, token)
168
- }
169
-
170
- return sseUrl.toString()
171
- }
172
-
173
- /**
174
- * Connect to SSE endpoint
175
- */
176
- connect(): void {
177
- // Clean up existing
178
- if (this._eventSource) {
179
- this._eventSource.close()
180
- this._eventSource = null
181
- }
182
-
183
- // Clear pending reconnect
184
- if (this._reconnectTimer) {
185
- clearTimeout(this._reconnectTimer)
186
- this._reconnectTimer = null
187
- }
188
-
189
- try {
190
- const url = this._buildUrl()
191
- this._log('Connecting to', url)
192
-
193
- this._eventSource = new EventSource(url, {
194
- withCredentials: this._withCredentials,
195
- })
196
9
 
197
- this._eventSource.onopen = (): void => {
198
- this._connected = true
199
- this._reconnecting = false
200
- this._log('Connected')
201
-
202
- this._signals.emit(SSE_SIGNALS.CONNECTED, {
203
- url: this._url,
204
- timestamp: new Date(),
205
- })
206
- }
207
-
208
- this._eventSource.onerror = (): void => {
209
- this._connected = false
210
- this._log('Connection error')
211
-
212
- this._signals.emit(SSE_SIGNALS.ERROR, {
213
- error: 'Connection error',
214
- timestamp: new Date(),
215
- })
216
-
217
- // Close broken connection
218
- if (this._eventSource) {
219
- this._eventSource.close()
220
- this._eventSource = null
221
- }
222
-
223
- this._signals.emit(SSE_SIGNALS.DISCONNECTED, {
224
- timestamp: new Date(),
225
- })
226
-
227
- // Schedule reconnect
228
- this._scheduleReconnect()
229
- }
230
-
231
- // Handle generic message events (event: message)
232
- this._eventSource.onmessage = (event: MessageEvent): void => {
233
- this._handleEvent('message', event)
234
- }
235
-
236
- // For named events, we need to add listeners dynamically
237
- // Since EventSource doesn't expose event names, we use a wrapper approach:
238
- // The server should send events with `event:` field, we handle them generically
239
-
240
- // Note: Named events require explicit addEventListener.
241
- // To support arbitrary event names, the app should either:
242
- // 1. Use `message` event type and include event name in data
243
- // 2. Pre-register known event names via registerEvents()
244
- } catch (err) {
245
- const error = err as Error
246
- this._log('Connect error:', error.message)
247
- this._signals.emit(SSE_SIGNALS.ERROR, {
248
- error: error.message,
249
- timestamp: new Date(),
250
- })
251
- this._scheduleReconnect()
252
- }
253
- }
254
-
255
- /**
256
- * Register listeners for specific SSE event types
257
- * Required because EventSource requires explicit addEventListener for named events.
258
- */
259
- registerEvents(eventNames: string[]): void {
260
- if (!this._eventSource) {
261
- this._log('Cannot register events: not connected')
262
- return
263
- }
264
-
265
- for (const eventName of eventNames) {
266
- this._eventSource.addEventListener(eventName, (event) => {
267
- this._handleEvent(eventName, event as MessageEvent)
268
- })
269
- this._log('Registered event:', eventName)
270
- }
271
- }
272
-
273
- /**
274
- * Handle incoming SSE event
275
- */
276
- private _handleEvent(eventName: string, event: MessageEvent): void {
277
- let data: unknown
278
- try {
279
- data = JSON.parse(event.data as string)
280
- } catch {
281
- data = event.data
282
- }
283
-
284
- const signal = this._buildSignal(eventName)
285
- this._log(`Emitting ${signal}:`, data)
286
-
287
- this._signals.emit(signal, {
288
- event: eventName,
289
- data,
290
- timestamp: new Date(),
291
- lastEventId: event.lastEventId,
292
- })
293
- }
294
-
295
- /**
296
- * Schedule reconnection
297
- */
298
- private _scheduleReconnect(): void {
299
- if (this._reconnectDelay <= 0) return
300
- if (this._reconnectTimer) return
301
-
302
- this._reconnecting = true
303
- this._log(`Reconnecting in ${this._reconnectDelay}ms`)
304
-
305
- this._reconnectTimer = setTimeout(() => {
306
- this._reconnectTimer = null
307
- if (!this._connected) {
308
- this.connect()
309
- }
310
- }, this._reconnectDelay)
311
- }
312
-
313
- /**
314
- * Disconnect from SSE endpoint
315
- */
316
- disconnect(): void {
317
- if (this._reconnectTimer) {
318
- clearTimeout(this._reconnectTimer)
319
- this._reconnectTimer = null
320
- }
321
-
322
- if (this._eventSource) {
323
- this._eventSource.close()
324
- this._eventSource = null
325
- }
326
-
327
- if (this._connected) {
328
- this._connected = false
329
- this._signals.emit(SSE_SIGNALS.DISCONNECTED, {
330
- timestamp: new Date(),
331
- })
332
- }
333
-
334
- this._reconnecting = false
335
- this._log('Disconnected')
336
- }
337
-
338
- /**
339
- * Reconnect (disconnect + connect)
340
- */
341
- reconnect(): void {
342
- this.disconnect()
343
- this.connect()
344
- }
345
-
346
- /**
347
- * Check if connected
348
- */
349
- isConnected(): boolean {
350
- return this._connected
351
- }
352
-
353
- /**
354
- * Check if reconnecting
355
- */
356
- isReconnecting(): boolean {
357
- return this._reconnecting
358
- }
359
- }
360
-
361
- /**
362
- * Factory function to create SSEBridge
363
- */
364
- export function createSSEBridge(options: SSEBridgeOptions): SSEBridge {
365
- return new SSEBridge(options)
366
- }
10
+ export { SSEBridge, createSSEBridge, SSE_SIGNALS } from '@quazardous/qdcore'
11
+ export type { SSEBridgeOptions } from '@quazardous/qdcore'