@sentinelsup/sdk 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -22
- package/index.d.ts +43 -2
- package/index.js +11 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,20 @@ Official Node.js SDK for [Sentinel](https://sntlhq.com) — real-time fraud dete
|
|
|
5
5
|
[](https://www.npmjs.com/package/@sentinelsup/sdk)
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
|
|
8
|
+
## Set up with AI (fastest)
|
|
9
|
+
|
|
10
|
+
Using Claude Code, Cursor, Copilot, or any AI coding assistant? Paste this
|
|
11
|
+
one prompt and it wires the whole integration — frontend script, backend
|
|
12
|
+
check, env var, and a test:
|
|
13
|
+
|
|
14
|
+
> Fetch https://sntlhq.com/integrate.md and follow it to add Sentinel fraud
|
|
15
|
+
> protection to this app — protect signup, login, and checkout. My API key
|
|
16
|
+
> is sk_live_YOUR_KEY; put it in a SENTINEL_KEY env var, never in
|
|
17
|
+
> client-side code. Then show me how to test it.
|
|
18
|
+
|
|
19
|
+
[`integrate.md`](https://sntlhq.com/integrate.md) is the canonical
|
|
20
|
+
machine-readable integration guide, kept in sync with the live API.
|
|
21
|
+
|
|
8
22
|
## Install
|
|
9
23
|
|
|
10
24
|
```bash
|
|
@@ -24,11 +38,10 @@ const result = await sentinel.evaluate({
|
|
|
24
38
|
token: req.body.sentinelToken // from the frontend SDK
|
|
25
39
|
});
|
|
26
40
|
|
|
27
|
-
if (result.
|
|
41
|
+
if (result.decision === 'block') {
|
|
28
42
|
return res.status(403).json({ error: 'blocked' });
|
|
29
43
|
}
|
|
30
|
-
|
|
31
|
-
// Safe — let the request through
|
|
44
|
+
// 'review' → let through but flag; 'allow' → clean
|
|
32
45
|
```
|
|
33
46
|
|
|
34
47
|
Get a free API key (no credit card) at [sntlhq.com/signup](https://sntlhq.com/signup).
|
|
@@ -37,27 +50,32 @@ Get a free API key (no credit card) at [sntlhq.com/signup](https://sntlhq.com/si
|
|
|
37
50
|
|
|
38
51
|
```ts
|
|
39
52
|
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
decision: 'review', // 'allow' | 'review' | 'block' — route on this
|
|
54
|
+
risk_score: 65, // 0–100
|
|
55
|
+
isSuspicious: true, // simple boolean verdict
|
|
56
|
+
ip: '198.51.100.18',
|
|
57
|
+
country: 'NL',
|
|
58
|
+
network: {
|
|
59
|
+
vpn: true, proxy: false, datacenter: true, anonymous: true,
|
|
60
|
+
tor: false, residential: false, service: 'PROTON_VPN'
|
|
61
|
+
},
|
|
62
|
+
device: { // present only when you pass fingerprintEventId
|
|
63
|
+
antidetect: false, // antidetect browser detected
|
|
64
|
+
automation: false, // bot / browser automation
|
|
65
|
+
emulator: false, virtual_machine: false, incognito: false,
|
|
66
|
+
ip_blocklisted: false, visitor_id: 'abc123', tampering_score: 0
|
|
49
67
|
},
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
browserTampering: true, // antidetect browser detected
|
|
53
|
-
botDetected: false,
|
|
54
|
-
incognito: false,
|
|
55
|
-
virtualMachine: false,
|
|
56
|
-
emulator: false
|
|
57
|
-
}
|
|
68
|
+
reasons: ['vpn_detected', 'datacenter_asn'], // machine-readable codes
|
|
69
|
+
evaluated_in_ms: 28
|
|
58
70
|
}
|
|
59
71
|
```
|
|
60
72
|
|
|
73
|
+
Try the live sample (same shape, no key needed):
|
|
74
|
+
`curl "https://sntlhq.com/v1/evaluate/sample?scenario=vpn"`
|
|
75
|
+
|
|
76
|
+
Legacy `details` / `deviceIntel` fields are still returned for backwards
|
|
77
|
+
compatibility with 0.1.0 integrations.
|
|
78
|
+
|
|
61
79
|
## Frontend setup
|
|
62
80
|
|
|
63
81
|
Add the Sentinel Edge SDK to your frontend so Sentinel can collect the token:
|
|
@@ -113,10 +131,10 @@ app.post('/auth/google', async (req, res) => {
|
|
|
113
131
|
### Custom policy with `shouldBlock`
|
|
114
132
|
|
|
115
133
|
```js
|
|
116
|
-
// Only block when we see both residential proxy AND browser
|
|
134
|
+
// Only block when we see both residential proxy AND an antidetect browser
|
|
117
135
|
const blocked = await sentinel.shouldBlock(
|
|
118
136
|
{ token },
|
|
119
|
-
r => r.
|
|
137
|
+
r => r.network.proxy && r.device?.antidetect
|
|
120
138
|
);
|
|
121
139
|
```
|
|
122
140
|
|
package/index.d.ts
CHANGED
|
@@ -23,11 +23,52 @@ export interface DeviceIntel {
|
|
|
23
23
|
tamperingScore?: number;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export interface NetworkSignals {
|
|
27
|
+
vpn: boolean;
|
|
28
|
+
proxy: boolean;
|
|
29
|
+
datacenter: boolean;
|
|
30
|
+
anonymous: boolean;
|
|
31
|
+
tor: boolean;
|
|
32
|
+
residential: boolean;
|
|
33
|
+
service: string | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DeviceSignals {
|
|
37
|
+
antidetect: boolean;
|
|
38
|
+
automation: boolean;
|
|
39
|
+
emulator: boolean;
|
|
40
|
+
virtual_machine: boolean;
|
|
41
|
+
incognito: boolean;
|
|
42
|
+
privacy_mode: boolean;
|
|
43
|
+
ip_blocklisted: boolean;
|
|
44
|
+
visitor_id: string | null;
|
|
45
|
+
tampering_score: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type ReasonCode =
|
|
49
|
+
| 'vpn_detected' | 'proxy_detected' | 'datacenter_asn' | 'tor_exit_node'
|
|
50
|
+
| 'anonymous_network' | 'antidetect_browser' | 'automation_detected'
|
|
51
|
+
| 'emulator_detected' | 'virtual_machine' | 'ip_blocklisted' | 'private_browsing';
|
|
52
|
+
|
|
26
53
|
export interface EvaluateResult {
|
|
27
|
-
|
|
54
|
+
/** "allow" | "review" | "block" — route on this */
|
|
55
|
+
decision: 'allow' | 'review' | 'block';
|
|
56
|
+
/** 0–100 weighted risk score */
|
|
57
|
+
risk_score: number;
|
|
58
|
+
/** Simple boolean verdict (network or device signals flagged) */
|
|
28
59
|
isSuspicious: boolean;
|
|
60
|
+
ip: string | null;
|
|
61
|
+
country: string | null;
|
|
62
|
+
network: NetworkSignals;
|
|
63
|
+
/** Present only when fingerprintEventId was supplied */
|
|
64
|
+
device?: DeviceSignals;
|
|
65
|
+
/** Machine-readable reason codes for the verdict */
|
|
66
|
+
reasons: ReasonCode[];
|
|
67
|
+
evaluated_in_ms: number;
|
|
68
|
+
/** Legacy fields (kept for backwards compatibility) */
|
|
69
|
+
status: string;
|
|
29
70
|
details: EvaluateDetails;
|
|
30
|
-
deviceIntel
|
|
71
|
+
deviceIntel?: DeviceIntel | null;
|
|
31
72
|
}
|
|
32
73
|
|
|
33
74
|
export interface SentinelOptions {
|
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* const Sentinel = require('@sentinelsup/sdk');
|
|
7
7
|
* const sentinel = new Sentinel({ apiKey: process.env.SENTINEL_KEY });
|
|
8
8
|
* const result = await sentinel.evaluate({ token });
|
|
9
|
-
* if (result.
|
|
9
|
+
* if (result.decision === 'block') return res.status(403).end();
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const DEFAULT_ENDPOINT = 'https://sntlhq.com';
|
|
@@ -108,9 +108,17 @@ module.exports.SentinelError = SentinelError;
|
|
|
108
108
|
|
|
109
109
|
/**
|
|
110
110
|
* @typedef {object} EvaluateResult
|
|
111
|
+
* @property {'allow'|'review'|'block'} decision — route on this
|
|
112
|
+
* @property {number} risk_score — 0–100 weighted risk score
|
|
111
113
|
* @property {boolean} isSuspicious — true if network or device signals flag the session
|
|
112
|
-
* @property {
|
|
113
|
-
* @property {
|
|
114
|
+
* @property {string|null} ip
|
|
115
|
+
* @property {string|null} country — 2-letter country code
|
|
116
|
+
* @property {object} network — { vpn, proxy, datacenter, anonymous, tor, residential, service }
|
|
117
|
+
* @property {object} [device] — { antidetect, automation, emulator, virtual_machine, incognito, visitor_id, tampering_score, ... } when fingerprintEventId was supplied
|
|
118
|
+
* @property {string[]} reasons — machine-readable reason codes (vpn_detected, proxy_detected, ...)
|
|
119
|
+
* @property {number} evaluated_in_ms
|
|
120
|
+
* @property {EvaluateDetails} details — legacy network signals (backwards compatibility)
|
|
121
|
+
* @property {DeviceIntel|null} [deviceIntel] — legacy device signals (backwards compatibility)
|
|
114
122
|
*/
|
|
115
123
|
|
|
116
124
|
/**
|
package/package.json
CHANGED