diff --git a/.changeset/clean-terms-argue.md b/.changeset/clean-terms-argue.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/clean-terms-argue.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/eventstream-serde-universal/package.json b/packages/eventstream-serde-universal/package.json index 2655c4082ff..7ae3ac0f67b 100644 --- a/packages/eventstream-serde-universal/package.json +++ b/packages/eventstream-serde-universal/package.json @@ -12,7 +12,9 @@ "lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"", "format": "prettier --config ../../prettier.config.js --ignore-path ../../.prettierignore --write \"**/*.{ts,md,json}\"", "test": "yarn g:vitest run", - "test:watch": "yarn g:vitest watch" + "test:watch": "yarn g:vitest watch", + "test:integration": "yarn g:vitest run -c vitest.config.integ.mts", + "test:integration:watch": "yarn g:vitest watch -c vitest.config.integ.mts" }, "main": "./dist-cjs/index.js", "module": "./dist-es/index.js", diff --git a/packages/eventstream-serde-universal/src/eventstream-cbor.integ.spec.ts b/packages/eventstream-serde-universal/src/eventstream-cbor.integ.spec.ts new file mode 100644 index 00000000000..f509228a692 --- /dev/null +++ b/packages/eventstream-serde-universal/src/eventstream-cbor.integ.spec.ts @@ -0,0 +1,139 @@ +import { cbor, dateToTag } from "@smithy/core/cbor"; +import { HttpResponse } from "@smithy/protocol-http"; +import { requireRequestsFrom } from "@smithy/util-test/src"; +import { Readable } from "node:stream"; +import { describe, expect, test as it } from "vitest"; +import { XYZService } from "xyz"; + +describe("local model integration test for cbor eventstreams", () => { + it("should read and write cbor event streams", async () => { + const client = new XYZService({ + endpoint: "https://localhost", + }); + + const body = cbor.serialize({ + id: "alpha", + timestamp: dateToTag(new Date(0)), + }); + + function toInt32(n: number): number[] { + const uint32 = new Uint8Array(4); + const dv = new DataView(uint32.buffer, 0, 4); + dv.setUint32(0, n); + return [...uint32]; + } + + requireRequestsFrom(client) + .toMatch({ + hostname: /localhost/, + async body(body) { + const outgoing = []; + for await (const chunk of body) { + outgoing.push(chunk); + } + expect(outgoing).toEqual([ + new Uint8Array([ + 0, 0, 0, 101, 0, 0, 0, 75, 213, 254, 191, 76, 11, 58, 101, 118, 101, 110, 116, 45, 116, 121, 112, 101, 7, + 0, 5, 97, 108, 112, 104, 97, 13, 58, 109, 101, 115, 115, 97, 103, 101, 45, 116, 121, 112, 101, 7, 0, 5, + 101, 118, 101, 110, 116, 13, 58, 99, 111, 110, 116, 101, 110, 116, 45, 116, 121, 112, 101, 7, 0, 16, 97, + 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 99, 98, 111, 114, 161, 98, 105, 100, 101, 97, 108, + 112, 104, 97, 32, 93, 69, 236, + ]), + new Uint8Array([ + 0, 0, 0, 91, 0, 0, 0, 74, 188, 232, 137, 61, 11, 58, 101, 118, 101, 110, 116, 45, 116, 121, 112, 101, 7, + 0, 4, 98, 101, 116, 97, 13, 58, 109, 101, 115, 115, 97, 103, 101, 45, 116, 121, 112, 101, 7, 0, 5, 101, + 118, 101, 110, 116, 13, 58, 99, 111, 110, 116, 101, 110, 116, 45, 116, 121, 112, 101, 7, 0, 16, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 99, 98, 111, 114, 160, 195, 209, 62, 47, + ]), + new Uint8Array([ + 0, 0, 0, 91, 0, 0, 0, 74, 188, 232, 137, 61, 11, 58, 101, 118, 101, 110, 116, 45, 116, 121, 112, 101, 7, + 0, 4, 98, 101, 116, 97, 13, 58, 109, 101, 115, 115, 97, 103, 101, 45, 116, 121, 112, 101, 7, 0, 5, 101, + 118, 101, 110, 116, 13, 58, 99, 111, 110, 116, 101, 110, 116, 45, 116, 121, 112, 101, 7, 0, 16, 97, 112, + 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 99, 98, 111, 114, 160, 195, 209, 62, 47, + ]), + new Uint8Array(), + ]); + }, + }) + .respondWith( + new HttpResponse({ + statusCode: 200, + headers: { + "smithy-protocol": "rpc-v2-cbor", + }, + body: Readable.from({ + async *[Symbol.asyncIterator]() { + yield new Uint8Array([ + /* message size */ ...toInt32(91 + body.byteLength), + /* header size */ ...toInt32(75), + /* prelude crc */ ...toInt32(1084132878), + /* headers */ + /* :event-type */ + 11, + ...[58, 101, 118, 101, 110, 116, 45, 116, 121, 112, 101], + 7, + /* alpha */ + 0, + 5, + ...[97, 108, 112, 104, 97], + /* :content-type */ + 13, + ...[58, 99, 111, 110, 116, 101, 110, 116, 45, 116, 121, 112, 101], + 7, + /* application/cbor */ + 0, + 16, + ...[97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 99, 98, 111, 114], + /* :message-type */ + 13, + ...[58, 109, 101, 115, 115, 97, 103, 101, 45, 116, 121, 112, 101], + 7, + /* event */ + 0, + 5, + ...[101, 118, 101, 110, 116], + + /* body */ + ...body, + + /* message crc */ + ...toInt32(1938836882), + ]); + }, + }), + }) + ); + + const response = await client.tradeEventStream({ + eventStream: { + async *[Symbol.asyncIterator]() { + yield { + alpha: { + id: "alpha", + }, + }; + yield { + beta: {}, + }; + yield { + gamma: {}, + }; + }, + }, + }); + + const responses = [] as any[]; + for await (const event of response.eventStream ?? []) { + responses.push(event); + } + + expect(responses).toEqual([ + { + alpha: { + id: "alpha", + timestamp: new Date(0), + }, + }, + ]); + }); +}); diff --git a/packages/eventstream-serde-universal/vitest.config.integ.mts b/packages/eventstream-serde-universal/vitest.config.integ.mts new file mode 100644 index 00000000000..5802db1ac64 --- /dev/null +++ b/packages/eventstream-serde-universal/vitest.config.integ.mts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["**/*.integ.spec.ts"], + environment: "node", + }, +}); diff --git a/private/my-local-model/package.json b/private/my-local-model/package.json index 7d0ed5d57e2..73ba8979e6a 100644 --- a/private/my-local-model/package.json +++ b/private/my-local-model/package.json @@ -21,6 +21,9 @@ "@aws-sdk/types": "latest", "@smithy/config-resolver": "workspace:^", "@smithy/core": "workspace:^", + "@smithy/eventstream-serde-browser": "workspace:^", + "@smithy/eventstream-serde-config-resolver": "workspace:^", + "@smithy/eventstream-serde-node": "workspace:^", "@smithy/fetch-http-handler": "workspace:^", "@smithy/hash-node": "workspace:^", "@smithy/invalid-dependency": "workspace:^", diff --git a/private/my-local-model/src/XYZService.ts b/private/my-local-model/src/XYZService.ts index 8ee1b9b0583..3b6f3dd7761 100644 --- a/private/my-local-model/src/XYZService.ts +++ b/private/my-local-model/src/XYZService.ts @@ -1,11 +1,17 @@ // smithy-typescript generated code import { XYZServiceClient, XYZServiceClientConfig } from "./XYZServiceClient"; import { GetNumbersCommand, GetNumbersCommandInput, GetNumbersCommandOutput } from "./commands/GetNumbersCommand"; +import { + TradeEventStreamCommand, + TradeEventStreamCommandInput, + TradeEventStreamCommandOutput, +} from "./commands/TradeEventStreamCommand"; import { createAggregatedClient } from "@smithy/smithy-client"; import { HttpHandlerOptions as __HttpHandlerOptions } from "@smithy/types"; const commands = { GetNumbersCommand, + TradeEventStreamCommand, }; export interface XYZService { @@ -20,6 +26,24 @@ export interface XYZService { options: __HttpHandlerOptions, cb: (err: any, data?: GetNumbersCommandOutput) => void ): void; + + /** + * @see {@link TradeEventStreamCommand} + */ + tradeEventStream(): Promise; + tradeEventStream( + args: TradeEventStreamCommandInput, + options?: __HttpHandlerOptions + ): Promise; + tradeEventStream( + args: TradeEventStreamCommandInput, + cb: (err: any, data?: TradeEventStreamCommandOutput) => void + ): void; + tradeEventStream( + args: TradeEventStreamCommandInput, + options: __HttpHandlerOptions, + cb: (err: any, data?: TradeEventStreamCommandOutput) => void + ): void; } /** diff --git a/private/my-local-model/src/XYZServiceClient.ts b/private/my-local-model/src/XYZServiceClient.ts index 4ebaee329ca..43a8d41b54c 100644 --- a/private/my-local-model/src/XYZServiceClient.ts +++ b/private/my-local-model/src/XYZServiceClient.ts @@ -6,6 +6,7 @@ import { resolveHttpAuthSchemeConfig, } from "./auth/httpAuthSchemeProvider"; import { GetNumbersCommandInput, GetNumbersCommandOutput } from "./commands/GetNumbersCommand"; +import { TradeEventStreamCommandInput, TradeEventStreamCommandOutput } from "./commands/TradeEventStreamCommand"; import { ClientInputEndpointParameters, ClientResolvedEndpointParameters, @@ -19,6 +20,11 @@ import { getHttpAuthSchemeEndpointRuleSetPlugin, getHttpSigningPlugin, } from "@smithy/core"; +import { + EventStreamSerdeInputConfig, + EventStreamSerdeResolvedConfig, + resolveEventStreamSerdeConfig, +} from "@smithy/eventstream-serde-config-resolver"; import { getContentLengthPlugin } from "@smithy/middleware-content-length"; import { EndpointInputConfig, @@ -42,6 +48,7 @@ import { ChecksumConstructor as __ChecksumConstructor, Decoder as __Decoder, Encoder as __Encoder, + EventStreamSerdeProvider as __EventStreamSerdeProvider, HashConstructor as __HashConstructor, HttpHandlerOptions as __HttpHandlerOptions, Logger as __Logger, @@ -55,12 +62,12 @@ export { __Client }; /** * @public */ -export type ServiceInputTypes = GetNumbersCommandInput; +export type ServiceInputTypes = GetNumbersCommandInput | TradeEventStreamCommandInput; /** * @public */ -export type ServiceOutputTypes = GetNumbersCommandOutput; +export type ServiceOutputTypes = GetNumbersCommandOutput | TradeEventStreamCommandOutput; /** * @public @@ -154,6 +161,11 @@ export interface ClientDefaults extends Partial<__SmithyConfiguration<__HttpHand */ extensions?: RuntimeExtension[]; + /** + * The function that provides necessary utilities for generating and parsing event stream + */ + eventStreamSerdeProvider?: __EventStreamSerdeProvider; + /** * The {@link @smithy/smithy-client#DefaultsMode} that will be used to determine how certain default configuration options are resolved in the SDK. */ @@ -168,6 +180,7 @@ export type XYZServiceClientConfigType = Partial<__SmithyConfiguration<__HttpHan RetryInputConfig & EndpointInputConfig & EndpointRequiredInputConfig & + EventStreamSerdeInputConfig & HttpAuthSchemeInputConfig & ClientInputEndpointParameters; /** @@ -186,6 +199,7 @@ export type XYZServiceClientResolvedConfigType = __SmithyResolvedConfiguration<_ RetryResolvedConfig & EndpointResolvedConfig & EndpointRequiredResolvedConfig & + EventStreamSerdeResolvedConfig & HttpAuthSchemeResolvedConfig & ClientResolvedEndpointParameters; /** @@ -218,9 +232,10 @@ export class XYZServiceClient extends __Client< let _config_2 = resolveRetryConfig(_config_1); let _config_3 = resolveEndpointConfig(_config_2); let _config_4 = resolveEndpointRequiredConfig(_config_3); - let _config_5 = resolveHttpAuthSchemeConfig(_config_4); - let _config_6 = resolveRuntimeExtensions(_config_5, configuration?.extensions || []); - this.config = _config_6; + let _config_5 = resolveEventStreamSerdeConfig(_config_4); + let _config_6 = resolveHttpAuthSchemeConfig(_config_5); + let _config_7 = resolveRuntimeExtensions(_config_6, configuration?.extensions || []); + this.config = _config_7; this.middlewareStack.use(getRetryPlugin(this.config)); this.middlewareStack.use(getContentLengthPlugin(this.config)); this.middlewareStack.use( diff --git a/private/my-local-model/src/commands/TradeEventStreamCommand.ts b/private/my-local-model/src/commands/TradeEventStreamCommand.ts new file mode 100644 index 00000000000..dc281ecc0f2 --- /dev/null +++ b/private/my-local-model/src/commands/TradeEventStreamCommand.ts @@ -0,0 +1,121 @@ +// smithy-typescript generated code +import { ServiceInputTypes, ServiceOutputTypes, XYZServiceClientResolvedConfig } from "../XYZServiceClient"; +import { commonParams } from "../endpoint/EndpointParameters"; +import { + TradeEventStreamRequest, + TradeEventStreamRequestFilterSensitiveLog, + TradeEventStreamResponse, + TradeEventStreamResponseFilterSensitiveLog, +} from "../models/models_0"; +import { de_TradeEventStreamCommand, se_TradeEventStreamCommand } from "../protocols/Rpcv2cbor"; +import { getEndpointPlugin } from "@smithy/middleware-endpoint"; +import { getSerdePlugin } from "@smithy/middleware-serde"; +import { Command as $Command } from "@smithy/smithy-client"; +import { MetadataBearer as __MetadataBearer } from "@smithy/types"; + +/** + * @public + */ +export type { __MetadataBearer }; +export { $Command }; +/** + * @public + * + * The input for {@link TradeEventStreamCommand}. + */ +export interface TradeEventStreamCommandInput extends TradeEventStreamRequest {} +/** + * @public + * + * The output of {@link TradeEventStreamCommand}. + */ +export interface TradeEventStreamCommandOutput extends TradeEventStreamResponse, __MetadataBearer {} + +/** + * @public + * + * @example + * Use a bare-bones client and the command you need to make an API call. + * ```javascript + * import { XYZServiceClient, TradeEventStreamCommand } from "xyz"; // ES Modules import + * // const { XYZServiceClient, TradeEventStreamCommand } = require("xyz"); // CommonJS import + * // import type { XYZServiceClientConfig } from "xyz"; + * const config = {}; // type is XYZServiceClientConfig + * const client = new XYZServiceClient(config); + * const input = { // TradeEventStreamRequest + * eventStream: { // TradeEvents Union: only one key present + * alpha: { // Alpha + * id: "STRING_VALUE", + * timestamp: new Date("TIMESTAMP"), + * }, + * beta: {}, + * gamma: {}, + * }, + * }; + * const command = new TradeEventStreamCommand(input); + * const response = await client.send(command); + * // { // TradeEventStreamResponse + * // eventStream: { // TradeEvents Union: only one key present + * // alpha: { // Alpha + * // id: "STRING_VALUE", + * // timestamp: new Date("TIMESTAMP"), + * // }, + * // beta: {}, + * // gamma: {}, + * // }, + * // }; + * + * ``` + * + * @param TradeEventStreamCommandInput - {@link TradeEventStreamCommandInput} + * @returns {@link TradeEventStreamCommandOutput} + * @see {@link TradeEventStreamCommandInput} for command's `input` shape. + * @see {@link TradeEventStreamCommandOutput} for command's `response` shape. + * @see {@link XYZServiceClientResolvedConfig | config} for XYZServiceClient's `config` shape. + * + * @throws {@link XYZServiceServiceException} + *

Base exception class for all service exceptions from XYZService service.

+ * + * + */ +export class TradeEventStreamCommand extends $Command + .classBuilder< + TradeEventStreamCommandInput, + TradeEventStreamCommandOutput, + XYZServiceClientResolvedConfig, + ServiceInputTypes, + ServiceOutputTypes + >() + .ep(commonParams) + .m(function (this: any, Command: any, cs: any, config: XYZServiceClientResolvedConfig, o: any) { + return [ + getSerdePlugin(config, this.serialize, this.deserialize), + getEndpointPlugin(config, Command.getEndpointParameterInstructions()), + ]; + }) + .s("XYZService", "TradeEventStream", { + /** + * @internal + */ + eventStream: { + input: true, + output: true, + }, + }) + .n("XYZServiceClient", "TradeEventStreamCommand") + .f(TradeEventStreamRequestFilterSensitiveLog, TradeEventStreamResponseFilterSensitiveLog) + .ser(se_TradeEventStreamCommand) + .de(de_TradeEventStreamCommand) + .build() { + /** @internal type navigation helper, not in runtime. */ + protected declare static __types: { + api: { + input: TradeEventStreamRequest; + output: TradeEventStreamResponse; + }; + sdk: { + input: TradeEventStreamCommandInput; + output: TradeEventStreamCommandOutput; + }; + }; +} diff --git a/private/my-local-model/src/commands/index.ts b/private/my-local-model/src/commands/index.ts index fd9ff35bcaf..3805f2459e2 100644 --- a/private/my-local-model/src/commands/index.ts +++ b/private/my-local-model/src/commands/index.ts @@ -1,2 +1,3 @@ // smithy-typescript generated code export * from "./GetNumbersCommand"; +export * from "./TradeEventStreamCommand"; diff --git a/private/my-local-model/src/models/models_0.ts b/private/my-local-model/src/models/models_0.ts index 9fb64af1dc7..75519962b58 100644 --- a/private/my-local-model/src/models/models_0.ts +++ b/private/my-local-model/src/models/models_0.ts @@ -3,6 +3,14 @@ import { XYZServiceServiceException as __BaseException } from "./XYZServiceServi import { NumericValue } from "@smithy/core/serde"; import { ExceptionOptionType as __ExceptionOptionType } from "@smithy/smithy-client"; +/** + * @public + */ +export interface Alpha { + id?: string | undefined; + timestamp?: Date | undefined; +} + /** * @public */ @@ -101,3 +109,106 @@ export class RetryableError extends __BaseException { Object.setPrototypeOf(this, RetryableError.prototype); } } + +/** + * @public + */ +export interface Unit {} + +/** + * @public + */ +export type TradeEvents = + | TradeEvents.AlphaMember + | TradeEvents.BetaMember + | TradeEvents.GammaMember + | TradeEvents.$UnknownMember; + +/** + * @public + */ +export namespace TradeEvents { + export interface AlphaMember { + alpha: Alpha; + beta?: never; + gamma?: never; + $unknown?: never; + } + + export interface BetaMember { + alpha?: never; + beta: Unit; + gamma?: never; + $unknown?: never; + } + + export interface GammaMember { + alpha?: never; + beta?: never; + gamma: Unit; + $unknown?: never; + } + + /** + * @public + */ + export interface $UnknownMember { + alpha?: never; + beta?: never; + gamma?: never; + $unknown: [string, any]; + } + + export interface Visitor { + alpha: (value: Alpha) => T; + beta: (value: Unit) => T; + gamma: (value: Unit) => T; + _: (name: string, value: any) => T; + } + + export const visit = (value: TradeEvents, visitor: Visitor): T => { + if (value.alpha !== undefined) return visitor.alpha(value.alpha); + if (value.beta !== undefined) return visitor.beta(value.beta); + if (value.gamma !== undefined) return visitor.gamma(value.gamma); + return visitor._(value.$unknown[0], value.$unknown[1]); + }; +} +/** + * @internal + */ +export const TradeEventsFilterSensitiveLog = (obj: TradeEvents): any => { + if (obj.alpha !== undefined) return { alpha: obj.alpha }; + if (obj.beta !== undefined) return { beta: obj.beta }; + if (obj.gamma !== undefined) return { gamma: obj.gamma }; + if (obj.$unknown !== undefined) return { [obj.$unknown[0]]: "UNKNOWN" }; +}; + +/** + * @public + */ +export interface TradeEventStreamRequest { + eventStream?: AsyncIterable | undefined; +} + +/** + * @internal + */ +export const TradeEventStreamRequestFilterSensitiveLog = (obj: TradeEventStreamRequest): any => ({ + ...obj, + ...(obj.eventStream && { eventStream: "STREAMING_CONTENT" }), +}); + +/** + * @public + */ +export interface TradeEventStreamResponse { + eventStream?: AsyncIterable | undefined; +} + +/** + * @internal + */ +export const TradeEventStreamResponseFilterSensitiveLog = (obj: TradeEventStreamResponse): any => ({ + ...obj, + ...(obj.eventStream && { eventStream: "STREAMING_CONTENT" }), +}); diff --git a/private/my-local-model/src/protocols/Rpcv2cbor.ts b/private/my-local-model/src/protocols/Rpcv2cbor.ts index 70558c90ce8..7c8ce383bd7 100644 --- a/private/my-local-model/src/protocols/Rpcv2cbor.ts +++ b/private/my-local-model/src/protocols/Rpcv2cbor.ts @@ -1,15 +1,20 @@ // smithy-typescript generated code import { GetNumbersCommandInput, GetNumbersCommandOutput } from "../commands/GetNumbersCommand"; +import { TradeEventStreamCommandInput, TradeEventStreamCommandOutput } from "../commands/TradeEventStreamCommand"; import { XYZServiceServiceException as __BaseException } from "../models/XYZServiceServiceException"; import { + Alpha, CodedThrottlingError, GetNumbersRequest, GetNumbersResponse, HaltError, MysteryThrottlingError, RetryableError, + TradeEvents, + Unit, } from "../models/models_0"; import { + dateToTag as __dateToTag, buildHttpRpcRequest, cbor, checkCborResponse as cr, @@ -21,6 +26,9 @@ import { nv as __nv } from "@smithy/core/serde"; import { HttpRequest as __HttpRequest, HttpResponse as __HttpResponse } from "@smithy/protocol-http"; import { decorateServiceException as __decorateServiceException, + expectNonNull as __expectNonNull, + expectString as __expectString, + parseEpochTimestamp as __parseEpochTimestamp, _json, collectBody, take, @@ -28,7 +36,10 @@ import { } from "@smithy/smithy-client"; import { Endpoint as __Endpoint, + EventStreamSerdeContext as __EventStreamSerdeContext, HeaderBag as __HeaderBag, + Message as __Message, + MessageHeaders as __MessageHeaders, ResponseMetadata as __ResponseMetadata, SerdeContext as __SerdeContext, } from "@smithy/types"; @@ -46,6 +57,23 @@ export const se_GetNumbersCommand = async ( return buildHttpRpcRequest(context, headers, "/service/XYZService/operation/GetNumbers", undefined, body); }; +/** + * serializeRpcv2cborTradeEventStreamCommand + */ +export const se_TradeEventStreamCommand = async ( + input: TradeEventStreamCommandInput, + context: __SerdeContext & __EventStreamSerdeContext +): Promise<__HttpRequest> => { + const headers: __HeaderBag = { ...SHARED_HEADERS }; + headers.accept = "application/vnd.amazon.eventstream"; + + headers["content-type"] = "application/vnd.amazon.eventstream"; + + let body: any; + body = se_TradeEvents(input.eventStream, context); + return buildHttpRpcRequest(context, headers, "/service/XYZService/operation/TradeEventStream", undefined, body); +}; + /** * deserializeRpcv2cborGetNumbersCommand */ @@ -68,6 +96,26 @@ export const de_GetNumbersCommand = async ( return response; }; +/** + * deserializeRpcv2cborTradeEventStreamCommand + */ +export const de_TradeEventStreamCommand = async ( + output: __HttpResponse, + context: __SerdeContext & __EventStreamSerdeContext +): Promise => { + cr(output); + if (output.statusCode >= 300) { + return de_CommandError(output, context); + } + + const contents = { eventStream: de_TradeEvents(output.body, context) }; + const response: TradeEventStreamCommandOutput = { + $metadata: deserializeMetadata(output), + ...contents, + }; + return response; +}; + /** * deserialize_Rpcv2cborCommandError */ @@ -158,6 +206,89 @@ const de_RetryableErrorRes = async (parsedOutput: any, context: __SerdeContext): return __decorateServiceException(exception, body); }; +/** + * serializeRpcv2cborTradeEvents + */ +const se_TradeEvents = (input: any, context: __SerdeContext & __EventStreamSerdeContext): any => { + const eventMarshallingVisitor = (event: any): __Message => + TradeEvents.visit(event, { + alpha: (value) => se_Alpha_event(value, context), + beta: (value) => se_Unit_event(value, context), + gamma: (value) => se_Unit_event(value, context), + _: (value) => value as any, + }); + return context.eventStreamMarshaller.serialize(input, eventMarshallingVisitor); +}; +const se_Alpha_event = (input: Alpha, context: __SerdeContext): __Message => { + const headers: __MessageHeaders = { + ":event-type": { type: "string", value: "alpha" }, + ":message-type": { type: "string", value: "event" }, + ":content-type": { type: "string", value: "application/cbor" }, + }; + let body = new Uint8Array(); + body = se_Alpha(input, context); + body = cbor.serialize(body); + return { headers, body }; +}; +const se_Unit_event = (input: Unit, context: __SerdeContext): __Message => { + const headers: __MessageHeaders = { + ":event-type": { type: "string", value: "beta" }, + ":message-type": { type: "string", value: "event" }, + ":content-type": { type: "string", value: "application/cbor" }, + }; + let body = new Uint8Array(); + body = _json(input); + body = cbor.serialize(body); + return { headers, body }; +}; +/** + * deserializeRpcv2cborTradeEvents + */ +const de_TradeEvents = ( + output: any, + context: __SerdeContext & __EventStreamSerdeContext +): AsyncIterable => { + return context.eventStreamMarshaller.deserialize(output, async (event) => { + if (event["alpha"] != null) { + return { + alpha: await de_Alpha_event(event["alpha"], context), + }; + } + if (event["beta"] != null) { + return { + beta: await de_Unit_event(event["beta"], context), + }; + } + if (event["gamma"] != null) { + return { + gamma: await de_Unit_event(event["gamma"], context), + }; + } + return { $unknown: event as any }; + }); +}; +const de_Alpha_event = async (output: any, context: __SerdeContext): Promise => { + const contents: Alpha = {} as any; + const data: any = await parseBody(output.body, context); + Object.assign(contents, de_Alpha(data, context)); + return contents; +}; +const de_Unit_event = async (output: any, context: __SerdeContext): Promise => { + const contents: Unit = {} as any; + const data: any = await parseBody(output.body, context); + Object.assign(contents, _json(data)); + return contents; +}; +/** + * serializeRpcv2cborAlpha + */ +const se_Alpha = (input: Alpha, context: __SerdeContext): any => { + return take(input, { + id: [], + timestamp: __dateToTag, + }); +}; + /** * serializeRpcv2cborGetNumbersRequest */ @@ -168,6 +299,18 @@ const se_GetNumbersRequest = (input: GetNumbersRequest, context: __SerdeContext) }); }; +// se_Unit omitted. + +/** + * deserializeRpcv2cborAlpha + */ +const de_Alpha = (output: any, context: __SerdeContext): Alpha => { + return take(output, { + id: __expectString, + timestamp: (_: any) => __expectNonNull(__parseEpochTimestamp(_)), + }) as any; +}; + // de_CodedThrottlingError omitted. /** @@ -186,6 +329,8 @@ const de_GetNumbersResponse = (output: any, context: __SerdeContext): GetNumbers // de_RetryableError omitted. +// de_Unit omitted. + const deserializeMetadata = (output: __HttpResponse): __ResponseMetadata => ({ httpStatusCode: output.statusCode, requestId: diff --git a/private/my-local-model/src/runtimeConfig.browser.ts b/private/my-local-model/src/runtimeConfig.browser.ts index 8c8ff855c25..c2e6c05ad0e 100644 --- a/private/my-local-model/src/runtimeConfig.browser.ts +++ b/private/my-local-model/src/runtimeConfig.browser.ts @@ -1,5 +1,6 @@ // smithy-typescript generated code import { Sha256 } from "@aws-crypto/sha256-browser"; +import { eventStreamSerdeProvider } from "@smithy/eventstream-serde-browser"; import { FetchHttpHandler as RequestHandler, streamCollector } from "@smithy/fetch-http-handler"; import { calculateBodyLength } from "@smithy/util-body-length-browser"; import { DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_MODE } from "@smithy/util-retry"; @@ -21,6 +22,7 @@ export const getRuntimeConfig = (config: XYZServiceClientConfig) => { runtime: "browser", defaultsMode, bodyLengthChecker: config?.bodyLengthChecker ?? calculateBodyLength, + eventStreamSerdeProvider: config?.eventStreamSerdeProvider ?? eventStreamSerdeProvider, maxAttempts: config?.maxAttempts ?? DEFAULT_MAX_ATTEMPTS, requestHandler: RequestHandler.create(config?.requestHandler ?? defaultConfigProvider), retryMode: config?.retryMode ?? (async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE), diff --git a/private/my-local-model/src/runtimeConfig.ts b/private/my-local-model/src/runtimeConfig.ts index 553aae1c203..0a45f2ae5aa 100644 --- a/private/my-local-model/src/runtimeConfig.ts +++ b/private/my-local-model/src/runtimeConfig.ts @@ -1,4 +1,5 @@ // smithy-typescript generated code +import { eventStreamSerdeProvider } from "@smithy/eventstream-serde-node"; import { Hash } from "@smithy/hash-node"; import { NODE_MAX_ATTEMPT_CONFIG_OPTIONS, NODE_RETRY_MODE_CONFIG_OPTIONS } from "@smithy/middleware-retry"; import { loadConfig as loadNodeConfig } from "@smithy/node-config-provider"; @@ -25,6 +26,7 @@ export const getRuntimeConfig = (config: XYZServiceClientConfig) => { runtime: "node", defaultsMode, bodyLengthChecker: config?.bodyLengthChecker ?? calculateBodyLength, + eventStreamSerdeProvider: config?.eventStreamSerdeProvider ?? eventStreamSerdeProvider, maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config), requestHandler: RequestHandler.create(config?.requestHandler ?? defaultConfigProvider), retryMode: diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/protocols/cbor/SmithyRpcV2Cbor.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/protocols/cbor/SmithyRpcV2Cbor.java index c647326a96a..556e5d365ad 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/protocols/cbor/SmithyRpcV2Cbor.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/protocols/cbor/SmithyRpcV2Cbor.java @@ -71,7 +71,7 @@ public void generateSharedComponents(GenerationContext context) { "cbor", null, TypeScriptDependency.SMITHY_CORE, SmithyCoreSubmodules.CBOR ); - writer.write("body = cbor.encode(body);"); + writer.write("body = cbor.serialize(body);"); }, serializingDocumentShapes ); diff --git a/smithy-typescript-protocol-test-codegen/model/my-local-model/main.smithy b/smithy-typescript-protocol-test-codegen/model/my-local-model/main.smithy index ce9a5189b9c..d7cb9f671d9 100644 --- a/smithy-typescript-protocol-test-codegen/model/my-local-model/main.smithy +++ b/smithy-typescript-protocol-test-codegen/model/my-local-model/main.smithy @@ -10,6 +10,7 @@ service XYZService { version: "1.0" operations: [ GetNumbers + TradeEventStream ] } @@ -52,3 +53,28 @@ structure RetryableError {} @error("client") structure HaltError {} + +operation TradeEventStream { + input: TradeEventStreamRequest + output: TradeEventStreamResponse +} + +structure TradeEventStreamRequest { + eventStream: TradeEvents +} + +structure TradeEventStreamResponse { + eventStream: TradeEvents +} + +@streaming +union TradeEvents { + alpha: Alpha + beta: Unit + gamma: Unit +} + +structure Alpha { + id: String + timestamp: Timestamp +} diff --git a/yarn.lock b/yarn.lock index 9365c51f040..45fab0dd8ae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2581,7 +2581,7 @@ __metadata: languageName: unknown linkType: soft -"@smithy/eventstream-serde-browser@workspace:packages/eventstream-serde-browser": +"@smithy/eventstream-serde-browser@workspace:^, @smithy/eventstream-serde-browser@workspace:packages/eventstream-serde-browser": version: 0.0.0-use.local resolution: "@smithy/eventstream-serde-browser@workspace:packages/eventstream-serde-browser" dependencies: @@ -2595,7 +2595,7 @@ __metadata: languageName: unknown linkType: soft -"@smithy/eventstream-serde-config-resolver@workspace:packages/eventstream-serde-config-resolver": +"@smithy/eventstream-serde-config-resolver@workspace:^, @smithy/eventstream-serde-config-resolver@workspace:packages/eventstream-serde-config-resolver": version: 0.0.0-use.local resolution: "@smithy/eventstream-serde-config-resolver@workspace:packages/eventstream-serde-config-resolver" dependencies: @@ -11627,6 +11627,9 @@ __metadata: "@aws-sdk/types": "npm:latest" "@smithy/config-resolver": "workspace:^" "@smithy/core": "workspace:^" + "@smithy/eventstream-serde-browser": "workspace:^" + "@smithy/eventstream-serde-config-resolver": "workspace:^" + "@smithy/eventstream-serde-node": "workspace:^" "@smithy/fetch-http-handler": "workspace:^" "@smithy/hash-node": "workspace:^" "@smithy/invalid-dependency": "workspace:^"