nomyo-js/doc/api-reference.md
alpha nerd eafab3d9ac
All checks were successful
NYX Security Scan / nyx-scan (pull_request) Successful in 5m43s
feat: align timeout, error types and docs with the Python SDK
Completes the parity work (step 4).

Request timeout now defaults to 900 s, matching Python, instead of 60 s.
Encrypted inference cannot stream, so an entire completion arrives in one
response; a long generation on a busy backend legitimately takes minutes
and was timing out here while succeeding in the Python client.

Error types now distinguish malformed data from integrity failures.
Python raises ValueError for a bad package, a non-200 or unparseable
/pki/public_key, and plaintext that will not parse, reserving
SecurityError for crypto failures. This port wrapped nearly all of it in
SecurityError — so a server sending malformed JSON was reported as an
authentication failure, pointing debugging in exactly the wrong
direction. Malformed data is now a plain Error (the JS equivalent of
ValueError), carried past the deliberately opaque catch-all by a symbol
marker rather than a new exported class. Genuine crypto failures still
report a single vague message so they cannot serve as a decryption
oracle.

Also adds the missing guard Python has: decrypting without a private key
now says so, instead of failing later and being reported as an integrity
failure.

doc/attestation.md ports the Python attestation guide to the JS API, and
documents the two deliberate divergences: no verify_ssl escape hatch, and
jose injection instead of a runtime dynamic import.

Version 0.1.0 -> 0.3.0 to match the Python client's feature level, now
that the two are at parity.

Not ported: Python's warning when secure_memory=True but the SecureMemory
module is unavailable. There is no JS equivalent — zeroing is always
available, and the weaker case (mlock unavailable) is already reported
honestly by getProtectionInfo().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 12:17:52 +02:00

16 KiB
Raw Blame History

API Reference

SecureChatCompletion

High-level OpenAI-compatible client. The recommended entry point for most use cases.

Constructor

new SecureChatCompletion(config?: ChatCompletionConfig)

ChatCompletionConfig

Option Type Default Description
baseUrl string 'https://api.nomyo.ai' NOMYO router URL. Must be HTTPS in production.
allowHttp boolean false Allow HTTP connections.Local development only.
apiKey string undefined Bearer token sent inAuthorization header.
secureMemory boolean true Enable immediate zeroing of sensitive buffers after use.
timeout number 900000 (15 min) Request timeout in milliseconds. Encrypted inference cannot stream, so the whole completion arrives in one response; long generations legitimately take minutes.
debug boolean false Print verbose logging to the console.
keyDir string | null null Directory to load/save RSA keys on startup. If the directory contains an existing key pair it is loaded; otherwise a new pair is generated and saved there. Omit (or pass null) for ephemeral keys generated in memory for this session only and never written to disk — this is the default, matching the Python SDK. Node.js only; browsers are always ephemeral.
keyRotationInterval number 86400000 (24 h) Auto-rotate RSA keys every N milliseconds. Set to0 to disable.
keyRotationDir string value of keyDir Directory where rotated key files are saved. When neither this nor keyDir is set, rotated keys stay in memory. Node.js only.
keyRotationPassword string undefined Password used to encrypt rotated key files.
maxRetries number 2 Maximum extra attempts on retryable errors (429, 500, 502, 503, 504, network errors). Uses exponential backoff (1 s, 2 s, …). Set to0 to disable retries.
attestationPolicy AttestationPolicy undefined Enables SGX attestation verification before any plaintext is sent. Omit to disable. See Attestation.
quoteVerifier QuoteVerifier undefined Performs the DCAP quote verification (e.g.JwtQuoteVerifier). Required for a policy to actually verify; without one, a set policy treats attestation as unverifiable.

Methods

create(request): Promise<ChatCompletionResponse>

Send an encrypted chat completion request. Returns the decrypted response.

async create(request: ChatCompletionRequest): Promise<ChatCompletionResponse>

ChatCompletionRequest fields:

Field Type Description
model string Required. Model ID (see Models).
messages Message[] Required. Conversation history.
temperature number Sampling temperature (02).
top_p number Nucleus sampling.
max_tokens number Maximum tokens to generate.
stop `string string[]`
n number Number of completions to generate.
stream boolean Ignored server-side (encryption requires full response).
presence_penalty number Presence penalty (2.02.0).
frequency_penalty number Frequency penalty (2.02.0).
logit_bias Record<string, number> Token bias map.
user string End-user identifier (passed through).
tools Tool[] Tool/function definitions.
tool_choice ToolChoice Tool selection strategy ("auto", "none", "required", or specific tool).
security_tier string NOMYO-specific."standard" | "high" | "maximum". Not encrypted into the payload.
api_key string NOMYO-specific. Per-request API key override. Not encrypted into the payload.
base_url string NOMYO-specific. Per-request router URL override. Creates a temporary client for this one call. Not encrypted into the payload.

Response shape (ChatCompletionResponse):

{
  id: string;
  object: 'chat.completion';
  created: number;
  model: string;
  choices: Array<{
    index: number;
    message: {
      role: string;
      content: string;
      tool_calls?: ToolCall[];       // present if tools were invoked
      reasoning_content?: string;   // chain-of-thought (Qwen3, DeepSeek-R1, etc.)
    };
    finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
  }>;
  usage?: {
    prompt_tokens: number;
    completion_tokens: number;
    total_tokens: number;
  };
  _metadata?: {
    payload_id: string;           // echoes the X-Payload-ID sent with the request
    processed_at: number;         // Unix timestamp of server-side processing
    is_encrypted: boolean;        // always true for this endpoint
    encryption_algorithm: string; // e.g. "hybrid-aes256-rsa4096"
    response_status: string;      // "success" on success
    security_tier?: string;       // active tier used by the server
    memory_protection?: {
      platform: string;
      memory_locking: boolean;
      secure_zeroing: boolean;
      core_dump_prevention: boolean;
    };
    cuda_device?: {
      available: boolean;
      device_hash: string;        // SHA-256 of device name (not the raw name)
    };
  };
}

acreate(request): Promise<ChatCompletionResponse>

Alias for create(). Provided for code that follows the OpenAI SDK naming convention.

dispose(): void

Stop the key-rotation timer and sever in-memory RSA key references so they can be garbage-collected. After calling dispose(), all methods throw DisposedError.

client.dispose();

SecureCompletionClient

Lower-level client that exposes key management and individual encryption/decryption operations. Use this when you need fine-grained control; for most use cases prefer SecureChatCompletion.

Constructor

new SecureCompletionClient(config?: ClientConfig)

ClientConfig

All options from ChatCompletionConfig, plus:

Option Type Default Description
routerUrl string 'https://api.nomyo.ai' NOMYO router base URL.
keySize `2048 4096` 4096

(baseUrl is renamed to routerUrl at this level; all other options are identical.)

Methods

generateKeys(options?): Promise<void>

Generate a fresh RSA key pair.

await client.generateKeys({
  keySize?: 2048 | 4096,     // default: 4096
  saveToFile?: boolean,      // default: false
  keyDir?: string,           // default: 'client_keys'
  password?: string,         // minimum 8 characters if provided
});

loadKeys(privateKeyPath, publicKeyPath?, password?): Promise<void>

Load an existing key pair from PEM files. Node.js only.

await client.loadKeys(
  'client_keys/private_key.pem',
  'client_keys/public_key.pem',  // optional; derived from private key path if omitted
  'your-password'                // required if private key is encrypted
);

fetchServerPublicKey(): Promise<string>

Fetch the server's RSA public key from /pki/public_key over HTTPS. Called automatically on every encryption; exposed for diagnostics.

encryptPayload(payload): Promise<ArrayBuffer>

Encrypt a request payload. Returns the encrypted binary package ready to POST.

decryptResponse(encrypted, payloadId): Promise<object>

Decrypt a response body received from the secure endpoint.

sendSecureRequest(payload, payloadId, apiKey?, securityTier?): Promise<object>

Full encrypt → POST → decrypt cycle with retry logic. Called internally by SecureChatCompletion.create().

dispose(): void

Same as SecureChatCompletion.dispose().


Secure Memory API

import {
  getMemoryProtectionInfo,
  disableSecureMemory,
  enableSecureMemory,
  SecureByteContext,
} from 'nomyo-js';

getMemoryProtectionInfo(): ProtectionInfo

Returns information about the memory protection available on the current platform:

interface ProtectionInfo {
  canLock: boolean;       // true if mlock is available (requires native addon)
  isPlatformSecure: boolean;
  method: 'mlock' | 'zero-only' | 'none';
  details?: string;
}

disableSecureMemory(): void

Disable secure-memory zeroing globally. Affects new SecureByteContext instances that do not pass an explicit useSecure argument. Existing client instances are unaffected (they pass useSecure explicitly).

enableSecureMemory(): void

Re-enable secure memory operations globally.

SecureByteContext

Low-level context manager that zeros an ArrayBuffer in a finally block even if an exception occurs. Analogous to Python's secure_bytearray() context manager.

const context = new SecureByteContext(sensitiveBuffer);
const result = await context.use(async (data) => {
  return doSomethingWith(data);
});
// sensitiveBuffer is zeroed here regardless of whether doSomethingWith threw

Error Classes

All errors are exported from the package root.

import {
  APIError,
  AuthenticationError,
  InvalidRequestError,
  RateLimitError,
  ForbiddenError,
  ServerError,
  ServiceUnavailableError,
  APIConnectionError,
  SecurityError,
  AttestationError,
  DisposedError,
} from 'nomyo-js';
Class HTTP status Thrown when
AuthenticationError 401 Invalid or missing API key
InvalidRequestError 400 Malformed request (e.g. streaming requested)
ForbiddenError 403 Model not allowed for the requested security tier
RateLimitError 429 Rate limit exceeded (after all retries exhausted)
ServerError 500 Internal server error (after all retries exhausted)
ServiceUnavailableError 503 Inference backend unavailable (after all retries exhausted)
APIError varies Other HTTP errors (404, 502, 504, etc.)
APIConnectionError Network failure or timeout (after all retries exhausted)
SecurityError HTTPS not used, header injection detected, or crypto failure
AttestationError SGX attestation failed underenforce (extends SecurityError)
DisposedError Method called afterdispose()

All errors that extend APIError expose statusCode?: number and errorDetails?: object.

Malformed data vs security failures

A plain Error — not a SecurityError — is thrown when a response is structurally wrong rather than cryptographically suspect: a missing package field, an unsupported protocol version, a non-200 or unparseable /pki/public_key response, or plaintext that decrypted and authenticated successfully but is not valid JSON.

SecurityError is reserved for actual security conditions, and stays deliberately vague about which stage failed so it cannot be used as a decryption oracle:

try {
  await client.create({ model, messages });
} catch (error) {
  if (error instanceof SecurityError) {
    // integrity/authentication failure, HTTPS violation, or failed attestation
  } else if (error instanceof APIError) {
    // server responded with an HTTP error
  } else {
    // malformed response data
  }
}

This mirrors the Python SDK, which raises ValueError where this client throws a plain Error.