@coderule/clients
v2.1.0
Published
TypeScript HTTP clients for core Coderule microservices (Auth, Sync, Retrieval, AST)
Downloads
100
Maintainers
Readme
Coderule TypeScript Client SDK
TypeScript HTTP clients for core Coderule microservices (Auth, Sync, Retrieval, AST) with automatic fetch polyfill support.
Requirements
- Node.js 14+ (automatically uses node-fetch for versions < 18, native fetch for 18+)
- TypeScript 5.0+
Node.js Version Compatibility
- Node.js 18+: Uses native fetch API (no additional dependencies needed)
- Node.js 14-17: Requires
node-fetchto be installed:npm install node-fetch@2
The library automatically detects your Node.js version and uses the appropriate fetch implementation.
Installation
npm install
npm run buildUsage Examples
Unified client access
import { CoderuleClients, consoleLogger } from '@coderule/clients';
const clients = new CoderuleClients({
token: process.env.CODERULE_TOKEN!,
auth: { baseUrl: 'https://r.coderule.ai:16803' }, // optional, defaults to this host
logger: consoleLogger, // optional, defaults to nullLogger (silent)
});
const snapshotStatus = await clients.sync.checkSnapshotStatus(snapshotHash);
const retrieval = await clients.retrieval.query(snapshotHash, 'Find the entrypoint');
const visitorRules = await clients.ast.getVisitorRulesV2();
clients.close();The unified client automatically exchanges your long-lived token for short-lived
JWTs using the Auth service. Tokens are cached and refreshed halfway through
their lifetime. Whenever the Auth service returns a JWT with a different
server_url, the AST, Retrieval, and Sync clients update their base URLs on
the fly.
You can override individual service hosts or timeouts:
const clients = new CoderuleClients({
token,
auth: { baseUrl: 'https://internal-auth.example.com' },
retrieval: { timeout: 90_000 },
sync: { baseUrl: 'http://localhost:8002' }, // static override keeps sync on localhost
});Manual wiring
If you prefer to manage dependency injection yourself, wire the Auth client and JWT factory and pass the provider into the other clients.
import {
AuthHttpClient,
JWTFactory,
RetrievalHttpClient,
SyncHttpClient,
ASTHttpClient,
} from '@coderule/clients';
const authClient = new AuthHttpClient('http://localhost:8001');
const jwtFactory = new JWTFactory(authClient, longLivedToken);
const syncClient = new SyncHttpClient({
baseUrl: 'http://localhost:8002',
jwtProvider: jwtFactory,
});
const astClient = new ASTHttpClient({
baseUrl: 'http://localhost:8003',
jwtProvider: jwtFactory,
});
const retrievalClient = new RetrievalHttpClient({
baseUrl: 'http://localhost:8004',
jwtProvider: jwtFactory,
});
const status = await syncClient.checkSnapshotStatus(snapshotHash);
const queryResult = await retrievalClient.query(snapshotHash, 'Find the entrypoint');
const rules = await astClient.getVisitorRulesV2();Authentication service
const authClient = new AuthHttpClient('http://localhost:8001');
try {
const authResponse = await authClient.authenticate('your-token');
console.log(`JWT expires at: ${authResponse.expires_at}`);
const health = await authClient.health();
console.log(`Auth service status: ${health.status}`);
} finally {
authClient.close();
}Sync service
const syncClient = new SyncHttpClient({
baseUrl: 'http://localhost:8002',
jwtProvider: jwtFactory,
});
const files = [
{ file_path: 'src/main.ts', content: 'const x = 1;' },
{ file_path: 'src/utils.ts', content: 'export function util() {}' },
{ file_path: 'package.json', content: '{"name": "test"}' },
];
const filesInfo = [];
const fileHashes = [];
const fileContents = new Map();
for (const file of files) {
const fileHash = SyncHttpClient.calculateFileHash(file.file_path, file.content);
filesInfo.push({ file_path: file.file_path, file_hash: fileHash });
fileContents.set(fileHash, {
path: file.file_path,
content: Buffer.from(file.content),
});
fileHashes.push(fileHash);
}
const snapshotHash = SyncHttpClient.calculateSnapshotHash(fileHashes);
const status = await syncClient.checkSnapshotStatus(snapshotHash);
if (status.status === 'NOT_FOUND') {
const result = await syncClient.createSnapshot(snapshotHash, filesInfo);
if (result.status === 'MISSING_CONTENT' && result.missing_files) {
const missingContent = new Map();
for (const missingFile of result.missing_files) {
if (fileContents.has(missingFile.file_hash)) {
missingContent.set(
missingFile.file_hash,
fileContents.get(missingFile.file_hash)!,
);
}
}
if (missingContent.size > 0) {
await syncClient.uploadFileContent(missingContent);
await syncClient.createSnapshot(snapshotHash, filesInfo);
}
}
}AST service
const astClient = new ASTHttpClient({
baseUrl: 'http://localhost:8003',
jwtProvider: jwtFactory,
});
const health = await astClient.health();
console.log(`AST service status: ${health.status}`);
const rules = await astClient.getVisitorRulesV2();
console.log(`Rules format: ${rules.format}`);
const compiled = ASTHttpClient.compileRulesV2(rules);
const ignoredPredicate = ASTHttpClient.buildIgnoredPredicate(compiled);Retrieval service
const retrievalClient = new RetrievalHttpClient({
baseUrl: 'http://localhost:8004',
jwtProvider: jwtFactory,
});
const result = await retrievalClient.query(
snapshotHash,
'Find the main authentication logic',
3000,
{
formatter: 'compact',
flow_strength: 1.5,
blend_alpha: 0.8,
},
);
console.log(result.formatted_output);
const status = await retrievalClient.checkSnapshotStatus(snapshotHash);
console.log(`Snapshot indexing status: ${status.status}`);
const cacheStats = await retrievalClient.getCacheStats();
console.log(`Cached snapshots: ${cacheStats.cached_snapshots}`);Utility Methods
The SyncHttpClient provides static utility methods for hash calculation:
import { SyncHttpClient } from '@coderule/clients';
// Calculate file hash from path and content
const fileHash = SyncHttpClient.calculateFileHash('src/main.ts', 'const x = 1;');
console.log(`File hash: ${fileHash}`);
// Calculate snapshot hash from file hashes
const fileHashes = ['hash1', 'hash2', 'hash3'];
const snapshotHash = SyncHttpClient.calculateSnapshotHash(fileHashes);
console.log(`Snapshot hash: ${snapshotHash}`);Error Handling
All clients throw errors with descriptive messages on failures:
try {
const result = await client.someMethod();
} catch (error) {
if (error.message.includes('timeout')) {
console.error('Request timed out');
} else if (error.message.includes('401')) {
console.error('Authentication failed');
} else {
console.error('Unexpected error:', error.message);
}
}Configuration
All clients support timeout configuration in milliseconds:
// Custom timeout of 30 seconds
const retrievalClient = new RetrievalHttpClient({
baseUrl: 'http://localhost:8004',
timeout: 30_000,
jwtProvider: jwtFactory,
logger: consoleLogger, // optional
});CoderuleClients also accepts per-service overrides via the auth, ast, retrieval,
and sync options. JWTFactory exposes an onTokenRefreshed callback if you need to
observe token rotations (for example, to log the current server_url).
Logging
The SDK includes a flexible logging interface that allows you to integrate with any logging library:
import { Logger, nullLogger, consoleLogger } from '@coderule/clients';
// Use the built-in silent logger (default)
const silentClients = new CoderuleClients({
token,
logger: nullLogger, // or omit for default
});
// Use the built-in console logger for debugging
const debugClients = new CoderuleClients({
token,
logger: consoleLogger,
});
// Implement your own logger
const customLogger: Logger = {
error: (message, ...meta) => myLogger.error(message, meta),
warn: (message, ...meta) => myLogger.warn(message, meta),
info: (message, ...meta) => myLogger.info(message, meta),
debug: (message, ...meta) => myLogger.debug(message, meta),
};
const clients = new CoderuleClients({
token,
logger: customLogger,
});All individual clients also accept an optional logger parameter:
const authClient = new AuthHttpClient('http://localhost:8001', 30000, consoleLogger);Breaking Changes
v1.6.0
- Logger interface added: All clients now accept an optional
loggerparameter - Default behavior is silent: By default, clients use
nullLoggerwhich produces no output - Backward compatible: The logger parameter is optional, existing code continues to work
v1.4.0
- Clients now require a JWT provider:
SyncHttpClient,RetrievalHttpClient, andASTHttpClientno longer accept JWT strings per method. Inject aJWTFactoryor anyJWTProviderimplementation through the constructor instead. - Unified entry point:
CoderuleClientscentralises token exchange. Auth defaults tohttps://r.coderule.ai:16803, and other clients automatically adopt theserver_urlprovided by the Auth service unless explicitly overridden.
Notes
- Automatic fetch detection: Works with Node.js 14+ (uses node-fetch for < 18, native fetch for 18+)
- Optional dependency:
node-fetchis only required for Node.js versions < 18 - Zero dependencies for Node.js 18+: Uses native fetch API
- Clients automatically handle JSON serialization/deserialization
- JWT handling is centralised through a
JWTProvider(JWTFactoryorCoderuleClients) - AST, Retrieval, and Sync clients update their base URLs when the JWT refresh
returns a different
server_url(unless a manual override is configured) - Health check endpoints don't require authentication
- All clients have a
close()method for consistency, though fetch doesn't maintain persistent connections
Building from Source
# Install dependencies
npm install
# Build TypeScript to JavaScript
npm run build
# Output will be in dist/ directoryLicense
ISC
