UEA-Prodem

This commit is contained in:
2026-06-10 12:38:42 -03:00
parent 3f33154e16
commit c41625e542
9352 changed files with 1128292 additions and 14752 deletions
File diff suppressed because it is too large Load Diff
+202
View File
@@ -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
View File
@@ -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
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+375
View File
@@ -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
View File
@@ -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
View File
@@ -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;
@@ -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
View File
@@ -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;
@@ -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
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+817
View File
@@ -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
View File
@@ -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
View File
@@ -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;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+184
View File
@@ -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;