chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,172 @@
/**
* Tests for reset password API route
*
* @vitest-environment node
*/
import { createMockRequest } from '@sim/testing'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const { mockResetPassword, mockLogger } = vi.hoisted(() => {
const logger = {
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
trace: vi.fn(),
fatal: vi.fn(),
child: vi.fn(),
}
return {
mockResetPassword: vi.fn(),
mockLogger: logger,
}
})
vi.mock('@/lib/auth', () => ({
auth: {
api: {
resetPassword: mockResetPassword,
},
},
}))
vi.mock('@sim/logger', () => ({
createLogger: vi.fn().mockReturnValue(mockLogger),
runWithRequestContext: <T>(_ctx: unknown, fn: () => T): T => fn(),
getRequestContext: () => undefined,
}))
import { POST } from '@/app/api/auth/reset-password/route'
describe('Reset Password API Route', () => {
beforeEach(() => {
vi.clearAllMocks()
mockResetPassword.mockResolvedValue(undefined)
})
afterEach(() => {
vi.clearAllMocks()
})
it('should reset password successfully', async () => {
const req = createMockRequest('POST', {
token: 'valid-reset-token',
newPassword: 'newSecurePassword123!',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(200)
expect(data.success).toBe(true)
expect(mockResetPassword).toHaveBeenCalledWith({
body: {
token: 'valid-reset-token',
newPassword: 'newSecurePassword123!',
},
method: 'POST',
})
})
it('should handle missing token', async () => {
const req = createMockRequest('POST', {
newPassword: 'newSecurePassword123!',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(400)
expect(data.message).toBe('Token is required')
expect(mockResetPassword).not.toHaveBeenCalled()
})
it('should handle missing new password', async () => {
const req = createMockRequest('POST', {
token: 'valid-reset-token',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(400)
expect(data.message).toBe('Password is required')
expect(mockResetPassword).not.toHaveBeenCalled()
})
it('should handle empty token', async () => {
const req = createMockRequest('POST', {
token: '',
newPassword: 'newSecurePassword123!',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(400)
expect(data.message).toBe('Token is required')
expect(mockResetPassword).not.toHaveBeenCalled()
})
it('should handle empty new password', async () => {
const req = createMockRequest('POST', {
token: 'valid-reset-token',
newPassword: '',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(400)
expect(data.message).toContain('Password must be at least 8 characters long')
expect(data.message).toContain('Password must contain at least one uppercase letter')
expect(data.message).toContain('Password must contain at least one lowercase letter')
expect(data.message).toContain('Password must contain at least one number')
expect(data.message).toContain('Password must contain at least one special character')
expect(mockResetPassword).not.toHaveBeenCalled()
})
it('should handle auth service error with message', async () => {
const errorMessage = 'Invalid or expired token'
mockResetPassword.mockRejectedValue(new Error(errorMessage))
const req = createMockRequest('POST', {
token: 'invalid-token',
newPassword: 'newSecurePassword123!',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(500)
expect(data.message).toBe(errorMessage)
expect(mockLogger.error).toHaveBeenCalledWith('Error during password reset:', {
error: expect.any(Error),
})
})
it('should handle unknown error', async () => {
mockResetPassword.mockRejectedValue('Unknown error')
const req = createMockRequest('POST', {
token: 'valid-reset-token',
newPassword: 'newSecurePassword123!',
})
const response = await POST(req)
const data = await response.json()
expect(response.status).toBe(500)
expect(data.message).toBe(
'Failed to reset password. Please try again or request a new reset link.'
)
expect(mockLogger.error).toHaveBeenCalled()
})
})
@@ -0,0 +1,52 @@
import { createLogger } from '@sim/logger'
import { type NextRequest, NextResponse } from 'next/server'
import { resetPasswordContract } from '@/lib/api/contracts'
import { parseRequest } from '@/lib/api/server'
import { auth } from '@/lib/auth'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
export const dynamic = 'force-dynamic'
const logger = createLogger('PasswordResetAPI')
export const POST = withRouteHandler(async (request: NextRequest) => {
try {
const parsed = await parseRequest(
resetPasswordContract,
request,
{},
{
validationErrorResponse: (error) => {
logger.warn('Invalid password reset request data', { errors: error.issues })
const message = error.issues.map((e) => e.message).join(' ')
return NextResponse.json({ message }, { status: 400 })
},
}
)
if (!parsed.success) return parsed.response
const { token, newPassword } = parsed.data.body
await auth.api.resetPassword({
body: {
newPassword,
token,
},
method: 'POST',
})
return NextResponse.json({ success: true })
} catch (error) {
logger.error('Error during password reset:', { error })
return NextResponse.json(
{
message:
error instanceof Error
? error.message
: 'Failed to reset password. Please try again or request a new reset link.',
},
{ status: 500 }
)
}
})