diff --git a/src/bin/keycloakify/buildJars/buildJar.ts b/src/bin/keycloakify/buildJars/buildJar.ts
index e1d58213..59a692cc 100644
--- a/src/bin/keycloakify/buildJars/buildJar.ts
+++ b/src/bin/keycloakify/buildJars/buildJar.ts
@@ -24,7 +24,7 @@ export type BuildContextLike = BuildContextLike_generatePom & {
     artifactId: string;
     themeVersion: string;
     cacheDirPath: string;
-    recordIsImplementedByThemeType: BuildContext["recordIsImplementedByThemeType"];
+    implementedThemeTypes: BuildContext["implementedThemeTypes"];
 };
 
 assert<BuildContext extends BuildContextLike ? true : false>();
@@ -135,7 +135,7 @@ export async function buildJar(params: {
     }
 
     route_legacy_pages: {
-        if (!buildContext.recordIsImplementedByThemeType.login) {
+        if (!buildContext.implementedThemeTypes.login.isImplemented) {
             break route_legacy_pages;
         }
 
diff --git a/src/bin/keycloakify/buildJars/buildJars.ts b/src/bin/keycloakify/buildJars/buildJars.ts
index 2a3c891b..1b11a05b 100644
--- a/src/bin/keycloakify/buildJars/buildJars.ts
+++ b/src/bin/keycloakify/buildJars/buildJars.ts
@@ -10,9 +10,8 @@ import type { BuildContext } from "../../shared/buildContext";
 export type BuildContextLike = BuildContextLike_buildJar & {
     projectDirPath: string;
     keycloakifyBuildDirPath: string;
-    recordIsImplementedByThemeType: BuildContext["recordIsImplementedByThemeType"];
+    implementedThemeTypes: BuildContext["implementedThemeTypes"];
     jarTargets: BuildContext["jarTargets"];
-    doUseAccountV3: boolean;
 };
 
 assert<BuildContext extends BuildContextLike ? true : false>();
@@ -24,8 +23,8 @@ export async function buildJars(params: {
     const { resourcesDirPath, buildContext } = params;
 
     const doesImplementAccountV1Theme =
-        buildContext.recordIsImplementedByThemeType.account &&
-        !buildContext.doUseAccountV3;
+        buildContext.implementedThemeTypes.account.isImplemented &&
+        buildContext.implementedThemeTypes.account.type === "Multi-Page";
 
     await Promise.all(
         keycloakAccountV1Versions
diff --git a/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts b/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts
index 00577423..4012c774 100644
--- a/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts
+++ b/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts
@@ -53,10 +53,9 @@ export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
         projectDirPath: string;
         projectBuildDirPath: string;
         environmentVariables: { name: string; default: string }[];
-        recordIsImplementedByThemeType: BuildContext["recordIsImplementedByThemeType"];
+        implementedThemeTypes: BuildContext["implementedThemeTypes"];
         themeSrcDirPath: string;
         bundler: { type: "vite" } | { type: "webpack" };
-        doUseAccountV3: boolean;
     };
 
 assert<BuildContext extends BuildContextLike ? true : false>();
@@ -74,11 +73,15 @@ export async function generateResourcesForMainTheme(params: {
     };
 
     for (const themeType of ["login", "account"] as const) {
-        const isAccountV3 = themeType === "account" && buildContext.doUseAccountV3;
-        if (!buildContext.recordIsImplementedByThemeType[themeType]) {
+        if (!buildContext.implementedThemeTypes[themeType].isImplemented) {
             continue;
         }
 
+        const isForAccountSpa =
+            themeType === "account" &&
+            (assert(buildContext.implementedThemeTypes.account.isImplemented),
+            buildContext.implementedThemeTypes.account.type === "Single-Page");
+
         const themeTypeDirPath = getThemeTypeDirPath({ themeType });
 
         apply_replacers_and_move_to_theme_resources: {
@@ -93,7 +96,7 @@ export async function generateResourcesForMainTheme(params: {
 
             if (
                 themeType === "account" &&
-                buildContext.recordIsImplementedByThemeType.login
+                buildContext.implementedThemeTypes.login.isImplemented
             ) {
                 // NOTE: We prevent doing it twice, it has been done for the login theme.
 
@@ -184,10 +187,10 @@ export async function generateResourcesForMainTheme(params: {
                     case "login":
                         return LOGIN_THEME_PAGE_IDS;
                     case "account":
-                        return isAccountV3 ? ["index.ftl"] : ACCOUNT_THEME_PAGE_IDS;
+                        return isForAccountSpa ? ["index.ftl"] : ACCOUNT_THEME_PAGE_IDS;
                 }
             })(),
-            ...(isAccountV3
+            ...(isForAccountSpa
                 ? []
                 : readExtraPagesNames({
                       themeType,
@@ -203,7 +206,7 @@ export async function generateResourcesForMainTheme(params: {
         });
 
         i18n_messages_generation: {
-            if (isAccountV3) {
+            if (isForAccountSpa) {
                 break i18n_messages_generation;
             }
 
@@ -230,7 +233,7 @@ export async function generateResourcesForMainTheme(params: {
         }
 
         keycloak_static_resources: {
-            if (isAccountV3) {
+            if (isForAccountSpa) {
                 break keycloak_static_resources;
             }
 
@@ -256,13 +259,13 @@ export async function generateResourcesForMainTheme(params: {
                     `parent=${(() => {
                         switch (themeType) {
                             case "account":
-                                return isAccountV3 ? "base" : ACCOUNT_V1_THEME_NAME;
+                                return isForAccountSpa ? "base" : ACCOUNT_V1_THEME_NAME;
                             case "login":
                                 return "keycloak";
                         }
                         assert<Equals<typeof themeType, never>>(false);
                     })()}`,
-                    ...(isAccountV3 ? ["deprecatedMode=false"] : []),
+                    ...(isForAccountSpa ? ["deprecatedMode=false"] : []),
                     ...(buildContext.extraThemeProperties ?? []),
                     ...buildContext.environmentVariables.map(
                         ({ name, default: defaultValue }) =>
@@ -275,7 +278,7 @@ export async function generateResourcesForMainTheme(params: {
     }
 
     email: {
-        if (!buildContext.recordIsImplementedByThemeType.email) {
+        if (!buildContext.implementedThemeTypes.email.isImplemented) {
             break email;
         }
 
@@ -288,11 +291,11 @@ export async function generateResourcesForMainTheme(params: {
     }
 
     bring_in_account_v1: {
-        if (buildContext.doUseAccountV3) {
+        if (!buildContext.implementedThemeTypes.account.isImplemented) {
             break bring_in_account_v1;
         }
 
-        if (!buildContext.recordIsImplementedByThemeType.account) {
+        if (buildContext.implementedThemeTypes.account.type !== "Multi-Page") {
             break bring_in_account_v1;
         }
 
@@ -303,7 +306,10 @@ export async function generateResourcesForMainTheme(params: {
     }
 
     bring_in_account_v3_i18n_messages: {
-        if (!buildContext.doUseAccountV3) {
+        if (!buildContext.implementedThemeTypes.account.isImplemented) {
+            break bring_in_account_v3_i18n_messages;
+        }
+        if (buildContext.implementedThemeTypes.account.type !== "Single-Page") {
             break bring_in_account_v3_i18n_messages;
         }
 
@@ -340,12 +346,12 @@ export async function generateResourcesForMainTheme(params: {
 
         metaInfKeycloakThemes.themes.push({
             name: themeName,
-            types: objectEntries(buildContext.recordIsImplementedByThemeType)
-                .filter(([, isImplemented]) => isImplemented)
+            types: objectEntries(buildContext.implementedThemeTypes)
+                .filter(([, { isImplemented }]) => isImplemented)
                 .map(([themeType]) => themeType)
         });
 
-        if (buildContext.recordIsImplementedByThemeType.account) {
+        if (buildContext.implementedThemeTypes.account.isImplemented) {
             metaInfKeycloakThemes.themes.push({
                 name: ACCOUNT_V1_THEME_NAME,
                 types: ["account"]
diff --git a/src/bin/shared/buildContext.ts b/src/bin/shared/buildContext.ts
index c970f420..e67df932 100644
--- a/src/bin/shared/buildContext.ts
+++ b/src/bin/shared/buildContext.ts
@@ -20,11 +20,9 @@ import type { KeycloakVersionRange } from "./KeycloakVersionRange";
 import { exclude } from "tsafe";
 import { crawl } from "../tools/crawl";
 import { THEME_TYPES } from "./constants";
-import { objectFromEntries } from "tsafe/objectFromEntries";
 import { objectEntries } from "tsafe/objectEntries";
 import { type ThemeType } from "./constants";
 import { id } from "tsafe/id";
-import { symToStr } from "tsafe/symToStr";
 import chalk from "chalk";
 import { getProxyFetchOptions, type ProxyFetchOptions } from "../tools/fetchProxyOptions";
 
@@ -49,11 +47,13 @@ export type BuildContext = {
     kcContextExclusionsFtlCode: string | undefined;
     environmentVariables: { name: string; default: string }[];
     themeSrcDirPath: string;
-    recordIsImplementedByThemeType: Readonly<Record<ThemeType | "email", boolean>>;
-    jarTargets: {
-        keycloakVersionRange: KeycloakVersionRange;
-        jarFileBasename: string;
-    }[];
+    implementedThemeTypes: {
+        login: { isImplemented: boolean };
+        email: { isImplemented: boolean };
+        account:
+            | { isImplemented: false }
+            | { isImplemented: true; type: "Single-Page" | "Multi-Page" };
+    };
     bundler:
         | {
               type: "vite";
@@ -63,9 +63,14 @@ export type BuildContext = {
               packageJsonDirPath: string;
               packageJsonScripts: Record<string, string>;
           };
-    doUseAccountV3: boolean;
+    jarTargets: {
+        keycloakVersionRange: KeycloakVersionRange;
+        jarFileBasename: string;
+    }[];
 };
 
+assert<Equals<keyof BuildContext["implementedThemeTypes"], ThemeType | "email">>();
+
 export type BuildOptions = {
     themeName?: string | string[];
     themeVersion?: string;
@@ -76,21 +81,30 @@ export type BuildOptions = {
     loginThemeResourcesFromKeycloakVersion?: string;
     keycloakifyBuildDirPath?: string;
     kcContextExclusionsFtl?: string;
-    /** https://docs.keycloakify.dev/v/v10/targetting-specific-keycloak-versions */
-    keycloakVersionTargets?: BuildOptions.KeycloakVersionTargets;
-    doUseAccountV3?: boolean;
-};
+} & BuildOptions.AccountThemeImplAndKeycloakVersionTargets;
 
 export namespace BuildOptions {
-    export type KeycloakVersionTargets =
-        | ({ hasAccountTheme: true } & Record<
-              KeycloakVersionRange.WithAccountV1Theme,
-              string | boolean
-          >)
-        | ({ hasAccountTheme: false } & Record<
-              KeycloakVersionRange.WithoutAccountV1Theme,
-              string | boolean
-          >);
+    export type AccountThemeImplAndKeycloakVersionTargets =
+        | AccountThemeImplAndKeycloakVersionTargets.MultiPageApp
+        | AccountThemeImplAndKeycloakVersionTargets.SinglePageAppOrNone;
+
+    export namespace AccountThemeImplAndKeycloakVersionTargets {
+        export type MultiPageApp = {
+            accountThemeImplementation: "Multi-Page";
+            keycloakVersionTargets?: Record<
+                KeycloakVersionRange.WithAccountV1Theme,
+                string | boolean
+            >;
+        };
+
+        export type SinglePageAppOrNone = {
+            accountThemeImplementation: "Single-Page" | "none";
+            keycloakVersionTargets?: Record<
+                KeycloakVersionRange.WithoutAccountV1Theme,
+                string | boolean
+            >;
+        };
+    }
 }
 
 export type ResolvedViteConfig = {
@@ -231,7 +245,7 @@ export function getBuildContext(params: {
             projectBuildDirPath?: string;
             staticDirPathInProjectBuildDirPath?: string;
             publicDirPath?: string;
-            doUseAccountV3?: boolean;
+            scripts?: Record<string, string>;
         };
 
         type ParsedPackageJson = {
@@ -241,85 +255,121 @@ export function getBuildContext(params: {
             keycloakify?: BuildOptions_packageJson;
         };
 
-        const zParsedPackageJson = z.object({
-            name: z.string().optional(),
-            version: z.string().optional(),
-            homepage: z.string().optional(),
-            keycloakify: id<z.ZodType<BuildOptions_packageJson>>(
-                (() => {
-                    const zBuildOptions_packageJson = z.object({
-                        extraThemeProperties: z.array(z.string()).optional(),
-                        artifactId: z.string().optional(),
-                        groupId: z.string().optional(),
-                        loginThemeResourcesFromKeycloakVersion: z.string().optional(),
-                        projectBuildDirPath: z.string().optional(),
-                        keycloakifyBuildDirPath: z.string().optional(),
-                        kcContextExclusionsFtl: z.string().optional(),
-                        environmentVariables: z
-                            .array(
-                                z.object({
-                                    name: z.string(),
-                                    default: z.string()
-                                })
-                            )
-                            .optional(),
-                        themeName: z.union([z.string(), z.array(z.string())]).optional(),
-                        themeVersion: z.string().optional(),
-                        staticDirPathInProjectBuildDirPath: z.string().optional(),
-                        publicDirPath: z.string().optional(),
-                        keycloakVersionTargets: id<
-                            z.ZodType<BuildOptions.KeycloakVersionTargets>
-                        >(
-                            (() => {
-                                const zKeycloakVersionTargets = z.union([
-                                    z.object({
-                                        hasAccountTheme: z.literal(true),
-                                        "21-and-below": z.union([
-                                            z.boolean(),
-                                            z.string()
-                                        ]),
-                                        "23": z.union([z.boolean(), z.string()]),
-                                        "24": z.union([z.boolean(), z.string()]),
-                                        "25-and-above": z.union([z.boolean(), z.string()])
-                                    }),
-                                    z.object({
-                                        hasAccountTheme: z.literal(false),
-                                        "21-and-below": z.union([
-                                            z.boolean(),
-                                            z.string()
-                                        ]),
-                                        "22-and-above": z.union([z.boolean(), z.string()])
-                                    })
-                                ]);
+        const zMultiPageApp = (() => {
+            type TargetType =
+                BuildOptions.AccountThemeImplAndKeycloakVersionTargets.MultiPageApp;
 
-                                {
-                                    type Got = z.infer<typeof zKeycloakVersionTargets>;
-                                    type Expected = BuildOptions.KeycloakVersionTargets;
-                                    assert<Equals<Got, Expected>>();
-                                }
+            const zTargetType = z.object({
+                accountThemeImplementation: z.literal("Multi-Page"),
+                keycloakVersionTargets: z
+                    .object({
+                        "21-and-below": z.union([z.boolean(), z.string()]),
+                        "23": z.union([z.boolean(), z.string()]),
+                        "24": z.union([z.boolean(), z.string()]),
+                        "25-and-above": z.union([z.boolean(), z.string()])
+                    })
+                    .optional()
+            });
 
-                                return zKeycloakVersionTargets;
-                            })()
-                        ).optional(),
-                        doUseAccountV3: z.boolean().optional()
-                    });
+            assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
 
-                    {
-                        type Got = z.infer<typeof zBuildOptions_packageJson>;
-                        type Expected = BuildOptions_packageJson;
-                        assert<Equals<Got, Expected>>();
-                    }
+            return id<z.ZodType<TargetType>>(zTargetType);
+        })();
 
-                    return zBuildOptions_packageJson;
-                })()
-            ).optional()
-        });
+        const zSinglePageApp = (() => {
+            type TargetType =
+                BuildOptions.AccountThemeImplAndKeycloakVersionTargets.SinglePageAppOrNone;
 
-        {
-            type Got = z.infer<typeof zParsedPackageJson>;
-            type Expected = ParsedPackageJson;
-            assert<Equals<Got, Expected>>();
-        }
+            const zTargetType = z.object({
+                accountThemeImplementation: z.union([
+                    z.literal("Single-Page"),
+                    z.literal("none")
+                ]),
+                keycloakVersionTargets: z
+                    .object({
+                        "21-and-below": z.union([z.boolean(), z.string()]),
+                        "22-and-above": z.union([z.boolean(), z.string()])
+                    })
+                    .optional()
+            });
+
+            assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
+
+            return id<z.ZodType<TargetType>>(zTargetType);
+        })();
+
+        const zAccountThemeImplAndKeycloakVersionTargets = (() => {
+            type TargetType = BuildOptions.AccountThemeImplAndKeycloakVersionTargets;
+
+            const zTargetType = z.union([zMultiPageApp, zSinglePageApp]);
+
+            assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
+
+            return id<z.ZodType<TargetType>>(zTargetType);
+        })();
+
+        const zBuildOptions = (() => {
+            type TargetType = BuildOptions;
+
+            const zTargetType = z.intersection(
+                z.object({
+                    themeName: z.union([z.string(), z.array(z.string())]).optional(),
+                    themeVersion: z.string().optional(),
+                    environmentVariables: z
+                        .array(
+                            z.object({
+                                name: z.string(),
+                                default: z.string()
+                            })
+                        )
+                        .optional(),
+                    extraThemeProperties: z.array(z.string()).optional(),
+                    artifactId: z.string().optional(),
+                    groupId: z.string().optional(),
+                    loginThemeResourcesFromKeycloakVersion: z.string().optional(),
+                    keycloakifyBuildDirPath: z.string().optional(),
+                    kcContextExclusionsFtl: z.string().optional()
+                }),
+                zAccountThemeImplAndKeycloakVersionTargets
+            );
+
+            assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
+
+            return id<z.ZodType<TargetType>>(zTargetType);
+        })();
+
+        const zBuildOptions_packageJson = (() => {
+            type TargetType = BuildOptions_packageJson;
+
+            const zTargetType = z.intersection(
+                zBuildOptions,
+                z.object({
+                    projectBuildDirPath: z.string().optional(),
+                    staticDirPathInProjectBuildDirPath: z.string().optional(),
+                    publicDirPath: z.string().optional(),
+                    scripts: z.record(z.string()).optional()
+                })
+            );
+
+            assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
+
+            return id<z.ZodType<TargetType>>(zTargetType);
+        })();
+
+        const zParsedPackageJson = (() => {
+            type TargetType = ParsedPackageJson;
+
+            const zTargetType = z.object({
+                name: z.string().optional(),
+                version: z.string().optional(),
+                homepage: z.string().optional(),
+                keycloakify: zBuildOptions_packageJson.optional()
+            });
+
+            assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
+
+            return id<z.ZodType<TargetType>>(zTargetType);
+        })();
 
         const configurationPackageJsonFilePath = (() => {
             const rootPackageJsonFilePath = pathJoin(projectDirPath, "package.json");
@@ -334,17 +384,63 @@ export function getBuildContext(params: {
         );
     })();
 
-    const buildOptions = {
-        ...parsedPackageJson.keycloakify,
-        ...resolvedViteConfig?.buildOptions
+    const bundler = resolvedViteConfig !== undefined ? "vite" : "webpack";
+
+    if (bundler === "vite" && parsedPackageJson.keycloakify !== undefined) {
+        console.error(
+            chalk.red(
+                `In vite projects, provide your Keycloakify options in vite.config.ts, not in package.json`
+            )
+        );
+        process.exit(-1);
+    }
+
+    const buildOptions: BuildOptions = (() => {
+        switch (bundler) {
+            case "vite":
+                assert(resolvedViteConfig !== undefined);
+                return resolvedViteConfig.buildOptions;
+            case "webpack":
+                assert(parsedPackageJson.keycloakify !== undefined);
+                return parsedPackageJson.keycloakify;
+        }
+        assert<Equals<typeof bundler, never>>(false);
+    })();
+
+    const implementedThemeTypes: BuildContext["implementedThemeTypes"] = {
+        login: {
+            isImplemented: fs.existsSync(pathJoin(themeSrcDirPath, "login"))
+        },
+        email: {
+            isImplemented: fs.existsSync(pathJoin(themeSrcDirPath, "email"))
+        },
+        account: (() => {
+            if (buildOptions.accountThemeImplementation === "none") {
+                return { isImplemented: false };
+            }
+
+            return {
+                isImplemented: true,
+                type: buildOptions.accountThemeImplementation
+            };
+        })()
     };
 
-    const recordIsImplementedByThemeType = objectFromEntries(
-        (["login", "account", "email"] as const).map(themeType => [
-            themeType,
-            fs.existsSync(pathJoin(themeSrcDirPath, themeType))
-        ])
-    );
+    if (
+        implementedThemeTypes.account.isImplemented &&
+        !fs.existsSync(pathJoin(themeSrcDirPath, "account"))
+    ) {
+        console.error(
+            chalk.red(
+                [
+                    `You have set 'accountThemeImplementation' to '${implementedThemeTypes.account.type}'`,
+                    `but the 'account' directory is missing in your theme source directory`,
+                    "Use the `npx keycloakify initialize-account-theme` command to create it"
+                ].join(" ")
+            )
+        );
+        process.exit(-1);
+    }
 
     const themeNames = ((): [string, ...string[]] => {
         if (buildOptions.themeName === undefined) {
@@ -371,13 +467,15 @@ export function getBuildContext(params: {
 
     const projectBuildDirPath = (() => {
         webpack: {
-            if (resolvedViteConfig !== undefined) {
+            if (bundler !== "webpack") {
                 break webpack;
             }
 
-            if (buildOptions.projectBuildDirPath !== undefined) {
+            assert(parsedPackageJson.keycloakify !== undefined);
+
+            if (parsedPackageJson.keycloakify.projectBuildDirPath !== undefined) {
                 return getAbsoluteAndInOsFormatPath({
-                    pathIsh: buildOptions.projectBuildDirPath,
+                    pathIsh: parsedPackageJson.keycloakify.projectBuildDirPath,
                     cwd: projectDirPath
                 });
             }
@@ -385,34 +483,26 @@ export function getBuildContext(params: {
             return pathJoin(projectDirPath, "build");
         }
 
+        assert(bundler === "vite");
+        assert(resolvedViteConfig !== undefined);
+
         return pathJoin(projectDirPath, resolvedViteConfig.buildDir);
     })();
 
-    const bundler = resolvedViteConfig !== undefined ? "vite" : "webpack";
-
-    const doUseAccountV3 = buildOptions.doUseAccountV3 ?? false;
-
     return {
-        bundler:
-            resolvedViteConfig !== undefined
-                ? { type: "vite" }
-                : (() => {
-                      const { scripts } = z
-                          .object({
-                              scripts: z.record(z.string()).optional()
-                          })
-                          .parse(
-                              JSON.parse(
-                                  fs.readFileSync(packageJsonFilePath).toString("utf8")
-                              )
-                          );
-
-                      return {
-                          type: "webpack",
-                          packageJsonDirPath: pathDirname(packageJsonFilePath),
-                          packageJsonScripts: scripts ?? {}
-                      };
-                  })(),
+        bundler: (() => {
+            switch (bundler) {
+                case "vite":
+                    return { type: "vite" };
+                case "webpack":
+                    return {
+                        type: "webpack",
+                        packageJsonDirPath: pathDirname(packageJsonFilePath),
+                        packageJsonScripts: parsedPackageJson.keycloakify?.scripts ?? {}
+                    };
+            }
+            assert<Equals<typeof bundler, never>>(false);
+        })(),
         themeVersion: buildOptions.themeVersion ?? parsedPackageJson.version ?? "0.0.0",
         themeNames,
         extraThemeProperties: buildOptions.extraThemeProperties,
@@ -463,13 +553,15 @@ export function getBuildContext(params: {
             }
 
             webpack: {
-                if (resolvedViteConfig !== undefined) {
+                if (bundler !== "webpack") {
                     break webpack;
                 }
 
-                if (buildOptions.publicDirPath !== undefined) {
+                assert(parsedPackageJson.keycloakify !== undefined);
+
+                if (parsedPackageJson.keycloakify.publicDirPath !== undefined) {
                     return getAbsoluteAndInOsFormatPath({
-                        pathIsh: buildOptions.publicDirPath,
+                        pathIsh: parsedPackageJson.keycloakify.publicDirPath,
                         cwd: projectDirPath
                     });
                 }
@@ -477,6 +569,9 @@ export function getBuildContext(params: {
                 return pathJoin(projectDirPath, "public");
             }
 
+            assert(bundler === "vite");
+            assert(resolvedViteConfig !== undefined);
+
             return pathJoin(projectDirPath, resolvedViteConfig.publicDir);
         })(),
         cacheDirPath: (() => {
@@ -502,7 +597,7 @@ export function getBuildContext(params: {
         })(),
         urlPathname: (() => {
             webpack: {
-                if (resolvedViteConfig !== undefined) {
+                if (bundler !== "webpack") {
                     break webpack;
                 }
 
@@ -522,23 +617,35 @@ export function getBuildContext(params: {
                 return out === "/" ? undefined : out;
             }
 
+            assert(bundler === "vite");
+            assert(resolvedViteConfig !== undefined);
+
             return resolvedViteConfig.urlPathname;
         })(),
         assetsDirPath: (() => {
             webpack: {
-                if (resolvedViteConfig !== undefined) {
+                if (bundler !== "webpack") {
                     break webpack;
                 }
 
-                if (buildOptions.staticDirPathInProjectBuildDirPath !== undefined) {
+                assert(parsedPackageJson.keycloakify !== undefined);
+
+                if (
+                    parsedPackageJson.keycloakify.staticDirPathInProjectBuildDirPath !==
+                    undefined
+                ) {
                     getAbsoluteAndInOsFormatPath({
-                        pathIsh: buildOptions.staticDirPathInProjectBuildDirPath,
+                        pathIsh:
+                            parsedPackageJson.keycloakify
+                                .staticDirPathInProjectBuildDirPath,
                         cwd: projectBuildDirPath
                     });
                 }
 
                 return pathJoin(projectBuildDirPath, "static");
             }
+            assert(bundler === "vite");
+            assert(resolvedViteConfig !== undefined);
 
             return pathJoin(projectBuildDirPath, resolvedViteConfig.assetsDir);
         })(),
@@ -559,7 +666,7 @@ export function getBuildContext(params: {
             return buildOptions.kcContextExclusionsFtl;
         })(),
         environmentVariables: buildOptions.environmentVariables ?? [],
-        recordIsImplementedByThemeType,
+        implementedThemeTypes,
         themeSrcDirPath,
         fetchOptions: getProxyFetchOptions({
             npmConfigGetCwd: (function callee(upCount: number): string {
@@ -613,10 +720,10 @@ export function getBuildContext(params: {
                 }
 
                 const keycloakVersionRange: KeycloakVersionRange = (() => {
-                    const doesImplementAccountV1Theme =
-                        !doUseAccountV3 && recordIsImplementedByThemeType.account;
-
-                    if (doesImplementAccountV1Theme) {
+                    if (
+                        implementedThemeTypes.account.isImplemented &&
+                        implementedThemeTypes.account.type === "Multi-Page"
+                    ) {
                         const keycloakVersionRange = (() => {
                             if (buildForKeycloakMajorVersionNumber <= 21) {
                                 return "21-and-below" as const;
@@ -703,7 +810,10 @@ export function getBuildContext(params: {
             const jarTargets_default = (() => {
                 const jarTargets: BuildContext["jarTargets"] = [];
 
-                if (!doUseAccountV3 && recordIsImplementedByThemeType.account) {
+                if (
+                    implementedThemeTypes.account.isImplemented &&
+                    implementedThemeTypes.account.type === "Multi-Page"
+                ) {
                     for (const keycloakVersionRange of [
                         "21-and-below",
                         "23",
@@ -748,79 +858,11 @@ export function getBuildContext(params: {
                 return jarTargets_default;
             }
 
-            if (
-                buildOptions.keycloakVersionTargets.hasAccountTheme !== doUseAccountV3
-                    ? false
-                    : recordIsImplementedByThemeType.account
-            ) {
-                console.log(
-                    chalk.red(
-                        (() => {
-                            const { keycloakVersionTargets } = buildOptions;
-
-                            let message = `Bad ${symToStr({ keycloakVersionTargets })} configuration.\n`;
-
-                            if (keycloakVersionTargets.hasAccountTheme) {
-                                message +=
-                                    "Your codebase does not seem to implement an account theme ";
-                            } else {
-                                message += "Your codebase implements an account theme ";
-                            }
-
-                            const { hasAccountTheme } = keycloakVersionTargets;
-
-                            message += `but you have set ${symToStr({ keycloakVersionTargets })}.${symToStr({ hasAccountTheme })}`;
-                            message += ` to ${hasAccountTheme} in your `;
-                            message += (() => {
-                                switch (bundler) {
-                                    case "vite":
-                                        return "vite.config.ts";
-                                    case "webpack":
-                                        return "package.json";
-                                }
-                                assert<Equals<typeof bundler, never>>(false);
-                            })();
-                            message += `. Please set it to ${!hasAccountTheme} `;
-                            message +=
-                                "and fill up the relevant keycloak version ranges.\n";
-                            message += "Example:\n";
-                            message += JSON.stringify(
-                                id<Pick<BuildOptions, "keycloakVersionTargets">>({
-                                    keycloakVersionTargets: {
-                                        hasAccountTheme:
-                                            recordIsImplementedByThemeType.account,
-                                        ...objectFromEntries(
-                                            jarTargets_default.map(
-                                                ({
-                                                    keycloakVersionRange,
-                                                    jarFileBasename
-                                                }) => [
-                                                    keycloakVersionRange,
-                                                    jarFileBasename
-                                                ]
-                                            )
-                                        )
-                                    }
-                                }),
-                                null,
-                                2
-                            );
-                            message +=
-                                "\nSee: https://docs.keycloakify.dev/v/v10/targetting-specific-keycloak-versions";
-
-                            return message;
-                        })()
-                    )
-                );
-
-                process.exit(1);
-            }
-
             const jarTargets: BuildContext["jarTargets"] = [];
 
-            const { hasAccountTheme, ...rest } = buildOptions.keycloakVersionTargets;
-
-            for (const [keycloakVersionRange, jarNameOrBoolean] of objectEntries(rest)) {
+            for (const [keycloakVersionRange, jarNameOrBoolean] of objectEntries(
+                buildOptions.keycloakVersionTargets
+            )) {
                 if (jarNameOrBoolean === false) {
                     continue;
                 }
@@ -871,7 +913,6 @@ export function getBuildContext(params: {
             }
 
             return jarTargets;
-        })(),
-        doUseAccountV3
+        })()
     };
 }
diff --git a/src/vite-plugin/vite-plugin.ts b/src/vite-plugin/vite-plugin.ts
index 7130969a..3c5214b2 100644
--- a/src/vite-plugin/vite-plugin.ts
+++ b/src/vite-plugin/vite-plugin.ts
@@ -18,12 +18,14 @@ import {
 import MagicString from "magic-string";
 import { generateKcGenTs } from "../bin/shared/generateKcGenTs";
 
-export type Params = BuildOptions & {
-    postBuild?: (buildContext: Omit<BuildContext, "bundler">) => Promise<void>;
-};
+export namespace keycloakify {
+    export type Params = BuildOptions & {
+        postBuild?: (buildContext: Omit<BuildContext, "bundler">) => Promise<void>;
+    };
+}
 
-export function keycloakify(params?: Params) {
-    const { postBuild, ...buildOptions } = params ?? {};
+export function keycloakify(params: keycloakify.Params) {
+    const { postBuild, ...buildOptions } = params;
 
     let projectDirPath: string | undefined = undefined;
     let urlPathname: string | undefined = undefined;