@vesant-sdk/fraud 0.1.0 → 0.1.1-next.c8fef46
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/README.md +67 -0
- package/dist/index.d.mts +197 -11
- package/dist/index.d.ts +197 -11
- package/dist/index.js +461 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +436 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +47 -39
package/dist/index.js
CHANGED
|
@@ -2,15 +2,442 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@vesant-sdk/core');
|
|
4
4
|
|
|
5
|
+
// src/client.ts
|
|
6
|
+
|
|
7
|
+
// src/types/enums.ts
|
|
8
|
+
var SiftTransactionTypeValues = [
|
|
9
|
+
"$sale",
|
|
10
|
+
"$authorize",
|
|
11
|
+
"$capture",
|
|
12
|
+
"$void",
|
|
13
|
+
"$refund",
|
|
14
|
+
"$deposit",
|
|
15
|
+
"$withdrawal",
|
|
16
|
+
"$transfer",
|
|
17
|
+
"$buy",
|
|
18
|
+
"$sell",
|
|
19
|
+
"$send",
|
|
20
|
+
"$receive"
|
|
21
|
+
];
|
|
22
|
+
var TransactionType = {
|
|
23
|
+
Sale: "$sale",
|
|
24
|
+
Authorize: "$authorize",
|
|
25
|
+
Capture: "$capture",
|
|
26
|
+
Void: "$void",
|
|
27
|
+
Refund: "$refund",
|
|
28
|
+
Deposit: "$deposit",
|
|
29
|
+
Withdrawal: "$withdrawal",
|
|
30
|
+
Transfer: "$transfer",
|
|
31
|
+
Buy: "$buy",
|
|
32
|
+
Sell: "$sell",
|
|
33
|
+
Send: "$send",
|
|
34
|
+
Receive: "$receive"
|
|
35
|
+
};
|
|
36
|
+
var SiftChargebackStateValues = [
|
|
37
|
+
"$received",
|
|
38
|
+
"$accepted",
|
|
39
|
+
"$disputed",
|
|
40
|
+
"$won",
|
|
41
|
+
"$lost"
|
|
42
|
+
];
|
|
43
|
+
var ChargebackState = {
|
|
44
|
+
Received: "$received",
|
|
45
|
+
Accepted: "$accepted",
|
|
46
|
+
Disputed: "$disputed",
|
|
47
|
+
Won: "$won",
|
|
48
|
+
Lost: "$lost"
|
|
49
|
+
};
|
|
50
|
+
var SiftChargebackReasonValues = [
|
|
51
|
+
"$fraud",
|
|
52
|
+
"$duplicate",
|
|
53
|
+
"$product_not_received",
|
|
54
|
+
"$product_unacceptable",
|
|
55
|
+
"$authorization",
|
|
56
|
+
"$consumer_disputes",
|
|
57
|
+
"$processing_errors",
|
|
58
|
+
"$cancel_subscription",
|
|
59
|
+
"$friendly_fraud",
|
|
60
|
+
"$ach_return",
|
|
61
|
+
"$ach_reversal",
|
|
62
|
+
"$other"
|
|
63
|
+
];
|
|
64
|
+
var ChargebackReason = {
|
|
65
|
+
Fraud: "$fraud",
|
|
66
|
+
Duplicate: "$duplicate",
|
|
67
|
+
ProductNotReceived: "$product_not_received",
|
|
68
|
+
ProductUnacceptable: "$product_unacceptable",
|
|
69
|
+
Authorization: "$authorization",
|
|
70
|
+
ConsumerDisputes: "$consumer_disputes",
|
|
71
|
+
ProcessingErrors: "$processing_errors",
|
|
72
|
+
CancelSubscription: "$cancel_subscription",
|
|
73
|
+
FriendlyFraud: "$friendly_fraud",
|
|
74
|
+
AchReturn: "$ach_return",
|
|
75
|
+
AchReversal: "$ach_reversal",
|
|
76
|
+
Other: "$other"
|
|
77
|
+
};
|
|
78
|
+
var SiftLoginStatusValues = ["$success", "$failure"];
|
|
79
|
+
var LoginStatus = {
|
|
80
|
+
Success: "$success",
|
|
81
|
+
Failure: "$failure"
|
|
82
|
+
};
|
|
83
|
+
var SiftLoginFailureReasonValues = [
|
|
84
|
+
"$account_unknown",
|
|
85
|
+
"$account_suspended",
|
|
86
|
+
"$account_disabled",
|
|
87
|
+
"$wrong_password"
|
|
88
|
+
];
|
|
89
|
+
var SiftPasswordUpdateReasonValues = [
|
|
90
|
+
"$user_update",
|
|
91
|
+
"$forgot_password",
|
|
92
|
+
"$forced_reset"
|
|
93
|
+
];
|
|
94
|
+
var PasswordUpdateReason = {
|
|
95
|
+
UserUpdate: SiftPasswordUpdateReasonValues[0],
|
|
96
|
+
ForgotPassword: SiftPasswordUpdateReasonValues[1],
|
|
97
|
+
ForcedReset: SiftPasswordUpdateReasonValues[2]
|
|
98
|
+
};
|
|
99
|
+
var SiftPasswordUpdateStatusValues = [
|
|
100
|
+
"$pending",
|
|
101
|
+
"$success",
|
|
102
|
+
"$failure"
|
|
103
|
+
];
|
|
104
|
+
var PasswordUpdateStatus = {
|
|
105
|
+
Pending: "$pending",
|
|
106
|
+
Success: "$success",
|
|
107
|
+
Failure: "$failure"
|
|
108
|
+
};
|
|
109
|
+
var SiftWagerStatusValues = ["$accept", "$cancel"];
|
|
110
|
+
var WagerStatus = {
|
|
111
|
+
Accept: "$accept",
|
|
112
|
+
Cancel: "$cancel"
|
|
113
|
+
};
|
|
114
|
+
var SiftTransactionStatusValues = [
|
|
115
|
+
"$success",
|
|
116
|
+
"$failure",
|
|
117
|
+
"$pending"
|
|
118
|
+
];
|
|
119
|
+
var TransactionStatus = {
|
|
120
|
+
Success: "$success",
|
|
121
|
+
Failure: "$failure",
|
|
122
|
+
Pending: "$pending"
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// src/normalization/normalize.ts
|
|
126
|
+
function mergeMetadata(base, extras) {
|
|
127
|
+
return { ...base, ...extras };
|
|
128
|
+
}
|
|
129
|
+
function stripSdkOnlyFields(request, keys) {
|
|
130
|
+
const body = { ...request };
|
|
131
|
+
for (const key of keys) {
|
|
132
|
+
delete body[key];
|
|
133
|
+
}
|
|
134
|
+
return body;
|
|
135
|
+
}
|
|
136
|
+
function createStrippedBody(rest, metadata, stripKeys) {
|
|
137
|
+
return stripSdkOnlyFields(
|
|
138
|
+
{ ...rest, metadata: mergeMetadata(metadata, {}) },
|
|
139
|
+
stripKeys
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function applySiftMetadata(body, metadata, siftMetadata, onlyWhenNonEmpty = false) {
|
|
143
|
+
if (!onlyWhenNonEmpty || Object.keys(siftMetadata).length > 0) {
|
|
144
|
+
body.metadata = mergeMetadata(metadata, siftMetadata);
|
|
145
|
+
}
|
|
146
|
+
return body;
|
|
147
|
+
}
|
|
148
|
+
function normalizeUpdatePassword(request) {
|
|
149
|
+
const { password_reason, password_status, metadata, ...rest } = request;
|
|
150
|
+
const body = createStrippedBody(rest, metadata, []);
|
|
151
|
+
const siftMetadata = {};
|
|
152
|
+
if (password_reason) siftMetadata.$reason = password_reason;
|
|
153
|
+
if (password_status) siftMetadata.$status = password_status;
|
|
154
|
+
return applySiftMetadata(body, metadata, siftMetadata);
|
|
155
|
+
}
|
|
156
|
+
function normalizeWager(request) {
|
|
157
|
+
const { wager_type, wager_status, wager_event_type, wager_event_name, wager_event_id, metadata, ...rest } = request;
|
|
158
|
+
const body = createStrippedBody(rest, metadata, [
|
|
159
|
+
"wager_type",
|
|
160
|
+
"wager_status",
|
|
161
|
+
"wager_event_type",
|
|
162
|
+
"wager_event_name",
|
|
163
|
+
"wager_event_id"
|
|
164
|
+
]);
|
|
165
|
+
const siftMetadata = {
|
|
166
|
+
$wager_type: wager_type,
|
|
167
|
+
$wager_status: wager_status
|
|
168
|
+
};
|
|
169
|
+
if (wager_event_type) siftMetadata.wager_event_type = wager_event_type;
|
|
170
|
+
if (wager_event_name) siftMetadata.wager_event_name = wager_event_name;
|
|
171
|
+
if (wager_event_id) siftMetadata.wager_event_id = wager_event_id;
|
|
172
|
+
return applySiftMetadata(body, metadata, siftMetadata);
|
|
173
|
+
}
|
|
174
|
+
function normalizeLogin(request) {
|
|
175
|
+
const { login_status, login_failure_reason, metadata, ...rest } = request;
|
|
176
|
+
const effectiveStatus = login_status ?? LoginStatus.Success;
|
|
177
|
+
const body = createStrippedBody(rest, metadata, [
|
|
178
|
+
"login_status",
|
|
179
|
+
"login_failure_reason"
|
|
180
|
+
]);
|
|
181
|
+
const siftMetadata = {
|
|
182
|
+
$login_status: effectiveStatus
|
|
183
|
+
};
|
|
184
|
+
if (effectiveStatus === LoginStatus.Failure && login_failure_reason) {
|
|
185
|
+
siftMetadata.$failure_reason = login_failure_reason;
|
|
186
|
+
}
|
|
187
|
+
return applySiftMetadata(body, metadata, siftMetadata);
|
|
188
|
+
}
|
|
189
|
+
function normalizeTransaction(request) {
|
|
190
|
+
const { transaction_status, decline_category, transfer_recipient_user_id, metadata, ...rest } = request;
|
|
191
|
+
const body = createStrippedBody(rest, metadata, [
|
|
192
|
+
"transaction_status",
|
|
193
|
+
"decline_category",
|
|
194
|
+
"transfer_recipient_user_id"
|
|
195
|
+
]);
|
|
196
|
+
const siftMetadata = {};
|
|
197
|
+
if (transaction_status) siftMetadata.$transaction_status = transaction_status;
|
|
198
|
+
if (decline_category) siftMetadata.$decline_category = decline_category;
|
|
199
|
+
if (transfer_recipient_user_id) {
|
|
200
|
+
siftMetadata.$transfer_recipient_user_id = transfer_recipient_user_id;
|
|
201
|
+
}
|
|
202
|
+
return applySiftMetadata(body, metadata, siftMetadata, true);
|
|
203
|
+
}
|
|
204
|
+
function normalizeScoreRequestForApi(request) {
|
|
205
|
+
switch (request.event_type) {
|
|
206
|
+
case "$update_password":
|
|
207
|
+
return normalizeUpdatePassword(request);
|
|
208
|
+
case "$wager":
|
|
209
|
+
return normalizeWager(request);
|
|
210
|
+
case "$login":
|
|
211
|
+
return normalizeLogin(request);
|
|
212
|
+
case "$transaction":
|
|
213
|
+
return normalizeTransaction(request);
|
|
214
|
+
default:
|
|
215
|
+
return { ...request };
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/normalization/preview.ts
|
|
220
|
+
function buildScoreRequestPreview(request) {
|
|
221
|
+
return normalizeScoreRequestForApi(request);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/types/events.ts
|
|
225
|
+
var SCORED_FRAUD_EVENT_TYPES = [
|
|
226
|
+
"$create_account",
|
|
227
|
+
"$login",
|
|
228
|
+
"$logout",
|
|
229
|
+
"$update_account",
|
|
230
|
+
"$update_password",
|
|
231
|
+
"$transaction",
|
|
232
|
+
"$wager"
|
|
233
|
+
];
|
|
234
|
+
var CHARGEBACK_FRAUD_EVENT_TYPE = "$chargeback";
|
|
235
|
+
var SUPPORTED_FRAUD_EVENT_TYPES = [
|
|
236
|
+
...SCORED_FRAUD_EVENT_TYPES,
|
|
237
|
+
CHARGEBACK_FRAUD_EVENT_TYPE
|
|
238
|
+
];
|
|
239
|
+
var PLANNED_FRAUD_EVENT_TYPES = [
|
|
240
|
+
"$verification",
|
|
241
|
+
"$link_session_to_user",
|
|
242
|
+
"$security_notification",
|
|
243
|
+
"$create_order",
|
|
244
|
+
"$update_order",
|
|
245
|
+
"$order_status",
|
|
246
|
+
"$add_promotion"
|
|
247
|
+
];
|
|
248
|
+
function isPlannedFraudEventType(eventType) {
|
|
249
|
+
return PLANNED_FRAUD_EVENT_TYPES.includes(eventType);
|
|
250
|
+
}
|
|
251
|
+
function isSupportedFraudEventType(eventType) {
|
|
252
|
+
return SUPPORTED_FRAUD_EVENT_TYPES.includes(eventType);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/types/metadata.ts
|
|
256
|
+
function hasReservedMetadataKey(metadata) {
|
|
257
|
+
for (const key of Object.keys(metadata)) {
|
|
258
|
+
if (key.startsWith("$")) {
|
|
259
|
+
return key;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/validation/helpers.ts
|
|
266
|
+
function fieldPrefix(index) {
|
|
267
|
+
return index === void 0 ? "" : `requests[${index}].`;
|
|
268
|
+
}
|
|
269
|
+
function assertNonEmpty(value, field, errors, prefix) {
|
|
270
|
+
if (!value?.trim()) {
|
|
271
|
+
errors.push(`${prefix}${field} is required`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function assertEnum(value, allowed, field, errors, prefix) {
|
|
275
|
+
if (value === void 0) return;
|
|
276
|
+
if (!allowed.includes(value)) {
|
|
277
|
+
errors.push(`${prefix}${field} must be one of: ${allowed.join(", ")}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function assertPositiveAmount(amount, field, errors, prefix) {
|
|
281
|
+
if (amount === void 0 || amount <= 0) {
|
|
282
|
+
errors.push(`${prefix}${field} must be greater than 0`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function validateMetadata(metadata, errors, prefix) {
|
|
286
|
+
if (!metadata) return;
|
|
287
|
+
const reservedKey = hasReservedMetadataKey(metadata);
|
|
288
|
+
if (reservedKey) {
|
|
289
|
+
errors.push(
|
|
290
|
+
`${prefix}metadata keys must not start with '$' (found '${reservedKey}'). Use typed request fields instead.`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/validation/rules.ts
|
|
296
|
+
function validateBase(request, errors, prefix) {
|
|
297
|
+
assertNonEmpty(request.customer_id, "customer_id", errors, prefix);
|
|
298
|
+
assertNonEmpty(request.sift_user_id, "sift_user_id", errors, prefix);
|
|
299
|
+
assertNonEmpty(request.event_type, "event_type", errors, prefix);
|
|
300
|
+
validateMetadata(request.metadata, errors, prefix);
|
|
301
|
+
}
|
|
302
|
+
function validateLogin(request, errors, prefix) {
|
|
303
|
+
assertEnum(request.login_status, SiftLoginStatusValues, "login_status", errors, prefix);
|
|
304
|
+
if (request.login_failure_reason !== void 0) {
|
|
305
|
+
if (request.login_status === "$failure") {
|
|
306
|
+
assertEnum(
|
|
307
|
+
request.login_failure_reason,
|
|
308
|
+
SiftLoginFailureReasonValues,
|
|
309
|
+
"login_failure_reason",
|
|
310
|
+
errors,
|
|
311
|
+
prefix
|
|
312
|
+
);
|
|
313
|
+
} else {
|
|
314
|
+
errors.push(`${prefix}login_failure_reason is only allowed when login_status is '$failure'`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function validateUpdatePassword(request, errors, prefix) {
|
|
319
|
+
assertEnum(
|
|
320
|
+
request.password_reason,
|
|
321
|
+
SiftPasswordUpdateReasonValues,
|
|
322
|
+
"password_reason",
|
|
323
|
+
errors,
|
|
324
|
+
prefix
|
|
325
|
+
);
|
|
326
|
+
if (!request.password_reason) {
|
|
327
|
+
errors.push(`${prefix}password_reason is required`);
|
|
328
|
+
}
|
|
329
|
+
assertEnum(
|
|
330
|
+
request.password_status,
|
|
331
|
+
SiftPasswordUpdateStatusValues,
|
|
332
|
+
"password_status",
|
|
333
|
+
errors,
|
|
334
|
+
prefix
|
|
335
|
+
);
|
|
336
|
+
if (!request.password_status) {
|
|
337
|
+
errors.push(`${prefix}password_status is required`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function validateTransaction(request, errors, prefix) {
|
|
341
|
+
assertPositiveAmount(request.amount, "amount", errors, prefix);
|
|
342
|
+
assertNonEmpty(request.currency, "currency", errors, prefix);
|
|
343
|
+
assertEnum(request.transaction_type, SiftTransactionTypeValues, "transaction_type", errors, prefix);
|
|
344
|
+
assertEnum(
|
|
345
|
+
request.transaction_status,
|
|
346
|
+
SiftTransactionStatusValues,
|
|
347
|
+
"transaction_status",
|
|
348
|
+
errors,
|
|
349
|
+
prefix
|
|
350
|
+
);
|
|
351
|
+
if (request.decline_category !== void 0 && request.transaction_status !== "$failure") {
|
|
352
|
+
errors.push(
|
|
353
|
+
`${prefix}decline_category is only allowed when transaction_status is '$failure'`
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
if (request.transfer_recipient_user_id !== void 0 && request.transaction_type !== TransactionType.Transfer) {
|
|
357
|
+
errors.push(
|
|
358
|
+
`${prefix}transfer_recipient_user_id is only allowed when transaction_type is '$transfer'`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function validateWager(request, errors, prefix) {
|
|
363
|
+
assertNonEmpty(request.transaction_id, "transaction_id", errors, prefix);
|
|
364
|
+
assertNonEmpty(request.wager_type, "wager_type", errors, prefix);
|
|
365
|
+
assertEnum(request.wager_status, SiftWagerStatusValues, "wager_status", errors, prefix);
|
|
366
|
+
if (!request.wager_status) {
|
|
367
|
+
errors.push(`${prefix}wager_status is required`);
|
|
368
|
+
}
|
|
369
|
+
assertPositiveAmount(request.amount, "amount", errors, prefix);
|
|
370
|
+
assertNonEmpty(request.currency, "currency", errors, prefix);
|
|
371
|
+
}
|
|
372
|
+
function validateChargeback(request, errors, prefix) {
|
|
373
|
+
const hasTransactionId = !!request.transaction_id?.trim();
|
|
374
|
+
const hasOrderId = !!request.order_id?.trim();
|
|
375
|
+
if (!hasTransactionId && !hasOrderId) {
|
|
376
|
+
errors.push(`${prefix}transaction_id or order_id is required`);
|
|
377
|
+
}
|
|
378
|
+
assertEnum(request.chargeback_state, SiftChargebackStateValues, "chargeback_state", errors, prefix);
|
|
379
|
+
assertEnum(
|
|
380
|
+
request.chargeback_reason,
|
|
381
|
+
SiftChargebackReasonValues,
|
|
382
|
+
"chargeback_reason",
|
|
383
|
+
errors,
|
|
384
|
+
prefix
|
|
385
|
+
);
|
|
386
|
+
if (request.ach_return_code !== void 0 && request.ach_return_code.trim() !== "") {
|
|
387
|
+
if (!/^R\d{2}$/i.test(request.ach_return_code.trim())) {
|
|
388
|
+
errors.push(`${prefix}ach_return_code must match NACHA R## pattern (e.g. R01)`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function validateByEventType(request, errors, prefix) {
|
|
393
|
+
switch (request.event_type) {
|
|
394
|
+
case "$login":
|
|
395
|
+
validateLogin(request, errors, prefix);
|
|
396
|
+
break;
|
|
397
|
+
case "$update_password":
|
|
398
|
+
validateUpdatePassword(request, errors, prefix);
|
|
399
|
+
break;
|
|
400
|
+
case "$transaction":
|
|
401
|
+
validateTransaction(request, errors, prefix);
|
|
402
|
+
break;
|
|
403
|
+
case "$wager":
|
|
404
|
+
validateWager(request, errors, prefix);
|
|
405
|
+
break;
|
|
406
|
+
case "$chargeback":
|
|
407
|
+
validateChargeback(request, errors, prefix);
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function validateScoreRequest(request, index) {
|
|
412
|
+
const errors = [];
|
|
413
|
+
const prefix = fieldPrefix(index);
|
|
414
|
+
validateBase(request, errors, prefix);
|
|
415
|
+
if (request.event_type && isPlannedFraudEventType(request.event_type)) {
|
|
416
|
+
errors.push(
|
|
417
|
+
`${prefix}event_type ${request.event_type} is not supported by POST /api/v1/fraud/score. Supported: ${SUPPORTED_FRAUD_EVENT_TYPES.join(", ")}`
|
|
418
|
+
);
|
|
419
|
+
} else if (request.event_type && !isSupportedFraudEventType(request.event_type)) {
|
|
420
|
+
errors.push(
|
|
421
|
+
`${prefix}event_type must be one of: ${SUPPORTED_FRAUD_EVENT_TYPES.join(", ")}`
|
|
422
|
+
);
|
|
423
|
+
} else if (isSupportedFraudEventType(request.event_type)) {
|
|
424
|
+
validateByEventType(request, errors, prefix);
|
|
425
|
+
}
|
|
426
|
+
if (errors.length > 0) {
|
|
427
|
+
throw new core.ValidationError(`Invalid fraud score request: ${errors.join(", ")}`, errors);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
5
431
|
// src/client.ts
|
|
6
432
|
var FraudClient = class extends core.BaseClient {
|
|
7
433
|
async scoreEvent(request, requestOptions) {
|
|
8
|
-
|
|
434
|
+
validateScoreRequest(request);
|
|
435
|
+
const body = normalizeScoreRequestForApi(request);
|
|
9
436
|
return this.requestWithRetry(
|
|
10
437
|
"/api/v1/fraud/score",
|
|
11
438
|
{
|
|
12
439
|
method: "POST",
|
|
13
|
-
body: JSON.stringify(
|
|
440
|
+
body: JSON.stringify(body)
|
|
14
441
|
},
|
|
15
442
|
void 0,
|
|
16
443
|
void 0,
|
|
@@ -24,36 +451,50 @@ var FraudClient = class extends core.BaseClient {
|
|
|
24
451
|
["requests"]
|
|
25
452
|
);
|
|
26
453
|
}
|
|
27
|
-
requests.
|
|
454
|
+
const bodies = requests.map((request, index) => {
|
|
455
|
+
validateScoreRequest(request, index);
|
|
456
|
+
return normalizeScoreRequestForApi(request);
|
|
457
|
+
});
|
|
28
458
|
return this.requestWithRetry(
|
|
29
459
|
"/api/v1/fraud/score/bulk",
|
|
30
460
|
{
|
|
31
461
|
method: "POST",
|
|
32
|
-
body: JSON.stringify(
|
|
462
|
+
body: JSON.stringify(bodies)
|
|
33
463
|
},
|
|
34
464
|
void 0,
|
|
35
465
|
void 0,
|
|
36
466
|
requestOptions
|
|
37
467
|
);
|
|
38
468
|
}
|
|
39
|
-
validateScoreRequest(request, index) {
|
|
40
|
-
const errors = [];
|
|
41
|
-
const prefix = index === void 0 ? "" : `requests[${index}].`;
|
|
42
|
-
if (!request.customer_id?.trim()) {
|
|
43
|
-
errors.push(`${prefix}customer_id is required`);
|
|
44
|
-
}
|
|
45
|
-
if (!request.sift_user_id?.trim()) {
|
|
46
|
-
errors.push(`${prefix}sift_user_id is required`);
|
|
47
|
-
}
|
|
48
|
-
if (!request.event_type?.trim()) {
|
|
49
|
-
errors.push(`${prefix}event_type is required`);
|
|
50
|
-
}
|
|
51
|
-
if (errors.length > 0) {
|
|
52
|
-
throw new core.ValidationError(`Invalid fraud score request: ${errors.join(", ")}`, errors);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
469
|
};
|
|
56
470
|
|
|
471
|
+
exports.CHARGEBACK_FRAUD_EVENT_TYPE = CHARGEBACK_FRAUD_EVENT_TYPE;
|
|
472
|
+
exports.ChargebackReason = ChargebackReason;
|
|
473
|
+
exports.ChargebackState = ChargebackState;
|
|
57
474
|
exports.FraudClient = FraudClient;
|
|
475
|
+
exports.LoginStatus = LoginStatus;
|
|
476
|
+
exports.PLANNED_FRAUD_EVENT_TYPES = PLANNED_FRAUD_EVENT_TYPES;
|
|
477
|
+
exports.PasswordUpdateReason = PasswordUpdateReason;
|
|
478
|
+
exports.PasswordUpdateStatus = PasswordUpdateStatus;
|
|
479
|
+
exports.SCORED_FRAUD_EVENT_TYPES = SCORED_FRAUD_EVENT_TYPES;
|
|
480
|
+
exports.SUPPORTED_FRAUD_EVENT_TYPES = SUPPORTED_FRAUD_EVENT_TYPES;
|
|
481
|
+
exports.SiftChargebackReasonValues = SiftChargebackReasonValues;
|
|
482
|
+
exports.SiftChargebackStateValues = SiftChargebackStateValues;
|
|
483
|
+
exports.SiftLoginFailureReasonValues = SiftLoginFailureReasonValues;
|
|
484
|
+
exports.SiftLoginStatusValues = SiftLoginStatusValues;
|
|
485
|
+
exports.SiftPasswordUpdateReasonValues = SiftPasswordUpdateReasonValues;
|
|
486
|
+
exports.SiftPasswordUpdateStatusValues = SiftPasswordUpdateStatusValues;
|
|
487
|
+
exports.SiftTransactionStatusValues = SiftTransactionStatusValues;
|
|
488
|
+
exports.SiftTransactionTypeValues = SiftTransactionTypeValues;
|
|
489
|
+
exports.SiftWagerStatusValues = SiftWagerStatusValues;
|
|
490
|
+
exports.TransactionStatus = TransactionStatus;
|
|
491
|
+
exports.TransactionType = TransactionType;
|
|
492
|
+
exports.WagerStatus = WagerStatus;
|
|
493
|
+
exports.buildScoreRequestPreview = buildScoreRequestPreview;
|
|
494
|
+
exports.hasReservedMetadataKey = hasReservedMetadataKey;
|
|
495
|
+
exports.isPlannedFraudEventType = isPlannedFraudEventType;
|
|
496
|
+
exports.isSupportedFraudEventType = isSupportedFraudEventType;
|
|
497
|
+
exports.normalizeScoreRequestForApi = normalizeScoreRequestForApi;
|
|
498
|
+
exports.validateScoreRequest = validateScoreRequest;
|
|
58
499
|
//# sourceMappingURL=index.js.map
|
|
59
500
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":["BaseClient","ValidationError"],"mappings":";;;;;AAaO,IAAM,WAAA,GAAN,cAA0BA,eAAA,CAAW;AAAA,EAC1C,MAAM,UAAA,CACJ,OAAA,EACA,cAAA,EAC6D;AAC7D,IAAA,IAAA,CAAK,qBAAqB,OAAO,CAAA;AAEjC,IAAA,OAAO,IAAA,CAAK,gBAAA;AAAA,MACV,qBAAA;AAAA,MACA;AAAA,QACE,MAAA,EAAQ,MAAA;AAAA,QACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,OAC9B;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA,EAEA,MAAM,eAAA,CACJ,QAAA,EACA,cAAA,EAC+D;AAC/D,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,IAAK,QAAA,CAAS,WAAW,CAAA,EAAG;AACrD,MAAA,MAAM,IAAIC,oBAAA;AAAA,QACR,oEAAA;AAAA,QACA,CAAC,UAAU;AAAA,OACb;AAAA,IACF;AAEA,IAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,OAAA,EAAS,KAAA,KAAU,KAAK,oBAAA,CAAqB,OAAA,EAAS,KAAK,CAAC,CAAA;AAE9E,IAAA,OAAO,IAAA,CAAK,gBAAA;AAAA,MACV,0BAAA;AAAA,MACA;AAAA,QACE,MAAA,EAAQ,MAAA;AAAA,QACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,QAAQ;AAAA,OAC/B;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA,EAEQ,oBAAA,CAAqB,SAA4B,KAAA,EAAsB;AAC7E,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,MAAM,MAAA,GAAS,KAAA,KAAU,MAAA,GAAY,EAAA,GAAK,YAAY,KAAK,CAAA,EAAA,CAAA;AAE3D,IAAA,IAAI,CAAC,OAAA,CAAQ,WAAA,EAAa,IAAA,EAAK,EAAG;AAChC,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,MAAM,CAAA,uBAAA,CAAyB,CAAA;AAAA,IAChD;AACA,IAAA,IAAI,CAAC,OAAA,CAAQ,YAAA,EAAc,IAAA,EAAK,EAAG;AACjC,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,MAAM,CAAA,wBAAA,CAA0B,CAAA;AAAA,IACjD;AACA,IAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,EAAY,IAAA,EAAK,EAAG;AAC/B,MAAA,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,MAAM,CAAA,sBAAA,CAAwB,CAAA;AAAA,IAC/C;AAEA,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,MAAA,MAAM,IAAIA,qBAAgB,CAAA,6BAAA,EAAgC,MAAA,CAAO,KAAK,IAAI,CAAC,IAAI,MAAM,CAAA;AAAA,IACvF;AAAA,EACF;AACF","file":"index.js","sourcesContent":["/**\n * Fraud scoring API client.\n */\n\nimport { BaseClient } from '@vesant-sdk/core';\nimport type { RequestOptions } from '@vesant-sdk/core';\nimport { ValidationError } from '@vesant-sdk/core';\nimport type {\n FraudScoreRequest,\n FraudScoreResponseData,\n FraudScoreResponseEnvelope,\n} from './types';\n\nexport class FraudClient extends BaseClient {\n async scoreEvent(\n request: FraudScoreRequest,\n requestOptions?: RequestOptions\n ): Promise<FraudScoreResponseEnvelope<FraudScoreResponseData>> {\n this.validateScoreRequest(request);\n\n return this.requestWithRetry<FraudScoreResponseEnvelope<FraudScoreResponseData>>(\n '/api/v1/fraud/score',\n {\n method: 'POST',\n body: JSON.stringify(request),\n },\n undefined,\n undefined,\n requestOptions\n );\n }\n\n async scoreEventsBulk(\n requests: FraudScoreRequest[],\n requestOptions?: RequestOptions\n ): Promise<FraudScoreResponseEnvelope<FraudScoreResponseData[]>> {\n if (!Array.isArray(requests) || requests.length === 0) {\n throw new ValidationError(\n 'Invalid bulk score request: at least one score request is required',\n ['requests']\n );\n }\n\n requests.forEach((request, index) => this.validateScoreRequest(request, index));\n\n return this.requestWithRetry<FraudScoreResponseEnvelope<FraudScoreResponseData[]>>(\n '/api/v1/fraud/score/bulk',\n {\n method: 'POST',\n body: JSON.stringify(requests),\n },\n undefined,\n undefined,\n requestOptions\n );\n }\n\n private validateScoreRequest(request: FraudScoreRequest, index?: number): void {\n const errors: string[] = [];\n const prefix = index === undefined ? '' : `requests[${index}].`;\n\n if (!request.customer_id?.trim()) {\n errors.push(`${prefix}customer_id is required`);\n }\n if (!request.sift_user_id?.trim()) {\n errors.push(`${prefix}sift_user_id is required`);\n }\n if (!request.event_type?.trim()) {\n errors.push(`${prefix}event_type is required`);\n }\n\n if (errors.length > 0) {\n throw new ValidationError(`Invalid fraud score request: ${errors.join(', ')}`, errors);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/enums.ts","../src/normalization/normalize.ts","../src/normalization/preview.ts","../src/types/events.ts","../src/types/metadata.ts","../src/validation/helpers.ts","../src/validation/rules.ts","../src/client.ts"],"names":["ValidationError","BaseClient"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Sift-aligned enum types and const objects for fraud scoring requests.\n */\n\nexport type SiftTransactionType =\n | '$sale'\n | '$authorize'\n | '$capture'\n | '$void'\n | '$refund'\n | '$deposit'\n | '$withdrawal'\n | '$transfer'\n | '$buy'\n | '$sell'\n | '$send'\n | '$receive';\n\nexport const SiftTransactionTypeValues = [\n '$sale',\n '$authorize',\n '$capture',\n '$void',\n '$refund',\n '$deposit',\n '$withdrawal',\n '$transfer',\n '$buy',\n '$sell',\n '$send',\n '$receive',\n] as const satisfies readonly SiftTransactionType[];\n\nexport const TransactionType = {\n Sale: '$sale',\n Authorize: '$authorize',\n Capture: '$capture',\n Void: '$void',\n Refund: '$refund',\n Deposit: '$deposit',\n Withdrawal: '$withdrawal',\n Transfer: '$transfer',\n Buy: '$buy',\n Sell: '$sell',\n Send: '$send',\n Receive: '$receive',\n} as const satisfies Record<string, SiftTransactionType>;\n\nexport type SiftChargebackState =\n | '$received'\n | '$accepted'\n | '$disputed'\n | '$won'\n | '$lost';\n\nexport const SiftChargebackStateValues = [\n '$received',\n '$accepted',\n '$disputed',\n '$won',\n '$lost',\n] as const satisfies readonly SiftChargebackState[];\n\nexport const ChargebackState = {\n Received: '$received',\n Accepted: '$accepted',\n Disputed: '$disputed',\n Won: '$won',\n Lost: '$lost',\n} as const satisfies Record<string, SiftChargebackState>;\n\nexport type SiftChargebackReason =\n | '$fraud'\n | '$duplicate'\n | '$product_not_received'\n | '$product_unacceptable'\n | '$authorization'\n | '$consumer_disputes'\n | '$processing_errors'\n | '$cancel_subscription'\n | '$friendly_fraud'\n | '$ach_return'\n | '$ach_reversal'\n | '$other';\n\nexport const SiftChargebackReasonValues = [\n '$fraud',\n '$duplicate',\n '$product_not_received',\n '$product_unacceptable',\n '$authorization',\n '$consumer_disputes',\n '$processing_errors',\n '$cancel_subscription',\n '$friendly_fraud',\n '$ach_return',\n '$ach_reversal',\n '$other',\n] as const satisfies readonly SiftChargebackReason[];\n\nexport const ChargebackReason = {\n Fraud: '$fraud',\n Duplicate: '$duplicate',\n ProductNotReceived: '$product_not_received',\n ProductUnacceptable: '$product_unacceptable',\n Authorization: '$authorization',\n ConsumerDisputes: '$consumer_disputes',\n ProcessingErrors: '$processing_errors',\n CancelSubscription: '$cancel_subscription',\n FriendlyFraud: '$friendly_fraud',\n AchReturn: '$ach_return',\n AchReversal: '$ach_reversal',\n Other: '$other',\n} as const satisfies Record<string, SiftChargebackReason>;\n\nexport type SiftLoginStatus = '$success' | '$failure';\n\nexport const SiftLoginStatusValues = ['$success', '$failure'] as const satisfies readonly SiftLoginStatus[];\n\nexport const LoginStatus = {\n Success: '$success',\n Failure: '$failure',\n} as const satisfies Record<string, SiftLoginStatus>;\n\nexport type SiftLoginFailureReason =\n | '$account_unknown'\n | '$account_suspended'\n | '$account_disabled'\n | '$wrong_password';\n\nexport const SiftLoginFailureReasonValues = [\n '$account_unknown',\n '$account_suspended',\n '$account_disabled',\n '$wrong_password',\n] as const satisfies readonly SiftLoginFailureReason[];\n\nexport type SiftPasswordUpdateReason =\n | '$user_update'\n | '$forgot_password'\n | '$forced_reset';\n\nexport const SiftPasswordUpdateReasonValues = [\n '$user_update',\n '$forgot_password',\n '$forced_reset',\n] as const satisfies readonly SiftPasswordUpdateReason[];\n\nexport const PasswordUpdateReason = {\n UserUpdate: SiftPasswordUpdateReasonValues[0],\n ForgotPassword: SiftPasswordUpdateReasonValues[1],\n ForcedReset: SiftPasswordUpdateReasonValues[2],\n} as const satisfies Record<string, SiftPasswordUpdateReason>;\n\nexport type SiftPasswordUpdateStatus = '$pending' | '$success' | '$failure';\n\nexport const SiftPasswordUpdateStatusValues = [\n '$pending',\n '$success',\n '$failure',\n] as const satisfies readonly SiftPasswordUpdateStatus[];\n\nexport const PasswordUpdateStatus = {\n Pending: '$pending',\n Success: '$success',\n Failure: '$failure',\n} as const satisfies Record<string, SiftPasswordUpdateStatus>;\n\nexport type SiftWagerStatus = '$accept' | '$cancel';\n\nexport const SiftWagerStatusValues = ['$accept', '$cancel'] as const satisfies readonly SiftWagerStatus[];\n\nexport const WagerStatus = {\n Accept: '$accept',\n Cancel: '$cancel',\n} as const satisfies Record<string, SiftWagerStatus>;\n\nexport type SiftTransactionStatus = '$success' | '$failure' | '$pending';\n\nexport const SiftTransactionStatusValues = [\n '$success',\n '$failure',\n '$pending',\n] as const satisfies readonly SiftTransactionStatus[];\n\nexport const TransactionStatus = {\n Success: '$success',\n Failure: '$failure',\n Pending: '$pending',\n} as const satisfies Record<string, SiftTransactionStatus>;\n\nexport type FraudRiskLevel = 'low' | 'medium' | 'high' | 'critical';\n","import { LoginStatus } from '../types/enums';\nimport type { FraudScoreRequest } from '../types/requests';\nimport type { FraudCustomMetadata } from '../types/metadata';\n\nfunction mergeMetadata(\n base: FraudCustomMetadata | undefined,\n extras: FraudCustomMetadata\n): FraudCustomMetadata {\n return { ...base, ...extras };\n}\n\nfunction stripSdkOnlyFields(\n request: Record<string, unknown>,\n keys: string[]\n): Record<string, unknown> {\n const body = { ...request };\n for (const key of keys) {\n delete body[key];\n }\n return body;\n}\n\nfunction createStrippedBody(\n rest: Record<string, unknown>,\n metadata: FraudCustomMetadata | undefined,\n stripKeys: string[]\n): Record<string, unknown> {\n return stripSdkOnlyFields(\n { ...rest, metadata: mergeMetadata(metadata, {}) },\n stripKeys\n );\n}\n\nfunction applySiftMetadata(\n body: Record<string, unknown>,\n metadata: FraudCustomMetadata | undefined,\n siftMetadata: FraudCustomMetadata,\n onlyWhenNonEmpty = false\n): Record<string, unknown> {\n if (!onlyWhenNonEmpty || Object.keys(siftMetadata).length > 0) {\n body.metadata = mergeMetadata(metadata, siftMetadata);\n }\n return body;\n}\n\nfunction normalizeUpdatePassword(\n request: Extract<FraudScoreRequest, { event_type: '$update_password' }>\n): Record<string, unknown> {\n const { password_reason, password_status, metadata, ...rest } = request;\n const body = createStrippedBody(rest, metadata, []);\n const siftMetadata: FraudCustomMetadata = {};\n if (password_reason) siftMetadata.$reason = password_reason;\n if (password_status) siftMetadata.$status = password_status;\n return applySiftMetadata(body, metadata, siftMetadata);\n}\n\nfunction normalizeWager(\n request: Extract<FraudScoreRequest, { event_type: '$wager' }>\n): Record<string, unknown> {\n const { wager_type, wager_status, wager_event_type, wager_event_name, wager_event_id, metadata, ...rest } =\n request;\n const body = createStrippedBody(rest, metadata, [\n 'wager_type',\n 'wager_status',\n 'wager_event_type',\n 'wager_event_name',\n 'wager_event_id',\n ]);\n const siftMetadata: FraudCustomMetadata = {\n $wager_type: wager_type,\n $wager_status: wager_status,\n };\n if (wager_event_type) siftMetadata.wager_event_type = wager_event_type;\n if (wager_event_name) siftMetadata.wager_event_name = wager_event_name;\n if (wager_event_id) siftMetadata.wager_event_id = wager_event_id;\n return applySiftMetadata(body, metadata, siftMetadata);\n}\n\nfunction normalizeLogin(\n request: Extract<FraudScoreRequest, { event_type: '$login' }>\n): Record<string, unknown> {\n const { login_status, login_failure_reason, metadata, ...rest } = request;\n const effectiveStatus = login_status ?? LoginStatus.Success;\n const body = createStrippedBody(rest, metadata, [\n 'login_status',\n 'login_failure_reason',\n ]);\n const siftMetadata: FraudCustomMetadata = {\n $login_status: effectiveStatus,\n };\n if (effectiveStatus === LoginStatus.Failure && login_failure_reason) {\n siftMetadata.$failure_reason = login_failure_reason;\n }\n return applySiftMetadata(body, metadata, siftMetadata);\n}\n\nfunction normalizeTransaction(\n request: Extract<FraudScoreRequest, { event_type: '$transaction' }>\n): Record<string, unknown> {\n const { transaction_status, decline_category, transfer_recipient_user_id, metadata, ...rest } =\n request;\n const body = createStrippedBody(rest, metadata, [\n 'transaction_status',\n 'decline_category',\n 'transfer_recipient_user_id',\n ]);\n const siftMetadata: FraudCustomMetadata = {};\n if (transaction_status) siftMetadata.$transaction_status = transaction_status;\n if (decline_category) siftMetadata.$decline_category = decline_category;\n if (transfer_recipient_user_id) {\n siftMetadata.$transfer_recipient_user_id = transfer_recipient_user_id;\n }\n return applySiftMetadata(body, metadata, siftMetadata, true);\n}\n\nexport function normalizeScoreRequestForApi(request: FraudScoreRequest): Record<string, unknown> {\n switch (request.event_type) {\n case '$update_password':\n return normalizeUpdatePassword(request);\n case '$wager':\n return normalizeWager(request);\n case '$login':\n return normalizeLogin(request);\n case '$transaction':\n return normalizeTransaction(request);\n default:\n return { ...request };\n }\n}\n","import type { FraudScoreRequest } from '../types/requests';\nimport { normalizeScoreRequestForApi } from './normalize';\n\n/**\n * Returns the JSON body that would be sent to POST /api/v1/fraud/score after normalization.\n * Useful for debugging without calling the API.\n */\nexport function buildScoreRequestPreview(request: FraudScoreRequest): Record<string, unknown> {\n return normalizeScoreRequestForApi(request);\n}\n","/**\n * Fraud event type unions aligned with fraud-service support matrix.\n */\n\n/** Events that run Sift scoring + rule engine */\nexport type ScoredFraudEventType =\n | '$create_account'\n | '$login'\n | '$logout'\n | '$update_account'\n | '$update_password'\n | '$transaction'\n | '$wager';\n\n/** Feedback-only; no meaningful fraud score in response */\nexport type ChargebackFraudEventType = '$chargeback';\n\n/** Union accepted by scoreEvent / scoreEventsBulk */\nexport type SupportedFraudEventType = ScoredFraudEventType | ChargebackFraudEventType;\n\nexport const SCORED_FRAUD_EVENT_TYPES: readonly ScoredFraudEventType[] = [\n '$create_account',\n '$login',\n '$logout',\n '$update_account',\n '$update_password',\n '$transaction',\n '$wager',\n] as const;\n\nexport const CHARGEBACK_FRAUD_EVENT_TYPE = '$chargeback' as const;\n\nexport const SUPPORTED_FRAUD_EVENT_TYPES: readonly SupportedFraudEventType[] = [\n ...SCORED_FRAUD_EVENT_TYPES,\n CHARGEBACK_FRAUD_EVENT_TYPE,\n] as const;\n\nexport const PLANNED_FRAUD_EVENT_TYPES = [\n '$verification',\n '$link_session_to_user',\n '$security_notification',\n '$create_order',\n '$update_order',\n '$order_status',\n '$add_promotion',\n] as const;\n\n/**\n * Listed in Vesant dashboard / future API — NOT valid for scoreEvent today.\n * @deprecated Not supported by POST /api/v1/fraud/score\n */\nexport type PlannedFraudEventType = (typeof PLANNED_FRAUD_EVENT_TYPES)[number];\n\n/**\n * @deprecated Use SupportedFraudEventType; kept for migration\n */\nexport type FraudEventType = SupportedFraudEventType | (typeof PLANNED_FRAUD_EVENT_TYPES)[number];\n\nexport function isPlannedFraudEventType(\n eventType: string\n): eventType is (typeof PLANNED_FRAUD_EVENT_TYPES)[number] {\n return (PLANNED_FRAUD_EVENT_TYPES as readonly string[]).includes(eventType);\n}\n\nexport function isSupportedFraudEventType(\n eventType: string\n): eventType is SupportedFraudEventType {\n return (SUPPORTED_FRAUD_EVENT_TYPES as readonly string[]).includes(eventType);\n}\n","/**\n * Custom metadata for fraud score requests (non-Sift reserved keys).\n */\n\nexport type FraudCustomMetadata = Record<string, unknown>;\n\nexport function hasReservedMetadataKey(metadata: FraudCustomMetadata): string | undefined {\n for (const key of Object.keys(metadata)) {\n if (key.startsWith('$')) {\n return key;\n }\n }\n return undefined;\n}\n","import { hasReservedMetadataKey } from '../types/metadata';\nimport type { FraudCustomMetadata } from '../types/metadata';\n\nexport function fieldPrefix(index?: number): string {\n return index === undefined ? '' : `requests[${index}].`;\n}\n\nexport function assertNonEmpty(\n value: string | undefined,\n field: string,\n errors: string[],\n prefix: string\n): void {\n if (!value?.trim()) {\n errors.push(`${prefix}${field} is required`);\n }\n}\n\nexport function assertEnum<T extends string>(\n value: string | undefined,\n allowed: readonly T[],\n field: string,\n errors: string[],\n prefix: string\n): void {\n if (value === undefined) return;\n if (!(allowed as readonly string[]).includes(value)) {\n errors.push(`${prefix}${field} must be one of: ${allowed.join(', ')}`);\n }\n}\n\nexport function assertPositiveAmount(\n amount: number | undefined,\n field: string,\n errors: string[],\n prefix: string\n): void {\n if (amount === undefined || amount <= 0) {\n errors.push(`${prefix}${field} must be greater than 0`);\n }\n}\n\nexport function validateMetadata(\n metadata: FraudCustomMetadata | undefined,\n errors: string[],\n prefix: string\n): void {\n if (!metadata) return;\n const reservedKey = hasReservedMetadataKey(metadata);\n if (reservedKey) {\n errors.push(\n `${prefix}metadata keys must not start with '$' (found '${reservedKey}'). Use typed request fields instead.`\n );\n }\n}\n","import { ValidationError } from '@vesant-sdk/core';\nimport {\n SiftChargebackReasonValues,\n SiftChargebackStateValues,\n SiftLoginFailureReasonValues,\n SiftLoginStatusValues,\n SiftPasswordUpdateReasonValues,\n SiftPasswordUpdateStatusValues,\n SiftTransactionStatusValues,\n SiftTransactionTypeValues,\n SiftWagerStatusValues,\n TransactionType,\n} from '../types/enums';\nimport {\n isPlannedFraudEventType,\n isSupportedFraudEventType,\n SUPPORTED_FRAUD_EVENT_TYPES,\n} from '../types/events';\nimport type { FraudScoreRequest } from '../types/requests';\nimport {\n assertEnum,\n assertNonEmpty,\n assertPositiveAmount,\n fieldPrefix,\n validateMetadata,\n} from './helpers';\n\nfunction validateBase(\n request: FraudScoreRequest,\n errors: string[],\n prefix: string\n): void {\n assertNonEmpty(request.customer_id, 'customer_id', errors, prefix);\n assertNonEmpty(request.sift_user_id, 'sift_user_id', errors, prefix);\n assertNonEmpty(request.event_type, 'event_type', errors, prefix);\n validateMetadata(request.metadata, errors, prefix);\n}\n\nfunction validateLogin(\n request: Extract<FraudScoreRequest, { event_type: '$login' }>,\n errors: string[],\n prefix: string\n): void {\n assertEnum(request.login_status, SiftLoginStatusValues, 'login_status', errors, prefix);\n if (request.login_failure_reason !== undefined) {\n if (request.login_status === '$failure') {\n assertEnum(\n request.login_failure_reason,\n SiftLoginFailureReasonValues,\n 'login_failure_reason',\n errors,\n prefix\n );\n } else {\n errors.push(`${prefix}login_failure_reason is only allowed when login_status is '$failure'`);\n }\n }\n}\n\nfunction validateUpdatePassword(\n request: Extract<FraudScoreRequest, { event_type: '$update_password' }>,\n errors: string[],\n prefix: string\n): void {\n assertEnum(\n request.password_reason,\n SiftPasswordUpdateReasonValues,\n 'password_reason',\n errors,\n prefix\n );\n if (!request.password_reason) {\n errors.push(`${prefix}password_reason is required`);\n }\n assertEnum(\n request.password_status,\n SiftPasswordUpdateStatusValues,\n 'password_status',\n errors,\n prefix\n );\n if (!request.password_status) {\n errors.push(`${prefix}password_status is required`);\n }\n}\n\nfunction validateTransaction(\n request: Extract<FraudScoreRequest, { event_type: '$transaction' }>,\n errors: string[],\n prefix: string\n): void {\n assertPositiveAmount(request.amount, 'amount', errors, prefix);\n assertNonEmpty(request.currency, 'currency', errors, prefix);\n assertEnum(request.transaction_type, SiftTransactionTypeValues, 'transaction_type', errors, prefix);\n assertEnum(\n request.transaction_status,\n SiftTransactionStatusValues,\n 'transaction_status',\n errors,\n prefix\n );\n\n if (request.decline_category !== undefined && request.transaction_status !== '$failure') {\n errors.push(\n `${prefix}decline_category is only allowed when transaction_status is '$failure'`\n );\n }\n\n if (\n request.transfer_recipient_user_id !== undefined &&\n request.transaction_type !== TransactionType.Transfer\n ) {\n errors.push(\n `${prefix}transfer_recipient_user_id is only allowed when transaction_type is '$transfer'`\n );\n }\n}\n\nfunction validateWager(\n request: Extract<FraudScoreRequest, { event_type: '$wager' }>,\n errors: string[],\n prefix: string\n): void {\n assertNonEmpty(request.transaction_id, 'transaction_id', errors, prefix);\n assertNonEmpty(request.wager_type, 'wager_type', errors, prefix);\n assertEnum(request.wager_status, SiftWagerStatusValues, 'wager_status', errors, prefix);\n if (!request.wager_status) {\n errors.push(`${prefix}wager_status is required`);\n }\n assertPositiveAmount(request.amount, 'amount', errors, prefix);\n assertNonEmpty(request.currency, 'currency', errors, prefix);\n}\n\nfunction validateChargeback(\n request: Extract<FraudScoreRequest, { event_type: '$chargeback' }>,\n errors: string[],\n prefix: string\n): void {\n const hasTransactionId = !!request.transaction_id?.trim();\n const hasOrderId = !!request.order_id?.trim();\n if (!hasTransactionId && !hasOrderId) {\n errors.push(`${prefix}transaction_id or order_id is required`);\n }\n assertEnum(request.chargeback_state, SiftChargebackStateValues, 'chargeback_state', errors, prefix);\n assertEnum(\n request.chargeback_reason,\n SiftChargebackReasonValues,\n 'chargeback_reason',\n errors,\n prefix\n );\n if (request.ach_return_code !== undefined && request.ach_return_code.trim() !== '') {\n if (!/^R\\d{2}$/i.test(request.ach_return_code.trim())) {\n errors.push(`${prefix}ach_return_code must match NACHA R## pattern (e.g. R01)`);\n }\n }\n}\n\nfunction validateByEventType(request: FraudScoreRequest, errors: string[], prefix: string): void {\n switch (request.event_type) {\n case '$login':\n validateLogin(request, errors, prefix);\n break;\n case '$update_password':\n validateUpdatePassword(request, errors, prefix);\n break;\n case '$transaction':\n validateTransaction(request, errors, prefix);\n break;\n case '$wager':\n validateWager(request, errors, prefix);\n break;\n case '$chargeback':\n validateChargeback(request, errors, prefix);\n break;\n case '$create_account':\n case '$logout':\n case '$update_account':\n break;\n default:\n break;\n }\n}\n\nexport function validateScoreRequest(request: FraudScoreRequest, index?: number): void {\n const errors: string[] = [];\n const prefix = fieldPrefix(index);\n\n validateBase(request, errors, prefix);\n\n if (request.event_type && isPlannedFraudEventType(request.event_type)) {\n errors.push(\n `${prefix}event_type ${request.event_type} is not supported by POST /api/v1/fraud/score. Supported: ${SUPPORTED_FRAUD_EVENT_TYPES.join(', ')}`\n );\n } else if (request.event_type && !isSupportedFraudEventType(request.event_type)) {\n errors.push(\n `${prefix}event_type must be one of: ${SUPPORTED_FRAUD_EVENT_TYPES.join(', ')}`\n );\n } else if (isSupportedFraudEventType(request.event_type)) {\n validateByEventType(request, errors, prefix);\n }\n\n if (errors.length > 0) {\n throw new ValidationError(`Invalid fraud score request: ${errors.join(', ')}`, errors);\n }\n}\n","/**\n * Fraud scoring API client.\n */\n\nimport { BaseClient } from '@vesant-sdk/core';\nimport type { RequestOptions } from '@vesant-sdk/core';\nimport { ValidationError } from '@vesant-sdk/core';\nimport { normalizeScoreRequestForApi } from './normalization';\nimport type {\n FraudScoreRequest,\n FraudScoreResponseData,\n FraudScoreResponseEnvelope,\n} from './types';\nimport { validateScoreRequest } from './validation/rules';\n\nexport class FraudClient extends BaseClient {\n async scoreEvent(\n request: FraudScoreRequest,\n requestOptions?: RequestOptions\n ): Promise<FraudScoreResponseEnvelope<FraudScoreResponseData>> {\n validateScoreRequest(request);\n const body = normalizeScoreRequestForApi(request);\n\n return this.requestWithRetry<FraudScoreResponseEnvelope<FraudScoreResponseData>>(\n '/api/v1/fraud/score',\n {\n method: 'POST',\n body: JSON.stringify(body),\n },\n undefined,\n undefined,\n requestOptions\n );\n }\n\n async scoreEventsBulk(\n requests: FraudScoreRequest[],\n requestOptions?: RequestOptions\n ): Promise<FraudScoreResponseEnvelope<FraudScoreResponseData[]>> {\n if (!Array.isArray(requests) || requests.length === 0) {\n throw new ValidationError(\n 'Invalid bulk score request: at least one score request is required',\n ['requests']\n );\n }\n\n const bodies = requests.map((request, index) => {\n validateScoreRequest(request, index);\n return normalizeScoreRequestForApi(request);\n });\n\n return this.requestWithRetry<FraudScoreResponseEnvelope<FraudScoreResponseData[]>>(\n '/api/v1/fraud/score/bulk',\n {\n method: 'POST',\n body: JSON.stringify(bodies),\n },\n undefined,\n undefined,\n requestOptions\n );\n }\n}\n"]}
|