@chargebee/chargebee-apps-shared 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +113 -0
  3. package/SECURITY.md +8 -0
  4. package/dist/config/environment.d.ts +78 -0
  5. package/dist/config/environment.js +150 -0
  6. package/dist/config/path-resolver.d.ts +117 -0
  7. package/dist/config/path-resolver.js +247 -0
  8. package/dist/dependency/dependency-manager.d.ts +66 -0
  9. package/dist/dependency/dependency-manager.js +257 -0
  10. package/dist/errors.d.ts +8 -0
  11. package/dist/errors.js +17 -0
  12. package/dist/index.d.ts +19 -0
  13. package/dist/index.js +36 -0
  14. package/dist/libs/archive-service.d.ts +21 -0
  15. package/dist/libs/archive-service.js +145 -0
  16. package/dist/libs/file-management-service.d.ts +59 -0
  17. package/dist/libs/file-management-service.js +189 -0
  18. package/dist/libs/iparams-service.d.ts +69 -0
  19. package/dist/libs/iparams-service.js +136 -0
  20. package/dist/libs/template-service.d.ts +57 -0
  21. package/dist/libs/template-service.js +152 -0
  22. package/dist/logger/cb-logger.d.ts +56 -0
  23. package/dist/logger/cb-logger.js +13 -0
  24. package/dist/logger/internal-logger.d.ts +81 -0
  25. package/dist/logger/internal-logger.js +146 -0
  26. package/dist/node/file-system.d.ts +66 -0
  27. package/dist/node/file-system.js +76 -0
  28. package/dist/node/process.d.ts +30 -0
  29. package/dist/node/process.js +25 -0
  30. package/dist/sandbox/sandbox-context.d.ts +37 -0
  31. package/dist/sandbox/sandbox-context.js +48 -0
  32. package/dist/sandbox/sandbox-wrapper.d.ts +75 -0
  33. package/dist/sandbox/sandbox-wrapper.js +2 -0
  34. package/dist/types/common.d.ts +135 -0
  35. package/dist/types/common.js +20 -0
  36. package/dist/validator/iparam-constants.d.ts +49 -0
  37. package/dist/validator/iparam-constants.js +52 -0
  38. package/dist/validator/iparam-defns-validator.d.ts +46 -0
  39. package/dist/validator/iparam-defns-validator.js +291 -0
  40. package/dist/validator/iparams-inputs-validator.d.ts +62 -0
  41. package/dist/validator/iparams-inputs-validator.js +289 -0
  42. package/dist/validator/manifest-validator.d.ts +48 -0
  43. package/dist/validator/manifest-validator.js +138 -0
  44. package/dist/validator/package-validator.d.ts +27 -0
  45. package/dist/validator/package-validator.js +43 -0
  46. package/dist/validator/validator-utils.d.ts +13 -0
  47. package/dist/validator/validator-utils.js +26 -0
  48. package/package.json +45 -0
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.IparamDefnsValidator = void 0;
37
+ const common_1 = require("../types/common");
38
+ const iparam_constants_1 = require("./iparam-constants");
39
+ const iparams_inputs_validator_1 = require("./iparams-inputs-validator");
40
+ const validatorUtils = __importStar(require("./validator-utils"));
41
+ /**
42
+ * Validator for iparamDefns
43
+ * Validates the sectioned iparams.json schema
44
+ */
45
+ class IparamDefnsValidator {
46
+ constructor(fileSystem) {
47
+ this.fileSystem = fileSystem;
48
+ this.inputsValidator = new iparams_inputs_validator_1.IparamInputsValidator(fileSystem);
49
+ }
50
+ /**
51
+ * Validates and loads the iparamDefns from a file
52
+ * @param {string} path - Path to the iparams.json file
53
+ * @returns {IparamDefns} The validated iparamDefns
54
+ * @throws {Error} If the iparamDefns is invalid or cannot be read
55
+ */
56
+ validateAndGetIparamDefnsFile(path) {
57
+ validatorUtils.ensureFileExists(this.fileSystem, path);
58
+ try {
59
+ const iparamDefns = JSON.parse(this.fileSystem.readFileSync(path, 'utf8'));
60
+ try {
61
+ this.validate(iparamDefns);
62
+ return iparamDefns;
63
+ }
64
+ catch (validationError) {
65
+ const err = new Error(validationError.message);
66
+ err.rawContent = iparamDefns;
67
+ throw err;
68
+ }
69
+ }
70
+ catch (error) {
71
+ if (error.rawContent !== undefined) {
72
+ throw error;
73
+ }
74
+ if (error instanceof SyntaxError) {
75
+ throw new Error(`Failed to parse ${iparam_constants_1.IPARAMS_JSON_FILENAME}: ${error.message}`);
76
+ }
77
+ throw new Error(`Failed to read ${iparam_constants_1.IPARAMS_JSON_FILENAME}: ${error.message}`);
78
+ }
79
+ }
80
+ /**
81
+ * Validates an iparamDefns object
82
+ * @param {IparamDefns} iparamDefns - The iparamDefns object to validate
83
+ * @throws {Error} If the iparamDefns is invalid
84
+ */
85
+ validate(iparamDefns) {
86
+ if (!iparamDefns || typeof iparamDefns !== 'object' || Array.isArray(iparamDefns)) {
87
+ throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} must be an object`);
88
+ }
89
+ this.rejectUnknownKeys(iparamDefns, iparam_constants_1.IPARAMS_ROOT_ALLOWED_KEYS, iparam_constants_1.IPARAMS_JSON_FILENAME);
90
+ if (!Object.prototype.hasOwnProperty.call(iparamDefns, iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL)) {
91
+ return;
92
+ }
93
+ const installationParameters = iparamDefns.installation_parameters;
94
+ if (!installationParameters || typeof installationParameters !== 'object' || Array.isArray(installationParameters)) {
95
+ throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} must include ${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL} as an object containing a ${iparam_constants_1.IPARAMS_SECTIONS_LABEL} array`);
96
+ }
97
+ this.rejectUnknownKeys(installationParameters, iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_ALLOWED_KEYS, iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL);
98
+ if (!Object.prototype.hasOwnProperty.call(installationParameters, iparam_constants_1.IPARAMS_SECTIONS_LABEL)) {
99
+ throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL} must include ${iparam_constants_1.IPARAMS_SECTIONS_LABEL} in ${iparam_constants_1.IPARAMS_JSON_FILENAME}`);
100
+ }
101
+ const sections = installationParameters.sections;
102
+ if (!Array.isArray(sections)) {
103
+ throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL}.${iparam_constants_1.IPARAMS_SECTIONS_LABEL} must be an array of section objects`);
104
+ }
105
+ if (sections.length === 0) {
106
+ throw new Error(`${iparam_constants_1.IPARAMS_INSTALLATION_PARAMETERS_LABEL}.${iparam_constants_1.IPARAMS_SECTIONS_LABEL} must contain at least one section`);
107
+ }
108
+ for (let i = 0; i < sections.length; i++) {
109
+ this.validateSection(sections[i], i);
110
+ }
111
+ const totalParamCount = sections.reduce((count, section) => count + section.parameters.length, 0);
112
+ if (totalParamCount > iparam_constants_1.IPARAMS_MAX_COUNT) {
113
+ throw new Error(`${iparam_constants_1.IPARAMS_JSON_FILENAME} cannot define more than ${iparam_constants_1.IPARAMS_MAX_COUNT} parameters (found ${totalParamCount})`);
114
+ }
115
+ const sectionNames = sections.map((section) => section.name.trim());
116
+ const seenSectionNames = new Set();
117
+ const duplicateSections = [];
118
+ for (const name of sectionNames) {
119
+ if (seenSectionNames.has(name))
120
+ duplicateSections.push(name);
121
+ else
122
+ seenSectionNames.add(name);
123
+ }
124
+ if (duplicateSections.length > 0) {
125
+ throw new Error(`Duplicate section names found: ${duplicateSections.join(', ')}`);
126
+ }
127
+ for (const section of sections) {
128
+ const paramNames = section.parameters.map((param) => param.name.trim());
129
+ const seenParamNames = new Set();
130
+ const duplicateParams = [];
131
+ for (const name of paramNames) {
132
+ if (seenParamNames.has(name))
133
+ duplicateParams.push(name);
134
+ else
135
+ seenParamNames.add(name);
136
+ }
137
+ if (duplicateParams.length > 0) {
138
+ throw new Error(`Duplicate parameter names found in section "${section.name}": ${duplicateParams.join(', ')}`);
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Validates a single section definition
144
+ * @param {any} section - The section definition to validate
145
+ * @param {number} index - The index of the section in the array (for error messages)
146
+ * @throws {Error} If the section is invalid
147
+ */
148
+ validateSection(section, index) {
149
+ if (!section || typeof section !== 'object') {
150
+ throw new Error(`Section at index ${index} must be an object`);
151
+ }
152
+ const sectionName = this.validateSectionName(section, index);
153
+ this.requireNonEmptyStringField(section, sectionName, 'display_name', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DISPLAY_NAME, 'Section');
154
+ this.requireNonEmptyStringField(section, sectionName, 'description', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DESCRIPTION, 'Section');
155
+ const parameters = section['parameters'];
156
+ if (!Array.isArray(parameters)) {
157
+ throw new Error(`Section "${sectionName}": "parameters" must be an array`);
158
+ }
159
+ if (parameters.length === 0) {
160
+ throw new Error(`Section "${sectionName}": "parameters" must contain at least one parameter`);
161
+ }
162
+ for (let i = 0; i < parameters.length; i++) {
163
+ this.validateParameter(parameters[i], sectionName, i);
164
+ }
165
+ }
166
+ /**
167
+ * Validates a single parameter definition
168
+ * @param {any} param - The parameter definition to validate
169
+ * @param {string} sectionName - Parent section name for error messages
170
+ * @param {number} index - The index of the parameter in the section (for error messages)
171
+ * @throws {Error} If the parameter is invalid
172
+ */
173
+ validateParameter(param, sectionName, index) {
174
+ if (!param || typeof param !== 'object') {
175
+ throw new Error(`Section "${sectionName}": parameter at index ${index} must be an object`);
176
+ }
177
+ const paramName = this.validateParamName(param, sectionName, index);
178
+ const sectionDotParam = `${sectionName}.${paramName}`;
179
+ this.requireNonEmptyStringField(param, sectionDotParam, 'display_name', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DISPLAY_NAME);
180
+ this.requireNonEmptyStringField(param, sectionDotParam, 'description', iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.DESCRIPTION);
181
+ this.validateType(param, sectionDotParam);
182
+ if (param.required !== undefined && typeof param.required !== 'boolean') {
183
+ throw new Error(`Parameter "${sectionDotParam}": "required" must be a boolean`);
184
+ }
185
+ this.validateOptions(param, sectionDotParam);
186
+ if (param.type === 'SECRET' && param.default !== undefined && param.default !== null) {
187
+ throw new Error(`Parameter "${sectionDotParam}": SECRET type cannot have a default value`);
188
+ }
189
+ this.validateDefaultValue(param, sectionDotParam);
190
+ }
191
+ requireNonEmptyStringField(entity, entityName, fieldName, maxLength, entityLabel = 'Parameter') {
192
+ const value = entity[fieldName];
193
+ if (!validatorUtils.isNonEmptyString(value)) {
194
+ throw new Error(`${entityLabel} "${entityName}": "${fieldName}" must be a non-empty string`);
195
+ }
196
+ const trimmed = value.trim();
197
+ if (maxLength !== undefined && trimmed.length > maxLength) {
198
+ throw new Error(`${entityLabel} "${entityName}": "${fieldName}" cannot exceed ${maxLength} characters`);
199
+ }
200
+ }
201
+ rejectUnknownKeys(entity, allowedKeys, entityLabel) {
202
+ for (const key of Object.keys(entity)) {
203
+ if (!allowedKeys.includes(key)) {
204
+ throw new Error(`${entityLabel} must only contain ${allowedKeys.map((k) => `"${k}"`).join(', ')}`);
205
+ }
206
+ }
207
+ }
208
+ validateSectionName(section, index) {
209
+ const name = section['name'];
210
+ if (!validatorUtils.isNonEmptyString(name)) {
211
+ throw new Error(`Section at index ${index}: "name" must be a non-empty string`);
212
+ }
213
+ const sectionName = name.trim();
214
+ if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(sectionName)) {
215
+ throw new Error(`Section "${sectionName}": "name" can only contain letters, numbers, underscores, and hyphens, and must start with a letter or underscore`);
216
+ }
217
+ if (sectionName.length > iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME) {
218
+ throw new Error(`Section "${sectionName}": "name" must be between 1 and ${iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME} characters`);
219
+ }
220
+ return sectionName;
221
+ }
222
+ validateParamName(param, sectionName, index) {
223
+ const name = param['name'];
224
+ if (!validatorUtils.isNonEmptyString(name)) {
225
+ throw new Error(`Section "${sectionName}": parameter at index ${index}: "name" must be a non-empty string`);
226
+ }
227
+ const paramName = name.trim();
228
+ if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(paramName)) {
229
+ throw new Error(`Parameter "${sectionName}.${paramName}": "name" can only contain letters, numbers, underscores, and hyphens, and must start with a letter or underscore`);
230
+ }
231
+ if (paramName.length > iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME) {
232
+ throw new Error(`Parameter "${sectionName}.${paramName}": "name" must be between 1 and ${iparam_constants_1.IPARAM_DEFN_MAX_LENGTHS.NAME} characters`);
233
+ }
234
+ return paramName;
235
+ }
236
+ validateType(param, sectionDotParam) {
237
+ const type = param['type'];
238
+ if (!type || !common_1.VALID_IPARAM_TYPES.includes(type)) {
239
+ throw new Error(`Parameter "${sectionDotParam}": "type" must be one of: ${common_1.VALID_IPARAM_TYPES.join(', ')}`);
240
+ }
241
+ }
242
+ validateOptions(param, sectionDotParam) {
243
+ const paramType = param['type'];
244
+ if (paramType !== 'DROPDOWN' && paramType !== 'MULTISELECT_DROPDOWN') {
245
+ if (Object.prototype.hasOwnProperty.call(param, 'options')) {
246
+ throw new Error(`Parameter "${sectionDotParam}": "options" is only allowed for DROPDOWN and MULTISELECT_DROPDOWN types`);
247
+ }
248
+ return;
249
+ }
250
+ const options = param['options'];
251
+ if (!options || !Array.isArray(options) || options.length === 0) {
252
+ throw new Error(`Parameter "${sectionDotParam}": "options" is required and must be a non-empty array of strings for ${paramType} type`);
253
+ }
254
+ if (options.length > iparam_constants_1.OPTIONS_LIMITS.MAX_COUNT) {
255
+ throw new Error(`Parameter "${sectionDotParam}": "options" cannot exceed ${iparam_constants_1.OPTIONS_LIMITS.MAX_COUNT} items for ${paramType} type`);
256
+ }
257
+ const seenTrimmedOptions = new Set();
258
+ for (let i = 0; i < options.length; i++) {
259
+ if (typeof options[i] !== 'string') {
260
+ throw new Error(`Parameter "${sectionDotParam}": option at index ${i} must be a string`);
261
+ }
262
+ const optionStr = options[i].trim();
263
+ if (optionStr === '') {
264
+ throw new Error(`Parameter "${sectionDotParam}": option at index ${i} cannot be an empty string`);
265
+ }
266
+ if (seenTrimmedOptions.has(optionStr)) {
267
+ throw new Error(`Parameter "${sectionDotParam}": "options" must not contain duplicate entries`);
268
+ }
269
+ seenTrimmedOptions.add(optionStr);
270
+ if (optionStr.length > iparam_constants_1.OPTIONS_LIMITS.MAX_OPTION_LENGTH) {
271
+ throw new Error(`Parameter "${sectionDotParam}": option at index ${i} cannot exceed ${iparam_constants_1.OPTIONS_LIMITS.MAX_OPTION_LENGTH} characters`);
272
+ }
273
+ }
274
+ }
275
+ validateDefaultValue(param, sectionDotParam) {
276
+ const defaultValue = param['default'];
277
+ if (defaultValue === undefined || defaultValue === null)
278
+ return;
279
+ if (typeof defaultValue === 'string' && defaultValue.trim() === '') {
280
+ throw new Error(`Parameter "${sectionDotParam}": default value cannot be an empty string. Either remove the "default" key, set it to null, or provide a non-empty value.`);
281
+ }
282
+ try {
283
+ this.inputsValidator.validateParamValue(param, defaultValue, sectionDotParam);
284
+ }
285
+ catch (error) {
286
+ const msg = error.message.replace(/\bvalue\b/g, 'default value');
287
+ throw new Error(msg);
288
+ }
289
+ }
290
+ }
291
+ exports.IparamDefnsValidator = IparamDefnsValidator;
@@ -0,0 +1,62 @@
1
+ import { CBFileSystem } from '../node/file-system';
2
+ import { IparamDefn, IparamInputs, IparamDefns, IparamValue } from '../types/common';
3
+ /**
4
+ * Validator for parameter inputs
5
+ * Validates input values against the sectioned iparamDefns
6
+ */
7
+ export declare class IparamInputsValidator {
8
+ private fileSystem;
9
+ constructor(fileSystem: CBFileSystem);
10
+ /**
11
+ * Validates whether the value counts as a provided input.
12
+ * Not whether it is allowed by iparam definitions—that is handled by {@link IparamInputsValidator.validateInputs}.
13
+ */
14
+ static isProvidedIparamInputValue(value: IparamValue | undefined | null): value is IparamValue;
15
+ /**
16
+ * Validates and loads the iparam inputs from a file (no validation against iparamDefns).
17
+ * Only ensures the file is valid JSON and the root value is an object.
18
+ * @param {string} path - Path to the iparams.local.json file
19
+ * @returns {IparamInputs} The loaded inputs
20
+ * @throws {Error} If the file does not exist, cannot be read or parsed, or root is not an object
21
+ */
22
+ validateAndGetIparamInputsFile(path: string): IparamInputs;
23
+ /**
24
+ * Ensures the inputs value is a plain object
25
+ * @param {any} inputs - The value to check
26
+ * @throws {Error} If inputs is not a plain object
27
+ */
28
+ ensureInputsIsObject(inputs: any): void;
29
+ /**
30
+ * Validates inputs against the iparamDefns (without applying defaults)
31
+ * Only validates provided values, does not include defaults in the result
32
+ * @param {IparamInputs} inputs - The input values to validate
33
+ * @param {IparamDefns} iparamDefns - The iparamDefns
34
+ * @returns {IparamInputs} The validated inputs (only provided values, no defaults)
35
+ * @throws {Error} If validation fails
36
+ * @throws {MissingRequiredParamsError} If required parameters are missing
37
+ */
38
+ validateInputs(inputs: IparamInputs, iparamDefns: IparamDefns): IparamInputs;
39
+ /**
40
+ * Validates a single parameter value against its parameter definition.
41
+ * @param {IparamDefn} param - The parameter definition
42
+ * @param {any} value - The value to validate
43
+ * @param {string} [sectionDotParam] - Optional section.param identifier for error messages (e.g. processing_fee_configuration.fee_percentage)
44
+ * @throws {Error} If the value is invalid
45
+ */
46
+ validateParamValue(param: IparamDefn, value: unknown, sectionDotParam?: string): void;
47
+ /**
48
+ * Requires value to be a non-empty string, optionally with max length.
49
+ * @throws {Error} If not a string, empty after trim, or exceeds maxLength
50
+ */
51
+ private requireNonEmptyString;
52
+ /**
53
+ * Requires value to be one of the allowed options.
54
+ */
55
+ private requireInOptions;
56
+ private validateNumber;
57
+ private validateBoolean;
58
+ private validateUrl;
59
+ private validateDate;
60
+ private validateDropdown;
61
+ private validateMultiselectDropdown;
62
+ }
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.IparamInputsValidator = void 0;
37
+ const errors_1 = require("../errors");
38
+ const internal_logger_1 = require("../logger/internal-logger");
39
+ const iparam_constants_1 = require("./iparam-constants");
40
+ const validatorUtils = __importStar(require("./validator-utils"));
41
+ /**
42
+ * Validator for parameter inputs
43
+ * Validates input values against the sectioned iparamDefns
44
+ */
45
+ class IparamInputsValidator {
46
+ constructor(fileSystem) {
47
+ this.fileSystem = fileSystem;
48
+ }
49
+ /**
50
+ * Validates whether the value counts as a provided input.
51
+ * Not whether it is allowed by iparam definitions—that is handled by {@link IparamInputsValidator.validateInputs}.
52
+ */
53
+ static isProvidedIparamInputValue(value) {
54
+ if (value === undefined || value === null)
55
+ return false;
56
+ if (typeof value === 'string')
57
+ return value.trim() !== '';
58
+ if (Array.isArray(value))
59
+ return value.length > 0;
60
+ return true;
61
+ }
62
+ /**
63
+ * Validates and loads the iparam inputs from a file (no validation against iparamDefns).
64
+ * Only ensures the file is valid JSON and the root value is an object.
65
+ * @param {string} path - Path to the iparams.local.json file
66
+ * @returns {IparamInputs} The loaded inputs
67
+ * @throws {Error} If the file does not exist, cannot be read or parsed, or root is not an object
68
+ */
69
+ validateAndGetIparamInputsFile(path) {
70
+ validatorUtils.ensureFileExists(this.fileSystem, path);
71
+ try {
72
+ const inputs = JSON.parse(this.fileSystem.readFileSync(path, 'utf8'));
73
+ if (typeof inputs !== 'object' || Array.isArray(inputs)) {
74
+ throw new Error('iparams.local.json must be an object');
75
+ }
76
+ return inputs;
77
+ }
78
+ catch (error) {
79
+ if (error instanceof SyntaxError) {
80
+ throw new Error(`Failed to parse iparams.local.json: ${error.message}`);
81
+ }
82
+ throw new Error(`Failed to read iparams.local.json: ${error.message}`);
83
+ }
84
+ }
85
+ /**
86
+ * Ensures the inputs value is a plain object
87
+ * @param {any} inputs - The value to check
88
+ * @throws {Error} If inputs is not a plain object
89
+ */
90
+ ensureInputsIsObject(inputs) {
91
+ if (inputs === null || typeof inputs !== 'object' || Array.isArray(inputs)) {
92
+ throw new Error('Inputs must be an object');
93
+ }
94
+ }
95
+ /**
96
+ * Validates inputs against the iparamDefns (without applying defaults)
97
+ * Only validates provided values, does not include defaults in the result
98
+ * @param {IparamInputs} inputs - The input values to validate
99
+ * @param {IparamDefns} iparamDefns - The iparamDefns
100
+ * @returns {IparamInputs} The validated inputs (only provided values, no defaults)
101
+ * @throws {Error} If validation fails
102
+ * @throws {MissingRequiredParamsError} If required parameters are missing
103
+ */
104
+ validateInputs(inputs, iparamDefns) {
105
+ this.ensureInputsIsObject(inputs);
106
+ const validatedInputs = {};
107
+ const missingRequired = [];
108
+ const sections = iparamDefns.installation_parameters?.sections ?? [];
109
+ const sectionByName = new Map(sections.map((section) => [section.name, section]));
110
+ for (const section of sections) {
111
+ const sectionInputs = inputs[section.name];
112
+ if (sectionInputs !== undefined && sectionInputs !== null) {
113
+ if (typeof sectionInputs !== 'object' || Array.isArray(sectionInputs)) {
114
+ throw new Error(`Section "${section.name}": inputs must be an object`);
115
+ }
116
+ }
117
+ const sectionObject = {};
118
+ for (const param of section.parameters) {
119
+ const sectionDotParam = `${section.name}.${param.name}`;
120
+ const value = sectionInputs?.[param.name];
121
+ if (IparamInputsValidator.isProvidedIparamInputValue(value)) {
122
+ this.validateParamValue(param, value, sectionDotParam);
123
+ sectionObject[param.name] = value;
124
+ }
125
+ else if (param.required && (param.default === undefined || param.default === null)) {
126
+ missingRequired.push(sectionDotParam);
127
+ }
128
+ }
129
+ if (Object.keys(sectionObject).length > 0) {
130
+ validatedInputs[section.name] = sectionObject;
131
+ }
132
+ }
133
+ if (missingRequired.length > 0) {
134
+ throw new errors_1.MissingRequiredParamsError(missingRequired);
135
+ }
136
+ for (const [sectionName, sectionInputs] of Object.entries(inputs)) {
137
+ const section = sectionByName.get(sectionName);
138
+ if (!section) {
139
+ internal_logger_1.__logger.warn(`Unknown section "${sectionName}" will be ignored`);
140
+ continue;
141
+ }
142
+ if (sectionInputs === undefined || sectionInputs === null)
143
+ continue;
144
+ if (typeof sectionInputs !== 'object' || Array.isArray(sectionInputs))
145
+ continue;
146
+ const knownParamNames = new Set(section.parameters.map((param) => param.name));
147
+ for (const key of Object.keys(sectionInputs)) {
148
+ if (!knownParamNames.has(key)) {
149
+ internal_logger_1.__logger.warn(`Unknown parameter "${sectionName}.${key}" will be ignored`);
150
+ }
151
+ }
152
+ }
153
+ return validatedInputs;
154
+ }
155
+ /**
156
+ * Validates a single parameter value against its parameter definition.
157
+ * @param {IparamDefn} param - The parameter definition
158
+ * @param {any} value - The value to validate
159
+ * @param {string} [sectionDotParam] - Optional section.param identifier for error messages (e.g. processing_fee_configuration.fee_percentage)
160
+ * @throws {Error} If the value is invalid
161
+ */
162
+ validateParamValue(param, value, sectionDotParam = param.name) {
163
+ switch (param.type) {
164
+ case 'NUMBER':
165
+ this.validateNumber(sectionDotParam, value);
166
+ break;
167
+ case 'TEXT':
168
+ this.requireNonEmptyString(sectionDotParam, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.TEXT);
169
+ break;
170
+ case 'SECRET':
171
+ this.requireNonEmptyString(sectionDotParam, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.SECRET);
172
+ break;
173
+ case 'BOOLEAN':
174
+ this.validateBoolean(sectionDotParam, value);
175
+ break;
176
+ case 'URL':
177
+ this.validateUrl(sectionDotParam, value);
178
+ break;
179
+ case 'DATE':
180
+ this.validateDate(sectionDotParam, value);
181
+ break;
182
+ case 'DROPDOWN':
183
+ this.validateDropdown(param, value, sectionDotParam);
184
+ break;
185
+ case 'MULTISELECT_DROPDOWN':
186
+ this.validateMultiselectDropdown(param, value, sectionDotParam);
187
+ break;
188
+ default: {
189
+ const exhaustive = param.type;
190
+ throw new Error(`Parameter "${sectionDotParam}": unknown type "${exhaustive}"`);
191
+ }
192
+ }
193
+ }
194
+ /**
195
+ * Requires value to be a non-empty string, optionally with max length.
196
+ * @throws {Error} If not a string, empty after trim, or exceeds maxLength
197
+ */
198
+ requireNonEmptyString(paramName, value, maxLength) {
199
+ if (!validatorUtils.isNonEmptyString(value)) {
200
+ throw new Error(`Parameter "${paramName}": value must be a non-empty string`);
201
+ }
202
+ if (maxLength !== undefined && value.length > maxLength) {
203
+ throw new Error(`Parameter "${paramName}": value cannot exceed ${maxLength} characters`);
204
+ }
205
+ }
206
+ /**
207
+ * Requires value to be one of the allowed options.
208
+ */
209
+ requireInOptions(paramName, value, options) {
210
+ if (options.length === 0 || options.includes(value))
211
+ return;
212
+ throw new Error(`Parameter "${paramName}": value must be one of: ${options.join(', ')}`);
213
+ }
214
+ validateNumber(paramName, value) {
215
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
216
+ throw new Error(`Parameter "${paramName}": value must be a finite number`);
217
+ }
218
+ if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {
219
+ throw new Error(`Parameter "${paramName}": value must be within the range of ${Number.MIN_SAFE_INTEGER} to ${Number.MAX_SAFE_INTEGER}`);
220
+ }
221
+ }
222
+ validateBoolean(paramName, value) {
223
+ if (typeof value !== 'boolean') {
224
+ throw new Error(`Parameter "${paramName}": value must be a boolean`);
225
+ }
226
+ }
227
+ validateUrl(paramName, value) {
228
+ this.requireNonEmptyString(paramName, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.URL);
229
+ let parsed;
230
+ try {
231
+ parsed = new URL(value);
232
+ }
233
+ catch {
234
+ throw new Error(`Parameter "${paramName}": value must be a valid URL`);
235
+ }
236
+ if (!iparam_constants_1.IPARAM_URL_ALLOWED_PROTOCOLS.some((p) => p === parsed.protocol)) {
237
+ throw new Error(`Parameter "${paramName}": value must be a valid URL with protocol ${iparam_constants_1.IPARAM_URL_ALLOWED_PROTOCOLS.join(' or ')}`);
238
+ }
239
+ }
240
+ validateDate(paramName, value) {
241
+ this.requireNonEmptyString(paramName, value, iparam_constants_1.IPARAM_VALUE_MAX_LENGTHS.DATE);
242
+ const str = value;
243
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(str)) {
244
+ throw new Error(`Parameter "${paramName}": value must be a valid date in YYYY-MM-DD format (e.g., 2025-12-31)`);
245
+ }
246
+ const [y, m, d] = str.split('-').map(Number);
247
+ const dateObj = new Date(Date.UTC(y, m - 1, d));
248
+ if (isNaN(dateObj.getTime()) ||
249
+ dateObj.getUTCFullYear() !== y ||
250
+ dateObj.getUTCMonth() !== m - 1 ||
251
+ dateObj.getUTCDate() !== d) {
252
+ throw new Error(`Parameter "${paramName}": value must be a valid date in YYYY-MM-DD format (e.g., 2025-12-31)`);
253
+ }
254
+ }
255
+ validateDropdown(param, value, sectionDotParam) {
256
+ if (typeof value !== 'string') {
257
+ throw new Error(`Parameter "${sectionDotParam}": value must be a string for DROPDOWN type`);
258
+ }
259
+ this.requireNonEmptyString(sectionDotParam, value);
260
+ if (param.options)
261
+ this.requireInOptions(sectionDotParam, value, param.options);
262
+ }
263
+ validateMultiselectDropdown(param, value, sectionDotParam) {
264
+ if (!Array.isArray(value)) {
265
+ throw new Error(`Parameter "${sectionDotParam}": value must be an array of strings for MULTISELECT_DROPDOWN type`);
266
+ }
267
+ if (value.length === 0) {
268
+ throw new Error(`Parameter "${sectionDotParam}": value must be a non-empty array of strings for MULTISELECT_DROPDOWN type`);
269
+ }
270
+ const seenTrimmed = new Set();
271
+ for (let i = 0; i < value.length; i++) {
272
+ try {
273
+ this.requireNonEmptyString(sectionDotParam, value[i]);
274
+ if (param.options)
275
+ this.requireInOptions(sectionDotParam, value[i], param.options);
276
+ }
277
+ catch (error) {
278
+ const msg = error.message.replace(/\bvalue\b/g, `value array item at index ${i}`);
279
+ throw new Error(msg);
280
+ }
281
+ const trimmed = value[i].trim();
282
+ if (seenTrimmed.has(trimmed)) {
283
+ throw new Error(`Parameter "${sectionDotParam}": multiselect value must not contain duplicate entries`);
284
+ }
285
+ seenTrimmed.add(trimmed);
286
+ }
287
+ }
288
+ }
289
+ exports.IparamInputsValidator = IparamInputsValidator;