@coinbase-sample/prime-sdk-ts 0.7.1 → 0.8.1
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/activities/index.js +14 -0
- package/dist/addressBooks/index.js +10 -0
- package/dist/allocations/index.js +12 -0
- package/dist/assets/index.js +4 -0
- package/dist/balances/index.js +15 -0
- package/dist/commission/index.js +4 -0
- package/dist/constants.js +1 -1
- package/dist/financing/index.js +70 -0
- package/dist/futures/index.js +53 -0
- package/dist/index.js +7 -1
- package/dist/invoices/index.js +4 -0
- package/dist/model/DateOfBirth.js +21 -0
- package/dist/model/DetailedAddress.js +21 -0
- package/dist/model/GetFcmSettingsResponse.js +21 -0
- package/dist/model/GetUnstakingStatusResponse.js +21 -0
- package/dist/model/ListFinancingEligibleAssetsResponse.js +21 -0
- package/dist/model/ListTFObligationsResponse.js +21 -0
- package/dist/model/NaturalPersonName.js +21 -0
- package/dist/model/PreviewUnstakeRequest.js +21 -0
- package/dist/model/PreviewUnstakeResponse.js +21 -0
- package/dist/model/ProcessRequirements.js +21 -0
- package/dist/model/RewardMetadata.js +21 -0
- package/dist/model/SetFcmSettingsRequest.js +21 -0
- package/dist/model/SetFcmSettingsResponse.js +21 -0
- package/dist/model/TFAsset.js +21 -0
- package/dist/model/TFObligation.js +21 -0
- package/dist/model/TravelRuleEntry.js +21 -0
- package/dist/model/TravelRuleParty.js +21 -0
- package/dist/model/TravelRuleWalletDetails.js +21 -0
- package/dist/model/UnstakingStatus.js +21 -0
- package/dist/model/VASP.js +21 -0
- package/dist/model/ValidatorUnstakingInfo.js +21 -0
- package/dist/model/enums/CandlesGranularity.js +3 -3
- package/dist/model/enums/EstimateType.js +28 -0
- package/dist/model/enums/OrderType.js +2 -1
- package/dist/model/enums/PegOffsetType.js +31 -0
- package/dist/model/enums/RewardSubtype.js +34 -0
- package/dist/model/enums/TransactionType.js +3 -1
- package/dist/model/enums/TravelRuleStatus.js +28 -0
- package/dist/model/enums/TravelRuleWalletType.js +31 -0
- package/dist/model/enums/UnstakeType.js +28 -0
- package/dist/model/enums/UserRole.js +2 -1
- package/dist/model/enums/XMCallType.js +2 -1
- package/dist/model/enums/XMEntityCallStatus.js +2 -1
- package/dist/model/enums/index.js +14 -2
- package/dist/onchainAddressBook/index.js +14 -0
- package/dist/orders/index.js +59 -0
- package/dist/paymentMethods/index.js +8 -0
- package/dist/portfolios/index.js +10 -0
- package/dist/positions/index.js +7 -0
- package/dist/products/index.js +11 -0
- package/dist/shared/__tests__/validation.test.js +270 -0
- package/dist/shared/validation.js +210 -0
- package/dist/staking/index.js +63 -0
- package/dist/transactions/index.js +42 -0
- package/dist/types/activities/types.d.ts +1 -0
- package/dist/types/constants.d.ts +1 -1
- package/dist/types/financing/index.d.ts +5 -1
- package/dist/types/financing/types.d.ts +7 -1
- package/dist/types/futures/index.d.ts +6 -2
- package/dist/types/futures/types.d.ts +10 -1
- package/dist/types/index.d.ts +3 -0
- package/dist/types/model/CreateOrderRequest.d.ts +8 -1
- package/dist/types/model/CreatePortfolioAddressBookEntryRequest.d.ts +6 -0
- package/dist/types/model/DateOfBirth.d.ts +24 -0
- package/dist/types/model/DetailedAddress.d.ts +28 -0
- package/dist/types/model/GetFcmSettingsResponse.d.ts +25 -0
- package/dist/types/model/GetUnstakingStatusResponse.d.ts +42 -0
- package/dist/types/model/ListFinancingEligibleAssetsResponse.d.ts +26 -0
- package/dist/types/model/ListTFObligationsResponse.d.ts +26 -0
- package/dist/types/model/NaturalPersonName.d.ts +24 -0
- package/dist/types/model/NetworkDetails.d.ts +4 -0
- package/dist/types/model/Order.d.ts +12 -0
- package/dist/types/model/OrderPreviewRequest.d.ts +7 -0
- package/dist/types/model/PreviewUnstakeRequest.d.ts +28 -0
- package/dist/types/model/PreviewUnstakeResponse.d.ts +28 -0
- package/dist/types/model/ProcessRequirements.d.ts +23 -0
- package/dist/types/model/RewardMetadata.d.ts +23 -0
- package/dist/types/model/SetFcmSettingsRequest.d.ts +25 -0
- package/dist/types/model/SetFcmSettingsResponse.d.ts +25 -0
- package/dist/types/model/TFAsset.d.ts +33 -0
- package/dist/types/model/TFObligation.d.ts +41 -0
- package/dist/types/model/Transaction.d.ts +2 -0
- package/dist/types/model/TransactionMetadata.d.ts +2 -0
- package/dist/types/model/TravelRuleEntry.d.ts +38 -0
- package/dist/types/model/TravelRuleParty.d.ts +32 -0
- package/dist/types/model/TravelRuleWalletDetails.d.ts +28 -0
- package/dist/types/model/UnstakingStatus.d.ts +45 -0
- package/dist/types/model/VASP.d.ts +27 -0
- package/dist/types/model/ValidatorUnstakingInfo.d.ts +30 -0
- package/dist/types/model/enums/CandlesGranularity.d.ts +3 -3
- package/dist/types/model/enums/EstimateType.d.ts +24 -0
- package/dist/types/model/enums/OrderType.d.ts +3 -2
- package/dist/types/model/enums/PegOffsetType.d.ts +27 -0
- package/dist/types/model/enums/RewardSubtype.d.ts +30 -0
- package/dist/types/model/enums/TransactionType.d.ts +4 -2
- package/dist/types/model/enums/TravelRuleStatus.d.ts +24 -0
- package/dist/types/model/enums/TravelRuleWalletType.d.ts +27 -0
- package/dist/types/model/enums/UnstakeType.d.ts +24 -0
- package/dist/types/model/enums/UserRole.d.ts +3 -2
- package/dist/types/model/enums/XMCallType.d.ts +3 -2
- package/dist/types/model/enums/XMEntityCallStatus.d.ts +3 -2
- package/dist/types/model/enums/index.d.ts +6 -0
- package/dist/types/model/index.d.ts +21 -0
- package/dist/types/orders/types.d.ts +1 -1
- package/dist/types/shared/__tests__/validation.test.d.ts +1 -0
- package/dist/types/shared/validation.d.ts +88 -0
- package/dist/types/staking/index.d.ts +5 -1
- package/dist/types/staking/types.d.ts +12 -1
- package/dist/types/transactions/types.d.ts +3 -1
- package/dist/types/wallets/types.d.ts +2 -1
- package/dist/users/index.js +7 -0
- package/dist/wallets/index.js +27 -0
- package/package.json +13 -9
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Copyright 2025-present Coinbase Global, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
const validation_1 = require("../validation");
|
|
19
|
+
const errors_1 = require("../../errors");
|
|
20
|
+
describe('validation', () => {
|
|
21
|
+
describe('isValidUUID', () => {
|
|
22
|
+
it('should return true for valid UUIDs', () => {
|
|
23
|
+
expect((0, validation_1.isValidUUID)('123e4567-e89b-12d3-a456-426614174000')).toBe(true);
|
|
24
|
+
expect((0, validation_1.isValidUUID)('550e8400-e29b-41d4-a716-446655440000')).toBe(true);
|
|
25
|
+
expect((0, validation_1.isValidUUID)('ABCDEF12-3456-7890-ABCD-EF1234567890')).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('should return false for invalid UUIDs', () => {
|
|
28
|
+
expect((0, validation_1.isValidUUID)('not-a-uuid')).toBe(false);
|
|
29
|
+
expect((0, validation_1.isValidUUID)('123e4567-e89b-12d3-a456')).toBe(false);
|
|
30
|
+
expect((0, validation_1.isValidUUID)('123e4567e89b12d3a456426614174000')).toBe(false);
|
|
31
|
+
expect((0, validation_1.isValidUUID)('')).toBe(false);
|
|
32
|
+
expect((0, validation_1.isValidUUID)('12345678-1234-1234-1234-12345678901g')).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('PropertyValidator', () => {
|
|
36
|
+
it('should start with no errors', () => {
|
|
37
|
+
const validator = (0, validation_1.validate)({});
|
|
38
|
+
expect(validator.hasErrors()).toBe(false);
|
|
39
|
+
expect(validator.getErrors()).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
it('should accumulate errors', () => {
|
|
42
|
+
const validator = (0, validation_1.validate)({});
|
|
43
|
+
validator.addError('field1', 'is required');
|
|
44
|
+
validator.addError('field2', 'must be a valid UUID', 'invalid-value');
|
|
45
|
+
expect(validator.hasErrors()).toBe(true);
|
|
46
|
+
expect(validator.getErrors()).toHaveLength(2);
|
|
47
|
+
expect(validator.getErrors()[0]).toEqual({
|
|
48
|
+
paramName: 'field1',
|
|
49
|
+
message: 'is required',
|
|
50
|
+
});
|
|
51
|
+
expect(validator.getErrors()[1]).toEqual({
|
|
52
|
+
paramName: 'field2',
|
|
53
|
+
message: 'must be a valid UUID',
|
|
54
|
+
value: 'invalid-value',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it('should throw with formatted error message when there are errors', () => {
|
|
58
|
+
const validator = (0, validation_1.validate)({});
|
|
59
|
+
validator.addError('portfolioId', 'must be a valid UUID', 'bad-id');
|
|
60
|
+
validator.addError('orderId', 'is required');
|
|
61
|
+
expect(() => validator.check()).toThrow(errors_1.CoinbasePrimeClientException);
|
|
62
|
+
expect(() => validator.check()).toThrow(/Request validation failed:\n - portfolioId: must be a valid UUID \(received: 'bad-id'\)\n - orderId: is required/);
|
|
63
|
+
});
|
|
64
|
+
it('should not throw when there are no errors', () => {
|
|
65
|
+
const validator = (0, validation_1.validate)({});
|
|
66
|
+
expect(() => validator.check()).not.toThrow();
|
|
67
|
+
});
|
|
68
|
+
it('should include custom context message', () => {
|
|
69
|
+
const validator = (0, validation_1.validate)({});
|
|
70
|
+
validator.addError('field1', 'is invalid');
|
|
71
|
+
expect(() => validator.check('Custom operation failed')).toThrow(/Custom operation failed:/);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('requiredUUID', () => {
|
|
75
|
+
it('should not throw for valid UUID', () => {
|
|
76
|
+
const request = { testId: '123e4567-e89b-12d3-a456-426614174000' };
|
|
77
|
+
expect(() => (0, validation_1.validate)(request)
|
|
78
|
+
.requiredUUID((r) => r.testId)
|
|
79
|
+
.check()).not.toThrow();
|
|
80
|
+
});
|
|
81
|
+
it('should throw for undefined', () => {
|
|
82
|
+
const request = { testId: undefined };
|
|
83
|
+
expect(() => (0, validation_1.validate)(request)
|
|
84
|
+
.requiredUUID((r) => r.testId)
|
|
85
|
+
.check()).toThrow(/required/);
|
|
86
|
+
});
|
|
87
|
+
it('should throw for null', () => {
|
|
88
|
+
const request = { testId: null };
|
|
89
|
+
expect(() => (0, validation_1.validate)(request)
|
|
90
|
+
.requiredUUID((r) => r.testId)
|
|
91
|
+
.check()).toThrow(/required/);
|
|
92
|
+
});
|
|
93
|
+
it('should throw for empty string', () => {
|
|
94
|
+
const request = { testId: '' };
|
|
95
|
+
expect(() => (0, validation_1.validate)(request)
|
|
96
|
+
.requiredUUID((r) => r.testId)
|
|
97
|
+
.check()).toThrow(/required/);
|
|
98
|
+
});
|
|
99
|
+
it('should throw for whitespace-only string', () => {
|
|
100
|
+
const request = { testId: ' ' };
|
|
101
|
+
expect(() => (0, validation_1.validate)(request)
|
|
102
|
+
.requiredUUID((r) => r.testId)
|
|
103
|
+
.check()).toThrow(/whitespace/);
|
|
104
|
+
});
|
|
105
|
+
it('should throw for invalid UUID format', () => {
|
|
106
|
+
const request = { testId: 'not-a-uuid' };
|
|
107
|
+
expect(() => (0, validation_1.validate)(request)
|
|
108
|
+
.requiredUUID((r) => r.testId)
|
|
109
|
+
.check()).toThrow(/valid UUID/);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('optionalUUID', () => {
|
|
113
|
+
it('should not throw for valid UUID', () => {
|
|
114
|
+
const request = { testId: '123e4567-e89b-12d3-a456-426614174000' };
|
|
115
|
+
expect(() => (0, validation_1.validate)(request)
|
|
116
|
+
.optionalUUID((r) => r.testId)
|
|
117
|
+
.check()).not.toThrow();
|
|
118
|
+
});
|
|
119
|
+
it('should not throw for undefined', () => {
|
|
120
|
+
const request = { testId: undefined };
|
|
121
|
+
expect(() => (0, validation_1.validate)(request)
|
|
122
|
+
.optionalUUID((r) => r.testId)
|
|
123
|
+
.check()).not.toThrow();
|
|
124
|
+
});
|
|
125
|
+
it('should not throw for null', () => {
|
|
126
|
+
const request = { testId: null };
|
|
127
|
+
expect(() => (0, validation_1.validate)(request)
|
|
128
|
+
.optionalUUID((r) => r.testId)
|
|
129
|
+
.check()).not.toThrow();
|
|
130
|
+
});
|
|
131
|
+
it('should not throw for empty string', () => {
|
|
132
|
+
const request = { testId: '' };
|
|
133
|
+
expect(() => (0, validation_1.validate)(request)
|
|
134
|
+
.optionalUUID((r) => r.testId)
|
|
135
|
+
.check()).not.toThrow();
|
|
136
|
+
});
|
|
137
|
+
it('should throw for invalid UUID format', () => {
|
|
138
|
+
const request = { testId: 'not-a-uuid' };
|
|
139
|
+
expect(() => (0, validation_1.validate)(request)
|
|
140
|
+
.optionalUUID((r) => r.testId)
|
|
141
|
+
.check()).toThrow(/valid UUID/);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
describe('requiredString', () => {
|
|
145
|
+
it('should not throw for valid string', () => {
|
|
146
|
+
const request = { testField: 'valid-string' };
|
|
147
|
+
expect(() => (0, validation_1.validate)(request)
|
|
148
|
+
.requiredString((r) => r.testField)
|
|
149
|
+
.check()).not.toThrow();
|
|
150
|
+
});
|
|
151
|
+
it('should throw for undefined', () => {
|
|
152
|
+
const request = { testField: undefined };
|
|
153
|
+
expect(() => (0, validation_1.validate)(request)
|
|
154
|
+
.requiredString((r) => r.testField)
|
|
155
|
+
.check()).toThrow(/required/);
|
|
156
|
+
});
|
|
157
|
+
it('should throw for null', () => {
|
|
158
|
+
const request = { testField: null };
|
|
159
|
+
expect(() => (0, validation_1.validate)(request)
|
|
160
|
+
.requiredString((r) => r.testField)
|
|
161
|
+
.check()).toThrow(/required/);
|
|
162
|
+
});
|
|
163
|
+
it('should throw for empty string', () => {
|
|
164
|
+
const request = { testField: '' };
|
|
165
|
+
expect(() => (0, validation_1.validate)(request)
|
|
166
|
+
.requiredString((r) => r.testField)
|
|
167
|
+
.check()).toThrow(/required/);
|
|
168
|
+
});
|
|
169
|
+
it('should throw for whitespace-only string', () => {
|
|
170
|
+
const request = { testField: ' ' };
|
|
171
|
+
expect(() => (0, validation_1.validate)(request)
|
|
172
|
+
.requiredString((r) => r.testField)
|
|
173
|
+
.check()).toThrow(/whitespace/);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
describe('optionalString', () => {
|
|
177
|
+
it('should not throw for valid string', () => {
|
|
178
|
+
const request = { testField: 'valid-string' };
|
|
179
|
+
expect(() => (0, validation_1.validate)(request)
|
|
180
|
+
.optionalString((r) => r.testField)
|
|
181
|
+
.check()).not.toThrow();
|
|
182
|
+
});
|
|
183
|
+
it('should not throw for undefined', () => {
|
|
184
|
+
const request = { testField: undefined };
|
|
185
|
+
expect(() => (0, validation_1.validate)(request)
|
|
186
|
+
.optionalString((r) => r.testField)
|
|
187
|
+
.check()).not.toThrow();
|
|
188
|
+
});
|
|
189
|
+
it('should not throw for null', () => {
|
|
190
|
+
const request = { testField: null };
|
|
191
|
+
expect(() => (0, validation_1.validate)(request)
|
|
192
|
+
.optionalString((r) => r.testField)
|
|
193
|
+
.check()).not.toThrow();
|
|
194
|
+
});
|
|
195
|
+
it('should throw for whitespace-only when not empty', () => {
|
|
196
|
+
const request = { testField: ' ' };
|
|
197
|
+
expect(() => (0, validation_1.validate)(request)
|
|
198
|
+
.optionalString((r) => r.testField)
|
|
199
|
+
.check()).toThrow(/whitespace/);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
describe('requiredArray', () => {
|
|
203
|
+
it('should not throw for valid array', () => {
|
|
204
|
+
const request = { items: ['a', 'b', 'c'] };
|
|
205
|
+
expect(() => (0, validation_1.validate)(request)
|
|
206
|
+
.requiredArray((r) => r.items)
|
|
207
|
+
.check()).not.toThrow();
|
|
208
|
+
});
|
|
209
|
+
it('should throw for undefined', () => {
|
|
210
|
+
const request = { items: undefined };
|
|
211
|
+
expect(() => (0, validation_1.validate)(request)
|
|
212
|
+
.requiredArray((r) => r.items)
|
|
213
|
+
.check()).toThrow(/required/);
|
|
214
|
+
});
|
|
215
|
+
it('should throw for empty array', () => {
|
|
216
|
+
const request = { items: [] };
|
|
217
|
+
expect(() => (0, validation_1.validate)(request)
|
|
218
|
+
.requiredArray((r) => r.items)
|
|
219
|
+
.check()).toThrow(/empty array/);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
describe('requiredBoolean', () => {
|
|
223
|
+
it('should not throw for true', () => {
|
|
224
|
+
const request = { flag: true };
|
|
225
|
+
expect(() => (0, validation_1.validate)(request)
|
|
226
|
+
.requiredBoolean((r) => r.flag)
|
|
227
|
+
.check()).not.toThrow();
|
|
228
|
+
});
|
|
229
|
+
it('should not throw for false', () => {
|
|
230
|
+
const request = { flag: false };
|
|
231
|
+
expect(() => (0, validation_1.validate)(request)
|
|
232
|
+
.requiredBoolean((r) => r.flag)
|
|
233
|
+
.check()).not.toThrow();
|
|
234
|
+
});
|
|
235
|
+
it('should throw for undefined', () => {
|
|
236
|
+
const request = { flag: undefined };
|
|
237
|
+
expect(() => (0, validation_1.validate)(request)
|
|
238
|
+
.requiredBoolean((r) => r.flag)
|
|
239
|
+
.check()).toThrow(/required/);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
describe('multiple field validation', () => {
|
|
243
|
+
it('should collect all validation errors before throwing', () => {
|
|
244
|
+
const request = {
|
|
245
|
+
portfolioId: undefined,
|
|
246
|
+
orderId: 'invalid-uuid',
|
|
247
|
+
productId: '',
|
|
248
|
+
};
|
|
249
|
+
expect(() => (0, validation_1.validate)(request)
|
|
250
|
+
.requiredUUID((r) => r.portfolioId)
|
|
251
|
+
.requiredUUID((r) => r.orderId)
|
|
252
|
+
.requiredString((r) => r.productId)
|
|
253
|
+
.check('getOrder request validation failed')).toThrow(errors_1.CoinbasePrimeClientException);
|
|
254
|
+
try {
|
|
255
|
+
(0, validation_1.validate)(request)
|
|
256
|
+
.requiredUUID((r) => r.portfolioId)
|
|
257
|
+
.requiredUUID((r) => r.orderId)
|
|
258
|
+
.requiredString((r) => r.productId)
|
|
259
|
+
.check('getOrder request validation failed');
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (error instanceof errors_1.CoinbasePrimeClientException) {
|
|
263
|
+
expect(error.message).toContain('portfolioId');
|
|
264
|
+
expect(error.message).toContain('orderId');
|
|
265
|
+
expect(error.message).toContain('productId');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PropertyValidator = void 0;
|
|
4
|
+
exports.isValidUUID = isValidUUID;
|
|
5
|
+
exports.validate = validate;
|
|
6
|
+
/**
|
|
7
|
+
* Copyright 2025-present Coinbase Global, Inc.
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*/
|
|
21
|
+
const errors_1 = require("../errors");
|
|
22
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
23
|
+
/**
|
|
24
|
+
* Validates that a string is a valid UUID v4 format
|
|
25
|
+
*/
|
|
26
|
+
function isValidUUID(value) {
|
|
27
|
+
return UUID_REGEX.test(value);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a validator with property accessor support for automatic field name inference.
|
|
31
|
+
*
|
|
32
|
+
* @param source - The source object containing the fields to validate
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* validate(request)
|
|
37
|
+
* .requiredUUID(r => r.portfolioId)
|
|
38
|
+
* .requiredUUID(r => r.orderId)
|
|
39
|
+
* .check();
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
function validate(source) {
|
|
43
|
+
return new PropertyValidator(source);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Validator with property accessor support for automatic field name inference.
|
|
47
|
+
* Uses Proxy to track property accesses and extract field names automatically.
|
|
48
|
+
*/
|
|
49
|
+
class PropertyValidator {
|
|
50
|
+
constructor(source) {
|
|
51
|
+
this.errors = [];
|
|
52
|
+
this.source = source;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validates that a required UUID field is present and valid.
|
|
56
|
+
* Automatically extracts the field name from the property accessor.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* validate(request)
|
|
61
|
+
* .requiredUUID(r => r.portfolioId)
|
|
62
|
+
* .check();
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
requiredUUID(accessor) {
|
|
66
|
+
const { propertyName, value } = this.extractProperty(accessor);
|
|
67
|
+
if (value === undefined || value === null || value === '') {
|
|
68
|
+
this.addError(propertyName, 'is required and cannot be empty', value);
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
const trimmedValue = typeof value === 'string' ? value.trim() : value;
|
|
72
|
+
if (trimmedValue === '') {
|
|
73
|
+
this.addError(propertyName, 'cannot be empty or whitespace only', value);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
if (!isValidUUID(trimmedValue)) {
|
|
77
|
+
this.addError(propertyName, 'must be a valid UUID', value);
|
|
78
|
+
}
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Validates that an optional UUID field is valid if provided.
|
|
83
|
+
*/
|
|
84
|
+
optionalUUID(accessor) {
|
|
85
|
+
const { propertyName, value } = this.extractProperty(accessor);
|
|
86
|
+
if (value === undefined || value === null || value === '') {
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
const trimmedValue = typeof value === 'string' ? value.trim() : value;
|
|
90
|
+
if (trimmedValue !== '' && !isValidUUID(trimmedValue)) {
|
|
91
|
+
this.addError(propertyName, 'must be a valid UUID if provided', value);
|
|
92
|
+
}
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Validates that a required string field is present and not empty.
|
|
97
|
+
*/
|
|
98
|
+
requiredString(accessor) {
|
|
99
|
+
const { propertyName, value } = this.extractProperty(accessor);
|
|
100
|
+
if (value === undefined || value === null || value === '') {
|
|
101
|
+
this.addError(propertyName, 'is required and cannot be empty', value);
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
const trimmedValue = typeof value === 'string' ? value.trim() : value;
|
|
105
|
+
if (trimmedValue === '') {
|
|
106
|
+
this.addError(propertyName, 'cannot be empty or whitespace only', value);
|
|
107
|
+
}
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validates that an optional string field is not empty if provided.
|
|
112
|
+
*/
|
|
113
|
+
optionalString(accessor) {
|
|
114
|
+
const { propertyName, value } = this.extractProperty(accessor);
|
|
115
|
+
if (value === undefined || value === null) {
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
if (typeof value === 'string') {
|
|
119
|
+
const trimmedValue = value.trim();
|
|
120
|
+
if (value !== '' && trimmedValue === '') {
|
|
121
|
+
this.addError(propertyName, 'cannot be whitespace only if provided', value);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Validates that a required array field is present and not empty.
|
|
128
|
+
*/
|
|
129
|
+
requiredArray(accessor) {
|
|
130
|
+
const { propertyName, value } = this.extractProperty(accessor);
|
|
131
|
+
if (value === undefined || value === null) {
|
|
132
|
+
this.addError(propertyName, 'is required', value);
|
|
133
|
+
}
|
|
134
|
+
else if (!Array.isArray(value)) {
|
|
135
|
+
this.addError(propertyName, 'must be an array', value);
|
|
136
|
+
}
|
|
137
|
+
else if (value.length === 0) {
|
|
138
|
+
this.addError(propertyName, 'must not be an empty array', value);
|
|
139
|
+
}
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Validates that a required boolean field is present.
|
|
144
|
+
*/
|
|
145
|
+
requiredBoolean(accessor) {
|
|
146
|
+
const { propertyName, value } = this.extractProperty(accessor);
|
|
147
|
+
if (value === undefined || value === null) {
|
|
148
|
+
this.addError(propertyName, 'is required', value);
|
|
149
|
+
}
|
|
150
|
+
else if (typeof value !== 'boolean') {
|
|
151
|
+
this.addError(propertyName, 'must be a boolean', value);
|
|
152
|
+
}
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Throws if there are validation errors.
|
|
157
|
+
*/
|
|
158
|
+
check(contextMessage) {
|
|
159
|
+
if (this.errors.length > 0) {
|
|
160
|
+
const errorDetails = this.errors
|
|
161
|
+
.map((err) => {
|
|
162
|
+
const valueInfo = err.value !== undefined ? ` (received: '${err.value}')` : '';
|
|
163
|
+
return ` - ${err.paramName}: ${err.message}${valueInfo}`;
|
|
164
|
+
})
|
|
165
|
+
.join('\n');
|
|
166
|
+
const prefix = contextMessage || 'Request validation failed';
|
|
167
|
+
throw new errors_1.CoinbasePrimeClientException(`${prefix}:\n${errorDetails}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Add a validation error
|
|
172
|
+
*/
|
|
173
|
+
addError(paramName, message, value) {
|
|
174
|
+
this.errors.push({ paramName, message, value });
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check if there are any validation errors
|
|
178
|
+
*/
|
|
179
|
+
hasErrors() {
|
|
180
|
+
return this.errors.length > 0;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get all validation errors
|
|
184
|
+
*/
|
|
185
|
+
getErrors() {
|
|
186
|
+
return [...this.errors];
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Extracts the property name and value from a property accessor function.
|
|
190
|
+
* Uses a Proxy to track which property was accessed.
|
|
191
|
+
*/
|
|
192
|
+
extractProperty(accessor) {
|
|
193
|
+
let accessedProperty;
|
|
194
|
+
const proxy = new Proxy(this.source, {
|
|
195
|
+
get(target, prop) {
|
|
196
|
+
if (typeof prop === 'string') {
|
|
197
|
+
accessedProperty = prop;
|
|
198
|
+
return target[prop];
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
const value = accessor(proxy);
|
|
204
|
+
if (!accessedProperty) {
|
|
205
|
+
throw new Error('Unable to extract property name. Ensure the accessor accesses a property directly (e.g., r => r.fieldName)');
|
|
206
|
+
}
|
|
207
|
+
return { propertyName: accessedProperty, value };
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
exports.PropertyValidator = PropertyValidator;
|
package/dist/staking/index.js
CHANGED
|
@@ -27,12 +27,18 @@ exports.StakingService = void 0;
|
|
|
27
27
|
*/
|
|
28
28
|
const clients_1 = require("../clients");
|
|
29
29
|
const paginatedResponse_1 = require("../shared/paginatedResponse");
|
|
30
|
+
const validation_1 = require("../shared/validation");
|
|
30
31
|
class StakingService {
|
|
31
32
|
constructor(client) {
|
|
32
33
|
this.client = client;
|
|
33
34
|
}
|
|
34
35
|
createStake(request, options) {
|
|
35
36
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
(0, validation_1.validate)(request)
|
|
38
|
+
.requiredUUID((r) => r.portfolioId)
|
|
39
|
+
.requiredUUID((r) => r.walletId)
|
|
40
|
+
.requiredUUID((r) => r.idempotencyKey)
|
|
41
|
+
.check();
|
|
36
42
|
const bodyParams = Object.assign(Object.assign({}, request), { portfolioId: undefined, walletId: undefined });
|
|
37
43
|
const response = yield this.client.request({
|
|
38
44
|
url: `portfolios/${request.portfolioId}/wallets/${request.walletId}/staking/initiate`,
|
|
@@ -45,6 +51,11 @@ class StakingService {
|
|
|
45
51
|
}
|
|
46
52
|
createUnstake(request, options) {
|
|
47
53
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
(0, validation_1.validate)(request)
|
|
55
|
+
.requiredUUID((r) => r.portfolioId)
|
|
56
|
+
.requiredUUID((r) => r.walletId)
|
|
57
|
+
.requiredUUID((r) => r.idempotencyKey)
|
|
58
|
+
.check();
|
|
48
59
|
const bodyParams = Object.assign(Object.assign({}, request), { portfolioId: undefined, walletId: undefined });
|
|
49
60
|
const response = yield this.client.request({
|
|
50
61
|
url: `portfolios/${request.portfolioId}/wallets/${request.walletId}/staking/unstake`,
|
|
@@ -57,6 +68,12 @@ class StakingService {
|
|
|
57
68
|
}
|
|
58
69
|
createPortfolioStake(request, options) {
|
|
59
70
|
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
(0, validation_1.validate)(request)
|
|
72
|
+
.requiredUUID((r) => r.portfolioId)
|
|
73
|
+
.requiredUUID((r) => r.idempotencyKey)
|
|
74
|
+
.requiredString((r) => r.currencySymbol)
|
|
75
|
+
.requiredString((r) => r.amount)
|
|
76
|
+
.check();
|
|
60
77
|
const bodyParams = Object.assign(Object.assign({}, request), { portfolioId: undefined });
|
|
61
78
|
const response = yield this.client.request({
|
|
62
79
|
url: `portfolios/${request.portfolioId}/staking/initiate`,
|
|
@@ -69,6 +86,12 @@ class StakingService {
|
|
|
69
86
|
}
|
|
70
87
|
createPortfolioUnstake(request, options) {
|
|
71
88
|
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
(0, validation_1.validate)(request)
|
|
90
|
+
.requiredUUID((r) => r.portfolioId)
|
|
91
|
+
.requiredUUID((r) => r.idempotencyKey)
|
|
92
|
+
.requiredString((r) => r.currencySymbol)
|
|
93
|
+
.requiredString((r) => r.amount)
|
|
94
|
+
.check();
|
|
72
95
|
const bodyParams = Object.assign(Object.assign({}, request), { portfolioId: undefined });
|
|
73
96
|
const response = yield this.client.request({
|
|
74
97
|
url: `portfolios/${request.portfolioId}/staking/unstake`,
|
|
@@ -81,6 +104,10 @@ class StakingService {
|
|
|
81
104
|
}
|
|
82
105
|
queryTransactionValidators(request, options) {
|
|
83
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
107
|
+
(0, validation_1.validate)(request)
|
|
108
|
+
.requiredUUID((r) => r.portfolioId)
|
|
109
|
+
.requiredArray((r) => r.transactionIds)
|
|
110
|
+
.check();
|
|
84
111
|
const paginationOptions = (0, paginatedResponse_1.getDefaultPaginationOptions)(this.client, options);
|
|
85
112
|
const { transactionIds, cursor, limit, sortDirection } = request;
|
|
86
113
|
const bodyParams = {
|
|
@@ -101,6 +128,11 @@ class StakingService {
|
|
|
101
128
|
}
|
|
102
129
|
claimRewards(request, options) {
|
|
103
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
(0, validation_1.validate)(request)
|
|
132
|
+
.requiredUUID((r) => r.portfolioId)
|
|
133
|
+
.requiredUUID((r) => r.walletId)
|
|
134
|
+
.requiredUUID((r) => r.idempotencyKey)
|
|
135
|
+
.check();
|
|
104
136
|
const { idempotencyKey, inputs, portfolioId, walletId } = request;
|
|
105
137
|
const bodyParams = {
|
|
106
138
|
idempotencyKey,
|
|
@@ -115,5 +147,36 @@ class StakingService {
|
|
|
115
147
|
return response.data;
|
|
116
148
|
});
|
|
117
149
|
}
|
|
150
|
+
previewUnstake(request, options) {
|
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
(0, validation_1.validate)(request)
|
|
153
|
+
.requiredUUID((r) => r.portfolioId)
|
|
154
|
+
.requiredUUID((r) => r.walletId)
|
|
155
|
+
.requiredString((r) => r.amount)
|
|
156
|
+
.check();
|
|
157
|
+
const bodyParams = Object.assign(Object.assign({}, request), { portfolioId: undefined, walletId: undefined });
|
|
158
|
+
const response = yield this.client.request({
|
|
159
|
+
url: `portfolios/${request.portfolioId}/wallets/${request.walletId}/staking/unstake/preview`,
|
|
160
|
+
method: clients_1.Method.POST,
|
|
161
|
+
bodyParams,
|
|
162
|
+
callOptions: options,
|
|
163
|
+
});
|
|
164
|
+
return response.data;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
getUnstakingStatus(request, options) {
|
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
(0, validation_1.validate)(request)
|
|
170
|
+
.requiredUUID((r) => r.portfolioId)
|
|
171
|
+
.requiredUUID((r) => r.walletId)
|
|
172
|
+
.check();
|
|
173
|
+
const { portfolioId, walletId } = request;
|
|
174
|
+
const response = yield this.client.request({
|
|
175
|
+
url: `portfolios/${portfolioId}/wallets/${walletId}/staking/unstake/status`,
|
|
176
|
+
callOptions: options,
|
|
177
|
+
});
|
|
178
|
+
return response.data;
|
|
179
|
+
});
|
|
180
|
+
}
|
|
118
181
|
}
|
|
119
182
|
exports.StakingService = StakingService;
|