@reflog-io/client
v0.1.2
Published
TypeScript client for Reflog with runtime protobuf type generation
Downloads
127
Maintainers
Readme
@reflog/client
TypeScript client for Reflog with runtime protobuf type generation. This client automatically generates type-safe methods from your custom protobuf definitions at runtime.
Installation
npm install @reflog/clientOr if developing locally:
npm install
npm run buildRunning the Example
To run the example file, you need to use ts-node (included as a dev dependency):
npm install
npm run exampleOr directly with ts-node:
npx ts-node example.tsMake sure to set the required environment variables:
export REFLOG_HOST=localhost:50051
export REFLOG_CLIENT_ID=my-client-id
npm run exampleNote: You cannot run node example.ts directly because it's a TypeScript file. You must use ts-node or compile it first with npm run build and then run the compiled JavaScript from the dist folder.
Configuration
The client requires two environment variables:
REFLOG_HOST: The gRPC server host (e.g.,localhost:50051)REFLOG_CLIENT_ID: Your client identifier
Alternatively, you can pass these as configuration options when creating the client.
Usage
Basic Example
import { createClient } from '@reflog/client';
async function main() {
// Initialize the client (reads REFLOG_HOST and REFLOG_CLIENT_ID from env)
const reflog = await createClient();
// Insert a user
await reflog.insert.user({
entity_id: 'user-123',
payload: {
id: 'user-123',
name: 'John Doe',
email: '[email protected]',
},
});
// Update an article
await reflog.update.article({
entity_id: 'article-456',
payload: {
id: 'article-456',
title: 'Updated Title',
body: 'Updated body content',
},
});
// Delete a user
await reflog.delete.user({ entity_id: 'user-123' });
// Close the connection when done (waits for pending background retries for 5 seconds)
await reflog.close();
}
main().catch(console.error);With Custom Configuration
import { createClient } from '@reflog/client';
const reflog = await createClient({
host: 'localhost:50051',
clientId: 'my-client-id',
retry: {
maxRetries: 5,
initialBackoffMs: 200,
maxBackoffMs: 3000,
},
});Type Safety
The client automatically generates methods based on your protobuf definitions. For example, if your custom.proto defines:
message User {
string id = 1;
string name = 2;
string email = 3;
}
message Article {
string id = 1;
string author_id = 2;
string title = 3;
string body = 4;
}The client will automatically provide:
reflog.insert.user()reflog.insert.article()reflog.update.user()reflog.update.article()reflog.delete.user()reflog.delete.article()
All methods are fully typed based on your protobuf schema.
API
createClient(config?: Partial<ReflogConfig>): Promise<ReflogClient>
Creates and initializes a new Reflog client. The client will automatically parse your custom.proto file and generate type-safe methods.
ReflogClient
Methods
insert.<entityType>(options: IngestOptions): Promise<IngestResponse>- Insert/create a new entity (uses background retries)update.<entityType>(options: IngestOptions): Promise<IngestResponse>- Update an existing entity (uses background retries)delete.<entityType>(options: DeleteOptions): Promise<IngestResponse>- Delete an entity (uses background retries)close(waitForRetries?: boolean, timeoutMs?: number): Promise<void>- Close the gRPC connection and optionally wait for pending background retries
Types
interface IngestOptions {
entity_id: string;
payload: Record<string, any>; // Must match your protobuf message definition
created_at?: number; // Optional Unix timestamp for create operations (milliseconds)
updated_at?: number; // Optional Unix timestamp for update operations (milliseconds)
deleted_at?: number; // Optional Unix timestamp for update operations (milliseconds)
}
interface DeleteOptions {
entity_id: string;
deleted_at?: number; // Optional Unix timestamp for delete operations (milliseconds)
}
interface IngestResponse {
ok: boolean;
message: string;
}Retries
The client automatically retries certain transient gRPC errors (such as UNAVAILABLE or DEADLINE_EXCEEDED) using an exponential backoff strategy with jitter.
You can configure retry behavior via the optional retry field on ReflogConfig:
interface RetryOptions {
maxRetries?: number; // default: Infinity (retry forever)
initialBackoffMs?: number; // default: 100
maxBackoffMs?: number; // default: 2000
}Retries are applied to:
initialize()when calling theGetProtosRPC- All ingest operations (
insert.<entityType>,update.<entityType>,delete.<entityType>)
Requirements
- Node.js 16+
- TypeScript 4.5+ (for TypeScript projects)
- Access to the Reflog gRPC server
Proto Files
The client includes the necessary proto files (custom.proto, ingest.proto, options.proto) in the package. These are automatically loaded at runtime to generate the type-safe API.
Error Handling
Background Retries
All ingest operations (insert, update, delete) use background retries for maximum reliability:
- First attempt: The operation tries once immediately
- On failure: If the first attempt fails with a retryable error (network issues, server unavailable, etc.), the promise resolves immediately with
{ ok: true, message: 'Request queued for background retry' } - Background retries: The client continues retrying in the background until:
- The operation succeeds, OR
- Maximum retries are exhausted, OR
- The client is closed
This ensures your application doesn't block waiting for the service to come back online, while still guaranteeing eventual delivery of your messages.
Note: The initialize() method uses synchronous retries (it must complete before the client is usable).
Error Types
- Non-retryable errors (thrown immediately): Invalid payload, authentication failures, validation errors
- Retryable errors (background retries): Network issues, server unavailable, timeouts
// This resolves immediately even if the service is down
// Retries continue in the background automatically
const result = await reflog.insert.user({
entity_id: 'user-123',
payload: { id: 'user-123', name: 'John' },
});
// result.ok === true (even if service was down - retries happening in background)
// When closing, wait for pending retries to complete
await reflog.close(); // Waits up to 5 seconds for background retries
// Or close immediately without waiting
reflog.close(false); // Closes immediately, background retries are cancelled