@azure/cosmos
Version:
Microsoft Azure Cosmos DB Service Node.js SDK for NOSQL API
416 lines (415 loc) • 15.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var helper_exports = {};
__export(helper_exports, {
canApplyExcludedLocations: () => canApplyExcludedLocations,
copyObject: () => copyObject,
createDeserializer: () => createDeserializer,
createSerializer: () => createSerializer,
extractPath: () => extractPath,
getContainerLink: () => getContainerLink,
getHexaDigit: () => getHexaDigit,
getIdFromLink: () => getIdFromLink,
getPathFromLink: () => getPathFromLink,
getResourceIdFromPath: () => getResourceIdFromPath,
isItemResourceValid: () => isItemResourceValid,
isReadRequest: () => isReadRequest,
isResourceValid: () => isResourceValid,
isStringNullOrEmpty: () => isStringNullOrEmpty,
jsonStringifyAndEscapeNonASCII: () => jsonStringifyAndEscapeNonASCII,
parseConnectionString: () => parseConnectionString,
parseLink: () => parseLink,
parsePath: () => parsePath,
prepareURL: () => prepareURL,
sleep: () => sleep,
trimSlashFromLeftAndRight: () => trimSlashFromLeftAndRight,
trimSlashes: () => trimSlashes,
validateClientEncryptionPolicy: () => validateClientEncryptionPolicy,
validateItemResourceId: () => validateItemResourceId,
validateResourceId: () => validateResourceId
});
module.exports = __toCommonJS(helper_exports);
var import_Serializers = require("../encryption/Serializers/index.js");
var import_EncryptionType = require("../encryption/enums/EncryptionType.js");
var import_TypeMarker = require("../encryption/enums/TypeMarker.js");
var import_ErrorResponse = require("../request/ErrorResponse.js");
var import_constants = require("./constants.js");
const trimLeftSlashes = new RegExp("^[/]+");
const trimRightSlashes = new RegExp("[/]+$");
const illegalResourceIdCharacters = new RegExp("[/\\\\?#]");
const illegalItemResourceIdCharacters = new RegExp("[/\\\\#]");
function jsonStringifyAndEscapeNonASCII(arg) {
return JSON.stringify(arg).replace(/[\u007F-\uFFFF]/g, (m) => {
return "\\u" + ("0000" + m.charCodeAt(0).toString(16)).slice(-4);
});
}
function parseLink(resourcePath) {
if (resourcePath.length === 0) {
return {
type: void 0,
objectBody: void 0
};
}
if (resourcePath[resourcePath.length - 1] !== "/") {
resourcePath = resourcePath + "/";
}
if (resourcePath[0] !== "/") {
resourcePath = "/" + resourcePath;
}
const pathParts = resourcePath.split("/");
let id;
let type;
if (pathParts.length % 2 === 0) {
id = pathParts[pathParts.length - 2];
type = pathParts[pathParts.length - 3];
} else {
id = pathParts[pathParts.length - 3];
type = pathParts[pathParts.length - 2];
}
const result = {
type,
objectBody: {
id,
self: resourcePath
}
};
return result;
}
function isReadRequest(operationType) {
return operationType === import_constants.OperationType.Read || operationType === import_constants.OperationType.Query;
}
function sleep(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time);
});
}
function getContainerLink(link) {
return link.split("/").slice(0, 4).join("/");
}
function prepareURL(endpoint, path) {
return trimSlashes(endpoint) + path;
}
function trimSlashes(source) {
return source.replace(trimLeftSlashes, "").replace(trimRightSlashes, "");
}
function getHexaDigit() {
return Math.floor(Math.random() * 16).toString(16);
}
function parsePath(path) {
const pathParts = [];
let currentIndex = 0;
const throwError = () => {
throw new Error("Path " + path + " is invalid at index " + currentIndex);
};
const getEscapedToken = () => {
const quote = path[currentIndex];
let newIndex = ++currentIndex;
for (; ; ) {
newIndex = path.indexOf(quote, newIndex);
if (newIndex === -1) {
throwError();
}
if (path[newIndex - 1] !== "\\") {
break;
}
++newIndex;
}
const token = path.substr(currentIndex, newIndex - currentIndex);
currentIndex = newIndex + 1;
return token;
};
const getToken = () => {
const newIndex = path.indexOf("/", currentIndex);
let token = null;
if (newIndex === -1) {
token = path.substr(currentIndex);
currentIndex = path.length;
} else {
token = path.substr(currentIndex, newIndex - currentIndex);
currentIndex = newIndex;
}
token = token.trim();
return token;
};
while (currentIndex < path.length) {
if (path[currentIndex] !== "/") {
throwError();
}
if (++currentIndex === path.length) {
break;
}
if (path[currentIndex] === '"' || path[currentIndex] === "'") {
pathParts.push(getEscapedToken());
} else {
pathParts.push(getToken());
}
}
return pathParts;
}
function isResourceValid(resource, err) {
if (resource.id) {
if (typeof resource.id !== "string") {
err.message = "Id must be a string.";
return false;
}
if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1 || resource.id.indexOf("?") !== -1 || resource.id.indexOf("#") !== -1) {
err.message = "Id contains illegal chars.";
return false;
}
if (resource.id[resource.id.length - 1] === " ") {
err.message = "Id ends with a space.";
return false;
}
}
return true;
}
function isItemResourceValid(resource, err) {
if (resource.id) {
if (typeof resource.id !== "string") {
err.message = "Id must be a string.";
return false;
}
if (resource.id.indexOf("/") !== -1 || resource.id.indexOf("\\") !== -1 || resource.id.indexOf("#") !== -1) {
err.message = "Id contains illegal chars.";
return false;
}
}
return true;
}
function getIdFromLink(resourceLink) {
resourceLink = trimSlashes(resourceLink);
return resourceLink;
}
function getPathFromLink(resourceLink, resourceType) {
resourceLink = trimSlashes(resourceLink);
if (resourceType) {
return "/" + encodeURI(resourceLink) + "/" + resourceType;
} else {
return "/" + encodeURI(resourceLink);
}
}
function isStringNullOrEmpty(inputString) {
return !inputString || /^\s*$/.test(inputString);
}
function trimSlashFromLeftAndRight(inputString) {
if (typeof inputString !== "string") {
throw new Error("invalid input: input is not string");
}
return inputString.replace(trimLeftSlashes, "").replace(trimRightSlashes, "");
}
function validateResourceId(resourceId) {
if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) {
throw new Error("Resource ID must be a string and cannot be undefined, null or empty");
}
if (illegalResourceIdCharacters.test(resourceId)) {
throw new Error("Illegal characters ['/', '\\', '#', '?'] cannot be used in Resource ID");
}
return true;
}
function validateItemResourceId(resourceId) {
if (typeof resourceId !== "string" || isStringNullOrEmpty(resourceId)) {
throw new Error("Resource ID must be a string and cannot be undefined, null or empty");
}
if (illegalItemResourceIdCharacters.test(resourceId)) {
throw new Error("Illegal characters ['/', '\\', '#'] cannot be used in Resource ID");
}
return true;
}
function getResourceIdFromPath(resourcePath) {
if (!resourcePath || typeof resourcePath !== "string") {
return null;
}
const trimmedPath = trimSlashFromLeftAndRight(resourcePath);
const pathSegments = trimmedPath.split("/");
if (pathSegments.length % 2 !== 0) {
return null;
}
return pathSegments[pathSegments.length - 1];
}
function parseConnectionString(connectionString) {
const keyValueStrings = connectionString.split(";");
const { AccountEndpoint, AccountKey } = keyValueStrings.reduce(
(connectionObject, keyValueString) => {
const [key, ...value] = keyValueString.split("=");
connectionObject[key] = value.join("=");
return connectionObject;
},
{}
);
if (!AccountEndpoint || !AccountKey) {
throw new Error("Could not parse the provided connection string");
}
return {
endpoint: AccountEndpoint,
key: AccountKey
};
}
function copyObject(obj) {
return JSON.parse(
JSON.stringify(obj, (_, value) => {
if (typeof value === "bigint") {
throw new Error(`BigInt type is not supported`);
}
return value;
})
);
}
function createDeserializer(typeMarker) {
switch (typeMarker) {
case import_TypeMarker.TypeMarker.Long: {
return new import_Serializers.NumberSerializer();
}
case import_TypeMarker.TypeMarker.Double:
return new import_Serializers.FloatSerializer();
case import_TypeMarker.TypeMarker.String:
return new import_Serializers.StringSerializer();
case import_TypeMarker.TypeMarker.Boolean:
return new import_Serializers.BooleanSerializer();
default:
throw new Error("Invalid or Unsupported data type passed.");
}
}
function extractPath(path) {
const secondSlashIndex = path.indexOf("/", path.indexOf("/") + 1);
return secondSlashIndex === -1 ? path : path.substring(0, secondSlashIndex);
}
function createSerializer(propertyValue, type) {
if (type) {
if (type === import_TypeMarker.TypeMarker.Long) {
return [import_TypeMarker.TypeMarker.Long, new import_Serializers.NumberSerializer()];
} else if (type === import_TypeMarker.TypeMarker.Double) {
return [import_TypeMarker.TypeMarker.Double, new import_Serializers.FloatSerializer()];
} else if (type === import_TypeMarker.TypeMarker.String) {
return [import_TypeMarker.TypeMarker.String, new import_Serializers.StringSerializer()];
} else if (type === import_TypeMarker.TypeMarker.Boolean) {
return [import_TypeMarker.TypeMarker.Boolean, new import_Serializers.BooleanSerializer()];
} else {
throw new Error("Invalid or Unsupported data type passed.");
}
} else {
switch (typeof propertyValue) {
case "boolean":
return [import_TypeMarker.TypeMarker.Boolean, new import_Serializers.BooleanSerializer()];
case "string":
return [import_TypeMarker.TypeMarker.String, new import_Serializers.StringSerializer()];
case "object":
if (propertyValue.constructor === Date) {
return [import_TypeMarker.TypeMarker.String, new import_Serializers.StringSerializer()];
}
throw new Error("Invalid or Unsupported data type passed.");
case "number":
if (!Number.isInteger(propertyValue)) {
return [import_TypeMarker.TypeMarker.Double, new import_Serializers.FloatSerializer()];
} else {
return [import_TypeMarker.TypeMarker.Long, new import_Serializers.NumberSerializer()];
}
default:
throw new Error("Invalid or Unsupported data type passed.");
}
}
}
function validateClientEncryptionPolicy(clientEncryptionPolicy, partitionKey) {
const policyFormatVersion = clientEncryptionPolicy.policyFormatVersion;
if (policyFormatVersion < 1 || policyFormatVersion > 2) {
throw new import_ErrorResponse.ErrorResponse("Supported versions of client encryption policy are 1 and 2.");
}
const paths = /* @__PURE__ */ new Set();
for (const includedPath of clientEncryptionPolicy.includedPaths) {
if (paths.has(includedPath.path)) {
throw new import_ErrorResponse.ErrorResponse(
`Duplicate path found: ${includedPath.path} in client encryption policy.`
);
}
if (includedPath.path === void 0 || includedPath.path === null || includedPath.path === "" || includedPath.path === "/") {
throw new import_ErrorResponse.ErrorResponse("Path needs to be defined in ClientEncryptionIncludedPath.");
}
if (includedPath.clientEncryptionKeyId === void 0 || includedPath.clientEncryptionKeyId === null || includedPath.clientEncryptionKeyId === "" || typeof includedPath.clientEncryptionKeyId !== "string") {
throw new import_ErrorResponse.ErrorResponse(
"ClientEncryptionKeyId needs to be defined as string type in ClientEncryptionIncludedPath."
);
}
if (includedPath.path[0] !== "/") {
throw new import_ErrorResponse.ErrorResponse("Path in ClientEncryptionIncludedPath must start with '/'.");
}
const pathSegments = includedPath.path.split("/").filter((segment) => segment.length > 0);
if (pathSegments.length > 1) {
throw new import_ErrorResponse.ErrorResponse("Only top-level paths are currently supported for encryption");
}
paths.add(includedPath.path);
}
const encryptedPaths = clientEncryptionPolicy.includedPaths;
const partitionKeyPaths = partitionKey.paths.map(extractPath);
let isPartitionKeyEncrypted = false;
let isIdEncrypted = false;
for (const encryptedPath of encryptedPaths) {
if (encryptedPath.path === "/id") {
isIdEncrypted = true;
if (encryptedPath.encryptionType !== import_EncryptionType.EncryptionType.DETERMINISTIC) {
throw new import_ErrorResponse.ErrorResponse(
"The '/id' property must be encrypted using Deterministic encryption."
);
}
}
if (partitionKeyPaths.includes(encryptedPath.path)) {
isPartitionKeyEncrypted = true;
if (encryptedPath.encryptionType !== import_EncryptionType.EncryptionType.DETERMINISTIC) {
throw new import_ErrorResponse.ErrorResponse(
`Path: ${encryptedPath.path} which is part of the partition key has to be encrypted with Deterministic type Encryption.`
);
}
}
}
if ((isPartitionKeyEncrypted || isIdEncrypted) && clientEncryptionPolicy.policyFormatVersion === 1) {
throw new import_ErrorResponse.ErrorResponse(
"Encryption of partition key or id is only supported with policy format version 2."
);
}
}
function canApplyExcludedLocations(resourceType) {
return resourceType === import_constants.ResourceType.item;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
canApplyExcludedLocations,
copyObject,
createDeserializer,
createSerializer,
extractPath,
getContainerLink,
getHexaDigit,
getIdFromLink,
getPathFromLink,
getResourceIdFromPath,
isItemResourceValid,
isReadRequest,
isResourceValid,
isStringNullOrEmpty,
jsonStringifyAndEscapeNonASCII,
parseConnectionString,
parseLink,
parsePath,
prepareURL,
sleep,
trimSlashFromLeftAndRight,
trimSlashes,
validateClientEncryptionPolicy,
validateItemResourceId,
validateResourceId
});