Files
directus/api/src/extensions.ts
WoLfulus b8e7c80b72 Application initialization events (#3680)
* Adds `not_found` hook

* Separate hooks and endpoints initialization process

* Adds additional application events

* Remove unused import

* Change the event order to accound for notFound and errorHandler

* Change emitAsync.catch to use the emitAsyncSafe function

* Updated docs, reordered table by lifecycle and usage
2021-02-08 12:30:09 -05:00

132 lines
3.6 KiB
TypeScript

import listFolders from './utils/list-folders';
import path from 'path';
import env from './env';
import { ServiceUnavailableException } from './exceptions';
import express, { Router } from 'express';
import emitter from './emitter';
import logger from './logger';
import { HookRegisterFunction, EndpointRegisterFunction } from './types';
import { ensureDir } from 'fs-extra';
import * as exceptions from './exceptions';
import * as services from './services';
import database from './database';
export async function ensureFoldersExist() {
const folders = ['endpoints', 'hooks', 'interfaces', 'modules', 'layouts', 'displays'];
for (const folder of folders) {
const folderPath = path.resolve(env.EXTENSIONS_PATH, folder);
try {
await ensureDir(folderPath);
} catch (err) {
logger.warn(err);
}
}
}
export async function initializeExtensions() {
await ensureFoldersExist();
}
export async function listExtensions(type: string) {
const extensionsPath = env.EXTENSIONS_PATH as string;
const location = path.join(extensionsPath, type);
try {
return await listFolders(location);
} catch (err) {
if (err.code === 'ENOENT') {
throw new ServiceUnavailableException(`Extension folder "extensions/${type}" couldn't be opened`, {
service: 'extensions',
});
}
throw err;
}
}
export async function registerExtensions(router: Router) {
await registerExtensionHooks();
await registerExtensionEndpoints(router);
}
export async function registerExtensionEndpoints(router: Router) {
let endpoints: string[] = [];
try {
endpoints = await listExtensions('endpoints');
registerEndpoints(endpoints, router);
} catch (err) {
logger.warn(err);
}
}
export async function registerExtensionHooks() {
let hooks: string[] = [];
try {
hooks = await listExtensions('hooks');
registerHooks(hooks);
} catch (err) {
logger.warn(err);
}
}
function registerHooks(hooks: string[]) {
const extensionsPath = env.EXTENSIONS_PATH as string;
for (const hook of hooks) {
try {
registerHook(hook);
} catch (error) {
logger.warn(`Couldn't register hook "${hook}"`);
logger.warn(error);
}
}
function registerHook(hook: string) {
const hookPath = path.resolve(extensionsPath, 'hooks', hook, 'index.js');
const hookInstance: HookRegisterFunction | { default?: HookRegisterFunction } = require(hookPath);
let register: HookRegisterFunction = hookInstance as HookRegisterFunction;
if (typeof hookInstance !== 'function') {
if (hookInstance.default) {
register = hookInstance.default;
}
}
let events = register({ services, exceptions, env, database });
for (const [event, handler] of Object.entries(events)) {
emitter.on(event, handler);
}
}
}
function registerEndpoints(endpoints: string[], router: Router) {
const extensionsPath = env.EXTENSIONS_PATH as string;
for (const endpoint of endpoints) {
try {
registerEndpoint(endpoint);
} catch (error) {
logger.warn(`Couldn't register endpoint "${endpoint}"`);
logger.warn(error);
}
}
function registerEndpoint(endpoint: string) {
const endpointPath = path.resolve(extensionsPath, 'endpoints', endpoint, 'index.js');
const endpointInstance: EndpointRegisterFunction | { default?: EndpointRegisterFunction } = require(endpointPath);
let register: EndpointRegisterFunction = endpointInstance as EndpointRegisterFunction;
if (typeof endpointInstance !== 'function') {
if (endpointInstance.default) {
register = endpointInstance.default;
}
}
const scopedRouter = express.Router();
router.use(`/${endpoint}/`, scopedRouter);
register(scopedRouter, { services, exceptions, env, database });
}
}