@nextdog/core 0.1.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/LICENSE +21 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +50 -0
- package/dist/cli.js.map +1 -0
- package/dist/event-bus.d.ts +10 -0
- package/dist/event-bus.d.ts.map +1 -0
- package/dist/event-bus.js +13 -0
- package/dist/event-bus.js.map +1 -0
- package/dist/file-store.d.ts +14 -0
- package/dist/file-store.d.ts.map +1 -0
- package/dist/file-store.js +74 -0
- package/dist/file-store.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/ring-buffer.d.ts +14 -0
- package/dist/ring-buffer.d.ts.map +1 -0
- package/dist/ring-buffer.js +39 -0
- package/dist/ring-buffer.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +193 -0
- package/dist/server.js.map +1 -0
- package/dist/sse-stream.d.ts +13 -0
- package/dist/sse-stream.d.ts.map +1 -0
- package/dist/sse-stream.js +38 -0
- package/dist/sse-stream.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christopher Scherban
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createServer } from './server.js';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join, dirname } from 'node:path';
|
|
4
|
+
import { stat } from 'node:fs/promises';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
const DEFAULT_PORT = 6789;
|
|
7
|
+
const DEFAULT_DATA_DIR = join(homedir(), '.nextdog', 'data');
|
|
8
|
+
async function resolveUiDir() {
|
|
9
|
+
try {
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const uiPkgPath = require.resolve('@nextdog/ui/package.json');
|
|
12
|
+
const uiDir = join(dirname(uiPkgPath), 'dist');
|
|
13
|
+
const s = await stat(uiDir);
|
|
14
|
+
if (s.isDirectory())
|
|
15
|
+
return uiDir;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// UI package not installed or not built
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
async function main() {
|
|
23
|
+
const url = process.env.NEXTDOG_URL ?? `http://localhost:${DEFAULT_PORT}`;
|
|
24
|
+
const parsed = new URL(url);
|
|
25
|
+
const port = Number(parsed.port) || DEFAULT_PORT;
|
|
26
|
+
const host = parsed.hostname;
|
|
27
|
+
const dataDir = process.env.NEXTDOG_DATA_DIR ?? DEFAULT_DATA_DIR;
|
|
28
|
+
const uiDir = process.env.NEXTDOG_UI_DIR ?? await resolveUiDir();
|
|
29
|
+
const server = await createServer({ port, host, dataDir, uiDir });
|
|
30
|
+
console.log(`[nextdog] sidecar running at http://${host}:${port}`);
|
|
31
|
+
console.log(`[nextdog] data dir: ${dataDir}`);
|
|
32
|
+
if (uiDir) {
|
|
33
|
+
console.log(`[nextdog] UI served from: ${uiDir}`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.log(`[nextdog] UI not available (run pnpm build in @nextdog/ui)`);
|
|
37
|
+
}
|
|
38
|
+
process.on('SIGINT', () => {
|
|
39
|
+
console.log('\n[nextdog] shutting down...');
|
|
40
|
+
server.close(() => process.exit(0));
|
|
41
|
+
});
|
|
42
|
+
process.on('SIGTERM', () => {
|
|
43
|
+
server.close(() => process.exit(0));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
main().catch(err => {
|
|
47
|
+
console.error('[nextdog] failed to start:', err);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AAE7D,KAAK,UAAU,YAAY;IACzB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,KAAK,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,oBAAoB,YAAY,EAAE,CAAC;IAC1E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC;IACjD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,gBAAgB,CAAC;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,YAAY,EAAE,CAAC;IAEjE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;IAC9C,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NextDogEvent } from './types.js';
|
|
2
|
+
type EventType = NextDogEvent['type'] | '*';
|
|
3
|
+
type EventHandler = (event: NextDogEvent) => void;
|
|
4
|
+
export declare class EventBus {
|
|
5
|
+
private emitter;
|
|
6
|
+
on(type: EventType, handler: EventHandler): () => void;
|
|
7
|
+
emit(event: NextDogEvent): void;
|
|
8
|
+
}
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=event-bus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,KAAK,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC;AAC5C,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;AAElD,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAsB;IAErC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAKtD,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;CAIhC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
export class EventBus {
|
|
3
|
+
emitter = new EventEmitter();
|
|
4
|
+
on(type, handler) {
|
|
5
|
+
this.emitter.on(type, handler);
|
|
6
|
+
return () => this.emitter.off(type, handler);
|
|
7
|
+
}
|
|
8
|
+
emit(event) {
|
|
9
|
+
this.emitter.emit(event.type, event);
|
|
10
|
+
this.emitter.emit('*', event);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C,MAAM,OAAO,QAAQ;IACX,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;IAErC,EAAE,CAAC,IAAe,EAAE,OAAqB;QACvC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,CAAC,KAAmB;QACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NextDogEvent } from './types.js';
|
|
2
|
+
export interface QueryOptions {
|
|
3
|
+
service?: string;
|
|
4
|
+
traceId?: string;
|
|
5
|
+
last?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class FileStore {
|
|
8
|
+
private dir;
|
|
9
|
+
constructor(dir: string);
|
|
10
|
+
flush(events: NextDogEvent[]): Promise<void>;
|
|
11
|
+
query(opts: QueryOptions): Promise<NextDogEvent[]>;
|
|
12
|
+
cleanup(maxAgeMs: number): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=file-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAyB/C,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,SAAS;IACR,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,MAAM;IAEzB,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAwBlD,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB/C"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { appendFile, readdir, readFile, unlink, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
function hourlyFilename(date = new Date()) {
|
|
4
|
+
const y = date.getFullYear();
|
|
5
|
+
const m = String(date.getMonth() + 1).padStart(2, '0');
|
|
6
|
+
const d = String(date.getDate()).padStart(2, '0');
|
|
7
|
+
const h = String(date.getHours()).padStart(2, '0');
|
|
8
|
+
return `${y}-${m}-${d}-${h}.ndjson`;
|
|
9
|
+
}
|
|
10
|
+
function serialize(event) {
|
|
11
|
+
return JSON.stringify(event, (_key, value) => typeof value === 'bigint' ? value.toString() + 'n' : value);
|
|
12
|
+
}
|
|
13
|
+
function deserialize(line) {
|
|
14
|
+
return JSON.parse(line, (_key, value) => {
|
|
15
|
+
if (typeof value === 'string' && /^\d+n$/.test(value)) {
|
|
16
|
+
return BigInt(value.slice(0, -1));
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export class FileStore {
|
|
22
|
+
dir;
|
|
23
|
+
constructor(dir) {
|
|
24
|
+
this.dir = dir;
|
|
25
|
+
}
|
|
26
|
+
async flush(events) {
|
|
27
|
+
if (events.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
await mkdir(this.dir, { recursive: true });
|
|
30
|
+
const filename = hourlyFilename();
|
|
31
|
+
const lines = events.map(e => serialize(e)).join('\n') + '\n';
|
|
32
|
+
await appendFile(join(this.dir, filename), lines, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
async query(opts) {
|
|
35
|
+
await mkdir(this.dir, { recursive: true });
|
|
36
|
+
const files = (await readdir(this.dir))
|
|
37
|
+
.filter(f => f.endsWith('.ndjson'))
|
|
38
|
+
.sort();
|
|
39
|
+
const results = [];
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
const content = await readFile(join(this.dir, file), 'utf-8');
|
|
42
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
43
|
+
for (const line of lines) {
|
|
44
|
+
const event = deserialize(line);
|
|
45
|
+
if (opts.service && event.data.serviceName !== opts.service)
|
|
46
|
+
continue;
|
|
47
|
+
if (opts.traceId && ('traceId' in event.data) && event.data.traceId !== opts.traceId)
|
|
48
|
+
continue;
|
|
49
|
+
results.push(event);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (opts.last)
|
|
53
|
+
return results.slice(-opts.last);
|
|
54
|
+
return results;
|
|
55
|
+
}
|
|
56
|
+
async cleanup(maxAgeMs) {
|
|
57
|
+
await mkdir(this.dir, { recursive: true });
|
|
58
|
+
const files = await readdir(this.dir);
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
if (!file.endsWith('.ndjson'))
|
|
62
|
+
continue;
|
|
63
|
+
// Parse date from filename: YYYY-MM-DD-HH.ndjson
|
|
64
|
+
const match = file.match(/^(\d{4})-(\d{2})-(\d{2})-(\d{2})\.ndjson$/);
|
|
65
|
+
if (!match)
|
|
66
|
+
continue;
|
|
67
|
+
const fileDate = new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]), Number(match[4]));
|
|
68
|
+
if (now - fileDate.getTime() > maxAgeMs) {
|
|
69
|
+
await unlink(join(this.dir, file));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=file-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { EventBus } from './event-bus.js';
|
|
2
|
+
export { RingBuffer } from './ring-buffer.js';
|
|
3
|
+
export { FileStore } from './file-store.js';
|
|
4
|
+
export { SSEStream } from './sse-stream.js';
|
|
5
|
+
export { createServer } from './server.js';
|
|
6
|
+
export type { Span, LogEntry, NextDogEvent } from './types.js';
|
|
7
|
+
export type { QueryOptions } from './file-store.js';
|
|
8
|
+
export type { ServerOptions } from './server.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NextDogEvent } from './types.js';
|
|
2
|
+
export declare class RingBuffer {
|
|
3
|
+
private capacity;
|
|
4
|
+
private buffer;
|
|
5
|
+
private head;
|
|
6
|
+
private count;
|
|
7
|
+
private pending;
|
|
8
|
+
constructor(capacity: number);
|
|
9
|
+
push(event: NextDogEvent): void;
|
|
10
|
+
getAll(): NextDogEvent[];
|
|
11
|
+
getLast(n: number): NextDogEvent[];
|
|
12
|
+
drain(): NextDogEvent[];
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=ring-buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ring-buffer.d.ts","sourceRoot":"","sources":["../src/ring-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,qBAAa,UAAU;IAMT,OAAO,CAAC,QAAQ;IAL5B,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,OAAO,CAAsB;gBAEjB,QAAQ,EAAE,MAAM;IAIpC,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAO/B,MAAM,IAAI,YAAY,EAAE;IAWxB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAKlC,KAAK,IAAI,YAAY,EAAE;CAKxB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class RingBuffer {
|
|
2
|
+
capacity;
|
|
3
|
+
buffer;
|
|
4
|
+
head = 0;
|
|
5
|
+
count = 0;
|
|
6
|
+
pending = [];
|
|
7
|
+
constructor(capacity) {
|
|
8
|
+
this.capacity = capacity;
|
|
9
|
+
this.buffer = new Array(capacity);
|
|
10
|
+
}
|
|
11
|
+
push(event) {
|
|
12
|
+
this.buffer[this.head] = event;
|
|
13
|
+
this.head = (this.head + 1) % this.capacity;
|
|
14
|
+
if (this.count < this.capacity)
|
|
15
|
+
this.count++;
|
|
16
|
+
this.pending.push(event);
|
|
17
|
+
}
|
|
18
|
+
getAll() {
|
|
19
|
+
if (this.count === 0)
|
|
20
|
+
return [];
|
|
21
|
+
const result = [];
|
|
22
|
+
const start = this.count < this.capacity ? 0 : this.head;
|
|
23
|
+
for (let i = 0; i < this.count; i++) {
|
|
24
|
+
const idx = (start + i) % this.capacity;
|
|
25
|
+
result.push(this.buffer[idx]);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
getLast(n) {
|
|
30
|
+
const all = this.getAll();
|
|
31
|
+
return all.slice(-Math.min(n, all.length));
|
|
32
|
+
}
|
|
33
|
+
drain() {
|
|
34
|
+
const drained = this.pending;
|
|
35
|
+
this.pending = [];
|
|
36
|
+
return drained;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=ring-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ring-buffer.js","sourceRoot":"","sources":["../src/ring-buffer.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,UAAU;IAMD;IALZ,MAAM,CAA+B;IACrC,IAAI,GAAG,CAAC,CAAC;IACT,KAAK,GAAG,CAAC,CAAC;IACV,OAAO,GAAmB,EAAE,CAAC;IAErC,YAAoB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,KAAmB;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5C,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAE,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,CAAC,CAAS;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Server } from 'node:http';
|
|
2
|
+
export interface ServerOptions {
|
|
3
|
+
port: number;
|
|
4
|
+
host?: string;
|
|
5
|
+
dataDir: string;
|
|
6
|
+
uiDir?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function createServer(opts: ServerOptions): Promise<Server>;
|
|
9
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;AASrH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0CD,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAsKjE"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { createServer as httpCreateServer } from 'node:http';
|
|
2
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
3
|
+
import { extname, join } from 'node:path';
|
|
4
|
+
import { EventBus } from './event-bus.js';
|
|
5
|
+
import { RingBuffer } from './ring-buffer.js';
|
|
6
|
+
import { FileStore } from './file-store.js';
|
|
7
|
+
import { SSEStream } from './sse-stream.js';
|
|
8
|
+
const MIME_TYPES = {
|
|
9
|
+
'.html': 'text/html',
|
|
10
|
+
'.js': 'application/javascript',
|
|
11
|
+
'.css': 'text/css',
|
|
12
|
+
'.json': 'application/json',
|
|
13
|
+
'.svg': 'image/svg+xml',
|
|
14
|
+
'.png': 'image/png',
|
|
15
|
+
'.ico': 'image/x-icon',
|
|
16
|
+
};
|
|
17
|
+
function readBody(req) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const chunks = [];
|
|
20
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
21
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
22
|
+
req.on('error', reject);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function json(res, status, data) {
|
|
26
|
+
const body = JSON.stringify(data, (_key, value) => typeof value === 'bigint' ? value.toString() + 'n' : value);
|
|
27
|
+
res.writeHead(status, {
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
'Access-Control-Allow-Origin': '*',
|
|
30
|
+
});
|
|
31
|
+
res.end(body);
|
|
32
|
+
}
|
|
33
|
+
function cors(res) {
|
|
34
|
+
res.writeHead(204, {
|
|
35
|
+
'Access-Control-Allow-Origin': '*',
|
|
36
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
37
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
38
|
+
'Content-Length': '0',
|
|
39
|
+
});
|
|
40
|
+
res.end();
|
|
41
|
+
}
|
|
42
|
+
export function createServer(opts) {
|
|
43
|
+
const bus = new EventBus();
|
|
44
|
+
const ringBuffer = new RingBuffer(500);
|
|
45
|
+
const fileStore = new FileStore(opts.dataDir);
|
|
46
|
+
const sseStream = new SSEStream(ringBuffer);
|
|
47
|
+
const services = new Set();
|
|
48
|
+
// Wire EventBus subscribers
|
|
49
|
+
bus.on('*', (event) => {
|
|
50
|
+
ringBuffer.push(event);
|
|
51
|
+
sseStream.broadcast(event);
|
|
52
|
+
});
|
|
53
|
+
// Periodic flush to disk
|
|
54
|
+
let flushTimer;
|
|
55
|
+
const startFlushing = () => {
|
|
56
|
+
flushTimer = setInterval(async () => {
|
|
57
|
+
const events = ringBuffer.drain();
|
|
58
|
+
if (events.length > 0) {
|
|
59
|
+
await fileStore.flush(events);
|
|
60
|
+
}
|
|
61
|
+
}, 2000);
|
|
62
|
+
flushTimer.unref();
|
|
63
|
+
};
|
|
64
|
+
// Periodic cleanup of old files (every hour)
|
|
65
|
+
let cleanupTimer;
|
|
66
|
+
const startCleanup = () => {
|
|
67
|
+
const TWENTY_FOUR_HOURS = 24 * 60 * 60 * 1000;
|
|
68
|
+
cleanupTimer = setInterval(() => {
|
|
69
|
+
fileStore.cleanup(TWENTY_FOUR_HOURS);
|
|
70
|
+
}, 60 * 60 * 1000);
|
|
71
|
+
cleanupTimer.unref();
|
|
72
|
+
};
|
|
73
|
+
const server = httpCreateServer(async (req, res) => {
|
|
74
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
75
|
+
const { pathname } = url;
|
|
76
|
+
if (req.method === 'OPTIONS') {
|
|
77
|
+
return cors(res);
|
|
78
|
+
}
|
|
79
|
+
// Health check
|
|
80
|
+
if (req.method === 'GET' && pathname === '/health') {
|
|
81
|
+
return json(res, 200, { status: 'ok', uptime: process.uptime() });
|
|
82
|
+
}
|
|
83
|
+
// Ingest spans
|
|
84
|
+
if (req.method === 'POST' && pathname === '/v1/spans') {
|
|
85
|
+
const body = JSON.parse(await readBody(req));
|
|
86
|
+
const spans = (body.spans ?? []).map((s) => ({
|
|
87
|
+
...s,
|
|
88
|
+
startTimeUnixNano: BigInt(s.startTimeUnixNano),
|
|
89
|
+
endTimeUnixNano: BigInt(s.endTimeUnixNano),
|
|
90
|
+
}));
|
|
91
|
+
for (const span of spans) {
|
|
92
|
+
services.add(span.serviceName);
|
|
93
|
+
const event = {
|
|
94
|
+
type: 'span',
|
|
95
|
+
timestamp: Date.now(),
|
|
96
|
+
data: span,
|
|
97
|
+
};
|
|
98
|
+
bus.emit(event);
|
|
99
|
+
}
|
|
100
|
+
return json(res, 202, { accepted: spans.length });
|
|
101
|
+
}
|
|
102
|
+
// Ingest logs
|
|
103
|
+
if (req.method === 'POST' && pathname === '/v1/logs') {
|
|
104
|
+
const body = JSON.parse(await readBody(req));
|
|
105
|
+
const logs = body.logs ?? [];
|
|
106
|
+
for (const log of logs) {
|
|
107
|
+
const event = log.type === 'log'
|
|
108
|
+
? log
|
|
109
|
+
: { type: 'log', timestamp: Date.now(), data: log };
|
|
110
|
+
if (event.data.serviceName)
|
|
111
|
+
services.add(event.data.serviceName);
|
|
112
|
+
bus.emit(event);
|
|
113
|
+
}
|
|
114
|
+
return json(res, 202, { accepted: logs.length });
|
|
115
|
+
}
|
|
116
|
+
// Query spans
|
|
117
|
+
if (req.method === 'GET' && pathname === '/api/spans') {
|
|
118
|
+
const service = url.searchParams.get('service') ?? undefined;
|
|
119
|
+
const traceId = url.searchParams.get('traceId') ?? undefined;
|
|
120
|
+
const last = url.searchParams.has('last')
|
|
121
|
+
? Number(url.searchParams.get('last'))
|
|
122
|
+
: undefined;
|
|
123
|
+
// Serve from ring buffer for recent queries, file store for deeper
|
|
124
|
+
if (last && last <= 500 && !service && !traceId) {
|
|
125
|
+
return json(res, 200, { spans: ringBuffer.getLast(last) });
|
|
126
|
+
}
|
|
127
|
+
const results = await fileStore.query({ service, traceId, last });
|
|
128
|
+
return json(res, 200, { spans: results });
|
|
129
|
+
}
|
|
130
|
+
// List services
|
|
131
|
+
if (req.method === 'GET' && pathname === '/api/services') {
|
|
132
|
+
return json(res, 200, { services: [...services] });
|
|
133
|
+
}
|
|
134
|
+
// SSE live tail
|
|
135
|
+
if (req.method === 'GET' && pathname === '/sse') {
|
|
136
|
+
sseStream.addClient(res);
|
|
137
|
+
req.on('close', () => sseStream.removeClient(res));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Static file serving + SPA fallback
|
|
141
|
+
if (opts.uiDir) {
|
|
142
|
+
const filePath = join(opts.uiDir, pathname);
|
|
143
|
+
try {
|
|
144
|
+
const fileStat = await stat(filePath);
|
|
145
|
+
if (fileStat.isFile()) {
|
|
146
|
+
const ext = extname(filePath);
|
|
147
|
+
const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';
|
|
148
|
+
const cacheControl = ext === '.html'
|
|
149
|
+
? 'no-cache'
|
|
150
|
+
: 'public, max-age=31536000, immutable';
|
|
151
|
+
const content = await readFile(filePath);
|
|
152
|
+
res.writeHead(200, {
|
|
153
|
+
'Content-Type': contentType,
|
|
154
|
+
'Cache-Control': cacheControl,
|
|
155
|
+
});
|
|
156
|
+
return res.end(content);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// File not found — fall through
|
|
161
|
+
}
|
|
162
|
+
// SPA fallback: non-API, non-v1 routes serve index.html
|
|
163
|
+
if (!pathname.startsWith('/api/') && !pathname.startsWith('/v1/')) {
|
|
164
|
+
try {
|
|
165
|
+
const indexPath = join(opts.uiDir, 'index.html');
|
|
166
|
+
const content = await readFile(indexPath);
|
|
167
|
+
res.writeHead(200, {
|
|
168
|
+
'Content-Type': 'text/html',
|
|
169
|
+
'Cache-Control': 'no-cache',
|
|
170
|
+
});
|
|
171
|
+
return res.end(content);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// index.html missing — fall through to 404
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// 404
|
|
179
|
+
json(res, 404, { error: 'not found' });
|
|
180
|
+
});
|
|
181
|
+
startFlushing();
|
|
182
|
+
startCleanup();
|
|
183
|
+
server.on('close', () => {
|
|
184
|
+
if (flushTimer)
|
|
185
|
+
clearInterval(flushTimer);
|
|
186
|
+
if (cleanupTimer)
|
|
187
|
+
clearInterval(cleanupTimer);
|
|
188
|
+
});
|
|
189
|
+
return new Promise(resolve => {
|
|
190
|
+
server.listen(opts.port, opts.host ?? '127.0.0.1', () => resolve(server));
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAA0D,MAAM,WAAW,CAAC;AACrH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C,MAAM,UAAU,GAA2B;IACzC,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE,wBAAwB;IAC/B,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,cAAc;CACvB,CAAC;AAEF,SAAS,QAAQ,CAAC,GAAoB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC/D,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,IAAI,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAChD,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAC3D,CAAC;IACF,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,kBAAkB;QAClC,6BAA6B,EAAE,GAAG;KACnC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,GAAmB;IAC/B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,6BAA6B,EAAE,GAAG;QAClC,8BAA8B,EAAE,oBAAoB;QACpD,8BAA8B,EAAE,cAAc;QAC9C,gBAAgB,EAAE,GAAG;KACtB,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAmB;IAC9C,MAAM,GAAG,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,4BAA4B;IAC5B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE;QACpB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,yBAAyB;IACzB,IAAI,UAAsD,CAAC;IAC3D,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,UAAU,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YAClC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAC;QACT,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC,CAAC;IAEF,6CAA6C;IAC7C,IAAI,YAAwD,CAAC;IAC7D,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC9C,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;YAC9B,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACvC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACnB,YAAY,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACjD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;QAEzB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;QAED,eAAe;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,eAAe;QACf,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAW,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,CAAC;gBAC5E,GAAG,CAAC;gBACJ,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC,iBAA2B,CAAC;gBACxD,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,eAAyB,CAAC;aACrD,CAAC,CAAC,CAAC;YAEJ,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBAC/B,MAAM,KAAK,GAAiB;oBAC1B,IAAI,EAAE,MAAM;oBACZ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;oBACrB,IAAI,EAAE,IAAI;iBACX,CAAC;gBACF,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YACD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,cAAc;QACd,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;YACrD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;YAE7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,KAAK,GAAiB,GAAG,CAAC,IAAI,KAAK,KAAK;oBAC5C,CAAC,CAAC,GAAmB;oBACrB,CAAC,CAAC,EAAE,IAAI,EAAE,KAAc,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;gBAC/D,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW;oBAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACjE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YACD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,cAAc;QACd,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YACtD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;YAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;YAC7D,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;gBACvC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACtC,CAAC,CAAC,SAAS,CAAC;YAEd,mEAAmE;YACnE,IAAI,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC7D,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,gBAAgB;QAChB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,eAAe,EAAE,CAAC;YACzD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,gBAAgB;QAChB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YAChD,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACzB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAED,qCAAqC;QACrC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC5C,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACtC,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;oBACtB,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;oBAC9B,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;oBAClE,MAAM,YAAY,GAAG,GAAG,KAAK,OAAO;wBAClC,CAAC,CAAC,UAAU;wBACZ,CAAC,CAAC,qCAAqC,CAAC;oBAC1C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACzC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;wBACjB,cAAc,EAAE,WAAW;wBAC3B,eAAe,EAAE,YAAY;qBAC9B,CAAC,CAAC;oBACH,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,gCAAgC;YAClC,CAAC;YAED,wDAAwD;YACxD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClE,IAAI,CAAC;oBACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;oBACjD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,CAAC;oBAC1C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;wBACjB,cAAc,EAAE,WAAW;wBAC3B,eAAe,EAAE,UAAU;qBAC5B,CAAC,CAAC;oBACH,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC1B,CAAC;gBAAC,MAAM,CAAC;oBACP,2CAA2C;gBAC7C,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM;QACN,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC;IAEf,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACtB,IAAI,UAAU;YAAE,aAAa,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,YAAY;YAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;QAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ServerResponse } from 'node:http';
|
|
2
|
+
import type { NextDogEvent } from './types.js';
|
|
3
|
+
import type { RingBuffer } from './ring-buffer.js';
|
|
4
|
+
export declare class SSEStream {
|
|
5
|
+
private ringBuffer;
|
|
6
|
+
private clients;
|
|
7
|
+
constructor(ringBuffer: RingBuffer);
|
|
8
|
+
get clientCount(): number;
|
|
9
|
+
addClient(res: ServerResponse): void;
|
|
10
|
+
removeClient(res: ServerResponse): void;
|
|
11
|
+
broadcast(event: NextDogEvent): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=sse-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-stream.d.ts","sourceRoot":"","sources":["../src/sse-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASnD,qBAAa,SAAS;IAGR,OAAO,CAAC,UAAU;IAF9B,OAAO,CAAC,OAAO,CAA6B;gBAExB,UAAU,EAAE,UAAU;IAE1C,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAiBpC,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI;IAIvC,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;CAMrC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function serializeEvent(event) {
|
|
2
|
+
const json = JSON.stringify(event, (_key, value) => typeof value === 'bigint' ? value.toString() + 'n' : value);
|
|
3
|
+
return `data: ${json}\n\n`;
|
|
4
|
+
}
|
|
5
|
+
export class SSEStream {
|
|
6
|
+
ringBuffer;
|
|
7
|
+
clients = new Set();
|
|
8
|
+
constructor(ringBuffer) {
|
|
9
|
+
this.ringBuffer = ringBuffer;
|
|
10
|
+
}
|
|
11
|
+
get clientCount() {
|
|
12
|
+
return this.clients.size;
|
|
13
|
+
}
|
|
14
|
+
addClient(res) {
|
|
15
|
+
res.writeHead(200, {
|
|
16
|
+
'Content-Type': 'text/event-stream',
|
|
17
|
+
'Cache-Control': 'no-cache',
|
|
18
|
+
'Connection': 'keep-alive',
|
|
19
|
+
'Access-Control-Allow-Origin': '*',
|
|
20
|
+
});
|
|
21
|
+
// Backfill from ring buffer
|
|
22
|
+
const backfill = this.ringBuffer.getLast(50);
|
|
23
|
+
for (const event of backfill) {
|
|
24
|
+
res.write(serializeEvent(event));
|
|
25
|
+
}
|
|
26
|
+
this.clients.add(res);
|
|
27
|
+
}
|
|
28
|
+
removeClient(res) {
|
|
29
|
+
this.clients.delete(res);
|
|
30
|
+
}
|
|
31
|
+
broadcast(event) {
|
|
32
|
+
const message = serializeEvent(event);
|
|
33
|
+
for (const client of this.clients) {
|
|
34
|
+
client.write(message);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=sse-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-stream.js","sourceRoot":"","sources":["../src/sse-stream.ts"],"names":[],"mappings":"AAIA,SAAS,cAAc,CAAC,KAAmB;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACjD,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAC3D,CAAC;IACF,OAAO,SAAS,IAAI,MAAM,CAAC;AAC7B,CAAC;AAED,MAAM,OAAO,SAAS;IAGA;IAFZ,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,YAAoB,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAE9C,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,SAAS,CAAC,GAAmB;QAC3B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,YAAY,EAAE,YAAY;YAC1B,6BAA6B,EAAE,GAAG;SACnC,CAAC,CAAC;QAEH,4BAA4B;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7C,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,YAAY,CAAC,GAAmB;QAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,SAAS,CAAC,KAAmB;QAC3B,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACtC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;CACF"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface Span {
|
|
2
|
+
traceId: string;
|
|
3
|
+
spanId: string;
|
|
4
|
+
parentSpanId?: string;
|
|
5
|
+
name: string;
|
|
6
|
+
kind: 'SERVER' | 'CLIENT' | 'INTERNAL' | 'PRODUCER' | 'CONSUMER';
|
|
7
|
+
startTimeUnixNano: bigint;
|
|
8
|
+
endTimeUnixNano: bigint;
|
|
9
|
+
attributes: Record<string, string | number | boolean>;
|
|
10
|
+
status: {
|
|
11
|
+
code: 'OK' | 'ERROR' | 'UNSET';
|
|
12
|
+
message?: string;
|
|
13
|
+
};
|
|
14
|
+
statusCode?: number;
|
|
15
|
+
serviceName: string;
|
|
16
|
+
}
|
|
17
|
+
export interface LogEntry {
|
|
18
|
+
timestamp: number;
|
|
19
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
20
|
+
message: string;
|
|
21
|
+
attributes: Record<string, unknown>;
|
|
22
|
+
traceId?: string;
|
|
23
|
+
spanId?: string;
|
|
24
|
+
serviceName: string;
|
|
25
|
+
}
|
|
26
|
+
export type NextDogEvent = {
|
|
27
|
+
type: 'span';
|
|
28
|
+
timestamp: number;
|
|
29
|
+
data: Span;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'log';
|
|
32
|
+
timestamp: number;
|
|
33
|
+
data: LogEntry;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACjE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACtD,MAAM,EAAE;QAAE,IAAI,EAAE,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nextdog/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Zero-config dev observability sidecar for Next.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"nextdog": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@nextdog/ui": "0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^25.5.0",
|
|
22
|
+
"vitest": "^3"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/cscherban/NextDog"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"nextjs",
|
|
31
|
+
"observability",
|
|
32
|
+
"tracing",
|
|
33
|
+
"opentelemetry",
|
|
34
|
+
"devtools"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest"
|
|
40
|
+
}
|
|
41
|
+
}
|