$ npm install @qvac/registry-clientRead-only client library for querying the QVAC Registry. It replicates the registry HyperDB via Hyperswarm and provides APIs for searching and retrieving model information.
npm install @qvac/registry-client
Ensure the registry core key is available via environment variables or provided via options.
'use strict'
const { QVACRegistryClient } = require('@qvac/registry-client')
async function main () {
const client = new QVACRegistryClient({
registryCoreKey: process.env.QVAC_REGISTRY_CORE_KEY
})
const models = await client.findModels({})
console.log('All models:', models)
if (models.length > 0) {
const model = await client.getModel(models[0].path, models[0].source)
console.log('Model:', model)
}
await client.close()
}
main().catch(console.error)
ready(): Initialize client and connect to registry. Triggered from constructor asynchronously.close(): Close connection to registry and corestore.getModel(path, source): Retrieves a specific model's metadata by path and source.findModels(query): General search with filters. Supports path prefix queries for finding model shards.findModelsByEngine(query): Searches models by engine (indexed).findModelsByName(query): Searches models by name (indexed).findModelsByQuantization(query): Searches models by quantization (indexed).Query format for range queries:
// Exact match
const models = await client.findModelsByEngine({
gte: { engine: '@qvac/transcription-whispercpp' },
lte: { engine: '@qvac/transcription-whispercpp' }
})
// Prefix match (all models with path starting with 'hf/')
const hfModels = await client.findModels({
gte: { path: 'hf/' },
lte: { path: 'hf/\uffff' }
})
downloadModel(path, source, options): Downloads actual model file from Hyperblobs cores.
path: Registry path of the model (e.g., 'hf/model.gguf')source: Source identifier (e.g., 'hf')options:
timeout: Download timeout in ms (default: 30000)outputFile: Optional file path to save directly to disk{ model: QVACModelEntry, artifact: QVACDownloadedArtifact }
outputFile provided: artifact = { path: '/path/to/file' }artifact = { stream: ReadableStream }Example - Download to file:
const result = await client.downloadModel('hf/ggml-tiny.bin', 'hf', {
outputFile: './downloaded/whisper-tiny.ggml',
timeout: 60000
})
console.log('Downloaded to:', result.artifact.path)
console.log('Model metadata:', result.model)
Example - Download as stream:
const result = await client.downloadModel('hf/ggml-tiny.bin', 'hf')
const fs = require('fs')
result.artifact.stream.pipe(fs.createWriteStream('./model.ggml'))
downloadBlob(blobBinding, options): Downloads a blob directly using known blob coordinates, bypassing the metadata core lookup. Useful when coreKey, blockOffset, blockLength, and byteLength are already known (e.g., from a previous query or generated model constants).
blobBinding: { coreKey, blockOffset, blockLength, byteOffset, byteLength } — coreKey accepts Buffer, hex, or z-base-32 stringsoptions:
timeout: Download timeout in ms (default: 30000)outputFile: Optional file path to save directly to diskonProgress: Callback ({ downloaded, total, cachedBlocks, totalBlocks }) => voidsignal: AbortSignal for cancellation{ artifact: { path, totalSize } | { stream, totalSize } }This method only waits for the network layer (Corestore + Hyperswarm) — it does not wait for the metadata core to sync, making it faster for known blob coordinates.
const result = await client.downloadBlob({
coreKey: 'ey46cahego89xox118uhyryakz47bcs8bbxu97tnnpmuwmgi5wmo',
blockOffset: 0,
blockLength: 665,
byteOffset: 0,
byteLength: 43537433
}, {
outputFile: './downloaded/ggml-tiny-q8_0.bin',
timeout: 60000
})
console.log('Downloaded to:', result.artifact.path)
The package includes a CLI for querying and downloading models from the registry.
The package is hosted on npm. Configure npm to use the registry for the @qvac scope, then install globally:
echo "@qvac:registry=https://registry.npmjs.org" >> ~/.npmrc
echo "//registry.npmjs.org/:_authToken=YOUR_NPM_TOKEN" >> ~/.npmrc
npm install -g @qvac/registry-client
Verify installation:
qvac-registry --help
By default, list prints a compact table with path, source, quantization, and params:
$ qvac-registry list
Found 195 model(s)
PATH SOURCE QUANT PARAMS
BSC-LT/salamandraTA-2B-instruct-GGUF/blob/60046856fcac87c47fb0c706e994e70f01eda62b/salamandrata_2b_inst_q4.gguf hf q4 2B
Qwen/Qwen3-8B-GGUF/blob/main/Qwen3-8B-Q4_K_M.gguf hf q4_k_m 8B
ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-tiny-q8_0.bin hf q8_0
...
Use --full for detailed output per model:
$ qvac-registry list --full
Found 195 model(s)
Qwen/Qwen3-8B-GGUF/blob/main/Qwen3-8B-Q4_K_M.gguf
source: hf
engine: @qvac/llm-llamacpp
quantization: q4_k_m
params: 8B
size: 4.68 GB
license: Apache-2.0
sha256: d98cdcbd03e17ce47681435b5150e34c1417f50b5c0019dd560e4882c5745785
...
# By engine
$ qvac-registry list --engine @qvac/transcription-whispercpp
# By quantization
$ qvac-registry list -q q4_k_m
# By name (case-sensitive prefix match on filename)
$ qvac-registry list -n Qwen3
# Combined
$ qvac-registry list -e @qvac/llm-llamacpp -q q4_k_m --full
$ qvac-registry get \
"ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-tiny-q8_0.bin" hf
ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-tiny-q8_0.bin
source: hf
engine: @qvac/transcription-whispercpp
quantization: q8_0
size: 41.52 MB
license: MIT
sha256: ...
$ qvac-registry download \
"ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-tiny-q8_0.bin" hf \
--output ./ggml-tiny-q8_0.bin
Downloading ... -> /absolute/path/ggml-tiny-q8_0.bin
Download complete: 41.52 MB
Diagnose slow downloads by collecting UDX network stats, connection info, and hypercore metrics — similar to hyperdrive-profiler but for registry Hyperblobs:
$ qvac-registry profile \
"ggerganov/whisper.cpp/resolve/5359861c739e955e79d9a303bcbc70fb988958b1/ggml-tiny.bin" hf
--- 5.0s elapsed ---
Network (UDX)
Bytes received: 42.1MB (8.4MB/s)
Bytes transmitted: 128kB (25.6kB/s)
Packets rx/tx: 29034 / 1842
Packets dropped: 0
Connection
Firewalled: false
Blob peers: 2
Issues: rto=0 fast-recoveries=0 retransmits=0
Hypercore
Blob core: 665 / 665 (contiguous / length)
Hotswaps: 0
...
==================================================
FINAL SUMMARY
==================================================
Download
Model: ggerganov/whisper.cpp/resolve/.../ggml-tiny.bin
Size: 73.5MB (1120 blocks)
Metadata: 2.15s
Transfer: 8.72s
Avg speed: 8.4MB/s
Total: 10.87s
Flags:
--interval|-i [seconds] Stats print interval (default: 5)
--timeout|-t [ms] Stream read timeout (default: 120000)
All commands support --json for machine-readable output:
$ qvac-registry list --engine @qvac/transcription-whispercpp --json | jq '.[0].path'
--key|-k [key] Registry core key (overrides QVAC_REGISTRY_CORE_KEY env)
--storage|-s [path] Client storage path
--verbose|-v Enable verbose/debug logging
See the examples/ folder for complete working examples:
example.js: List models, query by engine/name/quantization, find shardsdownload-model.js: Download a single model to disk via metadata lookupdownload-blob.js: Download a blob directly using known blob coordinatesdownload-all-models.js: Download all models in the registryprofile-download.js: Profile download performance with network/connection/hypercore statsRun examples:
cd client
node examples/example.js
node examples/download-model.js
node examples/download-blob.js
node examples/download-all-models.js
node examples/profile-download.js "model/path"
storage: Path for local storage (defaults to temporary directory in os.tmpdir(), or REGISTRY_STORAGE env var if set).registryCoreKey: z-base-32 or hex string of the hypercore key (defaults to QVAC_REGISTRY_CORE_KEY env var).logger: Logger configuration object
level: Log level ('debug', 'info', 'warn', 'error')name: Logger name for identificationBy default, the client uses a temporary directory created in os.tmpdir() with a unique name. Temporary storage is used for replicating registry metadata and is separate from downloaded model files. The temporary storage is not automatically cleaned up on exit and should be manually removed if needed. If you need persistent storage or want to control the location:
const client = new QVACRegistryClient({
registryCoreKey: process.env.QVAC_REGISTRY_CORE_KEY,
storage: '/path/to/persistent/storage'
})
QVAC_REGISTRY_CORE_KEY: Core key for accessing the registry hypercoreREGISTRY_STORAGE: Path for local storage (optional, overrides temporary directory default)The client uses custom error codes in the range 19001-20000. All errors extend QvacErrorRegistryClient.
| Code | Name | Description | When Thrown |
|---|---|---|---|
| 19001 | FAILED_TO_CONNECT | Connection to registry failed | Missing core key, network issues during initialization |
| 19002 | FAILED_TO_CLOSE | Failed to close registry cleanly | Resource cleanup errors during shutdown |
| 19003 | MODEL_NOT_FOUND | Model not found or invalid | Model doesn't exist or missing blob binding |
const { QVACRegistryClient } = require('@qvac/registry-client')
const { QvacErrorRegistryClient } = require('@qvac/registry-client/utils/error')
async function handleErrors () {
const client = new QVACRegistryClient({
registryCoreKey: process.env.QVAC_REGISTRY_CORE_KEY
})
try {
const model = await client.getModel('hf/model-name.Q4_K_M.gguf', 'hf')
if (!model) {
console.log('Model not found')
} else {
console.log('Model found:', model)
}
} catch (error) {
if (error instanceof QvacErrorRegistryClient) {
console.error(`Registry error [${error.code}]:`, error.message)
} else {
console.error('Unexpected error:', error)
}
} finally {
await client.close()
}
}
Apache-2.0