Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
49ebf78
Merge pull request #3 from stuti-sudo-123/fix/washed-out-color-grading
Areeb-coder May 13, 2026
a7aa22e
feat: add typewriter effect to hero headlines (closes #9)
HirenGajjar May 14, 2026
b5b1fc6
fix: permanent database connection logic and production deployment co…
Areeb-coder May 14, 2026
54bcd00
fix: restore missing database import
Areeb-coder May 14, 2026
9674de3
fix: resolve typescript deprecation error in server build
Areeb-coder May 14, 2026
6591268
fix: force typescript to ignore deprecations (v6.0)
Areeb-coder May 14, 2026
d913141
fix: relax typescript rules for production build
Areeb-coder May 14, 2026
063b51d
fix: disable strict mode for production build
Areeb-coder May 14, 2026
98a74a5
fix: add specific vercel origin to allowed list
Areeb-coder May 14, 2026
fe81e1d
fix: make BASE_URL robust against double /api
Areeb-coder May 14, 2026
5418e03
fix: remove tsconfig baseUrl to fix local and render builds
Areeb-coder May 14, 2026
62984c7
Merge pull request #11 from HirenGajjar/feature/typewriter-hero
Areeb-coder May 14, 2026
1ab5eb4
Fix hero section typewriter animation layout shift
Areeb-coder May 14, 2026
66c7207
chore: clean up project root, move unused files to extra folder
Areeb-coder May 14, 2026
b60b984
feat: complete auth branding and oauth infrastructure integration
Divyansh77-cmd May 14, 2026
55820fa
Merge branch 'feat/auth-branding-oauth' into feat/auth-branding-oauth
Divyansh77-cmd May 14, 2026
5355e8e
fix: Responsive Animated Mobile Navigation
Areeb-coder May 17, 2026
20ee10b
feat: add show/hide password toggle for authentication forms
Areeb-coder May 17, 2026
2c33670
Merge pull request #14
Areeb-coder May 19, 2026
5b288a2
feat: add immersive writer sanctuary dashboard
Dhruva5vora May 22, 2026
260990f
erge branch 'main' into feature/writers-sanctuary-dashboard
Dhruva5vora May 22, 2026
81fa4fa
feat: implement google and facebook authentication
Areeb-coder May 25, 2026
ab71706
merge: resolve signup page conflict and sync with origin/main
Areeb-coder May 25, 2026
344a23e
fix: restore tsconfig ignoreDeprecations on backend and NextAuth plac…
Areeb-coder May 25, 2026
471ed05
fix: change moduleResolution to node10 on backend to fix deprecation …
Areeb-coder May 25, 2026
334f8de
fix: update module and moduleResolution to node16 in server tsconfig
Areeb-coder May 25, 2026
7170f89
fix: explicitly pass secret option in NextAuth configuration
Areeb-coder May 25, 2026
b6e660c
fix: resolve merge conflicts
Dhruva5vora May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,261 changes: 1,261 additions & 0 deletions diff.patch

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"framer-motion": "^12.40.0"
}
}
1 change: 1 addition & 0 deletions server/src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ export const env = {

FRONTEND_URL: process.env.FRONTEND_URL || 'http://localhost:3000',
ALLOW_DEGRADED_START: process.env.ALLOW_DEGRADED_START === 'true',
INTERNAL_AUTH_SHARED_SECRET: process.env.INTERNAL_AUTH_SHARED_SECRET || 'fallback_dev_secret',
};
39 changes: 39 additions & 0 deletions server/src/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,47 @@
import { Request, Response, NextFunction } from 'express';
import { authService } from '../services/auth.service';
import { AppError } from '../middleware/errorHandler';
import crypto from 'crypto';
import { env } from '../config/env';

export const authController = {
async oauthLogin(req: Request, res: Response, next: NextFunction) {
try {
const { email, displayName, avatarUrl, provider, providerId, signature } = req.body;

if (!email || !provider || !providerId || !signature) {
throw new AppError('Missing required OAuth parameters', 400);
}

// Secure backend verification using a shared secret
const expectedSignature = crypto
.createHmac('sha256', env.INTERNAL_AUTH_SHARED_SECRET)
.update(`${providerId}:${email}`)
.digest('hex');

if (signature !== expectedSignature) {
throw new AppError('Unauthorized internal request signature', 403);
}

const result = await authService.oauthLogin({
email,
displayName,
avatarUrl,
provider,
providerId,
});

const { user, tokens } = result;

res.status(200).json({
success: true,
user,
token: tokens.accessToken,
data: result,
});
} catch (err) { next(err); }
},

async register(req: Request, res: Response, next: NextFunction) {
try {
const { email, password, displayName, name, role } = req.body;
Expand Down
1 change: 1 addition & 0 deletions server/src/routes/auth.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const refreshSchema = z.object({
router.post('/register', authLimiter, validate(registerSchema), authController.register);
router.post('/signup', authLimiter, validate(registerSchema), authController.register);
router.post('/login', authLimiter, validate(loginSchema), authController.login);
router.post('/oauth-login', authLimiter, authController.oauthLogin);
router.post('/refresh', validate(refreshSchema), authController.refresh);
router.post('/logout', authenticate, authController.logout);
router.get('/me', authenticate, authController.getMe);
Expand Down
61 changes: 61 additions & 0 deletions server/src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,67 @@ function generateTokens(user: { id: string; email: string; role: UserRole }): Au
}

export const authService = {
async oauthLogin(data: {
email: string;
displayName: string;
avatarUrl?: string;
provider: 'google' | 'facebook';
providerId: string;
}) {
if (!data?.email || !data.email.trim()) {
throw new AppError('Email is required', 400);
}
if (!data?.provider || !data?.providerId) {
throw new AppError('OAuth provider and provider ID are required', 400);
}

const normalizedEmail = data.email.trim().toLowerCase();

// 1. Check if user already exists (by email or oauth credentials)
let userDoc = await UserModel.findOne({
$or: [
{ email: normalizedEmail },
{ oauth_provider: data.provider, oauth_id: data.providerId }
]
});

if (!userDoc) {
// 2. Register new OAuth user
userDoc = await UserModel.create({
email: normalizedEmail,
display_name: data.displayName.trim(),
avatar_url: data.avatarUrl || null,
oauth_provider: data.provider,
oauth_id: data.providerId,
role: 'writer', // Default role
is_verified: true, // OAuth verified users are pre-verified
});
} else {
// 3. User exists, link OAuth provider credentials if missing
let needsUpdate = false;
if (!userDoc.oauth_provider) {
userDoc.oauth_provider = data.provider;
userDoc.oauth_id = data.providerId;
needsUpdate = true;
}
if (data.avatarUrl && !userDoc.avatar_url) {
userDoc.avatar_url = data.avatarUrl;
needsUpdate = true;
}
if (needsUpdate) {
await userDoc.save();
}
}

// 4. Generate backend custom tokens
const user = normalize(userDoc);
const tokens = generateTokens({ id: user.id, email: user.email, role: user.role });
await UserModel.findByIdAndUpdate(user.id, { refresh_token: tokens.refreshToken });

const { password_hash, refresh_token, ...safeUser } = user as any;
return { user: safeUser, tokens };
},

async register(data: { email: string; password: string; displayName: string; role?: UserRole }) {
if (!data?.email || !data.email.trim()) {
throw new AppError('Email is required', 400);
Expand Down
5 changes: 2 additions & 3 deletions server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"module": "node16",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
Expand All @@ -12,8 +12,7 @@
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"moduleResolution": "node",
"ignoreDeprecations": "6.0",
"moduleResolution": "node16",
"strict": false,
"skipLibCheck": true,
"noImplicitAny": false
Expand Down
Binary file added web/lint.txt
Binary file not shown.
84 changes: 84 additions & 0 deletions web/lint8.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

> web@0.1.0 lint
> eslint


E:\Projects\writers-pub\web\src\app\agora\[id]\page.tsx
14:10 warning 'FeedbackItemSkeleton' is defined but never used @typescript-eslint/no-unused-vars
50:9 warning 'draftDateFormatted' is assigned a value but never used @typescript-eslint/no-unused-vars

E:\Projects\writers-pub\web\src\app\agora\leaderboard\page.tsx
74:64 error `'` can be escaped with `'`, `‘`, `'`, `’` react/no-unescaped-entities

E:\Projects\writers-pub\web\src\app\agora\page.tsx
8:10 warning 'Badge' is defined but never used @typescript-eslint/no-unused-vars
11:3 warning 'MessageSquare' is defined but never used @typescript-eslint/no-unused-vars
12:3 warning 'BookOpen' is defined but never used @typescript-eslint/no-unused-vars
13:3 warning 'Clock' is defined but never used @typescript-eslint/no-unused-vars
18:3 warning 'Eye' is defined but never used @typescript-eslint/no-unused-vars
23:10 warning 'useFormattedDate' is defined but never used @typescript-eslint/no-unused-vars
23:28 warning 'useFormattedNumber' is defined but never used @typescript-eslint/no-unused-vars

E:\Projects\writers-pub\web\src\app\studio\brainstorm\page.tsx
53:14 warning 'error' is defined but never used @typescript-eslint/no-unused-vars

E:\Projects\writers-pub\web\src\components\DraftCard.tsx
47:72 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any

E:\Projects\writers-pub\web\src\components\layout\MainLayout.tsx
27:5 error Error: Calling setState synchronously within an effect can trigger cascading renders

Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
* Update external systems with the latest state from React.
* Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

E:\Projects\writers-pub\web\src\components\layout\MainLayout.tsx:27:5
25 |
26 | useEffect(() => {
> 27 | setIsMounted(true);
| ^^^^^^^^^^^^ Avoid calling setState() directly within an effect
28 | }, []);
29 |
30 | useEffect(() => { react-hooks/set-state-in-effect

E:\Projects\writers-pub\web\src\components\ui\Avatar.tsx
38:9 warning Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element

E:\Projects\writers-pub\web\src\lib\useFormatDate.ts
16:7 error Error: Calling setState synchronously within an effect can trigger cascading renders

Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
* Update external systems with the latest state from React.
* Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

E:\Projects\writers-pub\web\src\lib\useFormatDate.ts:16:7
14 | const day = date.getDate();
15 | const year = date.getFullYear();
> 16 | setFormatted(`${month} ${day}, ${year}`);
| ^^^^^^^^^^^^ Avoid calling setState() directly within an effect
17 | } catch {
18 | setFormatted('Unknown date');
19 | } react-hooks/set-state-in-effect
34:7 error Error: Calling setState synchronously within an effect can trigger cascading renders

Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:
* Update external systems with the latest state from React.
* Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

E:\Projects\writers-pub\web\src\lib\useFormatDate.ts:34:7
32 | useEffect(() => {
33 | try {
> 34 | setFormatted(new Intl.NumberFormat('en-US').format(num));
| ^^^^^^^^^^^^ Avoid calling setState() directly within an effect
35 | } catch {
36 | setFormatted(String(num));
37 | } react-hooks/set-state-in-effect

Γ£û 16 problems (5 errors, 11 warnings)

Loading