nestforge-generator 0.4.0 → 0.5.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.
package/README.md CHANGED
@@ -16,6 +16,16 @@ Run the locally installed CLI:
16
16
  npx nestforge
17
17
  ```
18
18
 
19
+ ## Automatic update check
20
+
21
+ When the CLI starts, it checks the npm registry for a newer stable version. If an update is available, you can:
22
+
23
+ - download the latest version with `npx` and restart the CLI;
24
+ - continue with the currently installed version;
25
+ - hide the reminder until the next local day.
26
+
27
+ Registry metadata is cached for six hours in `~/.nestforge/update-check.json`. Network and cache failures are ignored so that the generator remains available offline.
28
+
19
29
  For the testing guide, CLI prompts, and complete checklist, see [`TESTING.md`](TESTING.md).
20
30
 
21
31
  ## What already works
package/README.pt-BR.md CHANGED
@@ -16,6 +16,16 @@ Execute a CLI instalada localmente:
16
16
  npx nestforge
17
17
  ```
18
18
 
19
+ ## Verificação automática de atualizações
20
+
21
+ Quando a CLI inicia, ela consulta o registro do npm em busca de uma versão estável mais recente. Se houver uma atualização, você pode:
22
+
23
+ * baixar a versão mais recente com `npx` e reiniciar a CLI;
24
+ * continuar com a versão instalada atualmente;
25
+ * ocultar o lembrete até o próximo dia no horário local.
26
+
27
+ Os metadados do registro ficam em cache durante seis horas em `~/.nestforge/update-check.json`. Falhas de rede ou de cache são ignoradas para que o gerador continue disponível offline.
28
+
19
29
  Para o guia de testes, perguntas da CLI e checklist completo, consulte [`TESTING.pt-BR.md`](TESTING.pt-BR.md).
20
30
 
21
31
  ## O que já funciona
package/dist/index.js CHANGED
@@ -4,7 +4,12 @@ import pc from 'picocolors';
4
4
  import path from 'node:path';
5
5
  import { runPrompts } from './prompts.js';
6
6
  import { generateProject } from './generator.js';
7
+ import { handleUpdateNotification } from './update-notifier.js';
7
8
  async function main() {
9
+ const updateResult = await handleUpdateNotification();
10
+ if (updateResult === 'restarted') {
11
+ return;
12
+ }
8
13
  const options = await runPrompts();
9
14
  try {
10
15
  const targetDir = await generateProject(options);
@@ -59,6 +64,10 @@ async function main() {
59
64
  'npm run start:dev',
60
65
  ];
61
66
  note(steps.join('\n'), 'Next steps');
67
+ note([
68
+ 'Enjoying NestForge? Visit the repository, leave a star, and help the project grow:',
69
+ 'https://github.com/jeiel2013/NestForge',
70
+ ].join('\n'), 'Support NestForge');
62
71
  outro(pc.green(`✅ Project "${options.projectName}" created successfully!`));
63
72
  }
64
73
  catch (error) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import fs from 'fs-extra';
3
+ const packageJsonPath = fileURLToPath(new URL('../package.json', import.meta.url));
4
+ export async function readPackageInfo() {
5
+ const manifest = (await fs.readJson(packageJsonPath));
6
+ if (typeof manifest.name !== 'string' ||
7
+ typeof manifest.version !== 'string') {
8
+ throw new Error('Unable to read the NestForge package information.');
9
+ }
10
+ return {
11
+ name: manifest.name,
12
+ version: manifest.version,
13
+ };
14
+ }
15
+ //# sourceMappingURL=package-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-info.js","sourceRoot":"","sources":["../src/package-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,UAAU,CAAC;AAO1B,MAAM,eAAe,GAAG,aAAa,CACjC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAC9C,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,eAAe;IAIjC,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAC/B,eAAe,CAClB,CAAoB,CAAC;IAEtB,IACI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QACjC,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EACtC,CAAC;QACC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO;QACH,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC5B,CAAC;AACN,CAAC"}
@@ -0,0 +1,102 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import fs from 'fs-extra';
4
+ import semver from 'semver';
5
+ const REGISTRY_URL = 'https://registry.npmjs.org/nestforge-generator/latest';
6
+ const CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
7
+ const REQUEST_TIMEOUT_MS = 2_000;
8
+ export function getUpdateCachePath() {
9
+ return path.join(os.homedir(), '.nestforge', 'update-check.json');
10
+ }
11
+ async function readCache(cachePath) {
12
+ try {
13
+ const cache = (await fs.readJson(cachePath));
14
+ return cache && typeof cache === 'object' ? cache : {};
15
+ }
16
+ catch {
17
+ return {};
18
+ }
19
+ }
20
+ async function writeCache(cachePath, cache) {
21
+ await fs.outputJson(cachePath, cache, { spaces: 2 });
22
+ }
23
+ async function fetchLatestVersion(fetchImplementation) {
24
+ const controller = new AbortController();
25
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
26
+ try {
27
+ const response = await fetchImplementation(REGISTRY_URL, {
28
+ headers: {
29
+ accept: 'application/json',
30
+ },
31
+ signal: controller.signal,
32
+ });
33
+ if (!response.ok) {
34
+ throw new Error(`The npm registry returned ${response.status}.`);
35
+ }
36
+ const metadata = (await response.json());
37
+ if (typeof metadata.version !== 'string' ||
38
+ !semver.valid(metadata.version)) {
39
+ throw new Error('The npm registry returned an invalid version.');
40
+ }
41
+ return metadata.version;
42
+ }
43
+ finally {
44
+ clearTimeout(timeout);
45
+ }
46
+ }
47
+ export async function checkForUpdate(currentVersion, options = {}) {
48
+ if (!semver.valid(currentVersion)) {
49
+ return null;
50
+ }
51
+ const now = options.now ?? Date.now();
52
+ const cachePath = options.cachePath ?? getUpdateCachePath();
53
+ try {
54
+ const cache = await readCache(cachePath);
55
+ if (typeof cache.dismissedUntil === 'number' &&
56
+ cache.dismissedUntil > now) {
57
+ return null;
58
+ }
59
+ const hasFreshCache = typeof cache.checkedAt === 'number' &&
60
+ typeof cache.latestVersion === 'string' &&
61
+ now - cache.checkedAt < CHECK_INTERVAL_MS &&
62
+ semver.valid(cache.latestVersion);
63
+ const latestVersion = hasFreshCache
64
+ ? cache.latestVersion
65
+ : await fetchLatestVersion(options.fetchImplementation ?? fetch);
66
+ if (!hasFreshCache) {
67
+ try {
68
+ await writeCache(cachePath, {
69
+ ...cache,
70
+ checkedAt: now,
71
+ latestVersion,
72
+ });
73
+ }
74
+ catch {
75
+ // The update can still be offered without a writable cache.
76
+ }
77
+ }
78
+ return semver.gt(latestVersion, currentVersion)
79
+ ? { currentVersion, latestVersion }
80
+ : null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ }
86
+ export async function dismissUpdatesForToday(options = {}) {
87
+ const now = options.now ?? Date.now();
88
+ const cachePath = options.cachePath ?? getUpdateCachePath();
89
+ const tomorrow = new Date(now);
90
+ tomorrow.setHours(24, 0, 0, 0);
91
+ try {
92
+ const cache = await readCache(cachePath);
93
+ await writeCache(cachePath, {
94
+ ...cache,
95
+ dismissedUntil: tomorrow.getTime(),
96
+ });
97
+ }
98
+ catch {
99
+ // A cache failure must never prevent the CLI from starting.
100
+ }
101
+ }
102
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { isCancel, log, note, select } from '@clack/prompts';
3
+ import pc from 'picocolors';
4
+ import { readPackageInfo } from './package-info.js';
5
+ import { checkForUpdate, dismissUpdatesForToday, } from './update-check.js';
6
+ export function getUpdateProcess(platform = process.platform) {
7
+ if (platform === 'win32') {
8
+ return {
9
+ command: process.env.ComSpec ?? 'cmd.exe',
10
+ args: [
11
+ '/d',
12
+ '/s',
13
+ '/c',
14
+ 'npx --yes nestforge-generator@latest',
15
+ ],
16
+ };
17
+ }
18
+ return {
19
+ command: 'npx',
20
+ args: ['--yes', 'nestforge-generator@latest'],
21
+ };
22
+ }
23
+ export async function runLatestVersion() {
24
+ return new Promise((resolve) => {
25
+ const updateProcess = getUpdateProcess();
26
+ const child = spawn(updateProcess.command, updateProcess.args, {
27
+ stdio: 'inherit',
28
+ shell: false,
29
+ });
30
+ let settled = false;
31
+ const finish = (success) => {
32
+ if (settled) {
33
+ return;
34
+ }
35
+ settled = true;
36
+ resolve(success);
37
+ };
38
+ child.once('error', () => finish(false));
39
+ child.once('exit', (code) => finish(code === 0));
40
+ });
41
+ }
42
+ async function promptForUpdate(update) {
43
+ note(`${pc.dim(update.currentVersion)} ${pc.dim('→')} ${pc.green(update.latestVersion)}`, 'NestForge update available');
44
+ const choice = await select({
45
+ message: 'How would you like to continue?',
46
+ options: [
47
+ {
48
+ value: 'update',
49
+ label: 'Update and restart',
50
+ hint: 'Recommended',
51
+ },
52
+ {
53
+ value: 'continue',
54
+ label: `Continue with version ${update.currentVersion}`,
55
+ },
56
+ {
57
+ value: 'dismiss-today',
58
+ label: "Don't remind me today",
59
+ },
60
+ ],
61
+ });
62
+ return isCancel(choice) ? 'continue' : choice;
63
+ }
64
+ export async function handleUpdateNotification(options = {}) {
65
+ try {
66
+ const packageInfo = await (options.readCurrentPackage ?? readPackageInfo)();
67
+ const update = await (options.check ?? checkForUpdate)(packageInfo.version);
68
+ if (!update) {
69
+ return 'continue';
70
+ }
71
+ const choice = await (options.prompt ?? promptForUpdate)(update);
72
+ if (choice === 'dismiss-today') {
73
+ await (options.dismiss ?? dismissUpdatesForToday)();
74
+ return 'continue';
75
+ }
76
+ if (choice === 'continue') {
77
+ return 'continue';
78
+ }
79
+ log.info('Downloading the latest NestForge version...');
80
+ const updated = await (options.runLatest ?? runLatestVersion)();
81
+ if (updated) {
82
+ return 'restarted';
83
+ }
84
+ log.warn('The update could not be started. Continuing with the current version.');
85
+ return 'continue';
86
+ }
87
+ catch {
88
+ return 'continue';
89
+ }
90
+ }
91
+ //# sourceMappingURL=update-notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-notifier.js","sourceRoot":"","sources":["../src/update-notifier.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nestforge-generator",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Interactive CLI for generating a NestJS project from a NestForge starter template",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -19,7 +19,7 @@
19
19
  "build": "tsc -p tsconfig.json && npm run copy:templates",
20
20
  "copy:templates": "node scripts/copy-templates.mjs",
21
21
  "dev": "tsx src/index.ts",
22
- "test": "tsx --test test/generator.test.ts",
22
+ "test": "tsx --test test/generator.test.ts test/update-check.test.ts",
23
23
  "lint": "eslint \"src/**/*.ts\" --fix",
24
24
  "prepack": "npm run build",
25
25
  "prepublishOnly": "npm test"
@@ -48,15 +48,17 @@
48
48
  ],
49
49
  "dependencies": {
50
50
  "@clack/prompts": "^0.9.0",
51
- "picocolors": "^1.1.0",
52
51
  "fs-extra": "^11.2.0",
53
52
  "gradient-string": "^2.0.2",
53
+ "picocolors": "^1.1.0",
54
+ "semver": "^7.8.5",
54
55
  "typescript": "^5.6.0"
55
56
  },
56
57
  "devDependencies": {
57
58
  "@types/fs-extra": "^11.0.4",
58
- "@types/node": "^22.0.0",
59
59
  "@types/gradient-string": "^1.1.6",
60
+ "@types/node": "^22.0.0",
61
+ "@types/semver": "^7.8.0",
60
62
  "tsx": "^4.19.0"
61
63
  },
62
64
  "engines": {