import { EventStreamCodec } from "@smithy/eventstream-codec"; import { Encoder, Message } from "@smithy/types"; /** * @internal */ export type UnmarshalledStreamOptions = { eventStreamCodec: EventStreamCodec; deserializer: (input: Record) => Promise; toUtf8: Encoder; }; /** * @internal */ export function getUnmarshalledStream>( source: AsyncIterable, options: UnmarshalledStreamOptions ): AsyncIterable { const messageUnmarshaller = getMessageUnmarshaller(options.deserializer, options.toUtf8); return { [Symbol.asyncIterator]: async function* () { for await (const chunk of source) { const message = options.eventStreamCodec.decode(chunk); const type = await messageUnmarshaller(message); if (type === undefined) continue; yield type; } }, }; } /** * @internal */ export function getMessageUnmarshaller>( deserializer: (input: Record) => Promise, toUtf8: Encoder ): (input: Message) => Promise { return async function (message: Message): Promise { const { value: messageType } = message.headers[":message-type"]; if (messageType === "error") { // Unmodeled exception in event const unmodeledError = new Error((message.headers[":error-message"].value as string) || "UnknownError"); unmodeledError.name = message.headers[":error-code"].value as string; throw unmodeledError; } else if (messageType === "exception") { // For modeled exception, push it to deserializer and throw after deserializing const code = message.headers[":exception-type"].value as string; const exception = { [code]: message }; // Get parsed exception event in key(error code) value(structured error) pair. const deserializedException = await deserializer(exception); if (deserializedException.$unknown) { //this is an unmodeled exception then try parsing it with best effort const error = new Error(toUtf8(message.body)); error.name = code; throw error; } throw deserializedException[code]; } else if (messageType === "event") { const event = { [message.headers[":event-type"].value as string]: message, }; const deserialized = await deserializer(event); if (deserialized.$unknown) return; return deserialized; } else { throw Error(`Unrecognizable event type: ${message.headers[":event-type"].value}`); } }; }