Feature/Use fastify instead of express (#1)
- Replaced Apollo Server with Mercurius for GraphQL API - Updated resolvers to use Mercurius-compatible GraphQL implementation - Migrated from Express to Fastify for server framework - Improved error handling with GraphQL error extensions - Added Zod for environment variable validation - Updated Prisma schema and migrations - Configured CORS and WebSocket subscriptions - Simplified GraphQL schema and resolver structure - Enhanced type safety and code organization - Replaced Apollo Server with Mercurius for GraphQL API - Updated resolvers to use Mercurius-compatible GraphQL implementation - Migrated from Express to Fastify for server framework - Improved error handling with GraphQL error extensions - Added Zod for environment variable validation - Updated Prisma schema and migrations - Configured CORS and WebSocket subscriptions - Simplified GraphQL schema and resolver structure - Enhanced type safety and code organization Reviewed-on: #1 Co-authored-by: Jusemon <juansmm@outlook.com> Co-committed-by: Jusemon <juansmm@outlook.com>
This commit is contained in:
parent
b4e5a04126
commit
6214b503bc
47 changed files with 4968 additions and 5424 deletions
4
apps/web/eslint.config.js
Normal file
4
apps/web/eslint.config.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { config } from '@repo/eslint-config/solid-js';
|
||||
|
||||
/** @type {import("eslint").Linter.Config} */
|
||||
export default config;
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Solid + TS</title>
|
||||
<title>Ultimate Chat</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
@ -5,20 +5,21 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"check-types": "tsc --noEmit"
|
||||
"build": "tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@urql/core": "^5.1.1",
|
||||
"graphql": "^16.8.1",
|
||||
"@urql/solid": "^0.1.2",
|
||||
"graphql-ws": "^6.0.4",
|
||||
"solid-js": "^1.8.15",
|
||||
"@urql/solid": "^0.1.2"
|
||||
"solid-js": "^1.9.5",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.1.4",
|
||||
"vite-plugin-solid": "^2.10.1"
|
||||
"@repo/eslint-config": "*",
|
||||
"@repo/typescript-config": "*",
|
||||
"typescript": "5.8.2",
|
||||
"vite": "^6.2.0",
|
||||
"vite-plugin-solid": "^2.11.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ function App() {
|
|||
// Call checkAuth on component mount
|
||||
checkAuth();
|
||||
|
||||
const handleLoginSuccess = (token: string, id: string) => {
|
||||
const handleLoginSuccess = (_: string, id: string) => {
|
||||
setIsAuthenticated(true);
|
||||
setUserId(id);
|
||||
};
|
||||
|
|
|
@ -79,17 +79,23 @@ export function RoomList(props: RoomListProps) {
|
|||
});
|
||||
|
||||
// Subscribe to new rooms
|
||||
const [roomAddedSubscription] = createSubscription({
|
||||
const [roomAddedSubscription] = createSubscription<{
|
||||
roomAdded: Room;
|
||||
}>({
|
||||
query: ROOM_ADDED_SUBSCRIPTION,
|
||||
});
|
||||
|
||||
// Subscribe to room updates (when members change)
|
||||
const [roomUpdatedSubscription] = createSubscription({
|
||||
const [roomUpdatedSubscription] = createSubscription<{
|
||||
roomUpdated: Room;
|
||||
}>({
|
||||
query: ROOM_UPDATED_SUBSCRIPTION,
|
||||
});
|
||||
|
||||
// Join room mutation
|
||||
const [joinRoomResult, joinRoom] = createMutation(JOIN_ROOM_MUTATION);
|
||||
const [joinRoomResult, joinRoom] = createMutation<{
|
||||
joinRoom: Room;
|
||||
}>(JOIN_ROOM_MUTATION);
|
||||
|
||||
// Load initial rooms
|
||||
createEffect(() => {
|
||||
|
@ -150,7 +156,7 @@ export function RoomList(props: RoomListProps) {
|
|||
setRooms((prev) =>
|
||||
prev.map((room) =>
|
||||
room.id === roomId
|
||||
? { ...room, members: result.data.joinRoom.members }
|
||||
? { ...room, members: result.data!.joinRoom.members }
|
||||
: room
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* @refresh reload */
|
||||
import { render } from 'solid-js/web'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
import { render } from 'solid-js/web';
|
||||
import './index.css';
|
||||
import App from './App.tsx';
|
||||
|
||||
const root = document.getElementById('root')
|
||||
const root = document.getElementById('root');
|
||||
|
||||
render(() => <App />, root!)
|
||||
render(() => <App />, root!);
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import { z } from 'zod';
|
||||
import { createClient, fetchExchange, subscriptionExchange } from '@urql/core';
|
||||
import { createClient as createWSClient } from 'graphql-ws';
|
||||
import { createClient as createWsClient } from 'graphql-ws';
|
||||
|
||||
// Get API URLs from environment variables
|
||||
const API_URL =
|
||||
import.meta.env.VITE_API_URL || 'https://chat-api.jusemon.com/graphql';
|
||||
const WS_URL =
|
||||
import.meta.env.VITE_WS_URL || 'wss://chat-api.jusemon.com/graphql';
|
||||
const envSchema = z
|
||||
.object({ VITE_API_URL: z.string(), VITE_WS_URL: z.string() })
|
||||
.transform((env) => ({
|
||||
API_URL: env.VITE_API_URL,
|
||||
WS_URL: env.VITE_WS_URL,
|
||||
}));
|
||||
const { API_URL, WS_URL } = envSchema.parse(import.meta.env);
|
||||
console.log('Current API_URL', API_URL);
|
||||
console.log('Current WS_URL', WS_URL);
|
||||
|
||||
// Create a WebSocket client for GraphQL subscriptions
|
||||
const wsClient = createWSClient({
|
||||
const wsClient = createWsClient({
|
||||
url: WS_URL,
|
||||
});
|
||||
|
||||
|
@ -23,11 +27,8 @@ export const client = createClient({
|
|||
forwardSubscription: (operation) => ({
|
||||
subscribe: (sink) => {
|
||||
const dispose = wsClient.subscribe(
|
||||
{
|
||||
...operation,
|
||||
query: operation.query || '',
|
||||
},
|
||||
sink as any
|
||||
{ ...operation, query: operation.query || '' },
|
||||
sink
|
||||
);
|
||||
return {
|
||||
unsubscribe: dispose,
|
||||
|
|
9
apps/web/src/vite-env.d.ts
vendored
9
apps/web/src/vite-env.d.ts
vendored
|
@ -1 +1,10 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_API_URL: string;
|
||||
readonly VITE_WS_URL: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
|
@ -1,7 +1,28 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
"extends": "@repo/typescript-config/solid.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "solid-js",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import solid from 'vite-plugin-solid'
|
||||
import { defineConfig } from 'vite';
|
||||
import solid from 'vite-plugin-solid';
|
||||
|
||||
export default defineConfig({
|
||||
envDir: '../../',
|
||||
plugins: [solid()],
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue