Compare commits

...

8 Commits

Author SHA1 Message Date
Gitea Actions
dd31141d4e ci: Bump version to 0.9.109 [skip ci] 2026-01-13 23:09:47 +05:00
8073094760 testing/staging fixin
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 16m15s
2026-01-13 10:08:28 -08:00
Gitea Actions
33a1e146ab ci: Bump version to 0.9.108 [skip ci] 2026-01-13 22:34:20 +05:00
4f8216db77 testing/staging fixin
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 15m55s
2026-01-13 09:33:38 -08:00
Gitea Actions
42d605d19f ci: Bump version to 0.9.107 [skip ci] 2026-01-13 22:06:39 +05:00
749350df7f testing/staging fixin
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 15m56s
2026-01-13 09:03:42 -08:00
Gitea Actions
ac085100fe ci: Bump version to 0.9.106 [skip ci] 2026-01-13 21:43:43 +05:00
ce4ecd1268 use port 3002 in test
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 16m13s
2026-01-13 08:42:34 -08:00
9 changed files with 49 additions and 19 deletions

View File

@@ -71,7 +71,7 @@ module.exports = {
exp_backoff_restart_delay: 100,
min_uptime: '10s',
env: {
NODE_ENV: 'test',
NODE_ENV: 'staging',
PORT: 3002,
WORKER_LOCK_DURATION: '120000',
...sharedEnv,
@@ -90,7 +90,7 @@ module.exports = {
exp_backoff_restart_delay: 100,
min_uptime: '10s',
env: {
NODE_ENV: 'test',
NODE_ENV: 'staging',
...sharedEnv,
},
},
@@ -107,7 +107,7 @@ module.exports = {
exp_backoff_restart_delay: 100,
min_uptime: '10s',
env: {
NODE_ENV: 'test',
NODE_ENV: 'staging',
...sharedEnv,
},
},

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "flyer-crawler",
"version": "0.9.105",
"version": "0.9.109",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "flyer-crawler",
"version": "0.9.105",
"version": "0.9.109",
"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.9.105",
"version": "0.9.109",
"type": "module",
"scripts": {
"dev": "concurrently \"npm:start:dev\" \"vite\"",

View File

@@ -128,7 +128,7 @@ const workerSchema = z.object({
* Server configuration schema.
*/
const serverSchema = z.object({
nodeEnv: z.enum(['development', 'production', 'test']).default('development'),
nodeEnv: z.enum(['development', 'production', 'test', 'staging']).default('development'),
port: intWithDefault(3001),
frontendUrl: z.string().url().optional(),
baseUrl: z.string().optional(),
@@ -262,8 +262,9 @@ function parseConfig(): EnvConfig {
'',
].join('\n');
// In test environment, throw instead of exiting to allow test frameworks to catch
if (process.env.NODE_ENV === 'test') {
// In test/staging environment, throw instead of exiting to allow test frameworks to catch
// and to provide better visibility into config errors during staging deployments
if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'staging') {
throw new Error(errorMessage);
}
@@ -318,6 +319,24 @@ export const isTest = config.server.nodeEnv === 'test';
*/
export const isDevelopment = config.server.nodeEnv === 'development';
/**
* Returns true if running in staging environment.
*/
export const isStaging = config.server.nodeEnv === 'staging';
/**
* Returns true if running in a test-like environment (test or staging).
* Use this for behaviors that should be shared between unit/integration tests
* and the staging deployment server, such as:
* - Using mock AI services (no GEMINI_API_KEY required)
* - Verbose error logging
* - Fallback URL handling
*
* Do NOT use this for security bypasses (auth, rate limiting) - those should
* only be active in NODE_ENV=test, not staging.
*/
export const isTestLikeEnvironment = isTest || isStaging;
/**
* Returns true if SMTP is configured (all required fields present).
*/

View File

@@ -161,9 +161,12 @@ export const errorHandler = (err: Error, req: Request, res: Response, next: Next
`Unhandled API Error (ID: ${errorId})`,
);
// Also log to console in test environment for visibility in test runners
if (process.env.NODE_ENV === 'test') {
console.error(`--- [TEST] UNHANDLED ERROR (ID: ${errorId}) ---`, err);
// Also log to console in test/staging environments for visibility in test runners
if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'staging') {
console.error(
`--- [${process.env.NODE_ENV?.toUpperCase()}] UNHANDLED ERROR (ID: ${errorId}) ---`,
err,
);
}
// In production, send a generic message to avoid leaking implementation details.

View File

@@ -239,10 +239,13 @@ router.post(
'Handling /upload-and-process',
);
// Fix: Explicitly clear userProfile if no auth header is present in test env
// Fix: Explicitly clear userProfile if no auth header is present in test/staging env
// This prevents mockAuth from injecting a non-existent user ID for anonymous requests.
let userProfile = req.user as UserProfile | undefined;
if (process.env.NODE_ENV === 'test' && !req.headers['authorization']) {
if (
(process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'staging') &&
!req.headers['authorization']
) {
userProfile = undefined;
}

View File

@@ -160,7 +160,11 @@ export class AIService {
this.logger = logger;
this.logger.info('---------------- [AIService] Constructor Start ----------------');
const isTestEnvironment = process.env.NODE_ENV === 'test' || !!process.env.VITEST_POOL_ID;
// Use mock AI in test and staging environments (no real API calls, no GEMINI_API_KEY needed)
const isTestEnvironment =
process.env.NODE_ENV === 'test' ||
process.env.NODE_ENV === 'staging' ||
!!process.env.VITEST_POOL_ID;
if (aiClient) {
this.logger.info(

View File

@@ -19,7 +19,8 @@ import path from 'path';
const isProduction = process.env.NODE_ENV === 'production';
const isTest = process.env.NODE_ENV === 'test';
const isDevelopment = !isProduction && !isTest;
const isStaging = process.env.NODE_ENV === 'staging';
const isDevelopment = !isProduction && !isTest && !isStaging;
// Determine log directory based on environment
// In production/test, use the application directory's logs folder

View File

@@ -15,9 +15,9 @@ export function getBaseUrl(logger: Logger): string {
let baseUrl = (process.env.FRONTEND_URL || process.env.BASE_URL || '').trim();
if (!baseUrl || !baseUrl.startsWith('http')) {
const port = process.env.PORT || 3000;
// In test/development, use http://localhost. In production, this should never be reached.
// In test/staging/development, use http://localhost. In production, this should never be reached.
const fallbackUrl =
process.env.NODE_ENV === 'test'
process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'staging'
? `http://localhost:${port}`
: `http://example.com:${port}`;
if (baseUrl) {
@@ -39,4 +39,4 @@ export function getBaseUrl(logger: Logger): string {
}
return finalUrl;
}
}