|
|
||
|---|---|---|
| doc | ||
| docs | ||
| examples | ||
| native | ||
| src | ||
| tests | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| jest.config.js | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| rollup.config.js | ||
| tsconfig.json | ||
NOMYO.js — Secure JavaScript Chat Client
OpenAI-compatible secure chat client with end-to-end encryption for NOMYO Inference Endpoints
- All prompts and responses are automatically encrypted and decrypted
- Hybrid encryption: AES-256-GCM payload + RSA-OAEP-SHA256 key exchange, 4096-bit keys
- Drop-in replacement for OpenAI's ChatCompletion API
- Works in both Node.js and browsers
Quick Start
Installation
npm install nomyo-js
Basic Usage (Node.js)
import { SecureChatCompletion } from 'nomyo-js';
const client = new SecureChatCompletion({
apiKey: process.env.NOMYO_API_KEY,
});
const response = await client.create({
model: 'Qwen/Qwen3-0.6B',
messages: [{ role: 'user', content: 'Hello!' }],
temperature: 0.7,
});
console.log(response.choices[0].message.content);
client.dispose();
Basic Usage (Browser)
<script type="module">
import { SecureChatCompletion } from 'https://unpkg.com/nomyo-js/dist/browser/index.js';
const client = new SecureChatCompletion({
baseUrl: 'https://api.nomyo.ai',
apiKey: 'your-api-key',
});
const response = await client.create({
model: 'Qwen/Qwen3-0.6B',
messages: [{ role: 'user', content: 'What is 2+2?' }],
});
console.log(response.choices[0].message.content);
</script>
Documentation
Full documentation is in the doc/ directory:
- Getting Started — walkthrough for new users
- API Reference — complete constructor options, methods, types, and error classes
- Models — available models and selection guide
- Security Guide — encryption, memory protection, key management, compliance
- Rate Limits — limits, automatic retry behaviour, batch throttling
- Examples — 12+ code examples for common scenarios
- Troubleshooting — error reference and debugging tips
Security Features
Hybrid Encryption
- Payload encryption: AES-256-GCM (authenticated encryption)
- Key exchange: RSA-OAEP-SHA256
- Key size: 4096-bit RSA keys
- Scope: All communication is end-to-end encrypted
Key Management
- Automatic: Keys are generated on first use and saved to
keyDir(default:client_keys/). Existing keys are reloaded on subsequent runs. Node.js only. - Password protection: Optional AES-encrypted private key files (minimum 8 characters).
- Secure permissions: Private key files saved at
0600(owner-only). - Auto-rotation: Keys rotate every 24 hours by default (configurable via
keyRotationInterval). - Explicit lifecycle: Call
dispose()to zero in-memory key material and stop the rotation timer.
Secure Memory
The library wraps all intermediate sensitive buffers (AES keys, plaintext payload, decrypted bytes) in SecureByteContext, which zeroes them in a finally block immediately after use.
Pure JavaScript cannot lock pages to prevent OS swapping (mlock). For environments where swap-file exposure is unacceptable, install the optional nomyo-native addon. Check the current protection level:
import { getMemoryProtectionInfo } from 'nomyo-js';
const info = getMemoryProtectionInfo();
// Without addon: { method: 'zero-only', canLock: false }
// With addon: { method: 'mlock', canLock: true }
Security Tiers
Pass security_tier per request to route inference to increasingly isolated hardware:
| Tier | Hardware | Use case |
|---|---|---|
"standard" |
GPU | General secure inference |
"high" |
CPU/GPU balanced | Sensitive business data |
"maximum" |
CPU only | HIPAA PHI, classified data |
const response = await client.create({
model: 'Qwen/Qwen3-0.6B',
messages: [{ role: 'user', content: 'Patient record summary...' }],
security_tier: 'maximum',
});
Usage Examples
With API Key
const client = new SecureChatCompletion({ apiKey: process.env.NOMYO_API_KEY });
Error Handling
import {
SecureChatCompletion,
AuthenticationError,
RateLimitError,
ForbiddenError,
} from 'nomyo-js';
try {
const response = await client.create({ model: 'Qwen/Qwen3-0.6B', messages: [...] });
} catch (err) {
if (err instanceof AuthenticationError) console.error('Check API key:', err.message);
else if (err instanceof RateLimitError) console.error('Rate limit hit:', err.message);
else if (err instanceof ForbiddenError) console.error('Model/tier mismatch:', err.message);
else throw err;
}
Per-Request Router Override
Send a single request to a different router without changing the main client:
const response = await client.create({
model: 'Qwen/Qwen3-0.6B',
messages: [{ role: 'user', content: 'Hello from secondary router' }],
base_url: 'https://secondary.nomyo.ai:12435', // temporary — main client unchanged
});
Tool / Function Calling
const response = await client.create({
model: 'Qwen/Qwen3-0.6B',
messages: [{ role: 'user', content: "What's the weather in Paris?" }],
tools: [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Get weather information for a location',
parameters: {
type: 'object',
properties: { location: { type: 'string' } },
required: ['location'],
},
},
},
],
tool_choice: 'auto',
});
Thinking Models
const response = await client.create({
model: 'LiquidAI/LFM2.5-1.2B-Thinking',
messages: [{ role: 'user', content: 'Is 9.9 larger than 9.11?' }],
});
const { content, reasoning_content } = response.choices[0].message;
console.log('Reasoning:', reasoning_content);
console.log('Answer:', content);
Resource Management
const client = new SecureChatCompletion({ apiKey: process.env.NOMYO_API_KEY });
try {
const response = await client.create({ model: 'Qwen/Qwen3-0.6B', messages: [...] });
console.log(response.choices[0].message.content);
} finally {
client.dispose(); // zeros key material, stops rotation timer
}
Local Development (HTTP)
const client = new SecureChatCompletion({
baseUrl: 'http://localhost:12435',
allowHttp: true, // required — also prints a visible warning
});
API Reference
SecureChatCompletion — Constructor Options
new SecureChatCompletion(config?: 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 for Authorization header. |
secureMemory |
boolean |
true |
Zero sensitive buffers immediately after use. |
timeout |
number |
60000 |
Request timeout in milliseconds. |
debug |
boolean |
false |
Print verbose logging to the console. |
keyDir |
string |
'client_keys' |
Directory to load/save RSA keys on startup. |
keyRotationInterval |
number |
86400000 |
Auto-rotate keys every N ms. 0 disables rotation. |
keyRotationDir |
string |
'client_keys' |
Directory for rotated key files. Node.js only. |
keyRotationPassword |
string |
undefined |
Password for encrypted rotated key files. |
maxRetries |
number |
2 |
Extra retry attempts on 429/5xx/network errors. Exponential backoff (1 s, 2 s, …). |
Methods
create(request): Promise<ChatCompletionResponse>— send an encrypted chat completionacreate(request): Promise<ChatCompletionResponse>— alias forcreate()dispose(): void— zero key material and stop the rotation timer
create() Request Fields
All standard OpenAI fields (model, messages, temperature, top_p, max_tokens, stop, n, tools, tool_choice, user, frequency_penalty, presence_penalty, logit_bias) plus:
| Field | Description |
|---|---|
security_tier |
"standard" | "high" | "maximum" — hardware isolation level |
api_key |
Per-request API key override |
base_url |
Per-request router URL override — creates a temporary client, used once, then disposed |
SecureCompletionClient — Constructor Options
Lower-level client. All options above apply, with these differences:
| Option | Type | Default | Description |
|---|---|---|---|
routerUrl |
string |
'https://api.nomyo.ai' |
Base URL (baseUrl is renamed here) |
keySize |
2048 | 4096 |
4096 |
RSA modulus length |
Methods
generateKeys(options?)— generate a new RSA key pairloadKeys(privateKeyPath, publicKeyPath?, password?)— load existing PEM filesfetchServerPublicKey()— fetch the server's RSA public keyencryptPayload(payload)— encrypt a request payloaddecryptResponse(encrypted, payloadId)— decrypt a response bodysendSecureRequest(payload, payloadId, apiKey?, securityTier?)— full encrypt → POST → decrypt cycledispose()— zero key material and stop rotation timer
Secure Memory Public API
import {
getMemoryProtectionInfo,
disableSecureMemory,
enableSecureMemory,
SecureByteContext,
} from 'nomyo-js';
| Export | Description |
|---|---|
getMemoryProtectionInfo() |
Returns { method, canLock, isPlatformSecure, details? } |
disableSecureMemory() |
Disable global secure-memory zeroing |
enableSecureMemory() |
Re-enable global secure-memory zeroing |
SecureByteContext |
Low-level buffer wrapper — zeros in finally block |
Error Classes
import {
AuthenticationError, InvalidRequestError, RateLimitError,
ForbiddenError, ServerError, ServiceUnavailableError,
APIConnectionError, SecurityError, DisposedError, APIError,
} from 'nomyo-js';
| Class | HTTP | Thrown when |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
InvalidRequestError |
400 | Malformed request |
ForbiddenError |
403 | Model not allowed for the security tier |
RateLimitError |
429 | Rate limit exceeded (after all retries) |
ServerError |
500 | Internal server error (after all retries) |
ServiceUnavailableError |
503 | Backend unavailable (after all retries) |
APIError |
varies | Other HTTP errors |
APIConnectionError |
— | Network failure or timeout (after all retries) |
SecurityError |
— | HTTPS not used, header injection, or crypto failure |
DisposedError |
— | Method called after dispose() |
Platform Support
Node.js
- Minimum: Node.js 14.17+
- Recommended: Node.js 18 LTS or later
- Key storage: File system (
keyDirdirectory, defaultclient_keys/)
Browsers
- Supported: Chrome 37+, Firefox 34+, Safari 11+, Edge 79+
- Key storage: In-memory only (not persisted)
- Limitation: File-based key operations (
keyDir,loadKeys) are not available
Security Best Practices
- Always use HTTPS (
allowHttpisfalseby default) - Load API key from an environment variable, never hardcode it
- Use password-protected key files (
keyRotationPassword) - Store keys outside the project directory and outside version control
- Add
client_keys/and*.pemto.gitignore - Call
dispose()when the client is no longer needed - Use
security_tier: 'maximum'for HIPAA PHI or classified data - Consider the
nomyo-nativeaddon if swap-file exposure is unacceptable
License
See LICENSE file.