Skip to content

Commit dd99969

Browse files
oschwaldclaude
andcommitted
Add CLAUDE.md for Claude Code guidance
This file provides documentation for Claude Code when working with this repository, including architecture, testing conventions, and development workflow. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 04e2e60 commit dd99969

File tree

1 file changed

+366
-0
lines changed

1 file changed

+366
-0
lines changed

CLAUDE.md

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
**minfraud-api-node** is MaxMind's official Node.js/TypeScript client library for the minFraud web services:
8+
- **minFraud Score**: Returns a risk score (0.01-99) indicating fraud likelihood
9+
- **minFraud Insights**: Score + additional data about IP, email, device, and shipping/billing addresses
10+
- **minFraud Factors**: Insights + risk score reasons and subscores (deprecated)
11+
- **Report Transactions API**: Report transaction outcomes to improve fraud detection
12+
13+
The library is server-side only and provides strongly-typed request/response models for fraud detection.
14+
15+
**Key Technologies:**
16+
- TypeScript with strict type checking
17+
- Node.js 18+ (targets active LTS versions)
18+
- Uses Node.js built-in `fetch` for HTTP requests
19+
- Jest for testing
20+
- ESLint + Prettier for code quality
21+
- TypeDoc for API documentation
22+
- Depends on @maxmind/geoip2-node for IP geolocation data
23+
24+
## Code Architecture
25+
26+
### Package Structure
27+
28+
```
29+
src/
30+
├── request/ # Transaction input models (Device, Email, Billing, etc.)
31+
│ ├── transaction.ts # Main Transaction class that aggregates all inputs
32+
│ └── *.ts # Individual request component classes
33+
├── response/
34+
│ ├── models/ # Response models (Score, Insights, Factors)
35+
│ ├── records.ts # TypeScript interfaces for response data records
36+
│ └── web-records.ts # Raw API response types (snake_case)
37+
├── webServiceClient.ts # HTTP client for minFraud web services
38+
├── constants.ts # Enums for API values (EventType, Processor, etc.)
39+
├── utils.ts # Utility functions (camelCase/snake_case conversion)
40+
├── errors.ts # Custom error classes
41+
└── types.ts # Type definitions
42+
```
43+
44+
### Key Design Patterns
45+
46+
#### 1. **Request/Response Transformation**
47+
48+
Requests use camelCase and are converted to snake_case for the API:
49+
```typescript
50+
// User provides: new Device({ ipAddress: '1.2.3.4' })
51+
// Sent to API: { ip_address: '1.2.3.4' }
52+
```
53+
54+
Responses use snake_case and are converted to camelCase in model constructors:
55+
```typescript
56+
// API returns: { risk_score: 50, funds_remaining: 10.50 }
57+
// Model exposes: response.riskScore, response.fundsRemaining
58+
```
59+
60+
The `camelizeResponse()` utility in `utils.ts` handles deep conversion for response data.
61+
The `snakecaseKeys()` utility converts request objects to snake_case.
62+
63+
#### 2. **Model Inheritance Hierarchy**
64+
65+
Response models follow clear inheritance:
66+
- `Score` → base model with risk score, disposition, warnings
67+
- `Insights` extends `Score` → adds billing/shipping addresses, device, email, credit card data
68+
- `Factors` extends `Insights` → adds risk score reasons and subscores (deprecated)
69+
70+
#### 3. **Transaction Builder Pattern**
71+
72+
Transactions are composed of optional components:
73+
```typescript
74+
const transaction = new minFraud.Transaction({
75+
device: new minFraud.Device({ ipAddress: '1.2.3.4' }),
76+
email: new minFraud.Email({ address: '[email protected]' }),
77+
billing: new minFraud.Billing({ /* ... */ }),
78+
// ... other components
79+
});
80+
```
81+
82+
Each component validates its inputs in the constructor and throws `ArgumentError` for invalid data.
83+
84+
#### 4. **Web Service Client Pattern**
85+
86+
The `WebServiceClient` provides direct methods for each endpoint:
87+
```typescript
88+
const client = new WebServiceClient(accountID, licenseKey, timeout, host);
89+
const response = await client.score(transaction);
90+
const response = await client.insights(transaction);
91+
const response = await client.factors(transaction);
92+
await client.reportTransaction(report);
93+
```
94+
95+
#### 5. **GeoIP2 Integration**
96+
97+
The Insights and Factors responses include IP geolocation data from the @maxmind/geoip2-node library:
98+
```typescript
99+
// In Insights constructor:
100+
const insights = new GeoInsights(response.ip_address) as records.IpAddress;
101+
// Augment with minFraud-specific fields
102+
insights.country.isHighRisk = response.ip_address.country.is_high_risk;
103+
insights.risk = response.ip_address.risk;
104+
```
105+
106+
## Testing Conventions
107+
108+
### Running Tests
109+
110+
```bash
111+
# Install dependencies
112+
npm install
113+
114+
# Run all tests
115+
npm test
116+
117+
# Run tests in watch mode
118+
npm run test:watch
119+
120+
# Run specific test file
121+
npx jest src/webServiceClient.spec.ts
122+
```
123+
124+
### Linting and Building
125+
126+
```bash
127+
# Lint code (ESLint + TypeScript)
128+
npm run lint
129+
130+
# Format code (Prettier)
131+
npm run prettier:ts
132+
npm run prettier:json
133+
134+
# Build TypeScript
135+
npm run build
136+
137+
# Build and deploy documentation
138+
npm run build:docs
139+
npm run deploy:docs
140+
```
141+
142+
### Test Structure
143+
144+
Tests use `.spec.ts` files co-located with source:
145+
- `src/webServiceClient.spec.ts` - Web service client tests
146+
- `src/request/*.spec.ts` - Request component tests
147+
- `src/response/models/*.spec.ts` - Response model tests
148+
- `src/utils.spec.ts` - Utility function tests
149+
- `e2e/` - End-to-end integration tests (JS and TS)
150+
151+
### Test Patterns
152+
153+
Tests typically use `nock` to mock HTTP responses:
154+
```typescript
155+
import nock from 'nock';
156+
157+
nock('https://minfraud.maxmind.com')
158+
.post('/minfraud/v2.0/score')
159+
.reply(200, { risk_score: 50, id: '...', /* ... */ });
160+
161+
const response = await client.score(transaction);
162+
expect(response.riskScore).toBe(50);
163+
```
164+
165+
When adding new fields to models:
166+
1. Update test fixtures/mocks to include the new field
167+
2. Add assertions to verify the field is properly mapped
168+
3. Test both presence and absence (undefined handling)
169+
4. Verify camelCase conversion from snake_case source
170+
171+
## Working with This Codebase
172+
173+
### Adding New Fields to Request Components
174+
175+
1. **Add the property** to the component class with validation:
176+
```typescript
177+
/**
178+
* Description of the field.
179+
*/
180+
public fieldName?: Type;
181+
```
182+
183+
2. **Update the constructor** if validation is needed:
184+
```typescript
185+
if (props.fieldName && !isValid(props.fieldName)) {
186+
throw new ArgumentError('Invalid fieldName');
187+
}
188+
this.fieldName = props.fieldName;
189+
```
190+
191+
3. **Add to the interface** (e.g., `DeviceProps`, `EmailProps`) for type safety
192+
193+
4. **Add tests** that verify validation and serialization
194+
195+
5. **Update CHANGELOG.md** with the change
196+
197+
### Adding New Fields to Response Models
198+
199+
1. **Add the property** with proper type annotation:
200+
```typescript
201+
/**
202+
* Description of the field, including availability (which endpoints).
203+
*/
204+
public readonly fieldName?: Type;
205+
```
206+
207+
2. **Update the constructor** to map from the response:
208+
```typescript
209+
// For simple fields:
210+
this.fieldName = response.field_name;
211+
212+
// For nested objects that need camelization:
213+
this.fieldName = this.maybeGet<records.FieldType>(response, 'field_name');
214+
```
215+
216+
3. **Update corresponding record interfaces** in `records.ts` or `web-records.ts`
217+
218+
4. **Add tests** that verify the field mapping and type
219+
220+
5. **Update CHANGELOG.md** with the change
221+
222+
### Adding New Constants/Enums
223+
224+
When the API adds new enum values (e.g., new payment processors, event types):
225+
226+
1. **Update `src/constants.ts`** with the new value:
227+
```typescript
228+
export enum Processor {
229+
Stripe = 'stripe',
230+
NewProcessor = 'new_processor',
231+
// ...
232+
}
233+
```
234+
235+
2. **Add tests** if the enum has validation logic
236+
237+
3. **Update CHANGELOG.md** with the change
238+
239+
### CHANGELOG.md Format
240+
241+
Always update `CHANGELOG.md` for user-facing changes.
242+
243+
**Important**: Do not add a date to changelog entries until release time.
244+
245+
- If the next version doesn't exist, create it as `X.Y.Z (unreleased)` or just `X.Y.Z` (the header format varies)
246+
- If it already exists without a date, add your changes there
247+
- The release date will be added when the version is actually released
248+
249+
```markdown
250+
8.2.0
251+
------------------
252+
253+
* Added `NewProcessor` to the `Processor` enum.
254+
* Added the output `/email/first_seen`. This is available as the
255+
`firstSeen` property on `response.email`.
256+
```
257+
258+
## Common Pitfalls and Solutions
259+
260+
### Problem: Incorrect snake_case to camelCase Mapping
261+
262+
API responses use snake_case but must be exposed as camelCase.
263+
264+
**Solution**: Use `camelizeResponse()` for nested objects:
265+
```typescript
266+
this.email = this.maybeGet<records.Email>(response, 'email');
267+
268+
private maybeGet<T>(response: Response, prop: keyof Response): T | undefined {
269+
return response[prop] ? (camelizeResponse(response[prop]) as T) : undefined;
270+
}
271+
```
272+
273+
### Problem: Request Validation Not Working
274+
275+
Request components should validate inputs in constructors.
276+
277+
**Solution**: Import validators from the `validator` package:
278+
```typescript
279+
import validator from 'validator';
280+
281+
if (!validator.isEmail(props.address)) {
282+
throw new ArgumentError('Invalid email address');
283+
}
284+
```
285+
286+
### Problem: Missing Error Handling
287+
288+
The client can throw various error types.
289+
290+
**Solution**: Check for error codes in catch blocks:
291+
```typescript
292+
try {
293+
const response = await client.score(transaction);
294+
} catch (error) {
295+
// error has shape: { code: string, error: string, url?: string }
296+
if (error.code === 'INSUFFICIENT_FUNDS') {
297+
// Handle insufficient funds
298+
}
299+
}
300+
```
301+
302+
### Problem: GeoIP2 Type Conflicts
303+
304+
The IP address data comes from @maxmind/geoip2-node and needs augmentation.
305+
306+
**Solution**: Cast the GeoInsights object and add minFraud-specific fields:
307+
```typescript
308+
const insights = new GeoInsights(response.ip_address) as records.IpAddress;
309+
insights.risk = response.ip_address.risk;
310+
```
311+
312+
## Code Style Requirements
313+
314+
- **TypeScript strict mode** - All files use strict type checking
315+
- **ESLint** - Configured with TypeScript ESLint rules (see `eslint.config.mjs`)
316+
- **Prettier** - Consistent formatting enforced
317+
- **Readonly response fields** - Response model properties are `readonly`
318+
- **Optional chaining** - Use `?.` for optional nested properties
319+
- **TypeDoc comments** - Document public APIs with JSDoc-style comments
320+
321+
## Development Workflow
322+
323+
### Setup
324+
```bash
325+
npm install
326+
```
327+
328+
### Before Committing
329+
```bash
330+
# Tidy code (auto-fix issues)
331+
precious tidy -g
332+
333+
# Lint code (check for issues)
334+
precious lint -g
335+
336+
# Run tests
337+
npm test
338+
339+
# Build
340+
npm run build
341+
```
342+
343+
Note: Precious is already set up and handles code formatting and linting. Use `precious tidy -g` to automatically fix issues, and `precious lint -g` to check for remaining problems.
344+
345+
### Version Requirements
346+
- **Node.js 18+** required (targets active LTS: 18, 20, 22)
347+
- Uses Node.js built-in `fetch` (no external HTTP libraries)
348+
- TypeScript 5.x
349+
350+
## Cross-Language Consistency
351+
352+
This library is part of MaxMind's multi-language client library ecosystem. When adding features:
353+
354+
- **Field names** should match other client libraries (PHP, Python, etc.) after camelCase conversion
355+
- **Model structure** should parallel other implementations where possible
356+
- **Error handling** patterns should be consistent
357+
- **Documentation style** should follow established patterns
358+
359+
Refer to other minFraud client implementations for guidance on new features.
360+
361+
## Additional Resources
362+
363+
- [API Documentation](https://maxmind.github.io/minfraud-api-node/)
364+
- [minFraud Web Services Docs](https://dev.maxmind.com/minfraud/)
365+
- [minFraud API Documentation](https://dev.maxmind.com/minfraud/api-documentation/)
366+
- GitHub Issues: https://github.com/maxmind/minfraud-api-node/issues

0 commit comments

Comments
 (0)