@quazardous/qdadm 1.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/package.json +101 -0
  4. package/src/assets/logo.svg +6 -0
  5. package/src/auth/SessionAuthAdapter.ts +459 -0
  6. package/src/auth/index.ts +15 -0
  7. package/src/chain/ActiveStack.ts +154 -0
  8. package/src/chain/StackHydrator.ts +292 -0
  9. package/src/chain/index.ts +25 -0
  10. package/src/chain/useActiveStack.ts +120 -0
  11. package/src/chain/useStackHydrator.ts +155 -0
  12. package/src/components/BoolCell.vue +34 -0
  13. package/src/components/InfoBanner.vue +73 -0
  14. package/src/components/QdadmRoot.vue +52 -0
  15. package/src/components/SeverityTag.vue +86 -0
  16. package/src/components/dialogs/BulkStatusDialog.vue +60 -0
  17. package/src/components/dialogs/MultiStepDialog.vue +331 -0
  18. package/src/components/dialogs/SimpleDialog.vue +122 -0
  19. package/src/components/dialogs/UnsavedChangesDialog.vue +80 -0
  20. package/src/components/display/BannerZone.vue +65 -0
  21. package/src/components/display/CardsGrid.vue +72 -0
  22. package/src/components/display/CopyableId.vue +84 -0
  23. package/src/components/display/EmptyState.vue +62 -0
  24. package/src/components/display/IntensityBar.vue +190 -0
  25. package/src/components/display/RichCardsGrid.vue +101 -0
  26. package/src/components/edit/FormActions.vue +78 -0
  27. package/src/components/edit/FormField.vue +82 -0
  28. package/src/components/edit/FormInput.vue +158 -0
  29. package/src/components/edit/FormPage.vue +260 -0
  30. package/src/components/edit/FormTab.vue +217 -0
  31. package/src/components/edit/FormTabs.vue +120 -0
  32. package/src/components/edit/LookupField.vue +406 -0
  33. package/src/components/edit/LookupPickerDialog.vue +230 -0
  34. package/src/components/editors/JsonEditorFoldable.vue +470 -0
  35. package/src/components/editors/JsonStructuredField.vue +264 -0
  36. package/src/components/editors/JsonViewer.vue +51 -0
  37. package/src/components/editors/KeyValueEditor.vue +314 -0
  38. package/src/components/editors/LanguageEditor.vue +259 -0
  39. package/src/components/editors/PermissionEditor.vue +558 -0
  40. package/src/components/editors/ScopeEditor.vue +372 -0
  41. package/src/components/editors/VanillaJsonEditor.vue +183 -0
  42. package/src/components/index.ts +83 -0
  43. package/src/components/item/FieldGroups.vue +392 -0
  44. package/src/components/layout/AppLayout.vue +1032 -0
  45. package/src/components/layout/BaseLayout.vue +190 -0
  46. package/src/components/layout/Breadcrumb.vue +55 -0
  47. package/src/components/layout/DashboardLayout.vue +104 -0
  48. package/src/components/layout/FormLayout.vue +256 -0
  49. package/src/components/layout/ListLayout.vue +278 -0
  50. package/src/components/layout/PageHeader.vue +156 -0
  51. package/src/components/layout/PageLayout.vue +126 -0
  52. package/src/components/layout/PageNav.vue +192 -0
  53. package/src/components/layout/SidebarBox.vue +87 -0
  54. package/src/components/layout/Zone.vue +182 -0
  55. package/src/components/layout/defaults/DefaultBreadcrumb.vue +149 -0
  56. package/src/components/layout/defaults/DefaultFooter.vue +89 -0
  57. package/src/components/layout/defaults/DefaultFormActions.vue +67 -0
  58. package/src/components/layout/defaults/DefaultHeader.vue +78 -0
  59. package/src/components/layout/defaults/DefaultMenu.vue +188 -0
  60. package/src/components/layout/defaults/DefaultPagination.vue +75 -0
  61. package/src/components/layout/defaults/DefaultTable.vue +137 -0
  62. package/src/components/layout/defaults/DefaultUserInfo.vue +111 -0
  63. package/src/components/layout/defaults/index.ts +16 -0
  64. package/src/components/lists/ActionButtons.vue +49 -0
  65. package/src/components/lists/ActionColumn.vue +40 -0
  66. package/src/components/lists/FilterBar.vue +54 -0
  67. package/src/components/lists/ListPage.vue +467 -0
  68. package/src/components/pages/LoginPage.vue +334 -0
  69. package/src/components/pages/NotFoundPage.vue +98 -0
  70. package/src/components/show/ShowDisplay.vue +343 -0
  71. package/src/components/show/ShowField.vue +67 -0
  72. package/src/components/show/ShowPage.vue +431 -0
  73. package/src/composables/index.ts +155 -0
  74. package/src/composables/useApp.ts +67 -0
  75. package/src/composables/useAuth.ts +98 -0
  76. package/src/composables/useBareForm.ts +319 -0
  77. package/src/composables/useBreadcrumb.ts +252 -0
  78. package/src/composables/useChildPage.ts +113 -0
  79. package/src/composables/useCurrentEntity.ts +60 -0
  80. package/src/composables/useDeferred.ts +94 -0
  81. package/src/composables/useDirtyState.ts +138 -0
  82. package/src/composables/useEntityItemFormPage.ts +942 -0
  83. package/src/composables/useEntityItemFormPage.types.ts +451 -0
  84. package/src/composables/useEntityItemPage.ts +438 -0
  85. package/src/composables/useEntityItemShowPage.ts +722 -0
  86. package/src/composables/useFieldManager.ts +692 -0
  87. package/src/composables/useForm.ts +544 -0
  88. package/src/composables/useGuardStore.ts +53 -0
  89. package/src/composables/useHooks.ts +56 -0
  90. package/src/composables/useInfoBanner.ts +217 -0
  91. package/src/composables/useJsonSyntax.ts +122 -0
  92. package/src/composables/useLayoutResolver.ts +329 -0
  93. package/src/composables/useListPage.ts +1535 -0
  94. package/src/composables/useListPage.types.ts +437 -0
  95. package/src/composables/useListPage.utils.ts +101 -0
  96. package/src/composables/useNavContext.ts +439 -0
  97. package/src/composables/useNavigation.ts +216 -0
  98. package/src/composables/useOptionsLookup.ts +323 -0
  99. package/src/composables/usePageTitle.ts +84 -0
  100. package/src/composables/useSSEBridge.ts +142 -0
  101. package/src/composables/useSemanticBreadcrumb.ts +222 -0
  102. package/src/composables/useSidebarState.ts +24 -0
  103. package/src/composables/useSignals.ts +52 -0
  104. package/src/composables/useUnsavedChangesGuard.ts +155 -0
  105. package/src/composables/useUserImpersonator.ts +317 -0
  106. package/src/composables/useZoneRegistry.ts +252 -0
  107. package/src/core/bundles.ts +558 -0
  108. package/src/core/decorator.ts +420 -0
  109. package/src/core/extension.ts +470 -0
  110. package/src/core/index.ts +59 -0
  111. package/src/deferred/DeferredRegistry.ts +353 -0
  112. package/src/deferred/index.ts +15 -0
  113. package/src/editors/index.ts +12 -0
  114. package/src/entity/EntityManager.cache.ts +530 -0
  115. package/src/entity/EntityManager.crud.ts +615 -0
  116. package/src/entity/EntityManager.interface.ts +78 -0
  117. package/src/entity/EntityManager.query.ts +221 -0
  118. package/src/entity/EntityManager.relations.ts +151 -0
  119. package/src/entity/EntityManager.ts +944 -0
  120. package/src/entity/EntityManager.types.ts +288 -0
  121. package/src/entity/auth/CompositeAuthAdapter.ts +194 -0
  122. package/src/entity/auth/EntityAuthAdapter.ts +119 -0
  123. package/src/entity/auth/PermissiveAdapter.ts +43 -0
  124. package/src/entity/auth/RoleHierarchy.ts +128 -0
  125. package/src/entity/auth/SecurityChecker.ts +202 -0
  126. package/src/entity/auth/factory.ts +203 -0
  127. package/src/entity/auth/index.ts +47 -0
  128. package/src/entity/factory.test.js +189 -0
  129. package/src/entity/factory.ts +146 -0
  130. package/src/entity/index.ts +49 -0
  131. package/src/entity/storage/ApiStorage.ts +228 -0
  132. package/src/entity/storage/IStorage.ts +100 -0
  133. package/src/entity/storage/LocalStorage.ts +200 -0
  134. package/src/entity/storage/MemoryStorage.ts +184 -0
  135. package/src/entity/storage/MockApiStorage.ts +318 -0
  136. package/src/entity/storage/SdkStorage.ts +377 -0
  137. package/src/entity/storage/factory.test.js +159 -0
  138. package/src/entity/storage/factory.ts +209 -0
  139. package/src/entity/storage/index.ts +75 -0
  140. package/src/gen/FieldMapper.ts +122 -0
  141. package/src/gen/StorageProfileFactory.ts +93 -0
  142. package/src/gen/connectors/BaseConnector.ts +150 -0
  143. package/src/gen/connectors/ManualConnector.test.js +499 -0
  144. package/src/gen/connectors/ManualConnector.ts +414 -0
  145. package/src/gen/connectors/OpenAPIConnector.test.js +836 -0
  146. package/src/gen/connectors/OpenAPIConnector.ts +693 -0
  147. package/src/gen/connectors/__fixtures__/sample-openapi.json +311 -0
  148. package/src/gen/connectors/index.ts +27 -0
  149. package/src/gen/createManagers.ts +245 -0
  150. package/src/gen/decorators.ts +134 -0
  151. package/src/gen/generateManagers.test.js +540 -0
  152. package/src/gen/generateManagers.ts +398 -0
  153. package/src/gen/index.ts +66 -0
  154. package/src/gen/schema.ts +248 -0
  155. package/src/gen/vite-plugin.ts +114 -0
  156. package/src/generated/managers/testManager.js +45 -0
  157. package/src/generated/managers/testManager.ts +46 -0
  158. package/src/hooks/HookRegistry.ts +16 -0
  159. package/src/hooks/index.ts +15 -0
  160. package/src/i18n/I18n.ts +344 -0
  161. package/src/i18n/IncrementalDomainProvider.ts +153 -0
  162. package/src/i18n/InlineTranslationProvider.ts +4 -0
  163. package/src/i18n/LazyTranslationProvider.ts +102 -0
  164. package/src/i18n/MessagesRegistry.ts +4 -0
  165. package/src/i18n/Resolver.ts +4 -0
  166. package/src/i18n/__tests__/I18n.test.ts +169 -0
  167. package/src/i18n/__tests__/IncrementalDomainProvider.test.ts +146 -0
  168. package/src/i18n/__tests__/LazyTranslationProvider.test.ts +100 -0
  169. package/src/i18n/__tests__/Resolver.test.ts +271 -0
  170. package/src/i18n/defaults/DefaultCoreProvider.ts +28 -0
  171. package/src/i18n/defaults/core.en.yml +55 -0
  172. package/src/i18n/defaults/core.fr.yml +55 -0
  173. package/src/i18n/index.ts +55 -0
  174. package/src/i18n/loaders/raw-modules.d.ts +15 -0
  175. package/src/i18n/loaders/yaml.ts +35 -0
  176. package/src/i18n/strategies.ts +4 -0
  177. package/src/i18n/types.ts +34 -0
  178. package/src/i18n/useI18n.ts +34 -0
  179. package/src/index.ts +453 -0
  180. package/src/kernel/EventRouter.ts +23 -0
  181. package/src/kernel/Kernel.api.ts +79 -0
  182. package/src/kernel/Kernel.auth.ts +120 -0
  183. package/src/kernel/Kernel.i18n.ts +29 -0
  184. package/src/kernel/Kernel.modules.ts +170 -0
  185. package/src/kernel/Kernel.registries.ts +237 -0
  186. package/src/kernel/Kernel.routing.ts +334 -0
  187. package/src/kernel/Kernel.ts +460 -0
  188. package/src/kernel/Kernel.types.ts +263 -0
  189. package/src/kernel/Kernel.vue.ts +304 -0
  190. package/src/kernel/KernelContext.entities.ts +80 -0
  191. package/src/kernel/KernelContext.events.ts +57 -0
  192. package/src/kernel/KernelContext.i18n.ts +37 -0
  193. package/src/kernel/KernelContext.permissions.ts +38 -0
  194. package/src/kernel/KernelContext.routing.ts +280 -0
  195. package/src/kernel/KernelContext.ts +252 -0
  196. package/src/kernel/KernelContext.types.ts +173 -0
  197. package/src/kernel/KernelContext.zones.ts +54 -0
  198. package/src/kernel/Module.ts +169 -0
  199. package/src/kernel/ModuleLoader.ts +645 -0
  200. package/src/kernel/SSEBridge.ts +11 -0
  201. package/src/kernel/SignalBus.ts +48 -0
  202. package/src/kernel/index.ts +56 -0
  203. package/src/module/index.ts +33 -0
  204. package/src/module/moduleRegistry.ts +492 -0
  205. package/src/modules/debug/AuthCollector.ts +501 -0
  206. package/src/modules/debug/Collector.ts +20 -0
  207. package/src/modules/debug/DebugBridge.ts +14 -0
  208. package/src/modules/debug/DebugModule.ts +220 -0
  209. package/src/modules/debug/EntitiesCollector.ts +839 -0
  210. package/src/modules/debug/ErrorCollector.ts +4 -0
  211. package/src/modules/debug/I18nCollector.ts +9 -0
  212. package/src/modules/debug/LocalStorageAdapter.ts +7 -0
  213. package/src/modules/debug/RouterCollector.ts +449 -0
  214. package/src/modules/debug/SignalCollector.ts +4 -0
  215. package/src/modules/debug/ToastCollector.ts +4 -0
  216. package/src/modules/debug/ZonesCollector.ts +447 -0
  217. package/src/modules/debug/components/DebugBar.vue +31 -0
  218. package/src/modules/debug/components/adminPanelsConfig.ts +42 -0
  219. package/src/modules/debug/components/index.ts +9 -0
  220. package/src/modules/debug/components/panels/AuthPanel.vue +267 -0
  221. package/src/modules/debug/components/panels/EntitiesPanel.vue +572 -0
  222. package/src/modules/debug/components/panels/I18nPanel.vue +738 -0
  223. package/src/modules/debug/components/panels/RouterPanel.vue +440 -0
  224. package/src/modules/debug/components/panels/ZonesPanel.vue +133 -0
  225. package/src/modules/debug/components/panels/index.ts +16 -0
  226. package/src/modules/debug/index.ts +58 -0
  227. package/src/modules/debug/styles.scss +2671 -0
  228. package/src/notifications/NotificationBadge.vue +35 -0
  229. package/src/notifications/NotificationListener.vue +71 -0
  230. package/src/notifications/NotificationModule.ts +76 -0
  231. package/src/notifications/NotificationPanel.vue +478 -0
  232. package/src/notifications/NotificationStore.ts +288 -0
  233. package/src/notifications/index.ts +42 -0
  234. package/src/notifications/styles.scss +32 -0
  235. package/src/orchestrator/Orchestrator.ts +427 -0
  236. package/src/orchestrator/index.ts +8 -0
  237. package/src/orchestrator/useOrchestrator.ts +80 -0
  238. package/src/plugin.ts +251 -0
  239. package/src/query/FilterQuery.ts +306 -0
  240. package/src/query/QueryExecutor.ts +341 -0
  241. package/src/query/index.ts +16 -0
  242. package/src/security/EntityRolesProvider.ts +385 -0
  243. package/src/security/PermissionMatcher.ts +152 -0
  244. package/src/security/PermissionRegistry.ts +273 -0
  245. package/src/security/PersistableRolesProvider.ts +584 -0
  246. package/src/security/RolesManager.ts +136 -0
  247. package/src/security/RolesProvider.ts +167 -0
  248. package/src/security/RolesProviderStorage.ts +211 -0
  249. package/src/security/SecurityModule.ts +94 -0
  250. package/src/security/StaticRolesProvider.ts +117 -0
  251. package/src/security/UsersManager.ts +163 -0
  252. package/src/security/index.ts +77 -0
  253. package/src/security/pages/RoleForm.vue +276 -0
  254. package/src/security/pages/RoleList.vue +123 -0
  255. package/src/styles/_alerts.scss +95 -0
  256. package/src/styles/_buttons.scss +391 -0
  257. package/src/styles/_cards.scss +241 -0
  258. package/src/styles/_code.scss +78 -0
  259. package/src/styles/_dialogs.scss +55 -0
  260. package/src/styles/_filter-bar.scss +70 -0
  261. package/src/styles/_forms.scss +434 -0
  262. package/src/styles/_helpers.scss +153 -0
  263. package/src/styles/_lists.scss +225 -0
  264. package/src/styles/_main.scss +356 -0
  265. package/src/styles/_markdown.scss +88 -0
  266. package/src/styles/_responsive.scss +255 -0
  267. package/src/styles/_show-pages.scss +186 -0
  268. package/src/styles/_sidebar.scss +380 -0
  269. package/src/styles/_states.scss +115 -0
  270. package/src/styles/_stats.scss +47 -0
  271. package/src/styles/_variables.scss +224 -0
  272. package/src/styles/index.scss +38 -0
  273. package/src/styles/theme/_components.scss +331 -0
  274. package/src/styles/theme/_index.scss +10 -0
  275. package/src/styles/theme/_tokens.scss +147 -0
  276. package/src/styles/theme/_utilities.scss +175 -0
  277. package/src/toast/ToastBridgeModule.ts +68 -0
  278. package/src/toast/ToastListener.vue +55 -0
  279. package/src/toast/index.ts +26 -0
  280. package/src/toast/useSignalToast.ts +154 -0
  281. package/src/types/index.ts +285 -0
  282. package/src/types/pluralize.d.ts +19 -0
  283. package/src/types/quarkernel.d.ts +50 -0
  284. package/src/utils/formatters.ts +174 -0
  285. package/src/utils/index.ts +35 -0
  286. package/src/utils/transformers.ts +131 -0
  287. package/src/vite/qdadmDebugPlugin.ts +401 -0
  288. package/src/vite-env.d.ts +50 -0
  289. package/src/zones/ZoneRegistry.ts +934 -0
  290. package/src/zones/index.ts +29 -0
  291. package/src/zones/zones.ts +191 -0
@@ -0,0 +1,304 @@
1
+ import {
2
+ createApp,
3
+ h,
4
+ defineComponent,
5
+ ref,
6
+ type App,
7
+ type Component,
8
+ type Ref,
9
+ } from 'vue'
10
+ import { createPinia } from 'pinia'
11
+ import ToastService from 'primevue/toastservice'
12
+ import ConfirmationService from 'primevue/confirmationservice'
13
+ import Tooltip from 'primevue/tooltip'
14
+ import Toast from 'primevue/toast'
15
+ import ToastListener from '../toast/ToastListener.vue'
16
+ import { createQdadm } from '../plugin.js'
17
+ import { createNotificationStore, NOTIFICATION_KEY } from '../notifications/NotificationStore'
18
+ import { I18N_INJECTION_KEY } from '../i18n/useI18n'
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ type Self = any
21
+
22
+ /**
23
+ * Reactive reference to the debug bar component, set by the Kernel
24
+ * constructor when `debugBar.component` is provided.
25
+ *
26
+ * Why a window-stashed ref instead of a plain module-level export:
27
+ * Vite's HMR can fragment a single source module into multiple live
28
+ * instances (each importer getting a different `?t=…` version after
29
+ * HMR), so a module-level `const ref` is NOT shared across
30
+ * importers. Stashing the ref on `window.__qdadmDebugBarRef` (and
31
+ * lazy-initialising) is the only way to guarantee a single instance
32
+ * across all callers in dev. The Kernel writes via
33
+ * `setQdadmDebugBar()`; `<QdadmRoot />` reads via the same getter.
34
+ */
35
+ const QDADM_DEBUG_BAR_GLOBAL_KEY = '__qdadmDebugBarRef'
36
+
37
+ export function getQdadmDebugBarRef(): Ref<Component | null> {
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ const w = typeof window !== 'undefined' ? (window as any) : null
40
+ if (w && w[QDADM_DEBUG_BAR_GLOBAL_KEY]) return w[QDADM_DEBUG_BAR_GLOBAL_KEY]
41
+ const r = ref<Component | null>(null)
42
+ if (w) w[QDADM_DEBUG_BAR_GLOBAL_KEY] = r
43
+ return r
44
+ }
45
+
46
+ /** Back-compat alias — same instance as `getQdadmDebugBarRef()`. */
47
+ export const qdadmDebugBarRef: Ref<Component | null> = getQdadmDebugBarRef()
48
+
49
+ /**
50
+ * Set the debug bar component reference (called from Kernel
51
+ * constructor). Equivalent to `getQdadmDebugBarRef().value = component`.
52
+ */
53
+ export function setQdadmDebugBar(component: Component | null): void {
54
+ getQdadmDebugBarRef().value = component
55
+ }
56
+
57
+ /**
58
+ * Patch Kernel prototype with Vue app creation methods.
59
+ */
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ export function applyVueMethods(KernelClass: { prototype: any }): void {
62
+ const proto = KernelClass.prototype as Self
63
+
64
+ /**
65
+ * Create layout components map for useLayoutResolver
66
+ */
67
+ proto._createLayoutComponents = function (this: Self): void {
68
+ const layouts = this.options.layouts || {}
69
+ this.layoutComponents = {
70
+ list: layouts.list || layouts.ListLayout || null,
71
+ form: layouts.form || layouts.FormLayout || null,
72
+ dashboard: layouts.dashboard || layouts.DashboardLayout || null,
73
+ base: layouts.base || layouts.BaseLayout || null,
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Create Vue app instance.
79
+ *
80
+ * When `options.existingApp` is provided, the Kernel reuses the
81
+ * host's app and skips its own `createApp(WrappedRoot)`. The host
82
+ * is then responsible for rendering qdadm's DOM extras (Toast,
83
+ * ToastListener, DebugBar) — see `<QdadmRoot />` for a drop-in
84
+ * helper that does it.
85
+ *
86
+ * `options.root` is ignored in this mode (the host already mounted
87
+ * its own root).
88
+ */
89
+ proto._createVueApp = function (this: Self): void {
90
+ if (this.options.existingApp) {
91
+ this.vueApp = this.options.existingApp
92
+ return
93
+ }
94
+
95
+ if (!this.options.root) {
96
+ throw new Error('[Kernel] root component is required (or pass options.existingApp)')
97
+ }
98
+
99
+ const OriginalRoot = this.options.root
100
+ const debugBarRef = getQdadmDebugBarRef()
101
+ const DebugBarComponent =
102
+ this.options.debugBar?.component && debugBarRef.value
103
+ ? debugBarRef.value
104
+ : null
105
+ const hasPrimeVue = !!this.options.primevue?.plugin
106
+ const appKey = this._appKey
107
+
108
+ const WrappedRoot = defineComponent({
109
+ name: 'QdadmRootWrapper',
110
+ setup() {
111
+ return () => {
112
+ const children = [h(OriginalRoot, { key: appKey.value })]
113
+
114
+ if (hasPrimeVue) {
115
+ children.push(h(Toast))
116
+ children.push(h(ToastListener))
117
+ }
118
+
119
+ if (DebugBarComponent) {
120
+ children.push(h(DebugBarComponent))
121
+ }
122
+
123
+ return h(
124
+ 'div',
125
+ { id: 'qdadm-root', style: 'display: contents' },
126
+ children
127
+ )
128
+ }
129
+ },
130
+ })
131
+
132
+ this.vueApp = createApp(WrappedRoot)
133
+ }
134
+
135
+ /**
136
+ * Install all plugins on Vue app.
137
+ *
138
+ * When a host shell uses `existingApp`, it may have already
139
+ * installed Pinia / PrimeVue / vue-router. Calling `app.use(plugin)`
140
+ * twice is harmless for stateless plugins (vue-router, Pinia
141
+ * recognise the duplicate and no-op), but PrimeVue does not — guard
142
+ * with `_qdadmPluginsInstalled` markers on globalProperties so the
143
+ * Kernel never double-installs PrimeVue, ToastService, or
144
+ * ConfirmationService.
145
+ */
146
+ proto._installPlugins = function (this: Self): void {
147
+ const app = this.vueApp!
148
+ const { authAdapter, features, primevue, existingApp } = this.options
149
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
150
+ const marks = (app.config.globalProperties as any).__qdadmInstalled ??= {
151
+ pinia: false,
152
+ primevue: false,
153
+ router: false,
154
+ }
155
+
156
+ if (!marks.pinia) {
157
+ app.use(createPinia())
158
+ marks.pinia = true
159
+ }
160
+
161
+ if (primevue?.plugin && !marks.primevue) {
162
+ const pvConfig = {
163
+ theme: {
164
+ preset: primevue.theme,
165
+ options: {
166
+ darkModeSelector: '.dark-mode',
167
+ ...primevue.options,
168
+ },
169
+ },
170
+ }
171
+ app.use(primevue.plugin as { install: (app: App, options: unknown) => void }, pvConfig)
172
+ app.use(ToastService)
173
+ app.use(ConfirmationService)
174
+ app.directive('tooltip', Tooltip)
175
+ marks.primevue = true
176
+ }
177
+
178
+ // Skip vue-router install when the host owned the router from the
179
+ // start — they already called `app.use(router)`. Calling it again
180
+ // emits Vue's "Plugin has already been applied" warning. When
181
+ // Kernel created the router itself, install is required.
182
+ if (!marks.router && !this.options.existingRouter) {
183
+ app.use(this.router!)
184
+ marks.router = true
185
+ }
186
+
187
+ // Avoid eslint unused-var warning when host owns the app
188
+ void existingApp
189
+
190
+ for (const [key, value] of this._pendingProvides) {
191
+ app.provide(key, value)
192
+ }
193
+ this._pendingProvides.clear()
194
+
195
+ for (const [name, component] of this._pendingComponents) {
196
+ app.component(name, component)
197
+ }
198
+ this._pendingComponents.clear()
199
+
200
+ const { homeRoute } = this.options
201
+ const homeRouteName =
202
+ typeof homeRoute === 'object' ? homeRoute?.name : homeRoute
203
+
204
+ app.provide('qdadmZoneRegistry', this.zoneRegistry)
205
+ app.provide('qdadmActiveStack', this.activeStack)
206
+ app.provide('qdadmStackHydrator', this.stackHydrator)
207
+
208
+ if (this.options.debug && typeof window !== 'undefined') {
209
+ const self = this
210
+ // Single namespaced surface for browser-console & agent introspection.
211
+ // The `debug` sub-object proxies to whatever DebugBridge the DebugModule
212
+ // installed (resolved lazily so we don't depend on module load order).
213
+ const debugProxy = {
214
+ get bridge() {
215
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
216
+ const debugMod = (self as any).moduleLoader?.getModules?.()?.get?.('debug')
217
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
218
+ return debugMod?.getBridge?.() ?? (debugMod as any)?._bridge ?? null
219
+ },
220
+ describe(): unknown {
221
+ const b = this.bridge
222
+ return b ? b.describe() : null
223
+ },
224
+ dump(): unknown {
225
+ const b = this.bridge
226
+ return b ? b.dump() : null
227
+ },
228
+ call(name: string, action: string, args: Record<string, unknown> = {}): Promise<unknown> {
229
+ const b = this.bridge
230
+ if (!b) return Promise.reject(new Error('[qdadm] DebugBridge unavailable'))
231
+ return b.call(name, action, args)
232
+ },
233
+ }
234
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
235
+ ;(window as any).__qdadm = {
236
+ kernel: this,
237
+ orchestrator: this.orchestrator,
238
+ signals: this.signals,
239
+ hooks: this.hookRegistry,
240
+ zones: this.zoneRegistry,
241
+ activeStack: this.activeStack,
242
+ stackHydrator: this.stackHydrator,
243
+ deferred: this.deferred,
244
+ router: this.router,
245
+ i18n: this.i18nInstance,
246
+ get: (name: string) => this.orchestrator!.get(name),
247
+ managers: () => this.orchestrator!.getRegisteredNames(),
248
+ debug: debugProxy,
249
+ }
250
+ console.debug(
251
+ '[qdadm] Debug mode: window.__qdadm.{kernel,orchestrator,signals,hooks,zones,router,i18n,debug.{describe,dump,call}}'
252
+ )
253
+ }
254
+
255
+ app.provide('qdadmSignals', this.signals)
256
+
257
+ if (this.i18nInstance) {
258
+ app.provide(I18N_INJECTION_KEY, this.i18nInstance)
259
+ app.provide('qdadmI18n', this.i18nInstance)
260
+ }
261
+
262
+ if (this.sseBridge) {
263
+ app.provide('qdadmSSEBridge', this.sseBridge)
264
+ }
265
+
266
+ app.provide('qdadmHooks', this.hookRegistry)
267
+ app.provide('qdadmDeferred', this.deferred)
268
+ app.provide('qdadmLayoutComponents', this.layoutComponents)
269
+ // Surface PrimeVue presence so host-rendered <QdadmRoot /> can
270
+ // decide whether to mount Toast / ToastListener.
271
+ app.provide('qdadmHasPrimeVue', !!primevue?.plugin)
272
+
273
+ if (this.securityChecker) {
274
+ app.provide('qdadmSecurityChecker', this.securityChecker)
275
+ }
276
+ if (this.permissionRegistry) {
277
+ app.provide('qdadmPermissionRegistry', this.permissionRegistry)
278
+ }
279
+
280
+ // Create and provide notification store if notifications are enabled
281
+ if (this.options.notifications?.enabled) {
282
+ this.notificationStore = createNotificationStore({
283
+ maxNotifications: this.options.notifications.maxNotifications,
284
+ })
285
+ app.provide(NOTIFICATION_KEY, this.notificationStore)
286
+ }
287
+
288
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
289
+ const qdadmOptions: any = {
290
+ orchestrator: this.orchestrator,
291
+ authAdapter,
292
+ router: this.router,
293
+ toast: app.config.globalProperties.$toast,
294
+ app: this.options.app,
295
+ homeRoute: homeRouteName,
296
+ features: {
297
+ auth: !!authAdapter,
298
+ poweredBy: true,
299
+ ...features,
300
+ },
301
+ }
302
+ app.use(createQdadm(qdadmOptions) as unknown as { install: (app: App) => void })
303
+ }
304
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Patch KernelContext prototype with entity registration methods:
3
+ * - entity(name, config) — generic EntityManager registration
4
+ * - userEntity(options) — UsersManager registration with conventions
5
+ */
6
+
7
+ import { managerFactory, type ManagerFactoryContext } from '../entity/factory.js'
8
+ import type { EntityManager } from '../entity/EntityManager'
9
+ import { UsersManager } from '../security/UsersManager'
10
+ import type { UserEntityOptions } from './KernelContext.types'
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ type Self = any
14
+
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ export function applyEntityMethods(KernelContextClass: { prototype: any }): void {
17
+ const proto = KernelContextClass.prototype as Self
18
+
19
+ /**
20
+ * Register an entity manager.
21
+ *
22
+ * Uses managerFactory to resolve config into a manager instance.
23
+ * Registers with Orchestrator for CRUD operations.
24
+ */
25
+ proto.entity = function (
26
+ this: Self,
27
+ name: string,
28
+ config: string | Record<string, unknown> | EntityManager
29
+ ): Self {
30
+ const factoryContext = {
31
+ storageResolver: this._kernel.options.storageResolver,
32
+ managerResolver: this._kernel.options.managerResolver,
33
+ managerRegistry: this._kernel.options.managerRegistry || {},
34
+ } as ManagerFactoryContext
35
+
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ const manager = managerFactory(config as any, name, factoryContext)
38
+
39
+ if (this._kernel.orchestrator) {
40
+ this._kernel.orchestrator.register(name, manager)
41
+ }
42
+
43
+ if (this._kernel.permissionRegistry) {
44
+ this._kernel.permissionRegistry.registerEntity(name, {
45
+ module: (this._module?.constructor as { name?: string })?.name || 'unknown',
46
+ // Register entity-own:* permissions if manager has isOwn configured
47
+ hasOwnership: !!(manager as unknown as { _isOwn?: unknown })._isOwn,
48
+ })
49
+ }
50
+
51
+ // Track entity → module for the 'module' i18n key strategy
52
+ if (this._kernel.i18nInstance) {
53
+ const moduleName = (this._module?.constructor as { name?: string })?.name
54
+ if (moduleName) {
55
+ this._kernel.i18nInstance.registerEntityModule(name, moduleName)
56
+ }
57
+ }
58
+
59
+ return this
60
+ }
61
+
62
+ /**
63
+ * Register a users entity with standard fields and role linking.
64
+ */
65
+ proto.userEntity = function (this: Self, options: UserEntityOptions): Self {
66
+ const manager = new UsersManager(options)
67
+
68
+ if (this._kernel.orchestrator) {
69
+ this._kernel.orchestrator.register('users', manager)
70
+ }
71
+
72
+ if (this._kernel.permissionRegistry) {
73
+ this._kernel.permissionRegistry.registerEntity('users', {
74
+ module: (this._module?.constructor as { name?: string })?.name || 'unknown',
75
+ })
76
+ }
77
+
78
+ return this
79
+ }
80
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Patch KernelContext prototype with event-bus / hook / deferred methods:
3
+ * - on(signal, handler, options) — signal subscription, auto-cleaned on
4
+ * module disconnect
5
+ * - hook(hookName, handler, options) — hook registration
6
+ * - defer(name, factory) — queue a deferred task
7
+ */
8
+
9
+ import type { ListenerOptions } from '@quazardous/quarkernel'
10
+ import type {
11
+ DeferredFactory,
12
+ HookHandler,
13
+ SignalHandler,
14
+ } 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 applyEventMethods(KernelContextClass: { prototype: any }): void {
21
+ const proto = KernelContextClass.prototype as Self
22
+
23
+ proto.on = function (
24
+ this: Self,
25
+ signal: string,
26
+ handler: SignalHandler,
27
+ options: ListenerOptions = {}
28
+ ): Self {
29
+ if (this._kernel.signals) {
30
+ const cleanup = this._kernel.signals.on(signal, handler, options)
31
+ // Register cleanup with module for automatic unsubscribe on disconnect
32
+ if (this._module && typeof this._module._addSignalCleanup === 'function') {
33
+ this._module._addSignalCleanup(cleanup)
34
+ }
35
+ }
36
+ return this
37
+ }
38
+
39
+ proto.hook = function (
40
+ this: Self,
41
+ hookName: string,
42
+ handler: HookHandler,
43
+ options: Record<string, unknown> = {}
44
+ ): Self {
45
+ if (this._kernel.hookRegistry) {
46
+ this._kernel.hookRegistry.register(hookName, handler, options)
47
+ }
48
+ return this
49
+ }
50
+
51
+ proto.defer = function (this: Self, name: string, factory: DeferredFactory): Self {
52
+ if (this._kernel.deferred) {
53
+ this._kernel.deferred.queue(name, factory)
54
+ }
55
+ return this
56
+ }
57
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Patch KernelContext prototype with i18n declarative methods:
3
+ * - messages(locale, bundle) — declare translations
4
+ * - aliases(patterns) — declare pattern aliases
5
+ * - messagesProvider(provider) — register a TranslationProvider
6
+ */
7
+
8
+ import type { AliasPattern, MessagesBundle, TranslationProvider } from '../i18n/types'
9
+
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ type Self = any
12
+
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ export function applyI18nMethods(KernelContextClass: { prototype: any }): void {
15
+ const proto = KernelContextClass.prototype as Self
16
+
17
+ proto.messages = function (this: Self, locale: string, bundle: MessagesBundle): Self {
18
+ if (this._kernel.i18nInstance) {
19
+ this._kernel.i18nInstance.addMessages(locale, bundle)
20
+ }
21
+ return this
22
+ }
23
+
24
+ proto.aliases = function (this: Self, patterns: AliasPattern[]): Self {
25
+ if (this._kernel.i18nInstance) {
26
+ this._kernel.i18nInstance.addAliases(patterns)
27
+ }
28
+ return this
29
+ }
30
+
31
+ proto.messagesProvider = function (this: Self, provider: TranslationProvider): Self {
32
+ if (this._kernel.i18nInstance) {
33
+ this._kernel.i18nInstance.addProvider(provider)
34
+ }
35
+ return this
36
+ }
37
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Patch KernelContext prototype with permission registration methods:
3
+ * - permissions(namespace, perms, options) — generic registration
4
+ * - entityPermissions(entity, perms) — shorthand for entity-scoped
5
+ */
6
+
7
+ import type { PermissionMeta, PermissionOptions } from './KernelContext.types'
8
+
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ type Self = any
11
+
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ export function applyPermissionMethods(KernelContextClass: { prototype: any }): void {
14
+ const proto = KernelContextClass.prototype as Self
15
+
16
+ proto.permissions = function (
17
+ this: Self,
18
+ namespace: string,
19
+ permissions: Record<string, string | PermissionMeta>,
20
+ options: PermissionOptions = {}
21
+ ): Self {
22
+ if (this._kernel.permissionRegistry) {
23
+ this._kernel.permissionRegistry.register(namespace, permissions, {
24
+ ...options,
25
+ module: (this._module?.constructor as { name?: string })?.name || 'unknown',
26
+ })
27
+ }
28
+ return this
29
+ }
30
+
31
+ proto.entityPermissions = function (
32
+ this: Self,
33
+ entity: string,
34
+ permissions: Record<string, string | PermissionMeta>
35
+ ): Self {
36
+ return this.permissions(entity, permissions, { isEntity: true })
37
+ }
38
+ }