create shared library
This commit is contained in:
parent
5f700a3374
commit
825b2856bb
|
@ -8,6 +8,15 @@
|
|||
"isBackground": true,
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "Start shared",
|
||||
"command": "yarn start",
|
||||
"options": {
|
||||
"cwd": "./shared"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"label": "Start backend",
|
||||
|
@ -15,6 +24,7 @@
|
|||
"options": {
|
||||
"cwd": "./backend"
|
||||
},
|
||||
"dependsOn": ["Start shared"],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
|
@ -24,6 +34,7 @@
|
|||
"options": {
|
||||
"cwd": "./frontend"
|
||||
},
|
||||
"dependsOn": ["Start shared"],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"repository": "https://github.com/rubikscraft/Imagur",
|
||||
"author": "Rubikscraft <contact@rubikscraft.nl>",
|
||||
"type": "module",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "nest build",
|
||||
|
@ -41,7 +42,8 @@
|
|||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.5.4",
|
||||
"typeorm": "^0.2.43"
|
||||
"typeorm": "^0.2.43",
|
||||
"imagur-shared": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.2.1",
|
||||
|
|
|
@ -7,8 +7,6 @@ import { ServeStaticModule } from '@nestjs/serve-static';
|
|||
import Config from './env';
|
||||
import { ImageEntity } from './collections/imagedb/image.entity';
|
||||
|
||||
const backendRoutes = ['i', 'api'];
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRoot({
|
||||
|
|
|
@ -3,8 +3,8 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||
import { Repository } from 'typeorm';
|
||||
import { ImageEntity } from './image.entity';
|
||||
import Crypto from 'crypto';
|
||||
import { AsyncFailable, Fail, HasFailed, HasSuccess } from 'src/types/failable';
|
||||
import { SupportedMime } from './mimes.service';
|
||||
import { AsyncFailable, Fail, HasFailed, HasSuccess } from 'imagur-shared/dist/types';
|
||||
|
||||
@Injectable()
|
||||
export class ImageDBService {
|
||||
|
@ -27,8 +27,8 @@ export class ImageDBService {
|
|||
imageEntity.hash = hash;
|
||||
try {
|
||||
await this.imageRepository.save(imageEntity);
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
|
||||
return imageEntity;
|
||||
|
@ -39,8 +39,8 @@ export class ImageDBService {
|
|||
const found = await this.imageRepository.findOne({ where: { hash } });
|
||||
if (found === undefined) return Fail('Image not found');
|
||||
return found;
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,8 +55,8 @@ export class ImageDBService {
|
|||
});
|
||||
if (found === undefined) return Fail('Images not found');
|
||||
return found;
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,8 +67,8 @@ export class ImageDBService {
|
|||
|
||||
try {
|
||||
await this.imageRepository.delete(image);
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Fail, Failable } from 'src/types/failable';
|
||||
import { Fail, Failable } from 'imagur-shared/dist/types';
|
||||
|
||||
const tuple = <T extends string[]>(...args: T): T => args;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { AsyncFailable, Fail, HasFailed, HasSuccess } from 'src/types/failable';
|
||||
import { AsyncFailable, Fail, HasFailed, HasSuccess } from 'imagur-shared/dist/types';
|
||||
import { Repository } from 'typeorm';
|
||||
import { UserEntity } from './user.entity';
|
||||
|
||||
|
@ -23,8 +23,8 @@ export class UsersService {
|
|||
|
||||
try {
|
||||
await this.usersRepository.save(user);
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
|
||||
return user;
|
||||
|
@ -37,8 +37,8 @@ export class UsersService {
|
|||
|
||||
try {
|
||||
await this.usersRepository.remove(userToModify);
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
|
||||
return userToModify;
|
||||
|
@ -49,16 +49,16 @@ export class UsersService {
|
|||
const found = await this.usersRepository.findOne({ where: { username } });
|
||||
if (!found) return Fail('User not found');
|
||||
return found;
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
}
|
||||
|
||||
public async findAll(): AsyncFailable<UserEntity[]> {
|
||||
try {
|
||||
return await this.usersRepository.find();
|
||||
} catch (e) {
|
||||
return Fail(e.message);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ import {
|
|||
import { validate } from 'class-validator';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import { Multipart, MultipartFields, MultipartFile } from 'fastify-multipart';
|
||||
import Config from 'src/env';
|
||||
import { Newable } from 'src/types/newable';
|
||||
import { Newable } from 'imagur-shared/dist/types';
|
||||
import Config from '../env';
|
||||
import { MultiPartFieldDto, MultiPartFileDto } from './multipart.dto';
|
||||
|
||||
const logger = new Logger('MultiPart');
|
||||
|
@ -56,7 +56,7 @@ export const MultiPart = createParamDecorator(
|
|||
|
||||
if (!req.isMultipart()) throw new BadRequestException('Invalid file');
|
||||
|
||||
let fields: MultipartFields;
|
||||
let fields: MultipartFields | null = null;
|
||||
try {
|
||||
fields = (
|
||||
await req.file({
|
||||
|
@ -74,9 +74,9 @@ export const MultiPart = createParamDecorator(
|
|||
}
|
||||
|
||||
if ((fields[key] as any).value) {
|
||||
dtoClass[key] = new MultiPartFieldDto(fields[key] as MultipartFile);
|
||||
(dtoClass as any)[key] = new MultiPartFieldDto(fields[key] as MultipartFile);
|
||||
} else {
|
||||
dtoClass[key] = new MultiPartFileDto(
|
||||
(dtoClass as any)[key] = new MultiPartFileDto(
|
||||
fields[key] as MultipartFile,
|
||||
new BadRequestException('Invalid file'),
|
||||
);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { MultipartFile } from 'fastify-multipart';
|
||||
import { BusboyFileStream } from '@fastify/busboy';
|
||||
import { IsDefined, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
import { AsyncFailable, Fail } from 'src/types/failable';
|
||||
import { IsDefined, IsNotEmpty, IsString } from 'class-validator';
|
||||
import { HttpException } from '@nestjs/common';
|
||||
|
||||
export class MultiPartFileDto {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ImageDBModule } from 'src/collections/imagedb/imagedb.module';
|
||||
import { ImageDBModule } from '../../collections/imagedb/imagedb.module';
|
||||
import { ImageManagerService } from './imagemanager.service';
|
||||
|
||||
@Module({
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { fileTypeFromBuffer, FileTypeResult } from 'file-type';
|
||||
import { ImageEntity } from 'src/collections/imagedb/image.entity';
|
||||
import { ImageDBService } from 'src/collections/imagedb/imagedb.service';
|
||||
import { FullMime, MimesService } from 'src/collections/imagedb/mimes.service';
|
||||
import { AsyncFailable, Fail, HasFailed } from 'src/types/failable';
|
||||
import { AsyncFailable, Fail, HasFailed } from 'imagur-shared/dist/types';
|
||||
import { ImageEntity } from '../../collections/imagedb/image.entity';
|
||||
import { ImageDBService } from '../../collections/imagedb/imagedb.service';
|
||||
import { MimesService, FullMime } from '../../collections/imagedb/mimes.service';
|
||||
|
||||
@Injectable()
|
||||
export class ImageManagerService {
|
||||
|
@ -38,7 +38,7 @@ export class ImageManagerService {
|
|||
}
|
||||
|
||||
private async getFullMimeFromBuffer(image: Buffer): AsyncFailable<FullMime> {
|
||||
const mime: FileTypeResult = await fileTypeFromBuffer(image);
|
||||
const mime: FileTypeResult | undefined = await fileTypeFromBuffer(image);
|
||||
const fullMime = await this.mimesService.getFullMime(
|
||||
mime?.mime ?? 'extra/discard',
|
||||
);
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
} from '@nestjs/common';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { User } from 'src/collections/userdb/user.dto';
|
||||
import { User } from '../../../collections/userdb/user.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AdminGuard implements CanActivate {
|
||||
|
|
|
@ -18,7 +18,8 @@ import {
|
|||
import { AuthService } from './auth.service';
|
||||
import { JwtAuthGuard } from './jwt.guard';
|
||||
import { AdminGuard } from './admin.guard';
|
||||
import { HasFailed } from 'src/types/failable';
|
||||
import { HasFailed } from 'imagur-shared/dist/types';
|
||||
import AuthFasityRequest from './authrequest';
|
||||
|
||||
@Controller('api/auth')
|
||||
export class AuthController {
|
||||
|
@ -26,7 +27,7 @@ export class AuthController {
|
|||
|
||||
@UseGuards(LocalAuthGuard)
|
||||
@Post('login')
|
||||
async login(@Request() req) {
|
||||
async login(@Request() req: AuthFasityRequest) {
|
||||
const response: LoginResponseDto = {
|
||||
access_token: await this.authService.createToken(req.user),
|
||||
};
|
||||
|
@ -36,7 +37,10 @@ export class AuthController {
|
|||
|
||||
@UseGuards(JwtAuthGuard, AdminGuard)
|
||||
@Post('create')
|
||||
async register(@Request() req, @Body() register: RegisterRequestDto) {
|
||||
async register(
|
||||
@Request() req: AuthFasityRequest,
|
||||
@Body() register: RegisterRequestDto,
|
||||
) {
|
||||
const user = await this.authService.createUser(
|
||||
register.username,
|
||||
register.password,
|
||||
|
@ -53,7 +57,10 @@ export class AuthController {
|
|||
|
||||
@UseGuards(JwtAuthGuard, AdminGuard)
|
||||
@Post('delete')
|
||||
async delete(@Request() req, @Body() deleteData: DeleteRequestDto) {
|
||||
async delete(
|
||||
@Request() req: AuthFasityRequest,
|
||||
@Body() deleteData: DeleteRequestDto,
|
||||
) {
|
||||
const user = await this.authService.deleteUser(deleteData.username);
|
||||
if (HasFailed(user)) throw new NotFoundException('User does not exist');
|
||||
|
||||
|
@ -62,7 +69,7 @@ export class AuthController {
|
|||
|
||||
@UseGuards(JwtAuthGuard, AdminGuard)
|
||||
@Get('list')
|
||||
async listUsers(@Request() req) {
|
||||
async listUsers(@Request() req: AuthFasityRequest) {
|
||||
const users = this.authService.listUsers();
|
||||
|
||||
if (HasFailed(users))
|
||||
|
@ -73,9 +80,7 @@ export class AuthController {
|
|||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('me')
|
||||
async me(@Request() req) {
|
||||
async me(@Request() req: AuthFasityRequest) {
|
||||
return req.user;
|
||||
}
|
||||
}
|
||||
|
||||
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7InVzZXJuYW1lIjoiYWRtaW4iLCJpc0FkbWluIjp0cnVlfSwiaWF0IjoxNjQ1NDUxMzg1LCJleHAiOjE2NDU1Mzc3ODV9.Uf6JmygblXgBS4ztTcfZl6m579YjH2R0uD0QyNCfQNs
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
IsString,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { User } from 'src/collections/userdb/user.dto';
|
||||
import { User } from '../../../collections/userdb/user.dto';
|
||||
|
||||
export class LoginResponseDto {
|
||||
@IsString()
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { Logger, Module, OnModuleInit } from '@nestjs/common';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { UsersModule } from 'src/collections/userdb/userdb.module';
|
||||
import { AuthService } from './auth.service';
|
||||
import { LocalStrategy } from './local.strategy';
|
||||
import { AuthController } from './auth.controller';
|
||||
import Config from 'src/env';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { JwtStrategy } from './jwt.strategy';
|
||||
import { UsersModule } from '../../../collections/userdb/userdb.module';
|
||||
import Config from '../../../env';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { AsyncFailable, Fail, HasFailed } from 'src/types/failable';
|
||||
import { User } from 'src/collections/userdb/user.dto';
|
||||
import { UserEntity } from 'src/collections/userdb/user.entity';
|
||||
import { UsersService } from 'src/collections/userdb/userdb.service';
|
||||
import { AsyncFailable, HasFailed, Fail } from 'imagur-shared/dist/types';
|
||||
import { User } from '../../../collections/userdb/user.dto';
|
||||
import { UserEntity } from '../../../collections/userdb/user.entity';
|
||||
import { UsersService } from '../../../collections/userdb/userdb.service';
|
||||
import { JwtDataDto } from './auth.dto';
|
||||
|
||||
@Injectable()
|
||||
|
@ -47,7 +47,7 @@ export class AuthService {
|
|||
return user;
|
||||
}
|
||||
|
||||
async createToken(user: UserEntity): Promise<string> {
|
||||
async createToken(user: User): Promise<string> {
|
||||
const jwtData: JwtDataDto = {
|
||||
user: {
|
||||
username: user.username,
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import { FastifyRequest } from 'fastify';
|
||||
import { User } from '../../../collections/userdb/user.dto';
|
||||
|
||||
export default interface AuthFasityRequest extends FastifyRequest {
|
||||
user: User;
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
|
||||
import Config from 'src/env';
|
||||
import { validate } from 'class-validator';
|
||||
import { JwtDataDto } from './auth.dto';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { User } from 'src/collections/userdb/user.dto';
|
||||
import { User } from '../../../collections/userdb/user.dto';
|
||||
import Config from '../../../env';
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
|
|
|
@ -2,8 +2,8 @@ import { Strategy } from 'passport-local';
|
|||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { AsyncFailable, HasFailed } from 'src/types/failable';
|
||||
import { UserEntity } from 'src/collections/userdb/user.entity';
|
||||
import { User } from '../../../collections/userdb/user.dto';
|
||||
import { AsyncFailable, HasFailed } from 'imagur-shared/dist/types';
|
||||
|
||||
@Injectable()
|
||||
export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
|
||||
|
@ -11,14 +11,16 @@ export class LocalStrategy extends PassportStrategy(Strategy, 'local') {
|
|||
super();
|
||||
}
|
||||
|
||||
async validate(
|
||||
username: string,
|
||||
password: string,
|
||||
): AsyncFailable<UserEntity> {
|
||||
const user = await this.authService.authenticate(username, password);
|
||||
if (HasFailed(user)) {
|
||||
async validate(username: string, password: string): AsyncFailable<User> {
|
||||
const userEntity = await this.authService.authenticate(username, password);
|
||||
if (HasFailed(userEntity)) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
const user: User = {
|
||||
username: userEntity.username,
|
||||
isAdmin: userEntity.isAdmin,
|
||||
};
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,18 +9,10 @@ import {
|
|||
Req,
|
||||
Res,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsDefined,
|
||||
Validate,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { User } from 'src/collections/userdb/user.dto';
|
||||
import { MultiPart, MultiPartDto } from 'src/decorators/multipart.decorator';
|
||||
import { MultiPartFileDto } from 'src/decorators/multipart.dto';
|
||||
import { ImageManagerService } from 'src/managers/imagemanager/imagemanager.service';
|
||||
import { HasFailed } from 'src/types/failable';
|
||||
import { HasFailed } from 'imagur-shared/dist/types';
|
||||
import { MultiPart } from '../../decorators/multipart.decorator';
|
||||
import { ImageManagerService } from '../../managers/imagemanager/imagemanager.service';
|
||||
import { ImageUploadDto } from './imageroute.dto';
|
||||
@Controller('i')
|
||||
export class ImageController {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { IsDefined, ValidateNested } from 'class-validator';
|
||||
import { MultiPartDto } from 'src/decorators/multipart.decorator';
|
||||
import { MultiPartFileDto } from 'src/decorators/multipart.dto';
|
||||
import { MultiPartDto } from '../../decorators/multipart.decorator';
|
||||
import { MultiPartFileDto } from '../../decorators/multipart.dto';
|
||||
|
||||
export class ImageUploadDto extends MultiPartDto {
|
||||
@IsDefined()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ImageManagerModule } from 'src/managers/imagemanager/imagemanager.module';
|
||||
|
||||
import { ImageManagerModule } from '../../managers/imagemanager/imagemanager.module';
|
||||
import { ImageController } from './imageroute.controller';
|
||||
|
||||
@Module({
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "es2020",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es2020",
|
||||
"sourceMap": true,
|
||||
"module": "es2020",
|
||||
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true
|
||||
}
|
||||
}
|
||||
|
|
3816
backend/yarn.lock
3816
backend/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1 @@
|
|||
BUILD_PATH='./dist'
|
|
@ -1,8 +1,10 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
devServer: {
|
||||
writeToDisk: true,
|
||||
port: 3300,
|
||||
liveReload: true,
|
||||
open: false
|
||||
},
|
||||
open: false,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"repository": "https://github.com/rubikscraft/Imagur",
|
||||
"author": "Rubikscraft <contact@rubikscraft.nl>",
|
||||
"type": "commonjs",
|
||||
"main": "dist/index.js",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.8.1",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
|
@ -16,7 +17,8 @@
|
|||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-dropzone": "^12.0.4",
|
||||
"react-router-dom": "^6.2.1"
|
||||
"react-router-dom": "^6.2.1",
|
||||
"imagur-shared": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { AsyncFailable, Fail } from '../types/failable';
|
||||
import { AsyncFailable, Fail } from 'imagur-shared/dist/types'
|
||||
|
||||
export function GetImageURL(image: string): string {
|
||||
const baseURL = window.location.protocol + '//' + window.location.host;
|
||||
|
|
|
@ -3,7 +3,7 @@ import CircularProgress from '@mui/material/CircularProgress';
|
|||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
import { UploadImage } from '../../api/images';
|
||||
import { HasFailed } from '../../types/failable';
|
||||
import { HasFailed } from 'imagur-shared/dist/types';
|
||||
|
||||
export interface ProcessingViewMetadata {
|
||||
imageFile: File;
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
export class Failure {
|
||||
constructor(private readonly reason?: string) {}
|
||||
|
||||
getReason(): string {
|
||||
return this.reason ?? 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
export function Fail(reason?: string): Failure {
|
||||
return new Failure(reason);
|
||||
}
|
||||
|
||||
export type Failable<T> = T | Failure;
|
||||
|
||||
export type AsyncFailable<T> = Promise<Failable<T>>;
|
||||
|
||||
export function HasFailed<T>(failable: Failable<T>): failable is Failure {
|
||||
return failable instanceof Failure;
|
||||
}
|
||||
|
||||
export function HasSuccess<T>(failable: Failable<T>): failable is T {
|
||||
return !(failable instanceof Failure);
|
||||
}
|
|
@ -1,20 +1,18 @@
|
|||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2015",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"jsx": "react-jsx",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"shared",
|
||||
"backend",
|
||||
"frontend"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
dist
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"private": false,
|
||||
"name": "imagur-shared",
|
||||
"version": "1.0.0",
|
||||
"description": "Shared libraries for Imagur",
|
||||
"license": "GPL-3.0",
|
||||
"repository": "https://github.com/rubikscraft/Imagur",
|
||||
"author": "Rubikscraft <contact@rubikscraft.nl>",
|
||||
"type": "commonjs",
|
||||
"main": "./dist/index.js",
|
||||
"dependencies": {
|
||||
"tsc-watch": "^4.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.20",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "tsc-watch",
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
// Nothing
|
||||
const a = 'hello';
|
||||
|
||||
export default a;
|
|
@ -0,0 +1,2 @@
|
|||
export * from './failable';
|
||||
export * from './newable';
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2015",
|
||||
"module": "esnext",
|
||||
|
||||
"outDir": "./dist",
|
||||
"declaration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
"experimentalDecorators": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
|
||||
"skipLibCheck": true,
|
||||
"removeComments": true,
|
||||
"isolatedModules": true,
|
||||
"incremental": true
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue