fix: base_url port

feat: add types for reasoning_content and _metadata

fix: key format incompatibility
This commit is contained in:
Alpha Nerd 2026-04-01 13:38:45 +02:00
parent c7601b2270
commit 76703e2e3e
5 changed files with 54 additions and 7 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ coverage/
.nyc_output/
build/
*.node
settings.json

View file

@ -13,7 +13,7 @@ export class SecureChatCompletion {
constructor(config: ChatCompletionConfig = {}) {
const {
baseUrl = 'https://api.nomyo.ai:12434',
baseUrl = 'https://api.nomyo.ai:12435',
allowHttp = false,
apiKey,
secureMemory = true,

View file

@ -64,9 +64,9 @@ export class SecureCompletionClient {
private secureMemoryImpl = createSecureMemory();
private readonly keySize: 2048 | 4096;
constructor(config: ClientConfig = { routerUrl: 'https://api.nomyo.ai:12434' }) {
constructor(config: ClientConfig = { routerUrl: 'https://api.nomyo.ai:12435' }) {
const {
routerUrl = 'https://api.nomyo.ai:12434',
routerUrl = 'https://api.nomyo.ai:12435',
allowHttp = false,
secureMemory = true,
keySize = 4096,
@ -174,7 +174,7 @@ export class SecureCompletionClient {
throw new SecurityError(
'Server public key must be fetched over HTTPS to prevent MITM attacks. ' +
'For local development, initialize with allowHttp=true: ' +
'new SecureChatCompletion({ baseUrl: "http://localhost:12434", allowHttp: true })'
'new SecureChatCompletion({ baseUrl: "http://localhost:12435", allowHttp: true })'
);
} else {
console.warn('Fetching key over HTTP (local development mode)');

View file

@ -7,6 +7,7 @@
*/
import { RSAOperations } from './rsa';
import { getCrypto } from './utils';
import { KeyGenOptions, KeyPaths } from '../../types/client';
export class KeyManager {
@ -66,8 +67,25 @@ export class KeyManager {
const path = require('path');
// Load private key
const privateKeyPem = await fs.readFile(paths.privateKeyPath, 'utf-8');
const privateKeyPem = await fs.readFile(paths.privateKeyPath, 'utf-8') as string;
if (password && privateKeyPem.includes('BEGIN ENCRYPTED PRIVATE KEY')) {
// Standard PKCS#8 encrypted format (produced by Python/OpenSSL)
const { createPrivateKey } = require('crypto') as typeof import('crypto');
const keyObject = createPrivateKey({ key: privateKeyPem, format: 'pem', passphrase: password });
const pkcs8Der = keyObject.export({ type: 'pkcs8', format: 'der' }) as Buffer;
const subtle = getCrypto();
this.privateKey = await subtle.importKey(
'pkcs8',
pkcs8Der,
{ name: 'RSA-OAEP', hash: 'SHA-256' },
true,
['decrypt']
);
} else {
// Unencrypted PKCS#8 or legacy JS custom-encrypted format
this.privateKey = await this.rsa.importPrivateKey(privateKeyPem, password);
}
// Validate private key size (minimum 2048 bits)
const privAlgorithm = this.privateKey.algorithm as RsaHashedKeyAlgorithm;
@ -120,7 +138,17 @@ export class KeyManager {
await fs.mkdir(directory, { recursive: true });
// Export and save private key
const privateKeyPem = await this.rsa.exportPrivateKey(this.privateKey, password);
let privateKeyPem: string;
if (password) {
// Use standard PKCS#8 encrypted format (compatible with Python/OpenSSL)
const { createPrivateKey } = require('crypto') as typeof import('crypto');
const subtle = getCrypto();
const pkcs8Der = await subtle.exportKey('pkcs8', this.privateKey);
const keyObject = createPrivateKey({ key: Buffer.from(pkcs8Der), format: 'der', type: 'pkcs8' });
privateKeyPem = keyObject.export({ type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: password }) as string;
} else {
privateKeyPem = await this.rsa.exportPrivateKey(this.privateKey);
}
const privateKeyPath = path.join(directory, 'private_key.pem');
await fs.writeFile(privateKeyPath, privateKeyPem, 'utf-8');

View file

@ -9,6 +9,8 @@ export interface Message {
name?: string;
tool_calls?: ToolCall[];
tool_call_id?: string;
/** Thinking-model reasoning output (Qwen3, DeepSeek-R1, etc.) */
reasoning_content?: string;
}
export interface ToolCall {
@ -70,12 +72,28 @@ export interface Choice {
logprobs?: unknown;
}
export interface MemoryProtectionInfo {
enabled: boolean;
platform: string;
protection_level: string;
has_memory_locking: boolean;
has_secure_zeroing: boolean;
supports_full_protection: boolean;
page_size?: number;
}
export interface ResponseMetadata {
payload_id: string;
processed_at: number;
is_encrypted: boolean;
encryption_algorithm: string;
response_status: string;
/** Hardware routing tier used for this request */
security_tier?: string;
/** Server-side memory protection details */
memory_protection?: MemoryProtectionInfo;
/** CUDA device ID used for inference (if applicable) */
cuda_device?: string | number;
}
export interface ChatCompletionResponse {