Node.js SDK

The official Torque Node.js SDK provides an HTTP client and TCP binary ingest client. Zero external dependencies — uses native fetch and Node.js built-in modules. Requires Node.js 20+.

Installation

npm install @truespar/torque-http

HTTP Client

The TorqueHttpClient class provides full access to the Torque REST API:

import { TorqueHttpClient } from '@truespar/torque-http';

const client = new TorqueHttpClient({
  url: 'http://localhost:8108',
  apiKey: 'YOUR_API_KEY',
});

// Health check
const health = await client.health();

// Search
const results = await client.search('products', {
  q: 'running shoes',
  query_by: 'title,description',
  filter_by: 'in_stock:true',
  sort_by: 'price:asc',
  per_page: 20,
});

for (const hit of results.hits) {
  console.log(`${hit.document.title} - ${hit.document.price}`);
}

Multi-Node with Failover

const client = new TorqueHttpClient({
  nodes: [
    { host: 'node1.example.com', port: 8108, protocol: 'https' },
    { host: 'node2.example.com', port: 8108, protocol: 'https' },
  ],
  apiKey: 'YOUR_API_KEY',
  retries: 3,
});

Collection Management

// Create a collection
await client.createCollection({
  name: 'products',
  fields: [
    { name: 'title', type: 'string' },
    { name: 'price', type: 'float', sort: true },
    { name: 'category', type: 'string', facet: true },
  ],
  default_sorting_field: 'price',
});

// List collections
const collections = await client.listCollections();

// Delete a collection
await client.deleteCollection('products');

Document Operations

// Import documents (JSONL)
const results = await client.importDocuments('products', [
  { id: '1', title: 'Running Shoes', price: 89.99, category: 'Footwear' },
  { id: '2', title: 'Laptop Stand', price: 49.99, category: 'Electronics' },
], { action: 'upsert' });

// Export documents
const docs = await client.exportDocuments('products');

// CRUD
await client.createDocument('products', { id: '3', title: 'Mouse', price: 29.99 });
const doc = await client.getDocument('products', '3');
await client.updateDocument('products', '3', { price: 24.99 });
await client.deleteDocument('products', '3');

Grouped & Multi-Search

// Grouped search (use group_by parameter with search)
const grouped = await client.search('products', {
  q: 'shoes',
  query_by: 'title',
  group_by: 'brand',
  group_limit: 3,
});

for (const group of grouped.grouped_hits) {
  console.log(`Brand: ${group.group_key.join(', ')} (${group.found} hits)`);
}

// Multi-search
const multi = await client.multiSearch([
  { collection: 'products', q: 'shoes', query_by: 'title' },
  { collection: 'articles', q: 'shoes', query_by: 'body' },
]);

Aliases, Keys & More

// Aliases (alias name first, then target collection)
await client.upsertAlias('products_alias', 'products');
const aliases = await client.listAliases();

// API keys
const key = await client.createKey({
  description: 'Search only',
  actions: ['documents:search'],
  collections: ['products'],
});

// Synonyms, presets, stopwords
await client.upsertSynonymSet('my_synonyms', { synonyms: [{root: 'laptop', synonyms: ['notebook']}] });
await client.upsertPreset('my_preset', { value: {q: 'default', query_by: 'title'} });
await client.upsertStopwords('my_stopwords', { stopwords: ['the', 'a', 'an'] });

TCP Binary Ingestion

The TorqueIngestClient provides high-throughput document streaming via the binary TCP protocol:

import { TorqueIngestClient, DocumentEncoder } from '@truespar/torque-http';

const schema = [
  { name: 'title', type: 'string' },
  { name: 'price', type: 'float' },
  { name: 'category', type: 'string' },
];

const ingest = new TorqueIngestClient();
await ingest.connect('localhost', 8109);
await ingest.startIngest('products');

// Send document dicts in batches — DocumentEncoder encodes internally
let batch = [];
for (let i = 0; i < 100000; i++) {
  batch.push({
    id: `product_${i}`,
    title: `Product ${i}`,
    price: 9.99 + i * 0.01,
    category: 'Electronics',
  });
  if (batch.length === 5000) {
    await ingest.sendBatch(batch, schema);
    batch = [];
  }
}
if (batch.length) await ingest.sendBatch(batch, schema);

const result = await ingest.commit();
console.log(`Committed: seq=${result.batchSeq}, docs=${result.docsReceived}`);
ingest.close();

TQBF Binary File Writer

import { TorqueBinaryWriter } from '@truespar/torque-http';

const writer = new TorqueBinaryWriter(schema, 'output.tqbf');

for (let i = 0; i < 100000; i++) {
  writer.write({ id: `p_${i}`, title: `Product ${i}`, price: 9.99 });
}
writer.finalize();

// Upload: POST /collections/products/documents/import-binary --data-binary @output.tqbf

HMAC Scoped Keys

const scopedKey = client.generateScopedSearchKey(
  'your-search-key',
  { filter_by: 'company_id:=123' },
);

TypeScript Support

The SDK includes TypeScript type definitions in types/index.d.ts. All method signatures, search parameters, and response types are fully typed.

Error Handling

HTTP API errors throw typed error classes:

Error ClassHTTP Status
RequestMalformed400
RequestUnauthorized401
RequestForbidden403
ObjectNotFound404
ObjectAlreadyExists409
ServerError500
ServiceUnavailable503

All errors extend TorqueApiError which provides statusCode and message properties.