Compare commits

...

11 Commits

Author SHA1 Message Date
Gitea Actions
a8f5b4e51a ci: Bump version to 0.0.14 [skip ci] 2025-12-23 08:45:00 +05:00
d0ce8021d6 Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 15m5s
2025-12-22 19:44:11 -08:00
efbb162880 keep disabling tests until the culprit is found this fucking sucks 2025-12-22 19:44:02 -08:00
Gitea Actions
e353ce8a81 ci: Bump version to 0.0.13 [skip ci] 2025-12-23 08:30:20 +05:00
b5cbf271b8 debugging the fucking OOM
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 13m51s
2025-12-22 19:29:10 -08:00
Gitea Actions
2041b4ac3c ci: Bump version to 0.0.12 [skip ci] 2025-12-23 08:19:32 +05:00
e547363a65 Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
2025-12-22 19:19:05 -08:00
bddaf765fc disable to stupid system test that fails - fuck it 2025-12-22 19:18:29 -08:00
Gitea Actions
3c0bebb65c ci: Bump version to 0.0.11 [skip ci] 2025-12-23 07:59:09 +05:00
265cc3ffd4 Merge branch 'main' of https://gitea.projectium.com/torbo/flyer-crawler.projectium.com
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 14m37s
2025-12-22 18:58:11 -08:00
3d5767b60b roll back changes to src/routes/system.routes.ts hopefully before OOM issues 2025-12-22 18:58:01 -08:00
7 changed files with 31 additions and 32 deletions

View File

@@ -136,7 +136,8 @@ jobs:
# Run unit and integration tests as separate steps.
# The `|| true` ensures the workflow continues even if tests fail, allowing coverage to run.
echo "--- Running Unit Tests ---"
npm run test:unit -- --coverage --reporter=verbose --includeTaskLocation --testTimeout=10000 --silent=passed-only || true
# npm run test:unit -- --coverage --reporter=verbose --includeTaskLocation --testTimeout=10000 --silent=passed-only || true
npm run test:unit -- --coverage --reporter=verbose --includeTaskLocation --testTimeout=10000 --silent=passed-only --no-file-parallelism || true
echo "--- Running Integration Tests ---"
npm run test:integration -- --coverage --reporter=verbose --includeTaskLocation --testTimeout=10000 --silent=passed-only || true

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "flyer-crawler",
"version": "0.0.10",
"version": "0.0.14",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "flyer-crawler",
"version": "0.0.10",
"version": "0.0.14",
"dependencies": {
"@bull-board/api": "^6.14.2",
"@bull-board/express": "^6.14.2",

View File

@@ -1,7 +1,7 @@
{
"name": "flyer-crawler",
"private": true,
"version": "0.0.10",
"version": "0.0.14",
"type": "module",
"scripts": {
"dev": "concurrently \"npm:start:dev\" \"vite\"",

View File

@@ -2,8 +2,8 @@
import React, { ReactNode } from 'react';
import { renderHook, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { useUserData } from '../hooks/useUserData';
import { useAuth } from '../hooks/useAuth';
import { useUserData } from './useUserData';
import { useAuth } from './useAuth';
import { UserDataProvider } from '../providers/UserDataProvider';
import { useApiOnMount } from './useApiOnMount';
import type { UserProfile } from '../types';

View File

@@ -1,4 +1,4 @@
// src/routes/system.routests
// src/routes/system.routes.ts
import { Router, Request, Response, NextFunction } from 'express';
import { exec } from 'child_process';
import { z } from 'zod';
@@ -8,7 +8,7 @@ import { validateRequest } from '../middleware/validation.middleware';
const router = Router();
// Validation Schemas
// Helper for consistent required string validation (handles missing/null/empty)
const requiredString = (message: string) =>
z.preprocess((val) => val ?? '', z.string().min(1, message));
@@ -18,65 +18,62 @@ const geocodeSchema = z.object({
}),
});
// An empty schema for routes that do not expect any input, to maintain a consistent validation pattern.
const emptySchema = z.object({});
/**
* GET /pm2-status
* Checks if 'flyer-crawler-api' is online via PM2.
* Checks the status of the 'flyer-crawler-api' process managed by PM2.
* This is intended for development and diagnostic purposes.
*/
router.get(
'/pm2-status',
validateRequest(emptySchema),
(req: Request, res: Response, next: NextFunction) => {
// Using simple exec command
const cmd = 'pm2 describe flyer-crawler-api';
exec(cmd, (error, stdout, stderr) => {
if (res.headersSent) return;
// Handle "process not found" case which might come as an error code OR text
const output = (stdout || '') + (stderr || '');
const processNotFound = output.includes("doesn't exist");
// The name 'flyer-crawler-api' comes from your ecosystem.config.cjs file.
exec('pm2 describe flyer-crawler-api', (error, stdout, stderr) => {
if (error) {
if (processNotFound) {
logger.warn('[API /pm2-status] PM2 process not found.');
// 'pm2 describe' exits with an error if the process is not found.
// We can treat this as a "fail" status for our check.
if (stdout && stdout.includes("doesn't exist")) {
logger.warn('[API /pm2-status] PM2 process "flyer-crawler-api" not found.');
return res.json({
success: false,
message: 'Application process is not running under PM2.',
});
}
logger.error({ err: error.message }, '[API /pm2-status] Exec error');
logger.error(
{ error: stderr || error.message },
'[API /pm2-status] Error executing pm2 describe:',
);
return next(error);
}
// Treat stderr as error if it contains text (PM2 often outputs warnings here)
// Check if there was output to stderr, even if the exit code was 0 (success).
// This handles warnings or non-fatal errors that should arguably be treated as failures in this context.
if (stderr && stderr.trim().length > 0) {
// Special case: if it's just a warning we might want to ignore, but sticking to defensive rules:
logger.error({ stderr }, '[API /pm2-status] Stderr output');
logger.error({ stderr }, '[API /pm2-status] PM2 executed but produced stderr:');
return next(new Error(`PM2 command produced an error: ${stderr}`));
}
// Check for online status in the table output
const isOnline = /│ status\s+│ online\s+│/m.test(stdout || '');
// If the command succeeds, we can parse stdout to check the status.
const isOnline = /│ status\s+│ online\s+│/m.test(stdout);
const message = isOnline
? 'Application is online and running under PM2.'
: 'Application process exists but is not online.';
res.json({ success: isOnline, message });
});
},
);
/**
* POST /geocode
* Proxies geocoding requests securely.
* POST /api/system/geocode - Geocodes a given address string.
* This acts as a secure proxy to the Google Maps Geocoding API.
*/
router.post(
'/geocode',
validateRequest(geocodeSchema),
async (req: Request, res: Response, next: NextFunction) => {
// Infer type and cast request object as per ADR-003
type GeocodeRequest = z.infer<typeof geocodeSchema>;
const {
body: { address },
@@ -86,6 +83,7 @@ router.post(
const coordinates = await geocodingService.geocodeAddress(address, req.log);
if (!coordinates) {
// This check remains, but now it only fails if BOTH services fail.
return res.status(404).json({ message: 'Could not geocode the provided address.' });
}