keycloakify 11.8.45 → 11.8.47-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/254.index.js +283 -0
- package/bin/30.index.js +25 -0
- package/bin/{864.index.js → 309.index.js} +6944 -28439
- package/bin/311.index.js +198 -0
- package/bin/{313.index.js → 355.index.js} +101 -147
- package/bin/{84.index.js → 502.index.js} +147 -101
- package/bin/626.index.js +194 -0
- package/bin/{698.index.js → 656.index.js} +101 -147
- package/bin/675.index.js +177 -0
- package/bin/69.index.js +1 -1
- package/bin/762.index.js +1475 -0
- package/bin/780.index.js +4 -2
- package/bin/786.index.js +115 -0
- package/bin/895.index.js +21501 -0
- package/bin/{618.index.js → 932.index.js} +117 -163
- package/bin/949.index.js +1 -1
- package/bin/97.index.js +537 -4
- package/bin/init/index.d.ts +1 -0
- package/bin/init/init.d.ts +3 -0
- package/bin/init/setupEslint.d.ts +4 -0
- package/bin/init/setupVitePluginIfNeeded.d.ts +4 -0
- package/bin/initialize-login-theme.d.ts +4 -0
- package/bin/main.js +19 -30
- package/bin/shared/customHandler.d.ts +1 -1
- package/bin/shared/customHandler.js.map +1 -1
- package/package.json +82 -66
- package/src/bin/init/index.ts +1 -0
- package/src/bin/init/init.ts +354 -0
- package/src/bin/init/setupEslint.ts +80 -0
- package/src/bin/init/setupVitePluginIfNeeded.ts +143 -0
- package/src/bin/initialize-account-theme/initialize-account-theme.ts +4 -0
- package/src/bin/initialize-login-theme.ts +323 -0
- package/src/bin/main.ts +14 -0
- package/src/bin/shared/buildContext.ts +2 -37
- package/src/bin/shared/customHandler.ts +3 -1
- package/src/bin/sync-extensions/extensionModuleMeta.ts +89 -73
- package/src/bin/sync-extensions/managedGitignoreFiles.ts +32 -2
- package/vite-plugin/index.js +1 -24
- package/bin/433.index.js +0 -140
- /package/res/public/keycloakify-dev-resources/account/{account/css → css}/account.css +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/img → img}/icon-sidebar-active.png +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/img → img}/keycloak-logo.png +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/img → img}/logo.png +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/img/favicon.ico +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly-additions.min.css +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly.min.css +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
- /package/res/public/keycloakify-dev-resources/account/{account/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/css → css}/login.css +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-error-arrow-down.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-error-sign.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-success-arrow-down.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-success-sign.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-warning-arrow-down.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/feedback-warning-sign.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/keycloak-bg.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/keycloak-logo-text.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/img → img}/keycloak-logo.png +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/authChecker.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/common.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/kcMultivalued.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/kcNumberFormat.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/kcNumberUnFormat.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/menu-button-links.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/passkeysConditionalAuth.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/passwordVisibility.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/userProfile.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/webauthnAuthenticate.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/js → js}/webauthnRegister.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/img/favicon.ico +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/lib/pficon/pficon.css +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/lib/pficon/pficon.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/RedHatDisplay/RedHatDisplay-Bold.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.woff +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/assets/fonts/overpass-webfont/overpass-bold.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/@patternfly/patternfly/patternfly.min.css +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/jquery/dist/jquery.min.js +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly-additions.min.css +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/css/patternfly.min.css +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.ttf +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Bold-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Light-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Regular-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-Semibold-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-SemiboldItalic-webfont.ttf +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-SemiboldItalic-webfont.woff +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/OpenSans-SemiboldItalic-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.ttf +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/PatternFlyIcons-webfont.woff +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/fonts/fontawesome-webfont.woff2 +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/patternfly/dist/img/bg-login.jpg +0 -0
- /package/res/public/keycloakify-dev-resources/login/{login/resources-common → resources-common}/node_modules/rfc4648/lib/rfc4648.js +0 -0
@@ -0,0 +1,323 @@
|
|
1
|
+
import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate";
|
2
|
+
import { dirname as pathDirname, join as pathJoin } from "path";
|
3
|
+
import type { BuildContext } from "./shared/buildContext";
|
4
|
+
import * as fs from "fs/promises";
|
5
|
+
import { assert, is, type Equals } from "tsafe/assert";
|
6
|
+
import { id } from "tsafe/id";
|
7
|
+
import { addSyncExtensionsToPostinstallScript } from "./shared/addSyncExtensionsToPostinstallScript";
|
8
|
+
import { getIsPrettierAvailable, runPrettier } from "./tools/runPrettier";
|
9
|
+
import { npmInstall } from "./tools/npmInstall";
|
10
|
+
import * as child_process from "child_process";
|
11
|
+
import { z } from "zod";
|
12
|
+
import chalk from "chalk";
|
13
|
+
import cliSelect from "cli-select";
|
14
|
+
import { existsAsync } from "./tools/fs.existsAsync";
|
15
|
+
|
16
|
+
export async function command(params: { buildContext: BuildContext }) {
|
17
|
+
const { buildContext } = params;
|
18
|
+
|
19
|
+
const { hasBeenHandled } = await maybeDelegateCommandToCustomHandler({
|
20
|
+
commandName: "initialize-login-theme",
|
21
|
+
buildContext
|
22
|
+
});
|
23
|
+
|
24
|
+
if (hasBeenHandled) {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
|
28
|
+
if (
|
29
|
+
buildContext.implementedThemeTypes.login.isImplemented ||
|
30
|
+
buildContext.implementedThemeTypes.login.isImplemented_native
|
31
|
+
) {
|
32
|
+
console.warn(chalk.red("There is already a login theme in your project"));
|
33
|
+
|
34
|
+
process.exit(-1);
|
35
|
+
}
|
36
|
+
|
37
|
+
const parsedPackageJson = await (async () => {
|
38
|
+
type ParsedPackageJson = {
|
39
|
+
scripts?: Record<string, string | undefined>;
|
40
|
+
dependencies?: Record<string, string | undefined>;
|
41
|
+
devDependencies?: Record<string, string | undefined>;
|
42
|
+
};
|
43
|
+
|
44
|
+
const zParsedPackageJson = (() => {
|
45
|
+
type TargetType = ParsedPackageJson;
|
46
|
+
|
47
|
+
const zTargetType = z.object({
|
48
|
+
scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
|
49
|
+
dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
|
50
|
+
devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
|
51
|
+
});
|
52
|
+
|
53
|
+
assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
|
54
|
+
|
55
|
+
return id<z.ZodType<TargetType>>(zTargetType);
|
56
|
+
})();
|
57
|
+
const parsedPackageJson = JSON.parse(
|
58
|
+
(await fs.readFile(buildContext.packageJsonFilePath)).toString("utf8")
|
59
|
+
);
|
60
|
+
|
61
|
+
zParsedPackageJson.parse(parsedPackageJson);
|
62
|
+
|
63
|
+
assert(is<ParsedPackageJson>(parsedPackageJson));
|
64
|
+
|
65
|
+
return parsedPackageJson;
|
66
|
+
})();
|
67
|
+
|
68
|
+
addSyncExtensionsToPostinstallScript({
|
69
|
+
parsedPackageJson,
|
70
|
+
buildContext
|
71
|
+
});
|
72
|
+
|
73
|
+
const doInstallStories = await (async () => {
|
74
|
+
console.log(chalk.cyan(`\nDo you want to install the Stories?`));
|
75
|
+
|
76
|
+
const YES = "Yes (Recommended)";
|
77
|
+
const NO = "No";
|
78
|
+
|
79
|
+
const { value } = await cliSelect({
|
80
|
+
values: [YES, NO]
|
81
|
+
}).catch(() => {
|
82
|
+
process.exit(-1);
|
83
|
+
});
|
84
|
+
|
85
|
+
console.log(`${value}\n`);
|
86
|
+
|
87
|
+
return value === YES;
|
88
|
+
})();
|
89
|
+
|
90
|
+
install_storybook: {
|
91
|
+
if (!doInstallStories) {
|
92
|
+
break install_storybook;
|
93
|
+
}
|
94
|
+
|
95
|
+
if (buildContext.bundler !== "vite") {
|
96
|
+
break install_storybook;
|
97
|
+
}
|
98
|
+
|
99
|
+
if (
|
100
|
+
Object.keys({
|
101
|
+
...parsedPackageJson.dependencies,
|
102
|
+
...parsedPackageJson.devDependencies
|
103
|
+
}).includes("storybook")
|
104
|
+
) {
|
105
|
+
break install_storybook;
|
106
|
+
}
|
107
|
+
|
108
|
+
(parsedPackageJson.scripts ??= {})["storybook"] = "storybook dev -p 6006";
|
109
|
+
parsedPackageJson.scripts["build-storybook"] = "storybook build";
|
110
|
+
|
111
|
+
(parsedPackageJson.devDependencies ??= {})["storybook"] = "^9.0.4";
|
112
|
+
parsedPackageJson.devDependencies["@storybook/react-vite"] = "^9.0.4";
|
113
|
+
|
114
|
+
const files: { relativeFilePath: string; fileContent: string }[] = [
|
115
|
+
{
|
116
|
+
relativeFilePath: "main.ts",
|
117
|
+
fileContent: [
|
118
|
+
`import type { StorybookConfig } from "@storybook/react-vite";`,
|
119
|
+
``,
|
120
|
+
`const config: StorybookConfig = {`,
|
121
|
+
` stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],`,
|
122
|
+
` addons: [],`,
|
123
|
+
` framework: {`,
|
124
|
+
` name: "@storybook/react-vite",`,
|
125
|
+
` options: {}`,
|
126
|
+
` },`,
|
127
|
+
`};`,
|
128
|
+
`export default config;`,
|
129
|
+
``
|
130
|
+
].join("\n")
|
131
|
+
},
|
132
|
+
{
|
133
|
+
relativeFilePath: "preview.ts",
|
134
|
+
fileContent: storybookPreviewTsFileContent
|
135
|
+
}
|
136
|
+
];
|
137
|
+
|
138
|
+
for (let { relativeFilePath, fileContent } of files) {
|
139
|
+
const filePath = pathJoin(
|
140
|
+
buildContext.projectDirPath,
|
141
|
+
".storybook",
|
142
|
+
relativeFilePath
|
143
|
+
);
|
144
|
+
|
145
|
+
{
|
146
|
+
const dirPath = pathDirname(filePath);
|
147
|
+
|
148
|
+
if (!(await existsAsync(dirPath))) {
|
149
|
+
await fs.mkdir(dirPath, { recursive: true });
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
run_prettier: {
|
154
|
+
if (!(await getIsPrettierAvailable())) {
|
155
|
+
break run_prettier;
|
156
|
+
}
|
157
|
+
|
158
|
+
fileContent = await runPrettier({
|
159
|
+
filePath: filePath,
|
160
|
+
sourceCode: fileContent
|
161
|
+
});
|
162
|
+
}
|
163
|
+
|
164
|
+
await fs.writeFile(filePath, Buffer.from(fileContent, "utf8"));
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
{
|
169
|
+
const moduleName = "@keycloakify/login-ui";
|
170
|
+
|
171
|
+
const latestVersion = await getModuleLatestVersion({ moduleName });
|
172
|
+
|
173
|
+
(parsedPackageJson.dependencies ??= {})[moduleName] = `~${latestVersion}`;
|
174
|
+
|
175
|
+
if (parsedPackageJson.devDependencies !== undefined) {
|
176
|
+
delete parsedPackageJson.devDependencies[moduleName];
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
install_stories: {
|
181
|
+
if (!doInstallStories) {
|
182
|
+
break install_stories;
|
183
|
+
}
|
184
|
+
|
185
|
+
const moduleName = "@keycloakify/login-ui-storybook";
|
186
|
+
|
187
|
+
const latestVersion = await getModuleLatestVersion({ moduleName });
|
188
|
+
|
189
|
+
(parsedPackageJson.devDependencies ??= {})[moduleName] = `~${latestVersion}`;
|
190
|
+
|
191
|
+
delete parsedPackageJson.dependencies[moduleName];
|
192
|
+
}
|
193
|
+
|
194
|
+
{
|
195
|
+
let sourceCode = JSON.stringify(parsedPackageJson, null, 2);
|
196
|
+
|
197
|
+
if (await getIsPrettierAvailable()) {
|
198
|
+
sourceCode = await runPrettier({
|
199
|
+
sourceCode,
|
200
|
+
filePath: buildContext.packageJsonFilePath
|
201
|
+
});
|
202
|
+
}
|
203
|
+
|
204
|
+
await fs.writeFile(
|
205
|
+
buildContext.packageJsonFilePath,
|
206
|
+
Buffer.from(sourceCode, "utf8")
|
207
|
+
);
|
208
|
+
}
|
209
|
+
|
210
|
+
await npmInstall({
|
211
|
+
packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
|
212
|
+
});
|
213
|
+
}
|
214
|
+
|
215
|
+
async function getModuleLatestVersion(params: { moduleName: string }) {
|
216
|
+
const { moduleName } = params;
|
217
|
+
|
218
|
+
const versions = ((): string[] => {
|
219
|
+
const cmdOutput = child_process
|
220
|
+
.execSync(`npm show ${moduleName} versions --json`)
|
221
|
+
.toString("utf8")
|
222
|
+
.trim();
|
223
|
+
|
224
|
+
const versions = JSON.parse(cmdOutput) as string | string[];
|
225
|
+
|
226
|
+
// NOTE: Bug in some older npm versions
|
227
|
+
if (typeof versions === "string") {
|
228
|
+
return [versions];
|
229
|
+
}
|
230
|
+
|
231
|
+
return versions;
|
232
|
+
})();
|
233
|
+
|
234
|
+
const version = versions.reverse().filter(version => !version.includes("-"))[0];
|
235
|
+
|
236
|
+
assert(version !== undefined);
|
237
|
+
|
238
|
+
return version;
|
239
|
+
}
|
240
|
+
|
241
|
+
const storybookPreviewTsFileContent = [
|
242
|
+
`import type { Preview } from "@storybook/react-vite";`,
|
243
|
+
``,
|
244
|
+
`const preview: Preview = {`,
|
245
|
+
` parameters: {`,
|
246
|
+
` controls: {`,
|
247
|
+
` matchers: {`,
|
248
|
+
` color: /(background|color)$/i,`,
|
249
|
+
` date: /Date$/i`,
|
250
|
+
` }`,
|
251
|
+
` },`,
|
252
|
+
` options: {`,
|
253
|
+
` storySort: (a, b)=> {`,
|
254
|
+
``,
|
255
|
+
` const orderedPagesPrefix = [`,
|
256
|
+
` "Introduction",`,
|
257
|
+
` "login/login.ftl",`,
|
258
|
+
` "login/register.ftl",`,
|
259
|
+
` "login/terms.ftl",`,
|
260
|
+
` "login/error.ftl",`,
|
261
|
+
` "login/code.ftl",`,
|
262
|
+
` "login/delete-account-confirm.ftl",`,
|
263
|
+
` "login/delete-credential.ftl",`,
|
264
|
+
` "login/frontchannel-logout.ftl",`,
|
265
|
+
` "login/idp-review-user-profile.ftl",`,
|
266
|
+
` "login/info.ftl",`,
|
267
|
+
` "login/login-config-totp.ftl",`,
|
268
|
+
` "login/login-idp-link-confirm.ftl",`,
|
269
|
+
` "login/login-idp-link-email.ftl",`,
|
270
|
+
` "login/login-oauth-grant.ftl",`,
|
271
|
+
` "login/login-otp.ftl",`,
|
272
|
+
` "login/login-page-expired.ftl",`,
|
273
|
+
` "login/login-password.ftl",`,
|
274
|
+
` "login/login-reset-otp.ftl",`,
|
275
|
+
` "login/login-reset-password.ftl",`,
|
276
|
+
` "login/login-update-password.ftl",`,
|
277
|
+
` "login/login-update-profile.ftl",`,
|
278
|
+
` "login/login-username.ftl",`,
|
279
|
+
` "login/login-verify-email.ftl",`,
|
280
|
+
` "login/login-x509-info.ftl",`,
|
281
|
+
` "login/logout-confirm.ftl",`,
|
282
|
+
` "login/saml-post-form.ftl",`,
|
283
|
+
` "login/select-authenticator.ftl",`,
|
284
|
+
` "login/update-email.ftl",`,
|
285
|
+
` "login/webauthn-authenticate.ftl",`,
|
286
|
+
` "login/webauthn-error.ftl",`,
|
287
|
+
` "login/webauthn-register.ftl",`,
|
288
|
+
` "login/login-oauth2-device-verify-user-code.ftl",`,
|
289
|
+
` "login/login-recovery-authn-code-config.ftl",`,
|
290
|
+
` "login/login-recovery-authn-code-input.ftl",`,
|
291
|
+
` "account/account.ftl",`,
|
292
|
+
` "account/password.ftl",`,
|
293
|
+
` "account/federatedIdentity.ftl",`,
|
294
|
+
` "account/log.ftl",`,
|
295
|
+
` "account/sessions.ftl",`,
|
296
|
+
` "account/totp.ftl"`,
|
297
|
+
` ];`,
|
298
|
+
``,
|
299
|
+
` function getHardCodedWeight(title) {`,
|
300
|
+
` for (let i = 0; i < orderedPagesPrefix.length; i++) {`,
|
301
|
+
` if (`,
|
302
|
+
` title`,
|
303
|
+
` .toLowerCase()`,
|
304
|
+
` .startsWith(orderedPagesPrefix[i].toLowerCase())`,
|
305
|
+
` ) {`,
|
306
|
+
` return orderedPagesPrefix.length - i;`,
|
307
|
+
` }`,
|
308
|
+
` }`,
|
309
|
+
``,
|
310
|
+
` return 0;`,
|
311
|
+
` }`,
|
312
|
+
``,
|
313
|
+
` return getHardCodedWeight(b.title) - getHardCodedWeight(a.title);`,
|
314
|
+
``,
|
315
|
+
` }`,
|
316
|
+
``,
|
317
|
+
` }`,
|
318
|
+
` }`,
|
319
|
+
`};`,
|
320
|
+
``,
|
321
|
+
`export default preview;`,
|
322
|
+
``
|
323
|
+
].join("\n");
|
package/src/bin/main.ts
CHANGED
@@ -146,6 +146,20 @@ program
|
|
146
146
|
}
|
147
147
|
});
|
148
148
|
|
149
|
+
program
|
150
|
+
.command({
|
151
|
+
name: "init",
|
152
|
+
description: "(BETA) Initialize a new theme type (login/account/admin/email)"
|
153
|
+
})
|
154
|
+
.task({
|
155
|
+
skip,
|
156
|
+
handler: async ({ projectDirPath }) => {
|
157
|
+
const { command } = await import("./init");
|
158
|
+
|
159
|
+
await command({ projectDirPath: projectDirPath ?? process.cwd() });
|
160
|
+
}
|
161
|
+
});
|
162
|
+
|
149
163
|
program
|
150
164
|
.command({
|
151
165
|
name: "eject-page",
|
@@ -2,7 +2,6 @@ import { parse as urlParse } from "url";
|
|
2
2
|
import {
|
3
3
|
join as pathJoin,
|
4
4
|
sep as pathSep,
|
5
|
-
relative as pathRelative,
|
6
5
|
resolve as pathResolve,
|
7
6
|
dirname as pathDirname
|
8
7
|
} from "path";
|
@@ -13,8 +12,7 @@ import { assert, type Equals, is } from "tsafe/assert";
|
|
13
12
|
import * as child_process from "child_process";
|
14
13
|
import {
|
15
14
|
VITE_PLUGIN_SUB_SCRIPTS_ENV_NAMES,
|
16
|
-
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
|
17
|
-
THEME_TYPES
|
15
|
+
BUILD_FOR_KEYCLOAK_MAJOR_VERSION_ENV_NAME
|
18
16
|
} from "./constants";
|
19
17
|
import type { KeycloakVersionRange } from "./KeycloakVersionRange";
|
20
18
|
import { exclude } from "tsafe";
|
@@ -167,40 +165,7 @@ export function getBuildContext(params: {
|
|
167
165
|
return { themeSrcDirPath };
|
168
166
|
}
|
169
167
|
|
170
|
-
{
|
171
|
-
const basenames = fs.readdirSync(srcDirPath);
|
172
|
-
|
173
|
-
for (const basename of basenames) {
|
174
|
-
const path = pathJoin(srcDirPath, basename);
|
175
|
-
|
176
|
-
if (!fs.statSync(path).isFile()) {
|
177
|
-
continue;
|
178
|
-
}
|
179
|
-
|
180
|
-
if (fs.readFileSync(path).toString("utf8").includes("./kc.gen")) {
|
181
|
-
return { themeSrcDirPath: srcDirPath };
|
182
|
-
}
|
183
|
-
}
|
184
|
-
}
|
185
|
-
|
186
|
-
for (const themeType of [...THEME_TYPES, "email"]) {
|
187
|
-
if (!fs.existsSync(pathJoin(srcDirPath, themeType))) {
|
188
|
-
continue;
|
189
|
-
}
|
190
|
-
return { themeSrcDirPath: srcDirPath };
|
191
|
-
}
|
192
|
-
|
193
|
-
console.log(
|
194
|
-
chalk.red(
|
195
|
-
[
|
196
|
-
`Can't locate your Keycloak theme source directory in .${pathSep}${pathRelative(process.cwd(), srcDirPath)}`,
|
197
|
-
`Make sure to either use the Keycloakify CLI in the root of your Keycloakify project or use the --project CLI option`,
|
198
|
-
`If you are collocating your Keycloak theme with your app you must have a directory named '${KEYCLOAK_THEME}' or '${KEYCLOAK_THEME.replace(/-/g, "_")}' in your 'src' directory`
|
199
|
-
].join("\n")
|
200
|
-
)
|
201
|
-
);
|
202
|
-
|
203
|
-
process.exit(1);
|
168
|
+
return { themeSrcDirPath: srcDirPath };
|
204
169
|
})();
|
205
170
|
|
206
171
|
const { resolvedViteConfig } = (() => {
|
@@ -10,11 +10,13 @@ export type CommandName =
|
|
10
10
|
| "update-kc-gen"
|
11
11
|
| "eject-page"
|
12
12
|
| "add-story"
|
13
|
+
| "initialize-login-theme"
|
13
14
|
| "initialize-account-theme"
|
14
15
|
| "initialize-admin-theme"
|
15
16
|
| "initialize-admin-theme"
|
16
17
|
| "initialize-email-theme"
|
17
|
-
| "copy-keycloak-resources-to-public"
|
18
|
+
| "copy-keycloak-resources-to-public"
|
19
|
+
| "init";
|
18
20
|
|
19
21
|
export type ApiVersion = "v1";
|
20
22
|
|
@@ -206,92 +206,108 @@ export async function getExtensionModuleMetas(params: {
|
|
206
206
|
})();
|
207
207
|
|
208
208
|
const extensionModuleMetas = await Promise.all(
|
209
|
-
installedExtensionModules
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
}
|
209
|
+
[...installedExtensionModules]
|
210
|
+
.sort((a, b) => a.moduleName.localeCompare(b.moduleName))
|
211
|
+
.map(
|
212
|
+
async ({
|
213
|
+
moduleName,
|
214
|
+
version,
|
215
|
+
peerDependencies,
|
216
|
+
dirPath
|
217
|
+
}): Promise<ExtensionModuleMeta> => {
|
218
|
+
use_cache: {
|
219
|
+
const extensionModuleMeta_cache =
|
220
|
+
extensionModuleMetas_cacheUpToDate.find(
|
221
|
+
extensionModuleMeta =>
|
222
|
+
extensionModuleMeta.moduleName === moduleName
|
223
|
+
);
|
224
|
+
|
225
|
+
if (extensionModuleMeta_cache === undefined) {
|
226
|
+
break use_cache;
|
227
|
+
}
|
229
228
|
|
230
|
-
|
229
|
+
return extensionModuleMeta_cache;
|
230
|
+
}
|
231
231
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
232
|
+
const files: ExtensionModuleMeta["files"] = [];
|
233
|
+
|
234
|
+
await crawlAsync({
|
235
|
+
dirPath: pathJoin(dirPath, KEYCLOAK_THEME),
|
236
|
+
returnedPathsType: "relative to dirPath",
|
237
|
+
onFileFound: async fileRelativePath_fromReservedDir => {
|
238
|
+
const isPublic = fileRelativePath_fromReservedDir.startsWith(
|
239
|
+
`public${pathSep}`
|
240
|
+
);
|
241
|
+
|
242
|
+
const fileRelativePath = isPublic
|
243
|
+
? pathRelative("public", fileRelativePath_fromReservedDir)
|
244
|
+
: fileRelativePath_fromReservedDir;
|
245
|
+
|
246
|
+
const sourceCode =
|
247
|
+
await getExtensionModuleFileSourceCodeReadyToBeCopied({
|
248
|
+
buildContext,
|
249
|
+
isPublic,
|
250
|
+
fileRelativePath,
|
251
|
+
isOwnershipAction: false,
|
252
|
+
extensionModuleDirPath: dirPath,
|
253
|
+
extensionModuleName: moduleName,
|
254
|
+
extensionModuleVersion: version
|
255
|
+
});
|
256
|
+
|
257
|
+
const hash = computeHash(sourceCode);
|
258
|
+
|
259
|
+
const copyableFilePath = pathJoin(
|
260
|
+
pathDirname(cacheFilePath),
|
261
|
+
KEYCLOAK_THEME,
|
262
|
+
fileRelativePath_fromReservedDir
|
263
|
+
);
|
264
|
+
|
265
|
+
{
|
266
|
+
const dirPath = pathDirname(copyableFilePath);
|
267
|
+
|
268
|
+
if (!(await existsAsync(dirPath))) {
|
269
|
+
await fsPr.mkdir(dirPath, { recursive: true });
|
270
|
+
}
|
271
|
+
}
|
239
272
|
|
240
|
-
|
241
|
-
? pathRelative("public", fileRelativePath_fromReservedDir)
|
242
|
-
: fileRelativePath_fromReservedDir;
|
273
|
+
fsPr.writeFile(copyableFilePath, sourceCode);
|
243
274
|
|
244
|
-
|
245
|
-
await getExtensionModuleFileSourceCodeReadyToBeCopied({
|
246
|
-
buildContext,
|
275
|
+
files.push({
|
247
276
|
isPublic,
|
248
277
|
fileRelativePath,
|
249
|
-
|
250
|
-
|
251
|
-
extensionModuleName: moduleName,
|
252
|
-
extensionModuleVersion: version
|
278
|
+
hash,
|
279
|
+
copyableFilePath
|
253
280
|
});
|
254
|
-
|
255
|
-
const hash = computeHash(sourceCode);
|
256
|
-
|
257
|
-
const copyableFilePath = pathJoin(
|
258
|
-
pathDirname(cacheFilePath),
|
259
|
-
KEYCLOAK_THEME,
|
260
|
-
fileRelativePath_fromReservedDir
|
261
|
-
);
|
262
|
-
|
263
|
-
{
|
264
|
-
const dirPath = pathDirname(copyableFilePath);
|
265
|
-
|
266
|
-
if (!(await existsAsync(dirPath))) {
|
267
|
-
await fsPr.mkdir(dirPath, { recursive: true });
|
268
|
-
}
|
269
281
|
}
|
282
|
+
});
|
270
283
|
|
271
|
-
|
284
|
+
{
|
285
|
+
const getId = (file: {
|
286
|
+
isPublic: boolean;
|
287
|
+
fileRelativePath: string;
|
288
|
+
}) =>
|
289
|
+
`${file.isPublic ? "public" : "src"} - ${file.fileRelativePath}`;
|
272
290
|
|
273
|
-
files.
|
274
|
-
isPublic,
|
275
|
-
fileRelativePath,
|
276
|
-
hash,
|
277
|
-
copyableFilePath
|
278
|
-
});
|
291
|
+
files.sort((a, b) => getId(a).localeCompare(getId(b)));
|
279
292
|
}
|
280
|
-
});
|
281
293
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
294
|
+
return id<ExtensionModuleMeta>({
|
295
|
+
moduleName,
|
296
|
+
version,
|
297
|
+
files,
|
298
|
+
peerDependencies: Object.fromEntries(
|
299
|
+
Object.entries(peerDependencies)
|
300
|
+
.filter(
|
301
|
+
([moduleName]) =>
|
302
|
+
!isAmong(["react", "@types/react"], moduleName)
|
303
|
+
)
|
304
|
+
.sort(([moduleName_a], [moduleName_b]) =>
|
305
|
+
moduleName_a.localeCompare(moduleName_b)
|
306
|
+
)
|
290
307
|
)
|
291
|
-
)
|
292
|
-
}
|
293
|
-
|
294
|
-
)
|
308
|
+
});
|
309
|
+
}
|
310
|
+
)
|
295
311
|
);
|
296
312
|
|
297
313
|
update_cache: {
|
@@ -73,10 +73,16 @@ export async function writeManagedGitignoreFiles(params: {
|
|
73
73
|
...ownedFilesRelativePaths_ctx
|
74
74
|
.map(({ fileRelativePath }) => fileRelativePath)
|
75
75
|
.map(fileRelativePath => fileRelativePath.split(pathSep).join("/"))
|
76
|
+
.sort(posixPathCompareFn)
|
76
77
|
.map(line => `# ${line}`),
|
77
78
|
DELIMITER_END,
|
78
79
|
``,
|
79
|
-
...extensionModuleMetas_ctx
|
80
|
+
...[...extensionModuleMetas_ctx]
|
81
|
+
.sort((a, b) => {
|
82
|
+
const n = a.moduleName.length - b.moduleName.length;
|
83
|
+
|
84
|
+
return n !== 0 ? n : a.moduleName.localeCompare(b.moduleName);
|
85
|
+
})
|
80
86
|
.map(extensionModuleMeta => [
|
81
87
|
`# === ${extensionModuleMeta.moduleName} v${extensionModuleMeta.version} ===`,
|
82
88
|
...extensionModuleMeta.files
|
@@ -90,7 +96,8 @@ export async function writeManagedGitignoreFiles(params: {
|
|
90
96
|
.map(
|
91
97
|
fileRelativePath =>
|
92
98
|
`/${fileRelativePath.split(pathSep).join("/").replace(/^\.\//, "")}`
|
93
|
-
)
|
99
|
+
)
|
100
|
+
.sort(posixPathCompareFn),
|
94
101
|
|
95
102
|
``
|
96
103
|
])
|
@@ -187,3 +194,26 @@ export async function readManagedGitignoresFile(params: {
|
|
187
194
|
|
188
195
|
return { ownedFilesRelativePaths };
|
189
196
|
}
|
197
|
+
|
198
|
+
function posixPathCompareFn(a: string, b: string) {
|
199
|
+
const aParts = a.split("/");
|
200
|
+
const bParts = b.split("/");
|
201
|
+
|
202
|
+
const diff = aParts.length - bParts.length;
|
203
|
+
|
204
|
+
if (diff !== 0) {
|
205
|
+
return diff;
|
206
|
+
}
|
207
|
+
|
208
|
+
const len = Math.min(aParts.length, bParts.length);
|
209
|
+
|
210
|
+
for (let i = 0; i < len; i++) {
|
211
|
+
const cmp = aParts[i].localeCompare(bParts[i], undefined, {
|
212
|
+
numeric: true,
|
213
|
+
sensitivity: "base"
|
214
|
+
});
|
215
|
+
if (cmp !== 0) return cmp;
|
216
|
+
}
|
217
|
+
|
218
|
+
return 0;
|
219
|
+
}
|