mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
* perf(rss): route RSS direct to Railway, skip Vercel middleman
Vercel /api/rss-proxy has 65% error rate (207K failed invocations/12h).
Route browser RSS requests directly to Railway (proxy.worldmonitor.app)
via Cloudflare CDN, eliminating Vercel as middleman.
- Add VITE_RSS_DIRECT_TO_RELAY feature flag (default off) for staged rollout
- Centralize RSS proxy URL in rssProxyUrl() with desktop/dev/prod routing
- Make Railway /rss public (skip auth, keep rate limiting with CF-Connecting-IP)
- Add wildcard *.worldmonitor.app CORS + always emit Vary: Origin on /rss
- Extract ~290 RSS domains to shared/rss-allowed-domains.cjs (single source of truth)
- Convert Railway domain check to Set for O(1) lookups
- Remove rss-proxy from KEYED_CLOUD_API_PATTERN (no longer needs API key header)
- Add edge function test for shared domain list import
* fix(edge): replace node:module with JSON import for edge-compatible RSS domains
api/_rss-allowed-domains.js used createRequire from node:module which is
unsupported in Vercel Edge Runtime, breaking all edge functions (including
api/gpsjam). Replaced with JSON import attribute syntax that works in both
esbuild (Vercel build) and Node.js 22+ (tests).
Also fixed middleware.ts TS18048 error where VARIANT_OG[variant] could be
undefined.
* test(edge): add guard against node: built-in imports in api/ files
Scans ALL api/*.js files (including _ helpers) for node: module imports
which are unsupported in Vercel Edge Runtime. This would have caught the
createRequire(node:module) bug before it reached Vercel.
* fix(edge): inline domain array and remove NextResponse reference
- Replace `import ... with { type: 'json' }` in _rss-allowed-domains.js
with inline array — Vercel esbuild doesn't support import attributes
- Replace `NextResponse.next()` with bare `return` in middleware.ts —
NextResponse was never imported
* ci(pre-push): add esbuild bundle check and edge function tests
The pre-push hook now catches Vercel build failures locally:
- esbuild bundles each api/*.js entrypoint (catches import attribute
syntax, missing modules, and other bundler errors)
- runs edge function test suite (node: imports, module isolation)
63 lines
2.6 KiB
JavaScript
63 lines
2.6 KiB
JavaScript
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync, readdirSync } from 'node:fs';
|
|
import { dirname, resolve, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const root = resolve(__dirname, '..');
|
|
const apiDir = join(root, 'api');
|
|
|
|
// All .js files in api/ except underscore-prefixed helpers (_cors.js, _api-key.js)
|
|
const edgeFunctions = readdirSync(apiDir)
|
|
.filter((f) => f.endsWith('.js') && !f.startsWith('_'))
|
|
.map((f) => ({ name: f, path: join(apiDir, f) }));
|
|
|
|
// ALL .js files in api/ (including helpers) — used for node: built-in checks
|
|
const allApiFiles = readdirSync(apiDir)
|
|
.filter((f) => f.endsWith('.js'))
|
|
.map((f) => ({ name: f, path: join(apiDir, f) }));
|
|
|
|
describe('Edge Function shared helpers resolve', () => {
|
|
it('_rss-allowed-domains.js re-exports shared domain list', async () => {
|
|
const mod = await import(join(apiDir, '_rss-allowed-domains.js'));
|
|
const domains = mod.default;
|
|
assert.ok(Array.isArray(domains), 'Expected default export to be an array');
|
|
assert.ok(domains.length > 200, `Expected 200+ domains, got ${domains.length}`);
|
|
assert.ok(domains.includes('feeds.bbci.co.uk'), 'Expected BBC feed domain in list');
|
|
});
|
|
});
|
|
|
|
describe('Edge Function no node: built-ins', () => {
|
|
for (const { name, path } of allApiFiles) {
|
|
it(`${name} does not import node: built-ins (unsupported in Vercel Edge Runtime)`, () => {
|
|
const src = readFileSync(path, 'utf-8');
|
|
const match = src.match(/from\s+['"]node:(\w+)['"]/);
|
|
assert.ok(
|
|
!match,
|
|
`${name}: imports node:${match?.[1]} — Vercel Edge Runtime does not support node: built-in modules. Use an edge-compatible alternative.`,
|
|
);
|
|
});
|
|
}
|
|
});
|
|
|
|
describe('Edge Function module isolation', () => {
|
|
for (const { name, path } of edgeFunctions) {
|
|
it(`${name} does not import from ../server/ (Edge Functions cannot resolve cross-directory TS)`, () => {
|
|
const src = readFileSync(path, 'utf-8');
|
|
assert.ok(
|
|
!src.includes("from '../server/"),
|
|
`${name}: imports from ../server/ — Vercel Edge Functions cannot resolve cross-directory TS imports. Inline the code or move to a same-directory .js helper.`,
|
|
);
|
|
});
|
|
|
|
it(`${name} does not import from ../src/ (Edge Functions cannot resolve TS aliases)`, () => {
|
|
const src = readFileSync(path, 'utf-8');
|
|
assert.ok(
|
|
!src.includes("from '../src/"),
|
|
`${name}: imports from ../src/ — Vercel Edge Functions cannot resolve @/ aliases or cross-directory TS. Inline the code instead.`,
|
|
);
|
|
});
|
|
}
|
|
});
|