Refactor checkpoint
This commit is contained in:
parent
8340608045
commit
93c1c56279
2
.gitignore
vendored
2
.gitignore
vendored
@ -50,6 +50,8 @@ jspm_packages
|
||||
|
||||
/src/login/i18n/messages_defaultSet/
|
||||
/src/account/i18n/messages_defaultSet/
|
||||
/resources/
|
||||
/account-v1/
|
||||
|
||||
# VS Code devcontainers
|
||||
.devcontainer
|
||||
|
@ -7,7 +7,7 @@
|
||||
"url": "git://github.com/keycloakify/keycloakify.git"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "tsx scripts/generate-i18n-messages.ts",
|
||||
"prepare": "tsx scripts/prepare/main.ts",
|
||||
"build": "tsx scripts/build.ts",
|
||||
"storybook": "tsx scripts/start-storybook.ts",
|
||||
"link-in-starter": "tsx scripts/link-in-starter.ts",
|
||||
|
@ -4,6 +4,7 @@ import { join } from "path";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { transformCodebase } from "../src/bin/tools/transformCodebase";
|
||||
import chalk from "chalk";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../src/bin/shared/constants";
|
||||
|
||||
console.log(chalk.cyan("Building Keycloakify..."));
|
||||
|
||||
@ -136,9 +137,17 @@ fs.rmSync(join("dist", "ncc_out"), { recursive: true });
|
||||
assert(hasBeenPatched);
|
||||
}
|
||||
|
||||
fs.rmSync(join("dist", "src"), { recursive: true, force: true });
|
||||
for (const dirBasename of [
|
||||
"src",
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES,
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.ACCOUNT_V1
|
||||
]) {
|
||||
const destDirPath = join("dist", dirBasename);
|
||||
|
||||
fs.cpSync("src", join("dist", "src"), { recursive: true });
|
||||
fs.rmSync(destDirPath, { recursive: true, force: true });
|
||||
|
||||
fs.cpSync(dirBasename, destDirPath, { recursive: true });
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: join("stories"),
|
||||
|
4
scripts/prepare/constants.ts
Normal file
4
scripts/prepare/constants.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const KEYCLOAK_VERSION = {
|
||||
FOR_LOGIN_THEME: "25.0.4",
|
||||
FOR_ACCOUNT_MULTI_PAGE: "21.1.2"
|
||||
};
|
77
scripts/prepare/createAccountV1Dir.ts
Normal file
77
scripts/prepare/createAccountV1Dir.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import * as fs from "fs";
|
||||
import { join as pathJoin } from "path";
|
||||
import { KEYCLOAK_VERSION } from "./constants";
|
||||
import { transformCodebase } from "../../src/bin/tools/transformCodebase";
|
||||
import { downloadKeycloakDefaultTheme } from "./downloadKeycloakDefaultTheme";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../src/bin/shared/constants";
|
||||
import { getThisCodebaseRootDirPath } from "../../src/bin/tools/getThisCodebaseRootDirPath";
|
||||
import { accountMultiPageSupportedLanguages } from "./generateI18nMessages";
|
||||
|
||||
export async function createAccountV1Dir() {
|
||||
const { extractedDirPath } = await downloadKeycloakDefaultTheme({
|
||||
keycloakVersion: KEYCLOAK_VERSION.FOR_ACCOUNT_MULTI_PAGE
|
||||
});
|
||||
|
||||
// TODO: Exclude unused resources.
|
||||
|
||||
const destDirPath = pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.ACCOUNT_V1
|
||||
);
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(extractedDirPath, "base", "account"),
|
||||
destDirPath
|
||||
});
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(extractedDirPath, "keycloak", "account", "resources"),
|
||||
destDirPath: pathJoin(destDirPath, "resources")
|
||||
});
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(extractedDirPath, "keycloak", "common", "resources"),
|
||||
destDirPath: pathJoin(
|
||||
destDirPath,
|
||||
"resources",
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES_COMMON
|
||||
)
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
pathJoin(destDirPath, "theme.properties"),
|
||||
Buffer.from(
|
||||
[
|
||||
"accountResourceProvider=account-v1",
|
||||
"",
|
||||
`locales=${accountMultiPageSupportedLanguages.join(",")}`,
|
||||
"",
|
||||
"styles=" +
|
||||
[
|
||||
"css/account.css",
|
||||
"img/icon-sidebar-active.png",
|
||||
"img/logo.png",
|
||||
...[
|
||||
"patternfly.min.css",
|
||||
"patternfly-additions.min.css",
|
||||
"patternfly-additions.min.css"
|
||||
].map(
|
||||
fileBasename =>
|
||||
`${WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES_COMMON}/node_modules/patternfly/dist/css/${fileBasename}`
|
||||
)
|
||||
].join(" "),
|
||||
"",
|
||||
"##### css classes for form buttons",
|
||||
"# main class used for all buttons",
|
||||
"kcButtonClass=btn",
|
||||
"# classes defining priority of the button - primary or default (there is typically only one priority button for the form)",
|
||||
"kcButtonPrimaryClass=btn-primary",
|
||||
"kcButtonDefaultClass=btn-default",
|
||||
"# classes defining size of the button",
|
||||
"kcButtonLargeClass=btn-lg",
|
||||
""
|
||||
].join("\n"),
|
||||
"utf8"
|
||||
)
|
||||
);
|
||||
}
|
70
scripts/prepare/createResourcesDir.ts
Normal file
70
scripts/prepare/createResourcesDir.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { join as pathJoin } from "path";
|
||||
import { downloadKeycloakDefaultTheme } from "./downloadKeycloakDefaultTheme";
|
||||
import { KEYCLOAK_VERSION } from "./constants";
|
||||
import { transformCodebase } from "../../src/bin/tools/transformCodebase";
|
||||
import { existsAsync } from "../../src/bin/tools/fs.existsAsync";
|
||||
import { getThisCodebaseRootDirPath } from "../../src/bin/tools/getThisCodebaseRootDirPath";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../src/bin/shared/constants";
|
||||
import { assert, type Equals } from "tsafe/assert";
|
||||
|
||||
export async function createResourcesDir() {
|
||||
await Promise.all(
|
||||
(["login", "account"] as const).map(async themeType => {
|
||||
const keycloakVersion = (() => {
|
||||
switch (themeType) {
|
||||
case "login":
|
||||
return KEYCLOAK_VERSION.FOR_LOGIN_THEME;
|
||||
case "account":
|
||||
return KEYCLOAK_VERSION.FOR_ACCOUNT_MULTI_PAGE;
|
||||
}
|
||||
assert<Equals<typeof themeType, never>>();
|
||||
})();
|
||||
|
||||
const { extractedDirPath } = await downloadKeycloakDefaultTheme({
|
||||
keycloakVersion
|
||||
});
|
||||
|
||||
const destDirPath = pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES,
|
||||
themeType
|
||||
);
|
||||
|
||||
base_resources: {
|
||||
const srcDirPath = pathJoin(
|
||||
extractedDirPath,
|
||||
"base",
|
||||
themeType,
|
||||
"resources"
|
||||
);
|
||||
|
||||
if (!(await existsAsync(srcDirPath))) {
|
||||
break base_resources;
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath,
|
||||
destDirPath
|
||||
});
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(
|
||||
extractedDirPath,
|
||||
"keycloak",
|
||||
themeType,
|
||||
"resources"
|
||||
),
|
||||
destDirPath
|
||||
});
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(extractedDirPath, "keycloak", "common", "resources"),
|
||||
destDirPath: pathJoin(
|
||||
destDirPath,
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES_COMMON
|
||||
)
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
34
scripts/prepare/downloadKeycloakDefaultTheme.ts
Normal file
34
scripts/prepare/downloadKeycloakDefaultTheme.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { relative as pathRelative } from "path";
|
||||
import { downloadAndExtractArchive } from "../../src/bin/tools/downloadAndExtractArchive";
|
||||
import { getProxyFetchOptions } from "../../src/bin/tools/fetchProxyOptions";
|
||||
import { join as pathJoin } from "path";
|
||||
import { getThisCodebaseRootDirPath } from "../../src/bin/tools/getThisCodebaseRootDirPath";
|
||||
|
||||
export async function downloadKeycloakDefaultTheme(params: { keycloakVersion: string }) {
|
||||
const { keycloakVersion } = params;
|
||||
|
||||
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||
url: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
|
||||
cacheDirPath: pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
"node_modules",
|
||||
".cache",
|
||||
"scripts"
|
||||
),
|
||||
fetchOptions: getProxyFetchOptions({
|
||||
npmConfigGetCwd: getThisCodebaseRootDirPath()
|
||||
}),
|
||||
uniqueIdOfOnArchiveFile: "downloadKeycloakDefaultTheme",
|
||||
onArchiveFile: async ({ fileRelativePath, writeFile }) => {
|
||||
const fileRelativePath_target = pathRelative("theme", fileRelativePath);
|
||||
|
||||
if (fileRelativePath_target.startsWith("..")) {
|
||||
return;
|
||||
}
|
||||
|
||||
await writeFile({ fileRelativePath: fileRelativePath_target });
|
||||
}
|
||||
});
|
||||
|
||||
return { extractedDirPath };
|
||||
}
|
@ -8,15 +8,12 @@ import {
|
||||
} from "path";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { same } from "evt/tools/inDepth";
|
||||
import { crawl } from "../src/bin/tools/crawl";
|
||||
import { downloadKeycloakDefaultTheme } from "../src/bin/shared/downloadKeycloakDefaultTheme";
|
||||
import { getThisCodebaseRootDirPath } from "../src/bin/tools/getThisCodebaseRootDirPath";
|
||||
import { deepAssign } from "../src/tools/deepAssign";
|
||||
import { getProxyFetchOptions } from "../src/bin/tools/fetchProxyOptions";
|
||||
import {
|
||||
THEME_TYPES,
|
||||
LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1
|
||||
} from "../src/bin/shared/constants";
|
||||
import { crawl } from "../../src/bin/tools/crawl";
|
||||
import { downloadKeycloakDefaultTheme } from "./downloadKeycloakDefaultTheme";
|
||||
import { getThisCodebaseRootDirPath } from "../../src/bin/tools/getThisCodebaseRootDirPath";
|
||||
import { deepAssign } from "../../src/tools/deepAssign";
|
||||
import { THEME_TYPES } from "../../src/bin/shared/constants";
|
||||
import { KEYCLOAK_VERSION } from "./constants";
|
||||
|
||||
// NOTE: To run without argument when we want to generate src/i18n/generated_kcMessages files,
|
||||
// update the version array for generating for newer version.
|
||||
@ -24,7 +21,7 @@ import {
|
||||
//@ts-ignore
|
||||
const propertiesParser = require("properties-parser");
|
||||
|
||||
async function main() {
|
||||
export async function generateI18nMessages() {
|
||||
const thisCodebaseRootDirPath = getThisCodebaseRootDirPath();
|
||||
|
||||
type Dictionary = { [idiomId: string]: string };
|
||||
@ -32,30 +29,19 @@ async function main() {
|
||||
const record: { [themeType: string]: { [language: string]: Dictionary } } = {};
|
||||
|
||||
for (const themeType of THEME_TYPES) {
|
||||
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
|
||||
const { extractedDirPath } = await downloadKeycloakDefaultTheme({
|
||||
keycloakVersion: (() => {
|
||||
switch (themeType) {
|
||||
case "login":
|
||||
return "25.0.4";
|
||||
return KEYCLOAK_VERSION.FOR_LOGIN_THEME;
|
||||
case "account":
|
||||
return LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1;
|
||||
return KEYCLOAK_VERSION.FOR_ACCOUNT_MULTI_PAGE;
|
||||
}
|
||||
})(),
|
||||
buildContext: {
|
||||
cacheDirPath: pathJoin(
|
||||
thisCodebaseRootDirPath,
|
||||
"node_modules",
|
||||
".cache",
|
||||
"keycloakify"
|
||||
),
|
||||
fetchOptions: getProxyFetchOptions({
|
||||
npmConfigGetCwd: thisCodebaseRootDirPath
|
||||
})
|
||||
}
|
||||
})()
|
||||
});
|
||||
|
||||
{
|
||||
const baseThemeDirPath = pathJoin(defaultThemeDirPath, "base");
|
||||
const baseThemeDirPath = pathJoin(extractedDirPath, "base");
|
||||
const re = new RegExp(
|
||||
`^([^\\${pathSep}]+)\\${pathSep}messages\\${pathSep}messages_([^.]+).properties$`
|
||||
);
|
||||
@ -597,30 +583,34 @@ const keycloakifyExtraMessages_login: Record<
|
||||
/* spell-checker: enable */
|
||||
};
|
||||
|
||||
export const accountMultiPageSupportedLanguages = [
|
||||
"en",
|
||||
"ar",
|
||||
"ca",
|
||||
"cs",
|
||||
"da",
|
||||
"de",
|
||||
"es",
|
||||
"fi",
|
||||
"fr",
|
||||
"hu",
|
||||
"it",
|
||||
"ja",
|
||||
"lt",
|
||||
"lv",
|
||||
"nl",
|
||||
"no",
|
||||
"pl",
|
||||
"pt-BR",
|
||||
"ru",
|
||||
"sk",
|
||||
"sv",
|
||||
"tr",
|
||||
"zh-CN"
|
||||
] as const;
|
||||
|
||||
const keycloakifyExtraMessages_account: Record<
|
||||
| "en"
|
||||
| "ar"
|
||||
| "ca"
|
||||
| "cs"
|
||||
| "da"
|
||||
| "de"
|
||||
| "es"
|
||||
| "fi"
|
||||
| "fr"
|
||||
| "hu"
|
||||
| "it"
|
||||
| "ja"
|
||||
| "lt"
|
||||
| "lv"
|
||||
| "nl"
|
||||
| "no"
|
||||
| "pl"
|
||||
| "pt-BR"
|
||||
| "ru"
|
||||
| "sk"
|
||||
| "sv"
|
||||
| "tr"
|
||||
| "zh-CN",
|
||||
(typeof accountMultiPageSupportedLanguages)[number],
|
||||
Record<"newPasswordSameAsOld" | "passwordConfirmNotMatch", string>
|
||||
> = {
|
||||
en: {
|
||||
@ -719,7 +709,3 @@ const keycloakifyExtraMessages_account: Record<
|
||||
}
|
||||
/* spell-checker: enable */
|
||||
};
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
13
scripts/prepare/main.ts
Normal file
13
scripts/prepare/main.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { generateI18nMessages } from "./generateI18nMessages";
|
||||
import { createAccountV1Dir } from "./createAccountV1Dir";
|
||||
import { createResourcesDir } from "./createResourcesDir";
|
||||
|
||||
(async () => {
|
||||
console.log("Pulling i18n messages...");
|
||||
await generateI18nMessages();
|
||||
console.log("Creating account-v1 dir...");
|
||||
await createAccountV1Dir();
|
||||
console.log("Creating resources dir...");
|
||||
await createResourcesDir();
|
||||
console.log("Done!");
|
||||
})();
|
@ -1,10 +1,10 @@
|
||||
import "keycloakify/tools/Object.fromEntries";
|
||||
import { RESOURCES_COMMON, KEYCLOAK_RESOURCES } from "keycloakify/bin/shared/constants";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "keycloakify/bin/shared/constants";
|
||||
import { id } from "tsafe/id";
|
||||
import type { KcContext } from "./KcContext";
|
||||
import { BASE_URL } from "keycloakify/lib/BASE_URL";
|
||||
|
||||
const resourcesPath = `${BASE_URL}${KEYCLOAK_RESOURCES}/account/resources`;
|
||||
const resourcesPath = `${BASE_URL}${WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY}/account`;
|
||||
|
||||
export const kcContextCommonMock: KcContext.Common = {
|
||||
themeVersion: "0.0.0",
|
||||
@ -13,7 +13,7 @@ export const kcContextCommonMock: KcContext.Common = {
|
||||
themeName: "my-theme-name",
|
||||
url: {
|
||||
resourcesPath,
|
||||
resourcesCommonPath: `${resourcesPath}/${RESOURCES_COMMON}`,
|
||||
resourcesCommonPath: `${resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES_COMMON}`,
|
||||
resourceUrl: "#",
|
||||
accountUrl: "#",
|
||||
applicationsUrl: "#",
|
||||
|
@ -7,7 +7,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
|
||||
const buildContext = getBuildContext({ cliCommandOptions });
|
||||
|
||||
await copyKeycloakResourcesToPublic({
|
||||
copyKeycloakResourcesToPublic({
|
||||
buildContext
|
||||
});
|
||||
}
|
||||
|
@ -11,11 +11,7 @@ import * as fs from "fs";
|
||||
import { join as pathJoin } from "path";
|
||||
import type { BuildContext } from "../../shared/buildContext";
|
||||
import { assert } from "tsafe/assert";
|
||||
import {
|
||||
type ThemeType,
|
||||
BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR,
|
||||
RESOURCES_COMMON
|
||||
} from "../../shared/constants";
|
||||
import { type ThemeType, WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../shared/constants";
|
||||
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
||||
|
||||
export type BuildContextLike = BuildContextLike_replaceImportsInJsCode &
|
||||
@ -94,7 +90,7 @@ export function generateFtlFilesCodeFactory(params: {
|
||||
new RegExp(
|
||||
`^${(buildContext.urlPathname ?? "/").replace(/\//g, "\\/")}`
|
||||
),
|
||||
`\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/`
|
||||
`\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/`
|
||||
)
|
||||
);
|
||||
})
|
||||
@ -119,7 +115,7 @@ export function generateFtlFilesCodeFactory(params: {
|
||||
.replace("{{keycloakifyVersion}}", keycloakifyVersion)
|
||||
.replace("{{themeVersion}}", buildContext.themeVersion)
|
||||
.replace("{{fieldNames}}", fieldNames.map(name => `"${name}"`).join(", "))
|
||||
.replace("{{RESOURCES_COMMON}}", RESOURCES_COMMON)
|
||||
.replace("{{RESOURCES_COMMON}}", WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES_COMMON)
|
||||
.replace(
|
||||
"{{userDefinedExclusions}}",
|
||||
buildContext.kcContextExclusionsFtlCode ?? ""
|
||||
|
@ -1,89 +0,0 @@
|
||||
import * as fs from "fs";
|
||||
import { join as pathJoin } from "path";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { BuildContext } from "../../shared/buildContext";
|
||||
import {
|
||||
RESOURCES_COMMON,
|
||||
LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1,
|
||||
ACCOUNT_V1_THEME_NAME
|
||||
} from "../../shared/constants";
|
||||
import {
|
||||
downloadKeycloakDefaultTheme,
|
||||
BuildContextLike as BuildContextLike_downloadKeycloakDefaultTheme
|
||||
} from "../../shared/downloadKeycloakDefaultTheme";
|
||||
import { transformCodebase } from "../../tools/transformCodebase";
|
||||
|
||||
export type BuildContextLike = BuildContextLike_downloadKeycloakDefaultTheme;
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
export async function bringInAccountV1(params: {
|
||||
resourcesDirPath: string;
|
||||
buildContext: BuildContextLike;
|
||||
}) {
|
||||
const { resourcesDirPath, buildContext } = params;
|
||||
|
||||
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
|
||||
keycloakVersion: LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1,
|
||||
buildContext
|
||||
});
|
||||
|
||||
const accountV1DirPath = pathJoin(
|
||||
resourcesDirPath,
|
||||
"theme",
|
||||
ACCOUNT_V1_THEME_NAME,
|
||||
"account"
|
||||
);
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(defaultThemeDirPath, "base", "account"),
|
||||
destDirPath: accountV1DirPath
|
||||
});
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(defaultThemeDirPath, "keycloak", "account", "resources"),
|
||||
destDirPath: pathJoin(accountV1DirPath, "resources")
|
||||
});
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(defaultThemeDirPath, "keycloak", "common", "resources"),
|
||||
destDirPath: pathJoin(accountV1DirPath, "resources", RESOURCES_COMMON)
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
pathJoin(accountV1DirPath, "theme.properties"),
|
||||
Buffer.from(
|
||||
[
|
||||
"accountResourceProvider=account-v1",
|
||||
"",
|
||||
"locales=ar,ca,cs,da,de,en,es,fr,fi,hu,it,ja,lt,nl,no,pl,pt-BR,ru,sk,sv,tr,zh-CN",
|
||||
"",
|
||||
"styles=" +
|
||||
[
|
||||
"css/account.css",
|
||||
"img/icon-sidebar-active.png",
|
||||
"img/logo.png",
|
||||
...[
|
||||
"patternfly.min.css",
|
||||
"patternfly-additions.min.css",
|
||||
"patternfly-additions.min.css"
|
||||
].map(
|
||||
fileBasename =>
|
||||
`${RESOURCES_COMMON}/node_modules/patternfly/dist/css/${fileBasename}`
|
||||
)
|
||||
].join(" "),
|
||||
"",
|
||||
"##### css classes for form buttons",
|
||||
"# main class used for all buttons",
|
||||
"kcButtonClass=btn",
|
||||
"# classes defining priority of the button - primary or default (there is typically only one priority button for the form)",
|
||||
"kcButtonPrimaryClass=btn-primary",
|
||||
"kcButtonDefaultClass=btn-default",
|
||||
"# classes defining size of the button",
|
||||
"kcButtonLargeClass=btn-lg",
|
||||
""
|
||||
].join("\n"),
|
||||
"utf8"
|
||||
)
|
||||
);
|
||||
}
|
@ -1,11 +1,6 @@
|
||||
import { transformCodebase } from "../../tools/transformCodebase";
|
||||
import * as fs from "fs";
|
||||
import {
|
||||
join as pathJoin,
|
||||
resolve as pathResolve,
|
||||
relative as pathRelative,
|
||||
dirname as pathDirname
|
||||
} from "path";
|
||||
import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path";
|
||||
import { replaceImportsInJsCode } from "../replacers/replaceImportsInJsCode";
|
||||
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
|
||||
import {
|
||||
@ -14,26 +9,15 @@ import {
|
||||
} from "../generateFtl";
|
||||
import {
|
||||
type ThemeType,
|
||||
LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1,
|
||||
KEYCLOAK_RESOURCES,
|
||||
ACCOUNT_V1_THEME_NAME,
|
||||
BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR,
|
||||
LOGIN_THEME_PAGE_IDS,
|
||||
ACCOUNT_THEME_PAGE_IDS
|
||||
ACCOUNT_THEME_PAGE_IDS,
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME
|
||||
} from "../../shared/constants";
|
||||
import type { BuildContext } from "../../shared/buildContext";
|
||||
import { assert, type Equals } from "tsafe/assert";
|
||||
import {
|
||||
downloadKeycloakStaticResources,
|
||||
type BuildContextLike as BuildContextLike_downloadKeycloakStaticResources
|
||||
} from "../../shared/downloadKeycloakStaticResources";
|
||||
import { readFieldNameUsage } from "./readFieldNameUsage";
|
||||
import { readExtraPagesNames } from "./readExtraPageNames";
|
||||
import { generateMessageProperties } from "./generateMessageProperties";
|
||||
import {
|
||||
bringInAccountV1,
|
||||
type BuildContextLike as BuildContextLike_bringInAccountV1
|
||||
} from "./bringInAccountV1";
|
||||
import { rmSync } from "../../tools/fs.rmSync";
|
||||
import { readThisNpmPackageVersion } from "../../tools/readThisNpmPackageVersion";
|
||||
import {
|
||||
@ -43,20 +27,18 @@ import {
|
||||
import { objectEntries } from "tsafe/objectEntries";
|
||||
import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
|
||||
import * as child_process from "child_process";
|
||||
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
||||
|
||||
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
|
||||
BuildContextLike_downloadKeycloakStaticResources &
|
||||
BuildContextLike_bringInAccountV1 & {
|
||||
extraThemeProperties: string[] | undefined;
|
||||
loginThemeResourcesFromKeycloakVersion: string;
|
||||
projectDirPath: string;
|
||||
projectBuildDirPath: string;
|
||||
environmentVariables: { name: string; default: string }[];
|
||||
implementedThemeTypes: BuildContext["implementedThemeTypes"];
|
||||
themeSrcDirPath: string;
|
||||
bundler: "vite" | "webpack";
|
||||
packageJsonFilePath: string;
|
||||
};
|
||||
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode & {
|
||||
extraThemeProperties: string[] | undefined;
|
||||
projectDirPath: string;
|
||||
projectBuildDirPath: string;
|
||||
environmentVariables: { name: string; default: string }[];
|
||||
implementedThemeTypes: BuildContext["implementedThemeTypes"];
|
||||
themeSrcDirPath: string;
|
||||
bundler: "vite" | "webpack";
|
||||
packageJsonFilePath: string;
|
||||
};
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
@ -88,7 +70,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
const destDirPath = pathJoin(
|
||||
themeTypeDirPath,
|
||||
"resources",
|
||||
BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.DIST
|
||||
);
|
||||
|
||||
// NOTE: Prevent accumulation of files in the assets dir, as names are hashed they pile up.
|
||||
@ -106,7 +88,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
themeType: "login"
|
||||
}),
|
||||
"resources",
|
||||
BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.DIST
|
||||
),
|
||||
destDirPath
|
||||
});
|
||||
@ -117,7 +99,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
{
|
||||
const dirPath = pathJoin(
|
||||
buildContext.projectBuildDirPath,
|
||||
KEYCLOAK_RESOURCES
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY
|
||||
);
|
||||
|
||||
if (fs.existsSync(dirPath)) {
|
||||
@ -125,7 +107,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
|
||||
throw new Error(
|
||||
[
|
||||
`Keycloakify build error: The ${KEYCLOAK_RESOURCES} directory shouldn't exist in your build directory.`,
|
||||
`Keycloakify build error: The ${WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY} directory shouldn't exist in your build directory.`,
|
||||
`(${pathRelative(process.cwd(), dirPath)}).\n`,
|
||||
`Theses assets are only required for local development with Storybook.",
|
||||
"Please remove this directory as an additional step of your command.\n`,
|
||||
@ -232,23 +214,50 @@ export async function generateResourcesForMainTheme(params: {
|
||||
});
|
||||
}
|
||||
|
||||
bring_in_account_v3_i18n_messages: {
|
||||
if (!buildContext.implementedThemeTypes.account.isImplemented) {
|
||||
break bring_in_account_v3_i18n_messages;
|
||||
}
|
||||
if (buildContext.implementedThemeTypes.account.type !== "Single-Page") {
|
||||
break bring_in_account_v3_i18n_messages;
|
||||
}
|
||||
|
||||
const accountUiDirPath = child_process
|
||||
.execSync("npm list @keycloakify/keycloak-account-ui --parseable", {
|
||||
cwd: pathDirname(buildContext.packageJsonFilePath)
|
||||
})
|
||||
.toString("utf8")
|
||||
.trim();
|
||||
|
||||
const messagesDirPath = pathJoin(accountUiDirPath, "messages");
|
||||
|
||||
if (!fs.existsSync(messagesDirPath)) {
|
||||
throw new Error(
|
||||
`Please update @keycloakify/keycloak-account-ui to 25.0.4-rc.5 or later.`
|
||||
);
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: messagesDirPath,
|
||||
destDirPath: pathJoin(
|
||||
getThemeTypeDirPath({ themeType: "account" }),
|
||||
"messages"
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
keycloak_static_resources: {
|
||||
if (isForAccountSpa) {
|
||||
break keycloak_static_resources;
|
||||
}
|
||||
|
||||
await downloadKeycloakStaticResources({
|
||||
keycloakVersion: (() => {
|
||||
switch (themeType) {
|
||||
case "account":
|
||||
return LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1;
|
||||
case "login":
|
||||
return buildContext.loginThemeResourcesFromKeycloakVersion;
|
||||
}
|
||||
})(),
|
||||
themeDirPath: pathResolve(pathJoin(themeTypeDirPath, "..")),
|
||||
themeType,
|
||||
buildContext
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES,
|
||||
themeType
|
||||
),
|
||||
destDirPath: pathJoin(themeTypeDirPath, "resources")
|
||||
});
|
||||
}
|
||||
|
||||
@ -259,7 +268,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
`parent=${(() => {
|
||||
switch (themeType) {
|
||||
case "account":
|
||||
return isForAccountSpa ? "base" : ACCOUNT_V1_THEME_NAME;
|
||||
return isForAccountSpa ? "base" : "account-v1";
|
||||
case "login":
|
||||
return "keycloak";
|
||||
}
|
||||
@ -299,41 +308,12 @@ export async function generateResourcesForMainTheme(params: {
|
||||
break bring_in_account_v1;
|
||||
}
|
||||
|
||||
await bringInAccountV1({
|
||||
resourcesDirPath,
|
||||
buildContext
|
||||
});
|
||||
}
|
||||
|
||||
bring_in_account_v3_i18n_messages: {
|
||||
if (!buildContext.implementedThemeTypes.account.isImplemented) {
|
||||
break bring_in_account_v3_i18n_messages;
|
||||
}
|
||||
if (buildContext.implementedThemeTypes.account.type !== "Single-Page") {
|
||||
break bring_in_account_v3_i18n_messages;
|
||||
}
|
||||
|
||||
const accountUiDirPath = child_process
|
||||
.execSync("npm list @keycloakify/keycloak-account-ui --parseable", {
|
||||
cwd: pathDirname(buildContext.packageJsonFilePath)
|
||||
})
|
||||
.toString("utf8")
|
||||
.trim();
|
||||
|
||||
const messagesDirPath = pathJoin(accountUiDirPath, "messages");
|
||||
|
||||
if (!fs.existsSync(messagesDirPath)) {
|
||||
throw new Error(
|
||||
`Please update @keycloakify/keycloak-account-ui to 25.0.4-rc.5 or later.`
|
||||
);
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: messagesDirPath,
|
||||
destDirPath: pathJoin(
|
||||
getThemeTypeDirPath({ themeType: "account" }),
|
||||
"messages"
|
||||
)
|
||||
srcDirPath: pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.ACCOUNT_V1
|
||||
),
|
||||
destDirPath: pathJoin(resourcesDirPath, "theme", "account-v1", "account")
|
||||
});
|
||||
}
|
||||
|
||||
@ -349,7 +329,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
|
||||
if (buildContext.implementedThemeTypes.account.isImplemented) {
|
||||
metaInfKeycloakThemes.themes.push({
|
||||
name: ACCOUNT_V1_THEME_NAME,
|
||||
name: "account-v1",
|
||||
types: ["account"]
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { BuildContext } from "../../shared/buildContext";
|
||||
import { BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR } from "../../shared/constants";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../shared/constants";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { posix } from "path";
|
||||
|
||||
@ -50,7 +50,7 @@ export function replaceImportsInCssCode(params: {
|
||||
break inline_style_in_html;
|
||||
}
|
||||
|
||||
return `url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}${assetFileAbsoluteUrlPathname}")`;
|
||||
return `url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}${assetFileAbsoluteUrlPathname}")`;
|
||||
}
|
||||
|
||||
const assetFileRelativeUrlPathname = posix.relative(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR } from "../../../shared/constants";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../../shared/constants";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { BuildContext } from "../../../shared/buildContext";
|
||||
import * as nodePath from "path";
|
||||
@ -85,13 +85,13 @@ export function replaceImportsInJsCode_vite(params: {
|
||||
fixedJsCode = replaceAll(
|
||||
fixedJsCode,
|
||||
`"${relativePathOfAssetFile}"`,
|
||||
`(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/${relativePathOfAssetFile}")`
|
||||
`(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/${relativePathOfAssetFile}")`
|
||||
);
|
||||
|
||||
fixedJsCode = replaceAll(
|
||||
fixedJsCode,
|
||||
`"${buildContext.urlPathname ?? "/"}${relativePathOfAssetFile}"`,
|
||||
`(window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/${relativePathOfAssetFile}")`
|
||||
`(window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/${relativePathOfAssetFile}")`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR } from "../../../shared/constants";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../../../shared/constants";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { BuildContext } from "../../../shared/buildContext";
|
||||
import * as nodePath from "path";
|
||||
@ -90,7 +90,7 @@ export function replaceImportsInJsCode_webpack(params: {
|
||||
return "${u}";
|
||||
})()] = ${
|
||||
isArrowFunction ? `${e} =>` : `function(${e}) { return `
|
||||
} "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/${staticDir}${language}/"`
|
||||
} "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/${staticDir}${language}/"`
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
@ -104,7 +104,7 @@ export function replaceImportsInJsCode_webpack(params: {
|
||||
`[a-zA-Z]+\\.[a-zA-Z]+\\+"${staticDir.replace(/\//g, "\\/")}`,
|
||||
"g"
|
||||
),
|
||||
`window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/${staticDir}`
|
||||
`window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/${staticDir}`
|
||||
);
|
||||
|
||||
return { fixedJsCode };
|
||||
|
@ -14,8 +14,7 @@ import { assert, type Equals } from "tsafe/assert";
|
||||
import * as child_process from "child_process";
|
||||
import {
|
||||
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES,
|
||||
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME,
|
||||
LOGIN_THEME_RESOURCES_FROM_KEYCLOAK_VERSION_DEFAULT
|
||||
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
|
||||
} from "./constants";
|
||||
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
|
||||
import { exclude } from "tsafe";
|
||||
@ -33,7 +32,6 @@ export type BuildContext = {
|
||||
extraThemeProperties: string[] | undefined;
|
||||
groupId: string;
|
||||
artifactId: string;
|
||||
loginThemeResourcesFromKeycloakVersion: string;
|
||||
projectDirPath: string;
|
||||
projectBuildDirPath: string;
|
||||
/** Directory that keycloakify outputs to. Defaults to {cwd}/build_keycloak */
|
||||
@ -85,7 +83,6 @@ export type BuildOptions = {
|
||||
extraThemeProperties?: string[];
|
||||
artifactId?: string;
|
||||
groupId?: string;
|
||||
loginThemeResourcesFromKeycloakVersion?: string;
|
||||
keycloakifyBuildDirPath?: string;
|
||||
kcContextExclusionsFtl?: string;
|
||||
startKeycloakOptions?: {
|
||||
@ -357,7 +354,6 @@ export function getBuildContext(params: {
|
||||
extraThemeProperties: z.array(z.string()).optional(),
|
||||
artifactId: z.string().optional(),
|
||||
groupId: z.string().optional(),
|
||||
loginThemeResourcesFromKeycloakVersion: z.string().optional(),
|
||||
keycloakifyBuildDirPath: z.string().optional(),
|
||||
kcContextExclusionsFtl: z.string().optional(),
|
||||
startKeycloakOptions: zStartKeycloakOptions.optional()
|
||||
@ -545,9 +541,6 @@ export function getBuildContext(params: {
|
||||
process.env.KEYCLOAKIFY_ARTIFACT_ID ??
|
||||
buildOptions.artifactId ??
|
||||
`${themeNames[0]}-keycloak-theme`,
|
||||
loginThemeResourcesFromKeycloakVersion:
|
||||
buildOptions.loginThemeResourcesFromKeycloakVersion ??
|
||||
LOGIN_THEME_RESOURCES_FROM_KEYCLOAK_VERSION_DEFAULT,
|
||||
projectDirPath,
|
||||
projectBuildDirPath,
|
||||
keycloakifyBuildDirPath: (() => {
|
||||
|
@ -1,10 +1,12 @@
|
||||
export const KEYCLOAK_RESOURCES = "keycloak-resources";
|
||||
export const RESOURCES_COMMON = "resources-common";
|
||||
export const LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1 = "21.1.2";
|
||||
export const BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR = "dist";
|
||||
export const WELL_KNOWN_DIRECTORY_BASE_NAME = {
|
||||
DOT_KEYCLOAKIFY: ".keycloakify",
|
||||
RESOURCES_COMMON: "resources-common",
|
||||
DIST: "dist",
|
||||
RESOURCES: "resources",
|
||||
ACCOUNT_V1: "account-v1"
|
||||
};
|
||||
|
||||
export const THEME_TYPES = ["login", "account"] as const;
|
||||
export const ACCOUNT_V1_THEME_NAME = "account-v1";
|
||||
|
||||
export type ThemeType = (typeof THEME_TYPES)[number];
|
||||
|
||||
@ -71,5 +73,3 @@ export type AccountThemePageId = (typeof ACCOUNT_THEME_PAGE_IDS)[number];
|
||||
export const CONTAINER_NAME = "keycloak-keycloakify";
|
||||
|
||||
export const FALLBACK_LANGUAGE_TAG = "en";
|
||||
|
||||
export const LOGIN_THEME_RESOURCES_FROM_KEYCLOAK_VERSION_DEFAULT = "24.0.4";
|
||||
|
@ -1,44 +1,34 @@
|
||||
import {
|
||||
downloadKeycloakStaticResources,
|
||||
type BuildContextLike as BuildContextLike_downloadKeycloakStaticResources
|
||||
} from "./downloadKeycloakStaticResources";
|
||||
import { join as pathJoin, relative as pathRelative } from "path";
|
||||
import {
|
||||
THEME_TYPES,
|
||||
KEYCLOAK_RESOURCES,
|
||||
LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1
|
||||
} from "../shared/constants";
|
||||
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "../shared/constants";
|
||||
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
||||
import { assert } from "tsafe/assert";
|
||||
import * as fs from "fs";
|
||||
import { rmSync } from "../tools/fs.rmSync";
|
||||
import type { BuildContext } from "./buildContext";
|
||||
import { transformCodebase } from "../tools/transformCodebase";
|
||||
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
|
||||
|
||||
export type BuildContextLike = BuildContextLike_downloadKeycloakStaticResources & {
|
||||
loginThemeResourcesFromKeycloakVersion: string;
|
||||
export type BuildContextLike = {
|
||||
publicDirPath: string;
|
||||
};
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
export async function copyKeycloakResourcesToPublic(params: {
|
||||
export function copyKeycloakResourcesToPublic(params: {
|
||||
buildContext: BuildContextLike;
|
||||
}) {
|
||||
const { buildContext } = params;
|
||||
|
||||
const destDirPath = pathJoin(buildContext.publicDirPath, KEYCLOAK_RESOURCES);
|
||||
const destDirPath = pathJoin(
|
||||
buildContext.publicDirPath,
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY
|
||||
);
|
||||
|
||||
const keycloakifyBuildinfoFilePath = pathJoin(destDirPath, "keycloakify.buildinfo");
|
||||
|
||||
const keycloakifyBuildinfoRaw = JSON.stringify(
|
||||
{
|
||||
destDirPath,
|
||||
keycloakifyVersion: readThisNpmPackageVersion(),
|
||||
buildContext: {
|
||||
loginThemeResourcesFromKeycloakVersion: readThisNpmPackageVersion(),
|
||||
cacheDirPath: pathRelative(destDirPath, buildContext.cacheDirPath),
|
||||
fetchOptions: buildContext.fetchOptions
|
||||
}
|
||||
keycloakifyVersion: readThisNpmPackageVersion()
|
||||
},
|
||||
null,
|
||||
2
|
||||
@ -62,35 +52,33 @@ export async function copyKeycloakResourcesToPublic(params: {
|
||||
|
||||
rmSync(destDirPath, { force: true, recursive: true });
|
||||
|
||||
// NOTE: To remove in a while, remove the legacy keycloak-resources directory
|
||||
rmSync(pathJoin(pathDirname(destDirPath), "keycloak-resources"), {
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
|
||||
fs.mkdirSync(destDirPath, { recursive: true });
|
||||
|
||||
fs.writeFileSync(pathJoin(destDirPath, ".gitignore"), Buffer.from("*", "utf8"));
|
||||
|
||||
for (const themeType of THEME_TYPES) {
|
||||
await downloadKeycloakStaticResources({
|
||||
keycloakVersion: (() => {
|
||||
switch (themeType) {
|
||||
case "login":
|
||||
return buildContext.loginThemeResourcesFromKeycloakVersion;
|
||||
case "account":
|
||||
return LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1;
|
||||
}
|
||||
})(),
|
||||
themeType,
|
||||
themeDirPath: destDirPath,
|
||||
buildContext
|
||||
});
|
||||
}
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES
|
||||
),
|
||||
destDirPath
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
pathJoin(destDirPath, "README.txt"),
|
||||
Buffer.from(
|
||||
// prettier-ignore
|
||||
[
|
||||
"This is just a test folder that helps develop",
|
||||
"the login and register page without having to run a Keycloak container\n",
|
||||
"This directory will be automatically excluded from the final build."
|
||||
].join(" ")
|
||||
"This directory is only used in dev mode by Keycloakify",
|
||||
"It won't be included in your final build.",
|
||||
"Do not modify anything in this directory.",
|
||||
].join("\n")
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1,338 +0,0 @@
|
||||
import { join as pathJoin, relative as pathRelative } from "path";
|
||||
import { type BuildContext } from "../buildContext";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1 } from "../constants";
|
||||
import { downloadAndExtractArchive } from "../../tools/downloadAndExtractArchive";
|
||||
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
||||
import * as fsPr from "fs/promises";
|
||||
|
||||
export type BuildContextLike = {
|
||||
cacheDirPath: string;
|
||||
fetchOptions: BuildContext["fetchOptions"];
|
||||
};
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
export async function downloadKeycloakDefaultTheme(params: {
|
||||
keycloakVersion: string;
|
||||
buildContext: BuildContextLike;
|
||||
}): Promise<{ defaultThemeDirPath: string }> {
|
||||
const { keycloakVersion, buildContext } = params;
|
||||
|
||||
let kcNodeModulesKeepFilePaths: Set<string> | undefined = undefined;
|
||||
let kcNodeModulesKeepFilePaths_lastAccountV1: Set<string> | undefined = undefined;
|
||||
|
||||
let areExtraAssetsFor24Copied = false;
|
||||
|
||||
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||
url: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
|
||||
cacheDirPath: buildContext.cacheDirPath,
|
||||
fetchOptions: buildContext.fetchOptions,
|
||||
uniqueIdOfOnArchiveFile: "downloadKeycloakDefaultTheme",
|
||||
onArchiveFile: async params => {
|
||||
const fileRelativePath = pathRelative("theme", params.fileRelativePath);
|
||||
|
||||
if (fileRelativePath.startsWith("..")) {
|
||||
return;
|
||||
}
|
||||
|
||||
skip_keycloak_v2: {
|
||||
if (!fileRelativePath.startsWith(pathJoin("keycloak.v2"))) {
|
||||
break skip_keycloak_v2;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { readFile, writeFile } = params;
|
||||
|
||||
last_account_v1_transformations: {
|
||||
if (LAST_KEYCLOAK_VERSION_WITH_ACCOUNT_V1 !== keycloakVersion) {
|
||||
break last_account_v1_transformations;
|
||||
}
|
||||
|
||||
skip_web_modules: {
|
||||
if (
|
||||
!fileRelativePath.startsWith(
|
||||
pathJoin("keycloak", "common", "resources", "web_modules")
|
||||
)
|
||||
) {
|
||||
break skip_web_modules;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
skip_lib: {
|
||||
if (
|
||||
!fileRelativePath.startsWith(
|
||||
pathJoin("keycloak", "common", "resources", "lib")
|
||||
)
|
||||
) {
|
||||
break skip_lib;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
skip_node_modules: {
|
||||
const nodeModulesRelativeDirPath = pathJoin(
|
||||
"keycloak",
|
||||
"common",
|
||||
"resources",
|
||||
"node_modules"
|
||||
);
|
||||
|
||||
if (!fileRelativePath.startsWith(nodeModulesRelativeDirPath)) {
|
||||
break skip_node_modules;
|
||||
}
|
||||
|
||||
if (kcNodeModulesKeepFilePaths_lastAccountV1 === undefined) {
|
||||
kcNodeModulesKeepFilePaths_lastAccountV1 = new Set([
|
||||
pathJoin("patternfly", "dist", "css", "patternfly.min.css"),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"css",
|
||||
"patternfly-additions.min.css"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Regular-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Bold-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Light-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Semibold-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"PatternFlyIcons-webfont.ttf"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"PatternFlyIcons-webfont.woff"
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
const fileRelativeToNodeModulesPath = fileRelativePath.substring(
|
||||
nodeModulesRelativeDirPath.length + 1
|
||||
);
|
||||
|
||||
if (
|
||||
kcNodeModulesKeepFilePaths_lastAccountV1.has(
|
||||
fileRelativeToNodeModulesPath
|
||||
)
|
||||
) {
|
||||
break skip_node_modules;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
patch_account_css: {
|
||||
if (
|
||||
fileRelativePath !==
|
||||
pathJoin("keycloak", "account", "resources", "css", "account.css")
|
||||
) {
|
||||
break patch_account_css;
|
||||
}
|
||||
|
||||
await writeFile({
|
||||
fileRelativePath,
|
||||
modifiedData: Buffer.from(
|
||||
(await readFile())
|
||||
.toString("utf8")
|
||||
.replace("top: -34px;", "top: -34px !important;"),
|
||||
"utf8"
|
||||
)
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
copy_extra_assets: {
|
||||
if (keycloakVersion !== "24.0.4") {
|
||||
break copy_extra_assets;
|
||||
}
|
||||
|
||||
if (areExtraAssetsFor24Copied) {
|
||||
break copy_extra_assets;
|
||||
}
|
||||
|
||||
const extraAssetsDirPath = pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
"src",
|
||||
"bin",
|
||||
"shared",
|
||||
"downloadKeycloakDefaultTheme",
|
||||
"extra-assets"
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
["webauthnAuthenticate.js", "passkeysConditionalAuth.js"].map(
|
||||
async fileBasename =>
|
||||
writeFile({
|
||||
fileRelativePath: pathJoin(
|
||||
"base",
|
||||
"login",
|
||||
"resources",
|
||||
"js",
|
||||
fileBasename
|
||||
),
|
||||
modifiedData: await fsPr.readFile(
|
||||
pathJoin(extraAssetsDirPath, fileBasename)
|
||||
)
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
skip_unused_resources: {
|
||||
if (keycloakVersion !== "24.0.4") {
|
||||
break skip_unused_resources;
|
||||
}
|
||||
|
||||
skip_node_modules: {
|
||||
const nodeModulesRelativeDirPath = pathJoin(
|
||||
"keycloak",
|
||||
"common",
|
||||
"resources",
|
||||
"node_modules"
|
||||
);
|
||||
|
||||
if (!fileRelativePath.startsWith(nodeModulesRelativeDirPath)) {
|
||||
break skip_node_modules;
|
||||
}
|
||||
|
||||
if (kcNodeModulesKeepFilePaths === undefined) {
|
||||
kcNodeModulesKeepFilePaths = new Set([
|
||||
pathJoin("@patternfly", "patternfly", "patternfly.min.css"),
|
||||
pathJoin("patternfly", "dist", "css", "patternfly.min.css"),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"css",
|
||||
"patternfly-additions.min.css"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Regular-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Light-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Bold-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Bold-webfont.woff"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Bold-webfont.ttf"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"fontawesome-webfont.woff2"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"PatternFlyIcons-webfont.ttf"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"PatternFlyIcons-webfont.woff"
|
||||
),
|
||||
pathJoin(
|
||||
"patternfly",
|
||||
"dist",
|
||||
"fonts",
|
||||
"OpenSans-Semibold-webfont.woff2"
|
||||
),
|
||||
pathJoin("patternfly", "dist", "img", "bg-login.jpg"),
|
||||
pathJoin("jquery", "dist", "jquery.min.js")
|
||||
]);
|
||||
}
|
||||
|
||||
const fileRelativeToNodeModulesPath = fileRelativePath.substring(
|
||||
nodeModulesRelativeDirPath.length + 1
|
||||
);
|
||||
|
||||
if (kcNodeModulesKeepFilePaths.has(fileRelativeToNodeModulesPath)) {
|
||||
break skip_node_modules;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
skip_vendor: {
|
||||
if (
|
||||
!fileRelativePath.startsWith(
|
||||
pathJoin("keycloak", "common", "resources", "vendor")
|
||||
)
|
||||
) {
|
||||
break skip_vendor;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
skip_rollup_config: {
|
||||
if (
|
||||
fileRelativePath !==
|
||||
pathJoin("keycloak", "common", "resources", "rollup.config.js")
|
||||
) {
|
||||
break skip_rollup_config;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await writeFile({ fileRelativePath });
|
||||
}
|
||||
});
|
||||
|
||||
return { defaultThemeDirPath: extractedDirPath };
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
import { base64url } from "rfc4648";
|
||||
import { returnSuccess, returnFailure } from "./webauthnAuthenticate.js";
|
||||
|
||||
export function initAuthenticate(input) {
|
||||
// Check if WebAuthn is supported by this browser
|
||||
if (!window.PublicKeyCredential) {
|
||||
returnFailure(input.errmsg);
|
||||
return;
|
||||
}
|
||||
if (input.isUserIdentified || typeof PublicKeyCredential.isConditionalMediationAvailable === "undefined") {
|
||||
document.getElementById("kc-form-passkey-button").style.display = 'block';
|
||||
} else {
|
||||
tryAutoFillUI(input);
|
||||
}
|
||||
}
|
||||
|
||||
function doAuthenticate(input) {
|
||||
// Check if WebAuthn is supported by this browser
|
||||
if (!window.PublicKeyCredential) {
|
||||
returnFailure(input.errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
const publicKey = {
|
||||
rpId : input.rpId,
|
||||
challenge: base64url.parse(input.challenge, { loose: true })
|
||||
};
|
||||
|
||||
publicKey.allowCredentials = !input.isUserIdentified ? [] : getAllowCredentials();
|
||||
|
||||
if (input.createTimeout !== 0) {
|
||||
publicKey.timeout = input.createTimeout * 1000;
|
||||
}
|
||||
|
||||
if (input.userVerification !== 'not specified') {
|
||||
publicKey.userVerification = input.userVerification;
|
||||
}
|
||||
|
||||
return navigator.credentials.get({
|
||||
publicKey: publicKey,
|
||||
...input.additionalOptions
|
||||
});
|
||||
}
|
||||
|
||||
async function tryAutoFillUI(input) {
|
||||
const isConditionalMediationAvailable = await PublicKeyCredential.isConditionalMediationAvailable();
|
||||
if (isConditionalMediationAvailable) {
|
||||
document.getElementById("kc-form-login").style.display = "block";
|
||||
input.additionalOptions = { mediation: 'conditional'};
|
||||
try {
|
||||
const result = await doAuthenticate(input);
|
||||
returnSuccess(result);
|
||||
} catch (error) {
|
||||
returnFailure(error);
|
||||
}
|
||||
} else {
|
||||
document.getElementById("kc-form-passkey-button").style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function getAllowCredentials() {
|
||||
const allowCredentials = [];
|
||||
const authnUse = document.forms['authn_select'].authn_use_chk;
|
||||
if (authnUse !== undefined) {
|
||||
if (authnUse.length === undefined) {
|
||||
allowCredentials.push({
|
||||
id: base64url.parse(authnUse.value, {loose: true}),
|
||||
type: 'public-key',
|
||||
});
|
||||
} else {
|
||||
authnUse.forEach((entry) =>
|
||||
allowCredentials.push({
|
||||
id: base64url.parse(entry.value, {loose: true}),
|
||||
type: 'public-key',
|
||||
}));
|
||||
}
|
||||
}
|
||||
return allowCredentials;
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
import { base64url } from "rfc4648";
|
||||
|
||||
export async function authenticateByWebAuthn(input) {
|
||||
if (!input.isUserIdentified) {
|
||||
try {
|
||||
const result = await doAuthenticate([], input.challenge, input.userVerification, input.rpId, input.createTimeout, input.errmsg);
|
||||
returnSuccess(result);
|
||||
} catch (error) {
|
||||
returnFailure(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
checkAllowCredentials(input.challenge, input.userVerification, input.rpId, input.createTimeout, input.errmsg);
|
||||
}
|
||||
|
||||
async function checkAllowCredentials(challenge, userVerification, rpId, createTimeout, errmsg) {
|
||||
const allowCredentials = [];
|
||||
const authnUse = document.forms['authn_select'].authn_use_chk;
|
||||
if (authnUse !== undefined) {
|
||||
if (authnUse.length === undefined) {
|
||||
allowCredentials.push({
|
||||
id: base64url.parse(authnUse.value, {loose: true}),
|
||||
type: 'public-key',
|
||||
});
|
||||
} else {
|
||||
authnUse.forEach((entry) =>
|
||||
allowCredentials.push({
|
||||
id: base64url.parse(entry.value, {loose: true}),
|
||||
type: 'public-key',
|
||||
}));
|
||||
}
|
||||
}
|
||||
try {
|
||||
const result = await doAuthenticate(allowCredentials, challenge, userVerification, rpId, createTimeout, errmsg);
|
||||
returnSuccess(result);
|
||||
} catch (error) {
|
||||
returnFailure(error);
|
||||
}
|
||||
}
|
||||
|
||||
function doAuthenticate(allowCredentials, challenge, userVerification, rpId, createTimeout, errmsg) {
|
||||
// Check if WebAuthn is supported by this browser
|
||||
if (!window.PublicKeyCredential) {
|
||||
returnFailure(errmsg);
|
||||
return;
|
||||
}
|
||||
|
||||
const publicKey = {
|
||||
rpId : rpId,
|
||||
challenge: base64url.parse(challenge, { loose: true })
|
||||
};
|
||||
|
||||
if (createTimeout !== 0) {
|
||||
publicKey.timeout = createTimeout * 1000;
|
||||
}
|
||||
|
||||
if (allowCredentials.length) {
|
||||
publicKey.allowCredentials = allowCredentials;
|
||||
}
|
||||
|
||||
if (userVerification !== 'not specified') {
|
||||
publicKey.userVerification = userVerification;
|
||||
}
|
||||
|
||||
return navigator.credentials.get({publicKey});
|
||||
}
|
||||
|
||||
export function returnSuccess(result) {
|
||||
document.getElementById("clientDataJSON").value = base64url.stringify(new Uint8Array(result.response.clientDataJSON), { pad: false });
|
||||
document.getElementById("authenticatorData").value = base64url.stringify(new Uint8Array(result.response.authenticatorData), { pad: false });
|
||||
document.getElementById("signature").value = base64url.stringify(new Uint8Array(result.response.signature), { pad: false });
|
||||
document.getElementById("credentialId").value = result.id;
|
||||
if (result.response.userHandle) {
|
||||
document.getElementById("userHandle").value = base64url.stringify(new Uint8Array(result.response.userHandle), { pad: false });
|
||||
}
|
||||
document.getElementById("webauth").submit();
|
||||
}
|
||||
|
||||
export function returnFailure(err) {
|
||||
document.getElementById("error").value = err;
|
||||
document.getElementById("webauth").submit();
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from "./downloadKeycloakDefaultTheme";
|
@ -1,53 +0,0 @@
|
||||
import { transformCodebase } from "../tools/transformCodebase";
|
||||
import { join as pathJoin } from "path";
|
||||
import {
|
||||
downloadKeycloakDefaultTheme,
|
||||
type BuildContextLike as BuildContextLike_downloadKeycloakDefaultTheme
|
||||
} from "./downloadKeycloakDefaultTheme";
|
||||
import { RESOURCES_COMMON, type ThemeType } from "./constants";
|
||||
import type { BuildContext } from "./buildContext";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { existsAsync } from "../tools/fs.existsAsync";
|
||||
|
||||
export type BuildContextLike = BuildContextLike_downloadKeycloakDefaultTheme & {};
|
||||
|
||||
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||
|
||||
export async function downloadKeycloakStaticResources(params: {
|
||||
themeType: ThemeType;
|
||||
themeDirPath: string;
|
||||
keycloakVersion: string;
|
||||
buildContext: BuildContextLike;
|
||||
}) {
|
||||
const { themeType, themeDirPath, keycloakVersion, buildContext } = params;
|
||||
|
||||
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
|
||||
keycloakVersion,
|
||||
buildContext
|
||||
});
|
||||
|
||||
const resourcesDirPath = pathJoin(themeDirPath, themeType, "resources");
|
||||
|
||||
repatriate_base_resources: {
|
||||
const srcDirPath = pathJoin(defaultThemeDirPath, "base", themeType, "resources");
|
||||
|
||||
if (!(await existsAsync(srcDirPath))) {
|
||||
break repatriate_base_resources;
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath,
|
||||
destDirPath: resourcesDirPath
|
||||
});
|
||||
}
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(defaultThemeDirPath, "keycloak", themeType, "resources"),
|
||||
destDirPath: resourcesDirPath
|
||||
});
|
||||
|
||||
transformCodebase({
|
||||
srcDirPath: pathJoin(defaultThemeDirPath, "keycloak", "common", "resources"),
|
||||
destDirPath: pathJoin(resourcesDirPath, RESOURCES_COMMON)
|
||||
});
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import "keycloakify/tools/Object.fromEntries";
|
||||
import type { KcContext, Attribute } from "./KcContext";
|
||||
import {
|
||||
RESOURCES_COMMON,
|
||||
KEYCLOAK_RESOURCES,
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME,
|
||||
type LoginThemePageId
|
||||
} from "keycloakify/bin/shared/constants";
|
||||
import { id } from "tsafe/id";
|
||||
@ -76,7 +75,7 @@ const attributesByName = Object.fromEntries(
|
||||
]).map(attribute => [attribute.name, attribute])
|
||||
);
|
||||
|
||||
const resourcesPath = `${BASE_URL}${KEYCLOAK_RESOURCES}/login/resources`;
|
||||
const resourcesPath = `${BASE_URL}${WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY}/login`;
|
||||
|
||||
export const kcContextCommonMock: KcContext.Common = {
|
||||
themeVersion: "0.0.0",
|
||||
@ -86,7 +85,7 @@ export const kcContextCommonMock: KcContext.Common = {
|
||||
url: {
|
||||
loginAction: "#",
|
||||
resourcesPath,
|
||||
resourcesCommonPath: `${resourcesPath}/${RESOURCES_COMMON}`,
|
||||
resourcesCommonPath: `${resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.RESOURCES_COMMON}`,
|
||||
loginRestartFlowUrl: "#",
|
||||
loginUrl: "#",
|
||||
ssoLoginInOtherTabsUrl: "#"
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
|
||||
import type { Plugin } from "vite";
|
||||
import {
|
||||
BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR,
|
||||
KEYCLOAK_RESOURCES,
|
||||
WELL_KNOWN_DIRECTORY_BASE_NAME,
|
||||
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES
|
||||
} from "../bin/shared/constants";
|
||||
import { id } from "tsafe/id";
|
||||
@ -128,14 +127,8 @@ export function keycloakify(params: keycloakify.Params) {
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
copyKeycloakResourcesToPublic({
|
||||
buildContext
|
||||
}),
|
||||
generateKcGenTs({
|
||||
buildContext
|
||||
})
|
||||
]);
|
||||
copyKeycloakResourcesToPublic({ buildContext }),
|
||||
await generateKcGenTs({ buildContext });
|
||||
},
|
||||
transform: (code, id) => {
|
||||
assert(command !== undefined);
|
||||
@ -174,7 +167,7 @@ export function keycloakify(params: keycloakify.Params) {
|
||||
`(`,
|
||||
`(window.kcContext === undefined || import.meta.env.MODE === "development")?`,
|
||||
`"${urlPathname ?? "/"}":`,
|
||||
`(window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/")`,
|
||||
`(window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/")`,
|
||||
`)`
|
||||
].join("")
|
||||
);
|
||||
@ -207,10 +200,13 @@ export function keycloakify(params: keycloakify.Params) {
|
||||
|
||||
assert(buildDirPath !== undefined);
|
||||
|
||||
await rm(pathJoin(buildDirPath, KEYCLOAK_RESOURCES), {
|
||||
recursive: true,
|
||||
force: true
|
||||
});
|
||||
await rm(
|
||||
pathJoin(buildDirPath, WELL_KNOWN_DIRECTORY_BASE_NAME.DOT_KEYCLOAKIFY),
|
||||
{
|
||||
recursive: true,
|
||||
force: true
|
||||
}
|
||||
);
|
||||
}
|
||||
} satisfies Plugin;
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { replaceImportsInJsCode_vite } from "keycloakify/bin/keycloakify/replace
|
||||
import { replaceImportsInJsCode_webpack } from "keycloakify/bin/keycloakify/replacers/replaceImportsInJsCode/webpack";
|
||||
import { replaceImportsInCssCode } from "keycloakify/bin/keycloakify/replacers/replaceImportsInCssCode";
|
||||
import { expect, it, describe } from "vitest";
|
||||
import { BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR } from "keycloakify/bin/shared/constants";
|
||||
import { WELL_KNOWN_DIRECTORY_BASE_NAME } from "keycloakify/bin/shared/constants";
|
||||
|
||||
describe("js replacer - vite", () => {
|
||||
it("replaceImportsInJsCode_vite - 1", () => {
|
||||
@ -87,13 +87,13 @@ describe("js replacer - vite", () => {
|
||||
});
|
||||
|
||||
const fixedJsCodeExpected = `
|
||||
S=(window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||
S=(window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||
|
||||
function __vite__mapDeps(indexes) {
|
||||
if (!__vite__mapDeps.viteFileDeps) {
|
||||
__vite__mapDeps.viteFileDeps = [
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/Login-dJpPRzM4.js"),
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/index-XwzrZ5Gu.js")
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/Login-dJpPRzM4.js"),
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/index-XwzrZ5Gu.js")
|
||||
]
|
||||
}
|
||||
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||
@ -146,13 +146,13 @@ describe("js replacer - vite", () => {
|
||||
});
|
||||
|
||||
const fixedJsCodeExpected = `
|
||||
S=(window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/foo/bar/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||
S=(window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/foo/bar/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||
|
||||
function __vite__mapDeps(indexes) {
|
||||
if (!__vite__mapDeps.viteFileDeps) {
|
||||
__vite__mapDeps.viteFileDeps = [
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/foo/bar/Login-dJpPRzM4.js"),
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/foo/bar/index-XwzrZ5Gu.js")
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/foo/bar/Login-dJpPRzM4.js"),
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/foo/bar/index-XwzrZ5Gu.js")
|
||||
]
|
||||
}
|
||||
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||
@ -205,13 +205,13 @@ describe("js replacer - vite", () => {
|
||||
});
|
||||
|
||||
const fixedJsCodeExpected = `
|
||||
S=(window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||
S=(window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/keycloakify-logo-mqjydaoZ.png"),H=(()=>{
|
||||
|
||||
function __vite__mapDeps(indexes) {
|
||||
if (!__vite__mapDeps.viteFileDeps) {
|
||||
__vite__mapDeps.viteFileDeps = [
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/Login-dJpPRzM4.js"),
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/index-XwzrZ5Gu.js")
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/Login-dJpPRzM4.js"),
|
||||
(window.kcContext["x-keycloakify"].resourcesPath.substring(1) + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/index-XwzrZ5Gu.js")
|
||||
]
|
||||
}
|
||||
return indexes.map((i) => __vite__mapDeps.viteFileDeps[i])
|
||||
@ -267,13 +267,13 @@ describe("js replacer - webpack", () => {
|
||||
|
||||
const fixedJsCodeExpected = `
|
||||
function f() {
|
||||
return window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/static/js/" + ({}[e] || e) + "." + {
|
||||
return window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/static/js/" + ({}[e] || e) + "." + {
|
||||
3: "0664cdc0"
|
||||
}[e] + ".chunk.js"
|
||||
}
|
||||
|
||||
function sameAsF() {
|
||||
return window.kcContext["x-keycloakify"].resourcesPath + "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/static/js/" + ({}[e] || e) + "." + {
|
||||
return window.kcContext["x-keycloakify"].resourcesPath + "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/static/js/" + ({}[e] || e) + "." + {
|
||||
3: "0664cdc0"
|
||||
}[e] + ".chunk.js"
|
||||
}
|
||||
@ -288,7 +288,7 @@ describe("js replacer - webpack", () => {
|
||||
}
|
||||
return "u";
|
||||
})()] = function(e) {
|
||||
return "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/static/js/" + e + "." + {
|
||||
return "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/static/js/" + e + "." + {
|
||||
147: "6c5cee76",
|
||||
787: "8da10fcf",
|
||||
922: "be170a73"
|
||||
@ -305,7 +305,7 @@ describe("js replacer - webpack", () => {
|
||||
}
|
||||
return "miniCssF";
|
||||
})()] = function(e) {
|
||||
return "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/static/css/" + e + "." + {
|
||||
return "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/static/css/" + e + "." + {
|
||||
164:"dcfd7749",
|
||||
908:"67c9ed2c"
|
||||
} [e] + ".chunk.css"
|
||||
@ -320,7 +320,7 @@ describe("js replacer - webpack", () => {
|
||||
});
|
||||
}
|
||||
return "u";
|
||||
})()] = e => "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/static/js/"+e+"."+{69:"4f205f87",128:"49264537",453:"b2fed72e",482:"f0106901"}[e]+".chunk.js"
|
||||
})()] = e => "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/static/js/"+e+"."+{69:"4f205f87",128:"49264537",453:"b2fed72e",482:"f0106901"}[e]+".chunk.js"
|
||||
|
||||
t[(function(){
|
||||
var pd = Object.getOwnPropertyDescriptor(t, "p");
|
||||
@ -331,7 +331,7 @@ describe("js replacer - webpack", () => {
|
||||
});
|
||||
}
|
||||
return "miniCssF";
|
||||
})()] = e => "/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/static/css/"+e+"."+{164:"dcfd7749",908:"67c9ed2c"}[e]+".chunk.css"
|
||||
})()] = e => "/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/static/css/"+e+"."+{164:"dcfd7749",908:"67c9ed2c"}[e]+".chunk.css"
|
||||
`;
|
||||
|
||||
expect(isSameCode(fixedJsCode, fixedJsCodeExpected)).toBe(true);
|
||||
@ -495,15 +495,15 @@ describe("css replacer", () => {
|
||||
|
||||
const fixedCssCodeExpected = `
|
||||
.my-div {
|
||||
background: url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/background.png") no-repeat center center;
|
||||
background: url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/background.png") no-repeat center center;
|
||||
}
|
||||
|
||||
.my-div2 {
|
||||
background: url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/background.png") repeat center center;
|
||||
background: url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/background.png") repeat center center;
|
||||
}
|
||||
|
||||
.my-div3 {
|
||||
background-image: url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/media/something.svg");
|
||||
background-image: url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/media/something.svg");
|
||||
}
|
||||
`;
|
||||
|
||||
@ -533,15 +533,15 @@ describe("css replacer", () => {
|
||||
|
||||
const fixedCssCodeExpected = `
|
||||
.my-div {
|
||||
background: url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/background.png") no-repeat center center;
|
||||
background: url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/background.png") no-repeat center center;
|
||||
}
|
||||
|
||||
.my-div2 {
|
||||
background: url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/background.png") repeat center center;
|
||||
background: url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/background.png") repeat center center;
|
||||
}
|
||||
|
||||
.my-div3 {
|
||||
background-image: url("\${xKeycloakify.resourcesPath}/${BASENAME_OF_KEYCLOAKIFY_RESOURCES_DIR}/assets/media/something.svg");
|
||||
background-image: url("\${xKeycloakify.resourcesPath}/${WELL_KNOWN_DIRECTORY_BASE_NAME.DIST}/assets/media/something.svg");
|
||||
}
|
||||
`;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user