@lv-agent/logdb-client 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,9 +31,21 @@ for (const r of records) {
31
31
  const stream = client.tail('my-app', 'main', { fromSeq: 0, consumerGroup: 'workers', consumerId: 'w1' });
32
32
  for await (const rec of stream) {
33
33
  console.log(`[${rec.seq}] ${rec.eventType}`);
34
- // Commit progress
35
34
  await client.commitOffset('my-app', 'main', 'workers', 'w1', rec.seq);
36
35
  }
36
+
37
+ // SQL query against cache
38
+ const rows = await client.query('my-app', 'main',
39
+ "SELECT seq, event_type FROM records WHERE event_type = 'llm.call' ORDER BY seq DESC LIMIT 10");
40
+ for (const row of rows) console.log(JSON.parse(row));
41
+
42
+ // Subscribe to event types in real-time
43
+ const sub = client.subscribe('my-app', 'main',
44
+ ['tool.call', 'llm.call'], 'sandbox-processors', 'worker-1');
45
+ sub.on('data', (rec) => {
46
+ console.log(`[${rec.seq}] ${rec.eventType}`);
47
+ client.commitOffset('my-app', 'main', 'sandbox-processors', 'worker-1', rec.seq);
48
+ });
37
49
  ```
38
50
 
39
51
  ## API
@@ -44,10 +56,14 @@ for await (const rec of stream) {
44
56
  | `read(ns, stream, seq)` | Point read |
45
57
  | `scanAll(ns, stream, fromSeq)` | Scan all records |
46
58
  | `tail(ns, stream, opts)` | Live subscription (async iterable) |
59
+ | `query(ns, stream, sql)` | SQL SELECT against query cache |
60
+ | `subscribe(ns, stream, eventTypes, group, id)` | Event-type push subscription |
47
61
  | `listNamespaces()` | List all namespaces |
48
62
  | `listStreams(ns)` | List streams in a namespace |
49
63
  | `status()` | Node status |
50
64
  | `verifyChain(ns, stream)` | Verify hash chain |
65
+ | `createStream(ns, stream)` | Create a stream (admin) |
66
+ | `deleteStream(ns, stream)` | Delete all records in a stream (admin) |
51
67
  | `commitOffset(...)` / `committedOffset(...)` | Consumer group offset management |
52
68
 
53
69
  ## TLS / mTLS
@@ -62,6 +78,17 @@ const client = new Client('logdbd.example.com:50051', {
62
78
  });
63
79
  ```
64
80
 
81
+ ## RBAC / Auth
82
+
83
+ Roles: `admin` (all), `writer` (append), `reader` (read/query), `subscriber` (subscribe).
84
+
85
+ ```typescript
86
+ // Pass token via ClientOptions
87
+ const client = new Client('logdbd.example.com:50051', {
88
+ authToken: 'admin-secret-token',
89
+ });
90
+ ```
91
+
65
92
  ## License
66
93
 
67
94
  Apache-2.0
package/dist/client.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as grpc from '@grpc/grpc-js';
1
2
  import { TailStream } from './tail-stream';
2
3
  import type { AppendResult, BatchAppendResult, NamespaceInfo, LogRecord, StreamInfo, StatusResult, Watermark, VerifyResult, TailOptions } from './types';
3
4
  export interface ClientOptions {
@@ -43,8 +44,25 @@ export declare class Client {
43
44
  read(namespace: string, stream: string, seq: number): Promise<LogRecord | null>;
44
45
  /** Scan records in range. Returns array of records. */
45
46
  scanAll(namespace: string, stream: string, fromSeq: number, limit?: number): Promise<LogRecord[]>;
47
+ /** Subscribe to matching event types in real-time.
48
+ *
49
+ * Returns a gRPC server-streaming call. Records are pushed as they
50
+ * are committed and filtered by `eventTypes`. The consumer offset
51
+ * is tracked server-side.
52
+ *
53
+ * Usage:
54
+ * const stream = client.subscribe('my-app', 'main', ['tool.call'], 'group', 'w1');
55
+ * stream.on('data', (rec) => console.log(rec.eventType, rec.content));
56
+ */
57
+ subscribe(namespace: string, stream: string, eventTypes: string[], consumerGroup: string, consumerId: string): grpc.ClientReadableStream<any>;
46
58
  /** Subscribe to new records via Tail. */
47
59
  tail(namespace: string, stream: string, opts?: TailOptions): TailStream;
60
+ /** Execute a read-only SQL query against a stream's query cache.
61
+ *
62
+ * Only SELECT is allowed — enforced at the SQLite kernel level.
63
+ * Each row is returned as a JSON string.
64
+ */
65
+ query(namespace: string, stream: string, sql: string): Promise<string[]>;
48
66
  /** Get the watermark for a namespace/stream. */
49
67
  watermark(namespace: string, stream: string): Promise<Watermark>;
50
68
  /** List all namespaces. */
@@ -59,6 +77,17 @@ export declare class Client {
59
77
  commitOffset(namespace: string, stream: string, consumerGroup: string, consumerId: string, seq: number): Promise<void>;
60
78
  /** Get committed offset for a consumer. */
61
79
  committedOffset(namespace: string, stream: string, consumerGroup: string, consumerId: string): Promise<number>;
80
+ /** Create a stream (and namespace if needed). Requires admin token. */
81
+ createStream(namespace: string, stream: string): Promise<{
82
+ namespaceId: number;
83
+ streamId: number;
84
+ created: boolean;
85
+ }>;
86
+ /** Mark all records in a stream as deleted. Requires admin token. */
87
+ deleteStream(namespace: string, stream: string): Promise<{
88
+ deleted: boolean;
89
+ deletedCount: number;
90
+ }>;
62
91
  /** Close the client connection. */
63
92
  close(): void;
64
93
  }
package/dist/client.js CHANGED
@@ -159,6 +159,26 @@ class Client {
159
159
  call.on('error', (err) => reject(err));
160
160
  });
161
161
  }
162
+ // ── Subscribe ───────────────────────────────────────────────────────
163
+ /** Subscribe to matching event types in real-time.
164
+ *
165
+ * Returns a gRPC server-streaming call. Records are pushed as they
166
+ * are committed and filtered by `eventTypes`. The consumer offset
167
+ * is tracked server-side.
168
+ *
169
+ * Usage:
170
+ * const stream = client.subscribe('my-app', 'main', ['tool.call'], 'group', 'w1');
171
+ * stream.on('data', (rec) => console.log(rec.eventType, rec.content));
172
+ */
173
+ subscribe(namespace, stream, eventTypes, consumerGroup, consumerId) {
174
+ return this.client.Subscribe({
175
+ namespace,
176
+ stream,
177
+ eventTypes,
178
+ consumerGroup,
179
+ consumerId,
180
+ });
181
+ }
162
182
  /** Subscribe to new records via Tail. */
163
183
  tail(namespace, stream, opts) {
164
184
  const call = this.client.Tail({
@@ -170,6 +190,21 @@ class Client {
170
190
  });
171
191
  return new tail_stream_1.TailStream(call, convertRecord);
172
192
  }
193
+ // ── Query ──────────────────────────────────────────────────────────
194
+ /** Execute a read-only SQL query against a stream's query cache.
195
+ *
196
+ * Only SELECT is allowed — enforced at the SQLite kernel level.
197
+ * Each row is returned as a JSON string.
198
+ */
199
+ query(namespace, stream, sql) {
200
+ return new Promise((resolve, reject) => {
201
+ this.client.Query({ namespace, stream, sql }, (err, resp) => {
202
+ if (err)
203
+ return reject(err);
204
+ resolve(resp.rows || []);
205
+ });
206
+ });
207
+ }
173
208
  // ── Watermark ──────────────────────────────────────────────────────
174
209
  /** Get the watermark for a namespace/stream. */
175
210
  watermark(namespace, stream) {
@@ -266,6 +301,26 @@ class Client {
266
301
  });
267
302
  });
268
303
  }
304
+ /** Create a stream (and namespace if needed). Requires admin token. */
305
+ createStream(namespace, stream) {
306
+ return new Promise((resolve, reject) => {
307
+ this.client.CreateStream({ namespace, stream, maxRecords: 0, maxBytes: 0 }, (err, resp) => {
308
+ if (err)
309
+ return reject(err);
310
+ resolve({ namespaceId: resp.namespaceId, streamId: resp.streamId, created: resp.created });
311
+ });
312
+ });
313
+ }
314
+ /** Mark all records in a stream as deleted. Requires admin token. */
315
+ deleteStream(namespace, stream) {
316
+ return new Promise((resolve, reject) => {
317
+ this.client.DeleteStream({ namespace, stream }, (err, resp) => {
318
+ if (err)
319
+ return reject(err);
320
+ resolve({ deleted: resp.deleted, deletedCount: Number(resp.deletedCount) });
321
+ });
322
+ });
323
+ }
269
324
  /** Close the client connection. */
270
325
  close() {
271
326
  if (!this.closed) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-agent/logdb-client",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "TypeScript SDK for logdbd — append-only audit log database",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",