feat: streaming entities

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-02-21 10:06:07 -05:00
parent e5eeeeb546
commit f520b8e5ac
6 changed files with 323 additions and 24 deletions

View File

@@ -2,7 +2,7 @@
* Entity management service
*/
import { transceivePost } from './transceive';
import { transceivePost, transceiveStream } from './transceive';
import type {
EntityListRequest,
EntityListResponse,
@@ -21,6 +21,10 @@ import type {
EntityTransmitRequest,
EntityTransmitResponse,
EntityInterface,
EntityStreamRequest,
EntityStreamLine,
EntityStreamEntityLine,
EntityStreamDoneLine,
} from '../types/entity';
import { useIntegrationStore } from '@KTXC/stores/integrationStore';
import { EntityObject } from '../models';
@@ -157,6 +161,41 @@ export const entityService = {
async transmit(request: EntityTransmitRequest): Promise<EntityTransmitResponse> {
return await transceivePost<EntityTransmitRequest, EntityTransmitResponse>('entity.transmit', request);
},
/**
* Stream entities as NDJSON, invoking onEntity for each entity as it arrives.
*
* The server emits one entity per line so the caller receives entities
* progressively rather than waiting for the full collection to load.
*
* @param request - stream request parameters (same shape as list)
* @param onEntity - called synchronously for each entity as it is received
*
* @returns Promise resolving to { total } when the stream completes
*/
async stream(
request: EntityStreamRequest,
onEntity: (entity: EntityObject) => void
): Promise<{ total: number }> {
let total = 0;
await transceiveStream<EntityStreamRequest, EntityStreamLine>(
'entity.stream',
request,
(line) => {
if (line.type === 'entity') {
onEntity(createEntityObject(line as EntityStreamEntityLine));
} else if (line.type === 'done') {
total = (line as EntityStreamDoneLine).total;
} else if (line.type === 'error') {
throw new Error(`[entity.stream] ${line.message}`);
}
// 'meta' lines are silently consumed
}
);
return { total };
},
};
export default entityService;