Compare commits

...

15 Commits

15 changed files with 114 additions and 59 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "keycloakify", "name": "keycloakify",
"version": "10.0.0-rc.126", "version": "10.0.0-rc.132",
"description": "Create Keycloak themes using React", "description": "Create Keycloak themes using React",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -2,7 +2,10 @@ import { join as pathJoin, relative as pathRelative, dirname as pathDirname } fr
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 { getLatestsSemVersionedTag } from "../shared/getLatestsSemVersionedTag"; import {
getLatestsSemVersionedTag,
type BuildContextLike as BuildContextLike_getLatestsSemVersionedTag
} from "../shared/getLatestsSemVersionedTag";
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 } from "tsafe/assert";
@ -12,8 +15,7 @@ import { npmInstall } from "../tools/npmInstall";
import { copyBoilerplate } from "./copyBoilerplate"; import { copyBoilerplate } from "./copyBoilerplate";
import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath"; import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
type BuildContextLike = { type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {
cacheDirPath: string;
fetchOptions: BuildContext["fetchOptions"]; fetchOptions: BuildContext["fetchOptions"];
packageJsonFilePath: string; packageJsonFilePath: string;
}; };
@ -30,11 +32,11 @@ export async function initializeAccountTheme_singlePage(params: {
const REPO = "keycloak-account-ui"; const REPO = "keycloak-account-ui";
const [semVersionedTag] = await getLatestsSemVersionedTag({ const [semVersionedTag] = await getLatestsSemVersionedTag({
cacheDirPath: buildContext.cacheDirPath,
owner: OWNER, owner: OWNER,
repo: REPO, repo: REPO,
count: 1, count: 1,
doIgnoreReleaseCandidates: false doIgnoreReleaseCandidates: false,
buildContext
}); });
const dependencies = await fetch( const dependencies = await fetch(

View File

@ -30,7 +30,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
// NOTE: This is arbitrary // NOTE: This is arbitrary
startingFromMajor: 17, startingFromMajor: 17,
excludeMajorVersions: [], excludeMajorVersions: [],
cacheDirPath: buildContext.cacheDirPath buildContext
}); });
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({ const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({

View File

@ -9,6 +9,7 @@ import { assert, type Equals } from "tsafe/assert";
import { id } from "tsafe/id"; import { id } from "tsafe/id";
import type { SemVer } from "../tools/SemVer"; import type { SemVer } from "../tools/SemVer";
import { same } from "evt/tools/inDepth/same"; import { same } from "evt/tools/inDepth/same";
import type { BuildContext } from "./buildContext";
type GetLatestsSemVersionedTag = ReturnType< type GetLatestsSemVersionedTag = ReturnType<
typeof getLatestsSemVersionedTagFactory typeof getLatestsSemVersionedTagFactory
@ -31,11 +32,23 @@ type Cache = {
}[]; }[];
}; };
export type BuildContextLike = {
cacheDirPath: string;
fetchOptions: BuildContext["fetchOptions"];
};
assert<BuildContext extends BuildContextLike ? true : false>();
export async function getLatestsSemVersionedTag({ export async function getLatestsSemVersionedTag({
cacheDirPath, buildContext,
...params ...params
}: Params & { cacheDirPath: string }): Promise<R> { }: Params & {
const cacheFilePath = pathJoin(cacheDirPath, "latest-sem-versioned-tags.json"); buildContext: BuildContextLike;
}): Promise<R> {
const cacheFilePath = pathJoin(
buildContext.cacheDirPath,
"latest-sem-versioned-tags.json"
);
const cacheLookupResult = (() => { const cacheLookupResult = (() => {
const getResult_currentCache = (currentCacheEntries: Cache["entries"]) => ({ const getResult_currentCache = (currentCacheEntries: Cache["entries"]) => ({
@ -144,9 +157,10 @@ export async function getLatestsSemVersionedTag({
const octokit = (() => { const octokit = (() => {
const githubToken = process.env.GITHUB_TOKEN; const githubToken = process.env.GITHUB_TOKEN;
const octokit = new Octokit( const octokit = new Octokit({
githubToken === undefined ? undefined : { auth: githubToken } ...(githubToken === undefined ? {} : { auth: githubToken }),
); request: buildContext.fetchOptions
});
return octokit; return octokit;
})(); })();

View File

@ -1,22 +1,31 @@
import { getLatestsSemVersionedTag } from "./getLatestsSemVersionedTag"; import {
getLatestsSemVersionedTag,
type BuildContextLike as BuildContextLike_getLatestsSemVersionedTag
} from "./getLatestsSemVersionedTag";
import cliSelect from "cli-select"; import cliSelect from "cli-select";
import { assert } from "tsafe/assert";
import { SemVer } from "../tools/SemVer"; import { SemVer } from "../tools/SemVer";
import type { BuildContext } from "./buildContext";
export type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & {};
assert<BuildContext extends BuildContextLike ? true : false>();
export async function promptKeycloakVersion(params: { export async function promptKeycloakVersion(params: {
startingFromMajor: number | undefined; startingFromMajor: number | undefined;
excludeMajorVersions: number[]; excludeMajorVersions: number[];
cacheDirPath: string; buildContext: BuildContextLike;
}) { }) {
const { startingFromMajor, excludeMajorVersions, cacheDirPath } = params; const { startingFromMajor, excludeMajorVersions, buildContext } = params;
const semVersionedTagByMajor = new Map<number, { tag: string; version: SemVer }>(); const semVersionedTagByMajor = new Map<number, { tag: string; version: SemVer }>();
const semVersionedTags = await getLatestsSemVersionedTag({ const semVersionedTags = await getLatestsSemVersionedTag({
cacheDirPath,
count: 50, count: 50,
owner: "keycloak", owner: "keycloak",
repo: "keycloak", repo: "keycloak",
doIgnoreReleaseCandidates: true doIgnoreReleaseCandidates: true,
buildContext
}); });
semVersionedTags.forEach(semVersionedTag => { semVersionedTags.forEach(semVersionedTag => {

View File

@ -73,7 +73,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["view-profile", "manage-account"] "account": ["delete-account", "view-profile", "manage-account"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -611,8 +611,8 @@
"name": "", "name": "",
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2099,7 +2099,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -73,7 +73,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["view-profile", "manage-account"] "account": ["delete-account", "view-profile", "manage-account"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -618,8 +618,8 @@
"name": "", "name": "",
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2130,7 +2130,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -73,7 +73,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["view-profile", "manage-account"] "account": ["delete-account", "view-profile", "manage-account"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -628,8 +628,8 @@
"name": "", "name": "",
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2140,7 +2140,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -73,7 +73,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["view-profile", "manage-account"] "account": ["delete-account", "view-profile", "manage-account"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -632,8 +632,8 @@
"name": "", "name": "",
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2144,7 +2144,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -55,7 +55,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["view-profile", "manage-account"] "account": ["delete-account", "view-profile", "manage-account"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -644,7 +644,7 @@
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "https://my-theme.keycloakify.dev", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2088,7 +2088,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -63,7 +63,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["manage-account", "view-profile"] "account": ["delete-account", "manage-account", "view-profile"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -653,7 +653,7 @@
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "https://my-theme.keycloakify.dev", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2235,7 +2235,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -63,7 +63,7 @@
"composites": { "composites": {
"realm": ["offline_access", "uma_authorization"], "realm": ["offline_access", "uma_authorization"],
"client": { "client": {
"account": ["manage-account", "view-profile"] "account": ["delete-account", "manage-account", "view-profile"]
} }
}, },
"clientRole": false, "clientRole": false,
@ -543,7 +543,7 @@
"favourite_pet": ["cat"], "favourite_pet": ["cat"],
"bio": ["Hello I'm Test User and I do not exist."], "bio": ["Hello I'm Test User and I do not exist."],
"phone_number": ["1111111111"], "phone_number": ["1111111111"],
"locale": ["fr"], "locale": ["en"],
"favorite_media": ["movies", "series"] "favorite_media": ["movies", "series"]
}, },
"createdTimestamp": 1716183898408, "createdTimestamp": 1716183898408,
@ -767,7 +767,7 @@
"description": "", "description": "",
"rootUrl": "https://my-theme.keycloakify.dev", "rootUrl": "https://my-theme.keycloakify.dev",
"adminUrl": "https://my-theme.keycloakify.dev", "adminUrl": "https://my-theme.keycloakify.dev",
"baseUrl": "", "baseUrl": "https://my-theme.keycloakify.dev",
"surrogateAuthRequired": false, "surrogateAuthRequired": false,
"enabled": true, "enabled": true,
"alwaysDisplayInConsole": false, "alwaysDisplayInConsole": false,
@ -2315,7 +2315,7 @@
"alias": "delete_account", "alias": "delete_account",
"name": "Delete Account", "name": "Delete Account",
"providerId": "delete_account", "providerId": "delete_account",
"enabled": false, "enabled": true,
"defaultAction": false, "defaultAction": false,
"priority": 60, "priority": 60,
"config": {} "config": {}

View File

@ -97,13 +97,20 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
} }
console.log( console.log(
chalk.cyan("On which version of Keycloak do you want to test your theme?") [
chalk.cyan(
"On which version of Keycloak do you want to test your theme?"
),
chalk.gray(
"You can also explicitly provide the version with `npx keycloakify start-keycloak --keycloak-version 25.0.2` (or any other version)"
)
].join("\n")
); );
const { keycloakVersion } = await promptKeycloakVersion({ const { keycloakVersion } = await promptKeycloakVersion({
startingFromMajor: 18, startingFromMajor: 18,
excludeMajorVersions: [22], excludeMajorVersions: [22],
cacheDirPath: buildContext.cacheDirPath buildContext
}); });
console.log(`${keycloakVersion}`); console.log(`${keycloakVersion}`);

View File

@ -5,9 +5,11 @@ export function assertNoPnpmDlx() {
if (__dirname.includes(`${pathSep}pnpm${pathSep}dlx${pathSep}`)) { if (__dirname.includes(`${pathSep}pnpm${pathSep}dlx${pathSep}`)) {
console.log( console.log(
[ [
chalk.red("Please don't use `pnpm dlx keycloakify`"), chalk.red(
"Please don't use `pnpm dlx keycloakify` (download and execute)"
),
"\nUse `npx keycloakify` or `pnpm exec keycloakify` instead since you want to use the keycloakify", "\nUse `npx keycloakify` or `pnpm exec keycloakify` instead since you want to use the keycloakify",
"version that is installed in your project and not the latest version on NPM." "version that is installed in your project and not download and run the latest NPM version of keycloakify."
].join(" ") ].join(" ")
); );
process.exit(1); process.exit(1);

View File

@ -1,6 +1,7 @@
import { type FetchOptions } from "make-fetch-happen"; import { type FetchOptions } from "make-fetch-happen";
import * as child_process from "child_process"; import * as child_process from "child_process";
import * as fs from "fs"; import * as fs from "fs";
import { exclude } from "tsafe/exclude";
export type ProxyFetchOptions = Pick< export type ProxyFetchOptions = Pick<
FetchOptions, FetchOptions,
@ -23,12 +24,32 @@ export function getProxyFetchOptions(params: {
.split("\n") .split("\n")
.filter(line => !line.startsWith(";")) .filter(line => !line.startsWith(";"))
.map(line => line.trim()) .map(line => line.trim())
.map(line => line.split("=", 2) as [string, string]) .map(line => {
const [key, value] = line.split("=");
if (key === undefined) {
return undefined;
}
if (value === undefined) {
return undefined;
}
return [key.trim(), value.trim()] as const;
})
.filter(exclude(undefined))
.filter(([key]) => key !== "")
.map(([key, value]) => {
if (value.startsWith('"') && value.endsWith('"')) {
return [key, value.slice(1, -1)] as const;
}
if (value === "true" || value === "false") {
return [key, value] as const;
}
return undefined;
})
.filter(exclude(undefined))
.reduce( .reduce(
( (cfg: Record<string, string | string[]>, [key, value]) =>
cfg: Record<string, string | string[]>,
[key, value]: [string, string]
) =>
key in cfg key in cfg
? { ...cfg, [key]: [...ensureArray(cfg[key]), value] } ? { ...cfg, [key]: [...ensureArray(cfg[key]), value] }
: { ...cfg, [key]: value }, : { ...cfg, [key]: value },
@ -37,18 +58,18 @@ export function getProxyFetchOptions(params: {
})(); })();
const proxy = ensureSingleOrNone(cfg["https-proxy"] ?? cfg["proxy"]); const proxy = ensureSingleOrNone(cfg["https-proxy"] ?? cfg["proxy"]);
const noProxy = cfg["noproxy"] ?? cfg["no-proxy"]; const noProxy = cfg["noproxy"] ?? cfg["no-proxy"];
function maybeBoolean(arg0: string | undefined) { const strictSSL = ensureSingleOrNone(cfg["strict-ssl"]) === "true";
return typeof arg0 === "undefined" ? undefined : Boolean(arg0);
}
const strictSSL = maybeBoolean(ensureSingleOrNone(cfg["strict-ssl"]));
const cert = cfg["cert"]; const cert = cfg["cert"];
const ca = ensureArray(cfg["ca"] ?? cfg["ca[]"]); const ca = ensureArray(cfg["ca"] ?? cfg["ca[]"]);
const cafile = ensureSingleOrNone(cfg["cafile"]); const cafile = ensureSingleOrNone(cfg["cafile"]);
if (typeof cafile !== "undefined" && cafile !== "null") { if (cafile !== undefined) {
ca.push( ca.push(
...(() => { ...(() => {
const cafileContent = fs.readFileSync(cafile).toString("utf8"); const cafileContent = fs.readFileSync(cafile).toString("utf8");
@ -82,7 +103,7 @@ export function getProxyFetchOptions(params: {
} }
function ensureArray<T>(arg0: T | T[]) { function ensureArray<T>(arg0: T | T[]) {
return Array.isArray(arg0) ? arg0 : typeof arg0 === "undefined" ? [] : [arg0]; return Array.isArray(arg0) ? arg0 : arg0 === undefined ? [] : [arg0];
} }
function ensureSingleOrNone<T>(arg0: T | T[]) { function ensureSingleOrNone<T>(arg0: T | T[]) {