@quantica-apps/platform-auth 0.1.1

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.
@@ -0,0 +1,37 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type PlatformKeycloakConfig } from './keycloak';
3
+ export interface PlatformAuthConfig {
4
+ readonly keycloak: PlatformKeycloakConfig;
5
+ readonly permissionsClientId?: string;
6
+ readonly skipAuth?: boolean;
7
+ readonly storageNamespace?: string;
8
+ }
9
+ export interface PlatformUserProfile {
10
+ readonly email?: string;
11
+ readonly firstName?: string;
12
+ readonly lastName?: string;
13
+ readonly username?: string;
14
+ }
15
+ export interface PlatformAuthContextValue {
16
+ readonly clearAccessBlock: () => void;
17
+ readonly error: string | null;
18
+ readonly hasClientRole: (role: string, clientId?: string) => boolean;
19
+ readonly hasRole: (role: string) => boolean;
20
+ readonly isAccessBlocked: boolean;
21
+ readonly isAuthenticated: boolean;
22
+ readonly isLoading: boolean;
23
+ readonly login: () => Promise<void>;
24
+ readonly logout: () => Promise<void>;
25
+ readonly refreshToken: (force?: boolean) => Promise<boolean>;
26
+ readonly retryAccess: () => void;
27
+ readonly token: string | null;
28
+ readonly user: PlatformUserProfile | null;
29
+ }
30
+ interface PlatformAuthProviderProps {
31
+ readonly children: ReactNode;
32
+ readonly config: PlatformAuthConfig;
33
+ }
34
+ export declare function PlatformAuthProvider({ children, config, }: PlatformAuthProviderProps): import("react/jsx-runtime").JSX.Element;
35
+ export declare function usePlatformAuth(): PlatformAuthContextValue;
36
+ export {};
37
+ //# sourceMappingURL=PlatformAuthProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformAuthProvider.d.ts","sourceRoot":"","sources":["../src/PlatformAuthProvider.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAyC,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAMhG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,IAAI,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACrE,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAC3C;AAED,UAAU,yBAAyB;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAYD,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,MAAM,GACP,EAAE,yBAAyB,2CAsP3B;AAED,wBAAgB,eAAe,6BAQ9B"}
@@ -0,0 +1,205 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
3
+ import { authStorage, createStorageKeys } from './storage';
4
+ import { getKeycloakInstance, initKeycloakOnce } from './keycloak';
5
+ const TOKEN_REFRESH_INTERVAL = 60000;
6
+ const TOKEN_MIN_VALIDITY = 70;
7
+ const PlatformAuthContext = createContext(null);
8
+ const normalizeKeycloakUrl = (url) => url.replace(/\/+$/, '').trim();
9
+ const isKeycloakConfigValid = (config) => Boolean(config.url.trim() && config.realm.trim() && config.clientId.trim());
10
+ export function PlatformAuthProvider({ children, config, }) {
11
+ const [error, setError] = useState(null);
12
+ const [isAccessBlocked, setIsAccessBlocked] = useState(false);
13
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
14
+ const [isLoading, setIsLoading] = useState(true);
15
+ const [token, setToken] = useState(null);
16
+ const [user, setUser] = useState(null);
17
+ const storageKeys = useMemo(() => createStorageKeys(config.storageNamespace ?? config.keycloak.clientId ?? 'quantica-platform-auth'), [config.keycloak.clientId, config.storageNamespace]);
18
+ const normalizedKeycloakConfig = useMemo(() => ({
19
+ ...config.keycloak,
20
+ clientId: config.keycloak.clientId.trim(),
21
+ realm: config.keycloak.realm.trim(),
22
+ url: normalizeKeycloakUrl(config.keycloak.url),
23
+ }), [config.keycloak]);
24
+ const skipAuth = config.skipAuth ?? false;
25
+ const rawDevFlag = import.meta.env?.DEV;
26
+ const isDevMode = rawDevFlag === true || String(rawDevFlag) === 'true';
27
+ const clearAccessBlock = useCallback(() => {
28
+ setIsAccessBlocked(false);
29
+ }, []);
30
+ const retryAccess = useCallback(() => {
31
+ clearAccessBlock();
32
+ window.location.reload();
33
+ }, [clearAccessBlock]);
34
+ useEffect(() => {
35
+ if (skipAuth) {
36
+ const mockUser = {
37
+ email: 'dev@local',
38
+ firstName: 'Dev',
39
+ lastName: '(skip auth)',
40
+ username: 'dev',
41
+ };
42
+ setUser(mockUser);
43
+ setToken(import.meta.env?.VITE_SKIP_AUTH_BEARER_TOKEN ?? null);
44
+ setIsAuthenticated(true);
45
+ setIsLoading(false);
46
+ authStorage.set(storageKeys.user, JSON.stringify(mockUser));
47
+ return;
48
+ }
49
+ if (!isKeycloakConfigValid(normalizedKeycloakConfig)) {
50
+ setError('Keycloak configuration is missing. Check your environment variables.');
51
+ setIsLoading(false);
52
+ return;
53
+ }
54
+ let tokenRefreshInterval = null;
55
+ const redirectUri = window.location.origin + window.location.pathname + window.location.search;
56
+ void initKeycloakOnce(normalizedKeycloakConfig, {
57
+ onLoad: 'login-required',
58
+ checkLoginIframe: false,
59
+ pkceMethod: 'S256',
60
+ redirectUri,
61
+ enableLogging: isDevMode,
62
+ })
63
+ .then(async (authenticated) => {
64
+ const keycloak = getKeycloakInstance(normalizedKeycloakConfig);
65
+ setIsAuthenticated(authenticated);
66
+ setToken(keycloak.token ?? null);
67
+ if (!authenticated) {
68
+ return;
69
+ }
70
+ const loadedUser = await keycloak.loadUserProfile();
71
+ setUser(loadedUser);
72
+ authStorage.set(storageKeys.user, JSON.stringify(loadedUser));
73
+ tokenRefreshInterval = setInterval(() => {
74
+ void keycloak
75
+ .updateToken(TOKEN_MIN_VALIDITY)
76
+ .then((refreshed) => {
77
+ if (!refreshed) {
78
+ return;
79
+ }
80
+ setToken(keycloak.token ?? null);
81
+ })
82
+ .catch(() => {
83
+ setError('Failed to refresh the authentication token.');
84
+ });
85
+ }, TOKEN_REFRESH_INTERVAL);
86
+ })
87
+ .catch((caughtError) => {
88
+ setError(caughtError.message || 'Failed to initialize Keycloak.');
89
+ })
90
+ .finally(() => {
91
+ setIsLoading(false);
92
+ });
93
+ return () => {
94
+ if (tokenRefreshInterval) {
95
+ clearInterval(tokenRefreshInterval);
96
+ }
97
+ };
98
+ }, [
99
+ clearAccessBlock,
100
+ isDevMode,
101
+ normalizedKeycloakConfig,
102
+ skipAuth,
103
+ storageKeys.user,
104
+ ]);
105
+ useEffect(() => {
106
+ const onForbidden = () => {
107
+ setIsAccessBlocked(true);
108
+ };
109
+ const onUnauthorized = () => {
110
+ clearAccessBlock();
111
+ };
112
+ window.addEventListener('auth:forbidden', onForbidden);
113
+ window.addEventListener('auth:unauthorized', onUnauthorized);
114
+ return () => {
115
+ window.removeEventListener('auth:forbidden', onForbidden);
116
+ window.removeEventListener('auth:unauthorized', onUnauthorized);
117
+ };
118
+ }, [clearAccessBlock]);
119
+ useEffect(() => {
120
+ if (!token) {
121
+ authStorage.remove(storageKeys.token);
122
+ return;
123
+ }
124
+ authStorage.set(storageKeys.token, token);
125
+ }, [storageKeys.token, token]);
126
+ const login = useCallback(async () => {
127
+ if (skipAuth) {
128
+ return;
129
+ }
130
+ const keycloak = getKeycloakInstance(normalizedKeycloakConfig);
131
+ await keycloak.login();
132
+ }, [normalizedKeycloakConfig, skipAuth]);
133
+ const logout = useCallback(async () => {
134
+ authStorage.clear(storageKeys);
135
+ clearAccessBlock();
136
+ if (skipAuth) {
137
+ window.location.reload();
138
+ return;
139
+ }
140
+ const keycloak = getKeycloakInstance(normalizedKeycloakConfig);
141
+ await keycloak.logout({
142
+ redirectUri: window.location.origin,
143
+ });
144
+ }, [clearAccessBlock, normalizedKeycloakConfig, skipAuth, storageKeys]);
145
+ const refreshToken = useCallback(async (force = false) => {
146
+ if (skipAuth) {
147
+ return true;
148
+ }
149
+ try {
150
+ const keycloak = getKeycloakInstance(normalizedKeycloakConfig);
151
+ const refreshed = await keycloak.updateToken(force ? -1 : 5);
152
+ if (refreshed) {
153
+ setToken(keycloak.token ?? null);
154
+ }
155
+ return true;
156
+ }
157
+ catch {
158
+ return false;
159
+ }
160
+ }, [normalizedKeycloakConfig, skipAuth]);
161
+ const hasRole = useCallback((role) => {
162
+ if (skipAuth) {
163
+ return false;
164
+ }
165
+ const keycloak = getKeycloakInstance(normalizedKeycloakConfig);
166
+ return keycloak.hasRealmRole(role);
167
+ }, [normalizedKeycloakConfig, skipAuth]);
168
+ const hasClientRole = useCallback((role, clientId) => {
169
+ if (skipAuth) {
170
+ return true;
171
+ }
172
+ const keycloak = getKeycloakInstance(normalizedKeycloakConfig);
173
+ const resolvedClientId = clientId ?? config.permissionsClientId;
174
+ if (!resolvedClientId) {
175
+ return false;
176
+ }
177
+ const tokenParsed = keycloak.tokenParsed;
178
+ const grantedRoles = tokenParsed?.resource_access?.[resolvedClientId]?.roles ?? [];
179
+ return grantedRoles.includes(role);
180
+ }, [config.permissionsClientId, normalizedKeycloakConfig, skipAuth]);
181
+ const contextValue = {
182
+ clearAccessBlock,
183
+ error,
184
+ hasClientRole,
185
+ hasRole,
186
+ isAccessBlocked,
187
+ isAuthenticated,
188
+ isLoading,
189
+ login,
190
+ logout,
191
+ refreshToken,
192
+ retryAccess,
193
+ token,
194
+ user,
195
+ };
196
+ return (_jsx(PlatformAuthContext.Provider, { value: contextValue, children: children }));
197
+ }
198
+ export function usePlatformAuth() {
199
+ const context = useContext(PlatformAuthContext);
200
+ if (!context) {
201
+ throw new Error('usePlatformAuth must be used within PlatformAuthProvider.');
202
+ }
203
+ return context;
204
+ }
205
+ //# sourceMappingURL=PlatformAuthProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlatformAuthProvider.js","sourceRoot":"","sources":["../src/PlatformAuthProvider.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { PlatformAuthConfig, PlatformAuthContextValue, PlatformUserProfile, } from './PlatformAuthProvider';
2
+ export { PlatformAuthProvider, usePlatformAuth } from './PlatformAuthProvider';
3
+ export type { PlatformKeycloakConfig } from './keycloak';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kBAAkB,EAClB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC/E,YAAY,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { PlatformAuthProvider, usePlatformAuth } from './PlatformAuthProvider';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import Keycloak from 'keycloak-js';
2
+ import type { KeycloakInitOptions } from 'keycloak-js';
3
+ export interface PlatformKeycloakConfig {
4
+ readonly url: string;
5
+ readonly realm: string;
6
+ readonly clientId: string;
7
+ }
8
+ export declare function getKeycloakInstance(config: PlatformKeycloakConfig): Keycloak;
9
+ export declare function initKeycloakOnce(config: PlatformKeycloakConfig, options: KeycloakInitOptions): Promise<boolean>;
10
+ //# sourceMappingURL=keycloak.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keycloak.d.ts","sourceRoot":"","sources":["../src/keycloak.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAQD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,sBAAsB,GAAG,QAAQ,CAY5E;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAkBlB"}
@@ -0,0 +1,30 @@
1
+ import Keycloak from 'keycloak-js';
2
+ const instanceMap = new Map();
3
+ const initMap = new Map();
4
+ const toKey = (config) => `${config.url}::${config.realm}::${config.clientId}`;
5
+ export function getKeycloakInstance(config) {
6
+ const key = toKey(config);
7
+ const existingInstance = instanceMap.get(key);
8
+ if (existingInstance) {
9
+ return existingInstance;
10
+ }
11
+ const newInstance = new Keycloak(config);
12
+ instanceMap.set(key, newInstance);
13
+ return newInstance;
14
+ }
15
+ export function initKeycloakOnce(config, options) {
16
+ const key = toKey(config);
17
+ const existingPromise = initMap.get(key);
18
+ if (existingPromise) {
19
+ return existingPromise;
20
+ }
21
+ const instance = getKeycloakInstance(config);
22
+ const initPromise = instance.init(options).catch((error) => {
23
+ initMap.delete(key);
24
+ instanceMap.delete(key);
25
+ throw error;
26
+ });
27
+ initMap.set(key, initPromise);
28
+ return initPromise;
29
+ }
30
+ //# sourceMappingURL=keycloak.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keycloak.js","sourceRoot":"","sources":["../src/keycloak.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,aAAa,CAAC;AASnC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;AAChD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEpD,MAAM,KAAK,GAAG,CAAC,MAA8B,EAAE,EAAE,CAC/C,GAAG,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;AAEvD,MAAM,UAAU,mBAAmB,CAAC,MAA8B;IAChE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE9C,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAElC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,MAA8B,EAC9B,OAA4B;IAE5B,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1B,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEzC,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;QAChE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpB,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAE9B,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface StorageKeys {
2
+ readonly token: string;
3
+ readonly user: string;
4
+ }
5
+ export declare const createStorageKeys: (namespace: string) => StorageKeys;
6
+ export declare const authStorage: {
7
+ clear(keys: StorageKeys): void;
8
+ get(key: string): string | null;
9
+ remove(key: string): void;
10
+ set(key: string, value: string): void;
11
+ };
12
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,KAAG,WAGpD,CAAC;AAUH,eAAO,MAAM,WAAW;gBACV,WAAW;aAUd,MAAM;gBASH,MAAM;aAST,MAAM,SAAS,MAAM;CAS/B,CAAC"}
@@ -0,0 +1,42 @@
1
+ export const createStorageKeys = (namespace) => ({
2
+ token: `${namespace}:auth-token`,
3
+ user: `${namespace}:auth-user`,
4
+ });
5
+ const getStorage = () => {
6
+ if (typeof window === 'undefined') {
7
+ return null;
8
+ }
9
+ return window.localStorage;
10
+ };
11
+ export const authStorage = {
12
+ clear(keys) {
13
+ const storage = getStorage();
14
+ if (!storage) {
15
+ return;
16
+ }
17
+ storage.removeItem(keys.token);
18
+ storage.removeItem(keys.user);
19
+ },
20
+ get(key) {
21
+ const storage = getStorage();
22
+ if (!storage) {
23
+ return null;
24
+ }
25
+ return storage.getItem(key);
26
+ },
27
+ remove(key) {
28
+ const storage = getStorage();
29
+ if (!storage) {
30
+ return;
31
+ }
32
+ storage.removeItem(key);
33
+ },
34
+ set(key, value) {
35
+ const storage = getStorage();
36
+ if (!storage) {
37
+ return;
38
+ }
39
+ storage.setItem(key, value);
40
+ },
41
+ };
42
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAe,EAAE,CAAC,CAAC;IACpE,KAAK,EAAE,GAAG,SAAS,aAAa;IAChC,IAAI,EAAE,GAAG,SAAS,YAAY;CAC/B,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,MAAM,CAAC,YAAY,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,CAAC,IAAiB;QACrB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,GAAG,CAAC,GAAW;QACb,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,CAAC,GAAW;QAChB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IACD,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAE7B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@quantica-apps/platform-auth",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.build.json",
16
+ "type-check": "tsc -p tsconfig.build.json --noEmit"
17
+ },
18
+ "peerDependencies": {
19
+ "keycloak-js": "^26.2.1",
20
+ "react": "^19.2.0",
21
+ "react-dom": "^19.2.0"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ }
26
+ }
27
+