@treeviz/familysearch-sdk 1.0.25 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,61 @@ A modern, TypeScript-first SDK for the FamilySearch API v3.
6
6
 
7
7
  > **Note:** This package was previously published as `familysearch-sdk`. It has been moved to the `@treeviz` organization.
8
8
 
9
+ ## ⚠️ Version 2.0.0 Breaking Changes
10
+
11
+ **Version 2.0.0 introduces a major architectural refactor** with breaking changes to the API surface. The SDK now uses a **modular architecture** where API methods are organized into dedicated modules instead of being exposed directly on the SDK instance.
12
+
13
+ ### Migration Guide (v1.x → v2.0.0)
14
+
15
+ | Old API (v1.x) | New API (v2.0.0) | Module |
16
+ |----------------|------------------|--------|
17
+ | `sdk.readCurrentUser()` | `sdk.user.readCurrentUser()` | User API |
18
+ | `sdk.readPerson(id)` | `sdk.persons.readPerson(id)` | Persons API |
19
+ | `sdk.searchPersons(query)` | `sdk.search.searchPersons(query)` | Search API |
20
+ | `sdk.matchPerson(person)` | `sdk.matches.matchPerson(person)` | Matches API |
21
+ | `sdk.searchPersonByData(person)` | `sdk.search.searchPersonByData(person)` | Search API |
22
+ | `sdk.searchPlaces(query)` | `sdk.places.searchPlaces(query)` | Places API |
23
+ | `sdk.exportGEDCOM(personId)` | `sdk.persons.exportGEDCOM(personId)` | Persons API |
24
+ | `sdk.getPersonSources(id)` | `sdk.sources.readPersonSources(id)` | Sources API |
25
+ | `sdk.getPersonMemories(id)` | `sdk.persons.readPersonMemories(id)` | Persons API |
26
+ | `sdk.getPersonDiscussions(id)` | `sdk.discussions.readPersonDiscussions(id)` | Discussions API |
27
+ | `sdk.getPersonPortraits(id)` | `sdk.persons.readPersonPortraits(id)` | Persons API |
28
+ | `sdk.getPersonChangeHistory(id)` | `sdk.persons.readPersonChangeHistory(id)` | Persons API |
29
+
30
+ ### Why This Change?
31
+
32
+ **Benefits of v2.0.0 architecture:**
33
+ - ✅ **Better organization**: Related functionality grouped into logical modules
34
+ - ✅ **Cleaner client.ts**: Core SDK now only handles HTTP methods and infrastructure
35
+ - ✅ **No duplicates**: Single source of truth for each API method
36
+ - ✅ **Better tree-shaking**: Import only the modules you need
37
+ - ✅ **Easier maintenance**: Changes isolated to specific modules
38
+ - ✅ **Consistent patterns**: All modules follow the same structure
39
+
40
+ ### Quick Migration Example
41
+
42
+ **Before (v1.x):**
43
+ ```typescript
44
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
45
+
46
+ const user = await sdk.readCurrentUser();
47
+ const person = await sdk.readPerson('KWQS-BBQ');
48
+ const matches = await sdk.matchPerson({ givenName: 'John', familyName: 'Smith' });
49
+ const places = await sdk.searchPlaces('London, England');
50
+ ```
51
+
52
+ **After (v2.0.0):**
53
+ ```typescript
54
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
55
+
56
+ const user = await sdk.user.readCurrentUser();
57
+ const person = await sdk.persons.readPerson('KWQS-BBQ');
58
+ const matches = await sdk.matches.matchPerson({ givenName: 'John', familyName: 'Smith' });
59
+ const places = await sdk.places.searchPlaces('London, England');
60
+ ```
61
+
62
+ **Pattern:** `sdk.<method>()` → `sdk.<module>.<method>()`
63
+
9
64
  ## Features
10
65
 
11
66
  - 🔷 **Full TypeScript support** with comprehensive type definitions
@@ -15,7 +70,13 @@ A modern, TypeScript-first SDK for the FamilySearch API v3.
15
70
  - 📝 **GEDCOM export** - Convert FamilySearch data to GEDCOM 5.5 format
16
71
  - 📍 **Places API** helpers for location searches
17
72
  - 👨‍👩‍👧 **Tree/Pedigree API** for ancestry data
18
- - 📚 **Sources API** - Fetch source references linked to persons
73
+ - 📚 **Sources API** - Fetch source references and descriptions
74
+ - 💬 **Discussions API** - Access person discussions and comments
75
+ - 🖼️ **Memories API** - Work with photos, documents, and stories
76
+ - 🔄 **Rate Limiting** - Built-in rate limiting with automatic retry on 429 errors
77
+ - ⚡ **Enhanced Error Handling** - Typed error classes for better error management
78
+ - 📜 **Change History** - Access person change history and audit logs
79
+ - 🧩 **Modular Architecture (v2.0.0)** - Organized API modules for better maintainability
19
80
 
20
81
  ## Installation
21
82
 
@@ -38,8 +99,12 @@ const sdk = createFamilySearchSDK({
38
99
  accessToken: 'your-oauth-token'
39
100
  });
40
101
 
102
+ // Fetch current user (v2.0.0 - note the module prefix)
103
+ const user = await sdk.user.readCurrentUser();
104
+ console.log('User:', user?.displayName);
105
+
41
106
  // Fetch pedigree data
42
- const pedigree = await fetchPedigree(sdk, undefined, {
107
+ const pedigree = await fetchPedigree(sdk, user?.personId, {
43
108
  generations: 5,
44
109
  onProgress: (progress) => {
45
110
  console.log(`${progress.percent}% complete`);
@@ -54,27 +119,98 @@ const gedcom = convertToGedcom(pedigree, {
54
119
  console.log(gedcom);
55
120
  ```
56
121
 
122
+ ## SDK Modules (v2.0.0)
123
+
124
+ The SDK is organized into the following modules:
125
+
126
+ | Module | Access via | Purpose |
127
+ |--------|-----------|---------|
128
+ | **User API** | `sdk.user.*` | Current user information |
129
+ | **Persons API** | `sdk.persons.*` | Person CRUD operations, memories, portraits, change history |
130
+ | **Search API** | `sdk.search.*` | Person search by query or structured data |
131
+ | **Matches API** | `sdk.matches.*` | Person matching for duplicate detection |
132
+ | **Relationships API** | `sdk.relationships.*` | Couple and parent-child relationships |
133
+ | **Sources API** | `sdk.sources.*` | Source descriptions and attachments |
134
+ | **Places API** | `sdk.places.*` | Place search and details |
135
+ | **Discussions API** | `sdk.discussions.*` | Person discussions and comments |
136
+ | **Memories API** | `sdk.memories.*` | Photos, documents, and stories |
137
+ | **Notes API** | `sdk.notes.*` | Person notes |
138
+ | **Pedigrees API** | `sdk.pedigrees.*` | Ancestry and descendancy queries |
139
+ | **Dates API** | `sdk.dates.*` | Date standardization |
140
+ | **Names API** | `sdk.names.*` | Name standardization |
141
+ | **Vocabularies API** | `sdk.vocabularies.*` | Controlled vocabularies |
142
+
143
+ ### Module Examples
144
+
145
+ ```typescript
146
+ // User API
147
+ const user = await sdk.user.readCurrentUser();
148
+
149
+ // Persons API
150
+ const person = await sdk.persons.readPerson('KWQS-BBQ');
151
+ const memories = await sdk.persons.readPersonMemories('KWQS-BBQ');
152
+ const changeHistory = await sdk.persons.readPersonChangeHistory('KWQS-BBQ');
153
+ const gedcom = await sdk.persons.exportGEDCOM('KWQS-BBQ');
154
+
155
+ // Search API
156
+ const searchResults = await sdk.search.searchPersons('John Smith');
157
+ const matchResults = await sdk.search.searchPersonByData({
158
+ givenName: 'John',
159
+ familyName: 'Smith',
160
+ birthDate: '1850'
161
+ });
162
+
163
+ // Matches API
164
+ const matches = await sdk.matches.matchPerson({
165
+ givenName: 'Mary',
166
+ familyName: 'Johnson',
167
+ gender: 'Female',
168
+ birthDate: '1875',
169
+ birthPlace: 'Boston, Massachusetts'
170
+ });
171
+
172
+ // Places API
173
+ const places = await sdk.places.searchPlaces('London, England');
174
+ const placeDetails = await sdk.places.readPlaceById('12345');
175
+
176
+ // Relationships API
177
+ const ancestry = await sdk.relationships.readPersonAncestry('KWQS-BBQ', { generations: 4 });
178
+ const parents = await sdk.relationships.readPersonParents('KWQS-BBQ');
179
+
180
+ // Sources API
181
+ const sources = await sdk.sources.readPersonSources('KWQS-BBQ');
182
+ const sourceDesc = await sdk.sources.readSourceDescription('SOURCE-123');
183
+
184
+ // Discussions API
185
+ const discussions = await sdk.discussions.readPersonDiscussions('KWQS-BBQ');
186
+ ```
187
+
57
188
  ## OAuth Authentication
58
189
 
59
190
  The SDK provides utilities for OAuth 2.0 authentication with FamilySearch.
60
191
 
192
+ ### Basic OAuth Flow
193
+
61
194
  ```typescript
62
195
  import {
63
196
  generateOAuthState,
64
197
  buildAuthorizationUrl,
65
198
  exchangeCodeForToken,
66
- validateAccessToken
67
- } from 'familysearch-sdk/auth';
199
+ validateAccessToken,
200
+ refreshAccessToken
201
+ } from '@treeviz/familysearch-sdk/auth';
68
202
 
69
203
  // Generate state for CSRF protection
70
204
  const state = generateOAuthState();
71
205
 
72
- // Build authorization URL
206
+ // Build authorization URL with offline_access scope for refresh tokens
73
207
  const authUrl = buildAuthorizationUrl({
74
208
  clientId: 'your-client-id',
75
209
  redirectUri: 'https://your-app.com/callback',
76
210
  environment: 'production'
77
- }, state);
211
+ }, state, {
212
+ scopes: ['offline_access'] // Request refresh token
213
+ });
78
214
 
79
215
  // Redirect user to authUrl...
80
216
 
@@ -85,29 +221,112 @@ const tokens = await exchangeCodeForToken(code, {
85
221
  environment: 'production'
86
222
  });
87
223
 
224
+ console.log('Access token:', tokens.access_token);
225
+ console.log('Refresh token:', tokens.refresh_token); // Available with offline_access scope
226
+ console.log('Expires in:', tokens.expires_in);
227
+
88
228
  // Validate token
89
229
  const isValid = await validateAccessToken(tokens.access_token, 'production');
230
+
231
+ // Refresh token when it expires
232
+ if (tokens.refresh_token) {
233
+ const newTokens = await refreshAccessToken(tokens.refresh_token, {
234
+ clientId: 'your-client-id',
235
+ redirectUri: 'https://your-app.com/callback',
236
+ environment: 'production'
237
+ });
238
+ console.log('New access token:', newTokens.access_token);
239
+ }
90
240
  ```
91
241
 
242
+ ### Token Storage (Browser Environment)
243
+
244
+ **Best Practice for storing FamilySearch tokens:**
245
+
246
+ ```typescript
247
+ import {
248
+ storeTokens,
249
+ getStoredAccessToken,
250
+ getStoredRefreshToken,
251
+ clearStoredTokens
252
+ } from '@treeviz/familysearch-sdk/auth';
253
+
254
+ // After obtaining tokens from OAuth flow
255
+ await storeTokens('user-id', {
256
+ accessToken: tokens.access_token,
257
+ expiresAt: Date.now() + (tokens.expires_in * 1000),
258
+ refreshToken: tokens.refresh_token, // Store for silent refresh
259
+ environment: 'production'
260
+ });
261
+
262
+ // Retrieve tokens later
263
+ const accessToken = getStoredAccessToken('user-id');
264
+ const refreshToken = getStoredRefreshToken('user-id');
265
+
266
+ // Clear tokens on sign out
267
+ clearStoredTokens('user-id');
268
+ ```
269
+
270
+ **Storage Strategy (FamilySearch Compatibility):**
271
+ - ✅ **Access tokens** → `sessionStorage` (temporary, cleared on browser close)
272
+ - ✅ **Refresh tokens** → `localStorage` (persistent, for re-authentication)
273
+ - ✅ **Compliant** with FamilySearch requirement: "No permanent storage of FamilySearch API Session ID"
274
+
275
+ ### Refresh Token Best Practices
276
+
277
+ **Always request `offline_access` scope** to ensure you receive a refresh token:
278
+
279
+ ```typescript
280
+ const authUrl = buildAuthorizationUrl(config, state, {
281
+ scopes: ['offline_access'] // ← Important!
282
+ });
283
+ ```
284
+
285
+ **Why `offline_access`?**
286
+ - ✅ Guarantees refresh token in response
287
+ - ✅ Refresh token is renewed on each refresh
288
+ - ✅ Prevents popup re-authentication loops
289
+ - ✅ Better user experience (silent token refresh)
290
+
291
+ Without `offline_access`:
292
+ - ❌ FamilySearch may not return refresh token
293
+ - ❌ Subsequent refreshes may not renew refresh token
294
+ - ❌ Eventually requires popup re-authentication
295
+
296
+ See [FamilySearch Refresh Token Implementation](../../docs/FAMILYSEARCH_REFRESH_TOKEN.md) for detailed information about token lifecycle and silent refresh implementation.
297
+
92
298
  ## Places API
93
299
 
94
300
  Search and retrieve place information from FamilySearch.
95
301
 
96
302
  ```typescript
97
- import { createFamilySearchSDK } from 'familysearch-sdk';
98
- import { searchPlaces, getPlaceDetails } from 'familysearch-sdk/places';
303
+ import { createFamilySearchSDK } from '@treeviz/familysearch-sdk';
99
304
 
100
305
  const sdk = createFamilySearchSDK({ accessToken: 'token' });
101
306
 
102
- // Search for places
103
- const results = await searchPlaces(sdk, 'London, England', {
307
+ // Search for places (v2.0.0 - using sdk.places module)
308
+ const results = await sdk.places.searchPlaces('London, England', {
104
309
  date: '1850',
105
310
  count: 10
106
311
  });
107
312
 
313
+ // Or use structured query parameters
314
+ const structuredResults = await sdk.places.searchPlaces({
315
+ name: 'London',
316
+ parentId: '12345', // Parent place ID
317
+ typeId: '789', // Place type ID (city, county, etc.)
318
+ date: '1850-01-01',
319
+ count: 10
320
+ });
321
+
108
322
  // Get place details
109
- const details = await getPlaceDetails(sdk, 'place-id');
323
+ const details = await sdk.places.readPlaceById('place-id');
110
324
  console.log(details.name, details.latitude, details.longitude);
325
+
326
+ // Get child places (e.g., counties in a state)
327
+ const children = await sdk.places.readPlaceChildren('place-id', {
328
+ count: 50
329
+ });
111
330
  ```
112
331
 
113
332
  ## Tree/Pedigree API
@@ -115,17 +334,30 @@ console.log(details.name, details.latitude, details.longitude);
115
334
  Fetch and manage family tree data.
116
335
 
117
336
  ```typescript
118
- import { createFamilySearchSDK } from 'familysearch-sdk';
119
- import { fetchPedigree, getCurrentUser } from 'familysearch-sdk/tree';
337
+ import { createFamilySearchSDK } from '@treeviz/familysearch-sdk';
120
338
 
121
339
  const sdk = createFamilySearchSDK({ accessToken: 'token' });
122
340
 
123
- // Get current user
124
- const user = await getCurrentUser(sdk);
125
- console.log(user?.displayName);
341
+ // Get current user (v2.0.0 - using sdk.user module)
342
+ const user = await sdk.user.readCurrentUser();
343
+ console.log(user?.displayName, user?.personId);
344
+
345
+ // Read a person (v2.0.0 - using sdk.persons module)
346
+ const person = await sdk.persons.readPerson('KWQS-BBQ');
347
+ console.log(person?.display?.name);
348
+
349
+ // Read person with relationships
350
+ const personWithRelations = await sdk.persons.readPersonWithDetails('KWQS-BBQ', {
351
+ sourceDescriptions: true
352
+ });
126
353
 
127
- // Fetch pedigree (will use current user's personId)
128
- const pedigree = await fetchPedigree(sdk, undefined, {
354
+ // Get ancestry (v2.0.0 - using sdk.relationships module)
355
+ const ancestry = await sdk.relationships.readPersonAncestry('KWQS-BBQ', {
356
+ generations: 4
357
+ });
358
+
359
+ // Fetch pedigree (will use current user's personId if not provided)
360
+ const pedigree = await fetchPedigree(sdk, user?.personId, {
129
361
  generations: 4,
130
362
  includeDetails: true,
131
363
  includeNotes: true
@@ -137,12 +369,12 @@ const pedigree = await fetchPedigree(sdk, undefined, {
137
369
  Retrieve source references linked to persons.
138
370
 
139
371
  ```typescript
140
- import { createFamilySearchSDK } from 'familysearch-sdk';
372
+ import { createFamilySearchSDK } from '@treeviz/familysearch-sdk';
141
373
 
142
374
  const sdk = createFamilySearchSDK({ accessToken: 'token' });
143
375
 
144
- // Fetch sources for a person
145
- const sources = await sdk.getPersonSources('KWQS-BBQ');
376
+ // Fetch sources for a person (v2.0.0 - using sdk.sources module)
377
+ const sources = await sdk.sources.readPersonSources('KWQS-BBQ');
146
378
 
147
379
  // Access source references
148
380
  if (sources?.persons?.[0]?.sources) {
@@ -160,6 +392,10 @@ if (sources?.sourceDescriptions) {
160
392
  console.log('About:', desc.about);
161
393
  });
162
394
  }
395
+
396
+ // Get a specific source description
397
+ const sourceDesc = await sdk.sources.readSourceDescription('SOURCE-123');
398
+ console.log('Source title:', sourceDesc?.titles?.[0]?.value);
163
399
  ```
164
400
 
165
401
  ## Person Match API
@@ -167,12 +403,12 @@ if (sources?.sourceDescriptions) {
167
403
  Find potential matches in the FamilySearch Tree for persons from external GEDCOM data or manually created trees.
168
404
 
169
405
  ```typescript
170
- import { createFamilySearchSDK } from 'familysearch-sdk';
406
+ import { createFamilySearchSDK } from '@treeviz/familysearch-sdk';
171
407
 
172
408
  const sdk = createFamilySearchSDK({ accessToken: 'token' });
173
409
 
174
- // Match a person from external GEDCOM data
175
- const matches = await sdk.matchPerson({
410
+ // Match a person from external GEDCOM data (v2.0.0 - using sdk.matches module)
411
+ const matches = await sdk.matches.matchPerson({
176
412
  givenName: 'John',
177
413
  familyName: 'Smith',
178
414
  gender: 'Male',
@@ -199,7 +435,7 @@ if (matches?.entries) {
199
435
  }
200
436
 
201
437
  // Filter by collection and limit results
202
- const censusMatches = await sdk.matchPerson({
438
+ const censusMatches = await sdk.matches.matchPerson({
203
439
  givenName: 'Mary',
204
440
  familyName: 'Johnson',
205
441
  birthDate: '1875'
@@ -207,6 +443,19 @@ const censusMatches = await sdk.matchPerson({
207
443
  collection: 'census',
208
444
  count: 10
209
445
  });
446
+
447
+ // Search by structured person data (v2.0.0 - using sdk.search module)
448
+ const searchResults = await sdk.search.searchPersonByData({
449
+ givenName: 'John',
450
+ familyName: 'Smith',
451
+ birthDate: '1850',
452
+ birthPlace: 'London, England',
453
+ fatherGivenName: 'William',
454
+ fatherFamilyName: 'Smith'
455
+ }, {
456
+ count: 20,
457
+ collection: 'tree'
458
+ });
210
459
  ```
211
460
 
212
461
  ## GEDCOM Conversion
@@ -226,6 +475,149 @@ const gedcom = convertToGedcom(pedigreeData, {
226
475
  fs.writeFileSync('family.ged', gedcom);
227
476
  ```
228
477
 
478
+ ## Discussions API
479
+
480
+ Access person discussions and comments.
481
+
482
+ ```typescript
483
+ import { createFamilySearchSDK } from 'familysearch-sdk';
484
+
485
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
486
+
487
+ // Get discussions for a person
488
+ const discussions = await sdk.getPersonDiscussions('KWQS-BBQ');
489
+
490
+ if (discussions?.discussions) {
491
+ discussions.discussions.forEach(discussion => {
492
+ console.log('Title:', discussion.title);
493
+ console.log('Details:', discussion.details);
494
+ console.log('Comments:', discussion.numberOfComments);
495
+ });
496
+ }
497
+ ```
498
+
499
+ ## Portraits API
500
+
501
+ Fetch portrait photos for persons.
502
+
503
+ ```typescript
504
+ import { createFamilySearchSDK } from 'familysearch-sdk';
505
+
506
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
507
+
508
+ // Get portraits for a person
509
+ const portraits = await sdk.getPersonPortraits('KWQS-BBQ');
510
+
511
+ if (portraits?.sourceDescriptions) {
512
+ portraits.sourceDescriptions.forEach(portrait => {
513
+ console.log('Portrait URL:', portrait.about);
514
+ console.log('Title:', portrait.titles?.[0]?.value);
515
+ });
516
+ }
517
+ ```
518
+
519
+ ## Memories API
520
+
521
+ Work with photos, documents, and stories.
522
+
523
+ ```typescript
524
+ import { createFamilySearchSDK } from 'familysearch-sdk';
525
+
526
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
527
+
528
+ // Get a specific memory
529
+ const memory = await sdk.getMemory('MEM-123');
530
+
531
+ // Get user's uploaded memories
532
+ const userMemories = await sdk.readUserMemories({ count: 50 });
533
+
534
+ // Get comments on a memory
535
+ const comments = await sdk.readMemoryComments('MEM-123');
536
+ if (comments?.discussions?.[0]?.comments) {
537
+ comments.discussions[0].comments.forEach(comment => {
538
+ console.log('Comment:', comment.text);
539
+ });
540
+ }
541
+ ```
542
+
543
+ ## Change History API
544
+
545
+ Access person change history and audit logs.
546
+
547
+ ```typescript
548
+ import { createFamilySearchSDK } from 'familysearch-sdk';
549
+
550
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
551
+
552
+ // Get change history for a person
553
+ const history = await sdk.getPersonChangeHistory('KWQS-BBQ');
554
+
555
+ if (history?.entries) {
556
+ history.entries.forEach(entry => {
557
+ console.log('Change:', entry.title);
558
+ console.log('Date:', new Date(entry.updated || 0));
559
+ entry.changeInfo?.forEach(info => {
560
+ console.log('Operation:', info.operation);
561
+ console.log('Object Type:', info.objectType);
562
+ });
563
+ });
564
+ }
565
+ ```
566
+
567
+ ## Rate Limiting
568
+
569
+ The SDK includes built-in rate limiting with automatic retry on 429 errors.
570
+
571
+ ```typescript
572
+ import { createFamilySearchSDK } from 'familysearch-sdk';
573
+
574
+ const sdk = createFamilySearchSDK({
575
+ accessToken: 'token',
576
+ rateLimiter: {
577
+ requestsPerSecond: 10, // Max requests per second
578
+ maxBurst: 20, // Max burst size
579
+ maxRetries: 3, // Max retry attempts on 429
580
+ initialBackoffMs: 1000, // Initial backoff delay
581
+ maxBackoffMs: 30000 // Max backoff delay
582
+ }
583
+ });
584
+
585
+ // Requests are automatically rate limited and retried on 429 errors
586
+ const person = await sdk.getPerson('KWQS-BBQ');
587
+ ```
588
+
589
+ ## Error Handling
590
+
591
+ The SDK provides typed error classes for better error management.
592
+
593
+ ```typescript
594
+ import {
595
+ createFamilySearchSDK,
596
+ AuthenticationError,
597
+ NotFoundError,
598
+ RateLimitError,
599
+ ValidationError,
600
+ ServerError,
601
+ NetworkError
602
+ } from 'familysearch-sdk';
603
+
604
+ const sdk = createFamilySearchSDK({ accessToken: 'token' });
605
+
606
+ try {
607
+ const person = await sdk.getPerson('INVALID-ID');
608
+ } catch (error) {
609
+ if (error instanceof NotFoundError) {
610
+ console.error('Person not found:', error.resourceId);
611
+ } else if (error instanceof AuthenticationError) {
612
+ console.error('Authentication failed:', error.statusCode);
613
+ } else if (error instanceof RateLimitError) {
614
+ console.error('Rate limit exceeded. Retry after:', error.retryAfter);
615
+ } else if (error instanceof NetworkError) {
616
+ console.error('Network error:', error.originalError);
617
+ }
618
+ }
619
+ ```
620
+
229
621
  ## Environment Configuration
230
622
 
231
623
  The SDK supports three FamilySearch environments:
@@ -285,20 +677,55 @@ const sdk = createFamilySearchSDK({
285
677
  ### Places (`/places`)
286
678
 
287
679
  - `searchPlaces(sdk, query, options)` - Search for places
288
- - `getPlaceById(sdk, id)` - Get place by ID
289
- - `getPlaceChildren(sdk, id, options)` - Get child places
290
- - `getPlaceDetails(sdk, id)` - Get detailed place info
680
+ - `readPlaceById(sdk, id)` - Get place by ID
681
+ - `readPlaceChildren(sdk, id, options)` - Get child places
682
+ - `readPlaceDetails(sdk, id)` - Get detailed place info
291
683
 
292
684
  ### Tree (`/tree`)
293
685
 
294
686
  - `fetchPedigree(sdk, personId, options)` - Fetch ancestry data
295
- - `getCurrentUser(sdk)` - Get current user info
687
+ - `readCurrentUser(sdk)` - Get current user info
296
688
  - `getPersonWithDetails(sdk, personId)` - Get person details
297
689
  - `fetchMultiplePersons(sdk, personIds)` - Batch fetch persons
298
690
 
299
- ### Person Sources
691
+ ### Person APIs
300
692
 
693
+ - `sdk.getPerson(personId)` - Get person by ID
301
694
  - `sdk.getPersonSources(personId)` - Get source references for a person
695
+ - `sdk.getPersonNotes(personId)` - Get notes for a person
696
+ - `sdk.getPersonMemories(personId)` - Get memories for a person
697
+ - `sdk.getPersonDiscussions(personId)` - Get discussions for a person
698
+ - `sdk.getPersonPortraits(personId)` - Get portrait photos for a person
699
+ - `sdk.getPersonChangeHistory(personId)` - Get change history for a person
700
+ - `sdk.searchPersons(query, options)` - Search for persons
701
+
702
+ ### Sources APIs
703
+
704
+ - `sdk.getSourceDescription(sourceId)` - Get source description by ID
705
+ - `sdk.searchSourceDescriptions(query, options)` - Search source descriptions
706
+
707
+ ### Memories APIs
708
+
709
+ - `sdk.getMemory(memoryId)` - Get memory by ID
710
+ - `sdk.readUserMemories(options)` - Get user's uploaded memories
711
+ - `sdk.readMemoryComments(memoryId)` - Get comments for a memory
712
+
713
+ ### Relationships APIs
714
+
715
+ - `sdk.getCoupleRelationship(relationshipId)` - Get couple relationship details
716
+ - `sdk.getChildAndParentsRelationship(relationshipId)` - Get parent-child relationship details
717
+ - `sdk.getAncestry(personId, generations)` - Get ancestry for a person
718
+ - `sdk.getDescendancy(personId, generations)` - Get descendancy for a person
719
+
720
+ ### Error Classes
721
+
722
+ - `FamilySearchError` - Base error class
723
+ - `AuthenticationError` - 401/403 authentication errors
724
+ - `NotFoundError` - 404 resource not found errors
725
+ - `RateLimitError` - 429 rate limit errors
726
+ - `ValidationError` - 400 validation errors
727
+ - `ServerError` - 5xx server errors
728
+ - `NetworkError` - Network/connection errors
302
729
 
303
730
  ### Person Matching
304
731
 
@@ -309,6 +736,47 @@ const sdk = createFamilySearchSDK({
309
736
 
310
737
  - `convertToGedcom(pedigreeData, options)` - Convert to GEDCOM
311
738
 
739
+ ## API Coverage
740
+
741
+ This SDK currently implements approximately **84% (172 endpoints)** of the FamilySearch API. For comprehensive analysis:
742
+
743
+ - 📊 **[API Coverage Analysis](./API_COVERAGE_ANALYSIS.md)** - Detailed English analysis with implementation roadmap
744
+ - 🇭🇺 **[API Coverage Analysis (Hungarian)](./API_COVERAGE_ANALYSIS_HU.md)** - Hungarian summary and recommendations
745
+ - 📋 **[Complete API Endpoints List](./API_ENDPOINTS_COMPLETE.md)** - Full endpoint inventory with implementation status
746
+ - 🎯 **[Latest Session Summary](./docs/SESSION_SUMMARY_2026_01_21.md)** - Recent implementation progress (73% → 84%)
747
+
748
+ ### Implementation Status
749
+
750
+ ✅ **Fully Implemented Categories (8/19)**:
751
+ - Change History, Discussions, Genealogies (User Trees)
752
+ - Groups, Matches, Notes, Places Standards, Vocabularies
753
+
754
+ 🚧 **Partial Implementation**:
755
+ - **Tree Persons**: 34/48 (71%) - Missing: reference deletions, search, matches
756
+ - **Relationships**: 43/48 (90%) - Missing: restore, notes, GedcomX format
757
+ - **Sources**: 16/19 (84%) - Missing: HEAD requests, user sources
758
+ - **Memories**: 4/5 (80%) - Missing: create memory
759
+ - **Other categories**: 90%+ coverage
760
+
761
+ ### Key Capabilities
762
+
763
+ ✅ **You CAN**:
764
+ - ✅ Read, create, update, delete persons
765
+ - ✅ Create and manage relationships (couple, parent-child)
766
+ - ✅ Read and manage sources (descriptions, attachments, collections)
767
+ - ✅ Search and match persons
768
+ - ✅ Fetch pedigrees and ancestry data
769
+ - ✅ Read memories, discussions, notes
770
+ - ✅ Work with User Trees (Genealogies API)
771
+
772
+ ⚠️ **Limited Support**:
773
+ - ⚠️ Reference deletions (discussion, memory, source references)
774
+ - ⚠️ Relationship restore operations
775
+ - ⚠️ Advanced search operations
776
+ - ⚠️ Match management (not-a-match operations)
777
+
778
+ See the [API Coverage Analysis](./API_COVERAGE_ANALYSIS.md) for detailed information about missing endpoints and implementation priorities.
779
+
312
780
  ## License
313
781
 
314
782
  MIT License - see [LICENSE](./LICENSE) file for details.
@@ -316,3 +784,4 @@ MIT License - see [LICENSE](./LICENSE) file for details.
316
784
  ## Contributing
317
785
 
318
786
  Contributions are welcome! Please read our contributing guidelines before submitting a pull request.
787
+