@kb-labs/adapters 0.5.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/.cursorrules +32 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/deploy.yml +28 -0
- package/.github/workflows/docker-build.yml +25 -0
- package/.github/workflows/drift-check.yml +10 -0
- package/.github/workflows/profiles-validate.yml +16 -0
- package/.github/workflows/release.yml +8 -0
- package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
- package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
- package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
- package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
- package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
- package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
- package/.kb/devkit/agents/release-manager/context.globs +7 -0
- package/.kb/devkit/agents/release-manager/prompt.md +27 -0
- package/.kb/devkit/agents/release-manager/runbook.md +17 -0
- package/.kb/devkit/agents/test-generator/context.globs +7 -0
- package/.kb/devkit/agents/test-generator/prompt.md +27 -0
- package/.kb/devkit/agents/test-generator/runbook.md +18 -0
- package/CONTRIBUTING.md +90 -0
- package/IMPLEMENTATION_COMPLETE.md +416 -0
- package/LICENSE +186 -0
- package/README-TEMPLATE.md +179 -0
- package/README.md +306 -0
- package/docs/DOCUMENTATION.md +74 -0
- package/docs/adr/0000-template.md +49 -0
- package/docs/adr/0001-architecture-and-repository-layout.md +33 -0
- package/docs/adr/0002-plugins-and-extensibility.md +46 -0
- package/docs/adr/0003-package-and-module-boundaries.md +37 -0
- package/docs/adr/0004-versioning-and-release-policy.md +38 -0
- package/docs/adr/0005-use-devkit-for-shared-tooling.md +48 -0
- package/docs/adr/0006-adopt-devkit-sync.md +47 -0
- package/docs/adr/0007-drift-kit-check.md +72 -0
- package/docs/adr/0008-devkit-sync-wrapper-strategy.md +67 -0
- package/docs/naming-convention.md +272 -0
- package/eslint.config.js +27 -0
- package/kb-labs.config.json +5 -0
- package/package.json +84 -0
- package/package.json.bin +25 -0
- package/package.json.lib +30 -0
- package/packages/adapters-analytics-duckdb/package.json +54 -0
- package/packages/adapters-analytics-duckdb/scripts/migrate-from-jsonl.mjs +253 -0
- package/packages/adapters-analytics-duckdb/src/index.ts +380 -0
- package/packages/adapters-analytics-duckdb/src/manifest.ts +36 -0
- package/packages/adapters-analytics-duckdb/src/schema.ts +161 -0
- package/packages/adapters-analytics-duckdb/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-duckdb/tsconfig.json +9 -0
- package/packages/adapters-analytics-duckdb/tsup.config.ts +9 -0
- package/packages/adapters-analytics-file/README.md +32 -0
- package/packages/adapters-analytics-file/eslint.config.js +27 -0
- package/packages/adapters-analytics-file/package.json +50 -0
- package/packages/adapters-analytics-file/src/__tests__/daily-stats.spec.ts +287 -0
- package/packages/adapters-analytics-file/src/__tests__/scoped-analytics.test.ts +233 -0
- package/packages/adapters-analytics-file/src/index.test.ts +214 -0
- package/packages/adapters-analytics-file/src/index.ts +830 -0
- package/packages/adapters-analytics-file/src/manifest.ts +45 -0
- package/packages/adapters-analytics-file/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-file/tsconfig.json +9 -0
- package/packages/adapters-analytics-file/tsup.config.ts +9 -0
- package/packages/adapters-analytics-sqlite/package.json +55 -0
- package/packages/adapters-analytics-sqlite/scripts/migrate-from-jsonl.mjs +194 -0
- package/packages/adapters-analytics-sqlite/src/index.ts +460 -0
- package/packages/adapters-analytics-sqlite/src/manifest.ts +41 -0
- package/packages/adapters-analytics-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-sqlite/tsconfig.json +9 -0
- package/packages/adapters-analytics-sqlite/tsup.config.ts +9 -0
- package/packages/adapters-environment-docker/README.md +28 -0
- package/packages/adapters-environment-docker/eslint.config.js +5 -0
- package/packages/adapters-environment-docker/package.json +49 -0
- package/packages/adapters-environment-docker/src/index.test.ts +138 -0
- package/packages/adapters-environment-docker/src/index.ts +439 -0
- package/packages/adapters-environment-docker/src/manifest.ts +65 -0
- package/packages/adapters-environment-docker/tsconfig.build.json +15 -0
- package/packages/adapters-environment-docker/tsconfig.json +16 -0
- package/packages/adapters-environment-docker/tsup.config.ts +9 -0
- package/packages/adapters-eventbus-cache/README.md +242 -0
- package/packages/adapters-eventbus-cache/eslint.config.js +27 -0
- package/packages/adapters-eventbus-cache/package.json +46 -0
- package/packages/adapters-eventbus-cache/src/index.test.ts +235 -0
- package/packages/adapters-eventbus-cache/src/index.ts +215 -0
- package/packages/adapters-eventbus-cache/src/manifest.ts +50 -0
- package/packages/adapters-eventbus-cache/src/types.ts +58 -0
- package/packages/adapters-eventbus-cache/tsconfig.build.json +15 -0
- package/packages/adapters-eventbus-cache/tsconfig.json +9 -0
- package/packages/adapters-eventbus-cache/tsup.config.ts +9 -0
- package/packages/adapters-fs/README.md +171 -0
- package/packages/adapters-fs/allowed.txt +1 -0
- package/packages/adapters-fs/conflict.txt +1 -0
- package/packages/adapters-fs/dest.txt +1 -0
- package/packages/adapters-fs/eslint.config.js +27 -0
- package/packages/adapters-fs/exists.txt +1 -0
- package/packages/adapters-fs/not-allowed.txt +1 -0
- package/packages/adapters-fs/other.txt +1 -0
- package/packages/adapters-fs/package.json +55 -0
- package/packages/adapters-fs/public/file1.txt +1 -0
- package/packages/adapters-fs/public/file2.txt +1 -0
- package/packages/adapters-fs/secret.txt +1 -0
- package/packages/adapters-fs/secrets/key.txt +1 -0
- package/packages/adapters-fs/src/index.test.ts +243 -0
- package/packages/adapters-fs/src/index.ts +258 -0
- package/packages/adapters-fs/src/manifest.ts +35 -0
- package/packages/adapters-fs/src/secure-storage.test.ts +380 -0
- package/packages/adapters-fs/src/secure-storage.ts +268 -0
- package/packages/adapters-fs/test.json +1 -0
- package/packages/adapters-fs/test.txt +1 -0
- package/packages/adapters-fs/test.xyz +1 -0
- package/packages/adapters-fs/test1.txt +1 -0
- package/packages/adapters-fs/test2.txt +1 -0
- package/packages/adapters-fs/tsconfig.build.json +15 -0
- package/packages/adapters-fs/tsconfig.json +9 -0
- package/packages/adapters-fs/tsup.config.ts +8 -0
- package/packages/adapters-fs/vitest.config.ts +19 -0
- package/packages/adapters-log-ringbuffer/README.md +228 -0
- package/packages/adapters-log-ringbuffer/eslint.config.js +27 -0
- package/packages/adapters-log-ringbuffer/package.json +47 -0
- package/packages/adapters-log-ringbuffer/src/__tests__/ring-buffer.test.ts +450 -0
- package/packages/adapters-log-ringbuffer/src/index.ts +212 -0
- package/packages/adapters-log-ringbuffer/src/manifest.ts +30 -0
- package/packages/adapters-log-ringbuffer/tsconfig.build.json +15 -0
- package/packages/adapters-log-ringbuffer/tsconfig.json +9 -0
- package/packages/adapters-log-ringbuffer/tsup.config.ts +9 -0
- package/packages/adapters-log-ringbuffer/vitest.config.ts +14 -0
- package/packages/adapters-log-sqlite/README.md +396 -0
- package/packages/adapters-log-sqlite/eslint.config.js +27 -0
- package/packages/adapters-log-sqlite/package.json +49 -0
- package/packages/adapters-log-sqlite/src/__tests__/log-persistence.test.ts +718 -0
- package/packages/adapters-log-sqlite/src/index.ts +1068 -0
- package/packages/adapters-log-sqlite/src/manifest.ts +36 -0
- package/packages/adapters-log-sqlite/src/schema.sql +46 -0
- package/packages/adapters-log-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-log-sqlite/tsconfig.json +9 -0
- package/packages/adapters-log-sqlite/tsup.config.ts +9 -0
- package/packages/adapters-log-sqlite/vitest.config.ts +15 -0
- package/packages/adapters-mongodb/README.md +147 -0
- package/packages/adapters-mongodb/eslint.config.js +27 -0
- package/packages/adapters-mongodb/package.json +53 -0
- package/packages/adapters-mongodb/src/index.ts +428 -0
- package/packages/adapters-mongodb/src/manifest.ts +45 -0
- package/packages/adapters-mongodb/src/secure-document.ts +231 -0
- package/packages/adapters-mongodb/tsconfig.build.json +15 -0
- package/packages/adapters-mongodb/tsconfig.json +9 -0
- package/packages/adapters-mongodb/tsup.config.ts +8 -0
- package/packages/adapters-openai/README.md +151 -0
- package/packages/adapters-openai/embeddings.ts +37 -0
- package/packages/adapters-openai/eslint.config.js +26 -0
- package/packages/adapters-openai/index.ts +22 -0
- package/packages/adapters-openai/package.json +57 -0
- package/packages/adapters-openai/src/embeddings-manifest.ts +45 -0
- package/packages/adapters-openai/src/embeddings.ts +104 -0
- package/packages/adapters-openai/src/index.ts +13 -0
- package/packages/adapters-openai/src/llm.ts +304 -0
- package/packages/adapters-openai/src/manifest.ts +47 -0
- package/packages/adapters-openai/tsconfig.build.json +15 -0
- package/packages/adapters-openai/tsconfig.json +9 -0
- package/packages/adapters-openai/tsup.config.ts +8 -0
- package/packages/adapters-pino/README.md +152 -0
- package/packages/adapters-pino/eslint.config.js +27 -0
- package/packages/adapters-pino/package.json +49 -0
- package/packages/adapters-pino/src/index.test.ts +44 -0
- package/packages/adapters-pino/src/index.ts +322 -0
- package/packages/adapters-pino/src/log-ring-buffer.ts +142 -0
- package/packages/adapters-pino/src/manifest.ts +49 -0
- package/packages/adapters-pino/tsconfig.build.json +15 -0
- package/packages/adapters-pino/tsconfig.json +9 -0
- package/packages/adapters-pino/tsup.config.ts +9 -0
- package/packages/adapters-pino-http/README.md +141 -0
- package/packages/adapters-pino-http/eslint.config.js +27 -0
- package/packages/adapters-pino-http/package.json +46 -0
- package/packages/adapters-pino-http/src/index.ts +229 -0
- package/packages/adapters-pino-http/tsconfig.build.json +15 -0
- package/packages/adapters-pino-http/tsconfig.json +9 -0
- package/packages/adapters-pino-http/tsup.config.ts +9 -0
- package/packages/adapters-qdrant/README.md +166 -0
- package/packages/adapters-qdrant/eslint.config.js +27 -0
- package/packages/adapters-qdrant/package.json +49 -0
- package/packages/adapters-qdrant/src/index.ts +490 -0
- package/packages/adapters-qdrant/src/manifest.ts +54 -0
- package/packages/adapters-qdrant/src/retry.ts +204 -0
- package/packages/adapters-qdrant/tsconfig.build.json +15 -0
- package/packages/adapters-qdrant/tsconfig.json +9 -0
- package/packages/adapters-qdrant/tsup.config.ts +9 -0
- package/packages/adapters-redis/README.md +159 -0
- package/packages/adapters-redis/eslint.config.js +27 -0
- package/packages/adapters-redis/package.json +49 -0
- package/packages/adapters-redis/src/index.ts +164 -0
- package/packages/adapters-redis/src/manifest.ts +49 -0
- package/packages/adapters-redis/tsconfig.build.json +15 -0
- package/packages/adapters-redis/tsconfig.json +9 -0
- package/packages/adapters-redis/tsup.config.ts +9 -0
- package/packages/adapters-snapshot-localfs/README.md +10 -0
- package/packages/adapters-snapshot-localfs/eslint.config.js +2 -0
- package/packages/adapters-snapshot-localfs/package.json +46 -0
- package/packages/adapters-snapshot-localfs/src/index.test.ts +40 -0
- package/packages/adapters-snapshot-localfs/src/index.ts +292 -0
- package/packages/adapters-snapshot-localfs/src/manifest.ts +32 -0
- package/packages/adapters-snapshot-localfs/tsconfig.build.json +15 -0
- package/packages/adapters-snapshot-localfs/tsconfig.json +16 -0
- package/packages/adapters-snapshot-localfs/tsup.config.ts +11 -0
- package/packages/adapters-sqlite/README.md +163 -0
- package/packages/adapters-sqlite/eslint.config.js +27 -0
- package/packages/adapters-sqlite/package.json +54 -0
- package/packages/adapters-sqlite/src/index.test.ts +245 -0
- package/packages/adapters-sqlite/src/index.ts +382 -0
- package/packages/adapters-sqlite/src/manifest.ts +47 -0
- package/packages/adapters-sqlite/src/secure-sql.test.ts +290 -0
- package/packages/adapters-sqlite/src/secure-sql.ts +281 -0
- package/packages/adapters-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-sqlite/tsconfig.json +9 -0
- package/packages/adapters-sqlite/tsup.config.ts +8 -0
- package/packages/adapters-sqlite/vitest.config.ts +19 -0
- package/packages/adapters-transport/README.md +170 -0
- package/packages/adapters-transport/eslint.config.js +27 -0
- package/packages/adapters-transport/package.json +49 -0
- package/packages/adapters-transport/src/__tests__/unix-socket-server.test.ts +550 -0
- package/packages/adapters-transport/src/index.ts +101 -0
- package/packages/adapters-transport/src/ipc-transport.ts +228 -0
- package/packages/adapters-transport/src/transport.ts +224 -0
- package/packages/adapters-transport/src/types.ts +92 -0
- package/packages/adapters-transport/src/unix-socket-server.ts +193 -0
- package/packages/adapters-transport/src/unix-socket-transport.ts +280 -0
- package/packages/adapters-transport/tsconfig.build.json +15 -0
- package/packages/adapters-transport/tsconfig.json +9 -0
- package/packages/adapters-transport/tsup.config.ts +9 -0
- package/packages/adapters-vibeproxy/README.md +159 -0
- package/packages/adapters-vibeproxy/eslint.config.js +27 -0
- package/packages/adapters-vibeproxy/package.json +51 -0
- package/packages/adapters-vibeproxy/src/index.ts +13 -0
- package/packages/adapters-vibeproxy/src/llm.ts +437 -0
- package/packages/adapters-vibeproxy/src/manifest.ts +51 -0
- package/packages/adapters-vibeproxy/tsconfig.build.json +15 -0
- package/packages/adapters-vibeproxy/tsconfig.json +9 -0
- package/packages/adapters-vibeproxy/tsup.config.ts +8 -0
- package/packages/adapters-workspace-agent/package.json +46 -0
- package/packages/adapters-workspace-agent/src/__tests__/adapter.test.ts +212 -0
- package/packages/adapters-workspace-agent/src/index.ts +220 -0
- package/packages/adapters-workspace-agent/src/manifest.ts +36 -0
- package/packages/adapters-workspace-agent/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-agent/tsconfig.json +16 -0
- package/packages/adapters-workspace-agent/tsup.config.ts +11 -0
- package/packages/adapters-workspace-localfs/README.md +9 -0
- package/packages/adapters-workspace-localfs/eslint.config.js +2 -0
- package/packages/adapters-workspace-localfs/package.json +46 -0
- package/packages/adapters-workspace-localfs/src/index.test.ts +27 -0
- package/packages/adapters-workspace-localfs/src/index.ts +172 -0
- package/packages/adapters-workspace-localfs/src/manifest.ts +32 -0
- package/packages/adapters-workspace-localfs/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-localfs/tsconfig.json +16 -0
- package/packages/adapters-workspace-localfs/tsup.config.ts +11 -0
- package/packages/adapters-workspace-worktree/README.md +9 -0
- package/packages/adapters-workspace-worktree/eslint.config.js +2 -0
- package/packages/adapters-workspace-worktree/package.json +46 -0
- package/packages/adapters-workspace-worktree/src/index.test.ts +38 -0
- package/packages/adapters-workspace-worktree/src/index.ts +245 -0
- package/packages/adapters-workspace-worktree/src/manifest.ts +38 -0
- package/packages/adapters-workspace-worktree/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-worktree/tsconfig.json +16 -0
- package/packages/adapters-workspace-worktree/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +2800 -0
- package/prettierrc.json +1 -0
- package/scripts/devkit-sync.mjs +37 -0
- package/scripts/hooks/post-push +9 -0
- package/scripts/hooks/pre-commit +9 -0
- package/scripts/hooks/pre-push +9 -0
- package/test-integration.ts +242 -0
- package/test.txt +1 -0
- package/tsconfig.base.json +6 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsconfig.paths.json +26 -0
- package/tsconfig.tools.json +17 -0
- package/tsup.config.bin.ts +34 -0
- package/tsup.config.cli.ts +41 -0
- package/tsup.config.dual.ts +46 -0
- package/tsup.config.ts +36 -0
- package/tsup.external.json +103 -0
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for LogRingBufferAdapter
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
6
|
+
import { LogRingBufferAdapter } from "../index";
|
|
7
|
+
import type { LogRecord } from "@kb-labs/core-platform/adapters";
|
|
8
|
+
|
|
9
|
+
describe("LogRingBufferAdapter", () => {
|
|
10
|
+
let buffer: LogRingBufferAdapter;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
buffer = new LogRingBufferAdapter({ maxSize: 5, ttl: 60000 }); // 60s TTL for testing
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("append", () => {
|
|
17
|
+
it("should append logs to buffer", () => {
|
|
18
|
+
const log: LogRecord = {
|
|
19
|
+
id: "test-1",
|
|
20
|
+
timestamp: Date.now(),
|
|
21
|
+
level: "info",
|
|
22
|
+
message: "Test log",
|
|
23
|
+
fields: {},
|
|
24
|
+
source: "test",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
buffer.append(log);
|
|
28
|
+
|
|
29
|
+
const stats = buffer.getStats();
|
|
30
|
+
expect(stats.size).toBe(1);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should evict oldest log when buffer is full", () => {
|
|
34
|
+
// Add 6 logs to a buffer with maxSize 5
|
|
35
|
+
for (let i = 0; i < 6; i++) {
|
|
36
|
+
buffer.append({
|
|
37
|
+
id: `test-${i}`,
|
|
38
|
+
timestamp: Date.now() + i,
|
|
39
|
+
level: "info",
|
|
40
|
+
message: `Log ${i}`,
|
|
41
|
+
fields: {},
|
|
42
|
+
source: "test",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stats = buffer.getStats();
|
|
47
|
+
expect(stats.size).toBe(5); // Only 5 logs fit
|
|
48
|
+
expect(stats.evictions).toBe(1); // 1 log evicted
|
|
49
|
+
|
|
50
|
+
const logs = buffer.query();
|
|
51
|
+
expect(logs[logs.length - 1]!.message).toBe("Log 1"); // Log 0 was evicted
|
|
52
|
+
expect(logs[0]!.message).toBe("Log 5"); // Newest first
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should notify subscribers when log is appended", () => {
|
|
56
|
+
const callback = vi.fn();
|
|
57
|
+
const unsubscribe = buffer.subscribe(callback);
|
|
58
|
+
|
|
59
|
+
const log: LogRecord = {
|
|
60
|
+
id: "test-2",
|
|
61
|
+
timestamp: Date.now(),
|
|
62
|
+
level: "info",
|
|
63
|
+
message: "Test log",
|
|
64
|
+
fields: {},
|
|
65
|
+
source: "test",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
buffer.append(log);
|
|
69
|
+
|
|
70
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
71
|
+
expect(callback).toHaveBeenCalledWith(log);
|
|
72
|
+
|
|
73
|
+
unsubscribe();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should handle subscriber errors gracefully", () => {
|
|
77
|
+
const errorCallback = vi.fn(() => {
|
|
78
|
+
throw new Error("Subscriber error");
|
|
79
|
+
});
|
|
80
|
+
const goodCallback = vi.fn();
|
|
81
|
+
|
|
82
|
+
buffer.subscribe(errorCallback);
|
|
83
|
+
buffer.subscribe(goodCallback);
|
|
84
|
+
|
|
85
|
+
const log: LogRecord = {
|
|
86
|
+
id: "test-3",
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
level: "info",
|
|
89
|
+
message: "Test log",
|
|
90
|
+
fields: {},
|
|
91
|
+
source: "test",
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Should not throw
|
|
95
|
+
expect(() => buffer.append(log)).not.toThrow();
|
|
96
|
+
|
|
97
|
+
// Good callback should still be called
|
|
98
|
+
expect(goodCallback).toHaveBeenCalledTimes(1);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("query", () => {
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
// Add test logs (use current time to avoid TTL eviction)
|
|
107
|
+
buffer.append({
|
|
108
|
+
id: "test-query-1",
|
|
109
|
+
timestamp: now - 4000,
|
|
110
|
+
level: "debug",
|
|
111
|
+
message: "Debug log",
|
|
112
|
+
fields: {},
|
|
113
|
+
source: "test",
|
|
114
|
+
});
|
|
115
|
+
buffer.append({
|
|
116
|
+
id: "test-query-2",
|
|
117
|
+
timestamp: now - 3000,
|
|
118
|
+
level: "info",
|
|
119
|
+
message: "Info log",
|
|
120
|
+
fields: {},
|
|
121
|
+
source: "test",
|
|
122
|
+
});
|
|
123
|
+
buffer.append({
|
|
124
|
+
id: "test-query-3",
|
|
125
|
+
timestamp: now - 2000,
|
|
126
|
+
level: "warn",
|
|
127
|
+
message: "Warn log",
|
|
128
|
+
fields: {},
|
|
129
|
+
source: "test",
|
|
130
|
+
});
|
|
131
|
+
buffer.append({
|
|
132
|
+
id: "test-query-4",
|
|
133
|
+
timestamp: now - 1000,
|
|
134
|
+
level: "error",
|
|
135
|
+
message: "Error log",
|
|
136
|
+
fields: {},
|
|
137
|
+
source: "api",
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should return all logs without filters", () => {
|
|
142
|
+
const logs = buffer.query();
|
|
143
|
+
expect(logs).toHaveLength(4);
|
|
144
|
+
expect(logs[0]!.timestamp).toBe(now - 1000); // Newest first
|
|
145
|
+
expect(logs[3]!.timestamp).toBe(now - 4000); // Oldest last
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("should filter by level", () => {
|
|
149
|
+
const logs = buffer.query({ level: "error" });
|
|
150
|
+
expect(logs).toHaveLength(1);
|
|
151
|
+
expect(logs[0]!.level).toBe("error");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should filter by source", () => {
|
|
155
|
+
const logs = buffer.query({ source: "api" });
|
|
156
|
+
expect(logs).toHaveLength(1);
|
|
157
|
+
expect(logs[0]!.source).toBe("api");
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it("should filter by timestamp range", () => {
|
|
161
|
+
const logs = buffer.query({ from: now - 3000, to: now - 2000 });
|
|
162
|
+
expect(logs).toHaveLength(2);
|
|
163
|
+
expect(logs[0]!.timestamp).toBe(now - 2000);
|
|
164
|
+
expect(logs[1]!.timestamp).toBe(now - 3000);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should apply limit", () => {
|
|
168
|
+
const logs = buffer.query({ limit: 2 });
|
|
169
|
+
expect(logs).toHaveLength(2);
|
|
170
|
+
expect(logs[0]!.timestamp).toBe(now - 1000); // Newest
|
|
171
|
+
expect(logs[1]!.timestamp).toBe(now - 2000);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should combine multiple filters", () => {
|
|
175
|
+
const logs = buffer.query({
|
|
176
|
+
level: "info",
|
|
177
|
+
source: "test",
|
|
178
|
+
from: now - 3500,
|
|
179
|
+
});
|
|
180
|
+
expect(logs).toHaveLength(1);
|
|
181
|
+
expect(logs[0]!.level).toBe("info");
|
|
182
|
+
expect(logs[0]!.source).toBe("test");
|
|
183
|
+
expect(logs[0]!.timestamp).toBeGreaterThanOrEqual(now - 3500);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("subscribe", () => {
|
|
188
|
+
it("should allow multiple subscribers", () => {
|
|
189
|
+
const callback1 = vi.fn();
|
|
190
|
+
const callback2 = vi.fn();
|
|
191
|
+
|
|
192
|
+
buffer.subscribe(callback1);
|
|
193
|
+
buffer.subscribe(callback2);
|
|
194
|
+
|
|
195
|
+
const log: LogRecord = {
|
|
196
|
+
id: "test-4",
|
|
197
|
+
timestamp: Date.now(),
|
|
198
|
+
level: "info",
|
|
199
|
+
message: "Test log",
|
|
200
|
+
fields: {},
|
|
201
|
+
source: "test",
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
buffer.append(log);
|
|
205
|
+
|
|
206
|
+
expect(callback1).toHaveBeenCalledTimes(1);
|
|
207
|
+
expect(callback2).toHaveBeenCalledTimes(1);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should unsubscribe correctly", () => {
|
|
211
|
+
const callback = vi.fn();
|
|
212
|
+
const unsubscribe = buffer.subscribe(callback);
|
|
213
|
+
|
|
214
|
+
const log: LogRecord = {
|
|
215
|
+
id: "test-5",
|
|
216
|
+
timestamp: Date.now(),
|
|
217
|
+
level: "info",
|
|
218
|
+
message: "Test log 1",
|
|
219
|
+
fields: {},
|
|
220
|
+
source: "test",
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
buffer.append(log);
|
|
224
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
225
|
+
|
|
226
|
+
// Unsubscribe
|
|
227
|
+
unsubscribe();
|
|
228
|
+
|
|
229
|
+
const log2: LogRecord = {
|
|
230
|
+
id: "test-6",
|
|
231
|
+
timestamp: Date.now(),
|
|
232
|
+
level: "info",
|
|
233
|
+
message: "Test log 2",
|
|
234
|
+
fields: {},
|
|
235
|
+
source: "test",
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
buffer.append(log2);
|
|
239
|
+
expect(callback).toHaveBeenCalledTimes(1); // Still 1, not called again
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe("getStats", () => {
|
|
244
|
+
it("should return correct stats", () => {
|
|
245
|
+
const now = Date.now();
|
|
246
|
+
const log1: LogRecord = {
|
|
247
|
+
id: "test-7",
|
|
248
|
+
timestamp: now - 1000,
|
|
249
|
+
level: "info",
|
|
250
|
+
message: "Log 1",
|
|
251
|
+
fields: {},
|
|
252
|
+
source: "test",
|
|
253
|
+
};
|
|
254
|
+
const log2: LogRecord = {
|
|
255
|
+
id: "test-8",
|
|
256
|
+
timestamp: now,
|
|
257
|
+
level: "info",
|
|
258
|
+
message: "Log 2",
|
|
259
|
+
fields: {},
|
|
260
|
+
source: "test",
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
buffer.append(log1);
|
|
264
|
+
buffer.append(log2);
|
|
265
|
+
|
|
266
|
+
const stats = buffer.getStats();
|
|
267
|
+
expect(stats.size).toBe(2);
|
|
268
|
+
expect(stats.maxSize).toBe(5);
|
|
269
|
+
expect(stats.oldestTimestamp).toBe(now - 1000);
|
|
270
|
+
expect(stats.newestTimestamp).toBe(now);
|
|
271
|
+
expect(stats.evictions).toBe(0);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it("should return zeros for empty buffer", () => {
|
|
275
|
+
const stats = buffer.getStats();
|
|
276
|
+
expect(stats.size).toBe(0);
|
|
277
|
+
expect(stats.maxSize).toBe(5);
|
|
278
|
+
expect(stats.oldestTimestamp).toBe(0);
|
|
279
|
+
expect(stats.newestTimestamp).toBe(0);
|
|
280
|
+
expect(stats.evictions).toBe(0);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("clear", () => {
|
|
285
|
+
it("should clear all logs", () => {
|
|
286
|
+
buffer.append({
|
|
287
|
+
id: "test-9",
|
|
288
|
+
timestamp: Date.now(),
|
|
289
|
+
level: "info",
|
|
290
|
+
message: "Test log",
|
|
291
|
+
fields: {},
|
|
292
|
+
source: "test",
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
expect(buffer.getStats().size).toBe(1);
|
|
296
|
+
|
|
297
|
+
buffer.clear();
|
|
298
|
+
|
|
299
|
+
const stats = buffer.getStats();
|
|
300
|
+
expect(stats.size).toBe(0);
|
|
301
|
+
expect(stats.evictions).toBe(0);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
describe("TTL eviction", () => {
|
|
306
|
+
it("should evict expired logs based on TTL", async () => {
|
|
307
|
+
const shortTtlBuffer = new LogRingBufferAdapter({
|
|
308
|
+
maxSize: 10,
|
|
309
|
+
ttl: 100,
|
|
310
|
+
}); // 100ms TTL
|
|
311
|
+
|
|
312
|
+
// Add old log
|
|
313
|
+
shortTtlBuffer.append({
|
|
314
|
+
id: "test-ttl-1",
|
|
315
|
+
timestamp: Date.now() - 200, // Expired
|
|
316
|
+
level: "info",
|
|
317
|
+
message: "Old log",
|
|
318
|
+
fields: {},
|
|
319
|
+
source: "test",
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Add new log
|
|
323
|
+
shortTtlBuffer.append({
|
|
324
|
+
id: "test-ttl-2",
|
|
325
|
+
timestamp: Date.now(),
|
|
326
|
+
level: "info",
|
|
327
|
+
message: "New log",
|
|
328
|
+
fields: {},
|
|
329
|
+
source: "test",
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Query should trigger eviction
|
|
333
|
+
const logs = shortTtlBuffer.query();
|
|
334
|
+
expect(logs).toHaveLength(1);
|
|
335
|
+
expect(logs[0]!.message).toBe("New log");
|
|
336
|
+
|
|
337
|
+
const stats = shortTtlBuffer.getStats();
|
|
338
|
+
expect(stats.size).toBe(1);
|
|
339
|
+
expect(stats.evictions).toBe(1); // Old log evicted
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it("should evict multiple expired logs", () => {
|
|
343
|
+
const now = Date.now();
|
|
344
|
+
const ttl = 1000;
|
|
345
|
+
const shortTtlBuffer = new LogRingBufferAdapter({ maxSize: 10, ttl });
|
|
346
|
+
|
|
347
|
+
// Add 3 expired logs
|
|
348
|
+
for (let i = 0; i < 3; i++) {
|
|
349
|
+
shortTtlBuffer.append({
|
|
350
|
+
id: `test-ttl-old-${i}`,
|
|
351
|
+
timestamp: now - ttl - 100, // Expired
|
|
352
|
+
level: "info",
|
|
353
|
+
message: `Old log ${i}`,
|
|
354
|
+
fields: {},
|
|
355
|
+
source: "test",
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Add 2 fresh logs
|
|
360
|
+
for (let i = 0; i < 2; i++) {
|
|
361
|
+
shortTtlBuffer.append({
|
|
362
|
+
id: `test-ttl-new-${i}`,
|
|
363
|
+
timestamp: now,
|
|
364
|
+
level: "info",
|
|
365
|
+
message: `New log ${i}`,
|
|
366
|
+
fields: {},
|
|
367
|
+
source: "test",
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const logs = shortTtlBuffer.query();
|
|
372
|
+
expect(logs).toHaveLength(2);
|
|
373
|
+
expect(logs.every((l) => l.message.startsWith("New log"))).toBe(true);
|
|
374
|
+
|
|
375
|
+
const stats = shortTtlBuffer.getStats();
|
|
376
|
+
expect(stats.evictions).toBe(3);
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
describe("edge cases", () => {
|
|
381
|
+
it("should handle zero maxSize", () => {
|
|
382
|
+
const zeroBuffer = new LogRingBufferAdapter({ maxSize: 0 });
|
|
383
|
+
|
|
384
|
+
zeroBuffer.append({
|
|
385
|
+
id: "test-10",
|
|
386
|
+
timestamp: Date.now(),
|
|
387
|
+
level: "info",
|
|
388
|
+
message: "Test log",
|
|
389
|
+
fields: {},
|
|
390
|
+
source: "test",
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const stats = zeroBuffer.getStats();
|
|
394
|
+
expect(stats.size).toBe(0); // Nothing stored
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("should handle negative timestamps", () => {
|
|
398
|
+
const now = Date.now();
|
|
399
|
+
// Use timestamp that won't be evicted by TTL (recent past)
|
|
400
|
+
const negativeTimestamp = now - 1000;
|
|
401
|
+
|
|
402
|
+
buffer.append({
|
|
403
|
+
id: "test-11",
|
|
404
|
+
timestamp: negativeTimestamp,
|
|
405
|
+
level: "info",
|
|
406
|
+
message: "Timestamp test",
|
|
407
|
+
fields: {},
|
|
408
|
+
source: "test",
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
const logs = buffer.query();
|
|
412
|
+
expect(logs).toHaveLength(1);
|
|
413
|
+
expect(logs[0]!.timestamp).toBe(negativeTimestamp);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("should handle empty fields", () => {
|
|
417
|
+
buffer.append({
|
|
418
|
+
id: "test-12",
|
|
419
|
+
timestamp: Date.now(),
|
|
420
|
+
level: "info",
|
|
421
|
+
message: "No fields",
|
|
422
|
+
fields: {},
|
|
423
|
+
source: "test",
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
const logs = buffer.query();
|
|
427
|
+
expect(logs[0]!.fields).toEqual({});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("should handle complex fields", () => {
|
|
431
|
+
const complexFields = {
|
|
432
|
+
user: { id: 123, name: "Alice" },
|
|
433
|
+
tags: ["api", "error"],
|
|
434
|
+
count: 42,
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
buffer.append({
|
|
438
|
+
id: "test-13",
|
|
439
|
+
timestamp: Date.now(),
|
|
440
|
+
level: "info",
|
|
441
|
+
message: "Complex fields",
|
|
442
|
+
fields: complexFields,
|
|
443
|
+
source: "test",
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
const logs = buffer.query();
|
|
447
|
+
expect(logs[0]!.fields).toEqual(complexFields);
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
});
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-log-ringbuffer
|
|
3
|
+
* In-memory ring buffer adapter for real-time log streaming.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Fixed-size circular buffer (default 1000 logs)
|
|
7
|
+
* - Time-to-live expiration (default 1 hour)
|
|
8
|
+
* - Real-time subscription support
|
|
9
|
+
* - Automatic eviction of oldest logs
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { createAdapter } from '@kb-labs/adapters-log-ringbuffer';
|
|
14
|
+
*
|
|
15
|
+
* const buffer = createAdapter({
|
|
16
|
+
* maxSize: 1000,
|
|
17
|
+
* ttl: 3600000, // 1 hour
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Append logs
|
|
21
|
+
* buffer.append({
|
|
22
|
+
* timestamp: Date.now(),
|
|
23
|
+
* level: 'info',
|
|
24
|
+
* message: 'Server started',
|
|
25
|
+
* fields: {},
|
|
26
|
+
* source: 'rest-api',
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Subscribe to real-time stream
|
|
30
|
+
* const unsubscribe = buffer.subscribe((log) => {
|
|
31
|
+
* console.log('New log:', log);
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Query logs
|
|
35
|
+
* const recentErrors = buffer.query({ level: 'error' });
|
|
36
|
+
* console.log(recentErrors);
|
|
37
|
+
*
|
|
38
|
+
* // Clean up
|
|
39
|
+
* unsubscribe();
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import type {
|
|
44
|
+
ILogRingBuffer,
|
|
45
|
+
LogRingBufferConfig,
|
|
46
|
+
LogRecord,
|
|
47
|
+
LogQuery,
|
|
48
|
+
} from "@kb-labs/core-platform/adapters";
|
|
49
|
+
|
|
50
|
+
// Re-export manifest
|
|
51
|
+
export { manifest } from "./manifest.js";
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* In-memory ring buffer for log streaming.
|
|
55
|
+
*
|
|
56
|
+
* Implementation details:
|
|
57
|
+
* - Uses circular array for O(1) append
|
|
58
|
+
* - Lazy TTL eviction (on query/append)
|
|
59
|
+
* - No locks needed (single-threaded Node.js)
|
|
60
|
+
* - Memory-bounded by maxSize
|
|
61
|
+
*/
|
|
62
|
+
export class LogRingBufferAdapter implements ILogRingBuffer {
|
|
63
|
+
private buffer: LogRecord[] = [];
|
|
64
|
+
private maxSize: number;
|
|
65
|
+
private ttl: number;
|
|
66
|
+
private subscribers: Set<(record: LogRecord) => void> = new Set();
|
|
67
|
+
private evictions = 0;
|
|
68
|
+
|
|
69
|
+
constructor(config: LogRingBufferConfig = {}) {
|
|
70
|
+
this.maxSize = config.maxSize ?? 1000;
|
|
71
|
+
this.ttl = config.ttl ?? 3600000; // 1 hour
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Append log record to buffer.
|
|
76
|
+
* Evicts oldest log if buffer is full.
|
|
77
|
+
*/
|
|
78
|
+
append(record: LogRecord): void {
|
|
79
|
+
// Remove expired logs before adding new one
|
|
80
|
+
this.evictExpired();
|
|
81
|
+
|
|
82
|
+
// Add new log
|
|
83
|
+
this.buffer.push(record);
|
|
84
|
+
|
|
85
|
+
// Evict oldest if buffer is full
|
|
86
|
+
if (this.buffer.length > this.maxSize) {
|
|
87
|
+
this.buffer.shift();
|
|
88
|
+
this.evictions++;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Notify subscribers (real-time streaming)
|
|
92
|
+
this.notifySubscribers(record);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Query logs from buffer with optional filters.
|
|
97
|
+
* Returns logs in reverse chronological order (newest first).
|
|
98
|
+
*/
|
|
99
|
+
query(query?: LogQuery): LogRecord[] {
|
|
100
|
+
// Remove expired logs before querying
|
|
101
|
+
this.evictExpired();
|
|
102
|
+
|
|
103
|
+
let results = [...this.buffer];
|
|
104
|
+
|
|
105
|
+
// Apply filters
|
|
106
|
+
if (query?.level) {
|
|
107
|
+
results = results.filter((r) => r.level === query.level);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (query?.from !== undefined) {
|
|
111
|
+
results = results.filter((r) => r.timestamp >= query.from!);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (query?.to !== undefined) {
|
|
115
|
+
results = results.filter((r) => r.timestamp <= query.to!);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (query?.source) {
|
|
119
|
+
results = results.filter((r) => r.source === query.source);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Apply limit
|
|
123
|
+
if (query?.limit !== undefined && query.limit > 0) {
|
|
124
|
+
results = results.slice(-query.limit);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Return newest first
|
|
128
|
+
return results.reverse();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Subscribe to real-time log events.
|
|
133
|
+
* Callback is invoked synchronously for each new log.
|
|
134
|
+
*/
|
|
135
|
+
subscribe(callback: (record: LogRecord) => void): () => void {
|
|
136
|
+
this.subscribers.add(callback);
|
|
137
|
+
return () => this.subscribers.delete(callback);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get buffer statistics.
|
|
142
|
+
*/
|
|
143
|
+
getStats() {
|
|
144
|
+
this.evictExpired();
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
size: this.buffer.length,
|
|
148
|
+
maxSize: this.maxSize,
|
|
149
|
+
oldestTimestamp: this.buffer[0]?.timestamp ?? 0,
|
|
150
|
+
newestTimestamp: this.buffer[this.buffer.length - 1]?.timestamp ?? 0,
|
|
151
|
+
evictions: this.evictions,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Clear all logs from buffer.
|
|
157
|
+
* Useful for testing or manual cleanup.
|
|
158
|
+
*/
|
|
159
|
+
clear(): void {
|
|
160
|
+
this.buffer = [];
|
|
161
|
+
this.evictions = 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Evict expired logs based on TTL.
|
|
166
|
+
* Called lazily on append/query operations.
|
|
167
|
+
*/
|
|
168
|
+
private evictExpired(): void {
|
|
169
|
+
if (this.buffer.length === 0) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const now = Date.now();
|
|
174
|
+
const cutoff = now - this.ttl;
|
|
175
|
+
|
|
176
|
+
// Remove logs older than TTL from beginning of buffer
|
|
177
|
+
while (this.buffer.length > 0 && this.buffer[0]!.timestamp < cutoff) {
|
|
178
|
+
this.buffer.shift();
|
|
179
|
+
this.evictions++;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Notify all subscribers about new log.
|
|
185
|
+
*/
|
|
186
|
+
private notifySubscribers(record: LogRecord): void {
|
|
187
|
+
this.subscribers.forEach((callback) => {
|
|
188
|
+
try {
|
|
189
|
+
callback(record);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// Don't let subscriber errors crash the buffer
|
|
192
|
+
console.error("Error in log buffer subscriber:", error);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Factory function for creating ring buffer adapter.
|
|
200
|
+
* This is the function called by platform initialization.
|
|
201
|
+
*
|
|
202
|
+
* @param config - Ring buffer configuration
|
|
203
|
+
* @returns Ring buffer adapter instance
|
|
204
|
+
*/
|
|
205
|
+
export function createAdapter(
|
|
206
|
+
config?: LogRingBufferConfig,
|
|
207
|
+
): LogRingBufferAdapter {
|
|
208
|
+
return new LogRingBufferAdapter(config);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Default export for convenience
|
|
212
|
+
export default createAdapter;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-log-ringbuffer/manifest
|
|
3
|
+
* Adapter manifest for log ring buffer extension.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AdapterManifest } from "@kb-labs/core-platform";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Adapter manifest for log ring buffer extension.
|
|
10
|
+
*/
|
|
11
|
+
export const manifest: AdapterManifest = {
|
|
12
|
+
manifestVersion: "1.0.0",
|
|
13
|
+
id: "log-ringbuffer",
|
|
14
|
+
name: "Log Ring Buffer",
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
description: "In-memory ring buffer for real-time log streaming",
|
|
17
|
+
author: "KB Labs Team",
|
|
18
|
+
license: "KBPL-1.1",
|
|
19
|
+
type: "extension",
|
|
20
|
+
implements: "ILogRingBuffer",
|
|
21
|
+
extends: {
|
|
22
|
+
adapter: "logger",
|
|
23
|
+
hook: "onLog",
|
|
24
|
+
method: "append",
|
|
25
|
+
priority: 10,
|
|
26
|
+
},
|
|
27
|
+
capabilities: {
|
|
28
|
+
streaming: true,
|
|
29
|
+
},
|
|
30
|
+
};
|