🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@smithy/util-endpoints

Package Overview
Dependencies
Maintainers
3
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@smithy/util-endpoints - npm Package Compare versions

Comparing version
3.3.4
to
3.4.0
+15
dist-es/bdd/BinaryDecisionDiagram.js
export 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);
}
}
import { EndpointError } from "./types";
import { evaluateCondition } from "./utils/evaluateCondition";
import { getEndpointHeaders } from "./utils/getEndpointHeaders";
import { getEndpointProperties } from "./utils/getEndpointProperties";
import { getEndpointUrl } from "./utils/getEndpointUrl";
const RESULT = 100_000_000;
export 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 [, errorMessage] = result;
throw new EndpointError(errorMessage);
}
const [url, properties, headers] = result;
return {
url: getEndpointUrl(url, closure),
properties: getEndpointProperties(properties, closure),
headers: getEndpointHeaders(headers, closure),
};
}
throw new EndpointError(`No matching endpoint.`);
};
export function coalesce(...args) {
for (const arg of args) {
if (arg != null) {
return arg;
}
}
return undefined;
}
export function ite(condition, trueValue, falseValue) {
return condition ? trueValue : falseValue;
}
export 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));
}
import type { EndpointObjectHeaders, ParameterObject } from "@smithy/types";
import type { FunctionArgv } from "../types/shared";
/**
* @internal
*/
type BddCondition = [string, FunctionArgv] | [string, FunctionArgv, string];
/**
* @internal
*/
type BddResult = [-1] | [-1, string] | [string, Record<string, ParameterObject>, EndpointObjectHeaders];
/**
* @internal
*/
export declare class BinaryDecisionDiagram {
nodes: Int32Array;
root: number;
conditions: BddCondition[];
results: BddResult[];
private constructor();
static from(bdd: Int32Array, root: number, conditions: BddCondition[] | any[], results: BddResult[] | any[]): BinaryDecisionDiagram;
}
export {};
import type { EndpointV2 } from "@smithy/types";
import type { BinaryDecisionDiagram } from "./bdd/BinaryDecisionDiagram";
import type { EndpointResolverOptions } from "./types";
/**
* Resolves an endpoint URL by processing the endpoints bdd and options.
*/
export declare const decideEndpoint: (bdd: BinaryDecisionDiagram, options: EndpointResolverOptions) => EndpointV2;
/**
* Evaluates arguments in order and returns the first non-empty result,
* otherwise returns the result of the last argument.
*
* @internal
*/
export declare function coalesce<T>(...args: (T | undefined)[]): T | undefined;
/**
* An if-then-else function that returns one of two values based on a boolean condition.
*
* @internal
*/
export declare function ite<T>(condition: boolean, trueValue: T | undefined, falseValue: T | undefined): T | undefined;
/**
* The split function divides a string into an array of substrings based on a non-empty delimiter.
* The behavior is controlled by the limit parameter:
*
* limit = 0: Split all occurrences (unlimited).
* limit = 1: No split performed (returns original string as single element array).
* limit > 1: Split into at most 'limit' parts (performs limit-1 splits).
*
* @internal
*/
export declare function split(value: string, delimiter: string, limit: number): string[];
+154
-61

@@ -5,2 +5,18 @@ 'use strict';

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 {

@@ -57,21 +73,9 @@ capacity;

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 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);
class EndpointError extends Error {
constructor(message) {
super(message);
this.name = "EndpointError";
}
const labels = value.split(".");
for (const label of labels) {
if (!isValidHostLabel(label)) {
return false;
}
}
return true;
};
}
const customEndpointFunctions = {};
const debugId = "endpoints";

@@ -92,11 +96,15 @@

class EndpointError extends Error {
constructor(message) {
super(message);
this.name = "EndpointError";
const customEndpointFunctions = {};
const booleanEquals = (value1, value2) => value1 === value2;
function coalesce(...args) {
for (const arg of args) {
if (arg != null) {
return arg;
}
}
return undefined;
}
const booleanEquals = (value1, value2) => value1 === value2;
const getAttrPathList = (path) => {

@@ -139,4 +147,25 @@ const parts = path.split(".");

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 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 = {

@@ -192,6 +221,20 @@ [types.EndpointURLScheme.HTTP]: 80,

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 (start >= stop || input.length < stop || /[^\u0000-\u007f]/.test(input)) {
if (input == null || start >= stop || input.length < stop || /[^\u0000-\u007f]/.test(input)) {
return null;

@@ -209,7 +252,10 @@ }

booleanEquals,
coalesce,
getAttr,
isSet,
isValidHostLabel,
ite,
not,
parseURL,
split,
stringEquals,

@@ -222,6 +268,3 @@ substring,

const evaluatedTemplateArr = [];
const templateContext = {
...options.endpointParams,
...options.referenceRecord,
};
const { referenceRecord, endpointParams } = options;
let currentIndex = 0;

@@ -247,6 +290,6 @@ while (currentIndex < template.length) {

const [refName, attrName] = parameterName.split("#");
evaluatedTemplateArr.push(getAttr(templateContext[refName], attrName));
evaluatedTemplateArr.push(getAttr((referenceRecord[refName] ?? endpointParams[refName]), attrName));
}
else {
evaluatedTemplateArr.push(templateContext[parameterName]);
evaluatedTemplateArr.push((referenceRecord[parameterName] ?? endpointParams[parameterName]));
}

@@ -259,7 +302,3 @@ currentIndex = closingBraceIndex + 1;

const getReferenceValue = ({ ref }, options) => {
const referenceRecord = {
...options.endpointParams,
...options.referenceRecord,
};
return referenceRecord[ref];
return options.referenceRecord[ref] ?? options.endpointParams[ref];
};

@@ -280,8 +319,23 @@

const callFunction = ({ fn, argv }, options) => {
const evaluatedArgs = argv.map((arg) => ["boolean", "number"].includes(typeof arg) ? arg : group$2.evaluateExpression(arg, "arg", options));
const fnSegments = fn.split(".");
if (fnSegments[0] in customEndpointFunctions && fnSegments[1] != null) {
return customEndpointFunctions[fnSegments[0]][fnSegments[1]](...evaluatedArgs);
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);
}
}
return endpointFunctions[fn](...evaluatedArgs);
if (fn.includes(".")) {
const fnSegments = fn.split(".");
if (fnSegments[0] in customEndpointFunctions && fnSegments[1] != null) {
return customEndpointFunctions[fnSegments[0]][fnSegments[1]](...evaluatedArgs);
}
}
if (typeof endpointFunctions[fn] !== "function") {
throw new Error(`function ${fn} not loaded in endpointFunctions.`);
}
const callable = endpointFunctions[fn];
return callable(...evaluatedArgs);
};

@@ -305,23 +359,2 @@ const group$2 = {

const evaluateConditions = (conditions = [], options) => {
const conditionsReferenceRecord = {};
for (const condition of conditions) {
const { result, toAssign } = evaluateCondition(condition, {
...options,
referenceRecord: {
...options.referenceRecord,
...conditionsReferenceRecord,
},
});
if (!result) {
return { result };
}
if (toAssign) {
conditionsReferenceRecord[toAssign.name] = toAssign.value;
options.logger?.debug?.(`${debugId} assign: ${toAssign.name} := ${toDebugString(toAssign.value)}`);
}
}
return { result: true, referenceRecord: conditionsReferenceRecord };
};
const getEndpointHeaders = (headers, options) => Object.entries(headers).reduce((acc, [headerKey, headerVal]) => ({

@@ -379,2 +412,60 @@ ...acc,

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 [, errorMessage] = result;
throw new EndpointError(errorMessage);
}
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 = {};
for (const condition of conditions) {
const { result, toAssign } = evaluateCondition(condition, {
...options,
referenceRecord: {
...options.referenceRecord,
...conditionsReferenceRecord,
},
});
if (!result) {
return { result };
}
if (toAssign) {
conditionsReferenceRecord[toAssign.name] = toAssign.value;
options.logger?.debug?.(`${debugId} assign: ${toAssign.name} := ${toDebugString(toAssign.value)}`);
}
}
return { result: true, referenceRecord: conditionsReferenceRecord };
};
const evaluateEndpointRule = (endpointRule, options) => {

@@ -479,7 +570,9 @@ const { conditions, endpoint } = endpointRule;

exports.BinaryDecisionDiagram = BinaryDecisionDiagram;
exports.EndpointCache = EndpointCache;
exports.EndpointError = EndpointError;
exports.customEndpointFunctions = customEndpointFunctions;
exports.decideEndpoint = decideEndpoint;
exports.isIpAddress = isIpAddress;
exports.isValidHostLabel = isValidHostLabel;
exports.resolveEndpoint = resolveEndpoint;

@@ -0,2 +1,4 @@

export { BinaryDecisionDiagram } from "./bdd/BinaryDecisionDiagram";
export * from "./cache/EndpointCache";
export { decideEndpoint } from "./decideEndpoint";
export * from "./lib/isIpAddress";

@@ -3,0 +5,0 @@ export * from "./lib/isValidHostLabel";

export * from "./booleanEquals";
export * from "./coalesce";
export * from "./getAttr";
export * from "./isSet";
export * from "./isValidHostLabel";
export * from "./ite";
export * from "./not";
export * from "./parseURL";
export * from "./split";
export * from "./stringEquals";
export * from "./substring";
export * from "./uriEncode";
export const substring = (input, start, stop, reverse) => {
if (start >= stop || input.length < stop || /[^\u0000-\u007f]/.test(input)) {
if (input == null || start >= stop || input.length < stop || /[^\u0000-\u007f]/.test(input)) {
return null;

@@ -4,0 +4,0 @@ }

@@ -1,9 +0,12 @@

import { booleanEquals, getAttr, isSet, isValidHostLabel, not, parseURL, stringEquals, substring, uriEncode, } from "../lib";
import { booleanEquals, coalesce, getAttr, isSet, isValidHostLabel, ite, not, parseURL, split, stringEquals, substring, uriEncode, } from "../lib";
export const endpointFunctions = {
booleanEquals,
coalesce,
getAttr,
isSet,
isValidHostLabel,
ite,
not,
parseURL,
split,
stringEquals,

@@ -10,0 +13,0 @@ substring,

@@ -19,8 +19,23 @@ import { EndpointError } from "../types";

export const callFunction = ({ fn, argv }, options) => {
const evaluatedArgs = argv.map((arg) => ["boolean", "number"].includes(typeof arg) ? arg : group.evaluateExpression(arg, "arg", options));
const fnSegments = fn.split(".");
if (fnSegments[0] in customEndpointFunctions && fnSegments[1] != null) {
return customEndpointFunctions[fnSegments[0]][fnSegments[1]](...evaluatedArgs);
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.evaluateExpression(arg, "arg", options);
}
}
return endpointFunctions[fn](...evaluatedArgs);
if (fn.includes(".")) {
const fnSegments = fn.split(".");
if (fnSegments[0] in customEndpointFunctions && fnSegments[1] != null) {
return customEndpointFunctions[fnSegments[0]][fnSegments[1]](...evaluatedArgs);
}
}
if (typeof endpointFunctions[fn] !== "function") {
throw new Error(`function ${fn} not loaded in endpointFunctions.`);
}
const callable = endpointFunctions[fn];
return callable(...evaluatedArgs);
};

@@ -27,0 +42,0 @@ export const group = {

import { getAttr } from "../lib";
export const evaluateTemplate = (template, options) => {
const evaluatedTemplateArr = [];
const templateContext = {
...options.endpointParams,
...options.referenceRecord,
};
const { referenceRecord, endpointParams } = options;
let currentIndex = 0;

@@ -28,6 +25,6 @@ while (currentIndex < template.length) {

const [refName, attrName] = parameterName.split("#");
evaluatedTemplateArr.push(getAttr(templateContext[refName], attrName));
evaluatedTemplateArr.push(getAttr((referenceRecord[refName] ?? endpointParams[refName]), attrName));
}
else {
evaluatedTemplateArr.push(templateContext[parameterName]);
evaluatedTemplateArr.push((referenceRecord[parameterName] ?? endpointParams[parameterName]));
}

@@ -34,0 +31,0 @@ currentIndex = closingBraceIndex + 1;

export const getReferenceValue = ({ ref }, options) => {
const referenceRecord = {
...options.endpointParams,
...options.referenceRecord,
};
return referenceRecord[ref];
return options.referenceRecord[ref] ?? options.endpointParams[ref];
};

@@ -0,2 +1,4 @@

export { BinaryDecisionDiagram } from "./bdd/BinaryDecisionDiagram";
export * from "./cache/EndpointCache";
export { decideEndpoint } from "./decideEndpoint";
export * from "./lib/isIpAddress";

@@ -3,0 +5,0 @@ export * from "./lib/isValidHostLabel";

export * from "./booleanEquals";
export * from "./coalesce";
export * from "./getAttr";
export * from "./isSet";
export * from "./isValidHostLabel";
export * from "./ite";
export * from "./not";
export * from "./parseURL";
export * from "./split";
export * from "./stringEquals";
export * from "./substring";
export * from "./uriEncode";

@@ -0,8 +1,12 @@

import { coalesce, ite, split } from "../lib";
export declare const endpointFunctions: {
booleanEquals: (value1: boolean, value2: boolean) => boolean;
coalesce: typeof coalesce;
getAttr: (value: import("../lib").GetAttrValue, path: string) => import("../lib").GetAttrValue;
isSet: (value: unknown) => value is {};
isValidHostLabel: (value: string, allowSubDomains?: boolean) => boolean;
ite: typeof ite;
not: (value: boolean) => boolean;
parseURL: (value: string | URL | import("@smithy/types").Endpoint) => import("@smithy/types").EndpointURL | null;
split: typeof split;
stringEquals: (value1: string, value2: string) => boolean;

@@ -9,0 +13,0 @@ substring: (input: string, start: number, stop: number, reverse: boolean) => string | null;

import type { EvaluateOptions, ReferenceObject } from "../types";
export declare const getReferenceValue: ({ ref }: ReferenceObject, options: EvaluateOptions) => import("../types").FunctionReturn;
export declare const getReferenceValue: ({ ref }: ReferenceObject, options: EvaluateOptions) => string | number | boolean | import("@smithy/types").EndpointPartition | import("@smithy/types").EndpointARN | {
[key: string]: import("../types").FunctionReturn;
};
{
"name": "@smithy/util-endpoints",
"version": "3.3.4",
"version": "3.4.0",
"description": "Utilities to help with endpoint resolution.",

@@ -5,0 +5,0 @@ "main": "./dist-cjs/index.js",