@ibdop/platform-kit 1.0.0

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 (51) hide show
  1. package/README.md +63 -0
  2. package/dist/components/ErrorBoundary.d.ts +68 -0
  3. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  4. package/dist/components/Notification.d.ts +46 -0
  5. package/dist/components/Notification.d.ts.map +1 -0
  6. package/dist/components/VersionInfo.d.ts +18 -0
  7. package/dist/components/VersionInfo.d.ts.map +1 -0
  8. package/dist/components/index.d.ts +8 -0
  9. package/dist/components/index.d.ts.map +1 -0
  10. package/dist/hooks/index.d.ts +9 -0
  11. package/dist/hooks/index.d.ts.map +1 -0
  12. package/dist/hooks/useApi.d.ts +65 -0
  13. package/dist/hooks/useApi.d.ts.map +1 -0
  14. package/dist/hooks/useInfoData.d.ts +35 -0
  15. package/dist/hooks/useInfoData.d.ts.map +1 -0
  16. package/dist/hooks/usePermissions.d.ts +23 -0
  17. package/dist/hooks/usePermissions.d.ts.map +1 -0
  18. package/dist/hooks/useShellAuth.d.ts +23 -0
  19. package/dist/hooks/useShellAuth.d.ts.map +1 -0
  20. package/dist/hooks/useV1Config.d.ts +27 -0
  21. package/dist/hooks/useV1Config.d.ts.map +1 -0
  22. package/dist/index.cjs.js +18 -0
  23. package/dist/index.d.ts +10 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.es.js +1500 -0
  26. package/dist/index.umd.js +18 -0
  27. package/dist/services/api.d.ts +59 -0
  28. package/dist/services/api.d.ts.map +1 -0
  29. package/dist/services/index.d.ts +8 -0
  30. package/dist/services/index.d.ts.map +1 -0
  31. package/dist/services/logger.d.ts +41 -0
  32. package/dist/services/logger.d.ts.map +1 -0
  33. package/dist/types/index.d.ts +178 -0
  34. package/dist/types/index.d.ts.map +1 -0
  35. package/package.json +90 -0
  36. package/src/components/ErrorBoundary.tsx +292 -0
  37. package/src/components/Notification.tsx +297 -0
  38. package/src/components/VersionInfo.tsx +271 -0
  39. package/src/components/index.ts +14 -0
  40. package/src/global.d.ts +40 -0
  41. package/src/hooks/index.ts +13 -0
  42. package/src/hooks/useApi.ts +314 -0
  43. package/src/hooks/useInfoData.ts +124 -0
  44. package/src/hooks/usePermissions.ts +88 -0
  45. package/src/hooks/useShellAuth.ts +145 -0
  46. package/src/hooks/useV1Config.ts +112 -0
  47. package/src/index.ts +17 -0
  48. package/src/services/api.ts +290 -0
  49. package/src/services/index.ts +9 -0
  50. package/src/services/logger.ts +71 -0
  51. package/src/types/index.ts +215 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * useInfoData - Хук для загрузки информации о версии MF
3
+ *
4
+ * Загружает info.json с информацией о версии, Git commit, CI/CD данные
5
+ */
6
+
7
+ import { useState, useEffect, useCallback } from 'react'
8
+ import type { InfoData } from '../types'
9
+
10
+ // Development mode flag
11
+ const isDev = import.meta.env?.DEV === true || import.meta.env?.MODE === 'development'
12
+
13
+ /**
14
+ * Logger for useInfoData
15
+ */
16
+ const logger = {
17
+ log: (...args: unknown[]) => {
18
+ if (isDev) console.log('[useInfoData]', ...args)
19
+ },
20
+ warn: (...args: unknown[]) => {
21
+ if (isDev) console.warn('[useInfoData]', ...args)
22
+ },
23
+ error: (...args: unknown[]) => {
24
+ console.error('[useInfoData]', ...args)
25
+ },
26
+ }
27
+
28
+ /**
29
+ * Interface для props useInfoData
30
+ */
31
+ interface UseInfoDataProps {
32
+ mfeName?: string
33
+ }
34
+
35
+ /**
36
+ * Interface для результата useInfoData
37
+ */
38
+ interface UseInfoDataResult {
39
+ data: InfoData | null
40
+ isLoading: boolean
41
+ error: string | null
42
+ refetch: () => void
43
+ }
44
+
45
+ /**
46
+ * Получить mfeName из props или window
47
+ */
48
+ function getMfeName(propsMfeName?: string): string {
49
+ if (propsMfeName) return propsMfeName
50
+
51
+ // Try window.__MF_NAME__
52
+ if (typeof window !== 'undefined') {
53
+ const win = window as unknown as { __MF_NAME__?: string }
54
+ if (win.__MF_NAME__) return win.__MF_NAME__
55
+ }
56
+
57
+ return 'unknown-mfe'
58
+ }
59
+
60
+ /**
61
+ * Централизованный хук для загрузки информации о версии MF
62
+ *
63
+ * @param props - { mfeName?: string } - опционально имя MF
64
+ * @returns { data, isLoading, error, refetch }
65
+ *
66
+ * @example
67
+ * ```tsx
68
+ * const { data, isLoading, error } = useInfoData({ mfeName: '@ib-dop/mf-home' })
69
+ *
70
+ * if (isLoading) return <Loading />
71
+ * if (error) return <Error>{error}</Error>
72
+ *
73
+ * return <Badge>{data?.BUILD_VERSION}</Badge>
74
+ * ```
75
+ */
76
+ export function useInfoData(props?: UseInfoDataProps): UseInfoDataResult {
77
+ const [data, setData] = useState<InfoData | null>(null)
78
+ const [isLoading, setIsLoading] = useState(true)
79
+ const [error, setError] = useState<string | null>(null)
80
+
81
+ const fetchInfo = useCallback(() => {
82
+ const mfeName = getMfeName(props?.mfeName)
83
+
84
+ // Normalize mfeName (remove @ib-dop/ prefix)
85
+ const normalizedName = mfeName.replace('@ib-dop/', '')
86
+
87
+ logger.log('Fetching info for:', normalizedName)
88
+ setIsLoading(true)
89
+ setError(null)
90
+
91
+ fetch(`/svc/${normalizedName}/info.json`)
92
+ .then((response) => {
93
+ if (!response.ok) {
94
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`)
95
+ }
96
+ return response.json()
97
+ })
98
+ .then((result) => {
99
+ logger.log('Info loaded successfully')
100
+ setData(result as InfoData)
101
+ })
102
+ .catch((err) => {
103
+ logger.error('Failed to load info:', err)
104
+ setError(err instanceof Error ? err.message : String(err))
105
+ })
106
+ .finally(() => {
107
+ setIsLoading(false)
108
+ })
109
+ }, [props?.mfeName])
110
+
111
+ useEffect(() => {
112
+ fetchInfo()
113
+ }, [fetchInfo])
114
+
115
+ return {
116
+ data,
117
+ isLoading,
118
+ error,
119
+ refetch: fetchInfo,
120
+ }
121
+ }
122
+
123
+ // Named exports
124
+ export type { UseInfoDataProps, UseInfoDataResult }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * usePermissions - Хук для проверки прав доступа
3
+ *
4
+ * Предоставляет API для проверки прав пользователя на основе ролей
5
+ */
6
+
7
+ import { useMemo } from 'react'
8
+ import { useShellAuth } from './useShellAuth'
9
+ import type { MfPermissionsConfig, MfPermissions } from '../types'
10
+
11
+ // Development mode flag
12
+ const isDev = import.meta.env?.DEV === true || import.meta.env?.MODE === 'development'
13
+
14
+ /**
15
+ * Logger for usePermissions
16
+ */
17
+ const logger = {
18
+ log: (...args: unknown[]) => {
19
+ if (isDev) console.log('[usePermissions]', ...args)
20
+ },
21
+ warn: (...args: unknown[]) => {
22
+ if (isDev) console.warn('[usePermissions]', ...args)
23
+ },
24
+ }
25
+
26
+ /**
27
+ * Default permissions configuration
28
+ */
29
+ export const DEFAULT_PERMISSIONS_CONFIG: MfPermissionsConfig = {
30
+ canView: ['all'] as string[],
31
+ canEdit: ['ibdop-user', 'ibdop-admin', 'ibdop-devops'] as string[],
32
+ canDelete: ['ibdop-admin', 'ibdop-devops'] as string[],
33
+ canAdmin: ['ibdop-admin'] as string[],
34
+ canViewSensitiveData: ['ibdop-admin', 'ibdop-devops'] as string[],
35
+ canExportData: ['ibdop-user'] as string[],
36
+ canManageUsers: ['ibdop-admin'] as string[],
37
+ }
38
+
39
+ /**
40
+ * Централизованный хук для проверки прав доступа
41
+ *
42
+ * @param config - конфигурация прав доступа (опционально)
43
+ * @returns MfPermissions - объект с правами доступа
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const permissions = usePermissions()
48
+ *
49
+ * if (permissions.canAdmin) {
50
+ * return <AdminPanel />
51
+ * }
52
+ * ```
53
+ */
54
+ export function usePermissions(config: Partial<MfPermissionsConfig> = {}): MfPermissions {
55
+ const auth = useShellAuth()
56
+
57
+ const mergedConfig = useMemo(() => ({
58
+ ...DEFAULT_PERMISSIONS_CONFIG,
59
+ ...config,
60
+ }), [config])
61
+
62
+ // Extract user roles
63
+ const userRoles = useMemo(() => {
64
+ const roles = auth.user?.profile?.realm_roles || auth.user?.profile?.roles || []
65
+ return Array.isArray(roles) ? roles : [roles]
66
+ }, [auth.user])
67
+
68
+ logger.log('User roles:', userRoles)
69
+
70
+ // Check if user has permission
71
+ const hasPermission = (requiredRoles: string[]): boolean => {
72
+ if (requiredRoles.includes('all')) return true
73
+ return requiredRoles.some(role => userRoles.includes(role))
74
+ }
75
+
76
+ return {
77
+ canView: hasPermission(mergedConfig.canView),
78
+ canEdit: hasPermission(mergedConfig.canEdit),
79
+ canDelete: hasPermission(mergedConfig.canDelete),
80
+ canAdmin: hasPermission(mergedConfig.canAdmin),
81
+ canViewSensitiveData: hasPermission(mergedConfig.canViewSensitiveData),
82
+ canExportData: hasPermission(mergedConfig.canExportData),
83
+ canManageUsers: hasPermission(mergedConfig.canManageUsers),
84
+ }
85
+ }
86
+
87
+ // Named exports
88
+ export type { MfPermissionsConfig }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * useShellAuth - Хук для получения состояния авторизации из shell
3
+ *
4
+ * Паттерн: MF подключается к shell через window.__SHELL_AUTH_INSTANCE__
5
+ * и ожидает события 'shell-auth-ready' если auth ещё не готов.
6
+ */
7
+
8
+ import { useEffect, useState, useCallback, useRef } from 'react'
9
+ import type { ShellAuth } from '../types'
10
+
11
+ // Development mode flag
12
+ const isDev = import.meta.env?.DEV === true || import.meta.env?.MODE === 'development'
13
+
14
+ /**
15
+ * Logger for useShellAuth
16
+ */
17
+ const logger = {
18
+ log: (...args: unknown[]) => {
19
+ if (isDev) console.log('[useShellAuth]', ...args)
20
+ },
21
+ warn: (...args: unknown[]) => {
22
+ if (isDev) console.warn('[useShellAuth]', ...args)
23
+ },
24
+ }
25
+
26
+ /**
27
+ * Получить auth из window globals
28
+ */
29
+ function getAuth(): ShellAuth | null {
30
+ if (typeof window === 'undefined') return null
31
+
32
+ // Try __SHELL_AUTH_INSTANCE__ first
33
+ const win = window as unknown as { __SHELL_AUTH_INSTANCE__?: ShellAuth }
34
+ if (win.__SHELL_AUTH_INSTANCE__) {
35
+ return win.__SHELL_AUTH_INSTANCE__
36
+ }
37
+
38
+ // Try __SHELL_AUTH__ format
39
+ const win2 = window as unknown as { __SHELL_AUTH__?: { authInstance?: ShellAuth } }
40
+ if (win2.__SHELL_AUTH__?.authInstance) {
41
+ return win2.__SHELL_AUTH__.authInstance
42
+ }
43
+
44
+ return null
45
+ }
46
+
47
+ /**
48
+ * Централизованный хук для получения состояния авторизации из shell
49
+ *
50
+ * @returns ShellAuth - объект с состоянием авторизации
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * const auth = useShellAuth()
55
+ *
56
+ * if (auth.isLoading) return <Loading />
57
+ * if (!auth.isAuthenticated) return <Login />
58
+ *
59
+ * return <div>{auth.user?.profile?.preferred_username}</div>
60
+ * ```
61
+ */
62
+ export function useShellAuth(): ShellAuth {
63
+ const [auth, setAuth] = useState<ShellAuth | null>(null)
64
+ const [isLoading, setIsLoading] = useState(true)
65
+ const attemptsRef = useRef(0)
66
+ const maxAttempts = 20 // 10 seconds max wait (20 * 500ms)
67
+
68
+ const getAuthState = useCallback((): ShellAuth | null => {
69
+ return getAuth()
70
+ }, [])
71
+
72
+ useEffect(() => {
73
+ // Immediate check for auth
74
+ const immediateAuth = getAuthState()
75
+ if (immediateAuth) {
76
+ logger.log('Auth found immediately')
77
+ setAuth(immediateAuth)
78
+ setIsLoading(false)
79
+ return
80
+ }
81
+
82
+ // Subscribe to auth ready event
83
+ const handleAuthReady = (event: CustomEvent<ShellAuth>) => {
84
+ logger.log('Auth ready via event')
85
+ setAuth(event.detail)
86
+ setIsLoading(false)
87
+ }
88
+
89
+ // Fallback polling with limit
90
+ const interval = setInterval(() => {
91
+ attemptsRef.current++
92
+ const foundAuth = getAuthState()
93
+
94
+ if (foundAuth) {
95
+ logger.log('Auth found via polling, attempts:', attemptsRef.current)
96
+ setAuth(foundAuth)
97
+ setIsLoading(false)
98
+ clearInterval(interval)
99
+ } else if (attemptsRef.current >= maxAttempts) {
100
+ logger.warn('Auth timeout after', maxAttempts, 'attempts')
101
+ setIsLoading(false)
102
+ clearInterval(interval)
103
+ }
104
+ }, 500)
105
+
106
+ window.addEventListener('shell-auth-ready', handleAuthReady as EventListener)
107
+
108
+ return () => {
109
+ clearInterval(interval)
110
+ window.removeEventListener('shell-auth-ready', handleAuthReady as EventListener)
111
+ }
112
+ }, [getAuthState])
113
+
114
+ // Fallback auth when shell auth is not available
115
+ const fallbackAuth: ShellAuth = {
116
+ user: null,
117
+ isAuthenticated: false,
118
+ isLoading: isLoading,
119
+ signinRedirect: async () => {
120
+ logger.log('Redirecting to login')
121
+ const shellAuth = getAuth()
122
+ if (shellAuth?.signinRedirect) {
123
+ await shellAuth.signinRedirect()
124
+ } else {
125
+ if (typeof window !== 'undefined') {
126
+ window.location.href = '/'
127
+ }
128
+ }
129
+ },
130
+ removeUser: async () => {
131
+ const shellAuth = getAuth()
132
+ if (shellAuth?.removeUser) {
133
+ await shellAuth.removeUser()
134
+ }
135
+ },
136
+ }
137
+
138
+ const result = auth || fallbackAuth
139
+ logger.log('Auth result:', { isAuthenticated: result.isAuthenticated, isLoading: result.isLoading })
140
+
141
+ return result
142
+ }
143
+
144
+ // Named exports for specific helpers
145
+ export { getAuth }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * useV1Config - Хук для загрузки конфигурации из sessionStorage
3
+ *
4
+ * Загружает V1 конфигурацию, которая используется для OIDC и других настроек
5
+ */
6
+
7
+ import { useState, useEffect } from 'react'
8
+ import type { V1ConfigData } from '../types'
9
+
10
+ // Development mode flag
11
+ const isDev = import.meta.env?.DEV === true || import.meta.env?.MODE === 'development'
12
+
13
+ /**
14
+ * Logger for useV1Config
15
+ */
16
+ const logger = {
17
+ log: (...args: unknown[]) => {
18
+ if (isDev) console.log('[useV1Config]', ...args)
19
+ },
20
+ warn: (...args: unknown[]) => {
21
+ if (isDev) console.warn('[useV1Config]', ...args)
22
+ },
23
+ error: (...args: unknown[]) => {
24
+ console.error('[useV1Config]', ...args)
25
+ },
26
+ }
27
+
28
+ /**
29
+ * Default config for fallback
30
+ */
31
+ const DEFAULT_CONFIG: V1ConfigData = {
32
+ authority: '',
33
+ client_id: '',
34
+ environment: 'development',
35
+ }
36
+
37
+ /**
38
+ * Interface для результата useV1Config
39
+ */
40
+ interface UseV1ConfigResult {
41
+ data: V1ConfigData | null
42
+ isLoading: boolean
43
+ error: string | null
44
+ }
45
+
46
+ /**
47
+ * Централизованный хук для загрузки конфигурации из sessionStorage
48
+ *
49
+ * @returns { data, isLoading, error }
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * const { data, isLoading, error } = useV1Config()
54
+ *
55
+ * if (isLoading) return null
56
+ * if (error || !data) return <Error>{error}</Error>
57
+ *
58
+ * return <ConfigDisplay config={data} />
59
+ * ```
60
+ */
61
+ export function useV1Config(): UseV1ConfigResult {
62
+ const [data, setData] = useState<V1ConfigData | null>(null)
63
+ const [isLoading, setIsLoading] = useState(true)
64
+ const [error, setError] = useState<string | null>(null)
65
+
66
+ useEffect(() => {
67
+ const fetchConfig = () => {
68
+ // Check if sessionStorage is available
69
+ if (typeof sessionStorage === 'undefined') {
70
+ logger.warn('sessionStorage not available')
71
+ setError('sessionStorage not available')
72
+ setData(DEFAULT_CONFIG)
73
+ setIsLoading(false)
74
+ return
75
+ }
76
+
77
+ try {
78
+ const storedConfig = sessionStorage.getItem('config')
79
+
80
+ if (storedConfig) {
81
+ const parsed = JSON.parse(storedConfig)
82
+ setData({ ...DEFAULT_CONFIG, ...parsed })
83
+ setError(null)
84
+ logger.log('Config loaded successfully')
85
+ } else {
86
+ // Config not found - use defaults instead of error
87
+ setData(DEFAULT_CONFIG)
88
+ setError('Config not found in sessionStorage')
89
+ logger.warn('Config not found in sessionStorage')
90
+ }
91
+ } catch (err) {
92
+ // Parse error - use defaults
93
+ logger.error('Error parsing config:', err)
94
+ setData(DEFAULT_CONFIG)
95
+ setError('Error parsing config')
96
+ } finally {
97
+ setIsLoading(false)
98
+ }
99
+ }
100
+
101
+ fetchConfig()
102
+ }, [])
103
+
104
+ return {
105
+ data,
106
+ isLoading,
107
+ error,
108
+ }
109
+ }
110
+
111
+ // Named exports
112
+ export type { UseV1ConfigResult }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @ib-dop/platform-kit - Platform Development Kit for Microfrontends
3
+ *
4
+ * Unified toolkit for all microfrontends in the IB DOP Platform
5
+ */
6
+
7
+ // Types
8
+ export * from './types'
9
+
10
+ // Hooks
11
+ export * from './hooks'
12
+
13
+ // Components
14
+ export * from './components'
15
+
16
+ // Services
17
+ export * from './services'