refactor(fase0): shared scaffold — crypto, file-url, schemas, test splits
- Add zod dep; new src/shared/validation/schemas.ts (BucketName, JsonUploadPayload, LoginBody, DeleteObjects, CompleteMultipart, clampMaxKeys, parseOrNull) + test/validation.test.ts - Dedup timingSafeCompare -> src/shared/utils/crypto.ts (auth middleware, authenticate use-case, s3/auth now import it) - Dedup AuthSession -> single type in dto/auth.ts - Dedup telegram file URL builder + filename sanitizer to shared modules (file-controller now imports the canonical ones) - Remove duplicate controllers/home.html (canonical: src/home.html) - Fix stale bootstrap mocks to real module paths; bootstrap now asserts public GET vs guarded POST separately - Fix health assertion to include version field - package.json: test -> test:unit alias; new test:quarantine for network/live tests; register previously unlisted test files
This commit is contained in:
+17
-4
@@ -42,7 +42,7 @@ mock.module('../src/interfaces/bot/handler', () => ({
|
||||
startBot: mockStartBot,
|
||||
}));
|
||||
|
||||
mock.module('../src/db/migrate', () => ({
|
||||
mock.module('../src/infrastructure/persistence/drizzle/migrate', () => ({
|
||||
runMigration: mock(() => Promise.resolve()),
|
||||
}));
|
||||
|
||||
@@ -75,7 +75,7 @@ mock.module('../src/interfaces/http/middleware/auth', () => ({
|
||||
requireAuth: mockRequireAuth,
|
||||
}));
|
||||
|
||||
mock.module('../src/utils/rateLimit', () => ({
|
||||
mock.module('../src/interfaces/http/middleware/rate-limit', () => ({
|
||||
cleanupRateLimitCache: mock(),
|
||||
clearRateLimitCache: mock(),
|
||||
checkRateLimit: mock(() => true),
|
||||
@@ -128,8 +128,21 @@ describe('Bootstrap Server', () => {
|
||||
expect(await res.json()).toEqual({ ok: true });
|
||||
expect(mockHandleUpload).toHaveBeenCalledTimes(1);
|
||||
|
||||
const webApiRoute = serveCallArgs.routes?.['/api/v1/*'] as { GET: RouteHandler };
|
||||
const protectedRes = await webApiRoute.GET(new Request('http://localhost/api/v1/files'));
|
||||
// GET /api/v1/* is intentionally public (read endpoints need no auth) —
|
||||
// it passes through to the raw handler (stubbed here to 404).
|
||||
const webApiRoute = serveCallArgs.routes?.['/api/v1/*'] as {
|
||||
GET: RouteHandler;
|
||||
POST: RouteHandler;
|
||||
};
|
||||
const publicRes = await webApiRoute.GET(new Request('http://localhost/api/v1/files'));
|
||||
|
||||
expect(publicRes.status).toBe(404);
|
||||
expect(await publicRes.json()).toEqual({ error: 'Not Found' });
|
||||
|
||||
// Write endpoints are auth-guarded — POST goes through requireAuth (401 here).
|
||||
const protectedRes = await webApiRoute.POST(
|
||||
new Request('http://localhost/api/v1/files', { method: 'POST' }),
|
||||
);
|
||||
|
||||
expect(protectedRes.status).toBe(401);
|
||||
expect(await protectedRes.json()).toEqual({ error: 'Unauthorized' });
|
||||
|
||||
Reference in New Issue
Block a user