/* * * @copyright Copyright (c) OX Software GmbH, Germany <info@open-xchange.com> * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>. * * Any use of the work other than as authorized under this license or copyright law is prohibited. * */ import { configMap } from './config_map.js' import { getRedisKey, viteManifestToDeps, viteToOxManifest } from './util.js' import logger from './logger.js' import * as cache from './cache.js' import zlib from 'node:zlib' import { promisify } from 'node:util' const brotliCompress = promisify(zlib.brotliCompress) export async function fetchViteManifests () { // vite manifests contains a set of objects with the vite-manifests // from the corresponding registered services const viteManifests = await Promise.all(configMap.urls.map(async baseUrl => { // fetch the manifests const result = await fetch(new URL('manifest.json', baseUrl), { cache: 'no-store' }) if (!result.ok) throw new Error(`Failed to load manifest for url ${result.url} (Status: ${result.status}: ${result.statusText})`) try { const manifest = await result.json() for (const file in manifest) { logger.debug(`[Manifest] Retrieved ${file} from ${baseUrl}`) manifest[file].meta = manifest[file].meta || {} manifest[file].meta.baseUrl = baseUrl } return manifest } catch (err) { throw new Error(`Failed to load manifest for url ${result.url}: ${err}`) } })) // combine all manifests by keys. With duplicates, last wins return viteManifests.reduce((memo, manifest) => Object.assign(memo, manifest), {}) } export async function getViteManifests ({ version }) { return cache.get(getRedisKey({ version, name: 'viteManifests' }), async () => [await fetchViteManifests()]) } export function getOxManifests ({ version }) { return cache.getFile({ name: 'oxManifests', version }, async () => { const headers = { 'content-type': 'application/json; charset=utf-8', 'content-encoding': 'br' } const viteManifests = await getViteManifests({ version }) const oxManifests = await viteToOxManifest(viteManifests) const body = await brotliCompress(JSON.stringify(oxManifests)) return { body, headers } }) } export function getDependencies ({ version }) { return cache.get(getRedisKey({ version, name: 'dependencies' }), async () => { const viteManifests = await getViteManifests({ version }) return [viteManifestToDeps(viteManifests)] }) } export async function getCSSDependenciesFor ({ file, version }) { const allDependencies = await getDependencies({ version }) const dependencies = allDependencies[file] || [] return dependencies.filter(dep => /\.css/i.test(dep)) }