mirror of
https://github.com/nocodb/nocodb.git
synced 2026-02-02 02:26:57 +00:00
@@ -58,6 +58,8 @@ export function useApi<Data = any, RequestConfig = any>({
|
||||
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
useSocketApi()
|
||||
|
||||
/** api instance - with interceptors for token refresh already bound */
|
||||
const api = useGlobalInstance && !!nuxtApp.$api ? nuxtApp.$api : createApiInstance(apiOptions)
|
||||
|
||||
@@ -138,6 +140,19 @@ export function useApi<Data = any, RequestConfig = any>({
|
||||
},
|
||||
)
|
||||
|
||||
api.instance.interceptors.response.use(
|
||||
(response) => {
|
||||
return response
|
||||
},
|
||||
(rs) => {
|
||||
if (rs?.socket) {
|
||||
isLoading.value = false
|
||||
return Promise.resolve(rs)
|
||||
}
|
||||
return rs
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
api,
|
||||
isLoading,
|
||||
|
||||
@@ -7,6 +7,35 @@ export function addAxiosInterceptors(api: Api<any>) {
|
||||
const state = useGlobal()
|
||||
const router = useRouter()
|
||||
const route = $(router.currentRoute)
|
||||
const { socket, request } = useSocketApi()
|
||||
|
||||
// first interceptor is executed last
|
||||
api.instance.interceptors.request.use(
|
||||
async (config) => {
|
||||
if (socket.value?.connected) {
|
||||
await request({
|
||||
...config,
|
||||
headers: {
|
||||
...config.headers,
|
||||
host: window.location.host,
|
||||
},
|
||||
protocol: window.location.protocol,
|
||||
})
|
||||
.then((t: any) => {
|
||||
throw t
|
||||
})
|
||||
.catch((e: any) => {
|
||||
if (e?.socket) throw e
|
||||
})
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
(rs) => {
|
||||
if (rs?.socket) return Promise.resolve(rs)
|
||||
return rs
|
||||
},
|
||||
)
|
||||
|
||||
api.instance.interceptors.request.use((config) => {
|
||||
config.headers['xc-gui'] = 'true'
|
||||
|
||||
78
packages/nc-gui/composables/useSocketApi.ts
Normal file
78
packages/nc-gui/composables/useSocketApi.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { Socket } from 'socket.io-client'
|
||||
import io from 'socket.io-client'
|
||||
import type { Ref } from 'vue'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useGlobal } from '#imports'
|
||||
|
||||
export const useSocketApi = createSharedComposable(() => {
|
||||
const state = useGlobal()
|
||||
|
||||
const requestQuery: Record<string, any> = {}
|
||||
|
||||
const socket: Ref<Socket | undefined> = ref()
|
||||
|
||||
const init = async (token: string) => {
|
||||
try {
|
||||
if (socket.value) socket.value.disconnect()
|
||||
|
||||
const url = new URL(state.appInfo.value.ncSiteUrl, window.location.href.split(/[?#]/)[0]).href
|
||||
|
||||
socket.value = io(url, {
|
||||
extraHeaders: { 'xc-auth': token },
|
||||
})
|
||||
|
||||
socket.value.on('connect_error', () => {
|
||||
socket.value?.disconnect()
|
||||
})
|
||||
|
||||
socket.value.on('api', (data) => {
|
||||
if (data.id in requestQuery) {
|
||||
const tq = requestQuery[data.id]
|
||||
if (data?.setCookie) {
|
||||
for (const ck of data.setCookie) {
|
||||
// TODO fix event
|
||||
setCookie({} as any, ck.name, ck.value, ck.options)
|
||||
}
|
||||
}
|
||||
tq.promise.resolve(data)
|
||||
|
||||
delete requestQuery[data.id]
|
||||
} else {
|
||||
console.log('Unknown query', data)
|
||||
}
|
||||
})
|
||||
} catch {}
|
||||
}
|
||||
|
||||
watch(
|
||||
state.token,
|
||||
(newToken, oldToken) => {
|
||||
if (newToken && newToken !== oldToken) init(newToken)
|
||||
else if (!newToken) socket.value?.disconnect()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
return {
|
||||
init,
|
||||
socket,
|
||||
request: (data: any): Promise<any> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!socket.value) return reject(new Error('Socket not initialized'))
|
||||
const tq = {
|
||||
id: uuidv4(),
|
||||
promise: {
|
||||
resolve,
|
||||
reject,
|
||||
},
|
||||
data,
|
||||
dt: Date.now(),
|
||||
}
|
||||
|
||||
requestQuery[tq.id] = tq
|
||||
|
||||
socket.value?.emit('api', { id: tq.id, ...tq.data })
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
96
packages/nc-gui/package-lock.json
generated
96
packages/nc-gui/package-lock.json
generated
@@ -36,6 +36,7 @@
|
||||
"sortablejs": "^1.15.0",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"uuid": "^9.0.0",
|
||||
"v3-infinite-loading": "^1.2.2",
|
||||
"validator": "^13.7.0",
|
||||
"vue-dompurify-html": "^3.0.0",
|
||||
@@ -71,6 +72,7 @@
|
||||
"@types/papaparse": "^5.3.2",
|
||||
"@types/sortablejs": "^1.13.0",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@types/validator": "^13.7.10",
|
||||
"@vitest/ui": "^0.18.0",
|
||||
"@vue/compiler-sfc": "^3.2.37",
|
||||
@@ -95,28 +97,6 @@
|
||||
"windicss": "^3.5.6"
|
||||
}
|
||||
},
|
||||
"../nocodb-sdk": {
|
||||
"version": "0.104.3",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"jsep": "^1.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
||||
"@typescript-eslint/parser": "^4.0.1",
|
||||
"cspell": "^4.1.0",
|
||||
"eslint": "^7.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-functional": "^3.0.2",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.1.1",
|
||||
"typescript": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||
@@ -3204,6 +3184,12 @@
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/validator": {
|
||||
"version": "13.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.10.tgz",
|
||||
@@ -8544,7 +8530,6 @@
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -11960,8 +11945,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nocodb-sdk": {
|
||||
"resolved": "../nocodb-sdk",
|
||||
"link": true
|
||||
"version": "0.104.3",
|
||||
"resolved": "file:../nocodb-sdk",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"jsep": "^1.3.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nocodb-sdk/node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.23.0",
|
||||
@@ -16258,6 +16256,14 @@
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v3-infinite-loading": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/v3-infinite-loading/-/v3-infinite-loading-1.2.2.tgz",
|
||||
@@ -20125,6 +20131,12 @@
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/validator": {
|
||||
"version": "13.7.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.10.tgz",
|
||||
@@ -23943,8 +23955,7 @@
|
||||
"follow-redirects": {
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
|
||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
|
||||
"devOptional": true
|
||||
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
@@ -26417,22 +26428,20 @@
|
||||
}
|
||||
},
|
||||
"nocodb-sdk": {
|
||||
"version": "file:../nocodb-sdk",
|
||||
"version": "0.104.3",
|
||||
"requires": {
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
||||
"@typescript-eslint/parser": "^4.0.1",
|
||||
"axios": "^0.21.1",
|
||||
"cspell": "^4.1.0",
|
||||
"eslint": "^7.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-functional": "^3.0.2",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jsep": "^1.3.6",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.1.1",
|
||||
"typescript": "^4.0.2"
|
||||
"jsep": "^1.3.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-abi": {
|
||||
@@ -29634,6 +29643,11 @@
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"dev": true
|
||||
},
|
||||
"uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
|
||||
},
|
||||
"v3-infinite-loading": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/v3-infinite-loading/-/v3-infinite-loading-1.2.2.tgz",
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
"sortablejs": "^1.15.0",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"uuid": "^9.0.0",
|
||||
"v3-infinite-loading": "^1.2.2",
|
||||
"validator": "^13.7.0",
|
||||
"vue-dompurify-html": "^3.0.0",
|
||||
@@ -94,6 +95,7 @@
|
||||
"@types/papaparse": "^5.3.2",
|
||||
"@types/sortablejs": "^1.13.0",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@types/validator": "^13.7.10",
|
||||
"@vitest/ui": "^0.18.0",
|
||||
"@vue/compiler-sfc": "^3.2.37",
|
||||
|
||||
@@ -13,6 +13,8 @@ const { api, isLoading, error } = useApi({ useGlobalInstance: true })
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { init } = useSocketApi()
|
||||
|
||||
useSidebar('nc-left-sidebar', { hasSidebar: false })
|
||||
|
||||
const formValidator = ref()
|
||||
@@ -52,6 +54,8 @@ async function signIn() {
|
||||
api.auth.signin(form).then(async ({ token }) => {
|
||||
_signIn(token!)
|
||||
|
||||
await init(token!)
|
||||
|
||||
await navigateTo('/')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ import syncSourceApis from './sync/syncSourceApis';
|
||||
const clients: { [id: string]: Socket } = {};
|
||||
const jobs: { [id: string]: { last_message: any } } = {};
|
||||
|
||||
const middlewares = [];
|
||||
const socketApis = [];
|
||||
|
||||
export default function (router: Router, server) {
|
||||
initStrategies(router);
|
||||
projectApis(router);
|
||||
@@ -148,9 +151,216 @@ export default function (router: Router, server) {
|
||||
socket.emit('progress', jobs[room].last_message);
|
||||
}
|
||||
});
|
||||
socket.on('api', (data) => {
|
||||
const startAt = process.hrtime();
|
||||
|
||||
const params = {};
|
||||
|
||||
const hf = socketApis.find((hf) => {
|
||||
if (hf.method !== data.method) return false;
|
||||
const hfpath = hf.path.replace(/\/$/, '').split('/')
|
||||
const dtpath = data.url.replace(/\?.+/, '').replace(/\/$/, '').split('/')
|
||||
if (hfpath.length !== dtpath.length) return false;
|
||||
for (let i = 0; i < hfpath.length; i++) {
|
||||
if (/^:/.test(hfpath[i])) {
|
||||
if (!dtpath[i]) return false;
|
||||
params[hfpath[i].substr(1)] = dtpath[i];
|
||||
} else {
|
||||
if (hfpath[i] !== dtpath[i]) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (hf) {
|
||||
const headers = Object.entries(data.headers)
|
||||
.reduce((obj, [key, val]) => {
|
||||
if (typeof val === 'string') {
|
||||
obj[key] = val;
|
||||
} else if (typeof val === 'object') {
|
||||
if (key === 'common' || key === data.method) {
|
||||
obj = { ...obj, ...val };
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}, { 'xc-socket': 'true'});
|
||||
|
||||
data.path = hf.path;
|
||||
data.query = data.params || {};
|
||||
data.params = params;
|
||||
data.headers = headers;
|
||||
data.body = data.data;
|
||||
data.originalUrl = data.url;
|
||||
|
||||
const req = createReq(data);
|
||||
|
||||
const res = createRes((_cd, dt, _hd) => {
|
||||
const rt: any = { id: data.id, socket: true, data: dt }
|
||||
if (dt?.setCookie) {
|
||||
rt.setCookie = dt.setCookie;
|
||||
delete dt.setCookie;
|
||||
}
|
||||
|
||||
const ms = process.hrtime(startAt)[0] * 1e3 + process.hrtime(startAt)[1] * 1e-6;
|
||||
|
||||
// :method :url :status - :response-time ms
|
||||
process.stdout.write(`${req.method } ${req.url} ${res.statusCode} - ${ms.toFixed(3)} ms\n`)
|
||||
socket.emit('api', rt);
|
||||
})
|
||||
|
||||
for (const middleware of middlewares) {
|
||||
middleware.handle(req, res, () => {});
|
||||
}
|
||||
|
||||
hf.handle(req, res, () => {})
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
importApis(router, io, jobs);
|
||||
|
||||
socketApis.push(...handleRouter(router));
|
||||
}
|
||||
|
||||
function createReq(data: any) {
|
||||
const req: any = { ...data };
|
||||
|
||||
req.header = req.get = (p) => req.headers[p];
|
||||
|
||||
req.login =
|
||||
req.logIn = function(user, options, done) {
|
||||
if (typeof options == 'function') {
|
||||
done = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
var property = 'user';
|
||||
if (this._passport && this._passport.instance) {
|
||||
property = this._passport.instance._userProperty || 'user';
|
||||
}
|
||||
var session = (options.session === undefined) ? true : options.session;
|
||||
|
||||
this[property] = user;
|
||||
if (session) {
|
||||
if (!this._passport) { throw new Error('passport.initialize() middleware not in use'); }
|
||||
if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }
|
||||
|
||||
var self = this;
|
||||
this._passport.instance._sm.logIn(this, user, function(err) {
|
||||
if (err) { self[property] = null; return done(err); }
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
done && done();
|
||||
}
|
||||
};
|
||||
|
||||
req.logout =
|
||||
req.logOut = function() {
|
||||
var property = 'user';
|
||||
if (this._passport && this._passport.instance) {
|
||||
property = this._passport.instance._userProperty || 'user';
|
||||
}
|
||||
|
||||
this[property] = null;
|
||||
if (this._passport) {
|
||||
this._passport.instance._sm.logOut(this);
|
||||
}
|
||||
};
|
||||
|
||||
req.isAuthenticated = function() {
|
||||
var property = 'user';
|
||||
if (this._passport && this._passport.instance) {
|
||||
property = this._passport.instance._userProperty || 'user';
|
||||
}
|
||||
|
||||
return (this[property]) ? true : false;
|
||||
};
|
||||
|
||||
req.isUnauthenticated = function() {
|
||||
return !this.isAuthenticated();
|
||||
};
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
function createRes(callback) {
|
||||
var res: any = {
|
||||
_removedHeader: {},
|
||||
headersSent: true,
|
||||
statusMessage: 'OK',
|
||||
statusCode: 200,
|
||||
locals: {},
|
||||
};
|
||||
|
||||
var headers = {};
|
||||
res.set = res.header = (x, y) => {
|
||||
if (arguments.length === 2) {
|
||||
res.setHeader(x, y);
|
||||
} else {
|
||||
for (var key in x) {
|
||||
res.setHeader(key, x[key]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
res.setHeader = (x, y) => {
|
||||
headers[x] = y;
|
||||
headers[x.toLowerCase()] = y;
|
||||
return res;
|
||||
};
|
||||
res.getHeader = (x) => headers[x];
|
||||
|
||||
res.redirect = function(_code, url) {
|
||||
if (Number.isNaN(_code)) {
|
||||
res.statusCode = 301;
|
||||
url = _code;
|
||||
} else {
|
||||
res.statusCode = _code;
|
||||
}
|
||||
res.setHeader("Location", url);
|
||||
res.end();
|
||||
};
|
||||
res.status = res.sendStatus = function(number) {
|
||||
res.statusCode = number;
|
||||
return res;
|
||||
};
|
||||
|
||||
res.cookie = function(name, value, options) {
|
||||
if (callback) callback(res.statusCode, { setCookie: [ { name, value, options} ] }, {})
|
||||
}
|
||||
|
||||
res.end = res.send = res.write = res.json = function(data) {
|
||||
if (callback) callback(res.statusCode, data, headers);
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function handleRouter(router: any) {
|
||||
if (!router.stack) return [];
|
||||
const tempRoutes = [];
|
||||
for (const layer of router.stack) {
|
||||
if (layer.name !== 'router' && layer.name !== 'logger' && layer.route === undefined && typeof layer.handle === 'function') {
|
||||
const rt = {
|
||||
method: 'MIDDLEWARE',
|
||||
handle: layer.handle,
|
||||
}
|
||||
middlewares.push(rt);
|
||||
}
|
||||
if (layer.name === 'bound dispatch' && typeof layer.route.path === 'string') {
|
||||
const rt = {
|
||||
method: Object.keys(layer.route.methods)[0],
|
||||
path: layer.route.path,
|
||||
stack: layer.route.stack,
|
||||
handle: layer.handle,
|
||||
}
|
||||
tempRoutes.push(rt);
|
||||
} else if (layer.name === 'router') {
|
||||
tempRoutes.push(...handleRouter(layer.handle));
|
||||
}
|
||||
}
|
||||
return tempRoutes;
|
||||
}
|
||||
|
||||
function getHash(str) {
|
||||
|
||||
Reference in New Issue
Block a user