feat(telemetry): CaptureService emits capture event (#7 v0.2.3)
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import type { NoteRepository } from '../repository/NoteRepository.js';
|
||||
import type { MediaStore } from './MediaStore.js';
|
||||
|
||||
export interface TelemetryEmitter {
|
||||
emit(input:
|
||||
| { kind: 'capture'; payload: { noteId: string; rawTextLength: number; hasMedia: boolean } }
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
export interface CaptureDeps {
|
||||
enqueue: (noteId: string) => Promise<void>;
|
||||
celebrate: (noteId: string) => void;
|
||||
telemetry?: TelemetryEmitter;
|
||||
}
|
||||
|
||||
export interface SubmitInput {
|
||||
@@ -39,6 +46,16 @@ export class CaptureService {
|
||||
}
|
||||
this.repo.insertMedia(rows);
|
||||
}
|
||||
if (this.deps.telemetry) {
|
||||
await this.deps.telemetry.emit({
|
||||
kind: 'capture',
|
||||
payload: {
|
||||
noteId: id,
|
||||
rawTextLength: input.text.length,
|
||||
hasMedia: input.images.length > 0
|
||||
}
|
||||
});
|
||||
}
|
||||
await this.deps.enqueue(id);
|
||||
this.deps.celebrate(id);
|
||||
return { noteId: id };
|
||||
|
||||
@@ -58,3 +58,56 @@ describe('CaptureService', () => {
|
||||
expect(repo.findById(noteId)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaptureService telemetry emit', () => {
|
||||
let db: Database.Database;
|
||||
let repo: NoteRepository;
|
||||
let store: MediaStore;
|
||||
let tmp: string;
|
||||
let events: Array<{ kind: string; payload: { noteId: string; rawTextLength: number; hasMedia: boolean } }>;
|
||||
|
||||
beforeEach(() => {
|
||||
db = new Database(':memory:');
|
||||
runMigrations(db);
|
||||
repo = new NoteRepository(db);
|
||||
tmp = mkdtempSync(join(tmpdir(), 'inkling-capture-'));
|
||||
store = new MediaStore(tmp);
|
||||
events = [];
|
||||
});
|
||||
|
||||
it('emits capture event with noteId/rawTextLength/hasMedia', async () => {
|
||||
const svc = new CaptureService(repo, store, {
|
||||
enqueue: async () => {},
|
||||
celebrate: () => {},
|
||||
telemetry: { emit: async (ev) => { events.push(ev as typeof events[number]); } }
|
||||
});
|
||||
await svc.submit({ text: '안녕하세요', images: [] });
|
||||
expect(events).toHaveLength(1);
|
||||
expect(events[0]!.kind).toBe('capture');
|
||||
expect(events[0]!.payload.rawTextLength).toBe('안녕하세요'.length);
|
||||
expect(events[0]!.payload.hasMedia).toBe(false);
|
||||
expect(typeof events[0]!.payload.noteId).toBe('string');
|
||||
});
|
||||
|
||||
it('emits hasMedia=true when images present', async () => {
|
||||
const svc = new CaptureService(repo, store, {
|
||||
enqueue: async () => {},
|
||||
celebrate: () => {},
|
||||
telemetry: { emit: async (ev) => { events.push(ev as typeof events[number]); } }
|
||||
});
|
||||
const img = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]).buffer;
|
||||
await svc.submit({ text: '이미지 메모', images: [img] });
|
||||
expect(events).toHaveLength(1);
|
||||
expect(events[0]!.payload.hasMedia).toBe(true);
|
||||
});
|
||||
|
||||
it('does NOT emit when telemetry dep absent (backward compat)', async () => {
|
||||
const svc = new CaptureService(repo, store, {
|
||||
enqueue: async () => {},
|
||||
celebrate: () => {}
|
||||
});
|
||||
const result = await svc.submit({ text: 'no telem', images: [] });
|
||||
expect(typeof result.noteId).toBe('string');
|
||||
expect(events).toHaveLength(0); // events array stays empty since no telemetry was wired
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user