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
@@ -1,175 +1,14 @@
1
1
  /**
2
- * DebugBridge - Central aggregator for debug collectors
2
+ * DebugBridge qdadm re-export.
3
3
  *
4
- * Manages multiple collectors and provides a unified interface
5
- * for the debug panel UI. Uses Vue reactivity for state management.
6
- *
7
- * @example
8
- * import { createDebugBridge, SignalCollector } from '@qdadm/core/debug'
9
- *
10
- * const debug = createDebugBridge()
11
- * debug.addCollector(new SignalCollector())
12
- * debug.install(ctx)
13
- */
14
-
15
- import { ref, shallowReactive, type Ref, type ShallowReactive } from 'vue'
16
- import type { Collector, CollectorContext } from './Collector'
17
-
18
- /**
19
- * Debug bridge options
4
+ * The actual implementation now lives in `@quazardous/qddebug` so it can be
5
+ * shared with qdcms.
20
6
  */
21
- export interface DebugBridgeOptions {
22
- enabled?: boolean
23
- }
24
-
25
- /**
26
- * Central aggregator for debug collectors
27
- */
28
- export class DebugBridge {
29
- options: DebugBridgeOptions
30
- enabled: Ref<boolean>
31
- collectors: ShallowReactive<Map<string, Collector>>
32
- tick: Ref<number>
33
- private _installed: boolean = false
34
- private _ctx: CollectorContext | null = null
35
-
36
- /**
37
- * Create a new DebugBridge
38
- * @param options - Bridge options
39
- */
40
- constructor(options: DebugBridgeOptions = {}) {
41
- this.options = options
42
- this.enabled = ref(options.enabled ?? false)
43
- // Use shallowReactive to avoid deep reactivity on collector instances
44
- this.collectors = shallowReactive(new Map())
45
- // Reactive tick for UI updates - collectors increment this when they have new data
46
- this.tick = ref(0)
47
- }
48
-
49
- /**
50
- * Notify that a collector has new data
51
- * Called by collectors when they record new entries or state changes
52
- */
53
- notify(): void {
54
- // Defensive check - ensure tick is still a ref
55
- if (this.tick && typeof this.tick === 'object' && 'value' in this.tick) {
56
- this.tick.value++
57
- }
58
- }
59
7
 
60
- /**
61
- * Add a collector to the bridge
62
- * @param collector - Collector instance to add
63
- * @returns this for chaining
64
- */
65
- addCollector(collector: Collector): this {
66
- const name = (collector.constructor as typeof Collector).collectorName || collector.name
67
- // Set bridge reference for reactive notifications
68
- collector._bridge = this
69
- this.collectors.set(name, collector)
70
- if (this._installed && this.enabled.value && this._ctx) {
71
- collector.install(this._ctx)
72
- }
73
- return this
74
- }
75
-
76
- /**
77
- * Get a collector by name
78
- * @param name - Collector name
79
- * @returns The collector or undefined
80
- */
81
- getCollector(name: string): Collector | undefined {
82
- return this.collectors.get(name)
83
- }
84
-
85
- /**
86
- * Get all collectors
87
- * @returns All collectors
88
- */
89
- getAllCollectors(): Map<string, Collector> {
90
- return this.collectors
91
- }
92
-
93
- /**
94
- * Install all collectors
95
- * @param ctx - Context object with signals, router, etc.
96
- * @returns this for chaining
97
- */
98
- install(ctx: CollectorContext): this {
99
- this._ctx = ctx
100
- this._installed = true
101
- if (this.enabled.value) {
102
- for (const collector of this.collectors.values()) {
103
- collector.install(ctx)
104
- }
105
- }
106
- // Initial notify after all collectors are installed
107
- // Use nextTick to ensure Vue reactivity is ready
108
- setTimeout(() => this.notify(), 0)
109
- return this
110
- }
111
-
112
- /**
113
- * Uninstall all collectors and cleanup
114
- */
115
- uninstall(): void {
116
- for (const collector of this.collectors.values()) {
117
- collector.uninstall()
118
- }
119
- this.collectors.clear()
120
- this._installed = false
121
- this._ctx = null
122
- }
123
-
124
- /**
125
- * Toggle enabled state
126
- * When enabled, installs all collectors; when disabled, uninstalls them
127
- * @returns New enabled state
128
- */
129
- toggle(): boolean {
130
- this.enabled.value = !this.enabled.value
131
- if (this._installed && this._ctx) {
132
- if (this.enabled.value) {
133
- for (const collector of this.collectors.values()) {
134
- collector.install(this._ctx)
135
- }
136
- } else {
137
- for (const collector of this.collectors.values()) {
138
- collector.uninstall()
139
- }
140
- }
141
- }
142
- return this.enabled.value
143
- }
144
-
145
- /**
146
- * Clear all collectors' entries
147
- */
148
- clearAll(): void {
149
- for (const collector of this.collectors.values()) {
150
- collector.clear()
151
- }
152
- }
153
-
154
- /**
155
- * Get total badge count across all collectors
156
- * @param countAll - If true, count all entries; otherwise unseen only
157
- * @returns Total entry count
158
- */
159
- getTotalBadge(countAll = false): number {
160
- let total = 0
161
- for (const collector of this.collectors.values()) {
162
- total += collector.getBadge(countAll)
163
- }
164
- return total
165
- }
166
- }
167
-
168
- /**
169
- * Factory function to create a DebugBridge
170
- * @param options - Bridge options
171
- * @returns New DebugBridge instance
172
- */
173
- export function createDebugBridge(options: DebugBridgeOptions = {}): DebugBridge {
174
- return new DebugBridge(options)
175
- }
8
+ export {
9
+ DebugBridge,
10
+ createDebugBridge,
11
+ type DebugBridgeOptions,
12
+ type BridgeManifest,
13
+ type BridgeSnapshot,
14
+ } from '@quazardous/qddebug'
@@ -21,13 +21,19 @@ import { ZonesCollector } from './ZonesCollector'
21
21
  import { AuthCollector } from './AuthCollector'
22
22
  import { EntitiesCollector } from './EntitiesCollector'
23
23
  import { RouterCollector } from './RouterCollector'
24
+ import { I18nCollector } from './I18nCollector'
24
25
  import DebugBar from './components/DebugBar.vue'
25
26
  import type { KernelContext } from '../../kernel/KernelContext'
26
27
 
27
28
  /**
28
29
  * Symbol for debug bridge injection key
29
30
  */
30
- export const DEBUG_BRIDGE_KEY = Symbol('debugBridge')
31
+ // Symbol.for() instead of Symbol() — the latter mints a fresh
32
+ // instance each time the module evaluates, and Vite HMR can fragment
33
+ // a single source module into multiple live instances per importer.
34
+ // Provider and consumer would then hold DIFFERENT symbols and the
35
+ // inject would fall back to its default (null), defeating the bridge.
36
+ export const DEBUG_BRIDGE_KEY = Symbol.for('qdadm.debugBridge')
31
37
 
32
38
  /**
33
39
  * Debug zone name for the DebugBar component
@@ -60,7 +66,17 @@ export interface DebugModuleOptions extends ModuleOptions {
60
66
  authCollector?: boolean
61
67
  entitiesCollector?: boolean
62
68
  routerCollector?: boolean
69
+ i18nCollector?: boolean
63
70
  _kernelManaged?: boolean
71
+ /**
72
+ * Existing DebugBridge to register collectors onto. When provided,
73
+ * the module skips its own `createDebugBridge()` AND skips
74
+ * `bridge.install(ctx)` — the host shell owns install timing so
75
+ * collectors from multiple sources (e.g. qdcms + qdadm) end up on
76
+ * the same bridge with a single merged install. When omitted, the
77
+ * module owns its bridge fully (legacy behaviour).
78
+ */
79
+ bridge?: DebugBridge
64
80
  }
65
81
 
66
82
  /**
@@ -94,8 +110,10 @@ export class DebugModule extends Module {
94
110
  override async connect(ctx: KernelContext): Promise<void> {
95
111
  this.ctx = ctx as unknown as Record<string, unknown>
96
112
 
97
- // Create debug bridge with options
98
- this._bridge = createDebugBridge({
113
+ // External bridge (host-owned) when provided — the host installs
114
+ // it later with a merged context. Otherwise create our own.
115
+ const externalBridge = this.options.bridge ?? null
116
+ this._bridge = externalBridge ?? createDebugBridge({
99
117
  enabled: this.options.enabled ?? false
100
118
  })
101
119
 
@@ -130,8 +148,16 @@ export class DebugModule extends Module {
130
148
  this._bridge.addCollector(new RouterCollector(collectorOptions))
131
149
  }
132
150
 
133
- // Install collectors with context
134
- this._bridge.install(ctx as unknown as Record<string, unknown>)
151
+ if (this.options.i18nCollector !== false) {
152
+ this._bridge.addCollector(new I18nCollector(collectorOptions))
153
+ }
154
+
155
+ // Install collectors with context — only when WE own the bridge.
156
+ // External bridges are installed by the host later with a merged
157
+ // context that may include data from other frameworks (e.g. cms).
158
+ if (!externalBridge) {
159
+ this._bridge.install(ctx as unknown as Record<string, unknown>)
160
+ }
135
161
 
136
162
  // Define the debug zone
137
163
  const extCtx = ctx as KernelContext & {
@@ -165,6 +191,10 @@ export class DebugModule extends Module {
165
191
 
166
192
  // Register global component for use in App.vue
167
193
  extCtx.component('QdadmDebugBar', QdadmDebugBar)
194
+
195
+ // The HTTP debug bridge (qdadmDebugPlugin) is wired entirely from the
196
+ // injected client script (see transformIndexHtml in the plugin). The
197
+ // DebugModule itself stays browser-pure and HMR-agnostic.
168
198
  }
169
199
 
170
200
  /**
@@ -11,7 +11,14 @@
11
11
  * Shows current state rather than historical events.
12
12
  */
13
13
 
14
- import { Collector, type CollectorContext, type CollectorEntry, type CollectorOptions } from './Collector'
14
+ import {
15
+ Collector,
16
+ type CollectorContext,
17
+ type CollectorEntry,
18
+ type CollectorManifest,
19
+ type CollectorOptions,
20
+ type CollectorSnapshot,
21
+ } from './Collector'
15
22
  import type { EntityManager } from '../../entity/EntityManager'
16
23
 
17
24
  /**
@@ -708,6 +715,95 @@ export class EntitiesCollector extends Collector<EntityEntry> {
708
715
  }
709
716
  }
710
717
 
718
+ override describe(): CollectorManifest {
719
+ return {
720
+ name: this.name,
721
+ records: false,
722
+ summary:
723
+ 'Lists every registered EntityManager with its storage, cache state, permissions, stats, fields and relations.',
724
+ entryShape: {
725
+ name: 'string',
726
+ system: 'boolean',
727
+ hasActivity: 'boolean',
728
+ label: 'string?',
729
+ labelPlural: 'string?',
730
+ routePrefix: 'string?',
731
+ idField: 'string?',
732
+ storage: 'StorageInfo',
733
+ multiStorage: 'MultiStorageInfo?',
734
+ cache: 'CacheInfo',
735
+ permissions: 'PermissionsInfo',
736
+ authSensitive: 'boolean',
737
+ warmup: 'WarmupInfo',
738
+ stats: 'StatsInfo',
739
+ fields: 'FieldsInfo',
740
+ relations: 'RelationsInfo',
741
+ },
742
+ stateShape: {
743
+ registered: 'string[] (entity names)',
744
+ activeEntities: 'string[] (entities with unseen activity)',
745
+ },
746
+ actions: [
747
+ ...this._builtinActionManifests(),
748
+ {
749
+ name: 'refreshCache',
750
+ summary: 'Invalidate one entity\'s cache (and optionally reload).',
751
+ args: { entity: 'string', reload: 'boolean?' },
752
+ mutates: true,
753
+ },
754
+ {
755
+ name: 'invalidateCache',
756
+ summary: 'Mark one entity\'s cache invalid without reloading.',
757
+ args: { entity: 'string' },
758
+ mutates: true,
759
+ },
760
+ {
761
+ name: 'testFetch',
762
+ summary: 'Probe an entity\'s primary storage with a list({page:1,page_size:1}).',
763
+ args: { entity: 'string' },
764
+ },
765
+ {
766
+ name: 'testStorageFetch',
767
+ summary: 'Probe a specific named storage on an entity.',
768
+ args: { entity: 'string', storage: 'string' },
769
+ },
770
+ ],
771
+ }
772
+ }
773
+
774
+ override snapshot(): CollectorSnapshot {
775
+ const entries = this.getEntries()
776
+ const registered = this._orchestrator?.getRegisteredNames() ?? []
777
+ return {
778
+ name: this.name,
779
+ entries,
780
+ count: entries.length,
781
+ unseen: this.getBadge(),
782
+ state: {
783
+ registered,
784
+ activeEntities: Array.from(this._activeEntities),
785
+ },
786
+ }
787
+ }
788
+
789
+ override async call(actionName: string, args: Record<string, unknown> = {}): Promise<unknown> {
790
+ if (actionName === 'refreshCache') {
791
+ const ok = await this.refreshCache(String(args.entity ?? ''), Boolean(args.reload))
792
+ return { ok }
793
+ }
794
+ if (actionName === 'invalidateCache') {
795
+ this.invalidateCache(String(args.entity ?? ''))
796
+ return { ok: true }
797
+ }
798
+ if (actionName === 'testFetch') {
799
+ return await this.testFetch(String(args.entity ?? ''))
800
+ }
801
+ if (actionName === 'testStorageFetch') {
802
+ return await this.testStorageFetch(String(args.entity ?? ''), String(args.storage ?? ''))
803
+ }
804
+ return super.call(actionName, args)
805
+ }
806
+
711
807
  /**
712
808
  * Test fetch data from a specific storage of an entity
713
809
  */
@@ -1,79 +1,4 @@
1
1
  /**
2
- * ErrorCollector - Captures JavaScript errors and unhandled promise rejections
3
- *
4
- * This collector listens to global window error events and unhandled promise
5
- * rejections, recording them for display in the debug panel.
6
- *
7
- * @example
8
- * const collector = new ErrorCollector()
9
- * collector.install(ctx)
10
- * // Errors are now automatically recorded
11
- * // Later...
12
- * collector.uninstall()
2
+ * ErrorCollector qdadm re-export from @quazardous/qddebug.
13
3
  */
14
-
15
- import { Collector, type CollectorContext, type CollectorEntry } from './Collector'
16
-
17
- /**
18
- * Error entry type
19
- */
20
- export interface ErrorEntry extends CollectorEntry {
21
- message?: string
22
- filename?: string
23
- lineno?: number
24
- colno?: number
25
- error?: string
26
- reason?: string
27
- }
28
-
29
- /**
30
- * Collector for JavaScript errors and unhandled promise rejections
31
- */
32
- export class ErrorCollector extends Collector<ErrorEntry> {
33
- /**
34
- * Collector name identifier
35
- */
36
- static override collectorName = 'errors'
37
-
38
- private _handler: ((event: ErrorEvent) => void) | null = null
39
- private _rejectionHandler: ((event: PromiseRejectionEvent) => void) | null = null
40
-
41
- /**
42
- * Internal install - subscribe to error and unhandledrejection events
43
- * @protected
44
- */
45
- protected override _doInstall(_ctx: CollectorContext): void {
46
- this._handler = (event: ErrorEvent) => {
47
- this.record({
48
- message: event.message,
49
- filename: event.filename,
50
- lineno: event.lineno,
51
- colno: event.colno,
52
- error: event.error?.stack
53
- })
54
- }
55
- this._rejectionHandler = (event: PromiseRejectionEvent) => {
56
- this.record({
57
- message: 'Unhandled Promise Rejection',
58
- reason: String(event.reason)
59
- })
60
- }
61
- window.addEventListener('error', this._handler)
62
- window.addEventListener('unhandledrejection', this._rejectionHandler)
63
- }
64
-
65
- /**
66
- * Internal uninstall - remove event listeners
67
- * @protected
68
- */
69
- protected override _doUninstall(): void {
70
- if (this._handler) {
71
- window.removeEventListener('error', this._handler)
72
- this._handler = null
73
- }
74
- if (this._rejectionHandler) {
75
- window.removeEventListener('unhandledrejection', this._rejectionHandler)
76
- this._rejectionHandler = null
77
- }
78
- }
79
- }
4
+ export { ErrorCollector, type ErrorEntry } from '@quazardous/qddebug'
@@ -0,0 +1,9 @@
1
+ /**
2
+ * I18nCollector — qdadm re-export from @quazardous/qddebug.
3
+ */
4
+ export {
5
+ I18nCollector,
6
+ type MissingKeyEntry,
7
+ type LocaleChange,
8
+ type I18nCollectorOptions,
9
+ } from '@quazardous/qddebug'
@@ -1,151 +1,7 @@
1
1
  /**
2
- * LocalStorageAdapter - Debug settings persistence
2
+ * LocalStorageAdapter qdadm re-export.
3
3
  *
4
- * Persists debug bridge state (enabled, collector settings) to localStorage.
5
- * Allows debug settings to survive page refreshes.
6
- *
7
- * @example
8
- * import { createDebugBridge, LocalStorageAdapter } from '@qdadm/core/debug'
9
- *
10
- * const debug = createDebugBridge()
11
- * const storage = new LocalStorageAdapter('qdadm-debug')
12
- * storage.attach(debug) // Auto-saves on change, restores on load
13
- */
14
-
15
- import type { DebugBridge } from './DebugBridge'
16
-
17
- /**
18
- * LocalStorage adapter for debug settings persistence
4
+ * The actual implementation now lives in `@quazardous/qddebug`.
19
5
  */
20
- export class LocalStorageAdapter {
21
- readonly key: string
22
- private _bridge: DebugBridge | null = null
23
- private _unwatch: (() => void) | null = null
24
-
25
- /**
26
- * Create a new LocalStorageAdapter
27
- * @param key - localStorage key prefix
28
- */
29
- constructor(key = 'qdadm-debug') {
30
- this.key = key
31
- }
32
-
33
- /**
34
- * Get the full key for a setting
35
- * @param name - Setting name
36
- * @returns Full localStorage key
37
- */
38
- private _getKey(name: string): string {
39
- return `${this.key}:${name}`
40
- }
41
-
42
- /**
43
- * Get a value from localStorage
44
- * @param name - Setting name
45
- * @param defaultValue - Default if not found
46
- * @returns The value
47
- */
48
- get<T>(name: string, defaultValue: T | null = null): T | null {
49
- try {
50
- const stored = localStorage.getItem(this._getKey(name))
51
- return stored !== null ? JSON.parse(stored) : defaultValue
52
- } catch {
53
- return defaultValue
54
- }
55
- }
56
-
57
- /**
58
- * Set a value in localStorage
59
- * @param name - Setting name
60
- * @param value - Value to store
61
- */
62
- set(name: string, value: unknown): void {
63
- try {
64
- localStorage.setItem(this._getKey(name), JSON.stringify(value))
65
- } catch {
66
- // localStorage might be full or disabled
67
- }
68
- }
69
-
70
- /**
71
- * Remove a value from localStorage
72
- * @param name - Setting name
73
- */
74
- remove(name: string): void {
75
- localStorage.removeItem(this._getKey(name))
76
- }
77
6
 
78
- /**
79
- * Clear all debug settings
80
- */
81
- clear(): void {
82
- const prefix = this.key + ':'
83
- const keys: string[] = []
84
- for (let i = 0; i < localStorage.length; i++) {
85
- const key = localStorage.key(i)
86
- if (key && key.startsWith(prefix)) {
87
- keys.push(key)
88
- }
89
- }
90
- keys.forEach(key => localStorage.removeItem(key))
91
- }
92
-
93
- /**
94
- * Attach to a DebugBridge and sync state
95
- * Restores saved state and watches for changes
96
- * @param bridge - The debug bridge to attach to
97
- * @returns this for chaining
98
- */
99
- attach(bridge: DebugBridge): this {
100
- this._bridge = bridge
101
-
102
- // Restore saved enabled state
103
- const savedEnabled = this.get<boolean>('enabled')
104
- if (savedEnabled !== null && bridge.enabled.value !== savedEnabled) {
105
- bridge.enabled.value = savedEnabled
106
- }
107
-
108
- // Watch for enabled changes (if Vue's watch is available)
109
- // In a real Vue app, use watch from vue
110
-
111
- return this
112
- }
113
-
114
- /**
115
- * Detach from the debug bridge
116
- */
117
- detach(): void {
118
- if (this._unwatch) {
119
- this._unwatch()
120
- this._unwatch = null
121
- }
122
- this._bridge = null
123
- }
124
-
125
- /**
126
- * Save current bridge state
127
- */
128
- save(): void {
129
- if (!this._bridge) return
130
- this.set('enabled', this._bridge.enabled.value)
131
- }
132
-
133
- /**
134
- * Restore bridge state from localStorage
135
- */
136
- restore(): void {
137
- if (!this._bridge) return
138
- const savedEnabled = this.get<boolean>('enabled')
139
- if (savedEnabled !== null) {
140
- this._bridge.enabled.value = savedEnabled
141
- }
142
- }
143
- }
144
-
145
- /**
146
- * Factory function to create a LocalStorageAdapter
147
- * @param key - localStorage key prefix
148
- */
149
- export function createLocalStorageAdapter(key?: string): LocalStorageAdapter {
150
- return new LocalStorageAdapter(key)
151
- }
7
+ export { LocalStorageAdapter, createLocalStorageAdapter } from '@quazardous/qddebug'