feat(phase-0): setup Docker Compose with TypeScript monorepo structure
- Create monorepo structure with apps/ and packages/ - Add Docker Compose for api, web, db, redis, worker services - Migrate existing Express.js logic to TypeScript with 100% backward compatibility - Preserve all existing API endpoints (/api/track, /api/v1/track) with identical behavior - Setup development environment with hot reload and proper networking - Add comprehensive TypeScript configuration with path mapping - Include production-ready Dockerfiles with multi-stage builds - Maintain existing rate limiting (100 req/hour/IP) and response formats - Add health checks and graceful shutdown handling - Setup Turbo for efficient monorepo builds and development
This commit is contained in:
18
packages/shared/src/index.ts
Normal file
18
packages/shared/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Shared utilities and types for Redirect Intelligence v2
|
||||
*/
|
||||
|
||||
export * from './types/api';
|
||||
|
||||
export const constants = {
|
||||
API_BASE_URL: process.env.REACT_APP_API_URL || 'http://localhost:3333',
|
||||
RATE_LIMIT: {
|
||||
WINDOW_MS: 60 * 60 * 1000, // 1 hour
|
||||
MAX_REQUESTS: 100,
|
||||
},
|
||||
REDIRECT_LIMITS: {
|
||||
MAX_HOPS: 20,
|
||||
TIMEOUT_MS: 15000,
|
||||
RESPONSE_BODY_LIMIT: 5000,
|
||||
},
|
||||
} as const;
|
||||
60
packages/shared/src/types/api.ts
Normal file
60
packages/shared/src/types/api.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Shared API types for Redirect Intelligence v2
|
||||
*/
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
// Base API response
|
||||
export const ApiResponseSchema = z.object({
|
||||
success: z.boolean(),
|
||||
status: z.number(),
|
||||
data: z.any().optional(),
|
||||
error: z.string().optional(),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
|
||||
export type ApiResponse<T = any> = {
|
||||
success: boolean;
|
||||
status: number;
|
||||
data?: T;
|
||||
error?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
// Legacy redirect result (for backward compatibility)
|
||||
export const LegacyRedirectSchema = z.object({
|
||||
url: z.string(),
|
||||
timestamp: z.number(),
|
||||
isSSL: z.boolean(),
|
||||
duration: z.number().optional(),
|
||||
statusCode: z.number().optional(),
|
||||
statusText: z.string().optional(),
|
||||
metadata: z.any().optional(),
|
||||
responseBody: z.string().optional(),
|
||||
sslInfo: z.any().optional(),
|
||||
error: z.string().optional(),
|
||||
final: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type LegacyRedirect = z.infer<typeof LegacyRedirectSchema>;
|
||||
|
||||
// Track request schemas
|
||||
export const TrackRequestSchema = z.object({
|
||||
url: z.string().url(),
|
||||
method: z.enum(['GET', 'HEAD', 'POST']).default('GET'),
|
||||
userAgent: z.string().optional(),
|
||||
});
|
||||
|
||||
export type TrackRequest = z.infer<typeof TrackRequestSchema>;
|
||||
|
||||
// Track response schema
|
||||
export const TrackResponseSchema = z.object({
|
||||
url: z.string(),
|
||||
method: z.string(),
|
||||
redirectCount: z.number(),
|
||||
finalUrl: z.string(),
|
||||
finalStatusCode: z.number().optional(),
|
||||
redirects: z.array(LegacyRedirectSchema),
|
||||
});
|
||||
|
||||
export type TrackResponse = z.infer<typeof TrackResponseSchema>;
|
||||
Reference in New Issue
Block a user