Compare commits
62 Commits
v11.4.0-rc
...
hmr_in_sta
Author | SHA1 | Date | |
---|---|---|---|
ec74ceef4d | |||
fd3261cdf1 | |||
b4b53d2552 | |||
0371d9ea7a | |||
73031e74ec | |||
f71ab4635f | |||
983db6780a | |||
ea22107b9b | |||
8e4a7fed9e | |||
30efd8fcf4 | |||
f4c4e92ca1 | |||
cfda99f5b0 | |||
5063b1c7ab | |||
955b6cac45 | |||
1fa3d6133c | |||
023939a064 | |||
de4490cf0f | |||
e0cda43724 | |||
d4ac67dba8 | |||
23f4b59559 | |||
4a7ba4a1c9 | |||
a3e765e1fc | |||
ee3614dbf1 | |||
8099ec1ffe | |||
2e2b0ab3ae | |||
a1f15f2f6b | |||
8fe74fe7ee | |||
232be50225 | |||
a00bb0c4db | |||
5517d6baf4 | |||
e2975503a4 | |||
1231c92198 | |||
64ca0bc0ca | |||
2bceb9385c | |||
954bc43c22 | |||
8c99aa4b9d | |||
884195d30d | |||
17dd726158 | |||
7ee30b6a42 | |||
397f8133bf | |||
c9abc6dc5c | |||
e78eafd1f1 | |||
e50f2bd692 | |||
ed0428bd55 | |||
2a126d65c5 | |||
30149ff1f2 | |||
32f471624a | |||
7f5eabb639 | |||
32fb1e2f71 | |||
7c3c6d3643 | |||
b6d2154d56 | |||
b8d4daf4c1 | |||
c03623875a | |||
c423e4cacc | |||
c593f5cb97 | |||
2ad36a8137 | |||
bccaddc2de | |||
97c12c8a12 | |||
b349a819ba | |||
792d4262c8 | |||
37a9046a40 | |||
5ad29d9f43 |
@ -309,6 +309,24 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"bug"
|
"bug"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "zvn2060",
|
||||||
|
"name": "HI_OuO",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/45450852?v=4",
|
||||||
|
"profile": "https://github.com/zvn2060",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "tripheo0412",
|
||||||
|
"name": "Tri Hoang",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/25382052?v=4",
|
||||||
|
"profile": "https://github.com/tripheo0412",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
@ -165,6 +165,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luca-peruzzo"><img src="https://avatars.githubusercontent.com/u/69015314?v=4?s=100" width="100px;" alt="Luca Peruzzo"/><br /><sub><b>Luca Peruzzo</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=luca-peruzzo" title="Code">💻</a> <a href="https://github.com/keycloakify/keycloakify/commits?author=luca-peruzzo" title="Tests">⚠️</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/luca-peruzzo"><img src="https://avatars.githubusercontent.com/u/69015314?v=4?s=100" width="100px;" alt="Luca Peruzzo"/><br /><sub><b>Luca Peruzzo</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=luca-peruzzo" title="Code">💻</a> <a href="https://github.com/keycloakify/keycloakify/commits?author=luca-peruzzo" title="Tests">⚠️</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nima70"><img src="https://avatars.githubusercontent.com/u/5094767?v=4?s=100" width="100px;" alt="Nima Shokouhfar"/><br /><sub><b>Nima Shokouhfar</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=nima70" title="Code">💻</a> <a href="https://github.com/keycloakify/keycloakify/commits?author=nima70" title="Tests">⚠️</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nima70"><img src="https://avatars.githubusercontent.com/u/5094767?v=4?s=100" width="100px;" alt="Nima Shokouhfar"/><br /><sub><b>Nima Shokouhfar</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=nima70" title="Code">💻</a> <a href="https://github.com/keycloakify/keycloakify/commits?author=nima70" title="Tests">⚠️</a></td>
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://mruder.dev"><img src="https://avatars.githubusercontent.com/u/18495294?v=4?s=100" width="100px;" alt="Marvin A. Ruder"/><br /><sub><b>Marvin A. Ruder</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/issues?q=author%3Amarvinruder" title="Bug reports">🐛</a></td>
|
<td align="center" valign="top" width="14.28%"><a href="https://mruder.dev"><img src="https://avatars.githubusercontent.com/u/18495294?v=4?s=100" width="100px;" alt="Marvin A. Ruder"/><br /><sub><b>Marvin A. Ruder</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/issues?q=author%3Amarvinruder" title="Bug reports">🐛</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zvn2060"><img src="https://avatars.githubusercontent.com/u/45450852?v=4?s=100" width="100px;" alt="HI_OuO"/><br /><sub><b>HI_OuO</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=zvn2060" title="Code">💻</a></td>
|
||||||
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tripheo0412"><img src="https://avatars.githubusercontent.com/u/25382052?v=4?s=100" width="100px;" alt="Tri Hoang"/><br /><sub><b>Tri Hoang</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=tripheo0412" title="Documentation">📖</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "keycloakify",
|
"name": "keycloakify",
|
||||||
"version": "11.4.0-rc.0",
|
"version": "11.3.32",
|
||||||
"description": "Framework to create custom Keycloak UIs",
|
"description": "Framework to create custom Keycloak UIs",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -64,7 +64,7 @@
|
|||||||
],
|
],
|
||||||
"homepage": "https://www.keycloakify.dev",
|
"homepage": "https://www.keycloakify.dev",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tsafe": "^1.7.5"
|
"tsafe": "^1.8.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.5",
|
"@babel/core": "^7.24.5",
|
||||||
@ -95,14 +95,14 @@
|
|||||||
"cli-select": "^1.1.2",
|
"cli-select": "^1.1.2",
|
||||||
"dompurify": "^3.1.6",
|
"dompurify": "^3.1.6",
|
||||||
"eslint-plugin-storybook": "^0.6.7",
|
"eslint-plugin-storybook": "^0.6.7",
|
||||||
"evt": "^2.5.7",
|
"evt": "^2.5.8",
|
||||||
"html-entities": "^2.5.2",
|
"html-entities": "^2.5.2",
|
||||||
"husky": "^4.3.8",
|
"husky": "^4.3.8",
|
||||||
"isomorphic-dompurify": "^2.15.0",
|
"isomorphic-dompurify": "^2.15.0",
|
||||||
"lint-staged": "^11.0.0",
|
"lint-staged": "^11.0.0",
|
||||||
"magic-string": "^0.30.7",
|
"magic-string": "^0.30.7",
|
||||||
"make-fetch-happen": "^11.0.3",
|
"make-fetch-happen": "^11.0.3",
|
||||||
"powerhooks": "^1.0.10",
|
"powerhooks": "^1.0.19",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"properties-parser": "^0.3.1",
|
"properties-parser": "^0.3.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -4,8 +4,7 @@ import { SemVer } from "../src/bin/tools/SemVer";
|
|||||||
import { join as pathJoin, relative as pathRelative } from "path";
|
import { join as pathJoin, relative as pathRelative } from "path";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { Deferred } from "evt/tools/Deferred";
|
import { Deferred } from "evt/tools/Deferred";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert, is } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import { run } from "./shared/run";
|
import { run } from "./shared/run";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
@ -125,7 +125,54 @@ if (testAppPaths.length === 0) {
|
|||||||
process.exit(-1);
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
testAppPaths.forEach(testAppPath => execSync("yarn install", { cwd: testAppPath }));
|
testAppPaths.forEach(testAppPath => {
|
||||||
|
const packageJsonFilePath = pathJoin(testAppPath, "package.json");
|
||||||
|
|
||||||
|
const packageJsonContent = fs.readFileSync(packageJsonFilePath);
|
||||||
|
|
||||||
|
const parsedPackageJson = JSON.parse(packageJsonContent.toString("utf8")) as {
|
||||||
|
scripts?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
let hasPostInstallOrPrepareScript = false;
|
||||||
|
|
||||||
|
if (parsedPackageJson.scripts !== undefined) {
|
||||||
|
for (const scriptName of ["postinstall", "prepare"]) {
|
||||||
|
if (parsedPackageJson.scripts[scriptName] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPostInstallOrPrepareScript = true;
|
||||||
|
|
||||||
|
delete parsedPackageJson.scripts[scriptName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPostInstallOrPrepareScript) {
|
||||||
|
fs.writeFileSync(
|
||||||
|
packageJsonFilePath,
|
||||||
|
Buffer.from(JSON.stringify(parsedPackageJson, null, 2), "utf8")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const restorePackageJson = () => {
|
||||||
|
if (!hasPostInstallOrPrepareScript) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(packageJsonFilePath, packageJsonContent);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
execSync("yarn install", { cwd: testAppPath });
|
||||||
|
} catch (error) {
|
||||||
|
restorePackageJson();
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
restorePackageJson();
|
||||||
|
});
|
||||||
|
|
||||||
console.log("=== Linking common dependencies ===");
|
console.log("=== Linking common dependencies ===");
|
||||||
|
|
||||||
@ -172,4 +219,20 @@ testAppPaths.forEach(testAppPath =>
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testAppPaths.forEach(testAppPath => {
|
||||||
|
const { scripts = {} } = JSON.parse(
|
||||||
|
fs.readFileSync(pathJoin(testAppPath, "package.json")).toString("utf8")
|
||||||
|
) as {
|
||||||
|
scripts?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const scriptName of ["postinstall", "prepare"]) {
|
||||||
|
if (scripts[scriptName] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
execSync(`yarn run ${scriptName}`, { cwd: testAppPath });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
@ -66,23 +66,30 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
return value;
|
return value;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
if (themeType === "admin") {
|
||||||
|
console.log(
|
||||||
|
"Use `npx keycloakify eject-file` command instead, see documentation"
|
||||||
|
);
|
||||||
|
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
themeType === "admin" ||
|
themeType === "account" &&
|
||||||
(themeType === "account" &&
|
(assert(buildContext.implementedThemeTypes.account.isImplemented),
|
||||||
(assert(buildContext.implementedThemeTypes.account.isImplemented),
|
buildContext.implementedThemeTypes.account.type === "Single-Page")
|
||||||
buildContext.implementedThemeTypes.account.type === "Single-Page"))
|
|
||||||
) {
|
) {
|
||||||
const srcDirPath = pathJoin(
|
const srcDirPath = pathJoin(
|
||||||
pathDirname(buildContext.packageJsonFilePath),
|
pathDirname(buildContext.packageJsonFilePath),
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"@keycloakify",
|
"@keycloakify",
|
||||||
`keycloak-${themeType}-ui`,
|
`keycloak-account-ui`,
|
||||||
"src"
|
"src"
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
[
|
[
|
||||||
`There isn't an interactive CLI to eject components of the ${themeType} UI.`,
|
`There isn't an interactive CLI to eject components of the Account SPA UI.`,
|
||||||
`You can however copy paste into your codebase the any file or directory from the following source directory:`,
|
`You can however copy paste into your codebase the any file or directory from the following source directory:`,
|
||||||
``,
|
``,
|
||||||
`${chalk.bold(pathJoin(pathRelative(process.cwd(), srcDirPath)))}`,
|
`${chalk.bold(pathJoin(pathRelative(process.cwd(), srcDirPath)))}`,
|
||||||
@ -91,9 +98,9 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
eject_entrypoint: {
|
eject_entrypoint: {
|
||||||
const kcUiTsxFileRelativePath = `Kc${capitalize(themeType)}Ui.tsx` as const;
|
const kcUiTsxFileRelativePath = `KcAccountUi.tsx` as const;
|
||||||
|
|
||||||
const themeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, themeType);
|
const themeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "account");
|
||||||
|
|
||||||
const targetFilePath = pathJoin(themeSrcDirPath, kcUiTsxFileRelativePath);
|
const targetFilePath = pathJoin(themeSrcDirPath, kcUiTsxFileRelativePath);
|
||||||
|
|
||||||
@ -113,11 +120,22 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
const modifiedKcPageTsxCode = kcPageTsxCode.replace(
|
let modifiedKcPageTsxCode = kcPageTsxCode.replace(
|
||||||
`@keycloakify/keycloak-${themeType}-ui/${componentName}`,
|
`@keycloakify/keycloak-account-ui/${componentName}`,
|
||||||
`./${componentName}`
|
`./${componentName}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
run_prettier: {
|
||||||
|
if (!(await getIsPrettierAvailable())) {
|
||||||
|
break run_prettier;
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiedKcPageTsxCode = await runPrettier({
|
||||||
|
filePath: kcPageTsxFilePath,
|
||||||
|
sourceCode: modifiedKcPageTsxCode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
kcPageTsxFilePath,
|
kcPageTsxFilePath,
|
||||||
Buffer.from(modifiedKcPageTsxCode, "utf8")
|
Buffer.from(modifiedKcPageTsxCode, "utf8")
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path";
|
import { relative as pathRelative, dirname as pathDirname } from "path";
|
||||||
import type { BuildContext } from "../shared/buildContext";
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
@ -9,12 +9,10 @@ import {
|
|||||||
import { SemVer } from "../tools/SemVer";
|
import { SemVer } from "../tools/SemVer";
|
||||||
import fetch from "make-fetch-happen";
|
import fetch from "make-fetch-happen";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { npmInstall } from "../tools/npmInstall";
|
import { npmInstall } from "../tools/npmInstall";
|
||||||
import { copyBoilerplate } from "./copyBoilerplate";
|
import { copyBoilerplate } from "./copyBoilerplate";
|
||||||
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
|
|
||||||
|
|
||||||
type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {
|
type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {
|
||||||
fetchOptions: BuildContext["fetchOptions"];
|
fetchOptions: BuildContext["fetchOptions"];
|
||||||
@ -121,20 +119,7 @@ export async function initializeAccountTheme_singlePage(params: {
|
|||||||
JSON.stringify(parsedPackageJson, undefined, 4)
|
JSON.stringify(parsedPackageJson, undefined, 4)
|
||||||
);
|
);
|
||||||
|
|
||||||
run_npm_install: {
|
npmInstall({ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath) });
|
||||||
if (
|
|
||||||
JSON.parse(
|
|
||||||
fs
|
|
||||||
.readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json"))
|
|
||||||
.toString("utf8")
|
|
||||||
)["version"] === "0.0.0"
|
|
||||||
) {
|
|
||||||
//NOTE: Linked version
|
|
||||||
break run_npm_install;
|
|
||||||
}
|
|
||||||
|
|
||||||
npmInstall({ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath) });
|
|
||||||
}
|
|
||||||
|
|
||||||
copyBoilerplate({
|
copyBoilerplate({
|
||||||
accountThemeType: "Single-Page",
|
accountThemeType: "Single-Page",
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
import type { BuildContext } from "../shared/buildContext";
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
|
|
||||||
export type BuildContextLike = {
|
export type BuildContextLike = {
|
||||||
bundler: BuildContext["bundler"];
|
bundler: BuildContext["bundler"];
|
||||||
|
@ -84,8 +84,47 @@ attributes_to_attributesByName: {
|
|||||||
kcContext.profile.attributesByName[attribute.name] = attribute;
|
kcContext.profile.attributesByName[attribute.name] = attribute;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redirect_to_dev_server: {
|
||||||
|
|
||||||
|
switch(kcContext.themeType){
|
||||||
|
case "login":
|
||||||
|
break redirect_to_dev_server;
|
||||||
|
case "account":
|
||||||
|
if( kcContext.pageId !== "index.ftl" ){
|
||||||
|
break redirect_to_dev_server;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "admin":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break redirect_to_dev_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
const devSeverPort = kcContext.properties.KEYCLOAKIFY_SPA_DEV_SERVER_PORT;
|
||||||
|
|
||||||
|
if( !devSeverPort ){
|
||||||
|
break redirect_to_dev_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirectUrl = new URL(window.location.href);
|
||||||
|
|
||||||
|
redirectUrl.port = devSeverPort;
|
||||||
|
|
||||||
|
delete kcContext.msgJSON;
|
||||||
|
|
||||||
|
console.log(kcContext);
|
||||||
|
|
||||||
|
redirectUrl.searchParams.set("kcContext", encodeURIComponent(JSON.stringify(kcContext)) );
|
||||||
|
|
||||||
|
window.location.href = redirectUrl.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
window.kcContext = kcContext;
|
window.kcContext = kcContext;
|
||||||
|
|
||||||
|
|
||||||
<#if xKeycloakify.themeType == "login" >
|
<#if xKeycloakify.themeType == "login" >
|
||||||
{
|
{
|
||||||
const script = document.createElement("script");
|
const script = document.createElement("script");
|
||||||
|
@ -20,7 +20,8 @@ import {
|
|||||||
LOGIN_THEME_PAGE_IDS,
|
LOGIN_THEME_PAGE_IDS,
|
||||||
ACCOUNT_THEME_PAGE_IDS,
|
ACCOUNT_THEME_PAGE_IDS,
|
||||||
WELL_KNOWN_DIRECTORY_BASE_NAME,
|
WELL_KNOWN_DIRECTORY_BASE_NAME,
|
||||||
THEME_TYPES
|
THEME_TYPES,
|
||||||
|
KEYCLOAKIFY_SPA_DEV_SERVER_PORT
|
||||||
} from "../../shared/constants";
|
} from "../../shared/constants";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
import { readFieldNameUsage } from "./readFieldNameUsage";
|
import { readFieldNameUsage } from "./readFieldNameUsage";
|
||||||
@ -379,7 +380,10 @@ export async function generateResources(params: {
|
|||||||
? ["deprecatedMode=false"]
|
? ["deprecatedMode=false"]
|
||||||
: []),
|
: []),
|
||||||
...(buildContext.extraThemeProperties ?? []),
|
...(buildContext.extraThemeProperties ?? []),
|
||||||
...buildContext.environmentVariables.map(
|
...[
|
||||||
|
...buildContext.environmentVariables,
|
||||||
|
{ name: KEYCLOAKIFY_SPA_DEV_SERVER_PORT, default: "" }
|
||||||
|
].map(
|
||||||
({ name, default: defaultValue }) =>
|
({ name, default: defaultValue }) =>
|
||||||
`${name}=\${env.${name}:${escapeStringForPropertiesFile(defaultValue)}}`
|
`${name}=\${env.${name}:${escapeStringForPropertiesFile(defaultValue)}}`
|
||||||
),
|
),
|
||||||
|
@ -5,6 +5,9 @@ import { readThisNpmPackageVersion } from "./tools/readThisNpmPackageVersion";
|
|||||||
import * as child_process from "child_process";
|
import * as child_process from "child_process";
|
||||||
import { assertNoPnpmDlx } from "./tools/assertNoPnpmDlx";
|
import { assertNoPnpmDlx } from "./tools/assertNoPnpmDlx";
|
||||||
import { getBuildContext } from "./shared/buildContext";
|
import { getBuildContext } from "./shared/buildContext";
|
||||||
|
import { SemVer } from "./tools/SemVer";
|
||||||
|
import { assert, is } from "tsafe/assert";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
type CliCommandOptions = {
|
type CliCommandOptions = {
|
||||||
projectDirPath: string | undefined;
|
projectDirPath: string | undefined;
|
||||||
@ -80,7 +83,7 @@ program
|
|||||||
program
|
program
|
||||||
.command<{
|
.command<{
|
||||||
port: number | undefined;
|
port: number | undefined;
|
||||||
keycloakVersion: string | undefined;
|
keycloakVersion: string | number | undefined;
|
||||||
realmJsonFilePath: string | undefined;
|
realmJsonFilePath: string | undefined;
|
||||||
}>({
|
}>({
|
||||||
name: "start-keycloak",
|
name: "start-keycloak",
|
||||||
@ -134,9 +137,50 @@ program
|
|||||||
handler: async ({ projectDirPath, keycloakVersion, port, realmJsonFilePath }) => {
|
handler: async ({ projectDirPath, keycloakVersion, port, realmJsonFilePath }) => {
|
||||||
const { command } = await import("./start-keycloak");
|
const { command } = await import("./start-keycloak");
|
||||||
|
|
||||||
|
validate_keycloak_version: {
|
||||||
|
if (keycloakVersion === undefined) {
|
||||||
|
break validate_keycloak_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidVersion = (() => {
|
||||||
|
if (typeof keycloakVersion === "number") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
SemVer.parse(keycloakVersion);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (isValidVersion) {
|
||||||
|
break validate_keycloak_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
chalk.red(
|
||||||
|
[
|
||||||
|
`Invalid Keycloak version: ${keycloakVersion}`,
|
||||||
|
"It should be a valid semver version example: 26.0.4"
|
||||||
|
].join(" ")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(is<string | undefined>(keycloakVersion));
|
||||||
|
|
||||||
await command({
|
await command({
|
||||||
buildContext: getBuildContext({ projectDirPath }),
|
buildContext: getBuildContext({ projectDirPath }),
|
||||||
cliCommandOptions: { keycloakVersion, port, realmJsonFilePath }
|
cliCommandOptions: {
|
||||||
|
keycloakVersion,
|
||||||
|
port,
|
||||||
|
realmJsonFilePath
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -201,7 +245,7 @@ program
|
|||||||
.command({
|
.command({
|
||||||
name: "copy-keycloak-resources-to-public",
|
name: "copy-keycloak-resources-to-public",
|
||||||
description:
|
description:
|
||||||
"(Webpack/Create-React-App only) Copy Keycloak default theme resources to the public directory."
|
"(Internal) Copy Keycloak default theme resources to the public directory."
|
||||||
})
|
})
|
||||||
.task({
|
.task({
|
||||||
skip,
|
skip,
|
||||||
@ -246,7 +290,10 @@ program
|
|||||||
file: string;
|
file: string;
|
||||||
}>({
|
}>({
|
||||||
name: "eject-file",
|
name: "eject-file",
|
||||||
description: "Take ownership over a given file"
|
description: [
|
||||||
|
"WARNING: Not usable yet, will be used for future features",
|
||||||
|
"Take ownership over a given file"
|
||||||
|
].join(" ")
|
||||||
})
|
})
|
||||||
.option({
|
.option({
|
||||||
key: "file",
|
key: "file",
|
||||||
|
@ -32,27 +32,38 @@ export async function getUiModuleFileSourceCodeReadyToBeCopied(params: {
|
|||||||
await fsPr.readFile(pathJoin(uiModuleDirPath, KEYCLOAK_THEME, fileRelativePath))
|
await fsPr.readFile(pathJoin(uiModuleDirPath, KEYCLOAK_THEME, fileRelativePath))
|
||||||
).toString("utf8");
|
).toString("utf8");
|
||||||
|
|
||||||
const comment = (() => {
|
const toComment = (lines: string[]) => {
|
||||||
if (isForEjection) {
|
for (const ext of [".ts", ".tsx", ".css", ".less", ".sass", ".js", ".jsx"]) {
|
||||||
return [
|
if (!fileRelativePath.endsWith(ext)) {
|
||||||
`/*`,
|
continue;
|
||||||
`This file was ejected from ${uiModuleName} version ${uiModuleVersion}.`,
|
}
|
||||||
`*/`
|
|
||||||
].join("\n");
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
`/*`,
|
|
||||||
`WARNING: Before modifying this file run the following command:`,
|
|
||||||
``,
|
|
||||||
`npx keycloakify eject-file --file ${fileRelativePath.split(pathSep).join("/")}\``,
|
|
||||||
``,
|
|
||||||
`This file comes from ${uiModuleName} version ${uiModuleVersion}.`,
|
|
||||||
`*/`
|
|
||||||
];
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
sourceCode = [comment, ``, sourceCode].join("\n");
|
return [`/**`, ...lines.map(line => ` * ${line}`), ` */`].join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileRelativePath.endsWith(".html")) {
|
||||||
|
return [`<!--`, ...lines.map(line => ` ${line}`), `-->`].join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const comment = toComment(
|
||||||
|
isForEjection
|
||||||
|
? [`This file was ejected from ${uiModuleName} version ${uiModuleVersion}.`]
|
||||||
|
: [
|
||||||
|
`WARNING: Before modifying this file run the following command:`,
|
||||||
|
``,
|
||||||
|
`$ npx keycloakify eject-file --file ${fileRelativePath.split(pathSep).join("/")}`,
|
||||||
|
``,
|
||||||
|
`This file comes from ${uiModuleName} version ${uiModuleVersion}.`,
|
||||||
|
`This file has been copied over to your repo by your postinstall script: \`npx keycloakify postinstall\``
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (comment !== undefined) {
|
||||||
|
sourceCode = [comment, ``, sourceCode].join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
|
const destFilePath = pathJoin(buildContext.themeSrcDirPath, fileRelativePath);
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import type { BuildContext } from "../shared/buildContext";
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
import type { UiModuleMeta } from "./uiModuleMeta";
|
import type { UiModuleMeta } from "./uiModuleMeta";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -9,6 +8,7 @@ import { SemVer } from "../tools/SemVer";
|
|||||||
import { same } from "evt/tools/inDepth/same";
|
import { same } from "evt/tools/inDepth/same";
|
||||||
import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
|
import { runPrettier, getIsPrettierAvailable } from "../tools/runPrettier";
|
||||||
import { npmInstall } from "../tools/npmInstall";
|
import { npmInstall } from "../tools/npmInstall";
|
||||||
|
import { dirname as pathDirname } from "path";
|
||||||
|
|
||||||
export type BuildContextLike = {
|
export type BuildContextLike = {
|
||||||
packageJsonFilePath: string;
|
packageJsonFilePath: string;
|
||||||
@ -150,7 +150,7 @@ export async function installUiModulesPeerDependencies(params: {
|
|||||||
await fsPr.writeFile(buildContext.packageJsonFilePath, packageJsonContentStr);
|
await fsPr.writeFile(buildContext.packageJsonFilePath, packageJsonContentStr);
|
||||||
|
|
||||||
npmInstall({
|
npmInstall({
|
||||||
packageJsonDirPath: buildContext.packageJsonFilePath
|
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
||||||
});
|
});
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
@ -38,9 +38,9 @@ export async function writeManagedGitignoreFile(params: {
|
|||||||
`# This file is managed by Keycloakify, do not edit it manually.`,
|
`# This file is managed by Keycloakify, do not edit it manually.`,
|
||||||
``,
|
``,
|
||||||
DELIMITER_START,
|
DELIMITER_START,
|
||||||
...ejectedFilesRelativePaths.map(fileRelativePath =>
|
...ejectedFilesRelativePaths
|
||||||
fileRelativePath.split(pathSep).join("/")
|
.map(fileRelativePath => fileRelativePath.split(pathSep).join("/"))
|
||||||
),
|
.map(line => `# ${line}`),
|
||||||
DELIMITER_END,
|
DELIMITER_END,
|
||||||
``,
|
``,
|
||||||
...uiModuleMetas
|
...uiModuleMetas
|
||||||
@ -122,6 +122,7 @@ export async function readManagedGitignoreFile(params: {
|
|||||||
const ejectedFilesRelativePaths = payload
|
const ejectedFilesRelativePaths = payload
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.map(line => line.trim())
|
.map(line => line.trim())
|
||||||
|
.map(line => line.replace(/^# /, ""))
|
||||||
.filter(line => line !== "")
|
.filter(line => line !== "")
|
||||||
.map(line =>
|
.map(line =>
|
||||||
getAbsoluteAndInOsFormatPath({
|
getAbsoluteAndInOsFormatPath({
|
||||||
|
@ -9,6 +9,8 @@ import { dirname as pathDirname } from "path";
|
|||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import { existsAsync } from "../tools/fs.existsAsync";
|
import { existsAsync } from "../tools/fs.existsAsync";
|
||||||
import * as fsPr from "fs/promises";
|
import * as fsPr from "fs/promises";
|
||||||
|
import { getIsTrackedByGit } from "../tools/isTrackedByGit";
|
||||||
|
import { untrackFromGit } from "../tools/untrackFromGit";
|
||||||
|
|
||||||
export async function command(params: { buildContext: BuildContext }) {
|
export async function command(params: { buildContext: BuildContext }) {
|
||||||
const { buildContext } = params;
|
const { buildContext } = params;
|
||||||
@ -45,8 +47,10 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
fileRelativePath
|
fileRelativePath
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const doesFileExist = await existsAsync(destFilePath);
|
||||||
|
|
||||||
skip_condition: {
|
skip_condition: {
|
||||||
if (!(await existsAsync(destFilePath))) {
|
if (!doesFileExist) {
|
||||||
break skip_condition;
|
break skip_condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,8 +65,26 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
git_untrack: {
|
||||||
|
if (!doesFileExist) {
|
||||||
|
break git_untrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTracked = await getIsTrackedByGit({
|
||||||
|
filePath: destFilePath
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isTracked) {
|
||||||
|
break git_untrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
await untrackFromGit({
|
||||||
|
filePath: destFilePath
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const dirName = pathDirname(copyableFilePath);
|
const dirName = pathDirname(destFilePath);
|
||||||
|
|
||||||
if (!(await existsAsync(dirName))) {
|
if (!(await existsAsync(dirName))) {
|
||||||
await fsPr.mkdir(dirName, { recursive: true });
|
await fsPr.mkdir(dirName, { recursive: true });
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { join as pathJoin, dirname as pathDirname } from "path";
|
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||||
import * as fsPr from "fs/promises";
|
import * as fsPr from "fs/promises";
|
||||||
import type { BuildContext } from "../shared/buildContext";
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import { existsAsync } from "../tools/fs.existsAsync";
|
import { existsAsync } from "../tools/fs.existsAsync";
|
||||||
import { listInstalledModules } from "../tools/listInstalledModules";
|
import { listInstalledModules } from "../tools/listInstalledModules";
|
||||||
import { crawlAsync } from "../tools/crawlAsync";
|
import { crawlAsync } from "../tools/crawlAsync";
|
||||||
import { getIsPrettierAvailable, getPrettierAndConfig } from "../tools/runPrettier";
|
import { getIsPrettierAvailable, getPrettier } from "../tools/runPrettier";
|
||||||
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
|
||||||
import {
|
import {
|
||||||
getUiModuleFileSourceCodeReadyToBeCopied,
|
getUiModuleFileSourceCodeReadyToBeCopied,
|
||||||
@ -16,6 +15,7 @@ import {
|
|||||||
} from "./getUiModuleFileSourceCodeReadyToBeCopied";
|
} from "./getUiModuleFileSourceCodeReadyToBeCopied";
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import { KEYCLOAK_THEME } from "../shared/constants";
|
import { KEYCLOAK_THEME } from "../shared/constants";
|
||||||
|
import { exclude } from "tsafe/exclude";
|
||||||
|
|
||||||
export type UiModuleMeta = {
|
export type UiModuleMeta = {
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
@ -100,9 +100,9 @@ export async function getUiModuleMetas(params: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { config } = await getPrettierAndConfig();
|
const { configHash } = await getPrettier();
|
||||||
|
|
||||||
return crypto.createHash("sha256").update(JSON.stringify(config)).digest("hex");
|
return configHash;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const installedUiModules = await (async () => {
|
const installedUiModules = await (async () => {
|
||||||
@ -113,11 +113,16 @@ export async function getUiModuleMetas(params: {
|
|||||||
moduleName.includes("keycloakify") && moduleName !== "keycloakify"
|
moduleName.includes("keycloakify") && moduleName !== "keycloakify"
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(
|
return (
|
||||||
installedModulesWithKeycloakifyInTheName.filter(async ({ dirPath }) =>
|
await Promise.all(
|
||||||
existsAsync(pathJoin(dirPath, KEYCLOAK_THEME))
|
installedModulesWithKeycloakifyInTheName.map(async entry => {
|
||||||
|
if (!(await existsAsync(pathJoin(entry.dirPath, KEYCLOAK_THEME)))) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
})
|
||||||
)
|
)
|
||||||
);
|
).filter(exclude(undefined));
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const cacheContent = await (async () => {
|
const cacheContent = await (async () => {
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
import { getAbsoluteAndInOsFormatPath } from "../tools/getAbsoluteAndInOsFormatPath";
|
import { getAbsoluteAndInOsFormatPath } from "../tools/getAbsoluteAndInOsFormatPath";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
import * as child_process from "child_process";
|
import * as child_process from "child_process";
|
||||||
import {
|
import {
|
||||||
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES,
|
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES,
|
||||||
@ -23,7 +23,6 @@ import { objectEntries } from "tsafe/objectEntries";
|
|||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { getProxyFetchOptions, type FetchOptionsLike } from "../tools/fetchProxyOptions";
|
import { getProxyFetchOptions, type FetchOptionsLike } from "../tools/fetchProxyOptions";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
|
|
||||||
export type BuildContext = {
|
export type BuildContext = {
|
||||||
themeVersion: string;
|
themeVersion: string;
|
||||||
|
@ -10,7 +10,8 @@ export type ThemeType = (typeof THEME_TYPES)[number];
|
|||||||
|
|
||||||
export const VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES = {
|
export const VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES = {
|
||||||
RUN_POST_BUILD_SCRIPT: "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT",
|
RUN_POST_BUILD_SCRIPT: "KEYCLOAKIFY_RUN_POST_BUILD_SCRIPT",
|
||||||
RESOLVE_VITE_CONFIG: "KEYCLOAKIFY_RESOLVE_VITE_CONFIG"
|
RESOLVE_VITE_CONFIG: "KEYCLOAKIFY_RESOLVE_VITE_CONFIG",
|
||||||
|
READ_KC_CONTEXT_FROM_URL: "KEYCLOAKIFY_READ_KC_CONTEXT_FROM_URL"
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME =
|
export const BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME =
|
||||||
@ -78,3 +79,5 @@ export const CUSTOM_HANDLER_ENV_NAMES = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const KEYCLOAK_THEME = "keycloak-theme";
|
export const KEYCLOAK_THEME = "keycloak-theme";
|
||||||
|
|
||||||
|
export const KEYCLOAKIFY_SPA_DEV_SERVER_PORT = "KEYCLOAKIFY_SPA_DEV_SERVER_PORT";
|
||||||
|
@ -628,14 +628,16 @@
|
|||||||
"id": "d8f14dc4-5f0f-4a1d-8c0b-cfe78ee55cb3",
|
"id": "d8f14dc4-5f0f-4a1d-8c0b-cfe78ee55cb3",
|
||||||
"clientId": "account-console",
|
"clientId": "account-console",
|
||||||
"name": "${client_account-console}",
|
"name": "${client_account-console}",
|
||||||
|
"description": "",
|
||||||
"rootUrl": "${authBaseUrl}",
|
"rootUrl": "${authBaseUrl}",
|
||||||
|
"adminUrl": "",
|
||||||
"baseUrl": "/realms/myrealm/account/",
|
"baseUrl": "/realms/myrealm/account/",
|
||||||
"surrogateAuthRequired": false,
|
"surrogateAuthRequired": false,
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"alwaysDisplayInConsole": false,
|
"alwaysDisplayInConsole": false,
|
||||||
"clientAuthenticatorType": "client-secret",
|
"clientAuthenticatorType": "client-secret",
|
||||||
"redirectUris": ["/realms/myrealm/account/*"],
|
"redirectUris": ["*"],
|
||||||
"webOrigins": [],
|
"webOrigins": ["*"],
|
||||||
"notBefore": 0,
|
"notBefore": 0,
|
||||||
"bearerOnly": false,
|
"bearerOnly": false,
|
||||||
"consentRequired": false,
|
"consentRequired": false,
|
||||||
@ -647,8 +649,13 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"oidc.ciba.grant.enabled": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
"post.logout.redirect.uris": "+",
|
"post.logout.redirect.uris": "+",
|
||||||
"pkce.code.challenge.method": "S256"
|
"oauth2.device.authorization.grant.enabled": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"pkce.code.challenge.method": "S256",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
"fullScopeAllowed": false,
|
"fullScopeAllowed": false,
|
||||||
@ -1574,14 +1581,14 @@
|
|||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"allowed-protocol-mapper-types": [
|
"allowed-protocol-mapper-types": [
|
||||||
|
"oidc-sha256-pairwise-sub-mapper",
|
||||||
"oidc-full-name-mapper",
|
"oidc-full-name-mapper",
|
||||||
"oidc-usermodel-attribute-mapper",
|
|
||||||
"oidc-address-mapper",
|
|
||||||
"saml-user-attribute-mapper",
|
|
||||||
"oidc-usermodel-property-mapper",
|
"oidc-usermodel-property-mapper",
|
||||||
"saml-user-property-mapper",
|
|
||||||
"saml-role-list-mapper",
|
"saml-role-list-mapper",
|
||||||
"oidc-sha256-pairwise-sub-mapper"
|
"saml-user-attribute-mapper",
|
||||||
|
"saml-user-property-mapper",
|
||||||
|
"oidc-usermodel-attribute-mapper",
|
||||||
|
"oidc-address-mapper"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1612,13 +1619,13 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"allowed-protocol-mapper-types": [
|
"allowed-protocol-mapper-types": [
|
||||||
"oidc-sha256-pairwise-sub-mapper",
|
"oidc-sha256-pairwise-sub-mapper",
|
||||||
"oidc-usermodel-property-mapper",
|
|
||||||
"oidc-address-mapper",
|
|
||||||
"oidc-usermodel-attribute-mapper",
|
|
||||||
"oidc-full-name-mapper",
|
|
||||||
"saml-user-attribute-mapper",
|
|
||||||
"saml-user-property-mapper",
|
"saml-user-property-mapper",
|
||||||
"saml-role-list-mapper"
|
"oidc-usermodel-attribute-mapper",
|
||||||
|
"oidc-address-mapper",
|
||||||
|
"saml-role-list-mapper",
|
||||||
|
"oidc-usermodel-property-mapper",
|
||||||
|
"saml-user-attribute-mapper",
|
||||||
|
"oidc-full-name-mapper"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1671,13 +1678,6 @@
|
|||||||
"providerId": "rsa-generated",
|
"providerId": "rsa-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"privateKey": [
|
|
||||||
"MIIEowIBAAKCAQEAsYUWzVfZMd6ywpBmLJYeF1U9Mgd/z3xWvl1Yq76oRPPfpcqQitN+cktWqu0hPerCVSl2ltwXDMrUwFzswG9MiM9hb+BLEld7kYiYkcFNt3lCtmmeRQEae7JwWimzeNV96Qlz0tHY8f9Zh0ffPDsLTN1HGAeRJJhI7mNQm6qCJNMCfVA/O5SWumsIn2XLnSMiQ05AACVHOLUq6rAZ2zCCaYmXTmJkuSOb8e26V303P6l63DSe5HSNXDdI00tjfFFf37q870zhvfsotrjjx0RMijy9Kjj8OZF+pFHpDRaGEi8tpQxZDnCTofTieB/Vp3QP+aTlvAyD3Q1ZnJxGQCLygwIDAQABAoIBABUJ9XMJGNQzamiVwuOWN7ht4UP8ezYvgdEA8NaLUO0PIYVIKyD7l4OwkHPPM9PfRACM2qG0MZp8sCyg4WxIeepy+D979oRqJYUmNRLSipqWlASuItRXIPjiY99uYXdjh2R8Os5pvCD+MZxPX9KHGuaVXmzSJMO7YAAPeYkMHcLYTp/U0c65Ztaaz1zz1FeyvpjkLr9SHiMcIN51zFmhvT1tcRIqy4zidisjrTSUr/KPVxeJtrEfyhTGk3z41yJf5YbeaxaMjJR5x0WXzt1fWVmA/V1bWa2Zlj9d8AxDReA1p7Lpstz34PRoCMj9bmFguI2+RTw6K0D++Jydfxmh8vUCgYEA5Zwk2r3TFO3i3V70LOn6CLzn15yLeuSIJ9p2os70jQOmFMCreLdcUbCaiUe7UV/IIVftbcxhFm9zECXZXX0wubcmHZqyptlbuAn1de4QkLJixXo1A7ZQXBEZk22WN2naXHQF5oK6lh/VSLcZBajTsyvBm5JWXrd8djjG06MugA8CgYEAxexKI5IwcLhpMDV9UPQb/+lDWHVqCT2xwYxnZ85y+5gmrOyyT7mIChz3DFYiaw4CHJWmBkIDBaiDgLEgQk4QXWzYshXawShBHnv1h08bVMMw98Ivec7ZRkV+/ET30YRwC2Uyk4bm4HpwVV5GCFhC4aAvRcCA1CIJk3MwcOwksk0CgYEAqxyaOomMbOR7VQ4WWgJkW26sOHppV8RH06tzDhG9HfnCI2USZHwBSL+b6wKSDiqbMn4cat8M23NjBH2wZ4OMdFqRBS7sRHtnZtfFHYW0wqCuCwzvxTxw1qvHq57Xe6RfHtc4LnjuJELE59PLyfPvEG9jcVS1GREUp+XYBpBtbvECgYAMhWBDU9JAr0noRNoCrw6+Z9Fc3UCyCPcf2XQJOyRHCl8X/XliVchna2GtpB1VTHORv13bc32hdAGtuIbj6vBaGLK0wXEvWw6TkR/9SWHfQOHuKpi6Sf2w1mCsMOjElm5IKkTC1Hvyo4xLukUP7hV9FJcpAH6l7OlSLK1Z13aS2QKBgB6w4gvmVEQruHV5+K60OatuFojr+kxJwmzCb5uKOULUFezT2pA3p3l6IWxGL2XtM+LD0SiZE3KZJUzf+LatYlBU9ek4F1krkVNUTRZpzUa0oADbymCL1chM4oPIs7sISQlFIH2wOSZt6Blvcw0E0wfjd9Gv/LHxcMnlRb1t1sLk"
|
|
||||||
],
|
|
||||||
"keyUse": ["SIG"],
|
|
||||||
"certificate": [
|
|
||||||
"MIICnTCCAYUCBgGQBsyplzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdteXJlYWxtMB4XDTI0MDYxMTEwMTQ1NFoXDTM0MDYxMTEwMTYzNFowEjEQMA4GA1UEAwwHbXlyZWFsbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGFFs1X2THessKQZiyWHhdVPTIHf898Vr5dWKu+qETz36XKkIrTfnJLVqrtIT3qwlUpdpbcFwzK1MBc7MBvTIjPYW/gSxJXe5GImJHBTbd5QrZpnkUBGnuycFops3jVfekJc9LR2PH/WYdH3zw7C0zdRxgHkSSYSO5jUJuqgiTTAn1QPzuUlrprCJ9ly50jIkNOQAAlRzi1KuqwGdswgmmJl05iZLkjm/Htuld9Nz+petw0nuR0jVw3SNNLY3xRX9+6vO9M4b37KLa448dETIo8vSo4/DmRfqRR6Q0WhhIvLaUMWQ5wk6H04ngf1ad0D/mk5bwMg90NWZycRkAi8oMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAVS+gJshIFX6cmBGI8UaOOI/9+XFb4Gi+DHaHVWVVHTd14MoqNK1bmmyTHbGIZbvK8UqgJ9+FhJX1ejx17d4KBzkZI3tYvPnVacHvaw1CIUMZ1Ini6u+UGUTnIlnQzCG0pcTKjOZXf3ih1B2CKdwyC7XeXyEJHicAIG7XfzYfYd9DYHvA+h6hrXaQcNJMW7WFNbtb3fJhtlv5P1Iw+ZEGdj15ukMI0bg2OEQA0F3jIw6QZpigSAGuai3HOY6OgoPO82d7TyTYlNhuwyutWr9izl6QMc2R7BmRfW9XQj4ICR2VWJiL9nqz+SOyqnjQiOObuw8Vywb8c36R1Ym1aaGjOw=="
|
|
||||||
],
|
|
||||||
"priority": ["100"]
|
"priority": ["100"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1687,13 +1687,6 @@
|
|||||||
"providerId": "rsa-enc-generated",
|
"providerId": "rsa-enc-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"privateKey": [
|
|
||||||
"MIIEogIBAAKCAQEAkQtefHy82e8d5dVWN00LnGI5YmBOTKh0tgqayVRjqLH6u3NfgJVVIe0tFnxa7Wka/ySHrn1KSsW52czZ4uPXLUo4sXBkQxyyFXeZiWN8H+9WiUQ+0hefZF4es5ZPhY2VpeMK9XAnphC362LFLVycXulkpJcQ+4DjI99To4LLyJmjQvsVaJ7amoVJ5xd62eUv+D7f2+jwuaTwjGE3+MWZADXjVxsUY1qJuGLGKnLkNNxJNMDhvnKYw+aa3Z4V90fQVyjN1Volgw3DdA59o4wrWEy+2xHc6j2ESi8+cM60fWzZU9sp2XkyJoCnV7nmwk7pZkDy3zvAkeOWzrr3OWeR3wIDAQABAoIBACWMcet8R0+L7YuATQ+H7IeRjhV/pQWHXp9541RXem1DlgtM9N5Oynk78z4s90Uavphqlo1/deohgdl2hLmODjh1THPzCqGtHhUcnyzICmwiA58JgdHVt7e9/eiz8uY6HxGQ01dyr3D4RwSyzyTNItYXSayqRwU0+phgykA8LhFCAQM/UkRXDf6UCFKBhDyE7VPBaDv0xyxNb7dKtE7C6Qo5t5D40xCfQ8ni8OcD5RvshQq5xOWcw7igxAhlmXCu1fuO2CDiSiqXLMENs4NlwilQ3caMXAIzUiblaKwCrrK2noBoitx6vuOR2tKmIZSlTyDAG4vLQQtOHk53hBoupGECgYEAx4jSmLM9uUzNwNY1zfs8iNswxbU3YibNe2Q+IFmOQofvTaq1jBBxdPWX5ifIbuTvOAA33pmJRh+BtWzOBBQC7Z4i9mdfvyWB6s8t9nnTnWIY5Hj+hV5gaqae59MjdudsORR887fxzPIeAwwaETfKaZnYpC6zLaE3BXwhIcjlFTcCgYEAuhcKf16JkEYNIwanVHpUXjFxwAThAogHWZAngRokmai67Iulx+rSUhhtOIXtmjj/EaObsrqo5yCKAVZ5EbPTOajdd9RtFzH6q3bRjRdp8o8ZVx4c1vMNaOnLbvK4YzJlKSZN9N7m255Mg+/ea3veKVZsSVHDMnuYmH8GjncjPJkCgYAOIUlQmPjZA3BapJDA2nbJ9kO47IFUiQzqHQotPkpNudSfemRK2+s87htoqA6Qk9PA8nsCX3sSJS8JSwA317bxXs55Bo8IOT6/AxbtKmlq7sR2gX78sNdBFjWQkyoixHasgB/tHmyYJ9kqPBQoffvuiH+H+OqlY5JC6CxseQ6H9wKBgF69Hj4MDjLiRwve9k9+2/b8azHcCgX05PEG/+WtPpbwHQIScnseJKdhAjH1lSqf+9OqHLlYaGcK3Nejg42spEvFmcLI5iUZ78lde3++PNUdX0RH81zHbrtL06MPdSojXPcfJi8VUCjdJY1CEFVeQZOACS8mrh7EZ8KzYM4k/055AoGAYqjBv3WS8ul7kAsjpZKpIw1QZZaTjBSmLpjB6X8InF+Zihjgm80Dd4RMFnMnEawhFBvnpklvyw5Ce6NSwcC137kN3NVpJypykkXuYkimg7OxgJjR7YFdbQWJWlc+1eB81WTHcEOHVI/DmeV2yVJcv6kA2iC+3/JA0VoJxvrRBKc="
|
|
||||||
],
|
|
||||||
"keyUse": ["ENC"],
|
|
||||||
"certificate": [
|
|
||||||
"MIICnTCCAYUCBgGQBsyq0jANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdteXJlYWxtMB4XDTI0MDYxMTEwMTQ1NFoXDTM0MDYxMTEwMTYzNFowEjEQMA4GA1UEAwwHbXlyZWFsbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJELXnx8vNnvHeXVVjdNC5xiOWJgTkyodLYKmslUY6ix+rtzX4CVVSHtLRZ8Wu1pGv8kh659SkrFudnM2eLj1y1KOLFwZEMcshV3mYljfB/vVolEPtIXn2ReHrOWT4WNlaXjCvVwJ6YQt+tixS1cnF7pZKSXEPuA4yPfU6OCy8iZo0L7FWie2pqFSecXetnlL/g+39vo8Lmk8IxhN/jFmQA141cbFGNaibhixipy5DTcSTTA4b5ymMPmmt2eFfdH0FcozdVaJYMNw3QOfaOMK1hMvtsR3Oo9hEovPnDOtH1s2VPbKdl5MiaAp1e55sJO6WZA8t87wJHjls669zlnkd8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAD9wQ+CJ0FRgls3JrUzxwHLgrJ3Yo4+mDFpSe1rh2XYK5FEIWDWSqxaXI3p0cOZq75RZmI2xV8oaiJMUz9WMZkbNe/KtGRzHY1N9AZooicGIsnFu1t++b8taFxxpvKWZgnbOum2PZlfcNiXL0QeMv0wwhfn9zKA9W1DRcqYGbIamoyVlumvbNyIjqXJKwGYIOW6GNt7v3wJl5AJw8qAU/O/DQwWwmzcnFGNRxRxAwI7we8EiQ5JlG0Wi+nyAQn74o3RhNr3zsY0ndmFx9bFV4BBo2AiYGozCDOCCG5HvrmoDbrm//wmGRv0tCwueBzWHL2mhtbZ6sGWmMWfiTJ2HPpg=="
|
|
||||||
],
|
|
||||||
"priority": ["100"],
|
"priority": ["100"],
|
||||||
"algorithm": ["RSA-OAEP"]
|
"algorithm": ["RSA-OAEP"]
|
||||||
}
|
}
|
||||||
@ -1704,8 +1697,6 @@
|
|||||||
"providerId": "aes-generated",
|
"providerId": "aes-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"kid": ["1c1d0c8a-6f0b-48a9-a66f-488489137d85"],
|
|
||||||
"secret": ["N4wzheVYYBWxFn9VGWTPQQ"],
|
|
||||||
"priority": ["100"]
|
"priority": ["100"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1715,10 +1706,6 @@
|
|||||||
"providerId": "hmac-generated",
|
"providerId": "hmac-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"kid": ["ce43821c-6cfd-4ea9-a29a-a724a37e6955"],
|
|
||||||
"secret": [
|
|
||||||
"j_8WeQHYt5R6coay0IOUeu9hGvCoJsgnENSoYm0gDlDx6IHOg-f6p17QIaesNmgrzXtJDRpYMhSjpTMHOnHCHLxwUM4eVg9TcszffndB850Yj3PHPeCc5aoHcpYzWN9NDZZ02nBYA04nfbkdlLXiGlpS3I3e502e4DX3rFtbFZ0"
|
|
||||||
],
|
|
||||||
"priority": ["100"],
|
"priority": ["100"],
|
||||||
"algorithm": ["HS512"]
|
"algorithm": ["HS512"]
|
||||||
}
|
}
|
||||||
@ -2388,7 +2375,7 @@
|
|||||||
"clientSessionMaxLifespan": "0",
|
"clientSessionMaxLifespan": "0",
|
||||||
"organizationsEnabled": "false"
|
"organizationsEnabled": "false"
|
||||||
},
|
},
|
||||||
"keycloakVersion": "25.0.0",
|
"keycloakVersion": "25.0.6",
|
||||||
"userManagedAccessAllowed": false,
|
"userManagedAccessAllowed": false,
|
||||||
"organizationsEnabled": false,
|
"organizationsEnabled": false,
|
||||||
"clientProfiles": {
|
"clientProfiles": {
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"bruteForceProtected": false,
|
"bruteForceProtected": false,
|
||||||
"permanentLockout": false,
|
"permanentLockout": false,
|
||||||
"maxTemporaryLockouts": 0,
|
"maxTemporaryLockouts": 0,
|
||||||
|
"bruteForceStrategy": "MULTIPLE",
|
||||||
"maxFailureWaitSeconds": 900,
|
"maxFailureWaitSeconds": 900,
|
||||||
"minimumQuickLoginWaitSeconds": 60,
|
"minimumQuickLoginWaitSeconds": 60,
|
||||||
"waitIncrementSeconds": 60,
|
"waitIncrementSeconds": 60,
|
||||||
@ -604,6 +605,7 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "false",
|
||||||
"post.logout.redirect.uris": "+"
|
"post.logout.redirect.uris": "+"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
@ -628,14 +630,16 @@
|
|||||||
"id": "d8f14dc4-5f0f-4a1d-8c0b-cfe78ee55cb3",
|
"id": "d8f14dc4-5f0f-4a1d-8c0b-cfe78ee55cb3",
|
||||||
"clientId": "account-console",
|
"clientId": "account-console",
|
||||||
"name": "${client_account-console}",
|
"name": "${client_account-console}",
|
||||||
|
"description": "",
|
||||||
"rootUrl": "${authBaseUrl}",
|
"rootUrl": "${authBaseUrl}",
|
||||||
|
"adminUrl": "",
|
||||||
"baseUrl": "/realms/myrealm/account/",
|
"baseUrl": "/realms/myrealm/account/",
|
||||||
"surrogateAuthRequired": false,
|
"surrogateAuthRequired": false,
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"alwaysDisplayInConsole": false,
|
"alwaysDisplayInConsole": false,
|
||||||
"clientAuthenticatorType": "client-secret",
|
"clientAuthenticatorType": "client-secret",
|
||||||
"redirectUris": ["/realms/myrealm/account/*"],
|
"redirectUris": ["*"],
|
||||||
"webOrigins": [],
|
"webOrigins": ["*"],
|
||||||
"notBefore": 0,
|
"notBefore": 0,
|
||||||
"bearerOnly": false,
|
"bearerOnly": false,
|
||||||
"consentRequired": false,
|
"consentRequired": false,
|
||||||
@ -647,8 +651,14 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "false",
|
||||||
|
"oidc.ciba.grant.enabled": "false",
|
||||||
|
"backchannel.logout.session.required": "true",
|
||||||
"post.logout.redirect.uris": "+",
|
"post.logout.redirect.uris": "+",
|
||||||
"pkce.code.challenge.method": "S256"
|
"oauth2.device.authorization.grant.enabled": "false",
|
||||||
|
"display.on.consent.screen": "false",
|
||||||
|
"pkce.code.challenge.method": "S256",
|
||||||
|
"backchannel.logout.revoke.offline.tokens": "false"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
"fullScopeAllowed": false,
|
"fullScopeAllowed": false,
|
||||||
@ -699,10 +709,12 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "false",
|
||||||
|
"client.use.lightweight.access.token.enabled": "true",
|
||||||
"post.logout.redirect.uris": "+"
|
"post.logout.redirect.uris": "+"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
"fullScopeAllowed": false,
|
"fullScopeAllowed": true,
|
||||||
"nodeReRegistrationTimeout": 0,
|
"nodeReRegistrationTimeout": 0,
|
||||||
"defaultClientScopes": [
|
"defaultClientScopes": [
|
||||||
"web-origins",
|
"web-origins",
|
||||||
@ -740,6 +752,7 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "true",
|
||||||
"post.logout.redirect.uris": "+"
|
"post.logout.redirect.uris": "+"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
@ -789,6 +802,7 @@
|
|||||||
"frontchannelLogout": true,
|
"frontchannelLogout": true,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "false",
|
||||||
"oidc.ciba.grant.enabled": "false",
|
"oidc.ciba.grant.enabled": "false",
|
||||||
"backchannel.logout.session.required": "true",
|
"backchannel.logout.session.required": "true",
|
||||||
"login_theme": "keycloakify-starter",
|
"login_theme": "keycloakify-starter",
|
||||||
@ -855,6 +869,7 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "true",
|
||||||
"post.logout.redirect.uris": "+"
|
"post.logout.redirect.uris": "+"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
@ -898,11 +913,13 @@
|
|||||||
"frontchannelLogout": false,
|
"frontchannelLogout": false,
|
||||||
"protocol": "openid-connect",
|
"protocol": "openid-connect",
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
"realm_client": "false",
|
||||||
|
"client.use.lightweight.access.token.enabled": "true",
|
||||||
"post.logout.redirect.uris": "+",
|
"post.logout.redirect.uris": "+",
|
||||||
"pkce.code.challenge.method": "S256"
|
"pkce.code.challenge.method": "S256"
|
||||||
},
|
},
|
||||||
"authenticationFlowBindingOverrides": {},
|
"authenticationFlowBindingOverrides": {},
|
||||||
"fullScopeAllowed": false,
|
"fullScopeAllowed": true,
|
||||||
"nodeReRegistrationTimeout": 0,
|
"nodeReRegistrationTimeout": 0,
|
||||||
"protocolMappers": [
|
"protocolMappers": [
|
||||||
{
|
{
|
||||||
@ -1574,14 +1591,14 @@
|
|||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"allowed-protocol-mapper-types": [
|
"allowed-protocol-mapper-types": [
|
||||||
"oidc-full-name-mapper",
|
|
||||||
"oidc-usermodel-attribute-mapper",
|
|
||||||
"oidc-address-mapper",
|
|
||||||
"saml-user-attribute-mapper",
|
"saml-user-attribute-mapper",
|
||||||
"oidc-usermodel-property-mapper",
|
"oidc-sha256-pairwise-sub-mapper",
|
||||||
|
"oidc-full-name-mapper",
|
||||||
"saml-user-property-mapper",
|
"saml-user-property-mapper",
|
||||||
|
"oidc-address-mapper",
|
||||||
|
"oidc-usermodel-property-mapper",
|
||||||
"saml-role-list-mapper",
|
"saml-role-list-mapper",
|
||||||
"oidc-sha256-pairwise-sub-mapper"
|
"oidc-usermodel-attribute-mapper"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1611,14 +1628,14 @@
|
|||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"allowed-protocol-mapper-types": [
|
"allowed-protocol-mapper-types": [
|
||||||
"oidc-sha256-pairwise-sub-mapper",
|
|
||||||
"oidc-usermodel-property-mapper",
|
|
||||||
"oidc-address-mapper",
|
|
||||||
"oidc-usermodel-attribute-mapper",
|
"oidc-usermodel-attribute-mapper",
|
||||||
"oidc-full-name-mapper",
|
"oidc-full-name-mapper",
|
||||||
"saml-user-attribute-mapper",
|
"oidc-usermodel-property-mapper",
|
||||||
|
"oidc-address-mapper",
|
||||||
"saml-user-property-mapper",
|
"saml-user-property-mapper",
|
||||||
"saml-role-list-mapper"
|
"saml-role-list-mapper",
|
||||||
|
"saml-user-attribute-mapper",
|
||||||
|
"oidc-sha256-pairwise-sub-mapper"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1671,13 +1688,6 @@
|
|||||||
"providerId": "rsa-generated",
|
"providerId": "rsa-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"privateKey": [
|
|
||||||
"MIIEowIBAAKCAQEAsYUWzVfZMd6ywpBmLJYeF1U9Mgd/z3xWvl1Yq76oRPPfpcqQitN+cktWqu0hPerCVSl2ltwXDMrUwFzswG9MiM9hb+BLEld7kYiYkcFNt3lCtmmeRQEae7JwWimzeNV96Qlz0tHY8f9Zh0ffPDsLTN1HGAeRJJhI7mNQm6qCJNMCfVA/O5SWumsIn2XLnSMiQ05AACVHOLUq6rAZ2zCCaYmXTmJkuSOb8e26V303P6l63DSe5HSNXDdI00tjfFFf37q870zhvfsotrjjx0RMijy9Kjj8OZF+pFHpDRaGEi8tpQxZDnCTofTieB/Vp3QP+aTlvAyD3Q1ZnJxGQCLygwIDAQABAoIBABUJ9XMJGNQzamiVwuOWN7ht4UP8ezYvgdEA8NaLUO0PIYVIKyD7l4OwkHPPM9PfRACM2qG0MZp8sCyg4WxIeepy+D979oRqJYUmNRLSipqWlASuItRXIPjiY99uYXdjh2R8Os5pvCD+MZxPX9KHGuaVXmzSJMO7YAAPeYkMHcLYTp/U0c65Ztaaz1zz1FeyvpjkLr9SHiMcIN51zFmhvT1tcRIqy4zidisjrTSUr/KPVxeJtrEfyhTGk3z41yJf5YbeaxaMjJR5x0WXzt1fWVmA/V1bWa2Zlj9d8AxDReA1p7Lpstz34PRoCMj9bmFguI2+RTw6K0D++Jydfxmh8vUCgYEA5Zwk2r3TFO3i3V70LOn6CLzn15yLeuSIJ9p2os70jQOmFMCreLdcUbCaiUe7UV/IIVftbcxhFm9zECXZXX0wubcmHZqyptlbuAn1de4QkLJixXo1A7ZQXBEZk22WN2naXHQF5oK6lh/VSLcZBajTsyvBm5JWXrd8djjG06MugA8CgYEAxexKI5IwcLhpMDV9UPQb/+lDWHVqCT2xwYxnZ85y+5gmrOyyT7mIChz3DFYiaw4CHJWmBkIDBaiDgLEgQk4QXWzYshXawShBHnv1h08bVMMw98Ivec7ZRkV+/ET30YRwC2Uyk4bm4HpwVV5GCFhC4aAvRcCA1CIJk3MwcOwksk0CgYEAqxyaOomMbOR7VQ4WWgJkW26sOHppV8RH06tzDhG9HfnCI2USZHwBSL+b6wKSDiqbMn4cat8M23NjBH2wZ4OMdFqRBS7sRHtnZtfFHYW0wqCuCwzvxTxw1qvHq57Xe6RfHtc4LnjuJELE59PLyfPvEG9jcVS1GREUp+XYBpBtbvECgYAMhWBDU9JAr0noRNoCrw6+Z9Fc3UCyCPcf2XQJOyRHCl8X/XliVchna2GtpB1VTHORv13bc32hdAGtuIbj6vBaGLK0wXEvWw6TkR/9SWHfQOHuKpi6Sf2w1mCsMOjElm5IKkTC1Hvyo4xLukUP7hV9FJcpAH6l7OlSLK1Z13aS2QKBgB6w4gvmVEQruHV5+K60OatuFojr+kxJwmzCb5uKOULUFezT2pA3p3l6IWxGL2XtM+LD0SiZE3KZJUzf+LatYlBU9ek4F1krkVNUTRZpzUa0oADbymCL1chM4oPIs7sISQlFIH2wOSZt6Blvcw0E0wfjd9Gv/LHxcMnlRb1t1sLk"
|
|
||||||
],
|
|
||||||
"keyUse": ["SIG"],
|
|
||||||
"certificate": [
|
|
||||||
"MIICnTCCAYUCBgGQBsyplzANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdteXJlYWxtMB4XDTI0MDYxMTEwMTQ1NFoXDTM0MDYxMTEwMTYzNFowEjEQMA4GA1UEAwwHbXlyZWFsbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGFFs1X2THessKQZiyWHhdVPTIHf898Vr5dWKu+qETz36XKkIrTfnJLVqrtIT3qwlUpdpbcFwzK1MBc7MBvTIjPYW/gSxJXe5GImJHBTbd5QrZpnkUBGnuycFops3jVfekJc9LR2PH/WYdH3zw7C0zdRxgHkSSYSO5jUJuqgiTTAn1QPzuUlrprCJ9ly50jIkNOQAAlRzi1KuqwGdswgmmJl05iZLkjm/Htuld9Nz+petw0nuR0jVw3SNNLY3xRX9+6vO9M4b37KLa448dETIo8vSo4/DmRfqRR6Q0WhhIvLaUMWQ5wk6H04ngf1ad0D/mk5bwMg90NWZycRkAi8oMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAVS+gJshIFX6cmBGI8UaOOI/9+XFb4Gi+DHaHVWVVHTd14MoqNK1bmmyTHbGIZbvK8UqgJ9+FhJX1ejx17d4KBzkZI3tYvPnVacHvaw1CIUMZ1Ini6u+UGUTnIlnQzCG0pcTKjOZXf3ih1B2CKdwyC7XeXyEJHicAIG7XfzYfYd9DYHvA+h6hrXaQcNJMW7WFNbtb3fJhtlv5P1Iw+ZEGdj15ukMI0bg2OEQA0F3jIw6QZpigSAGuai3HOY6OgoPO82d7TyTYlNhuwyutWr9izl6QMc2R7BmRfW9XQj4ICR2VWJiL9nqz+SOyqnjQiOObuw8Vywb8c36R1Ym1aaGjOw=="
|
|
||||||
],
|
|
||||||
"priority": ["100"]
|
"priority": ["100"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1687,13 +1697,6 @@
|
|||||||
"providerId": "rsa-enc-generated",
|
"providerId": "rsa-enc-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"privateKey": [
|
|
||||||
"MIIEogIBAAKCAQEAkQtefHy82e8d5dVWN00LnGI5YmBOTKh0tgqayVRjqLH6u3NfgJVVIe0tFnxa7Wka/ySHrn1KSsW52czZ4uPXLUo4sXBkQxyyFXeZiWN8H+9WiUQ+0hefZF4es5ZPhY2VpeMK9XAnphC362LFLVycXulkpJcQ+4DjI99To4LLyJmjQvsVaJ7amoVJ5xd62eUv+D7f2+jwuaTwjGE3+MWZADXjVxsUY1qJuGLGKnLkNNxJNMDhvnKYw+aa3Z4V90fQVyjN1Volgw3DdA59o4wrWEy+2xHc6j2ESi8+cM60fWzZU9sp2XkyJoCnV7nmwk7pZkDy3zvAkeOWzrr3OWeR3wIDAQABAoIBACWMcet8R0+L7YuATQ+H7IeRjhV/pQWHXp9541RXem1DlgtM9N5Oynk78z4s90Uavphqlo1/deohgdl2hLmODjh1THPzCqGtHhUcnyzICmwiA58JgdHVt7e9/eiz8uY6HxGQ01dyr3D4RwSyzyTNItYXSayqRwU0+phgykA8LhFCAQM/UkRXDf6UCFKBhDyE7VPBaDv0xyxNb7dKtE7C6Qo5t5D40xCfQ8ni8OcD5RvshQq5xOWcw7igxAhlmXCu1fuO2CDiSiqXLMENs4NlwilQ3caMXAIzUiblaKwCrrK2noBoitx6vuOR2tKmIZSlTyDAG4vLQQtOHk53hBoupGECgYEAx4jSmLM9uUzNwNY1zfs8iNswxbU3YibNe2Q+IFmOQofvTaq1jBBxdPWX5ifIbuTvOAA33pmJRh+BtWzOBBQC7Z4i9mdfvyWB6s8t9nnTnWIY5Hj+hV5gaqae59MjdudsORR887fxzPIeAwwaETfKaZnYpC6zLaE3BXwhIcjlFTcCgYEAuhcKf16JkEYNIwanVHpUXjFxwAThAogHWZAngRokmai67Iulx+rSUhhtOIXtmjj/EaObsrqo5yCKAVZ5EbPTOajdd9RtFzH6q3bRjRdp8o8ZVx4c1vMNaOnLbvK4YzJlKSZN9N7m255Mg+/ea3veKVZsSVHDMnuYmH8GjncjPJkCgYAOIUlQmPjZA3BapJDA2nbJ9kO47IFUiQzqHQotPkpNudSfemRK2+s87htoqA6Qk9PA8nsCX3sSJS8JSwA317bxXs55Bo8IOT6/AxbtKmlq7sR2gX78sNdBFjWQkyoixHasgB/tHmyYJ9kqPBQoffvuiH+H+OqlY5JC6CxseQ6H9wKBgF69Hj4MDjLiRwve9k9+2/b8azHcCgX05PEG/+WtPpbwHQIScnseJKdhAjH1lSqf+9OqHLlYaGcK3Nejg42spEvFmcLI5iUZ78lde3++PNUdX0RH81zHbrtL06MPdSojXPcfJi8VUCjdJY1CEFVeQZOACS8mrh7EZ8KzYM4k/055AoGAYqjBv3WS8ul7kAsjpZKpIw1QZZaTjBSmLpjB6X8InF+Zihjgm80Dd4RMFnMnEawhFBvnpklvyw5Ce6NSwcC137kN3NVpJypykkXuYkimg7OxgJjR7YFdbQWJWlc+1eB81WTHcEOHVI/DmeV2yVJcv6kA2iC+3/JA0VoJxvrRBKc="
|
|
||||||
],
|
|
||||||
"keyUse": ["ENC"],
|
|
||||||
"certificate": [
|
|
||||||
"MIICnTCCAYUCBgGQBsyq0jANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdteXJlYWxtMB4XDTI0MDYxMTEwMTQ1NFoXDTM0MDYxMTEwMTYzNFowEjEQMA4GA1UEAwwHbXlyZWFsbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJELXnx8vNnvHeXVVjdNC5xiOWJgTkyodLYKmslUY6ix+rtzX4CVVSHtLRZ8Wu1pGv8kh659SkrFudnM2eLj1y1KOLFwZEMcshV3mYljfB/vVolEPtIXn2ReHrOWT4WNlaXjCvVwJ6YQt+tixS1cnF7pZKSXEPuA4yPfU6OCy8iZo0L7FWie2pqFSecXetnlL/g+39vo8Lmk8IxhN/jFmQA141cbFGNaibhixipy5DTcSTTA4b5ymMPmmt2eFfdH0FcozdVaJYMNw3QOfaOMK1hMvtsR3Oo9hEovPnDOtH1s2VPbKdl5MiaAp1e55sJO6WZA8t87wJHjls669zlnkd8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAD9wQ+CJ0FRgls3JrUzxwHLgrJ3Yo4+mDFpSe1rh2XYK5FEIWDWSqxaXI3p0cOZq75RZmI2xV8oaiJMUz9WMZkbNe/KtGRzHY1N9AZooicGIsnFu1t++b8taFxxpvKWZgnbOum2PZlfcNiXL0QeMv0wwhfn9zKA9W1DRcqYGbIamoyVlumvbNyIjqXJKwGYIOW6GNt7v3wJl5AJw8qAU/O/DQwWwmzcnFGNRxRxAwI7we8EiQ5JlG0Wi+nyAQn74o3RhNr3zsY0ndmFx9bFV4BBo2AiYGozCDOCCG5HvrmoDbrm//wmGRv0tCwueBzWHL2mhtbZ6sGWmMWfiTJ2HPpg=="
|
|
||||||
],
|
|
||||||
"priority": ["100"],
|
"priority": ["100"],
|
||||||
"algorithm": ["RSA-OAEP"]
|
"algorithm": ["RSA-OAEP"]
|
||||||
}
|
}
|
||||||
@ -1704,8 +1707,6 @@
|
|||||||
"providerId": "aes-generated",
|
"providerId": "aes-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"kid": ["1c1d0c8a-6f0b-48a9-a66f-488489137d85"],
|
|
||||||
"secret": ["N4wzheVYYBWxFn9VGWTPQQ"],
|
|
||||||
"priority": ["100"]
|
"priority": ["100"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1715,10 +1716,6 @@
|
|||||||
"providerId": "hmac-generated",
|
"providerId": "hmac-generated",
|
||||||
"subComponents": {},
|
"subComponents": {},
|
||||||
"config": {
|
"config": {
|
||||||
"kid": ["ce43821c-6cfd-4ea9-a29a-a724a37e6955"],
|
|
||||||
"secret": [
|
|
||||||
"j_8WeQHYt5R6coay0IOUeu9hGvCoJsgnENSoYm0gDlDx6IHOg-f6p17QIaesNmgrzXtJDRpYMhSjpTMHOnHCHLxwUM4eVg9TcszffndB850Yj3PHPeCc5aoHcpYzWN9NDZZ02nBYA04nfbkdlLXiGlpS3I3e502e4DX3rFtbFZ0"
|
|
||||||
],
|
|
||||||
"priority": ["100"],
|
"priority": ["100"],
|
||||||
"algorithm": ["HS512"]
|
"algorithm": ["HS512"]
|
||||||
}
|
}
|
||||||
@ -2388,7 +2385,7 @@
|
|||||||
"clientSessionMaxLifespan": "0",
|
"clientSessionMaxLifespan": "0",
|
||||||
"organizationsEnabled": "false"
|
"organizationsEnabled": "false"
|
||||||
},
|
},
|
||||||
"keycloakVersion": "25.0.0",
|
"keycloakVersion": "26.0.6",
|
||||||
"userManagedAccessAllowed": false,
|
"userManagedAccessAllowed": false,
|
||||||
"organizationsEnabled": false,
|
"organizationsEnabled": false,
|
||||||
"clientProfiles": {
|
"clientProfiles": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { BuildContext } from "../shared/buildContext";
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
import { exclude } from "tsafe/exclude";
|
import { exclude } from "tsafe/exclude";
|
||||||
import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
|
import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
|
||||||
import { CONTAINER_NAME } from "../shared/constants";
|
import { CONTAINER_NAME, KEYCLOAKIFY_SPA_DEV_SERVER_PORT } from "../shared/constants";
|
||||||
import { SemVer } from "../tools/SemVer";
|
import { SemVer } from "../tools/SemVer";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
@ -27,6 +27,7 @@ import { isInside } from "../tools/isInside";
|
|||||||
import { existsAsync } from "../tools/fs.existsAsync";
|
import { existsAsync } from "../tools/fs.existsAsync";
|
||||||
import { rm } from "../tools/fs.rm";
|
import { rm } from "../tools/fs.rm";
|
||||||
import { downloadAndExtractArchive } from "../tools/downloadAndExtractArchive";
|
import { downloadAndExtractArchive } from "../tools/downloadAndExtractArchive";
|
||||||
|
import { startViteDevServer } from "./startViteDevServer";
|
||||||
|
|
||||||
export async function command(params: {
|
export async function command(params: {
|
||||||
buildContext: BuildContext;
|
buildContext: BuildContext;
|
||||||
@ -379,6 +380,54 @@ export async function command(params: {
|
|||||||
const port =
|
const port =
|
||||||
cliCommandOptions.port ?? buildContext.startKeycloakOptions.port ?? DEFAULT_PORT;
|
cliCommandOptions.port ?? buildContext.startKeycloakOptions.port ?? DEFAULT_PORT;
|
||||||
|
|
||||||
|
const devServerPort = (() => {
|
||||||
|
const hasSpaUi =
|
||||||
|
buildContext.implementedThemeTypes.admin.isImplemented ||
|
||||||
|
(buildContext.implementedThemeTypes.account.isImplemented &&
|
||||||
|
buildContext.implementedThemeTypes.account.type === "Single-Page");
|
||||||
|
|
||||||
|
if (!hasSpaUi) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildContext.bundler !== "vite") {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
[
|
||||||
|
`WARNING: Since you are using ${buildContext.bundler} instead of Vite,`,
|
||||||
|
`you'll have to wait serval seconds for the changes you made on your account or admin theme to be reflected in the browser.\n`,
|
||||||
|
`For a better development experience, consider migrating to Vite.`
|
||||||
|
].join(" ")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keycloakMajorVersionNumber < 25) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow(
|
||||||
|
[
|
||||||
|
`WARNING: Your account or admin theme can't be tested with hot module replacement on Keycloak ${keycloakMajorVersionNumber}.`,
|
||||||
|
`This mean that you'll have to wait serval seconds for the changes to be reflected in the browser.`,
|
||||||
|
`For a better development experience, select a more recent version of Keycloak.`
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return port + 1;
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (devServerPort !== undefined) {
|
||||||
|
startViteDevServer({
|
||||||
|
buildContext,
|
||||||
|
port: devServerPort
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const SPACE_PLACEHOLDER = "SPACE_PLACEHOLDER_xKLmdPd";
|
const SPACE_PLACEHOLDER = "SPACE_PLACEHOLDER_xKLmdPd";
|
||||||
|
|
||||||
const dockerRunArgs: string[] = [
|
const dockerRunArgs: string[] = [
|
||||||
@ -386,6 +435,11 @@ export async function command(params: {
|
|||||||
`--name${SPACE_PLACEHOLDER}${CONTAINER_NAME}`,
|
`--name${SPACE_PLACEHOLDER}${CONTAINER_NAME}`,
|
||||||
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN=admin`,
|
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN=admin`,
|
||||||
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN_PASSWORD=admin`,
|
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN_PASSWORD=admin`,
|
||||||
|
...(devServerPort === undefined
|
||||||
|
? []
|
||||||
|
: [
|
||||||
|
`-e${SPACE_PLACEHOLDER}${KEYCLOAKIFY_SPA_DEV_SERVER_PORT}=${devServerPort}`
|
||||||
|
]),
|
||||||
...(buildContext.startKeycloakOptions.dockerExtraArgs.length === 0
|
...(buildContext.startKeycloakOptions.dockerExtraArgs.length === 0
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
@ -592,6 +646,44 @@ export async function command(params: {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.on("all", async (...[, filePath]) => {
|
.on("all", async (...[, filePath]) => {
|
||||||
|
ignore_account_spa: {
|
||||||
|
const doImplementAccountSpa =
|
||||||
|
buildContext.implementedThemeTypes.account.isImplemented &&
|
||||||
|
buildContext.implementedThemeTypes.account.type === "Single-Page";
|
||||||
|
|
||||||
|
if (!doImplementAccountSpa) {
|
||||||
|
break ignore_account_spa;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isInside({
|
||||||
|
dirPath: pathJoin(buildContext.themeSrcDirPath, "account"),
|
||||||
|
filePath
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
break ignore_account_spa;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ignore_admin: {
|
||||||
|
if (!buildContext.implementedThemeTypes.admin.isImplemented) {
|
||||||
|
break ignore_admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isInside({
|
||||||
|
dirPath: pathJoin(buildContext.themeSrcDirPath, "admin"),
|
||||||
|
filePath
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
break ignore_admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`Detected changes in ${filePath}`);
|
console.log(`Detected changes in ${filePath}`);
|
||||||
|
|
||||||
await waitForDebounce();
|
await waitForDebounce();
|
||||||
|
39
src/bin/start-keycloak/startViteDevServer.ts
Normal file
39
src/bin/start-keycloak/startViteDevServer.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import * as child_process from "child_process";
|
||||||
|
import { assert } from "tsafe/assert";
|
||||||
|
import type { BuildContext } from "../shared/buildContext";
|
||||||
|
import chalk from "chalk";
|
||||||
|
import { VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES } from "../shared/constants";
|
||||||
|
|
||||||
|
export type BuildContextLike = {
|
||||||
|
projectDirPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert<BuildContext extends BuildContextLike ? true : false>();
|
||||||
|
|
||||||
|
export function startViteDevServer(params: {
|
||||||
|
buildContext: BuildContextLike;
|
||||||
|
port: number;
|
||||||
|
}): void {
|
||||||
|
const { buildContext, port } = params;
|
||||||
|
|
||||||
|
console.log(chalk.blue(`$ npx vite dev --port ${port}`));
|
||||||
|
|
||||||
|
const child = child_process.spawn("npx", ["vite", "dev", "--port", `${port}`], {
|
||||||
|
cwd: buildContext.projectDirPath,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
[VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.READ_KC_CONTEXT_FROM_URL]: "true"
|
||||||
|
},
|
||||||
|
shell: true
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stdout.on("data", data => {
|
||||||
|
if (!data.toString("utf8").includes("[vite] hmr")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdout.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stderr.on("data", data => process.stderr.write(data));
|
||||||
|
}
|
@ -6,19 +6,19 @@ import { assert, type Equals } from "tsafe/assert";
|
|||||||
export async function crawlAsync(params: {
|
export async function crawlAsync(params: {
|
||||||
dirPath: string;
|
dirPath: string;
|
||||||
returnedPathsType: "absolute" | "relative to dirPath";
|
returnedPathsType: "absolute" | "relative to dirPath";
|
||||||
onFileFound: (filePath: string) => void;
|
onFileFound: (filePath: string) => Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
const { dirPath, returnedPathsType, onFileFound } = params;
|
const { dirPath, returnedPathsType, onFileFound } = params;
|
||||||
|
|
||||||
await crawlAsyncRec({
|
await crawlAsyncRec({
|
||||||
dirPath,
|
dirPath,
|
||||||
onFileFound: ({ filePath }) => {
|
onFileFound: async ({ filePath }) => {
|
||||||
switch (returnedPathsType) {
|
switch (returnedPathsType) {
|
||||||
case "absolute":
|
case "absolute":
|
||||||
onFileFound(filePath);
|
await onFileFound(filePath);
|
||||||
return;
|
return;
|
||||||
case "relative to dirPath":
|
case "relative to dirPath":
|
||||||
onFileFound(pathRelative(dirPath, filePath));
|
await onFileFound(pathRelative(dirPath, filePath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert<Equals<typeof returnedPathsType, never>>();
|
assert<Equals<typeof returnedPathsType, never>>();
|
||||||
@ -28,7 +28,7 @@ export async function crawlAsync(params: {
|
|||||||
|
|
||||||
async function crawlAsyncRec(params: {
|
async function crawlAsyncRec(params: {
|
||||||
dirPath: string;
|
dirPath: string;
|
||||||
onFileFound: (params: { filePath: string }) => void;
|
onFileFound: (params: { filePath: string }) => Promise<void>;
|
||||||
}) {
|
}) {
|
||||||
const { dirPath, onFileFound } = params;
|
const { dirPath, onFileFound } = params;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ async function crawlAsyncRec(params: {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onFileFound({ filePath: fileOrDirPath });
|
await onFileFound({ filePath: fileOrDirPath });
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
29
src/bin/tools/isTrackedByGit.ts
Normal file
29
src/bin/tools/isTrackedByGit.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import * as child_process from "child_process";
|
||||||
|
import { dirname as pathDirname, basename as pathBasename } from "path";
|
||||||
|
import { Deferred } from "evt/tools/Deferred";
|
||||||
|
|
||||||
|
export function getIsTrackedByGit(params: { filePath: string }): Promise<boolean> {
|
||||||
|
const { filePath } = params;
|
||||||
|
|
||||||
|
const dIsTracked = new Deferred<boolean>();
|
||||||
|
|
||||||
|
child_process.exec(
|
||||||
|
`git ls-files --error-unmatch ${pathBasename(filePath)}`,
|
||||||
|
{ cwd: pathDirname(filePath) },
|
||||||
|
error => {
|
||||||
|
if (error === null) {
|
||||||
|
dIsTracked.resolve(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.code === 1) {
|
||||||
|
dIsTracked.resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dIsTracked.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return dIsTracked.pr;
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { join as pathJoin, dirname as pathDirname } from "path";
|
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||||
import * as fsPr from "fs/promises";
|
import * as fsPr from "fs/promises";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import { getInstalledModuleDirPath } from "../tools/getInstalledModuleDirPath";
|
import { getInstalledModuleDirPath } from "../tools/getInstalledModuleDirPath";
|
||||||
import { exclude } from "tsafe/exclude";
|
import { exclude } from "tsafe/exclude";
|
||||||
|
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin, dirname as pathDirname } from "path";
|
||||||
import * as child_process from "child_process";
|
import * as child_process from "child_process";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { assert, type Equals, is } from "tsafe/assert";
|
||||||
|
import { id } from "tsafe/id";
|
||||||
|
import { objectKeys } from "tsafe/objectKeys";
|
||||||
|
import { getAbsoluteAndInOsFormatPath } from "./getAbsoluteAndInOsFormatPath";
|
||||||
|
import { exclude } from "tsafe/exclude";
|
||||||
|
import { rmSync } from "./fs.rmSync";
|
||||||
|
|
||||||
export function npmInstall(params: { packageJsonDirPath: string }) {
|
export function npmInstall(params: { packageJsonDirPath: string }) {
|
||||||
const { packageJsonDirPath } = params;
|
const { packageJsonDirPath } = params;
|
||||||
@ -48,6 +55,27 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|||||||
|
|
||||||
console.log(`Installing the new dependencies...`);
|
console.log(`Installing the new dependencies...`);
|
||||||
|
|
||||||
|
install_without_breaking_links: {
|
||||||
|
if (packageManagerBinName !== "yarn") {
|
||||||
|
break install_without_breaking_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
const garronejLinkInfos = getGarronejLinkInfos({ packageJsonDirPath });
|
||||||
|
|
||||||
|
if (garronejLinkInfos === undefined) {
|
||||||
|
break install_without_breaking_links;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.green("Installing in a way that won't break the links..."));
|
||||||
|
|
||||||
|
installWithoutBreakingLinks({
|
||||||
|
packageJsonDirPath,
|
||||||
|
garronejLinkInfos
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
child_process.execSync(`${packageManagerBinName} install`, {
|
child_process.execSync(`${packageManagerBinName} install`, {
|
||||||
cwd: packageJsonDirPath,
|
cwd: packageJsonDirPath,
|
||||||
@ -61,3 +89,370 @@ export function npmInstall(params: { packageJsonDirPath: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGarronejLinkInfos(params: {
|
||||||
|
packageJsonDirPath: string;
|
||||||
|
}): { linkedModuleNames: string[]; yarnHomeDirPath: string } | undefined {
|
||||||
|
const { packageJsonDirPath } = params;
|
||||||
|
|
||||||
|
const nodeModuleDirPath = pathJoin(packageJsonDirPath, "node_modules");
|
||||||
|
|
||||||
|
if (!fs.existsSync(nodeModuleDirPath)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const linkedModuleNames: string[] = [];
|
||||||
|
|
||||||
|
let yarnHomeDirPath: string | undefined = undefined;
|
||||||
|
|
||||||
|
const getIsLinkedByGarronejScript = (path: string) => {
|
||||||
|
let realPath: string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
realPath = fs.readlinkSync(path);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const doesIncludeYarnHome = realPath.includes(".yarn_home");
|
||||||
|
|
||||||
|
if (!doesIncludeYarnHome) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_yarnHomeDirPath: {
|
||||||
|
if (yarnHomeDirPath !== undefined) {
|
||||||
|
break set_yarnHomeDirPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [firstElement] = getAbsoluteAndInOsFormatPath({
|
||||||
|
pathIsh: realPath,
|
||||||
|
cwd: pathDirname(path)
|
||||||
|
}).split(".yarn_home");
|
||||||
|
|
||||||
|
yarnHomeDirPath = pathJoin(firstElement, ".yarn_home");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const basename of fs.readdirSync(nodeModuleDirPath)) {
|
||||||
|
const path = pathJoin(nodeModuleDirPath, basename);
|
||||||
|
|
||||||
|
if (fs.lstatSync(path).isSymbolicLink()) {
|
||||||
|
if (basename.startsWith("@")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getIsLinkedByGarronejScript(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedModuleNames.push(basename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.lstatSync(path).isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basename.startsWith("@")) {
|
||||||
|
for (const subBasename of fs.readdirSync(path)) {
|
||||||
|
const subPath = pathJoin(path, subBasename);
|
||||||
|
|
||||||
|
if (!fs.lstatSync(subPath).isSymbolicLink()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getIsLinkedByGarronejScript(subPath)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedModuleNames.push(`${basename}/${subBasename}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yarnHomeDirPath === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { linkedModuleNames, yarnHomeDirPath };
|
||||||
|
}
|
||||||
|
|
||||||
|
function installWithoutBreakingLinks(params: {
|
||||||
|
packageJsonDirPath: string;
|
||||||
|
garronejLinkInfos: Exclude<ReturnType<typeof getGarronejLinkInfos>, undefined>;
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
packageJsonDirPath,
|
||||||
|
garronejLinkInfos: { linkedModuleNames, yarnHomeDirPath }
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
const parsedPackageJson = (() => {
|
||||||
|
const packageJsonFilePath = pathJoin(packageJsonDirPath, "package.json");
|
||||||
|
|
||||||
|
type ParsedPackageJson = {
|
||||||
|
scripts?: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const zParsedPackageJson = (() => {
|
||||||
|
type TargetType = ParsedPackageJson;
|
||||||
|
|
||||||
|
const zTargetType = z.object({
|
||||||
|
scripts: z.record(z.string()).optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
type InferredType = z.infer<typeof zTargetType>;
|
||||||
|
|
||||||
|
assert<Equals<TargetType, InferredType>>;
|
||||||
|
|
||||||
|
return id<z.ZodType<TargetType>>(zTargetType);
|
||||||
|
})();
|
||||||
|
|
||||||
|
const parsedPackageJson = JSON.parse(
|
||||||
|
fs.readFileSync(packageJsonFilePath).toString("utf8")
|
||||||
|
) as unknown;
|
||||||
|
|
||||||
|
zParsedPackageJson.parse(parsedPackageJson);
|
||||||
|
assert(is<ParsedPackageJson>(parsedPackageJson));
|
||||||
|
|
||||||
|
return parsedPackageJson;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const isImplementedScriptByName = {
|
||||||
|
postinstall: false,
|
||||||
|
prepare: false
|
||||||
|
};
|
||||||
|
|
||||||
|
delete_postinstall_script: {
|
||||||
|
if (parsedPackageJson.scripts === undefined) {
|
||||||
|
break delete_postinstall_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const scriptName of objectKeys(isImplementedScriptByName)) {
|
||||||
|
if (parsedPackageJson.scripts[scriptName] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
isImplementedScriptByName[scriptName] = true;
|
||||||
|
|
||||||
|
delete parsedPackageJson.scripts[scriptName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tmpProjectDirPath = pathJoin(yarnHomeDirPath, "tmpProject");
|
||||||
|
|
||||||
|
if (fs.existsSync(tmpProjectDirPath)) {
|
||||||
|
rmSync(tmpProjectDirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.mkdirSync(tmpProjectDirPath, { recursive: true });
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
pathJoin(tmpProjectDirPath, "package.json"),
|
||||||
|
JSON.stringify(parsedPackageJson, undefined, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
const YARN_LOCK = "yarn.lock";
|
||||||
|
|
||||||
|
fs.copyFileSync(
|
||||||
|
pathJoin(packageJsonDirPath, YARN_LOCK),
|
||||||
|
pathJoin(tmpProjectDirPath, YARN_LOCK)
|
||||||
|
);
|
||||||
|
|
||||||
|
child_process.execSync(`yarn install`, {
|
||||||
|
cwd: tmpProjectDirPath,
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
|
||||||
|
// NOTE: Moving the modules from the tmp project to the actual project
|
||||||
|
// without messing up the links.
|
||||||
|
{
|
||||||
|
const { getAreSameVersions } = (() => {
|
||||||
|
type ParsedPackageJson = {
|
||||||
|
version: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const zParsedPackageJson = (() => {
|
||||||
|
type TargetType = ParsedPackageJson;
|
||||||
|
|
||||||
|
const zTargetType = z.object({
|
||||||
|
version: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
type InferredType = z.infer<typeof zTargetType>;
|
||||||
|
|
||||||
|
assert<Equals<TargetType, InferredType>>;
|
||||||
|
|
||||||
|
return id<z.ZodType<TargetType>>(zTargetType);
|
||||||
|
})();
|
||||||
|
|
||||||
|
function readVersion(params: { moduleDirPath: string }): string {
|
||||||
|
const { moduleDirPath } = params;
|
||||||
|
|
||||||
|
const packageJsonFilePath = pathJoin(moduleDirPath, "package.json");
|
||||||
|
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
fs.readFileSync(packageJsonFilePath).toString("utf8")
|
||||||
|
);
|
||||||
|
|
||||||
|
zParsedPackageJson.parse(packageJson);
|
||||||
|
assert(is<ParsedPackageJson>(packageJson));
|
||||||
|
|
||||||
|
return packageJson.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAreSameVersions(params: {
|
||||||
|
moduleDirPath_a: string;
|
||||||
|
moduleDirPath_b: string;
|
||||||
|
}): boolean {
|
||||||
|
const { moduleDirPath_a, moduleDirPath_b } = params;
|
||||||
|
|
||||||
|
return (
|
||||||
|
readVersion({ moduleDirPath: moduleDirPath_a }) ===
|
||||||
|
readVersion({ moduleDirPath: moduleDirPath_b })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { getAreSameVersions };
|
||||||
|
})();
|
||||||
|
|
||||||
|
const nodeModulesDirPath_tmpProject = pathJoin(tmpProjectDirPath, "node_modules");
|
||||||
|
const nodeModulesDirPath = pathJoin(packageJsonDirPath, "node_modules");
|
||||||
|
|
||||||
|
const modulePaths = fs
|
||||||
|
.readdirSync(nodeModulesDirPath_tmpProject)
|
||||||
|
.map(basename => {
|
||||||
|
if (basename.startsWith(".")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = pathJoin(nodeModulesDirPath_tmpProject, basename);
|
||||||
|
|
||||||
|
if (basename.startsWith("@")) {
|
||||||
|
return fs
|
||||||
|
.readdirSync(path)
|
||||||
|
.map(subBasename => {
|
||||||
|
if (subBasename.startsWith(".")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subPath = pathJoin(path, subBasename);
|
||||||
|
|
||||||
|
if (!fs.lstatSync(subPath).isDirectory()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
moduleName: `${basename}/${subBasename}`,
|
||||||
|
moduleDirPath_tmpProject: subPath,
|
||||||
|
moduleDirPath: pathJoin(
|
||||||
|
nodeModulesDirPath,
|
||||||
|
basename,
|
||||||
|
subBasename
|
||||||
|
)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(exclude(undefined));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.lstatSync(path).isDirectory()) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
moduleName: basename,
|
||||||
|
moduleDirPath_tmpProject: path,
|
||||||
|
moduleDirPath: pathJoin(nodeModulesDirPath, basename)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
})
|
||||||
|
.filter(exclude(undefined))
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
for (const {
|
||||||
|
moduleName,
|
||||||
|
moduleDirPath,
|
||||||
|
moduleDirPath_tmpProject
|
||||||
|
} of modulePaths) {
|
||||||
|
if (linkedModuleNames.includes(moduleName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let doesTargetModuleExist = false;
|
||||||
|
|
||||||
|
skip_condition: {
|
||||||
|
if (!fs.existsSync(moduleDirPath)) {
|
||||||
|
break skip_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
doesTargetModuleExist = true;
|
||||||
|
|
||||||
|
const areSameVersions = getAreSameVersions({
|
||||||
|
moduleDirPath_a: moduleDirPath,
|
||||||
|
moduleDirPath_b: moduleDirPath_tmpProject
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!areSameVersions) {
|
||||||
|
break skip_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doesTargetModuleExist) {
|
||||||
|
rmSync(moduleDirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const dirPath = pathDirname(moduleDirPath);
|
||||||
|
|
||||||
|
if (!fs.existsSync(dirPath)) {
|
||||||
|
fs.mkdirSync(dirPath, { recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.renameSync(moduleDirPath_tmpProject, moduleDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
move_bin: {
|
||||||
|
const binDirPath_tmpProject = pathJoin(nodeModulesDirPath_tmpProject, ".bin");
|
||||||
|
const binDirPath = pathJoin(nodeModulesDirPath, ".bin");
|
||||||
|
|
||||||
|
if (!fs.existsSync(binDirPath_tmpProject)) {
|
||||||
|
break move_bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const basename of fs.readdirSync(binDirPath_tmpProject)) {
|
||||||
|
const path_tmpProject = pathJoin(binDirPath_tmpProject, basename);
|
||||||
|
const path = pathJoin(binDirPath, basename);
|
||||||
|
|
||||||
|
if (fs.existsSync(path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.renameSync(path_tmpProject, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.cpSync(
|
||||||
|
pathJoin(tmpProjectDirPath, YARN_LOCK),
|
||||||
|
pathJoin(packageJsonDirPath, YARN_LOCK)
|
||||||
|
);
|
||||||
|
|
||||||
|
rmSync(tmpProjectDirPath, { recursive: true });
|
||||||
|
|
||||||
|
for (const scriptName of objectKeys(isImplementedScriptByName)) {
|
||||||
|
if (!isImplementedScriptByName[scriptName]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child_process.execSync(`yarn run ${scriptName}`, {
|
||||||
|
cwd: packageJsonDirPath,
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { getNodeModulesBinDirPath } from "./nodeModulesBinDirPath";
|
import { getNodeModulesBinDirPath } from "./nodeModulesBinDirPath";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin, resolve as pathResolve } from "path";
|
||||||
import * as fsPr from "fs/promises";
|
import * as fsPr from "fs/promises";
|
||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert, is } from "tsafe/assert";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
|
import * as crypto from "crypto";
|
||||||
|
import { symToStr } from "tsafe/symToStr";
|
||||||
|
import { readThisNpmPackageVersion } from "./readThisNpmPackageVersion";
|
||||||
|
|
||||||
getIsPrettierAvailable.cache = id<boolean | undefined>(undefined);
|
getIsPrettierAvailable.cache = id<boolean | undefined>(undefined);
|
||||||
|
|
||||||
@ -25,28 +28,60 @@ export async function getIsPrettierAvailable(): Promise<boolean> {
|
|||||||
return isPrettierAvailable;
|
return isPrettierAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrettierAndConfig = {
|
type PrettierAndConfigHash = {
|
||||||
prettier: typeof import("prettier");
|
prettier: typeof import("prettier");
|
||||||
config: import("prettier").Options | null;
|
configHash: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
getPrettierAndConfig.cache = id<PrettierAndConfig | undefined>(undefined);
|
getPrettier.cache = id<PrettierAndConfigHash | undefined>(undefined);
|
||||||
|
|
||||||
export async function getPrettierAndConfig(): Promise<PrettierAndConfig> {
|
export async function getPrettier(): Promise<PrettierAndConfigHash> {
|
||||||
assert(getIsPrettierAvailable());
|
assert(getIsPrettierAvailable());
|
||||||
|
|
||||||
if (getPrettierAndConfig.cache !== undefined) {
|
if (getPrettier.cache !== undefined) {
|
||||||
return getPrettierAndConfig.cache;
|
return getPrettier.cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
const prettier = await import("prettier");
|
let prettier = id<typeof import("prettier") | undefined>(undefined);
|
||||||
|
|
||||||
const prettierAndConfig: PrettierAndConfig = {
|
import_prettier: {
|
||||||
|
// NOTE: When module is linked we want to make sure we import the correct version
|
||||||
|
// of prettier, that is the one of the project, not the one of this repo.
|
||||||
|
// So we do a sketchy eval to bypass ncc.
|
||||||
|
// We make sure to only do that when linking, otherwise we import properly.
|
||||||
|
if (readThisNpmPackageVersion().startsWith("0.0.0")) {
|
||||||
|
eval(
|
||||||
|
`${symToStr({ prettier })} = require("${pathResolve(pathJoin(getNodeModulesBinDirPath(), "..", "prettier"))}")`
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(!is<undefined>(prettier));
|
||||||
|
|
||||||
|
break import_prettier;
|
||||||
|
}
|
||||||
|
|
||||||
|
prettier = await import("prettier");
|
||||||
|
}
|
||||||
|
|
||||||
|
const configHash = await (async () => {
|
||||||
|
const configFilePath = await prettier.resolveConfigFile(
|
||||||
|
pathJoin(getNodeModulesBinDirPath(), "..")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (configFilePath === null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fsPr.readFile(configFilePath);
|
||||||
|
|
||||||
|
return crypto.createHash("sha256").update(data).digest("hex");
|
||||||
|
})();
|
||||||
|
|
||||||
|
const prettierAndConfig: PrettierAndConfigHash = {
|
||||||
prettier,
|
prettier,
|
||||||
config: await prettier.resolveConfig(pathJoin(getNodeModulesBinDirPath(), ".."))
|
configHash
|
||||||
};
|
};
|
||||||
|
|
||||||
getPrettierAndConfig.cache = prettierAndConfig;
|
getPrettier.cache = prettierAndConfig;
|
||||||
|
|
||||||
return prettierAndConfig;
|
return prettierAndConfig;
|
||||||
}
|
}
|
||||||
@ -60,9 +95,23 @@ export async function runPrettier(params: {
|
|||||||
let formattedSourceCode: string;
|
let formattedSourceCode: string;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { prettier, config } = await getPrettierAndConfig();
|
const { prettier } = await getPrettier();
|
||||||
|
|
||||||
formattedSourceCode = await prettier.format(sourceCode, { ...config, filePath });
|
const { ignored, inferredParser } = await prettier.getFileInfo(filePath, {
|
||||||
|
resolveConfig: true
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ignored) {
|
||||||
|
return sourceCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = await prettier.resolveConfig(filePath);
|
||||||
|
|
||||||
|
formattedSourceCode = await prettier.format(sourceCode, {
|
||||||
|
...config,
|
||||||
|
filePath,
|
||||||
|
parser: inferredParser ?? undefined
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.red(
|
chalk.red(
|
||||||
|
24
src/bin/tools/untrackFromGit.ts
Normal file
24
src/bin/tools/untrackFromGit.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import * as child_process from "child_process";
|
||||||
|
import { dirname as pathDirname, basename as pathBasename } from "path";
|
||||||
|
import { Deferred } from "evt/tools/Deferred";
|
||||||
|
|
||||||
|
export async function untrackFromGit(params: { filePath: string }): Promise<void> {
|
||||||
|
const { filePath } = params;
|
||||||
|
|
||||||
|
const dDone = new Deferred<void>();
|
||||||
|
|
||||||
|
child_process.exec(
|
||||||
|
`git rm --cached ${pathBasename(filePath)}`,
|
||||||
|
{ cwd: pathDirname(filePath) },
|
||||||
|
error => {
|
||||||
|
if (error !== null) {
|
||||||
|
dDone.reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dDone.resolve();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await dDone.pr;
|
||||||
|
}
|
@ -10,5 +10,5 @@
|
|||||||
"rootDir": "."
|
"rootDir": "."
|
||||||
},
|
},
|
||||||
"include": ["**/*.ts", "**/*.tsx"],
|
"include": ["**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["initialize-account-theme/src", "initialize-admin-theme/src"]
|
"exclude": ["initialize-account-theme/src"]
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,16 @@ import { getIsPrettierAvailable, runPrettier } from "./tools/runPrettier";
|
|||||||
export async function command(params: { buildContext: BuildContext }) {
|
export async function command(params: { buildContext: BuildContext }) {
|
||||||
const { buildContext } = params;
|
const { buildContext } = params;
|
||||||
|
|
||||||
|
run_copy_assets_to_public: {
|
||||||
|
if (buildContext.bundler !== "webpack") {
|
||||||
|
break run_copy_assets_to_public;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { command } = await import("./copy-keycloak-resources-to-public");
|
||||||
|
|
||||||
|
await command({ buildContext });
|
||||||
|
}
|
||||||
|
|
||||||
const { hasBeenHandled } = maybeDelegateCommandToCustomHandler({
|
const { hasBeenHandled } = maybeDelegateCommandToCustomHandler({
|
||||||
commandName: "update-kc-gen",
|
commandName: "update-kc-gen",
|
||||||
buildContext
|
buildContext
|
||||||
@ -18,7 +28,7 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = pathJoin(buildContext.themeSrcDirPath, "kc-gen.tsx");
|
const filePath = pathJoin(buildContext.themeSrcDirPath, "kc.gen.tsx");
|
||||||
|
|
||||||
const hasLoginTheme = buildContext.implementedThemeTypes.login.isImplemented;
|
const hasLoginTheme = buildContext.implementedThemeTypes.login.isImplemented;
|
||||||
const hasAccountTheme = buildContext.implementedThemeTypes.account.isImplemented;
|
const hasAccountTheme = buildContext.implementedThemeTypes.account.isImplemented;
|
||||||
@ -52,7 +62,12 @@ export async function command(params: { buildContext: BuildContext }) {
|
|||||||
2
|
2
|
||||||
)};`,
|
)};`,
|
||||||
``,
|
``,
|
||||||
`type KcContext =`,
|
`/**`,
|
||||||
|
` * NOTE: Do not import this type except maybe in your entrypoint. `,
|
||||||
|
` * If you need to import the KcContext import it either from src/login/KcContext.ts or src/account/KcContext.ts.`,
|
||||||
|
` * Depending on the theme type you are working on.`,
|
||||||
|
` */`,
|
||||||
|
`export type KcContext =`,
|
||||||
hasLoginTheme && ` | import("./login/KcContext").KcContext`,
|
hasLoginTheme && ` | import("./login/KcContext").KcContext`,
|
||||||
hasAccountTheme && ` | import("./account/KcContext").KcContext`,
|
hasAccountTheme && ` | import("./account/KcContext").KcContext`,
|
||||||
hasAdminTheme && ` | import("./admin/KcContext").KcContext`,
|
hasAdminTheme && ` | import("./admin/KcContext").KcContext`,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import type { Param0 } from "tsafe";
|
import type { Param0 } from "tsafe";
|
||||||
import { type CxArg, clsx_withTransform } from "../tools/clsx_withTransform";
|
import { type CxArg, clsx_withTransform } from "../tools/clsx_withTransform";
|
||||||
import { clsx } from "../tools/clsx";
|
import { clsx } from "../tools/clsx";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert, is } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
|
|
||||||
export function createGetKcClsx<ClassKey extends string>(params: {
|
export function createGetKcClsx<ClassKey extends string>(params: {
|
||||||
defaultClasses: Record<ClassKey, string | undefined>;
|
defaultClasses: Record<ClassKey, string | undefined>;
|
||||||
|
@ -33,7 +33,7 @@ export type KcContext =
|
|||||||
| KcContext.LoginResetPassword
|
| KcContext.LoginResetPassword
|
||||||
| KcContext.LoginVerifyEmail
|
| KcContext.LoginVerifyEmail
|
||||||
| KcContext.Terms
|
| KcContext.Terms
|
||||||
| KcContext.LoginDeviceVerifyUserCode
|
| KcContext.LoginOauth2DeviceVerifyUserCode
|
||||||
| KcContext.LoginOauthGrant
|
| KcContext.LoginOauthGrant
|
||||||
| KcContext.LoginOtp
|
| KcContext.LoginOtp
|
||||||
| KcContext.LoginUsername
|
| KcContext.LoginUsername
|
||||||
@ -277,7 +277,7 @@ export declare namespace KcContext {
|
|||||||
__localizationRealmOverridesTermsText?: string;
|
__localizationRealmOverridesTermsText?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LoginDeviceVerifyUserCode = Common & {
|
export type LoginOauth2DeviceVerifyUserCode = Common & {
|
||||||
pageId: "login-oauth2-device-verify-user-code.ftl";
|
pageId: "login-oauth2-device-verify-user-code.ftl";
|
||||||
url: {
|
url: {
|
||||||
oauth2DeviceVerificationAction: string;
|
oauth2DeviceVerificationAction: string;
|
||||||
|
@ -290,7 +290,7 @@ export const kcContextMocks = [
|
|||||||
...kcContextCommonMock,
|
...kcContextCommonMock,
|
||||||
pageId: "terms.ftl"
|
pageId: "terms.ftl"
|
||||||
}),
|
}),
|
||||||
id<KcContext.LoginDeviceVerifyUserCode>({
|
id<KcContext.LoginOauth2DeviceVerifyUserCode>({
|
||||||
...kcContextCommonMock,
|
...kcContextCommonMock,
|
||||||
pageId: "login-oauth2-device-verify-user-code.ftl",
|
pageId: "login-oauth2-device-verify-user-code.ftl",
|
||||||
url: loginUrl
|
url: loginUrl
|
||||||
|
@ -11,7 +11,6 @@ export type TemplateProps<KcContext, I18n> = {
|
|||||||
displayInfo?: boolean;
|
displayInfo?: boolean;
|
||||||
displayMessage?: boolean;
|
displayMessage?: boolean;
|
||||||
displayRequiredFields?: boolean;
|
displayRequiredFields?: boolean;
|
||||||
showAnotherWayIfPresent?: boolean;
|
|
||||||
headerNode: ReactNode;
|
headerNode: ReactNode;
|
||||||
socialProvidersNode?: ReactNode;
|
socialProvidersNode?: ReactNode;
|
||||||
infoNode?: ReactNode;
|
infoNode?: ReactNode;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import "keycloakify/tools/Object.fromEntries";
|
import "keycloakify/tools/Object.fromEntries";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert, is } from "tsafe/assert";
|
||||||
|
import { extractLastParenthesisContent } from "keycloakify/tools/extractLastParenthesisContent";
|
||||||
import messages_defaultSet_fallbackLanguage from "../messages_defaultSet/en";
|
import messages_defaultSet_fallbackLanguage from "../messages_defaultSet/en";
|
||||||
import { fetchMessages_defaultSet } from "../messages_defaultSet";
|
import { fetchMessages_defaultSet } from "../messages_defaultSet";
|
||||||
import type { KcContext } from "../../KcContext";
|
import type { KcContext } from "../../KcContext";
|
||||||
import { FALLBACK_LANGUAGE_TAG } from "keycloakify/bin/shared/constants";
|
import { FALLBACK_LANGUAGE_TAG } from "keycloakify/bin/shared/constants";
|
||||||
import { id } from "tsafe/id";
|
import { id } from "tsafe/id";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import { Reflect } from "tsafe/Reflect";
|
import { Reflect } from "tsafe/Reflect";
|
||||||
import {
|
import {
|
||||||
type LanguageTag as LanguageTag_defaultSet,
|
type LanguageTag as LanguageTag_defaultSet,
|
||||||
@ -169,12 +169,10 @@ export function createGetI18n<
|
|||||||
break from_server;
|
break from_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cspell: disable-next-line
|
const lastParenthesisContent = extractLastParenthesisContent(supportedEntry.label);
|
||||||
// from "Espagnol (Español)" we want to extract "Español"
|
|
||||||
const match = supportedEntry.label.match(/[^(]+\(([^)]+)\)/);
|
|
||||||
|
|
||||||
if (match !== null) {
|
if (lastParenthesisContent !== undefined) {
|
||||||
return match[1];
|
return lastParenthesisContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return supportedEntry.label;
|
return supportedEntry.label;
|
||||||
|
@ -47,11 +47,25 @@ export function createUseI18n<
|
|||||||
|
|
||||||
function renderHtmlString(params: { htmlString: string; msgKey: string }): JSX.Element {
|
function renderHtmlString(params: { htmlString: string; msgKey: string }): JSX.Element {
|
||||||
const { htmlString, msgKey } = params;
|
const { htmlString, msgKey } = params;
|
||||||
|
|
||||||
|
const htmlString_sanitized = kcSanitize(htmlString);
|
||||||
|
|
||||||
|
const Element = (() => {
|
||||||
|
if (htmlString_sanitized.includes("<") && htmlString_sanitized.includes(">")) {
|
||||||
|
for (const tagName of ["div", "section", "article", "ul", "ol"]) {
|
||||||
|
if (htmlString_sanitized.includes(`<${tagName}`)) {
|
||||||
|
return "div";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "span";
|
||||||
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Element
|
||||||
data-kc-msg={msgKey}
|
data-kc-msg={msgKey}
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: kcSanitize(htmlString)
|
__html: htmlString_sanitized
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -83,7 +97,7 @@ export function createUseI18n<
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
add_style: {
|
add_style: {
|
||||||
const attributeName = "data-kc-i18n";
|
const attributeName = "data-kc-msg";
|
||||||
|
|
||||||
// Check if already exists in head
|
// Check if already exists in head
|
||||||
if (document.querySelector(`style[${attributeName}]`) !== null) {
|
if (document.querySelector(`style[${attributeName}]`) !== null) {
|
||||||
@ -92,7 +106,7 @@ export function createUseI18n<
|
|||||||
|
|
||||||
const styleElement = document.createElement("style");
|
const styleElement = document.createElement("style");
|
||||||
styleElement.attributes.setNamedItem(document.createAttribute(attributeName));
|
styleElement.attributes.setNamedItem(document.createAttribute(attributeName));
|
||||||
styleElement.textContent = `[data-kc-msg] { display: inline-block; }`;
|
styleElement.textContent = `div[${attributeName}] { display: inline-block; }`;
|
||||||
document.head.prepend(styleElement);
|
document.head.prepend(styleElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,28 +52,26 @@ export default function LoginConfigTotp(props: PageProps<Extract<KcContext, { pa
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>{msg("loginTotpManualStep3")}</p>
|
<p>{msg("loginTotpManualStep3")}</p>
|
||||||
<p>
|
<ul>
|
||||||
<ul>
|
<li id="kc-totp-type">
|
||||||
<li id="kc-totp-type">
|
{msg("loginTotpType")}: {msg(`loginTotp.${totp.policy.type}`)}
|
||||||
{msg("loginTotpType")}: {msg(`loginTotp.${totp.policy.type}`)}
|
</li>
|
||||||
|
<li id="kc-totp-algorithm">
|
||||||
|
{msg("loginTotpAlgorithm")}: {totp.policy.getAlgorithmKey()}
|
||||||
|
</li>
|
||||||
|
<li id="kc-totp-digits">
|
||||||
|
{msg("loginTotpDigits")}: {totp.policy.digits}
|
||||||
|
</li>
|
||||||
|
{totp.policy.type === "totp" ? (
|
||||||
|
<li id="kc-totp-period">
|
||||||
|
{msg("loginTotpInterval")}: {totp.policy.period}
|
||||||
</li>
|
</li>
|
||||||
<li id="kc-totp-algorithm">
|
) : (
|
||||||
{msg("loginTotpAlgorithm")}: {totp.policy.getAlgorithmKey()}
|
<li id="kc-totp-counter">
|
||||||
|
{msg("loginTotpCounter")}: {totp.policy.initialCounter}
|
||||||
</li>
|
</li>
|
||||||
<li id="kc-totp-digits">
|
)}
|
||||||
{msg("loginTotpDigits")}: {totp.policy.digits}
|
</ul>
|
||||||
</li>
|
|
||||||
{totp.policy.type === "totp" ? (
|
|
||||||
<li id="kc-totp-period">
|
|
||||||
{msg("loginTotpInterval")}: {totp.policy.period}
|
|
||||||
</li>
|
|
||||||
) : (
|
|
||||||
<li id="kc-totp-counter">
|
|
||||||
{msg("loginTotpCounter")}: {totp.policy.initialCounter}
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
</li>
|
</li>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
@ -115,62 +115,61 @@ export default function LoginPasskeysConditionalAuthenticate(
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div id="kc-form">
|
|
||||||
<div id="kc-form-wrapper">
|
|
||||||
{realm.password && (
|
|
||||||
<form
|
|
||||||
id="kc-form-passkey"
|
|
||||||
action={url.loginAction}
|
|
||||||
method="post"
|
|
||||||
style={{ display: "none" }}
|
|
||||||
onSubmit={event => {
|
|
||||||
try {
|
|
||||||
// @ts-expect-error
|
|
||||||
event.target.login.disabled = true;
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!usernameHidden && (
|
|
||||||
<div className={kcClsx("kcFormGroupClass")}>
|
|
||||||
<label htmlFor="username" className={kcClsx("kcLabelClass")}>
|
|
||||||
{msg("passkey-autofill-select")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
tabIndex={1}
|
|
||||||
id="username"
|
|
||||||
aria-invalid={messagesPerField.existsError("username")}
|
|
||||||
className={kcClsx("kcInputClass")}
|
|
||||||
name="username"
|
|
||||||
defaultValue={login.username ?? ""}
|
|
||||||
//autoComplete="username webauthn"
|
|
||||||
type="text"
|
|
||||||
autoFocus
|
|
||||||
autoComplete="off"
|
|
||||||
/>
|
|
||||||
{messagesPerField.existsError("username") && (
|
|
||||||
<span id="input-error-username" className={kcClsx("kcInputErrorMessageClass")} aria-live="polite">
|
|
||||||
{messagesPerField.get("username")}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</form>
|
|
||||||
)}
|
|
||||||
<div id="kc-form-passkey-button" className={kcClsx("kcFormButtonsClass")} style={{ display: "none" }}>
|
|
||||||
<input
|
|
||||||
id={authButtonId}
|
|
||||||
type="button"
|
|
||||||
autoFocus
|
|
||||||
value={msgStr("passkey-doAuthenticate")}
|
|
||||||
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<div id="kc-form">
|
||||||
|
<div id="kc-form-wrapper">
|
||||||
|
{realm.password && (
|
||||||
|
<form
|
||||||
|
id="kc-form-login"
|
||||||
|
action={url.loginAction}
|
||||||
|
method="post"
|
||||||
|
style={{ display: "none" }}
|
||||||
|
onSubmit={event => {
|
||||||
|
try {
|
||||||
|
// @ts-expect-error
|
||||||
|
event.target.login.disabled = true;
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!usernameHidden && (
|
||||||
|
<div className={kcClsx("kcFormGroupClass")}>
|
||||||
|
<label htmlFor="username" className={kcClsx("kcLabelClass")}>
|
||||||
|
{msg("passkey-autofill-select")}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
tabIndex={1}
|
||||||
|
id="username"
|
||||||
|
aria-invalid={messagesPerField.existsError("username")}
|
||||||
|
className={kcClsx("kcInputClass")}
|
||||||
|
name="username"
|
||||||
|
defaultValue={login.username ?? ""}
|
||||||
|
autoComplete="username webauthn"
|
||||||
|
type="text"
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
{messagesPerField.existsError("username") && (
|
||||||
|
<span id="input-error-username" className={kcClsx("kcInputErrorMessageClass")} aria-live="polite">
|
||||||
|
{messagesPerField.get("username")}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
<div id="kc-form-passkey-button" className={kcClsx("kcFormButtonsClass")} style={{ display: "none" }}>
|
||||||
|
<input
|
||||||
|
id={authButtonId}
|
||||||
|
type="button"
|
||||||
|
autoFocus
|
||||||
|
value={msgStr("passkey-doAuthenticate")}
|
||||||
|
className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonBlockClass", "kcButtonLargeClass")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Template>
|
</Template>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { assert } from "tsafe/assert";
|
import { assert, is } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
|
|
||||||
export type StatefulObservable<T> = {
|
export type StatefulObservable<T> = {
|
||||||
current: T;
|
current: T;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { assert } from "tsafe/assert";
|
import { assert, is } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
|
||||||
import { structuredCloneButFunctions } from "./structuredCloneButFunctions";
|
import { structuredCloneButFunctions } from "./structuredCloneButFunctions";
|
||||||
|
|
||||||
/** NOTE: Array a copied over, not merged. */
|
/** NOTE: Array a copied over, not merged. */
|
||||||
|
43
src/tools/extractLastParenthesisContent.ts
Normal file
43
src/tools/extractLastParenthesisContent.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* "Hello (world)" => "world"
|
||||||
|
* "Hello (world) (foo)" => "foo"
|
||||||
|
* "Hello (world (foo))" => "world (foo)"
|
||||||
|
*/
|
||||||
|
export function extractLastParenthesisContent(str: string): string | undefined {
|
||||||
|
const chars: string[] = [];
|
||||||
|
|
||||||
|
for (const char of str) {
|
||||||
|
chars.push(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
const extractedChars: string[] = [];
|
||||||
|
let openingCount = 0;
|
||||||
|
|
||||||
|
loop_through_char: for (let i = chars.length - 1; i >= 0; i--) {
|
||||||
|
const char = chars[i];
|
||||||
|
|
||||||
|
if (i === chars.length - 1) {
|
||||||
|
if (char !== ")") {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (char) {
|
||||||
|
case ")":
|
||||||
|
openingCount++;
|
||||||
|
break;
|
||||||
|
case "(":
|
||||||
|
if (openingCount === 0) {
|
||||||
|
return extractedChars.join("");
|
||||||
|
}
|
||||||
|
openingCount--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
extractedChars.unshift(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
@ -212,6 +212,73 @@ export function keycloakify(params: keycloakify.Params) {
|
|||||||
force: true
|
force: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
transformIndexHtml: html => {
|
||||||
|
const doReadKcContextFromUrl =
|
||||||
|
process.env.NODE_ENV === "development" &&
|
||||||
|
process.env[
|
||||||
|
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES.READ_KC_CONTEXT_FROM_URL
|
||||||
|
] === "true";
|
||||||
|
|
||||||
|
if (!doReadKcContextFromUrl) {
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scriptContent = `
|
||||||
|
(()=>{
|
||||||
|
|
||||||
|
const kcContext = (()=>{
|
||||||
|
|
||||||
|
const paramName= "kcContext";
|
||||||
|
|
||||||
|
read_from_url_case: {
|
||||||
|
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
|
||||||
|
const paramValue = url.searchParams.get(paramName);
|
||||||
|
|
||||||
|
if( paramValue === null ){
|
||||||
|
break read_from_url_case;
|
||||||
|
}
|
||||||
|
|
||||||
|
url.searchParams.delete(paramName);
|
||||||
|
|
||||||
|
window.history.replaceState({}, "", url);
|
||||||
|
|
||||||
|
const kcContext = JSON.parse(decodeURIComponent(paramValue));
|
||||||
|
|
||||||
|
sessionStorage.setItem(paramName, JSON.stringify(kcContext));
|
||||||
|
|
||||||
|
return kcContext;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
read_from_session_storage_case: {
|
||||||
|
|
||||||
|
const paramValue = sessionStorage.getItem(paramName);
|
||||||
|
|
||||||
|
if( paramValue === null ){
|
||||||
|
break read_from_session_storage_case;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(paramValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
if( kcContext === undefined ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.kcContext = kcContext;
|
||||||
|
|
||||||
|
})();
|
||||||
|
`;
|
||||||
|
|
||||||
|
return html.replace(/<head>/, `<head><script>${scriptContent}</script>`);
|
||||||
}
|
}
|
||||||
} satisfies Plugin;
|
} satisfies Plugin;
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ export const Default: Story = {
|
|||||||
render: () => (
|
render: () => (
|
||||||
<KcPageStory
|
<KcPageStory
|
||||||
kcContext={{
|
kcContext={{
|
||||||
|
messageHeader: "Message header",
|
||||||
message: {
|
message: {
|
||||||
summary: "Server info message"
|
summary: "Server info message"
|
||||||
}
|
}
|
||||||
@ -29,6 +30,7 @@ export const WithLinkBack: Story = {
|
|||||||
render: () => (
|
render: () => (
|
||||||
<KcPageStory
|
<KcPageStory
|
||||||
kcContext={{
|
kcContext={{
|
||||||
|
messageHeader: "Message header",
|
||||||
message: {
|
message: {
|
||||||
summary: "Server message"
|
summary: "Server message"
|
||||||
},
|
},
|
||||||
@ -42,6 +44,7 @@ export const WithRequiredActions: Story = {
|
|||||||
render: () => (
|
render: () => (
|
||||||
<KcPageStory
|
<KcPageStory
|
||||||
kcContext={{
|
kcContext={{
|
||||||
|
messageHeader: "Message header",
|
||||||
message: {
|
message: {
|
||||||
summary: "Required actions: "
|
summary: "Required actions: "
|
||||||
},
|
},
|
||||||
@ -55,42 +58,3 @@ export const WithRequiredActions: Story = {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
export const WithPageRedirect: Story = {
|
|
||||||
render: () => (
|
|
||||||
<KcPageStory
|
|
||||||
kcContext={{
|
|
||||||
message: { summary: "You will be redirected shortly." },
|
|
||||||
pageRedirectUri: "https://example.com"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
export const WithoutClientBaseUrl: Story = {
|
|
||||||
render: () => (
|
|
||||||
<KcPageStory
|
|
||||||
kcContext={{
|
|
||||||
message: { summary: "No client base URL defined." },
|
|
||||||
client: { baseUrl: undefined }
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
export const WithMessageHeader: Story = {
|
|
||||||
render: () => (
|
|
||||||
<KcPageStory
|
|
||||||
kcContext={{
|
|
||||||
messageHeader: "Important Notice",
|
|
||||||
message: { summary: "This is an important message." }
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
export const WithAdvancedMessage: Story = {
|
|
||||||
render: () => (
|
|
||||||
<KcPageStory
|
|
||||||
kcContext={{
|
|
||||||
message: { summary: "Please take note of this <strong>important</strong> information." }
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import type { Meta, StoryObj } from "@storybook/react";
|
|
||||||
import { createKcPageStory } from "../KcPageStory";
|
|
||||||
|
|
||||||
const { KcPageStory } = createKcPageStory({ pageId: "login-oauth2-device-verify-user-code.ftl" });
|
|
||||||
|
|
||||||
const meta = {
|
|
||||||
title: "login/login-oauth2-device-verify-user-code.ftl",
|
|
||||||
component: KcPageStory
|
|
||||||
} satisfies Meta<typeof KcPageStory>;
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
type Story = StoryObj<typeof meta>;
|
|
||||||
|
|
||||||
export const Default: Story = {
|
|
||||||
render: () => <KcPageStory />
|
|
||||||
};
|
|
@ -17,8 +17,5 @@
|
|||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"include": ["../src", "."],
|
"include": ["../src", "."],
|
||||||
"exclude": [
|
"exclude": ["../src/bin/initialize-account-theme/src"]
|
||||||
"../src/bin/initialize-account-theme/src",
|
|
||||||
"../src/bin/initialize-admin-theme/src"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
79
yarn.lock
79
yarn.lock
@ -6172,6 +6172,14 @@ d@1, d@^1.0.1:
|
|||||||
es5-ext "^0.10.50"
|
es5-ext "^0.10.50"
|
||||||
type "^1.0.1"
|
type "^1.0.1"
|
||||||
|
|
||||||
|
d@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/d/-/d-1.0.2.tgz#2aefd554b81981e7dccf72d6842ae725cb17e5de"
|
||||||
|
integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==
|
||||||
|
dependencies:
|
||||||
|
es5-ext "^0.10.64"
|
||||||
|
type "^2.7.2"
|
||||||
|
|
||||||
data-urls@^5.0.0:
|
data-urls@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde"
|
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde"
|
||||||
@ -6743,7 +6751,7 @@ es-to-primitive@^1.2.1:
|
|||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
|
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
|
||||||
version "0.10.62"
|
version "0.10.62"
|
||||||
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5"
|
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5"
|
||||||
integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==
|
integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==
|
||||||
@ -6752,6 +6760,16 @@ es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@
|
|||||||
es6-symbol "^3.1.3"
|
es6-symbol "^3.1.3"
|
||||||
next-tick "^1.1.0"
|
next-tick "^1.1.0"
|
||||||
|
|
||||||
|
es5-ext@^0.10.62, es5-ext@^0.10.64:
|
||||||
|
version "0.10.64"
|
||||||
|
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.64.tgz#12e4ffb48f1ba2ea777f1fcdd1918ef73ea21714"
|
||||||
|
integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==
|
||||||
|
dependencies:
|
||||||
|
es6-iterator "^2.0.3"
|
||||||
|
es6-symbol "^3.1.3"
|
||||||
|
esniff "^2.0.1"
|
||||||
|
next-tick "^1.1.0"
|
||||||
|
|
||||||
es5-shim@^4.5.13:
|
es5-shim@^4.5.13:
|
||||||
version "4.6.7"
|
version "4.6.7"
|
||||||
resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955"
|
resolved "https://registry.yarnpkg.com/es5-shim/-/es5-shim-4.6.7.tgz#bc67ae0fc3dd520636e0a1601cc73b450ad3e955"
|
||||||
@ -6920,6 +6938,16 @@ eslint-visitor-keys@^3.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc"
|
||||||
integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
|
integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==
|
||||||
|
|
||||||
|
esniff@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
|
||||||
|
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
|
||||||
|
dependencies:
|
||||||
|
d "^1.0.1"
|
||||||
|
es5-ext "^0.10.62"
|
||||||
|
event-emitter "^0.3.5"
|
||||||
|
type "^2.7.2"
|
||||||
|
|
||||||
esprima@^4.0.1, esprima@~4.0.0:
|
esprima@^4.0.1, esprima@~4.0.0:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||||
@ -6994,14 +7022,14 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
|
|||||||
md5.js "^1.3.4"
|
md5.js "^1.3.4"
|
||||||
safe-buffer "^5.1.1"
|
safe-buffer "^5.1.1"
|
||||||
|
|
||||||
evt@^2.5.7:
|
evt@^2.5.8:
|
||||||
version "2.5.7"
|
version "2.5.8"
|
||||||
resolved "https://registry.yarnpkg.com/evt/-/evt-2.5.7.tgz#55c5f8ff910f4b7531bfac91e963d4cb3231f253"
|
resolved "https://registry.yarnpkg.com/evt/-/evt-2.5.8.tgz#4cc4e2db92d89cc43e00a0755703317f5f9b6d4c"
|
||||||
integrity sha512-dr7Wd16ry5F8WNU1xXLKpFpO3HsoAGg8zC48e08vDdzMzGWCP9/QFGt1PQptEEDh8SwYP3EL8M+d/Gb0kgUp6g==
|
integrity sha512-wjurRtEqepH03fZSzkCUAw2tNNtEoeoEYXf7EqG8uU52wQ3D/+ctyQE8hf+YR/5DXZlwl2jNGLMm4hAd/wyD6g==
|
||||||
dependencies:
|
dependencies:
|
||||||
minimal-polyfills "^2.2.3"
|
minimal-polyfills "^2.2.3"
|
||||||
run-exclusive "^2.2.19"
|
run-exclusive "^2.2.19"
|
||||||
tsafe "^1.6.6"
|
tsafe "^1.8.5"
|
||||||
|
|
||||||
execa@^5.1.1:
|
execa@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
@ -9350,13 +9378,13 @@ memfs@^3.1.2, memfs@^3.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fs-monkey "^1.0.3"
|
fs-monkey "^1.0.3"
|
||||||
|
|
||||||
memoizee@^0.4.15:
|
memoizee@^0.4.17:
|
||||||
version "0.4.15"
|
version "0.4.17"
|
||||||
resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72"
|
resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.17.tgz#942a5f8acee281fa6fb9c620bddc57e3b7382949"
|
||||||
integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==
|
integrity sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==
|
||||||
dependencies:
|
dependencies:
|
||||||
d "^1.0.1"
|
d "^1.0.2"
|
||||||
es5-ext "^0.10.53"
|
es5-ext "^0.10.64"
|
||||||
es6-weak-map "^2.0.3"
|
es6-weak-map "^2.0.3"
|
||||||
event-emitter "^0.3.5"
|
event-emitter "^0.3.5"
|
||||||
is-promise "^2.2.2"
|
is-promise "^2.2.2"
|
||||||
@ -10629,14 +10657,14 @@ postcss@^8.4.38:
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^1.2.0"
|
source-map-js "^1.2.0"
|
||||||
|
|
||||||
powerhooks@^1.0.10:
|
powerhooks@^1.0.19:
|
||||||
version "1.0.10"
|
version "1.0.19"
|
||||||
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-1.0.10.tgz#9d532b23294cba69d5872d859bdf843b91cb9c41"
|
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-1.0.19.tgz#e93ce44f55d31ca26a4511883a49cfe5341d47af"
|
||||||
integrity sha512-fJmKSVJk9Bkotl9rK1ryVPSqhY4xOZKxM6deyTaMbICK8jHh/CQztN2mNTxlKu6vkJBIFj1cRd/7N6slh3uM6w==
|
integrity sha512-kmZX0LLvJyaIphwf2FjKABAQwQFrRqsEA41N4CB8EzfDobyXle545t4teajVo/NPboy0HEaioyv55FWN7d58/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
evt "^2.5.7"
|
evt "^2.5.8"
|
||||||
memoizee "^0.4.15"
|
memoizee "^0.4.17"
|
||||||
tsafe "^1.6.6"
|
tsafe "^1.8.5"
|
||||||
|
|
||||||
prelude-ls@~1.1.2:
|
prelude-ls@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
@ -12574,15 +12602,10 @@ ts-pnp@^1.1.6:
|
|||||||
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
|
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
|
||||||
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
|
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
|
||||||
|
|
||||||
tsafe@^1.6.6:
|
tsafe@^1.8.5:
|
||||||
version "1.6.6"
|
version "1.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.6.6.tgz#fd93e64d6eb13ef83ed1650669cc24bad4f5df9f"
|
resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.8.5.tgz#cdf9fa3111974ac480d7ee519f8241815e5d22ea"
|
||||||
integrity sha512-gzkapsdbMNwBnTIjgO758GujLCj031IgHK/PKr2mrmkCSJMhSOR5FeOuSxKLMUoYc0vAA4RGEYYbjt/v6afD3g==
|
integrity sha512-LFWTWQrW6rwSY+IBNFl2ridGfUzVsPwrZ26T4KUJww/py8rzaQ/SY+MIz6YROozpUCaRcuISqagmlwub9YT9kw==
|
||||||
|
|
||||||
tsafe@^1.7.5:
|
|
||||||
version "1.7.5"
|
|
||||||
resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.7.5.tgz#0d3a31202b5ef87c7ba997e66e03fd80801278ef"
|
|
||||||
integrity sha512-tbNyyBSbwfbilFfiuXkSOj82a6++ovgANwcoqBAcO9/REPoZMEQoE8kWPeO0dy5A2D/2Lajr8Ohue5T0ifIvLQ==
|
|
||||||
|
|
||||||
tsc-alias@^1.8.10:
|
tsc-alias@^1.8.10:
|
||||||
version "1.8.10"
|
version "1.8.10"
|
||||||
|
Reference in New Issue
Block a user