mirror of
https://github.com/aljazceru/dvmcp.git
synced 2025-12-17 05:14:24 +01:00
feat: gh-actions (#2)
This commit is contained in:
26
.github/workflows/test.yml
vendored
Normal file
26
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Tests
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Bun Runtime
|
||||||
|
uses: oven-sh/setup-bun@v1
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
env:
|
||||||
|
NODE_ENV: test
|
||||||
|
run: bun test
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: bun run format --check
|
||||||
@@ -1,41 +1,96 @@
|
|||||||
import { parse } from 'yaml';
|
import { parse } from 'yaml';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { existsSync, readFileSync } from 'fs';
|
import { existsSync, readFileSync } from 'fs';
|
||||||
import type { MCPServerConfig } from './types';
|
import type { AppConfig, MCPServerConfig } from './types';
|
||||||
|
|
||||||
interface NostrConfig {
|
|
||||||
privateKey: string;
|
|
||||||
relayUrls: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MCPConfig {
|
|
||||||
name: string;
|
|
||||||
about: string;
|
|
||||||
clientName: string;
|
|
||||||
clientVersion: string;
|
|
||||||
servers: MCPServerConfig[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WhitelistConfig {
|
|
||||||
allowedPubkeys: Set<string> | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AppConfig {
|
|
||||||
nostr: NostrConfig;
|
|
||||||
mcp: MCPConfig;
|
|
||||||
whitelist: WhitelistConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONFIG_PATH = join(process.cwd(), 'config.yml');
|
const CONFIG_PATH = join(process.cwd(), 'config.yml');
|
||||||
const HEX_KEYS_REGEX = /^(?:[0-9a-fA-F]{64})$/;
|
const HEX_KEYS_REGEX = /^(?:[0-9a-fA-F]{64})$/;
|
||||||
|
|
||||||
if (!existsSync(CONFIG_PATH)) {
|
const TEST_CONFIG: AppConfig = {
|
||||||
|
nostr: {
|
||||||
|
privateKey:
|
||||||
|
'd4d4d7aae7857054596c4c0976b22a73acac3a10d30bf56db35ee038bbf0dd44',
|
||||||
|
relayUrls: ['ws://localhost:3334'],
|
||||||
|
},
|
||||||
|
mcp: {
|
||||||
|
name: 'Test DVM MCP Bridge',
|
||||||
|
about: 'Test MCP-enabled DVM',
|
||||||
|
clientName: 'Test Client',
|
||||||
|
clientVersion: '1.0.0',
|
||||||
|
servers: [],
|
||||||
|
},
|
||||||
|
whitelist: {
|
||||||
|
allowedPubkeys: new Set(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function validateRequiredField(value: any, fieldName: string): string {
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`Missing required config field: ${fieldName}`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConfigValue(
|
||||||
|
value: string | undefined,
|
||||||
|
defaultValue: string
|
||||||
|
): string {
|
||||||
|
return value || defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateRelayUrls(urls: any): string[] {
|
||||||
|
if (!Array.isArray(urls) || urls.length === 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'No config.yml file found. Please create one based on config.example.yml'
|
'At least one relay URL must be provided in nostr.relayUrls'
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
return urls.map((url: string) => {
|
||||||
|
try {
|
||||||
|
const trimmedUrl = url.trim();
|
||||||
|
new URL(trimmedUrl);
|
||||||
|
if (!trimmedUrl.startsWith('ws://') && !trimmedUrl.startsWith('wss://')) {
|
||||||
|
throw new Error(
|
||||||
|
`Relay URL must start with ws:// or wss://: ${trimmedUrl}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return trimmedUrl;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Invalid relay URL: ${url}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateMCPServers(servers: any): MCPServerConfig[] {
|
||||||
|
if (!Array.isArray(servers) || servers.length === 0) {
|
||||||
|
throw new Error(
|
||||||
|
'At least one MCP server must be configured in mcp.servers'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return servers.map((server: any, index: number) => {
|
||||||
|
if (!server.name || !server.command || !Array.isArray(server.args)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid MCP server configuration at index ${index}. Required fields: name, command, args[]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: server.name,
|
||||||
|
command: server.command,
|
||||||
|
args: server.args,
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadConfig(): AppConfig {
|
function loadConfig(): AppConfig {
|
||||||
|
if (process.env.NODE_ENV === 'test') {
|
||||||
|
return TEST_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existsSync(CONFIG_PATH)) {
|
||||||
|
throw new Error(
|
||||||
|
'No config.yml file found. Please create one based on config.example.yml'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const configFile = readFileSync(CONFIG_PATH, 'utf8');
|
const configFile = readFileSync(CONFIG_PATH, 'utf8');
|
||||||
const rawConfig = parse(configFile);
|
const rawConfig = parse(configFile);
|
||||||
@@ -83,63 +138,4 @@ function loadConfig(): AppConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateRequiredField(value: any, fieldName: string): string {
|
|
||||||
if (!value) {
|
|
||||||
throw new Error(`Missing required config field: ${fieldName}`);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getConfigValue(
|
|
||||||
value: string | undefined,
|
|
||||||
defaultValue: string
|
|
||||||
): string {
|
|
||||||
return value || defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateRelayUrls(urls: any): string[] {
|
|
||||||
if (!Array.isArray(urls) || urls.length === 0) {
|
|
||||||
throw new Error(
|
|
||||||
'At least one relay URL must be provided in nostr.relayUrls'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return urls.map((url: string) => {
|
|
||||||
try {
|
|
||||||
const trimmedUrl = url.trim();
|
|
||||||
new URL(trimmedUrl);
|
|
||||||
if (!trimmedUrl.startsWith('ws://') && !trimmedUrl.startsWith('wss://')) {
|
|
||||||
throw new Error(
|
|
||||||
`Relay URL must start with ws:// or wss://: ${trimmedUrl}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return trimmedUrl;
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(`Invalid relay URL: ${url}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateMCPServers(servers: any): MCPServerConfig[] {
|
|
||||||
if (!Array.isArray(servers) || servers.length === 0) {
|
|
||||||
throw new Error(
|
|
||||||
'At least one MCP server must be configured in mcp.servers'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return servers.map((server: any, index: number) => {
|
|
||||||
if (!server.name || !server.command || !Array.isArray(server.args)) {
|
|
||||||
throw new Error(
|
|
||||||
`Invalid MCP server configuration at index ${index}. Required fields: name, command, args[]`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: server.name,
|
|
||||||
command: server.command,
|
|
||||||
args: server.args,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CONFIG = loadConfig();
|
export const CONFIG = loadConfig();
|
||||||
|
|||||||
@@ -1,3 +1,26 @@
|
|||||||
|
export interface NostrConfig {
|
||||||
|
privateKey: string;
|
||||||
|
relayUrls: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MCPConfig {
|
||||||
|
name: string;
|
||||||
|
about: string;
|
||||||
|
clientName: string;
|
||||||
|
clientVersion: string;
|
||||||
|
servers: MCPServerConfig[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WhitelistConfig {
|
||||||
|
allowedPubkeys: Set<string> | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppConfig {
|
||||||
|
nostr: NostrConfig;
|
||||||
|
mcp: MCPConfig;
|
||||||
|
whitelist: WhitelistConfig;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MCPServerConfig {
|
export interface MCPServerConfig {
|
||||||
name: string;
|
name: string;
|
||||||
command: string;
|
command: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user