@xano/cli 0.0.69-beta.1 → 0.0.69-beta.2

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.
@@ -23,7 +23,10 @@ export default abstract class BaseCommand extends Command {
23
23
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
24
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
25
25
  };
26
+ private updateNotice;
26
27
  init(): Promise<void>;
28
+ finally(_: Error | undefined): Promise<void>;
29
+ private isJsonOutput;
27
30
  /**
28
31
  * Apply insecure TLS mode if the active profile has insecure: true.
29
32
  * Sets NODE_TLS_REJECT_UNAUTHORIZED=0 so all fetch() calls skip cert verification.
@@ -3,6 +3,7 @@ import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
4
  import * as os from 'node:os';
5
5
  import * as path from 'node:path';
6
+ import { checkForUpdate } from './update-check.js';
6
7
  export function buildUserAgent(version) {
7
8
  return `xano-cli/${version} (${process.platform}; ${process.arch}) node/${process.version}`;
8
9
  }
@@ -24,9 +25,30 @@ export default class BaseCommand extends Command {
24
25
  };
25
26
  // Override the flags property to include baseFlags
26
27
  static flags = BaseCommand.baseFlags;
28
+ updateNotice = null;
27
29
  async init() {
28
30
  await super.init();
29
31
  this.applyInsecureFromProfile();
32
+ const forceUpdateCheck = process.env.XANO_FORCE_UPDATE_CHECK === '1';
33
+ this.updateNotice = checkForUpdate(this.config.version, forceUpdateCheck);
34
+ }
35
+ async finally(_) {
36
+ if (this.updateNotice && !this.isJsonOutput()) {
37
+ this.log(this.updateNotice);
38
+ }
39
+ await super.finally(_);
40
+ }
41
+ isJsonOutput() {
42
+ const args = process.argv;
43
+ for (let i = 0; i < args.length; i++) {
44
+ if (args[i] === '--output' && args[i + 1] === 'json')
45
+ return true;
46
+ if (args[i] === '-o' && args[i + 1] === 'json')
47
+ return true;
48
+ if (args[i] === '--output=json' || args[i] === '-o=json')
49
+ return true;
50
+ }
51
+ return false;
30
52
  }
31
53
  /**
32
54
  * Apply insecure TLS mode if the active profile has insecure: true.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Check if an update is available. Returns an update message string if there
3
+ * is an update, or null if the CLI is up to date / on a beta / check not due.
4
+ *
5
+ * The check hits npm at most once every 24 hours and caches the result.
6
+ */
7
+ export declare function checkForUpdate(currentVersion: string, forceCheck?: boolean): string | null;
@@ -0,0 +1,71 @@
1
+ import { execSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import * as os from 'node:os';
5
+ const UPDATE_CHECK_FILE = path.join(os.homedir(), '.xano', 'update-check.json');
6
+ const CHECK_INTERVAL_MS = 8 * 60 * 60 * 1000; // 8 hours
7
+ function isBeta(version) {
8
+ return version.includes('beta') || version.includes('alpha') || version.includes('rc');
9
+ }
10
+ function readCache() {
11
+ try {
12
+ if (!fs.existsSync(UPDATE_CHECK_FILE))
13
+ return null;
14
+ const data = JSON.parse(fs.readFileSync(UPDATE_CHECK_FILE, 'utf8'));
15
+ if (data && typeof data.lastCheck === 'number' && typeof data.latestVersion === 'string') {
16
+ return data;
17
+ }
18
+ return null;
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ function writeCache(latestVersion) {
25
+ try {
26
+ const dir = path.dirname(UPDATE_CHECK_FILE);
27
+ if (!fs.existsSync(dir)) {
28
+ fs.mkdirSync(dir, { recursive: true });
29
+ }
30
+ fs.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify({ lastCheck: Date.now(), latestVersion }));
31
+ }
32
+ catch {
33
+ // Silently fail — update check is best-effort
34
+ }
35
+ }
36
+ function fetchLatestVersion() {
37
+ try {
38
+ return execSync('npm view @xano/cli version', { encoding: 'utf8', timeout: 5000 }).trim();
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ }
44
+ /**
45
+ * Check if an update is available. Returns an update message string if there
46
+ * is an update, or null if the CLI is up to date / on a beta / check not due.
47
+ *
48
+ * The check hits npm at most once every 24 hours and caches the result.
49
+ */
50
+ export function checkForUpdate(currentVersion, forceCheck = false) {
51
+ if (!forceCheck && isBeta(currentVersion))
52
+ return null;
53
+ const cache = readCache();
54
+ const now = Date.now();
55
+ let latestVersion = null;
56
+ if (cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
57
+ latestVersion = cache.latestVersion;
58
+ }
59
+ else {
60
+ latestVersion = fetchLatestVersion();
61
+ if (latestVersion) {
62
+ writeCache(latestVersion);
63
+ }
64
+ }
65
+ if (!latestVersion || latestVersion === currentVersion)
66
+ return null;
67
+ const yellow = '\u001B[33m';
68
+ const cyan = '\u001B[36m';
69
+ const reset = '\u001B[0m';
70
+ return `\n${yellow}Notice: Update available ${currentVersion} → ${latestVersion}\nRun ${cyan}xano update${yellow} to update${reset}\n`;
71
+ }