UNPKG

pricing4ts

Version:

![NPM Version](https://img.shields.io/npm/v/pricing4ts) Pricing4TS is a TypeScript-based toolkit designed to enhance the server-side functionality of a pricing-driven SaaS by enabling the seamless integration of pricing plans into the application logic. T

767 lines (766 loc) 37.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateName = validateName; exports.validateSyntaxVersion = validateSyntaxVersion; exports.validateVersion = validateVersion; exports.validateCreatedAt = validateCreatedAt; exports.validateCurrency = validateCurrency; exports.validateDescription = validateDescription; exports.validateValueType = validateValueType; exports.validateDefaultValue = validateDefaultValue; exports.validateExpression = validateExpression; exports.validateValue = validateValue; exports.validateFeatureType = validateFeatureType; exports.validateFeatureIntegrationType = validateFeatureIntegrationType; exports.validateFeatureAutomationType = validateFeatureAutomationType; exports.validateUnit = validateUnit; exports.validateUsageLimitType = validateUsageLimitType; exports.validateLinkedFeatures = validateLinkedFeatures; exports.validateRenderMode = validateRenderMode; exports.validatePlanFeatures = validatePlanFeatures; exports.validatePlanUsageLimits = validatePlanUsageLimits; exports.validatePrice = validatePrice; exports.validateAddonFeatures = validateAddonFeatures; exports.validateAddonUsageLimits = validateAddonUsageLimits; exports.validateAddonUsageLimitsExtensions = validateAddonUsageLimitsExtensions; exports.validateAvailableFor = validateAvailableFor; exports.validateDependsOnOrExcludes = validateDependsOnOrExcludes; exports.postValidateDependsOnOrExclude = postValidateDependsOnOrExclude; exports.validateTags = validateTags; exports.validatePlan = validatePlan; exports.validatePlans = validatePlans; exports.validateFeatures = validateFeatures; exports.validateFeature = validateFeature; exports.validateUsageLimits = validateUsageLimits; exports.validateUsageLimit = validateUsageLimit; exports.validateBilling = validateBilling; exports.validateVariables = validateVariables; exports.validateUrl = validateUrl; exports.validatePrivate = validatePrivate; exports.validatePricingUrls = validatePricingUrls; exports.validateDocUrl = validateDocUrl; exports.validatePeriodUnit = validatePeriodUnit; exports.validatePeriodValue = validatePeriodValue; exports.validateTrackable = validateTrackable; exports.validateSubscriptionConstraintMinQuantity = validateSubscriptionConstraintMinQuantity; exports.validateSubscriptionConstraintMaxQuantity = validateSubscriptionConstraintMaxQuantity; exports.validateSubscriptionConstraintQuantityStep = validateSubscriptionConstraintQuantityStep; var cc = __importStar(require("currency-codes")); var feature_1 = require("../models/pricing2yaml/feature"); var VERSION_REGEXP = /^\d+\.\d+$/; var unlimitedValue = 100000000; function validateName(name, item) { if (name === null || name === undefined) { throw new Error("The ".concat(item, " must have a name")); } if (typeof name !== 'string') { throw new Error("The ".concat(item, " name must be a string")); } var trimmedName = name.trim(); if (trimmedName.length === 0) { throw new Error("The ".concat(item, " name must not be empty")); } if (trimmedName.length < 3) { throw new Error("The ".concat(item, " name must have at least 3 characters")); } if (trimmedName.length > 255) { throw new Error("The ".concat(item, " name must have at most 255 characters")); } return trimmedName; } function validateSyntaxVersion(version) { if (version === null || version === undefined) { throw new Error("The syntaxVersion field of the pricing must not be null or undefined. Please ensure that the syntaxVersion field is present and correctly formatted"); } if (typeof version !== 'string' || !VERSION_REGEXP.test(version)) { throw new Error("The syntaxVersion field of the pricing does not follow the required structure: X.Y (being X and Y numbers). Please ensure it is a string in the format X.Y"); } return version; } function validateVersion(version, createdAt) { if (version === null || version === undefined) { version = "".concat(createdAt.getFullYear(), "-").concat(createdAt.getMonth() + 1, "-").concat(createdAt.getDate()); } if (typeof version !== 'string') { throw new Error("The version field of the pricing must be a string. Please ensure that the version field is present and correctly formatted"); } return version; } function validateCreatedAt(createdAt) { if (createdAt === null || createdAt === undefined) { throw new Error("The createdAt field must not be null or undefined. Please ensure that the createdAt field is present and correctly formatted (as Date or string)"); } if (typeof createdAt === 'string') { if (/^\d{4}-\d{2}-\d{2}$/.test(createdAt)) { createdAt = new Date(createdAt); } else { throw new Error("The createdAt field must be a string in the format yyyy-mm-dd or a valid Date object"); } } if (!(createdAt instanceof Date) || isNaN(createdAt.getTime())) { throw new Error("The createdAt field must be a valid Date object or a string in a recognized date format"); } var now = new Date(); if (createdAt > now) { throw new Error("The createdAt field must not be a future date"); } return createdAt; } function validateCurrency(currency) { if (currency === null || currency === undefined) { throw new Error("The currency field of the pricing must not be null or undefined. Please ensure that the currency field is present and correctly formatted"); } if (typeof currency !== 'string') { throw new Error("The currency field of the pricing must be a string"); } var trimmedCurrency = currency.trim(); if (trimmedCurrency.length === 0) { throw new Error("The currency field of the pricing must not be empty"); } var currencyCode = cc.code(trimmedCurrency); if (!currencyCode) { throw new Error("The currency code ".concat(trimmedCurrency, " is not a valid ISO 4217 currency code")); } return currency; } function validateDescription(description) { if (description === null) { description = undefined; } return description; } function validateValueType(valueType) { if (valueType === null || valueType === undefined) { throw new Error("The valueType field of a feature must not be null or undefined. Please ensure that the valueType field is present and it's value correspond to either BOOLEAN, NUMERIC or TEXT"); } if (typeof valueType !== 'string') { throw new Error("The valueType field of a feature must be a string, and its value must be either BOOLEAN, NUMERIC or TEXT. Received: ".concat(valueType, " ")); } valueType = valueType.trim().toUpperCase(); if (!['NUMERIC', 'BOOLEAN', 'TEXT'].includes(valueType)) { throw new Error("The valueType field of a feature must be one of NUMERIC, BOOLEAN, or TEXT. Received: ".concat(valueType)); } return valueType; } function validateDefaultValue(elem, item) { if (elem.defaultValue === null || elem.defaultValue === undefined) { throw new Error("The defaultValue field of a ".concat(item, " must not be null or undefined. Please ensure that the defaultValue field is present and its defaultValue type correspond to the declared valueType")); } switch (elem.valueType) { case 'NUMERIC': if (typeof elem.defaultValue !== 'number') { throw new Error("The defaultValue field of a ".concat(item, " must be a number when its valueType is NUMERIC. Received: ").concat(elem.defaultValue)); } if (elem.defaultValue > unlimitedValue) { elem.defaultValue = unlimitedValue; } break; case 'BOOLEAN': if (typeof elem.defaultValue !== 'boolean') { throw new Error("The defaultValue field of a ".concat(item, " must be a boolean when its valueType is BOOLEAN. Received: ").concat(elem.defaultValue)); } break; case 'TEXT': if (elem.type === 'PAYMENT') { if (!(elem.defaultValue instanceof Array)) { throw new Error("Payment method value must be an array of payment methods"); } for (var _i = 0, _a = elem.defaultValue; _i < _a.length; _i++) { var paymentMethod = _a[_i]; if (!['CARD', 'GATEWAY', 'INVOICE', 'ACH', 'WIRE_TRANSFER', 'OTHER'].includes(paymentMethod)) { throw new Error("Invalid payment method: ".concat(paymentMethod, ". Please provide one of the following: CARD, GATEWAY, INVOICE, ACH, WIRE_TRANSFER, OTHER")); } } break; } if (typeof elem.defaultValue !== 'string') { throw new Error("The defaultValue field of a ".concat(item, " must be a string when its valueType is TEXT. Received: ").concat(elem.defaultValue)); } break; default: throw new Error("The valueType field of a ".concat(item, " must be either BOOLEAN, NUMERIC or TEXT. Received: ").concat(elem.valueType)); } return elem.defaultValue; } function validateExpression(expression, item) { if (expression === null) { expression = undefined; } if (typeof expression === 'string') { if (expression.trim().length === 0) { throw new Error("The ".concat(item, " field of a feature must not be empty. If you don't want to declare an expression for this feature, either use null or undefined")); } } return expression; } function validateValue(elem, item, valueType) { if (valueType === void 0) { valueType = undefined; } if (elem.value === null || elem.value === undefined) { elem.value = undefined; } var valueTypeToValidate = valueType || elem.valueType; switch (valueTypeToValidate) { case 'NUMERIC': if (typeof elem.value !== 'number' && elem.value !== undefined) { throw new Error("The value field of a ".concat(item, " must be a number when its valueType is NUMERIC. Received: ").concat(elem.value)); } if (elem.value > unlimitedValue) { elem.value = unlimitedValue; } break; case 'BOOLEAN': if (typeof elem.value !== 'boolean' && elem.value !== undefined) { throw new Error("The value field of a ".concat(item, " must be a boolean when its valueType is BOOLEAN. Received: ").concat(elem.value)); } break; case 'TEXT': if (elem.type === 'PAYMENT' && elem.value !== undefined) { if (!(elem.value instanceof Array)) { throw new Error("Payment method value must be an array of payment methods"); } for (var _i = 0, _a = elem.value; _i < _a.length; _i++) { var paymentMethod = _a[_i]; if (!['CARD', 'GATEWAY', 'INVOICE', 'ACH', 'WIRE_TRANSFER', 'OTHER'].includes(paymentMethod)) { throw new Error("Invalid payment method: ".concat(paymentMethod, ". Please provide one of the following: CARD, GATEWAY, INVOICE, ACH, WIRE_TRANSFER, OTHER")); } } break; } if (typeof elem.value !== 'string' && elem.value !== undefined) { throw new Error("The value field of a ".concat(item, " must be a string when its valueType is TEXT. Received: ").concat(elem.value)); } break; default: throw new Error("The valueType field of a ".concat(item, " must be either BOOLEAN, NUMERIC or TEXT. Received: ").concat(elem.valueType)); } return elem.value; } function validateFeatureType(type) { if (type === null || type === undefined) { throw new Error("The type field of a feature must not be null or undefined. Please ensure that the type field is present and it's value correspond to either INFORMATION, INTEGRATION, DOMAIN, AUTOMATION, MANAGEMENT, GUARANTEE, SUPPORT or PAYMENT"); } if (typeof type !== 'string') { throw new Error("The type field of a feature must be a string, and its value must be either INFORMATION, INTEGRATION, DOMAIN, AUTOMATION, MANAGEMENT, GUARANTEE, SUPPORT or PAYMENT. Received: ".concat(type, " ")); } type = type.trim().toUpperCase(); if (![ 'INFORMATION', 'INTEGRATION', 'DOMAIN', 'AUTOMATION', 'MANAGEMENT', 'GUARANTEE', 'SUPPORT', 'PAYMENT', ].includes(type)) { throw new Error("The type field of a feature must be one of INFORMATION, INTEGRATION, DOMAIN, AUTOMATION, MANAGEMENT, GUARANTEE, SUPPORT or PAYMENT. Received: ".concat(type)); } return type; } function validateFeatureIntegrationType(integrationType, featureType) { if (integrationType === null || integrationType === undefined) { integrationType = undefined; } if (integrationType && typeof integrationType !== 'string') { throw new Error("The integrationType field of a feature must be an IntegrationType ('API' | 'EXTENSION' | 'IDENTITY_PROVIDER' | 'WEB_SAAS' | 'MARKETPLACE' | 'EXTERNAL_DEVICE'). Received: ".concat(integrationType)); } else if (featureType === 'INTEGRATION' && !integrationType) { throw new Error("The integrationType field of a feature of type INTEGRATION must not be null or undefined. Please ensure that the integrationType field is present and it's value correspond to either API, EXTENSION, IDENTITY_PROVIDER, WEB_SAAS, MARKETPLACE or EXTERNAL_DEVICE"); } else if (integrationType && typeof integrationType === "string" && !(0, feature_1.isIntegrationType)(integrationType)) { throw new Error("The integrationType field of a feature must be one of API, EXTENSION, IDENTITY_PROVIDER, WEB_SAAS, MARKETPLACE or EXTERNAL_DEVICE. Received: ".concat(integrationType)); } return integrationType; } function validateFeatureAutomationType(automationType, featureType) { if (automationType === null || automationType === undefined) { automationType = undefined; } if (automationType && typeof automationType !== 'string') { throw new Error("The automationType field of a feature must be an AutomationType ('BOT' | 'FILTERING' | 'TRACKING' | 'TASK_AUTOMATION'). Received: ".concat(automationType)); } else if (featureType === 'AUTOMATION' && !automationType) { throw new Error("The automationType field of a feature of type AUTOMATION must not be null or undefined. Please ensure that the automationType field is present and its value corresponds to either BOT, FILTERING, TRACKING, or TASK_AUTOMATION"); } else if (automationType && typeof automationType === "string" && !(0, feature_1.isAutomationType)(automationType)) { throw new Error("The automationType field of a feature must be one of BOT, FILTERING, TRACKING, or TASK_AUTOMATION. Received: ".concat(automationType)); } return automationType; } function validateUnit(unit) { if (unit === null || unit === undefined) { unit = ''; } if (typeof unit !== 'string') { throw new Error("The unit field of a usage limit must be a string. Received: ".concat(unit, " ")); } return unit; } function validateUsageLimitType(type) { if (type === null || type === undefined) { throw new Error("The type field of a usage limit must not be null or undefined. Please ensure that the type field is present and it's value correspond to either RENEWABLE or NON_RENEWABLE"); } if (typeof type !== 'string') { throw new Error("The type field of a usage limit must be a string, and its value must be either RENEWABLE or NON_RENEWABLE. Received: ".concat(type, " ")); } type = type.trim().toUpperCase(); if (!['RENEWABLE', 'NON_RENEWABLE'].includes(type)) { throw new Error("The type field of a usage limit must be one of RENEWABLE or NON_RENEWABLE. Received: ".concat(type)); } return type; } function validateLinkedFeatures(linkedFeatures, pricing) { if (linkedFeatures === null) { linkedFeatures = undefined; } // Check if linked features is an array if (Array.isArray(linkedFeatures)) { var pricingFeatures = Object.values(pricing.features).map(function (f) { return f.name; }); for (var _i = 0, linkedFeatures_1 = linkedFeatures; _i < linkedFeatures_1.length; _i++) { var featureName = linkedFeatures_1[_i]; if (!pricingFeatures.includes(featureName)) { throw new Error("The feature ".concat(featureName, ", declared as a linked feature for an usage limit, is not defined in the global features")); } } } return linkedFeatures; } function validateRenderMode(renderMode) { if (renderMode === null || renderMode === undefined) { renderMode = 'AUTO'; } renderMode = renderMode.toUpperCase(); if (!['AUTO', 'ENABLED', 'DISABLED'].includes(renderMode)) { throw new Error("The render field of a feature or usage limit must be one of AUTO, ENABLED or DISABLED. Received: ".concat(renderMode)); } return renderMode; } function validatePlanFeatures(plan, planFeatures) { var featuresModifiedByPlan = plan.features; plan.features = planFeatures; var _loop_1 = function (planFeature) { try { if (!Object.values(planFeatures).some(function (f) { return f.name === planFeature.name; })) { throw new Error("Feature ".concat(planFeature.name, " is not defined in the global features.")); } var featureWithDefaultValue = Object.values(plan.features).find(function (f) { return f.name === planFeature.name; }); featureWithDefaultValue.value = planFeature.value; featureWithDefaultValue.value = validateValue(featureWithDefaultValue, 'feature'); } catch (err) { throw new Error("Error while parsing the feature ".concat(planFeature.name, " of the plan ").concat(plan.name, ". Error: ").concat(err.message)); } }; for (var _i = 0, _a = Object.values(featuresModifiedByPlan); _i < _a.length; _i++) { var planFeature = _a[_i]; _loop_1(planFeature); } return plan.features; } function validatePlanUsageLimits(plan, planUsageLimits) { var usageLimitsModifiedByPlan = plan.usageLimits; plan.usageLimits = planUsageLimits; var _loop_2 = function (planUsageLimit) { try { if (!Object.values(planUsageLimits).some(function (l) { return l.name === planUsageLimit.name; })) { throw new Error("Usage limit ".concat(planUsageLimit.name, " is not defined in the global usage limits.")); } var globalUsageLimit = Object.values(planUsageLimits).find(function (l) { return l.name === planUsageLimit.name; }); globalUsageLimit.value = planUsageLimit.value; globalUsageLimit.value = validateValue(globalUsageLimit, 'usage limit'); } catch (err) { throw new Error("Error while parsing the usage limit ".concat(planUsageLimit.name, " of the plan ").concat(plan.name, ". Error: ").concat(err.message)); } }; for (var _i = 0, _a = Object.values(usageLimitsModifiedByPlan); _i < _a.length; _i++) { var planUsageLimit = _a[_i]; _loop_2(planUsageLimit); } return plan.usageLimits; } function validatePrice(price, variables) { if (price === null || price === undefined) { throw new Error("The price field must not be null or undefined. Please ensure that the price field is present and it's a number"); } if (typeof price !== 'string' && typeof price !== 'number') { throw new Error("The price field must be a number or a string (which can contain a formula). Received: ".concat(price)); } if (typeof price === 'number' && price < 0) { throw new Error("The price field must be a positive number. Received: ".concat(price, " ")); } if (typeof price === 'string') { if (price.includes('#')) { for (var _i = 0, _a = Object.entries(variables); _i < _a.length; _i++) { var _b = _a[_i], variable = _b[0], value = _b[1]; price = price.replace("#".concat(variable), "".concat(typeof value === 'string' ? "'".concat(value, "'") : value)); } try { // eslint-disable-next-line no-eval var evaluatedPrice = eval(price); if (typeof evaluatedPrice !== 'number' || isNaN(evaluatedPrice)) { throw new Error("The evaluated price must result in a valid number. Current result after evaluation: ".concat(evaluatedPrice)); } price = evaluatedPrice; } catch (err) { throw new Error("Error evaluating the price formula: ".concat(err.message)); } } else if (price.match(/^[0-9]+(\.[0-9]+)?$/)) { price = parseFloat(price); } } return price; } function validateAddonFeatures(addon, addOnFeatures) { var _loop_3 = function (addOnFeature) { try { if (!Object.values(addOnFeatures).some(function (f) { return f.name === addOnFeature.name; })) { throw new Error("Feature ".concat(addOnFeature.name, " is not defined in the global features.")); } addon.features[addOnFeature.name].value = addOnFeature.value; addon.features[addOnFeature.name].value = validateValue(addon.features[addOnFeature.name], 'feature', addOnFeatures[addOnFeature.name].valueType); } catch (err) { throw new Error("Error while parsing the feature ".concat(addOnFeature.name, " of the plan ").concat(addon.name, ". Error: ").concat(err.message)); } }; for (var _i = 0, _a = Object.values(addon.features); _i < _a.length; _i++) { var addOnFeature = _a[_i]; _loop_3(addOnFeature); } return addon.features; } function validateAddonUsageLimits(addon, addonUsageLimits) { var _loop_4 = function (addonUsageLimit) { try { if (!Object.values(addonUsageLimits).some(function (l) { return l.name === addonUsageLimit.name; })) { throw new Error("Usage limit ".concat(addonUsageLimit.name, " is not defined in the global usage limits.")); } if (!('value' in addonUsageLimit)) { throw new Error("When declaring a new value for an usage limit or a usage limit extension within an add-on, it must be provided through the 'value' field"); } addon.usageLimits[addonUsageLimit.name].value = addonUsageLimit.value; addon.usageLimits[addonUsageLimit.name].value = validateValue(addon.usageLimits[addonUsageLimit.name], 'usage limit', addonUsageLimits[addonUsageLimit.name].valueType); } catch (err) { throw new Error("Error while parsing the usage limit ".concat(addonUsageLimit.name, " of the add-on ").concat(addon.name, ". Error: ").concat(err.message)); } }; for (var _i = 0, _a = Object.values(addon.usageLimits); _i < _a.length; _i++) { var addonUsageLimit = _a[_i]; _loop_4(addonUsageLimit); } return addon.usageLimits; } function validateAddonUsageLimitsExtensions(addon, addonUsageLimits) { var _loop_5 = function (addonUsageLimitExtension) { try { if (!Object.values(addonUsageLimits).some(function (l) { return l.name === addonUsageLimitExtension.name; })) { throw new Error("Usage limit ".concat(addonUsageLimitExtension.name, " is not defined in the global usage limits.")); } if (!('value' in addonUsageLimitExtension)) { throw new Error("When declaring a new value for an usage limit or a usage limit extension within an add-on, it must be provided through the 'value' field"); } addon.usageLimitsExtensions[addonUsageLimitExtension.name].value = addonUsageLimitExtension.value; addon.usageLimitsExtensions[addonUsageLimitExtension.name].value = validateValue(addon.usageLimitsExtensions[addonUsageLimitExtension.name], 'usage limit', addonUsageLimits[addonUsageLimitExtension.name].valueType); } catch (err) { throw new Error("Error while parsing the usage limit ".concat(addonUsageLimitExtension.name, " of the add-on ").concat(addon.name, ". Error: ").concat(err.message)); } }; for (var _i = 0, _a = Object.values(addon.usageLimitsExtensions); _i < _a.length; _i++) { var addonUsageLimitExtension = _a[_i]; _loop_5(addonUsageLimitExtension); } return addon.usageLimitsExtensions; } function validateAvailableFor(availableFor, pricing) { var planNames = pricing.plans ? Object.values(pricing.plans).map(function (p) { return p.name; }) : []; if (availableFor === null || availableFor === undefined) { availableFor = planNames; } if (!Array.isArray(availableFor)) { throw new Error("The availableFor field must be an array of the plan names for which the addon can be contracted. Received: ".concat(availableFor)); } for (var _i = 0, availableFor_1 = availableFor; _i < availableFor_1.length; _i++) { var planName = availableFor_1[_i]; if (!planNames.includes(planName)) { throw new Error("The plan ".concat(planName, " is not defined in the pricing.")); } } return availableFor; } function validateDependsOnOrExcludes(fieldValue, pricing, fieldType) { var addonNames = pricing.addOns ? Object.values(pricing.addOns).map(function (a) { return a.name; }) : []; if (fieldValue === null || fieldValue === undefined) { fieldValue = []; } if (!Array.isArray(addonNames)) { throw new Error("The ".concat(fieldType, " field must be an array of the addons required to contract the addon. Received: ").concat(fieldValue)); } return fieldValue; } function postValidateDependsOnOrExclude(fieldValue, pricing) { var addonNames = pricing.addOns ? Object.values(pricing.addOns).map(function (a) { return a.name; }) : []; if (!fieldValue) return; for (var _i = 0, fieldValue_1 = fieldValue; _i < fieldValue_1.length; _i++) { var addonName = fieldValue_1[_i]; if (!addonNames.includes(addonName)) { throw new Error("The addon ".concat(addonName, " is not defined in the pricing.")); } } } function validateTags(tags) { if (tags === null || tags === undefined) { return []; } if (!Array.isArray(tags) || tags.some(function (tag) { return typeof tag !== 'string'; })) { throw new Error("The tags field must be an array of strings."); } return tags; } function validatePlan(plan) { if (typeof plan === 'object' && 'features' in plan) { return; } else { throw new Error("The plan must be an object of type Plan"); } } function validatePlans(plans) { if (!(typeof plans === 'object')) { throw new Error("The plans field must be a map of Plan objects"); } } function validateFeatures(features) { if (!(typeof features === 'object') || features === null || features === undefined) { throw new Error("The features field must be a map of Feature objects"); } } function validateFeature(feature) { if (typeof feature === 'object' && 'type' in feature && 'valueType' in feature && 'defaultValue' in feature) { return; } else { throw new Error("The feature must be an object of type Feature"); } } function validateUsageLimits(usageLimits) { if (!(typeof usageLimits === 'object')) { throw new Error("The usageLimits field must be a map of UsageLimit objects or undefined"); } } function validateUsageLimit(usageLimit) { if (typeof usageLimit === 'object' && 'type' in usageLimit && 'valueType' in usageLimit && 'defaultValue' in usageLimit) { return; } else { throw new Error("The usage limit must be an object of type UsageLimit"); } } function validateBilling(billing) { if (billing === undefined || billing === null) { billing = { monthly: 1, }; } if (!(typeof billing === 'object')) { throw new Error("The billing field must be an object of type {[key: string]: number}"); } for (var _i = 0, _a = Object.entries(billing); _i < _a.length; _i++) { var _b = _a[_i], key = _b[0], value = _b[1]; if (typeof value !== 'number') { throw new Error("The billing entry for ".concat(key, " must be a number. Received: ").concat(value)); } if (value <= 0 || value > 1) { throw new Error("The billing entry for ".concat(key, " must be a value in the range (0,1]. Received: ").concat(value)); } } return billing; } function validateVariables(variables) { if (variables === undefined || variables === null) { variables = {}; } if (typeof variables !== 'object') { throw new Error("The billing field must be an object of type {[key: string]: number | string | boolean}"); } for (var _i = 0, _a = Object.entries(variables); _i < _a.length; _i++) { var _b = _a[_i], key = _b[0], value = _b[1]; if (typeof value !== 'number' && typeof value !== 'string' && typeof value !== 'boolean') { throw new Error("The billing entry for ".concat(key, " must be either a number, a string or a boolean. Received: ").concat(value)); } } return variables; } function validateUrl(url) { if (url === undefined || url === null) { url = undefined; return; } if (typeof url !== 'string') { throw new Error("The url field must be a string. Received: ".concat(url)); } var urlPattern = /^(https?):\/\/[^\s\/$.?#].[^\s]*$/i; if (!urlPattern.test(url)) { throw new Error("The url field must be a valid URL with the http or https protocol. Received: ".concat(url)); } return url; } function validatePrivate(isPrivate) { if (isPrivate === undefined || isPrivate === null) { isPrivate = false; } if (typeof isPrivate !== 'boolean') { throw new Error("The private field must be a boolean. Received: ".concat(isPrivate)); } return isPrivate; } function validatePricingUrls(featureType, featureIntegrationType, pricingUrls) { if (pricingUrls === undefined || pricingUrls === null) { pricingUrls = undefined; } else { if (!Array.isArray(pricingUrls) || pricingUrls.some(function (url) { return typeof url !== 'string'; })) { throw new Error("The pricingUrls field must be an array of strings."); } for (var _i = 0, pricingUrls_1 = pricingUrls; _i < pricingUrls_1.length; _i++) { var url = pricingUrls_1[_i]; var urlPattern = /^(https?):\/\/[^\s\/$.?#].[^\s]*$/i; if (!urlPattern.test(url)) { throw new Error("The pricingUrls field must contain only valid URLs. Invalid URL: ".concat(url)); } } if (featureType !== 'INTEGRATION' || featureIntegrationType !== 'WEB_SAAS') { console.log("[WARNING] The pricingUrls field is only valid for features of 'type' INTEGRATION and 'integrationType' WEB_SAAS. The field will be ignored."); pricingUrls = undefined; } } return pricingUrls; } function validateDocUrl(featureType, docUrl) { if (docUrl === undefined || docUrl === null) { docUrl = undefined; } else { if (typeof docUrl !== 'string') { throw new Error("The docUrl field must be a string."); } var urlPattern = /^(https?):\/\/[^\s\/$.?#].[^\s]*$/i; if (!urlPattern.test(docUrl)) { throw new Error("The docUrl field must be a valid URL with the http or https protocol. Received: ".concat(docUrl)); } if (featureType !== 'GUARANTEE') { console.log("[WARNING] The docUrl field is only valid for features of 'type' GUARANTEE. The field will be ignored."); docUrl = undefined; } } return docUrl; } function validatePeriodUnit(periodUnit) { if (periodUnit === undefined || periodUnit === null) { periodUnit = 'MONTH'; } if (typeof periodUnit !== 'string') { throw new Error("The periodUnit field must be one of the following string values: \"SEC\" | \"MIN\" | \"HOUR\" | \"DAY\" | \"MONTH\" | \"YEAR\". Received: ".concat(periodUnit)); } periodUnit = periodUnit.toUpperCase(); if (!["SEC", "MIN", "HOUR", "DAY", "MONTH", "YEAR"].includes(periodUnit)) { throw new Error("The periodUnit field must be one of \"SEC\" | \"MIN\" | \"HOUR\" | \"DAY\" | \"MONTH\" | \"YEAR\". Received: ".concat(periodUnit)); } return periodUnit; } function validatePeriodValue(periodValue) { if (periodValue === undefined || periodValue === null) { periodValue = 1; } if (typeof periodValue !== 'number') { throw new Error("The periodValue field must be a number. Received: ".concat(periodValue)); } if (periodValue <= 0) { throw new Error("The periodValue field must be a positive number. Received: ".concat(periodValue)); } return periodValue; } function validateTrackable(trackable) { if (trackable === undefined || trackable === null) { trackable = false; } if (typeof trackable === 'string') { trackable = trackable.toLowerCase() === 'true'; } if (typeof trackable !== 'boolean') { throw new Error("The trackable field must be a boolean. Received: ".concat(trackable)); } return trackable; } function validateSubscriptionConstraintMinQuantity(subscriptionConstraintMinQuantity) { if (subscriptionConstraintMinQuantity === undefined || subscriptionConstraintMinQuantity === null) { subscriptionConstraintMinQuantity = 1; } if (typeof subscriptionConstraintMinQuantity !== 'number') { throw new Error("The subscriptionConstraintMinQuantity field must be a number. Received: ".concat(subscriptionConstraintMinQuantity)); } if (subscriptionConstraintMinQuantity < 0) { throw new Error("The subscriptionConstraintMinQuantity field must be a positive number. Received: ".concat(subscriptionConstraintMinQuantity)); } return subscriptionConstraintMinQuantity; } function validateSubscriptionConstraintMaxQuantity(subscriptionConstraintMaxQuantity, minQuantity) { if (subscriptionConstraintMaxQuantity === undefined || subscriptionConstraintMaxQuantity === null) { subscriptionConstraintMaxQuantity = unlimitedValue; } if (typeof subscriptionConstraintMaxQuantity !== 'number') { throw new Error("The subscriptionConstraintMaxQuantity field must be a number. Received: ".concat(subscriptionConstraintMaxQuantity)); } if (subscriptionConstraintMaxQuantity < minQuantity) { throw new Error("The subscriptionConstraintMaxQuantity field must be greater than or equal to the min quantity. Received: ".concat(subscriptionConstraintMaxQuantity)); } return subscriptionConstraintMaxQuantity; } function validateSubscriptionConstraintQuantityStep(subscriptionConstraintQuantityStep, minQuantity) { if (subscriptionConstraintQuantityStep === undefined || subscriptionConstraintQuantityStep === null) { subscriptionConstraintQuantityStep = 1; } if (typeof subscriptionConstraintQuantityStep !== 'number') { throw new Error("The subscriptionConstraintQuantityStep field must be a number. Received: ".concat(subscriptionConstraintQuantityStep)); } if (!(minQuantity % subscriptionConstraintQuantityStep === 0)) { throw new Error("The subscriptionConstraintQuantityStep field must be a divisor of, at least, the min quantity. Received: ".concat(subscriptionConstraintQuantityStep)); } return subscriptionConstraintQuantityStep; }