@rachelallyson/planning-center-people-ts 2.14.1 → 3.1.0

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.
Files changed (77) hide show
  1. package/CHANGELOG.md +82 -7
  2. package/README.md +42 -4
  3. package/dist/auth.d.ts +1 -1
  4. package/dist/auth.js +14 -6
  5. package/dist/client.d.ts +33 -8
  6. package/dist/client.js +47 -22
  7. package/dist/core.d.ts +4 -2
  8. package/dist/core.js +3 -2
  9. package/dist/error-handling.d.ts +4 -4
  10. package/dist/error-handling.js +13 -2
  11. package/dist/error-scenarios.d.ts +11 -7
  12. package/dist/error-scenarios.js +26 -10
  13. package/dist/helpers.d.ts +124 -48
  14. package/dist/helpers.js +237 -93
  15. package/dist/index.d.ts +10 -8
  16. package/dist/index.js +31 -72
  17. package/dist/matching/matcher.d.ts +8 -4
  18. package/dist/matching/matcher.js +51 -58
  19. package/dist/matching/scoring.d.ts +9 -6
  20. package/dist/matching/scoring.js +18 -14
  21. package/dist/modules/campus.d.ts +31 -36
  22. package/dist/modules/campus.js +36 -49
  23. package/dist/modules/contacts.d.ts +33 -29
  24. package/dist/modules/contacts.js +36 -12
  25. package/dist/modules/fields.d.ts +39 -55
  26. package/dist/modules/fields.js +65 -105
  27. package/dist/modules/forms.d.ts +35 -24
  28. package/dist/modules/forms.js +41 -23
  29. package/dist/modules/households.d.ts +17 -19
  30. package/dist/modules/households.js +25 -34
  31. package/dist/modules/lists.d.ts +38 -28
  32. package/dist/modules/lists.js +62 -42
  33. package/dist/modules/notes.d.ts +32 -30
  34. package/dist/modules/notes.js +40 -52
  35. package/dist/modules/people.d.ts +83 -71
  36. package/dist/modules/people.js +323 -172
  37. package/dist/modules/reports.d.ts +18 -32
  38. package/dist/modules/reports.js +28 -40
  39. package/dist/modules/service-time.d.ts +19 -24
  40. package/dist/modules/service-time.js +28 -28
  41. package/dist/modules/workflows.d.ts +42 -47
  42. package/dist/modules/workflows.js +52 -53
  43. package/dist/performance.d.ts +14 -10
  44. package/dist/performance.js +61 -25
  45. package/dist/testing/recorder.js +11 -2
  46. package/dist/testing/simple-builders.d.ts +6 -4
  47. package/dist/testing/simple-builders.js +36 -49
  48. package/dist/testing/types.d.ts +4 -0
  49. package/dist/types/api-options.d.ts +380 -0
  50. package/dist/types/api-options.js +6 -0
  51. package/dist/types/client.d.ts +4 -2
  52. package/dist/types/client.js +1 -1
  53. package/dist/types/index.d.ts +1 -1
  54. package/dist/types/people.d.ts +61 -9
  55. package/package.json +7 -7
  56. package/dist/core/http.d.ts +0 -56
  57. package/dist/core/http.js +0 -360
  58. package/dist/core/pagination.d.ts +0 -34
  59. package/dist/core/pagination.js +0 -178
  60. package/dist/people/contacts.d.ts +0 -43
  61. package/dist/people/contacts.js +0 -122
  62. package/dist/people/core.d.ts +0 -28
  63. package/dist/people/core.js +0 -69
  64. package/dist/people/fields.d.ts +0 -68
  65. package/dist/people/fields.js +0 -305
  66. package/dist/people/households.d.ts +0 -15
  67. package/dist/people/households.js +0 -31
  68. package/dist/people/index.d.ts +0 -8
  69. package/dist/people/index.js +0 -25
  70. package/dist/people/lists.d.ts +0 -34
  71. package/dist/people/lists.js +0 -48
  72. package/dist/people/notes.d.ts +0 -30
  73. package/dist/people/notes.js +0 -37
  74. package/dist/people/organization.d.ts +0 -12
  75. package/dist/people/organization.js +0 -15
  76. package/dist/people/workflows.d.ts +0 -37
  77. package/dist/people/workflows.js +0 -75
@@ -56,8 +56,12 @@ function isRetryableError(error, retryableStatuses) {
56
56
  return retryableStatuses.includes(error.status);
57
57
  }
58
58
  // Network errors are generally retryable
59
- if (error.name === 'TypeError' && error.message.includes('fetch')) {
60
- return true;
59
+ if (error && typeof error === 'object' && 'name' in error && 'message' in error) {
60
+ const errorName = error.name;
61
+ const errorMessage = error.message;
62
+ if (errorName === 'TypeError' && typeof errorMessage === 'string' && errorMessage.includes('fetch')) {
63
+ return true;
64
+ }
61
65
  }
62
66
  return false;
63
67
  }
@@ -198,7 +202,11 @@ function classifyError(error) {
198
202
  if (error instanceof planning_center_base_ts_1.PcoApiError) {
199
203
  return classifyPcoError(error);
200
204
  }
201
- if (error.name === 'TypeError' && error.message.includes('fetch')) {
205
+ // Type guard for Error-like objects
206
+ const isErrorLike = (e) => {
207
+ return typeof e === 'object' && e !== null;
208
+ };
209
+ if (isErrorLike(error) && error.name === 'TypeError' && error.message?.includes('fetch')) {
202
210
  return {
203
211
  category: 'network',
204
212
  retryable: true,
@@ -206,7 +214,7 @@ function classifyError(error) {
206
214
  userMessage: 'Network connection error. Please check your internet connection.',
207
215
  };
208
216
  }
209
- if (error.message.includes('timeout')) {
217
+ if (isErrorLike(error) && error.message?.includes('timeout')) {
210
218
  return {
211
219
  category: 'network',
212
220
  retryable: true,
@@ -282,11 +290,14 @@ function classifyPcoError(error) {
282
290
  userMessage: 'The requested resource was not found.',
283
291
  };
284
292
  }
293
+ const isErrorLike = (e) => {
294
+ return typeof e === 'object' && e !== null;
295
+ };
285
296
  return {
286
297
  category: 'unknown',
287
298
  retryable: false,
288
299
  severity: 'medium',
289
- userMessage: error.message || 'An error occurred while processing your request.',
300
+ userMessage: (isErrorLike(error) && error.message) || 'An error occurred while processing your request.',
290
301
  };
291
302
  }
292
303
  // ===== Error Recovery =====
@@ -329,6 +340,11 @@ async function attemptRecovery(operation, error, context) {
329
340
  */
330
341
  function createErrorReport(error, context) {
331
342
  const classification = classifyError(error);
343
+ // Type guard for error-like objects
344
+ const isErrorLike = (e) => {
345
+ return typeof e === 'object' && e !== null;
346
+ };
347
+ const errorObj = isErrorLike(error) ? error : {};
332
348
  return {
333
349
  classification,
334
350
  context: {
@@ -340,11 +356,11 @@ function createErrorReport(error, context) {
340
356
  requestInfo: context.requestInfo,
341
357
  },
342
358
  error: {
343
- errors: error.errors,
344
- message: error.message || 'Unknown error',
345
- name: error.name || 'UnknownError',
346
- stack: error.stack,
347
- status: error.status,
359
+ errors: errorObj.errors,
360
+ message: errorObj.message || 'Unknown error',
361
+ name: errorObj.name || 'UnknownError',
362
+ stack: errorObj.stack,
363
+ status: errorObj.status,
348
364
  },
349
365
  operation: context.operation,
350
366
  timestamp: new Date().toISOString(),
package/dist/helpers.d.ts CHANGED
@@ -1,16 +1,7 @@
1
- import type { PcoClientState } from './core';
2
- import type { ErrorContext } from './error-handling';
3
- import type { PersonAttributes, EmailAttributes, PhoneNumberAttributes, AddressAttributes, WorkflowCardNoteAttributes, PeopleList, PersonSingle, EmailSingle, PhoneNumberSingle, AddressSingle, WorkflowCardSingle, WorkflowCardNoteSingle, ListsList, ListCategoriesList, OrganizationSingle } from './types';
4
- /**
5
- * Transform complex params object into flat query params for API calls
6
- */
7
- export declare function buildQueryParams(params?: {
8
- where?: Record<string, any>;
9
- include?: string[];
10
- per_page?: number;
11
- page?: number;
12
- filter?: string;
13
- }): Record<string, any>;
1
+ import type { PcoClient } from './client';
2
+ import type { ResourceObject, ResourceIdentifier } from './types/json-api';
3
+ import { mapIncludedToRelationships as baseMapIncludedToRelationships } from '@rachelallyson/planning-center-base-ts';
4
+ import type { PersonAttributes, PersonResource, EmailAttributes, PhoneNumberAttributes, AddressAttributes, WorkflowCardNoteAttributes, PeopleList, ListsList, ListCategoriesList, EmailResource, PhoneNumberResource, AddressResource, FieldDatumResource, WorkflowCardResource, EmailsList, PhoneNumbersList, AddressesList, OrganizationResource, WorkflowCardNoteResource, Meta, TopLevelLinks, ListResource, HouseholdResource } from './types';
14
5
  /**
15
6
  * Calculate age from birthdate string
16
7
  */
@@ -131,7 +122,7 @@ export interface TrustResult {
131
122
  * @param trustWindow - Trust window in milliseconds (default: 1 hour)
132
123
  * @returns Object with trust decision, age, and reason
133
124
  *
134
- * @example
125
+ * @gmail.com
135
126
  * ```typescript
136
127
  * const trust = calculateTrust(pcoInfo.personIdCreatedAt);
137
128
  * if (trust.shouldTrust) {
@@ -166,7 +157,7 @@ export declare function validatePersonData(data: Partial<PersonAttributes>): {
166
157
  /**
167
158
  * Get primary contact information for a person
168
159
  */
169
- export declare function getPrimaryContact(client: PcoClientState, personId: string, context?: Partial<ErrorContext>): Promise<{
160
+ export declare function getPrimaryContact(client: PcoClient, personId: string): Promise<{
170
161
  email?: string;
171
162
  phone?: string;
172
163
  address?: string;
@@ -174,45 +165,61 @@ export declare function getPrimaryContact(client: PcoClientState, personId: stri
174
165
  /**
175
166
  * Create a person with contact information
176
167
  */
177
- export declare function createPersonWithContact(client: PcoClientState, personData: Partial<PersonAttributes>, contactData?: {
168
+ export declare function createPersonWithContact(client: PcoClient, personData: Partial<PersonAttributes>, contactData?: {
178
169
  email?: Partial<EmailAttributes>;
179
170
  phone?: Partial<PhoneNumberAttributes>;
180
171
  address?: Partial<AddressAttributes>;
181
- }, context?: Partial<ErrorContext>): Promise<{
182
- person: PersonSingle;
183
- email?: EmailSingle;
184
- phone?: PhoneNumberSingle;
185
- address?: AddressSingle;
172
+ }): Promise<{
173
+ person: PersonResource;
174
+ email?: EmailResource;
175
+ phone?: PhoneNumberResource;
176
+ address?: AddressResource;
186
177
  }>;
187
178
  /**
188
179
  * Search people by multiple criteria
189
180
  */
190
- export declare function searchPeople(client: PcoClientState, criteria: {
181
+ export declare function searchPeople(client: PcoClient, criteria: {
191
182
  status?: string;
192
183
  name?: string;
193
184
  email?: string;
194
- per_page?: number;
195
- }, context?: Partial<ErrorContext>): Promise<PeopleList>;
185
+ perPage?: number;
186
+ page?: number;
187
+ }): Promise<PeopleList>;
196
188
  /**
197
189
  * Get people by household
198
190
  */
199
- export declare function getPeopleByHousehold(client: PcoClientState, householdId: string, context?: Partial<ErrorContext>): Promise<PeopleList>;
191
+ export declare function getPeopleByHousehold(client: PcoClient, householdId: string): Promise<{
192
+ data: import("@rachelallyson/planning-center-base-ts").FlattenedResource<"Person", PersonAttributes, import("./types").PersonRelationships, import("./types").PersonRelationshipMap>[];
193
+ totalCount: number;
194
+ pagesFetched: number;
195
+ duration: number;
196
+ meta?: Meta;
197
+ links?: TopLevelLinks;
198
+ }>;
200
199
  /**
201
200
  * Get complete person profile with all related data
202
201
  */
203
- export declare function getCompletePersonProfile(client: PcoClientState, personId: string, context?: Partial<ErrorContext>): Promise<{
204
- person: PersonSingle;
205
- emails: any;
206
- phones: any;
207
- addresses: any;
208
- fieldData: any;
209
- workflowCards: any;
202
+ export declare function getCompletePersonProfile(client: PcoClient, personId: string): Promise<{
203
+ person: PersonResource;
204
+ emails: EmailsList;
205
+ phones: PhoneNumbersList;
206
+ addresses: AddressesList;
207
+ fieldData: {
208
+ data: FieldDatumResource[];
209
+ meta?: Meta;
210
+ links?: TopLevelLinks;
211
+ };
212
+ workflowCards: {
213
+ data: WorkflowCardResource[];
214
+ meta?: Meta;
215
+ links?: TopLevelLinks;
216
+ };
210
217
  }>;
211
218
  /**
212
219
  * Get organization info with statistics
213
220
  */
214
- export declare function getOrganizationInfo(client: PcoClientState, context?: Partial<ErrorContext>): Promise<{
215
- organization: OrganizationSingle;
221
+ export declare function getOrganizationInfo(client: PcoClient): Promise<{
222
+ organization: OrganizationResource | null;
216
223
  stats: {
217
224
  totalPeople: number;
218
225
  totalHouseholds: number;
@@ -222,42 +229,111 @@ export declare function getOrganizationInfo(client: PcoClientState, context?: Pa
222
229
  /**
223
230
  * Get lists with their categories
224
231
  */
225
- export declare function getListsWithCategories(client: PcoClientState, context?: Partial<ErrorContext>): Promise<{
232
+ export declare function getListsWithCategories(client: PcoClient): Promise<{
226
233
  lists: ListsList;
227
234
  categories: ListCategoriesList;
228
235
  }>;
229
236
  /**
230
237
  * Get workflow cards with notes for a person
231
238
  */
232
- export declare function getPersonWorkflowCardsWithNotes(client: PcoClientState, personId: string, context?: Partial<ErrorContext>): Promise<{
233
- workflowCards: any;
239
+ export declare function getPersonWorkflowCardsWithNotes(client: PcoClient, personId: string): Promise<{
240
+ workflowCards: {
241
+ data: WorkflowCardResource[];
242
+ meta?: Meta;
243
+ links?: TopLevelLinks;
244
+ };
234
245
  notes: {
235
- [cardId: string]: any;
246
+ [cardId: string]: {
247
+ data: WorkflowCardNoteResource[];
248
+ meta?: Meta;
249
+ links?: TopLevelLinks;
250
+ };
236
251
  };
237
252
  }>;
238
253
  /**
239
254
  * Create a workflow card with a note
240
255
  */
241
- export declare function createWorkflowCardWithNote(client: PcoClientState, workflowId: string, personId: string, noteData: Partial<WorkflowCardNoteAttributes>, context?: Partial<ErrorContext>): Promise<{
242
- workflowCard: WorkflowCardSingle;
243
- note: WorkflowCardNoteSingle;
256
+ export declare function createWorkflowCardWithNote(client: PcoClient, workflowId: string, personId: string, noteData: Partial<WorkflowCardNoteAttributes>): Promise<{
257
+ workflowCard: WorkflowCardResource;
258
+ note: WorkflowCardNoteResource;
244
259
  }>;
245
260
  /**
246
261
  * Export all people data in a structured format
247
262
  */
248
- export declare function exportAllPeopleData(client: PcoClientState, options?: {
263
+ export declare function exportAllPeopleData(client: PcoClient, options?: {
249
264
  includeInactive?: boolean;
250
265
  includeFieldData?: boolean;
251
266
  includeWorkflowCards?: boolean;
252
- perPage?: number;
253
- }, context?: Partial<ErrorContext>): Promise<{
254
- people: any[];
255
- households: any[];
256
- lists: any[];
257
- organization: any;
267
+ }): Promise<{
268
+ people: PersonResource[];
269
+ households: HouseholdResource[];
270
+ lists: ListResource[];
271
+ organization: OrganizationResource | null;
258
272
  exportDate: string;
259
273
  totalCount: number;
260
274
  }>;
275
+ /**
276
+ * Find an included resource by type and id
277
+ *
278
+ * In JSON:API, relationships contain resource identifiers like { type: 'Email', id: '456' }
279
+ * This helper finds the full resource object from the included array.
280
+ *
281
+ * @param included - Array of included resources from JSON:API response
282
+ * @param type - Resource type to find
283
+ * @param id - Resource id to find
284
+ * @returns The matching resource object, or undefined if not found
285
+ *
286
+ * @example
287
+ * ```typescript
288
+ * const person = await client.people.getPage({ include: ['emails'] });
289
+ * // Data is flattened: person.data[0].emails is the resolved array
290
+ * const email = person.data[0].emails?.[0];
291
+ * console.log(email?.address); // 'john@gmail.com'
292
+ * ```
293
+ */
294
+ export declare function findIncluded<T extends ResourceObject<string, any, any> = ResourceObject<string, any, any>>(included: ResourceObject<string, any, any>[] | undefined, type: string, id: string): T | undefined;
295
+ /**
296
+ * Resolve all resources from a relationship to their full included objects
297
+ *
298
+ * Takes a relationship's data array (which contains resource identifiers)
299
+ * and resolves them to full resource objects from the included array.
300
+ *
301
+ * @param included - Array of included resources from JSON:API response
302
+ * @param relationshipData - Relationship data array (from relationships.xxx.data)
303
+ * @returns Array of full resource objects, or empty array if none found
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * const person = await client.people.getPage({ include: ['emails', 'phone_numbers'] });
308
+ * // Data is flattened: person.data[0].emails is the resolved array
309
+ * const emails = person.data[0].emails ?? [];
310
+ * emails.forEach(email => console.log(email.address));
311
+ * ```
312
+ */
313
+ export declare function resolveIncluded<T extends ResourceObject<string, any, any> = ResourceObject<string, any, any>>(included: ResourceObject<string, any, any>[] | undefined, relationshipData: ResourceIdentifier | ResourceIdentifier[] | null | undefined): T[];
314
+ /**
315
+ * Create a lookup map for included resources by type and id
316
+ *
317
+ * This is more efficient than calling findIncluded() multiple times.
318
+ *
319
+ * @param included - Array of included resources from JSON:API response
320
+ * @returns Map with key format "type:id" -> resource object
321
+ *
322
+ * @gmail.com
323
+ * ```typescript
324
+ * const person = await client.people.getPage({ include: ['emails', 'phone_numbers'] });
325
+ * const lookup = createIncludedLookup(person.included);
326
+ * const email = lookup.get('Email:456'); // Fast lookup
327
+ * ```
328
+ */
329
+ export declare function createIncludedLookup(included: ResourceObject<string, any, any>[] | undefined): Map<string, ResourceObject<string, any, any>>;
330
+ /**
331
+ * Automatically map included resources to their relationships
332
+ *
333
+ * Re-exported from @rachelallyson/planning-center-base-ts for convenience.
334
+ * The mapping is now automatically applied in getList()/getPage() methods.
335
+ */
336
+ export declare const mapIncludedToRelationships: typeof baseMapIncludedToRelationships;
261
337
  /**
262
338
  * Extracts clean URL from HTML markup that contains file links
263
339
  * Handles cases like: <a href="https://onark.s3.us-east-1.amazonaws.com/file.pdf" download>View File: https://onark.s3.us-east-1.amazonaws.com/file.pdf</a>