@rachelallyson/planning-center-people-ts 2.14.1 → 3.0.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 +76 -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 +236 -93
  15. package/dist/index.d.ts +9 -7
  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 +30 -28
  32. package/dist/modules/lists.js +55 -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 +50 -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 +47 -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
@@ -25,55 +25,43 @@ exports.DEFAULT_AGGRESSIVE_RETRY_CONFIG = {
25
25
  backoffMultiplier: 2,
26
26
  };
27
27
  class PeopleModule extends planning_center_base_ts_1.BaseModule {
28
- constructor(httpClient, paginationHelper, eventEmitter) {
29
- super(httpClient, paginationHelper, eventEmitter);
30
- this.personMatcher = new matcher_1.PersonMatcher(this);
28
+ constructor(httpClient, paginationHelper, eventEmitter, getConfig) {
29
+ super(httpClient, paginationHelper, eventEmitter, getConfig);
30
+ this.personMatcher = new matcher_1.PersonMatcher(this, getConfig);
31
31
  }
32
32
  /**
33
- * Get all people with optional filtering
33
+ * Get all people across all pages with optional filtering
34
34
  */
35
35
  async getAll(options = {}) {
36
- const params = {};
37
- if (options.where) {
38
- Object.entries(options.where).forEach(([key, value]) => {
39
- params[`where[${key}]`] = value;
40
- });
41
- }
42
- if (options.include) {
43
- params.include = options.include.join(',');
44
- }
45
- if (options.perPage) {
46
- params.per_page = options.perPage;
47
- }
48
- if (options.page) {
49
- params.page = options.page;
50
- }
51
- return this.getList('/people', params);
36
+ this.debugLog('people.getAll', { options });
37
+ return await this.getAllPages('/people', {
38
+ where: options.where,
39
+ include: options.include,
40
+ order: options.order
41
+ });
52
42
  }
53
43
  /**
54
- * Get all people across all pages
44
+ * Get a single page of people with optional filtering and pagination control
45
+ * Use this when you need a specific page or want to limit the number of results
46
+ * @param options - List options including where, include, perPage, page, and order
47
+ * @returns A single page of results with meta and links for pagination
55
48
  */
56
- async getAllPagesPaginated(options = {}, paginationOptions) {
57
- const params = {};
58
- if (options.where) {
59
- Object.entries(options.where).forEach(([key, value]) => {
60
- params[`where[${key}]`] = value;
61
- });
62
- }
63
- if (options.include) {
64
- params.include = options.include.join(',');
65
- }
66
- return this.getAllPages('/people', params, paginationOptions);
49
+ async getPage(options = {}) {
50
+ this.debugLog('people.getPage', { options });
51
+ return this.getList('/people', {
52
+ where: options.where,
53
+ include: options.include,
54
+ per_page: options.perPage,
55
+ page: options.page,
56
+ order: options.order
57
+ });
67
58
  }
68
59
  /**
69
60
  * Get a single person by ID
70
61
  */
71
62
  async getById(id, include) {
72
- const params = {};
73
- if (include) {
74
- params.include = include.join(',');
75
- }
76
- return this.getSingle(`/people/${id}`, params);
63
+ this.debugLog('people.getById', { id, include });
64
+ return this.getSingle(`/people/${id}`, include);
77
65
  }
78
66
  /**
79
67
  * Verify that a person exists in PCO
@@ -87,7 +75,7 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
87
75
  * @returns True if person exists, false if not found
88
76
  * @throws Error if request times out or other error occurs (except 404)
89
77
  *
90
- * @example
78
+ * @gmail.com
91
79
  * ```typescript
92
80
  * const exists = await client.people.verifyPersonExists(cachedPersonId);
93
81
  * if (!exists) {
@@ -97,12 +85,15 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
97
85
  * ```
98
86
  */
99
87
  async verifyPersonExists(personId, options) {
88
+ this.debugLog('people.verifyPersonExists', { personId, options });
100
89
  const timeout = options?.timeout ?? 30000;
101
90
  const verificationPromise = this.getById(personId)
102
91
  .then(() => true)
103
92
  .catch((error) => {
104
93
  // 404 means person doesn't exist (merged or deleted)
105
- if (error?.status === 404 || error?.response?.status === 404) {
94
+ const status = error?.status
95
+ ?? error?.response?.status;
96
+ if (status === 404) {
106
97
  return false;
107
98
  }
108
99
  // Re-throw other errors
@@ -115,22 +106,167 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
115
106
  });
116
107
  return Promise.race([verificationPromise, timeoutPromise]);
117
108
  }
109
+ /**
110
+ * Transform PersonCreateOptions (camelCase) to API format (snake_case)
111
+ * Also handles snake_case input directly (passes through)
112
+ */
113
+ transformPersonData(data) {
114
+ const transformed = {};
115
+ const dataObj = data;
116
+ // If data is already in snake_case format, copy those fields directly
117
+ if (dataObj.first_name !== undefined)
118
+ transformed.first_name = dataObj.first_name;
119
+ if (dataObj.last_name !== undefined)
120
+ transformed.last_name = dataObj.last_name;
121
+ if (dataObj.given_name !== undefined)
122
+ transformed.given_name = dataObj.given_name;
123
+ if (dataObj.middle_name !== undefined)
124
+ transformed.middle_name = dataObj.middle_name;
125
+ if (dataObj.nickname !== undefined)
126
+ transformed.nickname = dataObj.nickname;
127
+ if (dataObj.birthdate !== undefined)
128
+ transformed.birthdate = dataObj.birthdate;
129
+ if (dataObj.anniversary !== undefined)
130
+ transformed.anniversary = dataObj.anniversary;
131
+ if (dataObj.gender !== undefined)
132
+ transformed.gender = dataObj.gender;
133
+ if (dataObj.grade !== undefined)
134
+ transformed.grade = dataObj.grade;
135
+ if (dataObj.child !== undefined)
136
+ transformed.child = dataObj.child;
137
+ if (dataObj.status !== undefined)
138
+ transformed.status = dataObj.status;
139
+ if (dataObj.medical_notes !== undefined)
140
+ transformed.medical_notes = dataObj.medical_notes;
141
+ if (dataObj.job_title !== undefined)
142
+ transformed.job_title = dataObj.job_title;
143
+ if (dataObj.employer !== undefined)
144
+ transformed.employer = dataObj.employer;
145
+ if (dataObj.school !== undefined)
146
+ transformed.school = dataObj.school;
147
+ if (dataObj.graduation_year !== undefined)
148
+ transformed.graduation_year = dataObj.graduation_year;
149
+ if (dataObj.avatar !== undefined)
150
+ transformed.avatar = dataObj.avatar;
151
+ if (dataObj.site_administrator !== undefined)
152
+ transformed.site_administrator = dataObj.site_administrator;
153
+ if (dataObj.accounting_administrator !== undefined)
154
+ transformed.accounting_administrator = dataObj.accounting_administrator;
155
+ if (dataObj.people_permissions !== undefined)
156
+ transformed.people_permissions = dataObj.people_permissions;
157
+ if (dataObj.directory_status !== undefined)
158
+ transformed.directory_status = dataObj.directory_status;
159
+ if (dataObj.login_identifier !== undefined)
160
+ transformed.login_identifier = dataObj.login_identifier;
161
+ if (dataObj.membership !== undefined)
162
+ transformed.membership = dataObj.membership;
163
+ if (dataObj.remote_id !== undefined)
164
+ transformed.remote_id = dataObj.remote_id;
165
+ if (dataObj.demographic_avatar_url !== undefined)
166
+ transformed.demographic_avatar_url = dataObj.demographic_avatar_url;
167
+ if (dataObj.inactivated_at !== undefined)
168
+ transformed.inactivated_at = dataObj.inactivated_at;
169
+ if (dataObj.resource_permission_flags !== undefined)
170
+ transformed.resource_permission_flags = dataObj.resource_permission_flags;
171
+ if (dataObj.primary_campus_id !== undefined)
172
+ transformed.primary_campus_id = dataObj.primary_campus_id;
173
+ if (dataObj.household_id !== undefined)
174
+ transformed.household_id = dataObj.household_id;
175
+ // Handle PersonCreateOptions fields (camelCase)
176
+ if (dataObj.firstName !== undefined)
177
+ transformed.first_name = dataObj.firstName;
178
+ if (dataObj.lastName !== undefined)
179
+ transformed.last_name = dataObj.lastName;
180
+ if (dataObj.givenName !== undefined)
181
+ transformed.given_name = dataObj.givenName;
182
+ if (dataObj.middleName !== undefined)
183
+ transformed.middle_name = dataObj.middleName;
184
+ if (dataObj.nickname !== undefined)
185
+ transformed.nickname = dataObj.nickname;
186
+ if (dataObj.birthdate !== undefined)
187
+ transformed.birthdate = dataObj.birthdate;
188
+ if (dataObj.anniversary !== undefined)
189
+ transformed.anniversary = dataObj.anniversary;
190
+ if (dataObj.gender !== undefined)
191
+ transformed.gender = dataObj.gender;
192
+ if (dataObj.grade !== undefined)
193
+ transformed.grade = dataObj.grade;
194
+ if (dataObj.child !== undefined)
195
+ transformed.child = dataObj.child;
196
+ if (dataObj.status !== undefined)
197
+ transformed.status = dataObj.status;
198
+ if (dataObj.medicalNotes !== undefined)
199
+ transformed.medical_notes = dataObj.medicalNotes;
200
+ if (dataObj.jobTitle !== undefined)
201
+ transformed.job_title = dataObj.jobTitle;
202
+ if (dataObj.employer !== undefined)
203
+ transformed.employer = dataObj.employer;
204
+ if (dataObj.school !== undefined)
205
+ transformed.school = dataObj.school;
206
+ if (dataObj.graduationYear !== undefined)
207
+ transformed.graduation_year = dataObj.graduationYear;
208
+ if (dataObj.avatar !== undefined)
209
+ transformed.avatar = dataObj.avatar;
210
+ if (dataObj.siteAdministrator !== undefined)
211
+ transformed.site_administrator = dataObj.siteAdministrator;
212
+ if (dataObj.accountingAdministrator !== undefined)
213
+ transformed.accounting_administrator = dataObj.accountingAdministrator;
214
+ if (dataObj.peoplePermissions !== undefined)
215
+ transformed.people_permissions = dataObj.peoplePermissions;
216
+ if (dataObj.directoryStatus !== undefined)
217
+ transformed.directory_status = dataObj.directoryStatus;
218
+ if (dataObj.loginIdentifier !== undefined)
219
+ transformed.login_identifier = dataObj.loginIdentifier;
220
+ if (dataObj.membership !== undefined)
221
+ transformed.membership = dataObj.membership;
222
+ if (dataObj.remoteId !== undefined)
223
+ transformed.remote_id = dataObj.remoteId;
224
+ if (dataObj.demographicAvatarUrl !== undefined)
225
+ transformed.demographic_avatar_url = dataObj.demographicAvatarUrl;
226
+ if (dataObj.inactivatedAt !== undefined)
227
+ transformed.inactivated_at = dataObj.inactivatedAt;
228
+ if (dataObj.resourcePermissionFlags !== undefined)
229
+ transformed.resource_permission_flags = dataObj.resourcePermissionFlags;
230
+ // Handle relationship fields
231
+ if (dataObj.primaryCampusId !== undefined)
232
+ transformed.primary_campus_id = dataObj.primaryCampusId;
233
+ if (dataObj.householdId !== undefined)
234
+ transformed.household_id = dataObj.householdId;
235
+ return transformed;
236
+ }
118
237
  /**
119
238
  * Create a new person
239
+ * Accepts both camelCase (PersonCreateOptions) and snake_case (PersonAttributes) fields
120
240
  */
121
241
  async create(data) {
122
- return this.createResource('/people', data);
242
+ this.debugLog('people.create', { data });
243
+ // Check if data is already in snake_case format (has first_name, last_name, etc.)
244
+ const hasSnakeCase = Object.keys(data).some(key => key.includes('_'));
245
+ // If it's already in snake_case, use it directly; otherwise transform
246
+ const transformedData = hasSnakeCase
247
+ ? data
248
+ : this.transformPersonData(data);
249
+ return this.createResource('/people', transformedData);
123
250
  }
124
251
  /**
125
252
  * Update a person
253
+ * Accepts both camelCase (PersonCreateOptions) and snake_case (PersonAttributes) fields
126
254
  */
127
255
  async update(id, data) {
128
- return this.updateResource(`/people/${id}`, data);
256
+ this.debugLog('people.update', { id, data });
257
+ // Check if data is already in snake_case format (has first_name, last_name, etc.)
258
+ const hasSnakeCase = Object.keys(data).some(key => key.includes('_'));
259
+ // If it's already in snake_case, use it directly; otherwise transform
260
+ const transformedData = hasSnakeCase
261
+ ? data
262
+ : this.transformPersonData(data);
263
+ return this.updateResource(`/people/${id}`, transformedData);
129
264
  }
130
265
  /**
131
266
  * Delete a person
132
267
  */
133
268
  async delete(id) {
269
+ this.debugLog('people.delete', { id });
134
270
  return this.deleteResource(`/people/${id}`);
135
271
  }
136
272
  // ===== Relationship Management =====
@@ -138,203 +274,193 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
138
274
  * Get a person's primary campus
139
275
  */
140
276
  async getPrimaryCampus(personId) {
277
+ this.debugLog('people.getPrimaryCampus', { personId });
141
278
  const person = await this.getById(personId, ['primary_campus']);
142
- const campusData = person.relationships?.primary_campus?.data;
143
- if (!campusData || Array.isArray(campusData) || !campusData.id) {
279
+ const campusData = person.primary_campus;
280
+ // campusData can be CampusResource, ResourceIdentifier, or null
281
+ if (!campusData || Array.isArray(campusData)) {
144
282
  return null;
145
283
  }
146
- // Get the full campus resource
147
- return this.httpClient.request({
148
- method: 'GET',
149
- endpoint: `/campuses/${campusData.id}`
150
- }).then(response => response.data.data);
284
+ // Check if it's a ResourceIdentifier (has id but might not have full attributes)
285
+ if ('id' in campusData && 'type' in campusData) {
286
+ // Get the full campus resource
287
+ return this.getSingle(`/campuses/${campusData.id}`);
288
+ }
289
+ // If it's already a full resource, return it
290
+ return campusData;
151
291
  }
152
292
  /**
153
293
  * Set a person's primary campus
154
294
  */
155
295
  async setPrimaryCampus(personId, campusId) {
156
- return this.httpClient.request({
157
- method: 'PATCH',
158
- endpoint: `/people/${personId}`,
159
- data: {
160
- data: {
161
- type: 'Person',
162
- id: personId,
163
- attributes: {
164
- primary_campus_id: campusId
165
- }
166
- }
167
- }
168
- }).then(response => response.data.data);
296
+ this.debugLog('people.setPrimaryCampus', { personId, campusId });
297
+ const transformedData = this.transformPersonData({ primaryCampusId: campusId });
298
+ return this.updateResource(`/people/${personId}`, transformedData);
169
299
  }
170
300
  /**
171
301
  * Remove a person's primary campus
172
302
  */
173
303
  async removePrimaryCampus(personId) {
174
- return this.httpClient.request({
175
- method: 'PATCH',
176
- endpoint: `/people/${personId}`,
177
- data: {
178
- data: {
179
- type: 'Person',
180
- id: personId,
181
- attributes: {
182
- primary_campus_id: null
183
- }
184
- }
185
- }
186
- }).then(response => response.data.data);
304
+ this.debugLog('people.removePrimaryCampus', { personId });
305
+ const transformedData = this.transformPersonData({ primaryCampusId: null });
306
+ return this.updateResource(`/people/${personId}`, transformedData);
187
307
  }
188
308
  /**
189
309
  * Get a person's household
190
310
  */
191
311
  async getHousehold(personId) {
312
+ this.debugLog('people.getHousehold', { personId });
192
313
  const person = await this.getById(personId, ['household']);
193
- const householdData = person.relationships?.household?.data;
194
- if (!householdData || Array.isArray(householdData) || !householdData.id) {
314
+ const householdData = person.household;
315
+ // householdData can be HouseholdResource, ResourceIdentifier, or null
316
+ if (!householdData || Array.isArray(householdData)) {
195
317
  return null;
196
318
  }
197
- // Get the full household resource
198
- return this.httpClient.request({
199
- method: 'GET',
200
- endpoint: `/households/${householdData.id}`
201
- }).then(response => response.data.data);
319
+ // Check if it's a ResourceIdentifier (has id but might not have full attributes)
320
+ if ('id' in householdData && 'type' in householdData) {
321
+ // Get the full household resource
322
+ return this.getSingle(`/households/${householdData.id}`);
323
+ }
324
+ // If it's already a full resource, return it
325
+ return householdData;
202
326
  }
203
327
  /**
204
328
  * Set a person's household
329
+ * Uses the household_memberships endpoint to create a membership record
205
330
  */
206
331
  async setHousehold(personId, householdId) {
207
- return this.httpClient.request({
208
- method: 'PATCH',
209
- endpoint: `/people/${personId}`,
210
- data: {
211
- data: {
212
- type: 'Person',
213
- id: personId,
214
- attributes: {
215
- household_id: householdId
332
+ this.debugLog('people.setHousehold', { personId, householdId });
333
+ await this.createResource(`/households/${householdId}/household_memberships`, {
334
+ relationships: {
335
+ person: {
336
+ data: {
337
+ type: 'Person',
338
+ id: personId
216
339
  }
217
340
  }
218
341
  }
219
- }).then(response => response.data.data);
342
+ });
343
+ // Return the updated person
344
+ return this.getById(personId);
220
345
  }
221
346
  /**
222
347
  * Remove a person from their household
348
+ * Uses the household_memberships endpoint to delete the membership record
223
349
  */
224
350
  async removeFromHousehold(personId) {
225
- return this.httpClient.request({
226
- method: 'PATCH',
227
- endpoint: `/people/${personId}`,
228
- data: {
229
- data: {
230
- type: 'Person',
231
- id: personId,
232
- attributes: {
233
- household_id: null
234
- }
351
+ this.debugLog('people.removeFromHousehold', { personId });
352
+ const membershipsResponse = await this.httpClient.request({
353
+ method: 'GET',
354
+ endpoint: `/people/${personId}/household_memberships`
355
+ });
356
+ if (!membershipsResponse.data.data || membershipsResponse.data.data.length === 0) {
357
+ throw new Error(`Person ${personId} is not in a household`);
358
+ }
359
+ // Get the first membership (a person can only be in one household)
360
+ const membership = membershipsResponse.data.data[0];
361
+ const membershipId = membership.id;
362
+ // Get the household ID from the membership relationship
363
+ const membershipHousehold = membership.relationships?.household?.data;
364
+ if (!membershipHousehold || Array.isArray(membershipHousehold) || !membershipHousehold.id) {
365
+ const membershipDetails = await this.httpClient.request({
366
+ method: 'GET',
367
+ endpoint: `/people/${personId}/household_memberships/${membershipId}`,
368
+ params: {
369
+ include: 'household'
235
370
  }
371
+ });
372
+ const householdData = membershipDetails.data.data.relationships?.household?.data;
373
+ if (!householdData || Array.isArray(householdData) || !householdData.id) {
374
+ throw new Error(`Could not determine household ID for membership ${membershipId}`);
236
375
  }
237
- }).then(response => response.data.data);
376
+ const householdId = householdData.id;
377
+ await this.deleteResource(`/households/${householdId}/household_memberships/${membershipId}`);
378
+ }
379
+ else {
380
+ const householdId = membershipHousehold.id;
381
+ await this.deleteResource(`/households/${householdId}/household_memberships/${membershipId}`);
382
+ }
383
+ // Return the updated person
384
+ return this.getById(personId);
238
385
  }
239
386
  /**
240
387
  * Get all people in a specific household
388
+ * Note: This uses getList() internally, so it returns a single page. Use getAll() with where[household_id] for all pages.
241
389
  */
242
390
  async getHouseholdMembers(householdId, options = {}) {
243
- const params = {
244
- 'where[household_id]': householdId
245
- };
246
- if (options.include) {
391
+ this.debugLog('people.getHouseholdMembers', { householdId, options });
392
+ // household_id is not in PersonWhereClause, so we need to use flat params
393
+ // Build the where clause manually and merge with other options
394
+ const params = {};
395
+ if (options.include)
247
396
  params.include = options.include.join(',');
248
- }
249
- if (options.perPage) {
397
+ if (options.perPage)
250
398
  params.per_page = options.perPage;
251
- }
252
- if (options.page) {
399
+ if (options.page)
253
400
  params.page = options.page;
254
- }
401
+ params['where[household_id]'] = householdId;
255
402
  return this.getList('/people', params);
256
403
  }
257
404
  /**
258
405
  * Get people by campus
406
+ * Note: This uses getList() internally, so it returns a single page. Use getAll() with where[primary_campus_id] for all pages.
259
407
  */
260
408
  async getByCampus(campusId, options = {}) {
261
- const params = {
262
- 'where[primary_campus_id]': campusId
263
- };
264
- if (options.include) {
265
- params.include = options.include.join(',');
266
- }
267
- if (options.perPage) {
268
- params.per_page = options.perPage;
269
- }
270
- if (options.page) {
271
- params.page = options.page;
272
- }
273
- return this.getList('/people', params);
409
+ this.debugLog('people.getByCampus', { campusId, options });
410
+ const campusIdNum = Number(campusId);
411
+ if (isNaN(campusIdNum)) {
412
+ throw new Error(`Invalid campus ID: ${campusId}`);
413
+ }
414
+ return this.getList('/people', {
415
+ where: { primary_campus_id: campusIdNum },
416
+ include: options.include,
417
+ per_page: options.perPage,
418
+ page: options.page
419
+ });
274
420
  }
275
421
  /**
276
422
  * Get a person's workflow cards
277
423
  */
278
424
  async getWorkflowCards(personId, options = {}) {
279
- const params = {};
280
- if (options.include) {
281
- params.include = options.include.join(',');
282
- }
283
- if (options.perPage) {
284
- params.per_page = options.perPage;
285
- }
286
- if (options.page) {
287
- params.page = options.page;
288
- }
289
- return this.getList(`/people/${personId}/workflow_cards`, params);
425
+ this.debugLog('people.getWorkflowCards', { personId, options });
426
+ return this.getList(`/people/${personId}/workflow_cards`, {
427
+ include: options.include,
428
+ per_page: options.perPage,
429
+ page: options.page
430
+ });
290
431
  }
291
432
  /**
292
433
  * Get a person's notes
293
434
  */
294
435
  async getNotes(personId, options = {}) {
295
- const params = {};
296
- if (options.include) {
297
- params.include = options.include.join(',');
298
- }
299
- if (options.perPage) {
300
- params.per_page = options.perPage;
301
- }
302
- if (options.page) {
303
- params.page = options.page;
304
- }
305
- return this.getList(`/people/${personId}/notes`, params);
436
+ this.debugLog('people.getNotes', { personId, options });
437
+ return this.getList(`/people/${personId}/notes`, {
438
+ include: options.include,
439
+ per_page: options.perPage,
440
+ page: options.page
441
+ });
306
442
  }
307
443
  /**
308
444
  * Get a person's field data
309
445
  */
310
446
  async getFieldData(personId, options = {}) {
311
- const params = {};
312
- if (options.include) {
313
- params.include = options.include.join(',');
314
- }
315
- if (options.perPage) {
316
- params.per_page = options.perPage;
317
- }
318
- if (options.page) {
319
- params.page = options.page;
320
- }
321
- return this.getList(`/people/${personId}/field_data`, params);
447
+ this.debugLog('people.getFieldData', { personId, options });
448
+ return this.getList(`/people/${personId}/field_data`, {
449
+ include: options.include,
450
+ per_page: options.perPage,
451
+ page: options.page
452
+ });
322
453
  }
323
454
  /**
324
455
  * Get a person's social profiles
325
456
  */
326
457
  async getSocialProfiles(personId, options = {}) {
327
- const params = {};
328
- if (options.include) {
329
- params.include = options.include.join(',');
330
- }
331
- if (options.perPage) {
332
- params.per_page = options.perPage;
333
- }
334
- if (options.page) {
335
- params.page = options.page;
336
- }
337
- return this.getList(`/people/${personId}/social_profiles`, params);
458
+ this.debugLog('people.getSocialProfiles', { personId, options });
459
+ return this.getList(`/people/${personId}/social_profiles`, {
460
+ include: options.include,
461
+ per_page: options.perPage,
462
+ page: options.page
463
+ });
338
464
  }
339
465
  /**
340
466
  * Find or create a person with smart matching
@@ -347,13 +473,13 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
347
473
  * to a person's profile when a match is found. The contacts are added as non-primary
348
474
  * to preserve existing primary contacts.
349
475
  *
350
- * @example
476
+ * @gmail.com
351
477
  * ```typescript
352
478
  * // Basic find or create
353
479
  * const person = await client.people.findOrCreate({
354
480
  * firstName: 'John',
355
481
  * lastName: 'Doe',
356
- * email: 'john@example.com',
482
+ * email: 'john@gmail.com',
357
483
  * phone: '+1234567890'
358
484
  * });
359
485
  *
@@ -361,7 +487,7 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
361
487
  * const person = await client.people.findOrCreate({
362
488
  * firstName: 'Jane',
363
489
  * lastName: 'Smith',
364
- * email: 'jane@example.com',
490
+ * email: 'jane@gmail.com',
365
491
  * phone: '+1987654321',
366
492
  * addMissingContactInfo: true // Will add phone if person only has email
367
493
  * });
@@ -370,12 +496,14 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
370
496
  * @returns The found or newly created person
371
497
  */
372
498
  async findOrCreate(options) {
499
+ this.debugLog('people.findOrCreate', { options });
373
500
  return this.personMatcher.findOrCreate(options);
374
501
  }
375
502
  /**
376
503
  * Search people by multiple criteria
377
504
  */
378
505
  async search(criteria) {
506
+ this.debugLog('people.search', { criteria });
379
507
  const where = {};
380
508
  // Use flexible search when we have multiple criteria or want broader matching
381
509
  if (criteria.email || criteria.phone) {
@@ -394,9 +522,16 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
394
522
  if (criteria.status) {
395
523
  where.status = criteria.status;
396
524
  }
525
+ // If pagination options are provided, use getPage instead of getAll
526
+ if (criteria.perPage !== undefined || criteria.page !== undefined) {
527
+ return this.getPage({
528
+ where,
529
+ perPage: criteria.perPage,
530
+ page: criteria.page,
531
+ });
532
+ }
397
533
  return this.getAll({
398
534
  where,
399
- perPage: criteria.perPage || 25,
400
535
  });
401
536
  }
402
537
  // Contact methods
@@ -404,96 +539,112 @@ class PeopleModule extends planning_center_base_ts_1.BaseModule {
404
539
  * Get person's emails
405
540
  */
406
541
  async getEmails(personId) {
542
+ this.debugLog('people.getEmails', { personId });
407
543
  return this.getList(`/people/${personId}/emails`);
408
544
  }
409
545
  /**
410
546
  * Add an email to a person
411
547
  */
412
548
  async addEmail(personId, data) {
549
+ this.debugLog('people.addEmail', { personId, data });
413
550
  return this.createResource(`/people/${personId}/emails`, data);
414
551
  }
415
552
  /**
416
553
  * Update a person's email
417
554
  */
418
555
  async updateEmail(personId, emailId, data) {
556
+ this.debugLog('people.updateEmail', { personId, emailId, data });
419
557
  return this.updateResource(`/people/${personId}/emails/${emailId}`, data);
420
558
  }
421
559
  /**
422
560
  * Delete a person's email
423
561
  */
424
562
  async deleteEmail(personId, emailId) {
563
+ this.debugLog('people.deleteEmail', { personId, emailId });
425
564
  return this.deleteResource(`/people/${personId}/emails/${emailId}`);
426
565
  }
427
566
  /**
428
567
  * Get person's phone numbers
429
568
  */
430
569
  async getPhoneNumbers(personId) {
570
+ this.debugLog('people.getPhoneNumbers', { personId });
431
571
  return this.getList(`/people/${personId}/phone_numbers`);
432
572
  }
433
573
  /**
434
574
  * Add a phone number to a person
435
575
  */
436
576
  async addPhoneNumber(personId, data) {
577
+ this.debugLog('people.addPhoneNumber', { personId, data });
437
578
  return this.createResource(`/people/${personId}/phone_numbers`, data);
438
579
  }
439
580
  /**
440
581
  * Update a person's phone number
441
582
  */
442
583
  async updatePhoneNumber(personId, phoneId, data) {
584
+ this.debugLog('people.updatePhoneNumber', { personId, phoneId, data });
443
585
  return this.updateResource(`/people/${personId}/phone_numbers/${phoneId}`, data);
444
586
  }
445
587
  /**
446
588
  * Delete a person's phone number
447
589
  */
448
590
  async deletePhoneNumber(personId, phoneId) {
591
+ this.debugLog('people.deletePhoneNumber', { personId, phoneId });
449
592
  return this.deleteResource(`/people/${personId}/phone_numbers/${phoneId}`);
450
593
  }
451
594
  /**
452
595
  * Get person's addresses
453
596
  */
454
597
  async getAddresses(personId) {
598
+ this.debugLog('people.getAddresses', { personId });
455
599
  return this.getList(`/people/${personId}/addresses`);
456
600
  }
457
601
  /**
458
602
  * Add an address to a person
459
603
  */
460
604
  async addAddress(personId, data) {
605
+ this.debugLog('people.addAddress', { personId, data });
461
606
  return this.createResource(`/people/${personId}/addresses`, data);
462
607
  }
463
608
  /**
464
609
  * Update a person's address
465
610
  */
466
611
  async updateAddress(personId, addressId, data) {
612
+ this.debugLog('people.updateAddress', { personId, addressId, data });
467
613
  return this.updateResource(`/people/${personId}/addresses/${addressId}`, data);
468
614
  }
469
615
  /**
470
616
  * Delete a person's address
471
617
  */
472
618
  async deleteAddress(personId, addressId) {
619
+ this.debugLog('people.deleteAddress', { personId, addressId });
473
620
  return this.deleteResource(`/people/${personId}/addresses/${addressId}`);
474
621
  }
475
622
  /**
476
623
  * Add a social profile to a person
477
624
  */
478
625
  async addSocialProfile(personId, data) {
626
+ this.debugLog('people.addSocialProfile', { personId, data });
479
627
  return this.createResource(`/people/${personId}/social_profiles`, data);
480
628
  }
481
629
  /**
482
630
  * Update a person's social profile
483
631
  */
484
632
  async updateSocialProfile(personId, profileId, data) {
633
+ this.debugLog('people.updateSocialProfile', { personId, profileId, data });
485
634
  return this.updateResource(`/people/${personId}/social_profiles/${profileId}`, data);
486
635
  }
487
636
  /**
488
637
  * Delete a person's social profile
489
638
  */
490
639
  async deleteSocialProfile(personId, profileId) {
640
+ this.debugLog('people.deleteSocialProfile', { personId, profileId });
491
641
  return this.deleteResource(`/people/${personId}/social_profiles/${profileId}`);
492
642
  }
493
643
  /**
494
644
  * Create a person with contact information
495
645
  */
496
646
  async createWithContacts(personData, contacts) {
647
+ this.debugLog('people.createWithContacts', { personData, contacts });
497
648
  const person = await this.create(personData);
498
649
  const result = { person };
499
650
  if (contacts?.email) {