1
0
mirror of https://gitee.com/bitdance-team/chrome-extension synced 2025-01-10 13:48:14 +08:00
Code Issues Projects Releases Wiki Activity GitHub Gitee

Merge branch 'feat-sst' into develop

This commit is contained in:
程序员小墨 2022-02-09 18:53:31 +08:00
commit 3686ddb6c9
49 changed files with 11218 additions and 5626 deletions

View File

@ -2,8 +2,11 @@
"root": true,
"ignorePatterns": ["**/*"],
"plugins": ["@nrwl/nx"],
"overrides": [
{
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off"
},
"overrides": [{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
@ -11,12 +14,10 @@
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
}
]
"depConstraints": [{
"sourceTag": "*",
"onlyDependOnLibsWithTags": ["*"]
}]
}
]
}

10
.gitignore vendored
View File

@ -1,12 +1,12 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
dist
tmp
out-tsc
# dependencies
/node_modules
node_modules
# IDEs and editors
/.idea
@ -37,3 +37,5 @@ testem.log
# System Files
.DS_Store
Thumbs.db
.inspirecloud.service.conf

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules\\typescript\\lib"
}

13
jsconfig.json Normal file
View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es2020",
"jsx": "preserve",
"strictFunctionTypes": true,
"experimentalDecorators": true
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

3871
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,8 @@
},
"private": true,
"dependencies": {
"@byteinspire/api": "^1.0.12",
"lodash": "^4.17.21",
"tslib": "^2.0.0",
"vue": "^3.0.5"
},
@ -24,6 +26,9 @@
"@nrwl/workspace": "13.5.3",
"@nx-plus/vite": "^12.2.0",
"@types/jest": "27.0.2",
"@types/koa": "^2.13.4",
"@types/koa__router": "^8.0.11",
"@types/lodash": "^4.14.178",
"@types/node": "16.11.7",
"@typescript-eslint/eslint-plugin": "~5.3.0",
"@typescript-eslint/parser": "~5.3.0",

View File

@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -0,0 +1,11 @@
# services-api
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build services-api` to build the library.
## Running unit tests
Run `nx test services-api` to execute the unit tests via [Jest](https://jestjs.io).

View File

@ -0,0 +1,14 @@
module.exports = {
displayName: 'services-api',
preset: '../../jest.preset.js',
globals: {
'ts-jest': {
tsconfig: '<rootDir>/tsconfig.spec.json',
},
},
transform: {
'^.+\\.[tj]s$': 'ts-jest',
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/packages/services-api',
};

View File

@ -0,0 +1,5 @@
{
"name": "@bitdance/services-api",
"version": "0.0.1",
"type": "commonjs"
}

View File

@ -0,0 +1,33 @@
{
"root": "packages/services-api",
"sourceRoot": "packages/services-api/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nrwl/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/packages/services-api",
"main": "packages/services-api/src/index.ts",
"tsConfig": "packages/services-api/tsconfig.lib.json",
"assets": ["packages/services-api/*.md"]
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["packages/services-api/**/*.ts"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/packages/services-api"],
"options": {
"jestConfig": "packages/services-api/jest.config.js",
"passWithNoTests": true
}
}
},
"tags": []
}

View File

@ -0,0 +1 @@
export * from './lib/services-api';

View File

@ -0,0 +1,7 @@
import { servicesApi } from './services-api';
describe('servicesApi', () => {
it('should work', () => {
expect(servicesApi()).toEqual('services-api');
});
});

View File

@ -0,0 +1,3 @@
export function servicesApi(): string {
return 'services-api';
}

View File

@ -0,0 +1,22 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "CommonJS",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@ -1,10 +1,13 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"overrides": [{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/triple-slash-reference": "off"
}
},
{
"files": ["*.ts", "*.tsx"],

View File

@ -0,0 +1,3 @@
**/node_modules
.*/**
src

View File

@ -0,0 +1,38 @@
const {src,dest,parallel,watch,series} = require('gulp');
const ts = require('gulp-typescript');
const tsProject = ts.createProject("tsconfig.app.json");
const shell = require('gulp-shell');
const nodemon = require('gulp-nodemon');
function buildTs () {
return src('./src/**/*.ts')
.pipe(tsProject())
.pipe(dest('./dist'));
}
function start (done) {
nodemon({
exec: 'inspirecloud dev',
ext: 'js,ts',
ignore: './dist',
delay: 50,
tasks: ['buildTs'],
done
})
}
function watchServe () {
return watch('src/**/*.ts', {
delay: 100
}, series(buildTs))
}
function serve () {
return series(buildTs, start)()
}
function deploy () {
return series(buildTs, shell.task('inspirecloud deploy'))()
}
module.exports = {serve,deploy,buildTs}

View File

@ -0,0 +1,3 @@
const { app } = require('./dist/app')
// 导出 HTTP handler, koa 对象不可直接作为 HTTP handler, 需要调用 callback() 获取
module.exports = app.callback()

View File

@ -0,0 +1,4 @@
{
"main": "index.js",
"watch": ["index.js"]
}

5580
packages/services/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,33 @@
{
"name": "@bitdance/services",
"version": "0.0.1",
"type": "commonjs"
"type": "commonjs",
"scripts": {
"dev": "gulp serve",
"deploy": "gulp deploy",
"test": "jest"
},
"dependencies": {
"@byteinspire/api": "^1.0.12",
"@byteinspire/cli": "^2.2.23",
"@koa/router": "^10.1.1",
"koa": "^2.13.4",
"koa-body": "^4.2.0",
"koa-bunyan-logger": "^2.1.0",
"koa-helmet": "^6.1.0",
"koa-static": "^5.0.0",
"koa-swagger-decorator": "^1.8.2",
"koa2-cors": "^2.0.6",
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/koa-bunyan-logger": "^2.1.4",
"@types/koa2-cors": "^2.0.2",
"gulp": "^4.0.2",
"gulp-cli": "^2.3.0",
"gulp-nodemon": "^2.5.0",
"gulp-shell": "^0.8.0",
"gulp-typescript": "^6.0.0-alpha.1",
"nodemon": "^2.0.15"
}
}

View File

@ -1,33 +1,4 @@
{
"root": "packages/services",
"sourceRoot": "packages/services/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nrwl/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/packages/services",
"main": "packages/services/src/index.ts",
"tsConfig": "packages/services/tsconfig.lib.json",
"assets": ["packages/services/*.md"]
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["packages/services/**/*.ts"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/packages/services"],
"options": {
"jestConfig": "packages/services/jest.config.js",
"passWithNoTests": true
}
}
},
"tags": []
}

View File

@ -0,0 +1,55 @@
import Koa from 'koa'
import koaBody from 'koa-body';
import router from './router';
import helmet from 'koa-helmet'
import koaBunyanLogger from 'koa-bunyan-logger'
import koaCors from 'koa2-cors';
import { errorHandler } from './utils/response'
const app = new Koa();
// 跨域请求设置
app.use(koaCors({
origin: function (ctx) { //设置允许来自指定域名请求
return '*'
},
maxAge: 5, //指定本次预检请求的有效期,单位为秒。
credentials: true, //是否允许发送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //设置所允许的HTTP请求方法'
allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'x-tt-session-v2'], //设置服务器支持的所有头信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //设置获取其他自定义字段
}))
// 过滤不安全的请求内容
// app.use(helmet.contentSecurityPolicy());
app.use(helmet.dnsPrefetchControl());
app.use(helmet.expectCt());
app.use(helmet.frameguard());
app.use(helmet.hidePoweredBy());
app.use(helmet.hsts());
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());
app.use(helmet.permittedCrossDomainPolicies());
app.use(helmet.referrerPolicy());
app.use(helmet.xssFilter());
// 解析不同类别的请求
app.use(koaBody({
multipart: true,
formidable: {
maxFileSize: 30 * 1024 * 1024
}
}));
// 请求日志
app.use(koaBunyanLogger());
app.use(koaBunyanLogger.requestIdContext());
app.use(koaBunyanLogger.requestLogger());
// 若后面的路由抛错,则封装为错误响应返回
app.use(errorHandler);
// 为应用使用路由定义
app.use(router.routes()).use(router.allowedMethods());
export { app }

View File

@ -0,0 +1,56 @@
import { getCurrentUser, login, logout, register } from '../services/user';
import { Context, description, middlewares, request, security, securityAll, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
import { authenticate, swaggerBody } from '../utils/swagger';
import { isNil } from 'lodash';
import { authentication } from '../utils/response';
@swaggerClass()
export class LoginRegDto {
@swaggerProperty({ type: "string", required: true }) username = "";
@swaggerProperty({ type: "string", required: true }) password = "";
};
@tagsAll('认证系统')
export default class Auth {
@request('POST', '/auth/register')
@summary('注册一个用户')
@swaggerBody(LoginRegDto)
static async register(ctx: Context) {
const params = ctx.validatedBody as LoginRegDto;
const data = await register(
ctx,
params.username,
params.password
);
ctx.body = { code: 200, msg: '' }
}
@request('POST', '/auth/login')
@summary('登录一个用户')
@swaggerBody(LoginRegDto)
static async login(ctx: Context) {
const params = ctx.validatedBody as LoginRegDto;
const data = await login(
ctx,
params.username,
params.password
);
ctx.body = { code: 200, msg: '' }
}
@request('GET', '/auth/info')
@summary('获取当前的用户信息')
@authenticate
static async info(ctx: Context) {
const data = await getCurrentUser(ctx)
ctx.body = { code: 200, msg: '', data };
}
@request('POST', '/auth/logout')
@summary('登出当前系统')
@security([{ session: [] }])
static async logout(ctx: Context) {
await logout(ctx)
ctx.body = { code: 200, msg: '' };
}
}

View File

@ -0,0 +1,29 @@
import { getCurrentUser, login, logout, register } from '../services/user';
import { Context, description, middlewares, formData, request, security, securityAll, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
import { swaggerBody } from '../utils/swagger';
import { isArray, isNil, uniqueId } from 'lodash';
import { authentication } from '../utils/response';
import { uploadFile } from '../services/files';
import { readFileSync } from 'fs'
@tagsAll('文件系统')
export default class RemoteFile {
@request('POST', '/files')
@summary('上传文件')
@formData({ file: { type: 'file', required: true, description: '文件内容' } })
@security([{ session: [] }])
@middlewares([authentication])
static async upload(ctx: Context) {
const file = ctx.request.files?.['file']
if (isNil(file)) throw { code: 400, msg: '未上传任何文件' }
if (isArray(file)) throw { code: 400, msg: '只能上传一个文件' }
const content = readFileSync(file.path)
const data = await uploadFile(file.name || uniqueId('file'), content)
ctx.body = { code: 200, msg: '', data }
}
}

View File

@ -0,0 +1,19 @@
import { Context, description, middlewares, request, security, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
import { authentication } from '../utils/response';
import { authenticate, swaggerBody } from '../utils/swagger';
@tagsAll('测试')
export default class Index {
@request('GET', '/test')
@summary('测试服务器是否正常')
static async test(ctx: Context) {
ctx.body = { code: 200, msg: '', data: new Date() }
}
@request('GET', '/authtest')
@summary('测试服务器是否正常')
@authenticate
static async authtest(ctx: Context) {
ctx.body = { code: 200, msg: '', data: new Date() }
}
}

View File

@ -0,0 +1,50 @@
import { getCurrentUser } from './../services/user';
import { Context, description, middlewares, path, request, security, summary, swaggerClass, swaggerProperty, tagsAll } from 'koa-swagger-decorator';
import { authentication } from '../utils/response';
import { authenticate, swaggerBody } from '../utils/swagger';
import { ObjectId, UserContext } from '../models/base';
import memoService from '../services/memo';
import { multipageHttpQuery } from '../utils/multipage';
import { User } from '../models/user';
export class CreateMemoDto {
@swaggerProperty({ type: "string", required: true }) content = "";
};
@tagsAll('备忘录')
export default class Memo {
@request('GET', '/memos')
@summary('获取个人所有的备忘录')
@authenticate
@multipageHttpQuery()
static async getAll(ctx: UserContext) {
const data = await memoService.findByUserPage(ctx.user._id, ctx.validatedQuery)
ctx.body = { code: 200, msg: '', data }
}
@request('POST', '/memos')
@summary('创建一个备忘录')
@authenticate
@swaggerBody(CreateMemoDto)
static async createOne(ctx: UserContext) {
// ctx.user 获取的只是一个JSON字段不支持数据库关联
const user = await memoService.db.table<User>('_user').where({ _id: new ObjectId(ctx.user._id) }).projection({ username: 1, lastLogin: 1, status: 1 }).findOne()
const data = await memoService.createOne({
content: ctx.validatedBody.content,
user
})
ctx.body = { code: 200, msg: '', data }
}
@request('DELETE', '/memos/{id}')
@summary('删除一个备忘录')
@authenticate
@path({ id: { type: 'string', required: true, description: 'ID' } })
static async deleteOne(ctx: UserContext) {
await memoService.deleteOne(ctx.validatedParams.id)
ctx.body = { code: 200, msg: '' }
}
}

View File

@ -1 +0,0 @@
export * from './lib/services';

View File

@ -1,7 +0,0 @@
import { services } from './services';
describe('services', () => {
it('should work', () => {
expect(services()).toEqual('services');
});
});

View File

@ -1,3 +0,0 @@
export function services(): string {
return 'services';
}

View File

@ -0,0 +1,15 @@
import { Context } from 'koa-swagger-decorator';
export type WithId<T extends object> = T & { _id: string }
import inspirecloud from '@byteinspire/api';
import { User } from './user';
export const ObjectId = inspirecloud.db.ObjectId
export type ObjectIdType = InstanceType<typeof ObjectId>
export interface PageQuery { page: number, pageSize: number }
export interface UserContext extends Context {
user: WithId<User>
}

View File

@ -0,0 +1,8 @@
import { IEntity } from '@byteinspire/db';
import { User } from './user';
import { ObjectIdType } from './base';
export interface Memo {
content: string;
user: User
}

View File

@ -0,0 +1,17 @@
export interface User {
avatar: string | null;
email: string | null;
phoneNumber: string | null;
intro: string | null;
lastLogin: number;
loginCount: number;
lastIp: string;
status: boolean;
createAt: number;
createdAt: number;
updatedAt: number;
username: string;
firstProvider: string;
loginAt: number;
expireAt: number;
}

View File

@ -0,0 +1,32 @@
import '@koa/router'
import { SwaggerRouter } from 'koa-swagger-decorator'
import path from 'path'
const router = new SwaggerRouter({ prefix: '/api' }) // extends from koa-router
// swagger docs avaliable at http://localhost:3000/api/swagger-html
router.swagger({
title: 'BitDance浏览器插件后台服务',
description: '请求认证头为 `x-tt-session-v2`',
version: '1.0.0',
prefix: '/api',
swaggerHtmlEndpoint: '/swagger-html',
swaggerJsonEndpoint: '/swagger-json',
swaggerOptions: {
securityDefinitions: {
session: {
type: 'apiKey',
in: 'header',
name: 'x-tt-session-v2',
},
},
},
})
// mapDir will scan the input dir, and automatically call router.map to all Router Class
router.mapDir(path.resolve(__dirname, 'controllers'), {
ignore: ["**.spec.ts", "**.d.ts"],
})
export default router

View File

@ -0,0 +1,108 @@
import { isNil } from 'lodash';
import { IEntity, ITable, API } from '@byteinspire/db';
import { Memo } from '../models/memo';
import { Context } from 'koa-swagger-decorator';
import inspirecloud from '@byteinspire/api'
import { multipageDbQuery } from '../utils/multipage';
import { PageQuery, ObjectIdType, ObjectId } from '../models/base';
export default class BaseDbService<T> {
table: ITable<T>
db: API = inspirecloud.db
/**
*
* @param name
*/
constructor(name: string) {
this.table = inspirecloud.db.table<T>(name)
}
/**
*
* @returns
*/
findMany(query: any): Promise<(T & IEntity)[]> {
return query.find()
}
/**
*
* @returns
*/
findAll(): Promise<(T & IEntity)[]> {
return this.findMany(this.table.where())
}
/**
*
* @returns
*/
findOne(id: string): Promise<(T & IEntity)> {
const result = this.table.where({ _id: new ObjectId(id) }).findOne()
if (isNil(result)) throw { status: 404, message: 'Not Found' }
return result
}
/**
*
* @returns
*/
findPage(pageArg: PageQuery, query: any) {
return multipageDbQuery(pageArg, query)
}
/**
*
* @param pageArg
* @returns
*/
findAllPage(pageArg: PageQuery) {
return this.findPage(pageArg, this.table.where())
}
/**
*
* @returns
*/
createOne(item: T): Promise<(T & IEntity)> {
return this.table.save(item)
}
/**
*
* @returns
*/
async updateOne(item: Partial<T> & { _id: string }): Promise<T & IEntity> {
const result = await this.findOne(item._id)
for (const [k, v] of Object.entries(item) as [keyof (T & IEntity), any][]) {
if (k === '_id' || k === 'createdAt' || k === 'updatedAt') continue
result[k] = v
}
return this.table.save(result)
}
/**
*
* @param id
*/
async deleteOne(id: string) {
const result = await this.table.where({ _id: new ObjectId(id) }).findOne()
if (isNil(result)) throw { status: 404, message: 'Not Found' }
return await this.table.delete([result])
}
/**
*
* @param ids
* @returns
*/
async deleteMany(ids: string[]) {
const result = await this.table.where({ _id: this.db.in(ids) }).find()
const delRes = await this.table.delete(result)
return (delRes as any).deletedCount
}
}

View File

@ -0,0 +1,14 @@
import inspirecloud from '@byteinspire/api';
const fileService = inspirecloud.file
const uploadFile = fileService.upload.bind(fileService) as any as (
name: string,
buffer: Buffer | string | { url: string },
) => Promise<{ url: string; id: string }>;
const downloadFile = fileService.download.bind(fileService)
const removeFile = fileService.delete.bind(fileService)
export { uploadFile, downloadFile, removeFile }

View File

@ -0,0 +1,19 @@
import { getCurrentUser } from './user';
import { ObjectId } from './../models/base';
import { Memo } from './../models/memo';
import BaseDbService from './base'
import { IEntity, ITable, API } from '@byteinspire/db';
import { PageQuery } from '../models/base';
class MemoService extends BaseDbService<Memo> {
findByUserPage(uid: string, pageArg: PageQuery) {
return this.findPage(pageArg, this.table.where({ user: new ObjectId(uid) }).populate({
ref: 'user',
projection: ['_id', 'username', 'nickname', 'lastLogin', 'status']
} as any))
}
}
const memoService = new MemoService('memo')
export default memoService

View File

@ -0,0 +1,25 @@
import { User } from './../models/user';
import { WithId } from '../models/base';
import { Context } from 'koa-swagger-decorator';
import inspirecloud from '@byteinspire/api';
import { isNil } from 'lodash';
const userService = (inspirecloud as any).user
export const login = userService.login as (ctx: Context, username: string, password: string) => Promise<undefined>
export const register = userService.register as (ctx: Context, username: string, password: string) => Promise<undefined>
export const getCurrentUser = userService.current as (ctx: Context) => Promise<WithId<User> | undefined>
export const logout = userService.logout as (ctx: Context) => Promise<undefined>
export const updateNewPassword = userService.changePassword as (context: Context, newPassword: string, originPassword?: string) => Promise<any>;
export async function isLogin(ctx: Context) {
try {
return !isNil(await getCurrentUser(ctx))
} catch (error) {
return false
}
}

View File

@ -0,0 +1,27 @@
import { Context, query } from 'koa-swagger-decorator';
import { PageQuery } from '../models/base';
// 用于分页的数据库查询辅助函数
export async function multipageDbQuery<T = any>(pageArg: PageQuery, query: any) {
const { page = 1, pageSize = 10 } = pageArg
if (page < 1 || pageSize < 1) throw { status: 400, message: '分页参数不合法' }
const total = await query.count();
const content = await query.skip((page - 1) * pageSize).limit(pageSize).find();
return {
total,
page,
pageSize,
content: (content || []) as T[]
}
}
//用于分页的HTTP Query查询
export function multipageHttpQuery() {
return query(
{
page: { type: 'number', required: false, default: 1, description: 'type' },
pageSize: { type: 'number', required: false, default: 10, description: 'type' }
})
}

View File

@ -0,0 +1,35 @@
import { Context } from 'koa-swagger-decorator';
import { UserContext } from '../models/base';
import { getCurrentUser, isLogin } from '../services/user';
// 处理请求中的错误
export async function errorHandler(ctx: Context, next: any) {
try {
await next();
} catch (err) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const error = err as any
// 抛出的错误可以附带 status 字段,代表 http 状态码
// 若没有提供,则默认状态码为 500代表服务器内部错误
ctx.status = error.status || 500;
ctx.body = { code: ctx.status, msg: error.message };
console.error(err)
}
}
/**
* ctx.user
* @param ctx
* @param next
*/
export async function authentication(ctx: UserContext, next: any) {
try {
const user = await getCurrentUser(ctx)
if (!user) throw ""
ctx.user = user
} catch (error) {
console.error(error)
throw { status: 401, message: "用户未登录" }
}
await next()
}

View File

@ -0,0 +1,24 @@
import { body, security } from 'koa-swagger-decorator'
import { authentication } from './response'
export function swaggerDocument(cls: any) {
return (cls as any).swaggerDocument
}
export function swaggerBody<T extends object>(cls: T) {
return body(swaggerDocument(cls))
}
export function authenticate(
target: any,
name: string,
descriptor: PropertyDescriptor
) {
if (!descriptor.value.middlewares) descriptor.value.middlewares = []
descriptor.value.middlewares.push(authentication)
// call other decorators
security([{ session: [] }])(target, name, descriptor)
return descriptor;
};

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"experimentalDecorators": true,
"types": []
},
"include": ["./src/**/*.ts"],
"exclude": ["**/*.spec.ts"]
}

View File

@ -5,18 +5,18 @@
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"strictFunctionTypes": false,
"experimentalDecorators": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
"noFallthroughCasesInSwitch": true,
"declaration": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
// "files": [],
"include": ["src/**/*.ts"],
"references": [{
"path": "./tsconfig.app.json"
}]
}

View File

@ -5,6 +5,7 @@
"composite": true,
"sourceMap": true,
"declaration": false,
"esModuleInterop": true,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
@ -16,7 +17,7 @@
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {
"@bitdance/services": ["packages/services/src/index.ts"],
"@bitdance/services-api": ["packages/services-api/src/index.ts"],
"@bitdance/shared": ["packages/shared/src/index.ts"]
}
},

View File

@ -3,6 +3,7 @@
"projects": {
"plugin-ui": "packages/plugin-ui",
"services": "packages/services",
"services-api": "packages/services-api",
"shared": "packages/shared",
"shell-chrome": "packages\\shell-chrome"
}

6535
yarn.lock

File diff suppressed because it is too large Load Diff