@coinbase-sample/prime-sdk-ts 0.8.2 → 0.10.0
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.
- package/dist/advancedTransfers/index.js +103 -0
- package/dist/advancedTransfers/types.js +2 -0
- package/dist/clients/clientWithServices.js +14 -0
- package/dist/constants.js +1 -1
- package/dist/financing/index.js +73 -0
- package/dist/futures/index.js +12 -0
- package/dist/index.js +3 -1
- package/dist/model/{CreateAddressGroup.js → ActiveLiquidationSummary.js} +1 -1
- package/dist/model/{DateOfBirth.js → AdvancedTransfer.js} +1 -1
- package/dist/model/{GetWalletAddressesResponse.js → BetaCrossMarginPrimeDerivativesEquityBreakdown.js} +1 -1
- package/dist/model/{StakingInputs.js → BetaCrossMarginPrimeMarginSummary.js} +1 -1
- package/dist/model/BetaCrossMarginPrimeRiskNettingInfo.js +21 -0
- package/dist/model/BetaCrossMarginPrimeSpotEquityBreakdown.js +21 -0
- package/dist/model/BetaCrossMarginPrimeXMPosition.js +21 -0
- package/dist/model/BetaCrossMarginRiskParameters.js +21 -0
- package/dist/model/BetaGetCrossMarginPrimeOverviewResponse.js +21 -0
- package/dist/model/BetaGetCrossMarginRiskParametersResponse.js +21 -0
- package/dist/model/BetaGetMarketDataResponse.js +21 -0
- package/dist/model/BetaMarketData.js +21 -0
- package/dist/model/BetaPrimeXMMarginCallThresholds.js +21 -0
- package/dist/model/BetaPrimeXMMarginRequirementBreakdown.js +21 -0
- package/dist/model/BetaPrimeXMMarginThreshold.js +21 -0
- package/dist/model/BetaPrimeXMOffsetCreditBreakdown.js +21 -0
- package/dist/model/BetaSetFundingSettingsResponse.js +21 -0
- package/dist/model/BetaTierPairRateEntry.js +21 -0
- package/dist/model/BlindMatchMetadata.js +21 -0
- package/dist/model/CancelAdvancedTransferResponse.js +21 -0
- package/dist/model/CommissionDetailTotal.js +21 -0
- package/dist/model/CreateAdvancedTransferRequest.js +21 -0
- package/dist/model/CreateAdvancedTransferResponse.js +21 -0
- package/dist/model/CrossMarginPrimeDerivativesEquityBreakdown.js +21 -0
- package/dist/model/CrossMarginPrimeMarginSummary.js +21 -0
- package/dist/model/CrossMarginPrimeRiskNettingInfo.js +21 -0
- package/dist/model/CrossMarginPrimeSpotEquityBreakdown.js +21 -0
- package/dist/model/CrossMarginPrimeXMPosition.js +21 -0
- package/dist/model/CrossMarginRiskParameters.js +21 -0
- package/dist/model/FcmScheduledMaintenance.js +21 -0
- package/dist/model/FcmTradingSessionDetails.js +21 -0
- package/dist/model/FundMovement.js +21 -0
- package/dist/model/FutureProductDetails.js +21 -0
- package/dist/model/GetCrossMarginPrimeOverviewResponse.js +21 -0
- package/dist/model/GetCrossMarginRiskParametersResponse.js +21 -0
- package/dist/model/GetFcmEquityResponse.js +21 -0
- package/dist/model/GetMarketDataResponse.js +21 -0
- package/dist/model/GetTransactionTravelRuleDataResponse.js +21 -0
- package/dist/model/ListAdvancedTransferTransactionsResponse.js +21 -0
- package/dist/model/ListAdvancedTransfersResponse.js +21 -0
- package/dist/model/MarketData.js +21 -0
- package/dist/model/PerpetualProductDetails.js +21 -0
- package/dist/model/PrimeXMMarginCallThresholds.js +21 -0
- package/dist/model/PrimeXMMarginRequirementBreakdown.js +21 -0
- package/dist/model/PrimeXMMarginThreshold.js +21 -0
- package/dist/model/PrimeXMOffsetCreditBreakdown.js +21 -0
- package/dist/model/SetFundingSettingsRequest.js +21 -0
- package/dist/model/SetFundingSettingsResponse.js +21 -0
- package/dist/model/TierPairRateEntry.js +21 -0
- package/dist/model/ValidatorAllocation.js +21 -0
- package/dist/model/ValidatorUnstakePreview.js +21 -0
- package/dist/model/enums/AdvancedTransferState.js +34 -0
- package/dist/model/enums/AdvancedTransferType.js +29 -0
- package/dist/model/enums/BetaPrimeXMControlStatus.js +32 -0
- package/dist/model/enums/BetaPrimeXMHealthStatus.js +36 -0
- package/dist/model/enums/BetaPrimeXMMarginLevel.js +34 -0
- package/dist/model/enums/BetaPrimeXMMarginRequirementType.js +31 -0
- package/dist/model/enums/BetaPrimeXMMarginThresholdType.js +32 -0
- package/dist/model/enums/ContractExpiryType.js +31 -0
- package/dist/model/enums/ExpiringContractStatus.js +31 -0
- package/dist/model/enums/FcmMarginHealthState.js +33 -0
- package/dist/model/enums/FcmTradingSessionClosedReason.js +32 -0
- package/dist/model/enums/FcmTradingSessionState.js +34 -0
- package/dist/model/enums/PrimeXMControlStatus.js +32 -0
- package/dist/model/enums/PrimeXMHealthStatus.js +36 -0
- package/dist/model/enums/PrimeXMMarginLevel.js +34 -0
- package/dist/model/enums/PrimeXMMarginRequirementType.js +31 -0
- package/dist/model/enums/PrimeXMMarginThresholdType.js +32 -0
- package/dist/model/enums/ProductType.js +30 -0
- package/dist/model/enums/RewardSubtype.js +2 -1
- package/dist/model/enums/RiskManagementType.js +31 -0
- package/dist/model/enums/SecondaryPermission.js +31 -0
- package/dist/model/enums/UserRole.js +2 -1
- package/dist/model/enums/XMLiquidationStatus.js +34 -0
- package/dist/model/enums/index.js +34 -2
- package/dist/model/primeBetaSetFundingSettingsRequest.js +21 -0
- package/dist/services.js +3 -1
- package/dist/shared/paginatedResponse.js +2 -0
- package/dist/transactions/index.js +13 -0
- package/dist/types/advancedTransfers/index.d.ts +31 -0
- package/dist/types/advancedTransfers/types.d.ts +46 -0
- package/dist/types/clients/clientWithServices.d.ts +10 -0
- package/dist/types/clients/clientWithServicesTypes.d.ts +5 -0
- package/dist/types/constants.d.ts +1 -1
- package/dist/types/financing/index.d.ts +9 -1
- package/dist/types/financing/types.d.ts +26 -1
- package/dist/types/futures/index.d.ts +4 -2
- package/dist/types/futures/types.d.ts +5 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/model/ActiveLiquidationSummary.d.ts +31 -0
- package/dist/types/model/{TravelRuleEntry.d.ts → AdvancedTransfer.d.ts} +11 -16
- package/dist/types/model/BetaCrossMarginPrimeDerivativesEquityBreakdown.d.ts +40 -0
- package/dist/types/model/BetaCrossMarginPrimeMarginSummary.d.ts +100 -0
- package/dist/types/model/BetaCrossMarginPrimeRiskNettingInfo.d.ts +51 -0
- package/dist/types/model/BetaCrossMarginPrimeSpotEquityBreakdown.d.ts +44 -0
- package/dist/types/model/BetaCrossMarginPrimeXMPosition.d.ts +84 -0
- package/dist/types/model/BetaCrossMarginRiskParameters.d.ts +72 -0
- package/dist/types/model/BetaGetCrossMarginPrimeOverviewResponse.d.ts +31 -0
- package/dist/types/model/BetaGetCrossMarginRiskParametersResponse.d.ts +43 -0
- package/dist/types/model/BetaGetMarketDataResponse.d.ts +28 -0
- package/dist/types/model/BetaMarketData.d.ts +45 -0
- package/dist/types/model/BetaPrimeXMMarginCallThresholds.d.ts +42 -0
- package/dist/types/model/BetaPrimeXMMarginRequirementBreakdown.d.ts +41 -0
- package/dist/types/model/BetaPrimeXMMarginThreshold.d.ts +26 -0
- package/dist/types/model/BetaPrimeXMOffsetCreditBreakdown.d.ts +45 -0
- package/dist/types/model/BetaSetFundingSettingsResponse.d.ts +36 -0
- package/dist/types/model/BetaTierPairRateEntry.d.ts +36 -0
- package/dist/types/model/BlindMatchMetadata.d.ts +37 -0
- package/dist/types/model/CancelAdvancedTransferResponse.d.ts +28 -0
- package/dist/types/model/CommissionDetailTotal.d.ts +40 -0
- package/dist/types/model/{CreateAddressGroup.d.ts → CreateAdvancedTransferRequest.d.ts} +7 -7
- package/dist/types/model/{DateOfBirth.d.ts → CreateAdvancedTransferResponse.d.ts} +7 -5
- package/dist/types/model/CrossMarginOverview.d.ts +2 -0
- package/dist/types/model/CrossMarginPrimeDerivativesEquityBreakdown.d.ts +40 -0
- package/dist/types/model/CrossMarginPrimeMarginSummary.d.ts +100 -0
- package/dist/types/model/CrossMarginPrimeRiskNettingInfo.d.ts +51 -0
- package/dist/types/model/CrossMarginPrimeSpotEquityBreakdown.d.ts +44 -0
- package/dist/types/model/CrossMarginPrimeXMPosition.d.ts +84 -0
- package/dist/types/model/CrossMarginRiskParameters.d.ts +72 -0
- package/dist/types/model/EntityUser.d.ts +9 -0
- package/dist/types/model/{StakingInputs.d.ts → FcmScheduledMaintenance.d.ts} +8 -4
- package/dist/types/model/FcmTradingSessionDetails.d.ts +51 -0
- package/dist/types/model/Fill.d.ts +4 -0
- package/dist/types/model/FundMovement.d.ts +30 -0
- package/dist/types/model/FutureProductDetails.d.ts +59 -0
- package/dist/types/model/GetCrossMarginPrimeOverviewResponse.d.ts +31 -0
- package/dist/types/model/GetCrossMarginRiskParametersResponse.d.ts +43 -0
- package/dist/types/model/GetFcmEquityResponse.d.ts +37 -0
- package/dist/types/model/GetFcmRiskLimitsResponse.d.ts +6 -0
- package/dist/types/model/{GetWalletAddressesResponse.d.ts → GetMarketDataResponse.d.ts} +8 -5
- package/dist/types/model/GetTransactionTravelRuleDataResponse.d.ts +31 -0
- package/dist/types/model/ListAdvancedTransferTransactionsResponse.d.ts +29 -0
- package/dist/types/model/ListAdvancedTransfersResponse.d.ts +28 -0
- package/dist/types/model/MarketData.d.ts +45 -0
- package/dist/types/model/NetworkDetails.d.ts +12 -0
- package/dist/types/model/Order.d.ts +4 -0
- package/dist/types/model/PerpetualProductDetails.d.ts +41 -0
- package/dist/types/model/PortfolioUser.d.ts +9 -0
- package/dist/types/model/PreviewUnstakeResponse.d.ts +17 -0
- package/dist/types/model/PrimeXMMarginCallThresholds.d.ts +42 -0
- package/dist/types/model/PrimeXMMarginRequirementBreakdown.d.ts +41 -0
- package/dist/types/model/PrimeXMMarginThreshold.d.ts +26 -0
- package/dist/types/model/PrimeXMOffsetCreditBreakdown.d.ts +45 -0
- package/dist/types/model/Product.d.ts +6 -0
- package/dist/types/model/QuoteResponse.d.ts +4 -0
- package/dist/types/model/RFQ.d.ts +4 -0
- package/dist/types/model/SetFundingSettingsRequest.d.ts +44 -0
- package/dist/types/model/SetFundingSettingsResponse.d.ts +36 -0
- package/dist/types/model/TierPairRateEntry.d.ts +36 -0
- package/dist/types/model/ValidatorAllocation.d.ts +32 -0
- package/dist/types/model/ValidatorUnstakePreview.d.ts +40 -0
- package/dist/types/model/WalletUnstakeInputs.d.ts +5 -0
- package/dist/types/model/XMRiskNettingInfo.d.ts +2 -2
- package/dist/types/model/enums/AdvancedTransferState.d.ts +30 -0
- package/dist/types/model/enums/AdvancedTransferType.d.ts +25 -0
- package/dist/types/model/enums/BetaPrimeXMControlStatus.d.ts +28 -0
- package/dist/types/model/enums/BetaPrimeXMHealthStatus.d.ts +32 -0
- package/dist/types/model/enums/BetaPrimeXMMarginLevel.d.ts +30 -0
- package/dist/types/model/enums/BetaPrimeXMMarginRequirementType.d.ts +27 -0
- package/dist/types/model/enums/BetaPrimeXMMarginThresholdType.d.ts +28 -0
- package/dist/types/model/enums/ContractExpiryType.d.ts +27 -0
- package/dist/types/model/enums/ExpiringContractStatus.d.ts +27 -0
- package/dist/types/model/enums/FcmMarginHealthState.d.ts +29 -0
- package/dist/types/model/enums/FcmTradingSessionClosedReason.d.ts +28 -0
- package/dist/types/model/enums/FcmTradingSessionState.d.ts +30 -0
- package/dist/types/model/enums/PrimeXMControlStatus.d.ts +28 -0
- package/dist/types/model/enums/PrimeXMHealthStatus.d.ts +32 -0
- package/dist/types/model/enums/PrimeXMMarginLevel.d.ts +30 -0
- package/dist/types/model/enums/PrimeXMMarginRequirementType.d.ts +27 -0
- package/dist/types/model/enums/PrimeXMMarginThresholdType.d.ts +28 -0
- package/dist/types/model/{VASP.d.ts → enums/ProductType.d.ts} +6 -7
- package/dist/types/model/enums/RewardSubtype.d.ts +3 -2
- package/dist/types/model/enums/RiskManagementType.d.ts +27 -0
- package/dist/types/model/{TravelRuleWalletDetails.d.ts → enums/SecondaryPermission.d.ts} +7 -8
- package/dist/types/model/enums/UserRole.d.ts +3 -2
- package/dist/types/model/enums/XMLiquidationStatus.d.ts +30 -0
- package/dist/types/model/enums/index.d.ts +16 -0
- package/dist/types/model/googleTypeDate.d.ts +1 -1
- package/dist/types/model/index.d.ts +35 -4
- package/dist/types/model/primeBetaSetFundingSettingsRequest.d.ts +44 -0
- package/dist/types/services.d.ts +1 -0
- package/dist/types/shared/paginatedResponse.d.ts +6 -0
- package/dist/types/transactions/index.d.ts +3 -1
- package/dist/types/transactions/types.d.ts +6 -1
- package/package.json +2 -2
- package/dist/model/TravelRuleEntry.js +0 -21
- package/dist/model/TravelRuleWalletDetails.js +0 -21
- package/dist/model/VASP.js +0 -21
- package/dist/model/enumPrefixes.js +0 -330
- package/dist/shared/dynamicEnumValidation.js +0 -184
- package/dist/shared/dynamicEnumValidation.old.js +0 -746
- package/dist/shared/enumHelpers.js +0 -219
- package/dist/shared/enumRegistry.js +0 -153
- package/dist/shared/enumValidationCore.js +0 -194
- package/dist/shared/enumValidators.js +0 -115
- package/dist/shared/fieldMapping.js +0 -242
- package/dist/shared/serviceContext.js +0 -157
- package/dist/types/model/enumPrefixes.d.ts +0 -206
- package/dist/types/shared/dynamicEnumValidation.d.ts +0 -48
- package/dist/types/shared/dynamicEnumValidation.old.d.ts +0 -143
- package/dist/types/shared/enumHelpers.d.ts +0 -135
- package/dist/types/shared/enumRegistry.d.ts +0 -74
- package/dist/types/shared/enumValidationCore.d.ts +0 -68
- package/dist/types/shared/enumValidators.d.ts +0 -117
- package/dist/types/shared/fieldMapping.d.ts +0 -35
- package/dist/types/shared/serviceContext.d.ts +0 -46
|
@@ -1,746 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright 2025-present Coinbase Global, Inc.
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
-
if (k2 === undefined) k2 = k;
|
|
19
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
-
}
|
|
23
|
-
Object.defineProperty(o, k2, desc);
|
|
24
|
-
}) : (function(o, m, k, k2) {
|
|
25
|
-
if (k2 === undefined) k2 = k;
|
|
26
|
-
o[k2] = m[k];
|
|
27
|
-
}));
|
|
28
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
-
}) : function(o, v) {
|
|
31
|
-
o["default"] = v;
|
|
32
|
-
});
|
|
33
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
-
var ownKeys = function(o) {
|
|
35
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
-
var ar = [];
|
|
37
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
-
return ar;
|
|
39
|
-
};
|
|
40
|
-
return ownKeys(o);
|
|
41
|
-
};
|
|
42
|
-
return function (mod) {
|
|
43
|
-
if (mod && mod.__esModule) return mod;
|
|
44
|
-
var result = {};
|
|
45
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
-
__setModuleDefault(result, mod);
|
|
47
|
-
return result;
|
|
48
|
-
};
|
|
49
|
-
})();
|
|
50
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.enumRegistry = exports.DynamicEnumValidationError = void 0;
|
|
52
|
-
exports.validateRequestEnums = validateRequestEnums;
|
|
53
|
-
exports.validateAndNormalizeRequest = validateAndNormalizeRequest;
|
|
54
|
-
exports.setDynamicValidationConfig = setDynamicValidationConfig;
|
|
55
|
-
exports.getDynamicValidationConfig = getDynamicValidationConfig;
|
|
56
|
-
exports.dynamicValidateRequest = dynamicValidateRequest;
|
|
57
|
-
exports.getEnumInfo = getEnumInfo;
|
|
58
|
-
/**
|
|
59
|
-
* Dynamic enum validation system that automatically discovers and validates
|
|
60
|
-
* enum fields in request objects without manual service-specific configuration.
|
|
61
|
-
*
|
|
62
|
-
* This approach is more scalable and maintainable than manual validation rules.
|
|
63
|
-
*/
|
|
64
|
-
const enumHelpers_1 = require("./enumHelpers");
|
|
65
|
-
const enumPrefixes_1 = require("../model/enumPrefixes");
|
|
66
|
-
// Import all enums dynamically
|
|
67
|
-
const AllEnums = __importStar(require("../model/enums/"));
|
|
68
|
-
/**
|
|
69
|
-
* Error thrown when a request contains invalid enum values
|
|
70
|
-
*/
|
|
71
|
-
class DynamicEnumValidationError extends Error {
|
|
72
|
-
constructor(field, value, enumName, validValues, validKeys) {
|
|
73
|
-
const validValuesStr = validValues.join(', ');
|
|
74
|
-
const validKeysStr = validKeys
|
|
75
|
-
? ` Valid keys: ${validKeys.join(', ')}.`
|
|
76
|
-
: '';
|
|
77
|
-
super(`Invalid ${field} (${enumName}): "${value}". Valid values: ${validValuesStr}.${validKeysStr} ` +
|
|
78
|
-
`Consider using enum helpers for automatic normalization.`);
|
|
79
|
-
this.field = field;
|
|
80
|
-
this.value = value;
|
|
81
|
-
this.enumName = enumName;
|
|
82
|
-
this.validValues = validValues;
|
|
83
|
-
this.validKeys = validKeys;
|
|
84
|
-
this.name = 'DynamicEnumValidationError';
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
exports.DynamicEnumValidationError = DynamicEnumValidationError;
|
|
88
|
-
/**
|
|
89
|
-
* Registry of all available enums for dynamic lookup
|
|
90
|
-
*/
|
|
91
|
-
class EnumRegistry {
|
|
92
|
-
constructor() {
|
|
93
|
-
this.enumMap = new Map();
|
|
94
|
-
this.enumNameMap = new Map();
|
|
95
|
-
this.registerAllEnums();
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Automatically register all enums from the model/enums directory
|
|
99
|
-
*/
|
|
100
|
-
registerAllEnums() {
|
|
101
|
-
Object.entries(AllEnums).forEach(([enumName, enumObject]) => {
|
|
102
|
-
if (this.isValidEnum(enumObject)) {
|
|
103
|
-
this.enumMap.set(enumName, enumObject);
|
|
104
|
-
this.enumNameMap.set(enumObject, enumName);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Check if an object is a valid enum
|
|
110
|
-
*/
|
|
111
|
-
isValidEnum(obj) {
|
|
112
|
-
return (obj &&
|
|
113
|
-
typeof obj === 'object' &&
|
|
114
|
-
Object.values(obj).every((val) => typeof val === 'string') &&
|
|
115
|
-
Object.keys(obj).length > 0);
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Get enum by name
|
|
119
|
-
*/
|
|
120
|
-
getEnum(enumName) {
|
|
121
|
-
return this.enumMap.get(enumName);
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Get enum name for a given enum object
|
|
125
|
-
*/
|
|
126
|
-
getEnumName(enumObject) {
|
|
127
|
-
return this.enumNameMap.get(enumObject);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Find enum that contains a specific value
|
|
131
|
-
*/
|
|
132
|
-
findEnumByValue(value) {
|
|
133
|
-
const normalizedValue = (0, enumHelpers_1.normalizeEnumValue)(value);
|
|
134
|
-
for (const [enumName, enumObject] of this.enumMap) {
|
|
135
|
-
if (Object.values(enumObject).includes(normalizedValue)) {
|
|
136
|
-
return { enum: enumObject, name: enumName };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return undefined;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Find enum that contains a specific key
|
|
143
|
-
*/
|
|
144
|
-
findEnumByKey(key) {
|
|
145
|
-
const normalizedKey = (0, enumHelpers_1.normalizeEnumValue)(key);
|
|
146
|
-
for (const [enumName, enumObject] of this.enumMap) {
|
|
147
|
-
for (const enumKey of Object.keys(enumObject)) {
|
|
148
|
-
if ((0, enumHelpers_1.normalizeEnumValue)(enumKey) === normalizedKey) {
|
|
149
|
-
return { enum: enumObject, name: enumName };
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return undefined;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Get all registered enum names
|
|
157
|
-
*/
|
|
158
|
-
getAllEnumNames() {
|
|
159
|
-
return Array.from(this.enumMap.keys());
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Validate a value against a specific enum with prefix handling
|
|
163
|
-
*/
|
|
164
|
-
validateEnumValue(enumName, value) {
|
|
165
|
-
const enumObject = this.getEnum(enumName);
|
|
166
|
-
if (!enumObject) {
|
|
167
|
-
return { valid: false, error: `Unknown enum: ${enumName}` };
|
|
168
|
-
}
|
|
169
|
-
// Use the enhanced validation with prefix handling
|
|
170
|
-
return validateEnumValueWithPrefix(enumObject, value);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Global enum registry instance
|
|
174
|
-
const enumRegistry = new EnumRegistry();
|
|
175
|
-
exports.enumRegistry = enumRegistry;
|
|
176
|
-
/**
|
|
177
|
-
* Cache for storing analyzed request types to avoid repeated reflection
|
|
178
|
-
*/
|
|
179
|
-
const requestTypeCache = new Map();
|
|
180
|
-
/**
|
|
181
|
-
* Analyzes a request object to identify enum fields dynamically
|
|
182
|
-
* This uses runtime type inspection and pattern matching
|
|
183
|
-
*/
|
|
184
|
-
function analyzeRequestObject(request) {
|
|
185
|
-
// Create a simple cache key based on the field names and types
|
|
186
|
-
const cacheKey = Object.keys(request || {})
|
|
187
|
-
.sort()
|
|
188
|
-
.join(',');
|
|
189
|
-
if (requestTypeCache.has(cacheKey)) {
|
|
190
|
-
return requestTypeCache.get(cacheKey);
|
|
191
|
-
}
|
|
192
|
-
const enumFields = [];
|
|
193
|
-
if (!request || typeof request !== 'object') {
|
|
194
|
-
return enumFields;
|
|
195
|
-
}
|
|
196
|
-
Object.entries(request).forEach(([fieldName, value]) => {
|
|
197
|
-
const fieldInfo = analyzeField(fieldName, value);
|
|
198
|
-
if (fieldInfo) {
|
|
199
|
-
enumFields.push(fieldInfo);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
// Cache the result
|
|
203
|
-
requestTypeCache.set(cacheKey, enumFields);
|
|
204
|
-
return enumFields;
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Analyzes a single field to determine if it's an enum
|
|
208
|
-
*/
|
|
209
|
-
function analyzeField(fieldName, value) {
|
|
210
|
-
if (value === undefined || value === null) {
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
// Handle array values
|
|
214
|
-
if (Array.isArray(value)) {
|
|
215
|
-
const firstNonNullValue = value.find((v) => v !== null && v !== undefined);
|
|
216
|
-
if (firstNonNullValue && typeof firstNonNullValue === 'string') {
|
|
217
|
-
const enumInfo = detectEnumType(fieldName, firstNonNullValue);
|
|
218
|
-
if (enumInfo) {
|
|
219
|
-
return {
|
|
220
|
-
fieldName,
|
|
221
|
-
enumName: enumInfo.name,
|
|
222
|
-
isOptional: false,
|
|
223
|
-
isArray: true,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
return null;
|
|
228
|
-
}
|
|
229
|
-
// Handle string values (potential enums)
|
|
230
|
-
if (typeof value === 'string') {
|
|
231
|
-
const enumInfo = detectEnumType(fieldName, value);
|
|
232
|
-
if (enumInfo) {
|
|
233
|
-
return {
|
|
234
|
-
fieldName,
|
|
235
|
-
enumName: enumInfo.name,
|
|
236
|
-
isOptional: false,
|
|
237
|
-
isArray: false,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Detects the enum type for a field based on field name patterns and value analysis
|
|
245
|
-
*/
|
|
246
|
-
function detectEnumType(fieldName, value) {
|
|
247
|
-
// Strategy 1: Direct field name to enum name mapping
|
|
248
|
-
const directMapping = getDirectEnumMapping(fieldName);
|
|
249
|
-
if (directMapping) {
|
|
250
|
-
const enumObject = enumRegistry.getEnum(directMapping);
|
|
251
|
-
if (enumObject) {
|
|
252
|
-
// If we have a confident field mapping, use it even if value doesn't match
|
|
253
|
-
// This allows validation to catch invalid values
|
|
254
|
-
return { enum: enumObject, name: directMapping };
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// Strategy 2: Find enum by value (exact match)
|
|
258
|
-
const enumByValue = enumRegistry.findEnumByValue(value);
|
|
259
|
-
if (enumByValue) {
|
|
260
|
-
return enumByValue;
|
|
261
|
-
}
|
|
262
|
-
// Strategy 3: Find enum by value with prefix normalization
|
|
263
|
-
const enumByValueWithPrefix = findEnumWithPrefixHandling(value);
|
|
264
|
-
if (enumByValueWithPrefix) {
|
|
265
|
-
return enumByValueWithPrefix;
|
|
266
|
-
}
|
|
267
|
-
// Strategy 4: Find enum by key (treating value as a potential key)
|
|
268
|
-
const enumByKey = enumRegistry.findEnumByKey(value);
|
|
269
|
-
if (enumByKey) {
|
|
270
|
-
return enumByKey;
|
|
271
|
-
}
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Common enum prefixes that can be automatically added or removed
|
|
276
|
-
* Now sourced from auto-generated analysis of OpenAPI enums
|
|
277
|
-
*/
|
|
278
|
-
// Sort prefixes by length (longest first) to prevent collision issues
|
|
279
|
-
// This ensures that "OTHER_ACTIVITY_" is checked before "OTHER_"
|
|
280
|
-
const ENUM_PREFIXES = [...enumPrefixes_1.GENERATED_ENUM_PREFIXES].sort((a, b) => b.length - a.length);
|
|
281
|
-
/**
|
|
282
|
-
* Finds an enum that matches the value with intelligent prefix handling
|
|
283
|
-
*/
|
|
284
|
-
function findEnumWithPrefixHandling(value) {
|
|
285
|
-
const normalizedValue = (0, enumHelpers_1.normalizeEnumValue)(value);
|
|
286
|
-
// Try to find enums where adding common prefixes makes a match
|
|
287
|
-
for (const enumName of enumRegistry.getAllEnumNames()) {
|
|
288
|
-
const enumObject = enumRegistry.getEnum(enumName);
|
|
289
|
-
if (!enumObject)
|
|
290
|
-
continue;
|
|
291
|
-
const enumValues = Object.values(enumObject);
|
|
292
|
-
// Check if any enum value matches when we add a prefix to the input
|
|
293
|
-
for (const prefix of ENUM_PREFIXES) {
|
|
294
|
-
const prefixedValue = `${prefix}${normalizedValue}`;
|
|
295
|
-
if (enumValues.includes(prefixedValue)) {
|
|
296
|
-
return { enum: enumObject, name: enumName };
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
// Check if any enum value matches when we remove a prefix from enum values
|
|
300
|
-
for (const enumValue of enumValues) {
|
|
301
|
-
for (const prefix of ENUM_PREFIXES) {
|
|
302
|
-
if (enumValue.startsWith(prefix)) {
|
|
303
|
-
const unprefixedEnumValue = enumValue.substring(prefix.length);
|
|
304
|
-
if (unprefixedEnumValue === normalizedValue) {
|
|
305
|
-
return { enum: enumObject, name: enumName };
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Enhanced enum validation that handles prefix normalization
|
|
315
|
-
*/
|
|
316
|
-
function validateEnumValueWithPrefix(enumObject, value) {
|
|
317
|
-
const normalizedInput = (0, enumHelpers_1.normalizeEnumValue)(value);
|
|
318
|
-
// Direct value match (no prefix handling needed)
|
|
319
|
-
if (Object.values(enumObject).includes(normalizedInput)) {
|
|
320
|
-
return { valid: true, normalizedValue: normalizedInput };
|
|
321
|
-
}
|
|
322
|
-
// Key-based lookup (no prefix handling needed)
|
|
323
|
-
for (const [key, enumValue] of Object.entries(enumObject)) {
|
|
324
|
-
if ((0, enumHelpers_1.normalizeEnumValue)(key) === normalizedInput) {
|
|
325
|
-
return { valid: true, normalizedValue: enumValue };
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
// Prefix-aware validation
|
|
329
|
-
const enumValues = Object.values(enumObject);
|
|
330
|
-
// Try adding prefixes to the input value
|
|
331
|
-
for (const prefix of ENUM_PREFIXES) {
|
|
332
|
-
const prefixedValue = `${prefix}${normalizedInput}`;
|
|
333
|
-
if (enumValues.includes(prefixedValue)) {
|
|
334
|
-
return { valid: true, normalizedValue: prefixedValue };
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// Try removing prefixes from enum values to match input
|
|
338
|
-
for (const enumValue of enumValues) {
|
|
339
|
-
for (const prefix of ENUM_PREFIXES) {
|
|
340
|
-
if (enumValue.startsWith(prefix)) {
|
|
341
|
-
const unprefixedEnumValue = enumValue.substring(prefix.length);
|
|
342
|
-
if (unprefixedEnumValue === normalizedInput) {
|
|
343
|
-
return { valid: true, normalizedValue: enumValue };
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
return {
|
|
349
|
-
valid: false,
|
|
350
|
-
error: `No match found for "${value}" (tried with/without prefixes)`,
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Maps common field names to their corresponding enum types
|
|
355
|
-
*/
|
|
356
|
-
function getDirectEnumMapping(fieldName) {
|
|
357
|
-
const fieldNameLower = fieldName.toLowerCase();
|
|
358
|
-
// First try dynamic enum name matching
|
|
359
|
-
const dynamicMatch = findEnumByFieldName(fieldNameLower);
|
|
360
|
-
if (dynamicMatch) {
|
|
361
|
-
return dynamicMatch;
|
|
362
|
-
}
|
|
363
|
-
// Fall back to essential manual mappings for common patterns that don't follow naming conventions
|
|
364
|
-
// These should be conservative and only include non-ambiguous cases
|
|
365
|
-
const essentialMappings = {
|
|
366
|
-
// Common trading/order fields (most frequent use case)
|
|
367
|
-
side: 'OrderSide',
|
|
368
|
-
status: 'OrderStatus', // Default to OrderStatus, validation will catch mismatches
|
|
369
|
-
role: 'UserRole',
|
|
370
|
-
action: 'Action',
|
|
371
|
-
direction: 'SortDirection',
|
|
372
|
-
// Specific compound fields to prevent wrong mappings
|
|
373
|
-
orderside: 'OrderSide',
|
|
374
|
-
ordertype: 'OrderType',
|
|
375
|
-
orderstatus: 'OrderStatus',
|
|
376
|
-
wallettype: 'WalletType',
|
|
377
|
-
transactiontype: 'TransactionType',
|
|
378
|
-
activitytype: 'CustodyActivityType',
|
|
379
|
-
activitystatus: 'ActivityStatus',
|
|
380
|
-
// Note: 'type' still removed (too ambiguous - let value-based detection handle it)
|
|
381
|
-
};
|
|
382
|
-
return essentialMappings[fieldNameLower] || null;
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Generate intelligent field name variations for plural/singular matching
|
|
386
|
-
*/
|
|
387
|
-
function getFieldNameVariations(fieldName) {
|
|
388
|
-
const variations = [fieldName];
|
|
389
|
-
// Handle irregular plurals and common patterns
|
|
390
|
-
const irregularPlurals = {
|
|
391
|
-
categories: 'category',
|
|
392
|
-
statuses: 'status',
|
|
393
|
-
activities: 'activity',
|
|
394
|
-
entities: 'entity',
|
|
395
|
-
currencies: 'currency',
|
|
396
|
-
portfolios: 'portfolio',
|
|
397
|
-
};
|
|
398
|
-
const irregularSingulars = {
|
|
399
|
-
category: 'categories',
|
|
400
|
-
status: 'statuses',
|
|
401
|
-
activity: 'activities',
|
|
402
|
-
entity: 'entities',
|
|
403
|
-
currency: 'currencies',
|
|
404
|
-
portfolio: 'portfolios',
|
|
405
|
-
};
|
|
406
|
-
// Check irregular mappings first
|
|
407
|
-
if (irregularPlurals[fieldName]) {
|
|
408
|
-
variations.push(irregularPlurals[fieldName]);
|
|
409
|
-
}
|
|
410
|
-
if (irregularSingulars[fieldName]) {
|
|
411
|
-
variations.push(irregularSingulars[fieldName]);
|
|
412
|
-
}
|
|
413
|
-
// Handle regular -s plurals only if not already handled by irregular rules
|
|
414
|
-
if (!irregularPlurals[fieldName] && !irregularSingulars[fieldName]) {
|
|
415
|
-
if (fieldName.endsWith('s') && fieldName.length > 3) {
|
|
416
|
-
// Only remove 's' if it's likely a regular plural (not words ending in 's')
|
|
417
|
-
const withoutS = fieldName.slice(0, -1);
|
|
418
|
-
// Avoid false positives like "address" → "addres"
|
|
419
|
-
if (!fieldName.endsWith('ss') && !fieldName.endsWith('us')) {
|
|
420
|
-
variations.push(withoutS);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
// Add regular plural
|
|
425
|
-
variations.push(fieldName + 's');
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
return variations;
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Check if a value is valid for a specific enum (includes normalization)
|
|
432
|
-
*/
|
|
433
|
-
function isValueValidForEnum(value, enumObject) {
|
|
434
|
-
if (!value || !enumObject)
|
|
435
|
-
return false;
|
|
436
|
-
// Direct value match
|
|
437
|
-
if (Object.values(enumObject).includes(value))
|
|
438
|
-
return true;
|
|
439
|
-
// Direct key match
|
|
440
|
-
if (Object.keys(enumObject).includes(value))
|
|
441
|
-
return true;
|
|
442
|
-
// Normalized value matches
|
|
443
|
-
const normalizedValue = (0, enumHelpers_1.normalizeEnumValue)(value);
|
|
444
|
-
if (Object.values(enumObject).includes(normalizedValue))
|
|
445
|
-
return true;
|
|
446
|
-
// Check with prefix normalization
|
|
447
|
-
for (const prefix of ENUM_PREFIXES) {
|
|
448
|
-
const withPrefix = `${prefix}${normalizedValue}`;
|
|
449
|
-
if (Object.values(enumObject).includes(withPrefix))
|
|
450
|
-
return true;
|
|
451
|
-
}
|
|
452
|
-
return false;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Find enum with context awareness to resolve collisions
|
|
456
|
-
* Handles cases where multiple enums could match (e.g., ActivityStatus vs OrderStatus vs TransactionStatus)
|
|
457
|
-
*/
|
|
458
|
-
function findEnumWithContext(fieldName, allEnumNames) {
|
|
459
|
-
// Handle ambiguous suffixes that appear in multiple enums
|
|
460
|
-
const ambiguousSuffixes = ['status', 'type', 'category'];
|
|
461
|
-
const fieldLower = fieldName.toLowerCase();
|
|
462
|
-
// Check if this is an ambiguous field name
|
|
463
|
-
const isAmbiguous = ambiguousSuffixes.some((suffix) => fieldLower.endsWith(suffix) || fieldLower === suffix);
|
|
464
|
-
if (isAmbiguous) {
|
|
465
|
-
// For ambiguous cases, look for context clues in the field name
|
|
466
|
-
const contextClues = extractContextClues(fieldName);
|
|
467
|
-
// Find enum that best matches the context
|
|
468
|
-
const matches = allEnumNames.filter((enumName) => {
|
|
469
|
-
const enumLower = enumName.toLowerCase();
|
|
470
|
-
// Exact compound match (e.g., "activitystatus" → "ActivityStatus")
|
|
471
|
-
if (enumLower === fieldLower)
|
|
472
|
-
return true;
|
|
473
|
-
// Context-based matching
|
|
474
|
-
for (const clue of contextClues) {
|
|
475
|
-
if (enumLower.includes(clue) &&
|
|
476
|
-
enumLower.endsWith(fieldLower.split(/(?=[a-z])/).pop() || '')) {
|
|
477
|
-
return true;
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
return false;
|
|
481
|
-
});
|
|
482
|
-
// Return the most specific match
|
|
483
|
-
if (matches.length === 1) {
|
|
484
|
-
return matches[0];
|
|
485
|
-
}
|
|
486
|
-
// If multiple matches, prefer the longest/most specific one
|
|
487
|
-
if (matches.length > 1) {
|
|
488
|
-
return matches.reduce((longest, current) => current.length > longest.length ? current : longest);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
// Non-ambiguous cases: use careful substring matching
|
|
492
|
-
// Sort enums by name length (shortest first) to prefer simpler matches
|
|
493
|
-
const sortedEnumNames = allEnumNames
|
|
494
|
-
.slice()
|
|
495
|
-
.sort((a, b) => a.length - b.length);
|
|
496
|
-
for (const enumName of sortedEnumNames) {
|
|
497
|
-
const enumNameLower = enumName.toLowerCase();
|
|
498
|
-
// Only match if field name is a meaningful part of the enum name
|
|
499
|
-
// Avoid greedy matches like "side" matching "FcmPositionSide"
|
|
500
|
-
if (enumNameLower === fieldLower) {
|
|
501
|
-
return enumName; // Exact match
|
|
502
|
-
}
|
|
503
|
-
// Check if field name appears as a word boundary in enum name
|
|
504
|
-
// e.g., "side" should match "OrderSide" but not "FcmPositionSide"
|
|
505
|
-
const wordBoundaryRegex = new RegExp(`\\b${fieldLower}\\b`, 'i');
|
|
506
|
-
if (wordBoundaryRegex.test(enumName)) {
|
|
507
|
-
return enumName;
|
|
508
|
-
}
|
|
509
|
-
// Check for field name at the end of enum name (most common pattern)
|
|
510
|
-
if (enumNameLower.endsWith(fieldLower) && enumNameLower !== fieldLower) {
|
|
511
|
-
// Ensure it's not a substring within a word
|
|
512
|
-
const beforeField = enumNameLower.slice(0, -fieldLower.length);
|
|
513
|
-
if (beforeField.length > 0 && /[a-z]$/.test(beforeField)) {
|
|
514
|
-
continue; // Skip if it's part of a word
|
|
515
|
-
}
|
|
516
|
-
return enumName;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
return null;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Extract context clues from field names to resolve enum ambiguity
|
|
523
|
-
*/
|
|
524
|
-
function extractContextClues(fieldName) {
|
|
525
|
-
const clues = [];
|
|
526
|
-
const fieldLower = fieldName.toLowerCase();
|
|
527
|
-
// Extract prefix context (e.g., "activitystatus" → ["activity"])
|
|
528
|
-
const prefixMatch = fieldLower.match(/^([a-z]+?)(?:status|type|category)$/);
|
|
529
|
-
if (prefixMatch) {
|
|
530
|
-
clues.push(prefixMatch[1]);
|
|
531
|
-
}
|
|
532
|
-
// Extract camelCase components (e.g., "activityStatus" → ["activity"])
|
|
533
|
-
const camelComponents = fieldName
|
|
534
|
-
.replace(/([A-Z])/g, '_$1')
|
|
535
|
-
.toLowerCase()
|
|
536
|
-
.split('_')
|
|
537
|
-
.filter(Boolean);
|
|
538
|
-
clues.push(...camelComponents.slice(0, -1)); // Exclude the last component (status/type/category)
|
|
539
|
-
// Extract underscore/dash separated components
|
|
540
|
-
const separatedComponents = fieldName.toLowerCase().split(/[_-]+/);
|
|
541
|
-
clues.push(...separatedComponents.slice(0, -1));
|
|
542
|
-
return [...new Set(clues)]; // Remove duplicates
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Dynamically find enum name based on field name patterns
|
|
546
|
-
* Uses the enum registry to match field names to actual enum names
|
|
547
|
-
*/
|
|
548
|
-
function findEnumByFieldName(fieldName) {
|
|
549
|
-
const allEnumNames = enumRegistry.getAllEnumNames();
|
|
550
|
-
// Strategy 1: Direct name match (e.g., "ActivityCategory" field → "ActivityCategory" enum)
|
|
551
|
-
const exactMatch = allEnumNames.find((enumName) => enumName.toLowerCase() === fieldName.toLowerCase());
|
|
552
|
-
if (exactMatch)
|
|
553
|
-
return exactMatch;
|
|
554
|
-
// Strategy 2: Smart plural/singular variations
|
|
555
|
-
const variations = getFieldNameVariations(fieldName);
|
|
556
|
-
for (const enumName of allEnumNames) {
|
|
557
|
-
const enumNameLower = enumName.toLowerCase();
|
|
558
|
-
if (variations.includes(enumNameLower)) {
|
|
559
|
-
return enumName;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
// Strategy 3: Context-aware enum matching (handles collisions)
|
|
563
|
-
const contextMatch = findEnumWithContext(fieldName, allEnumNames);
|
|
564
|
-
if (contextMatch) {
|
|
565
|
-
return contextMatch;
|
|
566
|
-
}
|
|
567
|
-
// Strategy 4: Smart pattern matching for compound field names
|
|
568
|
-
// Handle cases like "activitycategory" → "ActivityCategory"
|
|
569
|
-
for (const enumName of allEnumNames) {
|
|
570
|
-
const enumWords = enumName
|
|
571
|
-
.toLowerCase()
|
|
572
|
-
.replace(/([A-Z])/g, ' $1')
|
|
573
|
-
.trim()
|
|
574
|
-
.split(' ');
|
|
575
|
-
const fieldWords = fieldName
|
|
576
|
-
.replace(/([A-Z])/g, ' $1')
|
|
577
|
-
.trim()
|
|
578
|
-
.split(/[\s_-]+/);
|
|
579
|
-
// Check if all field words are contained in enum words
|
|
580
|
-
const allWordsMatch = fieldWords.every((word) => enumWords.some((enumWord) => enumWord.includes(word) || word.includes(enumWord)));
|
|
581
|
-
if (allWordsMatch && fieldWords.length > 1) {
|
|
582
|
-
return enumName;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
return null;
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Validates and normalizes enum fields in a request object
|
|
589
|
-
*/
|
|
590
|
-
function validateRequestEnums(request, options = {}) {
|
|
591
|
-
const { strict = true, autoNormalize = true } = options;
|
|
592
|
-
if (!request || typeof request !== 'object') {
|
|
593
|
-
return { validatedRequest: request, errors: [] };
|
|
594
|
-
}
|
|
595
|
-
const validatedRequest = Object.assign({}, request);
|
|
596
|
-
const errors = [];
|
|
597
|
-
// Analyze the request to find enum fields
|
|
598
|
-
const enumFields = analyzeRequestObject(request);
|
|
599
|
-
// Validate each enum field
|
|
600
|
-
enumFields.forEach((fieldInfo) => {
|
|
601
|
-
const { fieldName, enumName, isArray } = fieldInfo;
|
|
602
|
-
const fieldValue = request[fieldName];
|
|
603
|
-
if (fieldValue === undefined || fieldValue === null) {
|
|
604
|
-
return; // Skip undefined/null values
|
|
605
|
-
}
|
|
606
|
-
if (!enumName) {
|
|
607
|
-
return; // Skip if we couldn't determine the enum type
|
|
608
|
-
}
|
|
609
|
-
try {
|
|
610
|
-
if (isArray && Array.isArray(fieldValue)) {
|
|
611
|
-
// Handle array of enum values
|
|
612
|
-
const validatedArray = [];
|
|
613
|
-
fieldValue.forEach((item, index) => {
|
|
614
|
-
if (typeof item === 'string') {
|
|
615
|
-
const validation = enumRegistry.validateEnumValue(enumName, item);
|
|
616
|
-
if (validation.valid && validation.normalizedValue) {
|
|
617
|
-
validatedArray.push(autoNormalize ? validation.normalizedValue : item);
|
|
618
|
-
}
|
|
619
|
-
else if (strict) {
|
|
620
|
-
errors.push(`${fieldName}[${index}]: ${validation.error}`);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
});
|
|
624
|
-
if (autoNormalize) {
|
|
625
|
-
validatedRequest[fieldName] = validatedArray;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
else if (typeof fieldValue === 'string') {
|
|
629
|
-
// Handle single enum value
|
|
630
|
-
const validation = enumRegistry.validateEnumValue(enumName, fieldValue);
|
|
631
|
-
if (validation.valid && validation.normalizedValue) {
|
|
632
|
-
if (autoNormalize) {
|
|
633
|
-
validatedRequest[fieldName] = validation.normalizedValue;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
else if (strict) {
|
|
637
|
-
const enumObject = enumRegistry.getEnum(enumName);
|
|
638
|
-
if (enumObject) {
|
|
639
|
-
throw new DynamicEnumValidationError(fieldName, fieldValue, enumName, Object.values(enumObject), Object.keys(enumObject));
|
|
640
|
-
}
|
|
641
|
-
else {
|
|
642
|
-
errors.push(`${fieldName}: ${validation.error}`);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
catch (error) {
|
|
648
|
-
if (error instanceof DynamicEnumValidationError) {
|
|
649
|
-
throw error; // Re-throw enum validation errors
|
|
650
|
-
}
|
|
651
|
-
errors.push(`${fieldName}: Unexpected validation error: ${error}`);
|
|
652
|
-
}
|
|
653
|
-
});
|
|
654
|
-
return { validatedRequest, errors };
|
|
655
|
-
}
|
|
656
|
-
/**
|
|
657
|
-
* Simplified validation function that throws on first error
|
|
658
|
-
*/
|
|
659
|
-
function validateAndNormalizeRequest(request) {
|
|
660
|
-
const result = validateRequestEnums(request, {
|
|
661
|
-
strict: true,
|
|
662
|
-
autoNormalize: true,
|
|
663
|
-
});
|
|
664
|
-
if (result.errors.length > 0) {
|
|
665
|
-
throw new DynamicEnumValidationError('request', 'multiple fields', 'various', [], result.errors);
|
|
666
|
-
}
|
|
667
|
-
return result.validatedRequest;
|
|
668
|
-
}
|
|
669
|
-
const defaultConfig = {
|
|
670
|
-
enabled: true,
|
|
671
|
-
strict: true,
|
|
672
|
-
autoNormalize: true,
|
|
673
|
-
logWarnings: true,
|
|
674
|
-
};
|
|
675
|
-
let globalConfig = Object.assign({}, defaultConfig);
|
|
676
|
-
/**
|
|
677
|
-
* Set global dynamic validation configuration
|
|
678
|
-
*/
|
|
679
|
-
function setDynamicValidationConfig(config) {
|
|
680
|
-
globalConfig = Object.assign(Object.assign({}, globalConfig), config);
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Get current dynamic validation configuration
|
|
684
|
-
*/
|
|
685
|
-
function getDynamicValidationConfig() {
|
|
686
|
-
return Object.assign({}, globalConfig);
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Type-safe dynamic enum validation function
|
|
690
|
-
*
|
|
691
|
-
* Automatically validates and normalizes enum values in request objects
|
|
692
|
-
* using the auto-generated prefix patterns from the OpenAPI specification.
|
|
693
|
-
*
|
|
694
|
-
* @param request - The request object to validate and normalize
|
|
695
|
-
* @param config - Optional validation configuration
|
|
696
|
-
* @returns The validated request with normalized enum values
|
|
697
|
-
*
|
|
698
|
-
* @example
|
|
699
|
-
* ```typescript
|
|
700
|
-
* const validated = dynamicValidateRequest<CreateOrderRequest>({
|
|
701
|
-
* portfolioId: 'portfolio-123',
|
|
702
|
-
* side: 'buy', // → 'BUY'
|
|
703
|
-
* type: 'market' // → 'MARKET'
|
|
704
|
-
* });
|
|
705
|
-
* ```
|
|
706
|
-
*/
|
|
707
|
-
function dynamicValidateRequest(request, config) {
|
|
708
|
-
const effectiveConfig = Object.assign(Object.assign({}, globalConfig), config);
|
|
709
|
-
if (!effectiveConfig.enabled) {
|
|
710
|
-
return request;
|
|
711
|
-
}
|
|
712
|
-
try {
|
|
713
|
-
return validateAndNormalizeRequest(request);
|
|
714
|
-
}
|
|
715
|
-
catch (error) {
|
|
716
|
-
if (!effectiveConfig.strict &&
|
|
717
|
-
error instanceof DynamicEnumValidationError) {
|
|
718
|
-
if (effectiveConfig.logWarnings) {
|
|
719
|
-
console.warn(`[Prime SDK] Dynamic enum validation warning: ${error.message}`);
|
|
720
|
-
}
|
|
721
|
-
return request; // Return original request with warning
|
|
722
|
-
}
|
|
723
|
-
throw error;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Utility function to get information about available enums
|
|
728
|
-
*/
|
|
729
|
-
function getEnumInfo() {
|
|
730
|
-
const enumNames = enumRegistry.getAllEnumNames();
|
|
731
|
-
const enumDetails = {};
|
|
732
|
-
enumNames.forEach((name) => {
|
|
733
|
-
const enumObject = enumRegistry.getEnum(name);
|
|
734
|
-
if (enumObject) {
|
|
735
|
-
enumDetails[name] = {
|
|
736
|
-
values: Object.values(enumObject),
|
|
737
|
-
keys: Object.keys(enumObject),
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
return {
|
|
742
|
-
enumNames,
|
|
743
|
-
totalEnums: enumNames.length,
|
|
744
|
-
enumDetails,
|
|
745
|
-
};
|
|
746
|
-
}
|