@vesant-sdk/fraud 0.1.1-next.f221d37 → 0.1.2-dev.254dc8c
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 +303 -15
- package/dist/index.d.mts +249 -14
- package/dist/index.d.ts +249 -14
- package/dist/index.js +635 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +623 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -121,8 +121,321 @@ var TransactionStatus = {
|
|
|
121
121
|
Failure: "$failure",
|
|
122
122
|
Pending: "$pending"
|
|
123
123
|
};
|
|
124
|
+
var SiftPaymentTypeValues = [
|
|
125
|
+
"$cash",
|
|
126
|
+
"$check",
|
|
127
|
+
"$credit_card",
|
|
128
|
+
"$crypto_currency",
|
|
129
|
+
"$debit_card",
|
|
130
|
+
"$digital_wallet",
|
|
131
|
+
"$electronic_fund_transfer",
|
|
132
|
+
"$financing",
|
|
133
|
+
"$gift_card",
|
|
134
|
+
"$invoice",
|
|
135
|
+
"$in_app_purchase",
|
|
136
|
+
"$money_order",
|
|
137
|
+
"$points",
|
|
138
|
+
"$prepaid_card",
|
|
139
|
+
"$store_credit",
|
|
140
|
+
"$third_party_processor",
|
|
141
|
+
"$voucher",
|
|
142
|
+
"$sepa_credit",
|
|
143
|
+
"$sepa_instant_credit",
|
|
144
|
+
"$sepa_direct_debit",
|
|
145
|
+
"$ach_credit",
|
|
146
|
+
"$ach_debit",
|
|
147
|
+
"$wire_credit",
|
|
148
|
+
"$wire_debit"
|
|
149
|
+
];
|
|
150
|
+
var PaymentType = {
|
|
151
|
+
Cash: "$cash",
|
|
152
|
+
Check: "$check",
|
|
153
|
+
CreditCard: "$credit_card",
|
|
154
|
+
CryptoCurrency: "$crypto_currency",
|
|
155
|
+
DebitCard: "$debit_card",
|
|
156
|
+
DigitalWallet: "$digital_wallet",
|
|
157
|
+
ElectronicFundTransfer: "$electronic_fund_transfer",
|
|
158
|
+
Financing: "$financing",
|
|
159
|
+
GiftCard: "$gift_card",
|
|
160
|
+
Invoice: "$invoice",
|
|
161
|
+
InAppPurchase: "$in_app_purchase",
|
|
162
|
+
MoneyOrder: "$money_order",
|
|
163
|
+
Points: "$points",
|
|
164
|
+
PrepaidCard: "$prepaid_card",
|
|
165
|
+
StoreCredit: "$store_credit",
|
|
166
|
+
ThirdPartyProcessor: "$third_party_processor",
|
|
167
|
+
Voucher: "$voucher",
|
|
168
|
+
SepaCredit: "$sepa_credit",
|
|
169
|
+
SepaInstantCredit: "$sepa_instant_credit",
|
|
170
|
+
SepaDirectDebit: "$sepa_direct_debit",
|
|
171
|
+
AchCredit: "$ach_credit",
|
|
172
|
+
AchDebit: "$ach_debit",
|
|
173
|
+
WireCredit: "$wire_credit",
|
|
174
|
+
WireDebit: "$wire_debit"
|
|
175
|
+
};
|
|
176
|
+
var SiftWalletTypeValues = ["$crypto", "$digital", "$fiat"];
|
|
177
|
+
var WalletType = {
|
|
178
|
+
Crypto: "$crypto",
|
|
179
|
+
Digital: "$digital",
|
|
180
|
+
Fiat: "$fiat"
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/types/rule-signals.ts
|
|
184
|
+
var LOGIN_RULE_SIGNAL_KEYS = ["ip_country_mismatch"];
|
|
185
|
+
var UPDATE_ACCOUNT_RULE_SIGNAL_KEYS = [
|
|
186
|
+
"two_fa_enabled",
|
|
187
|
+
"two_fa_disabled",
|
|
188
|
+
"two_fa_method_changed"
|
|
189
|
+
];
|
|
190
|
+
var TRANSACTION_RULE_SIGNAL_KEYS = [
|
|
191
|
+
"payment_method",
|
|
192
|
+
"is_first_deposit",
|
|
193
|
+
"cumulative_deposit_amount",
|
|
194
|
+
"deposit_count",
|
|
195
|
+
"failed_deposit_count",
|
|
196
|
+
"is_first_withdrawal",
|
|
197
|
+
"withdrawal_method_differs",
|
|
198
|
+
"cumulative_withdrawal_amount",
|
|
199
|
+
"withdrawal_count",
|
|
200
|
+
"hours_since_last_deposit",
|
|
201
|
+
"days_since_last_activity",
|
|
202
|
+
"hours_since_account_creation"
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
// src/normalization/payment-methods.ts
|
|
206
|
+
var PAYMENT_TYPE_ALIASES = {
|
|
207
|
+
bank_account: "$electronic_fund_transfer",
|
|
208
|
+
electronic_fund_transfer: "$electronic_fund_transfer",
|
|
209
|
+
credit_card: "$credit_card",
|
|
210
|
+
crypto_currency: "$crypto_currency",
|
|
211
|
+
debit_card: "$debit_card",
|
|
212
|
+
digital_wallet: "$digital_wallet",
|
|
213
|
+
cash: "$cash",
|
|
214
|
+
check: "$check",
|
|
215
|
+
financing: "$financing",
|
|
216
|
+
gift_card: "$gift_card",
|
|
217
|
+
invoice: "$invoice",
|
|
218
|
+
in_app_purchase: "$in_app_purchase",
|
|
219
|
+
money_order: "$money_order",
|
|
220
|
+
points: "$points",
|
|
221
|
+
prepaid_card: "$prepaid_card",
|
|
222
|
+
store_credit: "$store_credit",
|
|
223
|
+
third_party_processor: "$third_party_processor",
|
|
224
|
+
voucher: "$voucher",
|
|
225
|
+
sepa_credit: "$sepa_credit",
|
|
226
|
+
sepa_instant_credit: "$sepa_instant_credit",
|
|
227
|
+
sepa_direct_debit: "$sepa_direct_debit",
|
|
228
|
+
ach_credit: "$ach_credit",
|
|
229
|
+
ach_debit: "$ach_debit",
|
|
230
|
+
wire_credit: "$wire_credit",
|
|
231
|
+
wire_debit: "$wire_debit"
|
|
232
|
+
};
|
|
233
|
+
var SIFT_PAYMENT_METHOD_WHITELIST = /* @__PURE__ */ new Set([
|
|
234
|
+
"payment_type",
|
|
235
|
+
"payment_gateway",
|
|
236
|
+
"card_bin",
|
|
237
|
+
"card_last4",
|
|
238
|
+
"avs_result_code",
|
|
239
|
+
"cvv_result_code",
|
|
240
|
+
"verification_status",
|
|
241
|
+
"routing_number",
|
|
242
|
+
"account_holder_name",
|
|
243
|
+
"account_number_last5",
|
|
244
|
+
"bank_name",
|
|
245
|
+
"bank_country",
|
|
246
|
+
"wallet_address",
|
|
247
|
+
"wallet_type",
|
|
248
|
+
"paypal_payer_id",
|
|
249
|
+
"paypal_payer_email"
|
|
250
|
+
]);
|
|
251
|
+
var DEPRECATED_PAYMENT_METHOD_KEYS = [
|
|
252
|
+
"account_number_last4",
|
|
253
|
+
"account_id",
|
|
254
|
+
"wallet_address_last4",
|
|
255
|
+
"crypto_currency",
|
|
256
|
+
"network"
|
|
257
|
+
];
|
|
258
|
+
var METADATA_STRIP_KEYS = /* @__PURE__ */ new Set([
|
|
259
|
+
"account_id",
|
|
260
|
+
"wallet_address_last4",
|
|
261
|
+
"crypto_currency",
|
|
262
|
+
"network"
|
|
263
|
+
]);
|
|
264
|
+
function isDevEnvironment() {
|
|
265
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
266
|
+
}
|
|
267
|
+
function warnDeprecatedKey(key) {
|
|
268
|
+
if (!isDevEnvironment()) return;
|
|
269
|
+
const messages = {
|
|
270
|
+
account_number_last4: "[vesant-sdk/fraud] account_number_last4 is not a Sift field; use account_number_last5",
|
|
271
|
+
account_id: "[vesant-sdk/fraud] account_id is not a Sift field; moved to metadata",
|
|
272
|
+
wallet_address_last4: "[vesant-sdk/fraud] wallet_address_last4 is not a Sift field; moved to metadata",
|
|
273
|
+
crypto_currency: "[vesant-sdk/fraud] crypto_currency is not a Sift field on payment_method; moved to metadata",
|
|
274
|
+
network: "[vesant-sdk/fraud] network is not a Sift field on payment_method; moved to metadata"
|
|
275
|
+
};
|
|
276
|
+
const message = messages[key];
|
|
277
|
+
if (message) {
|
|
278
|
+
console.warn(message);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function normalizeSiftPaymentType(value) {
|
|
282
|
+
if (value === void 0 || value === null) return void 0;
|
|
283
|
+
const trimmed = String(value).trim();
|
|
284
|
+
if (trimmed === "") return void 0;
|
|
285
|
+
const normalized = trimmed.startsWith("$") ? trimmed.slice(1) : trimmed;
|
|
286
|
+
const alias = PAYMENT_TYPE_ALIASES[normalized.toLowerCase()];
|
|
287
|
+
if (alias) return alias;
|
|
288
|
+
const withPrefix = `$${normalized}`;
|
|
289
|
+
if (SiftPaymentTypeValues.includes(withPrefix)) {
|
|
290
|
+
return withPrefix;
|
|
291
|
+
}
|
|
292
|
+
return void 0;
|
|
293
|
+
}
|
|
294
|
+
function toSiftAccountNumberLast5(value) {
|
|
295
|
+
if (value === void 0 || value === null) return void 0;
|
|
296
|
+
const digits = String(value).replace(/\D/g, "");
|
|
297
|
+
if (digits.length === 0) return void 0;
|
|
298
|
+
if (digits.length >= 5) return digits.slice(-5);
|
|
299
|
+
return digits.padStart(5, "0");
|
|
300
|
+
}
|
|
301
|
+
function collectMetadataExtra(metadataExtras, key, value) {
|
|
302
|
+
if (value === void 0) return;
|
|
303
|
+
metadataExtras[key] = value;
|
|
304
|
+
}
|
|
305
|
+
function normalizeSiftPaymentMethod(raw) {
|
|
306
|
+
const metadataExtras = {};
|
|
307
|
+
const method = {};
|
|
308
|
+
const rawPaymentType = raw.payment_type !== void 0 ? String(raw.payment_type) : raw.$payment_type !== void 0 ? String(raw.$payment_type) : void 0;
|
|
309
|
+
const normalizedType = normalizeSiftPaymentType(rawPaymentType);
|
|
310
|
+
if (rawPaymentType !== void 0 && normalizedType === void 0) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
if (normalizedType !== void 0) {
|
|
314
|
+
method.payment_type = normalizedType;
|
|
315
|
+
}
|
|
316
|
+
for (const key of DEPRECATED_PAYMENT_METHOD_KEYS) {
|
|
317
|
+
if (key in raw) warnDeprecatedKey(key);
|
|
318
|
+
}
|
|
319
|
+
const accountLast4 = raw.account_number_last4 ?? raw.$account_number_last4;
|
|
320
|
+
const accountLast5 = raw.account_number_last5 ?? raw.$account_number_last5;
|
|
321
|
+
const resolvedLast5 = toSiftAccountNumberLast5(accountLast5 ?? accountLast4);
|
|
322
|
+
if (resolvedLast5 !== void 0) {
|
|
323
|
+
method.account_number_last5 = resolvedLast5;
|
|
324
|
+
}
|
|
325
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
326
|
+
if (key === "payment_type" || key === "$payment_type") continue;
|
|
327
|
+
if (key === "account_number_last4" || key === "$account_number_last4") continue;
|
|
328
|
+
if (key === "account_number_last5" || key === "$account_number_last5") continue;
|
|
329
|
+
const plainKey = key.startsWith("$") ? key.slice(1) : key;
|
|
330
|
+
if (METADATA_STRIP_KEYS.has(plainKey)) {
|
|
331
|
+
if (plainKey === "account_id") {
|
|
332
|
+
collectMetadataExtra(metadataExtras, "linkmoney_account_id", String(value));
|
|
333
|
+
} else {
|
|
334
|
+
collectMetadataExtra(metadataExtras, plainKey, value);
|
|
335
|
+
}
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (!SIFT_PAYMENT_METHOD_WHITELIST.has(plainKey)) {
|
|
339
|
+
collectMetadataExtra(metadataExtras, `payment_method_${plainKey}`, value);
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (plainKey === "payment_type") {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
method[plainKey] = value;
|
|
346
|
+
}
|
|
347
|
+
const hasMetadata = Object.keys(metadataExtras).length > 0;
|
|
348
|
+
return {
|
|
349
|
+
method,
|
|
350
|
+
...hasMetadata ? { metadataExtras } : {}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function mergeAccountIds(target, accountId) {
|
|
354
|
+
const existing = target.linkmoney_account_ids;
|
|
355
|
+
if (Array.isArray(existing)) {
|
|
356
|
+
existing.push(accountId);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (typeof target.linkmoney_account_id === "string") {
|
|
360
|
+
target.linkmoney_account_ids = [target.linkmoney_account_id, accountId];
|
|
361
|
+
delete target.linkmoney_account_id;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
target.linkmoney_account_id = accountId;
|
|
365
|
+
}
|
|
366
|
+
function normalizeSiftPaymentMethods(methods) {
|
|
367
|
+
if (methods === void 0) return {};
|
|
368
|
+
const normalized = [];
|
|
369
|
+
const metadata = {};
|
|
370
|
+
for (const raw of methods) {
|
|
371
|
+
const result = normalizeSiftPaymentMethod(raw);
|
|
372
|
+
if (result === null) continue;
|
|
373
|
+
normalized.push(result.method);
|
|
374
|
+
if (result.metadataExtras) {
|
|
375
|
+
for (const [key, value] of Object.entries(result.metadataExtras)) {
|
|
376
|
+
if (key === "linkmoney_account_id" && typeof value === "string") {
|
|
377
|
+
mergeAccountIds(metadata, value);
|
|
378
|
+
} else if (key in metadata && Array.isArray(metadata[key]) && Array.isArray(value)) {
|
|
379
|
+
metadata[key] = [...metadata[key], ...value];
|
|
380
|
+
} else if (!(key in metadata)) {
|
|
381
|
+
metadata[key] = value;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const hasMetadata = Object.keys(metadata).length > 0;
|
|
387
|
+
return {
|
|
388
|
+
payment_methods: normalized,
|
|
389
|
+
...hasMetadata ? { metadata } : {}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// src/normalization/sift-keys.ts
|
|
394
|
+
function siftKey(key) {
|
|
395
|
+
return key.startsWith("$") ? key : `$${key}`;
|
|
396
|
+
}
|
|
397
|
+
function toSiftKeyedObject(value) {
|
|
398
|
+
if (value === null || value === void 0) {
|
|
399
|
+
return value;
|
|
400
|
+
}
|
|
401
|
+
if (Array.isArray(value)) {
|
|
402
|
+
return value.map((item) => toSiftKeyedObject(item));
|
|
403
|
+
}
|
|
404
|
+
if (typeof value === "object") {
|
|
405
|
+
const out = {};
|
|
406
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
407
|
+
out[siftKey(key)] = toSiftKeyedObject(nested);
|
|
408
|
+
}
|
|
409
|
+
return out;
|
|
410
|
+
}
|
|
411
|
+
return value;
|
|
412
|
+
}
|
|
124
413
|
|
|
125
414
|
// src/normalization/normalize.ts
|
|
415
|
+
var BASE_SIFT_FIELD_KEYS = [
|
|
416
|
+
"session_id",
|
|
417
|
+
"user_email",
|
|
418
|
+
"name",
|
|
419
|
+
"phone",
|
|
420
|
+
"sift_payment_method",
|
|
421
|
+
"payment_methods",
|
|
422
|
+
"billing_address",
|
|
423
|
+
"shipping_address",
|
|
424
|
+
"app",
|
|
425
|
+
"browser",
|
|
426
|
+
"verification_phone_number",
|
|
427
|
+
"order_id",
|
|
428
|
+
"exchange_rate",
|
|
429
|
+
"expedited_shipping",
|
|
430
|
+
"shipping_method",
|
|
431
|
+
"shipping_carrier",
|
|
432
|
+
"shipping_tracking_numbers",
|
|
433
|
+
"brand_name",
|
|
434
|
+
"site_country",
|
|
435
|
+
"site_domain",
|
|
436
|
+
"ip",
|
|
437
|
+
"skip_payment_method_normalization"
|
|
438
|
+
];
|
|
126
439
|
function mergeMetadata(base, extras) {
|
|
127
440
|
return { ...base, ...extras };
|
|
128
441
|
}
|
|
@@ -145,17 +458,152 @@ function applySiftMetadata(body, metadata, siftMetadata, onlyWhenNonEmpty = fals
|
|
|
145
458
|
}
|
|
146
459
|
return body;
|
|
147
460
|
}
|
|
461
|
+
function collectRuleSignals(request, keys) {
|
|
462
|
+
const signals = {};
|
|
463
|
+
for (const key of keys) {
|
|
464
|
+
const value = request[key];
|
|
465
|
+
if (value !== void 0) {
|
|
466
|
+
signals[key] = value;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return signals;
|
|
470
|
+
}
|
|
471
|
+
function buildBaseSiftMetadata(body) {
|
|
472
|
+
const {
|
|
473
|
+
event_type,
|
|
474
|
+
session_id,
|
|
475
|
+
user_email,
|
|
476
|
+
name,
|
|
477
|
+
phone,
|
|
478
|
+
sift_payment_method,
|
|
479
|
+
payment_methods,
|
|
480
|
+
billing_address,
|
|
481
|
+
shipping_address,
|
|
482
|
+
app,
|
|
483
|
+
browser,
|
|
484
|
+
verification_phone_number,
|
|
485
|
+
order_id,
|
|
486
|
+
amount,
|
|
487
|
+
currency_code,
|
|
488
|
+
exchange_rate,
|
|
489
|
+
expedited_shipping,
|
|
490
|
+
shipping_method,
|
|
491
|
+
shipping_carrier,
|
|
492
|
+
shipping_tracking_numbers,
|
|
493
|
+
brand_name,
|
|
494
|
+
site_country,
|
|
495
|
+
site_domain,
|
|
496
|
+
ip,
|
|
497
|
+
metadata,
|
|
498
|
+
skip_payment_method_normalization
|
|
499
|
+
} = body;
|
|
500
|
+
const siftMetadata = {
|
|
501
|
+
...metadata ?? {}
|
|
502
|
+
};
|
|
503
|
+
if (session_id !== void 0) siftMetadata.$session_id = session_id;
|
|
504
|
+
if (user_email !== void 0) siftMetadata.$user_email = user_email;
|
|
505
|
+
if (name !== void 0) siftMetadata.$name = name;
|
|
506
|
+
if (phone !== void 0) siftMetadata.$phone = phone;
|
|
507
|
+
if (sift_payment_method !== void 0) {
|
|
508
|
+
if (skip_payment_method_normalization) {
|
|
509
|
+
siftMetadata.$payment_method = toSiftKeyedObject(sift_payment_method);
|
|
510
|
+
} else {
|
|
511
|
+
const result = normalizeSiftPaymentMethod(
|
|
512
|
+
sift_payment_method
|
|
513
|
+
);
|
|
514
|
+
if (result !== null) {
|
|
515
|
+
siftMetadata.$payment_method = toSiftKeyedObject(result.method);
|
|
516
|
+
if (result.metadataExtras) {
|
|
517
|
+
Object.assign(siftMetadata, result.metadataExtras);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (payment_methods !== void 0) {
|
|
523
|
+
if (skip_payment_method_normalization) {
|
|
524
|
+
siftMetadata.$payment_methods = toSiftKeyedObject(payment_methods);
|
|
525
|
+
} else {
|
|
526
|
+
const { payment_methods: normalized, metadata: pmMetadata } = normalizeSiftPaymentMethods(
|
|
527
|
+
payment_methods
|
|
528
|
+
);
|
|
529
|
+
if (normalized !== void 0) {
|
|
530
|
+
siftMetadata.$payment_methods = toSiftKeyedObject(normalized);
|
|
531
|
+
}
|
|
532
|
+
if (pmMetadata) {
|
|
533
|
+
Object.assign(siftMetadata, pmMetadata);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (billing_address !== void 0) {
|
|
538
|
+
siftMetadata.$billing_address = toSiftKeyedObject(billing_address);
|
|
539
|
+
}
|
|
540
|
+
if (shipping_address !== void 0) {
|
|
541
|
+
siftMetadata.$shipping_address = toSiftKeyedObject(shipping_address);
|
|
542
|
+
}
|
|
543
|
+
if (app !== void 0) siftMetadata.$app = toSiftKeyedObject(app);
|
|
544
|
+
if (browser !== void 0) {
|
|
545
|
+
siftMetadata.$browser = toSiftKeyedObject(browser);
|
|
546
|
+
}
|
|
547
|
+
if (event_type === "$create_order" || event_type === "$update_account") {
|
|
548
|
+
if (verification_phone_number !== void 0) {
|
|
549
|
+
siftMetadata.$verification_phone_number = verification_phone_number;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (event_type === "$create_order") {
|
|
553
|
+
if (order_id !== void 0) siftMetadata.$order_id = order_id;
|
|
554
|
+
if (amount !== void 0) siftMetadata.$amount = amount;
|
|
555
|
+
if (currency_code !== void 0) siftMetadata.$currency_code = currency_code;
|
|
556
|
+
if (exchange_rate !== void 0) {
|
|
557
|
+
siftMetadata.$exchange_rate = toSiftKeyedObject(exchange_rate);
|
|
558
|
+
}
|
|
559
|
+
if (expedited_shipping !== void 0) siftMetadata.$expedited_shipping = expedited_shipping;
|
|
560
|
+
if (shipping_method !== void 0) siftMetadata.$shipping_method = shipping_method;
|
|
561
|
+
if (shipping_carrier !== void 0) siftMetadata.$shipping_carrier = shipping_carrier;
|
|
562
|
+
if (shipping_tracking_numbers !== void 0) {
|
|
563
|
+
siftMetadata.$shipping_tracking_numbers = shipping_tracking_numbers;
|
|
564
|
+
}
|
|
565
|
+
if (brand_name !== void 0) siftMetadata.$brand_name = brand_name;
|
|
566
|
+
if (site_country !== void 0) siftMetadata.$site_country = site_country;
|
|
567
|
+
if (site_domain !== void 0) siftMetadata.$site_domain = site_domain;
|
|
568
|
+
if (ip !== void 0) siftMetadata.$ip = ip;
|
|
569
|
+
}
|
|
570
|
+
return siftMetadata;
|
|
571
|
+
}
|
|
572
|
+
function normalizeBaseSiftFields(body) {
|
|
573
|
+
const siftMetadata = buildBaseSiftMetadata(body);
|
|
574
|
+
const stripped = stripSdkOnlyFields(body, [...BASE_SIFT_FIELD_KEYS]);
|
|
575
|
+
if (Object.keys(siftMetadata).length > 0) {
|
|
576
|
+
stripped.metadata = siftMetadata;
|
|
577
|
+
}
|
|
578
|
+
return stripped;
|
|
579
|
+
}
|
|
580
|
+
function applyRuleSignals(body, request, keys, stripKeys) {
|
|
581
|
+
const ruleSignals = collectRuleSignals(request, keys);
|
|
582
|
+
const stripped = stripSdkOnlyFields(body, [...stripKeys]);
|
|
583
|
+
if (Object.keys(ruleSignals).length > 0) {
|
|
584
|
+
stripped.metadata = mergeMetadata(
|
|
585
|
+
stripped.metadata,
|
|
586
|
+
ruleSignals
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
return stripped;
|
|
590
|
+
}
|
|
148
591
|
function normalizeUpdatePassword(request) {
|
|
149
592
|
const { password_reason, password_status, metadata, ...rest } = request;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
593
|
+
let body = createStrippedBody(rest, metadata, [
|
|
594
|
+
"password_reason",
|
|
595
|
+
"password_status"
|
|
596
|
+
]);
|
|
597
|
+
const siftMetadata = {
|
|
598
|
+
$reason: password_reason ?? PasswordUpdateReason.UserUpdate,
|
|
599
|
+
$status: password_status ?? PasswordUpdateStatus.Success
|
|
600
|
+
};
|
|
601
|
+
body = applySiftMetadata(body, metadata, siftMetadata);
|
|
602
|
+
return normalizeBaseSiftFields(body);
|
|
155
603
|
}
|
|
156
604
|
function normalizeWager(request) {
|
|
157
605
|
const { wager_type, wager_status, wager_event_type, wager_event_name, wager_event_id, metadata, ...rest } = request;
|
|
158
|
-
|
|
606
|
+
let body = createStrippedBody(rest, metadata, [
|
|
159
607
|
"wager_type",
|
|
160
608
|
"wager_status",
|
|
161
609
|
"wager_event_type",
|
|
@@ -166,17 +614,19 @@ function normalizeWager(request) {
|
|
|
166
614
|
$wager_type: wager_type,
|
|
167
615
|
$wager_status: wager_status
|
|
168
616
|
};
|
|
169
|
-
if (wager_event_type) siftMetadata
|
|
170
|
-
if (wager_event_name) siftMetadata
|
|
171
|
-
if (wager_event_id) siftMetadata
|
|
172
|
-
|
|
617
|
+
if (wager_event_type) siftMetadata.$wager_event_type = wager_event_type;
|
|
618
|
+
if (wager_event_name) siftMetadata.$wager_event_name = wager_event_name;
|
|
619
|
+
if (wager_event_id) siftMetadata.$wager_event_id = wager_event_id;
|
|
620
|
+
body = applySiftMetadata(body, metadata, siftMetadata);
|
|
621
|
+
return normalizeBaseSiftFields(body);
|
|
173
622
|
}
|
|
174
623
|
function normalizeLogin(request) {
|
|
175
624
|
const { login_status, login_failure_reason, metadata, ...rest } = request;
|
|
176
625
|
const effectiveStatus = login_status ?? LoginStatus.Success;
|
|
177
|
-
|
|
626
|
+
let body = createStrippedBody(rest, metadata, [
|
|
178
627
|
"login_status",
|
|
179
|
-
"login_failure_reason"
|
|
628
|
+
"login_failure_reason",
|
|
629
|
+
...LOGIN_RULE_SIGNAL_KEYS
|
|
180
630
|
]);
|
|
181
631
|
const siftMetadata = {
|
|
182
632
|
$login_status: effectiveStatus
|
|
@@ -184,14 +634,22 @@ function normalizeLogin(request) {
|
|
|
184
634
|
if (effectiveStatus === LoginStatus.Failure && login_failure_reason) {
|
|
185
635
|
siftMetadata.$failure_reason = login_failure_reason;
|
|
186
636
|
}
|
|
187
|
-
|
|
637
|
+
body = applySiftMetadata(body, metadata, siftMetadata);
|
|
638
|
+
body = applyRuleSignals(
|
|
639
|
+
body,
|
|
640
|
+
request,
|
|
641
|
+
LOGIN_RULE_SIGNAL_KEYS,
|
|
642
|
+
[]
|
|
643
|
+
);
|
|
644
|
+
return normalizeBaseSiftFields(body);
|
|
188
645
|
}
|
|
189
646
|
function normalizeTransaction(request) {
|
|
190
647
|
const { transaction_status, decline_category, transfer_recipient_user_id, metadata, ...rest } = request;
|
|
191
|
-
|
|
648
|
+
let body = createStrippedBody(rest, metadata, [
|
|
192
649
|
"transaction_status",
|
|
193
650
|
"decline_category",
|
|
194
|
-
"transfer_recipient_user_id"
|
|
651
|
+
"transfer_recipient_user_id",
|
|
652
|
+
...TRANSACTION_RULE_SIGNAL_KEYS
|
|
195
653
|
]);
|
|
196
654
|
const siftMetadata = {};
|
|
197
655
|
if (transaction_status) siftMetadata.$transaction_status = transaction_status;
|
|
@@ -199,7 +657,43 @@ function normalizeTransaction(request) {
|
|
|
199
657
|
if (transfer_recipient_user_id) {
|
|
200
658
|
siftMetadata.$transfer_recipient_user_id = transfer_recipient_user_id;
|
|
201
659
|
}
|
|
202
|
-
|
|
660
|
+
body = applySiftMetadata(body, metadata, siftMetadata, true);
|
|
661
|
+
body = applyRuleSignals(
|
|
662
|
+
body,
|
|
663
|
+
request,
|
|
664
|
+
TRANSACTION_RULE_SIGNAL_KEYS,
|
|
665
|
+
[]
|
|
666
|
+
);
|
|
667
|
+
return normalizeBaseSiftFields(body);
|
|
668
|
+
}
|
|
669
|
+
function normalizeUpdateAccount(request) {
|
|
670
|
+
const { metadata, ...rest } = request;
|
|
671
|
+
let body = createStrippedBody(rest, metadata, [
|
|
672
|
+
...UPDATE_ACCOUNT_RULE_SIGNAL_KEYS
|
|
673
|
+
]);
|
|
674
|
+
body = applyRuleSignals(
|
|
675
|
+
body,
|
|
676
|
+
request,
|
|
677
|
+
UPDATE_ACCOUNT_RULE_SIGNAL_KEYS,
|
|
678
|
+
[]
|
|
679
|
+
);
|
|
680
|
+
return normalizeBaseSiftFields(body);
|
|
681
|
+
}
|
|
682
|
+
function normalizeCreateOrder(request) {
|
|
683
|
+
const { amount, currency_code, metadata, ...rest } = request;
|
|
684
|
+
let body = createStrippedBody(rest, metadata, [
|
|
685
|
+
"amount",
|
|
686
|
+
"currency_code"
|
|
687
|
+
]);
|
|
688
|
+
const siftMetadata = {
|
|
689
|
+
$amount: amount,
|
|
690
|
+
$currency_code: currency_code
|
|
691
|
+
};
|
|
692
|
+
body = applySiftMetadata(body, metadata, siftMetadata);
|
|
693
|
+
return normalizeBaseSiftFields(body);
|
|
694
|
+
}
|
|
695
|
+
function normalizeDefault(request) {
|
|
696
|
+
return normalizeBaseSiftFields({ ...request });
|
|
203
697
|
}
|
|
204
698
|
function normalizeScoreRequestForApi(request) {
|
|
205
699
|
switch (request.event_type) {
|
|
@@ -211,8 +705,12 @@ function normalizeScoreRequestForApi(request) {
|
|
|
211
705
|
return normalizeLogin(request);
|
|
212
706
|
case "$transaction":
|
|
213
707
|
return normalizeTransaction(request);
|
|
708
|
+
case "$update_account":
|
|
709
|
+
return normalizeUpdateAccount(request);
|
|
710
|
+
case "$create_order":
|
|
711
|
+
return normalizeCreateOrder(request);
|
|
214
712
|
default:
|
|
215
|
-
return
|
|
713
|
+
return normalizeDefault(request);
|
|
216
714
|
}
|
|
217
715
|
}
|
|
218
716
|
|
|
@@ -224,6 +722,7 @@ function buildScoreRequestPreview(request) {
|
|
|
224
722
|
// src/types/events.ts
|
|
225
723
|
var SCORED_FRAUD_EVENT_TYPES = [
|
|
226
724
|
"$create_account",
|
|
725
|
+
"$create_order",
|
|
227
726
|
"$login",
|
|
228
727
|
"$logout",
|
|
229
728
|
"$update_account",
|
|
@@ -240,7 +739,6 @@ var PLANNED_FRAUD_EVENT_TYPES = [
|
|
|
240
739
|
"$verification",
|
|
241
740
|
"$link_session_to_user",
|
|
242
741
|
"$security_notification",
|
|
243
|
-
"$create_order",
|
|
244
742
|
"$update_order",
|
|
245
743
|
"$order_status",
|
|
246
744
|
"$add_promotion"
|
|
@@ -253,10 +751,33 @@ function isSupportedFraudEventType(eventType) {
|
|
|
253
751
|
}
|
|
254
752
|
|
|
255
753
|
// src/types/metadata.ts
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
754
|
+
var TYPED_SIFT_METADATA_KEYS = {
|
|
755
|
+
session_id: "$session_id",
|
|
756
|
+
user_email: "$user_email",
|
|
757
|
+
name: "$name",
|
|
758
|
+
phone: "$phone",
|
|
759
|
+
sift_payment_method: "$payment_method",
|
|
760
|
+
billing_address: "$billing_address",
|
|
761
|
+
payment_methods: "$payment_methods",
|
|
762
|
+
app: "$app",
|
|
763
|
+
verification_phone_number: "$verification_phone_number",
|
|
764
|
+
order_id: "$order_id",
|
|
765
|
+
exchange_rate: "$exchange_rate",
|
|
766
|
+
shipping_address: "$shipping_address",
|
|
767
|
+
expedited_shipping: "$expedited_shipping",
|
|
768
|
+
shipping_method: "$shipping_method",
|
|
769
|
+
shipping_carrier: "$shipping_carrier",
|
|
770
|
+
shipping_tracking_numbers: "$shipping_tracking_numbers",
|
|
771
|
+
browser: "$browser",
|
|
772
|
+
brand_name: "$brand_name",
|
|
773
|
+
site_country: "$site_country",
|
|
774
|
+
site_domain: "$site_domain",
|
|
775
|
+
ip: "$ip"
|
|
776
|
+
};
|
|
777
|
+
function findMetadataConflictWithTypedFields(metadata, request) {
|
|
778
|
+
for (const [field, metaKey] of Object.entries(TYPED_SIFT_METADATA_KEYS)) {
|
|
779
|
+
if (request[field] !== void 0 && metadata[metaKey] !== void 0) {
|
|
780
|
+
return metaKey;
|
|
260
781
|
}
|
|
261
782
|
}
|
|
262
783
|
return void 0;
|
|
@@ -282,22 +803,63 @@ function assertPositiveAmount(amount, field, errors, prefix) {
|
|
|
282
803
|
errors.push(`${prefix}${field} must be greater than 0`);
|
|
283
804
|
}
|
|
284
805
|
}
|
|
285
|
-
function validateMetadata(metadata, errors, prefix) {
|
|
806
|
+
function validateMetadata(metadata, request, errors, prefix) {
|
|
286
807
|
if (!metadata) return;
|
|
287
|
-
const
|
|
288
|
-
|
|
808
|
+
const conflictKey = findMetadataConflictWithTypedFields(
|
|
809
|
+
metadata,
|
|
810
|
+
request
|
|
811
|
+
);
|
|
812
|
+
if (conflictKey) {
|
|
289
813
|
errors.push(
|
|
290
|
-
`${prefix}metadata
|
|
814
|
+
`${prefix}metadata.${conflictKey} conflicts with a typed request field that maps to the same key; omit metadata.${conflictKey} or remove the typed field`
|
|
291
815
|
);
|
|
292
816
|
}
|
|
293
817
|
}
|
|
294
818
|
|
|
295
819
|
// src/validation/rules.ts
|
|
820
|
+
var E164_PHONE_PATTERN = /^\+[1-9]\d{7,14}$/;
|
|
821
|
+
function validatePaymentMethods(request, errors, prefix) {
|
|
822
|
+
const { payment_methods, skip_payment_method_normalization: skipNormalization } = request;
|
|
823
|
+
if (payment_methods === void 0) return;
|
|
824
|
+
if (payment_methods.length === 0) {
|
|
825
|
+
errors.push(`${prefix}payment_methods must include at least one item when provided`);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
payment_methods.forEach((method, index) => {
|
|
829
|
+
const raw = method;
|
|
830
|
+
if (skipNormalization) {
|
|
831
|
+
for (const key of Object.keys(raw)) {
|
|
832
|
+
const plainKey = key.startsWith("$") ? key.slice(1) : key;
|
|
833
|
+
if (!SIFT_PAYMENT_METHOD_WHITELIST.has(plainKey)) {
|
|
834
|
+
errors.push(
|
|
835
|
+
`${prefix}payment_methods[${index}].${plainKey} is not a valid Sift payment method field`
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
const rawType2 = raw.payment_type !== void 0 ? String(raw.payment_type) : void 0;
|
|
840
|
+
if (rawType2 !== void 0 && normalizeSiftPaymentType(rawType2) === void 0) {
|
|
841
|
+
errors.push(
|
|
842
|
+
`${prefix}payment_methods[${index}].payment_type is not a valid Sift payment type`
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
const rawType = raw.payment_type !== void 0 ? String(raw.payment_type) : raw.$payment_type !== void 0 ? String(raw.$payment_type) : void 0;
|
|
848
|
+
if (rawType !== void 0) {
|
|
849
|
+
const result = normalizeSiftPaymentMethod(raw);
|
|
850
|
+
if (result === null) {
|
|
851
|
+
errors.push(
|
|
852
|
+
`${prefix}payment_methods[${index}].payment_type is not a valid Sift payment type`
|
|
853
|
+
);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
296
858
|
function validateBase(request, errors, prefix) {
|
|
297
859
|
assertNonEmpty(request.customer_id, "customer_id", errors, prefix);
|
|
298
860
|
assertNonEmpty(request.sift_user_id, "sift_user_id", errors, prefix);
|
|
299
861
|
assertNonEmpty(request.event_type, "event_type", errors, prefix);
|
|
300
|
-
validateMetadata(request.metadata, errors, prefix);
|
|
862
|
+
validateMetadata(request.metadata, request, errors, prefix);
|
|
301
863
|
}
|
|
302
864
|
function validateLogin(request, errors, prefix) {
|
|
303
865
|
assertEnum(request.login_status, SiftLoginStatusValues, "login_status", errors, prefix);
|
|
@@ -323,9 +885,6 @@ function validateUpdatePassword(request, errors, prefix) {
|
|
|
323
885
|
errors,
|
|
324
886
|
prefix
|
|
325
887
|
);
|
|
326
|
-
if (!request.password_reason) {
|
|
327
|
-
errors.push(`${prefix}password_reason is required`);
|
|
328
|
-
}
|
|
329
888
|
assertEnum(
|
|
330
889
|
request.password_status,
|
|
331
890
|
SiftPasswordUpdateStatusValues,
|
|
@@ -333,9 +892,6 @@ function validateUpdatePassword(request, errors, prefix) {
|
|
|
333
892
|
errors,
|
|
334
893
|
prefix
|
|
335
894
|
);
|
|
336
|
-
if (!request.password_status) {
|
|
337
|
-
errors.push(`${prefix}password_status is required`);
|
|
338
|
-
}
|
|
339
895
|
}
|
|
340
896
|
function validateTransaction(request, errors, prefix) {
|
|
341
897
|
assertPositiveAmount(request.amount, "amount", errors, prefix);
|
|
@@ -369,6 +925,28 @@ function validateWager(request, errors, prefix) {
|
|
|
369
925
|
assertPositiveAmount(request.amount, "amount", errors, prefix);
|
|
370
926
|
assertNonEmpty(request.currency, "currency", errors, prefix);
|
|
371
927
|
}
|
|
928
|
+
function validateCreateAccount(request, errors, prefix) {
|
|
929
|
+
validatePaymentMethods(request, errors, prefix);
|
|
930
|
+
}
|
|
931
|
+
function validateUpdateAccount(request, errors, prefix) {
|
|
932
|
+
validatePaymentMethods(request, errors, prefix);
|
|
933
|
+
if (request.verification_phone_number !== void 0) {
|
|
934
|
+
if (!E164_PHONE_PATTERN.test(request.verification_phone_number.trim())) {
|
|
935
|
+
errors.push(`${prefix}verification_phone_number must be E.164 (e.g. +14155550123)`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
function validateCreateOrder(request, errors, prefix) {
|
|
940
|
+
assertPositiveAmount(request.amount, "amount", errors, prefix);
|
|
941
|
+
assertNonEmpty(request.currency_code, "currency_code", errors, prefix);
|
|
942
|
+
validatePaymentMethods(request, errors, prefix);
|
|
943
|
+
if (request.shipping_tracking_numbers !== void 0) {
|
|
944
|
+
const hasEmpty = request.shipping_tracking_numbers.some((n) => n.trim() === "");
|
|
945
|
+
if (hasEmpty) {
|
|
946
|
+
errors.push(`${prefix}shipping_tracking_numbers cannot contain empty values`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
372
950
|
function validateChargeback(request, errors, prefix) {
|
|
373
951
|
const hasTransactionId = !!request.transaction_id?.trim();
|
|
374
952
|
const hasOrderId = !!request.order_id?.trim();
|
|
@@ -403,9 +981,20 @@ function validateByEventType(request, errors, prefix) {
|
|
|
403
981
|
case "$wager":
|
|
404
982
|
validateWager(request, errors, prefix);
|
|
405
983
|
break;
|
|
984
|
+
case "$create_order":
|
|
985
|
+
validateCreateOrder(request, errors, prefix);
|
|
986
|
+
break;
|
|
406
987
|
case "$chargeback":
|
|
407
988
|
validateChargeback(request, errors, prefix);
|
|
408
989
|
break;
|
|
990
|
+
case "$create_account":
|
|
991
|
+
validateCreateAccount(request, errors, prefix);
|
|
992
|
+
break;
|
|
993
|
+
case "$logout":
|
|
994
|
+
break;
|
|
995
|
+
case "$update_account":
|
|
996
|
+
validateUpdateAccount(request, errors, prefix);
|
|
997
|
+
break;
|
|
409
998
|
}
|
|
410
999
|
}
|
|
411
1000
|
function validateScoreRequest(request, index) {
|
|
@@ -472,10 +1061,12 @@ exports.CHARGEBACK_FRAUD_EVENT_TYPE = CHARGEBACK_FRAUD_EVENT_TYPE;
|
|
|
472
1061
|
exports.ChargebackReason = ChargebackReason;
|
|
473
1062
|
exports.ChargebackState = ChargebackState;
|
|
474
1063
|
exports.FraudClient = FraudClient;
|
|
1064
|
+
exports.LOGIN_RULE_SIGNAL_KEYS = LOGIN_RULE_SIGNAL_KEYS;
|
|
475
1065
|
exports.LoginStatus = LoginStatus;
|
|
476
1066
|
exports.PLANNED_FRAUD_EVENT_TYPES = PLANNED_FRAUD_EVENT_TYPES;
|
|
477
1067
|
exports.PasswordUpdateReason = PasswordUpdateReason;
|
|
478
1068
|
exports.PasswordUpdateStatus = PasswordUpdateStatus;
|
|
1069
|
+
exports.PaymentType = PaymentType;
|
|
479
1070
|
exports.SCORED_FRAUD_EVENT_TYPES = SCORED_FRAUD_EVENT_TYPES;
|
|
480
1071
|
exports.SUPPORTED_FRAUD_EVENT_TYPES = SUPPORTED_FRAUD_EVENT_TYPES;
|
|
481
1072
|
exports.SiftChargebackReasonValues = SiftChargebackReasonValues;
|
|
@@ -484,17 +1075,27 @@ exports.SiftLoginFailureReasonValues = SiftLoginFailureReasonValues;
|
|
|
484
1075
|
exports.SiftLoginStatusValues = SiftLoginStatusValues;
|
|
485
1076
|
exports.SiftPasswordUpdateReasonValues = SiftPasswordUpdateReasonValues;
|
|
486
1077
|
exports.SiftPasswordUpdateStatusValues = SiftPasswordUpdateStatusValues;
|
|
1078
|
+
exports.SiftPaymentTypeValues = SiftPaymentTypeValues;
|
|
487
1079
|
exports.SiftTransactionStatusValues = SiftTransactionStatusValues;
|
|
488
1080
|
exports.SiftTransactionTypeValues = SiftTransactionTypeValues;
|
|
489
1081
|
exports.SiftWagerStatusValues = SiftWagerStatusValues;
|
|
1082
|
+
exports.SiftWalletTypeValues = SiftWalletTypeValues;
|
|
1083
|
+
exports.TRANSACTION_RULE_SIGNAL_KEYS = TRANSACTION_RULE_SIGNAL_KEYS;
|
|
1084
|
+
exports.TYPED_SIFT_METADATA_KEYS = TYPED_SIFT_METADATA_KEYS;
|
|
490
1085
|
exports.TransactionStatus = TransactionStatus;
|
|
491
1086
|
exports.TransactionType = TransactionType;
|
|
1087
|
+
exports.UPDATE_ACCOUNT_RULE_SIGNAL_KEYS = UPDATE_ACCOUNT_RULE_SIGNAL_KEYS;
|
|
492
1088
|
exports.WagerStatus = WagerStatus;
|
|
1089
|
+
exports.WalletType = WalletType;
|
|
493
1090
|
exports.buildScoreRequestPreview = buildScoreRequestPreview;
|
|
494
|
-
exports.
|
|
1091
|
+
exports.findMetadataConflictWithTypedFields = findMetadataConflictWithTypedFields;
|
|
495
1092
|
exports.isPlannedFraudEventType = isPlannedFraudEventType;
|
|
496
1093
|
exports.isSupportedFraudEventType = isSupportedFraudEventType;
|
|
497
1094
|
exports.normalizeScoreRequestForApi = normalizeScoreRequestForApi;
|
|
1095
|
+
exports.normalizeSiftPaymentMethod = normalizeSiftPaymentMethod;
|
|
1096
|
+
exports.normalizeSiftPaymentMethods = normalizeSiftPaymentMethods;
|
|
1097
|
+
exports.normalizeSiftPaymentType = normalizeSiftPaymentType;
|
|
1098
|
+
exports.toSiftAccountNumberLast5 = toSiftAccountNumberLast5;
|
|
498
1099
|
exports.validateScoreRequest = validateScoreRequest;
|
|
499
1100
|
//# sourceMappingURL=index.js.map
|
|
500
1101
|
//# sourceMappingURL=index.js.map
|