keycloakify 11.6.1 → 11.7.0

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.
Files changed (96) hide show
  1. package/bin/{653.index.js → 288.index.js} +221 -201
  2. package/bin/313.index.js +377 -0
  3. package/bin/{174.index.js → 33.index.js} +37 -2
  4. package/bin/{615.index.js → 355.index.js} +353 -102
  5. package/bin/363.index.js +1537 -0
  6. package/bin/453.index.js +6 -42
  7. package/bin/{503.index.js → 678.index.js} +577 -53
  8. package/bin/{921.index.js → 780.index.js} +54 -45
  9. package/bin/880.index.js +206 -21
  10. package/bin/9.index.js +850 -0
  11. package/bin/{525.index.js → 911.index.js} +1302 -2
  12. package/bin/930.index.js +164 -0
  13. package/bin/946.index.js +20 -0
  14. package/bin/{153.index.js → 947.index.js} +22 -797
  15. package/bin/main.js +61 -19
  16. package/bin/{eject-file.d.ts → own.d.ts} +2 -1
  17. package/bin/shared/{addPostinstallScriptIfNotPresent.d.ts → initializeSpa/addSyncExtensionsToPostinstallScript.d.ts} +1 -1
  18. package/bin/shared/initializeSpa/index.d.ts +1 -0
  19. package/bin/shared/initializeSpa/initializeSpa.d.ts +9 -0
  20. package/bin/{postinstall/uiModuleMeta.d.ts → sync-extensions/extensionModuleMeta.d.ts} +5 -5
  21. package/bin/sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.d.ts +12 -0
  22. package/bin/sync-extensions/index.d.ts +1 -0
  23. package/bin/{postinstall/installUiModulesPeerDependencies.d.ts → sync-extensions/installExtensionModulesPeerDependencies.d.ts} +3 -3
  24. package/bin/{postinstall → sync-extensions}/managedGitignoreFile.d.ts +4 -4
  25. package/bin/tools/getInstalledModuleDirPath.d.ts +0 -1
  26. package/bin/tools/isKnownByGit.d.ts +3 -0
  27. package/bin/tools/isRootPath.d.ts +1 -0
  28. package/bin/tools/listInstalledModules.d.ts +0 -1
  29. package/package.json +41 -63
  30. package/src/bin/eject-page.ts +8 -84
  31. package/src/bin/initialize-account-theme/initialize-account-theme.ts +15 -14
  32. package/src/bin/initialize-admin-theme.ts +17 -124
  33. package/src/bin/initialize-email-theme.ts +10 -34
  34. package/src/bin/keycloakify/generateResources/generateResources.ts +49 -21
  35. package/src/bin/main.ts +61 -16
  36. package/src/bin/own.ts +208 -0
  37. package/src/bin/shared/{addPostinstallScriptIfNotPresent.ts → initializeSpa/addSyncExtensionsToPostinstallScript.ts} +4 -4
  38. package/src/bin/shared/initializeSpa/index.ts +1 -0
  39. package/src/bin/shared/initializeSpa/initializeSpa.ts +149 -0
  40. package/src/bin/{postinstall/uiModuleMeta.ts → sync-extensions/extensionModuleMeta.ts} +48 -43
  41. package/src/bin/{postinstall/getUiModuleFileSourceCodeReadyToBeCopied.ts → sync-extensions/getExtensionModuleFileSourceCodeReadyToBeCopied.ts} +32 -21
  42. package/src/bin/sync-extensions/index.ts +1 -0
  43. package/src/bin/{postinstall/installUiModulesPeerDependencies.ts → sync-extensions/installExtensionModulesPeerDependencies.ts} +15 -13
  44. package/src/bin/{postinstall → sync-extensions}/managedGitignoreFile.ts +18 -18
  45. package/src/bin/{postinstall/postinstall.ts → sync-extensions/sync-extension.ts} +14 -26
  46. package/src/bin/tools/getInstalledModuleDirPath.ts +24 -22
  47. package/src/bin/tools/isKnownByGit.ts +45 -0
  48. package/src/bin/tools/isRootPath.ts +22 -0
  49. package/src/bin/tools/listInstalledModules.ts +4 -6
  50. package/src/bin/tools/npmInstall.ts +1 -1
  51. package/src/bin/tools/untrackFromGit.ts +19 -3
  52. package/src/bin/tsconfig.json +1 -1
  53. package/bin/300.index.js +0 -770
  54. package/bin/375.index.js +0 -4089
  55. package/bin/490.index.js +0 -1108
  56. package/bin/568.index.js +0 -1867
  57. package/bin/735.index.js +0 -907
  58. package/bin/743.index.js +0 -69
  59. package/bin/854.index.js +0 -68
  60. package/bin/initialize-account-theme/copyBoilerplate.d.ts +0 -4
  61. package/bin/initialize-account-theme/initializeAccountTheme_multiPage.d.ts +0 -3
  62. package/bin/initialize-account-theme/initializeAccountTheme_singlePage.d.ts +0 -11
  63. package/bin/postinstall/getUiModuleFileSourceCodeReadyToBeCopied.d.ts +0 -12
  64. package/bin/postinstall/index.d.ts +0 -1
  65. package/bin/shared/getLatestsSemVersionedTag.d.ts +0 -15
  66. package/bin/shared/promptKeycloakVersion.d.ts +0 -10
  67. package/bin/tools/OptionalIfCanBeUndefined.d.ts +0 -14
  68. package/bin/tools/crc32.d.ts +0 -9
  69. package/bin/tools/deflate.d.ts +0 -24
  70. package/bin/tools/isTrackedByGit.d.ts +0 -3
  71. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.d.ts +0 -15
  72. package/bin/tools/octokit-addons/listTags.d.ts +0 -13
  73. package/bin/tools/tee.d.ts +0 -3
  74. package/bin/tools/trimIndent.d.ts +0 -5
  75. package/src/bin/eject-file.ts +0 -68
  76. package/src/bin/initialize-account-theme/copyBoilerplate.ts +0 -32
  77. package/src/bin/initialize-account-theme/initializeAccountTheme_multiPage.ts +0 -21
  78. package/src/bin/initialize-account-theme/initializeAccountTheme_singlePage.ts +0 -142
  79. package/src/bin/initialize-account-theme/src/single-page/KcContext.ts +0 -7
  80. package/src/bin/initialize-account-theme/src/single-page/KcPage.tsx +0 -11
  81. package/src/bin/postinstall/index.ts +0 -1
  82. package/src/bin/shared/getLatestsSemVersionedTag.ts +0 -201
  83. package/src/bin/shared/promptKeycloakVersion.ts +0 -72
  84. package/src/bin/tools/OptionalIfCanBeUndefined.ts +0 -12
  85. package/src/bin/tools/crc32.ts +0 -73
  86. package/src/bin/tools/deflate.ts +0 -61
  87. package/src/bin/tools/isTrackedByGit.ts +0 -29
  88. package/src/bin/tools/octokit-addons/getLatestsSemVersionedTag.ts +0 -47
  89. package/src/bin/tools/octokit-addons/listTags.ts +0 -60
  90. package/src/bin/tools/tee.ts +0 -39
  91. package/src/bin/tools/trimIndent.ts +0 -49
  92. /package/bin/{postinstall/postinstall.d.ts → sync-extensions/sync-extension.d.ts} +0 -0
  93. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcContext.ts +0 -0
  94. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcPage.tsx +0 -0
  95. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/KcPageStory.tsx +0 -0
  96. /package/src/bin/initialize-account-theme/{src/multi-page → multi-page-boilerplate}/i18n.ts +0 -0
@@ -7,6 +7,7 @@ import { updateAccountThemeImplementationInConfig } from "./updateAccountThemeIm
7
7
  import { command as updateKcGenCommand } from "../update-kc-gen";
8
8
  import { maybeDelegateCommandToCustomHandler } from "../shared/customHandler_delegate";
9
9
  import { exitIfUncommittedChanges } from "../shared/exitIfUncommittedChanges";
10
+ import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath";
10
11
 
11
12
  export async function command(params: { buildContext: BuildContext }) {
12
13
  const { buildContext } = params;
@@ -50,24 +51,24 @@ export async function command(params: { buildContext: BuildContext }) {
50
51
 
51
52
  switch (accountThemeType) {
52
53
  case "Multi-Page":
53
- {
54
- const { initializeAccountTheme_multiPage } = await import(
55
- "./initializeAccountTheme_multiPage"
56
- );
57
-
58
- await initializeAccountTheme_multiPage({
59
- accountThemeSrcDirPath
60
- });
61
- }
54
+ fs.cpSync(
55
+ pathJoin(
56
+ getThisCodebaseRootDirPath(),
57
+ "src",
58
+ "bin",
59
+ "initialize-account-theme",
60
+ "multi-page-boilerplate"
61
+ ),
62
+ accountThemeSrcDirPath,
63
+ { recursive: true }
64
+ );
62
65
  break;
63
66
  case "Single-Page":
64
67
  {
65
- const { initializeAccountTheme_singlePage } = await import(
66
- "./initializeAccountTheme_singlePage"
67
- );
68
+ const { initializeSpa } = await import("../shared/initializeSpa");
68
69
 
69
- await initializeAccountTheme_singlePage({
70
- accountThemeSrcDirPath,
70
+ await initializeSpa({
71
+ themeType: "account",
71
72
  buildContext
72
73
  });
73
74
  }
@@ -1,15 +1,8 @@
1
- import { dirname as pathDirname, join as pathJoin, relative as pathRelative } from "path";
2
1
  import type { BuildContext } from "./shared/buildContext";
3
- import * as fs from "fs";
4
2
  import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate";
5
- import { assert, is, type Equals } from "tsafe/assert";
6
- import { id } from "tsafe/id";
7
- import { addPostinstallScriptIfNotPresent } from "./shared/addPostinstallScriptIfNotPresent";
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";
3
+ import { initializeSpa } from "./shared/initializeSpa";
4
+ import { exitIfUncommittedChanges } from "./shared/exitIfUncommittedChanges";
5
+ import { command as updateKcGenCommand } from "./update-kc-gen";
13
6
 
14
7
  export async function command(params: { buildContext: BuildContext }) {
15
8
  const { buildContext } = params;
@@ -23,124 +16,24 @@ export async function command(params: { buildContext: BuildContext }) {
23
16
  return;
24
17
  }
25
18
 
26
- {
27
- const adminThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "admin");
28
-
29
- if (
30
- fs.existsSync(adminThemeSrcDirPath) &&
31
- fs.readdirSync(adminThemeSrcDirPath).length > 0
32
- ) {
33
- console.warn(
34
- chalk.red(
35
- `There is already a ${pathRelative(
36
- process.cwd(),
37
- adminThemeSrcDirPath
38
- )} directory in your project. Aborting.`
39
- )
40
- );
41
-
42
- process.exit(-1);
43
- }
44
- }
45
-
46
- const parsedPackageJson = (() => {
47
- type ParsedPackageJson = {
48
- scripts?: Record<string, string | undefined>;
49
- dependencies?: Record<string, string | undefined>;
50
- devDependencies?: Record<string, string | undefined>;
51
- };
52
-
53
- const zParsedPackageJson = (() => {
54
- type TargetType = ParsedPackageJson;
55
-
56
- const zTargetType = z.object({
57
- scripts: z.record(z.union([z.string(), z.undefined()])).optional(),
58
- dependencies: z.record(z.union([z.string(), z.undefined()])).optional(),
59
- devDependencies: z.record(z.union([z.string(), z.undefined()])).optional()
60
- });
61
-
62
- assert<Equals<z.infer<typeof zTargetType>, TargetType>>;
63
-
64
- return id<z.ZodType<TargetType>>(zTargetType);
65
- })();
66
- const parsedPackageJson = JSON.parse(
67
- fs.readFileSync(buildContext.packageJsonFilePath).toString("utf8")
68
- );
69
-
70
- zParsedPackageJson.parse(parsedPackageJson);
71
-
72
- assert(is<ParsedPackageJson>(parsedPackageJson));
73
-
74
- return parsedPackageJson;
75
- })();
19
+ exitIfUncommittedChanges({
20
+ projectDirPath: buildContext.projectDirPath
21
+ });
76
22
 
77
- addPostinstallScriptIfNotPresent({
78
- parsedPackageJson,
23
+ await initializeSpa({
24
+ themeType: "admin",
79
25
  buildContext
80
26
  });
81
27
 
82
- const uiSharedMajor = (() => {
83
- const dependencies = {
84
- ...parsedPackageJson.devDependencies,
85
- ...parsedPackageJson.dependencies
86
- };
87
-
88
- const version = dependencies["@keycloakify/keycloak-ui-shared"];
89
-
90
- if (version === undefined) {
91
- return undefined;
28
+ await updateKcGenCommand({
29
+ buildContext: {
30
+ ...buildContext,
31
+ implementedThemeTypes: {
32
+ ...buildContext.implementedThemeTypes,
33
+ admin: {
34
+ isImplemented: true
35
+ }
36
+ }
92
37
  }
93
-
94
- const match = version.match(/^[^~]?(\d+)\./);
95
-
96
- if (match === null) {
97
- return undefined;
98
- }
99
-
100
- return match[1];
101
- })();
102
-
103
- const moduleName = "@keycloakify/keycloak-admin-ui";
104
-
105
- const version = (
106
- JSON.parse(
107
- child_process
108
- .execSync(`npm show ${moduleName} versions --json`)
109
- .toString("utf8")
110
- .trim()
111
- ) as string[]
112
- )
113
- .reverse()
114
- .filter(version => !version.includes("-"))
115
- .find(version =>
116
- uiSharedMajor === undefined ? true : version.startsWith(`${uiSharedMajor}.`)
117
- );
118
-
119
- assert(version !== undefined);
120
-
121
- (parsedPackageJson.dependencies ??= {})[moduleName] = `~${version}`;
122
-
123
- if (parsedPackageJson.devDependencies !== undefined) {
124
- delete parsedPackageJson.devDependencies[moduleName];
125
- }
126
-
127
- {
128
- let sourceCode = JSON.stringify(parsedPackageJson, undefined, 2);
129
-
130
- if (await getIsPrettierAvailable()) {
131
- sourceCode = await runPrettier({
132
- sourceCode,
133
- filePath: buildContext.packageJsonFilePath
134
- });
135
- }
136
-
137
- fs.writeFileSync(
138
- buildContext.packageJsonFilePath,
139
- Buffer.from(sourceCode, "utf8")
140
- );
141
- }
142
-
143
- await npmInstall({
144
- packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath)
145
38
  });
146
39
  }
@@ -1,13 +1,11 @@
1
1
  import { join as pathJoin, relative as pathRelative } from "path";
2
2
  import { transformCodebase } from "./tools/transformCodebase";
3
- import { promptKeycloakVersion } from "./shared/promptKeycloakVersion";
4
3
  import type { BuildContext } from "./shared/buildContext";
5
4
  import * as fs from "fs";
6
5
  import { downloadAndExtractArchive } from "./tools/downloadAndExtractArchive";
7
6
  import { maybeDelegateCommandToCustomHandler } from "./shared/customHandler_delegate";
8
- import fetch from "make-fetch-happen";
9
- import { SemVer } from "./tools/SemVer";
10
7
  import { assert } from "tsafe/assert";
8
+ import { getSupportedDockerImageTags } from "./start-keycloak/getSupportedDockerImageTags";
11
9
 
12
10
  export async function command(params: { buildContext: BuildContext }) {
13
11
  const { buildContext } = params;
@@ -39,40 +37,18 @@ export async function command(params: { buildContext: BuildContext }) {
39
37
 
40
38
  console.log("Initialize with the base email theme from which version of Keycloak?");
41
39
 
42
- let { keycloakVersion } = await promptKeycloakVersion({
43
- // NOTE: This is arbitrary
44
- startingFromMajor: 17,
45
- excludeMajorVersions: [],
46
- doOmitPatch: false,
47
- buildContext
48
- });
49
-
50
- const getUrl = (keycloakVersion: string) => {
51
- return `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`;
52
- };
53
-
54
- keycloakVersion = await (async () => {
55
- const keycloakVersionParsed = SemVer.parse(keycloakVersion);
56
-
57
- while (true) {
58
- const url = getUrl(SemVer.stringify(keycloakVersionParsed));
59
-
60
- const response = await fetch(url, buildContext.fetchOptions);
61
-
62
- if (response.ok) {
63
- break;
64
- }
65
-
66
- assert(keycloakVersionParsed.patch !== 0);
40
+ const { extractedDirPath } = await downloadAndExtractArchive({
41
+ url: await (async () => {
42
+ const { latestMajorTags } = await getSupportedDockerImageTags({
43
+ buildContext
44
+ });
67
45
 
68
- keycloakVersionParsed.patch--;
69
- }
46
+ const keycloakVersion = latestMajorTags[0];
70
47
 
71
- return SemVer.stringify(keycloakVersionParsed);
72
- })();
48
+ assert(keycloakVersion !== undefined);
73
49
 
74
- const { extractedDirPath } = await downloadAndExtractArchive({
75
- url: getUrl(keycloakVersion),
50
+ return `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`;
51
+ })(),
76
52
  cacheDirPath: buildContext.cacheDirPath,
77
53
  fetchOptions: buildContext.fetchOptions,
78
54
  uniqueIdOfOnArchiveFile: "extractOnlyEmailTheme",
@@ -37,10 +37,10 @@ import {
37
37
  } from "../../shared/metaInfKeycloakThemes";
38
38
  import { objectEntries } from "tsafe/objectEntries";
39
39
  import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
40
- import * as child_process from "child_process";
41
40
  import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
42
41
  import propertiesParser from "properties-parser";
43
42
  import { createObjectThatThrowsIfAccessed } from "../../tools/createObjectThatThrowsIfAccessed";
43
+ import { listInstalledModules } from "../../tools/listInstalledModules";
44
44
 
45
45
  export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
46
46
  BuildContextLike_generateMessageProperties & {
@@ -238,9 +238,9 @@ export async function generateResources(params: {
238
238
 
239
239
  let languageTags: string[] | undefined = undefined;
240
240
 
241
- i18n_messages_generation: {
241
+ i18n_multi_page: {
242
242
  if (isSpa) {
243
- break i18n_messages_generation;
243
+ break i18n_multi_page;
244
244
  }
245
245
 
246
246
  assert(themeType !== "admin");
@@ -257,23 +257,43 @@ export async function generateResources(params: {
257
257
  writeMessagePropertiesFiles;
258
258
  }
259
259
 
260
- bring_in_account_spa_messages: {
260
+ let isLegacyAccountSpa = false;
261
+
262
+ // NOTE: Eventually remove this block.
263
+ i18n_single_page_account_legacy: {
261
264
  if (!isSpa) {
262
- break bring_in_account_spa_messages;
265
+ break i18n_single_page_account_legacy;
263
266
  }
264
267
 
265
268
  if (themeType !== "account") {
266
- break bring_in_account_spa_messages;
269
+ break i18n_single_page_account_legacy;
267
270
  }
268
271
 
269
- const accountUiDirPath = child_process
270
- .execSync(`npm list @keycloakify/keycloak-account-ui --parseable`, {
271
- cwd: pathDirname(buildContext.packageJsonFilePath)
272
- })
273
- .toString("utf8")
274
- .trim();
272
+ const [moduleMeta] = await listInstalledModules({
273
+ packageJsonFilePath: buildContext.packageJsonFilePath,
274
+ filter: ({ moduleName }) =>
275
+ moduleName === "@keycloakify/keycloak-account-ui"
276
+ });
277
+
278
+ assert(
279
+ moduleMeta !== undefined,
280
+ `@keycloakify/keycloak-account-ui is supposed to be installed`
281
+ );
282
+
283
+ {
284
+ const [majorStr] = moduleMeta.version.split(".");
285
+
286
+ if (majorStr.length === 6) {
287
+ // NOTE: Now we use the format MMmmpp (Major, minor, patch) for example for
288
+ // 26.0.7 it would be 260007.
289
+ break i18n_single_page_account_legacy;
290
+ } else {
291
+ // 25.0.4-rc.5 or later
292
+ isLegacyAccountSpa = true;
293
+ }
294
+ }
275
295
 
276
- const messageDirPath_defaults = pathJoin(accountUiDirPath, "messages");
296
+ const messageDirPath_defaults = pathJoin(moduleMeta.dirPath, "messages");
277
297
 
278
298
  if (!fs.existsSync(messageDirPath_defaults)) {
279
299
  throw new Error(
@@ -281,6 +301,8 @@ export async function generateResources(params: {
281
301
  );
282
302
  }
283
303
 
304
+ isLegacyAccountSpa = true;
305
+
284
306
  const messagesDirPath_dest = pathJoin(
285
307
  getThemeTypeDirPath({ themeName, themeType: "account" }),
286
308
  "messages"
@@ -342,14 +364,20 @@ export async function generateResources(params: {
342
364
  );
343
365
  }
344
366
 
345
- bring_in_admin_messages: {
346
- if (themeType !== "admin") {
347
- break bring_in_admin_messages;
367
+ i18n_single_page: {
368
+ if (!isSpa) {
369
+ break i18n_single_page;
370
+ }
371
+
372
+ if (isLegacyAccountSpa) {
373
+ break i18n_single_page;
348
374
  }
349
375
 
376
+ assert(themeType === "account" || themeType === "admin");
377
+
350
378
  const messagesDirPath_theme = pathJoin(
351
379
  buildContext.themeSrcDirPath,
352
- "admin",
380
+ themeType,
353
381
  "i18n"
354
382
  );
355
383
 
@@ -423,7 +451,7 @@ export async function generateResources(params: {
423
451
 
424
452
  propertiesByLang[parsedBasename.lang] ??= {
425
453
  base: createObjectThatThrowsIfAccessed<Buffer>({
426
- debugMessage: `No base ${parsedBasename.lang} translation for admin theme`
454
+ debugMessage: `No base ${parsedBasename.lang} translation for ${themeType} theme`
427
455
  }),
428
456
  override: undefined,
429
457
  overrideByThemeName: {}
@@ -446,7 +474,9 @@ export async function generateResources(params: {
446
474
  ] = buffer;
447
475
  });
448
476
 
449
- writeMessagePropertiesFilesByThemeType.admin = ({
477
+ languageTags = Object.keys(propertiesByLang);
478
+
479
+ writeMessagePropertiesFilesByThemeType[themeType] = ({
450
480
  messageDirPath,
451
481
  themeName
452
482
  }) => {
@@ -456,8 +486,6 @@ export async function generateResources(params: {
456
486
 
457
487
  Object.entries(propertiesByLang).forEach(
458
488
  ([lang, { base, override, overrideByThemeName }]) => {
459
- (languageTags ??= []).push(lang);
460
-
461
489
  const messages = propertiesParser.parse(base.toString("utf8"));
462
490
 
463
491
  if (override !== undefined) {
package/src/bin/main.ts CHANGED
@@ -248,13 +248,30 @@ program
248
248
 
249
249
  program
250
250
  .command({
251
- name: "postinstall",
252
- description: "Initialize all the Keycloakify UI modules installed in the project."
251
+ name: "sync-extensions",
252
+ description: [
253
+ "Synchronizes all installed Keycloakify extension modules with your project.",
254
+ "",
255
+ "Example of extension modules: '@keycloakify/keycloak-account-ui', '@keycloakify/keycloak-admin-ui', '@keycloakify/keycloak-ui-shared'",
256
+ "",
257
+ "This command ensures that:",
258
+ "- All required files from installed extensions are copied into your project.",
259
+ "- The copied files are correctly ignored by Git to help you distinguish between your custom source files",
260
+ " and those provided by the extensions.",
261
+ "- Peer dependencies declared by the extensions are automatically added to your package.json.",
262
+ "",
263
+ "You can safely run this command multiple times. It will only update the files and dependencies if needed,",
264
+ "ensuring your project stays in sync with the installed extensions.",
265
+ "",
266
+ "Typical usage:",
267
+ "- Should be run as a postinstall script of your project.",
268
+ ""
269
+ ].join("\n")
253
270
  })
254
271
  .task({
255
272
  skip,
256
273
  handler: async ({ projectDirPath }) => {
257
- const { command } = await import("./postinstall");
274
+ const { command } = await import("./sync-extensions");
258
275
 
259
276
  await command({ buildContext: getBuildContext({ projectDirPath }) });
260
277
  }
@@ -262,37 +279,65 @@ program
262
279
 
263
280
  program
264
281
  .command<{
265
- file: string;
282
+ path: string;
283
+ revert: boolean;
266
284
  }>({
267
- name: "eject-file",
285
+ name: "own",
268
286
  description: [
269
- "WARNING: Not usable yet, will be used for future features",
270
- "Take ownership over a given file"
271
- ].join(" ")
287
+ "Manages ownership of auto-generated files provided by Keycloakify extensions.",
288
+ "",
289
+ "This command allows you to take ownership of a specific file or directory generated",
290
+ "by an extension. Once owned, you can freely modify and version-control the file.",
291
+ "",
292
+ "You can also use the --revert flag to relinquish ownership and restore the file",
293
+ "or directory to its original auto-generated state.",
294
+ "",
295
+ "For convenience, the exact command to take ownership of any file is included as a comment",
296
+ "in the header of each extension-generated file.",
297
+ "",
298
+ "Examples:",
299
+ "$ npx keycloakify own --path admin/KcPage.tsx"
300
+ ].join("\n")
272
301
  })
273
302
  .option({
274
- key: "file",
303
+ key: "path",
275
304
  name: (() => {
276
- const long = "file";
277
- const short = "f";
305
+ const long = "path";
306
+ const short = "p";
278
307
 
279
308
  optionsKeys.push(long, short);
280
309
 
281
310
  return { long, short };
282
311
  })(),
283
312
  description: [
284
- "Relative path of the file relative to the directory of your keycloak theme source",
285
- "Example `--file src/login/page/Login.tsx`"
313
+ "Specifies the relative path of the file or directory to take ownership of.",
314
+ "This path should be relative to your theme directory.",
315
+ "Example: `--path 'admin/KcPage.tsx'`"
286
316
  ].join(" ")
287
317
  })
318
+ .option({
319
+ key: "revert",
320
+ name: (() => {
321
+ const name = "revert";
322
+
323
+ optionsKeys.push(name);
324
+
325
+ return name;
326
+ })(),
327
+ description: [
328
+ "Restores a file or directory to its original auto-generated state,",
329
+ "removing your ownership claim and reverting any modifications."
330
+ ].join(" "),
331
+ defaultValue: false
332
+ })
288
333
  .task({
289
334
  skip,
290
- handler: async ({ projectDirPath, file }) => {
291
- const { command } = await import("./eject-file");
335
+ handler: async ({ projectDirPath, path, revert }) => {
336
+ const { command } = await import("./own");
292
337
 
293
338
  await command({
294
339
  buildContext: getBuildContext({ projectDirPath }),
295
- cliCommandOptions: { file }
340
+ cliCommandOptions: { path, isRevert: revert }
296
341
  });
297
342
  }
298
343
  });