diff --git a/src/bin/keycloakify/buildJars/buildJar.ts b/src/bin/keycloakify/buildJars/buildJar.ts index 96bb6e2b..9cd37344 100644 --- a/src/bin/keycloakify/buildJars/buildJar.ts +++ b/src/bin/keycloakify/buildJars/buildJar.ts @@ -122,7 +122,17 @@ export async function buildJar(params: { themes: await (async () => { const dirPath = pathJoin(tmpResourcesDirPath, "theme"); - const themeNames = await fs.readdir(dirPath); + const themeNames = (await fs.readdir(dirPath)).sort( + (a, b) => { + const indexA = buildContext.themeNames.indexOf(a); + const indexB = buildContext.themeNames.indexOf(b); + + const orderA = indexA === -1 ? Infinity : indexA; + const orderB = indexB === -1 ? Infinity : indexB; + + return orderA - orderB; + } + ); return Promise.all( themeNames.map(async themeName => { diff --git a/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts b/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts index 3a1820f7..ac986942 100644 --- a/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts +++ b/src/bin/start-keycloak/realmConfig/prepareRealmConfig.ts @@ -1,28 +1,20 @@ import { assert } from "tsafe/assert"; import type { ParsedRealmJson } from "./ParsedRealmJson"; import { getDefaultConfig } from "./defaultConfig"; -import type { BuildContext } from "../../shared/buildContext"; -import { objectKeys } from "tsafe/objectKeys"; -import { TEST_APP_URL } from "../../shared/constants"; +import { TEST_APP_URL, type ThemeType, THEME_TYPES } from "../../shared/constants"; import { sameFactory } from "evt/tools/inDepth/same"; -export type BuildContextLike = { - themeNames: BuildContext["themeNames"]; - implementedThemeTypes: BuildContext["implementedThemeTypes"]; -}; - -assert; - export function prepareRealmConfig(params: { parsedRealmJson: ParsedRealmJson; keycloakMajorVersionNumber: number; - buildContext: BuildContextLike; + parsedKeycloakThemesJsonEntry: { name: string; types: (ThemeType | "email")[] }; }): { realmName: string; clientName: string; username: string; } { - const { parsedRealmJson, keycloakMajorVersionNumber, buildContext } = params; + const { parsedRealmJson, keycloakMajorVersionNumber, parsedKeycloakThemesJsonEntry } = + params; const { username } = addOrEditTestUser({ parsedRealmJson, @@ -38,8 +30,7 @@ export function prepareRealmConfig(params: { enableCustomThemes({ parsedRealmJson, - themeName: buildContext.themeNames[0], - implementedThemeTypes: buildContext.implementedThemeTypes + parsedKeycloakThemesJsonEntry }); enable_custom_events_listeners: { @@ -63,17 +54,15 @@ export function prepareRealmConfig(params: { function enableCustomThemes(params: { parsedRealmJson: ParsedRealmJson; - themeName: string; - implementedThemeTypes: BuildContextLike["implementedThemeTypes"]; + parsedKeycloakThemesJsonEntry: { name: string; types: (ThemeType | "email")[] }; }) { - const { parsedRealmJson, themeName, implementedThemeTypes } = params; + const { parsedRealmJson, parsedKeycloakThemesJsonEntry } = params; - for (const themeType of objectKeys(implementedThemeTypes)) { - if (!implementedThemeTypes[themeType].isImplemented) { - continue; - } - - parsedRealmJson[`${themeType}Theme` as const] = themeName; + for (const themeType of [...THEME_TYPES, "email"] as const) { + parsedRealmJson[`${themeType}Theme` as const] = + !parsedKeycloakThemesJsonEntry.types.includes(themeType) + ? "" + : parsedKeycloakThemesJsonEntry.name; } } diff --git a/src/bin/start-keycloak/realmConfig/realmConfig.ts b/src/bin/start-keycloak/realmConfig/realmConfig.ts index 72ab2fef..4710465e 100644 --- a/src/bin/start-keycloak/realmConfig/realmConfig.ts +++ b/src/bin/start-keycloak/realmConfig/realmConfig.ts @@ -1,10 +1,7 @@ import type { BuildContext } from "../../shared/buildContext"; import { assert } from "tsafe/assert"; import { getDefaultConfig } from "./defaultConfig"; -import { - prepareRealmConfig, - type BuildContextLike as BuildContextLike_prepareRealmConfig -} from "./prepareRealmConfig"; +import { prepareRealmConfig } from "./prepareRealmConfig"; import * as fs from "fs"; import { join as pathJoin, @@ -24,18 +21,19 @@ import { } from "./dumpContainerConfig"; import * as runExclusive from "run-exclusive"; import { waitForDebounceFactory } from "powerhooks/tools/waitForDebounce"; +import type { ThemeType } from "../../shared/constants"; import chalk from "chalk"; -export type BuildContextLike = BuildContextLike_dumpContainerConfig & - BuildContextLike_prepareRealmConfig & { - projectDirPath: string; - }; +export type BuildContextLike = BuildContextLike_dumpContainerConfig & { + projectDirPath: string; +}; assert; export async function getRealmConfig(params: { keycloakMajorVersionNumber: number; realmJsonFilePath_userProvided: string | undefined; + parsedKeycloakThemesJsonEntry: { name: string; types: (ThemeType | "email")[] }; buildContext: BuildContextLike; }): Promise<{ realmJsonFilePath: string; @@ -44,8 +42,12 @@ export async function getRealmConfig(params: { username: string; onRealmConfigChange: () => Promise; }> { - const { keycloakMajorVersionNumber, realmJsonFilePath_userProvided, buildContext } = - params; + const { + keycloakMajorVersionNumber, + realmJsonFilePath_userProvided, + parsedKeycloakThemesJsonEntry, + buildContext + } = params; const realmJsonFilePath = pathJoin( buildContext.projectDirPath, @@ -71,8 +73,8 @@ export async function getRealmConfig(params: { const { clientName, realmName, username } = prepareRealmConfig({ parsedRealmJson, - buildContext, - keycloakMajorVersionNumber + keycloakMajorVersionNumber, + parsedKeycloakThemesJsonEntry }); { diff --git a/src/bin/start-keycloak/start-keycloak.ts b/src/bin/start-keycloak/start-keycloak.ts index c15230f6..dc60c1ff 100644 --- a/src/bin/start-keycloak/start-keycloak.ts +++ b/src/bin/start-keycloak/start-keycloak.ts @@ -4,7 +4,8 @@ import { CONTAINER_NAME, KEYCLOAKIFY_SPA_DEV_SERVER_PORT, KEYCLOAKIFY_LOGIN_JAR_BASENAME, - TEST_APP_URL + TEST_APP_URL, + ThemeType } from "../shared/constants"; import { SemVer } from "../tools/SemVer"; import { assert, type Equals } from "tsafe/assert"; @@ -34,6 +35,7 @@ import { startViteDevServer } from "./startViteDevServer"; import { getSupportedKeycloakMajorVersions } from "./realmConfig/defaultConfig"; import { getSupportedDockerImageTags } from "./getSupportedDockerImageTags"; import { getRealmConfig } from "./realmConfig"; +import { id } from "tsafe/id"; export async function command(params: { buildContext: BuildContext; @@ -270,32 +272,6 @@ export async function command(params: { return wrap.majorVersionNumber; })(); - const { clientName, onRealmConfigChange, realmJsonFilePath, realmName, username } = - await getRealmConfig({ - keycloakMajorVersionNumber, - realmJsonFilePath_userProvided: await (async () => { - if (cliCommandOptions.realmJsonFilePath !== undefined) { - return getAbsoluteAndInOsFormatPath({ - pathIsh: cliCommandOptions.realmJsonFilePath, - cwd: process.cwd() - }); - } - - if (buildContext.startKeycloakOptions.realmJsonFilePath !== undefined) { - assert( - await existsAsync( - buildContext.startKeycloakOptions.realmJsonFilePath - ), - `${pathRelative(process.cwd(), buildContext.startKeycloakOptions.realmJsonFilePath)} does not exist` - ); - return buildContext.startKeycloakOptions.realmJsonFilePath; - } - - return undefined; - })(), - buildContext - }); - { const { isAppBuildSuccess } = await appBuild({ buildContext @@ -376,10 +352,24 @@ export async function command(params: { )) ]; + let parsedKeycloakThemesJson = id< + { themes: { name: string; types: (ThemeType | "email")[] }[] } | undefined + >(undefined); + async function extractThemeResourcesFromJar() { await extractArchive({ archiveFilePath: jarFilePath, - onArchiveFile: async ({ relativeFilePathInArchive, writeFile }) => { + onArchiveFile: async ({ relativeFilePathInArchive, writeFile, readFile }) => { + if ( + relativeFilePathInArchive === + pathJoin("META-INF", "keycloak-themes.json") && + parsedKeycloakThemesJson === undefined + ) { + parsedKeycloakThemesJson = JSON.parse( + (await readFile()).toString("utf8") + ); + } + if (isInside({ dirPath: "theme", filePath: relativeFilePathInArchive })) { await writeFile({ filePath: pathJoin( @@ -401,6 +391,43 @@ export async function command(params: { await extractThemeResourcesFromJar(); + assert(parsedKeycloakThemesJson !== undefined); + + const { clientName, onRealmConfigChange, realmJsonFilePath, realmName, username } = + await getRealmConfig({ + keycloakMajorVersionNumber, + parsedKeycloakThemesJsonEntry: (() => { + const entry = parsedKeycloakThemesJson.themes.find( + ({ name }) => name === buildContext.themeNames[0] + ); + + assert(entry !== undefined); + + return entry; + })(), + realmJsonFilePath_userProvided: await (async () => { + if (cliCommandOptions.realmJsonFilePath !== undefined) { + return getAbsoluteAndInOsFormatPath({ + pathIsh: cliCommandOptions.realmJsonFilePath, + cwd: process.cwd() + }); + } + + if (buildContext.startKeycloakOptions.realmJsonFilePath !== undefined) { + assert( + await existsAsync( + buildContext.startKeycloakOptions.realmJsonFilePath + ), + `${pathRelative(process.cwd(), buildContext.startKeycloakOptions.realmJsonFilePath)} does not exist` + ); + return buildContext.startKeycloakOptions.realmJsonFilePath; + } + + return undefined; + })(), + buildContext + }); + const jarFilePath_cacheDir = pathJoin( buildContext.cacheDirPath, pathBasename(jarFilePath)