@treeviz/familysearch-sdk 1.0.10

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.
@@ -0,0 +1,89 @@
1
+ // src/places/places.ts
2
+ async function searchPlaces(sdk, query, options) {
3
+ const queryParts = [`name:"${query}"`];
4
+ if (options?.date) {
5
+ queryParts.push(`+date:${options.date}`);
6
+ }
7
+ if (options?.parentId) {
8
+ queryParts.push(`+parentId:${options.parentId}`);
9
+ }
10
+ const finalQuery = queryParts.join(" ");
11
+ const params = new URLSearchParams({
12
+ q: finalQuery,
13
+ ...options?.count && { count: options.count.toString() },
14
+ ...options?.start && { start: options.start.toString() }
15
+ });
16
+ const response = await sdk.get(
17
+ `/platform/places/search?${params.toString()}`
18
+ );
19
+ const data = response.data || {};
20
+ if (!data?.entries?.length) {
21
+ if (options?.date) {
22
+ const { date: _date, ...optionsWithoutDate } = options;
23
+ return searchPlaces(sdk, query, optionsWithoutDate);
24
+ }
25
+ return [];
26
+ }
27
+ return data.entries?.map((entry) => {
28
+ const place = entry.content?.gedcomx?.places?.[0];
29
+ return {
30
+ id: place?.id || entry.id,
31
+ title: entry.title,
32
+ fullyQualifiedName: entry.title,
33
+ names: place?.names,
34
+ standardized: place?.jurisdiction ? {
35
+ id: place.jurisdiction.id,
36
+ fullyQualifiedName: place.jurisdiction.name
37
+ } : void 0,
38
+ jurisdiction: place?.jurisdiction,
39
+ temporalDescription: place?.temporalDescription
40
+ };
41
+ }) || [];
42
+ }
43
+ async function getPlaceById(sdk, id) {
44
+ const response = await sdk.get(
45
+ `/platform/places/${id}`
46
+ );
47
+ return response.data?.places?.[0] || null;
48
+ }
49
+ async function getPlaceChildren(sdk, id, options) {
50
+ const params = new URLSearchParams({
51
+ ...options?.count && { count: options.count.toString() },
52
+ ...options?.start && { start: options.start.toString() }
53
+ });
54
+ const queryString = params.toString();
55
+ const url = `/platform/places/${id}/children${queryString ? `?${queryString}` : ""}`;
56
+ const response = await sdk.get(url);
57
+ const data = response.data || {};
58
+ return data.entries?.map((entry) => {
59
+ const place = entry.content?.gedcomx?.places?.[0];
60
+ return {
61
+ id: place?.id || entry.id,
62
+ title: entry.title,
63
+ fullyQualifiedName: entry.title,
64
+ names: place?.names,
65
+ jurisdiction: place?.jurisdiction
66
+ };
67
+ }) || [];
68
+ }
69
+ async function getPlaceDetails(sdk, id) {
70
+ const place = await getPlaceById(sdk, id);
71
+ if (!place) {
72
+ return null;
73
+ }
74
+ const primaryName = place.names?.find((n) => n.lang === "en")?.value || place.names?.[0]?.value || "";
75
+ const aliases = place.names?.filter((n) => n.value !== primaryName).map((n) => n.value || "").filter(Boolean) || [];
76
+ return {
77
+ id: place.id || id,
78
+ name: primaryName,
79
+ standardizedName: place.jurisdiction?.name,
80
+ aliases,
81
+ latitude: place.latitude,
82
+ longitude: place.longitude,
83
+ jurisdiction: place.jurisdiction?.name
84
+ };
85
+ }
86
+
87
+ export { getPlaceById, getPlaceChildren, getPlaceDetails, searchPlaces };
88
+ //# sourceMappingURL=index.js.map
89
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/places/places.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * FamilySearch Places API Module\n *\n * Provides helpers for searching and retrieving place information\n * from the FamilySearch Places API.\n *\n * API Documentation: https://developers.familysearch.org/main/page/places-endpoints\n */\n\nimport type { FamilySearchSDK } from \"../client\";\nimport type {\n\tPlaceDescription,\n\tPlaceDetailsResponse,\n\tPlaceSearchResponse,\n\tPlaceSearchResult,\n} from \"../types\";\n\n/**\n * Search for places by name\n *\n * @param sdk - FamilySearch SDK instance\n * @param query - The search query string\n * @param options - Optional search parameters\n * @returns Promise with search results\n *\n * @example\n * ```typescript\n * const results = await searchPlaces(sdk, \"London\", { date: \"1850\" });\n * ```\n */\nexport async function searchPlaces(\n\tsdk: FamilySearchSDK,\n\tquery: string,\n\toptions?: {\n\t\tcount?: number;\n\t\tstart?: number;\n\t\tdate?: string;\n\t\tparentId?: string;\n\t}\n): Promise<PlaceSearchResult[]> {\n\t// Build query parameters according to FamilySearch API docs\n\tconst queryParts = [`name:\"${query}\"`];\n\n\t// Add date to query if provided\n\tif (options?.date) {\n\t\tqueryParts.push(`+date:${options.date}`);\n\t}\n\n\t// Add parentId to query if provided\n\tif (options?.parentId) {\n\t\tqueryParts.push(`+parentId:${options.parentId}`);\n\t}\n\n\tconst finalQuery = queryParts.join(\" \");\n\n\tconst params = new URLSearchParams({\n\t\tq: finalQuery,\n\t\t...(options?.count && { count: options.count.toString() }),\n\t\t...(options?.start && { start: options.start.toString() }),\n\t});\n\n\tconst response = await sdk.get<PlaceSearchResponse>(\n\t\t`/platform/places/search?${params.toString()}`\n\t);\n\n\tconst data = response.data || {};\n\n\t// Check if entries exist\n\tif (!data?.entries?.length) {\n\t\t// If we had a date filter and got no results, try again without it\n\t\tif (options?.date) {\n\t\t\tconst { date: _date, ...optionsWithoutDate } = options;\n\t\t\treturn searchPlaces(sdk, query, optionsWithoutDate);\n\t\t}\n\t\treturn [];\n\t}\n\n\t// Transform the response into a cleaner format\n\treturn (\n\t\tdata.entries?.map((entry) => {\n\t\t\tconst place = entry.content?.gedcomx?.places?.[0];\n\t\t\treturn {\n\t\t\t\tid: place?.id || entry.id,\n\t\t\t\ttitle: entry.title,\n\t\t\t\tfullyQualifiedName: entry.title,\n\t\t\t\tnames: place?.names,\n\t\t\t\tstandardized: place?.jurisdiction\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tid: place.jurisdiction.id,\n\t\t\t\t\t\t\tfullyQualifiedName: place.jurisdiction.name,\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t\tjurisdiction: place?.jurisdiction,\n\t\t\t\ttemporalDescription: place?.temporalDescription,\n\t\t\t};\n\t\t}) || []\n\t);\n}\n\n/**\n * Get a specific place by its ID\n *\n * @param sdk - FamilySearch SDK instance\n * @param id - The FamilySearch place ID\n * @returns Promise with place details\n */\nexport async function getPlaceById(\n\tsdk: FamilySearchSDK,\n\tid: string\n): Promise<PlaceDescription | null> {\n\tconst response = await sdk.get<PlaceDetailsResponse>(\n\t\t`/platform/places/${id}`\n\t);\n\treturn response.data?.places?.[0] || null;\n}\n\n/**\n * Get child places of a specific place\n *\n * @param sdk - FamilySearch SDK instance\n * @param id - The parent place ID\n * @param options - Optional parameters\n * @returns Promise with child places\n */\nexport async function getPlaceChildren(\n\tsdk: FamilySearchSDK,\n\tid: string,\n\toptions?: {\n\t\tcount?: number;\n\t\tstart?: number;\n\t}\n): Promise<PlaceSearchResult[]> {\n\tconst params = new URLSearchParams({\n\t\t...(options?.count && { count: options.count.toString() }),\n\t\t...(options?.start && { start: options.start.toString() }),\n\t});\n\n\tconst queryString = params.toString();\n\tconst url = `/platform/places/${id}/children${queryString ? `?${queryString}` : \"\"}`;\n\n\tconst response = await sdk.get<PlaceSearchResponse>(url);\n\tconst data = response.data || {};\n\n\t// Transform the response\n\treturn (\n\t\tdata.entries?.map((entry) => {\n\t\t\tconst place = entry.content?.gedcomx?.places?.[0];\n\t\t\treturn {\n\t\t\t\tid: place?.id || entry.id,\n\t\t\t\ttitle: entry.title,\n\t\t\t\tfullyQualifiedName: entry.title,\n\t\t\t\tnames: place?.names,\n\t\t\t\tjurisdiction: place?.jurisdiction,\n\t\t\t};\n\t\t}) || []\n\t);\n}\n\n/**\n * Get detailed information about a place including standardized names and aliases\n *\n * @param sdk - FamilySearch SDK instance\n * @param id - The FamilySearch place ID\n * @returns Promise with detailed place information\n */\nexport async function getPlaceDetails(\n\tsdk: FamilySearchSDK,\n\tid: string\n): Promise<{\n\tid: string;\n\tname: string;\n\tstandardizedName?: string;\n\taliases: string[];\n\tlatitude?: number;\n\tlongitude?: number;\n\tjurisdiction?: string;\n} | null> {\n\tconst place = await getPlaceById(sdk, id);\n\n\tif (!place) {\n\t\treturn null;\n\t}\n\n\t// Extract primary name (first name entry or English name)\n\tconst primaryName =\n\t\tplace.names?.find((n) => n.lang === \"en\")?.value ||\n\t\tplace.names?.[0]?.value ||\n\t\t\"\";\n\n\t// Extract all alternative names as aliases\n\tconst aliases =\n\t\tplace.names\n\t\t\t?.filter((n) => n.value !== primaryName)\n\t\t\t.map((n) => n.value || \"\")\n\t\t\t.filter(Boolean) || [];\n\n\treturn {\n\t\tid: place.id || id,\n\t\tname: primaryName,\n\t\tstandardizedName: place.jurisdiction?.name,\n\t\taliases,\n\t\tlatitude: place.latitude,\n\t\tlongitude: place.longitude,\n\t\tjurisdiction: place.jurisdiction?.name,\n\t};\n}\n"]}
@@ -0,0 +1,191 @@
1
+ 'use strict';
2
+
3
+ // src/tree/pedigree.ts
4
+ async function fetchPedigree(sdk, personId, options = {}) {
5
+ const {
6
+ generations = 4,
7
+ onProgress,
8
+ includeDetails = true,
9
+ includeNotes = true,
10
+ includeRelationshipDetails = true
11
+ } = options;
12
+ let targetPersonId = personId;
13
+ if (!targetPersonId) {
14
+ onProgress?.({
15
+ stage: "getting_current_user",
16
+ current: 0,
17
+ total: 1,
18
+ percent: 0
19
+ });
20
+ const currentUser = await sdk.getCurrentUser();
21
+ targetPersonId = currentUser?.personId || currentUser?.treeUserId || currentUser?.id;
22
+ if (!targetPersonId) {
23
+ throw new Error("Could not determine person ID for current user");
24
+ }
25
+ }
26
+ onProgress?.({
27
+ stage: "fetching_ancestry_structure",
28
+ current: 1,
29
+ total: 3,
30
+ percent: 10
31
+ });
32
+ const ancestryResponse = await sdk.getAncestry(targetPersonId, generations);
33
+ const ancestry = ancestryResponse.data;
34
+ if (!ancestry.persons || ancestry.persons.length === 0) {
35
+ throw new Error("No persons found in ancestry");
36
+ }
37
+ onProgress?.({
38
+ stage: "fetching_person_details",
39
+ current: 0,
40
+ total: ancestry.persons.length,
41
+ percent: 20
42
+ });
43
+ const personsWithDetails = [];
44
+ for (let i = 0; i < ancestry.persons.length; i++) {
45
+ const person = ancestry.persons[i];
46
+ onProgress?.({
47
+ stage: "fetching_person_details",
48
+ current: i + 1,
49
+ total: ancestry.persons.length,
50
+ percent: 20 + Math.floor((i + 1) / ancestry.persons.length * 45)
51
+ });
52
+ try {
53
+ const enhanced = { ...person };
54
+ if (includeDetails) {
55
+ enhanced.fullDetails = await sdk.getPersonWithDetails(
56
+ person.id
57
+ );
58
+ }
59
+ if (includeNotes) {
60
+ enhanced.notes = await sdk.getPersonNotes(
61
+ person.id
62
+ );
63
+ }
64
+ personsWithDetails.push(enhanced);
65
+ } catch {
66
+ personsWithDetails.push(person);
67
+ }
68
+ }
69
+ onProgress?.({
70
+ stage: "fetching_relationship_details",
71
+ current: 0,
72
+ total: ancestry.relationships?.length || 0,
73
+ percent: 65
74
+ });
75
+ const relationshipsWithDetails = [];
76
+ if (ancestry.relationships && includeRelationshipDetails) {
77
+ for (let i = 0; i < ancestry.relationships.length; i++) {
78
+ const rel = ancestry.relationships[i];
79
+ onProgress?.({
80
+ stage: "fetching_relationship_details",
81
+ current: i + 1,
82
+ total: ancestry.relationships.length,
83
+ percent: 65 + Math.floor((i + 1) / ancestry.relationships.length * 25)
84
+ });
85
+ try {
86
+ if (rel.type?.includes?.("Couple")) {
87
+ const relDetails = await sdk.getCoupleRelationship(rel.id);
88
+ relationshipsWithDetails.push({
89
+ ...rel,
90
+ details: relDetails
91
+ });
92
+ } else {
93
+ relationshipsWithDetails.push(rel);
94
+ }
95
+ } catch {
96
+ relationshipsWithDetails.push(rel);
97
+ }
98
+ }
99
+ } else if (ancestry.relationships) {
100
+ relationshipsWithDetails.push(...ancestry.relationships);
101
+ }
102
+ onProgress?.({
103
+ stage: "extracting_additional_relationships",
104
+ current: 0,
105
+ total: 1,
106
+ percent: 90
107
+ });
108
+ const allRelationships = [...relationshipsWithDetails];
109
+ const relationshipIds = new Set(relationshipsWithDetails.map((r) => r.id));
110
+ personsWithDetails.forEach((person) => {
111
+ const childAndParentsRels = person.fullDetails?.childAndParentsRelationships;
112
+ if (childAndParentsRels && Array.isArray(childAndParentsRels)) {
113
+ childAndParentsRels.forEach((rel) => {
114
+ if (!relationshipIds.has(rel.id)) {
115
+ relationshipIds.add(rel.id);
116
+ allRelationships.push({
117
+ id: rel.id,
118
+ type: "http://gedcomx.org/ParentChild",
119
+ person1: rel.parent1,
120
+ person2: rel.child,
121
+ parent2: rel.parent2
122
+ });
123
+ }
124
+ });
125
+ }
126
+ const relationships = person.fullDetails?.relationships;
127
+ if (relationships && Array.isArray(relationships)) {
128
+ relationships.forEach((rel) => {
129
+ if (rel.type?.includes?.("Couple") && !relationshipIds.has(rel.id)) {
130
+ relationshipIds.add(rel.id);
131
+ allRelationships.push({
132
+ id: rel.id,
133
+ type: rel.type,
134
+ person1: rel.person1,
135
+ person2: rel.person2,
136
+ facts: rel.facts
137
+ });
138
+ }
139
+ });
140
+ }
141
+ });
142
+ onProgress?.({
143
+ stage: "completing_data_fetch",
144
+ current: 1,
145
+ total: 1,
146
+ percent: 98
147
+ });
148
+ return {
149
+ persons: personsWithDetails,
150
+ relationships: allRelationships,
151
+ environment: sdk.getEnvironment()
152
+ };
153
+ }
154
+ async function getCurrentUser(sdk) {
155
+ return sdk.getCurrentUser();
156
+ }
157
+ async function getPersonWithDetails(sdk, personId) {
158
+ try {
159
+ const [details, notes] = await Promise.all([
160
+ sdk.getPersonWithDetails(personId),
161
+ sdk.getPersonNotes(personId)
162
+ ]);
163
+ if (!details) {
164
+ return null;
165
+ }
166
+ const fullDetails = details;
167
+ const personData = fullDetails?.persons?.[0];
168
+ if (!personData) {
169
+ return null;
170
+ }
171
+ return {
172
+ ...personData,
173
+ fullDetails,
174
+ notes
175
+ };
176
+ } catch {
177
+ return null;
178
+ }
179
+ }
180
+ async function fetchMultiplePersons(sdk, personIds) {
181
+ const pids = personIds.join(",");
182
+ const response = await sdk.get(`/platform/tree/persons?pids=${pids}`);
183
+ return response.data;
184
+ }
185
+
186
+ exports.fetchMultiplePersons = fetchMultiplePersons;
187
+ exports.fetchPedigree = fetchPedigree;
188
+ exports.getCurrentUser = getCurrentUser;
189
+ exports.getPersonWithDetails = getPersonWithDetails;
190
+ //# sourceMappingURL=index.cjs.map
191
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tree/pedigree.ts"],"names":[],"mappings":";;;AAiCA,eAAsB,aAAA,CACrB,GAAA,EACA,QAAA,EACA,OAAA,GAMI,EAAC,EAC2B;AAChC,EAAA,MAAM;AAAA,IACL,WAAA,GAAc,CAAA;AAAA,IACd,UAAA;AAAA,IACA,cAAA,GAAiB,IAAA;AAAA,IACjB,YAAA,GAAe,IAAA;AAAA,IACf,0BAAA,GAA6B;AAAA,GAC9B,GAAI,OAAA;AAGJ,EAAA,IAAI,cAAA,GAAiB,QAAA;AACrB,EAAA,IAAI,CAAC,cAAA,EAAgB;AACpB,IAAA,UAAA,GAAa;AAAA,MACZ,KAAA,EAAO,sBAAA;AAAA,MACP,OAAA,EAAS,CAAA;AAAA,MACT,KAAA,EAAO,CAAA;AAAA,MACP,OAAA,EAAS;AAAA,KACT,CAAA;AAED,IAAA,MAAM,WAAA,GAAc,MAAM,GAAA,CAAI,cAAA,EAAe;AAC7C,IAAA,cAAA,GACC,WAAA,EAAa,QAAA,IACb,WAAA,EAAa,UAAA,IACb,WAAA,EAAa,EAAA;AAEd,IAAA,IAAI,CAAC,cAAA,EAAgB;AACpB,MAAA,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAAA,IACjE;AAAA,EACD;AAGA,EAAA,UAAA,GAAa;AAAA,IACZ,KAAA,EAAO,6BAAA;AAAA,IACP,OAAA,EAAS,CAAA;AAAA,IACT,KAAA,EAAO,CAAA;AAAA,IACP,OAAA,EAAS;AAAA,GACT,CAAA;AAED,EAAA,MAAM,gBAAA,GAAmB,MAAM,GAAA,CAAI,WAAA,CAAY,gBAAgB,WAAW,CAAA;AAC1E,EAAA,MAAM,WAAW,gBAAA,CAAiB,IAAA;AAElC,EAAA,IAAI,CAAC,QAAA,CAAS,OAAA,IAAW,QAAA,CAAS,OAAA,CAAQ,WAAW,CAAA,EAAG;AACvD,IAAA,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAAA,EAC/C;AAGA,EAAA,UAAA,GAAa;AAAA,IACZ,KAAA,EAAO,yBAAA;AAAA,IACP,OAAA,EAAS,CAAA;AAAA,IACT,KAAA,EAAO,SAAS,OAAA,CAAQ,MAAA;AAAA,IACxB,OAAA,EAAS;AAAA,GACT,CAAA;AAED,EAAA,MAAM,qBAAuC,EAAC;AAC9C,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,OAAA,CAAQ,QAAQ,CAAA,EAAA,EAAK;AACjD,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAA;AAEjC,IAAA,UAAA,GAAa;AAAA,MACZ,KAAA,EAAO,yBAAA;AAAA,MACP,SAAS,CAAA,GAAI,CAAA;AAAA,MACb,KAAA,EAAO,SAAS,OAAA,CAAQ,MAAA;AAAA,MACxB,OAAA,EAAS,KAAK,IAAA,CAAK,KAAA,CAAA,CAAQ,IAAI,CAAA,IAAK,QAAA,CAAS,OAAA,CAAQ,MAAA,GAAU,EAAE;AAAA,KACjE,CAAA;AAED,IAAA,IAAI;AACH,MAAA,MAAM,QAAA,GAA2B,EAAE,GAAG,MAAA,EAAO;AAG7C,MAAA,IAAI,cAAA,EAAgB;AACnB,QAAA,QAAA,CAAS,WAAA,GAAe,MAAM,GAAA,CAAI,oBAAA;AAAA,UACjC,MAAA,CAAO;AAAA,SACR;AAAA,MACD;AAGA,MAAA,IAAI,YAAA,EAAc;AACjB,QAAA,QAAA,CAAS,KAAA,GAAS,MAAM,GAAA,CAAI,cAAA;AAAA,UAC3B,MAAA,CAAO;AAAA,SACR;AAAA,MACD;AAEA,MAAA,kBAAA,CAAmB,KAAK,QAAQ,CAAA;AAAA,IACjC,CAAA,CAAA,MAAQ;AAEP,MAAA,kBAAA,CAAmB,KAAK,MAAwB,CAAA;AAAA,IACjD;AAAA,EACD;AAGA,EAAA,UAAA,GAAa;AAAA,IACZ,KAAA,EAAO,+BAAA;AAAA,IACP,OAAA,EAAS,CAAA;AAAA,IACT,KAAA,EAAO,QAAA,CAAS,aAAA,EAAe,MAAA,IAAU,CAAA;AAAA,IACzC,OAAA,EAAS;AAAA,GACT,CAAA;AAED,EAAA,MAAM,2BAA2C,EAAC;AAClD,EAAA,IAAI,QAAA,CAAS,iBAAiB,0BAAA,EAA4B;AACzD,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA,EAAA,EAAK;AACvD,MAAA,MAAM,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,CAAC,CAAA;AAEpC,MAAA,UAAA,GAAa;AAAA,QACZ,KAAA,EAAO,+BAAA;AAAA,QACP,SAAS,CAAA,GAAI,CAAA;AAAA,QACb,KAAA,EAAO,SAAS,aAAA,CAAc,MAAA;AAAA,QAC9B,OAAA,EACC,KACA,IAAA,CAAK,KAAA,CAAA,CAAQ,IAAI,CAAA,IAAK,QAAA,CAAS,aAAA,CAAc,MAAA,GAAU,EAAE;AAAA,OAC1D,CAAA;AAED,MAAA,IAAI;AAEH,QAAA,IAAI,GAAA,CAAI,IAAA,EAAM,QAAA,GAAW,QAAQ,CAAA,EAAG;AACnC,UAAA,MAAM,UAAA,GAAa,MAAM,GAAA,CAAI,qBAAA,CAAsB,IAAI,EAAE,CAAA;AACzD,UAAA,wBAAA,CAAyB,IAAA,CAAK;AAAA,YAC7B,GAAG,GAAA;AAAA,YACH,OAAA,EAAS;AAAA,WACT,CAAA;AAAA,QACF,CAAA,MAAO;AACN,UAAA,wBAAA,CAAyB,KAAK,GAAG,CAAA;AAAA,QAClC;AAAA,MACD,CAAA,CAAA,MAAQ;AACP,QAAA,wBAAA,CAAyB,KAAK,GAAG,CAAA;AAAA,MAClC;AAAA,IACD;AAAA,EACD,CAAA,MAAA,IAAW,SAAS,aAAA,EAAe;AAClC,IAAA,wBAAA,CAAyB,IAAA,CAAK,GAAG,QAAA,CAAS,aAAa,CAAA;AAAA,EACxD;AAGA,EAAA,UAAA,GAAa;AAAA,IACZ,KAAA,EAAO,qCAAA;AAAA,IACP,OAAA,EAAS,CAAA;AAAA,IACT,KAAA,EAAO,CAAA;AAAA,IACP,OAAA,EAAS;AAAA,GACT,CAAA;AAED,EAAA,MAAM,gBAAA,GAAmB,CAAC,GAAG,wBAAwB,CAAA;AACrD,EAAA,MAAM,eAAA,GAAkB,IAAI,GAAA,CAAI,wBAAA,CAAyB,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,EAAE,CAAC,CAAA;AAEzE,EAAA,kBAAA,CAAmB,OAAA,CAAQ,CAAC,MAAA,KAAW;AAEtC,IAAA,MAAM,mBAAA,GACL,OAAO,WAAA,EAAa,4BAAA;AACrB,IAAA,IAAI,mBAAA,IAAuB,KAAA,CAAM,OAAA,CAAQ,mBAAmB,CAAA,EAAG;AAC9D,MAAA,mBAAA,CAAoB,OAAA,CAAQ,CAAC,GAAA,KAAQ;AACpC,QAAA,IAAI,CAAC,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG;AACjC,UAAA,eAAA,CAAgB,GAAA,CAAI,IAAI,EAAE,CAAA;AAC1B,UAAA,gBAAA,CAAiB,IAAA,CAAK;AAAA,YACrB,IAAI,GAAA,CAAI,EAAA;AAAA,YACR,IAAA,EAAM,gCAAA;AAAA,YACN,SAAS,GAAA,CAAI,OAAA;AAAA,YACb,SAAS,GAAA,CAAI,KAAA;AAAA,YACb,SAAS,GAAA,CAAI;AAAA,WACb,CAAA;AAAA,QACF;AAAA,MACD,CAAC,CAAA;AAAA,IACF;AAGA,IAAA,MAAM,aAAA,GAAgB,OAAO,WAAA,EAAa,aAAA;AAC1C,IAAA,IAAI,aAAA,IAAiB,KAAA,CAAM,OAAA,CAAQ,aAAa,CAAA,EAAG;AAClD,MAAA,aAAA,CAAc,OAAA,CAAQ,CAAC,GAAA,KAAQ;AAC9B,QAAA,IAAI,GAAA,CAAI,IAAA,EAAM,QAAA,GAAW,QAAQ,CAAA,IAAK,CAAC,eAAA,CAAgB,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG;AACnE,UAAA,eAAA,CAAgB,GAAA,CAAI,IAAI,EAAE,CAAA;AAC1B,UAAA,gBAAA,CAAiB,IAAA,CAAK;AAAA,YACrB,IAAI,GAAA,CAAI,EAAA;AAAA,YACR,MAAM,GAAA,CAAI,IAAA;AAAA,YACV,SAAS,GAAA,CAAI,OAAA;AAAA,YACb,SAAS,GAAA,CAAI,OAAA;AAAA,YACb,OAAO,GAAA,CAAI;AAAA,WACX,CAAA;AAAA,QACF;AAAA,MACD,CAAC,CAAA;AAAA,IACF;AAAA,EACD,CAAC,CAAA;AAED,EAAA,UAAA,GAAa;AAAA,IACZ,KAAA,EAAO,uBAAA;AAAA,IACP,OAAA,EAAS,CAAA;AAAA,IACT,KAAA,EAAO,CAAA;AAAA,IACP,OAAA,EAAS;AAAA,GACT,CAAA;AAED,EAAA,OAAO;AAAA,IACN,OAAA,EAAS,kBAAA;AAAA,IACT,aAAA,EAAe,gBAAA;AAAA,IACf,WAAA,EAAa,IAAI,cAAA;AAAe,GACjC;AACD;AAKA,eAAsB,eACrB,GAAA,EACmC;AACnC,EAAA,OAAO,IAAI,cAAA,EAAe;AAC3B;AAKA,eAAsB,oBAAA,CACrB,KACA,QAAA,EACiC;AACjC,EAAA,IAAI;AACH,IAAA,MAAM,CAAC,OAAA,EAAS,KAAK,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MAC1C,GAAA,CAAI,qBAAqB,QAAQ,CAAA;AAAA,MACjC,GAAA,CAAI,eAAe,QAAQ;AAAA,KAC3B,CAAA;AAED,IAAA,IAAI,CAAC,OAAA,EAAS;AACb,MAAA,OAAO,IAAA;AAAA,IACR;AAGA,IAAA,MAAM,WAAA,GAAc,OAAA;AACpB,IAAA,MAAM,UAAA,GAAa,WAAA,EAAa,OAAA,GAAU,CAAC,CAAA;AAE3C,IAAA,IAAI,CAAC,UAAA,EAAY;AAChB,MAAA,OAAO,IAAA;AAAA,IACR;AAEA,IAAA,OAAO;AAAA,MACN,GAAG,UAAA;AAAA,MACH,WAAA;AAAA,MACA;AAAA,KACD;AAAA,EACD,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,IAAA;AAAA,EACR;AACD;AAKA,eAAsB,oBAAA,CACrB,KACA,SAAA,EACmB;AACnB,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,IAAA,CAAK,GAAG,CAAA;AAC/B,EAAA,MAAM,WAAW,MAAM,GAAA,CAAI,GAAA,CAAI,CAAA,4BAAA,EAA+B,IAAI,CAAA,CAAE,CAAA;AACpE,EAAA,OAAO,QAAA,CAAS,IAAA;AACjB","file":"index.cjs","sourcesContent":["/**\n * FamilySearch Tree/Pedigree API Module\n *\n * Provides helpers for fetching and managing family tree data\n * including pedigree, ancestry, and relationship information.\n */\n\nimport type { FamilySearchSDK } from \"../client\";\nimport type {\n\tEnhancedPedigreeData,\n\tEnhancedPerson,\n\tFamilySearchUser,\n\tPedigreeData,\n\tProgressCallback,\n\tRelationship,\n} from \"../types\";\n\n/**\n * Fetch pedigree/ancestry data with enhanced details\n *\n * @param sdk - FamilySearch SDK instance\n * @param personId - Optional person ID to start from. If not provided, uses current user.\n * @param options - Fetch options\n * @returns Promise with enhanced pedigree data\n *\n * @example\n * ```typescript\n * const pedigree = await fetchPedigree(sdk, \"XXXX-YYY\", {\n * generations: 5,\n * onProgress: (p) => console.log(`${p.percent}% complete`)\n * });\n * ```\n */\nexport async function fetchPedigree(\n\tsdk: FamilySearchSDK,\n\tpersonId?: string,\n\toptions: {\n\t\tgenerations?: number;\n\t\tonProgress?: ProgressCallback;\n\t\tincludeDetails?: boolean;\n\t\tincludeNotes?: boolean;\n\t\tincludeRelationshipDetails?: boolean;\n\t} = {}\n): Promise<EnhancedPedigreeData> {\n\tconst {\n\t\tgenerations = 4,\n\t\tonProgress,\n\t\tincludeDetails = true,\n\t\tincludeNotes = true,\n\t\tincludeRelationshipDetails = true,\n\t} = options;\n\n\t// Get current user's person ID if not provided\n\tlet targetPersonId = personId;\n\tif (!targetPersonId) {\n\t\tonProgress?.({\n\t\t\tstage: \"getting_current_user\",\n\t\t\tcurrent: 0,\n\t\t\ttotal: 1,\n\t\t\tpercent: 0,\n\t\t});\n\n\t\tconst currentUser = await sdk.getCurrentUser();\n\t\ttargetPersonId =\n\t\t\tcurrentUser?.personId ||\n\t\t\tcurrentUser?.treeUserId ||\n\t\t\tcurrentUser?.id;\n\n\t\tif (!targetPersonId) {\n\t\t\tthrow new Error(\"Could not determine person ID for current user\");\n\t\t}\n\t}\n\n\t// Step 1: Fetch ancestry structure\n\tonProgress?.({\n\t\tstage: \"fetching_ancestry_structure\",\n\t\tcurrent: 1,\n\t\ttotal: 3,\n\t\tpercent: 10,\n\t});\n\n\tconst ancestryResponse = await sdk.getAncestry(targetPersonId, generations);\n\tconst ancestry = ancestryResponse.data as PedigreeData;\n\n\tif (!ancestry.persons || ancestry.persons.length === 0) {\n\t\tthrow new Error(\"No persons found in ancestry\");\n\t}\n\n\t// Step 2: Enhance each person with detailed data\n\tonProgress?.({\n\t\tstage: \"fetching_person_details\",\n\t\tcurrent: 0,\n\t\ttotal: ancestry.persons.length,\n\t\tpercent: 20,\n\t});\n\n\tconst personsWithDetails: EnhancedPerson[] = [];\n\tfor (let i = 0; i < ancestry.persons.length; i++) {\n\t\tconst person = ancestry.persons[i];\n\n\t\tonProgress?.({\n\t\t\tstage: \"fetching_person_details\",\n\t\t\tcurrent: i + 1,\n\t\t\ttotal: ancestry.persons.length,\n\t\t\tpercent: 20 + Math.floor(((i + 1) / ancestry.persons.length) * 45),\n\t\t});\n\n\t\ttry {\n\t\t\tconst enhanced: EnhancedPerson = { ...person };\n\n\t\t\t// Fetch full person details with sources\n\t\t\tif (includeDetails) {\n\t\t\t\tenhanced.fullDetails = (await sdk.getPersonWithDetails(\n\t\t\t\t\tperson.id\n\t\t\t\t)) as EnhancedPerson[\"fullDetails\"];\n\t\t\t}\n\n\t\t\t// Fetch notes\n\t\t\tif (includeNotes) {\n\t\t\t\tenhanced.notes = (await sdk.getPersonNotes(\n\t\t\t\t\tperson.id\n\t\t\t\t)) as EnhancedPerson[\"notes\"];\n\t\t\t}\n\n\t\t\tpersonsWithDetails.push(enhanced);\n\t\t} catch {\n\t\t\t// Fallback to basic person data\n\t\t\tpersonsWithDetails.push(person as EnhancedPerson);\n\t\t}\n\t}\n\n\t// Step 3: Enhance couple relationships with marriage details\n\tonProgress?.({\n\t\tstage: \"fetching_relationship_details\",\n\t\tcurrent: 0,\n\t\ttotal: ancestry.relationships?.length || 0,\n\t\tpercent: 65,\n\t});\n\n\tconst relationshipsWithDetails: Relationship[] = [];\n\tif (ancestry.relationships && includeRelationshipDetails) {\n\t\tfor (let i = 0; i < ancestry.relationships.length; i++) {\n\t\t\tconst rel = ancestry.relationships[i];\n\n\t\t\tonProgress?.({\n\t\t\t\tstage: \"fetching_relationship_details\",\n\t\t\t\tcurrent: i + 1,\n\t\t\t\ttotal: ancestry.relationships.length,\n\t\t\t\tpercent:\n\t\t\t\t\t65 +\n\t\t\t\t\tMath.floor(((i + 1) / ancestry.relationships.length) * 25),\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\t// Only fetch details for couple relationships\n\t\t\t\tif (rel.type?.includes?.(\"Couple\")) {\n\t\t\t\t\tconst relDetails = await sdk.getCoupleRelationship(rel.id);\n\t\t\t\t\trelationshipsWithDetails.push({\n\t\t\t\t\t\t...rel,\n\t\t\t\t\t\tdetails: relDetails as Relationship[\"details\"],\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\trelationshipsWithDetails.push(rel);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\trelationshipsWithDetails.push(rel);\n\t\t\t}\n\t\t}\n\t} else if (ancestry.relationships) {\n\t\trelationshipsWithDetails.push(...ancestry.relationships);\n\t}\n\n\t// Step 4: Extract additional relationships from person details\n\tonProgress?.({\n\t\tstage: \"extracting_additional_relationships\",\n\t\tcurrent: 0,\n\t\ttotal: 1,\n\t\tpercent: 90,\n\t});\n\n\tconst allRelationships = [...relationshipsWithDetails];\n\tconst relationshipIds = new Set(relationshipsWithDetails.map((r) => r.id));\n\n\tpersonsWithDetails.forEach((person) => {\n\t\t// Extract child-parent relationships from person details\n\t\tconst childAndParentsRels =\n\t\t\tperson.fullDetails?.childAndParentsRelationships;\n\t\tif (childAndParentsRels && Array.isArray(childAndParentsRels)) {\n\t\t\tchildAndParentsRels.forEach((rel) => {\n\t\t\t\tif (!relationshipIds.has(rel.id)) {\n\t\t\t\t\trelationshipIds.add(rel.id);\n\t\t\t\t\tallRelationships.push({\n\t\t\t\t\t\tid: rel.id,\n\t\t\t\t\t\ttype: \"http://gedcomx.org/ParentChild\",\n\t\t\t\t\t\tperson1: rel.parent1,\n\t\t\t\t\t\tperson2: rel.child,\n\t\t\t\t\t\tparent2: rel.parent2,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Extract couple relationships from person details\n\t\tconst relationships = person.fullDetails?.relationships;\n\t\tif (relationships && Array.isArray(relationships)) {\n\t\t\trelationships.forEach((rel) => {\n\t\t\t\tif (rel.type?.includes?.(\"Couple\") && !relationshipIds.has(rel.id)) {\n\t\t\t\t\trelationshipIds.add(rel.id);\n\t\t\t\t\tallRelationships.push({\n\t\t\t\t\t\tid: rel.id,\n\t\t\t\t\t\ttype: rel.type,\n\t\t\t\t\t\tperson1: rel.person1,\n\t\t\t\t\t\tperson2: rel.person2,\n\t\t\t\t\t\tfacts: rel.facts,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t});\n\n\tonProgress?.({\n\t\tstage: \"completing_data_fetch\",\n\t\tcurrent: 1,\n\t\ttotal: 1,\n\t\tpercent: 98,\n\t});\n\n\treturn {\n\t\tpersons: personsWithDetails,\n\t\trelationships: allRelationships,\n\t\tenvironment: sdk.getEnvironment(),\n\t};\n}\n\n/**\n * Get current user information\n */\nexport async function getCurrentUser(\n\tsdk: FamilySearchSDK\n): Promise<FamilySearchUser | null> {\n\treturn sdk.getCurrentUser();\n}\n\n/**\n * Get person by ID with full details\n */\nexport async function getPersonWithDetails(\n\tsdk: FamilySearchSDK,\n\tpersonId: string\n): Promise<EnhancedPerson | null> {\n\ttry {\n\t\tconst [details, notes] = await Promise.all([\n\t\t\tsdk.getPersonWithDetails(personId),\n\t\t\tsdk.getPersonNotes(personId),\n\t\t]);\n\n\t\tif (!details) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// The details response contains the person data in persons array\n\t\tconst fullDetails = details as EnhancedPerson[\"fullDetails\"];\n\t\tconst personData = fullDetails?.persons?.[0];\n\n\t\tif (!personData) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\t...personData,\n\t\t\tfullDetails: fullDetails,\n\t\t\tnotes: notes as EnhancedPerson[\"notes\"],\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Fetch multiple persons at once\n */\nexport async function fetchMultiplePersons(\n\tsdk: FamilySearchSDK,\n\tpersonIds: string[]\n): Promise<unknown> {\n\tconst pids = personIds.join(\",\");\n\tconst response = await sdk.get(`/platform/tree/persons?pids=${pids}`);\n\treturn response.data;\n}\n"]}
@@ -0,0 +1,47 @@
1
+ import { F as FamilySearchSDK } from '../client-ohjqX4t5.cjs';
2
+ import { v as ProgressCallback, r as EnhancedPedigreeData, d as FamilySearchUser, q as EnhancedPerson } from '../index-D6H-lvis.cjs';
3
+
4
+ /**
5
+ * FamilySearch Tree/Pedigree API Module
6
+ *
7
+ * Provides helpers for fetching and managing family tree data
8
+ * including pedigree, ancestry, and relationship information.
9
+ */
10
+
11
+ /**
12
+ * Fetch pedigree/ancestry data with enhanced details
13
+ *
14
+ * @param sdk - FamilySearch SDK instance
15
+ * @param personId - Optional person ID to start from. If not provided, uses current user.
16
+ * @param options - Fetch options
17
+ * @returns Promise with enhanced pedigree data
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const pedigree = await fetchPedigree(sdk, "XXXX-YYY", {
22
+ * generations: 5,
23
+ * onProgress: (p) => console.log(`${p.percent}% complete`)
24
+ * });
25
+ * ```
26
+ */
27
+ declare function fetchPedigree(sdk: FamilySearchSDK, personId?: string, options?: {
28
+ generations?: number;
29
+ onProgress?: ProgressCallback;
30
+ includeDetails?: boolean;
31
+ includeNotes?: boolean;
32
+ includeRelationshipDetails?: boolean;
33
+ }): Promise<EnhancedPedigreeData>;
34
+ /**
35
+ * Get current user information
36
+ */
37
+ declare function getCurrentUser(sdk: FamilySearchSDK): Promise<FamilySearchUser | null>;
38
+ /**
39
+ * Get person by ID with full details
40
+ */
41
+ declare function getPersonWithDetails(sdk: FamilySearchSDK, personId: string): Promise<EnhancedPerson | null>;
42
+ /**
43
+ * Fetch multiple persons at once
44
+ */
45
+ declare function fetchMultiplePersons(sdk: FamilySearchSDK, personIds: string[]): Promise<unknown>;
46
+
47
+ export { fetchMultiplePersons, fetchPedigree, getCurrentUser, getPersonWithDetails };
@@ -0,0 +1,47 @@
1
+ import { F as FamilySearchSDK } from '../client-DIpYSHtx.js';
2
+ import { v as ProgressCallback, r as EnhancedPedigreeData, d as FamilySearchUser, q as EnhancedPerson } from '../index-D6H-lvis.js';
3
+
4
+ /**
5
+ * FamilySearch Tree/Pedigree API Module
6
+ *
7
+ * Provides helpers for fetching and managing family tree data
8
+ * including pedigree, ancestry, and relationship information.
9
+ */
10
+
11
+ /**
12
+ * Fetch pedigree/ancestry data with enhanced details
13
+ *
14
+ * @param sdk - FamilySearch SDK instance
15
+ * @param personId - Optional person ID to start from. If not provided, uses current user.
16
+ * @param options - Fetch options
17
+ * @returns Promise with enhanced pedigree data
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const pedigree = await fetchPedigree(sdk, "XXXX-YYY", {
22
+ * generations: 5,
23
+ * onProgress: (p) => console.log(`${p.percent}% complete`)
24
+ * });
25
+ * ```
26
+ */
27
+ declare function fetchPedigree(sdk: FamilySearchSDK, personId?: string, options?: {
28
+ generations?: number;
29
+ onProgress?: ProgressCallback;
30
+ includeDetails?: boolean;
31
+ includeNotes?: boolean;
32
+ includeRelationshipDetails?: boolean;
33
+ }): Promise<EnhancedPedigreeData>;
34
+ /**
35
+ * Get current user information
36
+ */
37
+ declare function getCurrentUser(sdk: FamilySearchSDK): Promise<FamilySearchUser | null>;
38
+ /**
39
+ * Get person by ID with full details
40
+ */
41
+ declare function getPersonWithDetails(sdk: FamilySearchSDK, personId: string): Promise<EnhancedPerson | null>;
42
+ /**
43
+ * Fetch multiple persons at once
44
+ */
45
+ declare function fetchMultiplePersons(sdk: FamilySearchSDK, personIds: string[]): Promise<unknown>;
46
+
47
+ export { fetchMultiplePersons, fetchPedigree, getCurrentUser, getPersonWithDetails };
@@ -0,0 +1,186 @@
1
+ // src/tree/pedigree.ts
2
+ async function fetchPedigree(sdk, personId, options = {}) {
3
+ const {
4
+ generations = 4,
5
+ onProgress,
6
+ includeDetails = true,
7
+ includeNotes = true,
8
+ includeRelationshipDetails = true
9
+ } = options;
10
+ let targetPersonId = personId;
11
+ if (!targetPersonId) {
12
+ onProgress?.({
13
+ stage: "getting_current_user",
14
+ current: 0,
15
+ total: 1,
16
+ percent: 0
17
+ });
18
+ const currentUser = await sdk.getCurrentUser();
19
+ targetPersonId = currentUser?.personId || currentUser?.treeUserId || currentUser?.id;
20
+ if (!targetPersonId) {
21
+ throw new Error("Could not determine person ID for current user");
22
+ }
23
+ }
24
+ onProgress?.({
25
+ stage: "fetching_ancestry_structure",
26
+ current: 1,
27
+ total: 3,
28
+ percent: 10
29
+ });
30
+ const ancestryResponse = await sdk.getAncestry(targetPersonId, generations);
31
+ const ancestry = ancestryResponse.data;
32
+ if (!ancestry.persons || ancestry.persons.length === 0) {
33
+ throw new Error("No persons found in ancestry");
34
+ }
35
+ onProgress?.({
36
+ stage: "fetching_person_details",
37
+ current: 0,
38
+ total: ancestry.persons.length,
39
+ percent: 20
40
+ });
41
+ const personsWithDetails = [];
42
+ for (let i = 0; i < ancestry.persons.length; i++) {
43
+ const person = ancestry.persons[i];
44
+ onProgress?.({
45
+ stage: "fetching_person_details",
46
+ current: i + 1,
47
+ total: ancestry.persons.length,
48
+ percent: 20 + Math.floor((i + 1) / ancestry.persons.length * 45)
49
+ });
50
+ try {
51
+ const enhanced = { ...person };
52
+ if (includeDetails) {
53
+ enhanced.fullDetails = await sdk.getPersonWithDetails(
54
+ person.id
55
+ );
56
+ }
57
+ if (includeNotes) {
58
+ enhanced.notes = await sdk.getPersonNotes(
59
+ person.id
60
+ );
61
+ }
62
+ personsWithDetails.push(enhanced);
63
+ } catch {
64
+ personsWithDetails.push(person);
65
+ }
66
+ }
67
+ onProgress?.({
68
+ stage: "fetching_relationship_details",
69
+ current: 0,
70
+ total: ancestry.relationships?.length || 0,
71
+ percent: 65
72
+ });
73
+ const relationshipsWithDetails = [];
74
+ if (ancestry.relationships && includeRelationshipDetails) {
75
+ for (let i = 0; i < ancestry.relationships.length; i++) {
76
+ const rel = ancestry.relationships[i];
77
+ onProgress?.({
78
+ stage: "fetching_relationship_details",
79
+ current: i + 1,
80
+ total: ancestry.relationships.length,
81
+ percent: 65 + Math.floor((i + 1) / ancestry.relationships.length * 25)
82
+ });
83
+ try {
84
+ if (rel.type?.includes?.("Couple")) {
85
+ const relDetails = await sdk.getCoupleRelationship(rel.id);
86
+ relationshipsWithDetails.push({
87
+ ...rel,
88
+ details: relDetails
89
+ });
90
+ } else {
91
+ relationshipsWithDetails.push(rel);
92
+ }
93
+ } catch {
94
+ relationshipsWithDetails.push(rel);
95
+ }
96
+ }
97
+ } else if (ancestry.relationships) {
98
+ relationshipsWithDetails.push(...ancestry.relationships);
99
+ }
100
+ onProgress?.({
101
+ stage: "extracting_additional_relationships",
102
+ current: 0,
103
+ total: 1,
104
+ percent: 90
105
+ });
106
+ const allRelationships = [...relationshipsWithDetails];
107
+ const relationshipIds = new Set(relationshipsWithDetails.map((r) => r.id));
108
+ personsWithDetails.forEach((person) => {
109
+ const childAndParentsRels = person.fullDetails?.childAndParentsRelationships;
110
+ if (childAndParentsRels && Array.isArray(childAndParentsRels)) {
111
+ childAndParentsRels.forEach((rel) => {
112
+ if (!relationshipIds.has(rel.id)) {
113
+ relationshipIds.add(rel.id);
114
+ allRelationships.push({
115
+ id: rel.id,
116
+ type: "http://gedcomx.org/ParentChild",
117
+ person1: rel.parent1,
118
+ person2: rel.child,
119
+ parent2: rel.parent2
120
+ });
121
+ }
122
+ });
123
+ }
124
+ const relationships = person.fullDetails?.relationships;
125
+ if (relationships && Array.isArray(relationships)) {
126
+ relationships.forEach((rel) => {
127
+ if (rel.type?.includes?.("Couple") && !relationshipIds.has(rel.id)) {
128
+ relationshipIds.add(rel.id);
129
+ allRelationships.push({
130
+ id: rel.id,
131
+ type: rel.type,
132
+ person1: rel.person1,
133
+ person2: rel.person2,
134
+ facts: rel.facts
135
+ });
136
+ }
137
+ });
138
+ }
139
+ });
140
+ onProgress?.({
141
+ stage: "completing_data_fetch",
142
+ current: 1,
143
+ total: 1,
144
+ percent: 98
145
+ });
146
+ return {
147
+ persons: personsWithDetails,
148
+ relationships: allRelationships,
149
+ environment: sdk.getEnvironment()
150
+ };
151
+ }
152
+ async function getCurrentUser(sdk) {
153
+ return sdk.getCurrentUser();
154
+ }
155
+ async function getPersonWithDetails(sdk, personId) {
156
+ try {
157
+ const [details, notes] = await Promise.all([
158
+ sdk.getPersonWithDetails(personId),
159
+ sdk.getPersonNotes(personId)
160
+ ]);
161
+ if (!details) {
162
+ return null;
163
+ }
164
+ const fullDetails = details;
165
+ const personData = fullDetails?.persons?.[0];
166
+ if (!personData) {
167
+ return null;
168
+ }
169
+ return {
170
+ ...personData,
171
+ fullDetails,
172
+ notes
173
+ };
174
+ } catch {
175
+ return null;
176
+ }
177
+ }
178
+ async function fetchMultiplePersons(sdk, personIds) {
179
+ const pids = personIds.join(",");
180
+ const response = await sdk.get(`/platform/tree/persons?pids=${pids}`);
181
+ return response.data;
182
+ }
183
+
184
+ export { fetchMultiplePersons, fetchPedigree, getCurrentUser, getPersonWithDetails };
185
+ //# sourceMappingURL=index.js.map
186
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tree/pedigree.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * FamilySearch Tree/Pedigree API Module\n *\n * Provides helpers for fetching and managing family tree data\n * including pedigree, ancestry, and relationship information.\n */\n\nimport type { FamilySearchSDK } from \"../client\";\nimport type {\n\tEnhancedPedigreeData,\n\tEnhancedPerson,\n\tFamilySearchUser,\n\tPedigreeData,\n\tProgressCallback,\n\tRelationship,\n} from \"../types\";\n\n/**\n * Fetch pedigree/ancestry data with enhanced details\n *\n * @param sdk - FamilySearch SDK instance\n * @param personId - Optional person ID to start from. If not provided, uses current user.\n * @param options - Fetch options\n * @returns Promise with enhanced pedigree data\n *\n * @example\n * ```typescript\n * const pedigree = await fetchPedigree(sdk, \"XXXX-YYY\", {\n * generations: 5,\n * onProgress: (p) => console.log(`${p.percent}% complete`)\n * });\n * ```\n */\nexport async function fetchPedigree(\n\tsdk: FamilySearchSDK,\n\tpersonId?: string,\n\toptions: {\n\t\tgenerations?: number;\n\t\tonProgress?: ProgressCallback;\n\t\tincludeDetails?: boolean;\n\t\tincludeNotes?: boolean;\n\t\tincludeRelationshipDetails?: boolean;\n\t} = {}\n): Promise<EnhancedPedigreeData> {\n\tconst {\n\t\tgenerations = 4,\n\t\tonProgress,\n\t\tincludeDetails = true,\n\t\tincludeNotes = true,\n\t\tincludeRelationshipDetails = true,\n\t} = options;\n\n\t// Get current user's person ID if not provided\n\tlet targetPersonId = personId;\n\tif (!targetPersonId) {\n\t\tonProgress?.({\n\t\t\tstage: \"getting_current_user\",\n\t\t\tcurrent: 0,\n\t\t\ttotal: 1,\n\t\t\tpercent: 0,\n\t\t});\n\n\t\tconst currentUser = await sdk.getCurrentUser();\n\t\ttargetPersonId =\n\t\t\tcurrentUser?.personId ||\n\t\t\tcurrentUser?.treeUserId ||\n\t\t\tcurrentUser?.id;\n\n\t\tif (!targetPersonId) {\n\t\t\tthrow new Error(\"Could not determine person ID for current user\");\n\t\t}\n\t}\n\n\t// Step 1: Fetch ancestry structure\n\tonProgress?.({\n\t\tstage: \"fetching_ancestry_structure\",\n\t\tcurrent: 1,\n\t\ttotal: 3,\n\t\tpercent: 10,\n\t});\n\n\tconst ancestryResponse = await sdk.getAncestry(targetPersonId, generations);\n\tconst ancestry = ancestryResponse.data as PedigreeData;\n\n\tif (!ancestry.persons || ancestry.persons.length === 0) {\n\t\tthrow new Error(\"No persons found in ancestry\");\n\t}\n\n\t// Step 2: Enhance each person with detailed data\n\tonProgress?.({\n\t\tstage: \"fetching_person_details\",\n\t\tcurrent: 0,\n\t\ttotal: ancestry.persons.length,\n\t\tpercent: 20,\n\t});\n\n\tconst personsWithDetails: EnhancedPerson[] = [];\n\tfor (let i = 0; i < ancestry.persons.length; i++) {\n\t\tconst person = ancestry.persons[i];\n\n\t\tonProgress?.({\n\t\t\tstage: \"fetching_person_details\",\n\t\t\tcurrent: i + 1,\n\t\t\ttotal: ancestry.persons.length,\n\t\t\tpercent: 20 + Math.floor(((i + 1) / ancestry.persons.length) * 45),\n\t\t});\n\n\t\ttry {\n\t\t\tconst enhanced: EnhancedPerson = { ...person };\n\n\t\t\t// Fetch full person details with sources\n\t\t\tif (includeDetails) {\n\t\t\t\tenhanced.fullDetails = (await sdk.getPersonWithDetails(\n\t\t\t\t\tperson.id\n\t\t\t\t)) as EnhancedPerson[\"fullDetails\"];\n\t\t\t}\n\n\t\t\t// Fetch notes\n\t\t\tif (includeNotes) {\n\t\t\t\tenhanced.notes = (await sdk.getPersonNotes(\n\t\t\t\t\tperson.id\n\t\t\t\t)) as EnhancedPerson[\"notes\"];\n\t\t\t}\n\n\t\t\tpersonsWithDetails.push(enhanced);\n\t\t} catch {\n\t\t\t// Fallback to basic person data\n\t\t\tpersonsWithDetails.push(person as EnhancedPerson);\n\t\t}\n\t}\n\n\t// Step 3: Enhance couple relationships with marriage details\n\tonProgress?.({\n\t\tstage: \"fetching_relationship_details\",\n\t\tcurrent: 0,\n\t\ttotal: ancestry.relationships?.length || 0,\n\t\tpercent: 65,\n\t});\n\n\tconst relationshipsWithDetails: Relationship[] = [];\n\tif (ancestry.relationships && includeRelationshipDetails) {\n\t\tfor (let i = 0; i < ancestry.relationships.length; i++) {\n\t\t\tconst rel = ancestry.relationships[i];\n\n\t\t\tonProgress?.({\n\t\t\t\tstage: \"fetching_relationship_details\",\n\t\t\t\tcurrent: i + 1,\n\t\t\t\ttotal: ancestry.relationships.length,\n\t\t\t\tpercent:\n\t\t\t\t\t65 +\n\t\t\t\t\tMath.floor(((i + 1) / ancestry.relationships.length) * 25),\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\t// Only fetch details for couple relationships\n\t\t\t\tif (rel.type?.includes?.(\"Couple\")) {\n\t\t\t\t\tconst relDetails = await sdk.getCoupleRelationship(rel.id);\n\t\t\t\t\trelationshipsWithDetails.push({\n\t\t\t\t\t\t...rel,\n\t\t\t\t\t\tdetails: relDetails as Relationship[\"details\"],\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\trelationshipsWithDetails.push(rel);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\trelationshipsWithDetails.push(rel);\n\t\t\t}\n\t\t}\n\t} else if (ancestry.relationships) {\n\t\trelationshipsWithDetails.push(...ancestry.relationships);\n\t}\n\n\t// Step 4: Extract additional relationships from person details\n\tonProgress?.({\n\t\tstage: \"extracting_additional_relationships\",\n\t\tcurrent: 0,\n\t\ttotal: 1,\n\t\tpercent: 90,\n\t});\n\n\tconst allRelationships = [...relationshipsWithDetails];\n\tconst relationshipIds = new Set(relationshipsWithDetails.map((r) => r.id));\n\n\tpersonsWithDetails.forEach((person) => {\n\t\t// Extract child-parent relationships from person details\n\t\tconst childAndParentsRels =\n\t\t\tperson.fullDetails?.childAndParentsRelationships;\n\t\tif (childAndParentsRels && Array.isArray(childAndParentsRels)) {\n\t\t\tchildAndParentsRels.forEach((rel) => {\n\t\t\t\tif (!relationshipIds.has(rel.id)) {\n\t\t\t\t\trelationshipIds.add(rel.id);\n\t\t\t\t\tallRelationships.push({\n\t\t\t\t\t\tid: rel.id,\n\t\t\t\t\t\ttype: \"http://gedcomx.org/ParentChild\",\n\t\t\t\t\t\tperson1: rel.parent1,\n\t\t\t\t\t\tperson2: rel.child,\n\t\t\t\t\t\tparent2: rel.parent2,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// Extract couple relationships from person details\n\t\tconst relationships = person.fullDetails?.relationships;\n\t\tif (relationships && Array.isArray(relationships)) {\n\t\t\trelationships.forEach((rel) => {\n\t\t\t\tif (rel.type?.includes?.(\"Couple\") && !relationshipIds.has(rel.id)) {\n\t\t\t\t\trelationshipIds.add(rel.id);\n\t\t\t\t\tallRelationships.push({\n\t\t\t\t\t\tid: rel.id,\n\t\t\t\t\t\ttype: rel.type,\n\t\t\t\t\t\tperson1: rel.person1,\n\t\t\t\t\t\tperson2: rel.person2,\n\t\t\t\t\t\tfacts: rel.facts,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t});\n\n\tonProgress?.({\n\t\tstage: \"completing_data_fetch\",\n\t\tcurrent: 1,\n\t\ttotal: 1,\n\t\tpercent: 98,\n\t});\n\n\treturn {\n\t\tpersons: personsWithDetails,\n\t\trelationships: allRelationships,\n\t\tenvironment: sdk.getEnvironment(),\n\t};\n}\n\n/**\n * Get current user information\n */\nexport async function getCurrentUser(\n\tsdk: FamilySearchSDK\n): Promise<FamilySearchUser | null> {\n\treturn sdk.getCurrentUser();\n}\n\n/**\n * Get person by ID with full details\n */\nexport async function getPersonWithDetails(\n\tsdk: FamilySearchSDK,\n\tpersonId: string\n): Promise<EnhancedPerson | null> {\n\ttry {\n\t\tconst [details, notes] = await Promise.all([\n\t\t\tsdk.getPersonWithDetails(personId),\n\t\t\tsdk.getPersonNotes(personId),\n\t\t]);\n\n\t\tif (!details) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// The details response contains the person data in persons array\n\t\tconst fullDetails = details as EnhancedPerson[\"fullDetails\"];\n\t\tconst personData = fullDetails?.persons?.[0];\n\n\t\tif (!personData) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\t...personData,\n\t\t\tfullDetails: fullDetails,\n\t\t\tnotes: notes as EnhancedPerson[\"notes\"],\n\t\t};\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Fetch multiple persons at once\n */\nexport async function fetchMultiplePersons(\n\tsdk: FamilySearchSDK,\n\tpersonIds: string[]\n): Promise<unknown> {\n\tconst pids = personIds.join(\",\");\n\tconst response = await sdk.get(`/platform/tree/persons?pids=${pids}`);\n\treturn response.data;\n}\n"]}