# 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](/docs/authentication/) 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`: ```javascript 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: ```bash 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`: ```json { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "outDir": "dist" }, "include": ["src/**/*.ts"] } ``` Save the following as `src/quote.ts`: ```typescript 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 ```javascript 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 ```javascript 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 ```javascript 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 ```javascript 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.