refactor: app middlewares
This commit is contained in:
parent
6906ccadb0
commit
17362a8444
52
.env.example
52
.env.example
@ -1,29 +1,47 @@
|
||||
########## DOCKER COMPOSE ENV ##########
|
||||
|
||||
DB_MYSQL_PORT=3306
|
||||
DB_POSTGRES_PORT=5432
|
||||
API_PORT=23000
|
||||
VERDACCIO_PORT=4873
|
||||
|
||||
########## NOCOBASE ENV ##########
|
||||
|
||||
# DATABASE
|
||||
|
||||
DB_DIALECT=postgres
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=nocobase
|
||||
DB_USER=test
|
||||
DB_PASSWORD=test
|
||||
|
||||
DB_USER=nocobase
|
||||
DB_PASSWORD=nocobase
|
||||
# set to 'on' to enable log
|
||||
DB_LOG_SQL=
|
||||
|
||||
# DB_DIALECT=mysql
|
||||
# DB_PORT=3306
|
||||
|
||||
DB_MYSQL_PORT=3306
|
||||
DB_POSTGRES_PORT=5432
|
||||
# API & APP
|
||||
|
||||
NOCOBASE_ENV=
|
||||
API_PORT=23000
|
||||
APP_USE_STATIC_SERVER=true
|
||||
APP_DIST=packages/app/dist
|
||||
|
||||
VERDACCIO_PORT=4873
|
||||
# ADMIN USER (Initialization only)
|
||||
|
||||
APP_DIST=
|
||||
USE_STATIC_SERVER=true
|
||||
LOCAL_STORAGE_BASE_URL=http://localhost:23000/uploads
|
||||
STORAGE_BASE_URL=http://localhost:23000/uploads
|
||||
ADMIN_EMAIL=admin@nocobase.com
|
||||
ADMIN_PASSWORD=admin
|
||||
|
||||
ALIYUN_OSS_REGION=oss-cn-beijing
|
||||
ALIYUN_OSS_ACCESS_KEY_ID=
|
||||
ALIYUN_OSS_ACCESS_KEY_SECRET=
|
||||
ALIYUN_OSS_BUCKET=
|
||||
# STORAGE (Initialization only)
|
||||
|
||||
# local or ali-oss
|
||||
STORAGE_TYPE=local
|
||||
|
||||
# LOCAL STORAGE
|
||||
LOCAL_STORAGE_USE_STATIC_SERVER=true
|
||||
LOCAL_STORAGE_BASE_URL=http://localhost:23000
|
||||
|
||||
# ALI OSS STORAGE
|
||||
ALI_OSS_STORAGE_BASE_URL=
|
||||
ALI_OSS_REGION=oss-cn-beijing
|
||||
ALI_OSS_ACCESS_KEY_ID=
|
||||
ALI_OSS_ACCESS_KEY_SECRET=
|
||||
ALI_OSS_BUCKET=
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"watch": ["packages/"],
|
||||
"watch": ["packages/", ".env"],
|
||||
"ignore": ["packages/app"],
|
||||
"ext": "ts",
|
||||
"exec": "ts-node ./packages/api/src/dev.ts"
|
||||
"exec": "ts-node -r dotenv/config ./packages/api/src/index.ts"
|
||||
}
|
@ -10,8 +10,7 @@
|
||||
"bootstrap": "lerna bootstrap --no-ci",
|
||||
"build": "father-build",
|
||||
"clean": "lerna clean",
|
||||
"db-migrate": "cd packages/api && npm run db-migrate",
|
||||
"db:start": "docker-compose up -d",
|
||||
"db-migrate": "ts-node -r dotenv/config ./packages/api/src/migrate.ts",
|
||||
"lint": "eslint --ext .ts,.tsx,.js \"packages/*/src/**.@(ts|tsx|js)\" --fix",
|
||||
"test": "npm run lint && jest",
|
||||
"debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
||||
|
@ -4,10 +4,7 @@
|
||||
"main": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "nodemon",
|
||||
"db-migrate": "ts-node ./src/migrate.ts"
|
||||
},
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"@nocobase/actions": "^0.4.0-alpha.1",
|
||||
"@nocobase/client": "^0.4.0-alpha.1",
|
||||
|
@ -2,9 +2,9 @@ import Api from '@nocobase/server';
|
||||
|
||||
// @ts-ignore
|
||||
const sync = global.sync || {
|
||||
force: true,
|
||||
force: false,
|
||||
alter: {
|
||||
drop: true,
|
||||
drop: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
import path from 'path';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config({
|
||||
path: path.resolve(__dirname, '../../../.env'),
|
||||
});
|
||||
|
||||
import './index';
|
@ -1,61 +1,16 @@
|
||||
import api from './app';
|
||||
import actions from '@nocobase/actions';
|
||||
import send from 'koa-send';
|
||||
import serve from 'koa-static';
|
||||
|
||||
api.resourcer.use(async (ctx: actions.Context, next) => {
|
||||
const { actionName, resourceField, resourceName, fields = {} } = ctx.action.params;
|
||||
const table = ctx.db.getTable(resourceField ? resourceField.options.target : resourceName);
|
||||
// ctx.state.developerMode = {[Op.not]: null};
|
||||
ctx.state.developerMode = false;
|
||||
if (table && table.hasField('developerMode') && ctx.state.developerMode === false) {
|
||||
ctx.action.mergeParams({ filter: { "developerMode.$isFalsy": true } }, { filter: 'and' });
|
||||
}
|
||||
if (table && ['get', 'list'].includes(actionName)) {
|
||||
const except = [];
|
||||
const appends = [];
|
||||
for (const [name, field] of table.getFields()) {
|
||||
if (field.options.hidden) {
|
||||
except.push(field.options.name);
|
||||
}
|
||||
// if (field.options.appends) {
|
||||
// appends.push(field.options.name);
|
||||
// }
|
||||
}
|
||||
ctx.action.mergeParams({ fields: {
|
||||
except,
|
||||
appends
|
||||
} }, { fields: 'append' });
|
||||
// console.log('ctx.action.params.fields', ctx.action.params.fields, except, appends);
|
||||
}
|
||||
await next();
|
||||
});
|
||||
import { middlewares } from '@nocobase/server';
|
||||
|
||||
(async () => {
|
||||
api.resourcer.use(middlewares.actionParams());
|
||||
|
||||
await api.loadPlugins();
|
||||
|
||||
api.database.getModel('users').addHook('beforeUpdate', function (model) {
|
||||
console.log('users.beforeUpdate', model.get(), model.changed('password' as any));
|
||||
});
|
||||
|
||||
api.resourcer.use(async (ctx, next) => {
|
||||
if (process.env.NOCOBASE_ENV !== 'demo') {
|
||||
return next();
|
||||
}
|
||||
const currentUser = ctx.state.currentUser;
|
||||
if (currentUser && currentUser.username === 'admin') {
|
||||
return next();
|
||||
}
|
||||
const { actionName } = ctx.action.params;
|
||||
if (['create', 'update', 'destroy', 'sort', 'upload'].includes(actionName)) {
|
||||
ctx.body = {
|
||||
data: {},
|
||||
meta: {},
|
||||
};
|
||||
return;
|
||||
}
|
||||
await next();
|
||||
});
|
||||
if (process.env.NOCOBASE_ENV === 'demo') {
|
||||
api.resourcer.use(middlewares.demoBlacklistedActions({
|
||||
emails: [process.env.ADMIN_EMAIL],
|
||||
}));
|
||||
}
|
||||
|
||||
await api.database.getModel('collections').load({skipExisting: true});
|
||||
await api.database.getModel('collections').load({where: {
|
||||
@ -63,17 +18,14 @@ api.resourcer.use(async (ctx: actions.Context, next) => {
|
||||
}});
|
||||
await api.database.getModel('automations').load();
|
||||
|
||||
api.use(async (ctx, next) => {
|
||||
if (!process.env.APP_DIST || !process.env.USE_STATIC_SERVER || process.env.USE_STATIC_SERVER === 'false') {
|
||||
return next();
|
||||
}
|
||||
await serve(process.env.APP_DIST)(ctx, next);
|
||||
if (ctx.status == 404) {
|
||||
return send(ctx, 'index.html', { root: process.env.APP_DIST });
|
||||
}
|
||||
});
|
||||
api.use(middlewares.appDistServe({
|
||||
root: process.env.APP_DIST,
|
||||
useStaticServer: !(process.env.APP_USE_STATIC_SERVER === 'false' || !process.env.APP_USE_STATIC_SERVER),
|
||||
}));
|
||||
|
||||
api.listen(process.env.API_PORT, () => {
|
||||
console.log(`http://localhost:${process.env.API_PORT}/`);
|
||||
});
|
||||
if (require.main === module) {
|
||||
api.listen(process.env.API_PORT, () => {
|
||||
console.log(`http://localhost:${process.env.API_PORT}/`);
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
// @ts-ignore
|
||||
const keys = process.argv;
|
||||
|
||||
|
@ -76,47 +76,31 @@ const data = [
|
||||
await Collection.import(table.getOptions(), { update: true, migrate: false });
|
||||
}
|
||||
await Page.import(data);
|
||||
let user = await User.findOne({
|
||||
where: {
|
||||
username: "admin",
|
||||
},
|
||||
|
||||
const user = await User.create({
|
||||
email: process.env.ADMIN_EMAIL,
|
||||
password: process.env.ADMIN_PASSWORD,
|
||||
});
|
||||
if (!user) {
|
||||
user = await User.create({
|
||||
nickname: "超级管理员",
|
||||
password: "admin",
|
||||
username: "admin",
|
||||
email: 'dev@nocobase.com',
|
||||
token: "38979f07e1fca68fb3d2",
|
||||
});
|
||||
}
|
||||
const Storage = database.getModel('storages');
|
||||
// await Storage.create({
|
||||
// title: '本地存储',
|
||||
// name: `local`,
|
||||
// type: 'local',
|
||||
// baseUrl: process.env.LOCAL_STORAGE_BASE_URL,
|
||||
// default: true
|
||||
// });
|
||||
const storage = await Storage.findOne({
|
||||
where: {
|
||||
name: "ali-oss",
|
||||
},
|
||||
await Storage.create({
|
||||
title: '本地存储',
|
||||
name: `local`,
|
||||
type: 'local',
|
||||
baseUrl: process.env.LOCAL_STORAGE_BASE_URL,
|
||||
default: process.env.STORAGE_TYPE === 'local',
|
||||
});
|
||||
await Storage.create({
|
||||
name: `ali-oss`,
|
||||
type: 'ali-oss',
|
||||
baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,
|
||||
options: {
|
||||
region: process.env.ALI_OSS_REGION,
|
||||
accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,
|
||||
accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,
|
||||
bucket: process.env.ALI_OSS_BUCKET,
|
||||
},
|
||||
default: process.env.STORAGE_TYPE === 'ali-oss',
|
||||
});
|
||||
if (!storage) {
|
||||
await Storage.create({
|
||||
name: `ali-oss`,
|
||||
type: 'ali-oss',
|
||||
baseUrl: process.env.ALIYUN_STORAGE_BASE_URL,
|
||||
options: {
|
||||
region: process.env.ALIYUN_OSS_REGION,
|
||||
accessKeyId: process.env.ALIYUN_OSS_ACCESS_KEY_ID,
|
||||
accessKeySecret: process.env.ALIYUN_OSS_ACCESS_KEY_SECRET,
|
||||
bucket: process.env.ALIYUN_OSS_BUCKET,
|
||||
},
|
||||
default: true
|
||||
});
|
||||
}
|
||||
const Role = database.getModel('roles');
|
||||
if (Role) {
|
||||
const roles = await Role.bulkCreate([
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"watch": ["../"],
|
||||
"ignore": ["../app"],
|
||||
"ext": "ts",
|
||||
"exec": "ts-node ../api/src/dev.ts"
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
"name": "@nocobase/app",
|
||||
"version": "0.4.0-alpha.1",
|
||||
"scripts": {
|
||||
"start": "concurrently \"nodemon\" \"umi dev\"",
|
||||
"start": "concurrently \"cd ../../ && nodemon\" \"umi dev\"",
|
||||
"dev": "umi dev",
|
||||
"build": "umi build",
|
||||
"postinstall": "umi generate tmp",
|
||||
"prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
|
||||
|
@ -54,7 +54,7 @@ export function middleware(app) {
|
||||
// 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)
|
||||
// TODO(bug): https、端口 80 默认值和其他本地 ip/hostname 的情况未考虑
|
||||
// TODO 实际应该用 NOCOBASE_ENV 来判断,或者抛给 env 处理
|
||||
if (process.env.USE_STATIC_SERVER) {
|
||||
if (process.env.LOCAL_STORAGE_USE_STATIC_SERVER) {
|
||||
const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;
|
||||
app.use(mount(basePath, serve(getDocumentRoot(storage))));
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
"dotenv": "^8.2.0",
|
||||
"koa": "^2.13.0",
|
||||
"koa-bodyparser": "^4.3.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"mysql2": "^2.1.0",
|
||||
"pg": "^8.3.3",
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { actions, middlewares } from '@nocobase/actions';
|
||||
import { actions, middlewares as m } from '@nocobase/actions';
|
||||
import Application from './application';
|
||||
import bodyParser from 'koa-bodyparser';
|
||||
import cors from '@koa/cors';
|
||||
import middleware from './middleware';
|
||||
import { dbResourceRouter } from './middlewares';
|
||||
|
||||
export * from './application';
|
||||
export * from './middleware';
|
||||
export * as middlewares from './middlewares';
|
||||
|
||||
export default {
|
||||
/**
|
||||
@ -29,10 +30,10 @@ export default {
|
||||
await next();
|
||||
});
|
||||
|
||||
app.resourcer.use(middlewares.associated);
|
||||
app.use(middlewares.dataWrapping);
|
||||
app.resourcer.use(m.associated);
|
||||
app.use(m.dataWrapping);
|
||||
|
||||
app.use(middleware({
|
||||
app.use(dbResourceRouter({
|
||||
database: app.database,
|
||||
resourcer: app.resourcer,
|
||||
...(options.resourcer||{}),
|
||||
|
31
packages/server/src/middlewares/action-params.ts
Normal file
31
packages/server/src/middlewares/action-params.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { actions } from '@nocobase/actions';
|
||||
|
||||
export function actionParams(options: any = {}) {
|
||||
return async (ctx: actions.Context, next: actions.Next) => {
|
||||
const { actionName, resourceField, resourceName, fields = {} } = ctx.action.params;
|
||||
const table = ctx.db.getTable(resourceField ? resourceField.options.target : resourceName);
|
||||
// ctx.state.developerMode = {[Op.not]: null};
|
||||
ctx.state.developerMode = false;
|
||||
if (table && table.hasField('developerMode') && ctx.state.developerMode === false) {
|
||||
ctx.action.mergeParams({ filter: { "developerMode.$isFalsy": true } }, { filter: 'and' });
|
||||
}
|
||||
if (table && ['get', 'list'].includes(actionName)) {
|
||||
const except = [];
|
||||
const appends = [];
|
||||
for (const [name, field] of table.getFields()) {
|
||||
if (field.options.hidden) {
|
||||
except.push(field.options.name);
|
||||
}
|
||||
// if (field.options.appends) {
|
||||
// appends.push(field.options.name);
|
||||
// }
|
||||
}
|
||||
ctx.action.mergeParams({ fields: {
|
||||
except,
|
||||
appends
|
||||
} }, { fields: 'append' });
|
||||
// console.log('ctx.action.params.fields', ctx.action.params.fields, except, appends);
|
||||
}
|
||||
await next();
|
||||
}
|
||||
}
|
25
packages/server/src/middlewares/app-dist-serve.ts
Normal file
25
packages/server/src/middlewares/app-dist-serve.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import path from 'path';
|
||||
import send from 'koa-send';
|
||||
import serve from 'koa-static';
|
||||
import actions from '@nocobase/actions';
|
||||
|
||||
export interface AppDistServeOptions {
|
||||
root?: string;
|
||||
useStaticServer?: boolean;
|
||||
}
|
||||
|
||||
export function appDistServe(options: AppDistServeOptions = {}) {
|
||||
return async (ctx: actions.Context, next: actions.Next) => {
|
||||
if (!options.root || !options.useStaticServer) {
|
||||
return next();
|
||||
}
|
||||
let root = options.root;
|
||||
if (!root.startsWith('/')) {
|
||||
root = path.resolve(process.cwd(), root);
|
||||
}
|
||||
await serve(root)(ctx, next);
|
||||
if (ctx.status == 404) {
|
||||
return send(ctx, 'index.html', { root });
|
||||
}
|
||||
}
|
||||
}
|
133
packages/server/src/middlewares/db-resource-router.ts
Normal file
133
packages/server/src/middlewares/db-resource-router.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import compose from 'koa-compose';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import Resourcer, { getNameByParams, KoaMiddlewareOptions, parseRequest, parseQuery, ResourcerContext, ResourceType } from '@nocobase/resourcer';
|
||||
import Database, { BELONGSTO, BELONGSTOMANY, HASMANY, HASONE } from '@nocobase/database';
|
||||
|
||||
interface MiddlewareOptions extends KoaMiddlewareOptions {
|
||||
resourcer?: Resourcer;
|
||||
database?: Database;
|
||||
}
|
||||
/**
|
||||
* database + resourcer 结合的中间件(暂时不知道起什么名好)
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
export function dbResourceRouter(options: MiddlewareOptions = {}) {
|
||||
const {
|
||||
prefix,
|
||||
database,
|
||||
resourcer,
|
||||
accessors,
|
||||
paramsKey = 'params',
|
||||
nameRule = getNameByParams,
|
||||
} = options;
|
||||
return async (ctx: ResourcerContext, next: () => Promise<any>) => {
|
||||
ctx.resourcer = resourcer;
|
||||
let params = parseRequest({
|
||||
path: ctx.request.path,
|
||||
method: ctx.request.method,
|
||||
}, {
|
||||
prefix,
|
||||
accessors,
|
||||
});
|
||||
if (!params) {
|
||||
return next();
|
||||
}
|
||||
try {
|
||||
const resourceName = nameRule(params);
|
||||
// 如果资源名称未被定义
|
||||
if (!resourcer.isDefined(resourceName)) {
|
||||
const [tableName, fieldName] = resourceName.split('.');
|
||||
const Collection = database.getModel('collections');
|
||||
// 检查资源对应的表名是否已经定义
|
||||
if (!database.isDefined(tableName) && Collection) {
|
||||
// 未定义则尝试通过 collection 表来加载
|
||||
await Collection.load({
|
||||
where: {
|
||||
name: tableName,
|
||||
},
|
||||
});
|
||||
}
|
||||
// 如果经过加载后是已经定义的表
|
||||
if (database.isDefined(tableName)) {
|
||||
const table = database.getTable(tableName);
|
||||
const field = table.getField(fieldName) as BELONGSTO | HASMANY | BELONGSTOMANY | HASONE;
|
||||
if (!fieldName || field) {
|
||||
let resourceType: ResourceType = 'single';
|
||||
let actions = {};
|
||||
if (field) {
|
||||
if (field instanceof HASONE) {
|
||||
resourceType = 'hasOne';
|
||||
} else if (field instanceof HASMANY) {
|
||||
resourceType = 'hasMany';
|
||||
} else if (field instanceof BELONGSTO) {
|
||||
resourceType = 'belongsTo';
|
||||
} else if (field instanceof BELONGSTOMANY) {
|
||||
resourceType = 'belongsToMany';
|
||||
}
|
||||
if (field.options.actions) {
|
||||
actions = field.options.actions;
|
||||
}
|
||||
} else {
|
||||
const items = table.getOptions('actions') || [];
|
||||
for (const item of (items as any[])) {
|
||||
actions[item.name] = item;
|
||||
}
|
||||
}
|
||||
resourcer.define({
|
||||
type: resourceType,
|
||||
name: resourceName,
|
||||
actions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const resource = resourcer.getResource(resourceName);
|
||||
// 为关系资源时,暂时需要再执行一遍 parseRequest
|
||||
if (resource.options.type !== 'single') {
|
||||
params = parseRequest({
|
||||
path: ctx.request.path,
|
||||
method: ctx.request.method,
|
||||
type: resource.options.type,
|
||||
}, {
|
||||
prefix,
|
||||
accessors,
|
||||
});
|
||||
if (!params) {
|
||||
return next();
|
||||
}
|
||||
}
|
||||
// console.log(resource);
|
||||
// action 需要 clone 之后再赋给 ctx
|
||||
ctx.action = resourcer.getAction(resourceName, params.actionName).clone();
|
||||
ctx.action.setContext(ctx);
|
||||
// 自带 query 处理的不太给力,需要用 qs 转一下
|
||||
const query = parseQuery(ctx.request.querystring);
|
||||
// 兼容 ctx.params 的处理,之后的版本里会去掉
|
||||
ctx[paramsKey] = {
|
||||
table: params.resourceName,
|
||||
tableKey: params.resourceKey,
|
||||
relatedTable: params.associatedName,
|
||||
relatedKey: params.resourceKey,
|
||||
action: params.actionName,
|
||||
};
|
||||
if (pathToRegexp('/resourcer/{:associatedName.}?:resourceName{\\::actionName}').test(ctx.request.path)) {
|
||||
await ctx.action.mergeParams({
|
||||
...query,
|
||||
...params,
|
||||
...ctx.request.body,
|
||||
});
|
||||
} else {
|
||||
await ctx.action.mergeParams({
|
||||
...query,
|
||||
...params,
|
||||
values: ctx.request.body,
|
||||
});
|
||||
}
|
||||
return compose(ctx.action.getHandlers())(ctx, next);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
}
|
27
packages/server/src/middlewares/demo-blacklisted-actions.ts
Normal file
27
packages/server/src/middlewares/demo-blacklisted-actions.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { actions } from '@nocobase/actions';
|
||||
|
||||
export interface DemoBlackListedActionsOptions {
|
||||
emails?: string[];
|
||||
blacklist?: string[];
|
||||
}
|
||||
|
||||
const defaultBlacklist = ['create', 'update', 'destroy', 'sort', 'upload'];
|
||||
|
||||
export function demoBlacklistedActions(options: DemoBlackListedActionsOptions = {}) {
|
||||
const { emails, blacklist = defaultBlacklist } = options;
|
||||
return async (ctx: actions.Context, next: actions.Next) => {
|
||||
const currentUser = ctx.state.currentUser;
|
||||
if (currentUser && emails.includes(currentUser.email)) {
|
||||
return next();
|
||||
}
|
||||
const { actionName } = ctx.action.params;
|
||||
if (blacklist.includes(actionName)) {
|
||||
ctx.body = {
|
||||
data: {},
|
||||
meta: {},
|
||||
};
|
||||
return;
|
||||
}
|
||||
await next();
|
||||
}
|
||||
}
|
4
packages/server/src/middlewares/index.ts
Normal file
4
packages/server/src/middlewares/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './action-params';
|
||||
export * from './app-dist-serve';
|
||||
export * from './db-resource-router';
|
||||
export * from './demo-blacklisted-actions';
|
Loading…
Reference in New Issue
Block a user