UEA-Prodem
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# @smithy/core
|
||||
|
||||
[](https://www.npmjs.com/package/@smithy/core)
|
||||
[](https://www.npmjs.com/package/@smithy/core)
|
||||
|
||||
### :warning: Internal API :warning:
|
||||
|
||||
> This is an internal package.
|
||||
> That means this is used as a dependency for other, public packages, but
|
||||
> should not be taken directly as a dependency in your application's `package.json`.
|
||||
|
||||
> If you are updating the version of this package, for example to bring in a
|
||||
> bug-fix, you should do so by updating your application lockfile with
|
||||
> e.g. `npm up @scope/package` or equivalent command in another
|
||||
> package manager, rather than taking a direct dependency.
|
||||
|
||||
---
|
||||
|
||||
This package provides common or core functionality for generic Smithy clients.
|
||||
|
||||
You do not need to explicitly install this package, since it will be installed during code generation if used.
|
||||
|
||||
## Development of `@smithy/core` submodules
|
||||
|
||||
Core submodules are organized for distribution via the `package.json` `exports` field.
|
||||
|
||||
`exports` is supported by default by the latest Node.js, webpack, and esbuild. For react-native, it can be
|
||||
enabled via instructions found at [reactnative.dev/blog](https://reactnative.dev/blog/2023/06/21/package-exports-support), but we also provide a compatibility redirect.
|
||||
|
||||
Think of `@smithy/core` as a mono-package within the monorepo.
|
||||
It preserves the benefits of modularization, for example to optimize Node.js initialization speed,
|
||||
while making it easier to have a consistent version of core dependencies, reducing package sprawl when
|
||||
installing a Smithy runtime client.
|
||||
|
||||
### Guide for submodules
|
||||
|
||||
- Each `index.ts` file corresponding to the pattern `./src/submodules/<MODULE_NAME>/index.ts` will be
|
||||
published as a separate `dist-cjs` bundled submodule index using the `Inliner.js` build script.
|
||||
- create a folder as `./src/submodules/<SUBMODULE>` including an `index.ts` file and a `README.md` file.
|
||||
- The linter will throw an error on missing submodule metadata in `package.json` and the various `tsconfig.json` files, but it will automatically fix them if possible.
|
||||
- a submodule is equivalent to a standalone `@smithy/<pkg>` package in that importing it in Node.js will resolve a separate bundle.
|
||||
- submodules may not relatively import files from other submodules. Instead, directly use the `@scope/pkg/submodule` name as the import.
|
||||
- The linter will check for this and throw an error.
|
||||
- To the extent possible, correctly declaring submodule metadata is validated by the linter in `@smithy/core`.
|
||||
The linter runs during `yarn build` and also as `yarn lint`.
|
||||
|
||||
### When should I create an `@smithy/core/submodule` vs. `@smithy/new-package`?
|
||||
|
||||
Keep in mind that the core package is installed by all downstream clients.
|
||||
|
||||
If the component functionality is upstream of multiple clients, it is
|
||||
a good candidate for a core submodule. For example, if `middleware-retry` had been written
|
||||
after the support for submodules was added, it would have been a submodule.
|
||||
|
||||
If the component's functionality is downstream of a client (rare), or only expected to be used by a very small
|
||||
subset of clients, it could be written as a standalone package.
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
export * from "./dist-types/submodules/cbor/index";
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
module.exports = require("./dist-cjs/submodules/cbor/index.js");
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
export * from "./dist-types/submodules/checksum/index";
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
module.exports = require("./dist-cjs/submodules/checksum/index.js");
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
export * from "./dist-types/submodules/client/index";
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
module.exports = require("./dist-cjs/submodules/client/index.js");
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
export * from "./dist-types/submodules/config/index";
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Do not edit:
|
||||
* This is a compatibility redirect for contexts that do not understand package.json exports field.
|
||||
*/
|
||||
module.exports = require("./dist-cjs/submodules/config/index.js");
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
'use strict';
|
||||
|
||||
var transport = require('@smithy/core/transport');
|
||||
var protocols = require('@smithy/core/protocols');
|
||||
var types = require('@smithy/types');
|
||||
var client = require('@smithy/core/client');
|
||||
|
||||
const resolveAuthOptions = (candidateAuthOptions, authSchemePreference) => {
|
||||
if (!authSchemePreference || authSchemePreference.length === 0) {
|
||||
return candidateAuthOptions;
|
||||
}
|
||||
const preferredAuthOptions = [];
|
||||
for (const preferredSchemeName of authSchemePreference) {
|
||||
for (const candidateAuthOption of candidateAuthOptions) {
|
||||
const candidateAuthSchemeName = candidateAuthOption.schemeId.split("#")[1];
|
||||
if (candidateAuthSchemeName === preferredSchemeName) {
|
||||
preferredAuthOptions.push(candidateAuthOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const candidateAuthOption of candidateAuthOptions) {
|
||||
if (!preferredAuthOptions.find(({ schemeId }) => schemeId === candidateAuthOption.schemeId)) {
|
||||
preferredAuthOptions.push(candidateAuthOption);
|
||||
}
|
||||
}
|
||||
return preferredAuthOptions;
|
||||
};
|
||||
|
||||
function convertHttpAuthSchemesToMap(httpAuthSchemes) {
|
||||
const map = new Map();
|
||||
for (const scheme of httpAuthSchemes) {
|
||||
map.set(scheme.schemeId, scheme);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
const httpAuthSchemeMiddleware = (config, mwOptions) => (next, context) => async (args) => {
|
||||
const options = config.httpAuthSchemeProvider(await mwOptions.httpAuthSchemeParametersProvider(config, context, args.input));
|
||||
const authSchemePreference = config.authSchemePreference ? await config.authSchemePreference() : [];
|
||||
const resolvedOptions = resolveAuthOptions(options, authSchemePreference);
|
||||
const authSchemes = convertHttpAuthSchemesToMap(config.httpAuthSchemes);
|
||||
const smithyContext = client.getSmithyContext(context);
|
||||
const failureReasons = [];
|
||||
for (const option of resolvedOptions) {
|
||||
const scheme = authSchemes.get(option.schemeId);
|
||||
if (!scheme) {
|
||||
failureReasons.push(`HttpAuthScheme \`${option.schemeId}\` was not enabled for this service.`);
|
||||
continue;
|
||||
}
|
||||
const identityProvider = scheme.identityProvider(await mwOptions.identityProviderConfigProvider(config));
|
||||
if (!identityProvider) {
|
||||
failureReasons.push(`HttpAuthScheme \`${option.schemeId}\` did not have an IdentityProvider configured.`);
|
||||
continue;
|
||||
}
|
||||
const { identityProperties = {}, signingProperties = {} } = option.propertiesExtractor?.(config, context) || {};
|
||||
option.identityProperties = Object.assign(option.identityProperties || {}, identityProperties);
|
||||
option.signingProperties = Object.assign(option.signingProperties || {}, signingProperties);
|
||||
smithyContext.selectedHttpAuthScheme = {
|
||||
httpAuthOption: option,
|
||||
identity: await identityProvider(option.identityProperties),
|
||||
signer: scheme.signer,
|
||||
};
|
||||
break;
|
||||
}
|
||||
if (!smithyContext.selectedHttpAuthScheme) {
|
||||
throw new Error(failureReasons.join("\n"));
|
||||
}
|
||||
return next(args);
|
||||
};
|
||||
|
||||
const httpAuthSchemeEndpointRuleSetMiddlewareOptions = {
|
||||
step: "serialize",
|
||||
tags: ["HTTP_AUTH_SCHEME"],
|
||||
name: "httpAuthSchemeMiddleware",
|
||||
override: true,
|
||||
relation: "before",
|
||||
toMiddleware: "endpointV2Middleware",
|
||||
};
|
||||
const getHttpAuthSchemeEndpointRuleSetPlugin = (config, { httpAuthSchemeParametersProvider, identityProviderConfigProvider, }) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(httpAuthSchemeMiddleware(config, {
|
||||
httpAuthSchemeParametersProvider,
|
||||
identityProviderConfigProvider,
|
||||
}), httpAuthSchemeEndpointRuleSetMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
|
||||
const httpAuthSchemeMiddlewareOptions = {
|
||||
step: "serialize",
|
||||
tags: ["HTTP_AUTH_SCHEME"],
|
||||
name: "httpAuthSchemeMiddleware",
|
||||
override: true,
|
||||
relation: "before",
|
||||
toMiddleware: "serializerMiddleware",
|
||||
};
|
||||
const getHttpAuthSchemePlugin = (config, { httpAuthSchemeParametersProvider, identityProviderConfigProvider, }) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(httpAuthSchemeMiddleware(config, {
|
||||
httpAuthSchemeParametersProvider,
|
||||
identityProviderConfigProvider,
|
||||
}), httpAuthSchemeMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
|
||||
const defaultErrorHandler = (signingProperties) => (error) => {
|
||||
throw error;
|
||||
};
|
||||
const defaultSuccessHandler = (httpResponse, signingProperties) => { };
|
||||
const httpSigningMiddleware = (config) => (next, context) => async (args) => {
|
||||
if (!protocols.HttpRequest.isInstance(args.request)) {
|
||||
return next(args);
|
||||
}
|
||||
const smithyContext = client.getSmithyContext(context);
|
||||
const scheme = smithyContext.selectedHttpAuthScheme;
|
||||
if (!scheme) {
|
||||
throw new Error(`No HttpAuthScheme was selected: unable to sign request`);
|
||||
}
|
||||
const { httpAuthOption: { signingProperties = {} }, identity, signer, } = scheme;
|
||||
const output = await next({
|
||||
...args,
|
||||
request: await signer.sign(args.request, identity, signingProperties),
|
||||
}).catch((signer.errorHandler || defaultErrorHandler)(signingProperties));
|
||||
(signer.successHandler || defaultSuccessHandler)(output.response, signingProperties);
|
||||
return output;
|
||||
};
|
||||
|
||||
const httpSigningMiddlewareOptions = {
|
||||
step: "finalizeRequest",
|
||||
tags: ["HTTP_SIGNING"],
|
||||
name: "httpSigningMiddleware",
|
||||
aliases: ["apiKeyMiddleware", "tokenMiddleware", "awsAuthMiddleware"],
|
||||
override: true,
|
||||
relation: "after",
|
||||
toMiddleware: "retryMiddleware",
|
||||
};
|
||||
const getHttpSigningPlugin = (config) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(httpSigningMiddleware(), httpSigningMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
|
||||
const normalizeProvider = (input) => {
|
||||
if (typeof input === "function")
|
||||
return input;
|
||||
const promisified = Promise.resolve(input);
|
||||
return () => promisified;
|
||||
};
|
||||
|
||||
const makePagedClientRequest = async (CommandCtor, client, input, withCommand = (_) => _, ...args) => {
|
||||
let command = new CommandCtor(input);
|
||||
command = withCommand(command) ?? command;
|
||||
return await client.send(command, ...args);
|
||||
};
|
||||
function createPaginator(ClientCtor, CommandCtor, inputTokenName, outputTokenName, pageSizeTokenName) {
|
||||
return async function* paginateOperation(config, input, ...additionalArguments) {
|
||||
const _input = input;
|
||||
let token = config.startingToken ?? _input[inputTokenName];
|
||||
let hasNext = true;
|
||||
let page;
|
||||
while (hasNext) {
|
||||
_input[inputTokenName] = token;
|
||||
if (pageSizeTokenName) {
|
||||
_input[pageSizeTokenName] = _input[pageSizeTokenName] ?? config.pageSize;
|
||||
}
|
||||
if (config.client instanceof ClientCtor) {
|
||||
page = await makePagedClientRequest(CommandCtor, config.client, input, config.withCommand, ...additionalArguments);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Invalid client, expected instance of ${ClientCtor.name}`);
|
||||
}
|
||||
yield page;
|
||||
const prevToken = token;
|
||||
token = get(page, outputTokenName);
|
||||
hasNext = !!(token && (!config.stopOnSameToken || token !== prevToken));
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
const get = (fromObject, path) => {
|
||||
let cursor = fromObject;
|
||||
const pathComponents = path.split(".");
|
||||
for (const step of pathComponents) {
|
||||
if (!cursor || typeof cursor !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
cursor = cursor[step];
|
||||
}
|
||||
return cursor;
|
||||
};
|
||||
|
||||
function setFeature(context, feature, value) {
|
||||
if (!context.__smithy_context) {
|
||||
context.__smithy_context = {
|
||||
features: {},
|
||||
};
|
||||
}
|
||||
else if (!context.__smithy_context.features) {
|
||||
context.__smithy_context.features = {};
|
||||
}
|
||||
context.__smithy_context.features[feature] = value;
|
||||
}
|
||||
|
||||
class DefaultIdentityProviderConfig {
|
||||
authSchemes = new Map();
|
||||
constructor(config) {
|
||||
for (const key in config) {
|
||||
const value = config[key];
|
||||
if (value !== undefined) {
|
||||
this.authSchemes.set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
getIdentityProvider(schemeId) {
|
||||
return this.authSchemes.get(schemeId);
|
||||
}
|
||||
}
|
||||
|
||||
class HttpApiKeyAuthSigner {
|
||||
async sign(httpRequest, identity, signingProperties) {
|
||||
if (!signingProperties) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `name` and `in` signer properties are missing");
|
||||
}
|
||||
if (!signingProperties.name) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `name` signer property is missing");
|
||||
}
|
||||
if (!signingProperties.in) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `in` signer property is missing");
|
||||
}
|
||||
if (!identity.apiKey) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `apiKey` is not defined");
|
||||
}
|
||||
const clonedRequest = protocols.HttpRequest.clone(httpRequest);
|
||||
if (signingProperties.in === types.HttpApiKeyAuthLocation.QUERY) {
|
||||
clonedRequest.query[signingProperties.name] = identity.apiKey;
|
||||
}
|
||||
else if (signingProperties.in === types.HttpApiKeyAuthLocation.HEADER) {
|
||||
clonedRequest.headers[signingProperties.name] = signingProperties.scheme
|
||||
? `${signingProperties.scheme} ${identity.apiKey}`
|
||||
: identity.apiKey;
|
||||
}
|
||||
else {
|
||||
throw new Error("request can only be signed with `apiKey` locations `query` or `header`, " +
|
||||
"but found: `" +
|
||||
signingProperties.in +
|
||||
"`");
|
||||
}
|
||||
return clonedRequest;
|
||||
}
|
||||
}
|
||||
|
||||
class HttpBearerAuthSigner {
|
||||
async sign(httpRequest, identity, signingProperties) {
|
||||
const clonedRequest = protocols.HttpRequest.clone(httpRequest);
|
||||
if (!identity.token) {
|
||||
throw new Error("request could not be signed with `token` since the `token` is not defined");
|
||||
}
|
||||
clonedRequest.headers["Authorization"] = `Bearer ${identity.token}`;
|
||||
return clonedRequest;
|
||||
}
|
||||
}
|
||||
|
||||
class NoAuthSigner {
|
||||
async sign(httpRequest, identity, signingProperties) {
|
||||
return httpRequest;
|
||||
}
|
||||
}
|
||||
|
||||
const createIsIdentityExpiredFunction = (expirationMs) => function isIdentityExpired(identity) {
|
||||
return doesIdentityRequireRefresh(identity) && identity.expiration.getTime() - Date.now() < expirationMs;
|
||||
};
|
||||
const EXPIRATION_MS = 300_000;
|
||||
const isIdentityExpired = createIsIdentityExpiredFunction(EXPIRATION_MS);
|
||||
const doesIdentityRequireRefresh = (identity) => identity.expiration !== undefined;
|
||||
const memoizeIdentityProvider = (provider, isExpired, requiresRefresh) => {
|
||||
if (provider === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const normalizedProvider = typeof provider !== "function" ? async () => Promise.resolve(provider) : provider;
|
||||
let resolved;
|
||||
let pending;
|
||||
let hasResult;
|
||||
let isConstant = false;
|
||||
const coalesceProvider = async (options) => {
|
||||
if (!pending) {
|
||||
pending = normalizedProvider(options);
|
||||
}
|
||||
try {
|
||||
resolved = await pending;
|
||||
hasResult = true;
|
||||
isConstant = false;
|
||||
}
|
||||
finally {
|
||||
pending = undefined;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
if (isExpired === undefined) {
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider(options);
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
}
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider(options);
|
||||
}
|
||||
if (isConstant) {
|
||||
return resolved;
|
||||
}
|
||||
if (!requiresRefresh(resolved)) {
|
||||
isConstant = true;
|
||||
return resolved;
|
||||
}
|
||||
if (isExpired(resolved)) {
|
||||
await coalesceProvider(options);
|
||||
return resolved;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
};
|
||||
|
||||
exports.getSmithyContext = transport.getSmithyContext;
|
||||
exports.requestBuilder = protocols.requestBuilder;
|
||||
exports.DefaultIdentityProviderConfig = DefaultIdentityProviderConfig;
|
||||
exports.EXPIRATION_MS = EXPIRATION_MS;
|
||||
exports.HttpApiKeyAuthSigner = HttpApiKeyAuthSigner;
|
||||
exports.HttpBearerAuthSigner = HttpBearerAuthSigner;
|
||||
exports.NoAuthSigner = NoAuthSigner;
|
||||
exports.createIsIdentityExpiredFunction = createIsIdentityExpiredFunction;
|
||||
exports.createPaginator = createPaginator;
|
||||
exports.doesIdentityRequireRefresh = doesIdentityRequireRefresh;
|
||||
exports.getHttpAuthSchemeEndpointRuleSetPlugin = getHttpAuthSchemeEndpointRuleSetPlugin;
|
||||
exports.getHttpAuthSchemePlugin = getHttpAuthSchemePlugin;
|
||||
exports.getHttpSigningPlugin = getHttpSigningPlugin;
|
||||
exports.httpAuthSchemeEndpointRuleSetMiddlewareOptions = httpAuthSchemeEndpointRuleSetMiddlewareOptions;
|
||||
exports.httpAuthSchemeMiddleware = httpAuthSchemeMiddleware;
|
||||
exports.httpAuthSchemeMiddlewareOptions = httpAuthSchemeMiddlewareOptions;
|
||||
exports.httpSigningMiddleware = httpSigningMiddleware;
|
||||
exports.httpSigningMiddlewareOptions = httpSigningMiddlewareOptions;
|
||||
exports.isIdentityExpired = isIdentityExpired;
|
||||
exports.memoizeIdentityProvider = memoizeIdentityProvider;
|
||||
exports.normalizeProvider = normalizeProvider;
|
||||
exports.setFeature = setFeature;
|
||||
+1110
File diff suppressed because it is too large
Load Diff
+202
@@ -0,0 +1,202 @@
|
||||
'use strict';
|
||||
|
||||
var serde = require('@smithy/core/serde');
|
||||
|
||||
async function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
||||
const size = blob.size;
|
||||
let totalBytesRead = 0;
|
||||
while (totalBytesRead < size) {
|
||||
const slice = blob.slice(totalBytesRead, Math.min(size, totalBytesRead + chunkSize));
|
||||
onChunk(new Uint8Array(await slice.arrayBuffer()));
|
||||
totalBytesRead += slice.size;
|
||||
}
|
||||
}
|
||||
|
||||
const blobHasher = async function blobHasher(hashCtor, blob) {
|
||||
const hash = new hashCtor();
|
||||
await blobReader(blob, (chunk) => {
|
||||
hash.update(chunk);
|
||||
});
|
||||
return hash.digest();
|
||||
};
|
||||
|
||||
const BLOCK_SIZE = 64;
|
||||
const DIGEST_LENGTH = 16;
|
||||
const INIT = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
|
||||
|
||||
class Md5 {
|
||||
state;
|
||||
buffer;
|
||||
bufferLength;
|
||||
bytesHashed;
|
||||
finished;
|
||||
constructor() {
|
||||
this.reset();
|
||||
}
|
||||
update(sourceData) {
|
||||
if (isEmptyData(sourceData)) {
|
||||
return;
|
||||
}
|
||||
else if (this.finished) {
|
||||
throw new Error("Attempted to update an already finished hash.");
|
||||
}
|
||||
const data = convertToBuffer(sourceData);
|
||||
let position = 0;
|
||||
let { byteLength } = data;
|
||||
this.bytesHashed += byteLength;
|
||||
while (byteLength > 0) {
|
||||
this.buffer.setUint8(this.bufferLength++, data[position++]);
|
||||
byteLength--;
|
||||
if (this.bufferLength === BLOCK_SIZE) {
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
async digest() {
|
||||
if (!this.finished) {
|
||||
const { buffer, bufferLength: undecoratedLength, bytesHashed } = this;
|
||||
const bitsHashed = bytesHashed * 8;
|
||||
buffer.setUint8(this.bufferLength++, 0b10000000);
|
||||
if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
buffer.setUint32(BLOCK_SIZE - 8, bitsHashed >>> 0, true);
|
||||
buffer.setUint32(BLOCK_SIZE - 4, Math.floor(bitsHashed / 0x100000000), true);
|
||||
this.hashBuffer();
|
||||
this.finished = true;
|
||||
}
|
||||
const out = new DataView(new ArrayBuffer(DIGEST_LENGTH));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out.setUint32(i * 4, this.state[i], true);
|
||||
}
|
||||
return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
||||
}
|
||||
hashBuffer() {
|
||||
const { buffer, state } = this;
|
||||
let a = state[0], b = state[1], c = state[2], d = state[3];
|
||||
a = ff(a, b, c, d, buffer.getUint32(0, true), 7, 0xd76aa478);
|
||||
d = ff(d, a, b, c, buffer.getUint32(4, true), 12, 0xe8c7b756);
|
||||
c = ff(c, d, a, b, buffer.getUint32(8, true), 17, 0x242070db);
|
||||
b = ff(b, c, d, a, buffer.getUint32(12, true), 22, 0xc1bdceee);
|
||||
a = ff(a, b, c, d, buffer.getUint32(16, true), 7, 0xf57c0faf);
|
||||
d = ff(d, a, b, c, buffer.getUint32(20, true), 12, 0x4787c62a);
|
||||
c = ff(c, d, a, b, buffer.getUint32(24, true), 17, 0xa8304613);
|
||||
b = ff(b, c, d, a, buffer.getUint32(28, true), 22, 0xfd469501);
|
||||
a = ff(a, b, c, d, buffer.getUint32(32, true), 7, 0x698098d8);
|
||||
d = ff(d, a, b, c, buffer.getUint32(36, true), 12, 0x8b44f7af);
|
||||
c = ff(c, d, a, b, buffer.getUint32(40, true), 17, 0xffff5bb1);
|
||||
b = ff(b, c, d, a, buffer.getUint32(44, true), 22, 0x895cd7be);
|
||||
a = ff(a, b, c, d, buffer.getUint32(48, true), 7, 0x6b901122);
|
||||
d = ff(d, a, b, c, buffer.getUint32(52, true), 12, 0xfd987193);
|
||||
c = ff(c, d, a, b, buffer.getUint32(56, true), 17, 0xa679438e);
|
||||
b = ff(b, c, d, a, buffer.getUint32(60, true), 22, 0x49b40821);
|
||||
a = gg(a, b, c, d, buffer.getUint32(4, true), 5, 0xf61e2562);
|
||||
d = gg(d, a, b, c, buffer.getUint32(24, true), 9, 0xc040b340);
|
||||
c = gg(c, d, a, b, buffer.getUint32(44, true), 14, 0x265e5a51);
|
||||
b = gg(b, c, d, a, buffer.getUint32(0, true), 20, 0xe9b6c7aa);
|
||||
a = gg(a, b, c, d, buffer.getUint32(20, true), 5, 0xd62f105d);
|
||||
d = gg(d, a, b, c, buffer.getUint32(40, true), 9, 0x02441453);
|
||||
c = gg(c, d, a, b, buffer.getUint32(60, true), 14, 0xd8a1e681);
|
||||
b = gg(b, c, d, a, buffer.getUint32(16, true), 20, 0xe7d3fbc8);
|
||||
a = gg(a, b, c, d, buffer.getUint32(36, true), 5, 0x21e1cde6);
|
||||
d = gg(d, a, b, c, buffer.getUint32(56, true), 9, 0xc33707d6);
|
||||
c = gg(c, d, a, b, buffer.getUint32(12, true), 14, 0xf4d50d87);
|
||||
b = gg(b, c, d, a, buffer.getUint32(32, true), 20, 0x455a14ed);
|
||||
a = gg(a, b, c, d, buffer.getUint32(52, true), 5, 0xa9e3e905);
|
||||
d = gg(d, a, b, c, buffer.getUint32(8, true), 9, 0xfcefa3f8);
|
||||
c = gg(c, d, a, b, buffer.getUint32(28, true), 14, 0x676f02d9);
|
||||
b = gg(b, c, d, a, buffer.getUint32(48, true), 20, 0x8d2a4c8a);
|
||||
a = hh(a, b, c, d, buffer.getUint32(20, true), 4, 0xfffa3942);
|
||||
d = hh(d, a, b, c, buffer.getUint32(32, true), 11, 0x8771f681);
|
||||
c = hh(c, d, a, b, buffer.getUint32(44, true), 16, 0x6d9d6122);
|
||||
b = hh(b, c, d, a, buffer.getUint32(56, true), 23, 0xfde5380c);
|
||||
a = hh(a, b, c, d, buffer.getUint32(4, true), 4, 0xa4beea44);
|
||||
d = hh(d, a, b, c, buffer.getUint32(16, true), 11, 0x4bdecfa9);
|
||||
c = hh(c, d, a, b, buffer.getUint32(28, true), 16, 0xf6bb4b60);
|
||||
b = hh(b, c, d, a, buffer.getUint32(40, true), 23, 0xbebfbc70);
|
||||
a = hh(a, b, c, d, buffer.getUint32(52, true), 4, 0x289b7ec6);
|
||||
d = hh(d, a, b, c, buffer.getUint32(0, true), 11, 0xeaa127fa);
|
||||
c = hh(c, d, a, b, buffer.getUint32(12, true), 16, 0xd4ef3085);
|
||||
b = hh(b, c, d, a, buffer.getUint32(24, true), 23, 0x04881d05);
|
||||
a = hh(a, b, c, d, buffer.getUint32(36, true), 4, 0xd9d4d039);
|
||||
d = hh(d, a, b, c, buffer.getUint32(48, true), 11, 0xe6db99e5);
|
||||
c = hh(c, d, a, b, buffer.getUint32(60, true), 16, 0x1fa27cf8);
|
||||
b = hh(b, c, d, a, buffer.getUint32(8, true), 23, 0xc4ac5665);
|
||||
a = ii(a, b, c, d, buffer.getUint32(0, true), 6, 0xf4292244);
|
||||
d = ii(d, a, b, c, buffer.getUint32(28, true), 10, 0x432aff97);
|
||||
c = ii(c, d, a, b, buffer.getUint32(56, true), 15, 0xab9423a7);
|
||||
b = ii(b, c, d, a, buffer.getUint32(20, true), 21, 0xfc93a039);
|
||||
a = ii(a, b, c, d, buffer.getUint32(48, true), 6, 0x655b59c3);
|
||||
d = ii(d, a, b, c, buffer.getUint32(12, true), 10, 0x8f0ccc92);
|
||||
c = ii(c, d, a, b, buffer.getUint32(40, true), 15, 0xffeff47d);
|
||||
b = ii(b, c, d, a, buffer.getUint32(4, true), 21, 0x85845dd1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(32, true), 6, 0x6fa87e4f);
|
||||
d = ii(d, a, b, c, buffer.getUint32(60, true), 10, 0xfe2ce6e0);
|
||||
c = ii(c, d, a, b, buffer.getUint32(24, true), 15, 0xa3014314);
|
||||
b = ii(b, c, d, a, buffer.getUint32(52, true), 21, 0x4e0811a1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(16, true), 6, 0xf7537e82);
|
||||
d = ii(d, a, b, c, buffer.getUint32(44, true), 10, 0xbd3af235);
|
||||
c = ii(c, d, a, b, buffer.getUint32(8, true), 15, 0x2ad7d2bb);
|
||||
b = ii(b, c, d, a, buffer.getUint32(36, true), 21, 0xeb86d391);
|
||||
state[0] = (a + state[0]) & 0xffffffff;
|
||||
state[1] = (b + state[1]) & 0xffffffff;
|
||||
state[2] = (c + state[2]) & 0xffffffff;
|
||||
state[3] = (d + state[3]) & 0xffffffff;
|
||||
}
|
||||
reset() {
|
||||
this.state = Uint32Array.from(INIT);
|
||||
this.buffer = new DataView(new ArrayBuffer(BLOCK_SIZE));
|
||||
this.bufferLength = 0;
|
||||
this.bytesHashed = 0;
|
||||
this.finished = false;
|
||||
}
|
||||
}
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
a = (((a + q) & 0xffffffff) + ((x + t) & 0xffffffff)) & 0xffffffff;
|
||||
return (((a << s) | (a >>> (32 - s))) + b) & 0xffffffff;
|
||||
}
|
||||
function ff(a, b, c, d, x, s, t) {
|
||||
return cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
function gg(a, b, c, d, x, s, t) {
|
||||
return cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
function hh(a, b, c, d, x, s, t) {
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
function ii(a, b, c, d, x, s, t) {
|
||||
return cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
function isEmptyData(data) {
|
||||
if (typeof data === "string") {
|
||||
return data.length === 0;
|
||||
}
|
||||
return data.byteLength === 0;
|
||||
}
|
||||
function convertToBuffer(data) {
|
||||
if (typeof data === "string") {
|
||||
return serde.fromUtf8(data);
|
||||
}
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
|
||||
}
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
|
||||
const no = Symbol.for("node-only");
|
||||
const fileStreamHasher = no;
|
||||
const readableStreamHasher = no;
|
||||
|
||||
exports.Md5 = Md5;
|
||||
exports.blobHasher = blobHasher;
|
||||
exports.blobReader = blobReader;
|
||||
exports.fileStreamHasher = fileStreamHasher;
|
||||
exports.readableStreamHasher = readableStreamHasher;
|
||||
+259
@@ -0,0 +1,259 @@
|
||||
'use strict';
|
||||
|
||||
var node_fs = require('node:fs');
|
||||
var node_stream = require('node:stream');
|
||||
var serde = require('@smithy/core/serde');
|
||||
|
||||
async function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
||||
const size = blob.size;
|
||||
let totalBytesRead = 0;
|
||||
while (totalBytesRead < size) {
|
||||
const slice = blob.slice(totalBytesRead, Math.min(size, totalBytesRead + chunkSize));
|
||||
onChunk(new Uint8Array(await slice.arrayBuffer()));
|
||||
totalBytesRead += slice.size;
|
||||
}
|
||||
}
|
||||
|
||||
const blobHasher = async function blobHasher(hashCtor, blob) {
|
||||
const hash = new hashCtor();
|
||||
await blobReader(blob, (chunk) => {
|
||||
hash.update(chunk);
|
||||
});
|
||||
return hash.digest();
|
||||
};
|
||||
|
||||
class HashCalculator extends node_stream.Writable {
|
||||
hash;
|
||||
constructor(hash, options) {
|
||||
super(options);
|
||||
this.hash = hash;
|
||||
}
|
||||
_write(chunk, encoding, callback) {
|
||||
try {
|
||||
this.hash.update(serde.toUint8Array(chunk));
|
||||
}
|
||||
catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
const fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve, reject) => {
|
||||
if (!isReadStream(fileStream)) {
|
||||
reject(new Error("Unable to calculate hash for non-file streams."));
|
||||
return;
|
||||
}
|
||||
const fileStreamTee = node_fs.createReadStream(fileStream.path, {
|
||||
start: fileStream.start,
|
||||
end: fileStream.end,
|
||||
});
|
||||
const hash = new hashCtor();
|
||||
const hashCalculator = new HashCalculator(hash);
|
||||
fileStreamTee.pipe(hashCalculator);
|
||||
fileStreamTee.on("error", (err) => {
|
||||
hashCalculator.end();
|
||||
reject(err);
|
||||
});
|
||||
hashCalculator.on("error", reject);
|
||||
hashCalculator.on("finish", function () {
|
||||
hash.digest().then(resolve).catch(reject);
|
||||
});
|
||||
});
|
||||
const isReadStream = (stream) => typeof stream.path === "string";
|
||||
|
||||
const readableStreamHasher = (hashCtor, readableStream) => {
|
||||
if (readableStream.readableFlowing !== null) {
|
||||
throw new Error("Unable to calculate hash for flowing readable stream");
|
||||
}
|
||||
const hash = new hashCtor();
|
||||
const hashCalculator = new HashCalculator(hash);
|
||||
readableStream.pipe(hashCalculator);
|
||||
return new Promise((resolve, reject) => {
|
||||
readableStream.on("error", (err) => {
|
||||
hashCalculator.end();
|
||||
reject(err);
|
||||
});
|
||||
hashCalculator.on("error", reject);
|
||||
hashCalculator.on("finish", () => {
|
||||
hash.digest().then(resolve).catch(reject);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const BLOCK_SIZE = 64;
|
||||
const DIGEST_LENGTH = 16;
|
||||
const INIT = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
|
||||
|
||||
class Md5 {
|
||||
state;
|
||||
buffer;
|
||||
bufferLength;
|
||||
bytesHashed;
|
||||
finished;
|
||||
constructor() {
|
||||
this.reset();
|
||||
}
|
||||
update(sourceData) {
|
||||
if (isEmptyData(sourceData)) {
|
||||
return;
|
||||
}
|
||||
else if (this.finished) {
|
||||
throw new Error("Attempted to update an already finished hash.");
|
||||
}
|
||||
const data = convertToBuffer(sourceData);
|
||||
let position = 0;
|
||||
let { byteLength } = data;
|
||||
this.bytesHashed += byteLength;
|
||||
while (byteLength > 0) {
|
||||
this.buffer.setUint8(this.bufferLength++, data[position++]);
|
||||
byteLength--;
|
||||
if (this.bufferLength === BLOCK_SIZE) {
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
async digest() {
|
||||
if (!this.finished) {
|
||||
const { buffer, bufferLength: undecoratedLength, bytesHashed } = this;
|
||||
const bitsHashed = bytesHashed * 8;
|
||||
buffer.setUint8(this.bufferLength++, 0b10000000);
|
||||
if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
buffer.setUint32(BLOCK_SIZE - 8, bitsHashed >>> 0, true);
|
||||
buffer.setUint32(BLOCK_SIZE - 4, Math.floor(bitsHashed / 0x100000000), true);
|
||||
this.hashBuffer();
|
||||
this.finished = true;
|
||||
}
|
||||
const out = new DataView(new ArrayBuffer(DIGEST_LENGTH));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out.setUint32(i * 4, this.state[i], true);
|
||||
}
|
||||
return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
||||
}
|
||||
hashBuffer() {
|
||||
const { buffer, state } = this;
|
||||
let a = state[0], b = state[1], c = state[2], d = state[3];
|
||||
a = ff(a, b, c, d, buffer.getUint32(0, true), 7, 0xd76aa478);
|
||||
d = ff(d, a, b, c, buffer.getUint32(4, true), 12, 0xe8c7b756);
|
||||
c = ff(c, d, a, b, buffer.getUint32(8, true), 17, 0x242070db);
|
||||
b = ff(b, c, d, a, buffer.getUint32(12, true), 22, 0xc1bdceee);
|
||||
a = ff(a, b, c, d, buffer.getUint32(16, true), 7, 0xf57c0faf);
|
||||
d = ff(d, a, b, c, buffer.getUint32(20, true), 12, 0x4787c62a);
|
||||
c = ff(c, d, a, b, buffer.getUint32(24, true), 17, 0xa8304613);
|
||||
b = ff(b, c, d, a, buffer.getUint32(28, true), 22, 0xfd469501);
|
||||
a = ff(a, b, c, d, buffer.getUint32(32, true), 7, 0x698098d8);
|
||||
d = ff(d, a, b, c, buffer.getUint32(36, true), 12, 0x8b44f7af);
|
||||
c = ff(c, d, a, b, buffer.getUint32(40, true), 17, 0xffff5bb1);
|
||||
b = ff(b, c, d, a, buffer.getUint32(44, true), 22, 0x895cd7be);
|
||||
a = ff(a, b, c, d, buffer.getUint32(48, true), 7, 0x6b901122);
|
||||
d = ff(d, a, b, c, buffer.getUint32(52, true), 12, 0xfd987193);
|
||||
c = ff(c, d, a, b, buffer.getUint32(56, true), 17, 0xa679438e);
|
||||
b = ff(b, c, d, a, buffer.getUint32(60, true), 22, 0x49b40821);
|
||||
a = gg(a, b, c, d, buffer.getUint32(4, true), 5, 0xf61e2562);
|
||||
d = gg(d, a, b, c, buffer.getUint32(24, true), 9, 0xc040b340);
|
||||
c = gg(c, d, a, b, buffer.getUint32(44, true), 14, 0x265e5a51);
|
||||
b = gg(b, c, d, a, buffer.getUint32(0, true), 20, 0xe9b6c7aa);
|
||||
a = gg(a, b, c, d, buffer.getUint32(20, true), 5, 0xd62f105d);
|
||||
d = gg(d, a, b, c, buffer.getUint32(40, true), 9, 0x02441453);
|
||||
c = gg(c, d, a, b, buffer.getUint32(60, true), 14, 0xd8a1e681);
|
||||
b = gg(b, c, d, a, buffer.getUint32(16, true), 20, 0xe7d3fbc8);
|
||||
a = gg(a, b, c, d, buffer.getUint32(36, true), 5, 0x21e1cde6);
|
||||
d = gg(d, a, b, c, buffer.getUint32(56, true), 9, 0xc33707d6);
|
||||
c = gg(c, d, a, b, buffer.getUint32(12, true), 14, 0xf4d50d87);
|
||||
b = gg(b, c, d, a, buffer.getUint32(32, true), 20, 0x455a14ed);
|
||||
a = gg(a, b, c, d, buffer.getUint32(52, true), 5, 0xa9e3e905);
|
||||
d = gg(d, a, b, c, buffer.getUint32(8, true), 9, 0xfcefa3f8);
|
||||
c = gg(c, d, a, b, buffer.getUint32(28, true), 14, 0x676f02d9);
|
||||
b = gg(b, c, d, a, buffer.getUint32(48, true), 20, 0x8d2a4c8a);
|
||||
a = hh(a, b, c, d, buffer.getUint32(20, true), 4, 0xfffa3942);
|
||||
d = hh(d, a, b, c, buffer.getUint32(32, true), 11, 0x8771f681);
|
||||
c = hh(c, d, a, b, buffer.getUint32(44, true), 16, 0x6d9d6122);
|
||||
b = hh(b, c, d, a, buffer.getUint32(56, true), 23, 0xfde5380c);
|
||||
a = hh(a, b, c, d, buffer.getUint32(4, true), 4, 0xa4beea44);
|
||||
d = hh(d, a, b, c, buffer.getUint32(16, true), 11, 0x4bdecfa9);
|
||||
c = hh(c, d, a, b, buffer.getUint32(28, true), 16, 0xf6bb4b60);
|
||||
b = hh(b, c, d, a, buffer.getUint32(40, true), 23, 0xbebfbc70);
|
||||
a = hh(a, b, c, d, buffer.getUint32(52, true), 4, 0x289b7ec6);
|
||||
d = hh(d, a, b, c, buffer.getUint32(0, true), 11, 0xeaa127fa);
|
||||
c = hh(c, d, a, b, buffer.getUint32(12, true), 16, 0xd4ef3085);
|
||||
b = hh(b, c, d, a, buffer.getUint32(24, true), 23, 0x04881d05);
|
||||
a = hh(a, b, c, d, buffer.getUint32(36, true), 4, 0xd9d4d039);
|
||||
d = hh(d, a, b, c, buffer.getUint32(48, true), 11, 0xe6db99e5);
|
||||
c = hh(c, d, a, b, buffer.getUint32(60, true), 16, 0x1fa27cf8);
|
||||
b = hh(b, c, d, a, buffer.getUint32(8, true), 23, 0xc4ac5665);
|
||||
a = ii(a, b, c, d, buffer.getUint32(0, true), 6, 0xf4292244);
|
||||
d = ii(d, a, b, c, buffer.getUint32(28, true), 10, 0x432aff97);
|
||||
c = ii(c, d, a, b, buffer.getUint32(56, true), 15, 0xab9423a7);
|
||||
b = ii(b, c, d, a, buffer.getUint32(20, true), 21, 0xfc93a039);
|
||||
a = ii(a, b, c, d, buffer.getUint32(48, true), 6, 0x655b59c3);
|
||||
d = ii(d, a, b, c, buffer.getUint32(12, true), 10, 0x8f0ccc92);
|
||||
c = ii(c, d, a, b, buffer.getUint32(40, true), 15, 0xffeff47d);
|
||||
b = ii(b, c, d, a, buffer.getUint32(4, true), 21, 0x85845dd1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(32, true), 6, 0x6fa87e4f);
|
||||
d = ii(d, a, b, c, buffer.getUint32(60, true), 10, 0xfe2ce6e0);
|
||||
c = ii(c, d, a, b, buffer.getUint32(24, true), 15, 0xa3014314);
|
||||
b = ii(b, c, d, a, buffer.getUint32(52, true), 21, 0x4e0811a1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(16, true), 6, 0xf7537e82);
|
||||
d = ii(d, a, b, c, buffer.getUint32(44, true), 10, 0xbd3af235);
|
||||
c = ii(c, d, a, b, buffer.getUint32(8, true), 15, 0x2ad7d2bb);
|
||||
b = ii(b, c, d, a, buffer.getUint32(36, true), 21, 0xeb86d391);
|
||||
state[0] = (a + state[0]) & 0xffffffff;
|
||||
state[1] = (b + state[1]) & 0xffffffff;
|
||||
state[2] = (c + state[2]) & 0xffffffff;
|
||||
state[3] = (d + state[3]) & 0xffffffff;
|
||||
}
|
||||
reset() {
|
||||
this.state = Uint32Array.from(INIT);
|
||||
this.buffer = new DataView(new ArrayBuffer(BLOCK_SIZE));
|
||||
this.bufferLength = 0;
|
||||
this.bytesHashed = 0;
|
||||
this.finished = false;
|
||||
}
|
||||
}
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
a = (((a + q) & 0xffffffff) + ((x + t) & 0xffffffff)) & 0xffffffff;
|
||||
return (((a << s) | (a >>> (32 - s))) + b) & 0xffffffff;
|
||||
}
|
||||
function ff(a, b, c, d, x, s, t) {
|
||||
return cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
function gg(a, b, c, d, x, s, t) {
|
||||
return cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
function hh(a, b, c, d, x, s, t) {
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
function ii(a, b, c, d, x, s, t) {
|
||||
return cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
function isEmptyData(data) {
|
||||
if (typeof data === "string") {
|
||||
return data.length === 0;
|
||||
}
|
||||
return data.byteLength === 0;
|
||||
}
|
||||
function convertToBuffer(data) {
|
||||
if (typeof data === "string") {
|
||||
return serde.fromUtf8(data);
|
||||
}
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
|
||||
}
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
|
||||
exports.Md5 = Md5;
|
||||
exports.blobHasher = blobHasher;
|
||||
exports.blobReader = blobReader;
|
||||
exports.fileStreamHasher = fileStreamHasher;
|
||||
exports.readableStreamHasher = readableStreamHasher;
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
'use strict';
|
||||
|
||||
var serde = require('@smithy/core/serde');
|
||||
|
||||
async function blobReader$1(blob, onChunk, chunkSize = 1024 * 1024) {
|
||||
const size = blob.size;
|
||||
let totalBytesRead = 0;
|
||||
while (totalBytesRead < size) {
|
||||
const slice = blob.slice(totalBytesRead, Math.min(size, totalBytesRead + chunkSize));
|
||||
onChunk(new Uint8Array(await slice.arrayBuffer()));
|
||||
totalBytesRead += slice.size;
|
||||
}
|
||||
}
|
||||
|
||||
const blobHasher = async function blobHasher(hashCtor, blob) {
|
||||
const hash = new hashCtor();
|
||||
await blobReader$1(blob, (chunk) => {
|
||||
hash.update(chunk);
|
||||
});
|
||||
return hash.digest();
|
||||
};
|
||||
|
||||
const BLOCK_SIZE = 64;
|
||||
const DIGEST_LENGTH = 16;
|
||||
const INIT = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
|
||||
|
||||
class Md5 {
|
||||
state;
|
||||
buffer;
|
||||
bufferLength;
|
||||
bytesHashed;
|
||||
finished;
|
||||
constructor() {
|
||||
this.reset();
|
||||
}
|
||||
update(sourceData) {
|
||||
if (isEmptyData(sourceData)) {
|
||||
return;
|
||||
}
|
||||
else if (this.finished) {
|
||||
throw new Error("Attempted to update an already finished hash.");
|
||||
}
|
||||
const data = convertToBuffer(sourceData);
|
||||
let position = 0;
|
||||
let { byteLength } = data;
|
||||
this.bytesHashed += byteLength;
|
||||
while (byteLength > 0) {
|
||||
this.buffer.setUint8(this.bufferLength++, data[position++]);
|
||||
byteLength--;
|
||||
if (this.bufferLength === BLOCK_SIZE) {
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
async digest() {
|
||||
if (!this.finished) {
|
||||
const { buffer, bufferLength: undecoratedLength, bytesHashed } = this;
|
||||
const bitsHashed = bytesHashed * 8;
|
||||
buffer.setUint8(this.bufferLength++, 0b10000000);
|
||||
if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
buffer.setUint32(BLOCK_SIZE - 8, bitsHashed >>> 0, true);
|
||||
buffer.setUint32(BLOCK_SIZE - 4, Math.floor(bitsHashed / 0x100000000), true);
|
||||
this.hashBuffer();
|
||||
this.finished = true;
|
||||
}
|
||||
const out = new DataView(new ArrayBuffer(DIGEST_LENGTH));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out.setUint32(i * 4, this.state[i], true);
|
||||
}
|
||||
return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
||||
}
|
||||
hashBuffer() {
|
||||
const { buffer, state } = this;
|
||||
let a = state[0], b = state[1], c = state[2], d = state[3];
|
||||
a = ff(a, b, c, d, buffer.getUint32(0, true), 7, 0xd76aa478);
|
||||
d = ff(d, a, b, c, buffer.getUint32(4, true), 12, 0xe8c7b756);
|
||||
c = ff(c, d, a, b, buffer.getUint32(8, true), 17, 0x242070db);
|
||||
b = ff(b, c, d, a, buffer.getUint32(12, true), 22, 0xc1bdceee);
|
||||
a = ff(a, b, c, d, buffer.getUint32(16, true), 7, 0xf57c0faf);
|
||||
d = ff(d, a, b, c, buffer.getUint32(20, true), 12, 0x4787c62a);
|
||||
c = ff(c, d, a, b, buffer.getUint32(24, true), 17, 0xa8304613);
|
||||
b = ff(b, c, d, a, buffer.getUint32(28, true), 22, 0xfd469501);
|
||||
a = ff(a, b, c, d, buffer.getUint32(32, true), 7, 0x698098d8);
|
||||
d = ff(d, a, b, c, buffer.getUint32(36, true), 12, 0x8b44f7af);
|
||||
c = ff(c, d, a, b, buffer.getUint32(40, true), 17, 0xffff5bb1);
|
||||
b = ff(b, c, d, a, buffer.getUint32(44, true), 22, 0x895cd7be);
|
||||
a = ff(a, b, c, d, buffer.getUint32(48, true), 7, 0x6b901122);
|
||||
d = ff(d, a, b, c, buffer.getUint32(52, true), 12, 0xfd987193);
|
||||
c = ff(c, d, a, b, buffer.getUint32(56, true), 17, 0xa679438e);
|
||||
b = ff(b, c, d, a, buffer.getUint32(60, true), 22, 0x49b40821);
|
||||
a = gg(a, b, c, d, buffer.getUint32(4, true), 5, 0xf61e2562);
|
||||
d = gg(d, a, b, c, buffer.getUint32(24, true), 9, 0xc040b340);
|
||||
c = gg(c, d, a, b, buffer.getUint32(44, true), 14, 0x265e5a51);
|
||||
b = gg(b, c, d, a, buffer.getUint32(0, true), 20, 0xe9b6c7aa);
|
||||
a = gg(a, b, c, d, buffer.getUint32(20, true), 5, 0xd62f105d);
|
||||
d = gg(d, a, b, c, buffer.getUint32(40, true), 9, 0x02441453);
|
||||
c = gg(c, d, a, b, buffer.getUint32(60, true), 14, 0xd8a1e681);
|
||||
b = gg(b, c, d, a, buffer.getUint32(16, true), 20, 0xe7d3fbc8);
|
||||
a = gg(a, b, c, d, buffer.getUint32(36, true), 5, 0x21e1cde6);
|
||||
d = gg(d, a, b, c, buffer.getUint32(56, true), 9, 0xc33707d6);
|
||||
c = gg(c, d, a, b, buffer.getUint32(12, true), 14, 0xf4d50d87);
|
||||
b = gg(b, c, d, a, buffer.getUint32(32, true), 20, 0x455a14ed);
|
||||
a = gg(a, b, c, d, buffer.getUint32(52, true), 5, 0xa9e3e905);
|
||||
d = gg(d, a, b, c, buffer.getUint32(8, true), 9, 0xfcefa3f8);
|
||||
c = gg(c, d, a, b, buffer.getUint32(28, true), 14, 0x676f02d9);
|
||||
b = gg(b, c, d, a, buffer.getUint32(48, true), 20, 0x8d2a4c8a);
|
||||
a = hh(a, b, c, d, buffer.getUint32(20, true), 4, 0xfffa3942);
|
||||
d = hh(d, a, b, c, buffer.getUint32(32, true), 11, 0x8771f681);
|
||||
c = hh(c, d, a, b, buffer.getUint32(44, true), 16, 0x6d9d6122);
|
||||
b = hh(b, c, d, a, buffer.getUint32(56, true), 23, 0xfde5380c);
|
||||
a = hh(a, b, c, d, buffer.getUint32(4, true), 4, 0xa4beea44);
|
||||
d = hh(d, a, b, c, buffer.getUint32(16, true), 11, 0x4bdecfa9);
|
||||
c = hh(c, d, a, b, buffer.getUint32(28, true), 16, 0xf6bb4b60);
|
||||
b = hh(b, c, d, a, buffer.getUint32(40, true), 23, 0xbebfbc70);
|
||||
a = hh(a, b, c, d, buffer.getUint32(52, true), 4, 0x289b7ec6);
|
||||
d = hh(d, a, b, c, buffer.getUint32(0, true), 11, 0xeaa127fa);
|
||||
c = hh(c, d, a, b, buffer.getUint32(12, true), 16, 0xd4ef3085);
|
||||
b = hh(b, c, d, a, buffer.getUint32(24, true), 23, 0x04881d05);
|
||||
a = hh(a, b, c, d, buffer.getUint32(36, true), 4, 0xd9d4d039);
|
||||
d = hh(d, a, b, c, buffer.getUint32(48, true), 11, 0xe6db99e5);
|
||||
c = hh(c, d, a, b, buffer.getUint32(60, true), 16, 0x1fa27cf8);
|
||||
b = hh(b, c, d, a, buffer.getUint32(8, true), 23, 0xc4ac5665);
|
||||
a = ii(a, b, c, d, buffer.getUint32(0, true), 6, 0xf4292244);
|
||||
d = ii(d, a, b, c, buffer.getUint32(28, true), 10, 0x432aff97);
|
||||
c = ii(c, d, a, b, buffer.getUint32(56, true), 15, 0xab9423a7);
|
||||
b = ii(b, c, d, a, buffer.getUint32(20, true), 21, 0xfc93a039);
|
||||
a = ii(a, b, c, d, buffer.getUint32(48, true), 6, 0x655b59c3);
|
||||
d = ii(d, a, b, c, buffer.getUint32(12, true), 10, 0x8f0ccc92);
|
||||
c = ii(c, d, a, b, buffer.getUint32(40, true), 15, 0xffeff47d);
|
||||
b = ii(b, c, d, a, buffer.getUint32(4, true), 21, 0x85845dd1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(32, true), 6, 0x6fa87e4f);
|
||||
d = ii(d, a, b, c, buffer.getUint32(60, true), 10, 0xfe2ce6e0);
|
||||
c = ii(c, d, a, b, buffer.getUint32(24, true), 15, 0xa3014314);
|
||||
b = ii(b, c, d, a, buffer.getUint32(52, true), 21, 0x4e0811a1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(16, true), 6, 0xf7537e82);
|
||||
d = ii(d, a, b, c, buffer.getUint32(44, true), 10, 0xbd3af235);
|
||||
c = ii(c, d, a, b, buffer.getUint32(8, true), 15, 0x2ad7d2bb);
|
||||
b = ii(b, c, d, a, buffer.getUint32(36, true), 21, 0xeb86d391);
|
||||
state[0] = (a + state[0]) & 0xffffffff;
|
||||
state[1] = (b + state[1]) & 0xffffffff;
|
||||
state[2] = (c + state[2]) & 0xffffffff;
|
||||
state[3] = (d + state[3]) & 0xffffffff;
|
||||
}
|
||||
reset() {
|
||||
this.state = Uint32Array.from(INIT);
|
||||
this.buffer = new DataView(new ArrayBuffer(BLOCK_SIZE));
|
||||
this.bufferLength = 0;
|
||||
this.bytesHashed = 0;
|
||||
this.finished = false;
|
||||
}
|
||||
}
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
a = (((a + q) & 0xffffffff) + ((x + t) & 0xffffffff)) & 0xffffffff;
|
||||
return (((a << s) | (a >>> (32 - s))) + b) & 0xffffffff;
|
||||
}
|
||||
function ff(a, b, c, d, x, s, t) {
|
||||
return cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
function gg(a, b, c, d, x, s, t) {
|
||||
return cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
function hh(a, b, c, d, x, s, t) {
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
function ii(a, b, c, d, x, s, t) {
|
||||
return cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
function isEmptyData(data) {
|
||||
if (typeof data === "string") {
|
||||
return data.length === 0;
|
||||
}
|
||||
return data.byteLength === 0;
|
||||
}
|
||||
function convertToBuffer(data) {
|
||||
if (typeof data === "string") {
|
||||
return serde.fromUtf8(data);
|
||||
}
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
|
||||
}
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
|
||||
function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onerror = reject;
|
||||
fileReader.onabort = reject;
|
||||
const size = blob.size;
|
||||
let totalBytesRead = 0;
|
||||
const read = () => {
|
||||
if (totalBytesRead >= size) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
fileReader.readAsDataURL(blob.slice(totalBytesRead, Math.min(size, totalBytesRead + chunkSize)));
|
||||
};
|
||||
fileReader.onload = (event) => {
|
||||
const result = event.target.result;
|
||||
const dataOffset = result.indexOf(",") + 1;
|
||||
const data = result.substring(dataOffset);
|
||||
const decoded = serde.fromBase64(data);
|
||||
onChunk(decoded);
|
||||
totalBytesRead += decoded.byteLength;
|
||||
read();
|
||||
};
|
||||
read();
|
||||
});
|
||||
}
|
||||
|
||||
const no = Symbol.for("node-only");
|
||||
const fileStreamHasher = no;
|
||||
const readableStreamHasher = no;
|
||||
|
||||
exports.Md5 = Md5;
|
||||
exports.blobHasher = blobHasher;
|
||||
exports.blobReader = blobReader;
|
||||
exports.fileStreamHasher = fileStreamHasher;
|
||||
exports.readableStreamHasher = readableStreamHasher;
|
||||
+1128
File diff suppressed because it is too large
Load Diff
+375
@@ -0,0 +1,375 @@
|
||||
'use strict';
|
||||
|
||||
var client = require('@smithy/core/client');
|
||||
var transport = require('@smithy/core/transport');
|
||||
|
||||
class ProviderError extends Error {
|
||||
name = "ProviderError";
|
||||
tryNextLink;
|
||||
constructor(message, options = true) {
|
||||
let logger;
|
||||
let tryNextLink = true;
|
||||
if (typeof options === "boolean") {
|
||||
logger = undefined;
|
||||
tryNextLink = options;
|
||||
}
|
||||
else if (options != null && typeof options === "object") {
|
||||
logger = options.logger;
|
||||
tryNextLink = options.tryNextLink ?? true;
|
||||
}
|
||||
super(message);
|
||||
this.tryNextLink = tryNextLink;
|
||||
Object.setPrototypeOf(this, ProviderError.prototype);
|
||||
logger?.debug?.(`@smithy/property-provider ${tryNextLink ? "->" : "(!)"} ${message}`);
|
||||
}
|
||||
static from(error, options = true) {
|
||||
return Object.assign(new this(error.message, options), error);
|
||||
}
|
||||
}
|
||||
|
||||
class CredentialsProviderError extends ProviderError {
|
||||
name = "CredentialsProviderError";
|
||||
constructor(message, options = true) {
|
||||
super(message, options);
|
||||
Object.setPrototypeOf(this, CredentialsProviderError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
class TokenProviderError extends ProviderError {
|
||||
name = "TokenProviderError";
|
||||
constructor(message, options = true) {
|
||||
super(message, options);
|
||||
Object.setPrototypeOf(this, TokenProviderError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
const chain = (...providers) => async () => {
|
||||
if (providers.length === 0) {
|
||||
throw new ProviderError("No providers in chain");
|
||||
}
|
||||
let lastProviderError;
|
||||
for (const provider of providers) {
|
||||
try {
|
||||
const credentials = await provider();
|
||||
return credentials;
|
||||
}
|
||||
catch (err) {
|
||||
lastProviderError = err;
|
||||
if (err?.tryNextLink) {
|
||||
continue;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
throw lastProviderError;
|
||||
};
|
||||
|
||||
const fromValue = (staticValue) => () => Promise.resolve(staticValue);
|
||||
|
||||
const memoize = (provider, isExpired, requiresRefresh) => {
|
||||
let resolved;
|
||||
let pending;
|
||||
let hasResult;
|
||||
let isConstant = false;
|
||||
const coalesceProvider = async () => {
|
||||
if (!pending) {
|
||||
pending = provider();
|
||||
}
|
||||
try {
|
||||
resolved = await pending;
|
||||
hasResult = true;
|
||||
isConstant = false;
|
||||
}
|
||||
finally {
|
||||
pending = undefined;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
if (isExpired === undefined) {
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider();
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
}
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider();
|
||||
}
|
||||
if (isConstant) {
|
||||
return resolved;
|
||||
}
|
||||
if (requiresRefresh && !requiresRefresh(resolved)) {
|
||||
isConstant = true;
|
||||
return resolved;
|
||||
}
|
||||
if (isExpired(resolved)) {
|
||||
await coalesceProvider();
|
||||
return resolved;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
};
|
||||
|
||||
const booleanSelector = (obj, key, type) => {
|
||||
if (!(key in obj))
|
||||
return undefined;
|
||||
if (obj[key] === "true")
|
||||
return true;
|
||||
if (obj[key] === "false")
|
||||
return false;
|
||||
throw new Error(`Cannot load ${type} "${key}". Expected "true" or "false", got ${obj[key]}.`);
|
||||
};
|
||||
|
||||
const numberSelector = (obj, key, type) => {
|
||||
if (!(key in obj))
|
||||
return undefined;
|
||||
const numberValue = parseInt(obj[key], 10);
|
||||
if (Number.isNaN(numberValue)) {
|
||||
throw new TypeError(`Cannot load ${type} '${key}'. Expected number, got '${obj[key]}'.`);
|
||||
}
|
||||
return numberValue;
|
||||
};
|
||||
|
||||
exports.SelectorType = void 0;
|
||||
(function (SelectorType) {
|
||||
SelectorType["ENV"] = "env";
|
||||
SelectorType["CONFIG"] = "shared config entry";
|
||||
})(exports.SelectorType || (exports.SelectorType = {}));
|
||||
|
||||
const resolveCustomEndpointsConfig = (input) => {
|
||||
const { tls, endpoint, urlParser, useDualstackEndpoint } = input;
|
||||
return Object.assign(input, {
|
||||
tls: tls ?? true,
|
||||
endpoint: client.normalizeProvider(typeof endpoint === "string" ? urlParser(endpoint) : endpoint),
|
||||
isCustomEndpoint: true,
|
||||
useDualstackEndpoint: client.normalizeProvider(useDualstackEndpoint ?? false),
|
||||
});
|
||||
};
|
||||
|
||||
const getEndpointFromRegion = async (input) => {
|
||||
const { tls = true } = input;
|
||||
const region = await input.region();
|
||||
const dnsHostRegex = new RegExp(/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$/);
|
||||
if (!dnsHostRegex.test(region)) {
|
||||
throw new Error("Invalid region in client config");
|
||||
}
|
||||
const useDualstackEndpoint = await input.useDualstackEndpoint();
|
||||
const useFipsEndpoint = await input.useFipsEndpoint();
|
||||
const { hostname } = (await input.regionInfoProvider(region, { useDualstackEndpoint, useFipsEndpoint })) ?? {};
|
||||
if (!hostname) {
|
||||
throw new Error("Cannot resolve hostname from client config");
|
||||
}
|
||||
return input.urlParser(`${tls ? "https:" : "http:"}//${hostname}`);
|
||||
};
|
||||
|
||||
const resolveEndpointsConfig = (input) => {
|
||||
const useDualstackEndpoint = client.normalizeProvider(input.useDualstackEndpoint ?? false);
|
||||
const { endpoint, useFipsEndpoint, urlParser, tls } = input;
|
||||
return Object.assign(input, {
|
||||
tls: tls ?? true,
|
||||
endpoint: endpoint
|
||||
? client.normalizeProvider(typeof endpoint === "string" ? urlParser(endpoint) : endpoint)
|
||||
: () => getEndpointFromRegion({ ...input, useDualstackEndpoint, useFipsEndpoint }),
|
||||
isCustomEndpoint: !!endpoint,
|
||||
useDualstackEndpoint,
|
||||
});
|
||||
};
|
||||
|
||||
const validRegions = new Set();
|
||||
const checkRegion = (region, check = transport.isValidHostLabel) => {
|
||||
if (!validRegions.has(region) && !check(region)) {
|
||||
if (region === "*") {
|
||||
console.warn(`@smithy/config-resolver WARN - Please use the caller region instead of "*". See "sigv4a" in https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md.`);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Region not accepted: region="${region}" is not a valid hostname component.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
validRegions.add(region);
|
||||
}
|
||||
};
|
||||
|
||||
const isFipsRegion = (region) => typeof region === "string" && (region.startsWith("fips-") || region.endsWith("-fips"));
|
||||
|
||||
const getRealRegion = (region) => isFipsRegion(region)
|
||||
? ["fips-aws-global", "aws-fips"].includes(region)
|
||||
? "us-east-1"
|
||||
: region.replace(/fips-(dkr-|prod-)?|-fips/, "")
|
||||
: region;
|
||||
|
||||
const resolveRegionConfig = (input) => {
|
||||
const { region, useFipsEndpoint } = input;
|
||||
if (!region) {
|
||||
throw new Error("Region is missing");
|
||||
}
|
||||
return Object.assign(input, {
|
||||
region: async () => {
|
||||
const providedRegion = typeof region === "function" ? await region() : region;
|
||||
const realRegion = getRealRegion(providedRegion);
|
||||
checkRegion(realRegion);
|
||||
return realRegion;
|
||||
},
|
||||
useFipsEndpoint: async () => {
|
||||
const providedRegion = typeof region === "string" ? region : await region();
|
||||
if (isFipsRegion(providedRegion)) {
|
||||
return true;
|
||||
}
|
||||
return typeof useFipsEndpoint !== "function" ? Promise.resolve(!!useFipsEndpoint) : useFipsEndpoint();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getHostnameFromVariants = (variants = [], { useFipsEndpoint, useDualstackEndpoint }) => variants.find(({ tags }) => useFipsEndpoint === tags.includes("fips") && useDualstackEndpoint === tags.includes("dualstack"))?.hostname;
|
||||
|
||||
const getResolvedHostname = (resolvedRegion, { regionHostname, partitionHostname }) => regionHostname
|
||||
? regionHostname
|
||||
: partitionHostname
|
||||
? partitionHostname.replace("{region}", resolvedRegion)
|
||||
: undefined;
|
||||
|
||||
const getResolvedPartition = (region, { partitionHash }) => Object.keys(partitionHash || {}).find((key) => partitionHash[key].regions.includes(region)) ?? "aws";
|
||||
|
||||
const getResolvedSigningRegion = (hostname, { signingRegion, regionRegex, useFipsEndpoint }) => {
|
||||
if (signingRegion) {
|
||||
return signingRegion;
|
||||
}
|
||||
else if (useFipsEndpoint) {
|
||||
const regionRegexJs = regionRegex.replace("\\\\", "\\").replace(/^\^/g, "\\.").replace(/\$$/g, "\\.");
|
||||
const regionRegexmatchArray = hostname.match(regionRegexJs);
|
||||
if (regionRegexmatchArray) {
|
||||
return regionRegexmatchArray[0].slice(1, -1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getRegionInfo = (region, { useFipsEndpoint = false, useDualstackEndpoint = false, signingService, regionHash, partitionHash, }) => {
|
||||
const partition = getResolvedPartition(region, { partitionHash });
|
||||
const resolvedRegion = region in regionHash ? region : partitionHash[partition]?.endpoint ?? region;
|
||||
const hostnameOptions = { useFipsEndpoint, useDualstackEndpoint };
|
||||
const regionHostname = getHostnameFromVariants(regionHash[resolvedRegion]?.variants, hostnameOptions);
|
||||
const partitionHostname = getHostnameFromVariants(partitionHash[partition]?.variants, hostnameOptions);
|
||||
const hostname = getResolvedHostname(resolvedRegion, { regionHostname, partitionHostname });
|
||||
if (hostname === undefined) {
|
||||
throw new Error(`Endpoint resolution failed for: ${{ resolvedRegion, useFipsEndpoint, useDualstackEndpoint }}`);
|
||||
}
|
||||
const signingRegion = getResolvedSigningRegion(hostname, {
|
||||
signingRegion: regionHash[resolvedRegion]?.signingRegion,
|
||||
regionRegex: partitionHash[partition].regionRegex,
|
||||
useFipsEndpoint,
|
||||
});
|
||||
return {
|
||||
partition,
|
||||
signingService,
|
||||
hostname,
|
||||
...(signingRegion && { signingRegion }),
|
||||
...(regionHash[resolvedRegion]?.signingService && {
|
||||
signingService: regionHash[resolvedRegion].signingService,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
const DEFAULTS_MODE_OPTIONS = ["in-region", "cross-region", "mobile", "standard", "legacy"];
|
||||
|
||||
const resolveDefaultsModeConfig = ({ defaultsMode, } = {}) => memoize(async () => {
|
||||
const mode = typeof defaultsMode === "function" ? await defaultsMode() : defaultsMode;
|
||||
switch (mode?.toLowerCase()) {
|
||||
case "auto":
|
||||
return Promise.resolve(useMobileConfiguration() ? "mobile" : "standard");
|
||||
case "mobile":
|
||||
case "in-region":
|
||||
case "cross-region":
|
||||
case "standard":
|
||||
case "legacy":
|
||||
return Promise.resolve(mode?.toLocaleLowerCase());
|
||||
case undefined:
|
||||
return Promise.resolve("legacy");
|
||||
default:
|
||||
throw new Error(`Invalid parameter for "defaultsMode", expect ${DEFAULTS_MODE_OPTIONS.join(", ")}, got ${mode}`);
|
||||
}
|
||||
});
|
||||
const useMobileConfiguration = () => {
|
||||
const navigator = window?.navigator;
|
||||
if (navigator?.connection) {
|
||||
const { effectiveType, rtt, downlink } = navigator?.connection;
|
||||
const slow = (typeof effectiveType === "string" && effectiveType !== "4g") || Number(rtt) > 100 || Number(downlink) < 10;
|
||||
if (slow) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (navigator?.userAgentData?.mobile || (typeof navigator?.maxTouchPoints === "number" && navigator?.maxTouchPoints > 1));
|
||||
};
|
||||
|
||||
const no = Symbol.for("node-only");
|
||||
const getHomeDir = no;
|
||||
const ENV_PROFILE = no;
|
||||
const DEFAULT_PROFILE = "default";
|
||||
const getProfileName = no;
|
||||
const getSSOTokenFilepath = no;
|
||||
const getSSOTokenFromFile = no;
|
||||
const CONFIG_PREFIX_SEPARATOR = no;
|
||||
const loadSharedConfigFiles = no;
|
||||
const loadSsoSessionData = no;
|
||||
const parseKnownFiles = no;
|
||||
const externalDataInterceptor = no;
|
||||
const readFile = no;
|
||||
const loadConfig = no;
|
||||
const fromStatic = no;
|
||||
const ENV_USE_DUALSTACK_ENDPOINT = no;
|
||||
const CONFIG_USE_DUALSTACK_ENDPOINT = no;
|
||||
const DEFAULT_USE_DUALSTACK_ENDPOINT = false;
|
||||
const NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS = no;
|
||||
const nodeDualstackConfigSelectors = no;
|
||||
const ENV_USE_FIPS_ENDPOINT = no;
|
||||
const CONFIG_USE_FIPS_ENDPOINT = no;
|
||||
const DEFAULT_USE_FIPS_ENDPOINT = false;
|
||||
const NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS = no;
|
||||
const nodeFipsConfigSelectors = no;
|
||||
const REGION_ENV_NAME = no;
|
||||
const REGION_INI_NAME = no;
|
||||
const NODE_REGION_CONFIG_OPTIONS = no;
|
||||
const NODE_REGION_CONFIG_FILE_OPTIONS = no;
|
||||
|
||||
exports.CONFIG_PREFIX_SEPARATOR = CONFIG_PREFIX_SEPARATOR;
|
||||
exports.CONFIG_USE_DUALSTACK_ENDPOINT = CONFIG_USE_DUALSTACK_ENDPOINT;
|
||||
exports.CONFIG_USE_FIPS_ENDPOINT = CONFIG_USE_FIPS_ENDPOINT;
|
||||
exports.CredentialsProviderError = CredentialsProviderError;
|
||||
exports.DEFAULT_PROFILE = DEFAULT_PROFILE;
|
||||
exports.DEFAULT_USE_DUALSTACK_ENDPOINT = DEFAULT_USE_DUALSTACK_ENDPOINT;
|
||||
exports.DEFAULT_USE_FIPS_ENDPOINT = DEFAULT_USE_FIPS_ENDPOINT;
|
||||
exports.ENV_PROFILE = ENV_PROFILE;
|
||||
exports.ENV_USE_DUALSTACK_ENDPOINT = ENV_USE_DUALSTACK_ENDPOINT;
|
||||
exports.ENV_USE_FIPS_ENDPOINT = ENV_USE_FIPS_ENDPOINT;
|
||||
exports.NODE_REGION_CONFIG_FILE_OPTIONS = NODE_REGION_CONFIG_FILE_OPTIONS;
|
||||
exports.NODE_REGION_CONFIG_OPTIONS = NODE_REGION_CONFIG_OPTIONS;
|
||||
exports.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS = NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS;
|
||||
exports.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS = NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS;
|
||||
exports.ProviderError = ProviderError;
|
||||
exports.REGION_ENV_NAME = REGION_ENV_NAME;
|
||||
exports.REGION_INI_NAME = REGION_INI_NAME;
|
||||
exports.TokenProviderError = TokenProviderError;
|
||||
exports.booleanSelector = booleanSelector;
|
||||
exports.chain = chain;
|
||||
exports.externalDataInterceptor = externalDataInterceptor;
|
||||
exports.fromStatic = fromStatic;
|
||||
exports.fromValue = fromValue;
|
||||
exports.getHomeDir = getHomeDir;
|
||||
exports.getProfileName = getProfileName;
|
||||
exports.getRegionInfo = getRegionInfo;
|
||||
exports.getSSOTokenFilepath = getSSOTokenFilepath;
|
||||
exports.getSSOTokenFromFile = getSSOTokenFromFile;
|
||||
exports.loadConfig = loadConfig;
|
||||
exports.loadSharedConfigFiles = loadSharedConfigFiles;
|
||||
exports.loadSsoSessionData = loadSsoSessionData;
|
||||
exports.memoize = memoize;
|
||||
exports.nodeDualstackConfigSelectors = nodeDualstackConfigSelectors;
|
||||
exports.nodeFipsConfigSelectors = nodeFipsConfigSelectors;
|
||||
exports.numberSelector = numberSelector;
|
||||
exports.parseKnownFiles = parseKnownFiles;
|
||||
exports.readFile = readFile;
|
||||
exports.resolveCustomEndpointsConfig = resolveCustomEndpointsConfig;
|
||||
exports.resolveDefaultsModeConfig = resolveDefaultsModeConfig;
|
||||
exports.resolveEndpointsConfig = resolveEndpointsConfig;
|
||||
exports.resolveRegionConfig = resolveRegionConfig;
|
||||
+735
@@ -0,0 +1,735 @@
|
||||
'use strict';
|
||||
|
||||
var node_os = require('node:os');
|
||||
var node_path = require('node:path');
|
||||
var node_crypto = require('node:crypto');
|
||||
var promises = require('node:fs/promises');
|
||||
var types = require('@smithy/types');
|
||||
var client = require('@smithy/core/client');
|
||||
var transport = require('@smithy/core/transport');
|
||||
|
||||
class ProviderError extends Error {
|
||||
name = "ProviderError";
|
||||
tryNextLink;
|
||||
constructor(message, options = true) {
|
||||
let logger;
|
||||
let tryNextLink = true;
|
||||
if (typeof options === "boolean") {
|
||||
logger = undefined;
|
||||
tryNextLink = options;
|
||||
}
|
||||
else if (options != null && typeof options === "object") {
|
||||
logger = options.logger;
|
||||
tryNextLink = options.tryNextLink ?? true;
|
||||
}
|
||||
super(message);
|
||||
this.tryNextLink = tryNextLink;
|
||||
Object.setPrototypeOf(this, ProviderError.prototype);
|
||||
logger?.debug?.(`@smithy/property-provider ${tryNextLink ? "->" : "(!)"} ${message}`);
|
||||
}
|
||||
static from(error, options = true) {
|
||||
return Object.assign(new this(error.message, options), error);
|
||||
}
|
||||
}
|
||||
|
||||
class CredentialsProviderError extends ProviderError {
|
||||
name = "CredentialsProviderError";
|
||||
constructor(message, options = true) {
|
||||
super(message, options);
|
||||
Object.setPrototypeOf(this, CredentialsProviderError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
class TokenProviderError extends ProviderError {
|
||||
name = "TokenProviderError";
|
||||
constructor(message, options = true) {
|
||||
super(message, options);
|
||||
Object.setPrototypeOf(this, TokenProviderError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
const chain = (...providers) => async () => {
|
||||
if (providers.length === 0) {
|
||||
throw new ProviderError("No providers in chain");
|
||||
}
|
||||
let lastProviderError;
|
||||
for (const provider of providers) {
|
||||
try {
|
||||
const credentials = await provider();
|
||||
return credentials;
|
||||
}
|
||||
catch (err) {
|
||||
lastProviderError = err;
|
||||
if (err?.tryNextLink) {
|
||||
continue;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
throw lastProviderError;
|
||||
};
|
||||
|
||||
const fromValue = (staticValue) => () => Promise.resolve(staticValue);
|
||||
|
||||
const memoize = (provider, isExpired, requiresRefresh) => {
|
||||
let resolved;
|
||||
let pending;
|
||||
let hasResult;
|
||||
let isConstant = false;
|
||||
const coalesceProvider = async () => {
|
||||
if (!pending) {
|
||||
pending = provider();
|
||||
}
|
||||
try {
|
||||
resolved = await pending;
|
||||
hasResult = true;
|
||||
isConstant = false;
|
||||
}
|
||||
finally {
|
||||
pending = undefined;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
if (isExpired === undefined) {
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider();
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
}
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider();
|
||||
}
|
||||
if (isConstant) {
|
||||
return resolved;
|
||||
}
|
||||
if (requiresRefresh && !requiresRefresh(resolved)) {
|
||||
isConstant = true;
|
||||
return resolved;
|
||||
}
|
||||
if (isExpired(resolved)) {
|
||||
await coalesceProvider();
|
||||
return resolved;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
};
|
||||
|
||||
const booleanSelector = (obj, key, type) => {
|
||||
if (!(key in obj))
|
||||
return undefined;
|
||||
if (obj[key] === "true")
|
||||
return true;
|
||||
if (obj[key] === "false")
|
||||
return false;
|
||||
throw new Error(`Cannot load ${type} "${key}". Expected "true" or "false", got ${obj[key]}.`);
|
||||
};
|
||||
|
||||
const numberSelector = (obj, key, type) => {
|
||||
if (!(key in obj))
|
||||
return undefined;
|
||||
const numberValue = parseInt(obj[key], 10);
|
||||
if (Number.isNaN(numberValue)) {
|
||||
throw new TypeError(`Cannot load ${type} '${key}'. Expected number, got '${obj[key]}'.`);
|
||||
}
|
||||
return numberValue;
|
||||
};
|
||||
|
||||
exports.SelectorType = void 0;
|
||||
(function (SelectorType) {
|
||||
SelectorType["ENV"] = "env";
|
||||
SelectorType["CONFIG"] = "shared config entry";
|
||||
})(exports.SelectorType || (exports.SelectorType = {}));
|
||||
|
||||
const homeDirCache = {};
|
||||
const getHomeDirCacheKey = () => {
|
||||
if (process && process.geteuid) {
|
||||
return `${process.geteuid()}`;
|
||||
}
|
||||
return "DEFAULT";
|
||||
};
|
||||
const getHomeDir = () => {
|
||||
const { HOME, USERPROFILE, HOMEPATH, HOMEDRIVE = `C:${node_path.sep}` } = process.env;
|
||||
if (HOME)
|
||||
return HOME;
|
||||
if (USERPROFILE)
|
||||
return USERPROFILE;
|
||||
if (HOMEPATH)
|
||||
return `${HOMEDRIVE}${HOMEPATH}`;
|
||||
const homeDirCacheKey = getHomeDirCacheKey();
|
||||
if (!homeDirCache[homeDirCacheKey])
|
||||
homeDirCache[homeDirCacheKey] = node_os.homedir();
|
||||
return homeDirCache[homeDirCacheKey];
|
||||
};
|
||||
|
||||
const ENV_PROFILE = "AWS_PROFILE";
|
||||
const DEFAULT_PROFILE = "default";
|
||||
const getProfileName = (init) => init.profile || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
|
||||
|
||||
const getSSOTokenFilepath = (id) => {
|
||||
const hasher = node_crypto.createHash("sha1");
|
||||
const cacheName = hasher.update(id).digest("hex");
|
||||
return node_path.join(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
|
||||
};
|
||||
|
||||
const tokenIntercept = {};
|
||||
const getSSOTokenFromFile = async (id) => {
|
||||
if (tokenIntercept[id]) {
|
||||
return tokenIntercept[id];
|
||||
}
|
||||
const ssoTokenFilepath = getSSOTokenFilepath(id);
|
||||
const ssoTokenText = await promises.readFile(ssoTokenFilepath, "utf8");
|
||||
return JSON.parse(ssoTokenText);
|
||||
};
|
||||
|
||||
const CONFIG_PREFIX_SEPARATOR = ".";
|
||||
|
||||
const getConfigData = (data) => Object.entries(data)
|
||||
.filter(([key]) => {
|
||||
const indexOfSeparator = key.indexOf(CONFIG_PREFIX_SEPARATOR);
|
||||
if (indexOfSeparator === -1) {
|
||||
return false;
|
||||
}
|
||||
return Object.values(types.IniSectionType).includes(key.substring(0, indexOfSeparator));
|
||||
})
|
||||
.reduce((acc, [key, value]) => {
|
||||
const indexOfSeparator = key.indexOf(CONFIG_PREFIX_SEPARATOR);
|
||||
const updatedKey = key.substring(0, indexOfSeparator) === types.IniSectionType.PROFILE ? key.substring(indexOfSeparator + 1) : key;
|
||||
acc[updatedKey] = value;
|
||||
return acc;
|
||||
}, {
|
||||
...(data.default && { default: data.default }),
|
||||
});
|
||||
|
||||
const ENV_CONFIG_PATH = "AWS_CONFIG_FILE";
|
||||
const getConfigFilepath = () => process.env[ENV_CONFIG_PATH] || node_path.join(getHomeDir(), ".aws", "config");
|
||||
|
||||
const ENV_CREDENTIALS_PATH = "AWS_SHARED_CREDENTIALS_FILE";
|
||||
const getCredentialsFilepath = () => process.env[ENV_CREDENTIALS_PATH] || node_path.join(getHomeDir(), ".aws", "credentials");
|
||||
|
||||
const prefixKeyRegex = /^([\w-]+)\s(["'])?([\w-@\+\.%:/]+)\2$/;
|
||||
const profileNameBlockList = ["__proto__", "profile __proto__"];
|
||||
const parseIni = (iniData) => {
|
||||
const map = {};
|
||||
let currentSection;
|
||||
let currentSubSection;
|
||||
for (const iniLine of iniData.split(/\r?\n/)) {
|
||||
const trimmedLine = iniLine.split(/(^|\s)[;#]/)[0].trim();
|
||||
const isSection = trimmedLine[0] === "[" && trimmedLine[trimmedLine.length - 1] === "]";
|
||||
if (isSection) {
|
||||
currentSection = undefined;
|
||||
currentSubSection = undefined;
|
||||
const sectionName = trimmedLine.substring(1, trimmedLine.length - 1);
|
||||
const matches = prefixKeyRegex.exec(sectionName);
|
||||
if (matches) {
|
||||
const [, prefix, , name] = matches;
|
||||
if (Object.values(types.IniSectionType).includes(prefix)) {
|
||||
currentSection = [prefix, name].join(CONFIG_PREFIX_SEPARATOR);
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentSection = sectionName;
|
||||
}
|
||||
if (profileNameBlockList.includes(sectionName)) {
|
||||
throw new Error(`Found invalid profile name "${sectionName}"`);
|
||||
}
|
||||
}
|
||||
else if (currentSection) {
|
||||
const indexOfEqualsSign = trimmedLine.indexOf("=");
|
||||
if (![0, -1].includes(indexOfEqualsSign)) {
|
||||
const [name, value] = [
|
||||
trimmedLine.substring(0, indexOfEqualsSign).trim(),
|
||||
trimmedLine.substring(indexOfEqualsSign + 1).trim(),
|
||||
];
|
||||
if (value === "") {
|
||||
currentSubSection = name;
|
||||
}
|
||||
else {
|
||||
if (currentSubSection && iniLine.trimStart() === iniLine) {
|
||||
currentSubSection = undefined;
|
||||
}
|
||||
map[currentSection] = map[currentSection] || {};
|
||||
const key = currentSubSection ? [currentSubSection, name].join(CONFIG_PREFIX_SEPARATOR) : name;
|
||||
map[currentSection][key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
};
|
||||
|
||||
const filePromises = {};
|
||||
const fileIntercept = {};
|
||||
const readFile = (path, options) => {
|
||||
if (fileIntercept[path] !== undefined) {
|
||||
return fileIntercept[path];
|
||||
}
|
||||
if (!filePromises[path] || options?.ignoreCache) {
|
||||
filePromises[path] = promises.readFile(path, "utf8");
|
||||
}
|
||||
return filePromises[path];
|
||||
};
|
||||
|
||||
const swallowError$1 = () => ({});
|
||||
const loadSharedConfigFiles = async (init = {}) => {
|
||||
const { filepath = getCredentialsFilepath(), configFilepath = getConfigFilepath() } = init;
|
||||
const homeDir = getHomeDir();
|
||||
const relativeHomeDirPrefix = "~/";
|
||||
let resolvedFilepath = filepath;
|
||||
if (filepath.startsWith(relativeHomeDirPrefix)) {
|
||||
resolvedFilepath = node_path.join(homeDir, filepath.slice(2));
|
||||
}
|
||||
let resolvedConfigFilepath = configFilepath;
|
||||
if (configFilepath.startsWith(relativeHomeDirPrefix)) {
|
||||
resolvedConfigFilepath = node_path.join(homeDir, configFilepath.slice(2));
|
||||
}
|
||||
const parsedFiles = await Promise.all([
|
||||
readFile(resolvedConfigFilepath, {
|
||||
ignoreCache: init.ignoreCache,
|
||||
})
|
||||
.then(parseIni)
|
||||
.then(getConfigData)
|
||||
.catch(swallowError$1),
|
||||
readFile(resolvedFilepath, {
|
||||
ignoreCache: init.ignoreCache,
|
||||
})
|
||||
.then(parseIni)
|
||||
.catch(swallowError$1),
|
||||
]);
|
||||
return {
|
||||
configFile: parsedFiles[0],
|
||||
credentialsFile: parsedFiles[1],
|
||||
};
|
||||
};
|
||||
|
||||
const getSsoSessionData = (data) => Object.entries(data)
|
||||
.filter(([key]) => key.startsWith(types.IniSectionType.SSO_SESSION + CONFIG_PREFIX_SEPARATOR))
|
||||
.reduce((acc, [key, value]) => ({ ...acc, [key.substring(key.indexOf(CONFIG_PREFIX_SEPARATOR) + 1)]: value }), {});
|
||||
|
||||
const swallowError = () => ({});
|
||||
const loadSsoSessionData = async (init = {}) => readFile(init.configFilepath ?? getConfigFilepath())
|
||||
.then(parseIni)
|
||||
.then(getSsoSessionData)
|
||||
.catch(swallowError);
|
||||
|
||||
const mergeConfigFiles = (...files) => {
|
||||
const merged = {};
|
||||
for (const file of files) {
|
||||
for (const [key, values] of Object.entries(file)) {
|
||||
if (merged[key] !== undefined) {
|
||||
Object.assign(merged[key], values);
|
||||
}
|
||||
else {
|
||||
merged[key] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
};
|
||||
|
||||
const parseKnownFiles = async (init) => {
|
||||
const parsedFiles = await loadSharedConfigFiles(init);
|
||||
return mergeConfigFiles(parsedFiles.configFile, parsedFiles.credentialsFile);
|
||||
};
|
||||
|
||||
const externalDataInterceptor = {
|
||||
getFileRecord() {
|
||||
return fileIntercept;
|
||||
},
|
||||
interceptFile(path, contents) {
|
||||
fileIntercept[path] = Promise.resolve(contents);
|
||||
},
|
||||
getTokenRecord() {
|
||||
return tokenIntercept;
|
||||
},
|
||||
interceptToken(id, contents) {
|
||||
tokenIntercept[id] = contents;
|
||||
},
|
||||
};
|
||||
|
||||
function getSelectorName(functionString) {
|
||||
try {
|
||||
const constants = new Set(Array.from(functionString.match(/([A-Z_]){3,}/g) ?? []));
|
||||
constants.delete("CONFIG");
|
||||
constants.delete("CONFIG_PREFIX_SEPARATOR");
|
||||
constants.delete("ENV");
|
||||
return [...constants].join(", ");
|
||||
}
|
||||
catch (e) {
|
||||
return functionString;
|
||||
}
|
||||
}
|
||||
|
||||
const fromEnv = (envVarSelector, options) => async () => {
|
||||
try {
|
||||
const config = envVarSelector(process.env, options);
|
||||
if (config === undefined) {
|
||||
throw new Error();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
catch (e) {
|
||||
throw new CredentialsProviderError(e.message || `Not found in ENV: ${getSelectorName(envVarSelector.toString())}`, { logger: options?.logger });
|
||||
}
|
||||
};
|
||||
|
||||
const fromSharedConfigFiles = (configSelector, { preferredFile = "config", ...init } = {}) => async () => {
|
||||
const profile = getProfileName(init);
|
||||
const { configFile, credentialsFile } = await loadSharedConfigFiles(init);
|
||||
const profileFromCredentials = credentialsFile[profile] || {};
|
||||
const profileFromConfig = configFile[profile] || {};
|
||||
const mergedProfile = preferredFile === "config"
|
||||
? { ...profileFromCredentials, ...profileFromConfig }
|
||||
: { ...profileFromConfig, ...profileFromCredentials };
|
||||
try {
|
||||
const cfgFile = preferredFile === "config" ? configFile : credentialsFile;
|
||||
const configValue = configSelector(mergedProfile, cfgFile);
|
||||
if (configValue === undefined) {
|
||||
throw new Error();
|
||||
}
|
||||
return configValue;
|
||||
}
|
||||
catch (e) {
|
||||
throw new CredentialsProviderError(e.message || `Not found in config files w/ profile [${profile}]: ${getSelectorName(configSelector.toString())}`, { logger: init.logger });
|
||||
}
|
||||
};
|
||||
|
||||
const isFunction = (func) => typeof func === "function";
|
||||
const fromStatic = (defaultValue) => isFunction(defaultValue) ? async () => await defaultValue() : fromValue(defaultValue);
|
||||
|
||||
const loadConfig = ({ environmentVariableSelector, configFileSelector, default: defaultValue }, configuration = {}) => {
|
||||
const { signingName, logger } = configuration;
|
||||
const envOptions = { signingName, logger };
|
||||
return memoize(chain(fromEnv(environmentVariableSelector, envOptions), fromSharedConfigFiles(configFileSelector, configuration), fromStatic(defaultValue)));
|
||||
};
|
||||
|
||||
const ENV_USE_DUALSTACK_ENDPOINT = "AWS_USE_DUALSTACK_ENDPOINT";
|
||||
const CONFIG_USE_DUALSTACK_ENDPOINT = "use_dualstack_endpoint";
|
||||
const DEFAULT_USE_DUALSTACK_ENDPOINT = false;
|
||||
const NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS = {
|
||||
environmentVariableSelector: (env) => booleanSelector(env, ENV_USE_DUALSTACK_ENDPOINT, exports.SelectorType.ENV),
|
||||
configFileSelector: (profile) => booleanSelector(profile, CONFIG_USE_DUALSTACK_ENDPOINT, exports.SelectorType.CONFIG),
|
||||
default: false,
|
||||
};
|
||||
const nodeDualstackConfigSelectors = {
|
||||
environmentVariableSelector: (env) => booleanSelector(env, ENV_USE_DUALSTACK_ENDPOINT, exports.SelectorType.ENV),
|
||||
configFileSelector: (profile) => booleanSelector(profile, CONFIG_USE_DUALSTACK_ENDPOINT, exports.SelectorType.CONFIG),
|
||||
default: undefined,
|
||||
};
|
||||
|
||||
const ENV_USE_FIPS_ENDPOINT = "AWS_USE_FIPS_ENDPOINT";
|
||||
const CONFIG_USE_FIPS_ENDPOINT = "use_fips_endpoint";
|
||||
const DEFAULT_USE_FIPS_ENDPOINT = false;
|
||||
const NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS = {
|
||||
environmentVariableSelector: (env) => booleanSelector(env, ENV_USE_FIPS_ENDPOINT, exports.SelectorType.ENV),
|
||||
configFileSelector: (profile) => booleanSelector(profile, CONFIG_USE_FIPS_ENDPOINT, exports.SelectorType.CONFIG),
|
||||
default: false,
|
||||
};
|
||||
const nodeFipsConfigSelectors = {
|
||||
environmentVariableSelector: (env) => booleanSelector(env, ENV_USE_FIPS_ENDPOINT, exports.SelectorType.ENV),
|
||||
configFileSelector: (profile) => booleanSelector(profile, CONFIG_USE_FIPS_ENDPOINT, exports.SelectorType.CONFIG),
|
||||
default: undefined,
|
||||
};
|
||||
|
||||
const resolveCustomEndpointsConfig = (input) => {
|
||||
const { tls, endpoint, urlParser, useDualstackEndpoint } = input;
|
||||
return Object.assign(input, {
|
||||
tls: tls ?? true,
|
||||
endpoint: client.normalizeProvider(typeof endpoint === "string" ? urlParser(endpoint) : endpoint),
|
||||
isCustomEndpoint: true,
|
||||
useDualstackEndpoint: client.normalizeProvider(useDualstackEndpoint ?? false),
|
||||
});
|
||||
};
|
||||
|
||||
const getEndpointFromRegion = async (input) => {
|
||||
const { tls = true } = input;
|
||||
const region = await input.region();
|
||||
const dnsHostRegex = new RegExp(/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$/);
|
||||
if (!dnsHostRegex.test(region)) {
|
||||
throw new Error("Invalid region in client config");
|
||||
}
|
||||
const useDualstackEndpoint = await input.useDualstackEndpoint();
|
||||
const useFipsEndpoint = await input.useFipsEndpoint();
|
||||
const { hostname } = (await input.regionInfoProvider(region, { useDualstackEndpoint, useFipsEndpoint })) ?? {};
|
||||
if (!hostname) {
|
||||
throw new Error("Cannot resolve hostname from client config");
|
||||
}
|
||||
return input.urlParser(`${tls ? "https:" : "http:"}//${hostname}`);
|
||||
};
|
||||
|
||||
const resolveEndpointsConfig = (input) => {
|
||||
const useDualstackEndpoint = client.normalizeProvider(input.useDualstackEndpoint ?? false);
|
||||
const { endpoint, useFipsEndpoint, urlParser, tls } = input;
|
||||
return Object.assign(input, {
|
||||
tls: tls ?? true,
|
||||
endpoint: endpoint
|
||||
? client.normalizeProvider(typeof endpoint === "string" ? urlParser(endpoint) : endpoint)
|
||||
: () => getEndpointFromRegion({ ...input, useDualstackEndpoint, useFipsEndpoint }),
|
||||
isCustomEndpoint: !!endpoint,
|
||||
useDualstackEndpoint,
|
||||
});
|
||||
};
|
||||
|
||||
const REGION_ENV_NAME = "AWS_REGION";
|
||||
const REGION_INI_NAME = "region";
|
||||
const NODE_REGION_CONFIG_OPTIONS = {
|
||||
environmentVariableSelector: (env) => env[REGION_ENV_NAME],
|
||||
configFileSelector: (profile) => profile[REGION_INI_NAME],
|
||||
default: () => {
|
||||
throw new Error("Region is missing");
|
||||
},
|
||||
};
|
||||
const NODE_REGION_CONFIG_FILE_OPTIONS = {
|
||||
preferredFile: "credentials",
|
||||
};
|
||||
|
||||
const validRegions = new Set();
|
||||
const checkRegion = (region, check = transport.isValidHostLabel) => {
|
||||
if (!validRegions.has(region) && !check(region)) {
|
||||
if (region === "*") {
|
||||
console.warn(`@smithy/config-resolver WARN - Please use the caller region instead of "*". See "sigv4a" in https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md.`);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Region not accepted: region="${region}" is not a valid hostname component.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
validRegions.add(region);
|
||||
}
|
||||
};
|
||||
|
||||
const isFipsRegion = (region) => typeof region === "string" && (region.startsWith("fips-") || region.endsWith("-fips"));
|
||||
|
||||
const getRealRegion = (region) => isFipsRegion(region)
|
||||
? ["fips-aws-global", "aws-fips"].includes(region)
|
||||
? "us-east-1"
|
||||
: region.replace(/fips-(dkr-|prod-)?|-fips/, "")
|
||||
: region;
|
||||
|
||||
const resolveRegionConfig = (input) => {
|
||||
const { region, useFipsEndpoint } = input;
|
||||
if (!region) {
|
||||
throw new Error("Region is missing");
|
||||
}
|
||||
return Object.assign(input, {
|
||||
region: async () => {
|
||||
const providedRegion = typeof region === "function" ? await region() : region;
|
||||
const realRegion = getRealRegion(providedRegion);
|
||||
checkRegion(realRegion);
|
||||
return realRegion;
|
||||
},
|
||||
useFipsEndpoint: async () => {
|
||||
const providedRegion = typeof region === "string" ? region : await region();
|
||||
if (isFipsRegion(providedRegion)) {
|
||||
return true;
|
||||
}
|
||||
return typeof useFipsEndpoint !== "function" ? Promise.resolve(!!useFipsEndpoint) : useFipsEndpoint();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getHostnameFromVariants = (variants = [], { useFipsEndpoint, useDualstackEndpoint }) => variants.find(({ tags }) => useFipsEndpoint === tags.includes("fips") && useDualstackEndpoint === tags.includes("dualstack"))?.hostname;
|
||||
|
||||
const getResolvedHostname = (resolvedRegion, { regionHostname, partitionHostname }) => regionHostname
|
||||
? regionHostname
|
||||
: partitionHostname
|
||||
? partitionHostname.replace("{region}", resolvedRegion)
|
||||
: undefined;
|
||||
|
||||
const getResolvedPartition = (region, { partitionHash }) => Object.keys(partitionHash || {}).find((key) => partitionHash[key].regions.includes(region)) ?? "aws";
|
||||
|
||||
const getResolvedSigningRegion = (hostname, { signingRegion, regionRegex, useFipsEndpoint }) => {
|
||||
if (signingRegion) {
|
||||
return signingRegion;
|
||||
}
|
||||
else if (useFipsEndpoint) {
|
||||
const regionRegexJs = regionRegex.replace("\\\\", "\\").replace(/^\^/g, "\\.").replace(/\$$/g, "\\.");
|
||||
const regionRegexmatchArray = hostname.match(regionRegexJs);
|
||||
if (regionRegexmatchArray) {
|
||||
return regionRegexmatchArray[0].slice(1, -1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getRegionInfo = (region, { useFipsEndpoint = false, useDualstackEndpoint = false, signingService, regionHash, partitionHash, }) => {
|
||||
const partition = getResolvedPartition(region, { partitionHash });
|
||||
const resolvedRegion = region in regionHash ? region : partitionHash[partition]?.endpoint ?? region;
|
||||
const hostnameOptions = { useFipsEndpoint, useDualstackEndpoint };
|
||||
const regionHostname = getHostnameFromVariants(regionHash[resolvedRegion]?.variants, hostnameOptions);
|
||||
const partitionHostname = getHostnameFromVariants(partitionHash[partition]?.variants, hostnameOptions);
|
||||
const hostname = getResolvedHostname(resolvedRegion, { regionHostname, partitionHostname });
|
||||
if (hostname === undefined) {
|
||||
throw new Error(`Endpoint resolution failed for: ${{ resolvedRegion, useFipsEndpoint, useDualstackEndpoint }}`);
|
||||
}
|
||||
const signingRegion = getResolvedSigningRegion(hostname, {
|
||||
signingRegion: regionHash[resolvedRegion]?.signingRegion,
|
||||
regionRegex: partitionHash[partition].regionRegex,
|
||||
useFipsEndpoint,
|
||||
});
|
||||
return {
|
||||
partition,
|
||||
signingService,
|
||||
hostname,
|
||||
...(signingRegion && { signingRegion }),
|
||||
...(regionHash[resolvedRegion]?.signingService && {
|
||||
signingService: regionHash[resolvedRegion].signingService,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
const AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV";
|
||||
const AWS_REGION_ENV = "AWS_REGION";
|
||||
const AWS_DEFAULT_REGION_ENV = "AWS_DEFAULT_REGION";
|
||||
const ENV_IMDS_DISABLED = "AWS_EC2_METADATA_DISABLED";
|
||||
const DEFAULTS_MODE_OPTIONS = ["in-region", "cross-region", "mobile", "standard", "legacy"];
|
||||
const IMDS_REGION_PATH = "/latest/meta-data/placement/region";
|
||||
|
||||
const AWS_DEFAULTS_MODE_ENV = "AWS_DEFAULTS_MODE";
|
||||
const AWS_DEFAULTS_MODE_CONFIG = "defaults_mode";
|
||||
const NODE_DEFAULTS_MODE_CONFIG_OPTIONS = {
|
||||
environmentVariableSelector: (env) => {
|
||||
return env[AWS_DEFAULTS_MODE_ENV];
|
||||
},
|
||||
configFileSelector: (profile) => {
|
||||
return profile[AWS_DEFAULTS_MODE_CONFIG];
|
||||
},
|
||||
default: "legacy",
|
||||
};
|
||||
|
||||
const resolveDefaultsModeConfig = ({ region = loadConfig(NODE_REGION_CONFIG_OPTIONS), defaultsMode = loadConfig(NODE_DEFAULTS_MODE_CONFIG_OPTIONS), } = {}) => memoize(async () => {
|
||||
const mode = typeof defaultsMode === "function" ? await defaultsMode() : defaultsMode;
|
||||
switch (mode?.toLowerCase()) {
|
||||
case "auto":
|
||||
return resolveNodeDefaultsModeAuto(region);
|
||||
case "in-region":
|
||||
case "cross-region":
|
||||
case "mobile":
|
||||
case "standard":
|
||||
case "legacy":
|
||||
return Promise.resolve(mode?.toLocaleLowerCase());
|
||||
case undefined:
|
||||
return Promise.resolve("legacy");
|
||||
default:
|
||||
throw new Error(`Invalid parameter for "defaultsMode", expect ${DEFAULTS_MODE_OPTIONS.join(", ")}, got ${mode}`);
|
||||
}
|
||||
});
|
||||
const resolveNodeDefaultsModeAuto = async (clientRegion) => {
|
||||
if (clientRegion) {
|
||||
const resolvedRegion = typeof clientRegion === "function" ? await clientRegion() : clientRegion;
|
||||
const inferredRegion = await inferPhysicalRegion();
|
||||
if (!inferredRegion) {
|
||||
return "standard";
|
||||
}
|
||||
if (resolvedRegion === inferredRegion) {
|
||||
return "in-region";
|
||||
}
|
||||
else {
|
||||
return "cross-region";
|
||||
}
|
||||
}
|
||||
return "standard";
|
||||
};
|
||||
const inferPhysicalRegion = async () => {
|
||||
if (process.env[AWS_EXECUTION_ENV] && (process.env[AWS_REGION_ENV] || process.env[AWS_DEFAULT_REGION_ENV])) {
|
||||
return process.env[AWS_REGION_ENV] ?? process.env[AWS_DEFAULT_REGION_ENV];
|
||||
}
|
||||
if (!process.env[ENV_IMDS_DISABLED]) {
|
||||
try {
|
||||
const endpoint = await getImdsEndpoint();
|
||||
return (await imdsHttpGet({ hostname: endpoint.hostname, path: IMDS_REGION_PATH })).toString();
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
const getImdsEndpoint = async () => {
|
||||
const envEndpoint = process.env.AWS_EC2_METADATA_SERVICE_ENDPOINT;
|
||||
if (envEndpoint) {
|
||||
const url = new URL(envEndpoint);
|
||||
return { hostname: url.hostname, path: url.pathname };
|
||||
}
|
||||
const envMode = process.env.AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE;
|
||||
if (envMode === "IPv6") {
|
||||
return { hostname: "fd00:ec2::254", path: "/" };
|
||||
}
|
||||
return { hostname: "169.254.169.254", path: "/" };
|
||||
};
|
||||
const imdsHttpGet = async ({ hostname, path }) => {
|
||||
const { request } = await import('node:http');
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = request({
|
||||
method: "GET",
|
||||
hostname: hostname.replace(/^\[(.+)]$/, "$1"),
|
||||
path,
|
||||
timeout: 1000,
|
||||
signal: AbortSignal.timeout(1000),
|
||||
});
|
||||
req.on("error", (err) => {
|
||||
reject(err);
|
||||
req.destroy();
|
||||
});
|
||||
req.on("timeout", () => {
|
||||
reject(new Error("TimeoutError from instance metadata service"));
|
||||
req.destroy();
|
||||
});
|
||||
req.on("response", (res) => {
|
||||
const { statusCode = 400 } = res;
|
||||
if (statusCode < 200 || 300 <= statusCode) {
|
||||
reject(Object.assign(new Error("Error response received from instance metadata service"), { statusCode }));
|
||||
req.destroy();
|
||||
return;
|
||||
}
|
||||
const chunks = [];
|
||||
res.on("data", (chunk) => chunks.push(chunk));
|
||||
res.on("end", () => {
|
||||
resolve(Buffer.concat(chunks));
|
||||
req.destroy();
|
||||
});
|
||||
});
|
||||
req.end();
|
||||
});
|
||||
};
|
||||
|
||||
exports.CONFIG_PREFIX_SEPARATOR = CONFIG_PREFIX_SEPARATOR;
|
||||
exports.CONFIG_USE_DUALSTACK_ENDPOINT = CONFIG_USE_DUALSTACK_ENDPOINT;
|
||||
exports.CONFIG_USE_FIPS_ENDPOINT = CONFIG_USE_FIPS_ENDPOINT;
|
||||
exports.CredentialsProviderError = CredentialsProviderError;
|
||||
exports.DEFAULT_PROFILE = DEFAULT_PROFILE;
|
||||
exports.DEFAULT_USE_DUALSTACK_ENDPOINT = DEFAULT_USE_DUALSTACK_ENDPOINT;
|
||||
exports.DEFAULT_USE_FIPS_ENDPOINT = DEFAULT_USE_FIPS_ENDPOINT;
|
||||
exports.ENV_PROFILE = ENV_PROFILE;
|
||||
exports.ENV_USE_DUALSTACK_ENDPOINT = ENV_USE_DUALSTACK_ENDPOINT;
|
||||
exports.ENV_USE_FIPS_ENDPOINT = ENV_USE_FIPS_ENDPOINT;
|
||||
exports.NODE_REGION_CONFIG_FILE_OPTIONS = NODE_REGION_CONFIG_FILE_OPTIONS;
|
||||
exports.NODE_REGION_CONFIG_OPTIONS = NODE_REGION_CONFIG_OPTIONS;
|
||||
exports.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS = NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS;
|
||||
exports.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS = NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS;
|
||||
exports.ProviderError = ProviderError;
|
||||
exports.REGION_ENV_NAME = REGION_ENV_NAME;
|
||||
exports.REGION_INI_NAME = REGION_INI_NAME;
|
||||
exports.TokenProviderError = TokenProviderError;
|
||||
exports.booleanSelector = booleanSelector;
|
||||
exports.chain = chain;
|
||||
exports.externalDataInterceptor = externalDataInterceptor;
|
||||
exports.fromStatic = fromStatic;
|
||||
exports.fromValue = fromValue;
|
||||
exports.getHomeDir = getHomeDir;
|
||||
exports.getProfileName = getProfileName;
|
||||
exports.getRegionInfo = getRegionInfo;
|
||||
exports.getSSOTokenFilepath = getSSOTokenFilepath;
|
||||
exports.getSSOTokenFromFile = getSSOTokenFromFile;
|
||||
exports.loadConfig = loadConfig;
|
||||
exports.loadSharedConfigFiles = loadSharedConfigFiles;
|
||||
exports.loadSsoSessionData = loadSsoSessionData;
|
||||
exports.memoize = memoize;
|
||||
exports.nodeDualstackConfigSelectors = nodeDualstackConfigSelectors;
|
||||
exports.nodeFipsConfigSelectors = nodeFipsConfigSelectors;
|
||||
exports.numberSelector = numberSelector;
|
||||
exports.parseKnownFiles = parseKnownFiles;
|
||||
exports.readFile = readFile;
|
||||
exports.resolveCustomEndpointsConfig = resolveCustomEndpointsConfig;
|
||||
exports.resolveDefaultsModeConfig = resolveDefaultsModeConfig;
|
||||
exports.resolveEndpointsConfig = resolveEndpointsConfig;
|
||||
exports.resolveRegionConfig = resolveRegionConfig;
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
'use strict';
|
||||
|
||||
var client = require('@smithy/core/client');
|
||||
var transport = require('@smithy/core/transport');
|
||||
|
||||
class ProviderError extends Error {
|
||||
name = "ProviderError";
|
||||
tryNextLink;
|
||||
constructor(message, options = true) {
|
||||
let logger;
|
||||
let tryNextLink = true;
|
||||
if (typeof options === "boolean") {
|
||||
logger = undefined;
|
||||
tryNextLink = options;
|
||||
}
|
||||
else if (options != null && typeof options === "object") {
|
||||
logger = options.logger;
|
||||
tryNextLink = options.tryNextLink ?? true;
|
||||
}
|
||||
super(message);
|
||||
this.tryNextLink = tryNextLink;
|
||||
Object.setPrototypeOf(this, ProviderError.prototype);
|
||||
logger?.debug?.(`@smithy/property-provider ${tryNextLink ? "->" : "(!)"} ${message}`);
|
||||
}
|
||||
static from(error, options = true) {
|
||||
return Object.assign(new this(error.message, options), error);
|
||||
}
|
||||
}
|
||||
|
||||
class CredentialsProviderError extends ProviderError {
|
||||
name = "CredentialsProviderError";
|
||||
constructor(message, options = true) {
|
||||
super(message, options);
|
||||
Object.setPrototypeOf(this, CredentialsProviderError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
class TokenProviderError extends ProviderError {
|
||||
name = "TokenProviderError";
|
||||
constructor(message, options = true) {
|
||||
super(message, options);
|
||||
Object.setPrototypeOf(this, TokenProviderError.prototype);
|
||||
}
|
||||
}
|
||||
|
||||
const chain = (...providers) => async () => {
|
||||
if (providers.length === 0) {
|
||||
throw new ProviderError("No providers in chain");
|
||||
}
|
||||
let lastProviderError;
|
||||
for (const provider of providers) {
|
||||
try {
|
||||
const credentials = await provider();
|
||||
return credentials;
|
||||
}
|
||||
catch (err) {
|
||||
lastProviderError = err;
|
||||
if (err?.tryNextLink) {
|
||||
continue;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
throw lastProviderError;
|
||||
};
|
||||
|
||||
const fromValue = (staticValue) => () => Promise.resolve(staticValue);
|
||||
|
||||
const memoize = (provider, isExpired, requiresRefresh) => {
|
||||
let resolved;
|
||||
let pending;
|
||||
let hasResult;
|
||||
let isConstant = false;
|
||||
const coalesceProvider = async () => {
|
||||
if (!pending) {
|
||||
pending = provider();
|
||||
}
|
||||
try {
|
||||
resolved = await pending;
|
||||
hasResult = true;
|
||||
isConstant = false;
|
||||
}
|
||||
finally {
|
||||
pending = undefined;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
if (isExpired === undefined) {
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider();
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
}
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider();
|
||||
}
|
||||
if (isConstant) {
|
||||
return resolved;
|
||||
}
|
||||
if (requiresRefresh && !requiresRefresh(resolved)) {
|
||||
isConstant = true;
|
||||
return resolved;
|
||||
}
|
||||
if (isExpired(resolved)) {
|
||||
await coalesceProvider();
|
||||
return resolved;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
};
|
||||
|
||||
const booleanSelector = (obj, key, type) => {
|
||||
if (!(key in obj))
|
||||
return undefined;
|
||||
if (obj[key] === "true")
|
||||
return true;
|
||||
if (obj[key] === "false")
|
||||
return false;
|
||||
throw new Error(`Cannot load ${type} "${key}". Expected "true" or "false", got ${obj[key]}.`);
|
||||
};
|
||||
|
||||
const numberSelector = (obj, key, type) => {
|
||||
if (!(key in obj))
|
||||
return undefined;
|
||||
const numberValue = parseInt(obj[key], 10);
|
||||
if (Number.isNaN(numberValue)) {
|
||||
throw new TypeError(`Cannot load ${type} '${key}'. Expected number, got '${obj[key]}'.`);
|
||||
}
|
||||
return numberValue;
|
||||
};
|
||||
|
||||
exports.SelectorType = void 0;
|
||||
(function (SelectorType) {
|
||||
SelectorType["ENV"] = "env";
|
||||
SelectorType["CONFIG"] = "shared config entry";
|
||||
})(exports.SelectorType || (exports.SelectorType = {}));
|
||||
|
||||
const resolveCustomEndpointsConfig = (input) => {
|
||||
const { tls, endpoint, urlParser, useDualstackEndpoint } = input;
|
||||
return Object.assign(input, {
|
||||
tls: tls ?? true,
|
||||
endpoint: client.normalizeProvider(typeof endpoint === "string" ? urlParser(endpoint) : endpoint),
|
||||
isCustomEndpoint: true,
|
||||
useDualstackEndpoint: client.normalizeProvider(useDualstackEndpoint ?? false),
|
||||
});
|
||||
};
|
||||
|
||||
const getEndpointFromRegion = async (input) => {
|
||||
const { tls = true } = input;
|
||||
const region = await input.region();
|
||||
const dnsHostRegex = new RegExp(/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])$/);
|
||||
if (!dnsHostRegex.test(region)) {
|
||||
throw new Error("Invalid region in client config");
|
||||
}
|
||||
const useDualstackEndpoint = await input.useDualstackEndpoint();
|
||||
const useFipsEndpoint = await input.useFipsEndpoint();
|
||||
const { hostname } = (await input.regionInfoProvider(region, { useDualstackEndpoint, useFipsEndpoint })) ?? {};
|
||||
if (!hostname) {
|
||||
throw new Error("Cannot resolve hostname from client config");
|
||||
}
|
||||
return input.urlParser(`${tls ? "https:" : "http:"}//${hostname}`);
|
||||
};
|
||||
|
||||
const resolveEndpointsConfig = (input) => {
|
||||
const useDualstackEndpoint = client.normalizeProvider(input.useDualstackEndpoint ?? false);
|
||||
const { endpoint, useFipsEndpoint, urlParser, tls } = input;
|
||||
return Object.assign(input, {
|
||||
tls: tls ?? true,
|
||||
endpoint: endpoint
|
||||
? client.normalizeProvider(typeof endpoint === "string" ? urlParser(endpoint) : endpoint)
|
||||
: () => getEndpointFromRegion({ ...input, useDualstackEndpoint, useFipsEndpoint }),
|
||||
isCustomEndpoint: !!endpoint,
|
||||
useDualstackEndpoint,
|
||||
});
|
||||
};
|
||||
|
||||
const validRegions = new Set();
|
||||
const checkRegion = (region, check = transport.isValidHostLabel) => {
|
||||
if (!validRegions.has(region) && !check(region)) {
|
||||
if (region === "*") {
|
||||
console.warn(`@smithy/config-resolver WARN - Please use the caller region instead of "*". See "sigv4a" in https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md.`);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Region not accepted: region="${region}" is not a valid hostname component.`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
validRegions.add(region);
|
||||
}
|
||||
};
|
||||
|
||||
const isFipsRegion = (region) => typeof region === "string" && (region.startsWith("fips-") || region.endsWith("-fips"));
|
||||
|
||||
const getRealRegion = (region) => isFipsRegion(region)
|
||||
? ["fips-aws-global", "aws-fips"].includes(region)
|
||||
? "us-east-1"
|
||||
: region.replace(/fips-(dkr-|prod-)?|-fips/, "")
|
||||
: region;
|
||||
|
||||
const resolveRegionConfig = (input) => {
|
||||
const { region, useFipsEndpoint } = input;
|
||||
if (!region) {
|
||||
throw new Error("Region is missing");
|
||||
}
|
||||
return Object.assign(input, {
|
||||
region: async () => {
|
||||
const providedRegion = typeof region === "function" ? await region() : region;
|
||||
const realRegion = getRealRegion(providedRegion);
|
||||
checkRegion(realRegion);
|
||||
return realRegion;
|
||||
},
|
||||
useFipsEndpoint: async () => {
|
||||
const providedRegion = typeof region === "string" ? region : await region();
|
||||
if (isFipsRegion(providedRegion)) {
|
||||
return true;
|
||||
}
|
||||
return typeof useFipsEndpoint !== "function" ? Promise.resolve(!!useFipsEndpoint) : useFipsEndpoint();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getHostnameFromVariants = (variants = [], { useFipsEndpoint, useDualstackEndpoint }) => variants.find(({ tags }) => useFipsEndpoint === tags.includes("fips") && useDualstackEndpoint === tags.includes("dualstack"))?.hostname;
|
||||
|
||||
const getResolvedHostname = (resolvedRegion, { regionHostname, partitionHostname }) => regionHostname
|
||||
? regionHostname
|
||||
: partitionHostname
|
||||
? partitionHostname.replace("{region}", resolvedRegion)
|
||||
: undefined;
|
||||
|
||||
const getResolvedPartition = (region, { partitionHash }) => Object.keys(partitionHash || {}).find((key) => partitionHash[key].regions.includes(region)) ?? "aws";
|
||||
|
||||
const getResolvedSigningRegion = (hostname, { signingRegion, regionRegex, useFipsEndpoint }) => {
|
||||
if (signingRegion) {
|
||||
return signingRegion;
|
||||
}
|
||||
else if (useFipsEndpoint) {
|
||||
const regionRegexJs = regionRegex.replace("\\\\", "\\").replace(/^\^/g, "\\.").replace(/\$$/g, "\\.");
|
||||
const regionRegexmatchArray = hostname.match(regionRegexJs);
|
||||
if (regionRegexmatchArray) {
|
||||
return regionRegexmatchArray[0].slice(1, -1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getRegionInfo = (region, { useFipsEndpoint = false, useDualstackEndpoint = false, signingService, regionHash, partitionHash, }) => {
|
||||
const partition = getResolvedPartition(region, { partitionHash });
|
||||
const resolvedRegion = region in regionHash ? region : partitionHash[partition]?.endpoint ?? region;
|
||||
const hostnameOptions = { useFipsEndpoint, useDualstackEndpoint };
|
||||
const regionHostname = getHostnameFromVariants(regionHash[resolvedRegion]?.variants, hostnameOptions);
|
||||
const partitionHostname = getHostnameFromVariants(partitionHash[partition]?.variants, hostnameOptions);
|
||||
const hostname = getResolvedHostname(resolvedRegion, { regionHostname, partitionHostname });
|
||||
if (hostname === undefined) {
|
||||
throw new Error(`Endpoint resolution failed for: ${{ resolvedRegion, useFipsEndpoint, useDualstackEndpoint }}`);
|
||||
}
|
||||
const signingRegion = getResolvedSigningRegion(hostname, {
|
||||
signingRegion: regionHash[resolvedRegion]?.signingRegion,
|
||||
regionRegex: partitionHash[partition].regionRegex,
|
||||
useFipsEndpoint,
|
||||
});
|
||||
return {
|
||||
partition,
|
||||
signingService,
|
||||
hostname,
|
||||
...(signingRegion && { signingRegion }),
|
||||
...(regionHash[resolvedRegion]?.signingService && {
|
||||
signingService: regionHash[resolvedRegion].signingService,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
const DEFAULTS_MODE_OPTIONS = ["in-region", "cross-region", "mobile", "standard", "legacy"];
|
||||
|
||||
const resolveDefaultsModeConfig = ({ defaultsMode, } = {}) => memoize(async () => {
|
||||
const mode = typeof defaultsMode === "function" ? await defaultsMode() : defaultsMode;
|
||||
switch (mode?.toLowerCase()) {
|
||||
case "auto":
|
||||
return Promise.resolve("mobile");
|
||||
case "mobile":
|
||||
case "in-region":
|
||||
case "cross-region":
|
||||
case "standard":
|
||||
case "legacy":
|
||||
return Promise.resolve(mode?.toLocaleLowerCase());
|
||||
case undefined:
|
||||
return Promise.resolve("legacy");
|
||||
default:
|
||||
throw new Error(`Invalid parameter for "defaultsMode", expect ${DEFAULTS_MODE_OPTIONS.join(", ")}, got ${mode}`);
|
||||
}
|
||||
});
|
||||
|
||||
const no = Symbol.for("node-only");
|
||||
const getHomeDir = no;
|
||||
const ENV_PROFILE = no;
|
||||
const DEFAULT_PROFILE = "default";
|
||||
const getProfileName = no;
|
||||
const getSSOTokenFilepath = no;
|
||||
const getSSOTokenFromFile = no;
|
||||
const CONFIG_PREFIX_SEPARATOR = no;
|
||||
const loadSharedConfigFiles = no;
|
||||
const loadSsoSessionData = no;
|
||||
const parseKnownFiles = no;
|
||||
const externalDataInterceptor = no;
|
||||
const readFile = no;
|
||||
const loadConfig = no;
|
||||
const fromStatic = no;
|
||||
const ENV_USE_DUALSTACK_ENDPOINT = no;
|
||||
const CONFIG_USE_DUALSTACK_ENDPOINT = no;
|
||||
const DEFAULT_USE_DUALSTACK_ENDPOINT = false;
|
||||
const NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS = no;
|
||||
const nodeDualstackConfigSelectors = no;
|
||||
const ENV_USE_FIPS_ENDPOINT = no;
|
||||
const CONFIG_USE_FIPS_ENDPOINT = no;
|
||||
const DEFAULT_USE_FIPS_ENDPOINT = false;
|
||||
const NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS = no;
|
||||
const nodeFipsConfigSelectors = no;
|
||||
const REGION_ENV_NAME = no;
|
||||
const REGION_INI_NAME = no;
|
||||
const NODE_REGION_CONFIG_OPTIONS = no;
|
||||
const NODE_REGION_CONFIG_FILE_OPTIONS = no;
|
||||
|
||||
exports.CONFIG_PREFIX_SEPARATOR = CONFIG_PREFIX_SEPARATOR;
|
||||
exports.CONFIG_USE_DUALSTACK_ENDPOINT = CONFIG_USE_DUALSTACK_ENDPOINT;
|
||||
exports.CONFIG_USE_FIPS_ENDPOINT = CONFIG_USE_FIPS_ENDPOINT;
|
||||
exports.CredentialsProviderError = CredentialsProviderError;
|
||||
exports.DEFAULT_PROFILE = DEFAULT_PROFILE;
|
||||
exports.DEFAULT_USE_DUALSTACK_ENDPOINT = DEFAULT_USE_DUALSTACK_ENDPOINT;
|
||||
exports.DEFAULT_USE_FIPS_ENDPOINT = DEFAULT_USE_FIPS_ENDPOINT;
|
||||
exports.ENV_PROFILE = ENV_PROFILE;
|
||||
exports.ENV_USE_DUALSTACK_ENDPOINT = ENV_USE_DUALSTACK_ENDPOINT;
|
||||
exports.ENV_USE_FIPS_ENDPOINT = ENV_USE_FIPS_ENDPOINT;
|
||||
exports.NODE_REGION_CONFIG_FILE_OPTIONS = NODE_REGION_CONFIG_FILE_OPTIONS;
|
||||
exports.NODE_REGION_CONFIG_OPTIONS = NODE_REGION_CONFIG_OPTIONS;
|
||||
exports.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS = NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS;
|
||||
exports.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS = NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS;
|
||||
exports.ProviderError = ProviderError;
|
||||
exports.REGION_ENV_NAME = REGION_ENV_NAME;
|
||||
exports.REGION_INI_NAME = REGION_INI_NAME;
|
||||
exports.TokenProviderError = TokenProviderError;
|
||||
exports.booleanSelector = booleanSelector;
|
||||
exports.chain = chain;
|
||||
exports.externalDataInterceptor = externalDataInterceptor;
|
||||
exports.fromStatic = fromStatic;
|
||||
exports.fromValue = fromValue;
|
||||
exports.getHomeDir = getHomeDir;
|
||||
exports.getProfileName = getProfileName;
|
||||
exports.getRegionInfo = getRegionInfo;
|
||||
exports.getSSOTokenFilepath = getSSOTokenFilepath;
|
||||
exports.getSSOTokenFromFile = getSSOTokenFromFile;
|
||||
exports.loadConfig = loadConfig;
|
||||
exports.loadSharedConfigFiles = loadSharedConfigFiles;
|
||||
exports.loadSsoSessionData = loadSsoSessionData;
|
||||
exports.memoize = memoize;
|
||||
exports.nodeDualstackConfigSelectors = nodeDualstackConfigSelectors;
|
||||
exports.nodeFipsConfigSelectors = nodeFipsConfigSelectors;
|
||||
exports.numberSelector = numberSelector;
|
||||
exports.parseKnownFiles = parseKnownFiles;
|
||||
exports.readFile = readFile;
|
||||
exports.resolveCustomEndpointsConfig = resolveCustomEndpointsConfig;
|
||||
exports.resolveDefaultsModeConfig = resolveDefaultsModeConfig;
|
||||
exports.resolveEndpointsConfig = resolveEndpointsConfig;
|
||||
exports.resolveRegionConfig = resolveRegionConfig;
|
||||
+829
@@ -0,0 +1,829 @@
|
||||
'use strict';
|
||||
|
||||
var transport = require('@smithy/core/transport');
|
||||
var client = require('@smithy/core/client');
|
||||
var types = require('@smithy/types');
|
||||
|
||||
const getEndpointFromConfig = async (serviceId) => undefined;
|
||||
|
||||
const resolveParamsForS3 = async (endpointParams) => {
|
||||
const bucket = endpointParams?.Bucket || "";
|
||||
if (typeof endpointParams.Bucket === "string") {
|
||||
endpointParams.Bucket = bucket.replace(/#/g, encodeURIComponent("#")).replace(/\?/g, encodeURIComponent("?"));
|
||||
}
|
||||
if (isArnBucketName(bucket)) {
|
||||
if (endpointParams.ForcePathStyle === true) {
|
||||
throw new Error("Path-style addressing cannot be used with ARN buckets");
|
||||
}
|
||||
}
|
||||
else if (!isDnsCompatibleBucketName(bucket) ||
|
||||
(bucket.indexOf(".") !== -1 && !String(endpointParams.Endpoint).startsWith("http:")) ||
|
||||
bucket.toLowerCase() !== bucket ||
|
||||
bucket.length < 3) {
|
||||
endpointParams.ForcePathStyle = true;
|
||||
}
|
||||
if (endpointParams.DisableMultiRegionAccessPoints) {
|
||||
endpointParams.disableMultiRegionAccessPoints = true;
|
||||
endpointParams.DisableMRAP = true;
|
||||
}
|
||||
return endpointParams;
|
||||
};
|
||||
const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/;
|
||||
const IP_ADDRESS_PATTERN = /(\d+\.){3}\d+/;
|
||||
const DOTS_PATTERN = /\.\./;
|
||||
const isDnsCompatibleBucketName = (bucketName) => DOMAIN_PATTERN.test(bucketName) && !IP_ADDRESS_PATTERN.test(bucketName) && !DOTS_PATTERN.test(bucketName);
|
||||
const isArnBucketName = (bucketName) => {
|
||||
const [arn, partition, service, , , bucket] = bucketName.split(":");
|
||||
const isArn = arn === "arn" && bucketName.split(":").length >= 6;
|
||||
const isValidArn = Boolean(isArn && partition && service && bucket);
|
||||
if (isArn && !isValidArn) {
|
||||
throw new Error(`Invalid ARN: ${bucketName} was an invalid ARN.`);
|
||||
}
|
||||
return isValidArn;
|
||||
};
|
||||
|
||||
const createConfigValueProvider = (configKey, canonicalEndpointParamKey, config, isClientContextParam = false) => {
|
||||
const configProvider = async () => {
|
||||
let configValue;
|
||||
if (isClientContextParam) {
|
||||
const clientContextParams = config.clientContextParams;
|
||||
const nestedValue = clientContextParams?.[configKey];
|
||||
configValue = nestedValue ?? config[configKey] ?? config[canonicalEndpointParamKey];
|
||||
}
|
||||
else {
|
||||
configValue = config[configKey] ?? config[canonicalEndpointParamKey];
|
||||
}
|
||||
if (typeof configValue === "function") {
|
||||
return configValue();
|
||||
}
|
||||
return configValue;
|
||||
};
|
||||
if (configKey === "credentialScope" || canonicalEndpointParamKey === "CredentialScope") {
|
||||
return async () => {
|
||||
const credentials = typeof config.credentials === "function" ? await config.credentials() : config.credentials;
|
||||
const configValue = credentials?.credentialScope ?? credentials?.CredentialScope;
|
||||
return configValue;
|
||||
};
|
||||
}
|
||||
if (configKey === "accountId" || canonicalEndpointParamKey === "AccountId") {
|
||||
return async () => {
|
||||
const credentials = typeof config.credentials === "function" ? await config.credentials() : config.credentials;
|
||||
const configValue = credentials?.accountId ?? credentials?.AccountId;
|
||||
return configValue;
|
||||
};
|
||||
}
|
||||
if (configKey === "endpoint" || canonicalEndpointParamKey === "endpoint") {
|
||||
return async () => {
|
||||
if (config.isCustomEndpoint === false) {
|
||||
return undefined;
|
||||
}
|
||||
const endpoint = await configProvider();
|
||||
if (endpoint && typeof endpoint === "object") {
|
||||
if ("url" in endpoint) {
|
||||
return endpoint.url.href;
|
||||
}
|
||||
if ("hostname" in endpoint) {
|
||||
const { protocol, hostname, port, path } = endpoint;
|
||||
return `${protocol}//${hostname}${port ? ":" + port : ""}${path}`;
|
||||
}
|
||||
}
|
||||
return endpoint;
|
||||
};
|
||||
}
|
||||
return configProvider;
|
||||
};
|
||||
|
||||
function bindGetEndpointFromInstructions(getEndpointFromConfig) {
|
||||
return async (commandInput, instructionsSupplier, clientConfig, context) => {
|
||||
if (!clientConfig.isCustomEndpoint) {
|
||||
let endpointFromConfig;
|
||||
if (clientConfig.serviceConfiguredEndpoint) {
|
||||
endpointFromConfig = await clientConfig.serviceConfiguredEndpoint();
|
||||
}
|
||||
else {
|
||||
endpointFromConfig = await getEndpointFromConfig(clientConfig.serviceId);
|
||||
}
|
||||
if (endpointFromConfig) {
|
||||
clientConfig.endpoint = () => Promise.resolve(transport.toEndpointV1(endpointFromConfig));
|
||||
clientConfig.isCustomEndpoint = true;
|
||||
}
|
||||
}
|
||||
const endpointParams = await resolveParams(commandInput, instructionsSupplier, clientConfig);
|
||||
if (typeof clientConfig.endpointProvider !== "function") {
|
||||
throw new Error("config.endpointProvider is not set.");
|
||||
}
|
||||
const endpoint = clientConfig.endpointProvider(endpointParams, context);
|
||||
if (clientConfig.isCustomEndpoint && clientConfig.endpoint) {
|
||||
const customEndpoint = await clientConfig.endpoint();
|
||||
if (customEndpoint?.headers) {
|
||||
endpoint.headers ??= {};
|
||||
for (const [name, value] of Object.entries(customEndpoint.headers)) {
|
||||
endpoint.headers[name] = Array.isArray(value) ? value : [value];
|
||||
}
|
||||
}
|
||||
}
|
||||
return endpoint;
|
||||
};
|
||||
}
|
||||
const resolveParams = async (commandInput, instructionsSupplier, clientConfig) => {
|
||||
const endpointParams = {};
|
||||
const instructions = instructionsSupplier?.getEndpointParameterInstructions?.() || {};
|
||||
for (const [name, instruction] of Object.entries(instructions)) {
|
||||
switch (instruction.type) {
|
||||
case "staticContextParams":
|
||||
endpointParams[name] = instruction.value;
|
||||
break;
|
||||
case "contextParams":
|
||||
endpointParams[name] = commandInput[instruction.name];
|
||||
break;
|
||||
case "clientContextParams":
|
||||
case "builtInParams":
|
||||
endpointParams[name] = await createConfigValueProvider(instruction.name, name, clientConfig, instruction.type !== "builtInParams")();
|
||||
break;
|
||||
case "operationContextParams":
|
||||
endpointParams[name] = instruction.get(commandInput);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unrecognized endpoint parameter instruction: " + JSON.stringify(instruction));
|
||||
}
|
||||
}
|
||||
if (Object.keys(instructions).length === 0) {
|
||||
Object.assign(endpointParams, clientConfig);
|
||||
}
|
||||
if (String(clientConfig.serviceId).toLowerCase() === "s3") {
|
||||
await resolveParamsForS3(endpointParams);
|
||||
}
|
||||
return endpointParams;
|
||||
};
|
||||
|
||||
function setFeature(context, feature, value) {
|
||||
if (!context.__smithy_context) {
|
||||
context.__smithy_context = { features: {} };
|
||||
}
|
||||
else if (!context.__smithy_context.features) {
|
||||
context.__smithy_context.features = {};
|
||||
}
|
||||
context.__smithy_context.features[feature] = value;
|
||||
}
|
||||
function bindEndpointMiddleware(getEndpointFromConfig) {
|
||||
const getEndpointFromInstructions = bindGetEndpointFromInstructions(getEndpointFromConfig);
|
||||
return ({ config, instructions, }) => {
|
||||
return (next, context) => async (args) => {
|
||||
if (config.isCustomEndpoint) {
|
||||
setFeature(context, "ENDPOINT_OVERRIDE", "N");
|
||||
}
|
||||
const endpoint = await getEndpointFromInstructions(args.input, {
|
||||
getEndpointParameterInstructions() {
|
||||
return instructions;
|
||||
},
|
||||
}, { ...config }, context);
|
||||
context.endpointV2 = endpoint;
|
||||
context.authSchemes = endpoint.properties?.authSchemes;
|
||||
const authScheme = context.authSchemes?.[0];
|
||||
if (authScheme) {
|
||||
context["signing_region"] = authScheme.signingRegion;
|
||||
context["signing_service"] = authScheme.signingName;
|
||||
const smithyContext = client.getSmithyContext(context);
|
||||
const httpAuthOption = smithyContext?.selectedHttpAuthScheme?.httpAuthOption;
|
||||
if (httpAuthOption) {
|
||||
httpAuthOption.signingProperties = Object.assign(httpAuthOption.signingProperties || {}, {
|
||||
signing_region: authScheme.signingRegion,
|
||||
signingRegion: authScheme.signingRegion,
|
||||
signing_service: authScheme.signingName,
|
||||
signingName: authScheme.signingName,
|
||||
signingRegionSet: authScheme.signingRegionSet,
|
||||
}, authScheme.properties);
|
||||
}
|
||||
}
|
||||
return next({
|
||||
...args,
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const serializerMiddlewareOption = {
|
||||
name: "serializerMiddleware"};
|
||||
const endpointMiddlewareOptions = {
|
||||
step: "serialize",
|
||||
tags: ["ENDPOINT_PARAMETERS", "ENDPOINT_V2", "ENDPOINT"],
|
||||
name: "endpointV2Middleware",
|
||||
override: true,
|
||||
relation: "before",
|
||||
toMiddleware: serializerMiddlewareOption.name,
|
||||
};
|
||||
function bindGetEndpointPlugin(getEndpointFromConfig) {
|
||||
const endpointMiddleware = bindEndpointMiddleware(getEndpointFromConfig);
|
||||
return (config, instructions) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(endpointMiddleware({
|
||||
config,
|
||||
instructions,
|
||||
}), endpointMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function bindResolveEndpointConfig(getEndpointFromConfig) {
|
||||
return (input) => {
|
||||
const tls = input.tls ?? true;
|
||||
const { endpoint, useDualstackEndpoint, useFipsEndpoint } = input;
|
||||
const customEndpointProvider = endpoint != null ? async () => transport.toEndpointV1(await transport.normalizeProvider(endpoint)()) : undefined;
|
||||
const isCustomEndpoint = !!endpoint;
|
||||
const resolvedConfig = Object.assign(input, {
|
||||
endpoint: customEndpointProvider,
|
||||
tls,
|
||||
isCustomEndpoint,
|
||||
useDualstackEndpoint: transport.normalizeProvider(useDualstackEndpoint ?? false),
|
||||
useFipsEndpoint: transport.normalizeProvider(useFipsEndpoint ?? false),
|
||||
});
|
||||
let configuredEndpointPromise = undefined;
|
||||
resolvedConfig.serviceConfiguredEndpoint = async () => {
|
||||
if (input.serviceId && !configuredEndpointPromise) {
|
||||
configuredEndpointPromise = getEndpointFromConfig(input.serviceId);
|
||||
}
|
||||
return configuredEndpointPromise;
|
||||
};
|
||||
return resolvedConfig;
|
||||
};
|
||||
}
|
||||
|
||||
class BinaryDecisionDiagram {
|
||||
nodes;
|
||||
root;
|
||||
conditions;
|
||||
results;
|
||||
constructor(bdd, root, conditions, results) {
|
||||
this.nodes = bdd;
|
||||
this.root = root;
|
||||
this.conditions = conditions;
|
||||
this.results = results;
|
||||
}
|
||||
static from(bdd, root, conditions, results) {
|
||||
return new BinaryDecisionDiagram(bdd, root, conditions, results);
|
||||
}
|
||||
}
|
||||
|
||||
class EndpointCache {
|
||||
capacity;
|
||||
data = new Map();
|
||||
parameters = [];
|
||||
constructor({ size, params }) {
|
||||
this.capacity = size ?? 50;
|
||||
if (params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
}
|
||||
get(endpointParams, resolver) {
|
||||
const key = this.hash(endpointParams);
|
||||
if (key === false) {
|
||||
return resolver();
|
||||
}
|
||||
if (!this.data.has(key)) {
|
||||
if (this.data.size > this.capacity + 10) {
|
||||
const keys = this.data.keys();
|
||||
let i = 0;
|
||||
while (true) {
|
||||
const { value, done } = keys.next();
|
||||
this.data.delete(value);
|
||||
if (done || ++i > 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data.set(key, resolver());
|
||||
}
|
||||
return this.data.get(key);
|
||||
}
|
||||
size() {
|
||||
return this.data.size;
|
||||
}
|
||||
hash(endpointParams) {
|
||||
let buffer = "";
|
||||
const { parameters } = this;
|
||||
if (parameters.length === 0) {
|
||||
return false;
|
||||
}
|
||||
for (const param of parameters) {
|
||||
const val = String(endpointParams[param] ?? "");
|
||||
if (val.includes("|;")) {
|
||||
return false;
|
||||
}
|
||||
buffer += val + "|;";
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
class EndpointError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "EndpointError";
|
||||
}
|
||||
}
|
||||
|
||||
const debugId = "endpoints";
|
||||
|
||||
function toDebugString(input) {
|
||||
if (typeof input !== "object" || input == null) {
|
||||
return input;
|
||||
}
|
||||
if ("ref" in input) {
|
||||
return `$${toDebugString(input.ref)}`;
|
||||
}
|
||||
if ("fn" in input) {
|
||||
return `${input.fn}(${(input.argv || []).map(toDebugString).join(", ")})`;
|
||||
}
|
||||
return JSON.stringify(input, null, 2);
|
||||
}
|
||||
|
||||
const customEndpointFunctions = {};
|
||||
|
||||
const booleanEquals = (value1, value2) => value1 === value2;
|
||||
|
||||
function coalesce(...args) {
|
||||
for (const arg of args) {
|
||||
if (arg != null) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const getAttrPathList = (path) => {
|
||||
const parts = path.split(".");
|
||||
const pathList = [];
|
||||
for (const part of parts) {
|
||||
const squareBracketIndex = part.indexOf("[");
|
||||
if (squareBracketIndex !== -1) {
|
||||
if (part.indexOf("]") !== part.length - 1) {
|
||||
throw new EndpointError(`Path: '${path}' does not end with ']'`);
|
||||
}
|
||||
const arrayIndex = part.slice(squareBracketIndex + 1, -1);
|
||||
if (Number.isNaN(parseInt(arrayIndex))) {
|
||||
throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${path}'`);
|
||||
}
|
||||
if (squareBracketIndex !== 0) {
|
||||
pathList.push(part.slice(0, squareBracketIndex));
|
||||
}
|
||||
pathList.push(arrayIndex);
|
||||
}
|
||||
else {
|
||||
pathList.push(part);
|
||||
}
|
||||
}
|
||||
return pathList;
|
||||
};
|
||||
|
||||
const getAttr = (value, path) => getAttrPathList(path).reduce((acc, index) => {
|
||||
if (typeof acc !== "object") {
|
||||
throw new EndpointError(`Index '${index}' in '${path}' not found in '${JSON.stringify(value)}'`);
|
||||
}
|
||||
else if (Array.isArray(acc)) {
|
||||
const i = parseInt(index);
|
||||
return acc[i < 0 ? acc.length + i : i];
|
||||
}
|
||||
return acc[index];
|
||||
}, value);
|
||||
|
||||
const isSet = (value) => value != null;
|
||||
|
||||
function ite(condition, trueValue, falseValue) {
|
||||
return condition ? trueValue : falseValue;
|
||||
}
|
||||
|
||||
const not = (value) => !value;
|
||||
|
||||
const IP_V4_REGEX = new RegExp(`^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$`);
|
||||
const isIpAddress = (value) => IP_V4_REGEX.test(value) || (value.startsWith("[") && value.endsWith("]"));
|
||||
|
||||
const DEFAULT_PORTS = {
|
||||
[types.EndpointURLScheme.HTTP]: 80,
|
||||
[types.EndpointURLScheme.HTTPS]: 443,
|
||||
};
|
||||
const parseURL = (value) => {
|
||||
const whatwgURL = (() => {
|
||||
try {
|
||||
if (value instanceof URL) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "object" && "hostname" in value) {
|
||||
const { hostname, port, protocol = "", path = "", query = {} } = value;
|
||||
const url = new URL(`${protocol}//${hostname}${port ? `:${port}` : ""}${path}`);
|
||||
url.search = Object.entries(query)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join("&");
|
||||
return url;
|
||||
}
|
||||
return new URL(value);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
if (!whatwgURL) {
|
||||
console.error(`Unable to parse ${JSON.stringify(value)} as a whatwg URL.`);
|
||||
return null;
|
||||
}
|
||||
const urlString = whatwgURL.href;
|
||||
const { host, hostname, pathname, protocol, search } = whatwgURL;
|
||||
if (search) {
|
||||
return null;
|
||||
}
|
||||
const scheme = protocol.slice(0, -1);
|
||||
if (!Object.values(types.EndpointURLScheme).includes(scheme)) {
|
||||
return null;
|
||||
}
|
||||
const isIp = isIpAddress(hostname);
|
||||
const inputContainsDefaultPort = urlString.includes(`${host}:${DEFAULT_PORTS[scheme]}`) ||
|
||||
(typeof value === "string" && value.includes(`${host}:${DEFAULT_PORTS[scheme]}`));
|
||||
const authority = `${host}${inputContainsDefaultPort ? `:${DEFAULT_PORTS[scheme]}` : ``}`;
|
||||
return {
|
||||
scheme,
|
||||
authority,
|
||||
path: pathname,
|
||||
normalizedPath: pathname.endsWith("/") ? pathname : `${pathname}/`,
|
||||
isIp,
|
||||
};
|
||||
};
|
||||
|
||||
function split(value, delimiter, limit) {
|
||||
if (limit === 1) {
|
||||
return [value];
|
||||
}
|
||||
if (value === "") {
|
||||
return [""];
|
||||
}
|
||||
const parts = value.split(delimiter);
|
||||
if (limit === 0) {
|
||||
return parts;
|
||||
}
|
||||
return parts.slice(0, limit - 1).concat(parts.slice(1).join(delimiter));
|
||||
}
|
||||
|
||||
const stringEquals = (value1, value2) => value1 === value2;
|
||||
|
||||
const substring = (input, start, stop, reverse) => {
|
||||
if (input == null || start >= stop || input.length < stop || /[^\u0000-\u007f]/.test(input)) {
|
||||
return null;
|
||||
}
|
||||
if (!reverse) {
|
||||
return input.substring(start, stop);
|
||||
}
|
||||
return input.substring(input.length - stop, input.length - start);
|
||||
};
|
||||
|
||||
const uriEncode = (value) => encodeURIComponent(value).replace(/[!*'()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
||||
|
||||
const endpointFunctions = {
|
||||
booleanEquals,
|
||||
coalesce,
|
||||
getAttr,
|
||||
isSet,
|
||||
isValidHostLabel: transport.isValidHostLabel,
|
||||
ite,
|
||||
not,
|
||||
parseURL,
|
||||
split,
|
||||
stringEquals,
|
||||
substring,
|
||||
uriEncode,
|
||||
};
|
||||
|
||||
const evaluateTemplate = (template, options) => {
|
||||
const evaluatedTemplateArr = [];
|
||||
const { referenceRecord, endpointParams } = options;
|
||||
let currentIndex = 0;
|
||||
while (currentIndex < template.length) {
|
||||
const openingBraceIndex = template.indexOf("{", currentIndex);
|
||||
if (openingBraceIndex === -1) {
|
||||
evaluatedTemplateArr.push(template.slice(currentIndex));
|
||||
break;
|
||||
}
|
||||
evaluatedTemplateArr.push(template.slice(currentIndex, openingBraceIndex));
|
||||
const closingBraceIndex = template.indexOf("}", openingBraceIndex);
|
||||
if (closingBraceIndex === -1) {
|
||||
evaluatedTemplateArr.push(template.slice(openingBraceIndex));
|
||||
break;
|
||||
}
|
||||
if (template[openingBraceIndex + 1] === "{" && template[closingBraceIndex + 1] === "}") {
|
||||
evaluatedTemplateArr.push(template.slice(openingBraceIndex + 1, closingBraceIndex));
|
||||
currentIndex = closingBraceIndex + 2;
|
||||
}
|
||||
const parameterName = template.substring(openingBraceIndex + 1, closingBraceIndex);
|
||||
if (parameterName.includes("#")) {
|
||||
const [refName, attrName] = parameterName.split("#");
|
||||
evaluatedTemplateArr.push(getAttr((referenceRecord[refName] ?? endpointParams[refName]), attrName));
|
||||
}
|
||||
else {
|
||||
evaluatedTemplateArr.push((referenceRecord[parameterName] ?? endpointParams[parameterName]));
|
||||
}
|
||||
currentIndex = closingBraceIndex + 1;
|
||||
}
|
||||
return evaluatedTemplateArr.join("");
|
||||
};
|
||||
|
||||
const getReferenceValue = ({ ref }, options) => {
|
||||
return options.referenceRecord[ref] ?? options.endpointParams[ref];
|
||||
};
|
||||
|
||||
const evaluateExpression = (obj, keyName, options) => {
|
||||
if (typeof obj === "string") {
|
||||
return evaluateTemplate(obj, options);
|
||||
}
|
||||
else if (obj["fn"]) {
|
||||
return group$2.callFunction(obj, options);
|
||||
}
|
||||
else if (obj["ref"]) {
|
||||
return getReferenceValue(obj, options);
|
||||
}
|
||||
throw new EndpointError(`'${keyName}': ${String(obj)} is not a string, function or reference.`);
|
||||
};
|
||||
const callFunction = ({ fn, argv }, options) => {
|
||||
const evaluatedArgs = Array(argv.length);
|
||||
for (let i = 0; i < evaluatedArgs.length; ++i) {
|
||||
const arg = argv[i];
|
||||
if (typeof arg === "boolean" || typeof arg === "number") {
|
||||
evaluatedArgs[i] = arg;
|
||||
}
|
||||
else {
|
||||
evaluatedArgs[i] = group$2.evaluateExpression(arg, "arg", options);
|
||||
}
|
||||
}
|
||||
const namespaceSeparatorIndex = fn.indexOf(".");
|
||||
if (namespaceSeparatorIndex !== -1) {
|
||||
const namespaceFunctions = customEndpointFunctions[fn.slice(0, namespaceSeparatorIndex)];
|
||||
const customFunction = namespaceFunctions?.[fn.slice(namespaceSeparatorIndex + 1)];
|
||||
if (typeof customFunction === "function") {
|
||||
return customFunction(...evaluatedArgs);
|
||||
}
|
||||
}
|
||||
const callable = endpointFunctions[fn];
|
||||
if (typeof callable === "function") {
|
||||
return callable(...evaluatedArgs);
|
||||
}
|
||||
throw new Error(`function ${fn} not loaded in endpointFunctions.`);
|
||||
};
|
||||
const group$2 = {
|
||||
evaluateExpression,
|
||||
callFunction,
|
||||
};
|
||||
|
||||
const evaluateCondition = (condition, options) => {
|
||||
const { assign } = condition;
|
||||
if (assign && assign in options.referenceRecord) {
|
||||
throw new EndpointError(`'${assign}' is already defined in Reference Record.`);
|
||||
}
|
||||
const value = callFunction(condition, options);
|
||||
options.logger?.debug?.(`${debugId} evaluateCondition: ${toDebugString(condition)} = ${toDebugString(value)}`);
|
||||
const result = value === "" ? true : !!value;
|
||||
if (assign != null) {
|
||||
return { result, toAssign: { name: assign, value } };
|
||||
}
|
||||
return { result };
|
||||
};
|
||||
|
||||
const getEndpointHeaders = (headers, options) => Object.entries(headers ?? {}).reduce((acc, [headerKey, headerVal]) => {
|
||||
acc[headerKey] = headerVal.map((headerValEntry) => {
|
||||
const processedExpr = evaluateExpression(headerValEntry, "Header value entry", options);
|
||||
if (typeof processedExpr !== "string") {
|
||||
throw new EndpointError(`Header '${headerKey}' value '${processedExpr}' is not a string`);
|
||||
}
|
||||
return processedExpr;
|
||||
});
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const getEndpointProperties = (properties, options) => Object.entries(properties).reduce((acc, [propertyKey, propertyVal]) => {
|
||||
acc[propertyKey] = group$1.getEndpointProperty(propertyVal, options);
|
||||
return acc;
|
||||
}, {});
|
||||
const getEndpointProperty = (property, options) => {
|
||||
if (Array.isArray(property)) {
|
||||
return property.map((propertyEntry) => getEndpointProperty(propertyEntry, options));
|
||||
}
|
||||
switch (typeof property) {
|
||||
case "string":
|
||||
return evaluateTemplate(property, options);
|
||||
case "object":
|
||||
if (property === null) {
|
||||
throw new EndpointError(`Unexpected endpoint property: ${property}`);
|
||||
}
|
||||
return group$1.getEndpointProperties(property, options);
|
||||
case "boolean":
|
||||
return property;
|
||||
default:
|
||||
throw new EndpointError(`Unexpected endpoint property type: ${typeof property}`);
|
||||
}
|
||||
};
|
||||
const group$1 = {
|
||||
getEndpointProperty,
|
||||
getEndpointProperties,
|
||||
};
|
||||
|
||||
const getEndpointUrl = (endpointUrl, options) => {
|
||||
const expression = evaluateExpression(endpointUrl, "Endpoint URL", options);
|
||||
if (typeof expression === "string") {
|
||||
try {
|
||||
return new URL(expression);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to construct URL with ${expression}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
throw new EndpointError(`Endpoint URL must be a string, got ${typeof expression}`);
|
||||
};
|
||||
|
||||
const RESULT = 100_000_000;
|
||||
const decideEndpoint = (bdd, options) => {
|
||||
const { nodes, root, results, conditions } = bdd;
|
||||
let ref = root;
|
||||
const referenceRecord = {};
|
||||
const closure = {
|
||||
referenceRecord,
|
||||
endpointParams: options.endpointParams,
|
||||
logger: options.logger,
|
||||
};
|
||||
while (ref !== 1 && ref !== -1 && ref < RESULT) {
|
||||
const node_i = 3 * (Math.abs(ref) - 1);
|
||||
const [condition_i, highRef, lowRef] = [nodes[node_i], nodes[node_i + 1], nodes[node_i + 2]];
|
||||
const [fn, argv, assign] = conditions[condition_i];
|
||||
const evaluation = evaluateCondition({ fn, assign, argv }, closure);
|
||||
if (evaluation.toAssign) {
|
||||
const { name, value } = evaluation.toAssign;
|
||||
referenceRecord[name] = value;
|
||||
}
|
||||
ref = ref >= 0 === evaluation.result ? highRef : lowRef;
|
||||
}
|
||||
if (ref >= RESULT) {
|
||||
const result = results[ref - RESULT];
|
||||
if (result[0] === -1) {
|
||||
const [, errorExpression] = result;
|
||||
throw new EndpointError(evaluateExpression(errorExpression, "Error", closure));
|
||||
}
|
||||
const [url, properties, headers] = result;
|
||||
return {
|
||||
url: getEndpointUrl(url, closure),
|
||||
properties: getEndpointProperties(properties, closure),
|
||||
headers: getEndpointHeaders(headers ?? {}, closure),
|
||||
};
|
||||
}
|
||||
throw new EndpointError(`No matching endpoint.`);
|
||||
};
|
||||
|
||||
const evaluateConditions = (conditions = [], options) => {
|
||||
const conditionsReferenceRecord = {};
|
||||
const conditionOptions = {
|
||||
...options,
|
||||
referenceRecord: { ...options.referenceRecord },
|
||||
};
|
||||
let didAssign = false;
|
||||
for (const condition of conditions) {
|
||||
const { result, toAssign } = evaluateCondition(condition, conditionOptions);
|
||||
if (!result) {
|
||||
return { result };
|
||||
}
|
||||
if (toAssign) {
|
||||
didAssign = true;
|
||||
conditionsReferenceRecord[toAssign.name] = toAssign.value;
|
||||
conditionOptions.referenceRecord[toAssign.name] = toAssign.value;
|
||||
options.logger?.debug?.(`${debugId} assign: ${toAssign.name} := ${toDebugString(toAssign.value)}`);
|
||||
}
|
||||
}
|
||||
if (didAssign) {
|
||||
return { result: true, referenceRecord: conditionsReferenceRecord };
|
||||
}
|
||||
return { result: true };
|
||||
};
|
||||
|
||||
const evaluateEndpointRule = (endpointRule, options) => {
|
||||
const { conditions, endpoint } = endpointRule;
|
||||
const { result, referenceRecord } = evaluateConditions(conditions, options);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const endpointRuleOptions = referenceRecord
|
||||
? {
|
||||
...options,
|
||||
referenceRecord: { ...options.referenceRecord, ...referenceRecord },
|
||||
}
|
||||
: options;
|
||||
const { url, properties, headers } = endpoint;
|
||||
options.logger?.debug?.(`${debugId} Resolving endpoint from template: ${toDebugString(endpoint)}`);
|
||||
const endpointToReturn = { url: getEndpointUrl(url, endpointRuleOptions) };
|
||||
if (headers != null) {
|
||||
endpointToReturn.headers = getEndpointHeaders(headers, endpointRuleOptions);
|
||||
}
|
||||
if (properties != null) {
|
||||
endpointToReturn.properties = getEndpointProperties(properties, endpointRuleOptions);
|
||||
}
|
||||
return endpointToReturn;
|
||||
};
|
||||
|
||||
const evaluateErrorRule = (errorRule, options) => {
|
||||
const { conditions, error } = errorRule;
|
||||
const { result, referenceRecord } = evaluateConditions(conditions, options);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const errorRuleOptions = referenceRecord
|
||||
? {
|
||||
...options,
|
||||
referenceRecord: { ...options.referenceRecord, ...referenceRecord },
|
||||
}
|
||||
: options;
|
||||
throw new EndpointError(evaluateExpression(error, "Error", errorRuleOptions));
|
||||
};
|
||||
|
||||
const evaluateRules = (rules, options) => {
|
||||
for (const rule of rules) {
|
||||
if (rule.type === "endpoint") {
|
||||
const endpointOrUndefined = evaluateEndpointRule(rule, options);
|
||||
if (endpointOrUndefined) {
|
||||
return endpointOrUndefined;
|
||||
}
|
||||
}
|
||||
else if (rule.type === "error") {
|
||||
evaluateErrorRule(rule, options);
|
||||
}
|
||||
else if (rule.type === "tree") {
|
||||
const endpointOrUndefined = group.evaluateTreeRule(rule, options);
|
||||
if (endpointOrUndefined) {
|
||||
return endpointOrUndefined;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new EndpointError(`Unknown endpoint rule: ${rule}`);
|
||||
}
|
||||
}
|
||||
throw new EndpointError(`Rules evaluation failed`);
|
||||
};
|
||||
const evaluateTreeRule = (treeRule, options) => {
|
||||
const { conditions, rules } = treeRule;
|
||||
const { result, referenceRecord } = evaluateConditions(conditions, options);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const treeRuleOptions = referenceRecord
|
||||
? { ...options, referenceRecord: { ...options.referenceRecord, ...referenceRecord } }
|
||||
: options;
|
||||
return group.evaluateRules(rules, treeRuleOptions);
|
||||
};
|
||||
const group = {
|
||||
evaluateRules,
|
||||
evaluateTreeRule,
|
||||
};
|
||||
|
||||
const resolveEndpoint = (ruleSetObject, options) => {
|
||||
const { endpointParams, logger } = options;
|
||||
const { parameters, rules } = ruleSetObject;
|
||||
options.logger?.debug?.(`${debugId} Initial EndpointParams: ${toDebugString(endpointParams)}`);
|
||||
for (const paramKey in parameters) {
|
||||
const parameter = parameters[paramKey];
|
||||
const endpointParam = endpointParams[paramKey];
|
||||
if (endpointParam == null && parameter.default != null) {
|
||||
endpointParams[paramKey] = parameter.default;
|
||||
continue;
|
||||
}
|
||||
if (parameter.required && endpointParam == null) {
|
||||
throw new EndpointError(`Missing required parameter: '${paramKey}'`);
|
||||
}
|
||||
}
|
||||
const endpoint = evaluateRules(rules, { endpointParams, logger, referenceRecord: {} });
|
||||
options.logger?.debug?.(`${debugId} Resolved endpoint: ${toDebugString(endpoint)}`);
|
||||
return endpoint;
|
||||
};
|
||||
|
||||
const resolveEndpointRequiredConfig = (input) => {
|
||||
const { endpoint } = input;
|
||||
if (endpoint === undefined) {
|
||||
input.endpoint = async () => {
|
||||
throw new Error("@smithy/middleware-endpoint: (default endpointRuleSet) endpoint is not set - you must configure an endpoint.");
|
||||
};
|
||||
}
|
||||
return input;
|
||||
};
|
||||
|
||||
const getEndpointFromInstructions = bindGetEndpointFromInstructions(getEndpointFromConfig);
|
||||
const resolveEndpointConfig = bindResolveEndpointConfig(getEndpointFromConfig);
|
||||
const endpointMiddleware = bindEndpointMiddleware(getEndpointFromConfig);
|
||||
const getEndpointPlugin = bindGetEndpointPlugin(getEndpointFromConfig);
|
||||
|
||||
exports.isValidHostLabel = transport.isValidHostLabel;
|
||||
exports.middlewareEndpointToEndpointV1 = transport.toEndpointV1;
|
||||
exports.toEndpointV1 = transport.toEndpointV1;
|
||||
exports.BinaryDecisionDiagram = BinaryDecisionDiagram;
|
||||
exports.EndpointCache = EndpointCache;
|
||||
exports.EndpointError = EndpointError;
|
||||
exports.customEndpointFunctions = customEndpointFunctions;
|
||||
exports.decideEndpoint = decideEndpoint;
|
||||
exports.endpointMiddleware = endpointMiddleware;
|
||||
exports.endpointMiddlewareOptions = endpointMiddlewareOptions;
|
||||
exports.getEndpointFromInstructions = getEndpointFromInstructions;
|
||||
exports.getEndpointPlugin = getEndpointPlugin;
|
||||
exports.isIpAddress = isIpAddress;
|
||||
exports.resolveEndpoint = resolveEndpoint;
|
||||
exports.resolveEndpointConfig = resolveEndpointConfig;
|
||||
exports.resolveEndpointRequiredConfig = resolveEndpointRequiredConfig;
|
||||
exports.resolveParams = resolveParams;
|
||||
+861
@@ -0,0 +1,861 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('@smithy/core/config');
|
||||
var transport = require('@smithy/core/transport');
|
||||
var client = require('@smithy/core/client');
|
||||
var types = require('@smithy/types');
|
||||
|
||||
const ENV_ENDPOINT_URL = "AWS_ENDPOINT_URL";
|
||||
const CONFIG_ENDPOINT_URL = "endpoint_url";
|
||||
const getEndpointUrlConfig = (serviceId) => ({
|
||||
environmentVariableSelector: (env) => {
|
||||
const serviceSuffixParts = serviceId.split(" ").map((w) => w.toUpperCase());
|
||||
const serviceEndpointUrl = env[[ENV_ENDPOINT_URL, ...serviceSuffixParts].join("_")];
|
||||
if (serviceEndpointUrl)
|
||||
return serviceEndpointUrl;
|
||||
const endpointUrl = env[ENV_ENDPOINT_URL];
|
||||
if (endpointUrl)
|
||||
return endpointUrl;
|
||||
return undefined;
|
||||
},
|
||||
configFileSelector: (profile, config$1) => {
|
||||
if (config$1 && profile.services) {
|
||||
const servicesSection = config$1[["services", profile.services].join(config.CONFIG_PREFIX_SEPARATOR)];
|
||||
if (servicesSection) {
|
||||
const servicePrefixParts = serviceId.split(" ").map((w) => w.toLowerCase());
|
||||
const endpointUrl = servicesSection[[servicePrefixParts.join("_"), CONFIG_ENDPOINT_URL].join(config.CONFIG_PREFIX_SEPARATOR)];
|
||||
if (endpointUrl)
|
||||
return endpointUrl;
|
||||
}
|
||||
}
|
||||
const endpointUrl = profile[CONFIG_ENDPOINT_URL];
|
||||
if (endpointUrl)
|
||||
return endpointUrl;
|
||||
return undefined;
|
||||
},
|
||||
default: undefined,
|
||||
});
|
||||
|
||||
const getEndpointFromConfig = async (serviceId) => config.loadConfig(getEndpointUrlConfig(serviceId ?? ""))();
|
||||
|
||||
const resolveParamsForS3 = async (endpointParams) => {
|
||||
const bucket = endpointParams?.Bucket || "";
|
||||
if (typeof endpointParams.Bucket === "string") {
|
||||
endpointParams.Bucket = bucket.replace(/#/g, encodeURIComponent("#")).replace(/\?/g, encodeURIComponent("?"));
|
||||
}
|
||||
if (isArnBucketName(bucket)) {
|
||||
if (endpointParams.ForcePathStyle === true) {
|
||||
throw new Error("Path-style addressing cannot be used with ARN buckets");
|
||||
}
|
||||
}
|
||||
else if (!isDnsCompatibleBucketName(bucket) ||
|
||||
(bucket.indexOf(".") !== -1 && !String(endpointParams.Endpoint).startsWith("http:")) ||
|
||||
bucket.toLowerCase() !== bucket ||
|
||||
bucket.length < 3) {
|
||||
endpointParams.ForcePathStyle = true;
|
||||
}
|
||||
if (endpointParams.DisableMultiRegionAccessPoints) {
|
||||
endpointParams.disableMultiRegionAccessPoints = true;
|
||||
endpointParams.DisableMRAP = true;
|
||||
}
|
||||
return endpointParams;
|
||||
};
|
||||
const DOMAIN_PATTERN = /^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$/;
|
||||
const IP_ADDRESS_PATTERN = /(\d+\.){3}\d+/;
|
||||
const DOTS_PATTERN = /\.\./;
|
||||
const isDnsCompatibleBucketName = (bucketName) => DOMAIN_PATTERN.test(bucketName) && !IP_ADDRESS_PATTERN.test(bucketName) && !DOTS_PATTERN.test(bucketName);
|
||||
const isArnBucketName = (bucketName) => {
|
||||
const [arn, partition, service, , , bucket] = bucketName.split(":");
|
||||
const isArn = arn === "arn" && bucketName.split(":").length >= 6;
|
||||
const isValidArn = Boolean(isArn && partition && service && bucket);
|
||||
if (isArn && !isValidArn) {
|
||||
throw new Error(`Invalid ARN: ${bucketName} was an invalid ARN.`);
|
||||
}
|
||||
return isValidArn;
|
||||
};
|
||||
|
||||
const createConfigValueProvider = (configKey, canonicalEndpointParamKey, config, isClientContextParam = false) => {
|
||||
const configProvider = async () => {
|
||||
let configValue;
|
||||
if (isClientContextParam) {
|
||||
const clientContextParams = config.clientContextParams;
|
||||
const nestedValue = clientContextParams?.[configKey];
|
||||
configValue = nestedValue ?? config[configKey] ?? config[canonicalEndpointParamKey];
|
||||
}
|
||||
else {
|
||||
configValue = config[configKey] ?? config[canonicalEndpointParamKey];
|
||||
}
|
||||
if (typeof configValue === "function") {
|
||||
return configValue();
|
||||
}
|
||||
return configValue;
|
||||
};
|
||||
if (configKey === "credentialScope" || canonicalEndpointParamKey === "CredentialScope") {
|
||||
return async () => {
|
||||
const credentials = typeof config.credentials === "function" ? await config.credentials() : config.credentials;
|
||||
const configValue = credentials?.credentialScope ?? credentials?.CredentialScope;
|
||||
return configValue;
|
||||
};
|
||||
}
|
||||
if (configKey === "accountId" || canonicalEndpointParamKey === "AccountId") {
|
||||
return async () => {
|
||||
const credentials = typeof config.credentials === "function" ? await config.credentials() : config.credentials;
|
||||
const configValue = credentials?.accountId ?? credentials?.AccountId;
|
||||
return configValue;
|
||||
};
|
||||
}
|
||||
if (configKey === "endpoint" || canonicalEndpointParamKey === "endpoint") {
|
||||
return async () => {
|
||||
if (config.isCustomEndpoint === false) {
|
||||
return undefined;
|
||||
}
|
||||
const endpoint = await configProvider();
|
||||
if (endpoint && typeof endpoint === "object") {
|
||||
if ("url" in endpoint) {
|
||||
return endpoint.url.href;
|
||||
}
|
||||
if ("hostname" in endpoint) {
|
||||
const { protocol, hostname, port, path } = endpoint;
|
||||
return `${protocol}//${hostname}${port ? ":" + port : ""}${path}`;
|
||||
}
|
||||
}
|
||||
return endpoint;
|
||||
};
|
||||
}
|
||||
return configProvider;
|
||||
};
|
||||
|
||||
function bindGetEndpointFromInstructions(getEndpointFromConfig) {
|
||||
return async (commandInput, instructionsSupplier, clientConfig, context) => {
|
||||
if (!clientConfig.isCustomEndpoint) {
|
||||
let endpointFromConfig;
|
||||
if (clientConfig.serviceConfiguredEndpoint) {
|
||||
endpointFromConfig = await clientConfig.serviceConfiguredEndpoint();
|
||||
}
|
||||
else {
|
||||
endpointFromConfig = await getEndpointFromConfig(clientConfig.serviceId);
|
||||
}
|
||||
if (endpointFromConfig) {
|
||||
clientConfig.endpoint = () => Promise.resolve(transport.toEndpointV1(endpointFromConfig));
|
||||
clientConfig.isCustomEndpoint = true;
|
||||
}
|
||||
}
|
||||
const endpointParams = await resolveParams(commandInput, instructionsSupplier, clientConfig);
|
||||
if (typeof clientConfig.endpointProvider !== "function") {
|
||||
throw new Error("config.endpointProvider is not set.");
|
||||
}
|
||||
const endpoint = clientConfig.endpointProvider(endpointParams, context);
|
||||
if (clientConfig.isCustomEndpoint && clientConfig.endpoint) {
|
||||
const customEndpoint = await clientConfig.endpoint();
|
||||
if (customEndpoint?.headers) {
|
||||
endpoint.headers ??= {};
|
||||
for (const [name, value] of Object.entries(customEndpoint.headers)) {
|
||||
endpoint.headers[name] = Array.isArray(value) ? value : [value];
|
||||
}
|
||||
}
|
||||
}
|
||||
return endpoint;
|
||||
};
|
||||
}
|
||||
const resolveParams = async (commandInput, instructionsSupplier, clientConfig) => {
|
||||
const endpointParams = {};
|
||||
const instructions = instructionsSupplier?.getEndpointParameterInstructions?.() || {};
|
||||
for (const [name, instruction] of Object.entries(instructions)) {
|
||||
switch (instruction.type) {
|
||||
case "staticContextParams":
|
||||
endpointParams[name] = instruction.value;
|
||||
break;
|
||||
case "contextParams":
|
||||
endpointParams[name] = commandInput[instruction.name];
|
||||
break;
|
||||
case "clientContextParams":
|
||||
case "builtInParams":
|
||||
endpointParams[name] = await createConfigValueProvider(instruction.name, name, clientConfig, instruction.type !== "builtInParams")();
|
||||
break;
|
||||
case "operationContextParams":
|
||||
endpointParams[name] = instruction.get(commandInput);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unrecognized endpoint parameter instruction: " + JSON.stringify(instruction));
|
||||
}
|
||||
}
|
||||
if (Object.keys(instructions).length === 0) {
|
||||
Object.assign(endpointParams, clientConfig);
|
||||
}
|
||||
if (String(clientConfig.serviceId).toLowerCase() === "s3") {
|
||||
await resolveParamsForS3(endpointParams);
|
||||
}
|
||||
return endpointParams;
|
||||
};
|
||||
|
||||
function setFeature(context, feature, value) {
|
||||
if (!context.__smithy_context) {
|
||||
context.__smithy_context = { features: {} };
|
||||
}
|
||||
else if (!context.__smithy_context.features) {
|
||||
context.__smithy_context.features = {};
|
||||
}
|
||||
context.__smithy_context.features[feature] = value;
|
||||
}
|
||||
function bindEndpointMiddleware(getEndpointFromConfig) {
|
||||
const getEndpointFromInstructions = bindGetEndpointFromInstructions(getEndpointFromConfig);
|
||||
return ({ config, instructions, }) => {
|
||||
return (next, context) => async (args) => {
|
||||
if (config.isCustomEndpoint) {
|
||||
setFeature(context, "ENDPOINT_OVERRIDE", "N");
|
||||
}
|
||||
const endpoint = await getEndpointFromInstructions(args.input, {
|
||||
getEndpointParameterInstructions() {
|
||||
return instructions;
|
||||
},
|
||||
}, { ...config }, context);
|
||||
context.endpointV2 = endpoint;
|
||||
context.authSchemes = endpoint.properties?.authSchemes;
|
||||
const authScheme = context.authSchemes?.[0];
|
||||
if (authScheme) {
|
||||
context["signing_region"] = authScheme.signingRegion;
|
||||
context["signing_service"] = authScheme.signingName;
|
||||
const smithyContext = client.getSmithyContext(context);
|
||||
const httpAuthOption = smithyContext?.selectedHttpAuthScheme?.httpAuthOption;
|
||||
if (httpAuthOption) {
|
||||
httpAuthOption.signingProperties = Object.assign(httpAuthOption.signingProperties || {}, {
|
||||
signing_region: authScheme.signingRegion,
|
||||
signingRegion: authScheme.signingRegion,
|
||||
signing_service: authScheme.signingName,
|
||||
signingName: authScheme.signingName,
|
||||
signingRegionSet: authScheme.signingRegionSet,
|
||||
}, authScheme.properties);
|
||||
}
|
||||
}
|
||||
return next({
|
||||
...args,
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const serializerMiddlewareOption = {
|
||||
name: "serializerMiddleware"};
|
||||
const endpointMiddlewareOptions = {
|
||||
step: "serialize",
|
||||
tags: ["ENDPOINT_PARAMETERS", "ENDPOINT_V2", "ENDPOINT"],
|
||||
name: "endpointV2Middleware",
|
||||
override: true,
|
||||
relation: "before",
|
||||
toMiddleware: serializerMiddlewareOption.name,
|
||||
};
|
||||
function bindGetEndpointPlugin(getEndpointFromConfig) {
|
||||
const endpointMiddleware = bindEndpointMiddleware(getEndpointFromConfig);
|
||||
return (config, instructions) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(endpointMiddleware({
|
||||
config,
|
||||
instructions,
|
||||
}), endpointMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function bindResolveEndpointConfig(getEndpointFromConfig) {
|
||||
return (input) => {
|
||||
const tls = input.tls ?? true;
|
||||
const { endpoint, useDualstackEndpoint, useFipsEndpoint } = input;
|
||||
const customEndpointProvider = endpoint != null ? async () => transport.toEndpointV1(await transport.normalizeProvider(endpoint)()) : undefined;
|
||||
const isCustomEndpoint = !!endpoint;
|
||||
const resolvedConfig = Object.assign(input, {
|
||||
endpoint: customEndpointProvider,
|
||||
tls,
|
||||
isCustomEndpoint,
|
||||
useDualstackEndpoint: transport.normalizeProvider(useDualstackEndpoint ?? false),
|
||||
useFipsEndpoint: transport.normalizeProvider(useFipsEndpoint ?? false),
|
||||
});
|
||||
let configuredEndpointPromise = undefined;
|
||||
resolvedConfig.serviceConfiguredEndpoint = async () => {
|
||||
if (input.serviceId && !configuredEndpointPromise) {
|
||||
configuredEndpointPromise = getEndpointFromConfig(input.serviceId);
|
||||
}
|
||||
return configuredEndpointPromise;
|
||||
};
|
||||
return resolvedConfig;
|
||||
};
|
||||
}
|
||||
|
||||
class BinaryDecisionDiagram {
|
||||
nodes;
|
||||
root;
|
||||
conditions;
|
||||
results;
|
||||
constructor(bdd, root, conditions, results) {
|
||||
this.nodes = bdd;
|
||||
this.root = root;
|
||||
this.conditions = conditions;
|
||||
this.results = results;
|
||||
}
|
||||
static from(bdd, root, conditions, results) {
|
||||
return new BinaryDecisionDiagram(bdd, root, conditions, results);
|
||||
}
|
||||
}
|
||||
|
||||
class EndpointCache {
|
||||
capacity;
|
||||
data = new Map();
|
||||
parameters = [];
|
||||
constructor({ size, params }) {
|
||||
this.capacity = size ?? 50;
|
||||
if (params) {
|
||||
this.parameters = params;
|
||||
}
|
||||
}
|
||||
get(endpointParams, resolver) {
|
||||
const key = this.hash(endpointParams);
|
||||
if (key === false) {
|
||||
return resolver();
|
||||
}
|
||||
if (!this.data.has(key)) {
|
||||
if (this.data.size > this.capacity + 10) {
|
||||
const keys = this.data.keys();
|
||||
let i = 0;
|
||||
while (true) {
|
||||
const { value, done } = keys.next();
|
||||
this.data.delete(value);
|
||||
if (done || ++i > 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.data.set(key, resolver());
|
||||
}
|
||||
return this.data.get(key);
|
||||
}
|
||||
size() {
|
||||
return this.data.size;
|
||||
}
|
||||
hash(endpointParams) {
|
||||
let buffer = "";
|
||||
const { parameters } = this;
|
||||
if (parameters.length === 0) {
|
||||
return false;
|
||||
}
|
||||
for (const param of parameters) {
|
||||
const val = String(endpointParams[param] ?? "");
|
||||
if (val.includes("|;")) {
|
||||
return false;
|
||||
}
|
||||
buffer += val + "|;";
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
class EndpointError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "EndpointError";
|
||||
}
|
||||
}
|
||||
|
||||
const debugId = "endpoints";
|
||||
|
||||
function toDebugString(input) {
|
||||
if (typeof input !== "object" || input == null) {
|
||||
return input;
|
||||
}
|
||||
if ("ref" in input) {
|
||||
return `$${toDebugString(input.ref)}`;
|
||||
}
|
||||
if ("fn" in input) {
|
||||
return `${input.fn}(${(input.argv || []).map(toDebugString).join(", ")})`;
|
||||
}
|
||||
return JSON.stringify(input, null, 2);
|
||||
}
|
||||
|
||||
const customEndpointFunctions = {};
|
||||
|
||||
const booleanEquals = (value1, value2) => value1 === value2;
|
||||
|
||||
function coalesce(...args) {
|
||||
for (const arg of args) {
|
||||
if (arg != null) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const getAttrPathList = (path) => {
|
||||
const parts = path.split(".");
|
||||
const pathList = [];
|
||||
for (const part of parts) {
|
||||
const squareBracketIndex = part.indexOf("[");
|
||||
if (squareBracketIndex !== -1) {
|
||||
if (part.indexOf("]") !== part.length - 1) {
|
||||
throw new EndpointError(`Path: '${path}' does not end with ']'`);
|
||||
}
|
||||
const arrayIndex = part.slice(squareBracketIndex + 1, -1);
|
||||
if (Number.isNaN(parseInt(arrayIndex))) {
|
||||
throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${path}'`);
|
||||
}
|
||||
if (squareBracketIndex !== 0) {
|
||||
pathList.push(part.slice(0, squareBracketIndex));
|
||||
}
|
||||
pathList.push(arrayIndex);
|
||||
}
|
||||
else {
|
||||
pathList.push(part);
|
||||
}
|
||||
}
|
||||
return pathList;
|
||||
};
|
||||
|
||||
const getAttr = (value, path) => getAttrPathList(path).reduce((acc, index) => {
|
||||
if (typeof acc !== "object") {
|
||||
throw new EndpointError(`Index '${index}' in '${path}' not found in '${JSON.stringify(value)}'`);
|
||||
}
|
||||
else if (Array.isArray(acc)) {
|
||||
const i = parseInt(index);
|
||||
return acc[i < 0 ? acc.length + i : i];
|
||||
}
|
||||
return acc[index];
|
||||
}, value);
|
||||
|
||||
const isSet = (value) => value != null;
|
||||
|
||||
function ite(condition, trueValue, falseValue) {
|
||||
return condition ? trueValue : falseValue;
|
||||
}
|
||||
|
||||
const not = (value) => !value;
|
||||
|
||||
const IP_V4_REGEX = new RegExp(`^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$`);
|
||||
const isIpAddress = (value) => IP_V4_REGEX.test(value) || (value.startsWith("[") && value.endsWith("]"));
|
||||
|
||||
const DEFAULT_PORTS = {
|
||||
[types.EndpointURLScheme.HTTP]: 80,
|
||||
[types.EndpointURLScheme.HTTPS]: 443,
|
||||
};
|
||||
const parseURL = (value) => {
|
||||
const whatwgURL = (() => {
|
||||
try {
|
||||
if (value instanceof URL) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "object" && "hostname" in value) {
|
||||
const { hostname, port, protocol = "", path = "", query = {} } = value;
|
||||
const url = new URL(`${protocol}//${hostname}${port ? `:${port}` : ""}${path}`);
|
||||
url.search = Object.entries(query)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join("&");
|
||||
return url;
|
||||
}
|
||||
return new URL(value);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
if (!whatwgURL) {
|
||||
console.error(`Unable to parse ${JSON.stringify(value)} as a whatwg URL.`);
|
||||
return null;
|
||||
}
|
||||
const urlString = whatwgURL.href;
|
||||
const { host, hostname, pathname, protocol, search } = whatwgURL;
|
||||
if (search) {
|
||||
return null;
|
||||
}
|
||||
const scheme = protocol.slice(0, -1);
|
||||
if (!Object.values(types.EndpointURLScheme).includes(scheme)) {
|
||||
return null;
|
||||
}
|
||||
const isIp = isIpAddress(hostname);
|
||||
const inputContainsDefaultPort = urlString.includes(`${host}:${DEFAULT_PORTS[scheme]}`) ||
|
||||
(typeof value === "string" && value.includes(`${host}:${DEFAULT_PORTS[scheme]}`));
|
||||
const authority = `${host}${inputContainsDefaultPort ? `:${DEFAULT_PORTS[scheme]}` : ``}`;
|
||||
return {
|
||||
scheme,
|
||||
authority,
|
||||
path: pathname,
|
||||
normalizedPath: pathname.endsWith("/") ? pathname : `${pathname}/`,
|
||||
isIp,
|
||||
};
|
||||
};
|
||||
|
||||
function split(value, delimiter, limit) {
|
||||
if (limit === 1) {
|
||||
return [value];
|
||||
}
|
||||
if (value === "") {
|
||||
return [""];
|
||||
}
|
||||
const parts = value.split(delimiter);
|
||||
if (limit === 0) {
|
||||
return parts;
|
||||
}
|
||||
return parts.slice(0, limit - 1).concat(parts.slice(1).join(delimiter));
|
||||
}
|
||||
|
||||
const stringEquals = (value1, value2) => value1 === value2;
|
||||
|
||||
const substring = (input, start, stop, reverse) => {
|
||||
if (input == null || start >= stop || input.length < stop || /[^\u0000-\u007f]/.test(input)) {
|
||||
return null;
|
||||
}
|
||||
if (!reverse) {
|
||||
return input.substring(start, stop);
|
||||
}
|
||||
return input.substring(input.length - stop, input.length - start);
|
||||
};
|
||||
|
||||
const uriEncode = (value) => encodeURIComponent(value).replace(/[!*'()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
||||
|
||||
const endpointFunctions = {
|
||||
booleanEquals,
|
||||
coalesce,
|
||||
getAttr,
|
||||
isSet,
|
||||
isValidHostLabel: transport.isValidHostLabel,
|
||||
ite,
|
||||
not,
|
||||
parseURL,
|
||||
split,
|
||||
stringEquals,
|
||||
substring,
|
||||
uriEncode,
|
||||
};
|
||||
|
||||
const evaluateTemplate = (template, options) => {
|
||||
const evaluatedTemplateArr = [];
|
||||
const { referenceRecord, endpointParams } = options;
|
||||
let currentIndex = 0;
|
||||
while (currentIndex < template.length) {
|
||||
const openingBraceIndex = template.indexOf("{", currentIndex);
|
||||
if (openingBraceIndex === -1) {
|
||||
evaluatedTemplateArr.push(template.slice(currentIndex));
|
||||
break;
|
||||
}
|
||||
evaluatedTemplateArr.push(template.slice(currentIndex, openingBraceIndex));
|
||||
const closingBraceIndex = template.indexOf("}", openingBraceIndex);
|
||||
if (closingBraceIndex === -1) {
|
||||
evaluatedTemplateArr.push(template.slice(openingBraceIndex));
|
||||
break;
|
||||
}
|
||||
if (template[openingBraceIndex + 1] === "{" && template[closingBraceIndex + 1] === "}") {
|
||||
evaluatedTemplateArr.push(template.slice(openingBraceIndex + 1, closingBraceIndex));
|
||||
currentIndex = closingBraceIndex + 2;
|
||||
}
|
||||
const parameterName = template.substring(openingBraceIndex + 1, closingBraceIndex);
|
||||
if (parameterName.includes("#")) {
|
||||
const [refName, attrName] = parameterName.split("#");
|
||||
evaluatedTemplateArr.push(getAttr((referenceRecord[refName] ?? endpointParams[refName]), attrName));
|
||||
}
|
||||
else {
|
||||
evaluatedTemplateArr.push((referenceRecord[parameterName] ?? endpointParams[parameterName]));
|
||||
}
|
||||
currentIndex = closingBraceIndex + 1;
|
||||
}
|
||||
return evaluatedTemplateArr.join("");
|
||||
};
|
||||
|
||||
const getReferenceValue = ({ ref }, options) => {
|
||||
return options.referenceRecord[ref] ?? options.endpointParams[ref];
|
||||
};
|
||||
|
||||
const evaluateExpression = (obj, keyName, options) => {
|
||||
if (typeof obj === "string") {
|
||||
return evaluateTemplate(obj, options);
|
||||
}
|
||||
else if (obj["fn"]) {
|
||||
return group$2.callFunction(obj, options);
|
||||
}
|
||||
else if (obj["ref"]) {
|
||||
return getReferenceValue(obj, options);
|
||||
}
|
||||
throw new EndpointError(`'${keyName}': ${String(obj)} is not a string, function or reference.`);
|
||||
};
|
||||
const callFunction = ({ fn, argv }, options) => {
|
||||
const evaluatedArgs = Array(argv.length);
|
||||
for (let i = 0; i < evaluatedArgs.length; ++i) {
|
||||
const arg = argv[i];
|
||||
if (typeof arg === "boolean" || typeof arg === "number") {
|
||||
evaluatedArgs[i] = arg;
|
||||
}
|
||||
else {
|
||||
evaluatedArgs[i] = group$2.evaluateExpression(arg, "arg", options);
|
||||
}
|
||||
}
|
||||
const namespaceSeparatorIndex = fn.indexOf(".");
|
||||
if (namespaceSeparatorIndex !== -1) {
|
||||
const namespaceFunctions = customEndpointFunctions[fn.slice(0, namespaceSeparatorIndex)];
|
||||
const customFunction = namespaceFunctions?.[fn.slice(namespaceSeparatorIndex + 1)];
|
||||
if (typeof customFunction === "function") {
|
||||
return customFunction(...evaluatedArgs);
|
||||
}
|
||||
}
|
||||
const callable = endpointFunctions[fn];
|
||||
if (typeof callable === "function") {
|
||||
return callable(...evaluatedArgs);
|
||||
}
|
||||
throw new Error(`function ${fn} not loaded in endpointFunctions.`);
|
||||
};
|
||||
const group$2 = {
|
||||
evaluateExpression,
|
||||
callFunction,
|
||||
};
|
||||
|
||||
const evaluateCondition = (condition, options) => {
|
||||
const { assign } = condition;
|
||||
if (assign && assign in options.referenceRecord) {
|
||||
throw new EndpointError(`'${assign}' is already defined in Reference Record.`);
|
||||
}
|
||||
const value = callFunction(condition, options);
|
||||
options.logger?.debug?.(`${debugId} evaluateCondition: ${toDebugString(condition)} = ${toDebugString(value)}`);
|
||||
const result = value === "" ? true : !!value;
|
||||
if (assign != null) {
|
||||
return { result, toAssign: { name: assign, value } };
|
||||
}
|
||||
return { result };
|
||||
};
|
||||
|
||||
const getEndpointHeaders = (headers, options) => Object.entries(headers ?? {}).reduce((acc, [headerKey, headerVal]) => {
|
||||
acc[headerKey] = headerVal.map((headerValEntry) => {
|
||||
const processedExpr = evaluateExpression(headerValEntry, "Header value entry", options);
|
||||
if (typeof processedExpr !== "string") {
|
||||
throw new EndpointError(`Header '${headerKey}' value '${processedExpr}' is not a string`);
|
||||
}
|
||||
return processedExpr;
|
||||
});
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const getEndpointProperties = (properties, options) => Object.entries(properties).reduce((acc, [propertyKey, propertyVal]) => {
|
||||
acc[propertyKey] = group$1.getEndpointProperty(propertyVal, options);
|
||||
return acc;
|
||||
}, {});
|
||||
const getEndpointProperty = (property, options) => {
|
||||
if (Array.isArray(property)) {
|
||||
return property.map((propertyEntry) => getEndpointProperty(propertyEntry, options));
|
||||
}
|
||||
switch (typeof property) {
|
||||
case "string":
|
||||
return evaluateTemplate(property, options);
|
||||
case "object":
|
||||
if (property === null) {
|
||||
throw new EndpointError(`Unexpected endpoint property: ${property}`);
|
||||
}
|
||||
return group$1.getEndpointProperties(property, options);
|
||||
case "boolean":
|
||||
return property;
|
||||
default:
|
||||
throw new EndpointError(`Unexpected endpoint property type: ${typeof property}`);
|
||||
}
|
||||
};
|
||||
const group$1 = {
|
||||
getEndpointProperty,
|
||||
getEndpointProperties,
|
||||
};
|
||||
|
||||
const getEndpointUrl = (endpointUrl, options) => {
|
||||
const expression = evaluateExpression(endpointUrl, "Endpoint URL", options);
|
||||
if (typeof expression === "string") {
|
||||
try {
|
||||
return new URL(expression);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Failed to construct URL with ${expression}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
throw new EndpointError(`Endpoint URL must be a string, got ${typeof expression}`);
|
||||
};
|
||||
|
||||
const RESULT = 100_000_000;
|
||||
const decideEndpoint = (bdd, options) => {
|
||||
const { nodes, root, results, conditions } = bdd;
|
||||
let ref = root;
|
||||
const referenceRecord = {};
|
||||
const closure = {
|
||||
referenceRecord,
|
||||
endpointParams: options.endpointParams,
|
||||
logger: options.logger,
|
||||
};
|
||||
while (ref !== 1 && ref !== -1 && ref < RESULT) {
|
||||
const node_i = 3 * (Math.abs(ref) - 1);
|
||||
const [condition_i, highRef, lowRef] = [nodes[node_i], nodes[node_i + 1], nodes[node_i + 2]];
|
||||
const [fn, argv, assign] = conditions[condition_i];
|
||||
const evaluation = evaluateCondition({ fn, assign, argv }, closure);
|
||||
if (evaluation.toAssign) {
|
||||
const { name, value } = evaluation.toAssign;
|
||||
referenceRecord[name] = value;
|
||||
}
|
||||
ref = ref >= 0 === evaluation.result ? highRef : lowRef;
|
||||
}
|
||||
if (ref >= RESULT) {
|
||||
const result = results[ref - RESULT];
|
||||
if (result[0] === -1) {
|
||||
const [, errorExpression] = result;
|
||||
throw new EndpointError(evaluateExpression(errorExpression, "Error", closure));
|
||||
}
|
||||
const [url, properties, headers] = result;
|
||||
return {
|
||||
url: getEndpointUrl(url, closure),
|
||||
properties: getEndpointProperties(properties, closure),
|
||||
headers: getEndpointHeaders(headers ?? {}, closure),
|
||||
};
|
||||
}
|
||||
throw new EndpointError(`No matching endpoint.`);
|
||||
};
|
||||
|
||||
const evaluateConditions = (conditions = [], options) => {
|
||||
const conditionsReferenceRecord = {};
|
||||
const conditionOptions = {
|
||||
...options,
|
||||
referenceRecord: { ...options.referenceRecord },
|
||||
};
|
||||
let didAssign = false;
|
||||
for (const condition of conditions) {
|
||||
const { result, toAssign } = evaluateCondition(condition, conditionOptions);
|
||||
if (!result) {
|
||||
return { result };
|
||||
}
|
||||
if (toAssign) {
|
||||
didAssign = true;
|
||||
conditionsReferenceRecord[toAssign.name] = toAssign.value;
|
||||
conditionOptions.referenceRecord[toAssign.name] = toAssign.value;
|
||||
options.logger?.debug?.(`${debugId} assign: ${toAssign.name} := ${toDebugString(toAssign.value)}`);
|
||||
}
|
||||
}
|
||||
if (didAssign) {
|
||||
return { result: true, referenceRecord: conditionsReferenceRecord };
|
||||
}
|
||||
return { result: true };
|
||||
};
|
||||
|
||||
const evaluateEndpointRule = (endpointRule, options) => {
|
||||
const { conditions, endpoint } = endpointRule;
|
||||
const { result, referenceRecord } = evaluateConditions(conditions, options);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const endpointRuleOptions = referenceRecord
|
||||
? {
|
||||
...options,
|
||||
referenceRecord: { ...options.referenceRecord, ...referenceRecord },
|
||||
}
|
||||
: options;
|
||||
const { url, properties, headers } = endpoint;
|
||||
options.logger?.debug?.(`${debugId} Resolving endpoint from template: ${toDebugString(endpoint)}`);
|
||||
const endpointToReturn = { url: getEndpointUrl(url, endpointRuleOptions) };
|
||||
if (headers != null) {
|
||||
endpointToReturn.headers = getEndpointHeaders(headers, endpointRuleOptions);
|
||||
}
|
||||
if (properties != null) {
|
||||
endpointToReturn.properties = getEndpointProperties(properties, endpointRuleOptions);
|
||||
}
|
||||
return endpointToReturn;
|
||||
};
|
||||
|
||||
const evaluateErrorRule = (errorRule, options) => {
|
||||
const { conditions, error } = errorRule;
|
||||
const { result, referenceRecord } = evaluateConditions(conditions, options);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const errorRuleOptions = referenceRecord
|
||||
? {
|
||||
...options,
|
||||
referenceRecord: { ...options.referenceRecord, ...referenceRecord },
|
||||
}
|
||||
: options;
|
||||
throw new EndpointError(evaluateExpression(error, "Error", errorRuleOptions));
|
||||
};
|
||||
|
||||
const evaluateRules = (rules, options) => {
|
||||
for (const rule of rules) {
|
||||
if (rule.type === "endpoint") {
|
||||
const endpointOrUndefined = evaluateEndpointRule(rule, options);
|
||||
if (endpointOrUndefined) {
|
||||
return endpointOrUndefined;
|
||||
}
|
||||
}
|
||||
else if (rule.type === "error") {
|
||||
evaluateErrorRule(rule, options);
|
||||
}
|
||||
else if (rule.type === "tree") {
|
||||
const endpointOrUndefined = group.evaluateTreeRule(rule, options);
|
||||
if (endpointOrUndefined) {
|
||||
return endpointOrUndefined;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new EndpointError(`Unknown endpoint rule: ${rule}`);
|
||||
}
|
||||
}
|
||||
throw new EndpointError(`Rules evaluation failed`);
|
||||
};
|
||||
const evaluateTreeRule = (treeRule, options) => {
|
||||
const { conditions, rules } = treeRule;
|
||||
const { result, referenceRecord } = evaluateConditions(conditions, options);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const treeRuleOptions = referenceRecord
|
||||
? { ...options, referenceRecord: { ...options.referenceRecord, ...referenceRecord } }
|
||||
: options;
|
||||
return group.evaluateRules(rules, treeRuleOptions);
|
||||
};
|
||||
const group = {
|
||||
evaluateRules,
|
||||
evaluateTreeRule,
|
||||
};
|
||||
|
||||
const resolveEndpoint = (ruleSetObject, options) => {
|
||||
const { endpointParams, logger } = options;
|
||||
const { parameters, rules } = ruleSetObject;
|
||||
options.logger?.debug?.(`${debugId} Initial EndpointParams: ${toDebugString(endpointParams)}`);
|
||||
for (const paramKey in parameters) {
|
||||
const parameter = parameters[paramKey];
|
||||
const endpointParam = endpointParams[paramKey];
|
||||
if (endpointParam == null && parameter.default != null) {
|
||||
endpointParams[paramKey] = parameter.default;
|
||||
continue;
|
||||
}
|
||||
if (parameter.required && endpointParam == null) {
|
||||
throw new EndpointError(`Missing required parameter: '${paramKey}'`);
|
||||
}
|
||||
}
|
||||
const endpoint = evaluateRules(rules, { endpointParams, logger, referenceRecord: {} });
|
||||
options.logger?.debug?.(`${debugId} Resolved endpoint: ${toDebugString(endpoint)}`);
|
||||
return endpoint;
|
||||
};
|
||||
|
||||
const resolveEndpointRequiredConfig = (input) => {
|
||||
const { endpoint } = input;
|
||||
if (endpoint === undefined) {
|
||||
input.endpoint = async () => {
|
||||
throw new Error("@smithy/middleware-endpoint: (default endpointRuleSet) endpoint is not set - you must configure an endpoint.");
|
||||
};
|
||||
}
|
||||
return input;
|
||||
};
|
||||
|
||||
const getEndpointFromInstructions = bindGetEndpointFromInstructions(getEndpointFromConfig);
|
||||
const resolveEndpointConfig = bindResolveEndpointConfig(getEndpointFromConfig);
|
||||
const endpointMiddleware = bindEndpointMiddleware(getEndpointFromConfig);
|
||||
const getEndpointPlugin = bindGetEndpointPlugin(getEndpointFromConfig);
|
||||
|
||||
exports.isValidHostLabel = transport.isValidHostLabel;
|
||||
exports.middlewareEndpointToEndpointV1 = transport.toEndpointV1;
|
||||
exports.toEndpointV1 = transport.toEndpointV1;
|
||||
exports.BinaryDecisionDiagram = BinaryDecisionDiagram;
|
||||
exports.EndpointCache = EndpointCache;
|
||||
exports.EndpointError = EndpointError;
|
||||
exports.customEndpointFunctions = customEndpointFunctions;
|
||||
exports.decideEndpoint = decideEndpoint;
|
||||
exports.endpointMiddleware = endpointMiddleware;
|
||||
exports.endpointMiddlewareOptions = endpointMiddlewareOptions;
|
||||
exports.getEndpointFromInstructions = getEndpointFromInstructions;
|
||||
exports.getEndpointPlugin = getEndpointPlugin;
|
||||
exports.isIpAddress = isIpAddress;
|
||||
exports.resolveEndpoint = resolveEndpoint;
|
||||
exports.resolveEndpointConfig = resolveEndpointConfig;
|
||||
exports.resolveEndpointRequiredConfig = resolveEndpointRequiredConfig;
|
||||
exports.resolveParams = resolveParams;
|
||||
+866
@@ -0,0 +1,866 @@
|
||||
'use strict';
|
||||
|
||||
var crc32 = require('@aws-crypto/crc32');
|
||||
var serde = require('@smithy/core/serde');
|
||||
|
||||
class Int64 {
|
||||
bytes;
|
||||
constructor(bytes) {
|
||||
this.bytes = bytes;
|
||||
if (bytes.byteLength !== 8) {
|
||||
throw new Error("Int64 buffers must be exactly 8 bytes");
|
||||
}
|
||||
}
|
||||
static fromNumber(number) {
|
||||
if (number > 9_223_372_036_854_775_807 || number < -9223372036854776e3) {
|
||||
throw new Error(`${number} is too large (or, if negative, too small) to represent as an Int64`);
|
||||
}
|
||||
const bytes = new Uint8Array(8);
|
||||
for (let i = 7, remaining = Math.abs(Math.round(number)); i > -1 && remaining > 0; i--, remaining /= 256) {
|
||||
bytes[i] = remaining;
|
||||
}
|
||||
if (number < 0) {
|
||||
negate(bytes);
|
||||
}
|
||||
return new Int64(bytes);
|
||||
}
|
||||
valueOf() {
|
||||
const bytes = this.bytes.slice(0);
|
||||
const negative = bytes[0] & 0b10000000;
|
||||
if (negative) {
|
||||
negate(bytes);
|
||||
}
|
||||
return parseInt(serde.toHex(bytes), 16) * (negative ? -1 : 1);
|
||||
}
|
||||
toString() {
|
||||
return String(this.valueOf());
|
||||
}
|
||||
}
|
||||
function negate(bytes) {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
bytes[i] ^= 0xff;
|
||||
}
|
||||
for (let i = 7; i > -1; i--) {
|
||||
bytes[i]++;
|
||||
if (bytes[i] !== 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderMarshaller {
|
||||
toUtf8;
|
||||
fromUtf8;
|
||||
constructor(toUtf8, fromUtf8) {
|
||||
this.toUtf8 = toUtf8;
|
||||
this.fromUtf8 = fromUtf8;
|
||||
}
|
||||
format(headers) {
|
||||
const chunks = [];
|
||||
for (const headerName of Object.keys(headers)) {
|
||||
const bytes = this.fromUtf8(headerName);
|
||||
chunks.push(Uint8Array.from([bytes.byteLength]), bytes, this.formatHeaderValue(headers[headerName]));
|
||||
}
|
||||
const out = new Uint8Array(chunks.reduce((carry, bytes) => carry + bytes.byteLength, 0));
|
||||
let position = 0;
|
||||
for (const chunk of chunks) {
|
||||
out.set(chunk, position);
|
||||
position += chunk.byteLength;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
formatHeaderValue(header) {
|
||||
switch (header.type) {
|
||||
case "boolean":
|
||||
return Uint8Array.from([header.value ? 0 : 1]);
|
||||
case "byte":
|
||||
return Uint8Array.from([2, header.value]);
|
||||
case "short":
|
||||
const shortView = new DataView(new ArrayBuffer(3));
|
||||
shortView.setUint8(0, 3);
|
||||
shortView.setInt16(1, header.value, false);
|
||||
return new Uint8Array(shortView.buffer);
|
||||
case "integer":
|
||||
const intView = new DataView(new ArrayBuffer(5));
|
||||
intView.setUint8(0, 4);
|
||||
intView.setInt32(1, header.value, false);
|
||||
return new Uint8Array(intView.buffer);
|
||||
case "long":
|
||||
const longBytes = new Uint8Array(9);
|
||||
longBytes[0] = 5;
|
||||
longBytes.set(header.value.bytes, 1);
|
||||
return longBytes;
|
||||
case "binary":
|
||||
const binView = new DataView(new ArrayBuffer(3 + header.value.byteLength));
|
||||
binView.setUint8(0, 6);
|
||||
binView.setUint16(1, header.value.byteLength, false);
|
||||
const binBytes = new Uint8Array(binView.buffer);
|
||||
binBytes.set(header.value, 3);
|
||||
return binBytes;
|
||||
case "string":
|
||||
const utf8Bytes = this.fromUtf8(header.value);
|
||||
const strView = new DataView(new ArrayBuffer(3 + utf8Bytes.byteLength));
|
||||
strView.setUint8(0, 7);
|
||||
strView.setUint16(1, utf8Bytes.byteLength, false);
|
||||
const strBytes = new Uint8Array(strView.buffer);
|
||||
strBytes.set(utf8Bytes, 3);
|
||||
return strBytes;
|
||||
case "timestamp":
|
||||
const tsBytes = new Uint8Array(9);
|
||||
tsBytes[0] = 8;
|
||||
tsBytes.set(Int64.fromNumber(header.value.valueOf()).bytes, 1);
|
||||
return tsBytes;
|
||||
case "uuid":
|
||||
if (!UUID_PATTERN.test(header.value)) {
|
||||
throw new Error(`Invalid UUID received: ${header.value}`);
|
||||
}
|
||||
const uuidBytes = new Uint8Array(17);
|
||||
uuidBytes[0] = 9;
|
||||
uuidBytes.set(serde.fromHex(header.value.replace(/\-/g, "")), 1);
|
||||
return uuidBytes;
|
||||
}
|
||||
}
|
||||
parse(headers) {
|
||||
const out = {};
|
||||
let position = 0;
|
||||
while (position < headers.byteLength) {
|
||||
const nameLength = headers.getUint8(position++);
|
||||
const name = this.toUtf8(new Uint8Array(headers.buffer, headers.byteOffset + position, nameLength));
|
||||
position += nameLength;
|
||||
switch (headers.getUint8(position++)) {
|
||||
case 0:
|
||||
out[name] = {
|
||||
type: BOOLEAN_TAG,
|
||||
value: true,
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
out[name] = {
|
||||
type: BOOLEAN_TAG,
|
||||
value: false,
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
out[name] = {
|
||||
type: BYTE_TAG,
|
||||
value: headers.getInt8(position++),
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
out[name] = {
|
||||
type: SHORT_TAG,
|
||||
value: headers.getInt16(position, false),
|
||||
};
|
||||
position += 2;
|
||||
break;
|
||||
case 4:
|
||||
out[name] = {
|
||||
type: INT_TAG,
|
||||
value: headers.getInt32(position, false),
|
||||
};
|
||||
position += 4;
|
||||
break;
|
||||
case 5:
|
||||
out[name] = {
|
||||
type: LONG_TAG,
|
||||
value: new Int64(new Uint8Array(headers.buffer, headers.byteOffset + position, 8)),
|
||||
};
|
||||
position += 8;
|
||||
break;
|
||||
case 6:
|
||||
const binaryLength = headers.getUint16(position, false);
|
||||
position += 2;
|
||||
out[name] = {
|
||||
type: BINARY_TAG,
|
||||
value: new Uint8Array(headers.buffer, headers.byteOffset + position, binaryLength),
|
||||
};
|
||||
position += binaryLength;
|
||||
break;
|
||||
case 7:
|
||||
const stringLength = headers.getUint16(position, false);
|
||||
position += 2;
|
||||
out[name] = {
|
||||
type: STRING_TAG,
|
||||
value: this.toUtf8(new Uint8Array(headers.buffer, headers.byteOffset + position, stringLength)),
|
||||
};
|
||||
position += stringLength;
|
||||
break;
|
||||
case 8:
|
||||
out[name] = {
|
||||
type: TIMESTAMP_TAG,
|
||||
value: new Date(new Int64(new Uint8Array(headers.buffer, headers.byteOffset + position, 8)).valueOf()),
|
||||
};
|
||||
position += 8;
|
||||
break;
|
||||
case 9:
|
||||
const uuidBytes = new Uint8Array(headers.buffer, headers.byteOffset + position, 16);
|
||||
position += 16;
|
||||
out[name] = {
|
||||
type: UUID_TAG,
|
||||
value: `${serde.toHex(uuidBytes.subarray(0, 4))}-${serde.toHex(uuidBytes.subarray(4, 6))}-${serde.toHex(uuidBytes.subarray(6, 8))}-${serde.toHex(uuidBytes.subarray(8, 10))}-${serde.toHex(uuidBytes.subarray(10))}`,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unrecognized header type tag`);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
var HEADER_VALUE_TYPE;
|
||||
(function (HEADER_VALUE_TYPE) {
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["boolTrue"] = 0] = "boolTrue";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["boolFalse"] = 1] = "boolFalse";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["byte"] = 2] = "byte";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["short"] = 3] = "short";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["integer"] = 4] = "integer";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["long"] = 5] = "long";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["byteArray"] = 6] = "byteArray";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["string"] = 7] = "string";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["timestamp"] = 8] = "timestamp";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["uuid"] = 9] = "uuid";
|
||||
})(HEADER_VALUE_TYPE || (HEADER_VALUE_TYPE = {}));
|
||||
const BOOLEAN_TAG = "boolean";
|
||||
const BYTE_TAG = "byte";
|
||||
const SHORT_TAG = "short";
|
||||
const INT_TAG = "integer";
|
||||
const LONG_TAG = "long";
|
||||
const BINARY_TAG = "binary";
|
||||
const STRING_TAG = "string";
|
||||
const TIMESTAMP_TAG = "timestamp";
|
||||
const UUID_TAG = "uuid";
|
||||
const UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
|
||||
|
||||
const PRELUDE_MEMBER_LENGTH = 4;
|
||||
const PRELUDE_LENGTH = PRELUDE_MEMBER_LENGTH * 2;
|
||||
const CHECKSUM_LENGTH = 4;
|
||||
const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2;
|
||||
function splitMessage({ byteLength, byteOffset, buffer }) {
|
||||
if (byteLength < MINIMUM_MESSAGE_LENGTH) {
|
||||
throw new Error("Provided message too short to accommodate event stream message overhead");
|
||||
}
|
||||
const view = new DataView(buffer, byteOffset, byteLength);
|
||||
const messageLength = view.getUint32(0, false);
|
||||
if (byteLength !== messageLength) {
|
||||
throw new Error("Reported message length does not match received message length");
|
||||
}
|
||||
const headerLength = view.getUint32(PRELUDE_MEMBER_LENGTH, false);
|
||||
const expectedPreludeChecksum = view.getUint32(PRELUDE_LENGTH, false);
|
||||
const expectedMessageChecksum = view.getUint32(byteLength - CHECKSUM_LENGTH, false);
|
||||
const checksummer = new crc32.Crc32().update(new Uint8Array(buffer, byteOffset, PRELUDE_LENGTH));
|
||||
if (expectedPreludeChecksum !== checksummer.digest()) {
|
||||
throw new Error(`The prelude checksum specified in the message (${expectedPreludeChecksum}) does not match the calculated CRC32 checksum (${checksummer.digest()})`);
|
||||
}
|
||||
checksummer.update(new Uint8Array(buffer, byteOffset + PRELUDE_LENGTH, byteLength - (PRELUDE_LENGTH + CHECKSUM_LENGTH)));
|
||||
if (expectedMessageChecksum !== checksummer.digest()) {
|
||||
throw new Error(`The message checksum (${checksummer.digest()}) did not match the expected value of ${expectedMessageChecksum}`);
|
||||
}
|
||||
return {
|
||||
headers: new DataView(buffer, byteOffset + PRELUDE_LENGTH + CHECKSUM_LENGTH, headerLength),
|
||||
body: new Uint8Array(buffer, byteOffset + PRELUDE_LENGTH + CHECKSUM_LENGTH + headerLength, messageLength - headerLength - (PRELUDE_LENGTH + CHECKSUM_LENGTH + CHECKSUM_LENGTH)),
|
||||
};
|
||||
}
|
||||
|
||||
class EventStreamCodec {
|
||||
headerMarshaller;
|
||||
messageBuffer;
|
||||
isEndOfStream;
|
||||
constructor(toUtf8, fromUtf8) {
|
||||
this.headerMarshaller = new HeaderMarshaller(toUtf8, fromUtf8);
|
||||
this.messageBuffer = [];
|
||||
this.isEndOfStream = false;
|
||||
}
|
||||
feed(message) {
|
||||
this.messageBuffer.push(this.decode(message));
|
||||
}
|
||||
endOfStream() {
|
||||
this.isEndOfStream = true;
|
||||
}
|
||||
getMessage() {
|
||||
const message = this.messageBuffer.pop();
|
||||
const isEndOfStream = this.isEndOfStream;
|
||||
return {
|
||||
getMessage() {
|
||||
return message;
|
||||
},
|
||||
isEndOfStream() {
|
||||
return isEndOfStream;
|
||||
},
|
||||
};
|
||||
}
|
||||
getAvailableMessages() {
|
||||
const messages = this.messageBuffer;
|
||||
this.messageBuffer = [];
|
||||
const isEndOfStream = this.isEndOfStream;
|
||||
return {
|
||||
getMessages() {
|
||||
return messages;
|
||||
},
|
||||
isEndOfStream() {
|
||||
return isEndOfStream;
|
||||
},
|
||||
};
|
||||
}
|
||||
encode({ headers: rawHeaders, body }) {
|
||||
const headers = this.headerMarshaller.format(rawHeaders);
|
||||
const length = headers.byteLength + body.byteLength + 16;
|
||||
const out = new Uint8Array(length);
|
||||
const view = new DataView(out.buffer, out.byteOffset, out.byteLength);
|
||||
const checksum = new crc32.Crc32();
|
||||
view.setUint32(0, length, false);
|
||||
view.setUint32(4, headers.byteLength, false);
|
||||
view.setUint32(8, checksum.update(out.subarray(0, 8)).digest(), false);
|
||||
out.set(headers, 12);
|
||||
out.set(body, headers.byteLength + 12);
|
||||
view.setUint32(length - 4, checksum.update(out.subarray(8, length - 4)).digest(), false);
|
||||
return out;
|
||||
}
|
||||
decode(message) {
|
||||
const { headers, body } = splitMessage(message);
|
||||
return { headers: this.headerMarshaller.parse(headers), body };
|
||||
}
|
||||
formatHeaders(rawHeaders) {
|
||||
return this.headerMarshaller.format(rawHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
class MessageDecoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const bytes of this.options.inputStream) {
|
||||
const decoded = this.options.decoder.decode(bytes);
|
||||
yield decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MessageEncoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const msg of this.options.messageStream) {
|
||||
const encoded = this.options.encoder.encode(msg);
|
||||
yield encoded;
|
||||
}
|
||||
if (this.options.includeEndFrame) {
|
||||
yield new Uint8Array(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SmithyMessageDecoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const message of this.options.messageStream) {
|
||||
const deserialized = await this.options.deserializer(message);
|
||||
if (deserialized === undefined)
|
||||
continue;
|
||||
yield deserialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SmithyMessageEncoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const chunk of this.options.inputStream) {
|
||||
const payloadBuf = this.options.serializer(chunk);
|
||||
yield payloadBuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getChunkedStream(source) {
|
||||
let currentMessageTotalLength = 0;
|
||||
let currentMessagePendingLength = 0;
|
||||
let currentMessage = null;
|
||||
let messageLengthBuffer = null;
|
||||
const allocateMessage = (size) => {
|
||||
if (typeof size !== "number") {
|
||||
throw new Error("Attempted to allocate an event message where size was not a number: " + size);
|
||||
}
|
||||
currentMessageTotalLength = size;
|
||||
currentMessagePendingLength = 4;
|
||||
currentMessage = new Uint8Array(size);
|
||||
const currentMessageView = new DataView(currentMessage.buffer);
|
||||
currentMessageView.setUint32(0, size, false);
|
||||
};
|
||||
const iterator = async function* () {
|
||||
const sourceIterator = source[Symbol.asyncIterator]();
|
||||
while (true) {
|
||||
const { value, done } = await sourceIterator.next();
|
||||
if (done) {
|
||||
if (!currentMessageTotalLength) {
|
||||
return;
|
||||
}
|
||||
else if (currentMessageTotalLength === currentMessagePendingLength) {
|
||||
yield currentMessage;
|
||||
}
|
||||
else {
|
||||
throw new Error("Truncated event message received.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
const chunkLength = value.length;
|
||||
let currentOffset = 0;
|
||||
while (currentOffset < chunkLength) {
|
||||
if (!currentMessage) {
|
||||
const bytesRemaining = chunkLength - currentOffset;
|
||||
if (!messageLengthBuffer) {
|
||||
messageLengthBuffer = new Uint8Array(4);
|
||||
}
|
||||
const numBytesForTotal = Math.min(4 - currentMessagePendingLength, bytesRemaining);
|
||||
messageLengthBuffer.set(value.slice(currentOffset, currentOffset + numBytesForTotal), currentMessagePendingLength);
|
||||
currentMessagePendingLength += numBytesForTotal;
|
||||
currentOffset += numBytesForTotal;
|
||||
if (currentMessagePendingLength < 4) {
|
||||
break;
|
||||
}
|
||||
allocateMessage(new DataView(messageLengthBuffer.buffer).getUint32(0, false));
|
||||
messageLengthBuffer = null;
|
||||
}
|
||||
const numBytesToWrite = Math.min(currentMessageTotalLength - currentMessagePendingLength, chunkLength - currentOffset);
|
||||
currentMessage.set(value.slice(currentOffset, currentOffset + numBytesToWrite), currentMessagePendingLength);
|
||||
currentMessagePendingLength += numBytesToWrite;
|
||||
currentOffset += numBytesToWrite;
|
||||
if (currentMessageTotalLength && currentMessageTotalLength === currentMessagePendingLength) {
|
||||
yield currentMessage;
|
||||
currentMessage = null;
|
||||
currentMessageTotalLength = 0;
|
||||
currentMessagePendingLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
[Symbol.asyncIterator]: iterator,
|
||||
};
|
||||
}
|
||||
|
||||
function getUnmarshalledStream(source, options) {
|
||||
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;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
function getMessageUnmarshaller(deserializer, toUtf8) {
|
||||
return async function (message) {
|
||||
const { value: messageType } = message.headers[":message-type"];
|
||||
if (messageType === "error") {
|
||||
const unmodeledError = new Error(message.headers[":error-message"].value || "UnknownError");
|
||||
unmodeledError.name = message.headers[":error-code"].value;
|
||||
throw unmodeledError;
|
||||
}
|
||||
else if (messageType === "exception") {
|
||||
const code = message.headers[":exception-type"].value;
|
||||
const exception = { [code]: message };
|
||||
const deserializedException = await deserializer(exception);
|
||||
if (deserializedException.$unknown) {
|
||||
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]: message,
|
||||
};
|
||||
const deserialized = await deserializer(event);
|
||||
if (deserialized.$unknown)
|
||||
return;
|
||||
return deserialized;
|
||||
}
|
||||
else {
|
||||
throw Error(`Unrecognizable event type: ${message.headers[":event-type"].value}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let EventStreamMarshaller$1 = class EventStreamMarshaller {
|
||||
eventStreamCodec;
|
||||
utfEncoder;
|
||||
constructor({ utf8Encoder, utf8Decoder }) {
|
||||
this.eventStreamCodec = new EventStreamCodec(utf8Encoder, utf8Decoder);
|
||||
this.utfEncoder = utf8Encoder;
|
||||
}
|
||||
deserialize(body, deserializer) {
|
||||
const inputStream = getChunkedStream(body);
|
||||
return new SmithyMessageDecoderStream({
|
||||
messageStream: new MessageDecoderStream({ inputStream, decoder: this.eventStreamCodec }),
|
||||
deserializer: getMessageUnmarshaller(deserializer, this.utfEncoder),
|
||||
});
|
||||
}
|
||||
serialize(inputStream, serializer) {
|
||||
return new MessageEncoderStream({
|
||||
messageStream: new SmithyMessageEncoderStream({ inputStream, serializer }),
|
||||
encoder: this.eventStreamCodec,
|
||||
includeEndFrame: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
const eventStreamSerdeProvider$1 = (options) => new EventStreamMarshaller$1(options);
|
||||
|
||||
const readableStreamToIterable = (readableStream) => ({
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
const reader = readableStream.getReader();
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done)
|
||||
return;
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
},
|
||||
});
|
||||
const iterableToReadableStream = (asyncIterable) => {
|
||||
const iterator = asyncIterable[Symbol.asyncIterator]();
|
||||
return new ReadableStream({
|
||||
async pull(controller) {
|
||||
const { done, value } = await iterator.next();
|
||||
if (done) {
|
||||
return controller.close();
|
||||
}
|
||||
controller.enqueue(value);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
class EventStreamMarshaller {
|
||||
universalMarshaller;
|
||||
constructor({ utf8Encoder, utf8Decoder }) {
|
||||
this.universalMarshaller = new EventStreamMarshaller$1({
|
||||
utf8Decoder,
|
||||
utf8Encoder,
|
||||
});
|
||||
}
|
||||
deserialize(body, deserializer) {
|
||||
const bodyIterable = isReadableStream(body) ? readableStreamToIterable(body) : body;
|
||||
return this.universalMarshaller.deserialize(bodyIterable, deserializer);
|
||||
}
|
||||
serialize(input, serializer) {
|
||||
const serializedIterable = this.universalMarshaller.serialize(input, serializer);
|
||||
return typeof ReadableStream === "function" ? iterableToReadableStream(serializedIterable) : serializedIterable;
|
||||
}
|
||||
}
|
||||
const isReadableStream = (body) => typeof ReadableStream === "function" && body instanceof ReadableStream;
|
||||
const eventStreamSerdeProvider = (options) => new EventStreamMarshaller(options);
|
||||
|
||||
const resolveEventStreamSerdeConfig = (input) => Object.assign(input, {
|
||||
eventStreamMarshaller: input.eventStreamSerdeProvider(input),
|
||||
});
|
||||
|
||||
class EventStreamSerde {
|
||||
marshaller;
|
||||
serializer;
|
||||
deserializer;
|
||||
serdeContext;
|
||||
defaultContentType;
|
||||
constructor({ marshaller, serializer, deserializer, serdeContext, defaultContentType, }) {
|
||||
this.marshaller = marshaller;
|
||||
this.serializer = serializer;
|
||||
this.deserializer = deserializer;
|
||||
this.serdeContext = serdeContext;
|
||||
this.defaultContentType = defaultContentType;
|
||||
}
|
||||
async serializeEventStream({ eventStream, requestSchema, initialRequest, }) {
|
||||
const marshaller = this.marshaller;
|
||||
const eventStreamMember = requestSchema.getEventStreamMember();
|
||||
const unionSchema = requestSchema.getMemberSchema(eventStreamMember);
|
||||
const serializer = this.serializer;
|
||||
const defaultContentType = this.defaultContentType;
|
||||
const initialRequestMarker = Symbol("initialRequestMarker");
|
||||
const eventStreamIterable = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
if (initialRequest) {
|
||||
const headers = {
|
||||
":event-type": { type: "string", value: "initial-request" },
|
||||
":message-type": { type: "string", value: "event" },
|
||||
":content-type": { type: "string", value: defaultContentType },
|
||||
};
|
||||
serializer.write(requestSchema, initialRequest);
|
||||
const body = serializer.flush();
|
||||
yield {
|
||||
[initialRequestMarker]: true,
|
||||
headers,
|
||||
body,
|
||||
};
|
||||
}
|
||||
for await (const page of eventStream) {
|
||||
yield page;
|
||||
}
|
||||
},
|
||||
};
|
||||
return marshaller.serialize(eventStreamIterable, (event) => {
|
||||
if (event[initialRequestMarker]) {
|
||||
return {
|
||||
headers: event.headers,
|
||||
body: event.body,
|
||||
};
|
||||
}
|
||||
let unionMember = "";
|
||||
for (const key in event) {
|
||||
if (key !== "__type") {
|
||||
unionMember = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const { additionalHeaders, body, eventType, explicitPayloadContentType } = this.writeEventBody(unionMember, unionSchema, event);
|
||||
const headers = {
|
||||
":event-type": { type: "string", value: eventType },
|
||||
":message-type": { type: "string", value: "event" },
|
||||
":content-type": { type: "string", value: explicitPayloadContentType ?? defaultContentType },
|
||||
...additionalHeaders,
|
||||
};
|
||||
return {
|
||||
headers,
|
||||
body,
|
||||
};
|
||||
});
|
||||
}
|
||||
async deserializeEventStream({ response, responseSchema, initialResponseContainer, }) {
|
||||
const marshaller = this.marshaller;
|
||||
const eventStreamMember = responseSchema.getEventStreamMember();
|
||||
const unionSchema = responseSchema.getMemberSchema(eventStreamMember);
|
||||
const memberSchemas = unionSchema.getMemberSchemas();
|
||||
const initialResponseMarker = Symbol("initialResponseMarker");
|
||||
const asyncIterable = marshaller.deserialize(response.body, async (event) => {
|
||||
let unionMember = "";
|
||||
for (const key in event) {
|
||||
if (key !== "__type") {
|
||||
unionMember = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const body = event[unionMember].body;
|
||||
if (unionMember === "initial-response") {
|
||||
const dataObject = await this.deserializer.read(responseSchema, body);
|
||||
delete dataObject[eventStreamMember];
|
||||
return {
|
||||
[initialResponseMarker]: true,
|
||||
...dataObject,
|
||||
};
|
||||
}
|
||||
else if (unionMember in memberSchemas) {
|
||||
const eventStreamSchema = memberSchemas[unionMember];
|
||||
if (eventStreamSchema.isStructSchema()) {
|
||||
const out = {};
|
||||
let hasBindings = false;
|
||||
for (const [name, member] of eventStreamSchema.structIterator()) {
|
||||
const { eventHeader, eventPayload } = member.getMergedTraits();
|
||||
hasBindings = hasBindings || Boolean(eventHeader || eventPayload);
|
||||
if (eventPayload) {
|
||||
if (member.isBlobSchema()) {
|
||||
out[name] = body;
|
||||
}
|
||||
else if (member.isStringSchema()) {
|
||||
out[name] = (this.serdeContext?.utf8Encoder ?? serde.toUtf8)(body);
|
||||
}
|
||||
else if (member.isStructSchema()) {
|
||||
out[name] = await this.deserializer.read(member, body);
|
||||
}
|
||||
}
|
||||
else if (eventHeader) {
|
||||
const value = event[unionMember].headers[name]?.value;
|
||||
if (value != null) {
|
||||
if (member.isNumericSchema()) {
|
||||
if (value && typeof value === "object" && "bytes" in value) {
|
||||
out[name] = BigInt(value.toString());
|
||||
}
|
||||
else {
|
||||
out[name] = Number(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasBindings) {
|
||||
return {
|
||||
[unionMember]: out,
|
||||
};
|
||||
}
|
||||
if (body.byteLength === 0) {
|
||||
return {
|
||||
[unionMember]: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
[unionMember]: await this.deserializer.read(eventStreamSchema, body),
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
$unknown: event,
|
||||
};
|
||||
}
|
||||
});
|
||||
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
|
||||
const firstEvent = await asyncIterator.next();
|
||||
if (firstEvent.done) {
|
||||
return asyncIterable;
|
||||
}
|
||||
if (firstEvent.value?.[initialResponseMarker]) {
|
||||
if (!responseSchema) {
|
||||
throw new Error("@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.");
|
||||
}
|
||||
for (const key in firstEvent.value) {
|
||||
initialResponseContainer[key] = firstEvent.value[key];
|
||||
}
|
||||
}
|
||||
return {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
if (!firstEvent?.value?.[initialResponseMarker]) {
|
||||
yield firstEvent.value;
|
||||
}
|
||||
while (true) {
|
||||
const { done, value } = await asyncIterator.next();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
yield value;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
writeEventBody(unionMember, unionSchema, event) {
|
||||
const serializer = this.serializer;
|
||||
let eventType = unionMember;
|
||||
let explicitPayloadMember = null;
|
||||
let explicitPayloadContentType;
|
||||
const isKnownSchema = (() => {
|
||||
const struct = unionSchema.getSchema();
|
||||
return struct[4].includes(unionMember);
|
||||
})();
|
||||
const additionalHeaders = {};
|
||||
if (!isKnownSchema) {
|
||||
const [type, value] = event[unionMember];
|
||||
eventType = type;
|
||||
serializer.write(15, value);
|
||||
}
|
||||
else {
|
||||
const eventSchema = unionSchema.getMemberSchema(unionMember);
|
||||
if (eventSchema.isStructSchema()) {
|
||||
for (const [memberName, memberSchema] of eventSchema.structIterator()) {
|
||||
const { eventHeader, eventPayload } = memberSchema.getMergedTraits();
|
||||
if (eventPayload) {
|
||||
explicitPayloadMember = memberName;
|
||||
}
|
||||
else if (eventHeader) {
|
||||
const value = event[unionMember][memberName];
|
||||
let type = "binary";
|
||||
if (memberSchema.isNumericSchema()) {
|
||||
if ((-2) ** 31 <= value && value <= 2 ** 31 - 1) {
|
||||
type = "integer";
|
||||
}
|
||||
else {
|
||||
type = "long";
|
||||
}
|
||||
}
|
||||
else if (memberSchema.isTimestampSchema()) {
|
||||
type = "timestamp";
|
||||
}
|
||||
else if (memberSchema.isStringSchema()) {
|
||||
type = "string";
|
||||
}
|
||||
else if (memberSchema.isBooleanSchema()) {
|
||||
type = "boolean";
|
||||
}
|
||||
if (value != null) {
|
||||
additionalHeaders[memberName] = {
|
||||
type,
|
||||
value,
|
||||
};
|
||||
delete event[unionMember][memberName];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (explicitPayloadMember !== null) {
|
||||
const payloadSchema = eventSchema.getMemberSchema(explicitPayloadMember);
|
||||
if (payloadSchema.isBlobSchema()) {
|
||||
explicitPayloadContentType = "application/octet-stream";
|
||||
}
|
||||
else if (payloadSchema.isStringSchema()) {
|
||||
explicitPayloadContentType = "text/plain";
|
||||
}
|
||||
serializer.write(payloadSchema, event[unionMember][explicitPayloadMember]);
|
||||
}
|
||||
else {
|
||||
serializer.write(eventSchema, event[unionMember]);
|
||||
}
|
||||
}
|
||||
else if (eventSchema.isUnitSchema()) {
|
||||
serializer.write(eventSchema, {});
|
||||
}
|
||||
else {
|
||||
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
|
||||
}
|
||||
}
|
||||
const messageSerialization = serializer.flush() ?? new Uint8Array();
|
||||
const body = typeof messageSerialization === "string"
|
||||
? (this.serdeContext?.utf8Decoder ?? serde.fromUtf8)(messageSerialization)
|
||||
: messageSerialization;
|
||||
return {
|
||||
body,
|
||||
eventType,
|
||||
explicitPayloadContentType,
|
||||
additionalHeaders,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
exports.EventStreamCodec = EventStreamCodec;
|
||||
exports.EventStreamMarshaller = EventStreamMarshaller;
|
||||
exports.EventStreamSerde = EventStreamSerde;
|
||||
exports.HeaderMarshaller = HeaderMarshaller;
|
||||
exports.Int64 = Int64;
|
||||
exports.MessageDecoderStream = MessageDecoderStream;
|
||||
exports.MessageEncoderStream = MessageEncoderStream;
|
||||
exports.SmithyMessageDecoderStream = SmithyMessageDecoderStream;
|
||||
exports.SmithyMessageEncoderStream = SmithyMessageEncoderStream;
|
||||
exports.UniversalEventStreamMarshaller = EventStreamMarshaller$1;
|
||||
exports.eventStreamSerdeProvider = eventStreamSerdeProvider;
|
||||
exports.getChunkedStream = getChunkedStream;
|
||||
exports.getMessageUnmarshaller = getMessageUnmarshaller;
|
||||
exports.getUnmarshalledStream = getUnmarshalledStream;
|
||||
exports.iterableToReadableStream = iterableToReadableStream;
|
||||
exports.readableStreamToIterable = readableStreamToIterable;
|
||||
exports.resolveEventStreamSerdeConfig = resolveEventStreamSerdeConfig;
|
||||
exports.universalEventStreamSerdeProvider = eventStreamSerdeProvider$1;
|
||||
+891
@@ -0,0 +1,891 @@
|
||||
'use strict';
|
||||
|
||||
var crc32 = require('@aws-crypto/crc32');
|
||||
var serde = require('@smithy/core/serde');
|
||||
var node_stream = require('node:stream');
|
||||
|
||||
class Int64 {
|
||||
bytes;
|
||||
constructor(bytes) {
|
||||
this.bytes = bytes;
|
||||
if (bytes.byteLength !== 8) {
|
||||
throw new Error("Int64 buffers must be exactly 8 bytes");
|
||||
}
|
||||
}
|
||||
static fromNumber(number) {
|
||||
if (number > 9_223_372_036_854_775_807 || number < -9223372036854776e3) {
|
||||
throw new Error(`${number} is too large (or, if negative, too small) to represent as an Int64`);
|
||||
}
|
||||
const bytes = new Uint8Array(8);
|
||||
for (let i = 7, remaining = Math.abs(Math.round(number)); i > -1 && remaining > 0; i--, remaining /= 256) {
|
||||
bytes[i] = remaining;
|
||||
}
|
||||
if (number < 0) {
|
||||
negate(bytes);
|
||||
}
|
||||
return new Int64(bytes);
|
||||
}
|
||||
valueOf() {
|
||||
const bytes = this.bytes.slice(0);
|
||||
const negative = bytes[0] & 0b10000000;
|
||||
if (negative) {
|
||||
negate(bytes);
|
||||
}
|
||||
return parseInt(serde.toHex(bytes), 16) * (negative ? -1 : 1);
|
||||
}
|
||||
toString() {
|
||||
return String(this.valueOf());
|
||||
}
|
||||
}
|
||||
function negate(bytes) {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
bytes[i] ^= 0xff;
|
||||
}
|
||||
for (let i = 7; i > -1; i--) {
|
||||
bytes[i]++;
|
||||
if (bytes[i] !== 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderMarshaller {
|
||||
toUtf8;
|
||||
fromUtf8;
|
||||
constructor(toUtf8, fromUtf8) {
|
||||
this.toUtf8 = toUtf8;
|
||||
this.fromUtf8 = fromUtf8;
|
||||
}
|
||||
format(headers) {
|
||||
const chunks = [];
|
||||
for (const headerName of Object.keys(headers)) {
|
||||
const bytes = this.fromUtf8(headerName);
|
||||
chunks.push(Uint8Array.from([bytes.byteLength]), bytes, this.formatHeaderValue(headers[headerName]));
|
||||
}
|
||||
const out = new Uint8Array(chunks.reduce((carry, bytes) => carry + bytes.byteLength, 0));
|
||||
let position = 0;
|
||||
for (const chunk of chunks) {
|
||||
out.set(chunk, position);
|
||||
position += chunk.byteLength;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
formatHeaderValue(header) {
|
||||
switch (header.type) {
|
||||
case "boolean":
|
||||
return Uint8Array.from([header.value ? 0 : 1]);
|
||||
case "byte":
|
||||
return Uint8Array.from([2, header.value]);
|
||||
case "short":
|
||||
const shortView = new DataView(new ArrayBuffer(3));
|
||||
shortView.setUint8(0, 3);
|
||||
shortView.setInt16(1, header.value, false);
|
||||
return new Uint8Array(shortView.buffer);
|
||||
case "integer":
|
||||
const intView = new DataView(new ArrayBuffer(5));
|
||||
intView.setUint8(0, 4);
|
||||
intView.setInt32(1, header.value, false);
|
||||
return new Uint8Array(intView.buffer);
|
||||
case "long":
|
||||
const longBytes = new Uint8Array(9);
|
||||
longBytes[0] = 5;
|
||||
longBytes.set(header.value.bytes, 1);
|
||||
return longBytes;
|
||||
case "binary":
|
||||
const binView = new DataView(new ArrayBuffer(3 + header.value.byteLength));
|
||||
binView.setUint8(0, 6);
|
||||
binView.setUint16(1, header.value.byteLength, false);
|
||||
const binBytes = new Uint8Array(binView.buffer);
|
||||
binBytes.set(header.value, 3);
|
||||
return binBytes;
|
||||
case "string":
|
||||
const utf8Bytes = this.fromUtf8(header.value);
|
||||
const strView = new DataView(new ArrayBuffer(3 + utf8Bytes.byteLength));
|
||||
strView.setUint8(0, 7);
|
||||
strView.setUint16(1, utf8Bytes.byteLength, false);
|
||||
const strBytes = new Uint8Array(strView.buffer);
|
||||
strBytes.set(utf8Bytes, 3);
|
||||
return strBytes;
|
||||
case "timestamp":
|
||||
const tsBytes = new Uint8Array(9);
|
||||
tsBytes[0] = 8;
|
||||
tsBytes.set(Int64.fromNumber(header.value.valueOf()).bytes, 1);
|
||||
return tsBytes;
|
||||
case "uuid":
|
||||
if (!UUID_PATTERN.test(header.value)) {
|
||||
throw new Error(`Invalid UUID received: ${header.value}`);
|
||||
}
|
||||
const uuidBytes = new Uint8Array(17);
|
||||
uuidBytes[0] = 9;
|
||||
uuidBytes.set(serde.fromHex(header.value.replace(/\-/g, "")), 1);
|
||||
return uuidBytes;
|
||||
}
|
||||
}
|
||||
parse(headers) {
|
||||
const out = {};
|
||||
let position = 0;
|
||||
while (position < headers.byteLength) {
|
||||
const nameLength = headers.getUint8(position++);
|
||||
const name = this.toUtf8(new Uint8Array(headers.buffer, headers.byteOffset + position, nameLength));
|
||||
position += nameLength;
|
||||
switch (headers.getUint8(position++)) {
|
||||
case 0:
|
||||
out[name] = {
|
||||
type: BOOLEAN_TAG,
|
||||
value: true,
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
out[name] = {
|
||||
type: BOOLEAN_TAG,
|
||||
value: false,
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
out[name] = {
|
||||
type: BYTE_TAG,
|
||||
value: headers.getInt8(position++),
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
out[name] = {
|
||||
type: SHORT_TAG,
|
||||
value: headers.getInt16(position, false),
|
||||
};
|
||||
position += 2;
|
||||
break;
|
||||
case 4:
|
||||
out[name] = {
|
||||
type: INT_TAG,
|
||||
value: headers.getInt32(position, false),
|
||||
};
|
||||
position += 4;
|
||||
break;
|
||||
case 5:
|
||||
out[name] = {
|
||||
type: LONG_TAG,
|
||||
value: new Int64(new Uint8Array(headers.buffer, headers.byteOffset + position, 8)),
|
||||
};
|
||||
position += 8;
|
||||
break;
|
||||
case 6:
|
||||
const binaryLength = headers.getUint16(position, false);
|
||||
position += 2;
|
||||
out[name] = {
|
||||
type: BINARY_TAG,
|
||||
value: new Uint8Array(headers.buffer, headers.byteOffset + position, binaryLength),
|
||||
};
|
||||
position += binaryLength;
|
||||
break;
|
||||
case 7:
|
||||
const stringLength = headers.getUint16(position, false);
|
||||
position += 2;
|
||||
out[name] = {
|
||||
type: STRING_TAG,
|
||||
value: this.toUtf8(new Uint8Array(headers.buffer, headers.byteOffset + position, stringLength)),
|
||||
};
|
||||
position += stringLength;
|
||||
break;
|
||||
case 8:
|
||||
out[name] = {
|
||||
type: TIMESTAMP_TAG,
|
||||
value: new Date(new Int64(new Uint8Array(headers.buffer, headers.byteOffset + position, 8)).valueOf()),
|
||||
};
|
||||
position += 8;
|
||||
break;
|
||||
case 9:
|
||||
const uuidBytes = new Uint8Array(headers.buffer, headers.byteOffset + position, 16);
|
||||
position += 16;
|
||||
out[name] = {
|
||||
type: UUID_TAG,
|
||||
value: `${serde.toHex(uuidBytes.subarray(0, 4))}-${serde.toHex(uuidBytes.subarray(4, 6))}-${serde.toHex(uuidBytes.subarray(6, 8))}-${serde.toHex(uuidBytes.subarray(8, 10))}-${serde.toHex(uuidBytes.subarray(10))}`,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unrecognized header type tag`);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
var HEADER_VALUE_TYPE;
|
||||
(function (HEADER_VALUE_TYPE) {
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["boolTrue"] = 0] = "boolTrue";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["boolFalse"] = 1] = "boolFalse";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["byte"] = 2] = "byte";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["short"] = 3] = "short";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["integer"] = 4] = "integer";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["long"] = 5] = "long";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["byteArray"] = 6] = "byteArray";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["string"] = 7] = "string";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["timestamp"] = 8] = "timestamp";
|
||||
HEADER_VALUE_TYPE[HEADER_VALUE_TYPE["uuid"] = 9] = "uuid";
|
||||
})(HEADER_VALUE_TYPE || (HEADER_VALUE_TYPE = {}));
|
||||
const BOOLEAN_TAG = "boolean";
|
||||
const BYTE_TAG = "byte";
|
||||
const SHORT_TAG = "short";
|
||||
const INT_TAG = "integer";
|
||||
const LONG_TAG = "long";
|
||||
const BINARY_TAG = "binary";
|
||||
const STRING_TAG = "string";
|
||||
const TIMESTAMP_TAG = "timestamp";
|
||||
const UUID_TAG = "uuid";
|
||||
const UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
|
||||
|
||||
const PRELUDE_MEMBER_LENGTH = 4;
|
||||
const PRELUDE_LENGTH = PRELUDE_MEMBER_LENGTH * 2;
|
||||
const CHECKSUM_LENGTH = 4;
|
||||
const MINIMUM_MESSAGE_LENGTH = PRELUDE_LENGTH + CHECKSUM_LENGTH * 2;
|
||||
function splitMessage({ byteLength, byteOffset, buffer }) {
|
||||
if (byteLength < MINIMUM_MESSAGE_LENGTH) {
|
||||
throw new Error("Provided message too short to accommodate event stream message overhead");
|
||||
}
|
||||
const view = new DataView(buffer, byteOffset, byteLength);
|
||||
const messageLength = view.getUint32(0, false);
|
||||
if (byteLength !== messageLength) {
|
||||
throw new Error("Reported message length does not match received message length");
|
||||
}
|
||||
const headerLength = view.getUint32(PRELUDE_MEMBER_LENGTH, false);
|
||||
const expectedPreludeChecksum = view.getUint32(PRELUDE_LENGTH, false);
|
||||
const expectedMessageChecksum = view.getUint32(byteLength - CHECKSUM_LENGTH, false);
|
||||
const checksummer = new crc32.Crc32().update(new Uint8Array(buffer, byteOffset, PRELUDE_LENGTH));
|
||||
if (expectedPreludeChecksum !== checksummer.digest()) {
|
||||
throw new Error(`The prelude checksum specified in the message (${expectedPreludeChecksum}) does not match the calculated CRC32 checksum (${checksummer.digest()})`);
|
||||
}
|
||||
checksummer.update(new Uint8Array(buffer, byteOffset + PRELUDE_LENGTH, byteLength - (PRELUDE_LENGTH + CHECKSUM_LENGTH)));
|
||||
if (expectedMessageChecksum !== checksummer.digest()) {
|
||||
throw new Error(`The message checksum (${checksummer.digest()}) did not match the expected value of ${expectedMessageChecksum}`);
|
||||
}
|
||||
return {
|
||||
headers: new DataView(buffer, byteOffset + PRELUDE_LENGTH + CHECKSUM_LENGTH, headerLength),
|
||||
body: new Uint8Array(buffer, byteOffset + PRELUDE_LENGTH + CHECKSUM_LENGTH + headerLength, messageLength - headerLength - (PRELUDE_LENGTH + CHECKSUM_LENGTH + CHECKSUM_LENGTH)),
|
||||
};
|
||||
}
|
||||
|
||||
class EventStreamCodec {
|
||||
headerMarshaller;
|
||||
messageBuffer;
|
||||
isEndOfStream;
|
||||
constructor(toUtf8, fromUtf8) {
|
||||
this.headerMarshaller = new HeaderMarshaller(toUtf8, fromUtf8);
|
||||
this.messageBuffer = [];
|
||||
this.isEndOfStream = false;
|
||||
}
|
||||
feed(message) {
|
||||
this.messageBuffer.push(this.decode(message));
|
||||
}
|
||||
endOfStream() {
|
||||
this.isEndOfStream = true;
|
||||
}
|
||||
getMessage() {
|
||||
const message = this.messageBuffer.pop();
|
||||
const isEndOfStream = this.isEndOfStream;
|
||||
return {
|
||||
getMessage() {
|
||||
return message;
|
||||
},
|
||||
isEndOfStream() {
|
||||
return isEndOfStream;
|
||||
},
|
||||
};
|
||||
}
|
||||
getAvailableMessages() {
|
||||
const messages = this.messageBuffer;
|
||||
this.messageBuffer = [];
|
||||
const isEndOfStream = this.isEndOfStream;
|
||||
return {
|
||||
getMessages() {
|
||||
return messages;
|
||||
},
|
||||
isEndOfStream() {
|
||||
return isEndOfStream;
|
||||
},
|
||||
};
|
||||
}
|
||||
encode({ headers: rawHeaders, body }) {
|
||||
const headers = this.headerMarshaller.format(rawHeaders);
|
||||
const length = headers.byteLength + body.byteLength + 16;
|
||||
const out = new Uint8Array(length);
|
||||
const view = new DataView(out.buffer, out.byteOffset, out.byteLength);
|
||||
const checksum = new crc32.Crc32();
|
||||
view.setUint32(0, length, false);
|
||||
view.setUint32(4, headers.byteLength, false);
|
||||
view.setUint32(8, checksum.update(out.subarray(0, 8)).digest(), false);
|
||||
out.set(headers, 12);
|
||||
out.set(body, headers.byteLength + 12);
|
||||
view.setUint32(length - 4, checksum.update(out.subarray(8, length - 4)).digest(), false);
|
||||
return out;
|
||||
}
|
||||
decode(message) {
|
||||
const { headers, body } = splitMessage(message);
|
||||
return { headers: this.headerMarshaller.parse(headers), body };
|
||||
}
|
||||
formatHeaders(rawHeaders) {
|
||||
return this.headerMarshaller.format(rawHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
class MessageDecoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const bytes of this.options.inputStream) {
|
||||
const decoded = this.options.decoder.decode(bytes);
|
||||
yield decoded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MessageEncoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const msg of this.options.messageStream) {
|
||||
const encoded = this.options.encoder.encode(msg);
|
||||
yield encoded;
|
||||
}
|
||||
if (this.options.includeEndFrame) {
|
||||
yield new Uint8Array(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SmithyMessageDecoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const message of this.options.messageStream) {
|
||||
const deserialized = await this.options.deserializer(message);
|
||||
if (deserialized === undefined)
|
||||
continue;
|
||||
yield deserialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SmithyMessageEncoderStream {
|
||||
options;
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
[Symbol.asyncIterator]() {
|
||||
return this.asyncIterator();
|
||||
}
|
||||
async *asyncIterator() {
|
||||
for await (const chunk of this.options.inputStream) {
|
||||
const payloadBuf = this.options.serializer(chunk);
|
||||
yield payloadBuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getChunkedStream(source) {
|
||||
let currentMessageTotalLength = 0;
|
||||
let currentMessagePendingLength = 0;
|
||||
let currentMessage = null;
|
||||
let messageLengthBuffer = null;
|
||||
const allocateMessage = (size) => {
|
||||
if (typeof size !== "number") {
|
||||
throw new Error("Attempted to allocate an event message where size was not a number: " + size);
|
||||
}
|
||||
currentMessageTotalLength = size;
|
||||
currentMessagePendingLength = 4;
|
||||
currentMessage = new Uint8Array(size);
|
||||
const currentMessageView = new DataView(currentMessage.buffer);
|
||||
currentMessageView.setUint32(0, size, false);
|
||||
};
|
||||
const iterator = async function* () {
|
||||
const sourceIterator = source[Symbol.asyncIterator]();
|
||||
while (true) {
|
||||
const { value, done } = await sourceIterator.next();
|
||||
if (done) {
|
||||
if (!currentMessageTotalLength) {
|
||||
return;
|
||||
}
|
||||
else if (currentMessageTotalLength === currentMessagePendingLength) {
|
||||
yield currentMessage;
|
||||
}
|
||||
else {
|
||||
throw new Error("Truncated event message received.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
const chunkLength = value.length;
|
||||
let currentOffset = 0;
|
||||
while (currentOffset < chunkLength) {
|
||||
if (!currentMessage) {
|
||||
const bytesRemaining = chunkLength - currentOffset;
|
||||
if (!messageLengthBuffer) {
|
||||
messageLengthBuffer = new Uint8Array(4);
|
||||
}
|
||||
const numBytesForTotal = Math.min(4 - currentMessagePendingLength, bytesRemaining);
|
||||
messageLengthBuffer.set(value.slice(currentOffset, currentOffset + numBytesForTotal), currentMessagePendingLength);
|
||||
currentMessagePendingLength += numBytesForTotal;
|
||||
currentOffset += numBytesForTotal;
|
||||
if (currentMessagePendingLength < 4) {
|
||||
break;
|
||||
}
|
||||
allocateMessage(new DataView(messageLengthBuffer.buffer).getUint32(0, false));
|
||||
messageLengthBuffer = null;
|
||||
}
|
||||
const numBytesToWrite = Math.min(currentMessageTotalLength - currentMessagePendingLength, chunkLength - currentOffset);
|
||||
currentMessage.set(value.slice(currentOffset, currentOffset + numBytesToWrite), currentMessagePendingLength);
|
||||
currentMessagePendingLength += numBytesToWrite;
|
||||
currentOffset += numBytesToWrite;
|
||||
if (currentMessageTotalLength && currentMessageTotalLength === currentMessagePendingLength) {
|
||||
yield currentMessage;
|
||||
currentMessage = null;
|
||||
currentMessageTotalLength = 0;
|
||||
currentMessagePendingLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
[Symbol.asyncIterator]: iterator,
|
||||
};
|
||||
}
|
||||
|
||||
function getUnmarshalledStream(source, options) {
|
||||
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;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
function getMessageUnmarshaller(deserializer, toUtf8) {
|
||||
return async function (message) {
|
||||
const { value: messageType } = message.headers[":message-type"];
|
||||
if (messageType === "error") {
|
||||
const unmodeledError = new Error(message.headers[":error-message"].value || "UnknownError");
|
||||
unmodeledError.name = message.headers[":error-code"].value;
|
||||
throw unmodeledError;
|
||||
}
|
||||
else if (messageType === "exception") {
|
||||
const code = message.headers[":exception-type"].value;
|
||||
const exception = { [code]: message };
|
||||
const deserializedException = await deserializer(exception);
|
||||
if (deserializedException.$unknown) {
|
||||
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]: message,
|
||||
};
|
||||
const deserialized = await deserializer(event);
|
||||
if (deserialized.$unknown)
|
||||
return;
|
||||
return deserialized;
|
||||
}
|
||||
else {
|
||||
throw Error(`Unrecognizable event type: ${message.headers[":event-type"].value}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let EventStreamMarshaller$1 = class EventStreamMarshaller {
|
||||
eventStreamCodec;
|
||||
utfEncoder;
|
||||
constructor({ utf8Encoder, utf8Decoder }) {
|
||||
this.eventStreamCodec = new EventStreamCodec(utf8Encoder, utf8Decoder);
|
||||
this.utfEncoder = utf8Encoder;
|
||||
}
|
||||
deserialize(body, deserializer) {
|
||||
const inputStream = getChunkedStream(body);
|
||||
return new SmithyMessageDecoderStream({
|
||||
messageStream: new MessageDecoderStream({ inputStream, decoder: this.eventStreamCodec }),
|
||||
deserializer: getMessageUnmarshaller(deserializer, this.utfEncoder),
|
||||
});
|
||||
}
|
||||
serialize(inputStream, serializer) {
|
||||
return new MessageEncoderStream({
|
||||
messageStream: new SmithyMessageEncoderStream({ inputStream, serializer }),
|
||||
encoder: this.eventStreamCodec,
|
||||
includeEndFrame: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
const eventStreamSerdeProvider$1 = (options) => new EventStreamMarshaller$1(options);
|
||||
|
||||
class EventStreamMarshaller {
|
||||
universalMarshaller;
|
||||
constructor({ utf8Encoder, utf8Decoder }) {
|
||||
this.universalMarshaller = new EventStreamMarshaller$1({
|
||||
utf8Decoder,
|
||||
utf8Encoder,
|
||||
});
|
||||
}
|
||||
deserialize(body, deserializer) {
|
||||
const bodyIterable = typeof body[Symbol.asyncIterator] === "function" ? body : readableToIterable(body);
|
||||
return this.universalMarshaller.deserialize(bodyIterable, deserializer);
|
||||
}
|
||||
serialize(input, serializer) {
|
||||
return node_stream.Readable.from(this.universalMarshaller.serialize(input, serializer));
|
||||
}
|
||||
}
|
||||
const eventStreamSerdeProvider = (options) => new EventStreamMarshaller(options);
|
||||
async function* readableToIterable(readStream) {
|
||||
let streamEnded = false;
|
||||
let generationEnded = false;
|
||||
const records = new Array();
|
||||
readStream.on("error", (err) => {
|
||||
if (!streamEnded) {
|
||||
streamEnded = true;
|
||||
}
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
readStream.on("data", (data) => {
|
||||
records.push(data);
|
||||
});
|
||||
readStream.on("end", () => {
|
||||
streamEnded = true;
|
||||
});
|
||||
while (!generationEnded) {
|
||||
const value = await new Promise((resolve) => setTimeout(() => resolve(records.shift()), 0));
|
||||
if (value) {
|
||||
yield value;
|
||||
}
|
||||
generationEnded = streamEnded && records.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
const readableStreamToIterable = (readableStream) => ({
|
||||
[Symbol.asyncIterator]: async function* () {
|
||||
const reader = readableStream.getReader();
|
||||
try {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done)
|
||||
return;
|
||||
yield value;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.releaseLock();
|
||||
}
|
||||
},
|
||||
});
|
||||
const iterableToReadableStream = (asyncIterable) => {
|
||||
const iterator = asyncIterable[Symbol.asyncIterator]();
|
||||
return new ReadableStream({
|
||||
async pull(controller) {
|
||||
const { done, value } = await iterator.next();
|
||||
if (done) {
|
||||
return controller.close();
|
||||
}
|
||||
controller.enqueue(value);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const resolveEventStreamSerdeConfig = (input) => Object.assign(input, {
|
||||
eventStreamMarshaller: input.eventStreamSerdeProvider(input),
|
||||
});
|
||||
|
||||
class EventStreamSerde {
|
||||
marshaller;
|
||||
serializer;
|
||||
deserializer;
|
||||
serdeContext;
|
||||
defaultContentType;
|
||||
constructor({ marshaller, serializer, deserializer, serdeContext, defaultContentType, }) {
|
||||
this.marshaller = marshaller;
|
||||
this.serializer = serializer;
|
||||
this.deserializer = deserializer;
|
||||
this.serdeContext = serdeContext;
|
||||
this.defaultContentType = defaultContentType;
|
||||
}
|
||||
async serializeEventStream({ eventStream, requestSchema, initialRequest, }) {
|
||||
const marshaller = this.marshaller;
|
||||
const eventStreamMember = requestSchema.getEventStreamMember();
|
||||
const unionSchema = requestSchema.getMemberSchema(eventStreamMember);
|
||||
const serializer = this.serializer;
|
||||
const defaultContentType = this.defaultContentType;
|
||||
const initialRequestMarker = Symbol("initialRequestMarker");
|
||||
const eventStreamIterable = {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
if (initialRequest) {
|
||||
const headers = {
|
||||
":event-type": { type: "string", value: "initial-request" },
|
||||
":message-type": { type: "string", value: "event" },
|
||||
":content-type": { type: "string", value: defaultContentType },
|
||||
};
|
||||
serializer.write(requestSchema, initialRequest);
|
||||
const body = serializer.flush();
|
||||
yield {
|
||||
[initialRequestMarker]: true,
|
||||
headers,
|
||||
body,
|
||||
};
|
||||
}
|
||||
for await (const page of eventStream) {
|
||||
yield page;
|
||||
}
|
||||
},
|
||||
};
|
||||
return marshaller.serialize(eventStreamIterable, (event) => {
|
||||
if (event[initialRequestMarker]) {
|
||||
return {
|
||||
headers: event.headers,
|
||||
body: event.body,
|
||||
};
|
||||
}
|
||||
let unionMember = "";
|
||||
for (const key in event) {
|
||||
if (key !== "__type") {
|
||||
unionMember = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const { additionalHeaders, body, eventType, explicitPayloadContentType } = this.writeEventBody(unionMember, unionSchema, event);
|
||||
const headers = {
|
||||
":event-type": { type: "string", value: eventType },
|
||||
":message-type": { type: "string", value: "event" },
|
||||
":content-type": { type: "string", value: explicitPayloadContentType ?? defaultContentType },
|
||||
...additionalHeaders,
|
||||
};
|
||||
return {
|
||||
headers,
|
||||
body,
|
||||
};
|
||||
});
|
||||
}
|
||||
async deserializeEventStream({ response, responseSchema, initialResponseContainer, }) {
|
||||
const marshaller = this.marshaller;
|
||||
const eventStreamMember = responseSchema.getEventStreamMember();
|
||||
const unionSchema = responseSchema.getMemberSchema(eventStreamMember);
|
||||
const memberSchemas = unionSchema.getMemberSchemas();
|
||||
const initialResponseMarker = Symbol("initialResponseMarker");
|
||||
const asyncIterable = marshaller.deserialize(response.body, async (event) => {
|
||||
let unionMember = "";
|
||||
for (const key in event) {
|
||||
if (key !== "__type") {
|
||||
unionMember = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const body = event[unionMember].body;
|
||||
if (unionMember === "initial-response") {
|
||||
const dataObject = await this.deserializer.read(responseSchema, body);
|
||||
delete dataObject[eventStreamMember];
|
||||
return {
|
||||
[initialResponseMarker]: true,
|
||||
...dataObject,
|
||||
};
|
||||
}
|
||||
else if (unionMember in memberSchemas) {
|
||||
const eventStreamSchema = memberSchemas[unionMember];
|
||||
if (eventStreamSchema.isStructSchema()) {
|
||||
const out = {};
|
||||
let hasBindings = false;
|
||||
for (const [name, member] of eventStreamSchema.structIterator()) {
|
||||
const { eventHeader, eventPayload } = member.getMergedTraits();
|
||||
hasBindings = hasBindings || Boolean(eventHeader || eventPayload);
|
||||
if (eventPayload) {
|
||||
if (member.isBlobSchema()) {
|
||||
out[name] = body;
|
||||
}
|
||||
else if (member.isStringSchema()) {
|
||||
out[name] = (this.serdeContext?.utf8Encoder ?? serde.toUtf8)(body);
|
||||
}
|
||||
else if (member.isStructSchema()) {
|
||||
out[name] = await this.deserializer.read(member, body);
|
||||
}
|
||||
}
|
||||
else if (eventHeader) {
|
||||
const value = event[unionMember].headers[name]?.value;
|
||||
if (value != null) {
|
||||
if (member.isNumericSchema()) {
|
||||
if (value && typeof value === "object" && "bytes" in value) {
|
||||
out[name] = BigInt(value.toString());
|
||||
}
|
||||
else {
|
||||
out[name] = Number(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
out[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasBindings) {
|
||||
return {
|
||||
[unionMember]: out,
|
||||
};
|
||||
}
|
||||
if (body.byteLength === 0) {
|
||||
return {
|
||||
[unionMember]: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
[unionMember]: await this.deserializer.read(eventStreamSchema, body),
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
$unknown: event,
|
||||
};
|
||||
}
|
||||
});
|
||||
const asyncIterator = asyncIterable[Symbol.asyncIterator]();
|
||||
const firstEvent = await asyncIterator.next();
|
||||
if (firstEvent.done) {
|
||||
return asyncIterable;
|
||||
}
|
||||
if (firstEvent.value?.[initialResponseMarker]) {
|
||||
if (!responseSchema) {
|
||||
throw new Error("@smithy::core/protocols - initial-response event encountered in event stream but no response schema given.");
|
||||
}
|
||||
for (const key in firstEvent.value) {
|
||||
initialResponseContainer[key] = firstEvent.value[key];
|
||||
}
|
||||
}
|
||||
return {
|
||||
async *[Symbol.asyncIterator]() {
|
||||
if (!firstEvent?.value?.[initialResponseMarker]) {
|
||||
yield firstEvent.value;
|
||||
}
|
||||
while (true) {
|
||||
const { done, value } = await asyncIterator.next();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
yield value;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
writeEventBody(unionMember, unionSchema, event) {
|
||||
const serializer = this.serializer;
|
||||
let eventType = unionMember;
|
||||
let explicitPayloadMember = null;
|
||||
let explicitPayloadContentType;
|
||||
const isKnownSchema = (() => {
|
||||
const struct = unionSchema.getSchema();
|
||||
return struct[4].includes(unionMember);
|
||||
})();
|
||||
const additionalHeaders = {};
|
||||
if (!isKnownSchema) {
|
||||
const [type, value] = event[unionMember];
|
||||
eventType = type;
|
||||
serializer.write(15, value);
|
||||
}
|
||||
else {
|
||||
const eventSchema = unionSchema.getMemberSchema(unionMember);
|
||||
if (eventSchema.isStructSchema()) {
|
||||
for (const [memberName, memberSchema] of eventSchema.structIterator()) {
|
||||
const { eventHeader, eventPayload } = memberSchema.getMergedTraits();
|
||||
if (eventPayload) {
|
||||
explicitPayloadMember = memberName;
|
||||
}
|
||||
else if (eventHeader) {
|
||||
const value = event[unionMember][memberName];
|
||||
let type = "binary";
|
||||
if (memberSchema.isNumericSchema()) {
|
||||
if ((-2) ** 31 <= value && value <= 2 ** 31 - 1) {
|
||||
type = "integer";
|
||||
}
|
||||
else {
|
||||
type = "long";
|
||||
}
|
||||
}
|
||||
else if (memberSchema.isTimestampSchema()) {
|
||||
type = "timestamp";
|
||||
}
|
||||
else if (memberSchema.isStringSchema()) {
|
||||
type = "string";
|
||||
}
|
||||
else if (memberSchema.isBooleanSchema()) {
|
||||
type = "boolean";
|
||||
}
|
||||
if (value != null) {
|
||||
additionalHeaders[memberName] = {
|
||||
type,
|
||||
value,
|
||||
};
|
||||
delete event[unionMember][memberName];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (explicitPayloadMember !== null) {
|
||||
const payloadSchema = eventSchema.getMemberSchema(explicitPayloadMember);
|
||||
if (payloadSchema.isBlobSchema()) {
|
||||
explicitPayloadContentType = "application/octet-stream";
|
||||
}
|
||||
else if (payloadSchema.isStringSchema()) {
|
||||
explicitPayloadContentType = "text/plain";
|
||||
}
|
||||
serializer.write(payloadSchema, event[unionMember][explicitPayloadMember]);
|
||||
}
|
||||
else {
|
||||
serializer.write(eventSchema, event[unionMember]);
|
||||
}
|
||||
}
|
||||
else if (eventSchema.isUnitSchema()) {
|
||||
serializer.write(eventSchema, {});
|
||||
}
|
||||
else {
|
||||
throw new Error("@smithy/core/event-streams - non-struct member not supported in event stream union.");
|
||||
}
|
||||
}
|
||||
const messageSerialization = serializer.flush() ?? new Uint8Array();
|
||||
const body = typeof messageSerialization === "string"
|
||||
? (this.serdeContext?.utf8Decoder ?? serde.fromUtf8)(messageSerialization)
|
||||
: messageSerialization;
|
||||
return {
|
||||
body,
|
||||
eventType,
|
||||
explicitPayloadContentType,
|
||||
additionalHeaders,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
exports.EventStreamCodec = EventStreamCodec;
|
||||
exports.EventStreamMarshaller = EventStreamMarshaller;
|
||||
exports.EventStreamSerde = EventStreamSerde;
|
||||
exports.HeaderMarshaller = HeaderMarshaller;
|
||||
exports.Int64 = Int64;
|
||||
exports.MessageDecoderStream = MessageDecoderStream;
|
||||
exports.MessageEncoderStream = MessageEncoderStream;
|
||||
exports.SmithyMessageDecoderStream = SmithyMessageDecoderStream;
|
||||
exports.SmithyMessageEncoderStream = SmithyMessageEncoderStream;
|
||||
exports.UniversalEventStreamMarshaller = EventStreamMarshaller$1;
|
||||
exports.eventStreamSerdeProvider = eventStreamSerdeProvider;
|
||||
exports.getChunkedStream = getChunkedStream;
|
||||
exports.getMessageUnmarshaller = getMessageUnmarshaller;
|
||||
exports.getUnmarshalledStream = getUnmarshalledStream;
|
||||
exports.iterableToReadableStream = iterableToReadableStream;
|
||||
exports.readableStreamToIterable = readableStreamToIterable;
|
||||
exports.resolveEventStreamSerdeConfig = resolveEventStreamSerdeConfig;
|
||||
exports.universalEventStreamSerdeProvider = eventStreamSerdeProvider$1;
|
||||
+1029
File diff suppressed because it is too large
Load Diff
+817
@@ -0,0 +1,817 @@
|
||||
'use strict';
|
||||
|
||||
var client = require('@smithy/core/client');
|
||||
var protocols = require('@smithy/core/protocols');
|
||||
var serde = require('@smithy/core/serde');
|
||||
|
||||
const isStreamingPayload = (request) => request?.body instanceof ReadableStream;
|
||||
|
||||
const CLOCK_SKEW_ERROR_CODES = [
|
||||
"AuthFailure",
|
||||
"InvalidSignatureException",
|
||||
"RequestExpired",
|
||||
"RequestInTheFuture",
|
||||
"RequestTimeTooSkewed",
|
||||
"SignatureDoesNotMatch",
|
||||
];
|
||||
const THROTTLING_ERROR_CODES = [
|
||||
"BandwidthLimitExceeded",
|
||||
"EC2ThrottledException",
|
||||
"LimitExceededException",
|
||||
"PriorRequestNotComplete",
|
||||
"ProvisionedThroughputExceededException",
|
||||
"RequestLimitExceeded",
|
||||
"RequestThrottled",
|
||||
"RequestThrottledException",
|
||||
"SlowDown",
|
||||
"ThrottledException",
|
||||
"Throttling",
|
||||
"ThrottlingException",
|
||||
"TooManyRequestsException",
|
||||
"TransactionInProgressException",
|
||||
];
|
||||
const TRANSIENT_ERROR_CODES = ["TimeoutError", "RequestTimeout", "RequestTimeoutException"];
|
||||
const TRANSIENT_ERROR_STATUS_CODES = [500, 502, 503, 504];
|
||||
const NODEJS_TIMEOUT_ERROR_CODES = ["ECONNRESET", "ECONNREFUSED", "EPIPE", "ETIMEDOUT"];
|
||||
const NODEJS_NETWORK_ERROR_CODES = ["EHOSTUNREACH", "ENETUNREACH", "ENOTFOUND", "EAI_AGAIN"];
|
||||
|
||||
const isRetryableByTrait = (error) => error?.$retryable !== undefined;
|
||||
const isClockSkewError = (error) => CLOCK_SKEW_ERROR_CODES.includes(error.name);
|
||||
const isClockSkewCorrectedError = (error) => error.$metadata?.clockSkewCorrected;
|
||||
const isBrowserNetworkError = (error) => {
|
||||
const errorMessages = new Set([
|
||||
"Failed to fetch",
|
||||
"NetworkError when attempting to fetch resource",
|
||||
"The Internet connection appears to be offline",
|
||||
"Load failed",
|
||||
"Network request failed",
|
||||
]);
|
||||
const isValid = error && error instanceof TypeError;
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
return errorMessages.has(error.message);
|
||||
};
|
||||
const isThrottlingError = (error) => error.$metadata?.httpStatusCode === 429 ||
|
||||
THROTTLING_ERROR_CODES.includes(error.name) ||
|
||||
error.$retryable?.throttling == true;
|
||||
const isTransientError = (error, depth = 0) => isRetryableByTrait(error) ||
|
||||
isClockSkewCorrectedError(error) ||
|
||||
(error.name === "InvalidSignatureException" && error.message?.includes("Signature expired")) ||
|
||||
TRANSIENT_ERROR_CODES.includes(error.name) ||
|
||||
NODEJS_TIMEOUT_ERROR_CODES.includes(error?.code || "") ||
|
||||
NODEJS_NETWORK_ERROR_CODES.includes(error?.code || "") ||
|
||||
TRANSIENT_ERROR_STATUS_CODES.includes(error.$metadata?.httpStatusCode || 0) ||
|
||||
isBrowserNetworkError(error) ||
|
||||
isNodeJsHttp2TransientError(error) ||
|
||||
(error.cause !== undefined && depth <= 10 && isTransientError(error.cause, depth + 1));
|
||||
const isServerError = (error) => {
|
||||
if (error.$metadata?.httpStatusCode !== undefined) {
|
||||
const statusCode = error.$metadata.httpStatusCode;
|
||||
if (500 <= statusCode && statusCode <= 599 && !isTransientError(error)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
function isNodeJsHttp2TransientError(error) {
|
||||
return error.code === "ERR_HTTP2_STREAM_ERROR" && error.message.includes("NGHTTP2_REFUSED_STREAM");
|
||||
}
|
||||
|
||||
const DEFAULT_RETRY_DELAY_BASE = 100;
|
||||
const MAXIMUM_RETRY_DELAY = 20 * 1000;
|
||||
const THROTTLING_RETRY_DELAY_BASE = 500;
|
||||
const INITIAL_RETRY_TOKENS = 500;
|
||||
const RETRY_COST = 5;
|
||||
const TIMEOUT_RETRY_COST = 10;
|
||||
const NO_RETRY_INCREMENT = 1;
|
||||
const INVOCATION_ID_HEADER = "amz-sdk-invocation-id";
|
||||
const REQUEST_HEADER = "amz-sdk-request";
|
||||
|
||||
function parseRetryAfterHeader(response, logger) {
|
||||
if (!protocols.HttpResponse.isInstance(response)) {
|
||||
return;
|
||||
}
|
||||
for (const header of Object.keys(response.headers)) {
|
||||
const h = header.toLowerCase();
|
||||
if (h === "retry-after") {
|
||||
const retryAfter = response.headers[header];
|
||||
let retryAfterSeconds = NaN;
|
||||
if (retryAfter.endsWith("GMT")) {
|
||||
try {
|
||||
const date = serde.parseRfc7231DateTime(retryAfter);
|
||||
retryAfterSeconds = (date.getTime() - Date.now()) / 1000;
|
||||
}
|
||||
catch (e) {
|
||||
logger?.trace?.("Failed to parse retry-after header");
|
||||
logger?.trace?.(e);
|
||||
}
|
||||
}
|
||||
else if (retryAfter.match(/ GMT, ((\d+)|(\d+\.\d+))$/)) {
|
||||
retryAfterSeconds = Number(retryAfter.match(/ GMT, ([\d.]+)$/)?.[1]);
|
||||
}
|
||||
else if (retryAfter.match(/^((\d+)|(\d+\.\d+))$/)) {
|
||||
retryAfterSeconds = Number(retryAfter);
|
||||
}
|
||||
else if (Date.parse(retryAfter) >= Date.now()) {
|
||||
retryAfterSeconds = (Date.parse(retryAfter) - Date.now()) / 1000;
|
||||
}
|
||||
if (isNaN(retryAfterSeconds)) {
|
||||
return;
|
||||
}
|
||||
return new Date(Date.now() + retryAfterSeconds * 1000);
|
||||
}
|
||||
else if (h === "x-amz-retry-after") {
|
||||
const v = response.headers[header];
|
||||
const backoffMilliseconds = Number(v);
|
||||
if (isNaN(backoffMilliseconds)) {
|
||||
logger?.trace?.(`Failed to parse x-amz-retry-after=${v}`);
|
||||
return;
|
||||
}
|
||||
return new Date(Date.now() + backoffMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getRetryAfterHint(response, logger) {
|
||||
return parseRetryAfterHeader(response, logger);
|
||||
}
|
||||
|
||||
const asSdkError = (error) => {
|
||||
if (error instanceof Error)
|
||||
return error;
|
||||
if (error instanceof Object)
|
||||
return Object.assign(new Error(), error);
|
||||
if (typeof error === "string")
|
||||
return new Error(error);
|
||||
return new Error(`AWS SDK error wrapper for ${error}`);
|
||||
};
|
||||
|
||||
function bindRetryMiddleware(isStreamingPayload) {
|
||||
return (options) => (next, context) => async (args) => {
|
||||
let retryStrategy = await options.retryStrategy();
|
||||
const maxAttempts = await options.maxAttempts();
|
||||
if (isRetryStrategyV2(retryStrategy)) {
|
||||
retryStrategy = retryStrategy;
|
||||
let retryToken = await retryStrategy.acquireInitialRetryToken((context["partition_id"] ?? "") + (context.__retryLongPoll ? ":longpoll" : ""));
|
||||
let lastError = new Error();
|
||||
let attempts = 0;
|
||||
let totalRetryDelay = 0;
|
||||
const { request } = args;
|
||||
const isRequest = protocols.HttpRequest.isInstance(request);
|
||||
if (isRequest) {
|
||||
request.headers[INVOCATION_ID_HEADER] = serde.v4();
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
if (isRequest) {
|
||||
request.headers[REQUEST_HEADER] = `attempt=${attempts + 1}; max=${maxAttempts}`;
|
||||
}
|
||||
const { response, output } = await next(args);
|
||||
retryStrategy.recordSuccess(retryToken);
|
||||
output.$metadata.attempts = attempts + 1;
|
||||
output.$metadata.totalRetryDelay = totalRetryDelay;
|
||||
return { response, output };
|
||||
}
|
||||
catch (e) {
|
||||
const retryErrorInfo = getRetryErrorInfo(e, options.logger);
|
||||
lastError = asSdkError(e);
|
||||
if (isRequest && isStreamingPayload(request)) {
|
||||
(context.logger instanceof client.NoOpLogger ? console : context.logger)?.warn("An error was encountered in a non-retryable streaming request.");
|
||||
throw lastError;
|
||||
}
|
||||
try {
|
||||
retryToken = await retryStrategy.refreshRetryTokenForRetry(retryToken, retryErrorInfo);
|
||||
}
|
||||
catch (refreshError) {
|
||||
if (!lastError.$metadata) {
|
||||
lastError.$metadata = {};
|
||||
}
|
||||
lastError.$metadata.attempts = attempts + 1;
|
||||
lastError.$metadata.totalRetryDelay = totalRetryDelay;
|
||||
throw lastError;
|
||||
}
|
||||
attempts = retryToken.getRetryCount();
|
||||
const delay = retryToken.getRetryDelay();
|
||||
totalRetryDelay += (retryToken?.$retryLog?.acquisitionDelay ?? 0) + delay;
|
||||
if (delay > 0) {
|
||||
await cooldown(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
retryStrategy = retryStrategy;
|
||||
if (retryStrategy?.mode) {
|
||||
context.userAgent = [...(context.userAgent || []), ["cfg/retry-mode", retryStrategy.mode]];
|
||||
}
|
||||
return retryStrategy.retry(next, args);
|
||||
}
|
||||
};
|
||||
}
|
||||
const cooldown = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const isRetryStrategyV2 = (retryStrategy) => typeof retryStrategy.acquireInitialRetryToken !== "undefined" &&
|
||||
typeof retryStrategy.refreshRetryTokenForRetry !== "undefined" &&
|
||||
typeof retryStrategy.recordSuccess !== "undefined";
|
||||
const getRetryErrorInfo = (error, logger) => {
|
||||
const errorInfo = {
|
||||
error,
|
||||
errorType: getRetryErrorType(error),
|
||||
};
|
||||
const retryAfterHint = parseRetryAfterHeader(error.$response, logger);
|
||||
if (retryAfterHint) {
|
||||
errorInfo.retryAfterHint = retryAfterHint;
|
||||
}
|
||||
return errorInfo;
|
||||
};
|
||||
const getRetryErrorType = (error) => {
|
||||
if (isThrottlingError(error))
|
||||
return "THROTTLING";
|
||||
if (isTransientError(error))
|
||||
return "TRANSIENT";
|
||||
if (isServerError(error))
|
||||
return "SERVER_ERROR";
|
||||
return "CLIENT_ERROR";
|
||||
};
|
||||
const retryMiddlewareOptions = {
|
||||
name: "retryMiddleware",
|
||||
tags: ["RETRY"],
|
||||
step: "finalizeRequest",
|
||||
priority: "high",
|
||||
override: true,
|
||||
};
|
||||
function bindGetRetryPlugin(isStreamingPayload) {
|
||||
const retryMiddleware = bindRetryMiddleware(isStreamingPayload);
|
||||
return (options) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.add(retryMiddleware(options), retryMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
class DefaultRateLimiter {
|
||||
static setTimeoutFn = setTimeout;
|
||||
beta;
|
||||
minCapacity;
|
||||
minFillRate;
|
||||
scaleConstant;
|
||||
smooth;
|
||||
enabled = false;
|
||||
availableTokens = 0;
|
||||
lastMaxRate = 0;
|
||||
measuredTxRate = 0;
|
||||
requestCount = 0;
|
||||
fillRate;
|
||||
lastThrottleTime;
|
||||
lastTimestamp = 0;
|
||||
lastTxRateBucket;
|
||||
maxCapacity;
|
||||
timeWindow = 0;
|
||||
constructor(options) {
|
||||
this.beta = options?.beta ?? 0.7;
|
||||
this.minCapacity = options?.minCapacity ?? 1;
|
||||
this.minFillRate = options?.minFillRate ?? 0.5;
|
||||
this.scaleConstant = options?.scaleConstant ?? 0.4;
|
||||
this.smooth = options?.smooth ?? 0.8;
|
||||
this.lastThrottleTime = this.getCurrentTimeInSeconds();
|
||||
this.lastTxRateBucket = Math.floor(this.getCurrentTimeInSeconds());
|
||||
this.fillRate = this.minFillRate;
|
||||
this.maxCapacity = this.minCapacity;
|
||||
}
|
||||
async getSendToken() {
|
||||
return this.acquireTokenBucket(1);
|
||||
}
|
||||
updateClientSendingRate(response) {
|
||||
let calculatedRate;
|
||||
this.updateMeasuredRate();
|
||||
const retryErrorInfo = response;
|
||||
const isThrottling = retryErrorInfo?.errorType === "THROTTLING" || isThrottlingError(retryErrorInfo?.error ?? response);
|
||||
if (isThrottling) {
|
||||
const rateToUse = !this.enabled ? this.measuredTxRate : Math.min(this.measuredTxRate, this.fillRate);
|
||||
this.lastMaxRate = rateToUse;
|
||||
this.calculateTimeWindow();
|
||||
this.lastThrottleTime = this.getCurrentTimeInSeconds();
|
||||
calculatedRate = this.cubicThrottle(rateToUse);
|
||||
this.enableTokenBucket();
|
||||
}
|
||||
else {
|
||||
this.calculateTimeWindow();
|
||||
calculatedRate = this.cubicSuccess(this.getCurrentTimeInSeconds());
|
||||
}
|
||||
const newRate = Math.min(calculatedRate, 2 * this.measuredTxRate);
|
||||
this.updateTokenBucketRate(newRate);
|
||||
}
|
||||
getCurrentTimeInSeconds() {
|
||||
return Date.now() / 1000;
|
||||
}
|
||||
async acquireTokenBucket(amount) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.refillTokenBucket();
|
||||
while (amount > this.availableTokens) {
|
||||
const delay = ((amount - this.availableTokens) / this.fillRate) * 1000;
|
||||
await new Promise((resolve) => DefaultRateLimiter.setTimeoutFn(resolve, delay));
|
||||
this.refillTokenBucket();
|
||||
}
|
||||
this.availableTokens = this.availableTokens - amount;
|
||||
}
|
||||
refillTokenBucket() {
|
||||
const timestamp = this.getCurrentTimeInSeconds();
|
||||
if (!this.lastTimestamp) {
|
||||
this.lastTimestamp = timestamp;
|
||||
return;
|
||||
}
|
||||
const fillAmount = (timestamp - this.lastTimestamp) * this.fillRate;
|
||||
this.availableTokens = Math.min(this.maxCapacity, this.availableTokens + fillAmount);
|
||||
this.lastTimestamp = timestamp;
|
||||
}
|
||||
calculateTimeWindow() {
|
||||
this.timeWindow = this.getPrecise(Math.pow((this.lastMaxRate * (1 - this.beta)) / this.scaleConstant, 1 / 3));
|
||||
}
|
||||
cubicThrottle(rateToUse) {
|
||||
return this.getPrecise(rateToUse * this.beta);
|
||||
}
|
||||
cubicSuccess(timestamp) {
|
||||
return this.getPrecise(this.scaleConstant * Math.pow(timestamp - this.lastThrottleTime - this.timeWindow, 3) + this.lastMaxRate);
|
||||
}
|
||||
enableTokenBucket() {
|
||||
this.enabled = true;
|
||||
}
|
||||
updateTokenBucketRate(newRate) {
|
||||
this.refillTokenBucket();
|
||||
this.fillRate = Math.max(newRate, this.minFillRate);
|
||||
this.maxCapacity = Math.max(newRate, this.minCapacity);
|
||||
this.availableTokens = Math.min(this.availableTokens, this.maxCapacity);
|
||||
}
|
||||
updateMeasuredRate() {
|
||||
const t = this.getCurrentTimeInSeconds();
|
||||
const timeBucket = Math.floor(t * 2) / 2;
|
||||
this.requestCount++;
|
||||
if (timeBucket > this.lastTxRateBucket) {
|
||||
const currentRate = this.requestCount / (timeBucket - this.lastTxRateBucket);
|
||||
this.measuredTxRate = this.getPrecise(currentRate * this.smooth + this.measuredTxRate * (1 - this.smooth));
|
||||
this.requestCount = 0;
|
||||
this.lastTxRateBucket = timeBucket;
|
||||
}
|
||||
}
|
||||
getPrecise(num) {
|
||||
return parseFloat(num.toFixed(8));
|
||||
}
|
||||
}
|
||||
|
||||
class Retry {
|
||||
static v2026 = typeof process !== "undefined" && process.env?.SMITHY_NEW_RETRIES_2026 === "true";
|
||||
static delay() {
|
||||
return Retry.v2026 ? 50 : 100;
|
||||
}
|
||||
static throttlingDelay() {
|
||||
return Retry.v2026 ? 1_000 : 500;
|
||||
}
|
||||
static cost() {
|
||||
return Retry.v2026 ? 14 : 5;
|
||||
}
|
||||
static throttlingCost() {
|
||||
return Retry.v2026 ? 5 : 10;
|
||||
}
|
||||
static modifiedCostType() {
|
||||
return Retry.v2026 ? "THROTTLING" : "TRANSIENT";
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultRetryBackoffStrategy {
|
||||
x = Retry.delay();
|
||||
computeNextBackoffDelay(i) {
|
||||
const b = Math.random();
|
||||
const r = 2;
|
||||
const t_i = b * Math.min(this.x * r ** i, MAXIMUM_RETRY_DELAY);
|
||||
return Math.floor(t_i);
|
||||
}
|
||||
setDelayBase(delay) {
|
||||
this.x = delay;
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultRetryToken {
|
||||
delay;
|
||||
count;
|
||||
cost;
|
||||
longPoll;
|
||||
$retryLog = {
|
||||
acquisitionDelay: 0,
|
||||
};
|
||||
constructor(delay, count, cost, longPoll) {
|
||||
this.delay = delay;
|
||||
this.count = count;
|
||||
this.cost = cost;
|
||||
this.longPoll = longPoll;
|
||||
}
|
||||
getRetryCount() {
|
||||
return this.count;
|
||||
}
|
||||
getRetryDelay() {
|
||||
return Math.min(MAXIMUM_RETRY_DELAY, this.delay);
|
||||
}
|
||||
getRetryCost() {
|
||||
return this.cost;
|
||||
}
|
||||
isLongPoll() {
|
||||
return this.longPoll;
|
||||
}
|
||||
}
|
||||
|
||||
exports.RETRY_MODES = void 0;
|
||||
(function (RETRY_MODES) {
|
||||
RETRY_MODES["STANDARD"] = "standard";
|
||||
RETRY_MODES["ADAPTIVE"] = "adaptive";
|
||||
})(exports.RETRY_MODES || (exports.RETRY_MODES = {}));
|
||||
const DEFAULT_MAX_ATTEMPTS = 3;
|
||||
const DEFAULT_RETRY_MODE = exports.RETRY_MODES.STANDARD;
|
||||
|
||||
const refusal = {
|
||||
incompatible: 1,
|
||||
attempts: 2,
|
||||
capacity: 3,
|
||||
};
|
||||
let StandardRetryStrategy$1 = class StandardRetryStrategy {
|
||||
mode = exports.RETRY_MODES.STANDARD;
|
||||
retryBackoffStrategy;
|
||||
capacity = INITIAL_RETRY_TOKENS;
|
||||
maxAttemptsProvider;
|
||||
baseDelay;
|
||||
constructor(arg1) {
|
||||
if (typeof arg1 === "number") {
|
||||
this.maxAttemptsProvider = async () => arg1;
|
||||
}
|
||||
else if (typeof arg1 === "function") {
|
||||
this.maxAttemptsProvider = arg1;
|
||||
}
|
||||
else if (arg1 && typeof arg1 === "object") {
|
||||
this.maxAttemptsProvider = async () => arg1.maxAttempts;
|
||||
this.baseDelay = arg1.baseDelay;
|
||||
this.retryBackoffStrategy = arg1.backoff;
|
||||
}
|
||||
this.maxAttemptsProvider ??= async () => DEFAULT_MAX_ATTEMPTS;
|
||||
this.baseDelay ??= Retry.delay();
|
||||
this.retryBackoffStrategy ??= new DefaultRetryBackoffStrategy();
|
||||
}
|
||||
async acquireInitialRetryToken(retryTokenScope) {
|
||||
return new DefaultRetryToken(Retry.delay(), 0, undefined, Retry.v2026 && retryTokenScope.includes(":longpoll"));
|
||||
}
|
||||
async refreshRetryTokenForRetry(token, errorInfo) {
|
||||
const maxAttempts = await this.getMaxAttempts();
|
||||
const retryCode = this.retryCode(token, errorInfo, maxAttempts);
|
||||
const shouldRetry = retryCode === 0;
|
||||
const isLongPoll = token.isLongPoll?.();
|
||||
if (shouldRetry || isLongPoll) {
|
||||
const errorType = errorInfo.errorType;
|
||||
this.retryBackoffStrategy.setDelayBase(errorType === "THROTTLING" ? Retry.throttlingDelay() : this.baseDelay);
|
||||
const delayFromErrorType = this.retryBackoffStrategy.computeNextBackoffDelay(token.getRetryCount());
|
||||
let retryDelay = delayFromErrorType;
|
||||
if (errorInfo.retryAfterHint instanceof Date) {
|
||||
retryDelay = Math.max(delayFromErrorType, Math.min(errorInfo.retryAfterHint.getTime() - Date.now(), delayFromErrorType + 5_000));
|
||||
}
|
||||
if (!shouldRetry) {
|
||||
const longPollBackoff = Retry.v2026 && retryCode === refusal.capacity && isLongPoll ? retryDelay : 0;
|
||||
if (longPollBackoff > 0) {
|
||||
await new Promise((r) => setTimeout(r, longPollBackoff));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const capacityCost = this.getCapacityCost(errorType);
|
||||
this.capacity -= capacityCost;
|
||||
const nextToken = new DefaultRetryToken(0, token.getRetryCount() + 1, capacityCost, token.isLongPoll?.() ?? false);
|
||||
await new Promise((r) => setTimeout(r, retryDelay));
|
||||
nextToken.$retryLog.acquisitionDelay = retryDelay;
|
||||
return nextToken;
|
||||
}
|
||||
}
|
||||
throw new Error("No retry token available");
|
||||
}
|
||||
recordSuccess(token) {
|
||||
this.capacity = Math.min(INITIAL_RETRY_TOKENS, this.capacity + (token.getRetryCost() ?? NO_RETRY_INCREMENT));
|
||||
}
|
||||
getCapacity() {
|
||||
return this.capacity;
|
||||
}
|
||||
async maxAttempts() {
|
||||
return this.maxAttemptsProvider();
|
||||
}
|
||||
async getMaxAttempts() {
|
||||
try {
|
||||
return await this.maxAttemptsProvider();
|
||||
}
|
||||
catch (error) {
|
||||
console.warn(`Max attempts provider could not resolve. Using default of ${DEFAULT_MAX_ATTEMPTS}`);
|
||||
return DEFAULT_MAX_ATTEMPTS;
|
||||
}
|
||||
}
|
||||
retryCode(tokenToRenew, errorInfo, maxAttempts) {
|
||||
const attempts = tokenToRenew.getRetryCount() + 1;
|
||||
const retryableStatus = this.isRetryableError(errorInfo.errorType) ? 0 : refusal.incompatible;
|
||||
const attemptStatus = attempts < maxAttempts ? 0 : refusal.attempts;
|
||||
const capacityStatus = this.capacity >= this.getCapacityCost(errorInfo.errorType) ? 0 : refusal.capacity;
|
||||
return retryableStatus || attemptStatus || capacityStatus;
|
||||
}
|
||||
getCapacityCost(errorType) {
|
||||
return errorType === Retry.modifiedCostType() ? Retry.throttlingCost() : Retry.cost();
|
||||
}
|
||||
isRetryableError(errorType) {
|
||||
return errorType === "THROTTLING" || errorType === "TRANSIENT";
|
||||
}
|
||||
};
|
||||
|
||||
let AdaptiveRetryStrategy$1 = class AdaptiveRetryStrategy {
|
||||
mode = exports.RETRY_MODES.ADAPTIVE;
|
||||
rateLimiter;
|
||||
standardRetryStrategy;
|
||||
constructor(maxAttemptsProvider, options) {
|
||||
const { rateLimiter } = options ?? {};
|
||||
this.rateLimiter = rateLimiter ?? new DefaultRateLimiter();
|
||||
this.standardRetryStrategy = options
|
||||
? new StandardRetryStrategy$1({
|
||||
maxAttempts: typeof maxAttemptsProvider === "number" ? maxAttemptsProvider : 3,
|
||||
...options,
|
||||
})
|
||||
: new StandardRetryStrategy$1(maxAttemptsProvider);
|
||||
}
|
||||
async acquireInitialRetryToken(retryTokenScope) {
|
||||
const token = await this.standardRetryStrategy.acquireInitialRetryToken(retryTokenScope);
|
||||
await this.rateLimiter.getSendToken();
|
||||
return token;
|
||||
}
|
||||
async refreshRetryTokenForRetry(tokenToRenew, errorInfo) {
|
||||
this.rateLimiter.updateClientSendingRate(errorInfo);
|
||||
const token = await this.standardRetryStrategy.refreshRetryTokenForRetry(tokenToRenew, errorInfo);
|
||||
await this.rateLimiter.getSendToken();
|
||||
return token;
|
||||
}
|
||||
recordSuccess(token) {
|
||||
this.rateLimiter.updateClientSendingRate({});
|
||||
this.standardRetryStrategy.recordSuccess(token);
|
||||
}
|
||||
async maxAttemptsProvider() {
|
||||
return this.standardRetryStrategy.maxAttempts();
|
||||
}
|
||||
};
|
||||
|
||||
class ConfiguredRetryStrategy extends StandardRetryStrategy$1 {
|
||||
computeNextBackoffDelay;
|
||||
constructor(maxAttempts, computeNextBackoffDelay = Retry.delay()) {
|
||||
super(typeof maxAttempts === "function" ? maxAttempts : async () => maxAttempts);
|
||||
if (typeof computeNextBackoffDelay === "number") {
|
||||
this.computeNextBackoffDelay = () => computeNextBackoffDelay;
|
||||
}
|
||||
else {
|
||||
this.computeNextBackoffDelay = computeNextBackoffDelay;
|
||||
}
|
||||
this.retryBackoffStrategy.computeNextBackoffDelay = (completedAttempt) => {
|
||||
const nextAttempt = completedAttempt + 1;
|
||||
return this.computeNextBackoffDelay(nextAttempt);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const getDefaultRetryQuota = (initialRetryTokens, options) => {
|
||||
const MAX_CAPACITY = initialRetryTokens;
|
||||
const noRetryIncrement = NO_RETRY_INCREMENT;
|
||||
const retryCost = RETRY_COST;
|
||||
const timeoutRetryCost = TIMEOUT_RETRY_COST;
|
||||
let availableCapacity = initialRetryTokens;
|
||||
const getCapacityAmount = (error) => (error.name === "TimeoutError" ? timeoutRetryCost : retryCost);
|
||||
const hasRetryTokens = (error) => getCapacityAmount(error) <= availableCapacity;
|
||||
const retrieveRetryTokens = (error) => {
|
||||
if (!hasRetryTokens(error)) {
|
||||
throw new Error("No retry token available");
|
||||
}
|
||||
const capacityAmount = getCapacityAmount(error);
|
||||
availableCapacity -= capacityAmount;
|
||||
return capacityAmount;
|
||||
};
|
||||
const releaseRetryTokens = (capacityReleaseAmount) => {
|
||||
availableCapacity += capacityReleaseAmount ?? noRetryIncrement;
|
||||
availableCapacity = Math.min(availableCapacity, MAX_CAPACITY);
|
||||
};
|
||||
return Object.freeze({
|
||||
hasRetryTokens,
|
||||
retrieveRetryTokens,
|
||||
releaseRetryTokens,
|
||||
});
|
||||
};
|
||||
|
||||
const defaultDelayDecider = (delayBase, attempts) => Math.floor(Math.min(MAXIMUM_RETRY_DELAY, Math.random() * 2 ** attempts * delayBase));
|
||||
|
||||
const defaultRetryDecider = (error) => {
|
||||
if (!error) {
|
||||
return false;
|
||||
}
|
||||
return isRetryableByTrait(error) || isClockSkewError(error) || isThrottlingError(error) || isTransientError(error);
|
||||
};
|
||||
|
||||
class StandardRetryStrategy {
|
||||
maxAttemptsProvider;
|
||||
retryDecider;
|
||||
delayDecider;
|
||||
retryQuota;
|
||||
mode = exports.RETRY_MODES.STANDARD;
|
||||
constructor(maxAttemptsProvider, options) {
|
||||
this.maxAttemptsProvider = maxAttemptsProvider;
|
||||
this.retryDecider = options?.retryDecider ?? defaultRetryDecider;
|
||||
this.delayDecider = options?.delayDecider ?? defaultDelayDecider;
|
||||
this.retryQuota = options?.retryQuota ?? getDefaultRetryQuota(INITIAL_RETRY_TOKENS);
|
||||
}
|
||||
shouldRetry(error, attempts, maxAttempts) {
|
||||
return attempts < maxAttempts && this.retryDecider(error) && this.retryQuota.hasRetryTokens(error);
|
||||
}
|
||||
async getMaxAttempts() {
|
||||
let maxAttempts;
|
||||
try {
|
||||
maxAttempts = await this.maxAttemptsProvider();
|
||||
}
|
||||
catch (error) {
|
||||
maxAttempts = DEFAULT_MAX_ATTEMPTS;
|
||||
}
|
||||
return maxAttempts;
|
||||
}
|
||||
async retry(next, args, options) {
|
||||
let retryTokenAmount;
|
||||
let attempts = 0;
|
||||
let totalDelay = 0;
|
||||
const maxAttempts = await this.getMaxAttempts();
|
||||
const { request } = args;
|
||||
if (protocols.HttpRequest.isInstance(request)) {
|
||||
request.headers[INVOCATION_ID_HEADER] = serde.v4();
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
if (protocols.HttpRequest.isInstance(request)) {
|
||||
request.headers[REQUEST_HEADER] = `attempt=${attempts + 1}; max=${maxAttempts}`;
|
||||
}
|
||||
if (options?.beforeRequest) {
|
||||
await options.beforeRequest();
|
||||
}
|
||||
const { response, output } = await next(args);
|
||||
if (options?.afterRequest) {
|
||||
options.afterRequest(response);
|
||||
}
|
||||
this.retryQuota.releaseRetryTokens(retryTokenAmount);
|
||||
output.$metadata.attempts = attempts + 1;
|
||||
output.$metadata.totalRetryDelay = totalDelay;
|
||||
return { response, output };
|
||||
}
|
||||
catch (e) {
|
||||
const err = asSdkError(e);
|
||||
attempts++;
|
||||
if (this.shouldRetry(err, attempts, maxAttempts)) {
|
||||
retryTokenAmount = this.retryQuota.retrieveRetryTokens(err);
|
||||
const delayFromDecider = this.delayDecider(isThrottlingError(err) ? THROTTLING_RETRY_DELAY_BASE : DEFAULT_RETRY_DELAY_BASE, attempts);
|
||||
const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
|
||||
const delay = Math.max(delayFromResponse || 0, delayFromDecider);
|
||||
totalDelay += delay;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
continue;
|
||||
}
|
||||
if (!err.$metadata) {
|
||||
err.$metadata = {};
|
||||
}
|
||||
err.$metadata.attempts = attempts;
|
||||
err.$metadata.totalRetryDelay = totalDelay;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const getDelayFromRetryAfterHeader = (response) => {
|
||||
if (!protocols.HttpResponse.isInstance(response))
|
||||
return;
|
||||
const retryAfterHeaderName = Object.keys(response.headers).find((key) => key.toLowerCase() === "retry-after");
|
||||
if (!retryAfterHeaderName)
|
||||
return;
|
||||
const retryAfter = response.headers[retryAfterHeaderName];
|
||||
const retryAfterSeconds = Number(retryAfter);
|
||||
if (!Number.isNaN(retryAfterSeconds))
|
||||
return retryAfterSeconds * 1000;
|
||||
const retryAfterDate = new Date(retryAfter);
|
||||
return retryAfterDate.getTime() - Date.now();
|
||||
};
|
||||
|
||||
class AdaptiveRetryStrategy extends StandardRetryStrategy {
|
||||
rateLimiter;
|
||||
constructor(maxAttemptsProvider, options) {
|
||||
const { rateLimiter, ...superOptions } = options ?? {};
|
||||
super(maxAttemptsProvider, superOptions);
|
||||
this.rateLimiter = rateLimiter ?? new DefaultRateLimiter();
|
||||
this.mode = exports.RETRY_MODES.ADAPTIVE;
|
||||
}
|
||||
async retry(next, args) {
|
||||
return super.retry(next, args, {
|
||||
beforeRequest: async () => {
|
||||
return this.rateLimiter.getSendToken();
|
||||
},
|
||||
afterRequest: (response) => {
|
||||
this.rateLimiter.updateClientSendingRate(response);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const resolveRetryConfig = (input, defaults) => {
|
||||
const { retryStrategy, retryMode } = input;
|
||||
const { defaultMaxAttempts = DEFAULT_MAX_ATTEMPTS, defaultBaseDelay = Retry.delay() } = defaults ?? {};
|
||||
const maxAttemptsProvider = client.normalizeProvider(input.maxAttempts ?? defaultMaxAttempts);
|
||||
let controller = retryStrategy
|
||||
? Promise.resolve(retryStrategy)
|
||||
: undefined;
|
||||
const getDefault = async () => {
|
||||
const maxAttempts = await maxAttemptsProvider();
|
||||
const adaptive = (await client.normalizeProvider(retryMode)()) === exports.RETRY_MODES.ADAPTIVE;
|
||||
if (adaptive) {
|
||||
return new AdaptiveRetryStrategy$1(maxAttemptsProvider, {
|
||||
maxAttempts,
|
||||
baseDelay: defaultBaseDelay,
|
||||
});
|
||||
}
|
||||
return new StandardRetryStrategy$1({
|
||||
maxAttempts,
|
||||
baseDelay: defaultBaseDelay,
|
||||
});
|
||||
};
|
||||
return Object.assign(input, {
|
||||
maxAttempts: maxAttemptsProvider,
|
||||
retryStrategy: () => (controller ??= getDefault()),
|
||||
});
|
||||
};
|
||||
|
||||
const omitRetryHeadersMiddleware = () => (next) => async (args) => {
|
||||
const { request } = args;
|
||||
if (protocols.HttpRequest.isInstance(request)) {
|
||||
delete request.headers[INVOCATION_ID_HEADER];
|
||||
delete request.headers[REQUEST_HEADER];
|
||||
}
|
||||
return next(args);
|
||||
};
|
||||
const omitRetryHeadersMiddlewareOptions = {
|
||||
name: "omitRetryHeadersMiddleware",
|
||||
tags: ["RETRY", "HEADERS", "OMIT_RETRY_HEADERS"],
|
||||
relation: "before",
|
||||
toMiddleware: "awsAuthMiddleware",
|
||||
override: true,
|
||||
};
|
||||
const getOmitRetryHeadersPlugin = (options) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(omitRetryHeadersMiddleware(), omitRetryHeadersMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
|
||||
const no = Symbol.for("node-only");
|
||||
const ENV_MAX_ATTEMPTS = no;
|
||||
const CONFIG_MAX_ATTEMPTS = no;
|
||||
const NODE_MAX_ATTEMPT_CONFIG_OPTIONS = no;
|
||||
const ENV_RETRY_MODE = no;
|
||||
const CONFIG_RETRY_MODE = no;
|
||||
const NODE_RETRY_MODE_CONFIG_OPTIONS = no;
|
||||
const retryMiddleware = bindRetryMiddleware(isStreamingPayload);
|
||||
const getRetryPlugin = bindGetRetryPlugin(isStreamingPayload);
|
||||
|
||||
exports.AdaptiveRetryStrategy = AdaptiveRetryStrategy$1;
|
||||
exports.CONFIG_MAX_ATTEMPTS = CONFIG_MAX_ATTEMPTS;
|
||||
exports.CONFIG_RETRY_MODE = CONFIG_RETRY_MODE;
|
||||
exports.ConfiguredRetryStrategy = ConfiguredRetryStrategy;
|
||||
exports.DEFAULT_MAX_ATTEMPTS = DEFAULT_MAX_ATTEMPTS;
|
||||
exports.DEFAULT_RETRY_DELAY_BASE = DEFAULT_RETRY_DELAY_BASE;
|
||||
exports.DEFAULT_RETRY_MODE = DEFAULT_RETRY_MODE;
|
||||
exports.DefaultRateLimiter = DefaultRateLimiter;
|
||||
exports.DeprecatedAdaptiveRetryStrategy = AdaptiveRetryStrategy;
|
||||
exports.DeprecatedStandardRetryStrategy = StandardRetryStrategy;
|
||||
exports.ENV_MAX_ATTEMPTS = ENV_MAX_ATTEMPTS;
|
||||
exports.ENV_RETRY_MODE = ENV_RETRY_MODE;
|
||||
exports.INITIAL_RETRY_TOKENS = INITIAL_RETRY_TOKENS;
|
||||
exports.INVOCATION_ID_HEADER = INVOCATION_ID_HEADER;
|
||||
exports.MAXIMUM_RETRY_DELAY = MAXIMUM_RETRY_DELAY;
|
||||
exports.NODE_MAX_ATTEMPT_CONFIG_OPTIONS = NODE_MAX_ATTEMPT_CONFIG_OPTIONS;
|
||||
exports.NODE_RETRY_MODE_CONFIG_OPTIONS = NODE_RETRY_MODE_CONFIG_OPTIONS;
|
||||
exports.NO_RETRY_INCREMENT = NO_RETRY_INCREMENT;
|
||||
exports.REQUEST_HEADER = REQUEST_HEADER;
|
||||
exports.RETRY_COST = RETRY_COST;
|
||||
exports.Retry = Retry;
|
||||
exports.StandardRetryStrategy = StandardRetryStrategy$1;
|
||||
exports.THROTTLING_RETRY_DELAY_BASE = THROTTLING_RETRY_DELAY_BASE;
|
||||
exports.TIMEOUT_RETRY_COST = TIMEOUT_RETRY_COST;
|
||||
exports.defaultDelayDecider = defaultDelayDecider;
|
||||
exports.defaultRetryDecider = defaultRetryDecider;
|
||||
exports.getOmitRetryHeadersPlugin = getOmitRetryHeadersPlugin;
|
||||
exports.getRetryAfterHint = getRetryAfterHint;
|
||||
exports.getRetryPlugin = getRetryPlugin;
|
||||
exports.isBrowserNetworkError = isBrowserNetworkError;
|
||||
exports.isClockSkewCorrectedError = isClockSkewCorrectedError;
|
||||
exports.isClockSkewError = isClockSkewError;
|
||||
exports.isNodeJsHttp2TransientError = isNodeJsHttp2TransientError;
|
||||
exports.isRetryableByTrait = isRetryableByTrait;
|
||||
exports.isServerError = isServerError;
|
||||
exports.isThrottlingError = isThrottlingError;
|
||||
exports.isTransientError = isTransientError;
|
||||
exports.omitRetryHeadersMiddleware = omitRetryHeadersMiddleware;
|
||||
exports.omitRetryHeadersMiddlewareOptions = omitRetryHeadersMiddlewareOptions;
|
||||
exports.resolveRetryConfig = resolveRetryConfig;
|
||||
exports.retryMiddleware = retryMiddleware;
|
||||
exports.retryMiddlewareOptions = retryMiddlewareOptions;
|
||||
+844
@@ -0,0 +1,844 @@
|
||||
'use strict';
|
||||
|
||||
var node_stream = require('node:stream');
|
||||
var client = require('@smithy/core/client');
|
||||
var protocols = require('@smithy/core/protocols');
|
||||
var serde = require('@smithy/core/serde');
|
||||
|
||||
const isStreamingPayload = (request) => request?.body instanceof node_stream.Readable ||
|
||||
(typeof ReadableStream !== "undefined" && request?.body instanceof ReadableStream);
|
||||
|
||||
const CLOCK_SKEW_ERROR_CODES = [
|
||||
"AuthFailure",
|
||||
"InvalidSignatureException",
|
||||
"RequestExpired",
|
||||
"RequestInTheFuture",
|
||||
"RequestTimeTooSkewed",
|
||||
"SignatureDoesNotMatch",
|
||||
];
|
||||
const THROTTLING_ERROR_CODES = [
|
||||
"BandwidthLimitExceeded",
|
||||
"EC2ThrottledException",
|
||||
"LimitExceededException",
|
||||
"PriorRequestNotComplete",
|
||||
"ProvisionedThroughputExceededException",
|
||||
"RequestLimitExceeded",
|
||||
"RequestThrottled",
|
||||
"RequestThrottledException",
|
||||
"SlowDown",
|
||||
"ThrottledException",
|
||||
"Throttling",
|
||||
"ThrottlingException",
|
||||
"TooManyRequestsException",
|
||||
"TransactionInProgressException",
|
||||
];
|
||||
const TRANSIENT_ERROR_CODES = ["TimeoutError", "RequestTimeout", "RequestTimeoutException"];
|
||||
const TRANSIENT_ERROR_STATUS_CODES = [500, 502, 503, 504];
|
||||
const NODEJS_TIMEOUT_ERROR_CODES = ["ECONNRESET", "ECONNREFUSED", "EPIPE", "ETIMEDOUT"];
|
||||
const NODEJS_NETWORK_ERROR_CODES = ["EHOSTUNREACH", "ENETUNREACH", "ENOTFOUND", "EAI_AGAIN"];
|
||||
|
||||
const isRetryableByTrait = (error) => error?.$retryable !== undefined;
|
||||
const isClockSkewError = (error) => CLOCK_SKEW_ERROR_CODES.includes(error.name);
|
||||
const isClockSkewCorrectedError = (error) => error.$metadata?.clockSkewCorrected;
|
||||
const isBrowserNetworkError = (error) => {
|
||||
const errorMessages = new Set([
|
||||
"Failed to fetch",
|
||||
"NetworkError when attempting to fetch resource",
|
||||
"The Internet connection appears to be offline",
|
||||
"Load failed",
|
||||
"Network request failed",
|
||||
]);
|
||||
const isValid = error && error instanceof TypeError;
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
return errorMessages.has(error.message);
|
||||
};
|
||||
const isThrottlingError = (error) => error.$metadata?.httpStatusCode === 429 ||
|
||||
THROTTLING_ERROR_CODES.includes(error.name) ||
|
||||
error.$retryable?.throttling == true;
|
||||
const isTransientError = (error, depth = 0) => isRetryableByTrait(error) ||
|
||||
isClockSkewCorrectedError(error) ||
|
||||
(error.name === "InvalidSignatureException" && error.message?.includes("Signature expired")) ||
|
||||
TRANSIENT_ERROR_CODES.includes(error.name) ||
|
||||
NODEJS_TIMEOUT_ERROR_CODES.includes(error?.code || "") ||
|
||||
NODEJS_NETWORK_ERROR_CODES.includes(error?.code || "") ||
|
||||
TRANSIENT_ERROR_STATUS_CODES.includes(error.$metadata?.httpStatusCode || 0) ||
|
||||
isBrowserNetworkError(error) ||
|
||||
isNodeJsHttp2TransientError(error) ||
|
||||
(error.cause !== undefined && depth <= 10 && isTransientError(error.cause, depth + 1));
|
||||
const isServerError = (error) => {
|
||||
if (error.$metadata?.httpStatusCode !== undefined) {
|
||||
const statusCode = error.$metadata.httpStatusCode;
|
||||
if (500 <= statusCode && statusCode <= 599 && !isTransientError(error)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
function isNodeJsHttp2TransientError(error) {
|
||||
return error.code === "ERR_HTTP2_STREAM_ERROR" && error.message.includes("NGHTTP2_REFUSED_STREAM");
|
||||
}
|
||||
|
||||
const DEFAULT_RETRY_DELAY_BASE = 100;
|
||||
const MAXIMUM_RETRY_DELAY = 20 * 1000;
|
||||
const THROTTLING_RETRY_DELAY_BASE = 500;
|
||||
const INITIAL_RETRY_TOKENS = 500;
|
||||
const RETRY_COST = 5;
|
||||
const TIMEOUT_RETRY_COST = 10;
|
||||
const NO_RETRY_INCREMENT = 1;
|
||||
const INVOCATION_ID_HEADER = "amz-sdk-invocation-id";
|
||||
const REQUEST_HEADER = "amz-sdk-request";
|
||||
|
||||
function parseRetryAfterHeader(response, logger) {
|
||||
if (!protocols.HttpResponse.isInstance(response)) {
|
||||
return;
|
||||
}
|
||||
for (const header of Object.keys(response.headers)) {
|
||||
const h = header.toLowerCase();
|
||||
if (h === "retry-after") {
|
||||
const retryAfter = response.headers[header];
|
||||
let retryAfterSeconds = NaN;
|
||||
if (retryAfter.endsWith("GMT")) {
|
||||
try {
|
||||
const date = serde.parseRfc7231DateTime(retryAfter);
|
||||
retryAfterSeconds = (date.getTime() - Date.now()) / 1000;
|
||||
}
|
||||
catch (e) {
|
||||
logger?.trace?.("Failed to parse retry-after header");
|
||||
logger?.trace?.(e);
|
||||
}
|
||||
}
|
||||
else if (retryAfter.match(/ GMT, ((\d+)|(\d+\.\d+))$/)) {
|
||||
retryAfterSeconds = Number(retryAfter.match(/ GMT, ([\d.]+)$/)?.[1]);
|
||||
}
|
||||
else if (retryAfter.match(/^((\d+)|(\d+\.\d+))$/)) {
|
||||
retryAfterSeconds = Number(retryAfter);
|
||||
}
|
||||
else if (Date.parse(retryAfter) >= Date.now()) {
|
||||
retryAfterSeconds = (Date.parse(retryAfter) - Date.now()) / 1000;
|
||||
}
|
||||
if (isNaN(retryAfterSeconds)) {
|
||||
return;
|
||||
}
|
||||
return new Date(Date.now() + retryAfterSeconds * 1000);
|
||||
}
|
||||
else if (h === "x-amz-retry-after") {
|
||||
const v = response.headers[header];
|
||||
const backoffMilliseconds = Number(v);
|
||||
if (isNaN(backoffMilliseconds)) {
|
||||
logger?.trace?.(`Failed to parse x-amz-retry-after=${v}`);
|
||||
return;
|
||||
}
|
||||
return new Date(Date.now() + backoffMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getRetryAfterHint(response, logger) {
|
||||
return parseRetryAfterHeader(response, logger);
|
||||
}
|
||||
|
||||
const asSdkError = (error) => {
|
||||
if (error instanceof Error)
|
||||
return error;
|
||||
if (error instanceof Object)
|
||||
return Object.assign(new Error(), error);
|
||||
if (typeof error === "string")
|
||||
return new Error(error);
|
||||
return new Error(`AWS SDK error wrapper for ${error}`);
|
||||
};
|
||||
|
||||
function bindRetryMiddleware(isStreamingPayload) {
|
||||
return (options) => (next, context) => async (args) => {
|
||||
let retryStrategy = await options.retryStrategy();
|
||||
const maxAttempts = await options.maxAttempts();
|
||||
if (isRetryStrategyV2(retryStrategy)) {
|
||||
retryStrategy = retryStrategy;
|
||||
let retryToken = await retryStrategy.acquireInitialRetryToken((context["partition_id"] ?? "") + (context.__retryLongPoll ? ":longpoll" : ""));
|
||||
let lastError = new Error();
|
||||
let attempts = 0;
|
||||
let totalRetryDelay = 0;
|
||||
const { request } = args;
|
||||
const isRequest = protocols.HttpRequest.isInstance(request);
|
||||
if (isRequest) {
|
||||
request.headers[INVOCATION_ID_HEADER] = serde.v4();
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
if (isRequest) {
|
||||
request.headers[REQUEST_HEADER] = `attempt=${attempts + 1}; max=${maxAttempts}`;
|
||||
}
|
||||
const { response, output } = await next(args);
|
||||
retryStrategy.recordSuccess(retryToken);
|
||||
output.$metadata.attempts = attempts + 1;
|
||||
output.$metadata.totalRetryDelay = totalRetryDelay;
|
||||
return { response, output };
|
||||
}
|
||||
catch (e) {
|
||||
const retryErrorInfo = getRetryErrorInfo(e, options.logger);
|
||||
lastError = asSdkError(e);
|
||||
if (isRequest && isStreamingPayload(request)) {
|
||||
(context.logger instanceof client.NoOpLogger ? console : context.logger)?.warn("An error was encountered in a non-retryable streaming request.");
|
||||
throw lastError;
|
||||
}
|
||||
try {
|
||||
retryToken = await retryStrategy.refreshRetryTokenForRetry(retryToken, retryErrorInfo);
|
||||
}
|
||||
catch (refreshError) {
|
||||
if (!lastError.$metadata) {
|
||||
lastError.$metadata = {};
|
||||
}
|
||||
lastError.$metadata.attempts = attempts + 1;
|
||||
lastError.$metadata.totalRetryDelay = totalRetryDelay;
|
||||
throw lastError;
|
||||
}
|
||||
attempts = retryToken.getRetryCount();
|
||||
const delay = retryToken.getRetryDelay();
|
||||
totalRetryDelay += (retryToken?.$retryLog?.acquisitionDelay ?? 0) + delay;
|
||||
if (delay > 0) {
|
||||
await cooldown(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
retryStrategy = retryStrategy;
|
||||
if (retryStrategy?.mode) {
|
||||
context.userAgent = [...(context.userAgent || []), ["cfg/retry-mode", retryStrategy.mode]];
|
||||
}
|
||||
return retryStrategy.retry(next, args);
|
||||
}
|
||||
};
|
||||
}
|
||||
const cooldown = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const isRetryStrategyV2 = (retryStrategy) => typeof retryStrategy.acquireInitialRetryToken !== "undefined" &&
|
||||
typeof retryStrategy.refreshRetryTokenForRetry !== "undefined" &&
|
||||
typeof retryStrategy.recordSuccess !== "undefined";
|
||||
const getRetryErrorInfo = (error, logger) => {
|
||||
const errorInfo = {
|
||||
error,
|
||||
errorType: getRetryErrorType(error),
|
||||
};
|
||||
const retryAfterHint = parseRetryAfterHeader(error.$response, logger);
|
||||
if (retryAfterHint) {
|
||||
errorInfo.retryAfterHint = retryAfterHint;
|
||||
}
|
||||
return errorInfo;
|
||||
};
|
||||
const getRetryErrorType = (error) => {
|
||||
if (isThrottlingError(error))
|
||||
return "THROTTLING";
|
||||
if (isTransientError(error))
|
||||
return "TRANSIENT";
|
||||
if (isServerError(error))
|
||||
return "SERVER_ERROR";
|
||||
return "CLIENT_ERROR";
|
||||
};
|
||||
const retryMiddlewareOptions = {
|
||||
name: "retryMiddleware",
|
||||
tags: ["RETRY"],
|
||||
step: "finalizeRequest",
|
||||
priority: "high",
|
||||
override: true,
|
||||
};
|
||||
function bindGetRetryPlugin(isStreamingPayload) {
|
||||
const retryMiddleware = bindRetryMiddleware(isStreamingPayload);
|
||||
return (options) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.add(retryMiddleware(options), retryMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
class DefaultRateLimiter {
|
||||
static setTimeoutFn = setTimeout;
|
||||
beta;
|
||||
minCapacity;
|
||||
minFillRate;
|
||||
scaleConstant;
|
||||
smooth;
|
||||
enabled = false;
|
||||
availableTokens = 0;
|
||||
lastMaxRate = 0;
|
||||
measuredTxRate = 0;
|
||||
requestCount = 0;
|
||||
fillRate;
|
||||
lastThrottleTime;
|
||||
lastTimestamp = 0;
|
||||
lastTxRateBucket;
|
||||
maxCapacity;
|
||||
timeWindow = 0;
|
||||
constructor(options) {
|
||||
this.beta = options?.beta ?? 0.7;
|
||||
this.minCapacity = options?.minCapacity ?? 1;
|
||||
this.minFillRate = options?.minFillRate ?? 0.5;
|
||||
this.scaleConstant = options?.scaleConstant ?? 0.4;
|
||||
this.smooth = options?.smooth ?? 0.8;
|
||||
this.lastThrottleTime = this.getCurrentTimeInSeconds();
|
||||
this.lastTxRateBucket = Math.floor(this.getCurrentTimeInSeconds());
|
||||
this.fillRate = this.minFillRate;
|
||||
this.maxCapacity = this.minCapacity;
|
||||
}
|
||||
async getSendToken() {
|
||||
return this.acquireTokenBucket(1);
|
||||
}
|
||||
updateClientSendingRate(response) {
|
||||
let calculatedRate;
|
||||
this.updateMeasuredRate();
|
||||
const retryErrorInfo = response;
|
||||
const isThrottling = retryErrorInfo?.errorType === "THROTTLING" || isThrottlingError(retryErrorInfo?.error ?? response);
|
||||
if (isThrottling) {
|
||||
const rateToUse = !this.enabled ? this.measuredTxRate : Math.min(this.measuredTxRate, this.fillRate);
|
||||
this.lastMaxRate = rateToUse;
|
||||
this.calculateTimeWindow();
|
||||
this.lastThrottleTime = this.getCurrentTimeInSeconds();
|
||||
calculatedRate = this.cubicThrottle(rateToUse);
|
||||
this.enableTokenBucket();
|
||||
}
|
||||
else {
|
||||
this.calculateTimeWindow();
|
||||
calculatedRate = this.cubicSuccess(this.getCurrentTimeInSeconds());
|
||||
}
|
||||
const newRate = Math.min(calculatedRate, 2 * this.measuredTxRate);
|
||||
this.updateTokenBucketRate(newRate);
|
||||
}
|
||||
getCurrentTimeInSeconds() {
|
||||
return Date.now() / 1000;
|
||||
}
|
||||
async acquireTokenBucket(amount) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.refillTokenBucket();
|
||||
while (amount > this.availableTokens) {
|
||||
const delay = ((amount - this.availableTokens) / this.fillRate) * 1000;
|
||||
await new Promise((resolve) => DefaultRateLimiter.setTimeoutFn(resolve, delay));
|
||||
this.refillTokenBucket();
|
||||
}
|
||||
this.availableTokens = this.availableTokens - amount;
|
||||
}
|
||||
refillTokenBucket() {
|
||||
const timestamp = this.getCurrentTimeInSeconds();
|
||||
if (!this.lastTimestamp) {
|
||||
this.lastTimestamp = timestamp;
|
||||
return;
|
||||
}
|
||||
const fillAmount = (timestamp - this.lastTimestamp) * this.fillRate;
|
||||
this.availableTokens = Math.min(this.maxCapacity, this.availableTokens + fillAmount);
|
||||
this.lastTimestamp = timestamp;
|
||||
}
|
||||
calculateTimeWindow() {
|
||||
this.timeWindow = this.getPrecise(Math.pow((this.lastMaxRate * (1 - this.beta)) / this.scaleConstant, 1 / 3));
|
||||
}
|
||||
cubicThrottle(rateToUse) {
|
||||
return this.getPrecise(rateToUse * this.beta);
|
||||
}
|
||||
cubicSuccess(timestamp) {
|
||||
return this.getPrecise(this.scaleConstant * Math.pow(timestamp - this.lastThrottleTime - this.timeWindow, 3) + this.lastMaxRate);
|
||||
}
|
||||
enableTokenBucket() {
|
||||
this.enabled = true;
|
||||
}
|
||||
updateTokenBucketRate(newRate) {
|
||||
this.refillTokenBucket();
|
||||
this.fillRate = Math.max(newRate, this.minFillRate);
|
||||
this.maxCapacity = Math.max(newRate, this.minCapacity);
|
||||
this.availableTokens = Math.min(this.availableTokens, this.maxCapacity);
|
||||
}
|
||||
updateMeasuredRate() {
|
||||
const t = this.getCurrentTimeInSeconds();
|
||||
const timeBucket = Math.floor(t * 2) / 2;
|
||||
this.requestCount++;
|
||||
if (timeBucket > this.lastTxRateBucket) {
|
||||
const currentRate = this.requestCount / (timeBucket - this.lastTxRateBucket);
|
||||
this.measuredTxRate = this.getPrecise(currentRate * this.smooth + this.measuredTxRate * (1 - this.smooth));
|
||||
this.requestCount = 0;
|
||||
this.lastTxRateBucket = timeBucket;
|
||||
}
|
||||
}
|
||||
getPrecise(num) {
|
||||
return parseFloat(num.toFixed(8));
|
||||
}
|
||||
}
|
||||
|
||||
class Retry {
|
||||
static v2026 = typeof process !== "undefined" && process.env?.SMITHY_NEW_RETRIES_2026 === "true";
|
||||
static delay() {
|
||||
return Retry.v2026 ? 50 : 100;
|
||||
}
|
||||
static throttlingDelay() {
|
||||
return Retry.v2026 ? 1_000 : 500;
|
||||
}
|
||||
static cost() {
|
||||
return Retry.v2026 ? 14 : 5;
|
||||
}
|
||||
static throttlingCost() {
|
||||
return Retry.v2026 ? 5 : 10;
|
||||
}
|
||||
static modifiedCostType() {
|
||||
return Retry.v2026 ? "THROTTLING" : "TRANSIENT";
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultRetryBackoffStrategy {
|
||||
x = Retry.delay();
|
||||
computeNextBackoffDelay(i) {
|
||||
const b = Math.random();
|
||||
const r = 2;
|
||||
const t_i = b * Math.min(this.x * r ** i, MAXIMUM_RETRY_DELAY);
|
||||
return Math.floor(t_i);
|
||||
}
|
||||
setDelayBase(delay) {
|
||||
this.x = delay;
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultRetryToken {
|
||||
delay;
|
||||
count;
|
||||
cost;
|
||||
longPoll;
|
||||
$retryLog = {
|
||||
acquisitionDelay: 0,
|
||||
};
|
||||
constructor(delay, count, cost, longPoll) {
|
||||
this.delay = delay;
|
||||
this.count = count;
|
||||
this.cost = cost;
|
||||
this.longPoll = longPoll;
|
||||
}
|
||||
getRetryCount() {
|
||||
return this.count;
|
||||
}
|
||||
getRetryDelay() {
|
||||
return Math.min(MAXIMUM_RETRY_DELAY, this.delay);
|
||||
}
|
||||
getRetryCost() {
|
||||
return this.cost;
|
||||
}
|
||||
isLongPoll() {
|
||||
return this.longPoll;
|
||||
}
|
||||
}
|
||||
|
||||
exports.RETRY_MODES = void 0;
|
||||
(function (RETRY_MODES) {
|
||||
RETRY_MODES["STANDARD"] = "standard";
|
||||
RETRY_MODES["ADAPTIVE"] = "adaptive";
|
||||
})(exports.RETRY_MODES || (exports.RETRY_MODES = {}));
|
||||
const DEFAULT_MAX_ATTEMPTS = 3;
|
||||
const DEFAULT_RETRY_MODE = exports.RETRY_MODES.STANDARD;
|
||||
|
||||
const refusal = {
|
||||
incompatible: 1,
|
||||
attempts: 2,
|
||||
capacity: 3,
|
||||
};
|
||||
let StandardRetryStrategy$1 = class StandardRetryStrategy {
|
||||
mode = exports.RETRY_MODES.STANDARD;
|
||||
retryBackoffStrategy;
|
||||
capacity = INITIAL_RETRY_TOKENS;
|
||||
maxAttemptsProvider;
|
||||
baseDelay;
|
||||
constructor(arg1) {
|
||||
if (typeof arg1 === "number") {
|
||||
this.maxAttemptsProvider = async () => arg1;
|
||||
}
|
||||
else if (typeof arg1 === "function") {
|
||||
this.maxAttemptsProvider = arg1;
|
||||
}
|
||||
else if (arg1 && typeof arg1 === "object") {
|
||||
this.maxAttemptsProvider = async () => arg1.maxAttempts;
|
||||
this.baseDelay = arg1.baseDelay;
|
||||
this.retryBackoffStrategy = arg1.backoff;
|
||||
}
|
||||
this.maxAttemptsProvider ??= async () => DEFAULT_MAX_ATTEMPTS;
|
||||
this.baseDelay ??= Retry.delay();
|
||||
this.retryBackoffStrategy ??= new DefaultRetryBackoffStrategy();
|
||||
}
|
||||
async acquireInitialRetryToken(retryTokenScope) {
|
||||
return new DefaultRetryToken(Retry.delay(), 0, undefined, Retry.v2026 && retryTokenScope.includes(":longpoll"));
|
||||
}
|
||||
async refreshRetryTokenForRetry(token, errorInfo) {
|
||||
const maxAttempts = await this.getMaxAttempts();
|
||||
const retryCode = this.retryCode(token, errorInfo, maxAttempts);
|
||||
const shouldRetry = retryCode === 0;
|
||||
const isLongPoll = token.isLongPoll?.();
|
||||
if (shouldRetry || isLongPoll) {
|
||||
const errorType = errorInfo.errorType;
|
||||
this.retryBackoffStrategy.setDelayBase(errorType === "THROTTLING" ? Retry.throttlingDelay() : this.baseDelay);
|
||||
const delayFromErrorType = this.retryBackoffStrategy.computeNextBackoffDelay(token.getRetryCount());
|
||||
let retryDelay = delayFromErrorType;
|
||||
if (errorInfo.retryAfterHint instanceof Date) {
|
||||
retryDelay = Math.max(delayFromErrorType, Math.min(errorInfo.retryAfterHint.getTime() - Date.now(), delayFromErrorType + 5_000));
|
||||
}
|
||||
if (!shouldRetry) {
|
||||
const longPollBackoff = Retry.v2026 && retryCode === refusal.capacity && isLongPoll ? retryDelay : 0;
|
||||
if (longPollBackoff > 0) {
|
||||
await new Promise((r) => setTimeout(r, longPollBackoff));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const capacityCost = this.getCapacityCost(errorType);
|
||||
this.capacity -= capacityCost;
|
||||
const nextToken = new DefaultRetryToken(0, token.getRetryCount() + 1, capacityCost, token.isLongPoll?.() ?? false);
|
||||
await new Promise((r) => setTimeout(r, retryDelay));
|
||||
nextToken.$retryLog.acquisitionDelay = retryDelay;
|
||||
return nextToken;
|
||||
}
|
||||
}
|
||||
throw new Error("No retry token available");
|
||||
}
|
||||
recordSuccess(token) {
|
||||
this.capacity = Math.min(INITIAL_RETRY_TOKENS, this.capacity + (token.getRetryCost() ?? NO_RETRY_INCREMENT));
|
||||
}
|
||||
getCapacity() {
|
||||
return this.capacity;
|
||||
}
|
||||
async maxAttempts() {
|
||||
return this.maxAttemptsProvider();
|
||||
}
|
||||
async getMaxAttempts() {
|
||||
try {
|
||||
return await this.maxAttemptsProvider();
|
||||
}
|
||||
catch (error) {
|
||||
console.warn(`Max attempts provider could not resolve. Using default of ${DEFAULT_MAX_ATTEMPTS}`);
|
||||
return DEFAULT_MAX_ATTEMPTS;
|
||||
}
|
||||
}
|
||||
retryCode(tokenToRenew, errorInfo, maxAttempts) {
|
||||
const attempts = tokenToRenew.getRetryCount() + 1;
|
||||
const retryableStatus = this.isRetryableError(errorInfo.errorType) ? 0 : refusal.incompatible;
|
||||
const attemptStatus = attempts < maxAttempts ? 0 : refusal.attempts;
|
||||
const capacityStatus = this.capacity >= this.getCapacityCost(errorInfo.errorType) ? 0 : refusal.capacity;
|
||||
return retryableStatus || attemptStatus || capacityStatus;
|
||||
}
|
||||
getCapacityCost(errorType) {
|
||||
return errorType === Retry.modifiedCostType() ? Retry.throttlingCost() : Retry.cost();
|
||||
}
|
||||
isRetryableError(errorType) {
|
||||
return errorType === "THROTTLING" || errorType === "TRANSIENT";
|
||||
}
|
||||
};
|
||||
|
||||
let AdaptiveRetryStrategy$1 = class AdaptiveRetryStrategy {
|
||||
mode = exports.RETRY_MODES.ADAPTIVE;
|
||||
rateLimiter;
|
||||
standardRetryStrategy;
|
||||
constructor(maxAttemptsProvider, options) {
|
||||
const { rateLimiter } = options ?? {};
|
||||
this.rateLimiter = rateLimiter ?? new DefaultRateLimiter();
|
||||
this.standardRetryStrategy = options
|
||||
? new StandardRetryStrategy$1({
|
||||
maxAttempts: typeof maxAttemptsProvider === "number" ? maxAttemptsProvider : 3,
|
||||
...options,
|
||||
})
|
||||
: new StandardRetryStrategy$1(maxAttemptsProvider);
|
||||
}
|
||||
async acquireInitialRetryToken(retryTokenScope) {
|
||||
const token = await this.standardRetryStrategy.acquireInitialRetryToken(retryTokenScope);
|
||||
await this.rateLimiter.getSendToken();
|
||||
return token;
|
||||
}
|
||||
async refreshRetryTokenForRetry(tokenToRenew, errorInfo) {
|
||||
this.rateLimiter.updateClientSendingRate(errorInfo);
|
||||
const token = await this.standardRetryStrategy.refreshRetryTokenForRetry(tokenToRenew, errorInfo);
|
||||
await this.rateLimiter.getSendToken();
|
||||
return token;
|
||||
}
|
||||
recordSuccess(token) {
|
||||
this.rateLimiter.updateClientSendingRate({});
|
||||
this.standardRetryStrategy.recordSuccess(token);
|
||||
}
|
||||
async maxAttemptsProvider() {
|
||||
return this.standardRetryStrategy.maxAttempts();
|
||||
}
|
||||
};
|
||||
|
||||
class ConfiguredRetryStrategy extends StandardRetryStrategy$1 {
|
||||
computeNextBackoffDelay;
|
||||
constructor(maxAttempts, computeNextBackoffDelay = Retry.delay()) {
|
||||
super(typeof maxAttempts === "function" ? maxAttempts : async () => maxAttempts);
|
||||
if (typeof computeNextBackoffDelay === "number") {
|
||||
this.computeNextBackoffDelay = () => computeNextBackoffDelay;
|
||||
}
|
||||
else {
|
||||
this.computeNextBackoffDelay = computeNextBackoffDelay;
|
||||
}
|
||||
this.retryBackoffStrategy.computeNextBackoffDelay = (completedAttempt) => {
|
||||
const nextAttempt = completedAttempt + 1;
|
||||
return this.computeNextBackoffDelay(nextAttempt);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const getDefaultRetryQuota = (initialRetryTokens, options) => {
|
||||
const MAX_CAPACITY = initialRetryTokens;
|
||||
const noRetryIncrement = NO_RETRY_INCREMENT;
|
||||
const retryCost = RETRY_COST;
|
||||
const timeoutRetryCost = TIMEOUT_RETRY_COST;
|
||||
let availableCapacity = initialRetryTokens;
|
||||
const getCapacityAmount = (error) => (error.name === "TimeoutError" ? timeoutRetryCost : retryCost);
|
||||
const hasRetryTokens = (error) => getCapacityAmount(error) <= availableCapacity;
|
||||
const retrieveRetryTokens = (error) => {
|
||||
if (!hasRetryTokens(error)) {
|
||||
throw new Error("No retry token available");
|
||||
}
|
||||
const capacityAmount = getCapacityAmount(error);
|
||||
availableCapacity -= capacityAmount;
|
||||
return capacityAmount;
|
||||
};
|
||||
const releaseRetryTokens = (capacityReleaseAmount) => {
|
||||
availableCapacity += capacityReleaseAmount ?? noRetryIncrement;
|
||||
availableCapacity = Math.min(availableCapacity, MAX_CAPACITY);
|
||||
};
|
||||
return Object.freeze({
|
||||
hasRetryTokens,
|
||||
retrieveRetryTokens,
|
||||
releaseRetryTokens,
|
||||
});
|
||||
};
|
||||
|
||||
const defaultDelayDecider = (delayBase, attempts) => Math.floor(Math.min(MAXIMUM_RETRY_DELAY, Math.random() * 2 ** attempts * delayBase));
|
||||
|
||||
const defaultRetryDecider = (error) => {
|
||||
if (!error) {
|
||||
return false;
|
||||
}
|
||||
return isRetryableByTrait(error) || isClockSkewError(error) || isThrottlingError(error) || isTransientError(error);
|
||||
};
|
||||
|
||||
class StandardRetryStrategy {
|
||||
maxAttemptsProvider;
|
||||
retryDecider;
|
||||
delayDecider;
|
||||
retryQuota;
|
||||
mode = exports.RETRY_MODES.STANDARD;
|
||||
constructor(maxAttemptsProvider, options) {
|
||||
this.maxAttemptsProvider = maxAttemptsProvider;
|
||||
this.retryDecider = options?.retryDecider ?? defaultRetryDecider;
|
||||
this.delayDecider = options?.delayDecider ?? defaultDelayDecider;
|
||||
this.retryQuota = options?.retryQuota ?? getDefaultRetryQuota(INITIAL_RETRY_TOKENS);
|
||||
}
|
||||
shouldRetry(error, attempts, maxAttempts) {
|
||||
return attempts < maxAttempts && this.retryDecider(error) && this.retryQuota.hasRetryTokens(error);
|
||||
}
|
||||
async getMaxAttempts() {
|
||||
let maxAttempts;
|
||||
try {
|
||||
maxAttempts = await this.maxAttemptsProvider();
|
||||
}
|
||||
catch (error) {
|
||||
maxAttempts = DEFAULT_MAX_ATTEMPTS;
|
||||
}
|
||||
return maxAttempts;
|
||||
}
|
||||
async retry(next, args, options) {
|
||||
let retryTokenAmount;
|
||||
let attempts = 0;
|
||||
let totalDelay = 0;
|
||||
const maxAttempts = await this.getMaxAttempts();
|
||||
const { request } = args;
|
||||
if (protocols.HttpRequest.isInstance(request)) {
|
||||
request.headers[INVOCATION_ID_HEADER] = serde.v4();
|
||||
}
|
||||
while (true) {
|
||||
try {
|
||||
if (protocols.HttpRequest.isInstance(request)) {
|
||||
request.headers[REQUEST_HEADER] = `attempt=${attempts + 1}; max=${maxAttempts}`;
|
||||
}
|
||||
if (options?.beforeRequest) {
|
||||
await options.beforeRequest();
|
||||
}
|
||||
const { response, output } = await next(args);
|
||||
if (options?.afterRequest) {
|
||||
options.afterRequest(response);
|
||||
}
|
||||
this.retryQuota.releaseRetryTokens(retryTokenAmount);
|
||||
output.$metadata.attempts = attempts + 1;
|
||||
output.$metadata.totalRetryDelay = totalDelay;
|
||||
return { response, output };
|
||||
}
|
||||
catch (e) {
|
||||
const err = asSdkError(e);
|
||||
attempts++;
|
||||
if (this.shouldRetry(err, attempts, maxAttempts)) {
|
||||
retryTokenAmount = this.retryQuota.retrieveRetryTokens(err);
|
||||
const delayFromDecider = this.delayDecider(isThrottlingError(err) ? THROTTLING_RETRY_DELAY_BASE : DEFAULT_RETRY_DELAY_BASE, attempts);
|
||||
const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
|
||||
const delay = Math.max(delayFromResponse || 0, delayFromDecider);
|
||||
totalDelay += delay;
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
continue;
|
||||
}
|
||||
if (!err.$metadata) {
|
||||
err.$metadata = {};
|
||||
}
|
||||
err.$metadata.attempts = attempts;
|
||||
err.$metadata.totalRetryDelay = totalDelay;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const getDelayFromRetryAfterHeader = (response) => {
|
||||
if (!protocols.HttpResponse.isInstance(response))
|
||||
return;
|
||||
const retryAfterHeaderName = Object.keys(response.headers).find((key) => key.toLowerCase() === "retry-after");
|
||||
if (!retryAfterHeaderName)
|
||||
return;
|
||||
const retryAfter = response.headers[retryAfterHeaderName];
|
||||
const retryAfterSeconds = Number(retryAfter);
|
||||
if (!Number.isNaN(retryAfterSeconds))
|
||||
return retryAfterSeconds * 1000;
|
||||
const retryAfterDate = new Date(retryAfter);
|
||||
return retryAfterDate.getTime() - Date.now();
|
||||
};
|
||||
|
||||
class AdaptiveRetryStrategy extends StandardRetryStrategy {
|
||||
rateLimiter;
|
||||
constructor(maxAttemptsProvider, options) {
|
||||
const { rateLimiter, ...superOptions } = options ?? {};
|
||||
super(maxAttemptsProvider, superOptions);
|
||||
this.rateLimiter = rateLimiter ?? new DefaultRateLimiter();
|
||||
this.mode = exports.RETRY_MODES.ADAPTIVE;
|
||||
}
|
||||
async retry(next, args) {
|
||||
return super.retry(next, args, {
|
||||
beforeRequest: async () => {
|
||||
return this.rateLimiter.getSendToken();
|
||||
},
|
||||
afterRequest: (response) => {
|
||||
this.rateLimiter.updateClientSendingRate(response);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const ENV_MAX_ATTEMPTS = "AWS_MAX_ATTEMPTS";
|
||||
const CONFIG_MAX_ATTEMPTS = "max_attempts";
|
||||
const NODE_MAX_ATTEMPT_CONFIG_OPTIONS = {
|
||||
environmentVariableSelector: (env) => {
|
||||
const value = env[ENV_MAX_ATTEMPTS];
|
||||
if (!value)
|
||||
return undefined;
|
||||
const maxAttempt = parseInt(value);
|
||||
if (Number.isNaN(maxAttempt)) {
|
||||
throw new Error(`Environment variable ${ENV_MAX_ATTEMPTS} mast be a number, got "${value}"`);
|
||||
}
|
||||
return maxAttempt;
|
||||
},
|
||||
configFileSelector: (profile) => {
|
||||
const value = profile[CONFIG_MAX_ATTEMPTS];
|
||||
if (!value)
|
||||
return undefined;
|
||||
const maxAttempt = parseInt(value);
|
||||
if (Number.isNaN(maxAttempt)) {
|
||||
throw new Error(`Shared config file entry ${CONFIG_MAX_ATTEMPTS} mast be a number, got "${value}"`);
|
||||
}
|
||||
return maxAttempt;
|
||||
},
|
||||
default: DEFAULT_MAX_ATTEMPTS,
|
||||
};
|
||||
const resolveRetryConfig = (input, defaults) => {
|
||||
const { retryStrategy, retryMode } = input;
|
||||
const { defaultMaxAttempts = DEFAULT_MAX_ATTEMPTS, defaultBaseDelay = Retry.delay() } = defaults ?? {};
|
||||
const maxAttemptsProvider = client.normalizeProvider(input.maxAttempts ?? defaultMaxAttempts);
|
||||
let controller = retryStrategy
|
||||
? Promise.resolve(retryStrategy)
|
||||
: undefined;
|
||||
const getDefault = async () => {
|
||||
const maxAttempts = await maxAttemptsProvider();
|
||||
const adaptive = (await client.normalizeProvider(retryMode)()) === exports.RETRY_MODES.ADAPTIVE;
|
||||
if (adaptive) {
|
||||
return new AdaptiveRetryStrategy$1(maxAttemptsProvider, {
|
||||
maxAttempts,
|
||||
baseDelay: defaultBaseDelay,
|
||||
});
|
||||
}
|
||||
return new StandardRetryStrategy$1({
|
||||
maxAttempts,
|
||||
baseDelay: defaultBaseDelay,
|
||||
});
|
||||
};
|
||||
return Object.assign(input, {
|
||||
maxAttempts: maxAttemptsProvider,
|
||||
retryStrategy: () => (controller ??= getDefault()),
|
||||
});
|
||||
};
|
||||
const ENV_RETRY_MODE = "AWS_RETRY_MODE";
|
||||
const CONFIG_RETRY_MODE = "retry_mode";
|
||||
const NODE_RETRY_MODE_CONFIG_OPTIONS = {
|
||||
environmentVariableSelector: (env) => env[ENV_RETRY_MODE],
|
||||
configFileSelector: (profile) => profile[CONFIG_RETRY_MODE],
|
||||
default: DEFAULT_RETRY_MODE,
|
||||
};
|
||||
|
||||
const omitRetryHeadersMiddleware = () => (next) => async (args) => {
|
||||
const { request } = args;
|
||||
if (protocols.HttpRequest.isInstance(request)) {
|
||||
delete request.headers[INVOCATION_ID_HEADER];
|
||||
delete request.headers[REQUEST_HEADER];
|
||||
}
|
||||
return next(args);
|
||||
};
|
||||
const omitRetryHeadersMiddlewareOptions = {
|
||||
name: "omitRetryHeadersMiddleware",
|
||||
tags: ["RETRY", "HEADERS", "OMIT_RETRY_HEADERS"],
|
||||
relation: "before",
|
||||
toMiddleware: "awsAuthMiddleware",
|
||||
override: true,
|
||||
};
|
||||
const getOmitRetryHeadersPlugin = (options) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(omitRetryHeadersMiddleware(), omitRetryHeadersMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
|
||||
const retryMiddleware = bindRetryMiddleware(isStreamingPayload);
|
||||
const getRetryPlugin = bindGetRetryPlugin(isStreamingPayload);
|
||||
|
||||
exports.AdaptiveRetryStrategy = AdaptiveRetryStrategy$1;
|
||||
exports.CONFIG_MAX_ATTEMPTS = CONFIG_MAX_ATTEMPTS;
|
||||
exports.CONFIG_RETRY_MODE = CONFIG_RETRY_MODE;
|
||||
exports.ConfiguredRetryStrategy = ConfiguredRetryStrategy;
|
||||
exports.DEFAULT_MAX_ATTEMPTS = DEFAULT_MAX_ATTEMPTS;
|
||||
exports.DEFAULT_RETRY_DELAY_BASE = DEFAULT_RETRY_DELAY_BASE;
|
||||
exports.DEFAULT_RETRY_MODE = DEFAULT_RETRY_MODE;
|
||||
exports.DefaultRateLimiter = DefaultRateLimiter;
|
||||
exports.DeprecatedAdaptiveRetryStrategy = AdaptiveRetryStrategy;
|
||||
exports.DeprecatedStandardRetryStrategy = StandardRetryStrategy;
|
||||
exports.ENV_MAX_ATTEMPTS = ENV_MAX_ATTEMPTS;
|
||||
exports.ENV_RETRY_MODE = ENV_RETRY_MODE;
|
||||
exports.INITIAL_RETRY_TOKENS = INITIAL_RETRY_TOKENS;
|
||||
exports.INVOCATION_ID_HEADER = INVOCATION_ID_HEADER;
|
||||
exports.MAXIMUM_RETRY_DELAY = MAXIMUM_RETRY_DELAY;
|
||||
exports.NODE_MAX_ATTEMPT_CONFIG_OPTIONS = NODE_MAX_ATTEMPT_CONFIG_OPTIONS;
|
||||
exports.NODE_RETRY_MODE_CONFIG_OPTIONS = NODE_RETRY_MODE_CONFIG_OPTIONS;
|
||||
exports.NO_RETRY_INCREMENT = NO_RETRY_INCREMENT;
|
||||
exports.REQUEST_HEADER = REQUEST_HEADER;
|
||||
exports.RETRY_COST = RETRY_COST;
|
||||
exports.Retry = Retry;
|
||||
exports.StandardRetryStrategy = StandardRetryStrategy$1;
|
||||
exports.THROTTLING_RETRY_DELAY_BASE = THROTTLING_RETRY_DELAY_BASE;
|
||||
exports.TIMEOUT_RETRY_COST = TIMEOUT_RETRY_COST;
|
||||
exports.defaultDelayDecider = defaultDelayDecider;
|
||||
exports.defaultRetryDecider = defaultRetryDecider;
|
||||
exports.getOmitRetryHeadersPlugin = getOmitRetryHeadersPlugin;
|
||||
exports.getRetryAfterHint = getRetryAfterHint;
|
||||
exports.getRetryPlugin = getRetryPlugin;
|
||||
exports.isBrowserNetworkError = isBrowserNetworkError;
|
||||
exports.isClockSkewCorrectedError = isClockSkewCorrectedError;
|
||||
exports.isClockSkewError = isClockSkewError;
|
||||
exports.isNodeJsHttp2TransientError = isNodeJsHttp2TransientError;
|
||||
exports.isRetryableByTrait = isRetryableByTrait;
|
||||
exports.isServerError = isServerError;
|
||||
exports.isThrottlingError = isThrottlingError;
|
||||
exports.isTransientError = isTransientError;
|
||||
exports.omitRetryHeadersMiddleware = omitRetryHeadersMiddleware;
|
||||
exports.omitRetryHeadersMiddlewareOptions = omitRetryHeadersMiddlewareOptions;
|
||||
exports.resolveRetryConfig = resolveRetryConfig;
|
||||
exports.retryMiddleware = retryMiddleware;
|
||||
exports.retryMiddlewareOptions = retryMiddlewareOptions;
|
||||
+713
@@ -0,0 +1,713 @@
|
||||
'use strict';
|
||||
|
||||
var transport = require('@smithy/core/transport');
|
||||
|
||||
const deref = (schemaRef) => {
|
||||
if (typeof schemaRef === "function") {
|
||||
return schemaRef();
|
||||
}
|
||||
return schemaRef;
|
||||
};
|
||||
|
||||
const operation = (namespace, name, traits, input, output) => ({
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
input,
|
||||
output,
|
||||
});
|
||||
|
||||
const schemaDeserializationMiddleware = (config) => (next, context) => async (args) => {
|
||||
const { response } = await next(args);
|
||||
const { operationSchema } = transport.getSmithyContext(context);
|
||||
const [, ns, n, t, i, o] = operationSchema ?? [];
|
||||
try {
|
||||
const parsed = await config.protocol.deserializeResponse(operation(ns, n, t, i, o), {
|
||||
...config,
|
||||
...context,
|
||||
}, response);
|
||||
return {
|
||||
response,
|
||||
output: parsed,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
Object.defineProperty(error, "$response", {
|
||||
value: response,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
configurable: false,
|
||||
});
|
||||
if (!("$metadata" in error)) {
|
||||
const hint = `Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`;
|
||||
try {
|
||||
error.message += "\n " + hint;
|
||||
}
|
||||
catch (e) {
|
||||
if (!context.logger || context.logger?.constructor?.name === "NoOpLogger") {
|
||||
console.warn(hint);
|
||||
}
|
||||
else {
|
||||
context.logger?.warn?.(hint);
|
||||
}
|
||||
}
|
||||
if (typeof error.$responseBodyText !== "undefined") {
|
||||
if (error.$response) {
|
||||
error.$response.body = error.$responseBodyText;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (transport.HttpResponse.isInstance(response)) {
|
||||
const { headers = {}, statusCode } = response;
|
||||
const headerEntries = Object.entries(headers);
|
||||
error.$metadata = {
|
||||
httpStatusCode: statusCode,
|
||||
requestId: findHeader(/^x-[\w-]+-request-?id$/, headerEntries),
|
||||
extendedRequestId: findHeader(/^x-[\w-]+-id-2$/, headerEntries),
|
||||
cfId: findHeader(/^x-[\w-]+-cf-id$/, headerEntries),
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
const findHeader = (pattern, headers) => {
|
||||
return (headers.find(([k]) => {
|
||||
return k.match(pattern);
|
||||
}) || [void 0, void 0])[1];
|
||||
};
|
||||
|
||||
const schemaSerializationMiddleware = (config) => (next, context) => async (args) => {
|
||||
const { operationSchema } = transport.getSmithyContext(context);
|
||||
const [, ns, n, t, i, o] = operationSchema ?? [];
|
||||
const endpoint = context.endpointV2
|
||||
? async () => transport.toEndpointV1(context.endpointV2)
|
||||
: config.endpoint;
|
||||
const request = await config.protocol.serializeRequest(operation(ns, n, t, i, o), args.input, {
|
||||
...config,
|
||||
...context,
|
||||
endpoint,
|
||||
});
|
||||
return next({
|
||||
...args,
|
||||
request,
|
||||
});
|
||||
};
|
||||
|
||||
const deserializerMiddlewareOption = {
|
||||
name: "deserializerMiddleware",
|
||||
step: "deserialize",
|
||||
tags: ["DESERIALIZER"],
|
||||
override: true,
|
||||
};
|
||||
const serializerMiddlewareOption = {
|
||||
name: "serializerMiddleware",
|
||||
step: "serialize",
|
||||
tags: ["SERIALIZER"],
|
||||
override: true,
|
||||
};
|
||||
function getSchemaSerdePlugin(config) {
|
||||
return {
|
||||
applyToStack: (commandStack) => {
|
||||
commandStack.add(schemaSerializationMiddleware(config), serializerMiddlewareOption);
|
||||
commandStack.add(schemaDeserializationMiddleware(config), deserializerMiddlewareOption);
|
||||
config.protocol.setSerdeContext(config);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
class Schema {
|
||||
name;
|
||||
namespace;
|
||||
traits;
|
||||
static assign(instance, values) {
|
||||
const schema = Object.assign(instance, values);
|
||||
return schema;
|
||||
}
|
||||
static [Symbol.hasInstance](lhs) {
|
||||
const isPrototype = this.prototype.isPrototypeOf(lhs);
|
||||
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
|
||||
const list = lhs;
|
||||
return list.symbol === this.symbol;
|
||||
}
|
||||
return isPrototype;
|
||||
}
|
||||
getName() {
|
||||
return this.namespace + "#" + this.name;
|
||||
}
|
||||
}
|
||||
|
||||
class ListSchema extends Schema {
|
||||
static symbol = Symbol.for("@smithy/lis");
|
||||
name;
|
||||
traits;
|
||||
valueSchema;
|
||||
symbol = ListSchema.symbol;
|
||||
}
|
||||
const list = (namespace, name, traits, valueSchema) => Schema.assign(new ListSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
valueSchema,
|
||||
});
|
||||
|
||||
class MapSchema extends Schema {
|
||||
static symbol = Symbol.for("@smithy/map");
|
||||
name;
|
||||
traits;
|
||||
keySchema;
|
||||
valueSchema;
|
||||
symbol = MapSchema.symbol;
|
||||
}
|
||||
const map = (namespace, name, traits, keySchema, valueSchema) => Schema.assign(new MapSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
keySchema,
|
||||
valueSchema,
|
||||
});
|
||||
|
||||
class OperationSchema extends Schema {
|
||||
static symbol = Symbol.for("@smithy/ope");
|
||||
name;
|
||||
traits;
|
||||
input;
|
||||
output;
|
||||
symbol = OperationSchema.symbol;
|
||||
}
|
||||
const op = (namespace, name, traits, input, output) => Schema.assign(new OperationSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
input,
|
||||
output,
|
||||
});
|
||||
|
||||
class StructureSchema extends Schema {
|
||||
static symbol = Symbol.for("@smithy/str");
|
||||
name;
|
||||
traits;
|
||||
memberNames;
|
||||
memberList;
|
||||
symbol = StructureSchema.symbol;
|
||||
}
|
||||
const struct = (namespace, name, traits, memberNames, memberList) => Schema.assign(new StructureSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
memberNames,
|
||||
memberList,
|
||||
});
|
||||
|
||||
class ErrorSchema extends StructureSchema {
|
||||
static symbol = Symbol.for("@smithy/err");
|
||||
ctor;
|
||||
symbol = ErrorSchema.symbol;
|
||||
}
|
||||
const error = (namespace, name, traits, memberNames, memberList, ctor) => Schema.assign(new ErrorSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
memberNames,
|
||||
memberList,
|
||||
ctor: null,
|
||||
});
|
||||
|
||||
const traitsCache = [];
|
||||
function translateTraits(indicator) {
|
||||
if (typeof indicator === "object") {
|
||||
return indicator;
|
||||
}
|
||||
indicator = indicator | 0;
|
||||
if (traitsCache[indicator]) {
|
||||
return traitsCache[indicator];
|
||||
}
|
||||
const traits = {};
|
||||
let i = 0;
|
||||
for (const trait of [
|
||||
"httpLabel",
|
||||
"idempotent",
|
||||
"idempotencyToken",
|
||||
"sensitive",
|
||||
"httpPayload",
|
||||
"httpResponseCode",
|
||||
"httpQueryParams",
|
||||
]) {
|
||||
if (((indicator >> i++) & 1) === 1) {
|
||||
traits[trait] = 1;
|
||||
}
|
||||
}
|
||||
return (traitsCache[indicator] = traits);
|
||||
}
|
||||
|
||||
const anno = {
|
||||
it: Symbol.for("@smithy/nor-struct-it"),
|
||||
ns: Symbol.for("@smithy/ns"),
|
||||
};
|
||||
const simpleSchemaCacheN = [];
|
||||
const simpleSchemaCacheS = {};
|
||||
class NormalizedSchema {
|
||||
ref;
|
||||
memberName;
|
||||
static symbol = Symbol.for("@smithy/nor");
|
||||
symbol = NormalizedSchema.symbol;
|
||||
name;
|
||||
schema;
|
||||
_isMemberSchema;
|
||||
traits;
|
||||
memberTraits;
|
||||
normalizedTraits;
|
||||
constructor(ref, memberName) {
|
||||
this.ref = ref;
|
||||
this.memberName = memberName;
|
||||
const traitStack = [];
|
||||
let _ref = ref;
|
||||
let schema = ref;
|
||||
this._isMemberSchema = false;
|
||||
while (isMemberSchema(_ref)) {
|
||||
traitStack.push(_ref[1]);
|
||||
_ref = _ref[0];
|
||||
schema = deref(_ref);
|
||||
this._isMemberSchema = true;
|
||||
}
|
||||
if (traitStack.length > 0) {
|
||||
this.memberTraits = {};
|
||||
for (let i = traitStack.length - 1; i >= 0; --i) {
|
||||
const traitSet = traitStack[i];
|
||||
Object.assign(this.memberTraits, translateTraits(traitSet));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.memberTraits = 0;
|
||||
}
|
||||
if (schema instanceof NormalizedSchema) {
|
||||
const computedMemberTraits = this.memberTraits;
|
||||
Object.assign(this, schema);
|
||||
this.memberTraits = Object.assign({}, computedMemberTraits, schema.getMemberTraits(), this.getMemberTraits());
|
||||
this.normalizedTraits = void 0;
|
||||
this.memberName = memberName ?? schema.memberName;
|
||||
return;
|
||||
}
|
||||
this.schema = deref(schema);
|
||||
if (isStaticSchema(this.schema)) {
|
||||
this.name = `${this.schema[1]}#${this.schema[2]}`;
|
||||
this.traits = this.schema[3];
|
||||
}
|
||||
else {
|
||||
this.name = this.memberName ?? String(schema);
|
||||
this.traits = 0;
|
||||
}
|
||||
if (this._isMemberSchema && !memberName) {
|
||||
throw new Error(`@smithy/core/schema - NormalizedSchema member init ${this.getName(true)} missing member name.`);
|
||||
}
|
||||
}
|
||||
static [Symbol.hasInstance](lhs) {
|
||||
const isPrototype = this.prototype.isPrototypeOf(lhs);
|
||||
if (!isPrototype && typeof lhs === "object" && lhs !== null) {
|
||||
const ns = lhs;
|
||||
return ns.symbol === this.symbol;
|
||||
}
|
||||
return isPrototype;
|
||||
}
|
||||
static of(ref) {
|
||||
const keyAble = typeof ref === "function" || (typeof ref === "object" && ref !== null);
|
||||
if (typeof ref === "number") {
|
||||
if (simpleSchemaCacheN[ref]) {
|
||||
return simpleSchemaCacheN[ref];
|
||||
}
|
||||
}
|
||||
else if (typeof ref === "string") {
|
||||
if (simpleSchemaCacheS[ref]) {
|
||||
return simpleSchemaCacheS[ref];
|
||||
}
|
||||
}
|
||||
else if (keyAble) {
|
||||
if (ref[anno.ns]) {
|
||||
return ref[anno.ns];
|
||||
}
|
||||
}
|
||||
const sc = deref(ref);
|
||||
if (sc instanceof NormalizedSchema) {
|
||||
return sc;
|
||||
}
|
||||
if (isMemberSchema(sc)) {
|
||||
const [ns, traits] = sc;
|
||||
if (ns instanceof NormalizedSchema) {
|
||||
Object.assign(ns.getMergedTraits(), translateTraits(traits));
|
||||
return ns;
|
||||
}
|
||||
throw new Error(`@smithy/core/schema - may not init unwrapped member schema=${JSON.stringify(ref, null, 2)}.`);
|
||||
}
|
||||
const ns = new NormalizedSchema(sc);
|
||||
if (keyAble) {
|
||||
return (ref[anno.ns] = ns);
|
||||
}
|
||||
if (typeof sc === "string") {
|
||||
return (simpleSchemaCacheS[sc] = ns);
|
||||
}
|
||||
if (typeof sc === "number") {
|
||||
return (simpleSchemaCacheN[sc] = ns);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
getSchema() {
|
||||
const sc = this.schema;
|
||||
if (Array.isArray(sc) && sc[0] === 0) {
|
||||
return sc[4];
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
getName(withNamespace = false) {
|
||||
const { name } = this;
|
||||
const short = !withNamespace && name && name.includes("#");
|
||||
return short ? name.split("#")[1] : name || undefined;
|
||||
}
|
||||
getMemberName() {
|
||||
return this.memberName;
|
||||
}
|
||||
isMemberSchema() {
|
||||
return this._isMemberSchema;
|
||||
}
|
||||
isListSchema() {
|
||||
const sc = this.getSchema();
|
||||
return typeof sc === "number"
|
||||
? sc >= 64 && sc < 128
|
||||
: sc[0] === 1;
|
||||
}
|
||||
isMapSchema() {
|
||||
const sc = this.getSchema();
|
||||
return typeof sc === "number"
|
||||
? sc >= 128 && sc <= 0b1111_1111
|
||||
: sc[0] === 2;
|
||||
}
|
||||
isStructSchema() {
|
||||
const sc = this.getSchema();
|
||||
if (typeof sc !== "object") {
|
||||
return false;
|
||||
}
|
||||
const id = sc[0];
|
||||
return (id === 3 ||
|
||||
id === -3 ||
|
||||
id === 4);
|
||||
}
|
||||
isUnionSchema() {
|
||||
const sc = this.getSchema();
|
||||
if (typeof sc !== "object") {
|
||||
return false;
|
||||
}
|
||||
return sc[0] === 4;
|
||||
}
|
||||
isBlobSchema() {
|
||||
const sc = this.getSchema();
|
||||
return sc === 21 || sc === 42;
|
||||
}
|
||||
isTimestampSchema() {
|
||||
const sc = this.getSchema();
|
||||
return (typeof sc === "number" &&
|
||||
sc >= 4 &&
|
||||
sc <= 7);
|
||||
}
|
||||
isUnitSchema() {
|
||||
return this.getSchema() === "unit";
|
||||
}
|
||||
isDocumentSchema() {
|
||||
return this.getSchema() === 15;
|
||||
}
|
||||
isStringSchema() {
|
||||
return this.getSchema() === 0;
|
||||
}
|
||||
isBooleanSchema() {
|
||||
return this.getSchema() === 2;
|
||||
}
|
||||
isNumericSchema() {
|
||||
return this.getSchema() === 1;
|
||||
}
|
||||
isBigIntegerSchema() {
|
||||
return this.getSchema() === 17;
|
||||
}
|
||||
isBigDecimalSchema() {
|
||||
return this.getSchema() === 19;
|
||||
}
|
||||
isStreaming() {
|
||||
const { streaming } = this.getMergedTraits();
|
||||
return !!streaming || this.getSchema() === 42;
|
||||
}
|
||||
isIdempotencyToken() {
|
||||
return !!this.getMergedTraits().idempotencyToken;
|
||||
}
|
||||
getMergedTraits() {
|
||||
return (this.normalizedTraits ??
|
||||
(this.normalizedTraits = {
|
||||
...this.getOwnTraits(),
|
||||
...this.getMemberTraits(),
|
||||
}));
|
||||
}
|
||||
getMemberTraits() {
|
||||
return translateTraits(this.memberTraits);
|
||||
}
|
||||
getOwnTraits() {
|
||||
return translateTraits(this.traits);
|
||||
}
|
||||
getKeySchema() {
|
||||
const [isDoc, isMap] = [this.isDocumentSchema(), this.isMapSchema()];
|
||||
if (!isDoc && !isMap) {
|
||||
throw new Error(`@smithy/core/schema - cannot get key for non-map: ${this.getName(true)}`);
|
||||
}
|
||||
const schema = this.getSchema();
|
||||
const memberSchema = isDoc
|
||||
? 15
|
||||
: schema[4] ?? 0;
|
||||
return member([memberSchema, 0], "key");
|
||||
}
|
||||
getValueSchema() {
|
||||
const sc = this.getSchema();
|
||||
const [isDoc, isMap, isList] = [this.isDocumentSchema(), this.isMapSchema(), this.isListSchema()];
|
||||
const memberSchema = typeof sc === "number"
|
||||
? 0b0011_1111 & sc
|
||||
: sc && typeof sc === "object" && (isMap || isList)
|
||||
? sc[3 + sc[0]]
|
||||
: isDoc
|
||||
? 15
|
||||
: void 0;
|
||||
if (memberSchema != null) {
|
||||
return member([memberSchema, 0], isMap ? "value" : "member");
|
||||
}
|
||||
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no value member.`);
|
||||
}
|
||||
getMemberSchema(memberName) {
|
||||
const struct = this.getSchema();
|
||||
if (this.isStructSchema() && struct[4].includes(memberName)) {
|
||||
const i = struct[4].indexOf(memberName);
|
||||
const memberSchema = struct[5][i];
|
||||
return member(isMemberSchema(memberSchema) ? memberSchema : [memberSchema, 0], memberName);
|
||||
}
|
||||
if (this.isDocumentSchema()) {
|
||||
return member([15, 0], memberName);
|
||||
}
|
||||
throw new Error(`@smithy/core/schema - ${this.getName(true)} has no member=${memberName}.`);
|
||||
}
|
||||
getMemberSchemas() {
|
||||
const buffer = {};
|
||||
try {
|
||||
for (const [k, v] of this.structIterator()) {
|
||||
buffer[k] = v;
|
||||
}
|
||||
}
|
||||
catch (ignored) { }
|
||||
return buffer;
|
||||
}
|
||||
getEventStreamMember() {
|
||||
if (this.isStructSchema()) {
|
||||
for (const [memberName, memberSchema] of this.structIterator()) {
|
||||
if (memberSchema.isStreaming() && memberSchema.isStructSchema()) {
|
||||
return memberName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
*structIterator() {
|
||||
if (this.isUnitSchema()) {
|
||||
return;
|
||||
}
|
||||
if (!this.isStructSchema()) {
|
||||
throw new Error("@smithy/core/schema - cannot iterate non-struct schema.");
|
||||
}
|
||||
const struct = this.getSchema();
|
||||
const z = struct[4].length;
|
||||
let it = struct[anno.it];
|
||||
if (it && z === it.length) {
|
||||
yield* it;
|
||||
return;
|
||||
}
|
||||
it = Array(z);
|
||||
for (let i = 0; i < z; ++i) {
|
||||
const k = struct[4][i];
|
||||
const v = member([struct[5][i], 0], k);
|
||||
yield (it[i] = [k, v]);
|
||||
}
|
||||
struct[anno.it] = it;
|
||||
}
|
||||
}
|
||||
function member(memberSchema, memberName) {
|
||||
if (memberSchema instanceof NormalizedSchema) {
|
||||
return Object.assign(memberSchema, {
|
||||
memberName,
|
||||
_isMemberSchema: true,
|
||||
});
|
||||
}
|
||||
const internalCtorAccess = NormalizedSchema;
|
||||
return new internalCtorAccess(memberSchema, memberName);
|
||||
}
|
||||
const isMemberSchema = (sc) => Array.isArray(sc) && sc.length === 2;
|
||||
const isStaticSchema = (sc) => Array.isArray(sc) && sc.length >= 5;
|
||||
|
||||
class SimpleSchema extends Schema {
|
||||
static symbol = Symbol.for("@smithy/sim");
|
||||
name;
|
||||
schemaRef;
|
||||
traits;
|
||||
symbol = SimpleSchema.symbol;
|
||||
}
|
||||
const sim = (namespace, name, schemaRef, traits) => Schema.assign(new SimpleSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
schemaRef,
|
||||
});
|
||||
const simAdapter = (namespace, name, traits, schemaRef) => Schema.assign(new SimpleSchema(), {
|
||||
name,
|
||||
namespace,
|
||||
traits,
|
||||
schemaRef,
|
||||
});
|
||||
|
||||
const SCHEMA = {
|
||||
BLOB: 0b0001_0101,
|
||||
STREAMING_BLOB: 0b0010_1010,
|
||||
BOOLEAN: 0b0000_0010,
|
||||
STRING: 0b0000_0000,
|
||||
NUMERIC: 0b0000_0001,
|
||||
BIG_INTEGER: 0b0001_0001,
|
||||
BIG_DECIMAL: 0b0001_0011,
|
||||
DOCUMENT: 0b0000_1111,
|
||||
TIMESTAMP_DEFAULT: 0b0000_0100,
|
||||
TIMESTAMP_DATE_TIME: 0b0000_0101,
|
||||
TIMESTAMP_HTTP_DATE: 0b0000_0110,
|
||||
TIMESTAMP_EPOCH_SECONDS: 0b0000_0111,
|
||||
LIST_MODIFIER: 0b0100_0000,
|
||||
MAP_MODIFIER: 0b1000_0000,
|
||||
};
|
||||
|
||||
class TypeRegistry {
|
||||
namespace;
|
||||
schemas;
|
||||
exceptions;
|
||||
static registries = new Map();
|
||||
constructor(namespace, schemas = new Map(), exceptions = new Map()) {
|
||||
this.namespace = namespace;
|
||||
this.schemas = schemas;
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
static for(namespace) {
|
||||
if (!TypeRegistry.registries.has(namespace)) {
|
||||
TypeRegistry.registries.set(namespace, new TypeRegistry(namespace));
|
||||
}
|
||||
return TypeRegistry.registries.get(namespace);
|
||||
}
|
||||
copyFrom(other) {
|
||||
const { schemas, exceptions } = this;
|
||||
for (const [k, v] of other.schemas) {
|
||||
if (!schemas.has(k)) {
|
||||
schemas.set(k, v);
|
||||
}
|
||||
}
|
||||
for (const [k, v] of other.exceptions) {
|
||||
if (!exceptions.has(k)) {
|
||||
exceptions.set(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
register(shapeId, schema) {
|
||||
const qualifiedName = this.normalizeShapeId(shapeId);
|
||||
for (const r of [this, TypeRegistry.for(qualifiedName.split("#")[0])]) {
|
||||
r.schemas.set(qualifiedName, schema);
|
||||
}
|
||||
}
|
||||
getSchema(shapeId) {
|
||||
const id = this.normalizeShapeId(shapeId);
|
||||
if (!this.schemas.has(id)) {
|
||||
if (!shapeId.includes("#")) {
|
||||
const suffix = "#" + shapeId;
|
||||
const candidates = [];
|
||||
for (const [shapeId, schema] of this.schemas.entries()) {
|
||||
if (shapeId.endsWith(suffix)) {
|
||||
candidates.push(schema);
|
||||
}
|
||||
}
|
||||
if (candidates.length === 1) {
|
||||
return candidates[0];
|
||||
}
|
||||
}
|
||||
throw new Error(`@smithy/core/schema - schema not found for ${id}`);
|
||||
}
|
||||
return this.schemas.get(id);
|
||||
}
|
||||
registerError(es, ctor) {
|
||||
const $error = es;
|
||||
const ns = $error[1];
|
||||
for (const r of [this, TypeRegistry.for(ns)]) {
|
||||
r.schemas.set(ns + "#" + $error[2], $error);
|
||||
r.exceptions.set($error, ctor);
|
||||
}
|
||||
}
|
||||
getErrorCtor(es) {
|
||||
const $error = es;
|
||||
if (this.exceptions.has($error)) {
|
||||
return this.exceptions.get($error);
|
||||
}
|
||||
const registry = TypeRegistry.for($error[1]);
|
||||
return registry.exceptions.get($error);
|
||||
}
|
||||
getBaseException() {
|
||||
for (const exceptionKey of this.exceptions.keys()) {
|
||||
if (Array.isArray(exceptionKey)) {
|
||||
const [, ns, name] = exceptionKey;
|
||||
const id = ns + "#" + name;
|
||||
if (id.startsWith("smithy.ts.sdk.synthetic.") && id.endsWith("ServiceException")) {
|
||||
return exceptionKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
find(predicate) {
|
||||
for (const schema of this.schemas.values()) {
|
||||
if (predicate(schema)) {
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
clear() {
|
||||
this.schemas.clear();
|
||||
this.exceptions.clear();
|
||||
}
|
||||
normalizeShapeId(shapeId) {
|
||||
if (shapeId.includes("#")) {
|
||||
return shapeId;
|
||||
}
|
||||
return this.namespace + "#" + shapeId;
|
||||
}
|
||||
}
|
||||
|
||||
exports.ErrorSchema = ErrorSchema;
|
||||
exports.ListSchema = ListSchema;
|
||||
exports.MapSchema = MapSchema;
|
||||
exports.NormalizedSchema = NormalizedSchema;
|
||||
exports.OperationSchema = OperationSchema;
|
||||
exports.SCHEMA = SCHEMA;
|
||||
exports.Schema = Schema;
|
||||
exports.SimpleSchema = SimpleSchema;
|
||||
exports.StructureSchema = StructureSchema;
|
||||
exports.TypeRegistry = TypeRegistry;
|
||||
exports.deref = deref;
|
||||
exports.deserializerMiddlewareOption = deserializerMiddlewareOption;
|
||||
exports.error = error;
|
||||
exports.getSchemaSerdePlugin = getSchemaSerdePlugin;
|
||||
exports.isStaticSchema = isStaticSchema;
|
||||
exports.list = list;
|
||||
exports.map = map;
|
||||
exports.op = op;
|
||||
exports.operation = operation;
|
||||
exports.serializerMiddlewareOption = serializerMiddlewareOption;
|
||||
exports.sim = sim;
|
||||
exports.simAdapter = simAdapter;
|
||||
exports.simpleSchemaCacheN = simpleSchemaCacheN;
|
||||
exports.simpleSchemaCacheS = simpleSchemaCacheS;
|
||||
exports.struct = struct;
|
||||
exports.traitsCache = traitsCache;
|
||||
exports.translateTraits = translateTraits;
|
||||
+1405
File diff suppressed because it is too large
Load Diff
+1789
File diff suppressed because it is too large
Load Diff
+1405
File diff suppressed because it is too large
Load Diff
+184
@@ -0,0 +1,184 @@
|
||||
'use strict';
|
||||
|
||||
var types = require('@smithy/types');
|
||||
|
||||
const getSmithyContext = (context) => context[types.SMITHY_CONTEXT_KEY] || (context[types.SMITHY_CONTEXT_KEY] = {});
|
||||
|
||||
class HttpRequest {
|
||||
method;
|
||||
protocol;
|
||||
hostname;
|
||||
port;
|
||||
path;
|
||||
query;
|
||||
headers;
|
||||
username;
|
||||
password;
|
||||
fragment;
|
||||
body;
|
||||
constructor(options) {
|
||||
this.method = options.method || "GET";
|
||||
this.hostname = options.hostname || "localhost";
|
||||
this.port = options.port;
|
||||
this.query = options.query || {};
|
||||
this.headers = options.headers || {};
|
||||
this.body = options.body;
|
||||
this.protocol = options.protocol
|
||||
? options.protocol.slice(-1) !== ":"
|
||||
? `${options.protocol}:`
|
||||
: options.protocol
|
||||
: "https:";
|
||||
this.path = options.path ? (options.path.charAt(0) !== "/" ? `/${options.path}` : options.path) : "/";
|
||||
this.username = options.username;
|
||||
this.password = options.password;
|
||||
this.fragment = options.fragment;
|
||||
}
|
||||
static clone(request) {
|
||||
const cloned = new HttpRequest({
|
||||
...request,
|
||||
headers: { ...request.headers },
|
||||
});
|
||||
if (cloned.query) {
|
||||
cloned.query = cloneQuery(cloned.query);
|
||||
}
|
||||
return cloned;
|
||||
}
|
||||
static isInstance(request) {
|
||||
if (!request) {
|
||||
return false;
|
||||
}
|
||||
const req = request;
|
||||
return ("method" in req &&
|
||||
"protocol" in req &&
|
||||
"hostname" in req &&
|
||||
"path" in req &&
|
||||
typeof req["query"] === "object" &&
|
||||
typeof req["headers"] === "object");
|
||||
}
|
||||
clone() {
|
||||
return HttpRequest.clone(this);
|
||||
}
|
||||
}
|
||||
function cloneQuery(query) {
|
||||
return Object.keys(query).reduce((carry, paramName) => {
|
||||
const param = query[paramName];
|
||||
return {
|
||||
...carry,
|
||||
[paramName]: Array.isArray(param) ? [...param] : param,
|
||||
};
|
||||
}, {});
|
||||
}
|
||||
|
||||
class HttpResponse {
|
||||
statusCode;
|
||||
reason;
|
||||
headers;
|
||||
body;
|
||||
constructor(options) {
|
||||
this.statusCode = options.statusCode;
|
||||
this.reason = options.reason;
|
||||
this.headers = options.headers || {};
|
||||
this.body = options.body;
|
||||
}
|
||||
static isInstance(response) {
|
||||
if (!response)
|
||||
return false;
|
||||
const resp = response;
|
||||
return typeof resp.statusCode === "number" && typeof resp.headers === "object";
|
||||
}
|
||||
}
|
||||
|
||||
const VALID_HOST_LABEL_REGEX = new RegExp(`^(?!.*-$)(?!-)[a-zA-Z0-9-]{1,63}$`);
|
||||
const isValidHostLabel = (value, allowSubDomains = false) => {
|
||||
if (!allowSubDomains) {
|
||||
return VALID_HOST_LABEL_REGEX.test(value);
|
||||
}
|
||||
const labels = value.split(".");
|
||||
for (const label of labels) {
|
||||
if (!isValidHostLabel(label)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
function isValidHostname(hostname) {
|
||||
const hostPattern = /^[a-z0-9][a-z0-9\.\-]*[a-z0-9]$/;
|
||||
return hostPattern.test(hostname);
|
||||
}
|
||||
|
||||
const normalizeProvider = (input) => {
|
||||
if (typeof input === "function")
|
||||
return input;
|
||||
const promisified = Promise.resolve(input);
|
||||
return () => promisified;
|
||||
};
|
||||
|
||||
function parseQueryString(querystring) {
|
||||
const query = {};
|
||||
querystring = querystring.replace(/^\?/, "");
|
||||
if (querystring) {
|
||||
for (const pair of querystring.split("&")) {
|
||||
let [key, value = null] = pair.split("=");
|
||||
key = decodeURIComponent(key);
|
||||
if (value) {
|
||||
value = decodeURIComponent(value);
|
||||
}
|
||||
if (!(key in query)) {
|
||||
query[key] = value;
|
||||
}
|
||||
else if (Array.isArray(query[key])) {
|
||||
query[key].push(value);
|
||||
}
|
||||
else {
|
||||
query[key] = [query[key], value];
|
||||
}
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
const parseUrl = (url) => {
|
||||
if (typeof url === "string") {
|
||||
return parseUrl(new URL(url));
|
||||
}
|
||||
const { hostname, pathname, port, protocol, search } = url;
|
||||
let query;
|
||||
if (search) {
|
||||
query = parseQueryString(search);
|
||||
}
|
||||
return {
|
||||
hostname,
|
||||
port: port ? parseInt(port) : undefined,
|
||||
protocol,
|
||||
path: pathname,
|
||||
query,
|
||||
};
|
||||
};
|
||||
|
||||
const toEndpointV1 = (endpoint) => {
|
||||
if (typeof endpoint === "object") {
|
||||
if ("url" in endpoint) {
|
||||
const v1Endpoint = parseUrl(endpoint.url);
|
||||
if (endpoint.headers) {
|
||||
v1Endpoint.headers = {};
|
||||
for (const name in endpoint.headers) {
|
||||
v1Endpoint.headers[name.toLowerCase()] = endpoint.headers[name].join(", ");
|
||||
}
|
||||
}
|
||||
return v1Endpoint;
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
return parseUrl(endpoint);
|
||||
};
|
||||
|
||||
exports.HttpRequest = HttpRequest;
|
||||
exports.HttpResponse = HttpResponse;
|
||||
exports.getSmithyContext = getSmithyContext;
|
||||
exports.isValidHostLabel = isValidHostLabel;
|
||||
exports.isValidHostname = isValidHostname;
|
||||
exports.normalizeProvider = normalizeProvider;
|
||||
exports.parseQueryString = parseQueryString;
|
||||
exports.parseUrl = parseUrl;
|
||||
exports.toEndpointV1 = toEndpointV1;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
export { getSmithyContext } from "@smithy/core/transport";
|
||||
export * from "./legacy-root-exports/middleware-http-auth-scheme";
|
||||
export * from "./legacy-root-exports/middleware-http-signing";
|
||||
export * from "./normalizeProvider";
|
||||
export { createPaginator } from "./legacy-root-exports/pagination/createPaginator";
|
||||
export { requestBuilder } from "@smithy/core/protocols";
|
||||
export * from "./setFeature";
|
||||
export * from "./legacy-root-exports/util-identity-and-auth";
|
||||
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
import { httpAuthSchemeMiddleware } from "./httpAuthSchemeMiddleware";
|
||||
export const httpAuthSchemeEndpointRuleSetMiddlewareOptions = {
|
||||
step: "serialize",
|
||||
tags: ["HTTP_AUTH_SCHEME"],
|
||||
name: "httpAuthSchemeMiddleware",
|
||||
override: true,
|
||||
relation: "before",
|
||||
toMiddleware: "endpointV2Middleware",
|
||||
};
|
||||
export const getHttpAuthSchemeEndpointRuleSetPlugin = (config, { httpAuthSchemeParametersProvider, identityProviderConfigProvider, }) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(httpAuthSchemeMiddleware(config, {
|
||||
httpAuthSchemeParametersProvider,
|
||||
identityProviderConfigProvider,
|
||||
}), httpAuthSchemeEndpointRuleSetMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
import { httpAuthSchemeMiddleware } from "./httpAuthSchemeMiddleware";
|
||||
export const httpAuthSchemeMiddlewareOptions = {
|
||||
step: "serialize",
|
||||
tags: ["HTTP_AUTH_SCHEME"],
|
||||
name: "httpAuthSchemeMiddleware",
|
||||
override: true,
|
||||
relation: "before",
|
||||
toMiddleware: "serializerMiddleware",
|
||||
};
|
||||
export const getHttpAuthSchemePlugin = (config, { httpAuthSchemeParametersProvider, identityProviderConfigProvider, }) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(httpAuthSchemeMiddleware(config, {
|
||||
httpAuthSchemeParametersProvider,
|
||||
identityProviderConfigProvider,
|
||||
}), httpAuthSchemeMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
Generated
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
import { getSmithyContext } from "@smithy/core/client";
|
||||
import { resolveAuthOptions } from "./resolveAuthOptions";
|
||||
function convertHttpAuthSchemesToMap(httpAuthSchemes) {
|
||||
const map = new Map();
|
||||
for (const scheme of httpAuthSchemes) {
|
||||
map.set(scheme.schemeId, scheme);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
export const httpAuthSchemeMiddleware = (config, mwOptions) => (next, context) => async (args) => {
|
||||
const options = config.httpAuthSchemeProvider(await mwOptions.httpAuthSchemeParametersProvider(config, context, args.input));
|
||||
const authSchemePreference = config.authSchemePreference ? await config.authSchemePreference() : [];
|
||||
const resolvedOptions = resolveAuthOptions(options, authSchemePreference);
|
||||
const authSchemes = convertHttpAuthSchemesToMap(config.httpAuthSchemes);
|
||||
const smithyContext = getSmithyContext(context);
|
||||
const failureReasons = [];
|
||||
for (const option of resolvedOptions) {
|
||||
const scheme = authSchemes.get(option.schemeId);
|
||||
if (!scheme) {
|
||||
failureReasons.push(`HttpAuthScheme \`${option.schemeId}\` was not enabled for this service.`);
|
||||
continue;
|
||||
}
|
||||
const identityProvider = scheme.identityProvider(await mwOptions.identityProviderConfigProvider(config));
|
||||
if (!identityProvider) {
|
||||
failureReasons.push(`HttpAuthScheme \`${option.schemeId}\` did not have an IdentityProvider configured.`);
|
||||
continue;
|
||||
}
|
||||
const { identityProperties = {}, signingProperties = {} } = option.propertiesExtractor?.(config, context) || {};
|
||||
option.identityProperties = Object.assign(option.identityProperties || {}, identityProperties);
|
||||
option.signingProperties = Object.assign(option.signingProperties || {}, signingProperties);
|
||||
smithyContext.selectedHttpAuthScheme = {
|
||||
httpAuthOption: option,
|
||||
identity: await identityProvider(option.identityProperties),
|
||||
signer: scheme.signer,
|
||||
};
|
||||
break;
|
||||
}
|
||||
if (!smithyContext.selectedHttpAuthScheme) {
|
||||
throw new Error(failureReasons.join("\n"));
|
||||
}
|
||||
return next(args);
|
||||
};
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export * from "./httpAuthSchemeMiddleware";
|
||||
export * from "./getHttpAuthSchemeEndpointRuleSetPlugin";
|
||||
export * from "./getHttpAuthSchemePlugin";
|
||||
Generated
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
export const resolveAuthOptions = (candidateAuthOptions, authSchemePreference) => {
|
||||
if (!authSchemePreference || authSchemePreference.length === 0) {
|
||||
return candidateAuthOptions;
|
||||
}
|
||||
const preferredAuthOptions = [];
|
||||
for (const preferredSchemeName of authSchemePreference) {
|
||||
for (const candidateAuthOption of candidateAuthOptions) {
|
||||
const candidateAuthSchemeName = candidateAuthOption.schemeId.split("#")[1];
|
||||
if (candidateAuthSchemeName === preferredSchemeName) {
|
||||
preferredAuthOptions.push(candidateAuthOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const candidateAuthOption of candidateAuthOptions) {
|
||||
if (!preferredAuthOptions.find(({ schemeId }) => schemeId === candidateAuthOption.schemeId)) {
|
||||
preferredAuthOptions.push(candidateAuthOption);
|
||||
}
|
||||
}
|
||||
return preferredAuthOptions;
|
||||
};
|
||||
Generated
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import { httpSigningMiddleware } from "./httpSigningMiddleware";
|
||||
export const httpSigningMiddlewareOptions = {
|
||||
step: "finalizeRequest",
|
||||
tags: ["HTTP_SIGNING"],
|
||||
name: "httpSigningMiddleware",
|
||||
aliases: ["apiKeyMiddleware", "tokenMiddleware", "awsAuthMiddleware"],
|
||||
override: true,
|
||||
relation: "after",
|
||||
toMiddleware: "retryMiddleware",
|
||||
};
|
||||
export const getHttpSigningPlugin = (config) => ({
|
||||
applyToStack: (clientStack) => {
|
||||
clientStack.addRelativeTo(httpSigningMiddleware(config), httpSigningMiddlewareOptions);
|
||||
},
|
||||
});
|
||||
Generated
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
import { getSmithyContext } from "@smithy/core/client";
|
||||
import { HttpRequest } from "@smithy/core/protocols";
|
||||
const defaultErrorHandler = (signingProperties) => (error) => {
|
||||
throw error;
|
||||
};
|
||||
const defaultSuccessHandler = (httpResponse, signingProperties) => { };
|
||||
export const httpSigningMiddleware = (config) => (next, context) => async (args) => {
|
||||
if (!HttpRequest.isInstance(args.request)) {
|
||||
return next(args);
|
||||
}
|
||||
const smithyContext = getSmithyContext(context);
|
||||
const scheme = smithyContext.selectedHttpAuthScheme;
|
||||
if (!scheme) {
|
||||
throw new Error(`No HttpAuthScheme was selected: unable to sign request`);
|
||||
}
|
||||
const { httpAuthOption: { signingProperties = {} }, identity, signer, } = scheme;
|
||||
const output = await next({
|
||||
...args,
|
||||
request: await signer.sign(args.request, identity, signingProperties),
|
||||
}).catch((signer.errorHandler || defaultErrorHandler)(signingProperties));
|
||||
(signer.successHandler || defaultSuccessHandler)(output.response, signingProperties);
|
||||
return output;
|
||||
};
|
||||
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
export * from "./httpSigningMiddleware";
|
||||
export * from "./getHttpSigningMiddleware";
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
const makePagedClientRequest = async (CommandCtor, client, input, withCommand = (_) => _, ...args) => {
|
||||
let command = new CommandCtor(input);
|
||||
command = withCommand(command) ?? command;
|
||||
return await client.send(command, ...args);
|
||||
};
|
||||
export function createPaginator(ClientCtor, CommandCtor, inputTokenName, outputTokenName, pageSizeTokenName) {
|
||||
return async function* paginateOperation(config, input, ...additionalArguments) {
|
||||
const _input = input;
|
||||
let token = config.startingToken ?? _input[inputTokenName];
|
||||
let hasNext = true;
|
||||
let page;
|
||||
while (hasNext) {
|
||||
_input[inputTokenName] = token;
|
||||
if (pageSizeTokenName) {
|
||||
_input[pageSizeTokenName] = _input[pageSizeTokenName] ?? config.pageSize;
|
||||
}
|
||||
if (config.client instanceof ClientCtor) {
|
||||
page = await makePagedClientRequest(CommandCtor, config.client, input, config.withCommand, ...additionalArguments);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Invalid client, expected instance of ${ClientCtor.name}`);
|
||||
}
|
||||
yield page;
|
||||
const prevToken = token;
|
||||
token = get(page, outputTokenName);
|
||||
hasNext = !!(token && (!config.stopOnSameToken || token !== prevToken));
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
const get = (fromObject, path) => {
|
||||
let cursor = fromObject;
|
||||
const pathComponents = path.split(".");
|
||||
for (const step of pathComponents) {
|
||||
if (!cursor || typeof cursor !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
cursor = cursor[step];
|
||||
}
|
||||
return cursor;
|
||||
};
|
||||
Generated
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
export class DefaultIdentityProviderConfig {
|
||||
authSchemes = new Map();
|
||||
constructor(config) {
|
||||
for (const key in config) {
|
||||
const value = config[key];
|
||||
if (value !== undefined) {
|
||||
this.authSchemes.set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
getIdentityProvider(schemeId) {
|
||||
return this.authSchemes.get(schemeId);
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
import { HttpRequest } from "@smithy/core/protocols";
|
||||
import { HttpApiKeyAuthLocation, } from "@smithy/types";
|
||||
export class HttpApiKeyAuthSigner {
|
||||
async sign(httpRequest, identity, signingProperties) {
|
||||
if (!signingProperties) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `name` and `in` signer properties are missing");
|
||||
}
|
||||
if (!signingProperties.name) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `name` signer property is missing");
|
||||
}
|
||||
if (!signingProperties.in) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `in` signer property is missing");
|
||||
}
|
||||
if (!identity.apiKey) {
|
||||
throw new Error("request could not be signed with `apiKey` since the `apiKey` is not defined");
|
||||
}
|
||||
const clonedRequest = HttpRequest.clone(httpRequest);
|
||||
if (signingProperties.in === HttpApiKeyAuthLocation.QUERY) {
|
||||
clonedRequest.query[signingProperties.name] = identity.apiKey;
|
||||
}
|
||||
else if (signingProperties.in === HttpApiKeyAuthLocation.HEADER) {
|
||||
clonedRequest.headers[signingProperties.name] = signingProperties.scheme
|
||||
? `${signingProperties.scheme} ${identity.apiKey}`
|
||||
: identity.apiKey;
|
||||
}
|
||||
else {
|
||||
throw new Error("request can only be signed with `apiKey` locations `query` or `header`, " +
|
||||
"but found: `" +
|
||||
signingProperties.in +
|
||||
"`");
|
||||
}
|
||||
return clonedRequest;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
import { HttpRequest } from "@smithy/core/protocols";
|
||||
export class HttpBearerAuthSigner {
|
||||
async sign(httpRequest, identity, signingProperties) {
|
||||
const clonedRequest = HttpRequest.clone(httpRequest);
|
||||
if (!identity.token) {
|
||||
throw new Error("request could not be signed with `token` since the `token` is not defined");
|
||||
}
|
||||
clonedRequest.headers["Authorization"] = `Bearer ${identity.token}`;
|
||||
return clonedRequest;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export * from "./httpApiKeyAuth";
|
||||
export * from "./httpBearerAuth";
|
||||
export * from "./noAuth";
|
||||
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
export class NoAuthSigner {
|
||||
async sign(httpRequest, identity, signingProperties) {
|
||||
return httpRequest;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export * from "./DefaultIdentityProviderConfig";
|
||||
export * from "./httpAuthSchemes";
|
||||
export * from "./memoizeIdentityProvider";
|
||||
Generated
Vendored
+55
@@ -0,0 +1,55 @@
|
||||
export const createIsIdentityExpiredFunction = (expirationMs) => function isIdentityExpired(identity) {
|
||||
return doesIdentityRequireRefresh(identity) && identity.expiration.getTime() - Date.now() < expirationMs;
|
||||
};
|
||||
export const EXPIRATION_MS = 300_000;
|
||||
export const isIdentityExpired = createIsIdentityExpiredFunction(EXPIRATION_MS);
|
||||
export const doesIdentityRequireRefresh = (identity) => identity.expiration !== undefined;
|
||||
export const memoizeIdentityProvider = (provider, isExpired, requiresRefresh) => {
|
||||
if (provider === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const normalizedProvider = typeof provider !== "function" ? async () => Promise.resolve(provider) : provider;
|
||||
let resolved;
|
||||
let pending;
|
||||
let hasResult;
|
||||
let isConstant = false;
|
||||
const coalesceProvider = async (options) => {
|
||||
if (!pending) {
|
||||
pending = normalizedProvider(options);
|
||||
}
|
||||
try {
|
||||
resolved = await pending;
|
||||
hasResult = true;
|
||||
isConstant = false;
|
||||
}
|
||||
finally {
|
||||
pending = undefined;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
if (isExpired === undefined) {
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider(options);
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
}
|
||||
return async (options) => {
|
||||
if (!hasResult || options?.forceRefresh) {
|
||||
resolved = await coalesceProvider(options);
|
||||
}
|
||||
if (isConstant) {
|
||||
return resolved;
|
||||
}
|
||||
if (!requiresRefresh(resolved)) {
|
||||
isConstant = true;
|
||||
return resolved;
|
||||
}
|
||||
if (isExpired(resolved)) {
|
||||
await coalesceProvider(options);
|
||||
return resolved;
|
||||
}
|
||||
return resolved;
|
||||
};
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export const normalizeProvider = (input) => {
|
||||
if (typeof input === "function")
|
||||
return input;
|
||||
const promisified = Promise.resolve(input);
|
||||
return () => promisified;
|
||||
};
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
export function setFeature(context, feature, value) {
|
||||
if (!context.__smithy_context) {
|
||||
context.__smithy_context = {
|
||||
features: {},
|
||||
};
|
||||
}
|
||||
else if (!context.__smithy_context.features) {
|
||||
context.__smithy_context.features = {};
|
||||
}
|
||||
context.__smithy_context.features[feature] = value;
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
import { SerdeContext } from "@smithy/core/protocols";
|
||||
import { NormalizedSchema } from "@smithy/core/schema";
|
||||
import { NumericValue, _parseEpochTimestamp, fromBase64, generateIdempotencyToken } from "@smithy/core/serde";
|
||||
import { cbor } from "./cbor";
|
||||
import { dateToTag } from "./parseCborBody";
|
||||
export class CborCodec extends SerdeContext {
|
||||
createSerializer() {
|
||||
const serializer = new CborShapeSerializer();
|
||||
serializer.setSerdeContext(this.serdeContext);
|
||||
return serializer;
|
||||
}
|
||||
createDeserializer() {
|
||||
const deserializer = new CborShapeDeserializer();
|
||||
deserializer.setSerdeContext(this.serdeContext);
|
||||
return deserializer;
|
||||
}
|
||||
}
|
||||
export class CborShapeSerializer extends SerdeContext {
|
||||
value;
|
||||
write(schema, value) {
|
||||
this.value = this.serialize(schema, value);
|
||||
}
|
||||
serialize(schema, source) {
|
||||
const ns = NormalizedSchema.of(schema);
|
||||
if (source == null) {
|
||||
if (ns.isIdempotencyToken()) {
|
||||
return generateIdempotencyToken();
|
||||
}
|
||||
return source;
|
||||
}
|
||||
if (ns.isBlobSchema()) {
|
||||
if (typeof source === "string") {
|
||||
return (this.serdeContext?.base64Decoder ?? fromBase64)(source);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
if (ns.isTimestampSchema()) {
|
||||
if (typeof source === "number" || typeof source === "bigint") {
|
||||
return dateToTag(new Date((Number(source) / 1000) | 0));
|
||||
}
|
||||
return dateToTag(source);
|
||||
}
|
||||
if (typeof source === "function" || typeof source === "object") {
|
||||
const sourceObject = source;
|
||||
if (ns.isListSchema() && Array.isArray(sourceObject)) {
|
||||
const sparse = !!ns.getMergedTraits().sparse;
|
||||
const newArray = [];
|
||||
let i = 0;
|
||||
for (const item of sourceObject) {
|
||||
const value = this.serialize(ns.getValueSchema(), item);
|
||||
if (value != null || sparse) {
|
||||
newArray[i++] = value;
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
if (sourceObject instanceof Date) {
|
||||
return dateToTag(sourceObject);
|
||||
}
|
||||
const newObject = {};
|
||||
if (ns.isMapSchema()) {
|
||||
const sparse = !!ns.getMergedTraits().sparse;
|
||||
for (const key in sourceObject) {
|
||||
const value = this.serialize(ns.getValueSchema(), sourceObject[key]);
|
||||
if (value != null || sparse) {
|
||||
newObject[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ns.isStructSchema()) {
|
||||
for (const [key, memberSchema] of ns.structIterator()) {
|
||||
const value = this.serialize(memberSchema, sourceObject[key]);
|
||||
if (value != null) {
|
||||
newObject[key] = value;
|
||||
}
|
||||
}
|
||||
const isUnion = ns.isUnionSchema();
|
||||
if (isUnion && Array.isArray(sourceObject.$unknown)) {
|
||||
const [k, v] = sourceObject.$unknown;
|
||||
newObject[k] = v;
|
||||
}
|
||||
else if (typeof sourceObject.__type === "string") {
|
||||
for (const k in sourceObject) {
|
||||
if (!(k in newObject)) {
|
||||
newObject[k] = this.serialize(15, sourceObject[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ns.isDocumentSchema()) {
|
||||
for (const key in sourceObject) {
|
||||
newObject[key] = this.serialize(ns.getValueSchema(), sourceObject[key]);
|
||||
}
|
||||
}
|
||||
else if (ns.isBigDecimalSchema()) {
|
||||
return sourceObject;
|
||||
}
|
||||
return newObject;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
flush() {
|
||||
const buffer = cbor.serialize(this.value);
|
||||
this.value = undefined;
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
export class CborShapeDeserializer extends SerdeContext {
|
||||
read(schema, bytes) {
|
||||
const data = cbor.deserialize(bytes);
|
||||
return this.readValue(schema, data);
|
||||
}
|
||||
readValue(_schema, value) {
|
||||
const ns = NormalizedSchema.of(_schema);
|
||||
if (ns.isTimestampSchema()) {
|
||||
if (typeof value === "number") {
|
||||
return _parseEpochTimestamp(value);
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
if (value.tag === 1 && "value" in value) {
|
||||
return _parseEpochTimestamp(value.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ns.isBlobSchema()) {
|
||||
if (typeof value === "string") {
|
||||
return (this.serdeContext?.base64Decoder ?? fromBase64)(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "undefined" ||
|
||||
typeof value === "boolean" ||
|
||||
typeof value === "number" ||
|
||||
typeof value === "string" ||
|
||||
typeof value === "bigint" ||
|
||||
typeof value === "symbol") {
|
||||
return value;
|
||||
}
|
||||
else if (typeof value === "object") {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
if ("byteLength" in value) {
|
||||
return value;
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return value;
|
||||
}
|
||||
if (ns.isDocumentSchema()) {
|
||||
return value;
|
||||
}
|
||||
if (ns.isListSchema()) {
|
||||
const newArray = [];
|
||||
const memberSchema = ns.getValueSchema();
|
||||
for (const item of value) {
|
||||
const itemValue = this.readValue(memberSchema, item);
|
||||
newArray.push(itemValue);
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
const newObject = {};
|
||||
if (ns.isMapSchema()) {
|
||||
const targetSchema = ns.getValueSchema();
|
||||
for (const key in value) {
|
||||
const itemValue = this.readValue(targetSchema, value[key]);
|
||||
newObject[key] = itemValue;
|
||||
}
|
||||
}
|
||||
else if (ns.isStructSchema()) {
|
||||
const isUnion = ns.isUnionSchema();
|
||||
let keys;
|
||||
if (isUnion) {
|
||||
keys = new Set();
|
||||
for (const k in value) {
|
||||
if (k !== "__type") {
|
||||
keys.add(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [key, memberSchema] of ns.structIterator()) {
|
||||
if (isUnion) {
|
||||
keys.delete(key);
|
||||
}
|
||||
if (value[key] != null) {
|
||||
newObject[key] = this.readValue(memberSchema, value[key]);
|
||||
}
|
||||
}
|
||||
if (isUnion && keys?.size === 1) {
|
||||
let newObjectEmpty = true;
|
||||
for (const _ in newObject) {
|
||||
newObjectEmpty = false;
|
||||
break;
|
||||
}
|
||||
if (newObjectEmpty) {
|
||||
const k = keys.values().next().value;
|
||||
newObject.$unknown = [k, value[k]];
|
||||
}
|
||||
}
|
||||
else if (typeof value.__type === "string") {
|
||||
for (const k in value) {
|
||||
if (!(k in newObject)) {
|
||||
newObject[k] = value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value instanceof NumericValue) {
|
||||
return value;
|
||||
}
|
||||
return newObject;
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
import { getSmithyContext } from "@smithy/core/client";
|
||||
import { RpcProtocol } from "@smithy/core/protocols";
|
||||
import { NormalizedSchema, TypeRegistry, deref } from "@smithy/core/schema";
|
||||
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, errorTypeRegistries, }) {
|
||||
super({ defaultNamespace, errorTypeRegistries });
|
||||
}
|
||||
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";
|
||||
const errorMetadata = {
|
||||
$metadata: metadata,
|
||||
$fault: response.statusCode <= 500 ? "client" : "server",
|
||||
};
|
||||
let namespace = this.options.defaultNamespace;
|
||||
if (errorName.includes("#")) {
|
||||
[namespace] = errorName.split("#");
|
||||
}
|
||||
const registry = this.compositeErrorRegistry;
|
||||
const nsRegistry = TypeRegistry.for(namespace);
|
||||
registry.copyFrom(nsRegistry);
|
||||
let errorSchema;
|
||||
try {
|
||||
errorSchema = registry.getSchema(errorName);
|
||||
}
|
||||
catch (e) {
|
||||
if (dataObject.Message) {
|
||||
dataObject.message = dataObject.Message;
|
||||
}
|
||||
const syntheticRegistry = TypeRegistry.for("smithy.ts.sdk.synthetic." + namespace);
|
||||
registry.copyFrom(syntheticRegistry);
|
||||
const baseExceptionSchema = registry.getBaseException();
|
||||
if (baseExceptionSchema) {
|
||||
const ErrorCtor = registry.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({});
|
||||
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";
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
export function printBytes(bytes) {
|
||||
return [...bytes].map((n) => {
|
||||
const pad = (num) => ("0".repeat(8) + num.toString(2)).slice(-8);
|
||||
const b = pad(n);
|
||||
const [maj, min] = [b.slice(0, 3), b.slice(3)];
|
||||
let dmaj = "";
|
||||
switch (maj) {
|
||||
case "000":
|
||||
dmaj = "0 - Uint64";
|
||||
break;
|
||||
case "001":
|
||||
dmaj = "1 - Neg Uint64";
|
||||
break;
|
||||
case "010":
|
||||
dmaj = "2 - unstructured bytestring";
|
||||
break;
|
||||
case "011":
|
||||
dmaj = "3 - utf8 string";
|
||||
break;
|
||||
case "100":
|
||||
dmaj = "4 - list";
|
||||
break;
|
||||
case "101":
|
||||
dmaj = "5 - map";
|
||||
break;
|
||||
case "110":
|
||||
dmaj = "6 - tag";
|
||||
break;
|
||||
case "111":
|
||||
dmaj = "7 - special";
|
||||
break;
|
||||
default:
|
||||
dmaj = String(parseInt(maj, 2));
|
||||
}
|
||||
return `${maj}_${min} (${dmaj}, ${parseInt(min, 2)})`;
|
||||
});
|
||||
}
|
||||
+425
@@ -0,0 +1,425 @@
|
||||
import { nv, toUtf8 } from "@smithy/core/serde";
|
||||
import { alloc, extendedFloat16, extendedFloat32, extendedFloat64, extendedOneByte, majorList, majorMap, majorNegativeInt64, majorTag, majorUint64, majorUnstructuredByteString, majorUtf8String, minorIndefinite, specialFalse, specialNull, specialTrue, specialUndefined, tag, } from "./cbor-types";
|
||||
const USE_TEXT_DECODER = typeof TextDecoder !== "undefined";
|
||||
const USE_BUFFER = typeof Buffer !== "undefined";
|
||||
let payload = alloc(0);
|
||||
let dataView = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
||||
const textDecoder = USE_TEXT_DECODER ? new TextDecoder() : null;
|
||||
let _offset = 0;
|
||||
export function setPayload(bytes) {
|
||||
payload = bytes;
|
||||
dataView = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
||||
}
|
||||
export function decode(at, to) {
|
||||
if (at >= to) {
|
||||
throw new Error("unexpected end of (decode) payload.");
|
||||
}
|
||||
const major = (payload[at] & 0b1110_0000) >> 5;
|
||||
const minor = payload[at] & 0b0001_1111;
|
||||
switch (major) {
|
||||
case majorUint64:
|
||||
case majorNegativeInt64:
|
||||
case majorTag:
|
||||
let unsignedInt;
|
||||
let offset;
|
||||
if (minor < 24) {
|
||||
unsignedInt = minor;
|
||||
offset = 1;
|
||||
}
|
||||
else {
|
||||
switch (minor) {
|
||||
case extendedOneByte:
|
||||
case extendedFloat16:
|
||||
case extendedFloat32:
|
||||
case extendedFloat64:
|
||||
const countLength = minorValueToArgumentLength[minor];
|
||||
const countOffset = (countLength + 1);
|
||||
offset = countOffset;
|
||||
if (to - at < countOffset) {
|
||||
throw new Error(`countLength ${countLength} greater than remaining buf len.`);
|
||||
}
|
||||
const countIndex = at + 1;
|
||||
if (countLength === 1) {
|
||||
unsignedInt = payload[countIndex];
|
||||
}
|
||||
else if (countLength === 2) {
|
||||
unsignedInt = dataView.getUint16(countIndex);
|
||||
}
|
||||
else if (countLength === 4) {
|
||||
unsignedInt = dataView.getUint32(countIndex);
|
||||
}
|
||||
else {
|
||||
unsignedInt = dataView.getBigUint64(countIndex);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`unexpected minor value ${minor}.`);
|
||||
}
|
||||
}
|
||||
if (major === majorUint64) {
|
||||
_offset = offset;
|
||||
return castBigInt(unsignedInt);
|
||||
}
|
||||
else if (major === majorNegativeInt64) {
|
||||
let negativeInt;
|
||||
if (typeof unsignedInt === "bigint") {
|
||||
negativeInt = BigInt(-1) - unsignedInt;
|
||||
}
|
||||
else {
|
||||
negativeInt = -1 - unsignedInt;
|
||||
}
|
||||
_offset = offset;
|
||||
return castBigInt(negativeInt);
|
||||
}
|
||||
else {
|
||||
if (minor === 2 || minor === 3) {
|
||||
const length = decodeCount(at + offset, to);
|
||||
let b = BigInt(0);
|
||||
const start = at + offset + _offset;
|
||||
for (let i = start; i < start + length; ++i) {
|
||||
b = (b << BigInt(8)) | BigInt(payload[i]);
|
||||
}
|
||||
_offset = offset + _offset + length;
|
||||
return minor === 3 ? -b - BigInt(1) : b;
|
||||
}
|
||||
else if (minor === 4) {
|
||||
const decimalFraction = decode(at + offset, to);
|
||||
const [exponent, mantissa] = decimalFraction;
|
||||
const normalizer = mantissa < 0 ? -1 : 1;
|
||||
const mantissaStr = "0".repeat(Math.abs(exponent) + 1) + String(BigInt(normalizer) * BigInt(mantissa));
|
||||
let numericString;
|
||||
const sign = mantissa < 0 ? "-" : "";
|
||||
numericString =
|
||||
exponent === 0
|
||||
? mantissaStr
|
||||
: mantissaStr.slice(0, mantissaStr.length + exponent) + "." + mantissaStr.slice(exponent);
|
||||
numericString = numericString.replace(/^0+/g, "");
|
||||
if (numericString === "") {
|
||||
numericString = "0";
|
||||
}
|
||||
if (numericString[0] === ".") {
|
||||
numericString = "0" + numericString;
|
||||
}
|
||||
numericString = sign + numericString;
|
||||
_offset = offset + _offset;
|
||||
return nv(numericString);
|
||||
}
|
||||
else {
|
||||
const value = decode(at + offset, to);
|
||||
const valueOffset = _offset;
|
||||
_offset = offset + valueOffset;
|
||||
return tag({ tag: castBigInt(unsignedInt), value });
|
||||
}
|
||||
}
|
||||
case majorUtf8String:
|
||||
case majorMap:
|
||||
case majorList:
|
||||
case majorUnstructuredByteString:
|
||||
if (minor === minorIndefinite) {
|
||||
switch (major) {
|
||||
case majorUtf8String:
|
||||
return decodeUtf8StringIndefinite(at, to);
|
||||
case majorMap:
|
||||
return decodeMapIndefinite(at, to);
|
||||
case majorList:
|
||||
return decodeListIndefinite(at, to);
|
||||
case majorUnstructuredByteString:
|
||||
return decodeUnstructuredByteStringIndefinite(at, to);
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (major) {
|
||||
case majorUtf8String:
|
||||
return decodeUtf8String(at, to);
|
||||
case majorMap:
|
||||
return decodeMap(at, to);
|
||||
case majorList:
|
||||
return decodeList(at, to);
|
||||
case majorUnstructuredByteString:
|
||||
return decodeUnstructuredByteString(at, to);
|
||||
}
|
||||
}
|
||||
default:
|
||||
return decodeSpecial(at, to);
|
||||
}
|
||||
}
|
||||
function bytesToUtf8(bytes, at, to) {
|
||||
if (USE_BUFFER && bytes.constructor?.name === "Buffer") {
|
||||
return bytes.toString("utf-8", at, to);
|
||||
}
|
||||
if (textDecoder) {
|
||||
return textDecoder.decode(bytes.subarray(at, to));
|
||||
}
|
||||
return toUtf8(bytes.subarray(at, to));
|
||||
}
|
||||
function demote(bigInteger) {
|
||||
const num = Number(bigInteger);
|
||||
if (num < Number.MIN_SAFE_INTEGER || Number.MAX_SAFE_INTEGER < num) {
|
||||
console.warn(new Error(`@smithy/core/cbor - truncating BigInt(${bigInteger}) to ${num} with loss of precision.`));
|
||||
}
|
||||
return num;
|
||||
}
|
||||
const minorValueToArgumentLength = {
|
||||
[extendedOneByte]: 1,
|
||||
[extendedFloat16]: 2,
|
||||
[extendedFloat32]: 4,
|
||||
[extendedFloat64]: 8,
|
||||
};
|
||||
export function bytesToFloat16(a, b) {
|
||||
const sign = a >> 7;
|
||||
const exponent = (a & 0b0111_1100) >> 2;
|
||||
const fraction = ((a & 0b0000_0011) << 8) | b;
|
||||
const scalar = sign === 0 ? 1 : -1;
|
||||
let exponentComponent;
|
||||
let summation;
|
||||
if (exponent === 0b00000) {
|
||||
if (fraction === 0b00000_00000) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
exponentComponent = Math.pow(2, 1 - 15);
|
||||
summation = 0;
|
||||
}
|
||||
}
|
||||
else if (exponent === 0b11111) {
|
||||
if (fraction === 0b00000_00000) {
|
||||
return scalar * Infinity;
|
||||
}
|
||||
else {
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
exponentComponent = Math.pow(2, exponent - 15);
|
||||
summation = 1;
|
||||
}
|
||||
summation += fraction / 1024;
|
||||
return scalar * (exponentComponent * summation);
|
||||
}
|
||||
function decodeCount(at, to) {
|
||||
const minor = payload[at] & 0b0001_1111;
|
||||
if (minor < 24) {
|
||||
_offset = 1;
|
||||
return minor;
|
||||
}
|
||||
if (minor === extendedOneByte ||
|
||||
minor === extendedFloat16 ||
|
||||
minor === extendedFloat32 ||
|
||||
minor === extendedFloat64) {
|
||||
const countLength = minorValueToArgumentLength[minor];
|
||||
_offset = (countLength + 1);
|
||||
if (to - at < _offset) {
|
||||
throw new Error(`countLength ${countLength} greater than remaining buf len.`);
|
||||
}
|
||||
const countIndex = at + 1;
|
||||
if (countLength === 1) {
|
||||
return payload[countIndex];
|
||||
}
|
||||
else if (countLength === 2) {
|
||||
return dataView.getUint16(countIndex);
|
||||
}
|
||||
else if (countLength === 4) {
|
||||
return dataView.getUint32(countIndex);
|
||||
}
|
||||
return demote(dataView.getBigUint64(countIndex));
|
||||
}
|
||||
throw new Error(`unexpected minor value ${minor}.`);
|
||||
}
|
||||
function decodeUtf8String(at, to) {
|
||||
const length = decodeCount(at, to);
|
||||
const offset = _offset;
|
||||
at += offset;
|
||||
if (to - at < length) {
|
||||
throw new Error(`string len ${length} greater than remaining buf len.`);
|
||||
}
|
||||
const value = bytesToUtf8(payload, at, at + length);
|
||||
_offset = offset + length;
|
||||
return value;
|
||||
}
|
||||
function decodeUtf8StringIndefinite(at, to) {
|
||||
at += 1;
|
||||
const vector = [];
|
||||
for (const base = at; at < to;) {
|
||||
if (payload[at] === 0b1111_1111) {
|
||||
const data = alloc(vector.length);
|
||||
data.set(vector, 0);
|
||||
_offset = at - base + 2;
|
||||
return bytesToUtf8(data, 0, data.length);
|
||||
}
|
||||
const major = (payload[at] & 0b1110_0000) >> 5;
|
||||
const minor = payload[at] & 0b0001_1111;
|
||||
if (major !== majorUtf8String) {
|
||||
throw new Error(`unexpected major type ${major} in indefinite string.`);
|
||||
}
|
||||
if (minor === minorIndefinite) {
|
||||
throw new Error("nested indefinite string.");
|
||||
}
|
||||
const bytes = decodeUnstructuredByteString(at, to);
|
||||
const length = _offset;
|
||||
at += length;
|
||||
for (let i = 0; i < bytes.length; ++i) {
|
||||
vector.push(bytes[i]);
|
||||
}
|
||||
}
|
||||
throw new Error("expected break marker.");
|
||||
}
|
||||
function decodeUnstructuredByteString(at, to) {
|
||||
const length = decodeCount(at, to);
|
||||
const offset = _offset;
|
||||
at += offset;
|
||||
if (to - at < length) {
|
||||
throw new Error(`unstructured byte string len ${length} greater than remaining buf len.`);
|
||||
}
|
||||
const value = payload.subarray(at, at + length);
|
||||
_offset = offset + length;
|
||||
return value;
|
||||
}
|
||||
function decodeUnstructuredByteStringIndefinite(at, to) {
|
||||
at += 1;
|
||||
const vector = [];
|
||||
for (const base = at; at < to;) {
|
||||
if (payload[at] === 0b1111_1111) {
|
||||
const data = alloc(vector.length);
|
||||
data.set(vector, 0);
|
||||
_offset = at - base + 2;
|
||||
return data;
|
||||
}
|
||||
const major = (payload[at] & 0b1110_0000) >> 5;
|
||||
const minor = payload[at] & 0b0001_1111;
|
||||
if (major !== majorUnstructuredByteString) {
|
||||
throw new Error(`unexpected major type ${major} in indefinite string.`);
|
||||
}
|
||||
if (minor === minorIndefinite) {
|
||||
throw new Error("nested indefinite string.");
|
||||
}
|
||||
const bytes = decodeUnstructuredByteString(at, to);
|
||||
const length = _offset;
|
||||
at += length;
|
||||
for (let i = 0; i < bytes.length; ++i) {
|
||||
vector.push(bytes[i]);
|
||||
}
|
||||
}
|
||||
throw new Error("expected break marker.");
|
||||
}
|
||||
function decodeList(at, to) {
|
||||
const listDataLength = decodeCount(at, to);
|
||||
const offset = _offset;
|
||||
at += offset;
|
||||
const base = at;
|
||||
const list = Array(listDataLength);
|
||||
for (let i = 0; i < listDataLength; ++i) {
|
||||
const item = decode(at, to);
|
||||
const itemOffset = _offset;
|
||||
list[i] = item;
|
||||
at += itemOffset;
|
||||
}
|
||||
_offset = offset + (at - base);
|
||||
return list;
|
||||
}
|
||||
function decodeListIndefinite(at, to) {
|
||||
at += 1;
|
||||
const list = [];
|
||||
for (const base = at; at < to;) {
|
||||
if (payload[at] === 0b1111_1111) {
|
||||
_offset = at - base + 2;
|
||||
return list;
|
||||
}
|
||||
const item = decode(at, to);
|
||||
const n = _offset;
|
||||
at += n;
|
||||
list.push(item);
|
||||
}
|
||||
throw new Error("expected break marker.");
|
||||
}
|
||||
function decodeMap(at, to) {
|
||||
const mapDataLength = decodeCount(at, to);
|
||||
const offset = _offset;
|
||||
at += offset;
|
||||
const base = at;
|
||||
const map = {};
|
||||
for (let i = 0; i < mapDataLength; ++i) {
|
||||
if (at >= to) {
|
||||
throw new Error("unexpected end of map payload.");
|
||||
}
|
||||
const major = (payload[at] & 0b1110_0000) >> 5;
|
||||
if (major !== majorUtf8String) {
|
||||
throw new Error(`unexpected major type ${major} for map key at index ${at}.`);
|
||||
}
|
||||
const key = decode(at, to);
|
||||
at += _offset;
|
||||
const value = decode(at, to);
|
||||
at += _offset;
|
||||
map[key] = value;
|
||||
}
|
||||
_offset = offset + (at - base);
|
||||
return map;
|
||||
}
|
||||
function decodeMapIndefinite(at, to) {
|
||||
at += 1;
|
||||
const base = at;
|
||||
const map = {};
|
||||
for (; at < to;) {
|
||||
if (at >= to) {
|
||||
throw new Error("unexpected end of map payload.");
|
||||
}
|
||||
if (payload[at] === 0b1111_1111) {
|
||||
_offset = at - base + 2;
|
||||
return map;
|
||||
}
|
||||
const major = (payload[at] & 0b1110_0000) >> 5;
|
||||
if (major !== majorUtf8String) {
|
||||
throw new Error(`unexpected major type ${major} for map key.`);
|
||||
}
|
||||
const key = decode(at, to);
|
||||
at += _offset;
|
||||
const value = decode(at, to);
|
||||
at += _offset;
|
||||
map[key] = value;
|
||||
}
|
||||
throw new Error("expected break marker.");
|
||||
}
|
||||
function decodeSpecial(at, to) {
|
||||
const minor = payload[at] & 0b0001_1111;
|
||||
switch (minor) {
|
||||
case specialTrue:
|
||||
case specialFalse:
|
||||
_offset = 1;
|
||||
return minor === specialTrue;
|
||||
case specialNull:
|
||||
_offset = 1;
|
||||
return null;
|
||||
case specialUndefined:
|
||||
_offset = 1;
|
||||
return null;
|
||||
case extendedFloat16:
|
||||
if (to - at < 3) {
|
||||
throw new Error("incomplete float16 at end of buf.");
|
||||
}
|
||||
_offset = 3;
|
||||
return bytesToFloat16(payload[at + 1], payload[at + 2]);
|
||||
case extendedFloat32:
|
||||
if (to - at < 5) {
|
||||
throw new Error("incomplete float32 at end of buf.");
|
||||
}
|
||||
_offset = 5;
|
||||
return dataView.getFloat32(at + 1);
|
||||
case extendedFloat64:
|
||||
if (to - at < 9) {
|
||||
throw new Error("incomplete float64 at end of buf.");
|
||||
}
|
||||
_offset = 9;
|
||||
return dataView.getFloat64(at + 1);
|
||||
default:
|
||||
throw new Error(`unexpected minor value ${minor}.`);
|
||||
}
|
||||
}
|
||||
function castBigInt(bigInt) {
|
||||
if (typeof bigInt === "number") {
|
||||
return bigInt;
|
||||
}
|
||||
const num = Number(bigInt);
|
||||
if (Number.MIN_SAFE_INTEGER <= num && num <= Number.MAX_SAFE_INTEGER) {
|
||||
return num;
|
||||
}
|
||||
return bigInt;
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
import { NumericValue, fromUtf8 } from "@smithy/core/serde";
|
||||
import { alloc, extendedFloat16, extendedFloat32, extendedFloat64, majorList, majorMap, majorNegativeInt64, majorSpecial, majorTag, majorUint64, majorUnstructuredByteString, majorUtf8String, specialFalse, specialNull, specialTrue, tagSymbol, } from "./cbor-types";
|
||||
const USE_BUFFER = typeof Buffer !== "undefined";
|
||||
const initialSize = 2048;
|
||||
let data = alloc(initialSize);
|
||||
let dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
||||
let cursor = 0;
|
||||
function ensureSpace(bytes) {
|
||||
const remaining = data.byteLength - cursor;
|
||||
if (remaining < bytes) {
|
||||
if (cursor < 16_000_000) {
|
||||
resize(Math.max(data.byteLength * 4, data.byteLength + bytes));
|
||||
}
|
||||
else {
|
||||
resize(data.byteLength + bytes + 16_000_000);
|
||||
}
|
||||
}
|
||||
}
|
||||
export function toUint8Array() {
|
||||
const out = alloc(cursor);
|
||||
out.set(data.subarray(0, cursor), 0);
|
||||
cursor = 0;
|
||||
return out;
|
||||
}
|
||||
export function resize(size) {
|
||||
const old = data;
|
||||
data = alloc(size);
|
||||
if (old) {
|
||||
if (old.copy) {
|
||||
old.copy(data, 0, 0, old.byteLength);
|
||||
}
|
||||
else {
|
||||
data.set(old, 0);
|
||||
}
|
||||
}
|
||||
dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
||||
}
|
||||
function encodeHeader(major, value) {
|
||||
if (value < 24) {
|
||||
data[cursor++] = (major << 5) | value;
|
||||
}
|
||||
else if (value < 1 << 8) {
|
||||
data[cursor++] = (major << 5) | 24;
|
||||
data[cursor++] = value;
|
||||
}
|
||||
else if (value < 1 << 16) {
|
||||
data[cursor++] = (major << 5) | extendedFloat16;
|
||||
dataView.setUint16(cursor, value);
|
||||
cursor += 2;
|
||||
}
|
||||
else if (value < 2 ** 32) {
|
||||
data[cursor++] = (major << 5) | extendedFloat32;
|
||||
dataView.setUint32(cursor, value);
|
||||
cursor += 4;
|
||||
}
|
||||
else {
|
||||
data[cursor++] = (major << 5) | extendedFloat64;
|
||||
dataView.setBigUint64(cursor, typeof value === "bigint" ? value : BigInt(value));
|
||||
cursor += 8;
|
||||
}
|
||||
}
|
||||
export function encode(_input) {
|
||||
const encodeStack = [_input];
|
||||
while (encodeStack.length) {
|
||||
const input = encodeStack.pop();
|
||||
ensureSpace(typeof input === "string" ? input.length * 4 : 64);
|
||||
if (typeof input === "string") {
|
||||
if (USE_BUFFER) {
|
||||
encodeHeader(majorUtf8String, Buffer.byteLength(input));
|
||||
cursor += data.write(input, cursor);
|
||||
}
|
||||
else {
|
||||
const bytes = fromUtf8(input);
|
||||
encodeHeader(majorUtf8String, bytes.byteLength);
|
||||
data.set(bytes, cursor);
|
||||
cursor += bytes.byteLength;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (typeof input === "number") {
|
||||
if (Number.isInteger(input)) {
|
||||
const nonNegative = input >= 0;
|
||||
const major = nonNegative ? majorUint64 : majorNegativeInt64;
|
||||
const value = nonNegative ? input : -input - 1;
|
||||
if (value < 24) {
|
||||
data[cursor++] = (major << 5) | value;
|
||||
}
|
||||
else if (value < 256) {
|
||||
data[cursor++] = (major << 5) | 24;
|
||||
data[cursor++] = value;
|
||||
}
|
||||
else if (value < 65536) {
|
||||
data[cursor++] = (major << 5) | extendedFloat16;
|
||||
data[cursor++] = value >> 8;
|
||||
data[cursor++] = value;
|
||||
}
|
||||
else if (value < 4294967296) {
|
||||
data[cursor++] = (major << 5) | extendedFloat32;
|
||||
dataView.setUint32(cursor, value);
|
||||
cursor += 4;
|
||||
}
|
||||
else {
|
||||
data[cursor++] = (major << 5) | extendedFloat64;
|
||||
dataView.setBigUint64(cursor, BigInt(value));
|
||||
cursor += 8;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
data[cursor++] = (majorSpecial << 5) | extendedFloat64;
|
||||
dataView.setFloat64(cursor, input);
|
||||
cursor += 8;
|
||||
continue;
|
||||
}
|
||||
else if (typeof input === "bigint") {
|
||||
const nonNegative = input >= 0;
|
||||
const major = nonNegative ? majorUint64 : majorNegativeInt64;
|
||||
const value = nonNegative ? input : -input - BigInt(1);
|
||||
const n = Number(value);
|
||||
if (n < 24) {
|
||||
data[cursor++] = (major << 5) | n;
|
||||
}
|
||||
else if (n < 256) {
|
||||
data[cursor++] = (major << 5) | 24;
|
||||
data[cursor++] = n;
|
||||
}
|
||||
else if (n < 65536) {
|
||||
data[cursor++] = (major << 5) | extendedFloat16;
|
||||
data[cursor++] = n >> 8;
|
||||
data[cursor++] = n & 0b1111_1111;
|
||||
}
|
||||
else if (n < 4294967296) {
|
||||
data[cursor++] = (major << 5) | extendedFloat32;
|
||||
dataView.setUint32(cursor, n);
|
||||
cursor += 4;
|
||||
}
|
||||
else if (value < BigInt("18446744073709551616")) {
|
||||
data[cursor++] = (major << 5) | extendedFloat64;
|
||||
dataView.setBigUint64(cursor, value);
|
||||
cursor += 8;
|
||||
}
|
||||
else {
|
||||
const binaryBigInt = value.toString(2);
|
||||
const bigIntBytes = new Uint8Array(Math.ceil(binaryBigInt.length / 8));
|
||||
let b = value;
|
||||
let i = 0;
|
||||
while (bigIntBytes.byteLength - ++i >= 0) {
|
||||
bigIntBytes[bigIntBytes.byteLength - i] = Number(b & BigInt(255));
|
||||
b >>= BigInt(8);
|
||||
}
|
||||
ensureSpace(bigIntBytes.byteLength * 2);
|
||||
data[cursor++] = nonNegative ? 0b110_00010 : 0b110_00011;
|
||||
if (USE_BUFFER) {
|
||||
encodeHeader(majorUnstructuredByteString, Buffer.byteLength(bigIntBytes));
|
||||
}
|
||||
else {
|
||||
encodeHeader(majorUnstructuredByteString, bigIntBytes.byteLength);
|
||||
}
|
||||
data.set(bigIntBytes, cursor);
|
||||
cursor += bigIntBytes.byteLength;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (input === null) {
|
||||
data[cursor++] = (majorSpecial << 5) | specialNull;
|
||||
continue;
|
||||
}
|
||||
else if (typeof input === "boolean") {
|
||||
data[cursor++] = (majorSpecial << 5) | (input ? specialTrue : specialFalse);
|
||||
continue;
|
||||
}
|
||||
else if (typeof input === "undefined") {
|
||||
throw new Error("@smithy/core/cbor: client may not serialize undefined value.");
|
||||
}
|
||||
else if (Array.isArray(input)) {
|
||||
for (let i = input.length - 1; i >= 0; --i) {
|
||||
encodeStack.push(input[i]);
|
||||
}
|
||||
encodeHeader(majorList, input.length);
|
||||
continue;
|
||||
}
|
||||
else if (typeof input.byteLength === "number") {
|
||||
ensureSpace(input.length * 2);
|
||||
encodeHeader(majorUnstructuredByteString, input.length);
|
||||
data.set(input, cursor);
|
||||
cursor += input.byteLength;
|
||||
continue;
|
||||
}
|
||||
else if (typeof input === "object") {
|
||||
if (input instanceof NumericValue) {
|
||||
const decimalIndex = input.string.indexOf(".");
|
||||
const exponent = decimalIndex === -1 ? 0 : decimalIndex - input.string.length + 1;
|
||||
const mantissa = BigInt(input.string.replace(".", ""));
|
||||
data[cursor++] = 0b110_00100;
|
||||
encodeStack.push(mantissa);
|
||||
encodeStack.push(exponent);
|
||||
encodeHeader(majorList, 2);
|
||||
continue;
|
||||
}
|
||||
if (input[tagSymbol]) {
|
||||
if ("tag" in input && "value" in input) {
|
||||
encodeStack.push(input.value);
|
||||
encodeHeader(majorTag, input.tag);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
throw new Error("tag encountered with missing fields, need 'tag' and 'value', found: " + JSON.stringify(input));
|
||||
}
|
||||
}
|
||||
const keys = Object.keys(input);
|
||||
for (let i = keys.length - 1; i >= 0; --i) {
|
||||
const key = keys[i];
|
||||
encodeStack.push(input[key]);
|
||||
encodeStack.push(key);
|
||||
}
|
||||
encodeHeader(majorMap, keys.length);
|
||||
continue;
|
||||
}
|
||||
throw new Error(`data type ${input?.constructor?.name ?? typeof input} not compatible for encoding.`);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
export const majorUint64 = 0;
|
||||
export const majorNegativeInt64 = 1;
|
||||
export const majorUnstructuredByteString = 2;
|
||||
export const majorUtf8String = 3;
|
||||
export const majorList = 4;
|
||||
export const majorMap = 5;
|
||||
export const majorTag = 6;
|
||||
export const majorSpecial = 7;
|
||||
export const specialFalse = 20;
|
||||
export const specialTrue = 21;
|
||||
export const specialNull = 22;
|
||||
export const specialUndefined = 23;
|
||||
export const extendedOneByte = 24;
|
||||
export const extendedFloat16 = 25;
|
||||
export const extendedFloat32 = 26;
|
||||
export const extendedFloat64 = 27;
|
||||
export const minorIndefinite = 31;
|
||||
export function alloc(size) {
|
||||
return typeof Buffer !== "undefined" ? Buffer.alloc(size) : new Uint8Array(size);
|
||||
}
|
||||
export const tagSymbol = Symbol("@smithy/core/cbor::tagSymbol");
|
||||
export function tag(data) {
|
||||
data[tagSymbol] = true;
|
||||
return data;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { decode, setPayload } from "./cbor-decode";
|
||||
import { encode, resize, toUint8Array } from "./cbor-encode";
|
||||
export const cbor = {
|
||||
deserialize(payload) {
|
||||
setPayload(payload);
|
||||
return decode(0, payload.length);
|
||||
},
|
||||
serialize(input) {
|
||||
try {
|
||||
encode(input);
|
||||
return toUint8Array();
|
||||
}
|
||||
catch (e) {
|
||||
toUint8Array();
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
resizeEncodingBuffer(size) {
|
||||
resize(size);
|
||||
},
|
||||
};
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export { cbor } from "./cbor";
|
||||
export { tag, tagSymbol } from "./cbor-types";
|
||||
export * from "./parseCborBody";
|
||||
export * from "./SmithyRpcV2CborProtocol";
|
||||
export * from "./CborCodec";
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
import { HttpRequest as __HttpRequest, collectBody } from "@smithy/core/protocols";
|
||||
import { calculateBodyLength } from "@smithy/core/serde";
|
||||
import { cbor } from "./cbor";
|
||||
import { tag } from "./cbor-types";
|
||||
export const parseCborBody = (streamBody, context) => {
|
||||
return collectBody(streamBody, context).then(async (bytes) => {
|
||||
if (bytes.length) {
|
||||
try {
|
||||
return cbor.deserialize(bytes);
|
||||
}
|
||||
catch (e) {
|
||||
Object.defineProperty(e, "$responseBodyText", {
|
||||
value: context.utf8Encoder(bytes),
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
});
|
||||
};
|
||||
export const dateToTag = (date) => {
|
||||
return tag({
|
||||
tag: 1,
|
||||
value: date.getTime() / 1000,
|
||||
});
|
||||
};
|
||||
export const parseCborErrorBody = async (errorBody, context) => {
|
||||
const value = await parseCborBody(errorBody, context);
|
||||
value.message = value.message ?? value.Message;
|
||||
return value;
|
||||
};
|
||||
export const loadSmithyRpcV2CborErrorCode = (output, data) => {
|
||||
const sanitizeErrorCode = (rawValue) => {
|
||||
let cleanValue = rawValue;
|
||||
if (typeof cleanValue === "number") {
|
||||
cleanValue = cleanValue.toString();
|
||||
}
|
||||
if (cleanValue.indexOf(",") >= 0) {
|
||||
cleanValue = cleanValue.split(",")[0];
|
||||
}
|
||||
if (cleanValue.indexOf(":") >= 0) {
|
||||
cleanValue = cleanValue.split(":")[0];
|
||||
}
|
||||
if (cleanValue.indexOf("#") >= 0) {
|
||||
cleanValue = cleanValue.split("#")[1];
|
||||
}
|
||||
return cleanValue;
|
||||
};
|
||||
if (data["__type"] !== undefined) {
|
||||
return sanitizeErrorCode(data["__type"]);
|
||||
}
|
||||
let codeKey;
|
||||
for (const key in data) {
|
||||
if (key.toLowerCase() === "code") {
|
||||
codeKey = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (codeKey && data[codeKey] !== undefined) {
|
||||
return sanitizeErrorCode(data[codeKey]);
|
||||
}
|
||||
};
|
||||
export const checkCborResponse = (response) => {
|
||||
if (String(response.headers["smithy-protocol"]).toLowerCase() !== "rpc-v2-cbor") {
|
||||
throw new Error("Malformed RPCv2 CBOR response, status: " + response.statusCode);
|
||||
}
|
||||
};
|
||||
export const buildHttpRpcRequest = async (context, headers, path, resolvedHostname, body) => {
|
||||
const endpoint = await context.endpoint();
|
||||
const { hostname, protocol = "https", port, path: basePath } = endpoint;
|
||||
const contents = {
|
||||
protocol,
|
||||
hostname,
|
||||
port,
|
||||
method: "POST",
|
||||
path: basePath.endsWith("/") ? basePath.slice(0, -1) + path : basePath + path,
|
||||
headers: {
|
||||
...headers,
|
||||
},
|
||||
};
|
||||
if (resolvedHostname !== undefined) {
|
||||
contents.hostname = resolvedHostname;
|
||||
}
|
||||
if (endpoint.headers) {
|
||||
for (const name in endpoint.headers) {
|
||||
contents.headers[name] = endpoint.headers[name];
|
||||
}
|
||||
}
|
||||
if (body !== undefined) {
|
||||
contents.body = body;
|
||||
try {
|
||||
contents.headers["content-length"] = String(calculateBodyLength(body));
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
return new __HttpRequest(contents);
|
||||
};
|
||||
Generated
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
export async function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
||||
const size = blob.size;
|
||||
let totalBytesRead = 0;
|
||||
while (totalBytesRead < size) {
|
||||
const slice = blob.slice(totalBytesRead, Math.min(size, totalBytesRead + chunkSize));
|
||||
onChunk(new Uint8Array(await slice.arrayBuffer()));
|
||||
totalBytesRead += slice.size;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
import { fromBase64 } from "@smithy/core/serde";
|
||||
export function blobReader(blob, onChunk, chunkSize = 1024 * 1024) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onerror = reject;
|
||||
fileReader.onabort = reject;
|
||||
const size = blob.size;
|
||||
let totalBytesRead = 0;
|
||||
const read = () => {
|
||||
if (totalBytesRead >= size) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
fileReader.readAsDataURL(blob.slice(totalBytesRead, Math.min(size, totalBytesRead + chunkSize)));
|
||||
};
|
||||
fileReader.onload = (event) => {
|
||||
const result = event.target.result;
|
||||
const dataOffset = result.indexOf(",") + 1;
|
||||
const data = result.substring(dataOffset);
|
||||
const decoded = fromBase64(data);
|
||||
onChunk(decoded);
|
||||
totalBytesRead += decoded.byteLength;
|
||||
read();
|
||||
};
|
||||
read();
|
||||
});
|
||||
}
|
||||
Generated
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
import { blobReader } from "../chunked-blob-reader/chunked-blob-reader";
|
||||
export const blobHasher = async function blobHasher(hashCtor, blob) {
|
||||
const hash = new hashCtor();
|
||||
await blobReader(blob, (chunk) => {
|
||||
hash.update(chunk);
|
||||
});
|
||||
return hash.digest();
|
||||
};
|
||||
Generated
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
import { Writable } from "node:stream";
|
||||
import { toUint8Array } from "@smithy/core/serde";
|
||||
export class HashCalculator extends Writable {
|
||||
hash;
|
||||
constructor(hash, options) {
|
||||
super(options);
|
||||
this.hash = hash;
|
||||
}
|
||||
_write(chunk, encoding, callback) {
|
||||
try {
|
||||
this.hash.update(toUint8Array(chunk));
|
||||
}
|
||||
catch (err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
import { createReadStream } from "node:fs";
|
||||
import { HashCalculator } from "./HashCalculator";
|
||||
export const fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve, reject) => {
|
||||
if (!isReadStream(fileStream)) {
|
||||
reject(new Error("Unable to calculate hash for non-file streams."));
|
||||
return;
|
||||
}
|
||||
const fileStreamTee = createReadStream(fileStream.path, {
|
||||
start: fileStream.start,
|
||||
end: fileStream.end,
|
||||
});
|
||||
const hash = new hashCtor();
|
||||
const hashCalculator = new HashCalculator(hash);
|
||||
fileStreamTee.pipe(hashCalculator);
|
||||
fileStreamTee.on("error", (err) => {
|
||||
hashCalculator.end();
|
||||
reject(err);
|
||||
});
|
||||
hashCalculator.on("error", reject);
|
||||
hashCalculator.on("finish", function () {
|
||||
hash.digest().then(resolve).catch(reject);
|
||||
});
|
||||
});
|
||||
const isReadStream = (stream) => typeof stream.path === "string";
|
||||
Generated
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
import { HashCalculator } from "./HashCalculator";
|
||||
export const readableStreamHasher = (hashCtor, readableStream) => {
|
||||
if (readableStream.readableFlowing !== null) {
|
||||
throw new Error("Unable to calculate hash for flowing readable stream");
|
||||
}
|
||||
const hash = new hashCtor();
|
||||
const hashCalculator = new HashCalculator(hash);
|
||||
readableStream.pipe(hashCalculator);
|
||||
return new Promise((resolve, reject) => {
|
||||
readableStream.on("error", (err) => {
|
||||
hashCalculator.end();
|
||||
reject(err);
|
||||
});
|
||||
hashCalculator.on("error", reject);
|
||||
hashCalculator.on("finish", () => {
|
||||
hash.digest().then(resolve).catch(reject);
|
||||
});
|
||||
});
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
const no = Symbol.for("node-only");
|
||||
export { blobHasher } from "./hash-blob-browser/blobHasher";
|
||||
export const fileStreamHasher = no;
|
||||
export const readableStreamHasher = no;
|
||||
export { Md5 } from "./md5-js/md5";
|
||||
export { blobReader } from "./chunked-blob-reader/chunked-blob-reader";
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export { blobHasher } from "./hash-blob-browser/blobHasher";
|
||||
export { fileStreamHasher } from "./hash-stream-node/fileStreamHasher";
|
||||
export { readableStreamHasher } from "./hash-stream-node/readableStreamHasher";
|
||||
export { Md5 } from "./md5-js/md5";
|
||||
export { blobReader } from "./chunked-blob-reader/chunked-blob-reader";
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
const no = Symbol.for("node-only");
|
||||
export { blobHasher } from "./hash-blob-browser/blobHasher";
|
||||
export const fileStreamHasher = no;
|
||||
export const readableStreamHasher = no;
|
||||
export { Md5 } from "./md5-js/md5";
|
||||
export { blobReader } from "./chunked-blob-reader/chunked-blob-reader.native";
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export const BLOCK_SIZE = 64;
|
||||
export const DIGEST_LENGTH = 16;
|
||||
export const INIT = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
import { fromUtf8 } from "@smithy/core/serde";
|
||||
import { BLOCK_SIZE, DIGEST_LENGTH, INIT } from "./constants";
|
||||
export class Md5 {
|
||||
state;
|
||||
buffer;
|
||||
bufferLength;
|
||||
bytesHashed;
|
||||
finished;
|
||||
constructor() {
|
||||
this.reset();
|
||||
}
|
||||
update(sourceData) {
|
||||
if (isEmptyData(sourceData)) {
|
||||
return;
|
||||
}
|
||||
else if (this.finished) {
|
||||
throw new Error("Attempted to update an already finished hash.");
|
||||
}
|
||||
const data = convertToBuffer(sourceData);
|
||||
let position = 0;
|
||||
let { byteLength } = data;
|
||||
this.bytesHashed += byteLength;
|
||||
while (byteLength > 0) {
|
||||
this.buffer.setUint8(this.bufferLength++, data[position++]);
|
||||
byteLength--;
|
||||
if (this.bufferLength === BLOCK_SIZE) {
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
async digest() {
|
||||
if (!this.finished) {
|
||||
const { buffer, bufferLength: undecoratedLength, bytesHashed } = this;
|
||||
const bitsHashed = bytesHashed * 8;
|
||||
buffer.setUint8(this.bufferLength++, 0b10000000);
|
||||
if (undecoratedLength % BLOCK_SIZE >= BLOCK_SIZE - 8) {
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
this.hashBuffer();
|
||||
this.bufferLength = 0;
|
||||
}
|
||||
for (let i = this.bufferLength; i < BLOCK_SIZE - 8; i++) {
|
||||
buffer.setUint8(i, 0);
|
||||
}
|
||||
buffer.setUint32(BLOCK_SIZE - 8, bitsHashed >>> 0, true);
|
||||
buffer.setUint32(BLOCK_SIZE - 4, Math.floor(bitsHashed / 0x100000000), true);
|
||||
this.hashBuffer();
|
||||
this.finished = true;
|
||||
}
|
||||
const out = new DataView(new ArrayBuffer(DIGEST_LENGTH));
|
||||
for (let i = 0; i < 4; i++) {
|
||||
out.setUint32(i * 4, this.state[i], true);
|
||||
}
|
||||
return new Uint8Array(out.buffer, out.byteOffset, out.byteLength);
|
||||
}
|
||||
hashBuffer() {
|
||||
const { buffer, state } = this;
|
||||
let a = state[0], b = state[1], c = state[2], d = state[3];
|
||||
a = ff(a, b, c, d, buffer.getUint32(0, true), 7, 0xd76aa478);
|
||||
d = ff(d, a, b, c, buffer.getUint32(4, true), 12, 0xe8c7b756);
|
||||
c = ff(c, d, a, b, buffer.getUint32(8, true), 17, 0x242070db);
|
||||
b = ff(b, c, d, a, buffer.getUint32(12, true), 22, 0xc1bdceee);
|
||||
a = ff(a, b, c, d, buffer.getUint32(16, true), 7, 0xf57c0faf);
|
||||
d = ff(d, a, b, c, buffer.getUint32(20, true), 12, 0x4787c62a);
|
||||
c = ff(c, d, a, b, buffer.getUint32(24, true), 17, 0xa8304613);
|
||||
b = ff(b, c, d, a, buffer.getUint32(28, true), 22, 0xfd469501);
|
||||
a = ff(a, b, c, d, buffer.getUint32(32, true), 7, 0x698098d8);
|
||||
d = ff(d, a, b, c, buffer.getUint32(36, true), 12, 0x8b44f7af);
|
||||
c = ff(c, d, a, b, buffer.getUint32(40, true), 17, 0xffff5bb1);
|
||||
b = ff(b, c, d, a, buffer.getUint32(44, true), 22, 0x895cd7be);
|
||||
a = ff(a, b, c, d, buffer.getUint32(48, true), 7, 0x6b901122);
|
||||
d = ff(d, a, b, c, buffer.getUint32(52, true), 12, 0xfd987193);
|
||||
c = ff(c, d, a, b, buffer.getUint32(56, true), 17, 0xa679438e);
|
||||
b = ff(b, c, d, a, buffer.getUint32(60, true), 22, 0x49b40821);
|
||||
a = gg(a, b, c, d, buffer.getUint32(4, true), 5, 0xf61e2562);
|
||||
d = gg(d, a, b, c, buffer.getUint32(24, true), 9, 0xc040b340);
|
||||
c = gg(c, d, a, b, buffer.getUint32(44, true), 14, 0x265e5a51);
|
||||
b = gg(b, c, d, a, buffer.getUint32(0, true), 20, 0xe9b6c7aa);
|
||||
a = gg(a, b, c, d, buffer.getUint32(20, true), 5, 0xd62f105d);
|
||||
d = gg(d, a, b, c, buffer.getUint32(40, true), 9, 0x02441453);
|
||||
c = gg(c, d, a, b, buffer.getUint32(60, true), 14, 0xd8a1e681);
|
||||
b = gg(b, c, d, a, buffer.getUint32(16, true), 20, 0xe7d3fbc8);
|
||||
a = gg(a, b, c, d, buffer.getUint32(36, true), 5, 0x21e1cde6);
|
||||
d = gg(d, a, b, c, buffer.getUint32(56, true), 9, 0xc33707d6);
|
||||
c = gg(c, d, a, b, buffer.getUint32(12, true), 14, 0xf4d50d87);
|
||||
b = gg(b, c, d, a, buffer.getUint32(32, true), 20, 0x455a14ed);
|
||||
a = gg(a, b, c, d, buffer.getUint32(52, true), 5, 0xa9e3e905);
|
||||
d = gg(d, a, b, c, buffer.getUint32(8, true), 9, 0xfcefa3f8);
|
||||
c = gg(c, d, a, b, buffer.getUint32(28, true), 14, 0x676f02d9);
|
||||
b = gg(b, c, d, a, buffer.getUint32(48, true), 20, 0x8d2a4c8a);
|
||||
a = hh(a, b, c, d, buffer.getUint32(20, true), 4, 0xfffa3942);
|
||||
d = hh(d, a, b, c, buffer.getUint32(32, true), 11, 0x8771f681);
|
||||
c = hh(c, d, a, b, buffer.getUint32(44, true), 16, 0x6d9d6122);
|
||||
b = hh(b, c, d, a, buffer.getUint32(56, true), 23, 0xfde5380c);
|
||||
a = hh(a, b, c, d, buffer.getUint32(4, true), 4, 0xa4beea44);
|
||||
d = hh(d, a, b, c, buffer.getUint32(16, true), 11, 0x4bdecfa9);
|
||||
c = hh(c, d, a, b, buffer.getUint32(28, true), 16, 0xf6bb4b60);
|
||||
b = hh(b, c, d, a, buffer.getUint32(40, true), 23, 0xbebfbc70);
|
||||
a = hh(a, b, c, d, buffer.getUint32(52, true), 4, 0x289b7ec6);
|
||||
d = hh(d, a, b, c, buffer.getUint32(0, true), 11, 0xeaa127fa);
|
||||
c = hh(c, d, a, b, buffer.getUint32(12, true), 16, 0xd4ef3085);
|
||||
b = hh(b, c, d, a, buffer.getUint32(24, true), 23, 0x04881d05);
|
||||
a = hh(a, b, c, d, buffer.getUint32(36, true), 4, 0xd9d4d039);
|
||||
d = hh(d, a, b, c, buffer.getUint32(48, true), 11, 0xe6db99e5);
|
||||
c = hh(c, d, a, b, buffer.getUint32(60, true), 16, 0x1fa27cf8);
|
||||
b = hh(b, c, d, a, buffer.getUint32(8, true), 23, 0xc4ac5665);
|
||||
a = ii(a, b, c, d, buffer.getUint32(0, true), 6, 0xf4292244);
|
||||
d = ii(d, a, b, c, buffer.getUint32(28, true), 10, 0x432aff97);
|
||||
c = ii(c, d, a, b, buffer.getUint32(56, true), 15, 0xab9423a7);
|
||||
b = ii(b, c, d, a, buffer.getUint32(20, true), 21, 0xfc93a039);
|
||||
a = ii(a, b, c, d, buffer.getUint32(48, true), 6, 0x655b59c3);
|
||||
d = ii(d, a, b, c, buffer.getUint32(12, true), 10, 0x8f0ccc92);
|
||||
c = ii(c, d, a, b, buffer.getUint32(40, true), 15, 0xffeff47d);
|
||||
b = ii(b, c, d, a, buffer.getUint32(4, true), 21, 0x85845dd1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(32, true), 6, 0x6fa87e4f);
|
||||
d = ii(d, a, b, c, buffer.getUint32(60, true), 10, 0xfe2ce6e0);
|
||||
c = ii(c, d, a, b, buffer.getUint32(24, true), 15, 0xa3014314);
|
||||
b = ii(b, c, d, a, buffer.getUint32(52, true), 21, 0x4e0811a1);
|
||||
a = ii(a, b, c, d, buffer.getUint32(16, true), 6, 0xf7537e82);
|
||||
d = ii(d, a, b, c, buffer.getUint32(44, true), 10, 0xbd3af235);
|
||||
c = ii(c, d, a, b, buffer.getUint32(8, true), 15, 0x2ad7d2bb);
|
||||
b = ii(b, c, d, a, buffer.getUint32(36, true), 21, 0xeb86d391);
|
||||
state[0] = (a + state[0]) & 0xffffffff;
|
||||
state[1] = (b + state[1]) & 0xffffffff;
|
||||
state[2] = (c + state[2]) & 0xffffffff;
|
||||
state[3] = (d + state[3]) & 0xffffffff;
|
||||
}
|
||||
reset() {
|
||||
this.state = Uint32Array.from(INIT);
|
||||
this.buffer = new DataView(new ArrayBuffer(BLOCK_SIZE));
|
||||
this.bufferLength = 0;
|
||||
this.bytesHashed = 0;
|
||||
this.finished = false;
|
||||
}
|
||||
}
|
||||
function cmn(q, a, b, x, s, t) {
|
||||
a = (((a + q) & 0xffffffff) + ((x + t) & 0xffffffff)) & 0xffffffff;
|
||||
return (((a << s) | (a >>> (32 - s))) + b) & 0xffffffff;
|
||||
}
|
||||
function ff(a, b, c, d, x, s, t) {
|
||||
return cmn((b & c) | (~b & d), a, b, x, s, t);
|
||||
}
|
||||
function gg(a, b, c, d, x, s, t) {
|
||||
return cmn((b & d) | (c & ~d), a, b, x, s, t);
|
||||
}
|
||||
function hh(a, b, c, d, x, s, t) {
|
||||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||||
}
|
||||
function ii(a, b, c, d, x, s, t) {
|
||||
return cmn(c ^ (b | ~d), a, b, x, s, t);
|
||||
}
|
||||
function isEmptyData(data) {
|
||||
if (typeof data === "string") {
|
||||
return data.length === 0;
|
||||
}
|
||||
return data.byteLength === 0;
|
||||
}
|
||||
function convertToBuffer(data) {
|
||||
if (typeof data === "string") {
|
||||
return fromUtf8(data);
|
||||
}
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength / Uint8Array.BYTES_PER_ELEMENT);
|
||||
}
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
export { constructStack } from "./middleware-stack/MiddlewareStack";
|
||||
export { getSmithyContext } from "@smithy/core/transport";
|
||||
export { normalizeProvider } from "@smithy/core/transport";
|
||||
export { invalidFunction } from "./invalid-dependency/invalidFunction";
|
||||
export { invalidProvider } from "./invalid-dependency/invalidProvider";
|
||||
export { createWaiter } from "./util-waiter/createWaiter";
|
||||
export { waiterServiceDefaults, WaiterState, checkExceptions, } from "./util-waiter/waiter";
|
||||
export { Client } from "./smithy-client/client";
|
||||
export { Command } from "./smithy-client/command";
|
||||
export { SENSITIVE_STRING } from "./smithy-client/constants";
|
||||
export { createAggregatedClient } from "./smithy-client/create-aggregated-client";
|
||||
export { throwDefaultError, withBaseException } from "./smithy-client/default-error-handler";
|
||||
export { loadConfigsForDefaultMode, } from "./smithy-client/defaults-mode";
|
||||
export { emitWarningIfUnsupportedVersion } from "./smithy-client/emitWarningIfUnsupportedVersion";
|
||||
export { ServiceException, decorateServiceException, } from "./smithy-client/exceptions";
|
||||
export { getDefaultExtensionConfiguration, getDefaultClientConfiguration, resolveDefaultRuntimeConfig, } from "./smithy-client/extensions/defaultExtensionConfiguration";
|
||||
export { AlgorithmId, getChecksumConfiguration, resolveChecksumRuntimeConfig, } from "./smithy-client/extensions/checksum";
|
||||
export { getRetryConfiguration, resolveRetryRuntimeConfig, } from "./smithy-client/extensions/retry";
|
||||
export { getArrayIfSingleItem } from "./smithy-client/get-array-if-single-item";
|
||||
export { getValueFromTextNode } from "./smithy-client/get-value-from-text-node";
|
||||
export { isSerializableHeaderValue } from "./smithy-client/is-serializable-header-value";
|
||||
export { NoOpLogger } from "./smithy-client/NoOpLogger";
|
||||
export { map, convertMap, take, } from "./smithy-client/object-mapping";
|
||||
export { schemaLogFilter } from "./smithy-client/schemaLogFilter";
|
||||
export { serializeFloat, serializeDateTime } from "./smithy-client/ser-utils";
|
||||
export { _json } from "./smithy-client/serde-json";
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export const invalidFunction = (message) => () => {
|
||||
throw new Error(message);
|
||||
};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
export const invalidProvider = (message) => () => Promise.reject(message);
|
||||
Generated
Vendored
+281
@@ -0,0 +1,281 @@
|
||||
const getAllAliases = (name, aliases) => {
|
||||
const _aliases = [];
|
||||
if (name) {
|
||||
_aliases.push(name);
|
||||
}
|
||||
if (aliases) {
|
||||
for (const alias of aliases) {
|
||||
_aliases.push(alias);
|
||||
}
|
||||
}
|
||||
return _aliases;
|
||||
};
|
||||
const getMiddlewareNameWithAliases = (name, aliases) => {
|
||||
return `${name || "anonymous"}${aliases && aliases.length > 0 ? ` (a.k.a. ${aliases.join(",")})` : ""}`;
|
||||
};
|
||||
export const constructStack = () => {
|
||||
let absoluteEntries = [];
|
||||
let relativeEntries = [];
|
||||
let identifyOnResolve = false;
|
||||
const entriesNameSet = new Set();
|
||||
const sort = (entries) => entries.sort((a, b) => stepWeights[b.step] - stepWeights[a.step] ||
|
||||
priorityWeights[b.priority || "normal"] - priorityWeights[a.priority || "normal"]);
|
||||
const removeByName = (toRemove) => {
|
||||
let isRemoved = false;
|
||||
const filterCb = (entry) => {
|
||||
const aliases = getAllAliases(entry.name, entry.aliases);
|
||||
if (aliases.includes(toRemove)) {
|
||||
isRemoved = true;
|
||||
for (const alias of aliases) {
|
||||
entriesNameSet.delete(alias);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
absoluteEntries = absoluteEntries.filter(filterCb);
|
||||
relativeEntries = relativeEntries.filter(filterCb);
|
||||
return isRemoved;
|
||||
};
|
||||
const removeByReference = (toRemove) => {
|
||||
let isRemoved = false;
|
||||
const filterCb = (entry) => {
|
||||
if (entry.middleware === toRemove) {
|
||||
isRemoved = true;
|
||||
for (const alias of getAllAliases(entry.name, entry.aliases)) {
|
||||
entriesNameSet.delete(alias);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
absoluteEntries = absoluteEntries.filter(filterCb);
|
||||
relativeEntries = relativeEntries.filter(filterCb);
|
||||
return isRemoved;
|
||||
};
|
||||
const cloneTo = (toStack) => {
|
||||
absoluteEntries.forEach((entry) => {
|
||||
toStack.add(entry.middleware, { ...entry });
|
||||
});
|
||||
relativeEntries.forEach((entry) => {
|
||||
toStack.addRelativeTo(entry.middleware, { ...entry });
|
||||
});
|
||||
toStack.identifyOnResolve?.(stack.identifyOnResolve());
|
||||
return toStack;
|
||||
};
|
||||
const expandRelativeMiddlewareList = (from) => {
|
||||
const expandedMiddlewareList = [];
|
||||
from.before.forEach((entry) => {
|
||||
if (entry.before.length === 0 && entry.after.length === 0) {
|
||||
expandedMiddlewareList.push(entry);
|
||||
}
|
||||
else {
|
||||
expandedMiddlewareList.push(...expandRelativeMiddlewareList(entry));
|
||||
}
|
||||
});
|
||||
expandedMiddlewareList.push(from);
|
||||
from.after.reverse().forEach((entry) => {
|
||||
if (entry.before.length === 0 && entry.after.length === 0) {
|
||||
expandedMiddlewareList.push(entry);
|
||||
}
|
||||
else {
|
||||
expandedMiddlewareList.push(...expandRelativeMiddlewareList(entry));
|
||||
}
|
||||
});
|
||||
return expandedMiddlewareList;
|
||||
};
|
||||
const getMiddlewareList = (debug = false) => {
|
||||
const normalizedAbsoluteEntries = [];
|
||||
const normalizedRelativeEntries = [];
|
||||
const normalizedEntriesNameMap = {};
|
||||
absoluteEntries.forEach((entry) => {
|
||||
const normalizedEntry = {
|
||||
...entry,
|
||||
before: [],
|
||||
after: [],
|
||||
};
|
||||
for (const alias of getAllAliases(normalizedEntry.name, normalizedEntry.aliases)) {
|
||||
normalizedEntriesNameMap[alias] = normalizedEntry;
|
||||
}
|
||||
normalizedAbsoluteEntries.push(normalizedEntry);
|
||||
});
|
||||
relativeEntries.forEach((entry) => {
|
||||
const normalizedEntry = {
|
||||
...entry,
|
||||
before: [],
|
||||
after: [],
|
||||
};
|
||||
for (const alias of getAllAliases(normalizedEntry.name, normalizedEntry.aliases)) {
|
||||
normalizedEntriesNameMap[alias] = normalizedEntry;
|
||||
}
|
||||
normalizedRelativeEntries.push(normalizedEntry);
|
||||
});
|
||||
normalizedRelativeEntries.forEach((entry) => {
|
||||
if (entry.toMiddleware) {
|
||||
const toMiddleware = normalizedEntriesNameMap[entry.toMiddleware];
|
||||
if (toMiddleware === undefined) {
|
||||
if (debug) {
|
||||
return;
|
||||
}
|
||||
throw new Error(`${entry.toMiddleware} is not found when adding ` +
|
||||
`${getMiddlewareNameWithAliases(entry.name, entry.aliases)} ` +
|
||||
`middleware ${entry.relation} ${entry.toMiddleware}`);
|
||||
}
|
||||
if (entry.relation === "after") {
|
||||
toMiddleware.after.push(entry);
|
||||
}
|
||||
if (entry.relation === "before") {
|
||||
toMiddleware.before.push(entry);
|
||||
}
|
||||
}
|
||||
});
|
||||
const mainChain = sort(normalizedAbsoluteEntries)
|
||||
.map(expandRelativeMiddlewareList)
|
||||
.reduce((wholeList, expandedMiddlewareList) => {
|
||||
wholeList.push(...expandedMiddlewareList);
|
||||
return wholeList;
|
||||
}, []);
|
||||
return mainChain;
|
||||
};
|
||||
const stack = {
|
||||
add: (middleware, options = {}) => {
|
||||
const { name, override, aliases: _aliases } = options;
|
||||
const entry = {
|
||||
step: "initialize",
|
||||
priority: "normal",
|
||||
middleware,
|
||||
...options,
|
||||
};
|
||||
const aliases = getAllAliases(name, _aliases);
|
||||
if (aliases.length > 0) {
|
||||
if (aliases.some((alias) => entriesNameSet.has(alias))) {
|
||||
if (!override)
|
||||
throw new Error(`Duplicate middleware name '${getMiddlewareNameWithAliases(name, _aliases)}'`);
|
||||
for (const alias of aliases) {
|
||||
const toOverrideIndex = absoluteEntries.findIndex((entry) => entry.name === alias || entry.aliases?.some((a) => a === alias));
|
||||
if (toOverrideIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
const toOverride = absoluteEntries[toOverrideIndex];
|
||||
if (toOverride.step !== entry.step || entry.priority !== toOverride.priority) {
|
||||
throw new Error(`"${getMiddlewareNameWithAliases(toOverride.name, toOverride.aliases)}" middleware with ` +
|
||||
`${toOverride.priority} priority in ${toOverride.step} step cannot ` +
|
||||
`be overridden by "${getMiddlewareNameWithAliases(name, _aliases)}" middleware with ` +
|
||||
`${entry.priority} priority in ${entry.step} step.`);
|
||||
}
|
||||
absoluteEntries.splice(toOverrideIndex, 1);
|
||||
}
|
||||
}
|
||||
for (const alias of aliases) {
|
||||
entriesNameSet.add(alias);
|
||||
}
|
||||
}
|
||||
absoluteEntries.push(entry);
|
||||
},
|
||||
addRelativeTo: (middleware, options) => {
|
||||
const { name, override, aliases: _aliases } = options;
|
||||
const entry = {
|
||||
middleware,
|
||||
...options,
|
||||
};
|
||||
const aliases = getAllAliases(name, _aliases);
|
||||
if (aliases.length > 0) {
|
||||
if (aliases.some((alias) => entriesNameSet.has(alias))) {
|
||||
if (!override)
|
||||
throw new Error(`Duplicate middleware name '${getMiddlewareNameWithAliases(name, _aliases)}'`);
|
||||
for (const alias of aliases) {
|
||||
const toOverrideIndex = relativeEntries.findIndex((entry) => entry.name === alias || entry.aliases?.some((a) => a === alias));
|
||||
if (toOverrideIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
const toOverride = relativeEntries[toOverrideIndex];
|
||||
if (toOverride.toMiddleware !== entry.toMiddleware || toOverride.relation !== entry.relation) {
|
||||
throw new Error(`"${getMiddlewareNameWithAliases(toOverride.name, toOverride.aliases)}" middleware ` +
|
||||
`${toOverride.relation} "${toOverride.toMiddleware}" middleware cannot be overridden ` +
|
||||
`by "${getMiddlewareNameWithAliases(name, _aliases)}" middleware ${entry.relation} ` +
|
||||
`"${entry.toMiddleware}" middleware.`);
|
||||
}
|
||||
relativeEntries.splice(toOverrideIndex, 1);
|
||||
}
|
||||
}
|
||||
for (const alias of aliases) {
|
||||
entriesNameSet.add(alias);
|
||||
}
|
||||
}
|
||||
relativeEntries.push(entry);
|
||||
},
|
||||
clone: () => cloneTo(constructStack()),
|
||||
use: (plugin) => {
|
||||
plugin.applyToStack(stack);
|
||||
},
|
||||
remove: (toRemove) => {
|
||||
if (typeof toRemove === "string")
|
||||
return removeByName(toRemove);
|
||||
else
|
||||
return removeByReference(toRemove);
|
||||
},
|
||||
removeByTag: (toRemove) => {
|
||||
let isRemoved = false;
|
||||
const filterCb = (entry) => {
|
||||
const { tags, name, aliases: _aliases } = entry;
|
||||
if (tags && tags.includes(toRemove)) {
|
||||
const aliases = getAllAliases(name, _aliases);
|
||||
for (const alias of aliases) {
|
||||
entriesNameSet.delete(alias);
|
||||
}
|
||||
isRemoved = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
absoluteEntries = absoluteEntries.filter(filterCb);
|
||||
relativeEntries = relativeEntries.filter(filterCb);
|
||||
return isRemoved;
|
||||
},
|
||||
concat: (from) => {
|
||||
const cloned = cloneTo(constructStack());
|
||||
cloned.use(from);
|
||||
cloned.identifyOnResolve(identifyOnResolve || cloned.identifyOnResolve() || (from.identifyOnResolve?.() ?? false));
|
||||
return cloned;
|
||||
},
|
||||
applyToStack: cloneTo,
|
||||
identify: () => {
|
||||
return getMiddlewareList(true).map((mw) => {
|
||||
const step = mw.step ??
|
||||
mw.relation +
|
||||
" " +
|
||||
mw.toMiddleware;
|
||||
return getMiddlewareNameWithAliases(mw.name, mw.aliases) + " - " + step;
|
||||
});
|
||||
},
|
||||
identifyOnResolve(toggle) {
|
||||
if (typeof toggle === "boolean")
|
||||
identifyOnResolve = toggle;
|
||||
return identifyOnResolve;
|
||||
},
|
||||
resolve: (handler, context) => {
|
||||
for (const middleware of getMiddlewareList()
|
||||
.map((entry) => entry.middleware)
|
||||
.reverse()) {
|
||||
handler = middleware(handler, context);
|
||||
}
|
||||
if (identifyOnResolve) {
|
||||
console.log(stack.identify());
|
||||
}
|
||||
return handler;
|
||||
},
|
||||
};
|
||||
return stack;
|
||||
};
|
||||
const stepWeights = {
|
||||
initialize: 5,
|
||||
serialize: 4,
|
||||
build: 3,
|
||||
finalizeRequest: 2,
|
||||
deserialize: 1,
|
||||
};
|
||||
const priorityWeights = {
|
||||
high: 3,
|
||||
normal: 2,
|
||||
low: 1,
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
export class NoOpLogger {
|
||||
trace() { }
|
||||
debug() { }
|
||||
info() { }
|
||||
warn() { }
|
||||
error() { }
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
import { constructStack } from "../middleware-stack/MiddlewareStack";
|
||||
export class Client {
|
||||
config;
|
||||
middlewareStack = constructStack();
|
||||
initConfig;
|
||||
handlers;
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
const { protocol, protocolSettings } = config;
|
||||
if (protocolSettings) {
|
||||
if (typeof protocol === "function") {
|
||||
config.protocol = new protocol(protocolSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
send(command, optionsOrCb, cb) {
|
||||
const options = typeof optionsOrCb !== "function" ? optionsOrCb : undefined;
|
||||
const callback = typeof optionsOrCb === "function" ? optionsOrCb : cb;
|
||||
const useHandlerCache = options === undefined && this.config.cacheMiddleware === true;
|
||||
let handler;
|
||||
if (useHandlerCache) {
|
||||
if (!this.handlers) {
|
||||
this.handlers = new WeakMap();
|
||||
}
|
||||
const handlers = this.handlers;
|
||||
if (handlers.has(command.constructor)) {
|
||||
handler = handlers.get(command.constructor);
|
||||
}
|
||||
else {
|
||||
handler = command.resolveMiddleware(this.middlewareStack, this.config, options);
|
||||
handlers.set(command.constructor, handler);
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete this.handlers;
|
||||
handler = command.resolveMiddleware(this.middlewareStack, this.config, options);
|
||||
}
|
||||
if (callback) {
|
||||
handler(command)
|
||||
.then((result) => callback(null, result.output), (err) => callback(err))
|
||||
.catch(() => { });
|
||||
}
|
||||
else {
|
||||
return handler(command).then((result) => result.output);
|
||||
}
|
||||
}
|
||||
destroy() {
|
||||
this.config?.requestHandler?.destroy?.();
|
||||
delete this.handlers;
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
import { SMITHY_CONTEXT_KEY, } from "@smithy/types";
|
||||
import { constructStack } from "../middleware-stack/MiddlewareStack";
|
||||
import { schemaLogFilter } from "./schemaLogFilter";
|
||||
export class Command {
|
||||
middlewareStack = constructStack();
|
||||
schema;
|
||||
static classBuilder() {
|
||||
return new ClassBuilder();
|
||||
}
|
||||
resolveMiddlewareWithContext(clientStack, configuration, options, { middlewareFn, clientName, commandName, inputFilterSensitiveLog, outputFilterSensitiveLog, smithyContext, additionalContext, CommandCtor, }) {
|
||||
for (const mw of middlewareFn.bind(this)(CommandCtor, clientStack, configuration, options)) {
|
||||
this.middlewareStack.use(mw);
|
||||
}
|
||||
const stack = clientStack.concat(this.middlewareStack);
|
||||
const { logger } = configuration;
|
||||
const handlerExecutionContext = {
|
||||
logger,
|
||||
clientName,
|
||||
commandName,
|
||||
inputFilterSensitiveLog,
|
||||
outputFilterSensitiveLog,
|
||||
[SMITHY_CONTEXT_KEY]: {
|
||||
commandInstance: this,
|
||||
...smithyContext,
|
||||
},
|
||||
...additionalContext,
|
||||
};
|
||||
const { requestHandler } = configuration;
|
||||
let requestOptions = options ?? {};
|
||||
if (smithyContext.eventStream) {
|
||||
requestOptions = {
|
||||
isEventStream: true,
|
||||
...requestOptions,
|
||||
};
|
||||
}
|
||||
return stack.resolve((request) => requestHandler.handle(request.request, requestOptions), handlerExecutionContext);
|
||||
}
|
||||
}
|
||||
class ClassBuilder {
|
||||
_init = () => { };
|
||||
_ep = {};
|
||||
_middlewareFn = () => [];
|
||||
_commandName = "";
|
||||
_clientName = "";
|
||||
_additionalContext = {};
|
||||
_smithyContext = {};
|
||||
_inputFilterSensitiveLog = undefined;
|
||||
_outputFilterSensitiveLog = undefined;
|
||||
_serializer = null;
|
||||
_deserializer = null;
|
||||
_operationSchema;
|
||||
init(cb) {
|
||||
this._init = cb;
|
||||
}
|
||||
ep(endpointParameterInstructions) {
|
||||
this._ep = endpointParameterInstructions;
|
||||
return this;
|
||||
}
|
||||
m(middlewareSupplier) {
|
||||
this._middlewareFn = middlewareSupplier;
|
||||
return this;
|
||||
}
|
||||
s(service, operation, smithyContext = {}) {
|
||||
this._smithyContext = {
|
||||
service,
|
||||
operation,
|
||||
...smithyContext,
|
||||
};
|
||||
return this;
|
||||
}
|
||||
c(additionalContext = {}) {
|
||||
this._additionalContext = additionalContext;
|
||||
return this;
|
||||
}
|
||||
n(clientName, commandName) {
|
||||
this._clientName = clientName;
|
||||
this._commandName = commandName;
|
||||
return this;
|
||||
}
|
||||
f(inputFilter = (_) => _, outputFilter = (_) => _) {
|
||||
this._inputFilterSensitiveLog = inputFilter;
|
||||
this._outputFilterSensitiveLog = outputFilter;
|
||||
return this;
|
||||
}
|
||||
ser(serializer) {
|
||||
this._serializer = serializer;
|
||||
return this;
|
||||
}
|
||||
de(deserializer) {
|
||||
this._deserializer = deserializer;
|
||||
return this;
|
||||
}
|
||||
sc(operation) {
|
||||
this._operationSchema = operation;
|
||||
this._smithyContext.operationSchema = operation;
|
||||
return this;
|
||||
}
|
||||
build() {
|
||||
const closure = this;
|
||||
let CommandRef;
|
||||
return (CommandRef = class extends Command {
|
||||
input;
|
||||
static getEndpointParameterInstructions() {
|
||||
return closure._ep;
|
||||
}
|
||||
constructor(...[input]) {
|
||||
super();
|
||||
this.input = input ?? {};
|
||||
closure._init(this);
|
||||
this.schema = closure._operationSchema;
|
||||
}
|
||||
resolveMiddleware(stack, configuration, options) {
|
||||
const op = closure._operationSchema;
|
||||
const input = op?.[4] ?? op?.input;
|
||||
const output = op?.[5] ?? op?.output;
|
||||
return this.resolveMiddlewareWithContext(stack, configuration, options, {
|
||||
CommandCtor: CommandRef,
|
||||
middlewareFn: closure._middlewareFn,
|
||||
clientName: closure._clientName,
|
||||
commandName: closure._commandName,
|
||||
inputFilterSensitiveLog: closure._inputFilterSensitiveLog ?? (op ? schemaLogFilter.bind(null, input) : (_) => _),
|
||||
outputFilterSensitiveLog: closure._outputFilterSensitiveLog ?? (op ? schemaLogFilter.bind(null, output) : (_) => _),
|
||||
smithyContext: closure._smithyContext,
|
||||
additionalContext: closure._additionalContext,
|
||||
});
|
||||
}
|
||||
serialize = closure._serializer;
|
||||
deserialize = closure._deserializer;
|
||||
});
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const SENSITIVE_STRING = "***SensitiveInformation***";
|
||||
Generated
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
export const createAggregatedClient = (commands, Client, options) => {
|
||||
for (const [command, CommandCtor] of Object.entries(commands)) {
|
||||
const methodImpl = async function (args, optionsOrCb, cb) {
|
||||
const command = new CommandCtor(args);
|
||||
if (typeof optionsOrCb === "function") {
|
||||
this.send(command, optionsOrCb);
|
||||
}
|
||||
else if (typeof cb === "function") {
|
||||
if (typeof optionsOrCb !== "object")
|
||||
throw new Error(`Expected http options but got ${typeof optionsOrCb}`);
|
||||
this.send(command, optionsOrCb || {}, cb);
|
||||
}
|
||||
else {
|
||||
return this.send(command, optionsOrCb);
|
||||
}
|
||||
};
|
||||
const methodName = (command[0].toLowerCase() + command.slice(1)).replace(/Command$/, "");
|
||||
Client.prototype[methodName] = methodImpl;
|
||||
}
|
||||
const { paginators = {}, waiters = {} } = options ?? {};
|
||||
for (const [paginatorName, paginatorFn] of Object.entries(paginators)) {
|
||||
if (Client.prototype[paginatorName] === void 0) {
|
||||
Client.prototype[paginatorName] = function (commandInput = {}, paginationConfiguration, ...rest) {
|
||||
return paginatorFn({
|
||||
...paginationConfiguration,
|
||||
client: this,
|
||||
}, commandInput, ...rest);
|
||||
};
|
||||
}
|
||||
}
|
||||
for (const [waiterName, waiterFn] of Object.entries(waiters)) {
|
||||
if (Client.prototype[waiterName] === void 0) {
|
||||
Client.prototype[waiterName] = async function (commandInput = {}, waiterConfiguration, ...rest) {
|
||||
let config = waiterConfiguration;
|
||||
if (typeof waiterConfiguration === "number") {
|
||||
config = {
|
||||
maxWaitTime: waiterConfiguration,
|
||||
};
|
||||
}
|
||||
return waiterFn({
|
||||
...config,
|
||||
client: this,
|
||||
}, commandInput, ...rest);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
import { decorateServiceException } from "./exceptions";
|
||||
export const throwDefaultError = ({ output, parsedBody, exceptionCtor, errorCode }) => {
|
||||
const $metadata = deserializeMetadata(output);
|
||||
const statusCode = $metadata.httpStatusCode ? $metadata.httpStatusCode + "" : undefined;
|
||||
const response = new exceptionCtor({
|
||||
name: parsedBody?.code || parsedBody?.Code || errorCode || statusCode || "UnknownError",
|
||||
$fault: "client",
|
||||
$metadata,
|
||||
});
|
||||
throw decorateServiceException(response, parsedBody);
|
||||
};
|
||||
export const withBaseException = (ExceptionCtor) => {
|
||||
return ({ output, parsedBody, errorCode }) => {
|
||||
throwDefaultError({ output, parsedBody, exceptionCtor: ExceptionCtor, errorCode });
|
||||
};
|
||||
};
|
||||
const deserializeMetadata = (output) => ({
|
||||
httpStatusCode: output.statusCode,
|
||||
requestId: output.headers["x-amzn-requestid"] ?? output.headers["x-amzn-request-id"] ?? output.headers["x-amz-request-id"],
|
||||
extendedRequestId: output.headers["x-amz-id-2"],
|
||||
cfId: output.headers["x-amz-cf-id"],
|
||||
});
|
||||
Generated
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
export const loadConfigsForDefaultMode = (mode) => {
|
||||
switch (mode) {
|
||||
case "standard":
|
||||
return {
|
||||
retryMode: "standard",
|
||||
connectionTimeout: 3100,
|
||||
};
|
||||
case "in-region":
|
||||
return {
|
||||
retryMode: "standard",
|
||||
connectionTimeout: 1100,
|
||||
};
|
||||
case "cross-region":
|
||||
return {
|
||||
retryMode: "standard",
|
||||
connectionTimeout: 3100,
|
||||
};
|
||||
case "mobile":
|
||||
return {
|
||||
retryMode: "standard",
|
||||
connectionTimeout: 30000,
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
node_modules/@smithy/core/dist-es/submodules/client/smithy-client/emitWarningIfUnsupportedVersion.js
Generated
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
let warningEmitted = false;
|
||||
export const emitWarningIfUnsupportedVersion = (version) => {
|
||||
if (version && !warningEmitted && parseInt(version.substring(1, version.indexOf("."))) < 16) {
|
||||
warningEmitted = true;
|
||||
}
|
||||
};
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
export class ServiceException extends Error {
|
||||
$fault;
|
||||
$response;
|
||||
$retryable;
|
||||
$metadata;
|
||||
constructor(options) {
|
||||
super(options.message);
|
||||
Object.setPrototypeOf(this, Object.getPrototypeOf(this).constructor.prototype);
|
||||
this.name = options.name;
|
||||
this.$fault = options.$fault;
|
||||
this.$metadata = options.$metadata;
|
||||
}
|
||||
static isInstance(value) {
|
||||
if (!value)
|
||||
return false;
|
||||
const candidate = value;
|
||||
return (ServiceException.prototype.isPrototypeOf(candidate) ||
|
||||
(Boolean(candidate.$fault) &&
|
||||
Boolean(candidate.$metadata) &&
|
||||
(candidate.$fault === "client" || candidate.$fault === "server")));
|
||||
}
|
||||
static [Symbol.hasInstance](instance) {
|
||||
if (!instance)
|
||||
return false;
|
||||
const candidate = instance;
|
||||
if (this === ServiceException) {
|
||||
return ServiceException.isInstance(instance);
|
||||
}
|
||||
if (ServiceException.isInstance(instance)) {
|
||||
if (candidate.name && this.name) {
|
||||
return this.prototype.isPrototypeOf(instance) || candidate.name === this.name;
|
||||
}
|
||||
return this.prototype.isPrototypeOf(instance);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export const decorateServiceException = (exception, additions = {}) => {
|
||||
Object.entries(additions)
|
||||
.filter(([, v]) => v !== undefined)
|
||||
.forEach(([k, v]) => {
|
||||
if (exception[k] == undefined || exception[k] === "") {
|
||||
exception[k] = v;
|
||||
}
|
||||
});
|
||||
const message = exception.message || exception.Message || "UnknownError";
|
||||
exception.message = message;
|
||||
delete exception.Message;
|
||||
return exception;
|
||||
};
|
||||
Generated
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
import { AlgorithmId, } from "@smithy/types";
|
||||
export { AlgorithmId };
|
||||
const knownAlgorithms = Object.values(AlgorithmId);
|
||||
export const getChecksumConfiguration = (runtimeConfig) => {
|
||||
const checksumAlgorithms = [];
|
||||
for (const id in AlgorithmId) {
|
||||
const algorithmId = AlgorithmId[id];
|
||||
if (runtimeConfig[algorithmId] === undefined) {
|
||||
continue;
|
||||
}
|
||||
checksumAlgorithms.push({
|
||||
algorithmId: () => algorithmId,
|
||||
checksumConstructor: () => runtimeConfig[algorithmId],
|
||||
});
|
||||
}
|
||||
for (const [id, ChecksumCtor] of Object.entries(runtimeConfig.checksumAlgorithms ?? {})) {
|
||||
checksumAlgorithms.push({
|
||||
algorithmId: () => id,
|
||||
checksumConstructor: () => ChecksumCtor,
|
||||
});
|
||||
}
|
||||
return {
|
||||
addChecksumAlgorithm(algo) {
|
||||
runtimeConfig.checksumAlgorithms = runtimeConfig.checksumAlgorithms ?? {};
|
||||
const id = algo.algorithmId();
|
||||
const ctor = algo.checksumConstructor();
|
||||
if (knownAlgorithms.includes(id)) {
|
||||
runtimeConfig.checksumAlgorithms[id.toUpperCase()] = ctor;
|
||||
}
|
||||
else {
|
||||
runtimeConfig.checksumAlgorithms[id] = ctor;
|
||||
}
|
||||
checksumAlgorithms.push(algo);
|
||||
},
|
||||
checksumAlgorithms() {
|
||||
return checksumAlgorithms;
|
||||
},
|
||||
};
|
||||
};
|
||||
export const resolveChecksumRuntimeConfig = (clientConfig) => {
|
||||
const runtimeConfig = {};
|
||||
clientConfig.checksumAlgorithms().forEach((checksumAlgorithm) => {
|
||||
const id = checksumAlgorithm.algorithmId();
|
||||
if (knownAlgorithms.includes(id)) {
|
||||
runtimeConfig[id] = checksumAlgorithm.checksumConstructor();
|
||||
}
|
||||
});
|
||||
return runtimeConfig;
|
||||
};
|
||||
Generated
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
import { getChecksumConfiguration, resolveChecksumRuntimeConfig, } from "./checksum";
|
||||
import { getRetryConfiguration, resolveRetryRuntimeConfig } from "./retry";
|
||||
export const getDefaultExtensionConfiguration = (runtimeConfig) => {
|
||||
return Object.assign(getChecksumConfiguration(runtimeConfig), getRetryConfiguration(runtimeConfig));
|
||||
};
|
||||
export const getDefaultClientConfiguration = getDefaultExtensionConfiguration;
|
||||
export const resolveDefaultRuntimeConfig = (config) => {
|
||||
return Object.assign(resolveChecksumRuntimeConfig(config), resolveRetryRuntimeConfig(config));
|
||||
};
|
||||
Generated
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
export const getRetryConfiguration = (runtimeConfig) => {
|
||||
return {
|
||||
setRetryStrategy(retryStrategy) {
|
||||
runtimeConfig.retryStrategy = retryStrategy;
|
||||
},
|
||||
retryStrategy() {
|
||||
return runtimeConfig.retryStrategy;
|
||||
},
|
||||
};
|
||||
};
|
||||
export const resolveRetryRuntimeConfig = (retryStrategyConfiguration) => {
|
||||
const runtimeConfig = {};
|
||||
runtimeConfig.retryStrategy = retryStrategyConfiguration.retryStrategy();
|
||||
return runtimeConfig;
|
||||
};
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
export const getArrayIfSingleItem = (mayBeArray) => Array.isArray(mayBeArray) ? mayBeArray : [mayBeArray];
|
||||
Generated
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
export const getValueFromTextNode = (obj) => {
|
||||
const textNodeName = "#text";
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key) && obj[key][textNodeName] !== undefined) {
|
||||
obj[key] = obj[key][textNodeName];
|
||||
}
|
||||
else if (typeof obj[key] === "object" && obj[key] !== null) {
|
||||
obj[key] = getValueFromTextNode(obj[key]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export const isSerializableHeaderValue = (value) => {
|
||||
return value != null;
|
||||
};
|
||||
Generated
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
export function map(arg0, arg1, arg2) {
|
||||
let target;
|
||||
let filter;
|
||||
let instructions;
|
||||
if (typeof arg1 === "undefined" && typeof arg2 === "undefined") {
|
||||
target = {};
|
||||
instructions = arg0;
|
||||
}
|
||||
else {
|
||||
target = arg0;
|
||||
if (typeof arg1 === "function") {
|
||||
filter = arg1;
|
||||
instructions = arg2;
|
||||
return mapWithFilter(target, filter, instructions);
|
||||
}
|
||||
else {
|
||||
instructions = arg1;
|
||||
}
|
||||
}
|
||||
for (const key of Object.keys(instructions)) {
|
||||
if (!Array.isArray(instructions[key])) {
|
||||
target[key] = instructions[key];
|
||||
continue;
|
||||
}
|
||||
applyInstruction(target, null, instructions, key);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
export const convertMap = (target) => {
|
||||
const output = {};
|
||||
for (const [k, v] of Object.entries(target || {})) {
|
||||
output[k] = [, v];
|
||||
}
|
||||
return output;
|
||||
};
|
||||
export const take = (source, instructions) => {
|
||||
const out = {};
|
||||
for (const key in instructions) {
|
||||
applyInstruction(out, source, instructions, key);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
const mapWithFilter = (target, filter, instructions) => {
|
||||
return map(target, Object.entries(instructions).reduce((_instructions, [key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
_instructions[key] = value;
|
||||
}
|
||||
else {
|
||||
if (typeof value === "function") {
|
||||
_instructions[key] = [filter, value()];
|
||||
}
|
||||
else {
|
||||
_instructions[key] = [filter, value];
|
||||
}
|
||||
}
|
||||
return _instructions;
|
||||
}, {}));
|
||||
};
|
||||
const applyInstruction = (target, source, instructions, targetKey) => {
|
||||
if (source !== null) {
|
||||
let instruction = instructions[targetKey];
|
||||
if (typeof instruction === "function") {
|
||||
instruction = [, instruction];
|
||||
}
|
||||
const [filter = nonNullish, valueFn = pass, sourceKey = targetKey] = instruction;
|
||||
if ((typeof filter === "function" && filter(source[sourceKey])) || (typeof filter !== "function" && !!filter)) {
|
||||
target[targetKey] = valueFn(source[sourceKey]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
let [filter, value] = instructions[targetKey];
|
||||
if (typeof value === "function") {
|
||||
let _value;
|
||||
const defaultFilterPassed = filter === undefined && (_value = value()) != null;
|
||||
const customFilterPassed = (typeof filter === "function" && !!filter(void 0)) || (typeof filter !== "function" && !!filter);
|
||||
if (defaultFilterPassed) {
|
||||
target[targetKey] = _value;
|
||||
}
|
||||
else if (customFilterPassed) {
|
||||
target[targetKey] = value();
|
||||
}
|
||||
}
|
||||
else {
|
||||
const defaultFilterPassed = filter === undefined && value != null;
|
||||
const customFilterPassed = (typeof filter === "function" && !!filter(value)) || (typeof filter !== "function" && !!filter);
|
||||
if (defaultFilterPassed || customFilterPassed) {
|
||||
target[targetKey] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
const nonNullish = (_) => _ != null;
|
||||
const pass = (_) => _;
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
import { NormalizedSchema } from "@smithy/core/schema";
|
||||
const SENSITIVE_STRING = "***SensitiveInformation***";
|
||||
export function schemaLogFilter(schema, data) {
|
||||
if (data == null) {
|
||||
return data;
|
||||
}
|
||||
const ns = NormalizedSchema.of(schema);
|
||||
if (ns.getMergedTraits().sensitive) {
|
||||
return SENSITIVE_STRING;
|
||||
}
|
||||
if (ns.isListSchema()) {
|
||||
const isSensitive = !!ns.getValueSchema().getMergedTraits().sensitive;
|
||||
if (isSensitive) {
|
||||
return SENSITIVE_STRING;
|
||||
}
|
||||
}
|
||||
else if (ns.isMapSchema()) {
|
||||
const isSensitive = !!ns.getKeySchema().getMergedTraits().sensitive || !!ns.getValueSchema().getMergedTraits().sensitive;
|
||||
if (isSensitive) {
|
||||
return SENSITIVE_STRING;
|
||||
}
|
||||
}
|
||||
else if (ns.isStructSchema() && typeof data === "object") {
|
||||
const object = data;
|
||||
const newObject = {};
|
||||
for (const [member, memberNs] of ns.structIterator()) {
|
||||
if (object[member] != null) {
|
||||
newObject[member] = schemaLogFilter(memberNs, object[member]);
|
||||
}
|
||||
}
|
||||
return newObject;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
export const serializeFloat = (value) => {
|
||||
if (value !== value) {
|
||||
return "NaN";
|
||||
}
|
||||
switch (value) {
|
||||
case Infinity:
|
||||
return "Infinity";
|
||||
case -Infinity:
|
||||
return "-Infinity";
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
};
|
||||
export const serializeDateTime = (date) => date.toISOString().replace(".000Z", "Z");
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
export const _json = (obj) => {
|
||||
if (obj == null) {
|
||||
return {};
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.filter((_) => _ != null).map(_json);
|
||||
}
|
||||
if (typeof obj === "object") {
|
||||
const target = {};
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (obj[key] == null) {
|
||||
continue;
|
||||
}
|
||||
target[key] = _json(obj[key]);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
Generated
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
export const getCircularReplacer = () => {
|
||||
const seen = new WeakSet();
|
||||
return (key, value) => {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return "[Circular]";
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
import { runPolling } from "./poller";
|
||||
import { validateWaiterOptions } from "./utils/validate";
|
||||
import { WaiterState, waiterServiceDefaults } from "./waiter";
|
||||
const abortTimeout = (abortSignal) => {
|
||||
let onAbort;
|
||||
const promise = new Promise((resolve) => {
|
||||
onAbort = () => resolve({ state: WaiterState.ABORTED });
|
||||
if (typeof abortSignal.addEventListener === "function") {
|
||||
abortSignal.addEventListener("abort", onAbort);
|
||||
}
|
||||
else {
|
||||
abortSignal.onabort = onAbort;
|
||||
}
|
||||
});
|
||||
return {
|
||||
clearListener() {
|
||||
if (typeof abortSignal.removeEventListener === "function") {
|
||||
abortSignal.removeEventListener("abort", onAbort);
|
||||
}
|
||||
},
|
||||
aborted: promise,
|
||||
};
|
||||
};
|
||||
export const createWaiter = async (options, input, acceptorChecks) => {
|
||||
const params = {
|
||||
...waiterServiceDefaults,
|
||||
...options,
|
||||
};
|
||||
validateWaiterOptions(params);
|
||||
const exitConditions = [runPolling(params, input, acceptorChecks)];
|
||||
const finalize = [];
|
||||
if (options.abortSignal) {
|
||||
const { aborted, clearListener } = abortTimeout(options.abortSignal);
|
||||
finalize.push(clearListener);
|
||||
exitConditions.push(aborted);
|
||||
}
|
||||
if (options.abortController?.signal) {
|
||||
const { aborted, clearListener } = abortTimeout(options.abortController.signal);
|
||||
finalize.push(clearListener);
|
||||
exitConditions.push(aborted);
|
||||
}
|
||||
return Promise.race(exitConditions).then((result) => {
|
||||
for (const fn of finalize) {
|
||||
fn();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
};
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
import { getCircularReplacer } from "./circularReplacer";
|
||||
import { sleep } from "./utils/sleep";
|
||||
import { WaiterState } from "./waiter";
|
||||
export const runPolling = async ({ minDelay, maxDelay, maxWaitTime, abortController, client, abortSignal }, input, acceptorChecks) => {
|
||||
const observedResponses = {};
|
||||
const [minDelayMs, maxDelayMs] = [minDelay * 1000, maxDelay * 1000];
|
||||
let currentAttempt = 0;
|
||||
const waitUntil = Date.now() + maxWaitTime * 1000;
|
||||
const warn403Time = Date.now() + 60_000;
|
||||
let didWarn403 = false;
|
||||
while (true) {
|
||||
if (currentAttempt > 0) {
|
||||
const delayMs = exponentialBackoffWithJitter(minDelayMs, maxDelayMs, currentAttempt, waitUntil);
|
||||
if (abortController?.signal?.aborted || abortSignal?.aborted) {
|
||||
const message = "AbortController signal aborted.";
|
||||
observedResponses[message] |= 0;
|
||||
observedResponses[message] += 1;
|
||||
return { state: WaiterState.ABORTED, observedResponses };
|
||||
}
|
||||
if (Date.now() + delayMs > waitUntil) {
|
||||
return { state: WaiterState.TIMEOUT, observedResponses };
|
||||
}
|
||||
await sleep(delayMs / 1_000);
|
||||
}
|
||||
const { state, reason } = await acceptorChecks(client, input);
|
||||
if (reason) {
|
||||
const message = createMessageFromResponse(reason);
|
||||
observedResponses[message] |= 0;
|
||||
observedResponses[message] += 1;
|
||||
}
|
||||
if (state !== WaiterState.RETRY) {
|
||||
return { state, reason, final: reason, observedResponses };
|
||||
}
|
||||
currentAttempt += 1;
|
||||
if (!didWarn403 && Date.now() >= warn403Time) {
|
||||
checkWarn403(observedResponses, client);
|
||||
didWarn403 = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
const checkWarn403 = (observedResponses = {}, client) => {
|
||||
const orderedErrors = Object.keys(observedResponses);
|
||||
let maxCount = 0;
|
||||
let count403 = 0;
|
||||
for (const response of orderedErrors) {
|
||||
const n = observedResponses[response] | 0;
|
||||
maxCount = Math.max(n, maxCount);
|
||||
if (response.startsWith("403:")) {
|
||||
count403 += n;
|
||||
}
|
||||
}
|
||||
const clientLogger = client?.config?.logger;
|
||||
const warningLogger = typeof clientLogger?.warn === "function" && !clientLogger.constructor?.name?.includes?.("NoOpLogger")
|
||||
? clientLogger
|
||||
: console;
|
||||
if (count403 >= 3 || orderedErrors[orderedErrors.length - 1]?.startsWith("403:")) {
|
||||
warningLogger.warn(`@smithy/util-waiter WARN - 403 status code encountered during waiter polling.`);
|
||||
}
|
||||
};
|
||||
const createMessageFromResponse = (reason) => {
|
||||
const status = reason?.$response?.statusCode ?? reason?.$metadata?.httpStatusCode;
|
||||
if (reason?.$responseBodyText) {
|
||||
return `${status ? status + ": " : ""}Deserialization error for body: ${reason.$responseBodyText}`;
|
||||
}
|
||||
if (status) {
|
||||
if (reason?.$response || reason?.message) {
|
||||
return `${status ?? "Unknown"}: ${reason?.message}`;
|
||||
}
|
||||
return `${status}: OK`;
|
||||
}
|
||||
return String(reason?.message ?? JSON.stringify(reason, getCircularReplacer()) ?? "Unknown");
|
||||
};
|
||||
const exponentialBackoffWithJitter = (minDelayMs, maxDelayMs, attempt, waitUntil) => {
|
||||
const attemptCountCeiling = Math.log(maxDelayMs / minDelayMs) / Math.log(2) + 1;
|
||||
if (attempt > attemptCountCeiling) {
|
||||
return maxDelayMs;
|
||||
}
|
||||
const delay = minDelayMs * 2 ** (attempt - 1);
|
||||
const capped = Math.min(delay, maxDelayMs);
|
||||
const waitFor = randomInRange(minDelayMs, capped);
|
||||
if (Date.now() + waitFor > waitUntil) {
|
||||
const timeRemaining = waitUntil - Date.now();
|
||||
return Math.max(0, timeRemaining - 500);
|
||||
}
|
||||
return waitFor;
|
||||
};
|
||||
const randomInRange = (min, max) => min + Math.random() * (max - min);
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export const sleep = (seconds) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
|
||||
};
|
||||
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
export const validateWaiterOptions = (options) => {
|
||||
if (options.maxWaitTime <= 0) {
|
||||
throw new Error(`WaiterConfiguration.maxWaitTime must be greater than 0`);
|
||||
}
|
||||
else if (options.minDelay <= 0) {
|
||||
throw new Error(`WaiterConfiguration.minDelay must be greater than 0`);
|
||||
}
|
||||
else if (options.maxDelay <= 0) {
|
||||
throw new Error(`WaiterConfiguration.maxDelay must be greater than 0`);
|
||||
}
|
||||
else if (options.maxWaitTime <= options.minDelay) {
|
||||
throw new Error(`WaiterConfiguration.maxWaitTime [${options.maxWaitTime}] must be greater than WaiterConfiguration.minDelay [${options.minDelay}] for this waiter`);
|
||||
}
|
||||
else if (options.maxDelay < options.minDelay) {
|
||||
throw new Error(`WaiterConfiguration.maxDelay [${options.maxDelay}] must be greater than WaiterConfiguration.minDelay [${options.minDelay}] for this waiter`);
|
||||
}
|
||||
};
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { getCircularReplacer } from "./circularReplacer";
|
||||
export const waiterServiceDefaults = {
|
||||
minDelay: 2,
|
||||
maxDelay: 120,
|
||||
};
|
||||
export var WaiterState;
|
||||
(function (WaiterState) {
|
||||
WaiterState["ABORTED"] = "ABORTED";
|
||||
WaiterState["FAILURE"] = "FAILURE";
|
||||
WaiterState["SUCCESS"] = "SUCCESS";
|
||||
WaiterState["RETRY"] = "RETRY";
|
||||
WaiterState["TIMEOUT"] = "TIMEOUT";
|
||||
})(WaiterState || (WaiterState = {}));
|
||||
export const checkExceptions = (result) => {
|
||||
if (result.state === WaiterState.ABORTED) {
|
||||
const abortError = new Error(`${JSON.stringify({
|
||||
...result,
|
||||
reason: "Request was aborted",
|
||||
}, getCircularReplacer())}`);
|
||||
abortError.name = "AbortError";
|
||||
throw abortError;
|
||||
}
|
||||
else if (result.state === WaiterState.TIMEOUT) {
|
||||
const timeoutError = new Error(`${JSON.stringify({
|
||||
...result,
|
||||
reason: "Waiter has timed out",
|
||||
}, getCircularReplacer())}`);
|
||||
timeoutError.name = "TimeoutError";
|
||||
throw timeoutError;
|
||||
}
|
||||
else if (result.state !== WaiterState.SUCCESS) {
|
||||
throw new Error(`${JSON.stringify(result, getCircularReplacer())}`);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user