@@ -58,6 +58,7 @@ export interface ProjectConfig {
5858 functions : string ;
5959 node : {
6060 externalPackages : string [ ] ;
61+ nodeVersion ?: string ;
6162 } ;
6263 generateCommonJSApi : boolean ;
6364 // deprecated
@@ -82,6 +83,7 @@ export interface Config {
8283 nodeDependencies : NodeDependency [ ] ;
8384 schemaId ?: string ;
8485 udfServerVersion ?: string ;
86+ nodeVersion ?: string ;
8587}
8688
8789export interface ConfigWithModuleHashes {
@@ -127,18 +129,32 @@ export async function parseProjectConfig(
127129 obj . node = {
128130 externalPackages : [ ] ,
129131 } ;
130- } else if ( typeof obj . node . externalPackages === "undefined" ) {
131- obj . node . externalPackages = [ ] ;
132- } else if (
133- ! Array . isArray ( obj . node . externalPackages ) ||
134- ! obj . node . externalPackages . every ( ( item : any ) => typeof item === "string" )
135- ) {
136- return await ctx . crash ( {
137- exitCode : 1 ,
138- errorType : "invalid filesystem data" ,
139- printedMessage :
140- "Expected `node.externalPackages` in `convex.json` to be an array of strings" ,
141- } ) ;
132+ } else {
133+ if ( typeof obj . node . externalPackages === "undefined" ) {
134+ obj . node . externalPackages = [ ] ;
135+ } else if (
136+ ! Array . isArray ( obj . node . externalPackages ) ||
137+ ! obj . node . externalPackages . every ( ( item : any ) => typeof item === "string" )
138+ ) {
139+ return await ctx . crash ( {
140+ exitCode : 1 ,
141+ errorType : "invalid filesystem data" ,
142+ printedMessage :
143+ "Expected `node.externalPackages` in `convex.json` to be an array of strings" ,
144+ } ) ;
145+ }
146+
147+ if (
148+ typeof obj . node . nodeVersion !== "undefined" &&
149+ typeof obj . node . nodeVersion !== "string"
150+ ) {
151+ return await ctx . crash ( {
152+ exitCode : 1 ,
153+ errorType : "invalid filesystem data" ,
154+ printedMessage :
155+ "Expected `node.nodeVersion` in `convex.json` to be a string" ,
156+ } ) ;
157+ }
142158 }
143159 if ( typeof obj . generateCommonJSApi === "undefined" ) {
144160 obj . generateCommonJSApi = false ;
@@ -209,29 +225,34 @@ export async function parseProjectConfig(
209225function parseBackendConfig ( obj : any ) : {
210226 functions : string ;
211227 authInfo ?: AuthInfo [ ] ;
228+ nodeVersion ?: string ;
212229} {
213- if ( typeof obj !== "object" ) {
230+ function throwParseError ( message : string ) {
214231 // Unexpected error
215232 // eslint-disable-next-line no-restricted-syntax
216- throw new ParseError ( "Expected an object" ) ;
233+ throw new ParseError ( message ) ;
217234 }
218- const { functions, authInfo } = obj ;
235+ if ( typeof obj !== "object" ) {
236+ throwParseError ( "Expected an object" ) ;
237+ }
238+ const { functions, authInfo, nodeVersion } = obj ;
219239 if ( typeof functions !== "string" ) {
220- // Unexpected error
221- // eslint-disable-next-line no-restricted-syntax
222- throw new ParseError ( "Expected functions to be a string" ) ;
240+ throwParseError ( "Expected functions to be a string" ) ;
223241 }
224242
225243 // Allow the `authInfo` key to be omitted
226244 if ( ( authInfo ?? null ) !== null && ! isAuthInfos ( authInfo ) ) {
227- // Unexpected error
228- // eslint-disable-next-line no-restricted-syntax
229- throw new ParseError ( "Expected authInfo to be type AuthInfo[]" ) ;
245+ throwParseError ( "Expected authInfo to be type AuthInfo[]" ) ;
246+ }
247+
248+ if ( typeof nodeVersion !== "undefined" && typeof nodeVersion !== "string" ) {
249+ throwParseError ( "Expected nodeVersion to be a string" ) ;
230250 }
231251
232252 return {
233253 functions,
234254 ...( ( authInfo ?? null ) !== null ? { authInfo : authInfo } : { } ) ,
255+ ...( ( nodeVersion ?? null ) !== null ? { nodeVersion : nodeVersion } : { } ) ,
235256 } ;
236257}
237258
@@ -452,6 +473,7 @@ export async function configFromProjectConfig(
452473 // This could be different than the version of `convex` the app runs with
453474 // if the CLI is installed globally.
454475 udfServerVersion : version ,
476+ nodeVersion : projectConfig . node . nodeVersion ,
455477 } ,
456478 bundledModuleInfos,
457479 } ;
@@ -661,10 +683,11 @@ export async function pullConfig(
661683 const backendConfig = parseBackendConfig ( data . config ) ;
662684 const projectConfig = {
663685 ...backendConfig ,
664- // This field is not stored in the backend, which is ok since it is also
665- // not used to diff configs.
666686 node : {
687+ // This field is not stored in the backend, which is ok since it is also
688+ // not used to diff configs.
667689 externalPackages : [ ] ,
690+ nodeVersion : data . nodeVersion ,
668691 } ,
669692 // This field is not stored in the backend, it only affects the client.
670693 generateCommonJSApi : false ,
@@ -754,6 +777,7 @@ export function configJSON(
754777 adminKey,
755778 pushMetrics,
756779 bundledModuleInfos,
780+ nodeVersion : config . nodeVersion ,
757781 } ;
758782}
759783
@@ -968,12 +992,20 @@ function compareModules(
968992export function diffConfig (
969993 oldConfig : ConfigWithModuleHashes ,
970994 newConfig : Config ,
971- ) : { diffString : string ; stats : ModuleDiffStats } {
972- const { diffString, stats } = compareModules (
973- oldConfig . moduleHashes ,
974- newConfig . modules ,
975- ) ;
976- let diff = diffString ;
995+ // We don't want to diff modules on the components push path
996+ // because it has its own diffing logic.
997+ shouldDiffModules : boolean ,
998+ ) : { diffString : string ; stats ?: ModuleDiffStats } {
999+ let diff = "" ;
1000+ let stats : ModuleDiffStats | undefined ;
1001+ if ( shouldDiffModules ) {
1002+ const { diffString, stats : moduleStats } = compareModules (
1003+ oldConfig . moduleHashes ,
1004+ newConfig . modules ,
1005+ ) ;
1006+ diff = diffString ;
1007+ stats = moduleStats ;
1008+ }
9771009 const droppedAuth = [ ] ;
9781010 if (
9791011 oldConfig . projectConfig . authInfo !== undefined &&
@@ -1037,6 +1069,16 @@ export function diffConfig(
10371069 diff += versionMessage ;
10381070 }
10391071
1072+ if ( oldConfig . projectConfig . node . nodeVersion !== newConfig . nodeVersion ) {
1073+ diff += "Change the server's version for Node.js actions:\n" ;
1074+ if ( oldConfig . projectConfig . node . nodeVersion ) {
1075+ diff += `[-] ${ oldConfig . projectConfig . node . nodeVersion } \n` ;
1076+ }
1077+ if ( newConfig . nodeVersion ) {
1078+ diff += `[+] ${ newConfig . nodeVersion } \n` ;
1079+ }
1080+ }
1081+
10401082 return { diffString : diff , stats } ;
10411083}
10421084
0 commit comments