@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 +28 -1
- package/dist/client.d.ts +29 -0
- package/dist/client.js +55 -0
- package/package.json +1 -1
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) {
|