chore: remove dead routes/components + fix redact/env cleanup
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
const secretPatterns = [
|
||||
/ghs_[A-Za-z0-9_]+/g,
|
||||
/github_pat_[A-Za-z0-9_]+/g,
|
||||
/sk-[A-Za-z0-9_-]+/g,
|
||||
/(client_secret|auth_secret|api_key|token|password)=([^ \n\r]+)/gi,
|
||||
const secretPatterns: { pattern: RegExp; replacement: string }[] = [
|
||||
{ pattern: /ghs_[A-Za-z0-9_]+/g, replacement: '[redacted]' },
|
||||
{ pattern: /github_pat_[A-Za-z0-9_]+/g, replacement: '[redacted]' },
|
||||
{ pattern: /sk-[A-Za-z0-9_-]+/g, replacement: '[redacted]' },
|
||||
{
|
||||
pattern: /(client_secret|auth_secret|api_key|token|password)=([^ \n\r]+)/gi,
|
||||
replacement: '$1=[redacted]',
|
||||
},
|
||||
];
|
||||
|
||||
export const createRedactor = (values: string[]) => {
|
||||
@@ -12,8 +15,8 @@ export const createRedactor = (values: string[]) => {
|
||||
for (const secret of secrets) {
|
||||
output = output.split(secret).join('[redacted]');
|
||||
}
|
||||
for (const pattern of secretPatterns) {
|
||||
output = output.replace(pattern, '$1=[redacted]');
|
||||
for (const { pattern, replacement } of secretPatterns) {
|
||||
output = output.replace(pattern, replacement);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { createRedactor } from '../../src/redact';
|
||||
|
||||
describe('createRedactor', () => {
|
||||
test('redacts group-less token patterns without emitting a literal $1', () => {
|
||||
const redact = createRedactor([]);
|
||||
const output = redact('token ghs_ABC123 and sk-xyz789 here');
|
||||
|
||||
expect(output).toContain('[redacted]');
|
||||
expect(output).not.toContain('$1');
|
||||
expect(output).not.toContain('ghs_ABC123');
|
||||
expect(output).not.toContain('sk-xyz789');
|
||||
});
|
||||
|
||||
test('redacts github_pat_ tokens to [redacted]', () => {
|
||||
const redact = createRedactor([]);
|
||||
const output = redact('github_pat_ABCDEF123456');
|
||||
|
||||
expect(output).toBe('[redacted]');
|
||||
expect(output).not.toContain('$1');
|
||||
});
|
||||
|
||||
test('keeps the key= prefix for key=value secrets', () => {
|
||||
const redact = createRedactor([]);
|
||||
|
||||
expect(redact('api_key=secret')).toBe('api_key=[redacted]');
|
||||
expect(redact('password=hunter2')).toBe('password=[redacted]');
|
||||
});
|
||||
|
||||
test('redacts caller-supplied secret values verbatim', () => {
|
||||
const redact = createRedactor(['super-secret-value']);
|
||||
|
||||
expect(redact('the value is super-secret-value')).toBe(
|
||||
'the value is [redacted]',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const AgentsRedirectPage = () => {
|
||||
redirect('/threads?source=user_request');
|
||||
};
|
||||
|
||||
export default AgentsRedirectPage;
|
||||
@@ -1,5 +0,0 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const AiSettingsPage = () => redirect('/settings/ai-providers');
|
||||
|
||||
export default AiSettingsPage;
|
||||
@@ -1,7 +0,0 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const UpdatesRedirectPage = () => {
|
||||
redirect('/threads?source=upstream_update');
|
||||
};
|
||||
|
||||
export default UpdatesRedirectPage;
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { isAuthenticatedNextjs } from '@convex-dev/auth/nextjs/server';
|
||||
|
||||
export const generateMetadata = (): Metadata => {
|
||||
return {
|
||||
title: 'Profile',
|
||||
robots: {
|
||||
index: false,
|
||||
follow: false,
|
||||
googleBot: {
|
||||
index: false,
|
||||
follow: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ProfileLayout = async ({
|
||||
children,
|
||||
}: Readonly<{ children: React.ReactNode }>) => {
|
||||
if (!(await isAuthenticatedNextjs())) redirect('/sign-in');
|
||||
return <>{children}</>;
|
||||
};
|
||||
export default ProfileLayout;
|
||||
@@ -1,6 +0,0 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const Profile = () => {
|
||||
redirect('/settings/profile');
|
||||
};
|
||||
export default Profile;
|
||||
@@ -1,75 +0,0 @@
|
||||
const techStack = [
|
||||
{
|
||||
category: 'Frontend',
|
||||
technologies: [
|
||||
{ name: 'Next.js 16', description: 'React framework with App Router' },
|
||||
{ name: 'Expo 54', description: 'React Native framework' },
|
||||
{ name: 'React 19', description: 'Latest React with Server Components' },
|
||||
{
|
||||
name: 'Tailwind CSS v4',
|
||||
description: 'Utility-first CSS framework',
|
||||
},
|
||||
{ name: 'shadcn/ui', description: 'Beautiful component library' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: 'Backend',
|
||||
technologies: [
|
||||
{ name: 'Convex', description: 'Self-hosted reactive backend' },
|
||||
{
|
||||
name: '@convex-dev/auth',
|
||||
description: 'Multi-provider authentication',
|
||||
},
|
||||
{ name: 'UseSend', description: 'Self-hosted email service' },
|
||||
{ name: 'File Storage', description: 'Built-in file uploads' },
|
||||
],
|
||||
},
|
||||
{
|
||||
category: 'Developer Tools',
|
||||
technologies: [
|
||||
{ name: 'Turborepo', description: 'High-performance build system' },
|
||||
{ name: 'TypeScript', description: 'Type-safe development' },
|
||||
{ name: 'Bun', description: 'Fast package manager and runtime' },
|
||||
{ name: 'ESLint + Prettier', description: 'Code quality tools' },
|
||||
{ name: 'Docker', description: 'Containerized deployment' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const TechStack = () => (
|
||||
<section id='tech-stack' className='border-border/40 bg-muted/30 border-t'>
|
||||
<div className='container mx-auto px-4 py-24'>
|
||||
<div className='mx-auto max-w-6xl'>
|
||||
<div className='mb-16 text-center'>
|
||||
<h2 className='mb-4 text-3xl font-bold tracking-tight sm:text-4xl md:text-5xl'>
|
||||
Modern Tech Stack
|
||||
</h2>
|
||||
<p className='text-muted-foreground mx-auto max-w-2xl text-lg'>
|
||||
Built with the latest and greatest tools for maximum productivity
|
||||
and performance.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='grid gap-12 md:grid-cols-3'>
|
||||
{techStack.map((stack) => (
|
||||
<div key={stack.category}>
|
||||
<h3 className='mb-6 text-xl font-semibold'>{stack.category}</h3>
|
||||
<ul className='space-y-4'>
|
||||
{stack.technologies.map((tech) => (
|
||||
<li key={tech.name}>
|
||||
<div className='text-foreground font-medium'>
|
||||
{tech.name}
|
||||
</div>
|
||||
<div className='text-muted-foreground text-sm'>
|
||||
{tech.description}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
@@ -33,7 +33,6 @@ const runtimeLabels: Record<RuntimeName, string> = {
|
||||
};
|
||||
|
||||
type AgentSettings = {
|
||||
_id?: Id<'spoonAgentSettings'>;
|
||||
enabled: boolean;
|
||||
runtime?: RuntimeName | 'openai_direct';
|
||||
defaultBaseBranch?: string;
|
||||
|
||||
@@ -34,7 +34,6 @@ const runtimeLabels: Record<RuntimeName, string> = {
|
||||
};
|
||||
|
||||
type AgentSettings = {
|
||||
_id?: Id<'spoonAgentSettings'>;
|
||||
defaultBaseBranch?: string;
|
||||
runtime?: RuntimeName | 'openai_direct';
|
||||
agentModel: string;
|
||||
|
||||
@@ -8,12 +8,9 @@ const isAuthRoute = createRouteMatcher(['/sign-in', '/forgot-password']);
|
||||
const isProtectedRoute = createRouteMatcher([
|
||||
'/dashboard(.*)',
|
||||
'/spoons(.*)',
|
||||
'/updates(.*)',
|
||||
'/agents(.*)',
|
||||
'/threads(.*)',
|
||||
'/github(.*)',
|
||||
'/settings(.*)',
|
||||
'/profile(.*)',
|
||||
]);
|
||||
|
||||
export default convexAuthNextjsMiddleware(
|
||||
|
||||
Reference in New Issue
Block a user