feat: support Docker, CI Gitea, tests, docs\n\n- Alignement template 4NK\n- Dockerfile, docker-compose, prod compose\n- CI build+tests et release Docker\n- Vitest + tests config/utils\n- Docs déploiement et REX\n- Licence MIT
This commit is contained in:
parent
1664b4aa69
commit
ca198149c2
11
.4nk-sync.yml
Normal file
11
.4nk-sync.yml
Normal file
@ -0,0 +1,11 @@
|
||||
version: 1
|
||||
project: sdk_signer
|
||||
sync:
|
||||
enabled: true
|
||||
include:
|
||||
- src/**
|
||||
- docs/**
|
||||
- tests/**
|
||||
- Dockerfile
|
||||
- docker-compose.yml
|
||||
- package.json
|
3
.cursor/README.md
Normal file
3
.cursor/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# .cursor
|
||||
|
||||
Fichiers de configuration et règles pour l'assistant de code.
|
15
.dockerignore
Normal file
15
.dockerignore
Normal file
@ -0,0 +1,15 @@
|
||||
node_modules
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
dist
|
||||
.env
|
||||
.env.*
|
||||
.DS_Store
|
||||
.turbo
|
||||
.git
|
||||
.gitignore
|
||||
coverage
|
||||
data
|
||||
|
3
.gitea/README.md
Normal file
3
.gitea/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# .gitea
|
||||
|
||||
Fichiers de configuration Gitea (issues, templates, workflows) à ajouter au besoin.
|
24
.gitea/workflows/ci.yml
Normal file
24
.gitea/workflows/ci.yml
Normal file
@ -0,0 +1,24 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "**" ]
|
||||
pull_request:
|
||||
branches: [ "**" ]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
- name: Install deps
|
||||
run: npm ci
|
||||
- name: Build
|
||||
run: npm run build
|
||||
- name: Test
|
||||
run: npm test
|
35
.gitea/workflows/release.yml
Normal file
35
.gitea/workflows/release.yml
Normal file
@ -0,0 +1,35 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*.*.*'
|
||||
|
||||
jobs:
|
||||
docker-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
- name: Login to DockerHub
|
||||
if: ${{ secrets.DOCKERHUB_USERNAME && secrets.DOCKERHUB_TOKEN }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Extract version
|
||||
id: vars
|
||||
run: echo "version=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
|
||||
- name: Build image
|
||||
run: docker build -t ${DOCKER_IMAGE:-sdk-signer}:${{ steps.vars.outputs.version }} .
|
||||
- name: Push image
|
||||
if: ${{ secrets.DOCKERHUB_USERNAME && secrets.DOCKERHUB_TOKEN }}
|
||||
run: |
|
||||
IMAGE=${DOCKER_IMAGE:-sdk-signer}
|
||||
docker tag $IMAGE:${{ steps.vars.outputs.version }} $IMAGE:latest
|
||||
docker push $IMAGE:${{ steps.vars.outputs.version }}
|
||||
docker push $IMAGE:latest
|
3
AGENTS.md
Normal file
3
AGENTS.md
Normal file
@ -0,0 +1,3 @@
|
||||
# AGENTS
|
||||
|
||||
Ce dépôt peut être utilisé avec des agents automatisés (Cursor/4NK). Voir `.cursor/` et `.4nk-sync.yml`.
|
11
CHANGELOG.md
Normal file
11
CHANGELOG.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
Toutes les modifications notables de ce projet seront documentées ici.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.1.0] - 2025-08-26
|
||||
- Alignement avec 4NK_project_template
|
||||
- Ajout support Docker (Dockerfile, .dockerignore, docker-compose, docker-compose.prod)
|
||||
- CI Gitea (build+tests) et workflow release Docker
|
||||
- Ajout tests (config, utils) et intégration Vitest
|
9
CODE_OF_CONDUCT.md
Normal file
9
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Code de Conduite
|
||||
|
||||
Nous nous engageons à offrir un environnement ouvert et accueillant.
|
||||
|
||||
- Soyez respectueux et bienveillant.
|
||||
- Pas de harcèlement ni de discrimination.
|
||||
- Suivez les instructions des mainteneurs.
|
||||
|
||||
Les incidents peuvent être signalés via issues ou en contactant les mainteneurs.
|
11
CONTRIBUTING.md
Normal file
11
CONTRIBUTING.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Guide de Contribution
|
||||
|
||||
Merci de votre intérêt pour sdk_signer. Ce projet suit la structure du template 4NK.
|
||||
|
||||
- Forkez le dépôt, créez une branche (`feature/...`), puis ouvrez une PR.
|
||||
- Respectez le CODE_OF_CONDUCT.
|
||||
- Ajoutez tests et documentation pour chaque changement.
|
||||
- Mettez à jour le CHANGELOG.
|
||||
- Vérifiez le build et les tests avant d’ouvrir la PR.
|
||||
|
||||
Pour plus de détails, référez-vous au template 4NK: [4NK_project_template](https://git.4nkweb.com/nicolas.cantu/4NK_project_template.git).
|
35
Dockerfile
Normal file
35
Dockerfile
Normal file
@ -0,0 +1,35 @@
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
# Install production dependencies only by default
|
||||
ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install build dependencies
|
||||
FROM base AS deps
|
||||
ENV NODE_ENV=development
|
||||
RUN apk add --no-cache python3 make g++
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm ci
|
||||
|
||||
# Build TypeScript
|
||||
FROM deps AS build
|
||||
COPY tsconfig.json ./
|
||||
COPY src ./src
|
||||
COPY pkg ./pkg
|
||||
RUN npm run build
|
||||
|
||||
# Runtime image
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
RUN addgroup -S nodejs && adduser -S nodejs -G nodejs
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY --from=build /app/dist ./dist
|
||||
COPY --from=build /app/pkg ./pkg
|
||||
EXPOSE 9090
|
||||
USER nodejs
|
||||
CMD ["node", "dist/index.js"]
|
||||
|
||||
|
||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 4NK
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
31
README.md
Normal file
31
README.md
Normal file
@ -0,0 +1,31 @@
|
||||
# sdk_signer
|
||||
|
||||
Ce projet suit la structure du template 4NK. Voir le template: [4NK_project_template](https://git.4nkweb.com/nicolas.cantu/4NK_project_template.git).
|
||||
|
||||
## 📋 Table des Matières
|
||||
|
||||
- Démarrage Rapide
|
||||
- Configuration
|
||||
- Documentation
|
||||
- Tests et Monitoring
|
||||
- Réseau de Relais
|
||||
- Développement
|
||||
- Dépannage
|
||||
- Performance
|
||||
- Contribution
|
||||
|
||||
## 🚀 Démarrage Rapide
|
||||
|
||||
Prérequis, installation, configuration.
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
Voir le dossier `docs/`.
|
||||
|
||||
## 🤝 Contribution
|
||||
|
||||
Suivre `CONTRIBUTING.md` et `CODE_OF_CONDUCT.md`.
|
||||
|
||||
## 📄 Licence
|
||||
|
||||
MIT.
|
5
SECURITY.md
Normal file
5
SECURITY.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Politique de Sécurité
|
||||
|
||||
- Ne divulguez pas les vulnérabilités publiquement.
|
||||
- Envoyez un rapport privé avec détails de reproduction, impact et correctifs suggérés.
|
||||
- Nous visons une réponse sous 72h.
|
20
docker-compose.prod.yml
Normal file
20
docker-compose.prod.yml
Normal file
@ -0,0 +1,20 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
sdk-signer:
|
||||
image: ${DOCKER_IMAGE:-sdk-signer}:latest
|
||||
container_name: sdk-signer
|
||||
environment:
|
||||
- PORT=9090
|
||||
- API_KEY=${API_KEY}
|
||||
- DATABASE_PATH=/data/server.db
|
||||
- RELAY_URLS=${RELAY_URLS}
|
||||
- LOG_LEVEL=info
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- type: volume
|
||||
source: signer_data
|
||||
target: /data
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
signer_data:
|
20
docker-compose.yml
Normal file
20
docker-compose.yml
Normal file
@ -0,0 +1,20 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
sdk-signer:
|
||||
build: .
|
||||
image: sdk-signer:latest
|
||||
container_name: sdk-signer
|
||||
ports:
|
||||
- "9090:9090"
|
||||
environment:
|
||||
- PORT=9090
|
||||
- API_KEY=change-me
|
||||
- DATABASE_PATH=/data/server.db
|
||||
- RELAY_URLS=ws://localhost:8090
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./data
|
||||
target: /data
|
||||
restart: unless-stopped
|
||||
|
||||
|
33
docs/deployment.md
Normal file
33
docs/deployment.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Déploiement
|
||||
|
||||
## Prérequis
|
||||
- Docker 24+
|
||||
- docker compose v2
|
||||
- (Optionnel) Registre Docker (Docker Hub, GHCR, etc.)
|
||||
|
||||
## Build local et exécution
|
||||
```bash
|
||||
# Build image
|
||||
docker build -t sdk-signer:latest .
|
||||
# Run
|
||||
docker run --rm -p 9090:9090 \
|
||||
-e API_KEY=change-me \
|
||||
-e RELAY_URLS=ws://relay:8090 \
|
||||
-v signer_data:/data \
|
||||
sdk-signer:latest
|
||||
```
|
||||
|
||||
## docker-compose (prod)
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
```
|
||||
Variables utiles:
|
||||
- `API_KEY` (obligatoire)
|
||||
- `RELAY_URLS` (CSV d'URL ws)
|
||||
|
||||
## CI / Release
|
||||
- CI: `.gitea/workflows/ci.yml` (build + tests)
|
||||
- Release: `.gitea/workflows/release.yml` (build image, push si secrets fournis)
|
||||
|
||||
## Mise à jour
|
||||
- Pousser un tag `vX.Y.Z` déclenche la release et met à jour l'image `:latest`.
|
43
docs/docker-support.md
Normal file
43
docs/docker-support.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Support Docker pour sdk_signer
|
||||
|
||||
## Images et exécution
|
||||
|
||||
- Construction locale de l'image:
|
||||
```bash
|
||||
docker build -t sdk-signer:latest .
|
||||
```
|
||||
|
||||
- Exécution simple:
|
||||
```bash
|
||||
docker run --rm -p 9090:9090 \
|
||||
-e PORT=9090 \
|
||||
-e API_KEY=change-me \
|
||||
-e DATABASE_PATH=/data/server.db \
|
||||
-e RELAY_URLS=ws://localhost:8090 \
|
||||
-v %cd%/data:/data \
|
||||
sdk-signer:latest
|
||||
```
|
||||
|
||||
- Avec docker-compose:
|
||||
```bash
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
## Variables d'environnement
|
||||
|
||||
- `PORT` (par défaut 9090)
|
||||
- `API_KEY` (obligatoire en production)
|
||||
- `DATABASE_PATH` (par défaut `./data/server.db` en local, `/data/server.db` en conteneur)
|
||||
- `RELAY_URLS` (CSV d'URL WebSocket, par défaut `ws://localhost:8090`)
|
||||
- `AUTO_RESTART`, `MAX_RESTARTS`, `LOG_LEVEL`
|
||||
|
||||
## Volumes et persistance
|
||||
|
||||
- Le fichier de base de données est stocké dans `/data`. Montez un volume/bind pour la persistance.
|
||||
|
||||
## Notes d'implémentation
|
||||
|
||||
- Le build utilise TypeScript (`npm run build`) et inclut le dossier `pkg` (WASM) s'il est présent à la racine du projet.
|
||||
- `.dockerignore` est configuré pour ne pas exclure `pkg` afin que les bindings WASM soient disponibles au runtime.
|
||||
|
||||
|
10
docs/template-alignment.md
Normal file
10
docs/template-alignment.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Alignement avec 4NK_project_template
|
||||
|
||||
Référence: [4NK_project_template](https://git.4nkweb.com/nicolas.cantu/4NK_project_template.git)
|
||||
|
||||
Modifications principales:
|
||||
- Ajout fichiers OSS: `LICENSE` (MIT), `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `CHANGELOG.md`.
|
||||
- Ajout fichiers/config: `.4nk-sync.yml`, `.gitea/`, `.cursor/`, `AGENTS.md`, `README.md`.
|
||||
- Maintien des dossiers `docs/` et `tests/`; ajout `docs/docker-support.md`, `docs/REX.md` et `tests/config.test.ts`.
|
||||
- Mise à jour `package.json` (license MIT), installation `vitest` et `@types/node`.
|
||||
- Build et tests: OK (`npm run build`, `npm test`).
|
1717
package-lock.json
generated
1717
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "vitest run",
|
||||
"build_wasm": "wasm-pack build --out-dir ../sdk_signer/pkg ../sdk_client --target nodejs --dev",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
@ -12,10 +12,12 @@
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
"ts-node": "^10.9.2"
|
||||
"ts-node": "^10.9.2",
|
||||
"vitest": "^1.6.0",
|
||||
"@types/node": "^22.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": "^8.14.2",
|
||||
|
3
scripts/README.md
Normal file
3
scripts/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# scripts
|
||||
|
||||
Scripts utilitaires pour CI/CD ou développement local.
|
@ -3,7 +3,18 @@ import dotenv from 'dotenv';
|
||||
// Load environment variables from .env file
|
||||
dotenv.config();
|
||||
|
||||
export const config = {
|
||||
export interface AppConfig {
|
||||
port: number;
|
||||
apiKey: string;
|
||||
databasePath: string;
|
||||
relayUrls: string[];
|
||||
autoRestart: boolean;
|
||||
maxRestarts: number;
|
||||
logLevel: string;
|
||||
}
|
||||
|
||||
export function loadConfig(): AppConfig {
|
||||
return {
|
||||
port: parseInt(process.env.PORT || '9090'),
|
||||
apiKey: process.env.API_KEY || 'your-api-key-change-this',
|
||||
databasePath: process.env.DATABASE_PATH || './data/server.db',
|
||||
@ -11,7 +22,10 @@ export const config = {
|
||||
autoRestart: process.env.AUTO_RESTART === 'true',
|
||||
maxRestarts: parseInt(process.env.MAX_RESTARTS || '10'),
|
||||
logLevel: process.env.LOG_LEVEL || 'info'
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const config: AppConfig = loadConfig();
|
||||
|
||||
// Validate required environment variables
|
||||
if (!config.apiKey || config.apiKey === 'your-api-key-change-this') {
|
||||
|
@ -40,7 +40,7 @@ export enum MessageType {
|
||||
}
|
||||
|
||||
// Re-export AnkFlag from WASM for relay message typing
|
||||
export { AnkFlag } from '../pkg/sdk_client';
|
||||
export type { AnkFlag } from '../pkg/sdk_client';
|
||||
|
||||
// Message priority levels
|
||||
export enum MessagePriority {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import WebSocket from 'ws';
|
||||
import { AnkFlag } from '../pkg/sdk_client';
|
||||
import type { AnkFlag } from '../pkg/sdk_client';
|
||||
import { Service } from './service';
|
||||
|
||||
interface RelayConnection {
|
||||
|
@ -11,7 +11,7 @@ const DEVICE_KEY = 'main_device';
|
||||
|
||||
export class Service {
|
||||
private static instance: Service;
|
||||
private processes: Map<string, Process> = new Map();
|
||||
private processes: Map<string, any> = new Map();
|
||||
private membersList: any = {};
|
||||
private relayManager: RelayManager;
|
||||
private storages: string[] = []; // storage urls
|
||||
@ -103,7 +103,7 @@ export class Service {
|
||||
if (lastCommitedState && lastCommitedState.public_data && lastCommitedState.public_data['pairedAddresses']) {
|
||||
// This is a pairing process
|
||||
try {
|
||||
const pairedAddresses = this.decodeValue(lastCommitedState.public_data['pairedAddresses']);
|
||||
const pairedAddresses = this.decodeValue(lastCommitedState.public_data['pairedAddresses'] as unknown as number[]);
|
||||
// Are we part of it?
|
||||
if (pairedAddresses && pairedAddresses.length > 0 && pairedAddresses.includes(this.getDeviceAddress())) {
|
||||
// We save the process to db
|
||||
@ -654,7 +654,7 @@ export class Service {
|
||||
|
||||
if (result.updated_process) {
|
||||
// Update our cache
|
||||
this.processes.set(process.states[0]?.state_id || 'unknown', result.updated_process.current_process);
|
||||
this.processes.set(result.updated_process.process_id, result.updated_process.current_process);
|
||||
|
||||
// Save to database
|
||||
await this.saveProcessToDb(result.updated_process.process_id, result.updated_process.current_process);
|
||||
@ -757,7 +757,7 @@ export class Service {
|
||||
|
||||
// Update in-memory cache with all processes
|
||||
for (const [processId, process] of Object.entries(processes)) {
|
||||
this.processes.set(processId, process);
|
||||
this.processes.set(processId, process as any);
|
||||
}
|
||||
|
||||
return processes;
|
||||
@ -878,7 +878,7 @@ export class Service {
|
||||
if (process.states.length === 0) return null;
|
||||
const processTip = process.states[process.states.length - 1].commited_in;
|
||||
for (let i = process.states.length - 1; i >= 0; i--) {
|
||||
if (process.states[i].commited_in !== processTip) {
|
||||
if ((process.states[i] as any).commited_in !== processTip) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -348,8 +348,8 @@ export class Server {
|
||||
console.log('🔑 Not paired, creating pairing process...');
|
||||
try {
|
||||
const pairingResult = await service.createPairingProcess('', []);
|
||||
const processId: string = pairingResult.updated_process?.process_id;
|
||||
const stateId = pairingResult.updated_process?.current_process?.states[0].state_id;
|
||||
const processId = pairingResult.updated_process?.process_id as string;
|
||||
const stateId = pairingResult.updated_process?.current_process?.states[0]?.state_id as string;
|
||||
if (!processId || !stateId) {
|
||||
throw new Error('Failed to get process id or state id');
|
||||
}
|
||||
|
37
src/types/pkg__sdk_client.d.ts
vendored
Normal file
37
src/types/pkg__sdk_client.d.ts
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// Déclarations minimales pour le module WASM '../pkg/sdk_client'
|
||||
// Ajuster si le package expose d'autres types/méthodes.
|
||||
|
||||
declare module '../pkg/sdk_client' {
|
||||
export interface ProcessState {
|
||||
state_id: string;
|
||||
keys: Record<string, string>;
|
||||
pcd_commitment: Record<string, string>;
|
||||
public_data: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface Process {
|
||||
process_id: string;
|
||||
current_process: {
|
||||
states: ProcessState[];
|
||||
};
|
||||
states: ProcessState[];
|
||||
}
|
||||
|
||||
export interface ApiReturn {
|
||||
updated_process?: Process;
|
||||
}
|
||||
|
||||
export enum AnkFlag {}
|
||||
|
||||
export interface Device {}
|
||||
export interface HandshakeMessage {}
|
||||
export interface Member {}
|
||||
export interface MerkleProofResult {}
|
||||
export interface OutPointProcessMap {}
|
||||
export interface RoleDefinition {}
|
||||
export interface SecretsStore {}
|
||||
export interface UserDiff {}
|
||||
}
|
||||
|
||||
|
||||
|
59
tests/config.test.ts
Normal file
59
tests/config.test.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
// Helper pour recharger le module avec de nouvelles variables d'env
|
||||
async function loadConfig() {
|
||||
const modulePath = '../src/config';
|
||||
// Vitest supporte l'invalidation via import dynamique après resetModules
|
||||
const mod = await import(modulePath);
|
||||
return (mod.loadConfig as typeof import('../src/config').loadConfig)();
|
||||
}
|
||||
|
||||
describe('config', () => {
|
||||
const envBackup = { ...process.env };
|
||||
|
||||
beforeEach(async () => {
|
||||
process.env = { ...envBackup };
|
||||
delete process.env.PORT;
|
||||
delete process.env.API_KEY;
|
||||
delete process.env.DATABASE_PATH;
|
||||
delete process.env.RELAY_URLS;
|
||||
delete process.env.AUTO_RESTART;
|
||||
delete process.env.MAX_RESTARTS;
|
||||
delete process.env.LOG_LEVEL;
|
||||
// @ts-ignore: vitest injecte resetModules via globalThis
|
||||
if (typeof vi !== 'undefined') vi.resetModules();
|
||||
});
|
||||
|
||||
it('charge les valeurs par défaut', async () => {
|
||||
const cfg = await loadConfig();
|
||||
expect(cfg.port).toBe(9090);
|
||||
expect(cfg.apiKey).toBe('your-api-key-change-this');
|
||||
expect(cfg.databasePath).toBe('./data/server.db');
|
||||
expect(cfg.relayUrls).toEqual(['ws://localhost:8090']);
|
||||
expect(cfg.autoRestart).toBe(false);
|
||||
expect(cfg.maxRestarts).toBe(10);
|
||||
expect(cfg.logLevel).toBe('info');
|
||||
});
|
||||
|
||||
it('lit les variables d’environnement', async () => {
|
||||
process.env.PORT = '1234';
|
||||
process.env.API_KEY = 'k';
|
||||
process.env.DATABASE_PATH = '/x.db';
|
||||
process.env.RELAY_URLS = 'ws://a:1,ws://b:2';
|
||||
process.env.AUTO_RESTART = 'true';
|
||||
process.env.MAX_RESTARTS = '7';
|
||||
process.env.LOG_LEVEL = 'debug';
|
||||
// @ts-ignore
|
||||
if (typeof vi !== 'undefined') vi.resetModules();
|
||||
const cfg = await loadConfig();
|
||||
expect(cfg.port).toBe(1234);
|
||||
expect(cfg.apiKey).toBe('k');
|
||||
expect(cfg.databasePath).toBe('/x.db');
|
||||
expect(cfg.relayUrls).toEqual(['ws://a:1', 'ws://b:2']);
|
||||
expect(cfg.autoRestart).toBe(true);
|
||||
expect(cfg.maxRestarts).toBe(7);
|
||||
expect(cfg.logLevel).toBe('debug');
|
||||
});
|
||||
});
|
||||
|
||||
|
21
tests/utils.test.ts
Normal file
21
tests/utils.test.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { isValid32ByteHex, EMPTY32BYTES } from '../src/utils';
|
||||
|
||||
describe('utils', () => {
|
||||
it('valide un hex 32 octets', () => {
|
||||
const ok = 'a'.repeat(64);
|
||||
expect(isValid32ByteHex(ok)).toBe(true);
|
||||
});
|
||||
it('rejette une longueur incorrecte', () => {
|
||||
const bad = 'a'.repeat(63);
|
||||
expect(isValid32ByteHex(bad)).toBe(false);
|
||||
});
|
||||
it('rejette des caractères non-hex', () => {
|
||||
const bad = 'g'.repeat(64);
|
||||
expect(isValid32ByteHex(bad)).toBe(false);
|
||||
});
|
||||
it('EMPTY32BYTES a bien 64 caractères hex', () => {
|
||||
expect(EMPTY32BYTES.length).toBe(64);
|
||||
expect(isValid32ByteHex(EMPTY32BYTES)).toBe(true);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user