@quazardous/qdadm 2.4.4 → 2.4.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quazardous/qdadm",
3
- "version": "2.4.4",
3
+ "version": "2.4.5",
4
4
  "description": "Vue 3 framework for admin dashboards with PrimeVue",
5
5
  "author": "quazardous",
6
6
  "license": "MIT",
@@ -501,10 +501,7 @@ export class EntityManager<T extends EntityRecord = EntityRecord> {
501
501
  * Check if SecurityChecker is configured via authAdapter
502
502
  */
503
503
  protected _hasSecurityChecker(): boolean {
504
- return (
505
- (this.authAdapter as unknown as { _securityChecker?: unknown })
506
- ?._securityChecker != null
507
- )
504
+ return this.authAdapter?.hasSecurityChecker?.() ?? false
508
505
  }
509
506
 
510
507
  /**
@@ -41,6 +41,16 @@ export class EntityAuthAdapter {
41
41
  this._securityChecker = checker
42
42
  }
43
43
 
44
+ /**
45
+ * Whether a SecurityChecker is configured (#1196).
46
+ *
47
+ * Public capability probe — EntityManager used to reach into the
48
+ * private _securityChecker field through a cast.
49
+ */
50
+ hasSecurityChecker(): boolean {
51
+ return this._securityChecker != null
52
+ }
53
+
44
54
  /**
45
55
  * Check if current user is granted an attribute (Symfony-like contract)
46
56
  *
@@ -52,28 +52,24 @@ export interface SecurityCheckerConfig {
52
52
  */
53
53
  export class SecurityChecker {
54
54
  protected _rolesProvider: RoleProvider
55
- protected _legacyRoleHierarchy: RoleHierarchy | null
56
55
  readonly getCurrentUser: () => AuthUser | null
57
56
 
58
57
  constructor({ rolesProvider, roleHierarchy, rolePermissions, getCurrentUser }: SecurityCheckerOptions) {
59
- // Support both new rolesProvider and legacy rolePermissions
60
58
  if (rolesProvider) {
61
59
  this._rolesProvider = rolesProvider
62
- this._legacyRoleHierarchy = null
63
60
  } else {
64
- // Legacy: create static provider from rolePermissions
61
+ // Legacy options (roleHierarchy/rolePermissions) are normalized ONCE
62
+ // into a static provider (#1196) — the parallel _legacyRoleHierarchy
63
+ // branch is gone; only the provider path remains.
65
64
  const hierarchyConfig =
66
- roleHierarchy instanceof RoleHierarchy ? {} : (roleHierarchy as RoleHierarchyConfig) || {}
65
+ roleHierarchy instanceof RoleHierarchy
66
+ ? roleHierarchy.map
67
+ : (roleHierarchy as RoleHierarchyConfig) || {}
67
68
 
68
69
  this._rolesProvider = new StaticRoleProvider({
69
70
  role_hierarchy: hierarchyConfig,
70
71
  role_permissions: rolePermissions || {},
71
72
  })
72
-
73
- this._legacyRoleHierarchy =
74
- roleHierarchy instanceof RoleHierarchy
75
- ? roleHierarchy
76
- : new RoleHierarchy(hierarchyConfig)
77
73
  }
78
74
 
79
75
  this.getCurrentUser = getCurrentUser
@@ -83,9 +79,6 @@ export class SecurityChecker {
83
79
  * Get role hierarchy (dynamically resolved from rolesProvider)
84
80
  */
85
81
  get roleHierarchy(): RoleHierarchy {
86
- if (this._legacyRoleHierarchy) {
87
- return this._legacyRoleHierarchy
88
- }
89
82
  return new RoleHierarchy(this._rolesProvider.getHierarchy())
90
83
  }
91
84
 
@@ -1,14 +1,14 @@
1
1
  import type { AxiosLikeClient, AxiosError } from './Kernel.types'
2
+ import type { Kernel } from './Kernel'
2
3
 
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
- type Self = any
4
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
5
+ type Self = Kernel
5
6
 
6
7
  /**
7
8
  * Patch Kernel prototype with API client methods.
8
9
  */
9
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
- export function applyApiMethods(KernelClass: { prototype: any }): void {
11
- const proto = KernelClass.prototype as Self
10
+ export function applyApiMethods(KernelClass: { prototype: Kernel }): void {
11
+ const proto = KernelClass.prototype
12
12
 
13
13
  /**
14
14
  * Setup an axios client with automatic auth and error handling
@@ -1,14 +1,14 @@
1
1
  import { authFactory, CompositeAuthAdapter } from '../entity/auth'
2
+ import type { Kernel } from './Kernel'
2
3
 
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
- type Self = any
4
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
5
+ type Self = Kernel
5
6
 
6
7
  /**
7
8
  * Patch Kernel prototype with auth-related methods.
8
9
  */
9
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
- export function applyAuthMethods(KernelClass: { prototype: any }): void {
11
- const proto = KernelClass.prototype as Self
10
+ export function applyAuthMethods(KernelClass: { prototype: Kernel }): void {
11
+ const proto = KernelClass.prototype
12
12
 
13
13
  /**
14
14
  * Resolve entityAuthAdapter through authFactory
@@ -9,13 +9,13 @@
9
9
 
10
10
  import { I18n } from '../i18n/I18n'
11
11
  import type { I18nOptions } from '../i18n/types'
12
+ import type { Kernel } from './Kernel'
12
13
 
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- type Self = any
14
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
15
+ type Self = Kernel
15
16
 
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- export function applyI18nMethods(KernelClass: { prototype: any }): void {
18
- const proto = KernelClass.prototype as Self
17
+ export function applyI18nMethods(KernelClass: { prototype: Kernel }): void {
18
+ const proto = KernelClass.prototype
19
19
 
20
20
  proto._createI18n = function (this: Self): void {
21
21
  const opts = (this.options.i18n as I18nOptions | undefined) ?? {}
@@ -1,15 +1,15 @@
1
1
  import { initModules, setSectionOrder } from '../module/moduleRegistry'
2
2
  import { createModuleLoader, type ModuleLike } from './ModuleLoader'
3
3
  import { createKernelContext, type KernelContext } from './KernelContext'
4
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
- type Self = any
4
+ import type { Kernel } from './Kernel'
5
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
6
+ type Self = Kernel
6
7
 
7
8
  /**
8
9
  * Patch Kernel prototype with module-related methods.
9
10
  */
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- export function applyModuleMethods(KernelClass: { prototype: any }): void {
12
- const proto = KernelClass.prototype as Self
11
+ export function applyModuleMethods(KernelClass: { prototype: Kernel }): void {
12
+ const proto = KernelClass.prototype
13
13
 
14
14
  /**
15
15
  * Fire entity cache warmups
@@ -13,15 +13,15 @@ import { ActiveStack } from '../chain/ActiveStack.js'
13
13
  import { StackHydrator } from '../chain/StackHydrator.js'
14
14
  import { Orchestrator } from '../orchestrator/Orchestrator'
15
15
  import type { EntityAuthAdapter } from '../entity/auth/EntityAuthAdapter'
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- type Self = any
16
+ import type { Kernel } from './Kernel'
17
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
18
+ type Self = Kernel
18
19
 
19
20
  /**
20
21
  * Patch Kernel prototype with registry-related methods.
21
22
  */
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
- export function applyRegistryMethods(KernelClass: { prototype: any }): void {
24
- const proto = KernelClass.prototype as Self
23
+ export function applyRegistryMethods(KernelClass: { prototype: Kernel }): void {
24
+ const proto = KernelClass.prototype
25
25
 
26
26
  /**
27
27
  * Create signal bus for event-driven communication.
@@ -8,15 +8,15 @@ import {
8
8
  type RouteRecordNormalized,
9
9
  } from 'vue-router'
10
10
  import { getRoutes } from '../module/moduleRegistry'
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- type Self = any
11
+ import type { Kernel } from './Kernel'
12
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
13
+ type Self = Kernel
13
14
 
14
15
  /**
15
16
  * Patch Kernel prototype with routing-related methods.
16
17
  */
17
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
- export function applyRoutingMethods(KernelClass: { prototype: any }): void {
19
- const proto = KernelClass.prototype as Self
18
+ export function applyRoutingMethods(KernelClass: { prototype: Kernel }): void {
19
+ const proto = KernelClass.prototype
20
20
 
21
21
  /**
22
22
  * Create Vue Router.
@@ -16,8 +16,9 @@ import ToastListener from '../toast/ToastListener.vue'
16
16
  import { createQdadm } from '../plugin.js'
17
17
  import { createNotificationStore, NOTIFICATION_KEY } from '../notifications/NotificationStore'
18
18
  import { I18N_INJECTION_KEY } from '../i18n/useI18n'
19
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
- type Self = any
19
+ import type { Kernel } from './Kernel'
20
+ // #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
21
+ type Self = Kernel
21
22
 
22
23
  /**
23
24
  * Reactive reference to the debug bar component, set by the Kernel
@@ -57,9 +58,8 @@ export function setQdadmDebugBar(component: Component | null): void {
57
58
  /**
58
59
  * Patch Kernel prototype with Vue app creation methods.
59
60
  */
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
61
+ export function applyVueMethods(KernelClass: { prototype: Kernel }): void {
62
+ const proto = KernelClass.prototype
63
63
 
64
64
  /**
65
65
  * Create layout components map for useLayoutResolver
@@ -8,13 +8,13 @@ import { managerFactory, type ManagerFactoryContext } from '../entity/factory.js
8
8
  import type { EntityManager } from '../entity/EntityManager'
9
9
  import { UsersManager } from '../security/UsersManager'
10
10
  import type { UserEntityOptions } from './KernelContext.types'
11
+ import type { KernelContext } from './KernelContext'
11
12
 
12
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
- type Self = any
13
+ // #1196 Phase B — this-typing against the real KernelContext shape (was Self = any)
14
+ type Self = KernelContext
14
15
 
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
16
+ export function applyEntityMethods(KernelContextClass: { prototype: KernelContext }): void {
17
+ const proto = KernelContextClass.prototype
18
18
 
19
19
  /**
20
20
  * Register an entity manager.
@@ -12,13 +12,13 @@ import type {
12
12
  HookHandler,
13
13
  SignalHandler,
14
14
  } from './KernelContext.types'
15
+ import type { KernelContext } from './KernelContext'
15
16
 
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- type Self = any
17
+ // #1196 Phase B — this-typing against the real KernelContext shape (was Self = any)
18
+ type Self = KernelContext
18
19
 
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
20
+ export function applyEventMethods(KernelContextClass: { prototype: KernelContext }): void {
21
+ const proto = KernelContextClass.prototype
22
22
 
23
23
  proto.on = function (
24
24
  this: Self,
@@ -6,13 +6,13 @@
6
6
  */
7
7
 
8
8
  import type { AliasPattern, MessagesBundle, TranslationProvider } from '../i18n/types'
9
+ import type { KernelContext } from './KernelContext'
9
10
 
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- type Self = any
11
+ // #1196 Phase B — this-typing against the real KernelContext shape (was Self = any)
12
+ type Self = KernelContext
12
13
 
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
14
+ export function applyI18nMethods(KernelContextClass: { prototype: KernelContext }): void {
15
+ const proto = KernelContextClass.prototype
16
16
 
17
17
  proto.messages = function (this: Self, locale: string, bundle: MessagesBundle): Self {
18
18
  if (this._kernel.i18nInstance) {
@@ -5,13 +5,13 @@
5
5
  */
6
6
 
7
7
  import type { PermissionMeta, PermissionOptions } from './KernelContext.types'
8
+ import type { KernelContext } from './KernelContext'
8
9
 
9
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
- type Self = any
10
+ // #1196 Phase B — this-typing against the real KernelContext shape (was Self = any)
11
+ type Self = KernelContext
11
12
 
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
13
+ export function applyPermissionMethods(KernelContextClass: { prototype: KernelContext }): void {
14
+ const proto = KernelContextClass.prototype
15
15
 
16
16
  proto.permissions = function (
17
17
  this: Self,
@@ -21,9 +21,10 @@ import type {
21
21
  ParentConfig,
22
22
  RouteOptions,
23
23
  } from './KernelContext.types'
24
+ import type { KernelContext } from './KernelContext'
24
25
 
25
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
- type Self = any
26
+ // #1196 Phase B — this-typing against the real KernelContext shape (was Self = any)
27
+ type Self = KernelContext
27
28
 
28
29
  /** Singularize a plural word (simple English rules) */
29
30
  function singularize(plural: string): string {
@@ -128,9 +129,8 @@ function resolveParentParam(opts: {
128
129
  return namespaced
129
130
  }
130
131
 
131
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
132
- export function applyRoutingMethods(KernelContextClass: { prototype: any }): void {
133
- const proto = KernelContextClass.prototype as Self
132
+ export function applyRoutingMethods(KernelContextClass: { prototype: KernelContext }): void {
133
+ const proto = KernelContextClass.prototype
134
134
 
135
135
  proto.routes = function (
136
136
  this: Self,
@@ -20,6 +20,7 @@ import type { DeferredRegistry } from '../deferred/DeferredRegistry.js'
20
20
  import type { SecurityChecker } from '../entity/auth/SecurityChecker'
21
21
  import type { PermissionRegistry } from '../security/PermissionRegistry'
22
22
  import type { I18n } from '../i18n/I18n'
23
+ import type { RouteParamResolverContext } from './KernelContext.routing'
23
24
 
24
25
  // ─────────────────────────────────────────────────────────────────────────────
25
26
  // Internal types — shared across patch modules, not exposed by index.ts
@@ -41,6 +42,10 @@ export interface AuthAdapter {
41
42
  export interface KernelOptions {
42
43
  debug?: boolean
43
44
  authAdapter?: AuthAdapter | null
45
+ /** Parent route param naming policy for child CRUD families (#1201). */
46
+ parentParamMode?: 'auto' | 'always' | 'bare'
47
+ /** Custom parent route param name resolver (#1201) — wins over parentParamMode. */
48
+ routeParamResolver?: (ctx: RouteParamResolverContext) => string | undefined
44
49
  storageResolver?: unknown
45
50
  managerResolver?: unknown
46
51
  managerRegistry?: Record<string, unknown>
@@ -12,13 +12,13 @@
12
12
 
13
13
  import type { Component } from 'vue'
14
14
  import type { BlockConfig, ZoneOptions } from './KernelContext.types'
15
+ import type { KernelContext } from './KernelContext'
15
16
 
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- type Self = any
17
+ // #1196 Phase B — this-typing against the real KernelContext shape (was Self = any)
18
+ type Self = KernelContext
18
19
 
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
20
+ export function applyZoneMethods(KernelContextClass: { prototype: KernelContext }): void {
21
+ const proto = KernelContextClass.prototype
22
22
 
23
23
  proto.zone = function (this: Self, name: string, options: ZoneOptions = {}): Self {
24
24
  if (this._kernel.zoneRegistry) {