-module(aws@internal@client@runtime). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/aws/internal/client/runtime.gleam"). -export([default_endpoint/2, default_config/3, with_sigv4a_region_set/2, with_sigv4a_path_normalization/2, with_credentials_provider/2, with_endpoint_param/3, with_endpoint_url/2, with_http_send/2, with_streaming_http_send/2, with_http2/1, with_retry_strategy/2, with_max_attempts/2, with_endpoint_rule_set/2, extract_error_type/2, invoke_with_endpoint_params_and_host_prefix/5, invoke_with_endpoint_params/4, invoke/3, invoke_streaming_with_endpoint_params/3, invoke_streaming/2, error_type_matches/2, translate_service_error/4, check_error_type_matches/3]). -export_type([client_config/0, sigv4a_signer/0, client_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Shared runtime for awsJson1_0 + awsJson1_1 generated clients.\n" "\n" " Generated per-service modules carry the per-operation `build_*` /\n" " `parse_*` codec pair plus the service-level metadata (endpoint\n" " prefix, signing name, region). They call into `invoke` here for\n" " everything else: credential resolution, endpoint URL construction,\n" " SigV4 signing, HTTP dispatch, response parsing.\n" "\n" " This keeps the generated code small: one `invoke` call per\n" " operation rather than ~30 lines of glue per op duplicated 57×\n" " across DynamoDB.\n" ). -type client_config() :: {client_config, aws@credentials:provider(), binary(), binary(), binary(), binary(), fun((gleam@http@request:request(bitstring())) -> {ok, gleam@http@response:response(bitstring())} | {error, aws@internal@http_send:http_error()}), fun((gleam@http@request:request(bitstring())) -> {ok, gleam@http@response:response(aws@streaming:streaming_body())} | {error, aws@internal@http_send:http_error()}), fun(() -> binary()), aws@retry:strategy(), gleam@option:option(aws@endpoints:rule_set()), gleam@dict:dict(binary(), aws@endpoints:value()), gleam@option:option(sigv4a_signer())}. -type sigv4a_signer() :: {sigv4a_signer, list(binary()), boolean()}. -type client_error() :: {credentials_error, aws@credentials:provider_error()} | {transport_error, aws@internal@http_send:http_error()} | {decode_error, binary()} | {service_error, integer(), binary(), bitstring()}. -file("src/aws/internal/client/runtime.gleam", 156). -spec default_endpoint(binary(), binary()) -> binary(). default_endpoint(Endpoint_prefix, Region) -> <<<<<<<<"https://"/utf8, Endpoint_prefix/binary>>/binary, "."/utf8>>/binary, Region/binary>>/binary, ".amazonaws.com"/utf8>>. -file("src/aws/internal/client/runtime.gleam", 95). ?DOC( " Sensible default config given a region. Credentials default to\n" " the standard chain (env → web-identity → SSO → profile → process →\n" " ECS → IMDS); callers swap in a custom provider via\n" " `with_credentials_provider`, matching the convention every other\n" " AWS SDK follows.\n" ). -spec default_config(binary(), binary(), binary()) -> client_config(). default_config(Region, Endpoint_prefix, Signing_name) -> {client_config, aws@credentials:default_chain( fun aws@internal@http_send:default_send/1, <<"default"/utf8>> ), Region, Endpoint_prefix, Signing_name, default_endpoint(Endpoint_prefix, Region), fun aws@internal@http_send:default_send/1, fun aws@internal@http_streaming:default_send/1, fun aws_ffi:aws_timestamp/0, aws@retry:standard(), none, maps:new(), none}. -file("src/aws/internal/client/runtime.gleam", 127). ?DOC( " Opt the Client into SigV4a (asymmetric ECDSA P-256) signing for\n" " every request. `region_set` becomes the `X-Amz-Region-Set` header\n" " — single-region callers pass `[\"us-east-1\"]`, multi-region callers\n" " pass the full list. Required for S3 Multi-Region Access Points.\n" "\n" " `normalize_path` defaults to `True`; S3 callers should follow up\n" " with `with_sigv4a_path_normalization(client, False)` so keys\n" " containing `.` / `..` survive the canonical-request step.\n" ). -spec with_sigv4a_region_set(client_config(), list(binary())) -> client_config(). with_sigv4a_region_set(Config, Region_set) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), {some, {sigv4a_signer, Region_set, true}}}. -file("src/aws/internal/client/runtime.gleam", 142). ?DOC( " Override the SigV4a `normalize_path` knob. No-op when the client\n" " hasn't opted into SigV4a yet (`with_sigv4a_region_set` not\n" " called). Pass `False` for S3 — its object-key paths can carry\n" " `.` / `..` that the RFC 3986 dot-segment removal would otherwise\n" " strip.\n" ). -spec with_sigv4a_path_normalization(client_config(), boolean()) -> client_config(). with_sigv4a_path_normalization(Config, Normalize) -> case erlang:element(13, Config) of {some, S} -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), {some, {sigv4a_signer, erlang:element(2, S), Normalize}}}; none -> Config end. -file("src/aws/internal/client/runtime.gleam", 162). ?DOC( " Override the credentials provider — use for non-default profiles,\n" " in-process static creds, or any custom resolution chain.\n" ). -spec with_credentials_provider(client_config(), aws@credentials:provider()) -> client_config(). with_credentials_provider(Config, Provider) -> {client_config, Provider, erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 256). ?DOC( " Set a single client-level endpoint-rule-set parameter (e.g.\n" " `\"UseFIPS\"` -> `BoolVal(True)`). Operation-specific params (S3\n" " `Bucket`, `Key`) are threaded per-call via\n" " `invoke_with_endpoint_params`.\n" ). -spec with_endpoint_param(client_config(), binary(), aws@endpoints:value()) -> client_config(). with_endpoint_param(Config, Name, Value) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), gleam@dict:insert(erlang:element(12, Config), Name, Value), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 183). ?DOC( " Override the request endpoint URL. Used for LocalStack, FIPS\n" " endpoints, custom DNS, and pre-signed-URL replay flows.\n" "\n" " When a Smithy endpoint rule set is attached (the codegen wires\n" " one on every generated service that declares one), the override\n" " is threaded into the rule set as the standard `Endpoint`\n" " parameter rather than replacing `endpoint_url` outright. AWS\n" " rule sets honour this parameter via an early-branch rule like\n" " `case isSet(Endpoint) -> endpoint { url: \"{Endpoint}\" }`, so the\n" " override wins consistently across all services that declare an\n" " `Endpoint` rule-set parameter.\n" "\n" " The static `endpoint_url` is also updated so services without a\n" " rule set continue to honour the override via the fallback path.\n" ). -spec with_endpoint_url(client_config(), binary()) -> client_config(). with_endpoint_url(Config, Url) -> _pipe = {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), Url, erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}, with_endpoint_param(_pipe, <<"Endpoint"/utf8>>, {string_val, Url}). -file("src/aws/internal/client/runtime.gleam", 188). -spec with_http_send( client_config(), fun((gleam@http@request:request(bitstring())) -> {ok, gleam@http@response:response(bitstring())} | {error, aws@internal@http_send:http_error()}) ) -> client_config(). with_http_send(Config, Send) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), Send, erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 196). ?DOC( " Override the streaming HTTP sender. Use for tests (stub the\n" " transport), for forcing the buffered-then-streamed path via\n" " `http_send.lift_to_streaming(custom_buffered)`, or to inject a\n" " future custom transport (proxy, gRPC tunnel, etc.).\n" ). -spec with_streaming_http_send( client_config(), fun((gleam@http@request:request(bitstring())) -> {ok, gleam@http@response:response(aws@streaming:streaming_body())} | {error, aws@internal@http_send:http_error()}) ) -> client_config(). with_streaming_http_send(Config, Send) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), Send, erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 212). ?DOC( " Switch the streaming sender to the HTTP/2 variant. httpc adds\n" " `{http_version, \"HTTP/2\"}` to its option list; servers that don't\n" " speak HTTP/2 negotiate down to HTTP/1.1 via ALPN, so calls keep\n" " working even when the peer doesn't support it. Buffered requests\n" " (`http_send`) are unaffected — HTTP/2 is for high-throughput\n" " streaming endpoints (S3 multipart, Bedrock streaming, Transcribe).\n" "\n" " Pair with `with_streaming_http_send` for finer control (e.g. a\n" " stubbed sender in tests that needs HTTP/2 wiring elsewhere).\n" ). -spec with_http2(client_config()) -> client_config(). with_http2(Config) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), fun aws@internal@http_streaming:default_send_http2/1, erlang:element(9, Config), erlang:element(10, Config), erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 219). ?DOC( " Override the retry strategy used to wrap `http_send`. Pass\n" " `retry.standard()` for the AWS-standard 3-attempt backoff (the\n" " default), or `retry.adaptive(bucket)` to add the token-bucket gate.\n" ). -spec with_retry_strategy(client_config(), aws@retry:strategy()) -> client_config(). with_retry_strategy(Config, Strategy) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), Strategy, erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 233). ?DOC( " Tune just the retry attempt budget without replacing the whole\n" " strategy. Equivalent to\n" " `with_retry_strategy(config, retry.with_max_attempts(config.retry_strategy, n))`,\n" " but reads as a single knob — the common case for production\n" " tuning. Pass `1` to disable retries entirely (single attempt\n" " per request), `5` for long-running batch workloads that tolerate\n" " extra wait, etc.\n" ). -spec with_max_attempts(client_config(), integer()) -> client_config(). with_max_attempts(Config, N) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), aws@retry:with_max_attempts(erlang:element(10, Config), N), erlang:element(11, Config), erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 245). ?DOC( " Attach a Smithy endpoint rule set. When set, the runtime walks the rule\n" " set per request to compute the endpoint URL — the value passed in via\n" " `with_endpoint_url` (or `default_endpoint`) is then ignored except as a\n" " fallback when the rule set is cleared. Use this from generated service\n" " constructors that embed their service's rule set.\n" ). -spec with_endpoint_rule_set(client_config(), aws@endpoints:rule_set()) -> client_config(). with_endpoint_rule_set(Config, Rule_set) -> {client_config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), erlang:element(5, Config), erlang:element(6, Config), erlang:element(7, Config), erlang:element(8, Config), erlang:element(9, Config), erlang:element(10, Config), {some, Rule_set}, erlang:element(12, Config), erlang:element(13, Config)}. -file("src/aws/internal/client/runtime.gleam", 765). -spec normalise_error_type(binary()) -> binary(). normalise_error_type(Raw) -> S = case gleam@string:split_once(Raw, <<":"/utf8>>) of {ok, {Prefix, _}} -> Prefix; {error, _} -> Raw end, S@1 = case gleam@string:split_once(S, <<","/utf8>>) of {ok, {Prefix@1, _}} -> Prefix@1; {error, _} -> S end, case gleam@string:split_once(S@1, <<"#"/utf8>>) of {ok, {_, Local}} -> Local; {error, _} -> S@1 end. -file("src/aws/internal/client/runtime.gleam", 799). ?DOC( " Pull the error code out of a restXml error body. Two shapes appear\n" " in the wild — S3-style `NoSuchBucket...`\n" " and SQS/SNS-style `X......`.\n" " In both cases the first `` element holds the error type, so a\n" " single text search keyed on `` covers both shapes without\n" " dragging in the full XML decoder for an error-only path. The trim\n" " + empty-check rejects `` and ` ` so the\n" " fallback to \"Unknown\" still fires for malformed bodies.\n" ). -spec extract_xml_error_code(binary()) -> {ok, binary()} | {error, nil}. extract_xml_error_code(Body) -> gleam@result:'try'( aws@internal@text_scan:xml_tag_text(Body, <<"Code"/utf8>>), fun(Raw) -> case gleam@string:trim(Raw) of <<""/utf8>> -> {error, nil}; Non_empty -> {ok, Non_empty} end end ). -file("src/aws/internal/client/runtime.gleam", 780). -spec error_type_from_body(binary()) -> binary(). error_type_from_body(Body) -> Found = begin _pipe = aws@internal@text_scan:json_string_after_key( Body, <<"__type"/utf8>> ), _pipe@1 = gleam@result:lazy_or( _pipe, fun() -> aws@internal@text_scan:json_string_after_key( Body, <<"code"/utf8>> ) end ), gleam@result:lazy_or(_pipe@1, fun() -> extract_xml_error_code(Body) end) end, case Found of {ok, V} -> normalise_error_type(V); {error, _} -> <<"Unknown"/utf8>> end. -file("src/aws/internal/client/runtime.gleam", 716). ?DOC( " Pull the wire-error-type local name out of a response. Looks at the\n" " `X-Amzn-Errortype` header first (restJson1, awsJson*); falls back to\n" " the body for `__type` / `code` / `` (covers JSON and XML\n" " error shapes). The returned string is the *local* shape name —\n" " namespace prefix, URI suffix, and Smithy `[Charlie,foo,bar]` suffix\n" " are all stripped. Exposed for codegen-emitted error-shape protocol\n" " test dispatchers; the in-process retry path uses it via the\n" " `ServiceError` discriminator.\n" ). -spec extract_error_type(gleam@dict:dict(binary(), binary()), bitstring()) -> binary(). extract_error_type(Headers, Body) -> case gleam_stdlib:map_get(Headers, <<"x-amzn-errortype"/utf8>>) of {ok, V} -> normalise_error_type(V); {error, _} -> case gleam@bit_array:to_string(Body) of {error, _} -> <<"Unknown"/utf8>>; {ok, Text} -> error_type_from_body(Text) end end. -file("src/aws/internal/client/runtime.gleam", 653). -spec headers_to_dict(list({binary(), binary()})) -> gleam@dict:dict(binary(), binary()). headers_to_dict(Headers) -> gleam@list:fold( Headers, maps:new(), fun(Acc, P) -> gleam@dict:insert( Acc, string:lowercase(erlang:element(1, P)), erlang:element(2, P) ) end ). -file("src/aws/internal/client/runtime.gleam", 638). -spec parse_method(binary()) -> gleam@http:method(). parse_method(Method) -> case string:uppercase(Method) of <<"GET"/utf8>> -> get; <<"POST"/utf8>> -> post; <<"PUT"/utf8>> -> put; <<"DELETE"/utf8>> -> delete; <<"HEAD"/utf8>> -> head; <<"PATCH"/utf8>> -> patch; <<"OPTIONS"/utf8>> -> options; <<"TRACE"/utf8>> -> trace; <<"CONNECT"/utf8>> -> connect; _ -> post end. -file("src/aws/internal/client/runtime.gleam", 509). -spec sign_sigv4( aws@internal@http_request:http_request(), aws@credentials:credentials(), client_config() ) -> aws@internal@http_request:http_request(). sign_sigv4(Unsigned, Creds, Config) -> Opts = {signing_options, (erlang:element(9, Config))(), erlang:element(3, Config), erlang:element(5, Config), true, true, false}, Signing_creds = {signing_credentials, erlang:element(2, Creds), erlang:element(3, Creds), erlang:element(4, Creds)}, aws@internal@sigv4:sign(Unsigned, Signing_creds, Opts). -file("src/aws/internal/client/runtime.gleam", 532). -spec sign_sigv4a( aws@internal@http_request:http_request(), aws@credentials:credentials(), client_config(), sigv4a_signer() ) -> aws@internal@http_request:http_request(). sign_sigv4a(Unsigned, Creds, Config, Signer) -> Private_key = aws@internal@sigv4a:derive_signing_key( erlang:element(2, Creds), erlang:element(3, Creds) ), Sigv4a_creds = {sigv4a_credentials, erlang:element(2, Creds), Private_key, erlang:element(4, Creds)}, Opts = {sigv4a_options, (erlang:element(9, Config))(), erlang:element(2, Signer), erlang:element(5, Config), true, erlang:element(3, Signer), false}, aws@internal@sigv4a:sign_with_credentials(Unsigned, Sigv4a_creds, Opts). -file("src/aws/internal/client/runtime.gleam", 604). -spec host_from_endpoint(binary()) -> binary(). host_from_endpoint(Url) -> After = case gleam@string:split_once(Url, <<"://"/utf8>>) of {ok, {_, Rest}} -> Rest; {error, _} -> Url end, case gleam@string:split_once(After, <<"/"/utf8>>) of {ok, {Host, _}} -> Host; {error, _} -> After end. -file("src/aws/internal/client/runtime.gleam", 626). ?DOC( " Prepend `prefix` to the authority portion of `url`. Scheme + path +\n" " query are preserved. `prefix` is already-substituted (e.g. `\"foo.\"`\n" " — no `{Label}` placeholders left). Mirrors the Rust SDK's\n" " `apply_endpoint_to_request` (`format!(\"{scheme}://{prefix}{authority}{path_and_query}\")`).\n" "\n" " Examples:\n" " `inject_host_prefix(\"https://s3.us-east-1.amazonaws.com/\", \"foo.\")`\n" " → `\"https://foo.s3.us-east-1.amazonaws.com/\"`\n" ). -spec inject_host_prefix(binary(), binary()) -> binary(). inject_host_prefix(Url, Prefix) -> {Scheme, Rest} = case gleam@string:split_once(Url, <<"://"/utf8>>) of {ok, {S, R}} -> {<>, R}; {error, _} -> {<<""/utf8>>, Url} end, {Authority, Path_and_query} = case gleam@string:split_once( Rest, <<"/"/utf8>> ) of {ok, {A, P}} -> {A, <<"/"/utf8, P/binary>>}; {error, _} -> {Rest, <<""/utf8>>} end, <<<<<>/binary, Authority/binary>>/binary, Path_and_query/binary>>. -file("src/aws/internal/client/runtime.gleam", 592). -spec describe_endpoint_error(aws@endpoints:resolve_error()) -> binary(). describe_endpoint_error(Err) -> case Err of {rule_error, M} -> <<"endpoint rule error: "/utf8, M/binary>>; no_match -> <<"endpoint rule set: no match"/utf8>>; {invalid_rule_set, R} -> <<"invalid endpoint rule set: "/utf8, R/binary>>; {unsupported, R@1} -> <<"endpoint unsupported: "/utf8, R@1/binary>>; {missing_parameter, N} -> <<"endpoint parameter missing: "/utf8, N/binary>>; {required_parameter_missing, N@1} -> <<"endpoint required parameter missing: "/utf8, N@1/binary>> end. -file("src/aws/internal/client/runtime.gleam", 588). -spec merge_params( gleam@dict:dict(binary(), aws@endpoints:value()), gleam@dict:dict(binary(), aws@endpoints:value()) ) -> gleam@dict:dict(binary(), aws@endpoints:value()). merge_params(Base, Overlay) -> gleam@dict:fold( Overlay, Base, fun(Acc, K, V) -> gleam@dict:insert(Acc, K, V) end ). -file("src/aws/internal/client/runtime.gleam", 567). ?DOC( " Compute the request URL using the rule set if attached, otherwise fall\n" " back to the static `endpoint_url`. Returns a runtime error if the rule\n" " set can't be resolved — bubbles up as `DecodeError` for now so existing\n" " callers don't need a new variant.\n" ). -spec resolve_endpoint_url( client_config(), gleam@dict:dict(binary(), aws@endpoints:value()) ) -> {ok, binary()} | {error, client_error()}. resolve_endpoint_url(Config, Op_params) -> case erlang:element(11, Config) of none -> {ok, erlang:element(6, Config)}; {some, Rs} -> Params = gleam@dict:insert( merge_params(erlang:element(12, Config), Op_params), <<"Region"/utf8>>, {string_val, erlang:element(3, Config)} ), case aws@endpoints:resolve(Rs, Params) of {ok, Endpoint} -> {ok, erlang:element(2, Endpoint)}; {error, Err} -> {error, {decode_error, describe_endpoint_error(Err)}} end end. -file("src/aws/internal/client/runtime.gleam", 442). -spec prepare_signed_request( client_config(), gleam@dict:dict(binary(), aws@endpoints:value()), gleam@option:option(binary()), {binary(), binary(), gleam@dict:dict(binary(), binary()), bitstring()} ) -> {ok, gleam@http@request:request(bitstring())} | {error, client_error()}. prepare_signed_request(Config, Op_params, Host_prefix, Built) -> {Method, Uri, Headers, Body} = Built, gleam@result:'try'( begin _pipe = aws@credentials:fetch(erlang:element(2, Config)), gleam@result:map_error( _pipe, fun(Field@0) -> {credentials_error, Field@0} end ) end, fun(Creds) -> gleam@result:'try'( resolve_endpoint_url(Config, Op_params), fun(Endpoint_url) -> {Endpoint_url@1, Host} = case Host_prefix of none -> {Endpoint_url, host_from_endpoint(Endpoint_url)}; {some, Prefix} -> Prefixed_url = inject_host_prefix( Endpoint_url, Prefix ), {Prefixed_url, host_from_endpoint(Prefixed_url)} end, Header_pairs = begin _pipe@1 = [{<<"host"/utf8>>, Host} | maps:to_list(Headers)], gleam@list:map( _pipe@1, fun(P) -> {header, erlang:element(1, P), erlang:element(2, P)} end ) end, {Path_only, Query_str} = case gleam@string:split_once( Uri, <<"?"/utf8>> ) of {ok, {P@1, Q}} -> {P@1, Q}; {error, _} -> {Uri, <<""/utf8>>} end, Unsigned = {http_request, Method, Path_only, Query_str, Header_pairs, Body}, Signed = case erlang:element(13, Config) of {some, Signer} -> sign_sigv4a(Unsigned, Creds, Config, Signer); none -> sign_sigv4(Unsigned, Creds, Config) end, Full_url = <>, Base@1 = case gleam@http@request:to(Full_url) of {ok, Base} -> Base; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"aws/internal/client/runtime"/utf8>>, function => <<"prepare_signed_request"/utf8>>, line => 497, value => _assert_fail, start => 19055, 'end' => 19097, pattern_start => 19066, pattern_end => 19074}) end, Http_req = begin _pipe@2 = Base@1, _pipe@3 = gleam@http@request:set_method( _pipe@2, parse_method(Method) ), gleam@http@request:set_body(_pipe@3, Body) end, Http_req@1 = gleam@list:fold( erlang:element(5, Signed), Http_req, fun(R, H) -> gleam@http@request:set_header( R, erlang:element(2, H), erlang:element(3, H) ) end ), {ok, Http_req@1} end ) end ). -file("src/aws/internal/client/runtime.gleam", 306). ?DOC( " `invoke_with_endpoint_params` with an already-substituted host\n" " prefix. Codegen passes `Some(prefix)` for ops carrying\n" " `@smithy.api#endpoint.hostPrefix` — the template (e.g.\n" " `\"{RequestRoute}.\"`) is expanded against the input's `@hostLabel`\n" " members in the generated wrapper, mirroring the Rust SDK's\n" " `read_before_execution` interceptor.\n" ). -spec invoke_with_endpoint_params_and_host_prefix( client_config(), gleam@dict:dict(binary(), aws@endpoints:value()), gleam@option:option(binary()), {binary(), binary(), gleam@dict:dict(binary(), binary()), bitstring()}, fun((integer(), gleam@dict:dict(binary(), binary()), bitstring()) -> {ok, LFD} | {error, binary()}) ) -> {ok, LFD} | {error, client_error()}. invoke_with_endpoint_params_and_host_prefix( Config, Op_params, Host_prefix, Built, Parse ) -> gleam@result:'try'( prepare_signed_request(Config, Op_params, Host_prefix, Built), fun(Http_req) -> Send = aws@retry:with_retry( erlang:element(7, Config), erlang:element(10, Config) ), gleam@result:'try'( begin _pipe = Send(Http_req), gleam@result:map_error( _pipe, fun(Field@0) -> {transport_error, Field@0} end ) end, fun(Resp) -> Resp_headers = headers_to_dict(erlang:element(3, Resp)), case (erlang:element(2, Resp) >= 200) andalso (erlang:element( 2, Resp ) < 300) of true -> _pipe@1 = Parse( erlang:element(2, Resp), Resp_headers, erlang:element(4, Resp) ), gleam@result:map_error( _pipe@1, fun(Reason) -> {decode_error, Reason} end ); false -> Error_type = extract_error_type( Resp_headers, erlang:element(4, Resp) ), {error, {service_error, erlang:element(2, Resp), Error_type, erlang:element(4, Resp)}} end end ) end ). -file("src/aws/internal/client/runtime.gleam", 285). ?DOC( " Same as `invoke` but with extra rule-set parameters merged in for this\n" " operation only — used by generated S3 ops to supply `Bucket`/`Key` etc.\n" " without leaking them onto the client config. If the client has no\n" " `endpoint_rule_set`, `op_params` is ignored (the static `endpoint_url`\n" " is used).\n" ). -spec invoke_with_endpoint_params( client_config(), gleam@dict:dict(binary(), aws@endpoints:value()), {binary(), binary(), gleam@dict:dict(binary(), binary()), bitstring()}, fun((integer(), gleam@dict:dict(binary(), binary()), bitstring()) -> {ok, LET} | {error, binary()}) ) -> {ok, LET} | {error, client_error()}. invoke_with_endpoint_params(Config, Op_params, Built, Parse) -> invoke_with_endpoint_params_and_host_prefix( Config, Op_params, none, Built, Parse ). -file("src/aws/internal/client/runtime.gleam", 272). ?DOC( " Run one operation end-to-end. See module docs for the pipeline.\n" "\n" " Operations that need to thread rule-set parameters known only to the\n" " op itself (e.g. S3's `Bucket`) should use `invoke_with_endpoint_params`\n" " instead and pass those parameters through `op_params`.\n" ). -spec invoke( client_config(), {binary(), binary(), gleam@dict:dict(binary(), binary()), bitstring()}, fun((integer(), gleam@dict:dict(binary(), binary()), bitstring()) -> {ok, LEK} | {error, binary()}) ) -> {ok, LEK} | {error, client_error()}. invoke(Config, Built, Parse) -> invoke_with_endpoint_params(Config, maps:new(), Built, Parse). -file("src/aws/internal/client/runtime.gleam", 411). -spec streaming_error( gleam@http@response:response(aws@streaming:streaming_body()) ) -> client_error(). streaming_error(Resp) -> Resp_headers = headers_to_dict(erlang:element(3, Resp)), case aws@streaming:to_bit_array_max(erlang:element(4, Resp), 1048576) of {ok, Body} -> {service_error, erlang:element(2, Resp), extract_error_type(Resp_headers, Body), Body}; {error, _} -> {decode_error, <<<<"streaming error body exceeded "/utf8, (erlang:integer_to_binary(1048576))/binary>>/binary, " bytes — refusing to materialise for typed-error extraction"/utf8>>} end. -file("src/aws/internal/client/runtime.gleam", 377). ?DOC( " `invoke_streaming` with per-op endpoint-rule-set parameters (the\n" " streaming-side counterpart to `invoke_with_endpoint_params`).\n" ). -spec invoke_streaming_with_endpoint_params( client_config(), gleam@dict:dict(binary(), aws@endpoints:value()), {binary(), binary(), gleam@dict:dict(binary(), binary()), bitstring()} ) -> {ok, aws@streaming:response()} | {error, client_error()}. invoke_streaming_with_endpoint_params(Config, Op_params, Built) -> gleam@result:'try'( prepare_signed_request(Config, Op_params, none, Built), fun(Http_req) -> gleam@result:'try'( begin _pipe = (erlang:element(8, Config))(Http_req), gleam@result:map_error( _pipe, fun(Field@0) -> {transport_error, Field@0} end ) end, fun(Resp) -> case (erlang:element(2, Resp) >= 200) andalso (erlang:element( 2, Resp ) < 300) of true -> {ok, {response, erlang:element(2, Resp), erlang:element(3, Resp), erlang:element(4, Resp)}}; false -> {error, streaming_error(Resp)} end end ) end ). -file("src/aws/internal/client/runtime.gleam", 368). ?DOC( " Streaming-response variant of `invoke`. Builds + signs the\n" " request exactly like `invoke`, but dispatches through\n" " `streaming_http_send` (chunked transport) and returns the raw\n" " `Response(StreamingBody)` so callers can consume the body\n" " incrementally — fold chunk-by-chunk via `streaming.fold_chunks`,\n" " decode event-stream frames via `event_stream.fold_events`, or\n" " stream-to-disk without buffering.\n" "\n" " Used by generated codegen for operations whose output carries\n" " `@streaming` — `S3.GetObject` for multi-GB downloads,\n" " `Transcribe.StartStreamTranscription` and `Kinesis.SubscribeToShard`\n" " for event-stream responses, etc.\n" "\n" " Error responses (non-2xx) are materialised via\n" " `streaming.to_bit_array_max(body, 1 MiB)` so `error_type`\n" " extraction works on the JSON/XML error body the same way as\n" " `invoke`. A response body that exceeds the 1 MiB cap on the\n" " error path surfaces as `DecodeError` since we can't safely\n" " extract a typed error from an oversized error body.\n" "\n" " Retry is intentionally NOT wrapped around `streaming_http_send`\n" " at this layer — replaying a streaming request after a transient\n" " failure is op-specific (idempotent vs. mutating). Callers that\n" " want retry on a streaming op should layer it themselves or\n" " drop down to the buffered `invoke`.\n" ). -spec invoke_streaming( client_config(), {binary(), binary(), gleam@dict:dict(binary(), binary()), bitstring()} ) -> {ok, aws@streaming:response()} | {error, client_error()}. invoke_streaming(Config, Built) -> invoke_streaming_with_endpoint_params(Config, maps:new(), Built). -file("src/aws/internal/client/runtime.gleam", 665). ?DOC( " Match an AWS `error_type` wire value against a local Smithy\n" " shape name. Used by the generated per-op `translate__error`\n" " dispatchers. `error_type` already passes through\n" " `normalise_error_type` (namespace + suffix stripped) at the\n" " invoke layer, so a plain equality check suffices; we keep this\n" " behind a helper to give the codegen one stable call-site.\n" ). -spec error_type_matches(binary(), binary()) -> boolean(). error_type_matches(Error_type, Local) -> Error_type =:= Local. -file("src/aws/internal/client/runtime.gleam", 681). ?DOC( " Generic translator from the runtime's `ClientError` to a per-op\n" " typed-error enum. Each generated `translate__error` is a\n" " one-liner that supplies its operation's decoder table plus\n" " constructors for the always-present `*Transport` and `*Unknown`\n" " variants. Saves ~15–25 LOC/op vs the previous open-coded nested\n" " match — see Pass 3c in plan.md.\n" "\n" " `decoders` is a list of `(wire_error_type_local_name, decoder)`\n" " pairs. The first pair whose error_type matches gets to attempt the\n" " decode; if its decoder returns `Error(Nil)`, we fall back to\n" " `on_unknown` with the textified body so the caller still sees\n" " something useful instead of a panic.\n" ). -spec translate_service_error( client_error(), list({binary(), fun((binary()) -> {ok, LGC} | {error, nil})}), fun((binary()) -> LGC), fun((binary(), integer(), binary()) -> LGC) ) -> LGC. translate_service_error(Err, Decoders, On_transport, On_unknown) -> case Err of {service_error, S, Et, B} -> Text = case gleam@bit_array:to_string(B) of {ok, T} -> T; {error, _} -> <<""/utf8>> end, case gleam@list:find( Decoders, fun(D) -> error_type_matches(Et, erlang:element(1, D)) end ) of {ok, {_, Decoder}} -> case Decoder(Text) of {ok, V} -> V; {error, _} -> On_unknown(Et, S, Text) end; {error, _} -> On_unknown(Et, S, Text) end; {transport_error, _} -> On_transport(<<"transport error"/utf8>>); {credentials_error, _} -> On_transport(<<"credentials error"/utf8>>); {decode_error, R} -> On_transport(<<"decode: "/utf8, R/binary>>) end. -file("src/aws/internal/client/runtime.gleam", 743). ?DOC( " Discriminator check for protocol-test error-shape dispatchers. Used\n" " by the generated `parse__response` function: if the wire-side\n" " discriminator (header or body) resolves to `expected_local`, the\n" " response was routed to the right error shape and the dispatcher\n" " reports `Ok(Nil)`. The runner's response-side assertion is binary\n" " — `Ok` vs `Error` — so returning `Nil` is enough.\n" "\n" " The runner hands fixture headers through with their literal-case\n" " keys (`X-Amzn-Errortype`), but `extract_error_type` expects the\n" " lowercased form that the real-request path produces via\n" " `headers_to_dict`. We lowercase here so the helper matches HTTP's\n" " case-insensitive header semantics regardless of which call-site\n" " invokes it.\n" ). -spec check_error_type_matches( gleam@dict:dict(binary(), binary()), bitstring(), binary() ) -> {ok, nil} | {error, binary()}. check_error_type_matches(Headers, Body, Expected_local) -> Lower = gleam@dict:fold( Headers, maps:new(), fun(Acc, K, V) -> gleam@dict:insert(Acc, string:lowercase(K), V) end ), Extracted = extract_error_type(Lower, Body), case Extracted =:= Expected_local of true -> {ok, nil}; false -> {error, <<<<<<"error type mismatch: expected "/utf8, Expected_local/binary>>/binary, ", got "/utf8>>/binary, Extracted/binary>>} end.