import { RpcProtocol } from "@smithy/core/protocols"; import { deref, NormalizedSchema, TypeRegistry } from "@smithy/core/schema"; import { getSmithyContext } from "@smithy/util-middleware"; import { CborCodec } from "./CborCodec"; import { loadSmithyRpcV2CborErrorCode } from "./parseCborBody"; export class SmithyRpcV2CborProtocol extends RpcProtocol { codec = new CborCodec(); serializer = this.codec.createSerializer(); deserializer = this.codec.createDeserializer(); constructor({ defaultNamespace }) { super({ defaultNamespace }); } getShapeId() { return "smithy.protocols#rpcv2Cbor"; } getPayloadCodec() { return this.codec; } async serializeRequest(operationSchema, input, context) { const request = await super.serializeRequest(operationSchema, input, context); Object.assign(request.headers, { "content-type": this.getDefaultContentType(), "smithy-protocol": "rpc-v2-cbor", accept: this.getDefaultContentType(), }); if (deref(operationSchema.input) === "unit") { delete request.body; delete request.headers["content-type"]; } else { if (!request.body) { this.serializer.write(15, {}); request.body = this.serializer.flush(); } try { request.headers["content-length"] = String(request.body.byteLength); } catch (e) { } } const { service, operation } = getSmithyContext(context); const path = `/service/${service}/operation/${operation}`; if (request.path.endsWith("/")) { request.path += path.slice(1); } else { request.path += path; } return request; } async deserializeResponse(operationSchema, context, response) { return super.deserializeResponse(operationSchema, context, response); } async handleError(operationSchema, context, response, dataObject, metadata) { const errorName = loadSmithyRpcV2CborErrorCode(response, dataObject) ?? "Unknown"; let namespace = this.options.defaultNamespace; if (errorName.includes("#")) { [namespace] = errorName.split("#"); } const errorMetadata = { $metadata: metadata, $fault: response.statusCode <= 500 ? "client" : "server", }; const registry = TypeRegistry.for(namespace); let errorSchema; try { errorSchema = registry.getSchema(errorName); } catch (e) { if (dataObject.Message) { dataObject.message = dataObject.Message; } const synthetic = TypeRegistry.for("smithy.ts.sdk.synthetic." + namespace); const baseExceptionSchema = synthetic.getBaseException(); if (baseExceptionSchema) { const ErrorCtor = synthetic.getErrorCtor(baseExceptionSchema); throw Object.assign(new ErrorCtor({ name: errorName }), errorMetadata, dataObject); } throw Object.assign(new Error(errorName), errorMetadata, dataObject); } const ns = NormalizedSchema.of(errorSchema); const ErrorCtor = registry.getErrorCtor(errorSchema); const message = dataObject.message ?? dataObject.Message ?? "Unknown"; const exception = new ErrorCtor(message); const output = {}; for (const [name, member] of ns.structIterator()) { output[name] = this.deserializer.readValue(member, dataObject[name]); } throw Object.assign(exception, errorMetadata, { $fault: ns.getMergedTraits().error, message, }, output); } getDefaultContentType() { return "application/cbor"; } }