Compare commits

..

15 Commits

29 changed files with 1001 additions and 745 deletions

View File

@ -1,24 +1,24 @@
{
"name": "keycloakify",
"version": "10.0.0-rc.63",
"version": "10.0.0-rc.66",
"description": "Create Keycloak themes using React",
"repository": {
"type": "git",
"url": "git://github.com/keycloakify/keycloakify.git"
},
"scripts": {
"prepare": "patch-package && ts-node --skipProject scripts/generate-i18n-messages.ts",
"build": "ts-node --skipProject scripts/build.ts",
"storybook": "ts-node --skipProject scripts/start-storybook.ts",
"link-in-starter": "ts-node --skipProject scripts/link-in-starter.ts",
"prepare": "patch-package && tsx scripts/generate-i18n-messages.ts",
"build": "tsx scripts/build.ts",
"storybook": "tsx scripts/start-storybook.ts",
"link-in-starter": "tsx scripts/link-in-starter.ts",
"test": "yarn test:types && vitest run",
"test:types": "tsc -p test/tsconfig.json --noEmit",
"_format": "prettier '**/*.{ts,tsx,json,md}'",
"format": "yarn _format --write",
"format:check": "yarn _format --list-different",
"link-in-app": "ts-node --skipProject scripts/link-in-app.ts",
"build-storybook": "ts-node --skipProject scripts/build-storybook.ts",
"dump-keycloak-realm": "ts-node --skipProject scripts/dump-keycloak-realm.ts"
"link-in-app": "tsx scripts/link-in-app.ts",
"build-storybook": "tsx scripts/build-storybook.ts",
"dump-keycloak-realm": "tsx scripts/dump-keycloak-realm.ts"
},
"bin": {
"keycloakify": "dist/bin/main.js"
@ -112,7 +112,6 @@
"run-exclusive": "^2.2.19",
"storybook-dark-mode": "^1.1.2",
"termost": "^0.12.0",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.10",
"tss-react": "^4.9.10",
"typescript": "^4.9.1-beta",
@ -120,6 +119,7 @@
"vitest": "^1.6.0",
"yauzl": "^2.10.0",
"zod": "^3.17.10",
"evt": "^2.5.7"
"evt": "^2.5.7",
"tsx": "^4.15.5"
}
}

View File

@ -11,13 +11,17 @@ import { is } from "tsafe/is";
{
const dCompleted = new Deferred<void>();
const child = child_process.spawn("docker", [
const child = child_process.spawn(
"docker",
[
...["exec", containerName],
...["/opt/keycloak/bin/kc.sh", "export"],
...["--dir", "/tmp"],
...["--realm", "myrealm"],
...["--users", "realm_file"]
]);
],
{ shell: true }
);
let output = "";

View File

@ -6,8 +6,24 @@ import * as os from "os";
const singletonDependencies: string[] = ["react", "@types/react"];
// For example [ "@emotion" ] it's more convenient than
// having to list every sub emotion packages (@emotion/css @emotion/utils ...)
// in singletonDependencies
const namespaceSingletonDependencies: string[] = [];
const rootDirPath = getThisCodebaseRootDirPath();
const commonThirdPartyDeps = [
...namespaceSingletonDependencies
.map(namespaceModuleName =>
fs
.readdirSync(pathJoin(rootDirPath, "node_modules", namespaceModuleName))
.map(submoduleName => `${namespaceModuleName}/${submoduleName}`)
)
.reduce((prev, curr) => [...prev, ...curr], []),
...singletonDependencies
];
//NOTE: This is only required because of: https://github.com/garronej/ts-ci/blob/c0e207b9677523d4ec97fe672ddd72ccbb3c1cc4/README.md?plain=1#L54-L58
{
let modifiedPackageJsonContent = fs
@ -34,26 +50,6 @@ const rootDirPath = getThisCodebaseRootDirPath();
);
}
const commonThirdPartyDeps = (() => {
// For example [ "@emotion" ] it's more convenient than
// having to list every sub emotion packages (@emotion/css @emotion/utils ...)
// in singletonDependencies
const namespaceSingletonDependencies: string[] = [];
return [
...namespaceSingletonDependencies
.map(namespaceModuleName =>
fs
.readdirSync(
pathJoin(rootDirPath, "node_modules", namespaceModuleName)
)
.map(submoduleName => `${namespaceModuleName}/${submoduleName}`)
)
.reduce((prev, curr) => [...prev, ...curr], []),
...singletonDependencies
];
})();
const yarnGlobalDirPath = pathJoin(rootDirPath, ".yarn_home");
fs.rmSync(yarnGlobalDirPath, { recursive: true, force: true });

View File

@ -17,7 +17,7 @@ fs.rmSync(join("..", "keycloakify-starter", "node_modules"), {
run("yarn install", { cwd: join("..", "keycloakify-starter") });
run(`npx ts-node --skipProject ${join("scripts", "link-in-app.ts")} keycloakify-starter`);
run(`npx tsx ${join("scripts", "link-in-app.ts")} keycloakify-starter`);
startRebuildOnSrcChange();

View File

@ -13,7 +13,9 @@ run(`node ${join("dist", "bin", "main.js")} copy-keycloak-resources-to-public`,
});
{
const child = child_process.spawn("npx", ["start-storybook", "-p", "6006"]);
const child = child_process.spawn("npx", ["start-storybook", "-p", "6006"], {
shell: true
});
child.stdout.on("data", data => process.stdout.write(data));

View File

@ -13,7 +13,7 @@ export function startRebuildOnSrcChange() {
const dCompleted = new Deferred<void>();
const child = child_process.spawn("yarn", ["build"]);
const child = child_process.spawn("yarn", ["build"], { shell: true });
child.stdout.on("data", data => process.stdout.write(data));

View File

@ -166,6 +166,7 @@ export declare namespace KcContext {
algorithm: "HmacSHA1" | "HmacSHA256" | "HmacSHA512";
digits: number;
lookAheadWindow: number;
getAlgorithmKey: () => string;
} & (
| {
type: "totp";

View File

@ -148,7 +148,8 @@ export const kcContextMocks: KcContext[] = [
digits: 6,
lookAheadWindow: 1,
type: "totp",
period: 30
period: 30,
getAlgorithmKey: () => "SHA1"
}
},
mode: "qr",

View File

@ -16,12 +16,6 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
const { msg, msgStr, advancedMsg } = i18n;
const algToKeyUriAlg: Record<(typeof kcContext)["totp"]["policy"]["algorithm"], string> = {
HmacSHA1: "SHA1",
HmacSHA256: "SHA256",
HmacSHA512: "SHA512"
};
return (
<Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="totp">
<>
@ -100,7 +94,7 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
{msg("totpType")}: {msg(`totp.${totp.policy.type}`)}
</li>
<li id="kc-totp-algorithm">
{msg("totpAlgorithm")}: {algToKeyUriAlg?.[totp.policy.algorithm] ?? totp.policy.algorithm}
{msg("totpAlgorithm")}: {totp.policy.getAlgorithmKey()}
</li>
<li id="kc-totp-digits">
{msg("totpDigits")}: {totp.policy.digits}

View File

@ -13,7 +13,6 @@ import * as fs from "fs";
import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path";
import { kebabCaseToCamelCase } from "./tools/kebabCaseToSnakeCase";
import { assert, Equals } from "tsafe/assert";
import { getThemeSrcDirPath } from "./shared/getThemeSrcDirPath";
import type { CliCommandOptions } from "./main";
import { getBuildContext } from "./shared/buildContext";
import chalk from "chalk";
@ -53,17 +52,13 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
console.log(`${pageId}`);
const { themeSrcDirPath } = getThemeSrcDirPath({
projectDirPath: buildContext.projectDirPath
});
const componentBasename = capitalize(kebabCaseToCamelCase(pageId)).replace(
/ftl$/,
"stories.tsx"
);
const targetFilePath = pathJoin(
themeSrcDirPath,
buildContext.themeSrcDirPath,
themeType,
"pages",
componentBasename
@ -103,7 +98,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
`${chalk.green("✓")} ${chalk.bold(
pathJoin(".", pathRelative(process.cwd(), targetFilePath))
)} copy pasted from the Keycloakify source code into your project`,
`You can start storybook with ${chalk.bold("yarn storybook")}`
`You can start storybook with ${chalk.bold("npm run storybook")}`
].join("\n")
);
}

View File

@ -15,7 +15,6 @@ import * as fs from "fs";
import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path";
import { kebabCaseToCamelCase } from "./tools/kebabCaseToSnakeCase";
import { assert, Equals } from "tsafe/assert";
import { getThemeSrcDirPath } from "./shared/getThemeSrcDirPath";
import type { CliCommandOptions } from "./main";
import { getBuildContext } from "./shared/buildContext";
import chalk from "chalk";
@ -68,10 +67,6 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
console.log(`${pageIdOrComponent}`);
const { themeSrcDirPath } = getThemeSrcDirPath({
projectDirPath: buildContext.projectDirPath
});
const componentBasename = (() => {
if (pageIdOrComponent === templateValue) {
return "Template.tsx";
@ -96,7 +91,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
})();
const targetFilePath = pathJoin(
themeSrcDirPath,
buildContext.themeSrcDirPath,
themeType,
pagesOrDot,
componentBasename
@ -149,7 +144,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
break edit_KcApp;
}
const kcAppTsxPath = pathJoin(themeSrcDirPath, themeType, "KcPage.tsx");
const kcAppTsxPath = pathJoin(
buildContext.themeSrcDirPath,
themeType,
"KcPage.tsx"
);
const kcAppTsxCode = fs.readFileSync(kcAppTsxPath).toString("utf8");
@ -199,7 +198,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
`${chalk.bold(
pathJoin(
".",
pathRelative(process.cwd(), themeSrcDirPath),
pathRelative(process.cwd(), buildContext.themeSrcDirPath),
themeType,
"KcPage.tsx"
)

View File

@ -4,7 +4,6 @@ import { transformCodebase } from "./tools/transformCodebase";
import { promptKeycloakVersion } from "./shared/promptKeycloakVersion";
import { getBuildContext } from "./shared/buildContext";
import * as fs from "fs";
import { getThemeSrcDirPath } from "./shared/getThemeSrcDirPath";
import type { CliCommandOptions } from "./main";
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
@ -12,11 +11,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
const buildContext = getBuildContext({ cliCommandOptions });
const { themeSrcDirPath } = getThemeSrcDirPath({
projectDirPath: buildContext.projectDirPath
});
const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email");
const emailThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "email");
if (fs.existsSync(emailThemeSrcDirPath)) {
console.warn(

View File

@ -16,7 +16,7 @@ import { readFileSync } from "fs";
import { isInside } from "../../tools/isInside";
import child_process from "child_process";
import { rmSync } from "../../tools/fs.rmSync";
import { getMetaInfKeycloakThemesJsonFilePath } from "../../shared/metaInfKeycloakThemes";
import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
export type BuildContextLike = BuildContextLike_generatePom & {
keycloakifyBuildDirPath: string;
@ -50,9 +50,16 @@ export async function buildJar(params: {
rmSync(keycloakifyBuildTmpDirPath, { recursive: true, force: true });
const tmpResourcesDirPath = pathJoin(
keycloakifyBuildTmpDirPath,
"src",
"main",
"resources"
);
transformCodebase({
srcDirPath: resourcesDirPath,
destDirPath: pathJoin(keycloakifyBuildTmpDirPath, "src", "main", "resources"),
destDirPath: tmpResourcesDirPath,
transformSourceCode:
keycloakAccountV1Version !== null
? undefined
@ -71,31 +78,6 @@ export async function buildJar(params: {
return undefined;
}
if (
fileRelativePath ===
getMetaInfKeycloakThemesJsonFilePath({
resourcesDirPath: "."
})
) {
const keycloakThemesJsonParsed = JSON.parse(
sourceCode.toString("utf8")
) as {
themes: { name: string; types: string[] }[];
};
keycloakThemesJsonParsed.themes =
keycloakThemesJsonParsed.themes.filter(
({ name }) => name !== accountV1ThemeName
);
return {
modifiedSourceCode: Buffer.from(
JSON.stringify(keycloakThemesJsonParsed, null, 2),
"utf8"
)
};
}
for (const themeName of buildContext.themeNames) {
if (
fileRelativePath ===
@ -123,6 +105,21 @@ export async function buildJar(params: {
}
});
if (keycloakAccountV1Version === null) {
writeMetaInfKeycloakThemes({
resourcesDirPath: tmpResourcesDirPath,
getNewMetaInfKeycloakTheme: ({ metaInfKeycloakTheme }) => {
assert(metaInfKeycloakTheme !== undefined);
metaInfKeycloakTheme.themes = metaInfKeycloakTheme.themes.filter(
({ name }) => name !== accountV1ThemeName
);
return metaInfKeycloakTheme;
}
});
}
route_legacy_pages: {
// NOTE: If there's no account theme there is no special target for keycloak 24 and up so we create
// the pages anyway. If there is an account pages, since we know that account-v1 is only support keycloak

View File

@ -1,5 +1,4 @@
import { assert } from "tsafe/assert";
import { exclude } from "tsafe/exclude";
import {
keycloakAccountV1Versions,
keycloakThemeAdditionalInfoExtensionVersions
@ -7,32 +6,29 @@ import {
import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar";
import { buildJar, BuildContextLike as BuildContextLike_buildJar } from "./buildJar";
import type { BuildContext } from "../../shared/buildContext";
import { getJarFileBasename } from "../../shared/getJarFileBasename";
import { readMetaInfKeycloakThemes_fromResourcesDirPath } from "../../shared/metaInfKeycloakThemes";
import { accountV1ThemeName } from "../../shared/constants";
export type BuildContextLike = BuildContextLike_buildJar & {
projectDirPath: string;
keycloakifyBuildDirPath: string;
recordIsImplementedByThemeType: BuildContext["recordIsImplementedByThemeType"];
jarTargets: BuildContext["jarTargets"];
};
assert<BuildContext extends BuildContextLike ? true : false>();
export async function buildJars(params: {
resourcesDirPath: string;
onlyBuildJarFileBasename: string | undefined;
buildContext: BuildContextLike;
}): Promise<void> {
const { onlyBuildJarFileBasename, resourcesDirPath, buildContext } = params;
const { resourcesDirPath, buildContext } = params;
const doesImplementAccountTheme = readMetaInfKeycloakThemes_fromResourcesDirPath({
resourcesDirPath
}).themes.some(({ name }) => name === accountV1ThemeName);
const doesImplementAccountTheme = buildContext.recordIsImplementedByThemeType.account;
await Promise.all(
keycloakAccountV1Versions
.map(keycloakAccountV1Version =>
keycloakThemeAdditionalInfoExtensionVersions
.map(keycloakThemeAdditionalInfoExtensionVersion => {
keycloakThemeAdditionalInfoExtensionVersions.map(
keycloakThemeAdditionalInfoExtensionVersion => {
const keycloakVersionRange = getKeycloakVersionRangeForJar({
doesImplementAccountTheme,
keycloakAccountV1Version,
@ -43,47 +39,25 @@ export async function buildJars(params: {
return undefined;
}
return {
keycloakThemeAdditionalInfoExtensionVersion,
keycloakVersionRange
};
})
.filter(exclude(undefined))
.map(
({
keycloakThemeAdditionalInfoExtensionVersion,
keycloakVersionRange
}) => {
const { jarFileBasename } = getJarFileBasename({
keycloakVersionRange
});
const jarTarget = buildContext.jarTargets.find(
jarTarget =>
jarTarget.keycloakVersionRange === keycloakVersionRange
);
if (
onlyBuildJarFileBasename !== undefined &&
onlyBuildJarFileBasename !== jarFileBasename
) {
if (jarTarget === undefined) {
return undefined;
}
return {
keycloakThemeAdditionalInfoExtensionVersion,
jarFileBasename
};
}
)
.filter(exclude(undefined))
.map(
({
keycloakThemeAdditionalInfoExtensionVersion,
jarFileBasename
}) =>
buildJar({
const { jarFileBasename } = jarTarget;
return buildJar({
jarFileBasename,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion,
resourcesDirPath,
buildContext
})
});
}
)
)
.flat()

View File

@ -305,12 +305,14 @@ function decodeHtmlEntities(htmlStr){
</#if>
<#if are_same_path(path, ["totp", "policy", "getAlgorithmKey"])>
<#local returnValue = "">
<#local returnValue = "error">
<#if mode?? && mode = "manual">
<#attempt>
<#local returnValue = totp.policy.getAlgorithmKey()>
<#recover>
<#return "ABORT: Couldn't evaluate totp.policy.getAlgorithmKey()">
</#attempt>
</#if>
<#return 'function(){ return "' + returnValue + '"; }'>
</#if>

View File

@ -1,6 +1,6 @@
import { transformCodebase } from "../../tools/transformCodebase";
import * as fs from "fs";
import { join as pathJoin, resolve as pathResolve } from "path";
import { join as pathJoin, resolve as pathResolve, relative as pathRelative } from "path";
import { replaceImportsInJsCode } from "../replacers/replaceImportsInJsCode";
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
import {
@ -16,7 +16,6 @@ import {
loginThemePageIds,
accountThemePageIds
} from "../../shared/constants";
import { isInside } from "../../tools/isInside";
import type { BuildContext } from "../../shared/buildContext";
import { assert, type Equals } from "tsafe/assert";
import {
@ -30,7 +29,6 @@ import {
bringInAccountV1,
type BuildContextLike as BuildContextLike_bringInAccountV1
} from "./bringInAccountV1";
import { getThemeSrcDirPath } from "../../shared/getThemeSrcDirPath";
import { rmSync } from "../../tools/fs.rmSync";
import { readThisNpmPackageVersion } from "../../tools/readThisNpmPackageVersion";
import {
@ -48,6 +46,8 @@ export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
projectDirPath: string;
projectBuildDirPath: string;
environmentVariables: { name: string; default: string }[];
recordIsImplementedByThemeType: BuildContext["recordIsImplementedByThemeType"];
themeSrcDirPath: string;
};
assert<BuildContext extends BuildContextLike ? true : false>();
@ -59,10 +59,6 @@ export async function generateResourcesForMainTheme(params: {
}): Promise<void> {
const { themeName, resourcesDirPath, buildContext } = params;
const { themeSrcDirPath } = getThemeSrcDirPath({
projectDirPath: buildContext.projectDirPath
});
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
const { themeType } = params;
return pathJoin(resourcesDirPath, "theme", themeName, themeType);
@ -70,19 +66,11 @@ export async function generateResourcesForMainTheme(params: {
const cssGlobalsToDefine: Record<string, string> = {};
const implementedThemeTypes: Record<ThemeType | "email", boolean> = {
login: false,
account: false,
email: false
};
for (const themeType of ["login", "account"] as const) {
if (!fs.existsSync(pathJoin(themeSrcDirPath, themeType))) {
if (!buildContext.recordIsImplementedByThemeType[themeType]) {
continue;
}
implementedThemeTypes[themeType] = true;
const themeTypeDirPath = getThemeTypeDirPath({ themeType });
apply_replacers_and_move_to_theme_resources: {
@ -95,7 +83,10 @@ export async function generateResourcesForMainTheme(params: {
// NOTE: Prevent accumulation of files in the assets dir, as names are hashed they pile up.
rmSync(destDirPath, { recursive: true, force: true });
if (themeType === "account" && implementedThemeTypes.login) {
if (
themeType === "account" &&
buildContext.recordIsImplementedByThemeType.login
) {
// NOTE: We prevent doing it twice, it has been done for the login theme.
transformCodebase({
@ -112,25 +103,32 @@ export async function generateResourcesForMainTheme(params: {
break apply_replacers_and_move_to_theme_resources;
}
{
const dirPath = pathJoin(
buildContext.projectBuildDirPath,
keycloak_resources
);
if (fs.existsSync(dirPath)) {
assert(buildContext.bundler === "webpack");
throw new Error(
[
`Keycloakify build error: The ${keycloak_resources} 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`,
`For example: \`"build": "... && rimraf ${pathRelative(buildContext.projectDirPath, dirPath)}"\``
].join(" ")
);
}
}
transformCodebase({
srcDirPath: buildContext.projectBuildDirPath,
destDirPath,
transformSourceCode: ({ filePath, sourceCode }) => {
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
// This should not happen if users follow the new instruction setup but we keep it for retrocompatibility.
if (
isInside({
dirPath: pathJoin(
buildContext.projectBuildDirPath,
keycloak_resources
),
filePath
})
) {
return undefined;
}
if (/\.css?$/i.test(filePath)) {
if (filePath.endsWith(".css")) {
const {
cssGlobalsToDefine: cssGlobalsToDefineForThisFile,
fixedCssCode
@ -149,7 +147,7 @@ export async function generateResourcesForMainTheme(params: {
};
}
if (/\.js?$/i.test(filePath)) {
if (filePath.endsWith(".js")) {
const { fixedJsCode } = replaceImportsInJsCode({
jsCode: sourceCode.toString("utf8"),
buildContext
@ -175,7 +173,7 @@ export async function generateResourcesForMainTheme(params: {
keycloakifyVersion: readThisNpmPackageVersion(),
themeType,
fieldNames: readFieldNameUsage({
themeSrcDirPath,
themeSrcDirPath: buildContext.themeSrcDirPath,
themeType
})
});
@ -191,7 +189,7 @@ export async function generateResourcesForMainTheme(params: {
})(),
...readExtraPagesNames({
themeType,
themeSrcDirPath
themeSrcDirPath: buildContext.themeSrcDirPath
})
].forEach(pageId => {
const { ftlCode } = generateFtlFilesCode({ pageId });
@ -203,7 +201,7 @@ export async function generateResourcesForMainTheme(params: {
});
generateMessageProperties({
themeSrcDirPath,
themeSrcDirPath: buildContext.themeSrcDirPath,
themeType
}).forEach(({ languageTag, propertiesFileSource }) => {
const messagesDirPath = pathJoin(themeTypeDirPath, "messages");
@ -262,13 +260,11 @@ export async function generateResourcesForMainTheme(params: {
}
email: {
const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email");
if (!fs.existsSync(emailThemeSrcDirPath)) {
if (!buildContext.recordIsImplementedByThemeType.email) {
break email;
}
implementedThemeTypes.email = true;
const emailThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "email");
transformCodebase({
srcDirPath: emailThemeSrcDirPath,
@ -276,7 +272,7 @@ export async function generateResourcesForMainTheme(params: {
});
}
if (implementedThemeTypes.account) {
if (buildContext.recordIsImplementedByThemeType.account) {
await bringInAccountV1({
resourcesDirPath,
buildContext
@ -288,12 +284,12 @@ export async function generateResourcesForMainTheme(params: {
metaInfKeycloakThemes.themes.push({
name: themeName,
types: objectEntries(implementedThemeTypes)
types: objectEntries(buildContext.recordIsImplementedByThemeType)
.filter(([, isImplemented]) => isImplemented)
.map(([themeType]) => themeType)
});
if (implementedThemeTypes.account) {
if (buildContext.recordIsImplementedByThemeType.account) {
metaInfKeycloakThemes.themes.push({
name: accountV1ThemeName,
types: ["account"]
@ -302,7 +298,7 @@ export async function generateResourcesForMainTheme(params: {
writeMetaInfKeycloakThemes({
resourcesDirPath,
metaInfKeycloakThemes
getNewMetaInfKeycloakTheme: () => metaInfKeycloakThemes
});
}
}

View File

@ -1,10 +1,7 @@
import { join as pathJoin, extname as pathExtname, sep as pathSep } from "path";
import { transformCodebase } from "../../tools/transformCodebase";
import type { BuildContext } from "../../shared/buildContext";
import {
readMetaInfKeycloakThemes_fromResourcesDirPath,
writeMetaInfKeycloakThemes
} from "../../shared/metaInfKeycloakThemes";
import { writeMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
import { assert } from "tsafe/assert";
export type BuildContextLike = {
@ -34,8 +31,8 @@ export function generateResourcesForThemeVariant(params: {
Buffer.from(sourceCode)
.toString("utf-8")
.replace(
`out["themeName"] = "${themeName}";`,
`out["themeName"] = "${themeVariantName}";`
`kcContext.themeName = "${themeName}";`,
`kcContext.themeName = "${themeVariantName}";`
),
"utf8"
);
@ -49,16 +46,17 @@ export function generateResourcesForThemeVariant(params: {
}
});
{
const updatedMetaInfKeycloakThemes =
readMetaInfKeycloakThemes_fromResourcesDirPath({
resourcesDirPath
});
writeMetaInfKeycloakThemes({
resourcesDirPath,
getNewMetaInfKeycloakTheme: ({ metaInfKeycloakTheme }) => {
assert(metaInfKeycloakTheme !== undefined);
updatedMetaInfKeycloakThemes.themes.push({
const newMetaInfKeycloakTheme = metaInfKeycloakTheme;
newMetaInfKeycloakTheme.themes.push({
name: themeVariantName,
types: (() => {
const theme = updatedMetaInfKeycloakThemes.themes.find(
const theme = newMetaInfKeycloakTheme.themes.find(
({ name }) => name === themeName
);
assert(theme !== undefined);
@ -66,9 +64,7 @@ export function generateResourcesForThemeVariant(params: {
})()
});
writeMetaInfKeycloakThemes({
resourcesDirPath,
metaInfKeycloakThemes: updatedMetaInfKeycloakThemes
});
return newMetaInfKeycloakTheme;
}
});
}

View File

@ -3,10 +3,7 @@ import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path
import * as child_process from "child_process";
import * as fs from "fs";
import { getBuildContext } from "../shared/buildContext";
import {
vitePluginSubScriptEnvNames,
onlyBuildJarFileBasenameEnvName
} from "../shared/constants";
import { vitePluginSubScriptEnvNames } from "../shared/constants";
import { buildJars } from "./buildJars";
import type { CliCommandOptions } from "../main";
import chalk from "chalk";
@ -96,16 +93,17 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
cwd: buildContext.projectDirPath,
env: {
...process.env,
[vitePluginSubScriptEnvNames.runPostBuildScript]:
JSON.stringify(buildContext)
[vitePluginSubScriptEnvNames.runPostBuildScript]: JSON.stringify({
resourcesDirPath,
buildContext
})
}
});
}
await buildJars({
resourcesDirPath,
buildContext,
onlyBuildJarFileBasename: process.env[onlyBuildJarFileBasenameEnvName]
buildContext
});
rmSync(resourcesDirPath, { recursive: true });

View File

@ -5,9 +5,22 @@ import { getNpmWorkspaceRootDirPath } from "../tools/getNpmWorkspaceRootDirPath"
import type { CliCommandOptions } from "../main";
import { z } from "zod";
import * as fs from "fs";
import { assert, type Equals } from "tsafe";
import { assert, type Equals } from "tsafe/assert";
import * as child_process from "child_process";
import { vitePluginSubScriptEnvNames } from "./constants";
import {
vitePluginSubScriptEnvNames,
buildForKeycloakMajorVersionEnvName
} from "./constants";
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
import { exclude } from "tsafe";
import { crawl } from "../tools/crawl";
import { themeTypes } from "./constants";
import { objectFromEntries } from "tsafe/objectFromEntries";
import { objectEntries } from "tsafe/objectEntries";
import { type ThemeType } from "./constants";
import { id } from "tsafe/id";
import { symToStr } from "tsafe/symToStr";
import chalk from "chalk";
export type BuildContext = {
bundler: "vite" | "webpack";
@ -30,6 +43,12 @@ export type BuildContext = {
npmWorkspaceRootDirPath: string;
kcContextExclusionsFtlCode: string | undefined;
environmentVariables: { name: string; default: string }[];
themeSrcDirPath: string;
recordIsImplementedByThemeType: Readonly<Record<ThemeType | "email", boolean>>;
jarTargets: {
keycloakVersionRange: KeycloakVersionRange;
jarFileBasename: string;
}[];
};
export type BuildOptions = {
@ -41,8 +60,21 @@ export type BuildOptions = {
loginThemeResourcesFromKeycloakVersion?: string;
keycloakifyBuildDirPath?: string;
kcContextExclusionsFtl?: string;
keycloakVersionTargets?: BuildOptions.KeycloakVersionTargets;
};
export namespace BuildOptions {
export type KeycloakVersionTargets =
| ({ hasAccountTheme: true } & Record<
KeycloakVersionRange.WithAccountTheme,
string | boolean
>)
| ({ hasAccountTheme: false } & Record<
KeycloakVersionRange.WithoutAccountTheme,
string | boolean
>);
}
export type ResolvedViteConfig = {
buildDir: string;
publicDir: string;
@ -102,7 +134,7 @@ export function getBuildContext(params: {
})();
const parsedPackageJson = (() => {
type WebpackSpecificBuildOptions = {
type BuildOptions_packageJson = BuildOptions & {
projectBuildDirPath?: string;
};
@ -110,31 +142,16 @@ export function getBuildContext(params: {
name: string;
version?: string;
homepage?: string;
keycloakify?: {
themeName?: string | string[];
environmentVariables?: { name: string; default: string }[];
extraThemeProperties?: string[];
artifactId?: string;
groupId?: string;
loginThemeResourcesFromKeycloakVersion?: string;
keycloakifyBuildDirPath?: string;
kcContextExclusionsFtl?: string;
projectBuildDirPath?: string;
keycloakify?: BuildOptions_packageJson;
};
};
{
type Got = NonNullable<ParsedPackageJson["keycloakify"]>;
type Expected = BuildOptions & WebpackSpecificBuildOptions;
assert<Equals<Got, Expected>>();
}
const zParsedPackageJson = z.object({
name: z.string(),
version: z.string().optional(),
homepage: z.string().optional(),
keycloakify: z
.object({
keycloakify: id<z.ZodType<BuildOptions_packageJson>>(
(() => {
const zBuildOptions_packageJson = z.object({
extraThemeProperties: z.array(z.string()).optional(),
artifactId: z.string().optional(),
groupId: z.string().optional(),
@ -150,9 +167,52 @@ export function getBuildContext(params: {
})
)
.optional(),
themeName: z.union([z.string(), z.array(z.string())]).optional()
themeName: z.union([z.string(), z.array(z.string())]).optional(),
keycloakVersionTargets: id<
z.ZodType<BuildOptions.KeycloakVersionTargets>
>(
(() => {
const zKeycloakVersionTargets = z.union([
z.object({
hasAccountTheme: z.literal(true),
"21-and-below": z.union([
z.boolean(),
z.string()
]),
"23": z.union([z.boolean(), z.string()]),
"24": z.union([z.boolean(), z.string()]),
"25-and-above": z.union([z.boolean(), z.string()])
}),
z.object({
hasAccountTheme: z.literal(false),
"21-and-below": z.union([
z.boolean(),
z.string()
]),
"22-and-above": z.union([z.boolean(), z.string()])
})
.optional()
]);
{
type Got = z.infer<typeof zKeycloakVersionTargets>;
type Expected = BuildOptions.KeycloakVersionTargets;
assert<Equals<Got, Expected>>();
}
return zKeycloakVersionTargets;
})()
).optional()
});
{
type Got = z.infer<typeof zBuildOptions_packageJson>;
type Expected = BuildOptions_packageJson;
assert<Equals<Got, Expected>>();
}
return zBuildOptions_packageJson;
})()
).optional()
});
{
@ -173,6 +233,54 @@ export function getBuildContext(params: {
...resolvedViteConfig?.buildOptions
};
const { themeSrcDirPath } = (() => {
const srcDirPath = pathJoin(projectDirPath, "src");
const themeSrcDirPath: string | undefined = crawl({
dirPath: srcDirPath,
returnedPathsType: "relative to dirPath"
})
.map(fileRelativePath => {
for (const themeSrcDirBasename of ["keycloak-theme", "keycloak_theme"]) {
const split = fileRelativePath.split(themeSrcDirBasename);
if (split.length === 2) {
return pathJoin(srcDirPath, split[0] + themeSrcDirBasename);
}
}
return undefined;
})
.filter(exclude(undefined))[0];
if (themeSrcDirPath !== undefined) {
return { themeSrcDirPath };
}
for (const themeType of [...themeTypes, "email"]) {
if (!fs.existsSync(pathJoin(srcDirPath, themeType))) {
continue;
}
return { themeSrcDirPath: srcDirPath };
}
console.log(
chalk.red(
[
"Can't locate your keycloak theme source directory.",
"See: https://docs.keycloakify.dev/v/v10/keycloakify-in-my-app/collocation"
].join("\n")
)
);
process.exit(1);
})();
const recordIsImplementedByThemeType = objectFromEntries(
(["login", "account", "email"] as const).map(themeType => [
themeType,
fs.existsSync(pathJoin(themeSrcDirPath, themeType))
])
);
const themeNames = ((): [string, ...string[]] => {
if (buildOptions.themeName === undefined) {
return [
@ -218,8 +326,10 @@ export function getBuildContext(params: {
dependencyExpected: "keycloakify"
});
const bundler = resolvedViteConfig !== undefined ? "vite" : "webpack";
return {
bundler: resolvedViteConfig !== undefined ? "vite" : "webpack",
bundler,
themeVersion:
process.env.KEYCLOAKIFY_THEME_VERSION ?? parsedPackageJson.version ?? "0.0.0",
themeNames,
@ -349,6 +459,288 @@ export function getBuildContext(params: {
return buildOptions.kcContextExclusionsFtl;
})(),
environmentVariables: buildOptions.environmentVariables ?? []
environmentVariables: buildOptions.environmentVariables ?? [],
recordIsImplementedByThemeType,
themeSrcDirPath,
jarTargets: (() => {
const getDefaultJarFileBasename = (range: string) =>
`keycloak-theme-for-kc-${range}.jar`;
build_for_specific_keycloak_major_version: {
const buildForKeycloakMajorVersionNumber = (() => {
const envValue = process.env[buildForKeycloakMajorVersionEnvName];
if (envValue === undefined) {
return undefined;
}
const major = parseInt(envValue);
assert(!isNaN(major));
return major;
})();
if (buildForKeycloakMajorVersionNumber === undefined) {
break build_for_specific_keycloak_major_version;
}
const keycloakVersionRange: KeycloakVersionRange = (() => {
const doesImplementAccountTheme =
recordIsImplementedByThemeType.account;
if (doesImplementAccountTheme) {
const keycloakVersionRange = (() => {
if (buildForKeycloakMajorVersionNumber <= 21) {
return "21-and-below" as const;
}
assert(buildForKeycloakMajorVersionNumber !== 22);
if (buildForKeycloakMajorVersionNumber === 23) {
return "23" as const;
}
if (buildForKeycloakMajorVersionNumber === 24) {
return "24" as const;
}
return "25-and-above" as const;
})();
assert<
Equals<
typeof keycloakVersionRange,
KeycloakVersionRange.WithAccountTheme
>
>();
return keycloakVersionRange;
} else {
const keycloakVersionRange = (() => {
if (buildForKeycloakMajorVersionNumber <= 21) {
return "21-and-below" as const;
}
return "22-and-above" as const;
})();
assert<
Equals<
typeof keycloakVersionRange,
KeycloakVersionRange.WithoutAccountTheme
>
>();
return keycloakVersionRange;
}
})();
const jarFileBasename = (() => {
use_custom_jar_basename: {
const { keycloakVersionTargets } = buildOptions;
if (keycloakVersionTargets === undefined) {
break use_custom_jar_basename;
}
const entry = objectEntries(keycloakVersionTargets).find(
([keycloakVersionRange_entry]) =>
keycloakVersionRange_entry === keycloakVersionRange
);
if (entry === undefined) {
break use_custom_jar_basename;
}
const maybeJarFileBasename = entry[1];
if (typeof maybeJarFileBasename !== "string") {
break use_custom_jar_basename;
}
return maybeJarFileBasename;
}
return getDefaultJarFileBasename(keycloakVersionRange);
})();
return [
{
keycloakVersionRange,
jarFileBasename
}
];
}
const jarTargets_default = (() => {
const jarTargets: BuildContext["jarTargets"] = [];
if (recordIsImplementedByThemeType.account) {
for (const keycloakVersionRange of [
"21-and-below",
"23",
"24",
"25-and-above"
] as const) {
assert<
Equals<
typeof keycloakVersionRange,
KeycloakVersionRange.WithAccountTheme
>
>(true);
jarTargets.push({
keycloakVersionRange,
jarFileBasename:
getDefaultJarFileBasename(keycloakVersionRange)
});
}
} else {
for (const keycloakVersionRange of [
"21-and-below",
"22-and-above"
] as const) {
assert<
Equals<
typeof keycloakVersionRange,
KeycloakVersionRange.WithoutAccountTheme
>
>(true);
jarTargets.push({
keycloakVersionRange,
jarFileBasename:
getDefaultJarFileBasename(keycloakVersionRange)
});
}
}
return jarTargets;
})();
if (buildOptions.keycloakVersionTargets === undefined) {
return jarTargets_default;
}
if (
buildOptions.keycloakVersionTargets.hasAccountTheme !==
recordIsImplementedByThemeType.account
) {
console.log(
chalk.red(
(() => {
const { keycloakVersionTargets } = buildOptions;
let message = `Bad ${symToStr({ keycloakVersionTargets })} configuration.\n`;
if (keycloakVersionTargets.hasAccountTheme) {
message +=
"Your codebase does not seem to implement an account theme ";
} else {
message += "Your codebase implements an account theme ";
}
const { hasAccountTheme } = keycloakVersionTargets;
message += `but you have set ${symToStr({ keycloakVersionTargets })}.${symToStr({ hasAccountTheme })}`;
message += ` to ${hasAccountTheme} in your `;
message += (() => {
switch (bundler) {
case "vite":
return "vite.config.ts";
case "webpack":
return "package.json";
}
assert<Equals<typeof bundler, never>>(false);
})();
message += `. Please set it to ${!hasAccountTheme} `;
message +=
"and fill up the relevant keycloak version ranges.\n";
message += "Example:\n";
message += JSON.stringify(
id<Pick<BuildOptions, "keycloakVersionTargets">>({
keycloakVersionTargets: {
hasAccountTheme:
recordIsImplementedByThemeType.account,
...objectFromEntries(
jarTargets_default.map(
({
keycloakVersionRange,
jarFileBasename
}) => [
keycloakVersionRange,
jarFileBasename
]
)
)
}
}),
null,
2
);
return message;
})()
)
);
process.exit(1);
}
const jarTargets: BuildContext["jarTargets"] = [];
const { hasAccountTheme, ...rest } = buildOptions.keycloakVersionTargets;
for (const [keycloakVersionRange, jarNameOrBoolean] of objectEntries(rest)) {
if (jarNameOrBoolean === false) {
continue;
}
if (jarNameOrBoolean === true) {
jarTargets.push({
keycloakVersionRange: keycloakVersionRange,
jarFileBasename: getDefaultJarFileBasename(keycloakVersionRange)
});
continue;
}
const jarFileBasename = jarNameOrBoolean;
if (!jarFileBasename.endsWith(".jar")) {
console.log(
chalk.red(`Bad ${jarFileBasename} should end with '.jar'\n`)
);
process.exit(1);
}
if (jarFileBasename.includes("/") || jarFileBasename.includes("\\")) {
console.log(
chalk.red(
[
`Invalid ${jarFileBasename}. It's not supposed to be a path,`,
`Only the basename of the jar file is expected.`,
`Example: keycloak-theme.jar`
].join(" ")
)
);
process.exit(1);
}
jarTargets.push({
keycloakVersionRange: keycloakVersionRange,
jarFileBasename: jarNameOrBoolean
});
}
if (jarTargets.length === 0) {
console.log(
chalk.red(
"All jar targets are disabled. Please enable at least one jar target."
)
);
process.exit(1);
}
return jarTargets;
})()
};
}

View File

@ -15,7 +15,8 @@ export const vitePluginSubScriptEnvNames = {
resolveViteConfig: "KEYCLOAKIFY_RESOLVE_VITE_CONFIG"
} as const;
export const onlyBuildJarFileBasenameEnvName = "KEYCLOAKIFY_ONLY_BUILD_JAR_FILE_BASENAME";
export const buildForKeycloakMajorVersionEnvName =
"KEYCLOAKIFY_BUILD_FOR_KEYCLOAK_MAJOR_VERSION";
export const loginThemePageIds = [
"login.ftl",

View File

@ -3,7 +3,6 @@ import { type BuildContext } from "./buildContext";
import { assert } from "tsafe/assert";
import { lastKeycloakVersionWithAccountV1 } from "./constants";
import { downloadAndExtractArchive } from "../tools/downloadAndExtractArchive";
import { isInside } from "../tools/isInside";
export type BuildContextLike = {
cacheDirPath: string;
@ -18,27 +17,25 @@ export async function downloadKeycloakDefaultTheme(params: {
}): Promise<{ defaultThemeDirPath: string }> {
const { keycloakVersion, buildContext } = params;
let kcNodeModulesKeepFilePaths: string[] | undefined = undefined;
let kcNodeModulesKeepFilePaths_lastAccountV1: string[] | undefined = undefined;
const { extractedDirPath } = await downloadAndExtractArchive({
url: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
cacheDirPath: buildContext.cacheDirPath,
npmWorkspaceRootDirPath: buildContext.npmWorkspaceRootDirPath,
uniqueIdOfOnOnArchiveFile: "downloadKeycloakDefaultTheme",
onArchiveFile: async params => {
if (!isInside({ dirPath: "theme", filePath: params.fileRelativePath })) {
const fileRelativePath = pathRelative("theme", params.fileRelativePath);
if (fileRelativePath.startsWith("..")) {
return;
}
const { readFile, writeFile } = params;
const fileRelativePath = pathRelative("theme", params.fileRelativePath);
skip_keycloak_v2: {
if (
!isInside({
dirPath: pathJoin("keycloak.v2"),
filePath: fileRelativePath
})
) {
if (!fileRelativePath.startsWith(pathJoin("keycloak.v2"))) {
break skip_keycloak_v2;
}
@ -50,6 +47,84 @@ export async function downloadKeycloakDefaultTheme(params: {
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: {
if (
!fileRelativePath.startsWith(
pathJoin("keycloak", "common", "resources", "node_modules")
)
) {
break skip_node_modules;
}
if (kcNodeModulesKeepFilePaths_lastAccountV1 === undefined) {
kcNodeModulesKeepFilePaths_lastAccountV1 = [
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"
)
];
}
for (const keepPath of kcNodeModulesKeepFilePaths_lastAccountV1) {
if (fileRelativePath.endsWith(keepPath)) {
break skip_node_modules;
}
}
return;
}
patch_account_css: {
if (
fileRelativePath !==
@ -70,69 +145,6 @@ export async function downloadKeycloakDefaultTheme(params: {
return;
}
skip_web_modules: {
if (
!isInside({
dirPath: pathJoin(
"keycloak",
"common",
"resources",
"web_modules"
),
filePath: fileRelativePath
})
) {
break skip_web_modules;
}
return;
}
skip_unused_node_modules: {
const nodeModulesDirPath = pathJoin(
"keycloak",
"common",
"resources",
"node_modules"
);
if (
!isInside({
dirPath: nodeModulesDirPath,
filePath: fileRelativePath
})
) {
break skip_unused_node_modules;
}
const toKeepPrefixes = [
...[
"patternfly.min.css",
"patternfly-additions.min.css",
"patternfly-additions.min.css"
].map(fileBasename =>
pathJoin(
nodeModulesDirPath,
"patternfly",
"dist",
"css",
fileBasename
)
),
pathJoin(nodeModulesDirPath, "patternfly", "dist", "fonts")
];
if (
toKeepPrefixes.find(prefix =>
fileRelativePath.startsWith(prefix)
) !== undefined
) {
break skip_unused_node_modules;
}
return;
}
}
skip_unused_resources: {
@ -140,61 +152,76 @@ export async function downloadKeycloakDefaultTheme(params: {
break skip_unused_resources;
}
for (const dirBasename of [
"@patternfly-v5",
"@rollup",
"rollup",
"react",
"react-dom",
"shx",
".pnpm"
]) {
skip_node_modules: {
if (
isInside({
dirPath: pathJoin(
"keycloak",
"common",
"resources",
"node_modules",
dirBasename
),
filePath: fileRelativePath
})
!fileRelativePath.startsWith(
pathJoin("keycloak", "common", "resources", "node_modules")
)
) {
return;
break skip_node_modules;
}
if (kcNodeModulesKeepFilePaths === undefined) {
kcNodeModulesKeepFilePaths = [
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",
"fontawesome-webfont.woff2"
),
pathJoin("jquery", "dist", "jquery.min.js")
];
}
for (const keepPath of kcNodeModulesKeepFilePaths) {
if (fileRelativePath.endsWith(keepPath)) {
break skip_node_modules;
}
}
for (const dirBasename of ["react", "react-dom"]) {
if (
isInside({
dirPath: pathJoin(
"keycloak",
"common",
"resources",
"vendor",
dirBasename
),
filePath: fileRelativePath
})
) {
return;
}
skip_vendor: {
if (
!fileRelativePath.startsWith(
pathJoin("keycloak", "common", "resources", "vendor")
)
) {
break skip_vendor;
}
return;
}
skip_rollup_config: {
if (
isInside({
dirPath: pathJoin(
"keycloak",
"common",
"resources",
"node_modules",
"@patternfly",
"react-core"
),
filePath: fileRelativePath
})
fileRelativePath !==
pathJoin("keycloak", "common", "resources", "rollup.config.js")
) {
break skip_rollup_config;
}
return;
}
}

View File

@ -1,6 +1,5 @@
import { assert } from "tsafe/assert";
import type { BuildContext } from "./buildContext";
import { getThemeSrcDirPath } from "./getThemeSrcDirPath";
import * as fs from "fs/promises";
import { join as pathJoin } from "path";
import { existsAsync } from "../tools/fs.existsAsync";
@ -9,6 +8,7 @@ export type BuildContextLike = {
projectDirPath: string;
themeNames: string[];
environmentVariables: { name: string; default: string }[];
themeSrcDirPath: string;
};
assert<BuildContext extends BuildContextLike ? true : false>();
@ -18,11 +18,7 @@ export async function generateKcGenTs(params: {
}): Promise<void> {
const { buildContext } = params;
const { themeSrcDirPath } = getThemeSrcDirPath({
projectDirPath: buildContext.projectDirPath
});
const filePath = pathJoin(themeSrcDirPath, "kc.gen.ts");
const filePath = pathJoin(buildContext.themeSrcDirPath, "kc.gen.ts");
const currentContent = (await existsAsync(filePath))
? await fs.readFile(filePath)

View File

@ -1,11 +0,0 @@
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
export function getJarFileBasename(params: {
keycloakVersionRange: KeycloakVersionRange;
}) {
const { keycloakVersionRange } = params;
const jarFileBasename = `keycloak-theme-for-kc-${keycloakVersionRange}.jar`;
return { jarFileBasename };
}

View File

@ -1,50 +0,0 @@
import * as fs from "fs";
import { exclude } from "tsafe";
import { crawl } from "../tools/crawl";
import { join as pathJoin } from "path";
import { themeTypes } from "./constants";
const themeSrcDirBasenames = ["keycloak-theme", "keycloak_theme"];
/** Can't catch error, if the directory isn't found, this function will just exit the process with an error message. */
export function getThemeSrcDirPath(params: { projectDirPath: string }) {
const { projectDirPath } = params;
const srcDirPath = pathJoin(projectDirPath, "src");
const themeSrcDirPath: string | undefined = crawl({
dirPath: srcDirPath,
returnedPathsType: "relative to dirPath"
})
.map(fileRelativePath => {
for (const themeSrcDirBasename of themeSrcDirBasenames) {
const split = fileRelativePath.split(themeSrcDirBasename);
if (split.length === 2) {
return pathJoin(srcDirPath, split[0] + themeSrcDirBasename);
}
}
return undefined;
})
.filter(exclude(undefined))[0];
if (themeSrcDirPath !== undefined) {
return { themeSrcDirPath };
}
for (const themeType of [...themeTypes, "email"]) {
if (!fs.existsSync(pathJoin(srcDirPath, themeType))) {
continue;
}
return { themeSrcDirPath: srcDirPath };
}
console.error(
[
"Can't locate your theme source directory. It should be either: ",
"src/ or src/keycloak-theme or src/keycloak_theme.",
"Example in the starter: https://github.com/keycloakify/keycloakify-starter/tree/main/src/keycloak-theme"
].join("\n")
);
process.exit(-1);
}

View File

@ -1,84 +1,40 @@
import { join as pathJoin, dirname as pathDirname } from "path";
import type { ThemeType } from "./constants";
import * as fs from "fs";
import { assert } from "tsafe/assert";
import { extractArchive } from "../tools/extractArchive";
export type MetaInfKeycloakTheme = {
themes: { name: string; types: (ThemeType | "email")[] }[];
};
export function getMetaInfKeycloakThemesJsonFilePath(params: {
resourcesDirPath: string;
}) {
const { resourcesDirPath } = params;
return pathJoin(
resourcesDirPath === "." ? "" : resourcesDirPath,
"META-INF",
"keycloak-themes.json"
);
}
export function readMetaInfKeycloakThemes_fromResourcesDirPath(params: {
resourcesDirPath: string;
}) {
const { resourcesDirPath } = params;
return JSON.parse(
fs
.readFileSync(
getMetaInfKeycloakThemesJsonFilePath({
resourcesDirPath
})
)
.toString("utf8")
) as MetaInfKeycloakTheme;
}
export async function readMetaInfKeycloakThemes_fromJar(params: {
jarFilePath: string;
}): Promise<MetaInfKeycloakTheme> {
const { jarFilePath } = params;
let metaInfKeycloakThemes: MetaInfKeycloakTheme | undefined = undefined;
await extractArchive({
archiveFilePath: jarFilePath,
onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => {
if (
relativeFilePathInArchive ===
getMetaInfKeycloakThemesJsonFilePath({ resourcesDirPath: "." })
) {
metaInfKeycloakThemes = JSON.parse((await readFile()).toString("utf8"));
earlyExit();
}
}
});
assert(metaInfKeycloakThemes !== undefined);
return metaInfKeycloakThemes;
}
export function writeMetaInfKeycloakThemes(params: {
resourcesDirPath: string;
metaInfKeycloakThemes: MetaInfKeycloakTheme;
getNewMetaInfKeycloakTheme: (params: {
metaInfKeycloakTheme: MetaInfKeycloakTheme | undefined;
}) => MetaInfKeycloakTheme;
}) {
const { resourcesDirPath, metaInfKeycloakThemes } = params;
const { resourcesDirPath, getNewMetaInfKeycloakTheme } = params;
const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({
resourcesDirPath
const filePath = pathJoin(resourcesDirPath, "META-INF", "keycloak-themes.json");
const currentMetaInfKeycloakTheme = !fs.existsSync(filePath)
? undefined
: (JSON.parse(
fs.readFileSync(filePath).toString("utf8")
) as MetaInfKeycloakTheme);
const newMetaInfKeycloakThemes = getNewMetaInfKeycloakTheme({
metaInfKeycloakTheme: currentMetaInfKeycloakTheme
});
{
const dirPath = pathDirname(metaInfKeycloakThemesJsonPath);
const dirPath = pathDirname(filePath);
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
fs.writeFileSync(
metaInfKeycloakThemesJsonPath,
Buffer.from(JSON.stringify(metaInfKeycloakThemes, null, 2), "utf8")
filePath,
Buffer.from(JSON.stringify(newMetaInfKeycloakThemes, null, 2), "utf8")
);
}

View File

@ -1,4 +1,4 @@
import { onlyBuildJarFileBasenameEnvName } from "../shared/constants";
import { buildForKeycloakMajorVersionEnvName } from "../shared/constants";
import * as child_process from "child_process";
import { Deferred } from "evt/tools/Deferred";
import { assert } from "tsafe/assert";
@ -14,10 +14,10 @@ export type BuildContextLike = {
assert<BuildContext extends BuildContextLike ? true : false>();
export async function keycloakifyBuild(params: {
onlyBuildJarFileBasename: string | undefined;
buildForKeycloakMajorVersionNumber: number;
buildContext: BuildContextLike;
}): Promise<{ isKeycloakifyBuildSuccess: boolean }> {
const { buildContext, onlyBuildJarFileBasename } = params;
const { buildForKeycloakMajorVersionNumber, buildContext } = params;
const dResult = new Deferred<{ isSuccess: boolean }>();
@ -25,7 +25,7 @@ export async function keycloakifyBuild(params: {
cwd: buildContext.projectDirPath,
env: {
...process.env,
[onlyBuildJarFileBasenameEnvName]: onlyBuildJarFileBasename
[buildForKeycloakMajorVersionEnvName]: `${buildForKeycloakMajorVersionNumber}`
},
shell: true
});

View File

@ -2,12 +2,9 @@ import { getBuildContext } from "../shared/buildContext";
import { exclude } from "tsafe/exclude";
import type { CliCommandOptions as CliCommandOptions_common } from "../main";
import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
import { readMetaInfKeycloakThemes_fromJar } from "../shared/metaInfKeycloakThemes";
import { accountV1ThemeName, containerName } from "../shared/constants";
import { SemVer } from "../tools/SemVer";
import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange";
import { getJarFileBasename } from "../shared/getJarFileBasename";
import { assert, type Equals } from "tsafe/assert";
import { assert } from "tsafe/assert";
import * as fs from "fs";
import {
join as pathJoin,
@ -91,71 +88,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
const buildContext = getBuildContext({ cliCommandOptions });
{
const { isAppBuildSuccess } = await appBuild({
buildContext
});
if (!isAppBuildSuccess) {
console.log(
chalk.red(
`App build failed, exiting. Try running 'yarn build-keycloak-theme' and see what's wrong.`
)
);
process.exit(1);
}
const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
onlyBuildJarFileBasename: undefined,
buildContext
});
if (!isKeycloakifyBuildSuccess) {
console.log(
chalk.red(
`Keycloakify build failed, exiting. Try running 'yarn build-keycloak-theme' and see what's wrong.`
)
);
process.exit(1);
}
}
const { doesImplementAccountTheme } = await (async () => {
const latestJarFilePath = fs
.readdirSync(buildContext.keycloakifyBuildDirPath)
.filter(fileBasename => fileBasename.endsWith(".jar"))
.map(fileBasename =>
pathJoin(buildContext.keycloakifyBuildDirPath, fileBasename)
)
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0];
assert(latestJarFilePath !== undefined);
const metaInfKeycloakThemes = await readMetaInfKeycloakThemes_fromJar({
jarFilePath: latestJarFilePath
});
const mainThemeEntry = metaInfKeycloakThemes.themes.find(
({ name }) => name === buildContext.themeNames[0]
);
assert(mainThemeEntry !== undefined);
const doesImplementAccountTheme = mainThemeEntry.types.includes("account");
return { doesImplementAccountTheme };
})();
const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } =
await (async function getKeycloakMajor(): Promise<{
keycloakVersion: string;
keycloakMajorNumber: number;
}> {
const { keycloakVersion } = await (async () => {
if (cliCommandOptions.keycloakVersion !== undefined) {
return {
keycloakVersion: cliCommandOptions.keycloakVersion,
keycloakMajorNumber: SemVer.parse(cliCommandOptions.keycloakVersion)
.major
keycloakMajorNumber: SemVer.parse(cliCommandOptions.keycloakVersion).major
};
}
@ -171,69 +108,49 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
console.log(`${keycloakVersion}`);
const keycloakMajorNumber = SemVer.parse(keycloakVersion).major;
return { keycloakVersion };
})();
if (doesImplementAccountTheme && keycloakMajorNumber === 22) {
const keycloakMajorVersionNumber = SemVer.parse(keycloakVersion).major;
{
const { isAppBuildSuccess } = await appBuild({
buildContext
});
if (!isAppBuildSuccess) {
console.log(
[
"Unfortunately, Keycloakify themes that implements an account theme do not work on Keycloak 22",
"Please select any other Keycloak version"
].join(" ")
chalk.red(
`App build failed, exiting. Try running 'npm run build' and see what's wrong.`
)
);
return getKeycloakMajor();
process.exit(1);
}
return { keycloakVersion, keycloakMajorNumber };
})();
const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
buildForKeycloakMajorVersionNumber: keycloakMajorVersionNumber,
buildContext
});
const keycloakVersionRange: KeycloakVersionRange = (() => {
if (doesImplementAccountTheme) {
const keycloakVersionRange = (() => {
if (keycloakMajorVersionNumber <= 21) {
return "21-and-below" as const;
if (!isKeycloakifyBuildSuccess) {
console.log(
chalk.red(
`Keycloakify build failed, exiting. Try running 'npx keycloakify build' and see what's wrong.`
)
);
process.exit(1);
}
}
assert(keycloakMajorVersionNumber !== 22);
const jarFilePath = fs
.readdirSync(buildContext.keycloakifyBuildDirPath)
.filter(fileBasename => fileBasename.endsWith(".jar"))
.map(fileBasename => pathJoin(buildContext.keycloakifyBuildDirPath, fileBasename))
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0];
if (keycloakMajorVersionNumber === 23) {
return "23" as const;
}
assert(jarFilePath !== undefined);
if (keycloakMajorVersionNumber === 24) {
return "24" as const;
}
return "25-and-above" as const;
})();
assert<
Equals<typeof keycloakVersionRange, KeycloakVersionRange.WithAccountTheme>
>();
return keycloakVersionRange;
} else {
const keycloakVersionRange = (() => {
if (keycloakMajorVersionNumber <= 21) {
return "21-and-below" as const;
}
return "22-and-above" as const;
})();
assert<
Equals<
typeof keycloakVersionRange,
KeycloakVersionRange.WithoutAccountTheme
>
>();
return keycloakVersionRange;
}
})();
const { jarFileBasename } = getJarFileBasename({ keycloakVersionRange });
console.log(`Using Keycloak ${chalk.bold(jarFileBasename)}`);
console.log(`Using ${chalk.bold(pathBasename(jarFilePath))}`);
const realmJsonFilePath = await (async () => {
if (cliCommandOptions.realmJsonFilePath !== undefined) {
@ -319,8 +236,6 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
return filePath;
})();
const jarFilePath = pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename);
async function extractThemeResourcesFromJar() {
await extractArchive({
archiveFilePath: jarFilePath,
@ -346,7 +261,10 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
await extractThemeResourcesFromJar();
const jarFilePath_cacheDir = pathJoin(buildContext.cacheDirPath, jarFileBasename);
const jarFilePath_cacheDir = pathJoin(
buildContext.cacheDirPath,
pathBasename(jarFilePath)
);
fs.copyFileSync(jarFilePath, jarFilePath_cacheDir);
@ -448,6 +366,10 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
console.log(
[
"",
`The ftl files from ${chalk.bold(
`.${pathSep}${pathRelative(process.cwd(), pathJoin(buildContext.keycloakifyBuildDirPath, "theme"))}`
)} are mounted in the Keycloak container.`,
"",
`Keycloak Admin console: ${chalk.cyan.bold(
`http://localhost:${cliCommandOptions.port}`
@ -488,7 +410,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
}
const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
onlyBuildJarFileBasename: jarFileBasename,
buildForKeycloakMajorVersionNumber: keycloakMajorVersionNumber,
buildContext
});

View File

@ -44,11 +44,12 @@ export function keycloakify(params?: Params) {
break run_post_build_script_case;
}
const buildContext = JSON.parse(envValue) as BuildContext;
const { buildContext, resourcesDirPath } = JSON.parse(envValue) as {
buildContext: BuildContext;
resourcesDirPath: string;
};
process.chdir(
pathJoin(buildContext.keycloakifyBuildDirPath, "resources")
);
process.chdir(resourcesDirPath);
await postBuild?.(buildContext);

262
yarn.lock
View File

@ -1354,13 +1354,6 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@cspotcode/source-map-support@^0.8.0":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@design-systems/utils@2.12.0":
version "2.12.0"
resolved "https://registry.yarnpkg.com/@design-systems/utils/-/utils-2.12.0.tgz#955c108be07cb8f01532207cbfea8f848fa760c9"
@ -1557,116 +1550,231 @@
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
"@esbuild/aix-ppc64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
"@esbuild/android-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
"@esbuild/android-arm64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
"@esbuild/android-arm@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
"@esbuild/android-arm@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
"@esbuild/android-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
"@esbuild/android-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
"@esbuild/darwin-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
"@esbuild/darwin-arm64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
"@esbuild/darwin-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0"
integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
"@esbuild/darwin-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
"@esbuild/freebsd-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
"@esbuild/freebsd-arm64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
"@esbuild/freebsd-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
"@esbuild/freebsd-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
"@esbuild/linux-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
"@esbuild/linux-arm64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
"@esbuild/linux-arm@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
"@esbuild/linux-arm@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
"@esbuild/linux-ia32@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
"@esbuild/linux-ia32@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
"@esbuild/linux-loong64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
"@esbuild/linux-loong64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
"@esbuild/linux-mips64el@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
"@esbuild/linux-mips64el@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
"@esbuild/linux-ppc64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
"@esbuild/linux-ppc64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
"@esbuild/linux-riscv64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
"@esbuild/linux-riscv64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
"@esbuild/linux-s390x@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
"@esbuild/linux-s390x@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
"@esbuild/linux-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
"@esbuild/linux-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
"@esbuild/netbsd-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
"@esbuild/netbsd-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
"@esbuild/openbsd-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
"@esbuild/openbsd-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
"@esbuild/sunos-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
"@esbuild/sunos-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
"@esbuild/win32-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
"@esbuild/win32-arm64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
"@esbuild/win32-ia32@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
"@esbuild/win32-ia32@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
"@esbuild/win32-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
"@esbuild/win32-x64@0.21.5":
version "0.21.5"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c"
integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@ -1768,11 +1876,6 @@
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
"@jridgewell/resolve-uri@^3.1.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
@ -1806,14 +1909,6 @@
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@0.3.9":
version "0.3.9"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.18"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6"
@ -3110,26 +3205,6 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
"@tsconfig/node12@^1.0.7":
version "1.0.11"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
"@tsconfig/node14@^1.0.0":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
"@tsconfig/node16@^1.0.2":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
"@types/aria-query@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.1.tgz#3286741fb8f1e1580ac28784add4c7a1d49bdfbc"
@ -3839,11 +3914,6 @@ acorn-walk@^7.2.0:
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn-walk@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa"
@ -3864,7 +3934,7 @@ acorn@^8.11.3:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1:
acorn@^8.5.0, acorn@^8.7.1:
version "8.8.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
@ -4072,11 +4142,6 @@ are-we-there-yet@^2.0.0:
delegates "^1.0.0"
readable-stream "^3.6.0"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -5499,11 +5564,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^6.0.0:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@ -5829,11 +5889,6 @@ diff-sequences@^29.6.3:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@ -6307,6 +6362,35 @@ esbuild@^0.20.1:
"@esbuild/win32-ia32" "0.20.2"
"@esbuild/win32-x64" "0.20.2"
esbuild@~0.21.4:
version "0.21.5"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
optionalDependencies:
"@esbuild/aix-ppc64" "0.21.5"
"@esbuild/android-arm" "0.21.5"
"@esbuild/android-arm64" "0.21.5"
"@esbuild/android-x64" "0.21.5"
"@esbuild/darwin-arm64" "0.21.5"
"@esbuild/darwin-x64" "0.21.5"
"@esbuild/freebsd-arm64" "0.21.5"
"@esbuild/freebsd-x64" "0.21.5"
"@esbuild/linux-arm" "0.21.5"
"@esbuild/linux-arm64" "0.21.5"
"@esbuild/linux-ia32" "0.21.5"
"@esbuild/linux-loong64" "0.21.5"
"@esbuild/linux-mips64el" "0.21.5"
"@esbuild/linux-ppc64" "0.21.5"
"@esbuild/linux-riscv64" "0.21.5"
"@esbuild/linux-s390x" "0.21.5"
"@esbuild/linux-x64" "0.21.5"
"@esbuild/netbsd-x64" "0.21.5"
"@esbuild/openbsd-x64" "0.21.5"
"@esbuild/sunos-x64" "0.21.5"
"@esbuild/win32-arm64" "0.21.5"
"@esbuild/win32-ia32" "0.21.5"
"@esbuild/win32-x64" "0.21.5"
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -7095,6 +7179,13 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
get-tsconfig@^4.7.5:
version "4.7.5"
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.5.tgz#5e012498579e9a6947511ed0cd403272c7acbbaf"
integrity sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==
dependencies:
resolve-pkg-maps "^1.0.0"
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@ -8770,11 +8861,6 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
make-fetch-happen@^11.0.3:
version "11.1.0"
resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-11.1.0.tgz#f26b05e89317e960b75fd5e080e40d40f8d7b2a5"
@ -10920,6 +11006,11 @@ resolve-from@^5.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
resolve-pkg-maps@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f"
integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@ -12169,25 +12260,6 @@ ts-dedent@^2.0.0, ts-dedent@^2.2.0:
resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5"
integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==
ts-node@^10.9.2:
version "10.9.2"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f"
integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==
dependencies:
"@cspotcode/source-map-support" "^0.8.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
ts-pnp@^1.1.6:
version "1.2.0"
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
@ -12236,6 +12308,16 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
tsx@^4.15.5:
version "4.15.5"
resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.15.5.tgz#9c1ddb10ed0035c595c9b3e00ae40a3647a94c82"
integrity sha512-iKi8jQ2VBmZ2kU/FkGkL2OSHBHsazsUzsdC/W/RwhKIEsIoZ1alCclZHP5jGfNHEaEWUJFM1GquzCf+4db3b0w==
dependencies:
esbuild "~0.21.4"
get-tsconfig "^4.7.5"
optionalDependencies:
fsevents "~2.3.3"
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@ -12646,11 +12728,6 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
v8-to-istanbul@^9.0.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265"
@ -13191,11 +13268,6 @@ yauzl@^2.10.0:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"