diff --git a/.gitignore b/.gitignore index ad2175b8..87fa643f 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,5 @@ jspm_packages .devcontainer /stories/assets/fonts/ -/.storybook/static/keycloak_static/ /build_storybook/ /storybook-static/ diff --git a/package.json b/package.json index 07d2e8cc..34d71bb6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "prepare": "yarn generate-i18n-messages && yarn setup-keycloak-static-assets-for-storybook", + "prepare": "yarn generate-i18n-messages", "build": "rimraf dist/ && tsc -p src/bin && tsc -p src && tsc-alias -p src/tsconfig.json && yarn grant-exec-perms && yarn copy-files dist/", "watch-in-starter": "yarn build && yarn link-in-starter && (concurrently \"tsc -p src -w\" \"tsc-alias -p src/tsconfig.json\" \"tsc -p src/bin -w\")", "generate:json-schema": "ts-node scripts/generate-json-schema.ts", @@ -24,12 +24,13 @@ "generate-i18n-messages": "ts-node --skipProject scripts/generate-i18n-messages.ts", "link-in-app": "ts-node --skipProject scripts/link-in-app.ts", "link-in-starter": "yarn link-in-app keycloakify-starter", - "storybook": "start-storybook -p 6006", - "build-storybook": "build-storybook", - "setup-keycloak-static-assets-for-storybook": "ts-node --skipProject scripts/setup-keycloak-static-assets-for-storybook.ts" + "copy-keycloak-resources-to-storybook-static": "PUBLIC_DIR_PATH=.storybook/static node dist/bin/copy-keycloak-resources-to-public.js", + "storybook": "yarn build && yarn copy-keycloak-resources-to-storybook-static && (concurrently \"tsc -p src -w\" \"tsc-alias -p src/tsconfig.json\" \"start-storybook -p 6006\")", + "build-storybook": "yarn build && yarn copy-keycloak-resources-to-storybook-static && build-storybook" }, "bin": { "keycloakify": "dist/bin/keycloakify/index.js", + "copy-keycloak-resources-to-public": "dist/bin/copy-keycloak-resources-to-public.js", "initialize-email-theme": "dist/bin/initialize-email-theme.js", "download-builtin-keycloak-theme": "dist/bin/download-builtin-keycloak-theme.js", "eject-keycloak-page": "dist/bin/eject-keycloak-page.js" diff --git a/scripts/setup-keycloak-static-assets-for-storybook.ts b/scripts/setup-keycloak-static-assets-for-storybook.ts deleted file mode 100644 index c8af853a..00000000 --- a/scripts/setup-keycloak-static-assets-for-storybook.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { downloadKeycloakStaticResources } from "../src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources"; -import { getProjectRoot } from "../src/bin/tools/getProjectRoot"; -import { join as pathJoin } from "path"; -import { mockTestingSubDirOfPublicDirBasename } from "../src/bin/mockTestingResourcesPath"; -import { defaultKeycloakVersionDefaultAssets } from "../src/bin/keycloakify/BuildOptions"; - -(async () => { - await downloadKeycloakStaticResources({ - "isSilent": false, - "keycloakVersion": defaultKeycloakVersionDefaultAssets, - "themeType": "login", - "themeDirPath": pathJoin(getProjectRoot(), ".storybook", "static", mockTestingSubDirOfPublicDirBasename) - }); - - console.log("Done"); -})(); diff --git a/src/account/kcContext/createGetKcContext.ts b/src/account/kcContext/createGetKcContext.ts index ad8c585e..19df1c81 100644 --- a/src/account/kcContext/createGetKcContext.ts +++ b/src/account/kcContext/createGetKcContext.ts @@ -4,7 +4,7 @@ import type { ExtendKcContext } from "./getKcContextFromWindow"; import { getKcContextFromWindow } from "./getKcContextFromWindow"; import { pathJoin } from "keycloakify/bin/tools/pathJoin"; import { pathBasename } from "keycloakify/tools/pathBasename"; -import { mockTestingResourcesCommonPath } from "keycloakify/bin/mockTestingResourcesPath"; +import { resourcesCommonDirPathRelativeToPublicDir } from "keycloakify/bin/mockTestingResourcesPath"; import { symToStr } from "tsafe/symToStr"; import { kcContextMocks, kcContextCommonMock } from "keycloakify/account/kcContext/kcContextMocks"; import { id } from "tsafe/id"; @@ -100,7 +100,7 @@ export function createGetKcContext { + const projectDirPath = process.cwd(); + + const buildOptions = readBuildOptions({ + "processArgv": process.argv.slice(2), + "projectDirPath": process.cwd() + }); + + const keycloakDirInPublicDir = pathJoin(process.env["PUBLIC_DIR_PATH"] || pathJoin(projectDirPath, "public"), basenameOfKeycloakDirInPublicDir); + + if (fs.existsSync(keycloakDirInPublicDir)) { + console.log(`${pathRelative(projectDirPath, keycloakDirInPublicDir)} already exists. Aborting.`); + return; + } + + for (const themeType of themeTypes) { + await downloadKeycloakStaticResources({ + "isSilent": false, + "keycloakVersion": buildOptions.keycloakVersionDefaultAssets, + "themeType": themeType, + "themeDirPath": keycloakDirInPublicDir + }); + } + + fs.writeFileSync( + pathJoin(keycloakDirInPublicDir, "README.txt"), + Buffer.from( + // prettier-ignore + [ + "This is just a test folder that helps develop", + "the login and register page without having to run a Keycloak container" + ].join(" ") + ) + ); + + fs.writeFileSync(pathJoin(keycloakDirInPublicDir, ".gitignore"), Buffer.from("*", "utf8")); +})(); diff --git a/src/bin/download-builtin-keycloak-theme.ts b/src/bin/download-builtin-keycloak-theme.ts index 1735c1ae..f260600b 100644 --- a/src/bin/download-builtin-keycloak-theme.ts +++ b/src/bin/download-builtin-keycloak-theme.ts @@ -2,7 +2,6 @@ import { join as pathJoin } from "path"; import { downloadAndUnzip } from "./tools/downloadAndUnzip"; import { promptKeycloakVersion } from "./promptKeycloakVersion"; -import { getCliOptions } from "./tools/cliOptions"; import { getLogger } from "./tools/logger"; import { readBuildOptions } from "./keycloakify/BuildOptions"; @@ -21,28 +20,22 @@ export async function downloadBuiltinKeycloakTheme(params: { keycloakVersion: st } async function main() { - const { isSilent } = getCliOptions(process.argv.slice(2)); - const logger = getLogger({ isSilent }); + const buildOptions = readBuildOptions({ + "projectDirPath": process.cwd(), + "processArgv": process.argv.slice(2) + }); + + const logger = getLogger({ "isSilent": buildOptions.isSilent }); const { keycloakVersion } = await promptKeycloakVersion(); - const destDirPath = pathJoin( - readBuildOptions({ - "isSilent": true, - "isExternalAssetsCliParamProvided": false, - "projectDirPath": process.cwd() - }).keycloakifyBuildDirPath, - "src", - "main", - "resources", - "theme" - ); + const destDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme"); logger.log(`Downloading builtins theme of Keycloak ${keycloakVersion} here ${destDirPath}`); await downloadBuiltinKeycloakTheme({ keycloakVersion, destDirPath, - isSilent + "isSilent": buildOptions.isSilent }); } diff --git a/src/bin/initialize-email-theme.ts b/src/bin/initialize-email-theme.ts index 1c9cce24..bd03cb6a 100644 --- a/src/bin/initialize-email-theme.ts +++ b/src/bin/initialize-email-theme.ts @@ -4,13 +4,17 @@ import { downloadBuiltinKeycloakTheme } from "./download-builtin-keycloak-theme" import { join as pathJoin, relative as pathRelative } from "path"; import { transformCodebase } from "./tools/transformCodebase"; import { promptKeycloakVersion } from "./promptKeycloakVersion"; +import { readBuildOptions } from "./keycloakify/BuildOptions"; import * as fs from "fs"; -import { getCliOptions } from "./tools/cliOptions"; import { getLogger } from "./tools/logger"; import { getEmailThemeSrcDirPath } from "./getSrcDirPath"; export async function main() { - const { isSilent } = getCliOptions(process.argv.slice(2)); + const { isSilent } = readBuildOptions({ + "projectDirPath": process.cwd(), + "processArgv": process.argv.slice(2) + }); + const logger = getLogger({ isSilent }); const { emailThemeSrcDirPath } = getEmailThemeSrcDirPath({ diff --git a/src/bin/keycloakify/BuildOptions.ts b/src/bin/keycloakify/BuildOptions.ts index 6ad833b4..d8fa05f5 100644 --- a/src/bin/keycloakify/BuildOptions.ts +++ b/src/bin/keycloakify/BuildOptions.ts @@ -6,6 +6,7 @@ import { symToStr } from "tsafe/symToStr"; import { bundlers, getParsedPackageJson, type Bundler } from "./parsedPackageJson"; import * as fs from "fs"; import { join as pathJoin, sep as pathSep } from "path"; +import parseArgv from "minimist"; /** Consolidated build option gathered form CLI arguments and config in package.json */ export type BuildOptions = BuildOptions.Standalone | BuildOptions.ExternalAssets; @@ -53,10 +54,17 @@ export namespace BuildOptions { } } -export const defaultKeycloakVersionDefaultAssets = "11.0.3"; +export function readBuildOptions(params: { projectDirPath: string; processArgv: string[] }): BuildOptions { + const { projectDirPath, processArgv } = params; -export function readBuildOptions(params: { projectDirPath: string; isExternalAssetsCliParamProvided: boolean; isSilent: boolean }): BuildOptions { - const { projectDirPath, isExternalAssetsCliParamProvided, isSilent } = params; + const { isExternalAssetsCliParamProvided, isSilentCliParamProvided } = (() => { + const argv = parseArgv(processArgv); + + return { + "isSilentCliParamProvided": typeof argv["silent"] === "boolean" ? argv["silent"] : false, + "isExternalAssetsCliParamProvided": typeof argv["external-assets"] === "boolean" ? argv["external-assets"] : false + }; + })(); const parsedPackageJson = getParsedPackageJson({ projectDirPath }); @@ -145,8 +153,8 @@ export function readBuildOptions(params: { projectDirPath: string; isExternalAss "extraLoginPages": [...(extraPages ?? []), ...(extraLoginPages ?? [])], extraAccountPages, extraThemeProperties, - isSilent, - "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? defaultKeycloakVersionDefaultAssets, + "isSilent": isSilentCliParamProvided, + "keycloakVersionDefaultAssets": keycloakVersionDefaultAssets ?? "11.0.3", "reactAppBuildDirPath": (() => { let { reactAppBuildDirPath = undefined } = parsedPackageJson.keycloakify ?? {}; diff --git a/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts b/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts index 111f5654..df23fd58 100644 --- a/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts +++ b/src/bin/keycloakify/generateTheme/downloadKeycloakStaticResources.ts @@ -3,7 +3,12 @@ import * as fs from "fs"; import { join as pathJoin, relative as pathRelative } from "path"; import type { ThemeType } from "../generateFtl"; import { downloadBuiltinKeycloakTheme } from "../../download-builtin-keycloak-theme"; -import { mockTestingResourcesCommonPath, mockTestingResourcesPath, mockTestingSubDirOfPublicDirBasename } from "../../mockTestingResourcesPath"; +import { + resourcesCommonDirPathRelativeToPublicDir, + resourcesDirPathRelativeToPublicDir, + basenameOfKeycloakDirInPublicDir +} from "../../mockTestingResourcesPath"; +import * as crypto from "crypto"; export async function downloadKeycloakStaticResources( // prettier-ignore @@ -16,7 +21,11 @@ export async function downloadKeycloakStaticResources( ) { const { themeType, isSilent, themeDirPath, keycloakVersion } = params; - const tmpDirPath = pathJoin(themeDirPath, "..", "tmp_suLeKsxId"); + const tmpDirPath = pathJoin( + themeDirPath, + "..", + `tmp_suLeKsxId_${crypto.createHash("sha256").update(`${themeType}-${keycloakVersion}`).digest("hex").slice(0, 8)}` + ); await downloadBuiltinKeycloakTheme({ keycloakVersion, @@ -26,12 +35,12 @@ export async function downloadKeycloakStaticResources( transformCodebase({ "srcDirPath": pathJoin(tmpDirPath, "keycloak", themeType, "resources"), - "destDirPath": pathJoin(themeDirPath, pathRelative(mockTestingSubDirOfPublicDirBasename, mockTestingResourcesPath)) + "destDirPath": pathJoin(themeDirPath, pathRelative(basenameOfKeycloakDirInPublicDir, resourcesDirPathRelativeToPublicDir)) }); transformCodebase({ "srcDirPath": pathJoin(tmpDirPath, "keycloak", "common", "resources"), - "destDirPath": pathJoin(themeDirPath, pathRelative(mockTestingSubDirOfPublicDirBasename, mockTestingResourcesCommonPath)) + "destDirPath": pathJoin(themeDirPath, pathRelative(basenameOfKeycloakDirInPublicDir, resourcesCommonDirPathRelativeToPublicDir)) }); fs.rmSync(tmpDirPath, { "recursive": true, "force": true }); diff --git a/src/bin/keycloakify/generateTheme/generateTheme.ts b/src/bin/keycloakify/generateTheme/generateTheme.ts index a2bd9f64..c62bde66 100644 --- a/src/bin/keycloakify/generateTheme/generateTheme.ts +++ b/src/bin/keycloakify/generateTheme/generateTheme.ts @@ -4,7 +4,7 @@ import { join as pathJoin } from "path"; import { replaceImportsFromStaticInJsCode } from "../replacers/replaceImportsFromStaticInJsCode"; import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode"; import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds, themeTypes, type ThemeType } from "../generateFtl"; -import { mockTestingSubDirOfPublicDirBasename } from "../../mockTestingResourcesPath"; +import { basenameOfKeycloakDirInPublicDir } from "../../mockTestingResourcesPath"; import { isInside } from "../../tools/isInside"; import type { BuildOptions } from "../BuildOptions"; import { assert } from "tsafe/assert"; @@ -84,7 +84,7 @@ export async function generateTheme(params: { if ( buildOptions.isStandalone && isInside({ - "dirPath": pathJoin(reactAppBuildDirPath, mockTestingSubDirOfPublicDirBasename), + "dirPath": pathJoin(reactAppBuildDirPath, basenameOfKeycloakDirInPublicDir), filePath }) ) { @@ -172,34 +172,12 @@ export async function generateTheme(params: { fs.writeFileSync(pathJoin(themeDirPath, pageId), Buffer.from(ftlCode, "utf8")); }); - const downloadKeycloakStaticResources_configured = async (themeDirPath: string) => - await downloadKeycloakStaticResources({ - "isSilent": buildOptions.isSilent, - "keycloakVersion": buildOptions.keycloakVersionDefaultAssets, - themeDirPath, - themeType - }); - - await downloadKeycloakStaticResources_configured(themeDirPath); - - { - const keycloakResourcesWithinPublicDirPath = pathJoin(reactAppBuildDirPath, "..", "public", mockTestingSubDirOfPublicDirBasename); - - await downloadKeycloakStaticResources_configured(keycloakResourcesWithinPublicDirPath); - - fs.writeFileSync( - pathJoin(keycloakResourcesWithinPublicDirPath, "README.txt"), - Buffer.from( - // prettier-ignore - [ - "This is just a test folder that helps develop", - "the login and register page without having to run a Keycloak container" - ].join(" ") - ) - ); - - fs.writeFileSync(pathJoin(keycloakResourcesWithinPublicDirPath, ".gitignore"), Buffer.from("*", "utf8")); - } + await downloadKeycloakStaticResources({ + "isSilent": buildOptions.isSilent, + "keycloakVersion": buildOptions.keycloakVersionDefaultAssets, + themeDirPath, + themeType + }); fs.writeFileSync( pathJoin(themeDirPath, "theme.properties"), diff --git a/src/bin/keycloakify/keycloakify.ts b/src/bin/keycloakify/keycloakify.ts index 28146b98..1dbc0df7 100644 --- a/src/bin/keycloakify/keycloakify.ts +++ b/src/bin/keycloakify/keycloakify.ts @@ -6,7 +6,6 @@ import { generateStartKeycloakTestingContainer } from "./generateStartKeycloakTe import * as fs from "fs"; import { readBuildOptions } from "./BuildOptions"; import { getLogger } from "../tools/logger"; -import { getCliOptions } from "../tools/cliOptions"; import jar from "../tools/jar"; import { assert } from "tsafe/assert"; import { Equals } from "tsafe"; @@ -14,18 +13,16 @@ import { getEmailThemeSrcDirPath } from "../getSrcDirPath"; import { getProjectRoot } from "../tools/getProjectRoot"; export async function main() { - const { isSilent, hasExternalAssets } = getCliOptions(process.argv.slice(2)); - const logger = getLogger({ isSilent }); - logger.log("🔏 Building the keycloak theme...⌚"); - const projectDirPath = process.cwd(); const buildOptions = readBuildOptions({ projectDirPath, - "isExternalAssetsCliParamProvided": hasExternalAssets, - "isSilent": isSilent + "processArgv": process.argv.slice(2) }); + const logger = getLogger({ "isSilent": buildOptions.isSilent }); + logger.log("🔏 Building the keycloak theme...⌚"); + const { doBundlesEmailTemplate } = await generateTheme({ keycloakThemeBuildingDirPath: buildOptions.keycloakifyBuildDirPath, "emailThemeSrcDirPath": (() => { diff --git a/src/bin/mockTestingResourcesPath.ts b/src/bin/mockTestingResourcesPath.ts index a9aaf6ef..a90b34e2 100644 --- a/src/bin/mockTestingResourcesPath.ts +++ b/src/bin/mockTestingResourcesPath.ts @@ -1,5 +1,5 @@ import { pathJoin } from "./tools/pathJoin"; -export const mockTestingSubDirOfPublicDirBasename = "keycloak_static"; -export const mockTestingResourcesPath = pathJoin(mockTestingSubDirOfPublicDirBasename, "resources"); -export const mockTestingResourcesCommonPath = pathJoin(mockTestingResourcesPath, "resources_common"); +export const basenameOfKeycloakDirInPublicDir = "keycloak-resources"; +export const resourcesDirPathRelativeToPublicDir = pathJoin(basenameOfKeycloakDirInPublicDir, "resources"); +export const resourcesCommonDirPathRelativeToPublicDir = pathJoin(basenameOfKeycloakDirInPublicDir, "resources_common"); diff --git a/src/bin/tools/cliOptions.ts b/src/bin/tools/cliOptions.ts deleted file mode 100644 index 97f7c609..00000000 --- a/src/bin/tools/cliOptions.ts +++ /dev/null @@ -1,15 +0,0 @@ -import parseArgv from "minimist"; - -export type CliOptions = { - isSilent: boolean; - hasExternalAssets: boolean; -}; - -export const getCliOptions = (processArgv: string[]): CliOptions => { - const argv = parseArgv(processArgv); - - return { - isSilent: typeof argv["silent"] === "boolean" ? argv["silent"] : false, - hasExternalAssets: typeof argv["external-assets"] === "boolean" ? argv["external-assets"] : false - }; -}; diff --git a/src/login/kcContext/createGetKcContext.ts b/src/login/kcContext/createGetKcContext.ts index 0a8d5d38..951c14a1 100644 --- a/src/login/kcContext/createGetKcContext.ts +++ b/src/login/kcContext/createGetKcContext.ts @@ -9,7 +9,7 @@ import type { ExtendKcContext } from "./getKcContextFromWindow"; import { getKcContextFromWindow } from "./getKcContextFromWindow"; import { pathJoin } from "keycloakify/bin/tools/pathJoin"; import { pathBasename } from "keycloakify/tools/pathBasename"; -import { mockTestingResourcesCommonPath } from "keycloakify/bin/mockTestingResourcesPath"; +import { resourcesCommonDirPathRelativeToPublicDir } from "keycloakify/bin/mockTestingResourcesPath"; import { symToStr } from "tsafe/symToStr"; import { loginThemePageIds } from "keycloakify/bin/keycloakify/generateFtl/pageId"; @@ -158,7 +158,7 @@ export function createGetKcContext