UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

131 lines (130 loc) 5.72 kB
import { randomUUID } from 'node:crypto'; import getDatabase from '../../database/index.js'; import { ExtensionsService } from '../../services/extensions.js'; import { getSchema } from '../../utils/get-schema.js'; import { list } from '@directus/extensions-registry'; /** * Loads stored settings for all extensions. Creates empty new rows in extensions tables for * extensions that don't have settings yet, and remove any settings for extensions that are no * longer installed. */ export const getExtensionsSettings = async ({ local, module, registry, }) => { const database = getDatabase(); const service = new ExtensionsService({ knex: database, schema: await getSchema(), }); const existingSettings = await service.extensionsItemService.readByQuery({ limit: -1 }); const newSettings = []; const removedSettingIds = []; const localSettings = existingSettings.filter(({ source }) => source === 'local'); const registrySettings = existingSettings.filter(({ source }) => source === 'registry'); const moduleSettings = existingSettings.filter(({ source }) => source === 'module'); const updateBundleEntriesSettings = (bundle, bundleSettings, allSettings) => { const bundleEntriesSettings = allSettings.filter(({ bundle }) => bundle === bundleSettings.id); // Remove settings of removed bundle entries from the DB for (const entry of bundleEntriesSettings) { const entryInBundle = bundle.entries.some(({ name }) => name === entry.folder); if (entryInBundle) continue; removedSettingIds.push(entry.id); } // Add new bundle entries to the settings for (const entry of bundle.entries) { const settingsExist = bundleEntriesSettings.some(({ folder }) => folder === entry.name); if (settingsExist) continue; newSettings.push({ id: randomUUID(), enabled: bundleSettings.enabled, source: bundleSettings.source, bundle: bundleSettings.id, folder: entry.name, }); } }; const generateSettingsEntry = async (folder, extension, source) => { let marketplaceId; if (source === 'registry') { const marketplace = await list({ search: extension.name }); marketplaceId = marketplace.data.find((ext) => ext.name === extension.name)?.id; } const id = marketplaceId ?? randomUUID(); if (extension.type === 'bundle') { newSettings.push({ id, enabled: true, source: source, bundle: null, folder: folder, }); for (const entry of extension.entries) { newSettings.push({ id: randomUUID(), enabled: true, source: source, bundle: id, folder: entry.name, }); } } else { newSettings.push({ id, enabled: true, source: source, bundle: null, folder: folder, }); } }; for (const [folder, extension] of local.entries()) { const existingSettings = localSettings.find((settings) => settings.folder === folder); if (existingSettings) { if (extension.type === 'bundle') { updateBundleEntriesSettings(extension, existingSettings, localSettings); } continue; } const settingsForName = localSettings.find((settings) => settings.folder === extension.name); /* * TODO: Consider removing this in follow-up versions after v10.10.0 * * Previously, the package name (from package.json) was used to identify * local extensions - now it's the folder name. * If those two are different, we need to check for existing settings * with the package name, too. On a match and if there's no other local extension * with such a folder name, these settings can be taken over with the folder updated. */ if (settingsForName && !local.has(extension.name)) { await service.extensionsItemService.updateOne(settingsForName.id, { folder }); continue; } await generateSettingsEntry(folder, extension, 'local'); } for (const [folder, extension] of module.entries()) { const existingSettings = moduleSettings.find((settings) => settings.folder === folder); if (!existingSettings) { await generateSettingsEntry(folder, extension, 'module'); } else if (extension.type === 'bundle') { updateBundleEntriesSettings(extension, existingSettings, moduleSettings); } } for (const [folder, extension] of registry.entries()) { const existingSettings = registrySettings.find((settings) => settings.folder === folder); if (!existingSettings) { await generateSettingsEntry(folder, extension, 'registry'); } else if (extension.type === 'bundle') { updateBundleEntriesSettings(extension, existingSettings, registrySettings); } } if (removedSettingIds.length > 0) { await service.extensionsItemService.deleteMany(removedSettingIds); } if (newSettings.length > 0) { await service.extensionsItemService.createMany(newSettings); } return [...existingSettings.filter(({ id }) => !removedSettingIds.includes(id)), ...newSettings]; };