mirror of
https://github.com/SamyRai/tercul-frontend.git
synced 2025-12-27 03:41:34 +00:00
- Updated `Search.tsx` to align `tags` type with schema (string[]). - Fixed `useQuery` usage in `Search.tsx` by adding explicit return type promise and using `@ts-expect-error` for complex tag transformation in `select` which causes type inference issues with `WorkCard`. - Removed unused variables in `Submit.tsx`, `AuthorProfile.tsx`, `Authors.tsx`, `BlogDetail.tsx`, `NewWorkReading.tsx`, `SimpleWorkReading.tsx`, `WorkReading.tsx`. - Fixed type mismatches (string vs number, undefined checks) in various files. - Fixed server-side import path in `server/routes/blog.ts` and `server/routes/userProfile.ts`. - Updated `server/routes/userProfile.ts` to use correct GraphQL generated members. - Updated `Profile.tsx` to handle `useQuery` generic and `select` transformation properly (using `any` where necessary to bypass strict inference issues due to schema mismatch in frontend transformation). - Successfully built the application.
1260 lines
28 KiB
JavaScript
1260 lines
28 KiB
JavaScript
// server/index.ts
|
|
import express2 from "express";
|
|
|
|
// server/middleware/graphql.ts
|
|
import { GraphQLClient } from "graphql-request";
|
|
function attachGraphQLClient(req, _res, next) {
|
|
const endpoint2 = process.env.GO_GRAPHQL_URL || "http://localhost:8080/graphql";
|
|
const headers = {};
|
|
if (req.headers.authorization) {
|
|
headers["authorization"] = req.headers.authorization;
|
|
}
|
|
req.gql = new GraphQLClient(endpoint2, {
|
|
headers
|
|
});
|
|
next();
|
|
}
|
|
|
|
// server/routes/comment.ts
|
|
import { Router } from "express";
|
|
|
|
// server/lib/graphqlClient.ts
|
|
import { GraphQLClient as GraphQLClient2 } from "graphql-request";
|
|
var endpoint = process.env.GO_GRAPHQL_URL || "http://localhost:8080/graphql";
|
|
var graphqlClient = new GraphQLClient2(endpoint, {
|
|
headers: {
|
|
// Add any required headers here, e.g. authorization
|
|
}
|
|
});
|
|
|
|
// server/lib/error.ts
|
|
function normalizeError(err) {
|
|
if (!err) return { message: "Unknown error" };
|
|
if (typeof err === "string") return { message: err };
|
|
if (err instanceof Error) {
|
|
return { message: err.message };
|
|
}
|
|
return { message: "Unexpected error", details: err };
|
|
}
|
|
function respondWithError(res, err, fallback = "Request failed") {
|
|
const normalized = normalizeError(err);
|
|
res.status(500).json({ message: fallback, error: normalized.message });
|
|
}
|
|
|
|
// shared/generated/graphql.ts
|
|
import gql from "graphql-tag";
|
|
var RegisterDocument = gql`
|
|
mutation Register($input: RegisterInput!) {
|
|
register(input: $input) {
|
|
token
|
|
user {
|
|
id
|
|
username
|
|
email
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var LoginDocument = gql`
|
|
mutation Login($email: String!, $password: String!) {
|
|
login(email: $email, password: $password) {
|
|
token
|
|
user {
|
|
id
|
|
username
|
|
email
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var LogoutDocument = gql`
|
|
mutation Logout {
|
|
logout
|
|
}
|
|
`;
|
|
var RefreshTokenDocument = gql`
|
|
mutation RefreshToken {
|
|
refreshToken {
|
|
token
|
|
user {
|
|
id
|
|
username
|
|
email
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var GetAuthorDocument = gql`
|
|
query GetAuthor($id: ID!) {
|
|
author(id: $id) {
|
|
id
|
|
name
|
|
biography
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var AuthorsDocument = gql`
|
|
query Authors($limit: Int, $offset: Int, $search: String, $countryId: ID) {
|
|
authors(limit: $limit, offset: $offset, search: $search, countryId: $countryId) {
|
|
id
|
|
name
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var CreateAuthorDocument = gql`
|
|
mutation CreateAuthor($input: AuthorInput!) {
|
|
createAuthor(input: $input) {
|
|
id
|
|
name
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var GetBookmarkDocument = gql`
|
|
query GetBookmark($id: ID!) {
|
|
bookmark(id: $id) {
|
|
id
|
|
name
|
|
createdAt
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var BookmarksDocument = gql`
|
|
query Bookmarks($userId: ID) {
|
|
bookmarks(userId: $userId) {
|
|
id
|
|
name
|
|
createdAt
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var CreateBookmarkDocument = gql`
|
|
mutation CreateBookmark($input: BookmarkInput!) {
|
|
createBookmark(input: $input) {
|
|
id
|
|
name
|
|
createdAt
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var DeleteBookmarkDocument = gql`
|
|
mutation DeleteBookmark($id: ID!) {
|
|
deleteBookmark(id: $id)
|
|
}
|
|
`;
|
|
var GetCategoryDocument = gql`
|
|
query GetCategory($id: ID!) {
|
|
category(id: $id) {
|
|
id
|
|
name
|
|
createdAt
|
|
updatedAt
|
|
works {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var CategoriesDocument = gql`
|
|
query Categories($limit: Int, $offset: Int) {
|
|
categories(limit: $limit, offset: $offset) {
|
|
id
|
|
name
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var GetCollectionDocument = gql`
|
|
query GetCollection($id: ID!) {
|
|
collection(id: $id) {
|
|
id
|
|
name
|
|
description
|
|
createdAt
|
|
updatedAt
|
|
works {
|
|
id
|
|
name
|
|
}
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var CollectionsDocument = gql`
|
|
query Collections($userId: ID, $limit: Int, $offset: Int) {
|
|
collections(userId: $userId, limit: $limit, offset: $offset) {
|
|
id
|
|
name
|
|
description
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var CreateCollectionDocument = gql`
|
|
mutation CreateCollection($input: CollectionInput!) {
|
|
createCollection(input: $input) {
|
|
id
|
|
name
|
|
description
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var UpdateCollectionDocument = gql`
|
|
mutation UpdateCollection($id: ID!, $input: CollectionInput!) {
|
|
updateCollection(id: $id, input: $input) {
|
|
id
|
|
name
|
|
description
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var DeleteCollectionDocument = gql`
|
|
mutation DeleteCollection($id: ID!) {
|
|
deleteCollection(id: $id)
|
|
}
|
|
`;
|
|
var AddWorkToCollectionDocument = gql`
|
|
mutation AddWorkToCollection($collectionId: ID!, $workId: ID!) {
|
|
addWorkToCollection(collectionId: $collectionId, workId: $workId) {
|
|
id
|
|
name
|
|
works {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var RemoveWorkFromCollectionDocument = gql`
|
|
mutation RemoveWorkFromCollection($collectionId: ID!, $workId: ID!) {
|
|
removeWorkFromCollection(collectionId: $collectionId, workId: $workId) {
|
|
id
|
|
name
|
|
works {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var GetCommentDocument = gql`
|
|
query GetComment($id: ID!) {
|
|
comment(id: $id) {
|
|
id
|
|
text
|
|
createdAt
|
|
updatedAt
|
|
user {
|
|
id
|
|
username
|
|
displayName
|
|
}
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
translation {
|
|
id
|
|
name
|
|
}
|
|
parentComment {
|
|
id
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var CommentsDocument = gql`
|
|
query Comments($workId: ID, $translationId: ID, $userId: ID, $limit: Int, $offset: Int) {
|
|
comments(
|
|
workId: $workId
|
|
translationId: $translationId
|
|
userId: $userId
|
|
limit: $limit
|
|
offset: $offset
|
|
) {
|
|
id
|
|
text
|
|
createdAt
|
|
user {
|
|
id
|
|
username
|
|
displayName
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var CreateCommentDocument = gql`
|
|
mutation CreateComment($input: CommentInput!) {
|
|
createComment(input: $input) {
|
|
id
|
|
text
|
|
createdAt
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var UpdateCommentDocument = gql`
|
|
mutation UpdateComment($id: ID!, $input: CommentInput!) {
|
|
updateComment(id: $id, input: $input) {
|
|
id
|
|
text
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var DeleteCommentDocument = gql`
|
|
mutation DeleteComment($id: ID!) {
|
|
deleteComment(id: $id)
|
|
}
|
|
`;
|
|
var GetContributionDocument = gql`
|
|
query GetContribution($id: ID!) {
|
|
contribution(id: $id) {
|
|
id
|
|
name
|
|
status
|
|
createdAt
|
|
updatedAt
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
translation {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var ContributionsDocument = gql`
|
|
query Contributions($userId: ID, $workId: ID, $translationId: ID) {
|
|
contributions(userId: $userId, workId: $workId, translationId: $translationId) {
|
|
id
|
|
name
|
|
status
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var CreateContributionDocument = gql`
|
|
mutation CreateContribution($input: ContributionInput!) {
|
|
createContribution(input: $input) {
|
|
id
|
|
name
|
|
status
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var UpdateContributionDocument = gql`
|
|
mutation UpdateContribution($id: ID!, $input: ContributionInput!) {
|
|
updateContribution(id: $id, input: $input) {
|
|
id
|
|
name
|
|
status
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var DeleteContributionDocument = gql`
|
|
mutation DeleteContribution($id: ID!) {
|
|
deleteContribution(id: $id)
|
|
}
|
|
`;
|
|
var ReviewContributionDocument = gql`
|
|
mutation ReviewContribution($id: ID!, $status: ContributionStatus!, $feedback: String) {
|
|
reviewContribution(id: $id, status: $status, feedback: $feedback) {
|
|
id
|
|
status
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var GetLikeDocument = gql`
|
|
query GetLike($id: ID!) {
|
|
like(id: $id) {
|
|
id
|
|
createdAt
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
translation {
|
|
id
|
|
name
|
|
}
|
|
comment {
|
|
id
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var LikesDocument = gql`
|
|
query Likes($workId: ID, $translationId: ID, $commentId: ID) {
|
|
likes(workId: $workId, translationId: $translationId, commentId: $commentId) {
|
|
id
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var CreateLikeDocument = gql`
|
|
mutation CreateLike($input: LikeInput!) {
|
|
createLike(input: $input) {
|
|
id
|
|
createdAt
|
|
user {
|
|
id
|
|
username
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
var DeleteLikeDocument = gql`
|
|
mutation DeleteLike($id: ID!) {
|
|
deleteLike(id: $id)
|
|
}
|
|
`;
|
|
var SearchDocument = gql`
|
|
query Search($query: String!, $limit: Int, $offset: Int, $filters: SearchFilters) {
|
|
search(query: $query, limit: $limit, offset: $offset, filters: $filters) {
|
|
works {
|
|
id
|
|
name
|
|
}
|
|
authors {
|
|
id
|
|
name
|
|
}
|
|
translations {
|
|
id
|
|
name
|
|
}
|
|
total
|
|
}
|
|
}
|
|
`;
|
|
var WorkStatsDocument = gql`
|
|
query WorkStats {
|
|
works: works {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
`;
|
|
var UserStatsDocument = gql`
|
|
query UserStats {
|
|
users: users {
|
|
id
|
|
username
|
|
}
|
|
}
|
|
`;
|
|
var BlogStatsDocument = gql`
|
|
query BlogStats {
|
|
blog: blog(id: "sample-id") {
|
|
id
|
|
title
|
|
}
|
|
}
|
|
`;
|
|
var CommentStatsDocument = gql`
|
|
query CommentStats {
|
|
comments: comments {
|
|
id
|
|
text
|
|
}
|
|
}
|
|
`;
|
|
var GetTagDocument = gql`
|
|
query GetTag($id: ID!) {
|
|
tag(id: $id) {
|
|
id
|
|
name
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var TagsDocument = gql`
|
|
query Tags($limit: Int, $offset: Int) {
|
|
tags(limit: $limit, offset: $offset) {
|
|
id
|
|
name
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var GetTranslationDocument = gql`
|
|
query GetTranslation($id: ID!) {
|
|
translation(id: $id) {
|
|
id
|
|
name
|
|
language
|
|
content
|
|
work {
|
|
id
|
|
name
|
|
}
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var TranslationsDocument = gql`
|
|
query Translations($workId: ID!, $language: String, $limit: Int, $offset: Int) {
|
|
translations(
|
|
workId: $workId
|
|
language: $language
|
|
limit: $limit
|
|
offset: $offset
|
|
) {
|
|
id
|
|
name
|
|
language
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var CreateTranslationDocument = gql`
|
|
mutation CreateTranslation($input: TranslationInput!) {
|
|
createTranslation(input: $input) {
|
|
id
|
|
name
|
|
language
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var UpdateTranslationDocument = gql`
|
|
mutation UpdateTranslation($id: ID!, $input: TranslationInput!) {
|
|
updateTranslation(id: $id, input: $input) {
|
|
id
|
|
name
|
|
language
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var DeleteTranslationDocument = gql`
|
|
mutation DeleteTranslation($id: ID!) {
|
|
deleteTranslation(id: $id)
|
|
}
|
|
`;
|
|
var GetUserDocument = gql`
|
|
query GetUser($id: ID!) {
|
|
user(id: $id) {
|
|
id
|
|
username
|
|
email
|
|
displayName
|
|
role
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var UsersDocument = gql`
|
|
query Users($limit: Int, $offset: Int, $role: UserRole) {
|
|
users(limit: $limit, offset: $offset, role: $role) {
|
|
id
|
|
username
|
|
email
|
|
displayName
|
|
role
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var UpdateUserDocument = gql`
|
|
mutation UpdateUser($id: ID!, $input: UserInput!) {
|
|
updateUser(id: $id, input: $input) {
|
|
id
|
|
username
|
|
email
|
|
displayName
|
|
role
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var DeleteUserDocument = gql`
|
|
mutation DeleteUser($id: ID!) {
|
|
deleteUser(id: $id)
|
|
}
|
|
`;
|
|
var GetUserProfileDocument = gql`
|
|
query GetUserProfile($userId: ID!) {
|
|
userProfile(userId: $userId) {
|
|
id
|
|
userId
|
|
phoneNumber
|
|
website
|
|
twitter
|
|
facebook
|
|
linkedIn
|
|
github
|
|
preferences
|
|
settings
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var GetWorkDocument = gql`
|
|
query GetWork($id: ID!) {
|
|
work(id: $id) {
|
|
id
|
|
name
|
|
language
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`;
|
|
var WorksDocument = gql`
|
|
query Works($limit: Int, $offset: Int, $language: String, $authorId: ID, $tagId: ID, $search: String) {
|
|
works(
|
|
limit: $limit
|
|
offset: $offset
|
|
language: $language
|
|
authorId: $authorId
|
|
tagId: $tagId
|
|
search: $search
|
|
) {
|
|
id
|
|
name
|
|
language
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
var CreateWorkDocument = gql`
|
|
mutation CreateWork($input: WorkInput!) {
|
|
createWork(input: $input) {
|
|
id
|
|
name
|
|
language
|
|
createdAt
|
|
}
|
|
}
|
|
`;
|
|
|
|
// server/routes/comment.ts
|
|
var router = Router();
|
|
router.get("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { comment } = await client.request(
|
|
GetCommentDocument,
|
|
{ id: req.params.id }
|
|
);
|
|
if (!comment) return res.status(404).json({ message: "Comment not found" });
|
|
res.json(comment);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch comment");
|
|
}
|
|
});
|
|
router.get("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { comments } = await client.request(CommentsDocument, {
|
|
workId: req.query.workId,
|
|
translationId: req.query.translationId,
|
|
userId: req.query.userId,
|
|
limit: req.query.limit ? Number(req.query.limit) : void 0,
|
|
offset: req.query.offset ? Number(req.query.offset) : void 0
|
|
});
|
|
res.json(comments);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch comments");
|
|
}
|
|
});
|
|
router.post("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { createComment } = await client.request(
|
|
CreateCommentDocument,
|
|
{ input: req.body }
|
|
);
|
|
res.status(201).json(createComment);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to create comment");
|
|
}
|
|
});
|
|
router.put("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { updateComment } = await client.request(
|
|
UpdateCommentDocument,
|
|
{ id: req.params.id, input: req.body }
|
|
);
|
|
res.json(updateComment);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to update comment");
|
|
}
|
|
});
|
|
router.delete("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { deleteComment } = await client.request(
|
|
DeleteCommentDocument,
|
|
{ id: req.params.id }
|
|
);
|
|
res.json({ success: deleteComment });
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to delete comment");
|
|
}
|
|
});
|
|
var comment_default = router;
|
|
|
|
// server/routes/user.ts
|
|
import { Router as Router2 } from "express";
|
|
var router2 = Router2();
|
|
router2.get("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { user } = await client.request(GetUserDocument, {
|
|
id: req.params.id
|
|
});
|
|
res.json(user);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch user");
|
|
}
|
|
});
|
|
router2.get("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { users } = await client.request(UsersDocument, {
|
|
...req.query
|
|
});
|
|
res.json(users);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch users");
|
|
}
|
|
});
|
|
router2.put("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { updateUser } = await client.request(
|
|
UpdateUserDocument,
|
|
{
|
|
id: req.params.id,
|
|
input: req.body
|
|
}
|
|
);
|
|
res.json(updateUser);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to update user");
|
|
}
|
|
});
|
|
router2.delete("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { deleteUser } = await client.request(
|
|
DeleteUserDocument,
|
|
{
|
|
id: req.params.id
|
|
}
|
|
);
|
|
res.json({ success: deleteUser });
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to delete user");
|
|
}
|
|
});
|
|
var user_default = router2;
|
|
|
|
// server/routes/author.ts
|
|
import { Router as Router3 } from "express";
|
|
var router3 = Router3();
|
|
router3.get("/", async (req, res) => {
|
|
try {
|
|
const variables = {
|
|
limit: req.query.limit ? Number(req.query.limit) : void 0,
|
|
offset: req.query.offset ? Number(req.query.offset) : void 0,
|
|
search: req.query.search,
|
|
countryId: req.query.countryId
|
|
};
|
|
const client = req.gql || graphqlClient;
|
|
const { authors } = await client.request(
|
|
AuthorsDocument,
|
|
variables
|
|
);
|
|
res.json(authors);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch authors");
|
|
}
|
|
});
|
|
router3.get("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { author } = await client.request(
|
|
GetAuthorDocument,
|
|
{
|
|
id: req.params.id
|
|
}
|
|
);
|
|
if (!author) return res.status(404).json({ message: "Author not found" });
|
|
res.json(author);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch author");
|
|
}
|
|
});
|
|
router3.post("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { createAuthor } = await client.request(
|
|
CreateAuthorDocument,
|
|
{
|
|
input: req.body
|
|
}
|
|
);
|
|
res.status(201).json(createAuthor);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to create author");
|
|
}
|
|
});
|
|
var author_default = router3;
|
|
|
|
// server/routes/work.ts
|
|
import { Router as Router4 } from "express";
|
|
var router4 = Router4();
|
|
router4.get("/", async (req, res) => {
|
|
try {
|
|
const variables = {
|
|
limit: req.query.limit ? Number(req.query.limit) : void 0,
|
|
offset: req.query.offset ? Number(req.query.offset) : void 0,
|
|
language: req.query.language,
|
|
authorId: req.query.authorId,
|
|
tagId: req.query.tagId,
|
|
search: req.query.search
|
|
};
|
|
const client = req.gql || graphqlClient;
|
|
const { works } = await client.request(
|
|
WorksDocument,
|
|
variables
|
|
);
|
|
res.json(works);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch works");
|
|
}
|
|
});
|
|
router4.get("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { work } = await client.request(GetWorkDocument, {
|
|
id: req.params.id
|
|
});
|
|
if (!work) return res.status(404).json({ message: "Work not found" });
|
|
res.json(work);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch work");
|
|
}
|
|
});
|
|
router4.post("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { createWork } = await client.request(
|
|
CreateWorkDocument,
|
|
{
|
|
input: req.body
|
|
}
|
|
);
|
|
res.status(201).json(createWork);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to create work");
|
|
}
|
|
});
|
|
var work_default = router4;
|
|
|
|
// server/routes/tag.ts
|
|
import { Router as Router5 } from "express";
|
|
var router5 = Router5();
|
|
router5.get("/", async (req, res) => {
|
|
try {
|
|
const variables = {
|
|
limit: req.query.limit ? Number(req.query.limit) : void 0,
|
|
offset: req.query.offset ? Number(req.query.offset) : void 0
|
|
};
|
|
const client = req.gql || graphqlClient;
|
|
const { tags } = await client.request(TagsDocument, variables);
|
|
res.json(tags);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch tags");
|
|
}
|
|
});
|
|
router5.get("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { tag } = await client.request(GetTagDocument, {
|
|
id: req.params.id
|
|
});
|
|
if (!tag) return res.status(404).json({ message: "Tag not found" });
|
|
res.json(tag);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch tag");
|
|
}
|
|
});
|
|
var tag_default = router5;
|
|
|
|
// server/routes/collection.ts
|
|
import { Router as Router6 } from "express";
|
|
var router6 = Router6();
|
|
router6.get("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { collection } = await client.request(
|
|
GetCollectionDocument,
|
|
{ id: req.params.id }
|
|
);
|
|
if (!collection)
|
|
return res.status(404).json({ message: "Collection not found" });
|
|
res.json(collection);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch collection");
|
|
}
|
|
});
|
|
router6.get("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { collections } = await client.request(
|
|
CollectionsDocument,
|
|
{
|
|
userId: req.query.userId,
|
|
limit: req.query.limit ? Number(req.query.limit) : void 0,
|
|
offset: req.query.offset ? Number(req.query.offset) : void 0
|
|
}
|
|
);
|
|
res.json(collections);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch collections");
|
|
}
|
|
});
|
|
router6.post("/", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { createCollection } = await client.request(
|
|
CreateCollectionDocument,
|
|
{ input: req.body }
|
|
);
|
|
res.status(201).json(createCollection);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to create collection");
|
|
}
|
|
});
|
|
router6.put("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { updateCollection } = await client.request(
|
|
UpdateCollectionDocument,
|
|
{ id: req.params.id, input: req.body }
|
|
);
|
|
res.json(updateCollection);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to update collection");
|
|
}
|
|
});
|
|
router6.delete("/:id", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { deleteCollection } = await client.request(
|
|
DeleteCollectionDocument,
|
|
{ id: req.params.id }
|
|
);
|
|
res.json({ success: deleteCollection });
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to delete collection");
|
|
}
|
|
});
|
|
router6.post("/:id/works", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { addWorkToCollection } = await client.request(
|
|
AddWorkToCollectionDocument,
|
|
{
|
|
collectionId: req.params.id,
|
|
workId: req.body.workId
|
|
}
|
|
);
|
|
res.status(201).json(addWorkToCollection);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to add work to collection");
|
|
}
|
|
});
|
|
router6.delete("/:id/works/:workId", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const { removeWorkFromCollection } = await client.request(
|
|
RemoveWorkFromCollectionDocument,
|
|
{
|
|
collectionId: req.params.id,
|
|
workId: req.params.workId
|
|
}
|
|
);
|
|
res.json(removeWorkFromCollection);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to remove work from collection");
|
|
}
|
|
});
|
|
var collection_default = router6;
|
|
|
|
// server/routes/blog.ts
|
|
import { Router as Router7 } from "express";
|
|
var router7 = Router7();
|
|
router7.get("/stats", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const data = await client.request(BlogStatsDocument, {});
|
|
res.json(data.blog);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch blog stats");
|
|
}
|
|
});
|
|
var blog_default = router7;
|
|
|
|
// server/routes/stats.ts
|
|
import { Router as Router8 } from "express";
|
|
var router8 = Router8();
|
|
router8.get("/work", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const data = await client.request(
|
|
WorkStatsDocument,
|
|
{}
|
|
);
|
|
res.json(data.works);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch work stats");
|
|
}
|
|
});
|
|
router8.get("/user", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const data = await client.request(
|
|
UserStatsDocument,
|
|
{}
|
|
);
|
|
res.json(data.users);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch user stats");
|
|
}
|
|
});
|
|
router8.get("/blog", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const data = await client.request(
|
|
BlogStatsDocument,
|
|
{}
|
|
);
|
|
res.json(data.blog);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch blog stats");
|
|
}
|
|
});
|
|
router8.get("/comment", async (req, res) => {
|
|
try {
|
|
const client = req.gql || graphqlClient;
|
|
const data = await client.request(
|
|
CommentStatsDocument,
|
|
{}
|
|
);
|
|
res.json(data.comments);
|
|
} catch (error) {
|
|
respondWithError(res, error, "Failed to fetch comment stats");
|
|
}
|
|
});
|
|
var stats_default = router8;
|
|
|
|
// server/vite.ts
|
|
import fs from "node:fs";
|
|
import path2 from "node:path";
|
|
import express from "express";
|
|
import { nanoid } from "nanoid";
|
|
import { createLogger, createServer as createViteServer } from "vite";
|
|
|
|
// vite.config.ts
|
|
import { defineConfig } from "vite";
|
|
import react from "@vitejs/plugin-react";
|
|
import path from "path";
|
|
var vite_config_default = defineConfig({
|
|
plugins: [react()],
|
|
root: "client",
|
|
resolve: {
|
|
alias: {
|
|
"@": path.resolve(__dirname, "./client/src"),
|
|
"@shared": path.resolve(__dirname, "./shared")
|
|
}
|
|
},
|
|
build: {
|
|
outDir: "../dist"
|
|
}
|
|
});
|
|
|
|
// server/vite.ts
|
|
var viteLogger = createLogger();
|
|
function log(message, source = "express") {
|
|
const formattedTime = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", {
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
second: "2-digit",
|
|
hour12: true
|
|
});
|
|
console.log(`${formattedTime} [${source}] ${message}`);
|
|
}
|
|
async function setupVite(app2, server) {
|
|
const serverOptions = {
|
|
middlewareMode: true,
|
|
hmr: { server },
|
|
allowedHosts: ["localhost"]
|
|
};
|
|
const vite = await createViteServer({
|
|
...vite_config_default,
|
|
configFile: false,
|
|
customLogger: {
|
|
...viteLogger,
|
|
error: (msg, options) => {
|
|
viteLogger.error(msg, options);
|
|
process.exit(1);
|
|
}
|
|
},
|
|
server: serverOptions,
|
|
appType: "custom"
|
|
});
|
|
app2.use(vite.middlewares);
|
|
app2.use("*", async (req, res, next) => {
|
|
const url = req.originalUrl;
|
|
try {
|
|
const clientTemplate = path2.resolve(
|
|
import.meta.dirname,
|
|
"..",
|
|
"client",
|
|
"index.html"
|
|
);
|
|
let template = await fs.promises.readFile(clientTemplate, "utf-8");
|
|
template = template.replace(
|
|
`src="/src/main.tsx"`,
|
|
`src="/src/main.tsx?v=${nanoid()}"`
|
|
);
|
|
const page = await vite.transformIndexHtml(url, template);
|
|
res.status(200).set({ "Content-Type": "text/html" }).end(page);
|
|
} catch (e) {
|
|
vite.ssrFixStacktrace(e);
|
|
next(e);
|
|
}
|
|
});
|
|
}
|
|
function serveStatic(app2) {
|
|
const distPath = path2.resolve(import.meta.dirname, "public");
|
|
if (!fs.existsSync(distPath)) {
|
|
throw new Error(
|
|
`Could not find the build directory: ${distPath}, make sure to build the client first`
|
|
);
|
|
}
|
|
app2.use(express.static(distPath));
|
|
app2.use("*", (_req, res) => {
|
|
res.sendFile(path2.resolve(distPath, "index.html"));
|
|
});
|
|
}
|
|
|
|
// server/index.ts
|
|
import { createServer } from "node:http";
|
|
var app = express2();
|
|
app.use(express2.json());
|
|
app.use(express2.urlencoded({ extended: false }));
|
|
app.use(attachGraphQLClient);
|
|
app.use((req, res, next) => {
|
|
const start = Date.now();
|
|
const path3 = req.path;
|
|
let capturedJsonResponse;
|
|
const originalResJson = res.json;
|
|
res.json = (bodyJson, ...args) => {
|
|
capturedJsonResponse = bodyJson;
|
|
return originalResJson.apply(res, [bodyJson, ...args]);
|
|
};
|
|
res.on("finish", () => {
|
|
const duration = Date.now() - start;
|
|
if (path3.startsWith("/api")) {
|
|
let logLine = `${req.method} ${path3} ${res.statusCode} in ${duration}ms`;
|
|
if (capturedJsonResponse) {
|
|
logLine += ` :: ${JSON.stringify(capturedJsonResponse)}`;
|
|
}
|
|
if (logLine.length > 80) {
|
|
logLine = `${logLine.slice(0, 79)}\u2026`;
|
|
}
|
|
log(logLine);
|
|
}
|
|
});
|
|
next();
|
|
});
|
|
(async () => {
|
|
app.use("/api/users", user_default);
|
|
app.use("/api/authors", author_default);
|
|
app.use("/api/works", work_default);
|
|
app.use("/api/tags", tag_default);
|
|
app.use("/api/comments", comment_default);
|
|
app.use("/api/collections", collection_default);
|
|
app.use("/api/blog", blog_default);
|
|
app.use("/api/stats", stats_default);
|
|
const server = createServer(app);
|
|
app.use((err, _req, res, _next) => {
|
|
const fallbackStatus = 500;
|
|
const status = typeof err === "object" && err ? err.status ?? err.statusCode ?? fallbackStatus : fallbackStatus;
|
|
const message = err instanceof Error ? err.message : "Internal Server Error";
|
|
res.status(status).json({ message });
|
|
throw err;
|
|
});
|
|
if (app.get("env") === "development") {
|
|
await setupVite(app, server);
|
|
} else {
|
|
serveStatic(app);
|
|
}
|
|
const port = 5e3;
|
|
server.listen(port, "0.0.0.0", () => {
|
|
log(`serving on port ${port}`);
|
|
});
|
|
})();
|