@@ -11,7 +11,12 @@ import inquirer from 'inquirer';
1111
1212import packageJson from './package.json' with { type : 'json' } ;
1313import { commandDescriptions , cliConfig } from './lib/parser.js' ;
14- import { getLatestVersion , compareVersions } from './lib/utils.js' ;
14+ import {
15+ getLatestVersion ,
16+ compareVersions ,
17+ getCachedUpdateNotification ,
18+ syncVersionCheckCache ,
19+ } from './lib/utils.js' ;
1520import inquirerSearchList from 'inquirer-search-list' ;
1621
1722import { client } from './lib/commands/generic.js' ;
@@ -49,6 +54,42 @@ import { webhooks } from './lib/commands/services/webhooks.js';
4954
5055const { version } = packageJson ;
5156inquirer . registerPrompt ( 'search-list' , inquirerSearchList ) ;
57+ const VERSION_CHECK_TIMEOUT_MS = 5000 ;
58+
59+ function writeUpdateAvailableNotice ( currentVersion : string , latestVersion : string , toStderr : boolean = false ) : void {
60+ const stream = toStderr ? process . stderr : process . stdout ;
61+
62+ stream . write (
63+ chalk . yellow (
64+ `\n⚠️ A newer version is available: ${ chalk . bold ( currentVersion ) } ${ chalk . bold ( '→' ) } ${ chalk . bold (
65+ latestVersion
66+ ) } `
67+ ) + '\n'
68+ ) ;
69+ stream . write (
70+ chalk . cyan (
71+ `💡 Run '${ chalk . bold ( 'appwrite update' ) } ' to update to the latest version.`
72+ ) + '\n'
73+ ) ;
74+ }
75+
76+ function shouldWriteUpdateNoticeToStderr ( ) : boolean {
77+ return process . argv . some ( ( arg ) => [ '-j' , '--json' , '-R' , '--raw' ] . includes ( arg ) ) ;
78+ }
79+
80+ async function maybeShowUpdateNotice ( ) : Promise < void > {
81+ try {
82+ const latestVersion = await getCachedUpdateNotification ( version ) ;
83+
84+ if ( ! latestVersion ) {
85+ return;
86+ }
87+
88+ writeUpdateAvailableNotice ( version , latestVersion , shouldWriteUpdateNoticeToStderr ( ) ) ;
89+ } catch ( _error ) {
90+ // Update checks should never affect command execution.
91+ }
92+ }
5293
5394/**
5495 * Check for updates and show version information
@@ -57,19 +98,12 @@ async function checkVersion(): Promise<void> {
5798 process. stdout . write ( chalk . bold ( `appwrite version ${ version } ` ) + '\n' ) ;
5899
59100 try {
60- const latestVersion = await getLatestVersion ( ) ;
101+ const latestVersion = await getLatestVersion ( { timeoutMs : VERSION_CHECK_TIMEOUT_MS } ) ;
102+ syncVersionCheckCache ( version , latestVersion ) ;
61103 const comparison = compareVersions ( version , latestVersion ) ;
62104
63105 if ( comparison > 0 ) {
64- // Current version is older than latest
65- process . stdout . write (
66- chalk . yellow ( `\n⚠️ A newer version is available: ${ chalk . bold ( latestVersion ) } ` ) + '\n'
67- ) ;
68- process . stdout . write (
69- chalk . cyan (
70- `💡 Run '${ chalk . bold ( 'appwrite update' ) } ' to update to the latest version.`
71- ) + '\n'
72- ) ;
106+ writeUpdateAvailableNotice ( version , latestVersion ) ;
73107 } else if ( comparison === 0 ) {
74108 process . stdout . write ( chalk . green ( '\n✅ You are running the latest version!' ) + '\n' ) ;
75109 } else {
@@ -89,93 +123,97 @@ if (process.argv.includes('-v') || process.argv.includes('--version')) {
89123 process . exit ( 0 ) ;
90124 } ) ( ) ;
91125} else {
92- program
93- . description ( commandDescriptions [ 'main' ] )
94- . configureHelp ( {
95- helpWidth : process . stdout . columns || 80 ,
96- sortSubcommands : true ,
97- } )
98- . helpOption ( '-h, --help' , 'Display help for command' )
99- . version ( version , '-v, --version' , 'Output the version number' )
100- . option ( '-V, --verbose' , 'Show complete error log' )
101- . option ( '-j, --json' , 'Output filtered JSON without empty values' )
102- . option ( '-R, --raw' , 'Output full JSON response (secrets still redacted unless --show-secrets is set)' )
103- . option ( '--show-secrets' , 'Display sensitive values like secrets and tokens in output' )
104- . hook ( 'preAction' , migrate )
105- . option ( '-f,--force' , 'Flag to confirm all warnings' )
106- . option ( '-a,--all' , 'Flag to push all resources' )
107- . option ( '--id [id...]' , 'Flag to pass a list of ids for a given action' )
108- . option ( '--report' , 'Enable reporting in case of CLI errors' )
109- . hook ( 'preAction' , ( _thisCommand , actionCommand ) => {
110- const commandConfig = actionCommand as typeof actionCommand & {
111- outputFields ?: string [ ] ;
112- } ;
113- cliConfig . displayFields = Array . isArray ( commandConfig . outputFields )
114- ? commandConfig . outputFields
115- : [ ] ;
116- } )
117- . on ( 'option:json' , ( ) => {
118- cliConfig . json = true ;
119- } )
120- . on ( 'option:raw' , ( ) => {
121- cliConfig . raw = true ;
122- } )
123- . on ( 'option:show-secrets' , ( ) => {
124- cliConfig . showSecrets = true ;
125- } )
126- . on ( 'option:verbose' , ( ) => {
127- cliConfig . verbose = true ;
128- } )
129- . on ( 'option:report' , function ( ) {
130- cliConfig . report = true ;
131- cliConfig . reportData = { data : this } ;
132- } )
133- . on ( 'option:force' , ( ) => {
134- cliConfig . force = true ;
135- } )
136- . on ( 'option:all' , ( ) => {
137- cliConfig . all = true ;
138- } )
139- . on ( 'option:id' , function ( ) {
140- cliConfig . ids = ( this . opts ( ) . id as string [ ] ) ;
141- } )
142- . showSuggestionAfterError ( )
143- . addCommand ( whoami )
144- . addCommand ( register )
145- . addCommand ( login )
146- . addCommand ( init )
147- . addCommand ( pull )
148- . addCommand ( push )
149- . addCommand ( types )
150- . addCommand ( deploy )
151- . addCommand ( run )
152- . addCommand ( update )
153- . addCommand ( generate )
154- . addCommand ( logout )
155- . addCommand ( account )
156- . addCommand ( activities )
157- . addCommand ( backups )
158- . addCommand ( databases )
159- . addCommand ( functions )
160- . addCommand ( graphql )
161- . addCommand ( health )
162- . addCommand ( locale )
163- . addCommand ( messaging )
164- . addCommand ( migrations )
165- . addCommand ( organizations )
166- . addCommand ( project )
167- . addCommand ( projects )
168- . addCommand ( proxy )
169- . addCommand ( sites )
170- . addCommand ( storage )
171- . addCommand ( tablesDB )
172- . addCommand ( teams )
173- . addCommand ( tokens )
174- . addCommand ( users )
175- . addCommand ( vcs )
176- . addCommand ( webhooks )
177- . addCommand ( client )
178- . parse ( process . argv ) ;
179-
180- process . stdout . columns = oldWidth ;
126+ void ( async ( ) => {
127+ await maybeShowUpdateNotice ( ) ;
128+
129+ program
130+ . description ( commandDescriptions [ 'main' ] )
131+ . configureHelp ( {
132+ helpWidth : process . stdout . columns || 80 ,
133+ sortSubcommands : true ,
134+ } )
135+ . helpOption ( '-h, --help' , 'Display help for command' )
136+ . version ( version , '-v, --version' , 'Output the version number' )
137+ . option ( '-V, --verbose' , 'Show complete error log' )
138+ . option ( '-j, --json' , 'Output filtered JSON without empty values' )
139+ . option ( '-R, --raw' , 'Output full JSON response (secrets still redacted unless --show-secrets is set)' )
140+ . option ( '--show-secrets' , 'Display sensitive values like secrets and tokens in output' )
141+ . hook ( 'preAction' , migrate )
142+ . option ( '-f,--force' , 'Flag to confirm all warnings' )
143+ . option ( '-a,--all' , 'Flag to push all resources' )
144+ . option ( '--id [id...]' , 'Flag to pass a list of ids for a given action' )
145+ . option ( '--report' , 'Enable reporting in case of CLI errors' )
146+ . hook ( 'preAction' , ( _thisCommand , actionCommand ) => {
147+ const commandConfig = actionCommand as typeof actionCommand & {
148+ outputFields ?: string [ ] ;
149+ } ;
150+ cliConfig . displayFields = Array . isArray ( commandConfig . outputFields )
151+ ? commandConfig . outputFields
152+ : [ ] ;
153+ } )
154+ . on ( 'option:json' , ( ) => {
155+ cliConfig . json = true ;
156+ } )
157+ . on ( 'option:raw' , ( ) => {
158+ cliConfig . raw = true ;
159+ } )
160+ . on ( 'option:show-secrets' , ( ) => {
161+ cliConfig . showSecrets = true ;
162+ } )
163+ . on ( 'option:verbose' , ( ) => {
164+ cliConfig . verbose = true ;
165+ } )
166+ . on ( 'option:report' , function ( ) {
167+ cliConfig . report = true ;
168+ cliConfig . reportData = { data : this } ;
169+ } )
170+ . on ( 'option:force' , ( ) => {
171+ cliConfig . force = true ;
172+ } )
173+ . on ( 'option:all' , ( ) => {
174+ cliConfig . all = true ;
175+ } )
176+ . on ( 'option:id' , function ( ) {
177+ cliConfig . ids = ( this . opts ( ) . id as string [ ] ) ;
178+ } )
179+ . showSuggestionAfterError ( )
180+ . addCommand ( whoami )
181+ . addCommand ( register )
182+ . addCommand ( login )
183+ . addCommand ( init )
184+ . addCommand ( pull )
185+ . addCommand ( push )
186+ . addCommand ( types )
187+ . addCommand ( deploy )
188+ . addCommand ( run )
189+ . addCommand ( update )
190+ . addCommand ( generate )
191+ . addCommand ( logout )
192+ . addCommand ( account )
193+ . addCommand ( activities )
194+ . addCommand ( backups )
195+ . addCommand ( databases )
196+ . addCommand ( functions )
197+ . addCommand ( graphql )
198+ . addCommand ( health )
199+ . addCommand ( locale )
200+ . addCommand ( messaging )
201+ . addCommand ( migrations )
202+ . addCommand ( organizations )
203+ . addCommand ( project )
204+ . addCommand ( projects )
205+ . addCommand ( proxy )
206+ . addCommand ( sites )
207+ . addCommand ( storage )
208+ . addCommand ( tablesDB )
209+ . addCommand ( teams )
210+ . addCommand ( tokens )
211+ . addCommand ( users )
212+ . addCommand ( vcs )
213+ . addCommand ( webhooks )
214+ . addCommand ( client )
215+ . parse ( process . argv ) ;
216+
217+ process . stdout . columns = oldWidth ;
218+ } ) ( ) ;
181219}
0 commit comments