@nsxbet/admin-sdk 0.7.0 → 0.8.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.
- 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/client/private-network-guidance.d.ts +2 -0
- package/dist/auth/client/private-network-guidance.js +38 -0
- package/dist/auth/components/LoginPage.d.ts +8 -0
- package/dist/auth/components/LoginPage.js +32 -0
- package/dist/auth/components/UserSelector.d.ts +29 -0
- package/dist/auth/components/UserSelector.js +38 -10
- package/dist/auth/components/UserSelector.stories.d.ts +9 -0
- package/dist/auth/components/UserSelector.stories.js +70 -0
- 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 +35 -17
- 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 +26 -21
- package/dist/hooks/useCallbackRef.d.ts +7 -0
- package/dist/hooks/useCallbackRef.js +14 -0
- package/dist/hooks/useFetch.js +6 -1
- package/dist/hooks/useI18n.js +2 -2
- package/dist/hooks/usePlatformAPI.d.ts +0 -3
- package/dist/hooks/usePlatformAPI.js +6 -4
- 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 +7 -5
- package/dist/index.js +6 -2
- package/dist/registry/AdminShellRegistry.js +4 -3
- package/dist/registry/client/http.js +6 -1
- package/dist/registry/client/in-memory.js +20 -5
- package/dist/registry/types/manifest.d.ts +5 -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/components/theme-provider.js +6 -8
- 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 +20 -6
- 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
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { AuthClient } from "../auth/client/interface";
|
|
2
2
|
import type { AdminModuleManifest, RegistryClient } from "../registry";
|
|
3
|
+
/** Use admin-bff cookie / Okta auth (`createBffAuthClient`). `true` uses current origin. */
|
|
4
|
+
export type AdminShellBffConfig = true | {
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
};
|
|
3
7
|
export interface AdminShellProps {
|
|
4
8
|
/**
|
|
5
9
|
* Module manifests to load (used for standalone mode when no registryClient)
|
|
@@ -12,17 +16,12 @@ export interface AdminShellProps {
|
|
|
12
16
|
*/
|
|
13
17
|
children?: React.ReactNode;
|
|
14
18
|
/**
|
|
15
|
-
*
|
|
16
|
-
* If not provided, uses in-memory (mock) authentication
|
|
19
|
+
* BFF / Okta cookie authentication (recommended for production).
|
|
17
20
|
*/
|
|
18
|
-
|
|
19
|
-
url: string;
|
|
20
|
-
realm: string;
|
|
21
|
-
clientId: string;
|
|
22
|
-
};
|
|
21
|
+
bff?: AdminShellBffConfig;
|
|
23
22
|
/**
|
|
24
23
|
* Auth client to use for authentication.
|
|
25
|
-
* If not provided, creates one
|
|
24
|
+
* If not provided, creates one from `bff` or in-memory (mock) authentication depending on environment.
|
|
26
25
|
*/
|
|
27
26
|
authClient?: AuthClient;
|
|
28
27
|
/** Registry client for fetching modules from API */
|
|
@@ -33,5 +32,9 @@ export interface AdminShellProps {
|
|
|
33
32
|
inMemoryRegistry?: boolean;
|
|
34
33
|
/** Environment (default: "local") */
|
|
35
34
|
environment?: string;
|
|
35
|
+
/** BFF base URL (passed from shell's env config). Only used when `bff` is `true`. */
|
|
36
|
+
bffBaseUrl?: string;
|
|
37
|
+
/** Registry polling interval in ms (passed from shell's env config). */
|
|
38
|
+
registryPollInterval?: number;
|
|
36
39
|
}
|
|
37
|
-
export declare function AdminShell({ modules: manifests, children,
|
|
40
|
+
export declare function AdminShell({ modules: manifests, children, bff, authClient: providedAuthClient, registryClient, apiUrl, inMemoryRegistry, environment, bffBaseUrl: bffBaseUrlProp, registryPollInterval: registryPollIntervalProp, }: AdminShellProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/shell/AdminShell.js
CHANGED
|
@@ -15,7 +15,7 @@ import { RegistryPage } from "./components/RegistryPage";
|
|
|
15
15
|
import { HomePage } from "./components/HomePage";
|
|
16
16
|
import { AuthProvider, useAuthContext } from "../components/AuthProvider";
|
|
17
17
|
import { createInMemoryAuthClient, createMockUsersFromRoles, } from "../auth/client/in-memory";
|
|
18
|
-
import {
|
|
18
|
+
import { createBffAuthClient } from "../auth/client/bff";
|
|
19
19
|
import { createInMemoryRegistryClient } from "../registry/client/in-memory";
|
|
20
20
|
import { createCachedCatalog } from "../registry/cache/cached-catalog";
|
|
21
21
|
import { DevtoolsPanel } from "./components/DevtoolsPanel";
|
|
@@ -25,8 +25,9 @@ import { useRegistryPolling } from "../registry/useRegistryPolling";
|
|
|
25
25
|
import { DynamicModule } from "../router/DynamicModule";
|
|
26
26
|
import { SidebarProvider, SidebarInset } from "@nsxbet/admin-ui";
|
|
27
27
|
import { initTelemetry, track, trackError } from "./telemetry";
|
|
28
|
-
import { initI18n, saveLocale, isSupportedLocale, i18n } from "../i18n";
|
|
28
|
+
import { initI18n, saveLocale, isSupportedLocale, i18n, DEFAULT_LOCALE } from "../i18n";
|
|
29
29
|
import { resolvePollingInterval } from "./polling-config";
|
|
30
|
+
import { SDK_PACKAGE_VERSION } from "../sdk-version.js";
|
|
30
31
|
const TIMEZONE_STORAGE_KEY = "admin-timezone-mode";
|
|
31
32
|
function getStoredTimezoneMode() {
|
|
32
33
|
if (typeof window === "undefined")
|
|
@@ -62,6 +63,7 @@ function manifestToModule(manifest, baseUrl) {
|
|
|
62
63
|
supportChannel: manifest.owners?.supportChannel || "",
|
|
63
64
|
},
|
|
64
65
|
status: "active",
|
|
66
|
+
sdkVersion: manifest.sdkVersion ?? SDK_PACKAGE_VERSION,
|
|
65
67
|
navigationOrder: manifest.navigationOrder,
|
|
66
68
|
icon: manifest.icon,
|
|
67
69
|
navigation: manifest.navigation ? {
|
|
@@ -96,6 +98,7 @@ function catalogModuleToModule(m) {
|
|
|
96
98
|
permissions: m.permissions,
|
|
97
99
|
owners: m.owners,
|
|
98
100
|
status: m.status,
|
|
101
|
+
sdkVersion: m.sdkVersion,
|
|
99
102
|
navigationOrder: m.navigationOrder,
|
|
100
103
|
icon: m.icon,
|
|
101
104
|
navigation: m.navigation ? {
|
|
@@ -176,6 +179,9 @@ function ShellContent({ modules, children, environment, locale, onLocaleChange,
|
|
|
176
179
|
fetch: async (input, init) => {
|
|
177
180
|
const token = await auth.getAccessToken();
|
|
178
181
|
const headers = new Headers(init?.headers);
|
|
182
|
+
if (token === null) {
|
|
183
|
+
return fetch(input, { ...init, headers, credentials: "include" });
|
|
184
|
+
}
|
|
179
185
|
headers.set("Authorization", `Bearer ${token}`);
|
|
180
186
|
return fetch(input, { ...init, headers });
|
|
181
187
|
},
|
|
@@ -220,12 +226,12 @@ function ShellContent({ modules, children, environment, locale, onLocaleChange,
|
|
|
220
226
|
owners: module.owners,
|
|
221
227
|
} })) : (_jsxs("div", { className: "text-muted-foreground", children: ["Module ", module.id, " has no baseUrl configured"] })) }) }, module.id))), _jsx(Route, { path: "*", element: _jsx(MainContent, { modules: modules, moduleBreadcrumbs: moduleBreadcrumbs, children: isStandaloneMode ? children : null }) })] })] })] }), _jsx(CommandPalette, { open: commandPaletteOpen, onOpenChange: onCommandPaletteChange, catalog: catalog }), _jsx(DevtoolsPanel, { environment: environment, modules: modules, catalogVersion: catalog.version, catalogGeneratedAt: catalog.generatedAt, registryMode: registryClient ? "api" : "in-memory", cacheStatus: cacheStatus })] }));
|
|
222
228
|
}
|
|
223
|
-
export function AdminShell({ modules: manifests = [], children,
|
|
229
|
+
export function AdminShell({ modules: manifests = [], children, bff, authClient: providedAuthClient, registryClient, apiUrl, inMemoryRegistry = true, environment = "local", bffBaseUrl: bffBaseUrlProp, registryPollInterval: registryPollIntervalProp, }) {
|
|
224
230
|
const [commandPaletteOpen, setCommandPaletteOpen] = useState(false);
|
|
225
231
|
const [locale, setLocale] = useState(() => {
|
|
226
232
|
// Initialize i18n and get the current language
|
|
227
233
|
initI18n();
|
|
228
|
-
return i18n.language ||
|
|
234
|
+
return i18n.language || DEFAULT_LOCALE;
|
|
229
235
|
});
|
|
230
236
|
const [apiModules, setApiModules] = useState([]);
|
|
231
237
|
const [initialCatalogVersion, setInitialCatalogVersion] = useState("");
|
|
@@ -270,70 +276,47 @@ export function AdminShell({ modules: manifests = [], children, keycloak, authCl
|
|
|
270
276
|
if (providedAuthClient) {
|
|
271
277
|
return providedAuthClient;
|
|
272
278
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
// Check if we should use mock auth
|
|
285
|
-
const useMockAuth = typeof window !== 'undefined' &&
|
|
286
|
-
(mockAuthExplicit || noAuthConfig);
|
|
287
|
-
if (useMockAuth) {
|
|
288
|
-
if (isProd && mockAuthExplicit) {
|
|
289
|
-
console.warn('[AdminShell] Mock auth is active in production build (VITE_MOCK_AUTH=true). ' +
|
|
290
|
-
'Use real authentication (Keycloak) for production deployments.');
|
|
291
|
-
}
|
|
292
|
-
// Default mock users with explicit roles for tasks and users modules
|
|
293
|
-
const defaultMockUsers = createMockUsersFromRoles({
|
|
294
|
-
admin: [
|
|
295
|
-
'admin.tasks.view',
|
|
296
|
-
'admin.tasks.edit',
|
|
297
|
-
'admin.tasks.delete',
|
|
298
|
-
'admin.users.view',
|
|
299
|
-
'admin.users.edit',
|
|
300
|
-
'admin.users.delete',
|
|
301
|
-
'admin.platform.view',
|
|
302
|
-
'admin.platform.edit',
|
|
303
|
-
'admin.platform.delete',
|
|
304
|
-
],
|
|
305
|
-
editor: [
|
|
306
|
-
'admin.tasks.view',
|
|
307
|
-
'admin.tasks.edit',
|
|
308
|
-
'admin.users.view',
|
|
309
|
-
'admin.users.edit',
|
|
310
|
-
'admin.platform.view',
|
|
311
|
-
'admin.platform.edit',
|
|
312
|
-
],
|
|
313
|
-
viewer: ['admin.tasks.view', 'admin.users.view', 'admin.platform.view'],
|
|
314
|
-
noAccess: [],
|
|
315
|
-
});
|
|
316
|
-
return createInMemoryAuthClient({ users: defaultMockUsers, gatewayUrl: import.meta.env.VITE_ADMIN_GATEWAY_URL });
|
|
279
|
+
if (bff) {
|
|
280
|
+
const baseUrl = bff === true
|
|
281
|
+
? bffBaseUrlProp
|
|
282
|
+
? bffBaseUrlProp.replace(/\/$/, '')
|
|
283
|
+
: window.location.origin
|
|
284
|
+
: bff.baseUrl
|
|
285
|
+
? bff.baseUrl.replace(/\/$/, '')
|
|
286
|
+
: bffBaseUrlProp
|
|
287
|
+
? bffBaseUrlProp.replace(/\/$/, '')
|
|
288
|
+
: window.location.origin;
|
|
289
|
+
return createBffAuthClient({ bffBaseUrl: baseUrl });
|
|
317
290
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
291
|
+
const defaultMockUsers = createMockUsersFromRoles({
|
|
292
|
+
admin: [
|
|
293
|
+
'admin.tasks.view',
|
|
294
|
+
'admin.tasks.edit',
|
|
295
|
+
'admin.tasks.delete',
|
|
296
|
+
'admin.users.view',
|
|
297
|
+
'admin.users.edit',
|
|
298
|
+
'admin.users.delete',
|
|
299
|
+
'admin.platform.view',
|
|
300
|
+
'admin.platform.edit',
|
|
301
|
+
'admin.platform.delete',
|
|
302
|
+
],
|
|
303
|
+
editor: [
|
|
304
|
+
'admin.tasks.view',
|
|
305
|
+
'admin.tasks.edit',
|
|
306
|
+
'admin.users.view',
|
|
307
|
+
'admin.users.edit',
|
|
308
|
+
'admin.platform.view',
|
|
309
|
+
'admin.platform.edit',
|
|
310
|
+
],
|
|
311
|
+
viewer: ['admin.tasks.view', 'admin.users.view', 'admin.platform.view'],
|
|
312
|
+
noAccess: [],
|
|
321
313
|
});
|
|
322
|
-
|
|
314
|
+
return createInMemoryAuthClient({ users: defaultMockUsers });
|
|
315
|
+
}, [providedAuthClient, bff, bffBaseUrlProp]);
|
|
323
316
|
// Initialize telemetry
|
|
324
317
|
useEffect(() => {
|
|
325
318
|
initTelemetry(environment);
|
|
326
319
|
}, [environment]);
|
|
327
|
-
// Initialize Keycloak configuration (for legacy support)
|
|
328
|
-
useEffect(() => {
|
|
329
|
-
if (keycloak) {
|
|
330
|
-
window.__KEYCLOAK_CONFIG__ = {
|
|
331
|
-
url: keycloak.url,
|
|
332
|
-
realm: keycloak.realm,
|
|
333
|
-
clientId: keycloak.clientId,
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
}, [keycloak]);
|
|
337
320
|
// Initialize in-memory registry if enabled and no registryClient
|
|
338
321
|
useEffect(() => {
|
|
339
322
|
if (!registryClient && inMemoryRegistry && manifests.length > 0) {
|
|
@@ -385,8 +368,8 @@ export function AdminShell({ modules: manifests = [], children, keycloak, authCl
|
|
|
385
368
|
const pollingInterval = useMemo(() => {
|
|
386
369
|
if (!registryClient || !initialCatalogVersion)
|
|
387
370
|
return 0;
|
|
388
|
-
return resolvePollingInterval(environment);
|
|
389
|
-
}, [registryClient, initialCatalogVersion, environment]);
|
|
371
|
+
return resolvePollingInterval(environment, registryPollIntervalProp);
|
|
372
|
+
}, [registryClient, initialCatalogVersion, environment, registryPollIntervalProp]);
|
|
390
373
|
// Poll for catalog version changes
|
|
391
374
|
const { hasUpdates, dismiss: dismissUpdate } = useRegistryPolling({
|
|
392
375
|
registryClient: registryClient,
|
|
@@ -428,13 +411,16 @@ export function AdminShell({ modules: manifests = [], children, keycloak, authCl
|
|
|
428
411
|
setCacheStatus(cachedCatalogOps.getStatus());
|
|
429
412
|
}
|
|
430
413
|
}, [cachedCatalogOps]);
|
|
431
|
-
//
|
|
414
|
+
// Resolve shell content — loading, unavailable, or ready
|
|
415
|
+
let shellContent;
|
|
432
416
|
if (isLoading) {
|
|
433
|
-
|
|
417
|
+
shellContent = (_jsx("div", { className: "flex h-screen items-center justify-center", children: _jsx("div", { className: "text-muted-foreground", children: "Loading modules..." }) }));
|
|
418
|
+
}
|
|
419
|
+
else if (cacheStatus.state === "unavailable") {
|
|
420
|
+
shellContent = _jsx(RegistryUnavailable, { onRetry: handleRetry });
|
|
434
421
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
return (_jsx(BrowserRouter, { children: _jsx(I18nextProvider, { i18n: i18n, children: _jsx(ThemeProvider, { children: _jsx(RegistryUnavailable, { onRetry: handleRetry }) }) }) }));
|
|
422
|
+
else {
|
|
423
|
+
shellContent = (_jsx(ShellContent, { modules: modules, environment: environment, locale: locale, onLocaleChange: handleLocaleChange, onSearchClick: handleSearchClick, catalog: catalog, commandPaletteOpen: commandPaletteOpen, onCommandPaletteChange: setCommandPaletteOpen, apiUrl: apiUrl, registryClient: registryClient, isStandaloneMode: isStandaloneMode, cacheStatus: cacheStatus, onRetry: handleRetry, hasUpdates: hasUpdates, onDismissUpdate: dismissUpdate, localeCallbacksRef: localeCallbacksRef, timezoneMode: timezoneMode, onTimezoneToggle: handleTimezoneToggle, timezoneCallbacksRef: timezoneCallbacksRef, children: children }));
|
|
438
424
|
}
|
|
439
|
-
return (_jsx(BrowserRouter, { children: _jsx(I18nextProvider, { i18n: i18n, children: _jsx(ThemeProvider, { children: _jsx(AuthProvider, { authClient: authClient, children:
|
|
425
|
+
return (_jsx(BrowserRouter, { children: _jsx(I18nextProvider, { i18n: i18n, children: _jsx(ThemeProvider, { children: _jsx(AuthProvider, { authClient: authClient, children: shellContent }) }) }) }));
|
|
440
426
|
}
|
|
@@ -13,11 +13,7 @@ export function ModuleOverview({ modules }) {
|
|
|
13
13
|
if (!module) {
|
|
14
14
|
return (_jsx("div", { className: "p-6 max-w-3xl mx-auto space-y-6", children: _jsx(Card, { className: "border-destructive", children: _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "flex items-center gap-3 text-destructive", children: [_jsx(Icon, { name: "alert-circle", className: "h-6 w-6" }), _jsxs("div", { children: [_jsx("h1", { className: "text-xl font-bold", children: t('errors.moduleNotFound') }), _jsx("p", { className: "text-muted-foreground mt-1", children: t('errors.moduleNotFoundDescription', { moduleId }) })] })] }) }) }) }));
|
|
15
15
|
}
|
|
16
|
-
const statusVariant = module.status === "active"
|
|
17
|
-
? "success"
|
|
18
|
-
: module.status === "deprecated"
|
|
19
|
-
? "warning"
|
|
20
|
-
: "secondary";
|
|
16
|
+
const statusVariant = module.status === "active" ? "success" : "secondary";
|
|
21
17
|
const moduleTitle = resolveLocalizedString(module.title, i18n.language);
|
|
22
18
|
const moduleDescription = resolveLocalizedString(module.description, i18n.language);
|
|
23
19
|
return (_jsxs("div", { className: "p-6 max-w-3xl mx-auto space-y-6", children: [_jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "flex-shrink-0 p-3 rounded-lg bg-muted", children: _jsx(Icon, { name: module.icon || "package", className: "h-8 w-8" }) }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-3 mb-1", children: [_jsx("h1", { className: "text-3xl font-bold", children: moduleTitle }), _jsx(Badge, { variant: statusVariant, className: "capitalize", children: module.status })] }), moduleDescription && (_jsx("p", { className: "text-muted-foreground", children: moduleDescription }))] })] }), module.commands && module.commands.length > 0 && (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { name: "zap", className: "h-5 w-5 text-muted-foreground" }), _jsx(CardTitle, { className: "text-lg", children: t('moduleOverview.actions') })] }), _jsx(CardDescription, { children: t('moduleOverview.actionsDescription') })] }), _jsx(CardContent, { children: _jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: module.commands.map((command) => (_jsxs("button", { onClick: () => navigate(command.route), className: "flex items-center gap-3 rounded-lg border border-border bg-card p-4 text-left transition-colors hover:bg-accent hover:border-accent", children: [_jsx("div", { className: "flex-shrink-0 p-2 rounded-md bg-muted", children: _jsx(Icon, { name: command.icon || "file-text", className: "h-5 w-5" }) }), _jsx("span", { className: "font-medium", children: resolveLocalizedString(command.title, i18n.language) })] }, command.id))) }) })] })), _jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { name: "info", className: "h-5 w-5 text-muted-foreground" }), _jsx(CardTitle, { className: "text-lg", children: t('moduleOverview.information') })] }) }), _jsx(CardContent, { children: _jsxs("dl", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between py-2 border-b border-border", children: [_jsxs("dt", { className: "text-sm font-medium text-muted-foreground flex items-center gap-2", children: [_jsx(Icon, { name: "folder", className: "h-4 w-4" }), t('moduleOverview.category')] }), _jsx("dd", { className: "text-sm font-medium", children: module.category })] }), _jsxs("div", { className: "flex items-center justify-between py-2 border-b border-border", children: [_jsxs("dt", { className: "text-sm font-medium text-muted-foreground flex items-center gap-2", children: [_jsx(Icon, { name: "activity", className: "h-4 w-4" }), t('moduleOverview.status')] }), _jsx("dd", { children: _jsx(Badge, { variant: statusVariant, className: "capitalize", children: module.status }) })] }), module.owners?.team && (_jsxs("div", { className: "flex items-center justify-between py-2 border-b border-border", children: [_jsxs("dt", { className: "text-sm font-medium text-muted-foreground flex items-center gap-2", children: [_jsx(Icon, { name: "users", className: "h-4 w-4" }), t('moduleOverview.owner')] }), _jsx("dd", { className: "text-sm font-medium", children: module.owners.team })] })), module.owners?.supportChannel && (_jsxs("div", { className: "flex items-center justify-between py-2", children: [_jsxs("dt", { className: "text-sm font-medium text-muted-foreground flex items-center gap-2", children: [_jsx(Icon, { name: "message-circle", className: "h-4 w-4" }), t('moduleOverview.support')] }), _jsx("dd", { className: "text-sm font-medium", children: module.owners.supportChannel })] }))] }) })] })] }));
|
|
@@ -201,7 +201,7 @@ export function RegistryPage({ apiUrl, registryClient }) {
|
|
|
201
201
|
}
|
|
202
202
|
return (_jsxs("div", { className: "p-6 max-w-4xl mx-auto space-y-6", "data-testid": "registry-page", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold mb-1", "data-testid": "registry-heading", children: t("registryPage.title") }), _jsx("p", { className: "text-muted-foreground", children: t("registryPage.description") })] }), _jsxs("div", { className: "flex items-center gap-2", children: [canEdit && !isReorderMode && (_jsxs(Button, { variant: "outline", size: "sm", onClick: enterReorderMode, children: [_jsx(Icon, { name: "arrow-up-down", className: "h-4 w-4 mr-2" }), t("registryPage.manageOrder")] })), _jsx(Badge, { variant: apiUrl ? "default" : "secondary", children: apiUrl ? t("registryPage.apiMode") : t("registryPage.inMemoryMode") })] })] }), error && (_jsx(Card, { className: "border-destructive bg-destructive/10", children: _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "flex items-center gap-3 text-destructive", children: [_jsx(Icon, { name: "alert-circle", className: "h-5 w-5" }), _jsx("p", { children: error })] }) }) })), isReorderMode && (_jsx(Card, { children: _jsxs(CardContent, { className: "pt-6", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("h2", { className: "text-lg font-semibold", children: t("registryPage.manageOrder") }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", onClick: cancelReorder, disabled: isSavingOrder, children: t("common.cancel") }), _jsx(Button, { size: "sm", onClick: saveOrder, disabled: isSavingOrder || !hasOrderChanged, children: isSavingOrder ? (_jsxs(_Fragment, { children: [_jsx(Icon, { name: "loader-2", className: "h-4 w-4 mr-2 animate-spin" }), t("registryPage.savingOrder")] })) : (t("registryPage.saveOrder")) })] })] }), _jsx("div", { className: "space-y-1", children: reorderList.map((module, index) => (_jsxs("div", { className: "flex items-center gap-3 p-2 rounded-lg border bg-background", children: [_jsx(Badge, { variant: "outline", className: "font-mono text-xs shrink-0", children: t("registryPage.position", { position: index + 1 }) }), _jsx("div", { className: "flex-shrink-0 p-1.5 rounded bg-muted", children: _jsx(Icon, { name: module.manifest.icon || "package", className: "h-4 w-4" }) }), _jsx("span", { className: "flex-1 font-medium truncate", children: resolveLocalizedString(module.manifest.title, i18n.language) }), _jsxs("div", { className: "flex gap-1 shrink-0", children: [_jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => moveUp(index), disabled: index === 0, children: _jsx(Icon, { name: "chevron-up", className: "h-4 w-4" }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => moveDown(index), disabled: index === reorderList.length - 1, children: _jsx(Icon, { name: "chevron-down", className: "h-4 w-4" }) })] })] }, module.id))) })] }) })), !isReorderMode && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { name: "package", className: "h-5 w-5 text-muted-foreground" }), _jsxs("h2", { className: "text-lg font-semibold", children: [t("registryPage.registeredModules"), " ", !isLoading && (_jsxs("span", { className: "text-muted-foreground font-normal", children: ["(", modules.length, ")"] }))] })] }), isLoading ? (_jsx(Card, { children: _jsxs(CardContent, { className: "py-8 text-center", children: [_jsx(Icon, { name: "loader-2", className: "h-8 w-8 mx-auto mb-3 animate-spin text-muted-foreground" }), _jsx("p", { className: "text-muted-foreground", children: t("registryPage.loadingModules") })] }) })) : modules.length === 0 ? (_jsx(Card, { children: _jsxs(CardContent, { className: "py-8 text-center", children: [_jsx(Icon, { name: "package", className: "h-8 w-8 mx-auto mb-3 text-muted-foreground" }), _jsx("p", { className: "text-muted-foreground", children: t("registryPage.noModules") }), _jsx("p", { className: "text-sm text-muted-foreground mt-1", children: t("registryPage.noModulesHint") })] }) })) : (_jsx("div", { className: "space-y-3", children: modules.map((module, index) => (_jsx(Card, { className: !module.enabled ? "opacity-60 border-dashed" : undefined, "data-testid": `module-card-${module.moduleId}`, children: _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex items-start gap-4 flex-1 min-w-0", children: [_jsx("div", { className: "flex-shrink-0 p-2 rounded-lg bg-muted", children: _jsx(Icon, { name: module.manifest.icon || "package", className: "h-6 w-6" }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 mb-1 flex-wrap", children: [_jsx("h3", { className: "font-semibold truncate", children: resolveLocalizedString(module.manifest.title, i18n.language) }), canEdit && (_jsx(Badge, { variant: module.enabled ? "success" : "secondary", children: module.enabled
|
|
203
203
|
? t("registryPage.enabled")
|
|
204
|
-
: t("registryPage.disabled") })), module.version ? (_jsxs(Badge, { variant: "outline", "data-testid": `version-badge-${module.moduleId}`, children: ["v", module.version] })) : (_jsx(Badge, { variant: "outline", className: "text-muted-foreground", children: t("registryPage.unversioned") }))] }), _jsx("p", { className: "text-sm text-muted-foreground mb-3", children: resolveLocalizedString(module.manifest.description, i18n.language) ||
|
|
204
|
+
: t("registryPage.disabled") })), module.version ? (_jsxs(Badge, { variant: "outline", "data-testid": `version-badge-${module.moduleId}`, children: ["v", module.version] })) : (_jsx(Badge, { variant: "outline", className: "text-muted-foreground", children: t("registryPage.unversioned") })), (module.sdkVersion ?? module.manifest.sdkVersion) && (_jsxs(Badge, { variant: "outline", className: "font-mono text-xs", children: ["SDK ", module.sdkVersion ?? module.manifest.sdkVersion] }))] }), _jsx("p", { className: "text-sm text-muted-foreground mb-3", children: resolveLocalizedString(module.manifest.description, i18n.language) ||
|
|
205
205
|
t("registryPage.noDescription") }), _jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground", children: [_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(Icon, { name: "hash", className: "h-3 w-3" }), module.moduleId] }), _jsxs("span", { className: "flex items-center gap-1", children: [_jsx(Icon, { name: "folder", className: "h-3 w-3" }), module.manifest.category || "General"] }), _jsxs("span", { className: "flex items-center gap-1", children: [_jsx(Icon, { name: "navigation", className: "h-3 w-3" }), module.manifest.routeBase] }), module.baseUrl && (_jsxs("span", { className: "flex items-center gap-1", title: module.baseUrl, children: [_jsx(Icon, { name: "link", className: "h-3 w-3" }), _jsx("span", { className: "truncate max-w-[200px]", children: module.baseUrl })] }))] })] })] }), _jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [_jsx(Badge, { variant: "outline", className: "font-mono text-xs", children: t("registryPage.position", { position: index + 1 }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => openVersionHistory(module), title: t("registryPage.versionHistory"), "data-testid": `version-history-btn-${module.moduleId}`, children: _jsx(Icon, { name: "history", className: "h-4 w-4" }) }), canEdit && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-sm text-muted-foreground", children: t("registryPage.enabled") }), _jsx(Switch, { checked: module.enabled, onCheckedChange: () => handleToggleEnabled(module), "data-testid": `enable-switch-${module.moduleId}` })] })), canDelete && (_jsx(Button, { variant: "destructive", size: "sm", onClick: () => handleDeleteModule(module), children: _jsx(Icon, { name: "trash-2", className: "h-4 w-4" }) }))] })] }) }) }, module.id))) }))] })), _jsx(Dialog, { open: !!disableTarget, onOpenChange: (open) => !open && setDisableTarget(null), children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: t("registryPage.disableTitle", {
|
|
206
206
|
name: disableTarget
|
|
207
207
|
? resolveLocalizedString(disableTarget.manifest.title, i18n.language)
|
|
@@ -3,7 +3,7 @@ import { useState, useEffect } from "react";
|
|
|
3
3
|
import { Search, Moon, Sun, Check, Clock, Globe } from "lucide-react";
|
|
4
4
|
import { useTheme } from "./theme-provider";
|
|
5
5
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Badge, Button, } from "@nsxbet/admin-ui";
|
|
6
|
-
import { SUPPORTED_LOCALES, LOCALE_FLAGS, LOCALE_NAMES } from "../../i18n";
|
|
6
|
+
import { SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_FLAGS, LOCALE_NAMES } from "../../i18n";
|
|
7
7
|
import { useI18n } from "../../hooks/useI18n";
|
|
8
8
|
const ENV_COLORS = {
|
|
9
9
|
local: "bg-gray-500",
|
|
@@ -30,7 +30,7 @@ const ENV_HEADER_COLORS_DARK = {
|
|
|
30
30
|
export function TopBar({ onSearchClick, environment = "local", locale: externalLocale, onLocaleChange, timezoneMode = "local", onTimezoneToggle, }) {
|
|
31
31
|
const { theme, setTheme } = useTheme();
|
|
32
32
|
const { t } = useI18n();
|
|
33
|
-
const [locale, setLocale] = useState(externalLocale ||
|
|
33
|
+
const [locale, setLocale] = useState(externalLocale || DEFAULT_LOCALE);
|
|
34
34
|
useEffect(() => {
|
|
35
35
|
if (externalLocale && SUPPORTED_LOCALES.includes(externalLocale)) {
|
|
36
36
|
setLocale(externalLocale);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useEffect, useState } from "react";
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
3
3
|
const initialState = {
|
|
4
4
|
theme: "system",
|
|
5
5
|
setTheme: () => null,
|
|
@@ -24,13 +24,11 @@ storageKey = "admin-ui-theme", ...props }) {
|
|
|
24
24
|
}
|
|
25
25
|
root.classList.add(theme);
|
|
26
26
|
}, [theme]);
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
setTheme
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
};
|
|
27
|
+
const setThemeStable = useCallback((newTheme) => {
|
|
28
|
+
localStorage.setItem(storageKey, newTheme);
|
|
29
|
+
setTheme(newTheme);
|
|
30
|
+
}, [storageKey]);
|
|
31
|
+
const value = useMemo(() => ({ theme, setTheme: setThemeStable }), [theme, setThemeStable]);
|
|
34
32
|
return (_jsx(ThemeProviderContext.Provider, { ...props, value: value, children: children }));
|
|
35
33
|
}
|
|
36
34
|
// eslint-disable-next-line react-refresh/only-export-components
|
package/dist/shell/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { AdminShell } from "./AdminShell";
|
|
2
|
-
export type { AdminShellProps } from "./AdminShell";
|
|
2
|
+
export type { AdminShellProps, AdminShellBffConfig } from "./AdminShell";
|
|
3
3
|
export { TopBar, LeftNav, MainContent, CommandPalette, ThemeProvider, useTheme, } from "./components";
|
|
4
4
|
export type { TopBarProps, CommandPaletteProps } from "./components";
|
|
5
5
|
export type { Module, ModuleCommand, ModuleStatus, NavigationSection, ModuleNavigation, Catalog, ImportMap, SearchableItem, SearchResult, } from "./types";
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Resolve the registry polling interval in milliseconds.
|
|
3
3
|
*
|
|
4
4
|
* Priority:
|
|
5
|
-
* 1. Explicit `
|
|
6
|
-
* 2.
|
|
5
|
+
* 1. Explicit `explicitInterval` parameter (passed from shell's env config)
|
|
6
|
+
* 2. `REGISTRY_POLL_INTERVAL` from SDK `env` (parsed from `window.__ENV__` via `/env.js`)
|
|
7
|
+
* 3. Environment-based default (local: 60s, staging: 5min, production: 15min)
|
|
7
8
|
*
|
|
8
9
|
* Returns 0 (disabled) when the explicit value is "0".
|
|
9
10
|
*/
|
|
10
|
-
export declare function resolvePollingInterval(environment: string): number;
|
|
11
|
+
export declare function resolvePollingInterval(environment: string, explicitInterval?: number): number;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { env } from "../env.js";
|
|
1
2
|
const ENVIRONMENT_DEFAULTS = {
|
|
2
3
|
local: 60000,
|
|
3
4
|
development: 60000,
|
|
@@ -9,18 +10,19 @@ const ENVIRONMENT_DEFAULTS = {
|
|
|
9
10
|
* Resolve the registry polling interval in milliseconds.
|
|
10
11
|
*
|
|
11
12
|
* Priority:
|
|
12
|
-
* 1. Explicit `
|
|
13
|
-
* 2.
|
|
13
|
+
* 1. Explicit `explicitInterval` parameter (passed from shell's env config)
|
|
14
|
+
* 2. `REGISTRY_POLL_INTERVAL` from SDK `env` (parsed from `window.__ENV__` via `/env.js`)
|
|
15
|
+
* 3. Environment-based default (local: 60s, staging: 5min, production: 15min)
|
|
14
16
|
*
|
|
15
17
|
* Returns 0 (disabled) when the explicit value is "0".
|
|
16
18
|
*/
|
|
17
|
-
export function resolvePollingInterval(environment) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
export function resolvePollingInterval(environment, explicitInterval) {
|
|
20
|
+
if (explicitInterval !== undefined) {
|
|
21
|
+
return explicitInterval;
|
|
22
|
+
}
|
|
23
|
+
const fromEnv = env.registryPollInterval;
|
|
24
|
+
if (fromEnv !== undefined) {
|
|
25
|
+
return fromEnv;
|
|
24
26
|
}
|
|
25
27
|
return ENVIRONMENT_DEFAULTS[environment] ?? ENVIRONMENT_DEFAULTS.local;
|
|
26
28
|
}
|
package/dist/shell/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { LocalizedField } from "../i18n/config.js";
|
|
|
5
5
|
/**
|
|
6
6
|
* Module status in the registry
|
|
7
7
|
*/
|
|
8
|
-
export type ModuleStatus = "active" | "
|
|
8
|
+
export type ModuleStatus = "active" | "disabled";
|
|
9
9
|
/**
|
|
10
10
|
* Command within a module that can be searched and invoked
|
|
11
11
|
*/
|
|
@@ -68,6 +68,8 @@ export interface Module {
|
|
|
68
68
|
};
|
|
69
69
|
/** Module status */
|
|
70
70
|
status: ModuleStatus;
|
|
71
|
+
/** Semver of @nsxbet/admin-sdk the module was built against */
|
|
72
|
+
sdkVersion: string;
|
|
71
73
|
/** Optional navigation order */
|
|
72
74
|
navigationOrder?: number;
|
|
73
75
|
/** Optional icon name */
|
package/dist/types/platform.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ export interface PlatformAPI {
|
|
|
30
30
|
locale: string;
|
|
31
31
|
/** Authentication methods */
|
|
32
32
|
auth: {
|
|
33
|
-
/** Get the current access token (auto-refreshed by shell) */
|
|
34
|
-
getAccessToken: () => Promise<string>;
|
|
33
|
+
/** Get the current access token (auto-refreshed by shell). Null when using BFF HttpOnly cookie auth. */
|
|
34
|
+
getAccessToken: () => Promise<string | null>;
|
|
35
35
|
/** Check if user has a specific permission (realm role) */
|
|
36
36
|
hasPermission: (permission: string) => boolean;
|
|
37
37
|
/** Get current user information */
|
|
@@ -74,21 +74,12 @@ export interface PlatformAPI {
|
|
|
74
74
|
/** Authenticated fetch wrapper */
|
|
75
75
|
fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
76
76
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Keycloak configuration stored in window
|
|
79
|
-
*/
|
|
80
|
-
export interface KeycloakWindowConfig {
|
|
81
|
-
url: string;
|
|
82
|
-
realm: string;
|
|
83
|
-
clientId: string;
|
|
84
|
-
}
|
|
85
77
|
/**
|
|
86
78
|
* Extend Window interface to include platform API
|
|
87
79
|
*/
|
|
88
80
|
declare global {
|
|
89
81
|
interface Window {
|
|
90
82
|
__ADMIN_PLATFORM_API__?: PlatformAPI;
|
|
91
|
-
__KEYCLOAK_CONFIG__?: KeycloakWindowConfig;
|
|
92
83
|
}
|
|
93
84
|
}
|
|
94
85
|
export {};
|
package/dist/vite/config.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { type Plugin } from "vite";
|
|
2
|
-
/**
|
|
3
|
-
* Default admin gateway URL (staging environment).
|
|
4
|
-
* Used by the env injection plugin when no explicit value is configured.
|
|
5
|
-
*/
|
|
6
|
-
export declare const ADMIN_GATEWAY_STAGING_URL = "https://admin-bff-stg.nsx.dev";
|
|
7
2
|
/**
|
|
8
3
|
* Shared dependencies that are externalized in module builds.
|
|
9
4
|
* These are provided by the shell via import maps.
|
|
@@ -35,11 +30,11 @@ export interface AdminModuleOptions {
|
|
|
35
30
|
buildMode?: "auto" | "always";
|
|
36
31
|
/**
|
|
37
32
|
* Admin gateway URL for BFF token integration (InMemory auth).
|
|
38
|
-
* - `undefined` (default):
|
|
39
|
-
* - `string`:
|
|
40
|
-
* - `null`: disable
|
|
33
|
+
* - `undefined` (default): use `ADMIN_GATEWAY_URL` from env, or {@link DEFAULT_GATEWAY_URL}
|
|
34
|
+
* - `string`: use this URL in `/env.js`
|
|
35
|
+
* - `null`: disable `/env.js` entirely (no runtime env injection)
|
|
41
36
|
*
|
|
42
|
-
* Explicit env vars (`.env` files, shell env)
|
|
37
|
+
* Explicit env vars (`.env` files, shell env) take precedence over the string option.
|
|
43
38
|
*/
|
|
44
39
|
gatewayUrl?: string | null;
|
|
45
40
|
}
|
package/dist/vite/config.js
CHANGED
|
@@ -2,18 +2,96 @@ import { loadEnv } from "vite";
|
|
|
2
2
|
import { generateModuleManifestPlugin, serveDistPlugin } from "./plugins.js";
|
|
3
3
|
import { adminModuleI18nPlugin } from "./i18n-plugin.js";
|
|
4
4
|
import { getSharedExternals } from "./AdminShellSharedDeps.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Default admin gateway URL (staging environment).
|
|
8
|
-
* Used by the env injection plugin when no explicit value is configured.
|
|
9
|
-
*/
|
|
10
|
-
export const ADMIN_GATEWAY_STAGING_URL = "https://admin-bff-stg.nsx.dev";
|
|
5
|
+
/** Default gateway when no env or option is set (internal to the plugin). */
|
|
6
|
+
const DEFAULT_GATEWAY_URL = "https://admin-bff-stg.nsx.dev";
|
|
11
7
|
/**
|
|
12
8
|
* Shared dependencies that are externalized in module builds.
|
|
13
9
|
* These are provided by the shell via import maps.
|
|
14
10
|
* Derived from SHARED_DEPS_CONFIG — the single source of truth.
|
|
15
11
|
*/
|
|
16
12
|
export const SHARED_EXTERNALS = getSharedExternals();
|
|
13
|
+
function buildEnvJs(mode, gatewayUrl) {
|
|
14
|
+
const loaded = loadEnv(mode, process.cwd(), "");
|
|
15
|
+
const fromEnv = process.env.ADMIN_GATEWAY_URL || loaded.ADMIN_GATEWAY_URL;
|
|
16
|
+
let adminGateway;
|
|
17
|
+
if (fromEnv) {
|
|
18
|
+
adminGateway = fromEnv;
|
|
19
|
+
}
|
|
20
|
+
else if (gatewayUrl !== undefined && gatewayUrl !== null) {
|
|
21
|
+
adminGateway = gatewayUrl;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
adminGateway = DEFAULT_GATEWAY_URL;
|
|
25
|
+
}
|
|
26
|
+
const entries = {
|
|
27
|
+
ADMIN_GATEWAY_URL: adminGateway,
|
|
28
|
+
};
|
|
29
|
+
const mockAuth = loaded.MOCK_AUTH ?? process.env.MOCK_AUTH;
|
|
30
|
+
if (mockAuth !== undefined && mockAuth !== "") {
|
|
31
|
+
entries.MOCK_AUTH = mockAuth;
|
|
32
|
+
}
|
|
33
|
+
const environment = loaded.ENVIRONMENT ?? process.env.ENVIRONMENT;
|
|
34
|
+
if (environment !== undefined && environment !== "") {
|
|
35
|
+
entries.ENVIRONMENT = environment;
|
|
36
|
+
}
|
|
37
|
+
const registryPollInterval = loaded.REGISTRY_POLL_INTERVAL ?? process.env.REGISTRY_POLL_INTERVAL;
|
|
38
|
+
if (registryPollInterval !== undefined && registryPollInterval !== "") {
|
|
39
|
+
entries.REGISTRY_POLL_INTERVAL = registryPollInterval;
|
|
40
|
+
}
|
|
41
|
+
const body = Object.entries(entries)
|
|
42
|
+
.map(([k, v]) => `${k}:${JSON.stringify(v)}`)
|
|
43
|
+
.join(",");
|
|
44
|
+
return `window.__ENV__={${body}};`;
|
|
45
|
+
}
|
|
46
|
+
function createAdminModuleEnvPlugin(gatewayUrl) {
|
|
47
|
+
return {
|
|
48
|
+
name: "admin-module-env",
|
|
49
|
+
configureServer(server) {
|
|
50
|
+
if (gatewayUrl === null)
|
|
51
|
+
return;
|
|
52
|
+
server.middlewares.use((req, res, next) => {
|
|
53
|
+
const url = req.url?.split("?")[0];
|
|
54
|
+
if (url === "/env.js") {
|
|
55
|
+
const mode = server.config.mode;
|
|
56
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
57
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
58
|
+
res.end(buildEnvJs(mode, gatewayUrl));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
next();
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
configurePreviewServer(server) {
|
|
65
|
+
if (gatewayUrl === null)
|
|
66
|
+
return;
|
|
67
|
+
server.middlewares.use((req, res, next) => {
|
|
68
|
+
const url = req.url?.split("?")[0];
|
|
69
|
+
if (url === "/env.js") {
|
|
70
|
+
const mode = server.config.mode;
|
|
71
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
72
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
73
|
+
res.end(buildEnvJs(mode, gatewayUrl));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
next();
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
transformIndexHtml: {
|
|
80
|
+
order: "pre",
|
|
81
|
+
handler(html) {
|
|
82
|
+
if (gatewayUrl === null)
|
|
83
|
+
return html;
|
|
84
|
+
if (html.includes('src="/env.js"') || html.includes("src='/env.js'")) {
|
|
85
|
+
return html;
|
|
86
|
+
}
|
|
87
|
+
if (html.includes("</head>")) {
|
|
88
|
+
return html.replace("</head>", ` <script src="/env.js"></script>\n </head>`);
|
|
89
|
+
}
|
|
90
|
+
return html;
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
17
95
|
/**
|
|
18
96
|
* Composable Vite plugin array for admin modules.
|
|
19
97
|
* Returns plugins that handle build-time lib config, dist serving, and manifest generation.
|
|
@@ -54,26 +132,6 @@ export function adminModule(options = {}) {
|
|
|
54
132
|
return true;
|
|
55
133
|
return process.env.ADMIN_MODULE === "true";
|
|
56
134
|
}
|
|
57
|
-
const envPlugin = {
|
|
58
|
-
name: "admin-module-env",
|
|
59
|
-
config(_config, { mode }) {
|
|
60
|
-
if (gatewayUrl === null)
|
|
61
|
-
return;
|
|
62
|
-
const env = loadEnv(mode, process.cwd(), "VITE_");
|
|
63
|
-
const fromEnv = process.env[ENV_KEY] || env[ENV_KEY];
|
|
64
|
-
if (fromEnv) {
|
|
65
|
-
console.log(`[admin-module-env] ${ENV_KEY} → ${fromEnv} (from env)`);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const url = gatewayUrl ?? ADMIN_GATEWAY_STAGING_URL;
|
|
69
|
-
console.log(`[admin-module-env] ${ENV_KEY} → ${url} (auto-injected)`);
|
|
70
|
-
return {
|
|
71
|
-
define: {
|
|
72
|
-
[`import.meta.env.${ENV_KEY}`]: JSON.stringify(url),
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
135
|
const buildConfigPlugin = {
|
|
78
136
|
name: "admin-module-build-config",
|
|
79
137
|
config(_config, { command }) {
|
|
@@ -100,7 +158,7 @@ export function adminModule(options = {}) {
|
|
|
100
158
|
},
|
|
101
159
|
};
|
|
102
160
|
return [
|
|
103
|
-
|
|
161
|
+
createAdminModuleEnvPlugin(gatewayUrl),
|
|
104
162
|
adminModuleI18nPlugin(),
|
|
105
163
|
serveDistPlugin({ distDir: outDir }),
|
|
106
164
|
generateModuleManifestPlugin(),
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export { generateModuleManifestPlugin, serveDistPlugin, type GenerateModuleManifestPluginOptions, type ServeDistPluginOptions, } from "./plugins.js";
|
|
17
17
|
export { adminModuleI18nPlugin, type AdminModuleI18nPluginOptions, } from "./i18n-plugin.js";
|
|
18
|
-
export { adminModule, defineModuleConfig, SHARED_EXTERNALS,
|
|
18
|
+
export { adminModule, defineModuleConfig, SHARED_EXTERNALS, type AdminModuleOptions, type ModuleConfigOptions, } from "./config.js";
|
|
19
19
|
export { AdminShellSharedDeps, SHARED_DEPS_CONFIG, getSharedExternals, type SharedDepConfig, } from "./AdminShellSharedDeps.js";
|
package/dist/vite/index.js
CHANGED
|
@@ -15,5 +15,5 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export { generateModuleManifestPlugin, serveDistPlugin, } from "./plugins.js";
|
|
17
17
|
export { adminModuleI18nPlugin, } from "./i18n-plugin.js";
|
|
18
|
-
export { adminModule, defineModuleConfig, SHARED_EXTERNALS,
|
|
18
|
+
export { adminModule, defineModuleConfig, SHARED_EXTERNALS, } from "./config.js";
|
|
19
19
|
export { AdminShellSharedDeps, SHARED_DEPS_CONFIG, getSharedExternals, } from "./AdminShellSharedDeps.js";
|