Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ pnpm fetch:status
mkdir -p public/status
wget https://status.ksp-ckan.space/status/netkan.json -O public/status/netkan.json
wget https://status.ksp-ckan.space/status/netkan-ksp2.json -O public/status/netkan-ksp2.json
# once the NetKAN bot publishes KSA status (returns 404 until then), also:
# wget https://status.ksp-ckan.space/status/netkan-ksa.json -O public/status/netkan-ksa.json
```

The app fetches two separate JSON files:
The app fetches a separate JSON file per game:

- `/status/netkan.json` - KSP mods status
- `/status/netkan-ksp2.json` - KSP2 mods status
- `/status/netkan-ksa.json` - KSA mods status

The fetcher skips a status file that is not published yet (HTTP 404) with a warning, and the app shows an empty list for that game.

Then run the development server:

Expand Down
20 changes: 17 additions & 3 deletions scripts/fetch-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import * as path from 'path';

const urls = {
'netkan.json': 'https://status.ksp-ckan.space/status/netkan.json',
'netkan-ksp2.json': 'https://status.ksp-ckan.space/status/netkan-ksp2.json'
'netkan-ksp2.json': 'https://status.ksp-ckan.space/status/netkan-ksp2.json',
'netkan-ksa.json': 'https://status.ksp-ckan.space/status/netkan-ksa.json'
};

const outputDir = 'public/status';
Expand All @@ -25,6 +26,15 @@ async function fetchAndSaveStatus() {

const response = await fetch(url);

// A game whose status file is not published yet comes back as 404;
// skip just that file so the other games are still fetched. Any
// other failure (5xx, network error, disk error) still fails the
// whole run loudly.
if (response.status === 404) {
console.warn(` ⚠️ Skipped ${filename}: not published (HTTP 404)`);
return null;
}

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status} for URL: ${url}`);
}
Expand All @@ -39,9 +49,13 @@ async function fetchAndSaveStatus() {
return outputPath;
});

await Promise.all(savePromises);
const saved = (await Promise.all(savePromises)).filter((p) => p !== null);

if (saved.length === 0) {
throw new Error('none of the status files are published');
}

console.log('\n🎉 All status files have been successfully fetched and saved.');
console.log(`\n🎉 Saved ${saved.length} of ${savePromises.length} status files.`);

} catch (error) {
console.error('\n❌ An error occurred during the fetch and save process:', error.message);
Expand Down
47 changes: 44 additions & 3 deletions src/lib/__tests__/game-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { ksp, ksp2, games } from '../game-config';
import { ksp, ksp2, ksa, games } from '../game-config';

describe('ksp config', () => {
it('should have correct id and name', () => {
Expand Down Expand Up @@ -78,11 +78,48 @@ describe('ksp2 config', () => {
});
});

describe('ksa config', () => {
it('should have correct id and name', () => {
expect(ksa.id).toBe('ksa');
expect(ksa.name).toBe('KSA');
});

it('should have correct status URL', () => {
expect(ksa.status).toBe('/status/netkan-ksa.json');
});

it('should generate netkan URL for active mod', () => {
const url = ksa.netkan('TestMod', false);
expect(url).toBe('https://github.com/KSAModding/KSA-NetKAN/tree/main/NetKAN/TestMod.netkan');
});

it('should generate netkan URL for frozen mod', () => {
const url = ksa.netkan('TestMod', true);
expect(url).toBe('https://github.com/KSAModding/KSA-NetKAN/tree/main/NetKAN/TestMod.frozen');
});

it('should generate history URL for active mod', () => {
const url = ksa.history('TestMod', false);
expect(url).toBe('https://github.com/KSAModding/KSA-NetKAN/commits/main/NetKAN/TestMod.netkan');
});

it('should generate history URL for frozen mod', () => {
const url = ksa.history('TestMod', true);
expect(url).toBe('https://github.com/KSAModding/KSA-NetKAN/commits/main/NetKAN/TestMod.frozen');
});

it('should generate metadata URL', () => {
const url = ksa.metadata('TestMod');
expect(url).toBe('https://github.com/KSAModding/KSA-CKAN-meta/tree/main/TestMod');
});
});

describe('games array', () => {
it('should contain both ksp and ksp2', () => {
expect(games).toHaveLength(2);
it('should contain ksp, ksp2, and ksa', () => {
expect(games).toHaveLength(3);
expect(games).toContain(ksp);
expect(games).toContain(ksp2);
expect(games).toContain(ksa);
});

it('should have ksp as first element', () => {
Expand All @@ -92,4 +129,8 @@ describe('games array', () => {
it('should have ksp2 as second element', () => {
expect(games[1]).toBe(ksp2);
});

it('should have ksa as third element', () => {
expect(games[2]).toBe(ksa);
});
});
18 changes: 17 additions & 1 deletion src/lib/game-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,20 @@ export const ksp2: GameConfig = {
`https://github.com/KSP-CKAN/KSP2-CKAN-meta/tree/main/${ident}`,
};

export const games: GameConfig[] = [ksp, ksp2];
export const ksa: GameConfig = {
id: 'ksa',
name: 'KSA',
status: '/status/netkan-ksa.json',
netkan: (ident: string, frozen?: boolean) =>
frozen
? `https://github.com/KSAModding/KSA-NetKAN/tree/main/NetKAN/${ident}.frozen`
: `https://github.com/KSAModding/KSA-NetKAN/tree/main/NetKAN/${ident}.netkan`,
history: (ident: string, frozen?: boolean) =>
frozen
? `https://github.com/KSAModding/KSA-NetKAN/commits/main/NetKAN/${ident}.frozen`
: `https://github.com/KSAModding/KSA-NetKAN/commits/main/NetKAN/${ident}.netkan`,
metadata: (ident: string) =>
`https://github.com/KSAModding/KSA-CKAN-meta/tree/main/${ident}`,
};

export const games: GameConfig[] = [ksp, ksp2, ksa];