@nsxbet/admin-sdk 0.7.1 → 0.8.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.
- package/CHECKLIST.md +48 -13
- package/README.md +24 -74
- package/dist/auth/client/bff.d.ts +38 -0
- package/dist/auth/client/bff.js +270 -0
- package/dist/auth/client/in-memory.d.ts +1 -1
- package/dist/auth/client/in-memory.js +2 -2
- package/dist/auth/client/index.d.ts +1 -1
- package/dist/auth/client/index.js +2 -2
- package/dist/auth/client/interface.d.ts +4 -4
- package/dist/auth/client/interface.js +1 -1
- package/dist/auth/components/LoginPage.d.ts +8 -0
- package/dist/auth/components/LoginPage.js +32 -0
- package/dist/auth/components/UserSelector.js +2 -2
- package/dist/auth/components/index.d.ts +2 -0
- package/dist/auth/components/index.js +1 -0
- package/dist/auth/index.d.ts +3 -2
- package/dist/auth/index.js +2 -2
- package/dist/components/AuthProvider.d.ts +3 -3
- package/dist/components/AuthProvider.js +25 -10
- package/dist/env.d.ts +17 -0
- package/dist/env.js +50 -0
- package/dist/hooks/useAuth.d.ts +3 -3
- package/dist/hooks/useAuth.js +1 -1
- package/dist/hooks/useFetch.js +6 -1
- package/dist/hooks/useI18n.js +2 -2
- package/dist/i18n/config.d.ts +2 -1
- package/dist/i18n/config.js +4 -3
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/locales/en-US.json +7 -0
- package/dist/i18n/locales/es.json +7 -0
- package/dist/i18n/locales/pt-BR.json +7 -0
- package/dist/i18n/locales/ro.json +7 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +5 -2
- package/dist/registry/client/http.js +6 -1
- package/dist/registry/client/in-memory.js +20 -5
- package/dist/registry/types/manifest.d.ts +7 -0
- package/dist/registry/types/manifest.js +4 -1
- package/dist/registry/types/module.d.ts +6 -2
- package/dist/sdk-version.d.ts +5 -0
- package/dist/sdk-version.js +5 -0
- package/dist/shell/AdminShell.d.ts +12 -9
- package/dist/shell/AdminShell.js +56 -70
- package/dist/shell/components/ModuleOverview.js +1 -5
- package/dist/shell/components/RegistryPage.js +1 -1
- package/dist/shell/components/TopBar.js +2 -2
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/polling-config.d.ts +4 -3
- package/dist/shell/polling-config.js +11 -9
- package/dist/shell/types.d.ts +3 -1
- package/dist/types/platform.d.ts +2 -11
- package/dist/vite/config.d.ts +4 -9
- package/dist/vite/config.js +85 -27
- package/dist/vite/index.d.ts +1 -1
- package/dist/vite/index.js +1 -1
- package/dist/vite/plugins.js +6 -1
- package/package.json +11 -5
- package/scripts/write-sdk-version.mjs +21 -0
- package/dist/auth/client/keycloak.d.ts +0 -18
- package/dist/auth/client/keycloak.js +0 -129
- package/dist/shell/BackofficeShell.d.ts +0 -37
- package/dist/shell/BackofficeShell.js +0 -339
- package/dist/types/keycloak.d.ts +0 -25
- package/dist/types/keycloak.js +0 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Users can be selected from a predefined list or created custom.
|
|
6
6
|
*/
|
|
7
7
|
import { fetchGatewayToken } from './gateway-token';
|
|
8
|
+
import { env } from '../../env';
|
|
8
9
|
export { GatewayTimeoutError, GatewayFetchError } from './gateway-token';
|
|
9
10
|
/**
|
|
10
11
|
* Create mock users from a role configuration
|
|
@@ -71,10 +72,9 @@ const DEFAULT_STORAGE_KEY = '@nsxbet/auth';
|
|
|
71
72
|
export function createInMemoryAuthClient(options) {
|
|
72
73
|
const { users, storageKey = DEFAULT_STORAGE_KEY, tokenTimeout = 5000 } = options;
|
|
73
74
|
const predefinedUsers = users;
|
|
74
|
-
// Resolve gatewayUrl: explicit option → env var → null (disabled)
|
|
75
75
|
const resolvedGatewayUrl = options.gatewayUrl !== undefined
|
|
76
76
|
? options.gatewayUrl ?? null
|
|
77
|
-
: (
|
|
77
|
+
: (env.adminGatewayUrl ?? null);
|
|
78
78
|
// State
|
|
79
79
|
let selectedUser = null;
|
|
80
80
|
let tokenCache = null;
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type { AuthClient, InMemoryAuthClient, MockUser, AuthState, AuthStateCallback, } from './interface';
|
|
5
5
|
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles, type InMemoryAuthClientOptions, type MockUserRoles, } from './in-memory';
|
|
6
|
-
export {
|
|
6
|
+
export { createBffAuthClient, clearLoggedOutFlag, isLoggedOutFlag, setLoggedOutFlag, type BffAuthClient, type BffAuthClientOptions, type BffMeResponse, } from './bff';
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*/
|
|
4
4
|
// In-memory client
|
|
5
5
|
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles, } from './in-memory';
|
|
6
|
-
//
|
|
7
|
-
export {
|
|
6
|
+
// BFF / Okta cookie auth
|
|
7
|
+
export { createBffAuthClient, clearLoggedOutFlag, isLoggedOutFlag, setLoggedOutFlag, } from './bff';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Auth Client Interface
|
|
3
3
|
*
|
|
4
4
|
* Defines the interface for authentication operations.
|
|
5
|
-
* Can be implemented by in-memory (mock) or
|
|
5
|
+
* Can be implemented by in-memory (mock) or BFF cookie auth.
|
|
6
6
|
*/
|
|
7
7
|
import type { User } from '../../types/platform';
|
|
8
8
|
/**
|
|
@@ -54,7 +54,7 @@ export interface AuthClient {
|
|
|
54
54
|
/**
|
|
55
55
|
* Client type identifier
|
|
56
56
|
*/
|
|
57
|
-
readonly type: 'in-memory' | '
|
|
57
|
+
readonly type: 'in-memory' | 'bff';
|
|
58
58
|
/**
|
|
59
59
|
* Initialize the auth client
|
|
60
60
|
* @returns true if user is authenticated, false if login/selection is needed
|
|
@@ -69,9 +69,9 @@ export interface AuthClient {
|
|
|
69
69
|
*/
|
|
70
70
|
getUser(): User | null;
|
|
71
71
|
/**
|
|
72
|
-
* Get access token for API calls
|
|
72
|
+
* Get access token for API calls. BFF cookie auth returns `null` (HttpOnly cookie — use credentialed fetch).
|
|
73
73
|
*/
|
|
74
|
-
getAccessToken(): Promise<string>;
|
|
74
|
+
getAccessToken(): Promise<string | null>;
|
|
75
75
|
/**
|
|
76
76
|
* Check if user has a specific permission/role
|
|
77
77
|
*/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BFF login landing — explicit user action starts OAuth (avoids IdP silent re-login after logout).
|
|
3
|
+
*/
|
|
4
|
+
export interface LoginPageProps {
|
|
5
|
+
/** Base URL of admin-bff (no trailing slash). */
|
|
6
|
+
bffBaseUrl: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function LoginPage({ bffBaseUrl }: LoginPageProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* BFF login landing — explicit user action starts OAuth (avoids IdP silent re-login after logout).
|
|
4
|
+
*/
|
|
5
|
+
import { useState, useCallback } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { ShieldCheck, LogIn, Check, Globe } from 'lucide-react';
|
|
8
|
+
import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@nsxbet/admin-ui';
|
|
9
|
+
import { clearLoggedOutFlag } from '../client/bff';
|
|
10
|
+
import { SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_FLAGS, LOCALE_NAMES, saveLocale, } from '../../i18n/config';
|
|
11
|
+
function normalizeBaseUrl(url) {
|
|
12
|
+
return url.replace(/\/+$/, '');
|
|
13
|
+
}
|
|
14
|
+
function NsxLogo() {
|
|
15
|
+
return (_jsx("div", { className: "inline-flex items-center justify-center w-[72px] h-[72px] rounded-2xl bg-primary text-primary-foreground shadow-lg shadow-primary/25", children: _jsx("span", { className: "text-2xl font-bold tracking-tighter select-none", "aria-hidden": true, children: "NSX" }) }));
|
|
16
|
+
}
|
|
17
|
+
export function LoginPage({ bffBaseUrl }) {
|
|
18
|
+
const base = normalizeBaseUrl(bffBaseUrl);
|
|
19
|
+
const { t, i18n } = useTranslation('shell');
|
|
20
|
+
const [locale, setLocale] = useState(i18n.language || DEFAULT_LOCALE);
|
|
21
|
+
const handleLocaleChange = useCallback((newLocale) => {
|
|
22
|
+
setLocale(newLocale);
|
|
23
|
+
i18n.changeLanguage(newLocale);
|
|
24
|
+
saveLocale(newLocale);
|
|
25
|
+
}, [i18n]);
|
|
26
|
+
const handleLogin = () => {
|
|
27
|
+
clearLoggedOutFlag();
|
|
28
|
+
const redirect = encodeURIComponent(window.location.origin);
|
|
29
|
+
window.location.assign(`${base}/auth/login?redirect_url=${redirect}`);
|
|
30
|
+
};
|
|
31
|
+
return (_jsxs("div", { className: "min-h-screen bg-muted/40 text-foreground flex flex-col", children: [_jsx("div", { className: "flex items-center justify-end px-4 py-3", children: _jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { className: "flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm text-muted-foreground transition-colors hover:text-foreground focus:outline-none", "data-testid": "login-language-selector", children: [_jsx(Globe, { className: "h-4 w-4" }), _jsx("span", { children: LOCALE_FLAGS[locale] })] }), _jsx(DropdownMenuContent, { align: "end", className: "z-[101] min-w-[180px]", children: SUPPORTED_LOCALES.map((opt) => (_jsxs(DropdownMenuItem, { onClick: () => handleLocaleChange(opt), className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center", children: [_jsx("span", { className: "mr-2 text-lg", children: LOCALE_FLAGS[opt] }), _jsx("span", { children: LOCALE_NAMES[opt] })] }), locale === opt && _jsx(Check, { className: "h-4 w-4 text-primary" })] }, opt))) })] }) }), _jsx("div", { className: "flex flex-1 items-center justify-center px-4 pb-14", children: _jsxs("div", { className: "w-full max-w-[420px] flex flex-col items-center text-center gap-8", children: [_jsx(NsxLogo, {}), _jsxs("div", { className: "space-y-1.5", children: [_jsxs("h1", { className: "text-2xl font-semibold tracking-tight", children: [t('loginPage.welcomeTo'), ' ', _jsx("span", { className: "text-primary", children: t('loginPage.brandName') })] }), _jsx("p", { className: "text-muted-foreground text-[15px]", children: t('loginPage.subtitle') })] }), _jsxs("div", { className: "w-full flex flex-col gap-3", children: [_jsxs(Button, { type: "button", size: "lg", className: "w-full h-12 text-[15px] gap-2.5 font-medium", onClick: handleLogin, children: [_jsx(LogIn, { className: "h-[18px] w-[18px]", "aria-hidden": true }), t('loginPage.loginButton')] }), _jsxs("div", { className: "w-full flex items-center justify-center gap-2 rounded-lg border border-border bg-background py-2.5 px-4 text-sm text-muted-foreground", children: [_jsx(ShieldCheck, { className: "h-4 w-4 text-muted-foreground/70 shrink-0", "aria-hidden": true }), t('loginPage.secureAuth')] })] })] }) })] }));
|
|
32
|
+
}
|
|
@@ -67,7 +67,7 @@ function UserCard({ user, isCustom, onClick, onDelete, }) {
|
|
|
67
67
|
onDelete();
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
|
-
return (_jsxs("div", { className: "relative group", children: [_jsx("button", { onClick: onClick, className: "w-full p-4 rounded-xl border border-border bg-card hover:bg-muted/50 hover:border-muted-foreground/30 transition-all duration-200 text-left", children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "flex-shrink-0", children: icon }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "font-semibold text-foreground group-hover:text-foreground transition-colors", children: user.displayName }), isCustom && (_jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-primary/20 text-primary border border-primary/30", children: "custom" }))] }), _jsx("p", { className: "text-sm text-muted-foreground truncate", children: user.email }), _jsxs("div", { className: "flex flex-wrap gap-1.5 mt-2", children: [user.roles.length === 0 ? (_jsx("span", { className: "text-xs px-2 py-0.5 rounded-full border bg-destructive/20 text-destructive border-destructive/30", children: "no roles" })) : (user.roles.slice(0, 4).map((role) => (_jsx("span", { className: `text-xs px-2 py-0.5 rounded-full border ${getRoleBadgeColor(role)}`, children: role }, role)))), user.roles.length > 4 && (_jsxs("span", { className: "text-xs px-2 py-0.5 rounded-full border bg-muted text-muted-foreground border-border", children: ["+", user.roles.length - 4, " more"] }))] })] }), _jsx("div", { className: "text-muted-foreground group-hover:text-foreground transition-colors", children: _jsx(ChevronRight, { className: "h-5 w-5" }) })] }) }), isCustom && onDelete && (_jsx("button", { onClick: handleDelete, className: "absolute top-2 right-2 p-1.5 rounded-lg bg-destructive/10 text-destructive opacity-0 group-hover:opacity-100 hover:bg-destructive/20 transition-all", title: "Delete user", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }));
|
|
70
|
+
return (_jsxs("div", { className: "relative group", children: [_jsx("button", { type: "button", "data-testid": `user-${user.id}`, onClick: onClick, className: "w-full p-4 rounded-xl border border-border bg-card hover:bg-muted/50 hover:border-muted-foreground/30 transition-all duration-200 text-left", children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "flex-shrink-0", children: icon }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "font-semibold text-foreground group-hover:text-foreground transition-colors", children: user.displayName }), isCustom && (_jsx("span", { className: "text-xs px-1.5 py-0.5 rounded bg-primary/20 text-primary border border-primary/30", children: "custom" }))] }), _jsx("p", { className: "text-sm text-muted-foreground truncate", children: user.email }), _jsxs("div", { className: "flex flex-wrap gap-1.5 mt-2", children: [user.roles.length === 0 ? (_jsx("span", { className: "text-xs px-2 py-0.5 rounded-full border bg-destructive/20 text-destructive border-destructive/30", children: "no roles" })) : (user.roles.slice(0, 4).map((role) => (_jsx("span", { className: `text-xs px-2 py-0.5 rounded-full border ${getRoleBadgeColor(role)}`, children: role }, role)))), user.roles.length > 4 && (_jsxs("span", { className: "text-xs px-2 py-0.5 rounded-full border bg-muted text-muted-foreground border-border", children: ["+", user.roles.length - 4, " more"] }))] })] }), _jsx("div", { className: "text-muted-foreground group-hover:text-foreground transition-colors", children: _jsx(ChevronRight, { className: "h-5 w-5" }) })] }) }), isCustom && onDelete && (_jsx("button", { onClick: handleDelete, className: "absolute top-2 right-2 p-1.5 rounded-lg bg-destructive/10 text-destructive opacity-0 group-hover:opacity-100 hover:bg-destructive/20 transition-all", title: "Delete user", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }));
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
73
|
* Custom User Form Component
|
|
@@ -214,7 +214,7 @@ export function UserSelector({ authClient, onUserSelected }) {
|
|
|
214
214
|
if (loginState.status === 'timeout') {
|
|
215
215
|
return (_jsx(LoginTimeoutScreen, { gatewayUrl: authClient.gatewayUrl, isLovable: isLovable, onRetry: handleRetry, onFallback: handleFallbackToMock, onBack: handleBack, retrying: false }));
|
|
216
216
|
}
|
|
217
|
-
return (_jsx("div", { className: "min-h-screen bg-background flex items-center justify-center p-4", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "text-center mb-8", children: [_jsx("div", { className: "inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-primary mb-4 shadow-lg shadow-primary/25", children: _jsx(Users, { className: "h-8 w-8 text-primary-foreground" }) }), _jsx("h1", { className: "text-2xl font-bold text-foreground mb-2", children: "Select User" }), _jsx("p", { className: "text-muted-foreground", children: "Choose a mock user to continue in development mode" })] }), _jsx("div", { className: "space-y-3 mb-6", children: users.map((user) => {
|
|
217
|
+
return (_jsx("div", { className: "min-h-screen bg-background flex items-center justify-center p-4", "data-testid": "user-selector", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "text-center mb-8", children: [_jsx("div", { className: "inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-primary mb-4 shadow-lg shadow-primary/25", children: _jsx(Users, { className: "h-8 w-8 text-primary-foreground" }) }), _jsx("h1", { className: "text-2xl font-bold text-foreground mb-2", children: "Select User" }), _jsx("p", { className: "text-muted-foreground", children: "Choose a mock user to continue in development mode" })] }), _jsx("div", { className: "space-y-3 mb-6", children: users.map((user) => {
|
|
218
218
|
const isCustom = authClient.isCustomUser(user.id);
|
|
219
219
|
return (_jsx(UserCard, { user: user, isCustom: isCustom, onClick: () => handleSelectUser(user.id), onDelete: isCustom ? () => handleDeleteUser(user.id) : undefined }, user.id));
|
|
220
220
|
}) }), _jsxs("div", { className: "relative my-6", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("div", { className: "w-full border-t border-border" }) }), _jsx("div", { className: "relative flex justify-center text-sm", children: _jsx("span", { className: "px-3 bg-background text-muted-foreground", children: "or" }) })] }), showCustomForm ? (_jsx(CustomUserForm, { onSubmit: handleCreateCustomUser, onCancel: () => setShowCustomForm(false) })) : (_jsxs("button", { onClick: () => setShowCustomForm(true), className: "w-full p-4 rounded-xl border border-dashed border-border text-muted-foreground hover:text-foreground hover:border-muted-foreground transition-colors flex items-center justify-center gap-2", children: [_jsx(Plus, { className: "h-5 w-5" }), "Create Custom User"] })), _jsxs("p", { className: "text-center text-xs text-muted-foreground mt-8 flex items-center justify-center gap-1", children: [_jsx(Wrench, { className: "h-3 w-3" }), "Development Mode \u2022 Data stored in localStorage"] })] }) }));
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
* Authentication module exports
|
|
3
3
|
*/
|
|
4
4
|
export type { AuthClient, InMemoryAuthClient, MockUser, AuthState, AuthStateCallback, } from './client';
|
|
5
|
-
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles,
|
|
6
|
-
export { UserSelector } from './components';
|
|
5
|
+
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles, createBffAuthClient, clearLoggedOutFlag, isLoggedOutFlag, setLoggedOutFlag, type InMemoryAuthClientOptions, type MockUserRoles, type BffAuthClient, type BffAuthClientOptions, type BffMeResponse, } from './client';
|
|
6
|
+
export { UserSelector, LoginPage } from './components';
|
|
7
|
+
export type { LoginPageProps } from './components';
|
package/dist/auth/index.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Authentication module exports
|
|
3
3
|
*/
|
|
4
4
|
// Auth client factories
|
|
5
|
-
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles,
|
|
5
|
+
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles, createBffAuthClient, clearLoggedOutFlag, isLoggedOutFlag, setLoggedOutFlag, } from './client';
|
|
6
6
|
// Auth components
|
|
7
|
-
export { UserSelector } from './components';
|
|
7
|
+
export { UserSelector, LoginPage } from './components';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AuthProvider - Manages authentication state using AuthClient
|
|
3
3
|
*
|
|
4
|
-
* Works with both in-memory (mock) and
|
|
4
|
+
* Works with both in-memory (mock) and BFF cookie auth clients.
|
|
5
5
|
* Shows user selection screen when in-memory client has no selected user.
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
@@ -15,8 +15,8 @@ interface AuthContextValue {
|
|
|
15
15
|
isAuthenticated: boolean;
|
|
16
16
|
/** Current user (null if not authenticated) */
|
|
17
17
|
user: User | null;
|
|
18
|
-
/** Get access token for API calls */
|
|
19
|
-
getAccessToken: () => Promise<string>;
|
|
18
|
+
/** Get access token for API calls (null for BFF HttpOnly cookie auth) */
|
|
19
|
+
getAccessToken: () => Promise<string | null>;
|
|
20
20
|
/** Check if user has a permission */
|
|
21
21
|
hasPermission: (permission: string) => boolean;
|
|
22
22
|
/** Log out current user */
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* AuthProvider - Manages authentication state using AuthClient
|
|
4
4
|
*
|
|
5
|
-
* Works with both in-memory (mock) and
|
|
5
|
+
* Works with both in-memory (mock) and BFF cookie auth clients.
|
|
6
6
|
* Shows user selection screen when in-memory client has no selected user.
|
|
7
7
|
*/
|
|
8
8
|
import { createContext, useContext, useEffect, useState, useCallback, useMemo } from 'react';
|
|
9
9
|
import { useCallbackRef } from '../hooks/useCallbackRef';
|
|
10
|
+
import { isLoggedOutFlag } from '../auth/client/bff';
|
|
10
11
|
import { UserSelector } from '../auth/components/UserSelector';
|
|
12
|
+
import { LoginPage } from '../auth/components/LoginPage';
|
|
11
13
|
const AuthContext = createContext(null);
|
|
12
14
|
/**
|
|
13
15
|
* Loading screen component - uses Brasa Design System tokens
|
|
@@ -23,8 +25,10 @@ export function AuthProvider({ children, authClient }) {
|
|
|
23
25
|
isAuthenticated: false,
|
|
24
26
|
user: null,
|
|
25
27
|
});
|
|
26
|
-
const
|
|
28
|
+
const bffLoggedOut = authClient.type === 'bff' && isLoggedOutFlag();
|
|
29
|
+
const [isInitializing, setIsInitializing] = useState(!bffLoggedOut);
|
|
27
30
|
const [needsUserSelection, setNeedsUserSelection] = useState(false);
|
|
31
|
+
const [needsLogin, setNeedsLogin] = useState(bffLoggedOut);
|
|
28
32
|
// Initialize auth client
|
|
29
33
|
useEffect(() => {
|
|
30
34
|
let mounted = true;
|
|
@@ -39,15 +43,22 @@ export function AuthProvider({ children, authClient }) {
|
|
|
39
43
|
user: authClient.getUser(),
|
|
40
44
|
});
|
|
41
45
|
setNeedsUserSelection(false);
|
|
46
|
+
setNeedsLogin(false);
|
|
42
47
|
}
|
|
43
48
|
else if (authClient.type === 'in-memory') {
|
|
44
|
-
// In-memory client needs user selection
|
|
45
49
|
setNeedsUserSelection(true);
|
|
50
|
+
setNeedsLogin(false);
|
|
51
|
+
}
|
|
52
|
+
else if (authClient.type === 'bff') {
|
|
53
|
+
setNeedsLogin(true);
|
|
54
|
+
setNeedsUserSelection(false);
|
|
46
55
|
}
|
|
47
|
-
// Keycloak will redirect to login page, so we don't need to handle it here
|
|
48
56
|
}
|
|
49
57
|
catch (error) {
|
|
50
58
|
console.error('[AuthProvider] Initialization failed:', error);
|
|
59
|
+
if (authClient.type === 'bff') {
|
|
60
|
+
setNeedsLogin(true);
|
|
61
|
+
}
|
|
51
62
|
}
|
|
52
63
|
finally {
|
|
53
64
|
if (mounted) {
|
|
@@ -62,9 +73,15 @@ export function AuthProvider({ children, authClient }) {
|
|
|
62
73
|
setAuthState(state);
|
|
63
74
|
if (!state.isAuthenticated && authClient.type === 'in-memory') {
|
|
64
75
|
setNeedsUserSelection(true);
|
|
76
|
+
setNeedsLogin(false);
|
|
77
|
+
}
|
|
78
|
+
else if (!state.isAuthenticated && authClient.type === 'bff') {
|
|
79
|
+
setNeedsLogin(true);
|
|
80
|
+
setNeedsUserSelection(false);
|
|
65
81
|
}
|
|
66
82
|
else {
|
|
67
83
|
setNeedsUserSelection(false);
|
|
84
|
+
setNeedsLogin(false);
|
|
68
85
|
}
|
|
69
86
|
}
|
|
70
87
|
});
|
|
@@ -96,11 +113,9 @@ export function AuthProvider({ children, authClient }) {
|
|
|
96
113
|
if (isInitializing) {
|
|
97
114
|
return _jsx(LoadingScreen, {});
|
|
98
115
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
return (_jsx(AuthContext.Provider, { value: contextValue, children: children }));
|
|
116
|
+
const bffLoginOverlay = needsLogin && authClient.type === 'bff' ? (_jsx("div", { className: "fixed inset-0 z-[100] bg-background", "data-testid": "bff-login-overlay", children: _jsx(LoginPage, { bffBaseUrl: authClient.bffBaseUrl }) })) : null;
|
|
117
|
+
const content = needsUserSelection && authClient.type === 'in-memory' ? (_jsx(UserSelector, { authClient: authClient, onUserSelected: handleUserSelected })) : (_jsxs(_Fragment, { children: [bffLoginOverlay, children] }));
|
|
118
|
+
return _jsx(AuthContext.Provider, { value: contextValue, children: content });
|
|
104
119
|
}
|
|
105
120
|
/**
|
|
106
121
|
* Hook to access auth context
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime environment from `window.__ENV__` (set by `/env.js` from the shell or adminModule() dev server).
|
|
3
|
+
*/
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
__ENV__?: Record<string, string | undefined>;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export interface EnvConfig {
|
|
10
|
+
/** Validated absolute URL, or `undefined` if missing/invalid */
|
|
11
|
+
adminGatewayUrl: string | undefined;
|
|
12
|
+
mockAuth: boolean;
|
|
13
|
+
environment: string;
|
|
14
|
+
/** Parsed from `REGISTRY_POLL_INTERVAL` in `window.__ENV__`, or `undefined` if missing/invalid */
|
|
15
|
+
registryPollInterval: number | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare const env: EnvConfig;
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime environment from `window.__ENV__` (set by `/env.js` from the shell or adminModule() dev server).
|
|
3
|
+
*/
|
|
4
|
+
function isValidUrl(value) {
|
|
5
|
+
try {
|
|
6
|
+
new URL(value);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function parseEnv() {
|
|
14
|
+
const raw = (typeof window !== "undefined" && window.__ENV__) || {};
|
|
15
|
+
let adminGatewayUrl;
|
|
16
|
+
if (typeof raw.ADMIN_GATEWAY_URL === "string" && raw.ADMIN_GATEWAY_URL) {
|
|
17
|
+
if (isValidUrl(raw.ADMIN_GATEWAY_URL)) {
|
|
18
|
+
adminGatewayUrl = raw.ADMIN_GATEWAY_URL;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.warn("[env] ADMIN_GATEWAY_URL is not a valid URL:", raw.ADMIN_GATEWAY_URL);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const mockAuthRaw = raw.MOCK_AUTH;
|
|
25
|
+
if (mockAuthRaw !== undefined &&
|
|
26
|
+
mockAuthRaw !== "true" &&
|
|
27
|
+
mockAuthRaw !== "false") {
|
|
28
|
+
console.warn('[env] MOCK_AUTH must be "true" or "false", got:', mockAuthRaw);
|
|
29
|
+
}
|
|
30
|
+
let registryPollInterval;
|
|
31
|
+
const rawPoll = raw.REGISTRY_POLL_INTERVAL;
|
|
32
|
+
if (rawPoll !== undefined && rawPoll !== null && rawPoll !== "") {
|
|
33
|
+
const parsed = Number(rawPoll);
|
|
34
|
+
if (!Number.isNaN(parsed)) {
|
|
35
|
+
registryPollInterval = parsed;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.warn("[env] REGISTRY_POLL_INTERVAL must be a number, got:", rawPoll);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
adminGatewayUrl,
|
|
43
|
+
mockAuth: mockAuthRaw === "true",
|
|
44
|
+
environment: typeof raw.ENVIRONMENT === "string" && raw.ENVIRONMENT
|
|
45
|
+
? raw.ENVIRONMENT
|
|
46
|
+
: "local",
|
|
47
|
+
registryPollInterval,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export const env = parseEnv();
|
package/dist/hooks/useAuth.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { User } from '../types/platform';
|
|
|
3
3
|
* Authentication methods available in all modes
|
|
4
4
|
*/
|
|
5
5
|
export interface UseAuthResult {
|
|
6
|
-
/** Get the current access token */
|
|
7
|
-
getAccessToken: () => Promise<string>;
|
|
6
|
+
/** Get the current access token. Null when using BFF HttpOnly cookie auth. */
|
|
7
|
+
getAccessToken: () => Promise<string | null>;
|
|
8
8
|
/** Check if user has a specific permission */
|
|
9
9
|
hasPermission: (permission: string) => boolean;
|
|
10
10
|
/** Get current user information */
|
|
@@ -15,6 +15,6 @@ export interface UseAuthResult {
|
|
|
15
15
|
/**
|
|
16
16
|
* useAuth provides authentication methods that work seamlessly across:
|
|
17
17
|
* - Shell mode (using platform API)
|
|
18
|
-
* - Standalone mode with AuthClient (
|
|
18
|
+
* - Standalone mode with AuthClient (BFF cookie or in-memory)
|
|
19
19
|
*/
|
|
20
20
|
export declare function useAuth(): UseAuthResult;
|
package/dist/hooks/useAuth.js
CHANGED
|
@@ -8,7 +8,7 @@ import { useOptionalAuthContext } from '../components/AuthProvider';
|
|
|
8
8
|
/**
|
|
9
9
|
* useAuth provides authentication methods that work seamlessly across:
|
|
10
10
|
* - Shell mode (using platform API)
|
|
11
|
-
* - Standalone mode with AuthClient (
|
|
11
|
+
* - Standalone mode with AuthClient (BFF cookie or in-memory)
|
|
12
12
|
*/
|
|
13
13
|
export function useAuth() {
|
|
14
14
|
const { isShellMode, api } = usePlatformAPI();
|
package/dist/hooks/useFetch.js
CHANGED
|
@@ -18,8 +18,13 @@ export function useFetch() {
|
|
|
18
18
|
// In shell mode, use platform fetch (handles auth automatically)
|
|
19
19
|
return api.fetch(input, init);
|
|
20
20
|
}
|
|
21
|
-
// In standalone mode, add auth header manually
|
|
22
21
|
const token = await getAccessToken();
|
|
22
|
+
if (token === null) {
|
|
23
|
+
return fetch(input, {
|
|
24
|
+
...init,
|
|
25
|
+
credentials: 'include',
|
|
26
|
+
});
|
|
27
|
+
}
|
|
23
28
|
return fetch(input, {
|
|
24
29
|
...init,
|
|
25
30
|
headers: {
|
package/dist/hooks/useI18n.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { useEffect, useState, useCallback } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { usePlatformAPI } from './usePlatformAPI';
|
|
7
|
-
import { saveLocale, isSupportedLocale, i18n } from '../i18n';
|
|
7
|
+
import { saveLocale, isSupportedLocale, i18n, DEFAULT_LOCALE } from '../i18n';
|
|
8
8
|
/**
|
|
9
9
|
* useI18n provides internationalization methods and translation access
|
|
10
10
|
*
|
|
@@ -37,7 +37,7 @@ import { saveLocale, isSupportedLocale, i18n } from '../i18n';
|
|
|
37
37
|
*/
|
|
38
38
|
export function useI18n(namespace) {
|
|
39
39
|
const { isShellMode, api } = usePlatformAPI();
|
|
40
|
-
const [standaloneLocale, setStandaloneLocale] = useState(i18n.language ||
|
|
40
|
+
const [standaloneLocale, setStandaloneLocale] = useState(i18n.language || DEFAULT_LOCALE);
|
|
41
41
|
// Use react-i18next's useTranslation for reactive updates
|
|
42
42
|
const { t, i18n: i18nInstance } = useTranslation(namespace || 'shell');
|
|
43
43
|
// Subscribe to platform locale changes in shell mode
|
package/dist/i18n/config.d.ts
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Supports: Portuguese (Brazil), Spanish, English (US), Romanian
|
|
5
5
|
*/
|
|
6
6
|
import i18n from 'i18next';
|
|
7
|
-
export declare const SUPPORTED_LOCALES: readonly ["
|
|
7
|
+
export declare const SUPPORTED_LOCALES: readonly ["en-US", "pt-BR", "es", "ro"];
|
|
8
8
|
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
9
|
+
export declare const DEFAULT_LOCALE: SupportedLocale;
|
|
9
10
|
/**
|
|
10
11
|
* Localized string value - one string per supported locale.
|
|
11
12
|
* Used for manifest title, description, and command titles.
|
package/dist/i18n/config.js
CHANGED
|
@@ -9,7 +9,8 @@ import ptBR from './locales/pt-BR.json';
|
|
|
9
9
|
import es from './locales/es.json';
|
|
10
10
|
import enUS from './locales/en-US.json';
|
|
11
11
|
import ro from './locales/ro.json';
|
|
12
|
-
export const SUPPORTED_LOCALES = ['
|
|
12
|
+
export const SUPPORTED_LOCALES = ['en-US', 'pt-BR', 'es', 'ro'];
|
|
13
|
+
export const DEFAULT_LOCALE = 'en-US';
|
|
13
14
|
/**
|
|
14
15
|
* Resolves a localized string for the given locale.
|
|
15
16
|
* Falls back to en-US if the locale is missing.
|
|
@@ -69,12 +70,12 @@ export function registerModuleTranslations(namespace, translations) {
|
|
|
69
70
|
*/
|
|
70
71
|
function getSavedLocale() {
|
|
71
72
|
if (typeof window === 'undefined')
|
|
72
|
-
return
|
|
73
|
+
return DEFAULT_LOCALE;
|
|
73
74
|
const saved = localStorage.getItem(STORAGE_KEY);
|
|
74
75
|
if (saved && SUPPORTED_LOCALES.includes(saved)) {
|
|
75
76
|
return saved;
|
|
76
77
|
}
|
|
77
|
-
return
|
|
78
|
+
return DEFAULT_LOCALE;
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
80
81
|
* Save locale to localStorage
|
package/dist/i18n/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* i18n module exports
|
|
3
3
|
*/
|
|
4
|
-
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, LOCALE_FLAGS, LOCALE_NAMES, } from './config';
|
|
4
|
+
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_FLAGS, LOCALE_NAMES, } from './config';
|
|
5
5
|
export type { SupportedLocale, LocalizedField } from './config';
|
package/dist/i18n/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* i18n module exports
|
|
3
3
|
*/
|
|
4
|
-
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, LOCALE_FLAGS, LOCALE_NAMES, } from './config';
|
|
4
|
+
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_FLAGS, LOCALE_NAMES, } from './config';
|
|
@@ -212,6 +212,13 @@
|
|
|
212
212
|
"baseUrl": "Base URL",
|
|
213
213
|
"id": "ID"
|
|
214
214
|
},
|
|
215
|
+
"loginPage": {
|
|
216
|
+
"welcomeTo": "Welcome to",
|
|
217
|
+
"brandName": "NSXBet Admin",
|
|
218
|
+
"subtitle": "Administration Platform",
|
|
219
|
+
"loginButton": "Login with Corporate SSO",
|
|
220
|
+
"secureAuth": "Secure Authentication"
|
|
221
|
+
},
|
|
215
222
|
"breadcrumbs": {
|
|
216
223
|
"home": "Home",
|
|
217
224
|
"registry": "Registry",
|
|
@@ -212,6 +212,13 @@
|
|
|
212
212
|
"baseUrl": "URL Base",
|
|
213
213
|
"id": "ID"
|
|
214
214
|
},
|
|
215
|
+
"loginPage": {
|
|
216
|
+
"welcomeTo": "Bienvenido a",
|
|
217
|
+
"brandName": "NSXBet Admin",
|
|
218
|
+
"subtitle": "Plataforma de Administración",
|
|
219
|
+
"loginButton": "Iniciar sesión con SSO Corporativo",
|
|
220
|
+
"secureAuth": "Autenticación Segura"
|
|
221
|
+
},
|
|
215
222
|
"breadcrumbs": {
|
|
216
223
|
"home": "Inicio",
|
|
217
224
|
"registry": "Registro",
|
|
@@ -212,6 +212,13 @@
|
|
|
212
212
|
"baseUrl": "URL Base",
|
|
213
213
|
"id": "ID"
|
|
214
214
|
},
|
|
215
|
+
"loginPage": {
|
|
216
|
+
"welcomeTo": "Bem-vindo ao",
|
|
217
|
+
"brandName": "NSXBet Admin",
|
|
218
|
+
"subtitle": "Plataforma de Administração",
|
|
219
|
+
"loginButton": "Entrar com SSO Corporativo",
|
|
220
|
+
"secureAuth": "Autenticação Segura"
|
|
221
|
+
},
|
|
215
222
|
"breadcrumbs": {
|
|
216
223
|
"home": "Início",
|
|
217
224
|
"registry": "Registro",
|
|
@@ -212,6 +212,13 @@
|
|
|
212
212
|
"baseUrl": "URL Bază",
|
|
213
213
|
"id": "ID"
|
|
214
214
|
},
|
|
215
|
+
"loginPage": {
|
|
216
|
+
"welcomeTo": "Bine ai venit la",
|
|
217
|
+
"brandName": "NSXBet Admin",
|
|
218
|
+
"subtitle": "Platformă de Administrare",
|
|
219
|
+
"loginButton": "Autentificare cu SSO Corporativ",
|
|
220
|
+
"secureAuth": "Autentificare Securizată"
|
|
221
|
+
},
|
|
215
222
|
"breadcrumbs": {
|
|
216
223
|
"home": "Acasă",
|
|
217
224
|
"registry": "Registru",
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* SDK for building NSX Admin modules
|
|
5
5
|
* Provides authentication, navigation, and platform integration
|
|
6
6
|
*/
|
|
7
|
+
export { env, type EnvConfig } from "./env";
|
|
8
|
+
export { SDK_PACKAGE_VERSION } from "./sdk-version";
|
|
7
9
|
export { AuthProvider, useAuthContext, useOptionalAuthContext } from './components/AuthProvider';
|
|
8
10
|
export { Timestamp } from './components/Timestamp';
|
|
9
11
|
export type { TimestampProps } from './components/Timestamp';
|
|
@@ -14,19 +16,18 @@ export { useTelemetry } from './hooks/useTelemetry';
|
|
|
14
16
|
export { useI18n } from './hooks/useI18n';
|
|
15
17
|
export { useTimestamp } from './hooks/useTimestamp';
|
|
16
18
|
export { useCallbackRef } from './hooks/useCallbackRef';
|
|
17
|
-
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles,
|
|
18
|
-
export type { AuthClient, InMemoryAuthClient, MockUser, MockUserRoles, AuthState, AuthStateCallback, InMemoryAuthClientOptions,
|
|
19
|
+
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles, createBffAuthClient, clearLoggedOutFlag, isLoggedOutFlag, setLoggedOutFlag, UserSelector, LoginPage, } from './auth';
|
|
20
|
+
export type { AuthClient, InMemoryAuthClient, MockUser, MockUserRoles, AuthState, AuthStateCallback, InMemoryAuthClientOptions, BffAuthClient, BffAuthClientOptions, BffMeResponse, LoginPageProps, } from './auth';
|
|
19
21
|
export type { PlatformAPI, Breadcrumb, User, TimezoneMode, TimestampFormat } from './types/platform';
|
|
20
|
-
export type { KeycloakConfig } from './types/keycloak';
|
|
21
22
|
export type { UseAuthResult } from './hooks/useAuth';
|
|
22
23
|
export type { UseTelemetryResult } from './hooks/useTelemetry';
|
|
23
24
|
export type { UseI18nResult } from './hooks/useI18n';
|
|
24
25
|
export type { UseTimestampResult } from './hooks/useTimestamp';
|
|
25
|
-
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, LOCALE_FLAGS, LOCALE_NAMES, } from './i18n';
|
|
26
|
+
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_FLAGS, LOCALE_NAMES, } from './i18n';
|
|
26
27
|
export type { SupportedLocale, LocalizedField } from './i18n';
|
|
27
28
|
export { createInMemoryRegistryClient, clearInMemoryRegistry, createHttpRegistryClient, validateManifest, parseManifest, useRegistryPolling, AdminShellRegistry, useRegistry, useRegistryClient, } from './registry';
|
|
28
29
|
export type { RegistryClient, ModuleOperations, CatalogOperations, InMemoryRegistryOptions, PreConfiguredModule, HttpRegistryOptions, AdminModuleManifest, ModuleCommand as RegistryModuleCommand, ModulePermissions, ModuleOwners, RegisteredModule, UpdateModuleDto, ReorderModuleDto, ModuleFilters, Catalog as RegistryCatalog, CatalogModule, CatalogVersion, ImportMap as RegistryImportMap, RegistryPollingState, UseRegistryPollingOptions, RegistryContextValue, AdminShellRegistryProps, } from './registry';
|
|
29
30
|
export { AdminShell, TopBar, LeftNav, MainContent, CommandPalette, ThemeProvider, useTheme, initTelemetry, track, trackError, fuzzySearch, } from './shell';
|
|
30
31
|
export { DynamicModule, ModuleLoading, ModuleErrorBoundary, } from './router';
|
|
31
32
|
export type { ModuleInfo, ErrorBoundaryProps, } from './router';
|
|
32
|
-
export type { AdminShellProps, TopBarProps, CommandPaletteProps, Module, ModuleCommand, ModuleStatus, NavigationSection, ModuleNavigation, Catalog, ImportMap, SearchableItem, SearchResult, SearchOptions, } from './shell';
|
|
33
|
+
export type { AdminShellProps, AdminShellBffConfig, TopBarProps, CommandPaletteProps, Module, ModuleCommand, ModuleStatus, NavigationSection, ModuleNavigation, Catalog, ImportMap, SearchableItem, SearchResult, SearchOptions, } from './shell';
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* SDK for building NSX Admin modules
|
|
5
5
|
* Provides authentication, navigation, and platform integration
|
|
6
6
|
*/
|
|
7
|
+
// Runtime env (`window.__ENV__` / `/env.js`)
|
|
8
|
+
export { env } from "./env";
|
|
9
|
+
export { SDK_PACKAGE_VERSION } from "./sdk-version";
|
|
7
10
|
// Components
|
|
8
11
|
export { AuthProvider, useAuthContext, useOptionalAuthContext } from './components/AuthProvider';
|
|
9
12
|
export { Timestamp } from './components/Timestamp';
|
|
@@ -16,9 +19,9 @@ export { useI18n } from './hooks/useI18n';
|
|
|
16
19
|
export { useTimestamp } from './hooks/useTimestamp';
|
|
17
20
|
export { useCallbackRef } from './hooks/useCallbackRef';
|
|
18
21
|
// Auth Client
|
|
19
|
-
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles,
|
|
22
|
+
export { createInMemoryAuthClient, clearInMemoryAuth, createMockUsersFromRoles, createBffAuthClient, clearLoggedOutFlag, isLoggedOutFlag, setLoggedOutFlag, UserSelector, LoginPage, } from './auth';
|
|
20
23
|
// i18n
|
|
21
|
-
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, LOCALE_FLAGS, LOCALE_NAMES, } from './i18n';
|
|
24
|
+
export { initI18n, saveLocale, isSupportedLocale, resolveLocalizedString, registerModuleTranslations, i18n, SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_FLAGS, LOCALE_NAMES, } from './i18n';
|
|
22
25
|
// Registry
|
|
23
26
|
export {
|
|
24
27
|
// Client factory
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Implementation of RegistryClient that communicates with the admin-api.
|
|
5
5
|
* Used when running with MySQL backend.
|
|
6
6
|
*/
|
|
7
|
+
import { SDK_PACKAGE_VERSION } from '../../sdk-version.js';
|
|
7
8
|
/**
|
|
8
9
|
* Create an HTTP registry client
|
|
9
10
|
*/
|
|
@@ -61,9 +62,13 @@ export function createHttpRegistryClient(options) {
|
|
|
61
62
|
});
|
|
62
63
|
},
|
|
63
64
|
async registerFromManifest(manifest, baseUrl = '') {
|
|
65
|
+
const merged = {
|
|
66
|
+
...manifest,
|
|
67
|
+
sdkVersion: manifest.sdkVersion ?? SDK_PACKAGE_VERSION,
|
|
68
|
+
};
|
|
64
69
|
return request('/modules/manifest', {
|
|
65
70
|
method: 'POST',
|
|
66
|
-
body: JSON.stringify({ manifest, baseUrl }),
|
|
71
|
+
body: JSON.stringify({ manifest: merged, baseUrl }),
|
|
67
72
|
});
|
|
68
73
|
},
|
|
69
74
|
async update(id, data) {
|