npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@phala/dstack-sdk

v0.5.8

Published

dstack SDK

Readme

@phala/dstack-sdk

JavaScript / TypeScript client for the dstack guest agent. Derive deterministic keys, generate TDX attestation quotes, issue TLS certificates, sign / verify payloads, and encrypt environment variables for KMS-managed deployments — all against the guest agent socket inside a confidential VM (CVM).

Installation

npm install @phala/dstack-sdk @noble/hashes

@noble/hashes is the only required peer dependency (used by the core for sha256 / sha384). Install the matching peer when you import a submodule:

| Import path | Extra peer dependency | | --- | --- | | @phala/dstack-sdk/viem | viem | | @phala/dstack-sdk/solana | @solana/web3.js | | @phala/dstack-sdk/encrypt-env-vars | @noble/curves | | @phala/dstack-sdk/verify-env-encrypt-public-key | @noble/curves |

Breaking change in 0.5.8. Prior releases listed @solana/web3.js, viem, and @noble/curves under optionalDependencies, so npm installed them automatically. They are now opt-in peers — install them yourself when you use the corresponding submodule.

Node 18+ supported. Tested through Node 24.

Quick start

import { DstackClient } from '@phala/dstack-sdk'

const client = new DstackClient()

const key = await client.getKey('wallet/eth')
console.log(Buffer.from(key.key).toString('hex'))

const quote = await client.getQuote('app-state-snapshot')
console.log(quote.quote)
console.log(quote.replayRtmrs())

The constructor probes /var/run/dstack.sock, then /run/dstack.sock, then the /var/run/dstack/ and /run/dstack/ variants. Pass an explicit endpoint for HTTP or for a non-default socket:

const client = new DstackClient('http://localhost:8090')        // simulator
const client = new DstackClient('/run/dstack/dstack.sock')      // custom path

DSTACK_SIMULATOR_ENDPOINT overrides the default when set.

Keys

getKey(path?, purpose?, algorithm?)

Derive a deterministic key. Same (app_id, path, purpose, algorithm) always returns the same key; different apps deriving on the same path get different keys.

const eth = await client.getKey('wallet/ethereum')                       // secp256k1 (default)
const sol = await client.getKey('wallet/solana', 'mainnet', 'ed25519')   // ed25519

Returns { key: Uint8Array, signature_chain: Uint8Array[] }. The signature chain proves the key was derived inside a genuine TEE.

algorithm: 'secp256k1' (default), 'k256' (alias), or 'ed25519'. ed25519 requires guest agent ≥ 0.5.7.

getTlsKey(options?)

Generate a fresh random TLS keypair plus certificate chain. Every call returns a new key — use getKey for deterministic material.

const tls = await client.getTlsKey({
  subject: 'api.example.com',
  altNames: ['localhost', '127.0.0.1'],
  usageRaTls: true,           // embed TDX quote in cert extension
})

Options: subject, altNames, usageRaTls, usageServerAuth (default true), usageClientAuth (default false), and — on guest agent ≥ 0.5.7 — notBefore, notAfter (Unix seconds), withAppInfo. The client probes version() before sending the new options and throws a clear error on older agents instead of silently dropping them.

Returns { key: string, certificate_chain: string[], asUint8Array(maxLength?) }. key is PEM-encoded.

Attestation

getQuote(reportData)

Generate a raw TDX quote. reportData is up to 64 bytes (string, Buffer, or Uint8Array).

const quote = await client.getQuote('user:alice:nonce123')
quote.quote        // hex-encoded TDX quote
quote.event_log    // JSON string of measured events
quote.replayRtmrs() // recompute RTMR[0..3] from the event log

attest(reportData)

Versioned dstack attestation that works across TDX / GCP / Nitro providers. Preferred for cross-platform verifiers.

const { attestation } = await client.attest('app-state-snapshot')

info()

App identity and TCB metadata.

const info = await client.info()
info.app_id              // application identifier
info.instance_id         // CVM instance identifier
info.tcb_info            // parsed { mrtd, rtmr0..3, event_log, ... }
info.compose_hash
info.cloud_vendor        // e.g. "Google" (guest agent ≥ 0.5.7)
info.cloud_product       // e.g. "Google Compute Engine" (guest agent ≥ 0.5.7)

version()

Returns { version, rev } of the guest agent. Throws on agents older than 0.5.7 (the RPC didn't exist).

Sign and verify

sign(algorithm, data)

Sign data with a derived key. The SDK rejects mismatched input early — secp256k1_prehashed requires a 32-byte digest.

const res = await client.sign('ed25519', 'hello dstack')
res.signature        // Uint8Array
res.public_key       // Uint8Array
res.signature_chain  // Uint8Array[] — proves the signing key came from this TEE

Algorithms: ed25519, secp256k1, secp256k1_prehashed. Requires guest agent ≥ 0.5.7.

verify(algorithm, data, signature, publicKey)

const ok = await client.verify('ed25519', 'hello dstack', res.signature, res.public_key)
ok.valid // boolean

emitEvent(event, payload)

Extends RTMR3 with a custom event. The event becomes part of the next quote's event log and cannot be removed.

await client.emitEvent('config_loaded', 'v1.0.0')

Requires guest agent ≥ 0.5.0.

Diagnostics

isReachable()

Sub-500ms probe against /Info. Returns a boolean and never throws — useful for liveness checks.

Blockchain helpers

Ethereum

import { toViemAccountSecure } from '@phala/dstack-sdk/viem'
import { createWalletClient, http } from 'viem'
import { mainnet } from 'viem/chains'

const key = await client.getKey('wallet/ethereum')
const account = toViemAccountSecure(key)

const wallet = createWalletClient({ account, chain: mainnet, transport: http() })

toViemAccountSecure hashes the derived key with SHA-256 before passing it to viem's privateKeyToAccount. The unhashed alternative toViemAccount is kept for migration only and emits a warning.

Solana

import { toKeypairSecure } from '@phala/dstack-sdk/solana'

const key = await client.getKey('wallet/solana')
const keypair = toKeypairSecure(key)
console.log(keypair.publicKey.toBase58())

Same pattern as the Ethereum helper. toKeypair is the unhashed legacy variant.

Compose hash

import { getComposeHash, type AppCompose } from '@phala/dstack-sdk/get-compose-hash'

const compose: AppCompose = {
  manifest_version: 2,
  name: 'my-app',
  runner: 'docker-compose',
  docker_compose_file: '...',
  kms_enabled: true,
}

const hash = getComposeHash(compose)
const normalized = getComposeHash(compose, true) // strip bash_script/docker_compose_file overlap

Pure function — no TEE call required. Produces the canonical SHA-256 used by the on-chain KMS allowlist.

Encrypted environment variables

The full deployment flow mirrors vmm-cli.py: fetch the env-encrypt public key from KMS, verify its signature locally, then ECIES-encrypt the env vars against it.

import {
  verifyEnvEncryptPublicKey,
  verifyEnvEncryptPublicKeyLegacy,
} from '@phala/dstack-sdk'
import { encryptEnvVars, type EnvVar } from '@phala/dstack-sdk/encrypt-env-vars'

const response = await fetch(`${kmsUrl}/prpc/GetAppEnvEncryptPubKey?json`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ app_id: appId }),
}).then(r => r.json())

const publicKey = Buffer.from(response.public_key, 'hex')

// Prefer v1 (timestamp-protected against replay)
let signer = response.signature_v1
  ? verifyEnvEncryptPublicKey(
      publicKey,
      Buffer.from(response.signature_v1, 'hex'),
      appId,
      BigInt(response.timestamp),
    )
  : null

// Fall back to legacy signature on older KMS
if (!signer && response.signature) {
  signer = verifyEnvEncryptPublicKeyLegacy(
    publicKey,
    Buffer.from(response.signature, 'hex'),
    appId,
  )
}

if (!signer) throw new Error('KMS signature did not verify')

const envs: EnvVar[] = [
  { key: 'DATABASE_URL', value: 'postgresql://…' },
  { key: 'API_KEY', value: 'sk-test-1234' },
]
const encrypted = await encryptEnvVars(envs, response.public_key)

Verify functions return the signer's compressed public key (hex) on success, or null on failure. Check the signer against your trusted-signer whitelist before encrypting.

Compatibility

| Feature | Minimum guest agent | | --- | --- | | getKey, getTlsKey, getQuote, info | 0.3.x | | emitEvent | 0.5.0 | | attest, sign, verify, version, ed25519 keys, info.cloud_vendor / cloud_product, getTlsKey notBefore / notAfter / withAppInfo | 0.5.7 |

The SDK's release versions track guest agent versions — 0.5.8-x targets dstack 0.5.7+.

Development

Run the standalone simulator instead of a real TDX host:

cd dstack/sdk/simulator
./build.sh
./dstack-simulator
export DSTACK_SIMULATOR_ENDPOINT=http://localhost:8090

Then point new DstackClient() at the simulator (it picks up DSTACK_SIMULATOR_ENDPOINT automatically).

Migration from TappdClient

TappdClient and its deriveKey / tdxQuote methods are deprecated but still exported. Replace them with DstackClient and the new methods:

| Old | New | | --- | --- | | new TappdClient() | new DstackClient() | | client.deriveKey(path, subject) | client.getTlsKey({ subject }) | | client.tdxQuote(data) | client.getQuote(data) | | /var/run/tappd.sock | /var/run/dstack.sock |

toViemAccount and toKeypair are kept for the same reason; prefer their Secure variants in new code.

License

Apache-2.0