import type { BinaryAttachment, NodeActivationId, NodeId, RunId, WorkflowId } from "../types"; import type { BinaryStorage, BinaryStorageReadResult, ExecutionBinaryService, NodeBinaryAttachmentService, } from "../types"; import { DefaultNodeBinaryAttachmentService } from "./DefaultNodeBinaryAttachmentServiceFactory"; import { boundedReadBinary } from "./boundedReadBinary.types"; export class DefaultExecutionBinaryService implements ExecutionBinaryService { constructor( private readonly storage: BinaryStorage, private readonly workflowId: WorkflowId, private readonly runId: RunId, private readonly now: () => Date, ) {} forNode(args: { nodeId: NodeId; activationId: NodeActivationId }): NodeBinaryAttachmentService { return new DefaultNodeBinaryAttachmentService( this.storage, this.workflowId, this.runId, args.nodeId, args.activationId, this.now, ); } openReadStream(attachment: BinaryAttachment): Promise { return this.storage.openReadStream(attachment.storageKey); } async getBytes(attachment: BinaryAttachment, maxBytes?: number): Promise { const stream = await this.openReadStream(attachment); if (!stream) { throw new Error("Binary attachment stream is unavailable."); } return boundedReadBinary(stream, attachment, maxBytes); } async getText(attachment: BinaryAttachment, maxBytes?: number): Promise { return new TextDecoder().decode(await this.getBytes(attachment, maxBytes)); } async getJson(attachment: BinaryAttachment, maxBytes?: number): Promise { const text = await this.getText(attachment, maxBytes); try { return JSON.parse(text) as T; } catch (cause) { throw new SyntaxError( `Binary attachment at storage key "${attachment.storageKey}" is not valid JSON: ${cause instanceof Error ? cause.message : String(cause)}`, { cause }, ); } } } export { DefaultNodeBinaryAttachmentService } from "./DefaultNodeBinaryAttachmentServiceFactory"; export { UnavailableBinaryStorage } from "./UnavailableBinaryStorage";