mirror of
https://github.com/usatiuk/photos.git
synced 2025-10-28 15:27:49 +01:00
more type safety with zod
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.idea/
|
.idea/
|
||||||
node_modules/
|
/node_modules
|
||||||
build/
|
build/
|
||||||
tmp/
|
tmp/
|
||||||
temp/
|
temp/
|
||||||
|
|||||||
39
backend/package-lock.json
generated
39
backend/package-lock.json
generated
@@ -15,7 +15,6 @@
|
|||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"exifreader": "^4.13.0",
|
"exifreader": "^4.13.0",
|
||||||
"hasha": "^5.2.2",
|
"hasha": "^5.2.2",
|
||||||
"io-ts": "^2.2.20",
|
|
||||||
"jsonwebtoken": "^9.0.1",
|
"jsonwebtoken": "^9.0.1",
|
||||||
"koa": "^2.14.2",
|
"koa": "^2.14.2",
|
||||||
"koa-body": "^5.0.0",
|
"koa-body": "^5.0.0",
|
||||||
@@ -2951,12 +2950,6 @@
|
|||||||
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fp-ts": {
|
|
||||||
"version": "2.16.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz",
|
|
||||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/fresh": {
|
"node_modules/fresh": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
@@ -3602,14 +3595,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/io-ts": {
|
|
||||||
"version": "2.2.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
|
||||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"fp-ts": "^2.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
||||||
@@ -4514,9 +4499,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/make-dir/node_modules/semver": {
|
"node_modules/make-dir/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -9572,12 +9557,6 @@
|
|||||||
"qs": "^6.11.0"
|
"qs": "^6.11.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fp-ts": {
|
|
||||||
"version": "2.16.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz",
|
|
||||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"fresh": {
|
"fresh": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
@@ -10027,12 +10006,6 @@
|
|||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"io-ts": {
|
|
||||||
"version": "2.2.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
|
||||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
|
||||||
"requires": {}
|
|
||||||
},
|
|
||||||
"is-array-buffer": {
|
"is-array-buffer": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
|
||||||
@@ -10694,9 +10667,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"exifreader": "^4.13.0",
|
"exifreader": "^4.13.0",
|
||||||
"hasha": "^5.2.2",
|
"hasha": "^5.2.2",
|
||||||
"io-ts": "^2.2.20",
|
|
||||||
"jsonwebtoken": "^9.0.1",
|
"jsonwebtoken": "^9.0.1",
|
||||||
"koa": "^2.14.2",
|
"koa": "^2.14.2",
|
||||||
"koa-body": "^5.0.0",
|
"koa-body": "^5.0.0",
|
||||||
@@ -48,12 +47,12 @@
|
|||||||
"@types/hasha": "^3.0.1",
|
"@types/hasha": "^3.0.1",
|
||||||
"@types/jsonwebtoken": "^9.0.2",
|
"@types/jsonwebtoken": "^9.0.2",
|
||||||
"@types/koa": "^2.13.7",
|
"@types/koa": "^2.13.7",
|
||||||
|
"@types/koa__cors": "^4.0.0",
|
||||||
|
"@types/koa__router": "^12.0.0",
|
||||||
"@types/koa-logger": "^3.1.2",
|
"@types/koa-logger": "^3.1.2",
|
||||||
"@types/koa-send": "^4.1.3",
|
"@types/koa-send": "^4.1.3",
|
||||||
"@types/koa-sslify": "^4.0.3",
|
"@types/koa-sslify": "^4.0.3",
|
||||||
"@types/koa-static": "^4.0.2",
|
"@types/koa-static": "^4.0.2",
|
||||||
"@types/koa__cors": "^4.0.0",
|
|
||||||
"@types/koa__router": "^12.0.0",
|
|
||||||
"@types/mime-types": "^2.1.1",
|
"@types/mime-types": "^2.1.1",
|
||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/mysql": "^2.15.21",
|
"@types/mysql": "^2.15.21",
|
||||||
@@ -85,4 +84,4 @@
|
|||||||
"pre-commit": "npm run lint-all && npm run prettier-check"
|
"pre-commit": "npm run lint-all && npm run prettier-check"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,15 @@ import { config, EnvType } from "~config";
|
|||||||
import { userRouter } from "~routes/users";
|
import { userRouter } from "~routes/users";
|
||||||
import { devRouter } from "~routes/dev";
|
import { devRouter } from "~routes/dev";
|
||||||
import { photosRouter } from "~routes/photos";
|
import { photosRouter } from "~routes/photos";
|
||||||
|
import { TUserJWT } from "~shared/types";
|
||||||
|
|
||||||
export const app = new Koa();
|
export interface IAppState extends Koa.DefaultState {
|
||||||
|
user?: TUserJWT;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAppContext extends Koa.DefaultContext {}
|
||||||
|
|
||||||
|
export const app = new Koa<IAppState, IAppContext>();
|
||||||
|
|
||||||
const tmpPath = path.join(config.dataDir, "tmp");
|
const tmpPath = path.join(config.dataDir, "tmp");
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as path from "path";
|
|||||||
import * as fs from "fs/promises";
|
import * as fs from "fs/promises";
|
||||||
import * as mime from "mime-types";
|
import * as mime from "mime-types";
|
||||||
import * as jwt from "jsonwebtoken";
|
import * as jwt from "jsonwebtoken";
|
||||||
import { IPhotoReqJSON, IPhotoJSON } from "~/shared/types";
|
import { TPhotoReqJSON, TPhotoJSON } from "~/shared/types";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BaseEntity,
|
BaseEntity,
|
||||||
@@ -212,7 +212,7 @@ export class Photo extends BaseEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async toJSON(): Promise<IPhotoJSON> {
|
public async toJSON(): Promise<TPhotoJSON> {
|
||||||
if (!isNumber(this.user.id)) {
|
if (!isNumber(this.user.id)) {
|
||||||
throw new Error("User not loaded");
|
throw new Error("User not loaded");
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ export class Photo extends BaseEntity {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async toReqJSON(): Promise<IPhotoReqJSON> {
|
public async toReqJSON(): Promise<TPhotoReqJSON> {
|
||||||
const token = await this.getJWTToken();
|
const token = await this.getJWTToken();
|
||||||
return { ...(await this.toJSON()), accessToken: token };
|
return { ...(await this.toJSON()), accessToken: token };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as bcrypt from "bcrypt";
|
|||||||
import * as jwt from "jsonwebtoken";
|
import * as jwt from "jsonwebtoken";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as fs from "fs/promises";
|
import * as fs from "fs/promises";
|
||||||
import { IUserJSON, IUserAuthJSON } from "~/shared/types";
|
import { TUserJSON, TUserAuthJSON } from "~/shared/types";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AfterInsert,
|
AfterInsert,
|
||||||
@@ -83,12 +83,12 @@ export class User extends BaseEntity {
|
|||||||
return validateOrReject(this);
|
return validateOrReject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public toJSON(): IUserJSON {
|
public toJSON(): TUserJSON {
|
||||||
const { id, username, isAdmin } = this;
|
const { id, username, isAdmin } = this;
|
||||||
return { id, username, isAdmin };
|
return { id, username, isAdmin };
|
||||||
}
|
}
|
||||||
|
|
||||||
public toAuthJSON(): IUserAuthJSON {
|
public toAuthJSON(): TUserAuthJSON {
|
||||||
const json = this.toJSON();
|
const json = this.toJSON();
|
||||||
return { ...json, jwt: this.toJWT() };
|
return { ...json, jwt: this.toJWT() };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import * as Router from "@koa/router";
|
import * as Router from "@koa/router";
|
||||||
import { Photo } from "~entity/Photo";
|
import { Photo } from "~entity/Photo";
|
||||||
import { User } from "~entity/User";
|
import { User } from "~entity/User";
|
||||||
|
import { IAppContext, IAppState } from "~app";
|
||||||
|
|
||||||
export const devRouter = new Router();
|
export const devRouter = new Router<IAppState, IAppContext>();
|
||||||
|
|
||||||
devRouter.get("/dev/clean", async (ctx) => {
|
type ContextType = Parameters<Parameters<(typeof devRouter)["post"]>["2"]>["0"];
|
||||||
|
|
||||||
|
devRouter.get("/dev/clean", async (ctx: ContextType) => {
|
||||||
await Photo.remove(await Photo.find());
|
await Photo.remove(await Photo.find());
|
||||||
await User.remove(await User.find());
|
await User.remove(await User.find());
|
||||||
ctx.body = { success: true };
|
ctx.body = { success: true };
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import * as Router from "@koa/router";
|
import * as Router from "@koa/router";
|
||||||
import { Photo } from "~entity/Photo";
|
import { Photo } from "~entity/Photo";
|
||||||
import {
|
import {
|
||||||
IPhotoReqJSON,
|
TPhotoReqJSON,
|
||||||
IPhotosNewRespBody,
|
TPhotosNewRespBody,
|
||||||
IPhotosNewPostBody,
|
TPhotoByIDDeleteRespBody,
|
||||||
IPhotoByIDDeleteRespBody,
|
TPhotosUploadRespBody,
|
||||||
IPhotosUploadRespBody,
|
TPhotosListRespBody,
|
||||||
IPhotosListRespBody,
|
TPhotosByIDGetRespBody,
|
||||||
IPhotosByIDGetRespBody,
|
TPhotosDeleteRespBody,
|
||||||
IPhotosDeleteRespBody,
|
PhotosListPagination,
|
||||||
IPhotosDeleteBody,
|
PhotosNewPostBody,
|
||||||
IPhotosGetShowTokenByID,
|
PhotoJSON,
|
||||||
IPhotoShowToken,
|
TPhotosGetShowTokenByIDRespBody,
|
||||||
IAPIResponse,
|
PhotosDeleteBody,
|
||||||
IPhotosListPagination,
|
|
||||||
} from "~/shared/types";
|
} from "~/shared/types";
|
||||||
import send = require("koa-send");
|
import send = require("koa-send");
|
||||||
import { getHash, getSize } from "~util";
|
import { getHash, getSize } from "~util";
|
||||||
@@ -21,24 +20,25 @@ import * as jwt from "jsonwebtoken";
|
|||||||
import { config } from "~config";
|
import { config } from "~config";
|
||||||
import { ValidationError } from "class-validator";
|
import { ValidationError } from "class-validator";
|
||||||
import { In } from "typeorm";
|
import { In } from "typeorm";
|
||||||
|
import { IAppContext, IAppState } from "~app";
|
||||||
|
|
||||||
export const photosRouter = new Router();
|
export const photosRouter = new Router<IAppState, IAppContext>();
|
||||||
|
|
||||||
photosRouter.post("/photos/new", async (ctx) => {
|
// Typescript requires explicit type annotations for CFA......
|
||||||
|
type ContextType = Parameters<
|
||||||
|
Parameters<(typeof photosRouter)["post"]>["2"]
|
||||||
|
>["0"];
|
||||||
|
|
||||||
|
photosRouter.post("/photos/new", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
const body = ctx.request.body as IPhotosNewPostBody;
|
const body = PhotosNewPostBody.parse(ctx.request.body);
|
||||||
const { hash, size, format } = body;
|
const { hash, size, format } = body;
|
||||||
|
|
||||||
if (!(hash && size && format)) {
|
const photo = Photo.create({ user, hash, size, format });
|
||||||
ctx.throw(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const photo = new Photo(user, hash, size, format);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await photo.save();
|
await photo.save();
|
||||||
@@ -47,13 +47,12 @@ photosRouter.post("/photos/new", async (ctx) => {
|
|||||||
const photo = await Photo.findOne({ hash, size, user });
|
const photo = await Photo.findOne({ hash, size, user });
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: await photo.toReqJSON(),
|
data: await photo.toReqJSON(),
|
||||||
} as IPhotosNewRespBody;
|
} as TPhotosNewRespBody;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -61,7 +60,6 @@ photosRouter.post("/photos/new", async (ctx) => {
|
|||||||
(Array.isArray(e) && e.some((e) => e instanceof ValidationError))
|
(Array.isArray(e) && e.some((e) => e instanceof ValidationError))
|
||||||
) {
|
) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
console.log(e);
|
console.log(e);
|
||||||
ctx.throw(500);
|
ctx.throw(500);
|
||||||
@@ -70,10 +68,10 @@ photosRouter.post("/photos/new", async (ctx) => {
|
|||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: await photo.toReqJSON(),
|
data: await photo.toReqJSON(),
|
||||||
} as IPhotosNewRespBody;
|
} as TPhotosNewRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.post("/photos/upload/:id", async (ctx) => {
|
photosRouter.post("/photos/upload/:id", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
@@ -84,32 +82,28 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
const photo = await Photo.findOne({ id: parseInt(id), user });
|
const photo = await Photo.findOne({ id: parseInt(id), user });
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.request.files || Object.keys(ctx.request.files).length === 0) {
|
if (!ctx.request.files || Object.keys(ctx.request.files).length === 0) {
|
||||||
ctx.throw(400, "No file");
|
ctx.throw(400, "No file");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (photo.uploaded) {
|
if (photo.uploaded) {
|
||||||
ctx.throw(400, "Already uploaded");
|
ctx.throw(400, "Already uploaded");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.request.files) {
|
if (ctx.request.files) {
|
||||||
const files = ctx.request.files;
|
const files = ctx.request.files;
|
||||||
if (Object.keys(files).length > 1) {
|
if (Object.keys(files).length > 1) {
|
||||||
ctx.throw(400, "Too many files");
|
ctx.throw(400, "Too many files");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = Object.values(files)[0];
|
const file = Object.values(files)[0];
|
||||||
if (Array.isArray(file)) {
|
if (Array.isArray(file)) {
|
||||||
throw "more than one file uploaded";
|
throw "more than one file uploaded";
|
||||||
@@ -120,7 +114,6 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (photoHash !== photo.hash || photoSize !== photo.size) {
|
if (photoHash !== photo.hash || photoSize !== photo.size) {
|
||||||
ctx.throw(400, "Wrong photo");
|
ctx.throw(400, "Wrong photo");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -134,14 +127,14 @@ photosRouter.post("/photos/upload/:id", async (ctx) => {
|
|||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: await photo.toReqJSON(),
|
data: await photo.toReqJSON(),
|
||||||
} as IPhotosUploadRespBody;
|
} as TPhotosUploadRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
export interface IPhotosByIDPatchBody {
|
export interface TPhotosByIDPatchBody {
|
||||||
}
|
}
|
||||||
export type IPhotosByIDPatchRespBody = IAPIResponse<IPhotoReqJSON>;
|
export type TPhotosByIDPatchRespBody = IAPIResponse<TPhotoReqJSON>;
|
||||||
photosRouter.patch("/photos/byID/:id", async (ctx) => {
|
photosRouter.patch("/photos/byID/:id", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
return;
|
return;
|
||||||
@@ -180,7 +173,7 @@ photosRouter.patch("/photos/byID/:id", async (ctx) => {
|
|||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
photosRouter.get("/photos/list", async (ctx) => {
|
photosRouter.get("/photos/list", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
@@ -200,8 +193,8 @@ photosRouter.get("/photos/list", async (ctx) => {
|
|||||||
skip = parseInt(skip);
|
skip = parseInt(skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!num || num > IPhotosListPagination) {
|
if (!num || num > PhotosListPagination) {
|
||||||
num = IPhotosListPagination;
|
num = PhotosListPagination;
|
||||||
}
|
}
|
||||||
|
|
||||||
const photos = await Photo.find({
|
const photos = await Photo.find({
|
||||||
@@ -211,17 +204,17 @@ photosRouter.get("/photos/list", async (ctx) => {
|
|||||||
order: { shotAt: "DESC" },
|
order: { shotAt: "DESC" },
|
||||||
});
|
});
|
||||||
|
|
||||||
const photosList: IPhotoReqJSON[] = await Promise.all(
|
const photosList: TPhotoReqJSON[] = await Promise.all(
|
||||||
photos.map(async (photo) => await photo.toReqJSON()),
|
photos.map(async (photo) => await photo.toReqJSON()),
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: photosList,
|
data: photosList,
|
||||||
} as IPhotosListRespBody;
|
} as TPhotosListRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.get("/photos/byID/:id", async (ctx) => {
|
photosRouter.get("/photos/byID/:id", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
@@ -232,7 +225,6 @@ photosRouter.get("/photos/byID/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
@@ -241,16 +233,15 @@ photosRouter.get("/photos/byID/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: await photo.toReqJSON(),
|
data: await photo.toReqJSON(),
|
||||||
} as IPhotosByIDGetRespBody;
|
} as TPhotosByIDGetRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
photosRouter.get("/photos/showByID/:id/:token", async (ctx: ContextType) => {
|
||||||
const { id, token } = ctx.params as {
|
const { id, token } = ctx.params as {
|
||||||
id: string | undefined;
|
id: string | undefined;
|
||||||
token: string | undefined;
|
token: string | undefined;
|
||||||
@@ -258,7 +249,6 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
|||||||
|
|
||||||
if (!(id && token)) {
|
if (!(id && token)) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -267,7 +257,7 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
|||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const photoReqJSON = jwt.decode(token) as IPhotoReqJSON;
|
const photoReqJSON = PhotoJSON.parse(jwt.decode(token));
|
||||||
const { user } = photoReqJSON;
|
const { user } = photoReqJSON;
|
||||||
|
|
||||||
const photo = await Photo.findOne({
|
const photo = await Photo.findOne({
|
||||||
@@ -277,7 +267,6 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
|||||||
|
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -292,7 +281,7 @@ photosRouter.get("/photos/showByID/:id/:token", async (ctx) => {
|
|||||||
await send(ctx, await photo.getReadyPath("original"));
|
await send(ctx, await photo.getReadyPath("original"));
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
photosRouter.get("/photos/showByID/:id", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
@@ -303,7 +292,6 @@ photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
@@ -312,7 +300,6 @@ photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -327,7 +314,7 @@ photosRouter.get("/photos/showByID/:id", async (ctx) => {
|
|||||||
await send(ctx, await photo.getReadyPath("original"));
|
await send(ctx, await photo.getReadyPath("original"));
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
photosRouter.get("/photos/getShowByIDToken/:id", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
@@ -338,7 +325,6 @@ photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
@@ -346,15 +332,14 @@ photosRouter.get("/photos/getShowByIDToken/:id", async (ctx) => {
|
|||||||
const photo = await Photo.findOne({ id: parseInt(id), user });
|
const photo = await Photo.findOne({ id: parseInt(id), user });
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = await photo.getJWTToken();
|
const token = await photo.getJWTToken();
|
||||||
|
|
||||||
ctx.body = { error: false, data: token } as IPhotosGetShowTokenByID;
|
ctx.body = { error: false, data: token } as TPhotosGetShowTokenByIDRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
photosRouter.delete("/photos/byID/:id", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
@@ -365,7 +350,6 @@ photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
@@ -374,7 +358,6 @@ photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
|||||||
|
|
||||||
if (!photo) {
|
if (!photo) {
|
||||||
ctx.throw(404);
|
ctx.throw(404);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await photo.remove();
|
await photo.remove();
|
||||||
@@ -382,22 +365,17 @@ photosRouter.delete("/photos/byID/:id", async (ctx) => {
|
|||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: true,
|
data: true,
|
||||||
} as IPhotoByIDDeleteRespBody;
|
} as TPhotoByIDDeleteRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
photosRouter.post("/photos/delete", async (ctx) => {
|
photosRouter.post("/photos/delete", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = ctx.request.body as IPhotosDeleteBody;
|
const body = PhotosDeleteBody.parse(ctx.request.body);
|
||||||
const { photos } = body;
|
const { photos } = body;
|
||||||
|
|
||||||
if (!photos || !Array.isArray(photos) || photos.length == 0) {
|
|
||||||
ctx.throw(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { user } = ctx.state;
|
const { user } = ctx.state;
|
||||||
try {
|
try {
|
||||||
await Photo.delete({
|
await Photo.delete({
|
||||||
@@ -408,11 +386,11 @@ photosRouter.post("/photos/delete", async (ctx) => {
|
|||||||
ctx.body = {
|
ctx.body = {
|
||||||
error: false,
|
error: false,
|
||||||
data: true,
|
data: true,
|
||||||
} as IPhotosDeleteRespBody;
|
} as TPhotosDeleteRespBody;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
data: null,
|
data: null,
|
||||||
error: "Internal server error",
|
error: "Internal server error",
|
||||||
} as IPhotosDeleteRespBody;
|
} as TPhotosDeleteRespBody;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,70 +2,65 @@ import * as Router from "@koa/router";
|
|||||||
import { getConfigValue, ConfigKey } from "~entity/Config";
|
import { getConfigValue, ConfigKey } from "~entity/Config";
|
||||||
import { User } from "~entity/User";
|
import { User } from "~entity/User";
|
||||||
import {
|
import {
|
||||||
IUserJWT,
|
TUserJWT,
|
||||||
IUserGetRespBody,
|
TUserGetRespBody,
|
||||||
IUserEditRespBody,
|
TUserEditRespBody,
|
||||||
IUserSignupBody,
|
TUserSignupBody,
|
||||||
IUserSignupRespBody,
|
TUserSignupRespBody,
|
||||||
IUserLoginRespBody,
|
TUserLoginRespBody,
|
||||||
IUserEditBody,
|
TUserEditBody,
|
||||||
IUserLoginBody,
|
TUserLoginBody,
|
||||||
|
UserLoginBody,
|
||||||
|
UserSignupBody,
|
||||||
|
UserEditBody,
|
||||||
} from "~/shared/types";
|
} from "~/shared/types";
|
||||||
|
import { IAppContext, IAppState } from "~app";
|
||||||
|
|
||||||
export const userRouter = new Router();
|
export const userRouter = new Router<IAppState, IAppContext>();
|
||||||
|
|
||||||
userRouter.get("/users/user", async (ctx) => {
|
type ContextType = Parameters<
|
||||||
|
Parameters<(typeof userRouter)["post"]>["2"]
|
||||||
|
>["0"];
|
||||||
|
|
||||||
|
userRouter.get("/users/user", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const jwt = ctx.state.user as IUserJWT;
|
const jwt = ctx.state.user;
|
||||||
|
|
||||||
const user = await User.findOne(jwt.id);
|
const user = await User.findOne(jwt.id);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserGetRespBody;
|
ctx.body = { error: false, data: user.toAuthJSON() } as TUserGetRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
userRouter.post("/users/login", async (ctx) => {
|
userRouter.post("/users/login", async (ctx: ContextType) => {
|
||||||
const request = ctx.request;
|
const request = ctx.request;
|
||||||
|
|
||||||
if (!request.body) {
|
if (!request.body) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
}
|
}
|
||||||
const { username, password } = request.body as IUserLoginBody;
|
const { username, password } = UserLoginBody.parse(request.body);
|
||||||
|
|
||||||
if (!(username && password)) {
|
|
||||||
ctx.throw(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = await User.findOne({ username });
|
const user = await User.findOne({ username });
|
||||||
if (!user || !(await user.verifyPassword(password))) {
|
if (!user || !(await user.verifyPassword(password))) {
|
||||||
ctx.throw(404, "User not found");
|
ctx.throw(404, "User not found");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserLoginRespBody;
|
ctx.body = { error: false, data: user.toAuthJSON() } as TUserLoginRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
userRouter.post("/users/signup", async (ctx) => {
|
userRouter.post("/users/signup", async (ctx: ContextType) => {
|
||||||
const request = ctx.request;
|
const request = ctx.request;
|
||||||
|
|
||||||
if (!request.body) {
|
if (!request.body) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { username, password, email } = request.body as IUserSignupBody;
|
const { username, password, email } = UserSignupBody.parse(request.body);
|
||||||
|
|
||||||
if (!(username && password && email)) {
|
|
||||||
ctx.throw(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = new User(username, email);
|
const user = new User(username, email);
|
||||||
const users = await User.find();
|
const users = await User.find();
|
||||||
@@ -91,33 +86,30 @@ userRouter.post("/users/signup", async (ctx) => {
|
|||||||
ctx.throw(500);
|
ctx.throw(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserSignupRespBody;
|
ctx.body = { error: false, data: user.toAuthJSON() } as TUserSignupRespBody;
|
||||||
});
|
});
|
||||||
|
|
||||||
userRouter.post("/users/edit", async (ctx) => {
|
userRouter.post("/users/edit", async (ctx: ContextType) => {
|
||||||
if (!ctx.state.user) {
|
if (!ctx.state.user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const jwt = ctx.state.user as IUserJWT;
|
const jwt = ctx.state.user;
|
||||||
const user = await User.findOne(jwt.id);
|
const user = await User.findOne(jwt.id);
|
||||||
const request = ctx.request;
|
const request = ctx.request;
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
ctx.throw(401);
|
ctx.throw(401);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request.body) {
|
if (!request.body) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { password } = request.body as IUserEditBody;
|
const { password } = UserEditBody.parse(request.body);
|
||||||
|
|
||||||
if (!password) {
|
if (!password) {
|
||||||
ctx.throw(400);
|
ctx.throw(400);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await user.setPassword(password);
|
await user.setPassword(password);
|
||||||
@@ -129,5 +121,5 @@ userRouter.post("/users/edit", async (ctx) => {
|
|||||||
ctx.throw(500);
|
ctx.throw(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = { error: false, data: user.toAuthJSON() } as IUserEditRespBody;
|
ctx.body = { error: false, data: user.toAuthJSON() } as TUserEditRespBody;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import * as request from "supertest";
|
|||||||
import { getConnection } from "typeorm";
|
import { getConnection } from "typeorm";
|
||||||
import { app } from "~app";
|
import { app } from "~app";
|
||||||
import { Photo } from "~entity/Photo";
|
import { Photo } from "~entity/Photo";
|
||||||
import { IPhotoReqJSON ,
|
import {
|
||||||
IPhotosDeleteBody,
|
TPhotoReqJSON,
|
||||||
IPhotosListRespBody,
|
TPhotosDeleteBody,
|
||||||
IPhotosNewPostBody,
|
TPhotosListRespBody,
|
||||||
|
TPhotosNewPostBody,
|
||||||
} from "~shared/types";
|
} from "~shared/types";
|
||||||
import * as fs from "fs/promises";
|
import * as fs from "fs/promises";
|
||||||
import { constants as fsConstants } from "fs";
|
import { constants as fsConstants } from "fs";
|
||||||
@@ -60,7 +61,7 @@ describe("photos", function () {
|
|||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
const usedPhoto = await seed.dogPhoto.toReqJSON();
|
const usedPhoto = await seed.dogPhoto.toReqJSON();
|
||||||
|
|
||||||
@@ -85,9 +86,7 @@ describe("photos", function () {
|
|||||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(parseInt(response.header["content-length"])).to.equal(
|
expect(parseInt(response.get("content-length"))).to.equal(dogFileSize);
|
||||||
dogFileSize,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should delete a photo after file has been deleted", async function () {
|
it("should delete a photo after file has been deleted", async function () {
|
||||||
@@ -97,12 +96,10 @@ describe("photos", function () {
|
|||||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(parseInt(response.header["content-length"])).to.equal(
|
expect(parseInt(response.get("content-length"))).to.equal(dogFileSize);
|
||||||
dogFileSize,
|
|
||||||
);
|
|
||||||
|
|
||||||
await fs.unlink(await seed.dogPhoto.getReadyPath("original"));
|
await fs.unlink(await seed.dogPhoto.getReadyPath("original"));
|
||||||
const response2 = await request(callback)
|
await request(callback)
|
||||||
.get(`/photos/showByID/${seed.dogPhoto.id}`)
|
.get(`/photos/showByID/${seed.dogPhoto.id}`)
|
||||||
.set({
|
.set({
|
||||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||||
@@ -122,13 +119,13 @@ describe("photos", function () {
|
|||||||
const dogSmallThumbSize = (
|
const dogSmallThumbSize = (
|
||||||
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
||||||
).size;
|
).size;
|
||||||
expect(parseInt(response.header["content-length"])).to.equal(
|
expect(parseInt(response.get("content-length"))).to.equal(
|
||||||
dogSmallThumbSize,
|
dogSmallThumbSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
await fs.unlink(await seed.dogPhoto.getReadyPath("512"));
|
await fs.unlink(await seed.dogPhoto.getReadyPath("512"));
|
||||||
await fs.unlink(await seed.dogPhoto.getReadyPath("original"));
|
await fs.unlink(await seed.dogPhoto.getReadyPath("original"));
|
||||||
const response2 = await request(callback)
|
await request(callback)
|
||||||
.get(`/photos/showByID/${seed.dogPhoto.id}?size=512`)
|
.get(`/photos/showByID/${seed.dogPhoto.id}?size=512`)
|
||||||
.set({
|
.set({
|
||||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||||
@@ -146,7 +143,7 @@ describe("photos", function () {
|
|||||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(parseInt(response.header["content-length"])).to.be.lessThan(
|
expect(parseInt(response.get("content-length"))).to.be.lessThan(
|
||||||
dogFileSize,
|
dogFileSize,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -161,12 +158,12 @@ describe("photos", function () {
|
|||||||
const dogSmallThumbSize = (
|
const dogSmallThumbSize = (
|
||||||
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
||||||
).size;
|
).size;
|
||||||
expect(parseInt(response.header["content-length"])).to.equal(
|
expect(parseInt(response.get("content-length"))).to.equal(
|
||||||
dogSmallThumbSize,
|
dogSmallThumbSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
await fs.unlink(seed.dogPhoto.getThumbPath("512"));
|
await fs.unlink(seed.dogPhoto.getThumbPath("512"));
|
||||||
const response2 = await request(callback)
|
await request(callback)
|
||||||
.get(`/photos/showByID/${seed.dogPhoto.id}?size=512`)
|
.get(`/photos/showByID/${seed.dogPhoto.id}?size=512`)
|
||||||
.set({
|
.set({
|
||||||
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
Authorization: `Bearer ${seed.user2.toJWT()}`,
|
||||||
@@ -175,7 +172,7 @@ describe("photos", function () {
|
|||||||
const dogSmallThumbSize2 = (
|
const dogSmallThumbSize2 = (
|
||||||
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
await fs.stat(seed.dogPhoto.getThumbPath("512"))
|
||||||
).size;
|
).size;
|
||||||
expect(parseInt(response.header["content-length"])).to.equal(
|
expect(parseInt(response.get("content-length"))).to.equal(
|
||||||
dogSmallThumbSize2,
|
dogSmallThumbSize2,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -188,7 +185,7 @@ describe("photos", function () {
|
|||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const listRespBody = listResp.body as IPhotosListRespBody;
|
const listRespBody = listResp.body as TPhotosListRespBody;
|
||||||
|
|
||||||
if (listRespBody.error !== false) {
|
if (listRespBody.error !== false) {
|
||||||
expect(listResp.body.error).to.be.false;
|
expect(listResp.body.error).to.be.false;
|
||||||
@@ -201,7 +198,7 @@ describe("photos", function () {
|
|||||||
const listAnyResp = await request(callback)
|
const listAnyResp = await request(callback)
|
||||||
.get(`/photos/showByID/${photos[0].id}/${photos[0].accessToken}`)
|
.get(`/photos/showByID/${photos[0].id}/${photos[0].accessToken}`)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(parseInt(listAnyResp.header["content-length"])).to.be.oneOf([
|
expect(parseInt(listAnyResp.get("content-length"))).to.be.oneOf([
|
||||||
dogFileSize,
|
dogFileSize,
|
||||||
catFileSize,
|
catFileSize,
|
||||||
]);
|
]);
|
||||||
@@ -219,9 +216,7 @@ describe("photos", function () {
|
|||||||
const response = await request(callback)
|
const response = await request(callback)
|
||||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(parseInt(response.header["content-length"])).to.equal(
|
expect(parseInt(response.get("content-length"))).to.equal(dogFileSize);
|
||||||
dogFileSize,
|
|
||||||
);
|
|
||||||
|
|
||||||
const tokenSelfSigned = jwt.sign(
|
const tokenSelfSigned = jwt.sign(
|
||||||
await seed.dogPhoto.toReqJSON(),
|
await seed.dogPhoto.toReqJSON(),
|
||||||
@@ -234,7 +229,7 @@ describe("photos", function () {
|
|||||||
const responseSS = await request(callback)
|
const responseSS = await request(callback)
|
||||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${tokenSelfSigned}`)
|
.get(`/photos/showByID/${seed.dogPhoto.id}/${tokenSelfSigned}`)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(parseInt(responseSS.header["content-length"])).to.equal(
|
expect(parseInt(responseSS.get("content-length"))).to.equal(
|
||||||
dogFileSize,
|
dogFileSize,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -248,7 +243,7 @@ describe("photos", function () {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const response = await request(callback)
|
await request(callback)
|
||||||
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
.get(`/photos/showByID/${seed.dogPhoto.id}/${token}`)
|
||||||
.expect(401);
|
.expect(401);
|
||||||
});
|
});
|
||||||
@@ -275,17 +270,17 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.hash).to.be.equal(dogHash);
|
expect(photo.hash).to.be.equal(dogHash);
|
||||||
const dbPhoto = await Photo.findOneOrFail({
|
const dbPhoto = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||||
|
|
||||||
@@ -302,7 +297,7 @@ describe("photos", function () {
|
|||||||
|
|
||||||
const dbPhotoUpl = await Photo.findOneOrFail({
|
const dbPhotoUpl = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhotoUpl.hash).to.be.equal(dogHash);
|
expect(dbPhotoUpl.hash).to.be.equal(dogHash);
|
||||||
expect(await dbPhotoUpl.origFileExists()).to.be.equal(true);
|
expect(await dbPhotoUpl.origFileExists()).to.be.equal(true);
|
||||||
@@ -317,9 +312,7 @@ describe("photos", function () {
|
|||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(parseInt(showResp.header["content-length"])).to.equal(
|
expect(parseInt(showResp.get("content-length"))).to.equal(dogFileSize);
|
||||||
dogFileSize,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create, upload and show a png file", async function () {
|
it("should create, upload and show a png file", async function () {
|
||||||
@@ -333,17 +326,17 @@ describe("photos", function () {
|
|||||||
hash: pngHash,
|
hash: pngHash,
|
||||||
size: pngSize,
|
size: pngSize,
|
||||||
format: pngFormat,
|
format: pngFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.hash).to.be.equal(pngHash);
|
expect(photo.hash).to.be.equal(pngHash);
|
||||||
const dbPhoto = await Photo.findOneOrFail({
|
const dbPhoto = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhoto.hash).to.be.equal(pngHash);
|
expect(dbPhoto.hash).to.be.equal(pngHash);
|
||||||
|
|
||||||
@@ -360,7 +353,7 @@ describe("photos", function () {
|
|||||||
|
|
||||||
const dbPhotoUpl = await Photo.findOneOrFail({
|
const dbPhotoUpl = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhotoUpl.hash).to.be.equal(pngHash);
|
expect(dbPhotoUpl.hash).to.be.equal(pngHash);
|
||||||
expect(dbPhotoUpl.format).to.be.equal(pngFormat);
|
expect(dbPhotoUpl.format).to.be.equal(pngFormat);
|
||||||
@@ -377,9 +370,7 @@ describe("photos", function () {
|
|||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(parseInt(showResp.header["content-length"])).to.equal(
|
expect(parseInt(showResp.get("content-length"))).to.equal(pngFileSize);
|
||||||
pngFileSize,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not create a photo twice", async function () {
|
it("should not create a photo twice", async function () {
|
||||||
@@ -393,12 +384,12 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const response2 = await request(callback)
|
await request(callback)
|
||||||
.post("/photos/new")
|
.post("/photos/new")
|
||||||
.set({
|
.set({
|
||||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||||
@@ -408,7 +399,7 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const dbPhoto = await Photo.find({
|
const dbPhoto = await Photo.find({
|
||||||
@@ -430,17 +421,17 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.hash).to.be.equal(dogHash);
|
expect(photo.hash).to.be.equal(dogHash);
|
||||||
const dbPhoto = await Photo.findOneOrFail({
|
const dbPhoto = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||||
|
|
||||||
@@ -473,9 +464,7 @@ describe("photos", function () {
|
|||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(parseInt(showResp.header["content-length"])).to.equal(
|
expect(parseInt(showResp.get("content-length"))).to.equal(dogFileSize);
|
||||||
dogFileSize,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not upload a wrong photo", async function () {
|
it("should not upload a wrong photo", async function () {
|
||||||
@@ -489,17 +478,17 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.hash).to.be.equal(dogHash);
|
expect(photo.hash).to.be.equal(dogHash);
|
||||||
const dbPhoto = await Photo.findOneOrFail({
|
const dbPhoto = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||||
|
|
||||||
@@ -516,7 +505,7 @@ describe("photos", function () {
|
|||||||
|
|
||||||
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
||||||
|
|
||||||
const showResp = await request(callback)
|
await request(callback)
|
||||||
.get(`/photos/showByID/${photo.id}`)
|
.get(`/photos/showByID/${photo.id}`)
|
||||||
.set({
|
.set({
|
||||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||||
@@ -535,17 +524,17 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.hash).to.be.equal(dogHash);
|
expect(photo.hash).to.be.equal(dogHash);
|
||||||
const dbPhoto = await Photo.findOneOrFail({
|
const dbPhoto = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||||
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
||||||
@@ -573,17 +562,17 @@ describe("photos", function () {
|
|||||||
hash: dogHash,
|
hash: dogHash,
|
||||||
size: dogSize,
|
size: dogSize,
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.hash).to.be.equal(dogHash);
|
expect(photo.hash).to.be.equal(dogHash);
|
||||||
const dbPhoto = await Photo.findOneOrFail({
|
const dbPhoto = await Photo.findOneOrFail({
|
||||||
id: photo.id,
|
id: photo.id,
|
||||||
user: seed.user1.id as any,
|
user: { id: seed.user1.id },
|
||||||
});
|
});
|
||||||
expect(dbPhoto.hash).to.be.equal(dogHash);
|
expect(dbPhoto.hash).to.be.equal(dogHash);
|
||||||
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
expect(await dbPhoto.origFileExists()).to.be.equal(false);
|
||||||
@@ -608,7 +597,7 @@ describe("photos", function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not create a photo with weird properties", async function () {
|
it("should not create a photo with weird properties", async function () {
|
||||||
const response = await request(callback)
|
await request(callback)
|
||||||
.post("/photos/new")
|
.post("/photos/new")
|
||||||
.set({
|
.set({
|
||||||
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||||
@@ -618,7 +607,7 @@ describe("photos", function () {
|
|||||||
hash: "../test",
|
hash: "../test",
|
||||||
size: "33333",
|
size: "33333",
|
||||||
format: dogFormat,
|
format: dogFormat,
|
||||||
} as IPhotosNewPostBody)
|
} as TPhotosNewPostBody)
|
||||||
.expect(400);
|
.expect(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -635,13 +624,13 @@ describe("photos", function () {
|
|||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
expect(photo.name).to.be.equal("Test1");
|
expect(photo.name).to.be.equal("Test1");
|
||||||
|
|
||||||
const dbPhoto = await Photo.findOne({
|
const dbPhoto = await Photo.findOne({
|
||||||
id: seed.dogPhoto.id,
|
id: seed.dogPhoto.id,
|
||||||
user: seed.user1.id as any,
|
user: {id:seed.user1.id} ,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(dbPhoto.name).to.be.equal("Test1");
|
expect(dbPhoto.name).to.be.equal("Test1");
|
||||||
@@ -662,7 +651,7 @@ describe("photos", function () {
|
|||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photos = response.body.data as IPhotoReqJSON[];
|
const photos = response.body.data as TPhotoReqJSON[];
|
||||||
const userPhotos = [
|
const userPhotos = [
|
||||||
await seed.dogPhoto.toReqJSON(),
|
await seed.dogPhoto.toReqJSON(),
|
||||||
await seed.catPhoto.toReqJSON(),
|
await seed.catPhoto.toReqJSON(),
|
||||||
@@ -685,7 +674,7 @@ describe("photos", function () {
|
|||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
const photo = response.body.data as IPhotoReqJSON;
|
const photo = response.body.data as TPhotoReqJSON;
|
||||||
|
|
||||||
const usedPhoto = seed.catPhoto.toReqJSON();
|
const usedPhoto = seed.catPhoto.toReqJSON();
|
||||||
|
|
||||||
@@ -704,7 +693,7 @@ describe("photos", function () {
|
|||||||
})
|
})
|
||||||
.send({
|
.send({
|
||||||
photos: [await seed.dogPhoto.toReqJSON()],
|
photos: [await seed.dogPhoto.toReqJSON()],
|
||||||
} as IPhotosDeleteBody)
|
} as TPhotosDeleteBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
@@ -736,7 +725,7 @@ describe("photos", function () {
|
|||||||
await seed.dogPhoto.toReqJSON(),
|
await seed.dogPhoto.toReqJSON(),
|
||||||
await seed.catPhoto.toReqJSON(),
|
await seed.catPhoto.toReqJSON(),
|
||||||
],
|
],
|
||||||
} as IPhotosDeleteBody)
|
} as TPhotosDeleteBody)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body.error).to.be.false;
|
expect(response.body.error).to.be.false;
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import { getConnection } from "typeorm";
|
|||||||
import { app } from "~app";
|
import { app } from "~app";
|
||||||
import { User } from "~entity/User";
|
import { User } from "~entity/User";
|
||||||
import {
|
import {
|
||||||
IUserEditBody,
|
TUserEditBody,
|
||||||
IUserEditRespBody,
|
TUserEditRespBody,
|
||||||
IUserGetRespBody,
|
TUserGetRespBody,
|
||||||
IUserLoginBody,
|
TUserLoginBody,
|
||||||
IUserLoginRespBody,
|
TUserLoginRespBody,
|
||||||
IUserSignupBody,
|
TUserSignupBody,
|
||||||
IUserSignupRespBody,
|
TUserSignupRespBody,
|
||||||
} from "~shared/types";
|
} from "~shared/types";
|
||||||
|
|
||||||
import { allowSignups, ISeed, seedDB } from "./util";
|
import { allowSignups, ISeed, seedDB } from "./util";
|
||||||
@@ -43,13 +43,13 @@ describe("users", function () {
|
|||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body = response.body as IUserGetRespBody;
|
const body = response.body as TUserGetRespBody;
|
||||||
|
|
||||||
if (body.error !== false) {
|
if (body.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: _, ...user } = body.data;
|
const { jwt: _, ...user } = body.data;
|
||||||
|
|
||||||
expect(user).to.deep.equal(seed.user1.toJSON());
|
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||||
@@ -59,17 +59,17 @@ describe("users", function () {
|
|||||||
const response = await request(callback)
|
const response = await request(callback)
|
||||||
.post("/users/login")
|
.post("/users/login")
|
||||||
.set({ "Content-Type": "application/json" })
|
.set({ "Content-Type": "application/json" })
|
||||||
.send({ username: "User1", password: "User1" } as IUserLoginBody)
|
.send({ username: "User1", password: "User1" } as TUserLoginBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body = response.body as IUserLoginRespBody;
|
const body = response.body as TUserLoginRespBody;
|
||||||
|
|
||||||
if (body.error !== false) {
|
if (body.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: _, ...user } = response.body.data;
|
const { jwt: _, ...user } = response.body.data;
|
||||||
expect(user).to.deep.equal(seed.user1.toJSON());
|
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||||
});
|
});
|
||||||
@@ -78,10 +78,10 @@ describe("users", function () {
|
|||||||
const response = await request(callback)
|
const response = await request(callback)
|
||||||
.post("/users/login")
|
.post("/users/login")
|
||||||
.set({ "Content-Type": "application/json" })
|
.set({ "Content-Type": "application/json" })
|
||||||
.send({ username: "User1", password: "asdf" } as IUserLoginBody)
|
.send({ username: "User1", password: "asdf" } as TUserLoginBody)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
|
|
||||||
const body = response.body as IUserLoginRespBody;
|
const body = response.body as TUserLoginRespBody;
|
||||||
expect(body.error).to.be.equal("User not found");
|
expect(body.error).to.be.equal("User not found");
|
||||||
expect(body.data).to.be.false;
|
expect(body.data).to.be.false;
|
||||||
});
|
});
|
||||||
@@ -96,17 +96,17 @@ describe("users", function () {
|
|||||||
username: "NUser1",
|
username: "NUser1",
|
||||||
password: "NUser1",
|
password: "NUser1",
|
||||||
email: "nuser1@users.com",
|
email: "nuser1@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body = response.body as IUserSignupRespBody;
|
const body = response.body as TUserSignupRespBody;
|
||||||
|
|
||||||
if (body.error !== false) {
|
if (body.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: _, ...user } = body.data;
|
const { jwt: _, ...user } = body.data;
|
||||||
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||||
expect(user).to.deep.equal(newUser.toJSON());
|
expect(user).to.deep.equal(newUser.toJSON());
|
||||||
@@ -120,11 +120,11 @@ describe("users", function () {
|
|||||||
username: "NUser1",
|
username: "NUser1",
|
||||||
password: "NUser1",
|
password: "NUser1",
|
||||||
email: "nuser1@users.com",
|
email: "nuser1@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(400);
|
.expect(400);
|
||||||
|
|
||||||
const body = response.body as IUserSignupRespBody;
|
const body = response.body as TUserSignupRespBody;
|
||||||
|
|
||||||
expect(body.error).to.be.equal("Signups not allowed");
|
expect(body.error).to.be.equal("Signups not allowed");
|
||||||
expect(body.data).to.be.false;
|
expect(body.data).to.be.false;
|
||||||
@@ -140,17 +140,17 @@ describe("users", function () {
|
|||||||
username: "NUser1",
|
username: "NUser1",
|
||||||
password: "NUser1",
|
password: "NUser1",
|
||||||
email: "nuser1@users.com",
|
email: "nuser1@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body = response.body as IUserSignupRespBody;
|
const body = response.body as TUserSignupRespBody;
|
||||||
|
|
||||||
if (body.error !== false) {
|
if (body.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: _, ...user } = body.data;
|
const { jwt: _, ...user } = body.data;
|
||||||
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||||
expect(user).to.deep.equal(newUser.toJSON());
|
expect(user).to.deep.equal(newUser.toJSON());
|
||||||
@@ -163,11 +163,11 @@ describe("users", function () {
|
|||||||
username: "NUser2",
|
username: "NUser2",
|
||||||
password: "NUser2",
|
password: "NUser2",
|
||||||
email: "nuser2@users.com",
|
email: "nuser2@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(400);
|
.expect(400);
|
||||||
|
|
||||||
const body2 = response2.body as IUserSignupRespBody;
|
const body2 = response2.body as TUserSignupRespBody;
|
||||||
|
|
||||||
expect(body2.error).to.be.equal("Signups not allowed");
|
expect(body2.error).to.be.equal("Signups not allowed");
|
||||||
expect(body2.data).to.be.false;
|
expect(body2.data).to.be.false;
|
||||||
@@ -184,17 +184,17 @@ describe("users", function () {
|
|||||||
username: "NUser1",
|
username: "NUser1",
|
||||||
password: "NUser1",
|
password: "NUser1",
|
||||||
email: "nuser1@users.com",
|
email: "nuser1@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body = response.body as IUserSignupRespBody;
|
const body = response.body as TUserSignupRespBody;
|
||||||
|
|
||||||
if (body.error !== false) {
|
if (body.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: jwt1, ...user } = body.data;
|
const { jwt: jwt1, ...user } = body.data;
|
||||||
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||||
expect(user).to.deep.equal(newUser.toJSON());
|
expect(user).to.deep.equal(newUser.toJSON());
|
||||||
@@ -207,17 +207,17 @@ describe("users", function () {
|
|||||||
username: "NUser2",
|
username: "NUser2",
|
||||||
password: "NUser2",
|
password: "NUser2",
|
||||||
email: "nuser2@users.com",
|
email: "nuser2@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body2 = response2.body as IUserSignupRespBody;
|
const body2 = response2.body as TUserSignupRespBody;
|
||||||
|
|
||||||
if (body2.error !== false) {
|
if (body2.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: jwt2, ...user2 } = body2.data;
|
const { jwt: jwt2, ...user2 } = body2.data;
|
||||||
const newUser2 = await User.findOneOrFail({ username: "NUser2" });
|
const newUser2 = await User.findOneOrFail({ username: "NUser2" });
|
||||||
expect(user2).to.deep.equal(newUser2.toJSON());
|
expect(user2).to.deep.equal(newUser2.toJSON());
|
||||||
@@ -234,10 +234,10 @@ describe("users", function () {
|
|||||||
username: "User1",
|
username: "User1",
|
||||||
password: "NUser1",
|
password: "NUser1",
|
||||||
email: "user1@users.com",
|
email: "user1@users.com",
|
||||||
} as IUserSignupBody)
|
} as TUserSignupBody)
|
||||||
.expect(400);
|
.expect(400);
|
||||||
|
|
||||||
const body = response.body as IUserSignupRespBody;
|
const body = response.body as TUserSignupRespBody;
|
||||||
|
|
||||||
expect(body.error).to.be.equal("User already exists");
|
expect(body.error).to.be.equal("User already exists");
|
||||||
expect(body.data).to.be.false;
|
expect(body.data).to.be.false;
|
||||||
@@ -252,15 +252,14 @@ describe("users", function () {
|
|||||||
})
|
})
|
||||||
.send({
|
.send({
|
||||||
password: "User1NewPass",
|
password: "User1NewPass",
|
||||||
} as IUserEditBody)
|
} as TUserEditBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const body = response.body as IUserEditRespBody;
|
const body = response.body as TUserEditRespBody;
|
||||||
|
|
||||||
if (body.error !== false) {
|
if (body.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const loginResponse = await request(callback)
|
const loginResponse = await request(callback)
|
||||||
@@ -269,27 +268,27 @@ describe("users", function () {
|
|||||||
.send({
|
.send({
|
||||||
username: "User1",
|
username: "User1",
|
||||||
password: "User1NewPass",
|
password: "User1NewPass",
|
||||||
} as IUserLoginBody)
|
} as TUserLoginBody)
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
const loginBody = loginResponse.body as IUserLoginRespBody;
|
const loginBody = loginResponse.body as TUserLoginRespBody;
|
||||||
|
|
||||||
if (loginBody.error !== false) {
|
if (loginBody.error !== false) {
|
||||||
assert(false);
|
assert(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { jwt: _, ...user } = loginBody.data;
|
const { jwt: _, ...user } = loginBody.data;
|
||||||
expect(user).to.deep.equal(seed.user1.toJSON());
|
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||||
|
|
||||||
const badLoginResponse = await request(callback)
|
const badLoginResponse = await request(callback)
|
||||||
.post("/users/login")
|
.post("/users/login")
|
||||||
.set({ "Content-Type": "application/json" })
|
.set({ "Content-Type": "application/json" })
|
||||||
.send({ username: "User1", password: "User1" } as IUserLoginBody)
|
.send({ username: "User1", password: "User1" } as TUserLoginBody)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
|
|
||||||
const badLoginBody = badLoginResponse.body as IUserLoginRespBody;
|
const badLoginBody = badLoginResponse.body as TUserLoginRespBody;
|
||||||
|
|
||||||
expect(badLoginBody.error).to.be.equal("User not found");
|
expect(badLoginBody.error).to.be.equal("User not found");
|
||||||
expect(badLoginBody.data).to.be.false;
|
expect(badLoginBody.data).to.be.false;
|
||||||
|
|||||||
@@ -24,8 +24,5 @@
|
|||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.ts",
|
"./src/**/*.ts",
|
||||||
"./tests/**/*.ts",
|
"./tests/**/*.ts",
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"frontend"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
99
frontend/package-lock.json
generated
99
frontend/package-lock.json
generated
@@ -26,7 +26,6 @@
|
|||||||
"eslint-plugin-react": "^7.33.0",
|
"eslint-plugin-react": "^7.33.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"flush-promises": "^1.0.2",
|
"flush-promises": "^1.0.2",
|
||||||
"io-ts": "^2.2.20",
|
|
||||||
"jest": "^29.6.2",
|
"jest": "^29.6.2",
|
||||||
"jest-environment-jsdom": "^29.6.2",
|
"jest-environment-jsdom": "^29.6.2",
|
||||||
"jest-junit": "^14.0.1",
|
"jest-junit": "^14.0.1",
|
||||||
@@ -140,9 +139,9 @@
|
|||||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core/node_modules/semver": {
|
"node_modules/@babel/core/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -180,9 +179,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -5963,9 +5962,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
|
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -6372,12 +6371,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fp-ts": {
|
|
||||||
"version": "2.16.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz",
|
|
||||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@@ -6962,14 +6955,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/io-ts": {
|
|
||||||
"version": "2.2.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
|
||||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"fp-ts": "^2.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
@@ -7387,9 +7372,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/istanbul-lib-instrument/node_modules/semver": {
|
"node_modules/istanbul-lib-instrument/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -10820,9 +10805,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tough-cookie": {
|
"node_modules/tough-cookie": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"psl": "^1.1.33",
|
"psl": "^1.1.33",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
@@ -11351,9 +11336,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/word-wrap": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
|
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -11540,9 +11525,9 @@
|
|||||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -11570,9 +11555,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -15526,9 +15511,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -15810,12 +15795,6 @@
|
|||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"fp-ts": {
|
|
||||||
"version": "2.16.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz",
|
|
||||||
"integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==",
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
@@ -16204,12 +16183,6 @@
|
|||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"io-ts": {
|
|
||||||
"version": "2.2.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz",
|
|
||||||
"integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==",
|
|
||||||
"requires": {}
|
|
||||||
},
|
|
||||||
"is-arguments": {
|
"is-arguments": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
@@ -16479,9 +16452,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -18916,9 +18889,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||||
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
|
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"psl": "^1.1.33",
|
"psl": "^1.1.33",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
@@ -19292,9 +19265,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"word-wrap": {
|
"word-wrap": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="
|
||||||
},
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
"eslint-plugin-react": "^7.33.0",
|
"eslint-plugin-react": "^7.33.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"flush-promises": "^1.0.2",
|
"flush-promises": "^1.0.2",
|
||||||
"io-ts": "^2.2.20",
|
|
||||||
"jest": "^29.6.2",
|
"jest": "^29.6.2",
|
||||||
"jest-environment-jsdom": "^29.6.2",
|
"jest-environment-jsdom": "^29.6.2",
|
||||||
"jest-junit": "^14.0.1",
|
"jest-junit": "^14.0.1",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function AccountComponent(props: IAccountComponentProps) {
|
|||||||
return (
|
return (
|
||||||
<Card className="AuthForm" elevation={2}>
|
<Card className="AuthForm" elevation={2}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e: React.FormEvent<any>) => {
|
onSubmit={(e: React.FormEvent<never>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (pass.trim()) {
|
if (pass.trim()) {
|
||||||
props.changePass(pass);
|
props.changePass(pass);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Position, Toaster } from "@blueprintjs/core";
|
import { Position, Toaster } from "@blueprintjs/core";
|
||||||
import { IPhotoReqJSON } from "./shared/types";
|
import { TPhotoReqJSON } from "./shared/types";
|
||||||
|
|
||||||
export const AppToaster = Toaster.create({
|
export const AppToaster = Toaster.create({
|
||||||
className: "recipe-toaster",
|
className: "recipe-toaster",
|
||||||
@@ -43,7 +43,7 @@ export function showPhotoCreateFailToast(f: File, e: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function showPhotoUploadJSONFailToast(
|
export function showPhotoUploadJSONFailToast(
|
||||||
p: IPhotoReqJSON | number,
|
p: TPhotoReqJSON | number,
|
||||||
e: string,
|
e: string,
|
||||||
): void {
|
): void {
|
||||||
const photoMsg = typeof p === "number" ? p : p.hash;
|
const photoMsg = typeof p === "number" ? p : p.hash;
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export class AuthScreenComponent extends React.PureComponent<IAuthScreenProps> {
|
|||||||
}
|
}
|
||||||
public render() {
|
public render() {
|
||||||
const { location } = this.props.history;
|
const { location } = this.props.history;
|
||||||
const { from } = (this.props.location.state as any) || { from: "/" };
|
const { from } = (this.props.location.state as { from: string }) || {
|
||||||
|
from: "/",
|
||||||
|
};
|
||||||
const { loggedIn } = this.props;
|
const { loggedIn } = this.props;
|
||||||
return loggedIn ? (
|
return loggedIn ? (
|
||||||
<Redirect to={from} />
|
<Redirect to={from} />
|
||||||
@@ -46,7 +48,7 @@ export class AuthScreenComponent extends React.PureComponent<IAuthScreenProps> {
|
|||||||
transform: "translate3d(400px,0,0)",
|
transform: "translate3d(400px,0,0)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(_location: any) => (style: any) => (
|
{(_location) => (style) => (
|
||||||
<animated.div style={style}>
|
<animated.div style={style}>
|
||||||
<Switch location={_location}>
|
<Switch location={_location}>
|
||||||
<Route path="/login" component={Login} />
|
<Route path="/login" component={Login} />
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class LoginComponent extends React.PureComponent<
|
|||||||
this.props.history.push("/signup");
|
this.props.history.push("/signup");
|
||||||
}
|
}
|
||||||
|
|
||||||
public submit(e: React.FormEvent<any>) {
|
public submit<T extends React.FormEvent>(e: T) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { username, password } = this.state;
|
const { username, password } = this.state;
|
||||||
if (!this.props.inProgress) {
|
if (!this.props.inProgress) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class SignupComponent extends React.PureComponent<
|
|||||||
this.props.history.push("/login");
|
this.props.history.push("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
public submit(e: React.FormEvent<any>) {
|
public submit<T extends React.FormEvent>(e: T) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const { username, password, email } = this.state;
|
const { username, password, email } = this.state;
|
||||||
if (!this.props.inProgress) {
|
if (!this.props.inProgress) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { connect } from "react-redux";
|
|||||||
import { Route, RouteComponentProps, Switch, withRouter } from "react-router";
|
import { Route, RouteComponentProps, Switch, withRouter } from "react-router";
|
||||||
import { animated, config, Transition } from "react-spring/renderprops";
|
import { animated, config, Transition } from "react-spring/renderprops";
|
||||||
import { Dispatch } from "redux";
|
import { Dispatch } from "redux";
|
||||||
import { IUserJSON } from "../shared/types";
|
import { TUserJSON } from "../shared/types";
|
||||||
import { Account } from "../Account/Account";
|
import { Account } from "../Account/Account";
|
||||||
import { Overview } from "../Photos/Overview";
|
import { Overview } from "../Photos/Overview";
|
||||||
import { toggleDarkMode } from "../redux/localSettings/actions";
|
import { toggleDarkMode } from "../redux/localSettings/actions";
|
||||||
@@ -24,7 +24,7 @@ import { PhotoRoute } from "../Photos/PhotoRoute";
|
|||||||
import { UploadStatus } from "./UploadStatus";
|
import { UploadStatus } from "./UploadStatus";
|
||||||
|
|
||||||
export interface IHomeProps extends RouteComponentProps {
|
export interface IHomeProps extends RouteComponentProps {
|
||||||
user: IUserJSON | null;
|
user: TUserJSON | null;
|
||||||
|
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ export class HomeComponent extends React.PureComponent<IHomeProps> {
|
|||||||
transform: "translate3d(400px,0,0)",
|
transform: "translate3d(400px,0,0)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(_location: any) => (style: any) => (
|
{(_location) => (style) => (
|
||||||
<animated.div
|
<animated.div
|
||||||
style={style}
|
style={style}
|
||||||
className="viewComponent"
|
className="viewComponent"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
photosDeleteStart,
|
photosDeleteStart,
|
||||||
photosLoadStart,
|
photosLoadStart,
|
||||||
} from "../redux/photos/actions";
|
} from "../redux/photos/actions";
|
||||||
import { IPhotoReqJSON } from "~/src/shared/types";
|
import { TPhotoReqJSON } from "~/src/shared/types";
|
||||||
import { PhotoCard } from "./PhotoCard";
|
import { PhotoCard } from "./PhotoCard";
|
||||||
import {
|
import {
|
||||||
Alignment,
|
Alignment,
|
||||||
@@ -26,7 +26,7 @@ import { Photo } from "./Photo";
|
|||||||
import { showDeletionToast } from "~/src/AppToaster";
|
import { showDeletionToast } from "~/src/AppToaster";
|
||||||
|
|
||||||
export interface IOverviewComponentProps {
|
export interface IOverviewComponentProps {
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
triedLoading: boolean;
|
triedLoading: boolean;
|
||||||
allPhotosLoaded: boolean;
|
allPhotosLoaded: boolean;
|
||||||
overviewFetching: boolean;
|
overviewFetching: boolean;
|
||||||
@@ -35,8 +35,8 @@ export interface IOverviewComponentProps {
|
|||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
|
|
||||||
fetchPhotos: () => void;
|
fetchPhotos: () => void;
|
||||||
startDeletePhotos: (photos: IPhotoReqJSON[]) => void;
|
startDeletePhotos: (photos: TPhotoReqJSON[]) => void;
|
||||||
cancelDelete: (photos: IPhotoReqJSON[]) => void;
|
cancelDelete: (photos: TPhotoReqJSON[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PhotoCardM = React.memo(PhotoCard);
|
const PhotoCardM = React.memo(PhotoCard);
|
||||||
@@ -80,7 +80,7 @@ export const OverviewComponent: React.FunctionComponent<
|
|||||||
(
|
(
|
||||||
acc: Record<
|
acc: Record<
|
||||||
string,
|
string,
|
||||||
Record<string, Record<string, IPhotoReqJSON[]>>
|
Record<string, Record<string, TPhotoReqJSON[]>>
|
||||||
>,
|
>,
|
||||||
photo,
|
photo,
|
||||||
) => {
|
) => {
|
||||||
@@ -108,7 +108,7 @@ export const OverviewComponent: React.FunctionComponent<
|
|||||||
const els = Object.keys(dates[year]).reduce(
|
const els = Object.keys(dates[year]).reduce(
|
||||||
(accMonths: JSX.Element[], month): JSX.Element[] => {
|
(accMonths: JSX.Element[], month): JSX.Element[] => {
|
||||||
const photos = Object.values(dates[year][month]).reduce(
|
const photos = Object.values(dates[year][month]).reduce(
|
||||||
(accDays: IPhotoReqJSON[], day) => {
|
(accDays: TPhotoReqJSON[], day) => {
|
||||||
return [...day, ...accDays];
|
return [...day, ...accDays];
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
@@ -264,9 +264,9 @@ function mapStateToProps(state: IAppState) {
|
|||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
return {
|
return {
|
||||||
fetchPhotos: () => dispatch(photosLoadStart()),
|
fetchPhotos: () => dispatch(photosLoadStart()),
|
||||||
startDeletePhotos: (photos: IPhotoReqJSON[]) =>
|
startDeletePhotos: (photos: TPhotoReqJSON[]) =>
|
||||||
dispatch(photosDeleteStart(photos)),
|
dispatch(photosDeleteStart(photos)),
|
||||||
cancelDelete: (photos: IPhotoReqJSON[]) =>
|
cancelDelete: (photos: TPhotoReqJSON[]) =>
|
||||||
dispatch(photosDeleteCancel(photos)),
|
dispatch(photosDeleteCancel(photos)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,24 +2,31 @@ import "./Photo.scss";
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Dispatch } from "redux";
|
import { Dispatch } from "redux";
|
||||||
import { IPhotoReqJSON } from "~/src/shared/types";
|
import { TPhotoReqJSON } from "~/src/shared/types";
|
||||||
import { LoadingStub } from "../LoadingStub";
|
import { LoadingStub } from "../LoadingStub";
|
||||||
import { getPhotoImgPath, getPhotoThumbPath } from "../redux/api/photos";
|
import { getPhotoImgPath, getPhotoThumbPath } from "../redux/api/photos";
|
||||||
import { photoLoadStart } from "../redux/photos/actions";
|
import { photoLoadStart } from "../redux/photos/actions";
|
||||||
import { IPhotoState } from "../redux/photos/reducer";
|
import { TPhotoState } from "../redux/photos/reducer";
|
||||||
import { IAppState } from "../redux/reducers";
|
import { IAppState } from "../redux/reducers";
|
||||||
import { LargeSize, PreviewSize } from "./helper";
|
import { LargeSize, PreviewSize } from "./helper";
|
||||||
|
|
||||||
export interface IPhotoComponentProps {
|
type StateProps = {
|
||||||
id: number;
|
photo: TPhotoReqJSON | undefined;
|
||||||
photo: IPhotoReqJSON | undefined;
|
photoState: TPhotoState | undefined;
|
||||||
photoState: IPhotoState | undefined;
|
};
|
||||||
|
|
||||||
|
type DispatchProps = {
|
||||||
fetchPhoto: (id: number) => void;
|
fetchPhoto: (id: number) => void;
|
||||||
close: () => void;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export const PhotoComponent: React.FunctionComponent<IPhotoComponentProps> = (
|
type OwnProps = {
|
||||||
|
id: number;
|
||||||
|
close: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TPhotoComponentProps = StateProps & DispatchProps & OwnProps;
|
||||||
|
|
||||||
|
export const PhotoComponent: React.FunctionComponent<TPhotoComponentProps> = (
|
||||||
props,
|
props,
|
||||||
) => {
|
) => {
|
||||||
const [smallPreviewFetching, setSmallPreviewFetching] =
|
const [smallPreviewFetching, setSmallPreviewFetching] =
|
||||||
@@ -114,7 +121,7 @@ export const PhotoComponent: React.FunctionComponent<IPhotoComponentProps> = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapStateToProps(state: IAppState, props: IPhotoComponentProps) {
|
function mapStateToProps(state: IAppState, props: OwnProps) {
|
||||||
const { id } = props;
|
const { id } = props;
|
||||||
return {
|
return {
|
||||||
photo: state.photos?.photos?.find((p) => p.id === id),
|
photo: state.photos?.photos?.find((p) => p.id === id),
|
||||||
@@ -126,8 +133,7 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
|||||||
return { fetchPhoto: (id: number) => dispatch(photoLoadStart(id)) };
|
return { fetchPhoto: (id: number) => dispatch(photoLoadStart(id)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because https://github.com/DefinitelyTyped/DefinitelyTyped/issues/16990
|
export const Photo = connect<StateProps, DispatchProps, OwnProps, IAppState>(
|
||||||
export const Photo = connect(
|
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps,
|
mapDispatchToProps,
|
||||||
)(PhotoComponent) as any;
|
)(PhotoComponent);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Spinner,
|
Spinner,
|
||||||
} from "@blueprintjs/core";
|
} from "@blueprintjs/core";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { IPhotoReqJSON } from "~/src/shared/types";
|
import { TPhotoReqJSON } from "~/src/shared/types";
|
||||||
import { getPhotoThumbPath } from "../redux/api/photos";
|
import { getPhotoThumbPath } from "../redux/api/photos";
|
||||||
import { showDeletionToast } from "../AppToaster";
|
import { showDeletionToast } from "../AppToaster";
|
||||||
import { Dispatch } from "redux";
|
import { Dispatch } from "redux";
|
||||||
@@ -17,30 +17,30 @@ import { connect } from "react-redux";
|
|||||||
import { RouteComponentProps, withRouter } from "react-router";
|
import { RouteComponentProps, withRouter } from "react-router";
|
||||||
import { PreviewSize } from "./helper";
|
import { PreviewSize } from "./helper";
|
||||||
|
|
||||||
export interface IPhotoCardComponentProps extends RouteComponentProps {
|
export interface TPhotoCardComponentProps extends RouteComponentProps {
|
||||||
photo: IPhotoReqJSON;
|
photo: TPhotoReqJSON;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
deletePhoto: (photos: IPhotoReqJSON[]) => void;
|
deletePhoto: (photos: TPhotoReqJSON[]) => void;
|
||||||
cancelDelete: (photos: IPhotoReqJSON[]) => void;
|
cancelDelete: (photos: TPhotoReqJSON[]) => void;
|
||||||
onClick: (e: React.MouseEvent<HTMLElement>) => void;
|
onClick: (e: React.MouseEvent<HTMLElement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoCardComponentState {
|
export interface TPhotoCardComponentState {
|
||||||
loaded: boolean;
|
loaded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPhotoCardState: IPhotoCardComponentState = {
|
const defaultPhotoCardState: TPhotoCardComponentState = {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ContextMenuTarget
|
@ContextMenuTarget
|
||||||
export class PhotoCardComponent extends React.PureComponent<
|
export class PhotoCardComponent extends React.PureComponent<
|
||||||
IPhotoCardComponentProps,
|
TPhotoCardComponentProps,
|
||||||
IPhotoCardComponentState
|
TPhotoCardComponentState
|
||||||
> {
|
> {
|
||||||
constructor(props: IPhotoCardComponentProps) {
|
constructor(props: TPhotoCardComponentProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleDelete = this.handleDelete.bind(this);
|
this.handleDelete = this.handleDelete.bind(this);
|
||||||
@@ -121,9 +121,9 @@ export class PhotoCardComponent extends React.PureComponent<
|
|||||||
|
|
||||||
function mapDispatchToProps(dispatch: Dispatch) {
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
return {
|
return {
|
||||||
deletePhoto: (photos: IPhotoReqJSON[]) =>
|
deletePhoto: (photos: TPhotoReqJSON[]) =>
|
||||||
dispatch(photosDeleteStart(photos)),
|
dispatch(photosDeleteStart(photos)),
|
||||||
cancelDelete: (photos: IPhotoReqJSON[]) =>
|
cancelDelete: (photos: TPhotoReqJSON[]) =>
|
||||||
dispatch(photosDeleteCancel(photos)),
|
dispatch(photosDeleteCancel(photos)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ function getId(props: RouteComponentProps) {
|
|||||||
return parseInt((props.match?.params as { id: string }).id);
|
return parseInt((props.match?.params as { id: string }).id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PhotoRouteComponent: React.FunctionComponent<RouteComponentProps> = (
|
export const PhotoRouteComponent: React.FunctionComponent<
|
||||||
props: RouteComponentProps,
|
RouteComponentProps
|
||||||
) => {
|
> = (props: RouteComponentProps) => {
|
||||||
const id = getId(props);
|
const id = getId(props);
|
||||||
|
|
||||||
return <Photo id={id} />;
|
return <Photo id={id} close={() => {}} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PhotoRoute = withRouter(PhotoRouteComponent);
|
export const PhotoRoute = withRouter(PhotoRouteComponent);
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import { IUserLoginRespBody, IUserSignupRespBody } from "~/src/shared/types";
|
import {
|
||||||
|
TUserLoginRespBody,
|
||||||
|
TUserSignupRespBody,
|
||||||
|
UserLoginRespBody,
|
||||||
|
UserSignupRespBody,
|
||||||
|
} from "~/src/shared/types";
|
||||||
import { fetchJSON } from "../utils";
|
import { fetchJSON } from "../utils";
|
||||||
|
|
||||||
export async function login(
|
export async function login(
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
): Promise<IUserLoginRespBody> {
|
): Promise<TUserLoginRespBody> {
|
||||||
return fetchJSON("/users/login", "POST", {
|
return fetchJSON("/users/login", "POST", UserLoginRespBody, {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
@@ -15,8 +20,8 @@ export async function signup(
|
|||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
email: string,
|
email: string,
|
||||||
): Promise<IUserSignupRespBody> {
|
): Promise<TUserSignupRespBody> {
|
||||||
return fetchJSON("/users/signup", "POST", {
|
return fetchJSON("/users/signup", "POST", UserSignupRespBody, {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
email,
|
email,
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
import { IPhotoReqJSON } from "~/src/shared/types";
|
|
||||||
import {
|
import {
|
||||||
IPhotosByIDGetRespBody,
|
PhotosByIDGetRespBody,
|
||||||
IPhotosDeleteRespBody,
|
PhotosDeleteRespBody,
|
||||||
IPhotosListRespBody,
|
PhotosListRespBody,
|
||||||
IPhotosNewRespBody,
|
PhotosNewRespBody,
|
||||||
IPhotosUploadRespBody,
|
PhotosUploadRespBody,
|
||||||
|
TPhotoReqJSON,
|
||||||
|
} from "~/src/shared/types";
|
||||||
|
import {
|
||||||
|
TPhotosByIDGetRespBody,
|
||||||
|
TPhotosDeleteRespBody,
|
||||||
|
TPhotosListRespBody,
|
||||||
|
TPhotosNewRespBody,
|
||||||
|
TPhotosUploadRespBody,
|
||||||
} from "~/src/shared/types";
|
} from "~/src/shared/types";
|
||||||
import { apiRoot } from "~src/env";
|
import { apiRoot } from "~src/env";
|
||||||
import { fetchJSONAuth } from "./utils";
|
import { fetchJSONAuth } from "./utils";
|
||||||
|
|
||||||
export function getPhotoImgPath(photo: IPhotoReqJSON): string {
|
export function getPhotoImgPath(photo: TPhotoReqJSON): string {
|
||||||
return `${apiRoot}/photos/showByID/${photo.id}/${photo.accessToken}`;
|
return `${apiRoot}/photos/showByID/${photo.id}/${photo.accessToken}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPhotoThumbPath(photo: IPhotoReqJSON, size: number): string {
|
export function getPhotoThumbPath(photo: TPhotoReqJSON, size: number): string {
|
||||||
return `${apiRoot}/photos/showByID/${photo.id}/${
|
return `${apiRoot}/photos/showByID/${photo.id}/${
|
||||||
photo.accessToken
|
photo.accessToken
|
||||||
}?size=${size.toString()}`;
|
}?size=${size.toString()}`;
|
||||||
@@ -22,35 +29,50 @@ export function getPhotoThumbPath(photo: IPhotoReqJSON, size: number): string {
|
|||||||
export async function fetchPhotosList(
|
export async function fetchPhotosList(
|
||||||
skip: number,
|
skip: number,
|
||||||
num: number,
|
num: number,
|
||||||
): Promise<IPhotosListRespBody> {
|
): Promise<TPhotosListRespBody> {
|
||||||
const params = new URLSearchParams({
|
const params = new URLSearchParams({
|
||||||
skip: skip.toString(),
|
skip: skip.toString(),
|
||||||
num: num.toString(),
|
num: num.toString(),
|
||||||
});
|
});
|
||||||
return fetchJSONAuth(`/photos/list?${params.toString()}`, "GET");
|
return fetchJSONAuth(
|
||||||
|
`/photos/list?${params.toString()}`,
|
||||||
|
"GET",
|
||||||
|
PhotosListRespBody,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchPhoto(id: number): Promise<IPhotosByIDGetRespBody> {
|
export async function fetchPhoto(id: number): Promise<TPhotosByIDGetRespBody> {
|
||||||
return fetchJSONAuth(`/photos/byID/${id}`, "GET");
|
return fetchJSONAuth(`/photos/byID/${id}`, "GET", PhotosByIDGetRespBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createPhoto(
|
export async function createPhoto(
|
||||||
hash: string,
|
hash: string,
|
||||||
size: string,
|
size: string,
|
||||||
format: string,
|
format: string,
|
||||||
): Promise<IPhotosNewRespBody> {
|
): Promise<TPhotosNewRespBody> {
|
||||||
return fetchJSONAuth("/photos/new", "POST", { hash, size, format });
|
return fetchJSONAuth("/photos/new", "POST", PhotosNewRespBody, {
|
||||||
|
hash,
|
||||||
|
size,
|
||||||
|
format,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function uploadPhoto(
|
export async function uploadPhoto(
|
||||||
file: File,
|
file: File,
|
||||||
id: number,
|
id: number,
|
||||||
): Promise<IPhotosUploadRespBody> {
|
): Promise<TPhotosUploadRespBody> {
|
||||||
return fetchJSONAuth(`/photos/upload/${id}`, "POST", file);
|
return fetchJSONAuth(
|
||||||
|
`/photos/upload/${id}`,
|
||||||
|
"POST",
|
||||||
|
PhotosUploadRespBody,
|
||||||
|
file,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deletePhotos(
|
export async function deletePhotos(
|
||||||
photos: IPhotoReqJSON[],
|
photos: TPhotoReqJSON[],
|
||||||
): Promise<IPhotosDeleteRespBody> {
|
): Promise<TPhotosDeleteRespBody> {
|
||||||
return fetchJSONAuth(`/photos/delete`, "POST", { photos });
|
return fetchJSONAuth(`/photos/delete`, "POST", PhotosDeleteRespBody, {
|
||||||
|
photos,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import { fetchJSONAuth } from "../utils";
|
import { fetchJSONAuth } from "../utils";
|
||||||
import { IUserEditRespBody, IUserGetRespBody } from "~/src/shared/types";
|
import {
|
||||||
|
TUserEditRespBody,
|
||||||
|
TUserGetRespBody,
|
||||||
|
UserEditRespBody,
|
||||||
|
UserGetRespBody,
|
||||||
|
} from "~/src/shared/types";
|
||||||
|
|
||||||
export async function fetchUser(): Promise<IUserGetRespBody> {
|
export async function fetchUser(): Promise<TUserGetRespBody> {
|
||||||
return fetchJSONAuth(
|
return fetchJSONAuth("/users/user", "GET", UserGetRespBody);
|
||||||
"/users/user",
|
|
||||||
"GET",
|
|
||||||
) as unknown as Promise<IUserGetRespBody>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeUserPassword(
|
export async function changeUserPassword(
|
||||||
newPassword: string,
|
newPassword: string,
|
||||||
): Promise<IUserEditRespBody> {
|
): Promise<TUserEditRespBody> {
|
||||||
return fetchJSONAuth("/users/edit", "POST", {
|
return fetchJSONAuth("/users/edit", "POST", UserEditRespBody, {
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { apiRoot } from "~src/env";
|
import { apiRoot } from "~src/env";
|
||||||
import { IAPIResponse } from "~/src/shared/types";
|
|
||||||
|
|
||||||
let token: string | null;
|
let token: string | null;
|
||||||
|
|
||||||
@@ -15,49 +14,44 @@ export function deleteToken(): void {
|
|||||||
token = null;
|
token = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchJSON<T>(
|
export async function fetchJSON<T, P extends { parse: (string) => T }>(
|
||||||
path: string,
|
path: string,
|
||||||
method: string,
|
method: string,
|
||||||
|
parser: P,
|
||||||
body?: string | Record<string, unknown> | File,
|
body?: string | Record<string, unknown> | File,
|
||||||
headers?: Record<string, string>,
|
headers?: Record<string, string>,
|
||||||
): Promise<IAPIResponse<T>> {
|
): Promise<T> {
|
||||||
if (typeof body === "object" && !(body instanceof File)) {
|
const reqBody = () =>
|
||||||
body = JSON.stringify(body);
|
body instanceof File
|
||||||
headers = {
|
? (() => {
|
||||||
...headers,
|
const fd = new FormData();
|
||||||
"Content-Type": "application/json",
|
fd.append("photo", body);
|
||||||
};
|
return fd;
|
||||||
}
|
})()
|
||||||
// TODO: io-ts or something like that
|
: JSON.stringify(body);
|
||||||
if (body instanceof File) {
|
|
||||||
const formData = new FormData();
|
const reqHeaders = () =>
|
||||||
formData.append("photo", body);
|
body instanceof File
|
||||||
const response = await fetch(apiRoot + path, {
|
? headers
|
||||||
method,
|
: { ...headers, "Content-Type": "application/json" };
|
||||||
headers,
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
const json = (await response.json()) as Record<string, unknown>;
|
|
||||||
return json as unknown as IAPIResponse<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(apiRoot + path, {
|
const response = await fetch(apiRoot + path, {
|
||||||
method,
|
method,
|
||||||
body,
|
headers: reqHeaders(),
|
||||||
headers,
|
body: reqBody(),
|
||||||
});
|
});
|
||||||
const json = (await response.json()) as Record<string, unknown>;
|
return parser.parse(await response.json());
|
||||||
return json as unknown as IAPIResponse<T>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchJSONAuth<T>(
|
export async function fetchJSONAuth<T, P extends { parse: (string) => T }>(
|
||||||
path: string,
|
path: string,
|
||||||
method: string,
|
method: string,
|
||||||
|
parser: P,
|
||||||
body?: string | Record<string, unknown> | File,
|
body?: string | Record<string, unknown> | File,
|
||||||
headers?: Record<string, unknown>,
|
headers?: Record<string, unknown>,
|
||||||
): Promise<IAPIResponse<T>> {
|
): Promise<T> {
|
||||||
if (token) {
|
if (token) {
|
||||||
return fetchJSON(path, method, body, {
|
return fetchJSON(path, method, parser, body, {
|
||||||
...headers,
|
...headers,
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Action } from "redux";
|
import { Action } from "redux";
|
||||||
import { IUserAuthJSON } from "~/src/shared/types";
|
import { TUserAuthJSON } from "~/src/shared/types";
|
||||||
|
|
||||||
export enum AuthTypes {
|
export enum AuthTypes {
|
||||||
AUTH_START = "AUTH_START",
|
AUTH_START = "AUTH_START",
|
||||||
@@ -28,7 +28,7 @@ export interface ISignupStartAction extends Action {
|
|||||||
|
|
||||||
export interface IAuthSuccessAction extends Action {
|
export interface IAuthSuccessAction extends Action {
|
||||||
type: AuthTypes.AUTH_SUCCESS;
|
type: AuthTypes.AUTH_SUCCESS;
|
||||||
payload: IUserAuthJSON;
|
payload: TUserAuthJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthFailureAction extends Action {
|
export interface IAuthFailureAction extends Action {
|
||||||
@@ -64,7 +64,7 @@ export function signupStart(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function authSuccess(user: IUserAuthJSON): IAuthSuccessAction {
|
export function authSuccess(user: TUserAuthJSON): IAuthSuccessAction {
|
||||||
return { type: AuthTypes.AUTH_SUCCESS, payload: user };
|
return { type: AuthTypes.AUTH_SUCCESS, payload: user };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Action } from "redux";
|
import { Action } from "redux";
|
||||||
import { IPhotoReqJSON } from "~src/shared/types";
|
import { TPhotoReqJSON } from "~src/shared/types";
|
||||||
import {
|
import {
|
||||||
showPhotoCreateFailToast,
|
showPhotoCreateFailToast,
|
||||||
showPhotoUploadFileFailToast,
|
showPhotoUploadFileFailToast,
|
||||||
@@ -29,242 +29,242 @@ export enum PhotoTypes {
|
|||||||
PHOTOS_DELETE_CANCEL = "PHOTOS_DELETE_CANCEL",
|
PHOTOS_DELETE_CANCEL = "PHOTOS_DELETE_CANCEL",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosLoadStartAction extends Action {
|
export interface TPhotosLoadStartAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_LOAD_START;
|
type: PhotoTypes.PHOTOS_LOAD_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosLoadSuccessAction extends Action {
|
export interface TPhotosLoadSuccessAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_LOAD_SUCCESS;
|
type: PhotoTypes.PHOTOS_LOAD_SUCCESS;
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosLoadFailAction extends Action {
|
export interface TPhotosLoadFailAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_LOAD_FAIL;
|
type: PhotoTypes.PHOTOS_LOAD_FAIL;
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoLoadStartAction extends Action {
|
export interface TPhotoLoadStartAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_LOAD_START;
|
type: PhotoTypes.PHOTO_LOAD_START;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoLoadSuccessAction extends Action {
|
export interface TPhotoLoadSuccessAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_LOAD_SUCCESS;
|
type: PhotoTypes.PHOTO_LOAD_SUCCESS;
|
||||||
photo: IPhotoReqJSON;
|
photo: TPhotoReqJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoLoadFailAction extends Action {
|
export interface TPhotoLoadFailAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_LOAD_FAIL;
|
type: PhotoTypes.PHOTO_LOAD_FAIL;
|
||||||
id: number;
|
id: number;
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosUploadStartAction extends Action {
|
export interface TPhotosUploadStartAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_UPLOAD_START;
|
type: PhotoTypes.PHOTOS_UPLOAD_START;
|
||||||
files: FileList;
|
files: FileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoCreateQueue extends Action {
|
export interface TPhotoCreateQueue extends Action {
|
||||||
type: PhotoTypes.PHOTO_CREATE_QUEUE;
|
type: PhotoTypes.PHOTO_CREATE_QUEUE;
|
||||||
file: File;
|
file: File;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoUploadQueue extends Action {
|
export interface TPhotoUploadQueue extends Action {
|
||||||
type: PhotoTypes.PHOTO_UPLOAD_QUEUE;
|
type: PhotoTypes.PHOTO_UPLOAD_QUEUE;
|
||||||
file: File;
|
file: File;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoCreateStart extends Action {
|
export interface TPhotoCreateStart extends Action {
|
||||||
type: PhotoTypes.PHOTO_CREATE_START;
|
type: PhotoTypes.PHOTO_CREATE_START;
|
||||||
file: File;
|
file: File;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoUploadStart extends Action {
|
export interface TPhotoUploadStart extends Action {
|
||||||
type: PhotoTypes.PHOTO_UPLOAD_START;
|
type: PhotoTypes.PHOTO_UPLOAD_START;
|
||||||
file: File;
|
file: File;
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoUploadSuccessAction extends Action {
|
export interface TPhotoUploadSuccessAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_UPLOAD_SUCCESS;
|
type: PhotoTypes.PHOTO_UPLOAD_SUCCESS;
|
||||||
photo: IPhotoReqJSON;
|
photo: TPhotoReqJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoUploadFailAction extends Action {
|
export interface TPhotoUploadFailAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_UPLOAD_FAIL;
|
type: PhotoTypes.PHOTO_UPLOAD_FAIL;
|
||||||
photo: IPhotoReqJSON | number;
|
photo: TPhotoReqJSON | number;
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoCreateSuccessAction extends Action {
|
export interface TPhotoCreateSuccessAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_CREATE_SUCCESS;
|
type: PhotoTypes.PHOTO_CREATE_SUCCESS;
|
||||||
photo: IPhotoReqJSON;
|
photo: TPhotoReqJSON;
|
||||||
file: File;
|
file: File;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotoCreateFailAction extends Action {
|
export interface TPhotoCreateFailAction extends Action {
|
||||||
type: PhotoTypes.PHOTO_CREATE_FAIL;
|
type: PhotoTypes.PHOTO_CREATE_FAIL;
|
||||||
file: File;
|
file: File;
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosDeleteStartAction extends Action {
|
export interface TPhotosDeleteStartAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_DELETE_START;
|
type: PhotoTypes.PHOTOS_DELETE_START;
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosDeleteSuccessAction extends Action {
|
export interface TPhotosDeleteSuccessAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_DELETE_SUCCESS;
|
type: PhotoTypes.PHOTOS_DELETE_SUCCESS;
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosDeleteFailAction extends Action {
|
export interface TPhotosDeleteFailAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_DELETE_FAIL;
|
type: PhotoTypes.PHOTOS_DELETE_FAIL;
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
error?: string;
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosDeleteCancelAction extends Action {
|
export interface TPhotosDeleteCancelAction extends Action {
|
||||||
type: PhotoTypes.PHOTOS_DELETE_CANCEL;
|
type: PhotoTypes.PHOTOS_DELETE_CANCEL;
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosStartFetchingSpinner extends Action {
|
export interface TPhotosStartFetchingSpinner extends Action {
|
||||||
type: PhotoTypes.PHOTOS_START_FETCHING_SPINNER;
|
type: PhotoTypes.PHOTOS_START_FETCHING_SPINNER;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoCreateQueue(file: File): IPhotoCreateQueue {
|
export function photoCreateQueue(file: File): TPhotoCreateQueue {
|
||||||
return { type: PhotoTypes.PHOTO_CREATE_QUEUE, file };
|
return { type: PhotoTypes.PHOTO_CREATE_QUEUE, file };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoUploadQueue(file: File, id: number): IPhotoUploadQueue {
|
export function photoUploadQueue(file: File, id: number): TPhotoUploadQueue {
|
||||||
return { type: PhotoTypes.PHOTO_UPLOAD_QUEUE, file, id };
|
return { type: PhotoTypes.PHOTO_UPLOAD_QUEUE, file, id };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoCreateStart(file: File): IPhotoCreateStart {
|
export function photoCreateStart(file: File): TPhotoCreateStart {
|
||||||
return { type: PhotoTypes.PHOTO_CREATE_START, file };
|
return { type: PhotoTypes.PHOTO_CREATE_START, file };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoUploadStart(file: File, id: number): IPhotoUploadStart {
|
export function photoUploadStart(file: File, id: number): TPhotoUploadStart {
|
||||||
return { type: PhotoTypes.PHOTO_UPLOAD_START, file, id };
|
return { type: PhotoTypes.PHOTO_UPLOAD_START, file, id };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosLoadStart(): IPhotosLoadStartAction {
|
export function photosLoadStart(): TPhotosLoadStartAction {
|
||||||
return { type: PhotoTypes.PHOTOS_LOAD_START };
|
return { type: PhotoTypes.PHOTOS_LOAD_START };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoLoadStart(id: number): IPhotoLoadStartAction {
|
export function photoLoadStart(id: number): TPhotoLoadStartAction {
|
||||||
return { type: PhotoTypes.PHOTO_LOAD_START, id };
|
return { type: PhotoTypes.PHOTO_LOAD_START, id };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosUploadStart(files: FileList): IPhotosUploadStartAction {
|
export function photosUploadStart(files: FileList): TPhotosUploadStartAction {
|
||||||
return { type: PhotoTypes.PHOTOS_UPLOAD_START, files };
|
return { type: PhotoTypes.PHOTOS_UPLOAD_START, files };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoUploadSuccess(
|
export function photoUploadSuccess(
|
||||||
photo: IPhotoReqJSON,
|
photo: TPhotoReqJSON,
|
||||||
): IPhotoUploadSuccessAction {
|
): TPhotoUploadSuccessAction {
|
||||||
return { type: PhotoTypes.PHOTO_UPLOAD_SUCCESS, photo };
|
return { type: PhotoTypes.PHOTO_UPLOAD_SUCCESS, photo };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoUploadFail(
|
export function photoUploadFail(
|
||||||
photo: IPhotoReqJSON | number,
|
photo: TPhotoReqJSON | number,
|
||||||
error: string,
|
error: string,
|
||||||
): IPhotoUploadFailAction {
|
): TPhotoUploadFailAction {
|
||||||
showPhotoUploadJSONFailToast(photo, error);
|
showPhotoUploadJSONFailToast(photo, error);
|
||||||
return { type: PhotoTypes.PHOTO_UPLOAD_FAIL, photo, error };
|
return { type: PhotoTypes.PHOTO_UPLOAD_FAIL, photo, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoUploadFailWithFile(
|
export function photoUploadFailWithFile(
|
||||||
photo: IPhotoReqJSON | number,
|
photo: TPhotoReqJSON | number,
|
||||||
file: File,
|
file: File,
|
||||||
error: string,
|
error: string,
|
||||||
): IPhotoUploadFailAction {
|
): TPhotoUploadFailAction {
|
||||||
showPhotoUploadFileFailToast(file, error);
|
showPhotoUploadFileFailToast(file, error);
|
||||||
return { type: PhotoTypes.PHOTO_UPLOAD_FAIL, photo, error };
|
return { type: PhotoTypes.PHOTO_UPLOAD_FAIL, photo, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoCreateSuccess(
|
export function photoCreateSuccess(
|
||||||
photo: IPhotoReqJSON,
|
photo: TPhotoReqJSON,
|
||||||
file: File,
|
file: File,
|
||||||
): IPhotoCreateSuccessAction {
|
): TPhotoCreateSuccessAction {
|
||||||
return { type: PhotoTypes.PHOTO_CREATE_SUCCESS, photo, file };
|
return { type: PhotoTypes.PHOTO_CREATE_SUCCESS, photo, file };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoCreateFail(
|
export function photoCreateFail(
|
||||||
file: File,
|
file: File,
|
||||||
error: string,
|
error: string,
|
||||||
): IPhotoCreateFailAction {
|
): TPhotoCreateFailAction {
|
||||||
showPhotoCreateFailToast(file, error);
|
showPhotoCreateFailToast(file, error);
|
||||||
return { type: PhotoTypes.PHOTO_CREATE_FAIL, file, error };
|
return { type: PhotoTypes.PHOTO_CREATE_FAIL, file, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosLoadSuccess(
|
export function photosLoadSuccess(
|
||||||
photos: IPhotoReqJSON[],
|
photos: TPhotoReqJSON[],
|
||||||
): IPhotosLoadSuccessAction {
|
): TPhotosLoadSuccessAction {
|
||||||
return { type: PhotoTypes.PHOTOS_LOAD_SUCCESS, photos };
|
return { type: PhotoTypes.PHOTOS_LOAD_SUCCESS, photos };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosLoadFail(error: string): IPhotosLoadFailAction {
|
export function photosLoadFail(error: string): TPhotosLoadFailAction {
|
||||||
return { type: PhotoTypes.PHOTOS_LOAD_FAIL, error };
|
return { type: PhotoTypes.PHOTOS_LOAD_FAIL, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoLoadSuccess(
|
export function photoLoadSuccess(
|
||||||
photo: IPhotoReqJSON,
|
photo: TPhotoReqJSON,
|
||||||
): IPhotoLoadSuccessAction {
|
): TPhotoLoadSuccessAction {
|
||||||
return { type: PhotoTypes.PHOTO_LOAD_SUCCESS, photo };
|
return { type: PhotoTypes.PHOTO_LOAD_SUCCESS, photo };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photoLoadFail(id: number, error: string): IPhotoLoadFailAction {
|
export function photoLoadFail(id: number, error: string): TPhotoLoadFailAction {
|
||||||
return { type: PhotoTypes.PHOTO_LOAD_FAIL, id, error };
|
return { type: PhotoTypes.PHOTO_LOAD_FAIL, id, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosDeleteStart(
|
export function photosDeleteStart(
|
||||||
photos: IPhotoReqJSON[],
|
photos: TPhotoReqJSON[],
|
||||||
): IPhotosDeleteStartAction {
|
): TPhotosDeleteStartAction {
|
||||||
return { type: PhotoTypes.PHOTOS_DELETE_START, photos };
|
return { type: PhotoTypes.PHOTOS_DELETE_START, photos };
|
||||||
}
|
}
|
||||||
export function photosDeleteSuccess(
|
export function photosDeleteSuccess(
|
||||||
photos: IPhotoReqJSON[],
|
photos: TPhotoReqJSON[],
|
||||||
): IPhotosDeleteSuccessAction {
|
): TPhotosDeleteSuccessAction {
|
||||||
return { type: PhotoTypes.PHOTOS_DELETE_SUCCESS, photos };
|
return { type: PhotoTypes.PHOTOS_DELETE_SUCCESS, photos };
|
||||||
}
|
}
|
||||||
export function photosDeleteFail(
|
export function photosDeleteFail(
|
||||||
photos: IPhotoReqJSON[],
|
photos: TPhotoReqJSON[],
|
||||||
error?: string,
|
error?: string,
|
||||||
): IPhotosDeleteFailAction {
|
): TPhotosDeleteFailAction {
|
||||||
return { type: PhotoTypes.PHOTOS_DELETE_FAIL, photos, error };
|
return { type: PhotoTypes.PHOTOS_DELETE_FAIL, photos, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosDeleteCancel(
|
export function photosDeleteCancel(
|
||||||
photos: IPhotoReqJSON[],
|
photos: TPhotoReqJSON[],
|
||||||
): IPhotosDeleteCancelAction {
|
): TPhotosDeleteCancelAction {
|
||||||
return { type: PhotoTypes.PHOTOS_DELETE_CANCEL, photos };
|
return { type: PhotoTypes.PHOTOS_DELETE_CANCEL, photos };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function photosStartFetchingSpinner(): IPhotosStartFetchingSpinner {
|
export function photosStartFetchingSpinner(): TPhotosStartFetchingSpinner {
|
||||||
return { type: PhotoTypes.PHOTOS_START_FETCHING_SPINNER };
|
return { type: PhotoTypes.PHOTOS_START_FETCHING_SPINNER };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PhotoAction =
|
export type PhotoAction =
|
||||||
| IPhotosLoadStartAction
|
| TPhotosLoadStartAction
|
||||||
| IPhotosLoadFailAction
|
| TPhotosLoadFailAction
|
||||||
| IPhotosLoadSuccessAction
|
| TPhotosLoadSuccessAction
|
||||||
| IPhotosStartFetchingSpinner
|
| TPhotosStartFetchingSpinner
|
||||||
| IPhotosUploadStartAction
|
| TPhotosUploadStartAction
|
||||||
| IPhotoCreateFailAction
|
| TPhotoCreateFailAction
|
||||||
| IPhotoCreateSuccessAction
|
| TPhotoCreateSuccessAction
|
||||||
| IPhotoUploadFailAction
|
| TPhotoUploadFailAction
|
||||||
| IPhotoUploadSuccessAction
|
| TPhotoUploadSuccessAction
|
||||||
| IPhotosDeleteFailAction
|
| TPhotosDeleteFailAction
|
||||||
| IPhotosDeleteStartAction
|
| TPhotosDeleteStartAction
|
||||||
| IPhotosDeleteSuccessAction
|
| TPhotosDeleteSuccessAction
|
||||||
| IPhotosDeleteCancelAction
|
| TPhotosDeleteCancelAction
|
||||||
| IPhotoLoadFailAction
|
| TPhotoLoadFailAction
|
||||||
| IPhotoLoadStartAction
|
| TPhotoLoadStartAction
|
||||||
| IPhotoLoadSuccessAction
|
| TPhotoLoadSuccessAction
|
||||||
| IPhotoUploadQueue
|
| TPhotoUploadQueue
|
||||||
| IPhotoCreateQueue
|
| TPhotoCreateQueue
|
||||||
| IPhotoCreateStart
|
| TPhotoCreateStart
|
||||||
| IPhotoUploadStart;
|
| TPhotoUploadStart;
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { Reducer } from "redux";
|
import { Reducer } from "redux";
|
||||||
import { IPhotoReqJSON } from "~/src/shared/types";
|
import { TPhotoReqJSON } from "~/src/shared/types";
|
||||||
import { UserAction, UserTypes } from "~src/redux/user/actions";
|
import { UserAction, UserTypes } from "~src/redux/user/actions";
|
||||||
import { PhotoAction, PhotoTypes } from "./actions";
|
import { PhotoAction, PhotoTypes } from "./actions";
|
||||||
|
|
||||||
export interface IPhotoState {
|
export interface TPhotoState {
|
||||||
fetching: boolean;
|
fetching: boolean;
|
||||||
fetchingError: string | null;
|
fetchingError: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPhotosState {
|
export interface TPhotosState {
|
||||||
photos: IPhotoReqJSON[];
|
photos: TPhotoReqJSON[];
|
||||||
|
|
||||||
photoStates: Record<number, IPhotoState>;
|
photoStates: Record<number, TPhotoState>;
|
||||||
|
|
||||||
overviewFetching: boolean;
|
overviewFetching: boolean;
|
||||||
allPhotosLoaded: boolean;
|
allPhotosLoaded: boolean;
|
||||||
@@ -24,10 +24,10 @@ export interface IPhotosState {
|
|||||||
photoUploadQueue: Record<number, File>;
|
photoUploadQueue: Record<number, File>;
|
||||||
photosUploading: number;
|
photosUploading: number;
|
||||||
|
|
||||||
deleteCache: Record<number, IPhotoReqJSON>;
|
deleteCache: Record<number, TPhotoReqJSON>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPhotosState: IPhotosState = {
|
const defaultPhotosState: TPhotosState = {
|
||||||
photos: [],
|
photos: [],
|
||||||
allPhotosLoaded: false,
|
allPhotosLoaded: false,
|
||||||
overviewFetching: false,
|
overviewFetching: false,
|
||||||
@@ -45,12 +45,12 @@ const defaultPhotosState: IPhotosState = {
|
|||||||
deleteCache: {},
|
deleteCache: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export function sortPhotos(photos: IPhotoReqJSON[]): IPhotoReqJSON[] {
|
export function sortPhotos(photos: TPhotoReqJSON[]): TPhotoReqJSON[] {
|
||||||
return [...photos].sort((a, b) => b.shotAt - a.shotAt);
|
return [...photos].sort((a, b) => b.shotAt - a.shotAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const photosReducer: Reducer<IPhotosState, PhotoAction> = (
|
export const photosReducer: Reducer<TPhotosState, PhotoAction> = (
|
||||||
state: IPhotosState = defaultPhotosState,
|
state: TPhotosState = defaultPhotosState,
|
||||||
action: PhotoAction | UserAction,
|
action: PhotoAction | UserAction,
|
||||||
) => {
|
) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@@ -230,7 +230,7 @@ export const photosReducer: Reducer<IPhotosState, PhotoAction> = (
|
|||||||
case PhotoTypes.PHOTOS_DELETE_FAIL:
|
case PhotoTypes.PHOTOS_DELETE_FAIL:
|
||||||
case PhotoTypes.PHOTOS_DELETE_CANCEL: {
|
case PhotoTypes.PHOTOS_DELETE_CANCEL: {
|
||||||
const delCache = { ...state.deleteCache };
|
const delCache = { ...state.deleteCache };
|
||||||
let photos: IPhotoReqJSON[] = [...state.photos];
|
let photos: TPhotoReqJSON[] = [...state.photos];
|
||||||
for (const photo of action.photos) {
|
for (const photo of action.photos) {
|
||||||
if (delCache[photo.id]) {
|
if (delCache[photo.id]) {
|
||||||
photos = sortPhotos([...photos, delCache[photo.id]]);
|
photos = sortPhotos([...photos, delCache[photo.id]]);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import {
|
|||||||
uploadPhoto,
|
uploadPhoto,
|
||||||
} from "~src/redux/api/photos";
|
} from "~src/redux/api/photos";
|
||||||
import {
|
import {
|
||||||
IPhotosDeleteStartAction,
|
TPhotosDeleteStartAction,
|
||||||
IPhotoLoadStartAction,
|
TPhotoLoadStartAction,
|
||||||
IPhotosUploadStartAction,
|
TPhotosUploadStartAction,
|
||||||
photoCreateFail,
|
photoCreateFail,
|
||||||
photoCreateQueue,
|
photoCreateQueue,
|
||||||
photoCreateStart,
|
photoCreateStart,
|
||||||
@@ -38,7 +38,7 @@ import {
|
|||||||
photoUploadStart,
|
photoUploadStart,
|
||||||
photoUploadSuccess,
|
photoUploadSuccess,
|
||||||
} from "./actions";
|
} from "./actions";
|
||||||
import { IPhotosNewRespBody, IPhotosListPagination } from "~src/shared/types";
|
import { TPhotosNewRespBody, PhotosListPagination } from "~src/shared/types";
|
||||||
|
|
||||||
// Thanks, https://dev.to/qortex/compute-md5-checksum-for-a-file-in-typescript-59a4
|
// Thanks, https://dev.to/qortex/compute-md5-checksum-for-a-file-in-typescript-59a4
|
||||||
function computeChecksumMd5(file: File): Promise<string> {
|
function computeChecksumMd5(file: File): Promise<string> {
|
||||||
@@ -112,7 +112,7 @@ function* photosLoad() {
|
|||||||
|
|
||||||
const skip = state.photos.photos ? state.photos.photos.length : 0;
|
const skip = state.photos.photos ? state.photos.photos.length : 0;
|
||||||
const { response, timeout } = yield race({
|
const { response, timeout } = yield race({
|
||||||
response: call(fetchPhotosList, skip, IPhotosListPagination),
|
response: call(fetchPhotosList, skip, PhotosListPagination),
|
||||||
timeout: delay(10000),
|
timeout: delay(10000),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ function* photosLoad() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* photoLoad(action: IPhotoLoadStartAction) {
|
function* photoLoad(action: TPhotoLoadStartAction) {
|
||||||
try {
|
try {
|
||||||
//const spinner = yield fork(startSpinner);
|
//const spinner = yield fork(startSpinner);
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ function* photoCreate() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response.data || response.error === "Photo already exists") {
|
if (response.data || response.error === "Photo already exists") {
|
||||||
const photo = (response as IPhotosNewRespBody).data;
|
const photo = (response as TPhotosNewRespBody).data;
|
||||||
yield put(photoCreateSuccess(photo, f));
|
yield put(photoCreateSuccess(photo, f));
|
||||||
yield put(photoUploadQueue(f, photo.id));
|
yield put(photoUploadQueue(f, photo.id));
|
||||||
} else {
|
} else {
|
||||||
@@ -233,14 +233,14 @@ function* photoUpload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* photosUpload(action: IPhotosUploadStartAction) {
|
function* photosUpload(action: TPhotosUploadStartAction) {
|
||||||
const files = Array.from(action.files);
|
const files = Array.from(action.files);
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
yield put(photoCreateQueue(file));
|
yield put(photoCreateQueue(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* photosDelete(action: IPhotosDeleteStartAction) {
|
function* photosDelete(action: TPhotosDeleteStartAction) {
|
||||||
try {
|
try {
|
||||||
const { cancelled } = yield race({
|
const { cancelled } = yield race({
|
||||||
timeout: delay(3000),
|
timeout: delay(3000),
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import {
|
|||||||
ILocalSettingsState,
|
ILocalSettingsState,
|
||||||
localSettingsReducer,
|
localSettingsReducer,
|
||||||
} from "./localSettings/reducer";
|
} from "./localSettings/reducer";
|
||||||
import { IPhotosState, photosReducer } from "./photos/reducer";
|
import { TPhotosState, photosReducer } from "./photos/reducer";
|
||||||
import { IUserState, userReducer } from "./user/reducer";
|
import { TUserState, userReducer } from "./user/reducer";
|
||||||
|
|
||||||
export interface IAppState {
|
export interface IAppState {
|
||||||
auth: IAuthState & PersistPartial;
|
auth: IAuthState & PersistPartial;
|
||||||
user: IUserState;
|
user: TUserState;
|
||||||
localSettings: ILocalSettingsState & PersistPartial;
|
localSettings: ILocalSettingsState & PersistPartial;
|
||||||
photos: IPhotosState;
|
photos: TPhotosState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const authPersistConfig = {
|
const authPersistConfig = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Action } from "redux";
|
import { Action } from "redux";
|
||||||
import { IUserAuthJSON } from "~src/shared/types";
|
import { TUserAuthJSON } from "~src/shared/types";
|
||||||
import {
|
import {
|
||||||
showPasswordNotSavedToast,
|
showPasswordNotSavedToast,
|
||||||
showPasswordSavedToast,
|
showPasswordSavedToast,
|
||||||
@@ -15,20 +15,20 @@ export enum UserTypes {
|
|||||||
USER_PASS_CHANGE_FAIL = "USER_PASS_CHANGE_FAIL",
|
USER_PASS_CHANGE_FAIL = "USER_PASS_CHANGE_FAIL",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserGetAction extends Action {
|
export interface TUserGetAction extends Action {
|
||||||
type: UserTypes.USER_GET;
|
type: UserTypes.USER_GET;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserLogoutAction extends Action {
|
export interface TUserLogoutAction extends Action {
|
||||||
type: UserTypes.USER_LOGOUT;
|
type: UserTypes.USER_LOGOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserGetSuccessAction extends Action {
|
export interface TUserGetSuccessAction extends Action {
|
||||||
type: UserTypes.USER_GET_SUCCESS;
|
type: UserTypes.USER_GET_SUCCESS;
|
||||||
payload: IUserAuthJSON;
|
payload: TUserAuthJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserGetFailAction extends Action {
|
export interface TUserGetFailAction extends Action {
|
||||||
type: UserTypes.USER_GET_FAIL;
|
type: UserTypes.USER_GET_FAIL;
|
||||||
payload: {
|
payload: {
|
||||||
error: string;
|
error: string;
|
||||||
@@ -36,17 +36,17 @@ export interface IUserGetFailAction extends Action {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserPassChangeAction extends Action {
|
export interface TUserPassChangeAction extends Action {
|
||||||
type: UserTypes.USER_PASS_CHANGE;
|
type: UserTypes.USER_PASS_CHANGE;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserPassChangeSuccessAction extends Action {
|
export interface TUserPassChangeSuccessAction extends Action {
|
||||||
type: UserTypes.USER_PASS_CHANGE_SUCCESS;
|
type: UserTypes.USER_PASS_CHANGE_SUCCESS;
|
||||||
payload: IUserAuthJSON;
|
payload: TUserAuthJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserPassChangeFailAction extends Action {
|
export interface TUserPassChangeFailAction extends Action {
|
||||||
type: UserTypes.USER_PASS_CHANGE_FAIL;
|
type: UserTypes.USER_PASS_CHANGE_FAIL;
|
||||||
payload: {
|
payload: {
|
||||||
error: string;
|
error: string;
|
||||||
@@ -54,32 +54,32 @@ export interface IUserPassChangeFailAction extends Action {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUser(): IUserGetAction {
|
export function getUser(): TUserGetAction {
|
||||||
return { type: UserTypes.USER_GET };
|
return { type: UserTypes.USER_GET };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logoutUser(): IUserLogoutAction {
|
export function logoutUser(): TUserLogoutAction {
|
||||||
return { type: UserTypes.USER_LOGOUT };
|
return { type: UserTypes.USER_LOGOUT };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserSuccess(user: IUserAuthJSON): IUserGetSuccessAction {
|
export function getUserSuccess(user: TUserAuthJSON): TUserGetSuccessAction {
|
||||||
return { type: UserTypes.USER_GET_SUCCESS, payload: user };
|
return { type: UserTypes.USER_GET_SUCCESS, payload: user };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserFail(
|
export function getUserFail(
|
||||||
error: string,
|
error: string,
|
||||||
logout: boolean,
|
logout: boolean,
|
||||||
): IUserGetFailAction {
|
): TUserGetFailAction {
|
||||||
return { type: UserTypes.USER_GET_FAIL, payload: { error, logout } };
|
return { type: UserTypes.USER_GET_FAIL, payload: { error, logout } };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function userPassChange(password: string): IUserPassChangeAction {
|
export function userPassChange(password: string): TUserPassChangeAction {
|
||||||
return { type: UserTypes.USER_PASS_CHANGE, password };
|
return { type: UserTypes.USER_PASS_CHANGE, password };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function userPassChangeSuccess(
|
export function userPassChangeSuccess(
|
||||||
user: IUserAuthJSON,
|
user: TUserAuthJSON,
|
||||||
): IUserPassChangeSuccessAction {
|
): TUserPassChangeSuccessAction {
|
||||||
showPasswordSavedToast();
|
showPasswordSavedToast();
|
||||||
return { type: UserTypes.USER_PASS_CHANGE_SUCCESS, payload: user };
|
return { type: UserTypes.USER_PASS_CHANGE_SUCCESS, payload: user };
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ export function userPassChangeSuccess(
|
|||||||
export function userPassChangeFail(
|
export function userPassChangeFail(
|
||||||
error: string,
|
error: string,
|
||||||
logout: boolean,
|
logout: boolean,
|
||||||
): IUserPassChangeFailAction {
|
): TUserPassChangeFailAction {
|
||||||
showPasswordNotSavedToast(error);
|
showPasswordNotSavedToast(error);
|
||||||
return {
|
return {
|
||||||
type: UserTypes.USER_PASS_CHANGE_FAIL,
|
type: UserTypes.USER_PASS_CHANGE_FAIL,
|
||||||
@@ -96,10 +96,10 @@ export function userPassChangeFail(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type UserAction =
|
export type UserAction =
|
||||||
| IUserGetAction
|
| TUserGetAction
|
||||||
| IUserGetSuccessAction
|
| TUserGetSuccessAction
|
||||||
| IUserGetFailAction
|
| TUserGetFailAction
|
||||||
| IUserLogoutAction
|
| TUserLogoutAction
|
||||||
| IUserPassChangeAction
|
| TUserPassChangeAction
|
||||||
| IUserPassChangeFailAction
|
| TUserPassChangeFailAction
|
||||||
| IUserPassChangeSuccessAction;
|
| TUserPassChangeSuccessAction;
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { Reducer } from "react";
|
import { Reducer } from "react";
|
||||||
import { IUserJSON } from "~/src/shared/types";
|
import { TUserJSON } from "~/src/shared/types";
|
||||||
import { AuthAction, AuthTypes } from "~src/redux/auth/actions";
|
import { AuthAction, AuthTypes } from "~src/redux/auth/actions";
|
||||||
import { UserAction, UserTypes } from "./actions";
|
import { UserAction, UserTypes } from "./actions";
|
||||||
|
|
||||||
export interface IUserState {
|
export interface TUserState {
|
||||||
user: IUserJSON | null;
|
user: TUserJSON | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultUserState: IUserState = {
|
const defaultUserState: TUserState = {
|
||||||
user: null,
|
user: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userReducer: Reducer<IUserState, AuthAction> = (
|
export const userReducer: Reducer<TUserState, AuthAction> = (
|
||||||
state: IUserState = defaultUserState,
|
state: TUserState = defaultUserState,
|
||||||
action: AuthAction | UserAction,
|
action: AuthAction | UserAction,
|
||||||
): IUserState => {
|
): TUserState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case AuthTypes.AUTH_SUCCESS:
|
case AuthTypes.AUTH_SUCCESS:
|
||||||
case UserTypes.USER_GET_SUCCESS:
|
case UserTypes.USER_GET_SUCCESS:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { changeUserPassword, fetchUser } from "~src/redux/api/user";
|
|||||||
import {
|
import {
|
||||||
getUserFail,
|
getUserFail,
|
||||||
getUserSuccess,
|
getUserSuccess,
|
||||||
IUserPassChangeAction,
|
TUserPassChangeAction,
|
||||||
userPassChangeFail,
|
userPassChangeFail,
|
||||||
userPassChangeSuccess,
|
userPassChangeSuccess,
|
||||||
UserTypes,
|
UserTypes,
|
||||||
@@ -32,7 +32,7 @@ function* getUser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* userPassChange(action: IUserPassChangeAction) {
|
function* userPassChange(action: TUserPassChangeAction) {
|
||||||
try {
|
try {
|
||||||
const { response, timeout } = yield race({
|
const { response, timeout } = yield race({
|
||||||
response: call(changeUserPassword, action.password),
|
response: call(changeUserPassword, action.password),
|
||||||
|
|||||||
15
shared/node_modules/.package-lock.json
generated
vendored
Normal file
15
shared/node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "photos-shared",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "3.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||||
|
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
shared/node_modules/zod/LICENSE
generated
vendored
Normal file
21
shared/node_modules/zod/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Colin McDonnell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
2739
shared/node_modules/zod/README.md
generated
vendored
Normal file
2739
shared/node_modules/zod/README.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
shared/node_modules/zod/index.d.ts
generated
vendored
Normal file
2
shared/node_modules/zod/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./lib";
|
||||||
|
export as namespace Zod;
|
||||||
163
shared/node_modules/zod/lib/ZodError.d.ts
generated
vendored
Normal file
163
shared/node_modules/zod/lib/ZodError.d.ts
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import type { TypeOf, ZodType } from ".";
|
||||||
|
import { Primitive } from "./helpers/typeAliases";
|
||||||
|
import { util, ZodParsedType } from "./helpers/util";
|
||||||
|
declare type allKeys<T> = T extends any ? keyof T : never;
|
||||||
|
export declare type inferFlattenedErrors<T extends ZodType<any, any, any>, U = string> = typeToFlattenedError<TypeOf<T>, U>;
|
||||||
|
export declare type typeToFlattenedError<T, U = string> = {
|
||||||
|
formErrors: U[];
|
||||||
|
fieldErrors: {
|
||||||
|
[P in allKeys<T>]?: U[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export declare const ZodIssueCode: {
|
||||||
|
invalid_type: "invalid_type";
|
||||||
|
invalid_literal: "invalid_literal";
|
||||||
|
custom: "custom";
|
||||||
|
invalid_union: "invalid_union";
|
||||||
|
invalid_union_discriminator: "invalid_union_discriminator";
|
||||||
|
invalid_enum_value: "invalid_enum_value";
|
||||||
|
unrecognized_keys: "unrecognized_keys";
|
||||||
|
invalid_arguments: "invalid_arguments";
|
||||||
|
invalid_return_type: "invalid_return_type";
|
||||||
|
invalid_date: "invalid_date";
|
||||||
|
invalid_string: "invalid_string";
|
||||||
|
too_small: "too_small";
|
||||||
|
too_big: "too_big";
|
||||||
|
invalid_intersection_types: "invalid_intersection_types";
|
||||||
|
not_multiple_of: "not_multiple_of";
|
||||||
|
not_finite: "not_finite";
|
||||||
|
};
|
||||||
|
export declare type ZodIssueCode = keyof typeof ZodIssueCode;
|
||||||
|
export declare type ZodIssueBase = {
|
||||||
|
path: (string | number)[];
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
export interface ZodInvalidTypeIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_type;
|
||||||
|
expected: ZodParsedType;
|
||||||
|
received: ZodParsedType;
|
||||||
|
}
|
||||||
|
export interface ZodInvalidLiteralIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_literal;
|
||||||
|
expected: unknown;
|
||||||
|
received: unknown;
|
||||||
|
}
|
||||||
|
export interface ZodUnrecognizedKeysIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.unrecognized_keys;
|
||||||
|
keys: string[];
|
||||||
|
}
|
||||||
|
export interface ZodInvalidUnionIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_union;
|
||||||
|
unionErrors: ZodError[];
|
||||||
|
}
|
||||||
|
export interface ZodInvalidUnionDiscriminatorIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_union_discriminator;
|
||||||
|
options: Primitive[];
|
||||||
|
}
|
||||||
|
export interface ZodInvalidEnumValueIssue extends ZodIssueBase {
|
||||||
|
received: string | number;
|
||||||
|
code: typeof ZodIssueCode.invalid_enum_value;
|
||||||
|
options: (string | number)[];
|
||||||
|
}
|
||||||
|
export interface ZodInvalidArgumentsIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_arguments;
|
||||||
|
argumentsError: ZodError;
|
||||||
|
}
|
||||||
|
export interface ZodInvalidReturnTypeIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_return_type;
|
||||||
|
returnTypeError: ZodError;
|
||||||
|
}
|
||||||
|
export interface ZodInvalidDateIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_date;
|
||||||
|
}
|
||||||
|
export declare type StringValidation = "email" | "url" | "emoji" | "uuid" | "regex" | "cuid" | "cuid2" | "ulid" | "datetime" | "ip" | {
|
||||||
|
includes: string;
|
||||||
|
position?: number;
|
||||||
|
} | {
|
||||||
|
startsWith: string;
|
||||||
|
} | {
|
||||||
|
endsWith: string;
|
||||||
|
};
|
||||||
|
export interface ZodInvalidStringIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_string;
|
||||||
|
validation: StringValidation;
|
||||||
|
}
|
||||||
|
export interface ZodTooSmallIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.too_small;
|
||||||
|
minimum: number | bigint;
|
||||||
|
inclusive: boolean;
|
||||||
|
exact?: boolean;
|
||||||
|
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
||||||
|
}
|
||||||
|
export interface ZodTooBigIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.too_big;
|
||||||
|
maximum: number | bigint;
|
||||||
|
inclusive: boolean;
|
||||||
|
exact?: boolean;
|
||||||
|
type: "array" | "string" | "number" | "set" | "date" | "bigint";
|
||||||
|
}
|
||||||
|
export interface ZodInvalidIntersectionTypesIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.invalid_intersection_types;
|
||||||
|
}
|
||||||
|
export interface ZodNotMultipleOfIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.not_multiple_of;
|
||||||
|
multipleOf: number | bigint;
|
||||||
|
}
|
||||||
|
export interface ZodNotFiniteIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.not_finite;
|
||||||
|
}
|
||||||
|
export interface ZodCustomIssue extends ZodIssueBase {
|
||||||
|
code: typeof ZodIssueCode.custom;
|
||||||
|
params?: {
|
||||||
|
[k: string]: any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export declare type DenormalizedError = {
|
||||||
|
[k: string]: DenormalizedError | string[];
|
||||||
|
};
|
||||||
|
export declare type ZodIssueOptionalMessage = ZodInvalidTypeIssue | ZodInvalidLiteralIssue | ZodUnrecognizedKeysIssue | ZodInvalidUnionIssue | ZodInvalidUnionDiscriminatorIssue | ZodInvalidEnumValueIssue | ZodInvalidArgumentsIssue | ZodInvalidReturnTypeIssue | ZodInvalidDateIssue | ZodInvalidStringIssue | ZodTooSmallIssue | ZodTooBigIssue | ZodInvalidIntersectionTypesIssue | ZodNotMultipleOfIssue | ZodNotFiniteIssue | ZodCustomIssue;
|
||||||
|
export declare type ZodIssue = ZodIssueOptionalMessage & {
|
||||||
|
fatal?: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
export declare const quotelessJson: (obj: any) => string;
|
||||||
|
declare type recursiveZodFormattedError<T> = T extends [any, ...any[]] ? {
|
||||||
|
[K in keyof T]?: ZodFormattedError<T[K]>;
|
||||||
|
} : T extends any[] ? {
|
||||||
|
[k: number]: ZodFormattedError<T[number]>;
|
||||||
|
} : T extends object ? {
|
||||||
|
[K in keyof T]?: ZodFormattedError<T[K]>;
|
||||||
|
} : unknown;
|
||||||
|
export declare type ZodFormattedError<T, U = string> = {
|
||||||
|
_errors: U[];
|
||||||
|
} & recursiveZodFormattedError<NonNullable<T>>;
|
||||||
|
export declare type inferFormattedError<T extends ZodType<any, any, any>, U = string> = ZodFormattedError<TypeOf<T>, U>;
|
||||||
|
export declare class ZodError<T = any> extends Error {
|
||||||
|
issues: ZodIssue[];
|
||||||
|
get errors(): ZodIssue[];
|
||||||
|
constructor(issues: ZodIssue[]);
|
||||||
|
format(): ZodFormattedError<T>;
|
||||||
|
format<U>(mapper: (issue: ZodIssue) => U): ZodFormattedError<T, U>;
|
||||||
|
static create: (issues: ZodIssue[]) => ZodError<any>;
|
||||||
|
toString(): string;
|
||||||
|
get message(): string;
|
||||||
|
get isEmpty(): boolean;
|
||||||
|
addIssue: (sub: ZodIssue) => void;
|
||||||
|
addIssues: (subs?: ZodIssue[]) => void;
|
||||||
|
flatten(): typeToFlattenedError<T>;
|
||||||
|
flatten<U>(mapper?: (issue: ZodIssue) => U): typeToFlattenedError<T, U>;
|
||||||
|
get formErrors(): typeToFlattenedError<T, string>;
|
||||||
|
}
|
||||||
|
declare type stripPath<T extends object> = T extends any ? util.OmitKeys<T, "path"> : never;
|
||||||
|
export declare type IssueData = stripPath<ZodIssueOptionalMessage> & {
|
||||||
|
path?: (string | number)[];
|
||||||
|
fatal?: boolean;
|
||||||
|
};
|
||||||
|
export declare type ErrorMapCtx = {
|
||||||
|
defaultError: string;
|
||||||
|
data: any;
|
||||||
|
};
|
||||||
|
export declare type ZodErrorMap = (issue: ZodIssueOptionalMessage, _ctx: ErrorMapCtx) => {
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
export {};
|
||||||
124
shared/node_modules/zod/lib/ZodError.js
generated
vendored
Normal file
124
shared/node_modules/zod/lib/ZodError.js
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.ZodError = exports.quotelessJson = exports.ZodIssueCode = void 0;
|
||||||
|
const util_1 = require("./helpers/util");
|
||||||
|
exports.ZodIssueCode = util_1.util.arrayToEnum([
|
||||||
|
"invalid_type",
|
||||||
|
"invalid_literal",
|
||||||
|
"custom",
|
||||||
|
"invalid_union",
|
||||||
|
"invalid_union_discriminator",
|
||||||
|
"invalid_enum_value",
|
||||||
|
"unrecognized_keys",
|
||||||
|
"invalid_arguments",
|
||||||
|
"invalid_return_type",
|
||||||
|
"invalid_date",
|
||||||
|
"invalid_string",
|
||||||
|
"too_small",
|
||||||
|
"too_big",
|
||||||
|
"invalid_intersection_types",
|
||||||
|
"not_multiple_of",
|
||||||
|
"not_finite",
|
||||||
|
]);
|
||||||
|
const quotelessJson = (obj) => {
|
||||||
|
const json = JSON.stringify(obj, null, 2);
|
||||||
|
return json.replace(/"([^"]+)":/g, "$1:");
|
||||||
|
};
|
||||||
|
exports.quotelessJson = quotelessJson;
|
||||||
|
class ZodError extends Error {
|
||||||
|
constructor(issues) {
|
||||||
|
super();
|
||||||
|
this.issues = [];
|
||||||
|
this.addIssue = (sub) => {
|
||||||
|
this.issues = [...this.issues, sub];
|
||||||
|
};
|
||||||
|
this.addIssues = (subs = []) => {
|
||||||
|
this.issues = [...this.issues, ...subs];
|
||||||
|
};
|
||||||
|
const actualProto = new.target.prototype;
|
||||||
|
if (Object.setPrototypeOf) {
|
||||||
|
Object.setPrototypeOf(this, actualProto);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.__proto__ = actualProto;
|
||||||
|
}
|
||||||
|
this.name = "ZodError";
|
||||||
|
this.issues = issues;
|
||||||
|
}
|
||||||
|
get errors() {
|
||||||
|
return this.issues;
|
||||||
|
}
|
||||||
|
format(_mapper) {
|
||||||
|
const mapper = _mapper ||
|
||||||
|
function (issue) {
|
||||||
|
return issue.message;
|
||||||
|
};
|
||||||
|
const fieldErrors = { _errors: [] };
|
||||||
|
const processError = (error) => {
|
||||||
|
for (const issue of error.issues) {
|
||||||
|
if (issue.code === "invalid_union") {
|
||||||
|
issue.unionErrors.map(processError);
|
||||||
|
}
|
||||||
|
else if (issue.code === "invalid_return_type") {
|
||||||
|
processError(issue.returnTypeError);
|
||||||
|
}
|
||||||
|
else if (issue.code === "invalid_arguments") {
|
||||||
|
processError(issue.argumentsError);
|
||||||
|
}
|
||||||
|
else if (issue.path.length === 0) {
|
||||||
|
fieldErrors._errors.push(mapper(issue));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let curr = fieldErrors;
|
||||||
|
let i = 0;
|
||||||
|
while (i < issue.path.length) {
|
||||||
|
const el = issue.path[i];
|
||||||
|
const terminal = i === issue.path.length - 1;
|
||||||
|
if (!terminal) {
|
||||||
|
curr[el] = curr[el] || { _errors: [] };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curr[el] = curr[el] || { _errors: [] };
|
||||||
|
curr[el]._errors.push(mapper(issue));
|
||||||
|
}
|
||||||
|
curr = curr[el];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
processError(this);
|
||||||
|
return fieldErrors;
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
get message() {
|
||||||
|
return JSON.stringify(this.issues, util_1.util.jsonStringifyReplacer, 2);
|
||||||
|
}
|
||||||
|
get isEmpty() {
|
||||||
|
return this.issues.length === 0;
|
||||||
|
}
|
||||||
|
flatten(mapper = (issue) => issue.message) {
|
||||||
|
const fieldErrors = {};
|
||||||
|
const formErrors = [];
|
||||||
|
for (const sub of this.issues) {
|
||||||
|
if (sub.path.length > 0) {
|
||||||
|
fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || [];
|
||||||
|
fieldErrors[sub.path[0]].push(mapper(sub));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
formErrors.push(mapper(sub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { formErrors, fieldErrors };
|
||||||
|
}
|
||||||
|
get formErrors() {
|
||||||
|
return this.flatten();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ZodError = ZodError;
|
||||||
|
ZodError.create = (issues) => {
|
||||||
|
const error = new ZodError(issues);
|
||||||
|
return error;
|
||||||
|
};
|
||||||
17
shared/node_modules/zod/lib/__tests__/Mocker.d.ts
generated
vendored
Normal file
17
shared/node_modules/zod/lib/__tests__/Mocker.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
export declare class Mocker {
|
||||||
|
pick: (...args: any[]) => any;
|
||||||
|
get string(): string;
|
||||||
|
get number(): number;
|
||||||
|
get bigint(): bigint;
|
||||||
|
get boolean(): boolean;
|
||||||
|
get date(): Date;
|
||||||
|
get symbol(): symbol;
|
||||||
|
get null(): null;
|
||||||
|
get undefined(): undefined;
|
||||||
|
get stringOptional(): any;
|
||||||
|
get stringNullable(): any;
|
||||||
|
get numberOptional(): any;
|
||||||
|
get numberNullable(): any;
|
||||||
|
get booleanOptional(): any;
|
||||||
|
get booleanNullable(): any;
|
||||||
|
}
|
||||||
57
shared/node_modules/zod/lib/__tests__/Mocker.js
generated
vendored
Normal file
57
shared/node_modules/zod/lib/__tests__/Mocker.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Mocker = void 0;
|
||||||
|
function getRandomInt(max) {
|
||||||
|
return Math.floor(Math.random() * Math.floor(max));
|
||||||
|
}
|
||||||
|
const testSymbol = Symbol("test");
|
||||||
|
class Mocker {
|
||||||
|
constructor() {
|
||||||
|
this.pick = (...args) => {
|
||||||
|
return args[getRandomInt(args.length)];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
get string() {
|
||||||
|
return Math.random().toString(36).substring(7);
|
||||||
|
}
|
||||||
|
get number() {
|
||||||
|
return Math.random() * 100;
|
||||||
|
}
|
||||||
|
get bigint() {
|
||||||
|
return BigInt(Math.floor(Math.random() * 10000));
|
||||||
|
}
|
||||||
|
get boolean() {
|
||||||
|
return Math.random() < 0.5;
|
||||||
|
}
|
||||||
|
get date() {
|
||||||
|
return new Date(Math.floor(Date.now() * Math.random()));
|
||||||
|
}
|
||||||
|
get symbol() {
|
||||||
|
return testSymbol;
|
||||||
|
}
|
||||||
|
get null() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
get undefined() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
get stringOptional() {
|
||||||
|
return this.pick(this.string, this.undefined);
|
||||||
|
}
|
||||||
|
get stringNullable() {
|
||||||
|
return this.pick(this.string, this.null);
|
||||||
|
}
|
||||||
|
get numberOptional() {
|
||||||
|
return this.pick(this.number, this.undefined);
|
||||||
|
}
|
||||||
|
get numberNullable() {
|
||||||
|
return this.pick(this.number, this.null);
|
||||||
|
}
|
||||||
|
get booleanOptional() {
|
||||||
|
return this.pick(this.boolean, this.undefined);
|
||||||
|
}
|
||||||
|
get booleanNullable() {
|
||||||
|
return this.pick(this.boolean, this.null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Mocker = Mocker;
|
||||||
5
shared/node_modules/zod/lib/benchmarks/discriminatedUnion.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/benchmarks/discriminatedUnion.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Benchmark from "benchmark";
|
||||||
|
declare const _default: {
|
||||||
|
suites: Benchmark.Suite[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
79
shared/node_modules/zod/lib/benchmarks/discriminatedUnion.js
generated
vendored
Normal file
79
shared/node_modules/zod/lib/benchmarks/discriminatedUnion.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const benchmark_1 = __importDefault(require("benchmark"));
|
||||||
|
const index_1 = require("../index");
|
||||||
|
const doubleSuite = new benchmark_1.default.Suite("z.discriminatedUnion: double");
|
||||||
|
const manySuite = new benchmark_1.default.Suite("z.discriminatedUnion: many");
|
||||||
|
const aSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("a"),
|
||||||
|
});
|
||||||
|
const objA = {
|
||||||
|
type: "a",
|
||||||
|
};
|
||||||
|
const bSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("b"),
|
||||||
|
});
|
||||||
|
const objB = {
|
||||||
|
type: "b",
|
||||||
|
};
|
||||||
|
const cSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("c"),
|
||||||
|
});
|
||||||
|
const objC = {
|
||||||
|
type: "c",
|
||||||
|
};
|
||||||
|
const dSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("d"),
|
||||||
|
});
|
||||||
|
const double = index_1.z.discriminatedUnion("type", [aSchema, bSchema]);
|
||||||
|
const many = index_1.z.discriminatedUnion("type", [aSchema, bSchema, cSchema, dSchema]);
|
||||||
|
doubleSuite
|
||||||
|
.add("valid: a", () => {
|
||||||
|
double.parse(objA);
|
||||||
|
})
|
||||||
|
.add("valid: b", () => {
|
||||||
|
double.parse(objB);
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
double.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.add("invalid: wrong shape", () => {
|
||||||
|
try {
|
||||||
|
double.parse(objC);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${doubleSuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
manySuite
|
||||||
|
.add("valid: a", () => {
|
||||||
|
many.parse(objA);
|
||||||
|
})
|
||||||
|
.add("valid: c", () => {
|
||||||
|
many.parse(objC);
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
many.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.add("invalid: wrong shape", () => {
|
||||||
|
try {
|
||||||
|
many.parse({ type: "unknown" });
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${manySuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
exports.default = {
|
||||||
|
suites: [doubleSuite, manySuite],
|
||||||
|
};
|
||||||
1
shared/node_modules/zod/lib/benchmarks/index.d.ts
generated
vendored
Normal file
1
shared/node_modules/zod/lib/benchmarks/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {};
|
||||||
46
shared/node_modules/zod/lib/benchmarks/index.js
generated
vendored
Normal file
46
shared/node_modules/zod/lib/benchmarks/index.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const discriminatedUnion_1 = __importDefault(require("./discriminatedUnion"));
|
||||||
|
const object_1 = __importDefault(require("./object"));
|
||||||
|
const primitives_1 = __importDefault(require("./primitives"));
|
||||||
|
const realworld_1 = __importDefault(require("./realworld"));
|
||||||
|
const string_1 = __importDefault(require("./string"));
|
||||||
|
const union_1 = __importDefault(require("./union"));
|
||||||
|
const argv = process.argv.slice(2);
|
||||||
|
let suites = [];
|
||||||
|
if (!argv.length) {
|
||||||
|
suites = [
|
||||||
|
...realworld_1.default.suites,
|
||||||
|
...primitives_1.default.suites,
|
||||||
|
...string_1.default.suites,
|
||||||
|
...object_1.default.suites,
|
||||||
|
...union_1.default.suites,
|
||||||
|
...discriminatedUnion_1.default.suites,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (argv.includes("--realworld")) {
|
||||||
|
suites.push(...realworld_1.default.suites);
|
||||||
|
}
|
||||||
|
if (argv.includes("--primitives")) {
|
||||||
|
suites.push(...primitives_1.default.suites);
|
||||||
|
}
|
||||||
|
if (argv.includes("--string")) {
|
||||||
|
suites.push(...string_1.default.suites);
|
||||||
|
}
|
||||||
|
if (argv.includes("--object")) {
|
||||||
|
suites.push(...object_1.default.suites);
|
||||||
|
}
|
||||||
|
if (argv.includes("--union")) {
|
||||||
|
suites.push(...union_1.default.suites);
|
||||||
|
}
|
||||||
|
if (argv.includes("--discriminatedUnion")) {
|
||||||
|
suites.push(...discriminatedUnion_1.default.suites);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const suite of suites) {
|
||||||
|
suite.run();
|
||||||
|
}
|
||||||
5
shared/node_modules/zod/lib/benchmarks/object.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/benchmarks/object.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Benchmark from "benchmark";
|
||||||
|
declare const _default: {
|
||||||
|
suites: Benchmark.Suite[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
70
shared/node_modules/zod/lib/benchmarks/object.js
generated
vendored
Normal file
70
shared/node_modules/zod/lib/benchmarks/object.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const benchmark_1 = __importDefault(require("benchmark"));
|
||||||
|
const index_1 = require("../index");
|
||||||
|
const emptySuite = new benchmark_1.default.Suite("z.object: empty");
|
||||||
|
const shortSuite = new benchmark_1.default.Suite("z.object: short");
|
||||||
|
const longSuite = new benchmark_1.default.Suite("z.object: long");
|
||||||
|
const empty = index_1.z.object({});
|
||||||
|
const short = index_1.z.object({
|
||||||
|
string: index_1.z.string(),
|
||||||
|
});
|
||||||
|
const long = index_1.z.object({
|
||||||
|
string: index_1.z.string(),
|
||||||
|
number: index_1.z.number(),
|
||||||
|
boolean: index_1.z.boolean(),
|
||||||
|
});
|
||||||
|
emptySuite
|
||||||
|
.add("valid", () => {
|
||||||
|
empty.parse({});
|
||||||
|
})
|
||||||
|
.add("valid: extra keys", () => {
|
||||||
|
empty.parse({ string: "string" });
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
empty.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${emptySuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
shortSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
short.parse({ string: "string" });
|
||||||
|
})
|
||||||
|
.add("valid: extra keys", () => {
|
||||||
|
short.parse({ string: "string", number: 42 });
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
short.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${shortSuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
longSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
long.parse({ string: "string", number: 42, boolean: true });
|
||||||
|
})
|
||||||
|
.add("valid: extra keys", () => {
|
||||||
|
long.parse({ string: "string", number: 42, boolean: true, list: [] });
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
long.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${longSuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
exports.default = {
|
||||||
|
suites: [emptySuite, shortSuite, longSuite],
|
||||||
|
};
|
||||||
5
shared/node_modules/zod/lib/benchmarks/primitives.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/benchmarks/primitives.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Benchmark from "benchmark";
|
||||||
|
declare const _default: {
|
||||||
|
suites: Benchmark.Suite[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
136
shared/node_modules/zod/lib/benchmarks/primitives.js
generated
vendored
Normal file
136
shared/node_modules/zod/lib/benchmarks/primitives.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const benchmark_1 = __importDefault(require("benchmark"));
|
||||||
|
const Mocker_1 = require("../__tests__/Mocker");
|
||||||
|
const index_1 = require("../index");
|
||||||
|
const val = new Mocker_1.Mocker();
|
||||||
|
const enumSuite = new benchmark_1.default.Suite("z.enum");
|
||||||
|
const enumSchema = index_1.z.enum(["a", "b", "c"]);
|
||||||
|
enumSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
enumSchema.parse("a");
|
||||||
|
})
|
||||||
|
.add("invalid", () => {
|
||||||
|
try {
|
||||||
|
enumSchema.parse("x");
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`z.enum: ${e.target}`);
|
||||||
|
});
|
||||||
|
const undefinedSuite = new benchmark_1.default.Suite("z.undefined");
|
||||||
|
const undefinedSchema = index_1.z.undefined();
|
||||||
|
undefinedSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
undefinedSchema.parse(undefined);
|
||||||
|
})
|
||||||
|
.add("invalid", () => {
|
||||||
|
try {
|
||||||
|
undefinedSchema.parse(1);
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`z.undefined: ${e.target}`);
|
||||||
|
});
|
||||||
|
const literalSuite = new benchmark_1.default.Suite("z.literal");
|
||||||
|
const short = "short";
|
||||||
|
const bad = "bad";
|
||||||
|
const literalSchema = index_1.z.literal("short");
|
||||||
|
literalSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
literalSchema.parse(short);
|
||||||
|
})
|
||||||
|
.add("invalid", () => {
|
||||||
|
try {
|
||||||
|
literalSchema.parse(bad);
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`z.literal: ${e.target}`);
|
||||||
|
});
|
||||||
|
const numberSuite = new benchmark_1.default.Suite("z.number");
|
||||||
|
const numberSchema = index_1.z.number().int();
|
||||||
|
numberSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
numberSchema.parse(1);
|
||||||
|
})
|
||||||
|
.add("invalid type", () => {
|
||||||
|
try {
|
||||||
|
numberSchema.parse("bad");
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.add("invalid number", () => {
|
||||||
|
try {
|
||||||
|
numberSchema.parse(0.5);
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`z.number: ${e.target}`);
|
||||||
|
});
|
||||||
|
const dateSuite = new benchmark_1.default.Suite("z.date");
|
||||||
|
const plainDate = index_1.z.date();
|
||||||
|
const minMaxDate = index_1.z
|
||||||
|
.date()
|
||||||
|
.min(new Date("2021-01-01"))
|
||||||
|
.max(new Date("2030-01-01"));
|
||||||
|
dateSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
plainDate.parse(new Date());
|
||||||
|
})
|
||||||
|
.add("invalid", () => {
|
||||||
|
try {
|
||||||
|
plainDate.parse(1);
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.add("valid min and max", () => {
|
||||||
|
minMaxDate.parse(new Date("2023-01-01"));
|
||||||
|
})
|
||||||
|
.add("invalid min", () => {
|
||||||
|
try {
|
||||||
|
minMaxDate.parse(new Date("2019-01-01"));
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.add("invalid max", () => {
|
||||||
|
try {
|
||||||
|
minMaxDate.parse(new Date("2031-01-01"));
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`z.date: ${e.target}`);
|
||||||
|
});
|
||||||
|
const symbolSuite = new benchmark_1.default.Suite("z.symbol");
|
||||||
|
const symbolSchema = index_1.z.symbol();
|
||||||
|
symbolSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
symbolSchema.parse(val.symbol);
|
||||||
|
})
|
||||||
|
.add("invalid", () => {
|
||||||
|
try {
|
||||||
|
symbolSchema.parse(1);
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`z.symbol: ${e.target}`);
|
||||||
|
});
|
||||||
|
exports.default = {
|
||||||
|
suites: [
|
||||||
|
enumSuite,
|
||||||
|
undefinedSuite,
|
||||||
|
literalSuite,
|
||||||
|
numberSuite,
|
||||||
|
dateSuite,
|
||||||
|
symbolSuite,
|
||||||
|
],
|
||||||
|
};
|
||||||
5
shared/node_modules/zod/lib/benchmarks/realworld.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/benchmarks/realworld.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Benchmark from "benchmark";
|
||||||
|
declare const _default: {
|
||||||
|
suites: Benchmark.Suite[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
56
shared/node_modules/zod/lib/benchmarks/realworld.js
generated
vendored
Normal file
56
shared/node_modules/zod/lib/benchmarks/realworld.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const benchmark_1 = __importDefault(require("benchmark"));
|
||||||
|
const index_1 = require("../index");
|
||||||
|
const shortSuite = new benchmark_1.default.Suite("realworld");
|
||||||
|
const People = index_1.z.array(index_1.z.object({
|
||||||
|
type: index_1.z.literal("person"),
|
||||||
|
hair: index_1.z.enum(["blue", "brown"]),
|
||||||
|
active: index_1.z.boolean(),
|
||||||
|
name: index_1.z.string(),
|
||||||
|
age: index_1.z.number().int(),
|
||||||
|
hobbies: index_1.z.array(index_1.z.string()),
|
||||||
|
address: index_1.z.object({
|
||||||
|
street: index_1.z.string(),
|
||||||
|
zip: index_1.z.string(),
|
||||||
|
country: index_1.z.string(),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
let i = 0;
|
||||||
|
function num() {
|
||||||
|
return ++i;
|
||||||
|
}
|
||||||
|
function str() {
|
||||||
|
return (++i % 100).toString(16);
|
||||||
|
}
|
||||||
|
function array(fn) {
|
||||||
|
return Array.from({ length: ++i % 10 }, () => fn());
|
||||||
|
}
|
||||||
|
const people = Array.from({ length: 100 }, () => {
|
||||||
|
return {
|
||||||
|
type: "person",
|
||||||
|
hair: i % 2 ? "blue" : "brown",
|
||||||
|
active: !!(i % 2),
|
||||||
|
name: str(),
|
||||||
|
age: num(),
|
||||||
|
hobbies: array(str),
|
||||||
|
address: {
|
||||||
|
street: str(),
|
||||||
|
zip: str(),
|
||||||
|
country: str(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
shortSuite
|
||||||
|
.add("valid", () => {
|
||||||
|
People.parse(people);
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${shortSuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
exports.default = {
|
||||||
|
suites: [shortSuite],
|
||||||
|
};
|
||||||
5
shared/node_modules/zod/lib/benchmarks/string.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/benchmarks/string.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Benchmark from "benchmark";
|
||||||
|
declare const _default: {
|
||||||
|
suites: Benchmark.Suite[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
55
shared/node_modules/zod/lib/benchmarks/string.js
generated
vendored
Normal file
55
shared/node_modules/zod/lib/benchmarks/string.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const benchmark_1 = __importDefault(require("benchmark"));
|
||||||
|
const index_1 = require("../index");
|
||||||
|
const SUITE_NAME = "z.string";
|
||||||
|
const suite = new benchmark_1.default.Suite(SUITE_NAME);
|
||||||
|
const empty = "";
|
||||||
|
const short = "short";
|
||||||
|
const long = "long".repeat(256);
|
||||||
|
const manual = (str) => {
|
||||||
|
if (typeof str !== "string") {
|
||||||
|
throw new Error("Not a string");
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
const stringSchema = index_1.z.string();
|
||||||
|
const optionalStringSchema = index_1.z.string().optional();
|
||||||
|
const optionalNullableStringSchema = index_1.z.string().optional().nullable();
|
||||||
|
suite
|
||||||
|
.add("empty string", () => {
|
||||||
|
stringSchema.parse(empty);
|
||||||
|
})
|
||||||
|
.add("short string", () => {
|
||||||
|
stringSchema.parse(short);
|
||||||
|
})
|
||||||
|
.add("long string", () => {
|
||||||
|
stringSchema.parse(long);
|
||||||
|
})
|
||||||
|
.add("optional string", () => {
|
||||||
|
optionalStringSchema.parse(long);
|
||||||
|
})
|
||||||
|
.add("nullable string", () => {
|
||||||
|
optionalNullableStringSchema.parse(long);
|
||||||
|
})
|
||||||
|
.add("nullable (null) string", () => {
|
||||||
|
optionalNullableStringSchema.parse(null);
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
stringSchema.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.add("manual parser: long", () => {
|
||||||
|
manual(long);
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${SUITE_NAME}: ${e.target}`);
|
||||||
|
});
|
||||||
|
exports.default = {
|
||||||
|
suites: [suite],
|
||||||
|
};
|
||||||
5
shared/node_modules/zod/lib/benchmarks/union.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/benchmarks/union.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Benchmark from "benchmark";
|
||||||
|
declare const _default: {
|
||||||
|
suites: Benchmark.Suite[];
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
79
shared/node_modules/zod/lib/benchmarks/union.js
generated
vendored
Normal file
79
shared/node_modules/zod/lib/benchmarks/union.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const benchmark_1 = __importDefault(require("benchmark"));
|
||||||
|
const index_1 = require("../index");
|
||||||
|
const doubleSuite = new benchmark_1.default.Suite("z.union: double");
|
||||||
|
const manySuite = new benchmark_1.default.Suite("z.union: many");
|
||||||
|
const aSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("a"),
|
||||||
|
});
|
||||||
|
const objA = {
|
||||||
|
type: "a",
|
||||||
|
};
|
||||||
|
const bSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("b"),
|
||||||
|
});
|
||||||
|
const objB = {
|
||||||
|
type: "b",
|
||||||
|
};
|
||||||
|
const cSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("c"),
|
||||||
|
});
|
||||||
|
const objC = {
|
||||||
|
type: "c",
|
||||||
|
};
|
||||||
|
const dSchema = index_1.z.object({
|
||||||
|
type: index_1.z.literal("d"),
|
||||||
|
});
|
||||||
|
const double = index_1.z.union([aSchema, bSchema]);
|
||||||
|
const many = index_1.z.union([aSchema, bSchema, cSchema, dSchema]);
|
||||||
|
doubleSuite
|
||||||
|
.add("valid: a", () => {
|
||||||
|
double.parse(objA);
|
||||||
|
})
|
||||||
|
.add("valid: b", () => {
|
||||||
|
double.parse(objB);
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
double.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.add("invalid: wrong shape", () => {
|
||||||
|
try {
|
||||||
|
double.parse(objC);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${doubleSuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
manySuite
|
||||||
|
.add("valid: a", () => {
|
||||||
|
many.parse(objA);
|
||||||
|
})
|
||||||
|
.add("valid: c", () => {
|
||||||
|
many.parse(objC);
|
||||||
|
})
|
||||||
|
.add("invalid: null", () => {
|
||||||
|
try {
|
||||||
|
many.parse(null);
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.add("invalid: wrong shape", () => {
|
||||||
|
try {
|
||||||
|
many.parse({ type: "unknown" });
|
||||||
|
}
|
||||||
|
catch (err) { }
|
||||||
|
})
|
||||||
|
.on("cycle", (e) => {
|
||||||
|
console.log(`${manySuite.name}: ${e.target}`);
|
||||||
|
});
|
||||||
|
exports.default = {
|
||||||
|
suites: [doubleSuite, manySuite],
|
||||||
|
};
|
||||||
5
shared/node_modules/zod/lib/errors.d.ts
generated
vendored
Normal file
5
shared/node_modules/zod/lib/errors.d.ts
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import defaultErrorMap from "./locales/en";
|
||||||
|
import type { ZodErrorMap } from "./ZodError";
|
||||||
|
export { defaultErrorMap };
|
||||||
|
export declare function setErrorMap(map: ZodErrorMap): void;
|
||||||
|
export declare function getErrorMap(): ZodErrorMap;
|
||||||
17
shared/node_modules/zod/lib/errors.js
generated
vendored
Normal file
17
shared/node_modules/zod/lib/errors.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getErrorMap = exports.setErrorMap = exports.defaultErrorMap = void 0;
|
||||||
|
const en_1 = __importDefault(require("./locales/en"));
|
||||||
|
exports.defaultErrorMap = en_1.default;
|
||||||
|
let overrideErrorMap = en_1.default;
|
||||||
|
function setErrorMap(map) {
|
||||||
|
overrideErrorMap = map;
|
||||||
|
}
|
||||||
|
exports.setErrorMap = setErrorMap;
|
||||||
|
function getErrorMap() {
|
||||||
|
return overrideErrorMap;
|
||||||
|
}
|
||||||
|
exports.getErrorMap = getErrorMap;
|
||||||
6
shared/node_modules/zod/lib/external.d.ts
generated
vendored
Normal file
6
shared/node_modules/zod/lib/external.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export * from "./errors";
|
||||||
|
export * from "./helpers/parseUtil";
|
||||||
|
export * from "./helpers/typeAliases";
|
||||||
|
export * from "./helpers/util";
|
||||||
|
export * from "./types";
|
||||||
|
export * from "./ZodError";
|
||||||
18
shared/node_modules/zod/lib/external.js
generated
vendored
Normal file
18
shared/node_modules/zod/lib/external.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||||
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
__exportStar(require("./errors"), exports);
|
||||||
|
__exportStar(require("./helpers/parseUtil"), exports);
|
||||||
|
__exportStar(require("./helpers/typeAliases"), exports);
|
||||||
|
__exportStar(require("./helpers/util"), exports);
|
||||||
|
__exportStar(require("./types"), exports);
|
||||||
|
__exportStar(require("./ZodError"), exports);
|
||||||
8
shared/node_modules/zod/lib/helpers/enumUtil.d.ts
generated
vendored
Normal file
8
shared/node_modules/zod/lib/helpers/enumUtil.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export declare namespace enumUtil {
|
||||||
|
type UnionToIntersectionFn<T> = (T extends unknown ? (k: () => T) => void : never) extends (k: infer Intersection) => void ? Intersection : never;
|
||||||
|
type GetUnionLast<T> = UnionToIntersectionFn<T> extends () => infer Last ? Last : never;
|
||||||
|
type UnionToTuple<T, Tuple extends unknown[] = []> = [T] extends [never] ? Tuple : UnionToTuple<Exclude<T, GetUnionLast<T>>, [GetUnionLast<T>, ...Tuple]>;
|
||||||
|
type CastToStringTuple<T> = T extends [string, ...string[]] ? T : never;
|
||||||
|
export type UnionToTupleString<T> = CastToStringTuple<UnionToTuple<T>>;
|
||||||
|
export {};
|
||||||
|
}
|
||||||
2
shared/node_modules/zod/lib/helpers/enumUtil.js
generated
vendored
Normal file
2
shared/node_modules/zod/lib/helpers/enumUtil.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
9
shared/node_modules/zod/lib/helpers/errorUtil.d.ts
generated
vendored
Normal file
9
shared/node_modules/zod/lib/helpers/errorUtil.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export declare namespace errorUtil {
|
||||||
|
type ErrMessage = string | {
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
const errToObj: (message?: ErrMessage | undefined) => {
|
||||||
|
message?: string | undefined;
|
||||||
|
};
|
||||||
|
const toString: (message?: ErrMessage | undefined) => string | undefined;
|
||||||
|
}
|
||||||
8
shared/node_modules/zod/lib/helpers/errorUtil.js
generated
vendored
Normal file
8
shared/node_modules/zod/lib/helpers/errorUtil.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.errorUtil = void 0;
|
||||||
|
var errorUtil;
|
||||||
|
(function (errorUtil) {
|
||||||
|
errorUtil.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
||||||
|
errorUtil.toString = (message) => typeof message === "string" ? message : message === null || message === void 0 ? void 0 : message.message;
|
||||||
|
})(errorUtil = exports.errorUtil || (exports.errorUtil = {}));
|
||||||
78
shared/node_modules/zod/lib/helpers/parseUtil.d.ts
generated
vendored
Normal file
78
shared/node_modules/zod/lib/helpers/parseUtil.d.ts
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import type { IssueData, ZodErrorMap, ZodIssue } from "../ZodError";
|
||||||
|
import type { ZodParsedType } from "./util";
|
||||||
|
export declare const makeIssue: (params: {
|
||||||
|
data: any;
|
||||||
|
path: (string | number)[];
|
||||||
|
errorMaps: ZodErrorMap[];
|
||||||
|
issueData: IssueData;
|
||||||
|
}) => ZodIssue;
|
||||||
|
export declare type ParseParams = {
|
||||||
|
path: (string | number)[];
|
||||||
|
errorMap: ZodErrorMap;
|
||||||
|
async: boolean;
|
||||||
|
};
|
||||||
|
export declare type ParsePathComponent = string | number;
|
||||||
|
export declare type ParsePath = ParsePathComponent[];
|
||||||
|
export declare const EMPTY_PATH: ParsePath;
|
||||||
|
export interface ParseContext {
|
||||||
|
readonly common: {
|
||||||
|
readonly issues: ZodIssue[];
|
||||||
|
readonly contextualErrorMap?: ZodErrorMap;
|
||||||
|
readonly async: boolean;
|
||||||
|
};
|
||||||
|
readonly path: ParsePath;
|
||||||
|
readonly schemaErrorMap?: ZodErrorMap;
|
||||||
|
readonly parent: ParseContext | null;
|
||||||
|
readonly data: any;
|
||||||
|
readonly parsedType: ZodParsedType;
|
||||||
|
}
|
||||||
|
export declare type ParseInput = {
|
||||||
|
data: any;
|
||||||
|
path: (string | number)[];
|
||||||
|
parent: ParseContext;
|
||||||
|
};
|
||||||
|
export declare function addIssueToContext(ctx: ParseContext, issueData: IssueData): void;
|
||||||
|
export declare type ObjectPair = {
|
||||||
|
key: SyncParseReturnType<any>;
|
||||||
|
value: SyncParseReturnType<any>;
|
||||||
|
};
|
||||||
|
export declare class ParseStatus {
|
||||||
|
value: "aborted" | "dirty" | "valid";
|
||||||
|
dirty(): void;
|
||||||
|
abort(): void;
|
||||||
|
static mergeArray(status: ParseStatus, results: SyncParseReturnType<any>[]): SyncParseReturnType;
|
||||||
|
static mergeObjectAsync(status: ParseStatus, pairs: {
|
||||||
|
key: ParseReturnType<any>;
|
||||||
|
value: ParseReturnType<any>;
|
||||||
|
}[]): Promise<SyncParseReturnType<any>>;
|
||||||
|
static mergeObjectSync(status: ParseStatus, pairs: {
|
||||||
|
key: SyncParseReturnType<any>;
|
||||||
|
value: SyncParseReturnType<any>;
|
||||||
|
alwaysSet?: boolean;
|
||||||
|
}[]): SyncParseReturnType;
|
||||||
|
}
|
||||||
|
export interface ParseResult {
|
||||||
|
status: "aborted" | "dirty" | "valid";
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
export declare type INVALID = {
|
||||||
|
status: "aborted";
|
||||||
|
};
|
||||||
|
export declare const INVALID: INVALID;
|
||||||
|
export declare type DIRTY<T> = {
|
||||||
|
status: "dirty";
|
||||||
|
value: T;
|
||||||
|
};
|
||||||
|
export declare const DIRTY: <T>(value: T) => DIRTY<T>;
|
||||||
|
export declare type OK<T> = {
|
||||||
|
status: "valid";
|
||||||
|
value: T;
|
||||||
|
};
|
||||||
|
export declare const OK: <T>(value: T) => OK<T>;
|
||||||
|
export declare type SyncParseReturnType<T = any> = OK<T> | DIRTY<T> | INVALID;
|
||||||
|
export declare type AsyncParseReturnType<T> = Promise<SyncParseReturnType<T>>;
|
||||||
|
export declare type ParseReturnType<T> = SyncParseReturnType<T> | AsyncParseReturnType<T>;
|
||||||
|
export declare const isAborted: (x: ParseReturnType<any>) => x is INVALID;
|
||||||
|
export declare const isDirty: <T>(x: ParseReturnType<T>) => x is OK<T> | DIRTY<T>;
|
||||||
|
export declare const isValid: <T>(x: ParseReturnType<T>) => x is OK<T> | DIRTY<T>;
|
||||||
|
export declare const isAsync: <T>(x: ParseReturnType<T>) => x is AsyncParseReturnType<T>;
|
||||||
114
shared/node_modules/zod/lib/helpers/parseUtil.js
generated
vendored
Normal file
114
shared/node_modules/zod/lib/helpers/parseUtil.js
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.isAsync = exports.isValid = exports.isDirty = exports.isAborted = exports.OK = exports.DIRTY = exports.INVALID = exports.ParseStatus = exports.addIssueToContext = exports.EMPTY_PATH = exports.makeIssue = void 0;
|
||||||
|
const errors_1 = require("../errors");
|
||||||
|
const en_1 = __importDefault(require("../locales/en"));
|
||||||
|
const makeIssue = (params) => {
|
||||||
|
const { data, path, errorMaps, issueData } = params;
|
||||||
|
const fullPath = [...path, ...(issueData.path || [])];
|
||||||
|
const fullIssue = {
|
||||||
|
...issueData,
|
||||||
|
path: fullPath,
|
||||||
|
};
|
||||||
|
let errorMessage = "";
|
||||||
|
const maps = errorMaps
|
||||||
|
.filter((m) => !!m)
|
||||||
|
.slice()
|
||||||
|
.reverse();
|
||||||
|
for (const map of maps) {
|
||||||
|
errorMessage = map(fullIssue, { data, defaultError: errorMessage }).message;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...issueData,
|
||||||
|
path: fullPath,
|
||||||
|
message: issueData.message || errorMessage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
exports.makeIssue = makeIssue;
|
||||||
|
exports.EMPTY_PATH = [];
|
||||||
|
function addIssueToContext(ctx, issueData) {
|
||||||
|
const issue = (0, exports.makeIssue)({
|
||||||
|
issueData: issueData,
|
||||||
|
data: ctx.data,
|
||||||
|
path: ctx.path,
|
||||||
|
errorMaps: [
|
||||||
|
ctx.common.contextualErrorMap,
|
||||||
|
ctx.schemaErrorMap,
|
||||||
|
(0, errors_1.getErrorMap)(),
|
||||||
|
en_1.default,
|
||||||
|
].filter((x) => !!x),
|
||||||
|
});
|
||||||
|
ctx.common.issues.push(issue);
|
||||||
|
}
|
||||||
|
exports.addIssueToContext = addIssueToContext;
|
||||||
|
class ParseStatus {
|
||||||
|
constructor() {
|
||||||
|
this.value = "valid";
|
||||||
|
}
|
||||||
|
dirty() {
|
||||||
|
if (this.value === "valid")
|
||||||
|
this.value = "dirty";
|
||||||
|
}
|
||||||
|
abort() {
|
||||||
|
if (this.value !== "aborted")
|
||||||
|
this.value = "aborted";
|
||||||
|
}
|
||||||
|
static mergeArray(status, results) {
|
||||||
|
const arrayValue = [];
|
||||||
|
for (const s of results) {
|
||||||
|
if (s.status === "aborted")
|
||||||
|
return exports.INVALID;
|
||||||
|
if (s.status === "dirty")
|
||||||
|
status.dirty();
|
||||||
|
arrayValue.push(s.value);
|
||||||
|
}
|
||||||
|
return { status: status.value, value: arrayValue };
|
||||||
|
}
|
||||||
|
static async mergeObjectAsync(status, pairs) {
|
||||||
|
const syncPairs = [];
|
||||||
|
for (const pair of pairs) {
|
||||||
|
syncPairs.push({
|
||||||
|
key: await pair.key,
|
||||||
|
value: await pair.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return ParseStatus.mergeObjectSync(status, syncPairs);
|
||||||
|
}
|
||||||
|
static mergeObjectSync(status, pairs) {
|
||||||
|
const finalObject = {};
|
||||||
|
for (const pair of pairs) {
|
||||||
|
const { key, value } = pair;
|
||||||
|
if (key.status === "aborted")
|
||||||
|
return exports.INVALID;
|
||||||
|
if (value.status === "aborted")
|
||||||
|
return exports.INVALID;
|
||||||
|
if (key.status === "dirty")
|
||||||
|
status.dirty();
|
||||||
|
if (value.status === "dirty")
|
||||||
|
status.dirty();
|
||||||
|
if (typeof value.value !== "undefined" || pair.alwaysSet) {
|
||||||
|
finalObject[key.value] = value.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { status: status.value, value: finalObject };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.ParseStatus = ParseStatus;
|
||||||
|
exports.INVALID = Object.freeze({
|
||||||
|
status: "aborted",
|
||||||
|
});
|
||||||
|
const DIRTY = (value) => ({ status: "dirty", value });
|
||||||
|
exports.DIRTY = DIRTY;
|
||||||
|
const OK = (value) => ({ status: "valid", value });
|
||||||
|
exports.OK = OK;
|
||||||
|
const isAborted = (x) => x.status === "aborted";
|
||||||
|
exports.isAborted = isAborted;
|
||||||
|
const isDirty = (x) => x.status === "dirty";
|
||||||
|
exports.isDirty = isDirty;
|
||||||
|
const isValid = (x) => x.status === "valid";
|
||||||
|
exports.isValid = isValid;
|
||||||
|
const isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
||||||
|
exports.isAsync = isAsync;
|
||||||
8
shared/node_modules/zod/lib/helpers/partialUtil.d.ts
generated
vendored
Normal file
8
shared/node_modules/zod/lib/helpers/partialUtil.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import type { ZodArray, ZodNullable, ZodObject, ZodOptional, ZodRawShape, ZodTuple, ZodTupleItems, ZodTypeAny } from "../index";
|
||||||
|
export declare namespace partialUtil {
|
||||||
|
type DeepPartial<T extends ZodTypeAny> = T extends ZodObject<ZodRawShape> ? ZodObject<{
|
||||||
|
[k in keyof T["shape"]]: ZodOptional<DeepPartial<T["shape"][k]>>;
|
||||||
|
}, T["_def"]["unknownKeys"], T["_def"]["catchall"]> : T extends ZodArray<infer Type, infer Card> ? ZodArray<DeepPartial<Type>, Card> : T extends ZodOptional<infer Type> ? ZodOptional<DeepPartial<Type>> : T extends ZodNullable<infer Type> ? ZodNullable<DeepPartial<Type>> : T extends ZodTuple<infer Items> ? {
|
||||||
|
[k in keyof Items]: Items[k] extends ZodTypeAny ? DeepPartial<Items[k]> : never;
|
||||||
|
} extends infer PI ? PI extends ZodTupleItems ? ZodTuple<PI> : never : never : T;
|
||||||
|
}
|
||||||
2
shared/node_modules/zod/lib/helpers/partialUtil.js
generated
vendored
Normal file
2
shared/node_modules/zod/lib/helpers/partialUtil.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
2
shared/node_modules/zod/lib/helpers/typeAliases.d.ts
generated
vendored
Normal file
2
shared/node_modules/zod/lib/helpers/typeAliases.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export declare type Primitive = string | number | symbol | bigint | boolean | null | undefined;
|
||||||
|
export declare type Scalars = Primitive | Primitive[];
|
||||||
2
shared/node_modules/zod/lib/helpers/typeAliases.js
generated
vendored
Normal file
2
shared/node_modules/zod/lib/helpers/typeAliases.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
68
shared/node_modules/zod/lib/helpers/util.d.ts
generated
vendored
Normal file
68
shared/node_modules/zod/lib/helpers/util.d.ts
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
export declare namespace util {
|
||||||
|
type AssertEqual<T, U> = (<V>() => V extends T ? 1 : 2) extends <V>() => V extends U ? 1 : 2 ? true : false;
|
||||||
|
export type isAny<T> = 0 extends 1 & T ? true : false;
|
||||||
|
export const assertEqual: <A, B>(val: AssertEqual<A, B>) => AssertEqual<A, B>;
|
||||||
|
export function assertIs<T>(_arg: T): void;
|
||||||
|
export function assertNever(_x: never): never;
|
||||||
|
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||||
|
export type OmitKeys<T, K extends string> = Pick<T, Exclude<keyof T, K>>;
|
||||||
|
export type MakePartial<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
||||||
|
export const arrayToEnum: <T extends string, U extends [T, ...T[]]>(items: U) => { [k in U[number]]: k; };
|
||||||
|
export const getValidEnumValues: (obj: any) => any[];
|
||||||
|
export const objectValues: (obj: any) => any[];
|
||||||
|
export const objectKeys: ObjectConstructor["keys"];
|
||||||
|
export const find: <T>(arr: T[], checker: (arg: T) => any) => T | undefined;
|
||||||
|
export type identity<T> = objectUtil.identity<T>;
|
||||||
|
export type flatten<T> = objectUtil.flatten<T>;
|
||||||
|
export type noUndefined<T> = T extends undefined ? never : T;
|
||||||
|
export const isInteger: NumberConstructor["isInteger"];
|
||||||
|
export function joinValues<T extends any[]>(array: T, separator?: string): string;
|
||||||
|
export const jsonStringifyReplacer: (_: string, value: any) => any;
|
||||||
|
export {};
|
||||||
|
}
|
||||||
|
export declare namespace objectUtil {
|
||||||
|
export type MergeShapes<U, V> = {
|
||||||
|
[k in Exclude<keyof U, keyof V>]: U[k];
|
||||||
|
} & V;
|
||||||
|
type requiredKeys<T extends object> = {
|
||||||
|
[k in keyof T]: undefined extends T[k] ? never : k;
|
||||||
|
}[keyof T];
|
||||||
|
export type addQuestionMarks<T extends object, R extends keyof T = requiredKeys<T>> = Pick<Required<T>, R> & Partial<T>;
|
||||||
|
export type identity<T> = T;
|
||||||
|
export type flatten<T> = identity<{
|
||||||
|
[k in keyof T]: T[k];
|
||||||
|
}>;
|
||||||
|
export type noNeverKeys<T> = {
|
||||||
|
[k in keyof T]: [T[k]] extends [never] ? never : k;
|
||||||
|
}[keyof T];
|
||||||
|
export type noNever<T> = identity<{
|
||||||
|
[k in noNeverKeys<T>]: k extends keyof T ? T[k] : never;
|
||||||
|
}>;
|
||||||
|
export const mergeShapes: <U, T>(first: U, second: T) => T & U;
|
||||||
|
export type extendShape<A, B> = flatten<Omit<A, keyof B> & B>;
|
||||||
|
export {};
|
||||||
|
}
|
||||||
|
export declare const ZodParsedType: {
|
||||||
|
function: "function";
|
||||||
|
number: "number";
|
||||||
|
string: "string";
|
||||||
|
nan: "nan";
|
||||||
|
integer: "integer";
|
||||||
|
float: "float";
|
||||||
|
boolean: "boolean";
|
||||||
|
date: "date";
|
||||||
|
bigint: "bigint";
|
||||||
|
symbol: "symbol";
|
||||||
|
undefined: "undefined";
|
||||||
|
null: "null";
|
||||||
|
array: "array";
|
||||||
|
object: "object";
|
||||||
|
unknown: "unknown";
|
||||||
|
promise: "promise";
|
||||||
|
void: "void";
|
||||||
|
never: "never";
|
||||||
|
map: "map";
|
||||||
|
set: "set";
|
||||||
|
};
|
||||||
|
export declare type ZodParsedType = keyof typeof ZodParsedType;
|
||||||
|
export declare const getParsedType: (data: any) => ZodParsedType;
|
||||||
142
shared/node_modules/zod/lib/helpers/util.js
generated
vendored
Normal file
142
shared/node_modules/zod/lib/helpers/util.js
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.getParsedType = exports.ZodParsedType = exports.objectUtil = exports.util = void 0;
|
||||||
|
var util;
|
||||||
|
(function (util) {
|
||||||
|
util.assertEqual = (val) => val;
|
||||||
|
function assertIs(_arg) { }
|
||||||
|
util.assertIs = assertIs;
|
||||||
|
function assertNever(_x) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
util.assertNever = assertNever;
|
||||||
|
util.arrayToEnum = (items) => {
|
||||||
|
const obj = {};
|
||||||
|
for (const item of items) {
|
||||||
|
obj[item] = item;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
util.getValidEnumValues = (obj) => {
|
||||||
|
const validKeys = util.objectKeys(obj).filter((k) => typeof obj[obj[k]] !== "number");
|
||||||
|
const filtered = {};
|
||||||
|
for (const k of validKeys) {
|
||||||
|
filtered[k] = obj[k];
|
||||||
|
}
|
||||||
|
return util.objectValues(filtered);
|
||||||
|
};
|
||||||
|
util.objectValues = (obj) => {
|
||||||
|
return util.objectKeys(obj).map(function (e) {
|
||||||
|
return obj[e];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
util.objectKeys = typeof Object.keys === "function"
|
||||||
|
? (obj) => Object.keys(obj)
|
||||||
|
: (object) => {
|
||||||
|
const keys = [];
|
||||||
|
for (const key in object) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
||||||
|
keys.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
};
|
||||||
|
util.find = (arr, checker) => {
|
||||||
|
for (const item of arr) {
|
||||||
|
if (checker(item))
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
util.isInteger = typeof Number.isInteger === "function"
|
||||||
|
? (val) => Number.isInteger(val)
|
||||||
|
: (val) => typeof val === "number" && isFinite(val) && Math.floor(val) === val;
|
||||||
|
function joinValues(array, separator = " | ") {
|
||||||
|
return array
|
||||||
|
.map((val) => (typeof val === "string" ? `'${val}'` : val))
|
||||||
|
.join(separator);
|
||||||
|
}
|
||||||
|
util.joinValues = joinValues;
|
||||||
|
util.jsonStringifyReplacer = (_, value) => {
|
||||||
|
if (typeof value === "bigint") {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
})(util = exports.util || (exports.util = {}));
|
||||||
|
var objectUtil;
|
||||||
|
(function (objectUtil) {
|
||||||
|
objectUtil.mergeShapes = (first, second) => {
|
||||||
|
return {
|
||||||
|
...first,
|
||||||
|
...second,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})(objectUtil = exports.objectUtil || (exports.objectUtil = {}));
|
||||||
|
exports.ZodParsedType = util.arrayToEnum([
|
||||||
|
"string",
|
||||||
|
"nan",
|
||||||
|
"number",
|
||||||
|
"integer",
|
||||||
|
"float",
|
||||||
|
"boolean",
|
||||||
|
"date",
|
||||||
|
"bigint",
|
||||||
|
"symbol",
|
||||||
|
"function",
|
||||||
|
"undefined",
|
||||||
|
"null",
|
||||||
|
"array",
|
||||||
|
"object",
|
||||||
|
"unknown",
|
||||||
|
"promise",
|
||||||
|
"void",
|
||||||
|
"never",
|
||||||
|
"map",
|
||||||
|
"set",
|
||||||
|
]);
|
||||||
|
const getParsedType = (data) => {
|
||||||
|
const t = typeof data;
|
||||||
|
switch (t) {
|
||||||
|
case "undefined":
|
||||||
|
return exports.ZodParsedType.undefined;
|
||||||
|
case "string":
|
||||||
|
return exports.ZodParsedType.string;
|
||||||
|
case "number":
|
||||||
|
return isNaN(data) ? exports.ZodParsedType.nan : exports.ZodParsedType.number;
|
||||||
|
case "boolean":
|
||||||
|
return exports.ZodParsedType.boolean;
|
||||||
|
case "function":
|
||||||
|
return exports.ZodParsedType.function;
|
||||||
|
case "bigint":
|
||||||
|
return exports.ZodParsedType.bigint;
|
||||||
|
case "symbol":
|
||||||
|
return exports.ZodParsedType.symbol;
|
||||||
|
case "object":
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
return exports.ZodParsedType.array;
|
||||||
|
}
|
||||||
|
if (data === null) {
|
||||||
|
return exports.ZodParsedType.null;
|
||||||
|
}
|
||||||
|
if (data.then &&
|
||||||
|
typeof data.then === "function" &&
|
||||||
|
data.catch &&
|
||||||
|
typeof data.catch === "function") {
|
||||||
|
return exports.ZodParsedType.promise;
|
||||||
|
}
|
||||||
|
if (typeof Map !== "undefined" && data instanceof Map) {
|
||||||
|
return exports.ZodParsedType.map;
|
||||||
|
}
|
||||||
|
if (typeof Set !== "undefined" && data instanceof Set) {
|
||||||
|
return exports.ZodParsedType.set;
|
||||||
|
}
|
||||||
|
if (typeof Date !== "undefined" && data instanceof Date) {
|
||||||
|
return exports.ZodParsedType.date;
|
||||||
|
}
|
||||||
|
return exports.ZodParsedType.object;
|
||||||
|
default:
|
||||||
|
return exports.ZodParsedType.unknown;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exports.getParsedType = getParsedType;
|
||||||
4
shared/node_modules/zod/lib/index.d.ts
generated
vendored
Normal file
4
shared/node_modules/zod/lib/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import * as z from "./external";
|
||||||
|
export * from "./external";
|
||||||
|
export { z };
|
||||||
|
export default z;
|
||||||
29
shared/node_modules/zod/lib/index.js
generated
vendored
Normal file
29
shared/node_modules/zod/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||||
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.z = void 0;
|
||||||
|
const z = __importStar(require("./external"));
|
||||||
|
exports.z = z;
|
||||||
|
__exportStar(require("./external"), exports);
|
||||||
|
exports.default = z;
|
||||||
3953
shared/node_modules/zod/lib/index.mjs
generated
vendored
Normal file
3953
shared/node_modules/zod/lib/index.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4066
shared/node_modules/zod/lib/index.umd.js
generated
vendored
Normal file
4066
shared/node_modules/zod/lib/index.umd.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3
shared/node_modules/zod/lib/locales/en.d.ts
generated
vendored
Normal file
3
shared/node_modules/zod/lib/locales/en.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { ZodErrorMap } from "../ZodError";
|
||||||
|
declare const errorMap: ZodErrorMap;
|
||||||
|
export default errorMap;
|
||||||
129
shared/node_modules/zod/lib/locales/en.js
generated
vendored
Normal file
129
shared/node_modules/zod/lib/locales/en.js
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const util_1 = require("../helpers/util");
|
||||||
|
const ZodError_1 = require("../ZodError");
|
||||||
|
const errorMap = (issue, _ctx) => {
|
||||||
|
let message;
|
||||||
|
switch (issue.code) {
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_type:
|
||||||
|
if (issue.received === util_1.ZodParsedType.undefined) {
|
||||||
|
message = "Required";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message = `Expected ${issue.expected}, received ${issue.received}`;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_literal:
|
||||||
|
message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util_1.util.jsonStringifyReplacer)}`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.unrecognized_keys:
|
||||||
|
message = `Unrecognized key(s) in object: ${util_1.util.joinValues(issue.keys, ", ")}`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_union:
|
||||||
|
message = `Invalid input`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_union_discriminator:
|
||||||
|
message = `Invalid discriminator value. Expected ${util_1.util.joinValues(issue.options)}`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_enum_value:
|
||||||
|
message = `Invalid enum value. Expected ${util_1.util.joinValues(issue.options)}, received '${issue.received}'`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_arguments:
|
||||||
|
message = `Invalid function arguments`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_return_type:
|
||||||
|
message = `Invalid function return type`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_date:
|
||||||
|
message = `Invalid date`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_string:
|
||||||
|
if (typeof issue.validation === "object") {
|
||||||
|
if ("includes" in issue.validation) {
|
||||||
|
message = `Invalid input: must include "${issue.validation.includes}"`;
|
||||||
|
if (typeof issue.validation.position === "number") {
|
||||||
|
message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ("startsWith" in issue.validation) {
|
||||||
|
message = `Invalid input: must start with "${issue.validation.startsWith}"`;
|
||||||
|
}
|
||||||
|
else if ("endsWith" in issue.validation) {
|
||||||
|
message = `Invalid input: must end with "${issue.validation.endsWith}"`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
util_1.util.assertNever(issue.validation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (issue.validation !== "regex") {
|
||||||
|
message = `Invalid ${issue.validation}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message = "Invalid";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.too_small:
|
||||||
|
if (issue.type === "array")
|
||||||
|
message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
|
||||||
|
else if (issue.type === "string")
|
||||||
|
message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
|
||||||
|
else if (issue.type === "number")
|
||||||
|
message = `Number must be ${issue.exact
|
||||||
|
? `exactly equal to `
|
||||||
|
: issue.inclusive
|
||||||
|
? `greater than or equal to `
|
||||||
|
: `greater than `}${issue.minimum}`;
|
||||||
|
else if (issue.type === "date")
|
||||||
|
message = `Date must be ${issue.exact
|
||||||
|
? `exactly equal to `
|
||||||
|
: issue.inclusive
|
||||||
|
? `greater than or equal to `
|
||||||
|
: `greater than `}${new Date(Number(issue.minimum))}`;
|
||||||
|
else
|
||||||
|
message = "Invalid input";
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.too_big:
|
||||||
|
if (issue.type === "array")
|
||||||
|
message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
|
||||||
|
else if (issue.type === "string")
|
||||||
|
message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
|
||||||
|
else if (issue.type === "number")
|
||||||
|
message = `Number must be ${issue.exact
|
||||||
|
? `exactly`
|
||||||
|
: issue.inclusive
|
||||||
|
? `less than or equal to`
|
||||||
|
: `less than`} ${issue.maximum}`;
|
||||||
|
else if (issue.type === "bigint")
|
||||||
|
message = `BigInt must be ${issue.exact
|
||||||
|
? `exactly`
|
||||||
|
: issue.inclusive
|
||||||
|
? `less than or equal to`
|
||||||
|
: `less than`} ${issue.maximum}`;
|
||||||
|
else if (issue.type === "date")
|
||||||
|
message = `Date must be ${issue.exact
|
||||||
|
? `exactly`
|
||||||
|
: issue.inclusive
|
||||||
|
? `smaller than or equal to`
|
||||||
|
: `smaller than`} ${new Date(Number(issue.maximum))}`;
|
||||||
|
else
|
||||||
|
message = "Invalid input";
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.custom:
|
||||||
|
message = `Invalid input`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.invalid_intersection_types:
|
||||||
|
message = `Intersection results could not be merged`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.not_multiple_of:
|
||||||
|
message = `Number must be a multiple of ${issue.multipleOf}`;
|
||||||
|
break;
|
||||||
|
case ZodError_1.ZodIssueCode.not_finite:
|
||||||
|
message = "Number must be finite";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = _ctx.defaultError;
|
||||||
|
util_1.util.assertNever(issue);
|
||||||
|
}
|
||||||
|
return { message };
|
||||||
|
};
|
||||||
|
exports.default = errorMap;
|
||||||
1012
shared/node_modules/zod/lib/types.d.ts
generated
vendored
Normal file
1012
shared/node_modules/zod/lib/types.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3252
shared/node_modules/zod/lib/types.js
generated
vendored
Normal file
3252
shared/node_modules/zod/lib/types.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105
shared/node_modules/zod/package.json
generated
vendored
Normal file
105
shared/node_modules/zod/package.json
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"name": "zod",
|
||||||
|
"version": "3.21.4",
|
||||||
|
"author": "Colin McDonnell <colin@colinhacks.com>",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/colinhacks/zod"
|
||||||
|
},
|
||||||
|
"main": "./lib/index.js",
|
||||||
|
"module": "./lib/index.mjs",
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-typescript": "^8.2.0",
|
||||||
|
"@types/benchmark": "^2.1.0",
|
||||||
|
"@types/jest": "^29.2.2",
|
||||||
|
"@types/node": "14",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.15.0",
|
||||||
|
"@typescript-eslint/parser": "^5.15.0",
|
||||||
|
"benchmark": "^2.1.4",
|
||||||
|
"dependency-cruiser": "^9.19.0",
|
||||||
|
"eslint": "^8.11.0",
|
||||||
|
"eslint-config-prettier": "^8.5.0",
|
||||||
|
"eslint-plugin-ban": "^1.6.0",
|
||||||
|
"eslint-plugin-import": "^2.25.4",
|
||||||
|
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||||
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
|
"husky": "^7.0.4",
|
||||||
|
"jest": "^29.3.1",
|
||||||
|
"lint-staged": "^12.3.7",
|
||||||
|
"nodemon": "^2.0.15",
|
||||||
|
"prettier": "^2.6.0",
|
||||||
|
"pretty-quick": "^3.1.3",
|
||||||
|
"rollup": "^2.70.1",
|
||||||
|
"ts-jest": "^29.0.3",
|
||||||
|
"ts-morph": "^14.0.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"tsx": "^3.8.0",
|
||||||
|
"typescript": "~4.5.0"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"require": "./lib/index.js",
|
||||||
|
"import": "./lib/index.mjs",
|
||||||
|
"types": "./index.d.ts"
|
||||||
|
},
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
"./locales/*": "./lib/locales/*"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/colinhacks/zod/issues"
|
||||||
|
},
|
||||||
|
"description": "TypeScript-first schema declaration and validation library with static type inference",
|
||||||
|
"files": [
|
||||||
|
"/lib",
|
||||||
|
"/index.d.ts"
|
||||||
|
],
|
||||||
|
"funding": "https://github.com/sponsors/colinhacks",
|
||||||
|
"homepage": "https://zod.dev",
|
||||||
|
"keywords": [
|
||||||
|
"typescript",
|
||||||
|
"schema",
|
||||||
|
"validation",
|
||||||
|
"type",
|
||||||
|
"inference"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"lint-staged": {
|
||||||
|
"src/*.ts": [
|
||||||
|
"eslint --cache --fix",
|
||||||
|
"prettier --ignore-unknown --write"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"prettier:check": "prettier --check src/**/*.ts deno/lib/**/*.ts --no-error-on-unmatched-pattern",
|
||||||
|
"prettier:fix": "prettier --write src/**/*.ts deno/lib/**/*.ts --ignore-unknown --no-error-on-unmatched-pattern",
|
||||||
|
"lint:check": "eslint --cache --ext .ts ./src",
|
||||||
|
"lint:fix": "eslint --cache --fix --ext .ts ./src",
|
||||||
|
"check": "yarn lint:check && yarn prettier:check",
|
||||||
|
"fix": "yarn lint:fix && yarn prettier:fix",
|
||||||
|
"clean": "rm -rf lib/* deno/lib/*",
|
||||||
|
"build": "yarn run clean && npm run build:cjs && npm run build:esm && npm run build:deno",
|
||||||
|
"build:deno": "node ./deno/build.mjs && cp ./README.md ./deno/lib",
|
||||||
|
"build:esm": "rollup --config rollup.config.js",
|
||||||
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
||||||
|
"build:types": "tsc -p tsconfig.types.json",
|
||||||
|
"build:test": "tsc -p tsconfig.test.json",
|
||||||
|
"rollup": "rollup --config rollup.config.js",
|
||||||
|
"test:watch": "jest --watch",
|
||||||
|
"test": "jest --coverage",
|
||||||
|
"test:deno": "cd deno && deno test",
|
||||||
|
"prepublishOnly": "npm run test && npm run build && npm run build:deno",
|
||||||
|
"play": "nodemon -e ts -w . -x tsx playground.ts",
|
||||||
|
"depcruise": "depcruise -c .dependency-cruiser.js src",
|
||||||
|
"benchmark": "tsx src/benchmarks/index.ts",
|
||||||
|
"prepare": "husky install"
|
||||||
|
},
|
||||||
|
"sideEffects": false,
|
||||||
|
"support": {
|
||||||
|
"backing": {
|
||||||
|
"npm-funding": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
28
shared/package-lock.json
generated
Normal file
28
shared/package-lock.json
generated
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "photos-shared",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "photos-shared",
|
||||||
|
"dependencies": {
|
||||||
|
"zod": "^3.21.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "3.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||||
|
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"zod": {
|
||||||
|
"version": "3.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||||
|
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
shared/package.json
Normal file
6
shared/package.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "photos-shared",
|
||||||
|
"dependencies": {
|
||||||
|
"zod": "^3.21.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
171
shared/types.ts
171
shared/types.ts
@@ -1,85 +1,124 @@
|
|||||||
interface IAPIErrorResponse {
|
import { z } from "zod";
|
||||||
data: null;
|
|
||||||
error: string;
|
export const APIErrorResponse = z.object({
|
||||||
|
data: z.null(),
|
||||||
|
error: z.string(),
|
||||||
|
});
|
||||||
|
export type TAPIErrorResponse = z.infer<typeof APIErrorResponse>;
|
||||||
|
|
||||||
|
function CreateAPISuccessResponse<T extends z.ZodTypeAny>(obj: T) {
|
||||||
|
return z.object({
|
||||||
|
error: z.literal(false),
|
||||||
|
data: obj,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IAPISuccessResponse<T> {
|
function CreateAPIResponse<T extends z.ZodTypeAny>(obj: T) {
|
||||||
error: false;
|
return z.union([APIErrorResponse, CreateAPISuccessResponse(obj)]);
|
||||||
data: T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IAPIResponse<T> = IAPIErrorResponse | IAPISuccessResponse<T>;
|
export const PhotoJSON = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
user: z.number(),
|
||||||
|
hash: z.string(),
|
||||||
|
size: z.string(),
|
||||||
|
format: z.string(),
|
||||||
|
createdAt: z.number(),
|
||||||
|
editedAt: z.number(),
|
||||||
|
shotAt: z.number(),
|
||||||
|
uploaded: z.boolean(),
|
||||||
|
});
|
||||||
|
export type TPhotoJSON = z.infer<typeof PhotoJSON>;
|
||||||
|
|
||||||
export interface IPhotoJSON {
|
export const PhotoReqJSON = PhotoJSON.extend({
|
||||||
id: number;
|
accessToken: z.string(),
|
||||||
user: number;
|
});
|
||||||
hash: string;
|
export type TPhotoReqJSON = z.infer<typeof PhotoReqJSON>;
|
||||||
size: string;
|
|
||||||
format: string;
|
|
||||||
createdAt: number;
|
|
||||||
editedAt: number;
|
|
||||||
shotAt: number;
|
|
||||||
uploaded: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPhotoReqJSON extends IPhotoJSON {
|
export const PhotoShowToken = z.string();
|
||||||
accessToken: string;
|
export type TPhotoShowToken = z.infer<typeof PhotoShowToken>;
|
||||||
}
|
|
||||||
|
|
||||||
export type IPhotoShowToken = string;
|
export const PhotosGetShowTokenByIDRespBody = CreateAPIResponse(PhotoShowToken);
|
||||||
export type IPhotosGetShowTokenByID = IAPIResponse<IPhotoShowToken>;
|
export type TPhotosGetShowTokenByIDRespBody = z.infer<
|
||||||
|
typeof PhotosGetShowTokenByIDRespBody
|
||||||
|
>;
|
||||||
|
|
||||||
export interface IPhotosNewPostBody {
|
export const PhotosNewPostBody = z.object({
|
||||||
hash: string | undefined;
|
hash: z.string(),
|
||||||
size: string | undefined;
|
size: z.string(),
|
||||||
format: string | undefined;
|
format: z.string(),
|
||||||
}
|
});
|
||||||
|
export type TPhotosNewPostBody = z.infer<typeof PhotosNewPostBody>;
|
||||||
|
|
||||||
export interface IPhotosDeleteBody {
|
export const PhotosDeleteBody = z.object({
|
||||||
photos: IPhotoReqJSON[];
|
photos: z.array(PhotoReqJSON),
|
||||||
}
|
});
|
||||||
|
export type TPhotosDeleteBody = z.infer<typeof PhotosDeleteBody>;
|
||||||
|
|
||||||
export const IPhotosListPagination = 50;
|
export const PhotosListPagination = 50;
|
||||||
|
|
||||||
export type IPhotosNewRespBody = IAPIResponse<IPhotoReqJSON>;
|
export const PhotosNewRespBody = CreateAPIResponse(PhotoReqJSON);
|
||||||
export type IPhotosUploadRespBody = IAPIResponse<IPhotoReqJSON>;
|
export type TPhotosNewRespBody = z.infer<typeof PhotosNewRespBody>;
|
||||||
export type IPhotosListRespBody = IAPIResponse<IPhotoReqJSON[]>;
|
|
||||||
export type IPhotosByIDGetRespBody = IAPIResponse<IPhotoReqJSON>;
|
|
||||||
export type IPhotoByIDDeleteRespBody = IAPIResponse<boolean>;
|
|
||||||
export type IPhotosDeleteRespBody = IAPIResponse<boolean>;
|
|
||||||
|
|
||||||
export interface IUserJSON {
|
export const PhotosUploadRespBody = CreateAPIResponse(PhotoReqJSON);
|
||||||
id: number;
|
export type TPhotosUploadRespBody = z.infer<typeof PhotosUploadRespBody>;
|
||||||
username: string;
|
|
||||||
isAdmin: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUserJWT extends IUserJSON {
|
export const PhotosListRespBody = CreateAPIResponse(z.array(PhotoReqJSON));
|
||||||
ext: number;
|
export type TPhotosListRespBody = z.infer<typeof PhotosListRespBody>;
|
||||||
iat: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUserAuthJSON extends IUserJSON {
|
export const PhotosByIDGetRespBody = CreateAPIResponse(PhotoReqJSON);
|
||||||
jwt: string;
|
export type TPhotosByIDGetRespBody = z.infer<typeof PhotosByIDGetRespBody>;
|
||||||
}
|
|
||||||
|
|
||||||
export interface IUserSignupBody {
|
export const PhotoByIDDeleteRespBody = CreateAPIResponse(z.boolean());
|
||||||
username: string | undefined;
|
export type TPhotoByIDDeleteRespBody = z.infer<typeof PhotoByIDDeleteRespBody>;
|
||||||
password: string | undefined;
|
|
||||||
email: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type IUserSignupRespBody = IAPIResponse<IUserAuthJSON>;
|
export const PhotosDeleteRespBody = CreateAPIResponse(z.boolean());
|
||||||
|
export type TPhotosDeleteRespBody = z.infer<typeof PhotosDeleteRespBody>;
|
||||||
|
|
||||||
export type IUserGetRespBody = IAPIResponse<IUserAuthJSON>;
|
export const UserJSON = z.object({
|
||||||
export type IUserLoginRespBody = IAPIResponse<IUserAuthJSON>;
|
id: z.number(),
|
||||||
|
username: z.string(),
|
||||||
|
isAdmin: z.boolean(),
|
||||||
|
});
|
||||||
|
export type TUserJSON = z.infer<typeof UserJSON>;
|
||||||
|
|
||||||
export interface IUserEditBody {
|
export const UserJWT = UserJSON.extend({
|
||||||
password: string | undefined;
|
ext: z.number(),
|
||||||
}
|
iat: z.number(),
|
||||||
|
});
|
||||||
|
export type TUserJWT = z.infer<typeof UserJWT>;
|
||||||
|
|
||||||
export type IUserEditRespBody = IAPIResponse<IUserAuthJSON>;
|
export const UserAuthJSON = UserJSON.extend({
|
||||||
export interface IUserLoginBody {
|
jwt: z.string(),
|
||||||
username: string | undefined;
|
});
|
||||||
password: string | undefined;
|
export type TUserAuthJSON = z.infer<typeof UserAuthJSON>;
|
||||||
}
|
|
||||||
|
export const UserSignupBody = z.object({
|
||||||
|
username: z.string(),
|
||||||
|
password: z.string(),
|
||||||
|
email: z.string(),
|
||||||
|
});
|
||||||
|
export type TUserSignupBody = z.infer<typeof UserSignupBody>;
|
||||||
|
|
||||||
|
export const UserSignupRespBody = CreateAPIResponse(UserAuthJSON);
|
||||||
|
export type TUserSignupRespBody = z.infer<typeof UserSignupRespBody>;
|
||||||
|
|
||||||
|
export const UserGetRespBody = CreateAPIResponse(UserAuthJSON);
|
||||||
|
export type TUserGetRespBody = z.infer<typeof UserGetRespBody>;
|
||||||
|
|
||||||
|
export const UserLoginRespBody = CreateAPIResponse(UserAuthJSON);
|
||||||
|
export type TUserLoginRespBody = z.infer<typeof UserLoginRespBody>;
|
||||||
|
|
||||||
|
export const UserEditBody = z.object({
|
||||||
|
password: z.optional(z.string()),
|
||||||
|
});
|
||||||
|
export type TUserEditBody = z.infer<typeof UserEditBody>;
|
||||||
|
|
||||||
|
export const UserEditRespBody = CreateAPIResponse(UserAuthJSON);
|
||||||
|
export type TUserEditRespBody = z.infer<typeof UserEditRespBody>;
|
||||||
|
|
||||||
|
export const UserLoginBody = z.object({
|
||||||
|
username: z.string(),
|
||||||
|
password: z.string(),
|
||||||
|
});
|
||||||
|
export type TUserLoginBody = z.infer<typeof UserLoginBody>;
|
||||||
|
|||||||
Reference in New Issue
Block a user