mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-10-25 23:46:06 +02:00
update packages and fix build
This commit is contained in:
@@ -21,65 +21,65 @@
|
||||
"purge": "rm -rf dist && rm -rf node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/helmet": "^10.1.1",
|
||||
"@fastify/multipart": "^7.6.1",
|
||||
"@fastify/reply-from": "^9.3.0",
|
||||
"@fastify/static": "^6.10.2",
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^2.3.4",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/jwt": "^10.1.0",
|
||||
"@nestjs/passport": "^9.0.3",
|
||||
"@nestjs/platform-fastify": "^10.0.0",
|
||||
"@nestjs/schedule": "^3.0.0",
|
||||
"@fastify/helmet": "^11.1.1",
|
||||
"@fastify/multipart": "^8.0.0",
|
||||
"@fastify/reply-from": "^9.4.0",
|
||||
"@fastify/static": "^6.12.0",
|
||||
"@nestjs/common": "^10.2.10",
|
||||
"@nestjs/config": "^3.1.1",
|
||||
"@nestjs/core": "^10.2.10",
|
||||
"@nestjs/jwt": "^10.2.0",
|
||||
"@nestjs/passport": "^10.0.2",
|
||||
"@nestjs/platform-fastify": "^10.2.10",
|
||||
"@nestjs/schedule": "^4.0.0",
|
||||
"@nestjs/serve-static": "^4.0.0",
|
||||
"@nestjs/throttler": "^4.0.0",
|
||||
"@nestjs/typeorm": "^9.0.1",
|
||||
"bcrypt": "^5.1.0",
|
||||
"@nestjs/throttler": "^5.0.1",
|
||||
"@nestjs/typeorm": "^10.0.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bmp-img": "^1.2.1",
|
||||
"cors": "^2.8.5",
|
||||
"extensionless": "^1.4.5",
|
||||
"file-type": "^18.5.0",
|
||||
"extensionless": "^1.7.3",
|
||||
"file-type": "^18.7.0",
|
||||
"is-docker": "^3.0.0",
|
||||
"ms": "2.1.3",
|
||||
"node-fetch": "^3.3.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
"p-timeout": "^6.1.2",
|
||||
"passport": "^0.6.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-headerapikey": "^1.2.2",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-strategy": "^1.0.0",
|
||||
"pg": "^8.11.0",
|
||||
"pg": "^8.11.3",
|
||||
"picsur-shared": "*",
|
||||
"posix.js": "^0.1.1",
|
||||
"qoi-img": "^2.1.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^5.0.1",
|
||||
"rimraf": "^5.0.5",
|
||||
"rxjs": "^7.8.1",
|
||||
"sharp": "^0.32.1",
|
||||
"sharp": "^0.32.6",
|
||||
"stream-parser": "^0.3.1",
|
||||
"thunks": "^4.9.6",
|
||||
"typeorm": "0.3.16",
|
||||
"zod": "^3.21.4"
|
||||
"typeorm": "0.3.17",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.1",
|
||||
"@nestjs/schematics": "^10.0.1",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/passport-jwt": "^3.0.8",
|
||||
"@types/passport-local": "^1.0.35",
|
||||
"@types/passport-strategy": "^0.2.35",
|
||||
"@nestjs/cli": "^10.2.1",
|
||||
"@nestjs/schematics": "^10.0.3",
|
||||
"@nestjs/testing": "^10.2.10",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/multer": "^1.4.11",
|
||||
"@types/node": "^20.10.0",
|
||||
"@types/passport-jwt": "^3.0.13",
|
||||
"@types/passport-local": "^1.0.38",
|
||||
"@types/passport-strategy": "^0.2.38",
|
||||
"@types/sharp": "^0.32.0",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"prettier": "^2.8.8",
|
||||
"@types/supertest": "^2.0.16",
|
||||
"prettier": "^3.1.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-loader": "^9.5.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.1.3"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export class JwtConfigService implements JwtOptionsFactory {
|
||||
await this.prefService.getStringPreference('jwt_expires_in'),
|
||||
);
|
||||
|
||||
let milliseconds = ms(expiresIn as any);
|
||||
let milliseconds = ms(expiresIn as string);
|
||||
if (isNaN(milliseconds)) {
|
||||
milliseconds = 1000 * 60 * 60 * 24; // 1 day
|
||||
}
|
||||
|
||||
12
backend/src/decorators/easy-throttle.decorator.ts
Normal file
12
backend/src/decorators/easy-throttle.decorator.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
|
||||
export const EasyThrottle = (
|
||||
limit: number,
|
||||
ttl?: number,
|
||||
): MethodDecorator & ClassDecorator =>
|
||||
Throttle({
|
||||
default: {
|
||||
limit,
|
||||
ttl: ttl ?? 60,
|
||||
},
|
||||
});
|
||||
@@ -8,8 +8,12 @@ import { ZodValidationPipe } from './validate/zod-validator.pipe';
|
||||
@Module({
|
||||
imports: [
|
||||
ThrottlerModule.forRoot({
|
||||
ttl: 60,
|
||||
limit: 60,
|
||||
throttlers: [
|
||||
{
|
||||
limit: 60,
|
||||
ttl: 60,
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
|
||||
@@ -4,7 +4,7 @@ import { FT, Fail } from 'picsur-shared/dist/types/failable';
|
||||
|
||||
@Injectable()
|
||||
export class PicsurThrottlerGuard extends ThrottlerGuard {
|
||||
protected override throwThrottlingException(): void {
|
||||
protected override throwThrottlingException(): Promise<void> {
|
||||
throw Fail(FT.RateLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export class ImageConverterService {
|
||||
if (HasFailed(memLimit) || HasFailed(timeLimit)) {
|
||||
return Fail(FT.Internal, 'Failed to get conversion limits');
|
||||
}
|
||||
let timeLimitMS = ms(timeLimit as any);
|
||||
let timeLimitMS = ms(timeLimit as string);
|
||||
if (isNaN(timeLimitMS) || timeLimitMS === 0) timeLimitMS = 15 * 1000; // 15 seconds
|
||||
|
||||
const sharpWrapper = new SharpWrapper(timeLimitMS, memLimit);
|
||||
|
||||
@@ -49,7 +49,7 @@ export class ImageManagerModule implements OnModuleInit {
|
||||
return;
|
||||
}
|
||||
|
||||
let after_ms = ms(remove_derivatives_after as any);
|
||||
let after_ms = ms(remove_derivatives_after as string);
|
||||
if (isNaN(after_ms) || after_ms === 0) {
|
||||
this.logger.log('remove_derivatives_after is 0, skipping cron');
|
||||
return;
|
||||
@@ -59,6 +59,7 @@ export class ImageManagerModule implements OnModuleInit {
|
||||
const result = await this.imageFileDB.cleanupDerivatives(after_ms / 1000);
|
||||
if (HasFailed(result)) {
|
||||
result.print(this.logger);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result > 0) this.logger.log(`Cleaned up ${result} derivatives`);
|
||||
|
||||
@@ -242,9 +242,8 @@ export class ImageManagerService {
|
||||
// Util stuff ==================================================================
|
||||
|
||||
private async getFileTypeFromBuffer(image: Buffer): AsyncFailable<FileType> {
|
||||
const filetypeResult: FileTypeResult | undefined = await fileTypeFromBuffer(
|
||||
image,
|
||||
);
|
||||
const filetypeResult: FileTypeResult | undefined =
|
||||
await fileTypeFromBuffer(image);
|
||||
|
||||
let mime: string | undefined;
|
||||
if (filetypeResult === undefined) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
ApiKeyCreateResponse,
|
||||
ApiKeyDeleteRequest,
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { ApiKeyDbService } from '../../../collections/apikey-db/apikey-db.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import {
|
||||
HasPermission,
|
||||
RequiredPermissions,
|
||||
@@ -54,7 +54,7 @@ export class ApiKeysController {
|
||||
|
||||
@Post('create')
|
||||
@Returns(ApiKeyCreateResponse)
|
||||
@Throttle(10)
|
||||
@EasyThrottle(10)
|
||||
async createApiKey(
|
||||
@ReqUserID() userID: string,
|
||||
): Promise<ApiKeyCreateResponse> {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Body, Controller, Get, Logger, Param, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
GetPreferenceResponse,
|
||||
MultiplePreferencesResponse,
|
||||
@@ -8,6 +7,7 @@ import {
|
||||
} from 'picsur-shared/dist/dto/api/pref.dto';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { SysPreferenceDbService } from '../../../collections/preference-db/sys-preference-db.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
import { Permission } from '../../../models/constants/permissions.const';
|
||||
@@ -21,7 +21,7 @@ export class SysPrefController {
|
||||
|
||||
@Get()
|
||||
@Returns(MultiplePreferencesResponse)
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async getAllSysPrefs(): Promise<MultiplePreferencesResponse> {
|
||||
const prefs = ThrowIfFailed(await this.prefService.getAllPreferences());
|
||||
|
||||
@@ -41,7 +41,7 @@ export class SysPrefController {
|
||||
|
||||
@Post(':key')
|
||||
@Returns(UpdatePreferenceResponse)
|
||||
@Throttle(30)
|
||||
@EasyThrottle(30)
|
||||
async setSysPref(
|
||||
@Param('key') key: string,
|
||||
@Body() body: UpdatePreferenceRequest,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Body, Controller, Get, Logger, Param, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
GetPreferenceResponse,
|
||||
MultiplePreferencesResponse,
|
||||
@@ -8,6 +7,7 @@ import {
|
||||
} from 'picsur-shared/dist/dto/api/pref.dto';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { UsrPreferenceDbService } from '../../../collections/preference-db/usr-preference-db.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
|
||||
import { ReqUserID } from '../../../decorators/request-user.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
@@ -22,7 +22,7 @@ export class UsrPrefController {
|
||||
|
||||
@Get()
|
||||
@Returns(MultiplePreferencesResponse)
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async getAllUsrPrefs(
|
||||
@ReqUserID() userid: string,
|
||||
): Promise<MultiplePreferencesResponse> {
|
||||
@@ -51,7 +51,7 @@ export class UsrPrefController {
|
||||
|
||||
@Post(':key')
|
||||
@Returns(UpdatePreferenceResponse)
|
||||
@Throttle(30)
|
||||
@EasyThrottle(30)
|
||||
async setUsrPref(
|
||||
@Param('key') key: string,
|
||||
@ReqUserID() userid: string,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
RoleCreateRequest,
|
||||
RoleCreateResponse,
|
||||
@@ -12,9 +11,10 @@ import {
|
||||
RoleUpdateResponse,
|
||||
SpecialRolesResponse,
|
||||
} from 'picsur-shared/dist/dto/api/roles.dto';
|
||||
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { FT, Fail, ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { RoleDbService } from '../../../collections/role-db/role-db.service';
|
||||
import { UserDbService } from '../../../collections/user-db/user-db.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
import { Permission } from '../../../models/constants/permissions.const';
|
||||
@@ -57,7 +57,7 @@ export class RolesController {
|
||||
|
||||
@Post('update')
|
||||
@Returns(RoleUpdateResponse)
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async updateRole(
|
||||
@Body() body: RoleUpdateRequest,
|
||||
): Promise<RoleUpdateResponse> {
|
||||
@@ -75,7 +75,7 @@ export class RolesController {
|
||||
|
||||
@Post('create')
|
||||
@Returns(RoleCreateResponse)
|
||||
@Throttle(10)
|
||||
@EasyThrottle(10)
|
||||
async createRole(
|
||||
@Body() role: RoleCreateRequest,
|
||||
): Promise<RoleCreateResponse> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Controller, Logger, Post, Req, Res } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { Fail, FT, ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { FT, Fail, ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { UsageConfigService } from '../../../config/late/usage.config.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import { NoPermissions } from '../../../decorators/permissions.decorator';
|
||||
import { ReturnsAnything } from '../../../decorators/returns.decorator';
|
||||
|
||||
@@ -15,7 +15,7 @@ export class UsageController {
|
||||
|
||||
@Post(['report', 'report/*'])
|
||||
@ReturnsAnything()
|
||||
@Throttle(120)
|
||||
@EasyThrottle(120)
|
||||
async deleteRole(
|
||||
@Req() req: FastifyRequest,
|
||||
@Res({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
GetSpecialUsersResponse,
|
||||
UserCreateRequest,
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
} from 'picsur-shared/dist/dto/api/user-manage.dto';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { UserDbService } from '../../../collections/user-db/user-db.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
|
||||
import { Returns } from '../../../decorators/returns.decorator';
|
||||
import { Permission } from '../../../models/constants/permissions.const';
|
||||
@@ -47,7 +47,7 @@ export class UserAdminController {
|
||||
|
||||
@Post('create')
|
||||
@Returns(UserCreateResponse)
|
||||
@Throttle(10)
|
||||
@EasyThrottle(10)
|
||||
async register(
|
||||
@Body() create: UserCreateRequest,
|
||||
): Promise<UserCreateResponse> {
|
||||
@@ -80,7 +80,7 @@ export class UserAdminController {
|
||||
|
||||
@Post('update')
|
||||
@Returns(UserUpdateResponse)
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async setPermissions(
|
||||
@Body() body: UserUpdateRequest,
|
||||
): Promise<UserUpdateResponse> {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Body, Controller, Get, Logger, Post } from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import {
|
||||
UserCheckNameRequest,
|
||||
UserCheckNameResponse,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
import type { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
import { ThrowIfFailed } from 'picsur-shared/dist/types/failable';
|
||||
import { UserDbService } from '../../../collections/user-db/user-db.service';
|
||||
import { EasyThrottle } from '../../../decorators/easy-throttle.decorator';
|
||||
import {
|
||||
NoPermissions,
|
||||
RequiredPermissions,
|
||||
@@ -35,7 +35,7 @@ export class UserController {
|
||||
@Post('login')
|
||||
@Returns(UserLoginResponse)
|
||||
@UseLocalAuth(Permission.UserLogin)
|
||||
@Throttle(30, 300)
|
||||
@EasyThrottle(30, 300)
|
||||
async login(@ReqUser() user: EUser): Promise<UserLoginResponse> {
|
||||
const jwt_token = ThrowIfFailed(await this.authService.createToken(user));
|
||||
|
||||
@@ -45,7 +45,7 @@ export class UserController {
|
||||
@Post('register')
|
||||
@Returns(UserRegisterResponse)
|
||||
@RequiredPermissions(Permission.UserRegister)
|
||||
@Throttle(5, 300)
|
||||
@EasyThrottle(5, 300)
|
||||
async register(
|
||||
@Body() register: UserRegisterRequest,
|
||||
): Promise<UserRegisterResponse> {
|
||||
@@ -59,7 +59,7 @@ export class UserController {
|
||||
@Post('checkname')
|
||||
@Returns(UserCheckNameResponse)
|
||||
@RequiredPermissions(Permission.UserRegister)
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async checkName(
|
||||
@Body() checkName: UserCheckNameRequest,
|
||||
): Promise<UserCheckNameResponse> {
|
||||
@@ -71,7 +71,7 @@ export class UserController {
|
||||
@Get('me')
|
||||
@Returns(UserMeResponse)
|
||||
@RequiredPermissions(Permission.UserKeepLogin)
|
||||
@Throttle(10)
|
||||
@EasyThrottle(10)
|
||||
async me(@ReqUserID() userid: string): Promise<UserMeResponse> {
|
||||
const backenduser = ThrowIfFailed(await this.usersService.findOne(userid));
|
||||
|
||||
@@ -86,7 +86,7 @@ export class UserController {
|
||||
@Get('me/permissions')
|
||||
@Returns(UserMePermissionsResponse)
|
||||
@NoPermissions()
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async refresh(
|
||||
@ReqUserID() userid: string,
|
||||
): Promise<UserMePermissionsResponse> {
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
Post,
|
||||
Res,
|
||||
} from '@nestjs/common';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import type { FastifyReply } from 'fastify';
|
||||
import {
|
||||
ImageDeleteRequest,
|
||||
@@ -22,11 +21,12 @@ import {
|
||||
} from 'picsur-shared/dist/dto/api/image-manage.dto';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||
import {
|
||||
Fail,
|
||||
FT,
|
||||
Fail,
|
||||
HasFailed,
|
||||
ThrowIfFailed,
|
||||
} from 'picsur-shared/dist/types/failable';
|
||||
import { EasyThrottle } from '../../decorators/easy-throttle.decorator';
|
||||
import { PostFiles } from '../../decorators/multipart/multipart.decorator';
|
||||
import type { FileIterator } from '../../decorators/multipart/postfiles.pipe';
|
||||
import {
|
||||
@@ -37,6 +37,7 @@ import { ReqUserID } from '../../decorators/request-user.decorator';
|
||||
import { Returns } from '../../decorators/returns.decorator';
|
||||
import { ImageManagerService } from '../../managers/image/image.service';
|
||||
import { GetNextAsync } from '../../util/iterator';
|
||||
|
||||
@Controller('api/image')
|
||||
@RequiredPermissions(Permission.ImageUpload)
|
||||
export class ImageManageController {
|
||||
@@ -46,7 +47,7 @@ export class ImageManageController {
|
||||
|
||||
@Post('upload')
|
||||
@Returns(ImageUploadResponse)
|
||||
@Throttle(20)
|
||||
@EasyThrottle(20)
|
||||
async uploadImage(
|
||||
@PostFiles(1) multipart: FileIterator,
|
||||
@ReqUserID() userid: string,
|
||||
|
||||
@@ -21,9 +21,6 @@ export const HelmetOptions: FastifyHelmetOptions = {
|
||||
// Destroy reference to global object on new page
|
||||
crossOriginOpenerPolicy: true,
|
||||
crossOriginResourcePolicy: true,
|
||||
// Dont fully understand the purpose of this
|
||||
// But pretty sure we dont need it
|
||||
expectCt: false,
|
||||
// Do not send referrer header
|
||||
referrerPolicy: true,
|
||||
// Ensure browser doesnt connect with HTTP
|
||||
|
||||
@@ -124,7 +124,7 @@ async function bmpSharpOut(sharpImage: Sharp): Promise<SharpResult> {
|
||||
const encoded = BMPencode(raw.data, {
|
||||
width: raw.info.width,
|
||||
height: raw.info.height,
|
||||
channels: raw.info.channels,
|
||||
channels: raw.info.channels as 3 | 4,
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -141,7 +141,7 @@ async function qoiSharpOut(sharpImage: Sharp): Promise<SharpResult> {
|
||||
const encoded = QOIencode(raw.data, {
|
||||
width: raw.info.width,
|
||||
height: raw.info.height,
|
||||
channels: raw.info.channels,
|
||||
channels: raw.info.channels as 3 | 4,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
"ngx-auto-unsubscribe-decorator",
|
||||
"moment",
|
||||
"platform",
|
||||
"form-data"
|
||||
"form-data",
|
||||
"ms"
|
||||
],
|
||||
"optimization": true,
|
||||
"webWorkerTsConfig": "tsconfig.worker.json",
|
||||
|
||||
@@ -14,40 +14,40 @@
|
||||
"purge": "rm -rf dist && rm -rf node_modules && rm -rf .angular"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-builders/custom-webpack": "^16.0.0",
|
||||
"@angular-devkit/build-angular": "^16.1.0",
|
||||
"@angular/animations": "^16.1.1",
|
||||
"@angular/cdk": "^16.1.1",
|
||||
"@angular/cli": "^16.1.0",
|
||||
"@angular/common": "^16.1.1",
|
||||
"@angular/compiler": "^16.1.1",
|
||||
"@angular/compiler-cli": "^16.1.1",
|
||||
"@angular/core": "^16.1.1",
|
||||
"@angular/forms": "^16.1.1",
|
||||
"@angular/material": "^16.1.1",
|
||||
"@angular/platform-browser": "^16.1.1",
|
||||
"@angular/platform-browser-dynamic": "^16.1.1",
|
||||
"@angular/router": "^16.1.1",
|
||||
"@babel/cli": "^7.22.5",
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@fontsource/roboto": "^5.0.3",
|
||||
"@ng-web-apis/common": "^2.1.0",
|
||||
"@ng-web-apis/resize-observer": "^2.0.0",
|
||||
"@angular-builders/custom-webpack": "^17.0.0",
|
||||
"@angular-devkit/build-angular": "^17.0.3",
|
||||
"@angular/animations": "^17.0.4",
|
||||
"@angular/cdk": "^17.0.1",
|
||||
"@angular/cli": "^17.0.3",
|
||||
"@angular/common": "^17.0.4",
|
||||
"@angular/compiler": "^17.0.4",
|
||||
"@angular/compiler-cli": "^17.0.4",
|
||||
"@angular/core": "^17.0.4",
|
||||
"@angular/forms": "^17.0.4",
|
||||
"@angular/material": "^17.0.1",
|
||||
"@angular/platform-browser": "^17.0.4",
|
||||
"@angular/platform-browser-dynamic": "^17.0.4",
|
||||
"@angular/router": "^17.0.4",
|
||||
"@babel/cli": "^7.23.4",
|
||||
"@babel/core": "^7.23.3",
|
||||
"@babel/preset-env": "^7.23.3",
|
||||
"@fontsource/roboto": "^5.0.8",
|
||||
"@ng-web-apis/common": "^3.0.6",
|
||||
"@ng-web-apis/resize-observer": "^3.0.6",
|
||||
"@ngui/common": "^1.0.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@types/ackee-tracker": "^5.0.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/resize-observer-browser": "^0.1.7",
|
||||
"@types/validator": "^13.7.17",
|
||||
"@types/ackee-tracker": "^5.0.4",
|
||||
"@types/node": "^20.10.0",
|
||||
"@types/resize-observer-browser": "^0.1.11",
|
||||
"@types/validator": "^13.11.7",
|
||||
"ackee-tracker": "^5.1.0",
|
||||
"axios": "^1.4.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"bootstrap": "^5.3.0",
|
||||
"browserslist": "^4.21.8",
|
||||
"caniuse-lite": "^1.0.30001503",
|
||||
"fuse.js": "^6.6.2",
|
||||
"material-icons": "^1.13.8",
|
||||
"axios": "^1.6.2",
|
||||
"babel-loader": "^9.1.3",
|
||||
"bootstrap": "^5.3.2",
|
||||
"browserslist": "^4.22.1",
|
||||
"caniuse-lite": "^1.0.30001565",
|
||||
"fuse.js": "^7.0.0",
|
||||
"material-icons": "^1.13.12",
|
||||
"moment": "^2.29.4",
|
||||
"ng-mat-select-infinite-scroll": "^4.0.0",
|
||||
"ngx-auto-unsubscribe-decorator": "^1.1.0",
|
||||
@@ -56,11 +56,11 @@
|
||||
"picsur-shared": "*",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
"tslib": "^2.5.3",
|
||||
"typescript": "^5.1.3",
|
||||
"webpack-bundle-analyzer": "^4.9.0",
|
||||
"zod": "^3.21.4",
|
||||
"zone.js": "^0.13.1"
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.3.2",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"zod": "^3.22.4",
|
||||
"zone.js": "^0.14.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@leteu/jwt-decoder": "^1.0.4"
|
||||
|
||||
@@ -52,8 +52,10 @@ mat-toolbar {
|
||||
/* Make sure the toolbar will stay on top of the content as it scrolls past. */
|
||||
z-index: 2;
|
||||
|
||||
box-shadow: 0px 2px 5px -3px rgba(0, 0, 0, 0.2),
|
||||
0px 5px 8px 0px rgba(0, 0, 0, 0.14), 0px 1px 14px 0px rgba(0, 0, 0, 0.12);
|
||||
box-shadow:
|
||||
0px 2px 5px -3px rgba(0, 0, 0, 0.2),
|
||||
0px 5px 8px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 14px 0px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.loading-bar {
|
||||
|
||||
@@ -80,12 +80,12 @@ export class PrefOptionComponent implements OnInit {
|
||||
this.pref.type === 'string'
|
||||
? `Updated ${this.name}`
|
||||
: this.pref.type === 'number'
|
||||
? `Updated ${this.name}`
|
||||
: this.pref.type === 'boolean'
|
||||
? value
|
||||
? `Enabled ${this.name}`
|
||||
: `Disabled ${this.name}`
|
||||
: '';
|
||||
? `Updated ${this.name}`
|
||||
: this.pref.type === 'boolean'
|
||||
? value
|
||||
? `Enabled ${this.name}`
|
||||
: `Disabled ${this.name}`
|
||||
: '';
|
||||
this.errorService.success(message);
|
||||
} else {
|
||||
this.errorService.showFailure(result, this.logger);
|
||||
|
||||
@@ -29,18 +29,18 @@ export class InfoService {
|
||||
return this.infoSubject.value;
|
||||
}
|
||||
|
||||
private infoSubject: BehaviorSubject<ServerInfo>;
|
||||
constructor(
|
||||
@Inject(LOCATION) private readonly location: Location,
|
||||
private readonly api: ApiService,
|
||||
private readonly infoStorage: InfoStorageService,
|
||||
) {
|
||||
this.updateInfo().catch((e) => this.logger.warn(e));
|
||||
this.infoSubject = new BehaviorSubject<ServerInfo>(
|
||||
this.infoStorage?.get() ?? new ServerInfo(),
|
||||
);
|
||||
}
|
||||
|
||||
private infoSubject = new BehaviorSubject<ServerInfo>(
|
||||
this.infoStorage?.get() ?? new ServerInfo(),
|
||||
);
|
||||
|
||||
public async getLoadedSnapshot(): Promise<ServerInfo> {
|
||||
if (this.isLoaded()) {
|
||||
return this.snapshot;
|
||||
|
||||
@@ -60,16 +60,16 @@ export class BootstrapService {
|
||||
const size = xxxl
|
||||
? BSScreenSize.xxxl
|
||||
: xxl
|
||||
? BSScreenSize.xxl
|
||||
: xl
|
||||
? BSScreenSize.xl
|
||||
: lg
|
||||
? BSScreenSize.lg
|
||||
: md
|
||||
? BSScreenSize.md
|
||||
: sm
|
||||
? BSScreenSize.sm
|
||||
: BSScreenSize.xs;
|
||||
? BSScreenSize.xxl
|
||||
: xl
|
||||
? BSScreenSize.xl
|
||||
: lg
|
||||
? BSScreenSize.lg
|
||||
: md
|
||||
? BSScreenSize.md
|
||||
: sm
|
||||
? BSScreenSize.sm
|
||||
: BSScreenSize.xs;
|
||||
|
||||
this.screenSizeSubject.next(size);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
18
package.json
18
package.json
@@ -23,22 +23,22 @@
|
||||
"terser": ">=5.14.2",
|
||||
"typeorm": ">=0.3.9",
|
||||
"jsonwebtoken": ">=9.0.0",
|
||||
"typescript": "~4.9.5",
|
||||
"typescript": "~5.2.0",
|
||||
"webpack": ">=5.76.0",
|
||||
"fastify-static": "npm:@fastify/static@*",
|
||||
"fastify-formbody": "npm:@fastify/formbody@*",
|
||||
"minimist": "npm:minimist-lite@*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||
"@typescript-eslint/parser": "^5.59.11",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
||||
"@typescript-eslint/parser": "^6.13.1",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-plugin-require-extensions": "^0.1.3",
|
||||
"ms": "3.0.0-canary.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-sh": "^0.12.8"
|
||||
"ms": "2.1.3",
|
||||
"prettier": "^3.1.0",
|
||||
"prettier-plugin-sh": "^0.13.1"
|
||||
},
|
||||
"packageManager": "yarn@3.2.2"
|
||||
}
|
||||
|
||||
@@ -14,12 +14,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": "2.1.3",
|
||||
"zod": "^3.21.4"
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/ms": "^0.7.34",
|
||||
"@types/node": "^20.10.0",
|
||||
"tsc-watch": "^6.0.4",
|
||||
"typescript": "^5.1.3"
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf ./dist",
|
||||
|
||||
@@ -2,24 +2,24 @@ import { z } from 'zod';
|
||||
import { EImageSchema } from '../../entities/image.entity';
|
||||
import { EUserSchema } from '../../entities/user.entity';
|
||||
import { createZodDto } from '../../util/create-zod-dto';
|
||||
import { ParseBool, ParseInt } from '../../util/parse-simple';
|
||||
import { ParseBoolZ, ParseIntZ } from '../../util/parse-simple';
|
||||
import { ImageEntryVariant } from '../image-entry-variant.enum';
|
||||
|
||||
export const ImageRequestParamsSchema = z
|
||||
.object({
|
||||
height: z.preprocess(ParseInt, z.number().int().min(1).max(32767)),
|
||||
width: z.preprocess(ParseInt, z.number().int().min(1).max(32767)),
|
||||
height: z.preprocess(ParseIntZ, z.number().int().min(1).max(32767)),
|
||||
width: z.preprocess(ParseIntZ, z.number().int().min(1).max(32767)),
|
||||
rotate: z.preprocess(
|
||||
ParseInt,
|
||||
ParseIntZ,
|
||||
z.number().int().multipleOf(90).min(0).max(360),
|
||||
),
|
||||
flipx: z.preprocess(ParseBool, z.boolean()),
|
||||
flipy: z.preprocess(ParseBool, z.boolean()),
|
||||
greyscale: z.preprocess(ParseBool, z.boolean()),
|
||||
noalpha: z.preprocess(ParseBool, z.boolean()),
|
||||
negative: z.preprocess(ParseBool, z.boolean()),
|
||||
shrinkonly: z.preprocess(ParseBool, z.boolean()),
|
||||
quality: z.preprocess(ParseInt, z.number().int().min(1).max(100)),
|
||||
flipx: z.preprocess(ParseBoolZ, z.boolean()),
|
||||
flipy: z.preprocess(ParseBoolZ, z.boolean()),
|
||||
greyscale: z.preprocess(ParseBoolZ, z.boolean()),
|
||||
noalpha: z.preprocess(ParseBoolZ, z.boolean()),
|
||||
negative: z.preprocess(ParseBoolZ, z.boolean()),
|
||||
shrinkonly: z.preprocess(ParseBoolZ, z.boolean()),
|
||||
quality: z.preprocess(ParseIntZ, z.number().int().min(1).max(100)),
|
||||
})
|
||||
.partial();
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ export const ParseBool = <T extends boolean | null = null>(
|
||||
return fallback === undefined ? (null as T) : fallback;
|
||||
};
|
||||
|
||||
export const ParseBoolZ = (value: unknown): boolean | null => {
|
||||
return ParseBool(value, null);
|
||||
};
|
||||
|
||||
export const ParseInt = <T extends number | null = null>(
|
||||
value: unknown,
|
||||
fallback?: T,
|
||||
@@ -23,8 +27,12 @@ export const ParseInt = <T extends number | null = null>(
|
||||
return fallback === undefined
|
||||
? (null as T)
|
||||
: fallback === null
|
||||
? fallback
|
||||
: Math.round(fallback);
|
||||
? fallback
|
||||
: Math.round(fallback);
|
||||
};
|
||||
|
||||
export const ParseIntZ = (value: unknown): number | null => {
|
||||
return ParseInt(value, null);
|
||||
};
|
||||
|
||||
export const ParseString = <T extends string | null = null>(
|
||||
@@ -36,3 +44,7 @@ export const ParseString = <T extends string | null = null>(
|
||||
if (typeof value === 'number') return value.toString();
|
||||
return fallback === undefined ? (null as T) : fallback;
|
||||
};
|
||||
|
||||
export const ParseStringZ = (value: unknown): string | null => {
|
||||
return ParseString(value, null);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user