async function FetchSteamUserData( callback )
{
	if( userDataCache !== null )
	{
		callback( { data: userDataCache } );
		return;
	}

	const now = Date.now();
	const cacheData = await GetLocalOption( { 'userdata.cached': now } );
	let cacheTime = cacheData[ 'userdata.cached' ];

	if( now > cacheTime + 3600000 )
	{
		await SetLocalOption( 'userdata.cached', now );
		cacheTime = now;
	}

	const params = new URLSearchParams();
	params.set( '_', cacheTime );

	try
	{
		const responseFetch = await fetch(
			`https://store.steampowered.com/dynamicstore/userdata/?${params.toString()}`,
			{
				credentials: 'include',
				headers: {
				// Pretend we're doing a normal navigation request.
				// This will trigger login.steampowered.com redirect flow if user has expired cookies.
					Accept: 'text/html',
				},
			}
		);
		const response = await responseFetch.json();

		if( !response || !response.rgOwnedPackages || !response.rgOwnedPackages.length )
		{
			throw new Error( 'Are you logged on the Steam Store in this browser?' );
		}

		// Only keep the data we actually need
		userDataCache =
		{
			rgOwnedPackages: response.rgOwnedPackages || [],
			rgOwnedApps: response.rgOwnedApps || [],

			rgPackagesInCart: response.rgPackagesInCart || [],
			rgAppsInCart: response.rgAppsInCart || [],

			rgIgnoredApps: response.rgIgnoredApps || {}, // object, not array
			rgIgnoredPackages: response.rgIgnoredPackages || {},

			rgFollowedApps: response.rgFollowedApps || [],
			rgWishlist: response.rgWishlist || [],
		};

		callback( { data: userDataCache } );

		await SetLocalOption( 'userdata.stored', JSON.stringify( userDataCache ) );
	}
	catch( error )
	{
		InvalidateCache();

		const data = await GetLocalOption( { 'userdata.stored': false } );

		/** @type {{error: string, data?: any}} */
		const response =
		{
			error: error instanceof Error ? error.message : String( error ),
		};

		if( data[ 'userdata.stored' ] )
		{
			response.data = JSON.parse( data[ 'userdata.stored' ] );
		}

		callback( response );
	}
}
@param {(obj: {data: Record<string, any>}|{error: string, data?: Record<string, any>}) => void} callback