1717
1818logger = logging .getLogger (__name__ )
1919
20+ _VALID_SCRIPT_FILE_TYPES = frozenset ({"SERVER_JS" , "HTML" , "JSON" })
21+
2022# These locks serialize updates only within this process. Other worker
2123# processes or service instances can still race while merging the same script_id.
2224_SCRIPT_UPDATE_LOCKS : weakref .WeakValueDictionary [str , asyncio .Lock ] = (
@@ -36,7 +38,11 @@ def _normalize_script_file(file: Dict[str, Any]) -> Dict[str, str]:
3638 are dropped. Fields the caller omitted stay omitted so a merge can fall
3739 back to the existing value instead of blanking it.
3840 """
39- return {key : file [key ] for key in ("name" , "type" , "source" ) if key in file }
41+ return {
42+ key : file [key ]
43+ for key in ("name" , "type" , "source" )
44+ if key in file and file [key ] is not None
45+ }
4046
4147
4248def _merge_script_files (
@@ -63,8 +69,20 @@ def _merge_script_files(
6369 raise UserInputError (
6470 f"File at index { index } is missing a non-empty 'name'."
6571 )
66- key = (name , file .get ("type" ))
67- if key not in merged and file .get ("type" ) is None :
72+ file_type = file .get ("type" )
73+ if file_type is not None :
74+ if file_type not in _VALID_SCRIPT_FILE_TYPES :
75+ raise UserInputError (
76+ f"File '{ name } ' has unsupported type '{ file_type } '; it must "
77+ "be one of SERVER_JS, HTML, or JSON."
78+ )
79+ if file_type == "JSON" and name != "appsscript" :
80+ raise UserInputError (
81+ f"JSON file '{ name } ' must use the manifest name 'appsscript'."
82+ )
83+
84+ key = (name , file_type )
85+ if key not in merged and file_type is None :
6886 same_name = [existing for existing in merged if existing [0 ] == name ]
6987 if len (same_name ) != 1 :
7088 raise UserInputError (
0 commit comments