JavaScript & TypeScript SDK
Use @security-run/sdk from a Node.js 20+ project. It is ESM, has no runtime dependencies, and includes TypeScript declarations. Complete repository installation and API access first. Keep the SDK and its credential on the server, not in a browser bundle.
JavaScript quickstart
Save as quickstart.mjs and run node quickstart.mjs:
import { Client } from '@security-run/sdk';
import { createInterface } from 'node:readline/promises';
import { stdin, stdout } from 'node:process';
const client = new Client();
const prompt = createInterface({ input: stdin, output: stdout });
try {
await client.withSession('windows-server-2025', { ttl: '30m' }, async session => {
console.log('Session:', session.id);
console.log('IP:', session.ip);
console.log('Browser:', session.browserUrl);
await prompt.question('Open the browser URL. Press Enter here when finished: ');
});
} finally {
prompt.close();
}
withSession() waits for readiness, loads native credentials, invokes your callback, and requests destruction in a finally block. Keep all work inside the callback and await it before returning. Use ubuntu-24.04 for a Linux terminal.
TypeScript project setup
Install the SDK from your checkout, plus your project's TypeScript tools:
npm install /absolute/path/to/security-run/sdk/javascript
npm install --save-dev typescript @types/node
Use "type": "module" in package.json. A minimal tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"outDir": "dist"
},
"include": ["src/**/*.ts"]
}
Save the following as src/quote.ts:
import { Client, type Duration } from '@security-run/sdk';
const client = new Client();
const ttl: Duration = '30m';
const quote = await client.quote('ubuntu-24.04', {
ttl,
transferBudgetCredits: 10,
});
console.log('Usage upper limit:', quote.max_credits, 'credits');
console.log('Available:', (await client.credits()).available_credits, 'credits');
Compile with npx tsc, then run node dist/quote.js. This example only reads a quote and balance; it does not launch a VM.
Launch options
const session = await client.launch('ubuntu-24.04', {
ttl: '30m',
transferBudgetCredits: 50,
wait: true,
timeout: 900_000,
idempotencyKey: 'case-482-linux',
});
| Option | Default | Meaning |
|---|---|---|
ttl |
'30m' |
Duration string or integer seconds; 300–14,400 seconds, subject to trial limits. |
transferBudgetCredits |
Server default: 50 | Integer outbound-credit budget from 10 to 500. |
wait |
true |
Wait for ready and load native credentials. |
timeout |
900_000 |
Readiness wait timeout, in milliseconds. |
idempotencyKey |
Generated UUID | Reuse for an identical retry of this logical launch. |
JavaScript timeouts are in milliseconds, while integer ttl values are in seconds. The wait timeout does not cancel the server-side session. transferBudgetCents remains a legacy alias; new code should use only transferBudgetCredits.
Reference
| Call or property | Result |
|---|---|
new Client({ apiKey, baseUrl, fetch }) |
Optional overrides; otherwise uses environment variables and native fetch. |
await client.images() |
Array of image objects. |
await client.credits() |
Credit account response. |
await client.quote(image, options) |
Rates and usage upper limit without a launch. |
await client.launch(image, options) |
A Session; ready by default. |
await client.withSession(image, options, fn) |
The callback's return value, after cleanup. options can be omitted. |
await client.list() |
All of your session objects, automatically paginated. |
await client.get(id) |
A session with its current state. |
session.id, .ip, .state, .browserUrl |
Cached values; IP may be null before readiness. |
session.credentials |
A copy of loaded credentials, or undefined. Reading this property does not fetch them. |
await session.refresh() |
Update state and return the same object. |
await session.connect() |
Fetch and cache native connection credentials for a ready session. |
session.toJSON() |
A deep copy of the cached response, potentially including secrets. |
await session.destroy({ wait: true, timeout: 180_000 }) |
Request teardown and wait for a terminal state by default. |
Method options use camelCase; raw API fields returned by credits(), quote(), and toJSON() use snake_case. The SDK does not have remote command execution or file-transfer methods. Use SSH/SFTP, RDP, or the browser with the returned connection details.
Manage a session explicitly
import { Client } from '@security-run/sdk';
const client = new Client();
const session = await client.launch('ubuntu-24.04', { ttl: '30m' });
try {
console.log(session.browserUrl);
// Await your SSH/SFTP workflow here using session.ip and session.credentials.
} finally {
await session.destroy();
}
The VM is destroyed as soon as the finally block runs. Do not use this short example to open a browser and then expect the VM to remain available after the script exits.
For Linux, native credentials include username, private_key and host_public_key. Windows includes username, password and certificate_fingerprint. Keep private keys/passwords out of console output and verify the returned host identity when connecting.
Track startup in a background job
import { Client } from '@security-run/sdk';
import { writeFile } from 'node:fs/promises';
const client = new Client();
const session = await client.launch('ubuntu-24.04', { wait: false, ttl: '30m' });
await writeFile('session-id.txt', session.id, { mode: 0o600 });
console.log(session.browserUrl);
In a later job, use client.get(savedId) and session.refresh() until ready, then call session.connect() to load credentials. A refresh replaces the cached response and clears previously loaded credentials, so call connect() again when you need them.
Persist the ID and define who is responsible for destruction. A stopped job or lost browser connection does not stop the VM; server expiry is the final fallback.
Error handling and cleanup
import { Client, SessionError } from '@security-run/sdk';
const client = new Client();
try {
await client.withSession('ubuntu-24.04', {
ttl: '30m', timeout: 120_000, idempotencyKey: 'case-482-linux',
}, async session => {
console.log(session.browserUrl);
});
} catch (error) {
if (error instanceof SessionError && error.sessionId) {
await (await client.get(error.sessionId)).destroy();
}
throw error;
}
A launch error occurs before withSession() can enter its callback cleanup block. Readiness errors include sessionId. A connection error before an ID was received must be resolved by retrying the same idempotency key and options.
If both the callback and cleanup fail, withSession() preserves the callback's error and attaches cleanupError to it when it is an Error object. Inspect or destroy the saved session separately. Do not start another VM merely because a readiness response was delayed.
Machine sizes
Basic Linux terminals default to Small: 2 vCPUs and 2 GiB RAM at 10 credits/hour. Select Standard for 4 GiB at 40 credits/hour: client.launch("ubuntu-24.04", { size: "standard" }). Security desktops and Windows support Standard only (4 GiB, 15 credits/hour). SDK sessions retain their explicit TTL and are not subject to browser inactivity cleanup by default.
Preconfigured security desktops
Use parrot, sift, remnux or flare as the image ID with the same launch and cleanup methods. Standard size is selected automatically. For example: const session = await client.launch('remnux', { ttl: '30m' });
The Linux desktops return both credentials.password for RDP and credentials.private_key for SSH. The connection response includes port: 3389 and ssh_port: 22. Use credentials.username instead of assuming a login name. FLARE-VM provides RDP on Windows Server 2022.