@rachelallyson/planning-center-people-ts 2.14.0 → 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 +93 -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 -71
  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 +42 -54
  26. package/dist/modules/fields.js +70 -100
  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 -62
  65. package/dist/people/fields.js +0 -294
  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
@@ -7,94 +7,89 @@ exports.WorkflowsModule = void 0;
7
7
  const planning_center_base_ts_1 = require("@rachelallyson/planning-center-base-ts");
8
8
  class WorkflowsModule extends planning_center_base_ts_1.BaseModule {
9
9
  /**
10
- * Get all workflows
10
+ * Get all workflows across all pages
11
11
  */
12
12
  async getAll(options = {}) {
13
- const params = {};
14
- if (options.where) {
15
- Object.entries(options.where).forEach(([key, value]) => {
16
- params[`where[${key}]`] = value;
17
- });
18
- }
19
- if (options.include) {
20
- params.include = options.include.join(',');
21
- }
22
- if (options.perPage) {
23
- params.per_page = options.perPage;
24
- }
25
- if (options.page) {
26
- params.page = options.page;
27
- }
28
- return this.getList('/workflows', params);
13
+ this.debugLog('workflows.getAll', { options });
14
+ return await this.getAllPages('/workflows', {
15
+ where: options.where,
16
+ include: options.include,
17
+ order: options.order
18
+ });
29
19
  }
30
20
  /**
31
- * Get all workflows across all pages
21
+ * Get a single page of workflows with optional filtering and pagination control
22
+ * Use this when you need a specific page or want to limit the number of results
23
+ * @param options - List options including where, include, perPage, and page
24
+ * @returns A single page of results with meta and links for pagination
32
25
  */
33
- async getAllPagesPaginated(options = {}, paginationOptions) {
34
- const params = {};
35
- if (options.where) {
36
- Object.entries(options.where).forEach(([key, value]) => {
37
- params[`where[${key}]`] = value;
38
- });
39
- }
40
- if (options.include) {
41
- params.include = options.include.join(',');
42
- }
43
- return this.getAllPages('/workflows', params, paginationOptions);
26
+ async getPage(options = {}) {
27
+ this.debugLog('workflows.getPage', { options });
28
+ return this.getList('/workflows', {
29
+ where: options.where,
30
+ include: options.include,
31
+ per_page: options.perPage,
32
+ page: options.page,
33
+ order: options.order
34
+ });
44
35
  }
45
36
  /**
46
37
  * Get a single workflow by ID
47
38
  */
48
39
  async getById(id, include) {
49
- const params = {};
50
- if (include) {
51
- params.include = include.join(',');
52
- }
53
- return this.getSingle(`/workflows/${id}`, params);
40
+ this.debugLog('workflows.getById', { id, include });
41
+ return this.getSingle(`/workflows/${id}`, include);
54
42
  }
55
43
  /**
56
44
  * Create a workflow
57
45
  */
58
46
  async create(data) {
47
+ this.debugLog('workflows.create', { data });
59
48
  return this.createResource('/workflows', data);
60
49
  }
61
50
  /**
62
51
  * Update a workflow
63
52
  */
64
53
  async update(id, data) {
54
+ this.debugLog('workflows.update', { id, data });
65
55
  return this.updateResource(`/workflows/${id}`, data);
66
56
  }
67
57
  /**
68
58
  * Delete a workflow
69
59
  */
70
60
  async delete(id) {
61
+ this.debugLog('workflows.delete', { id });
71
62
  return this.deleteResource(`/workflows/${id}`);
72
63
  }
73
64
  /**
74
65
  * Get workflow cards for a person
66
+ * @param personId - The person ID
67
+ * @param options - Optional pagination options
75
68
  */
76
- async getPersonWorkflowCards(personId) {
77
- return this.getList(`/people/${personId}/workflow_cards`);
69
+ async getPersonWorkflowCards(personId, options) {
70
+ this.debugLog('workflows.getPersonWorkflowCards', { personId, options });
71
+ return this.getList(`/people/${personId}/workflow_cards`, options);
78
72
  }
79
73
  /**
80
74
  * Add a person to a workflow with smart duplicate detection
81
75
  */
82
76
  async addPersonToWorkflow(personId, workflowId, options = {}) {
77
+ this.debugLog('workflows.addPersonToWorkflow', { personId, workflowId, options });
83
78
  const { skipIfExists = true, skipIfActive = true } = options;
84
79
  // Check for existing workflow cards if requested
85
80
  if (skipIfExists || skipIfActive) {
86
81
  const existingCards = await this.getPersonWorkflowCards(personId);
87
82
  const existingCard = existingCards.data.find(card => {
88
- const workflowData = card.relationships?.workflow?.data;
83
+ const workflowData = card?.workflow?.data;
89
84
  return workflowData && !Array.isArray(workflowData) && workflowData.id === workflowId;
90
85
  });
91
- if (existingCard && existingCard.attributes) {
86
+ if (existingCard) {
92
87
  // Check if card is completed or removed
93
- if (skipIfExists && (existingCard.attributes.completed_at || existingCard.attributes.removed_at)) {
88
+ if (skipIfExists && (existingCard.completed_at || existingCard.removed_at)) {
94
89
  throw new Error(`Person already has a completed/removed card in this workflow`);
95
90
  }
96
91
  // Check if card is active
97
- if (skipIfActive && !existingCard.attributes.completed_at && !existingCard.attributes.removed_at) {
92
+ if (skipIfActive && !existingCard.completed_at && !existingCard.removed_at) {
98
93
  throw new Error(`Person already has an active card in this workflow`);
99
94
  }
100
95
  }
@@ -114,6 +109,7 @@ class WorkflowsModule extends planning_center_base_ts_1.BaseModule {
114
109
  * Create a workflow card
115
110
  */
116
111
  async createWorkflowCard(workflowId, personId) {
112
+ this.debugLog('workflows.createWorkflowCard', { workflowId, personId });
117
113
  return this.createResource(`/workflows/${workflowId}/cards`, {
118
114
  person_id: personId,
119
115
  });
@@ -122,6 +118,7 @@ class WorkflowsModule extends planning_center_base_ts_1.BaseModule {
122
118
  * Update a workflow card
123
119
  */
124
120
  async updateWorkflowCard(workflowCardId, data, personId) {
121
+ this.debugLog('workflows.updateWorkflowCard', { workflowCardId, data, personId });
125
122
  // If personId is provided, use the person-specific endpoint
126
123
  if (personId) {
127
124
  return this.updateResource(`/people/${personId}/workflow_cards/${workflowCardId}`, data);
@@ -133,30 +130,21 @@ class WorkflowsModule extends planning_center_base_ts_1.BaseModule {
133
130
  * Get workflow card notes
134
131
  */
135
132
  async getWorkflowCardNotes(personId, workflowCardId) {
133
+ this.debugLog('workflows.getWorkflowCardNotes', { personId, workflowCardId });
136
134
  return this.getList(`/people/${personId}/workflow_cards/${workflowCardId}/notes`);
137
135
  }
138
136
  /**
139
137
  * Create a workflow card note
140
138
  */
141
139
  async createWorkflowCardNote(personId, workflowCardId, data) {
140
+ this.debugLog('workflows.createWorkflowCardNote', { personId, workflowCardId, data });
142
141
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/notes`, data);
143
142
  }
144
- /**
145
- * Update a workflow card note
146
- */
147
- async updateWorkflowCardNote(personId, workflowCardId, noteId, data) {
148
- return this.updateResource(`/people/${personId}/workflow_cards/${workflowCardId}/notes/${noteId}`, data);
149
- }
150
- /**
151
- * Delete a workflow card note
152
- */
153
- async deleteWorkflowCardNote(personId, workflowCardId, noteId) {
154
- return this.deleteResource(`/people/${personId}/workflow_cards/${workflowCardId}/notes/${noteId}`);
155
- }
156
143
  /**
157
144
  * Create a workflow card with a note
158
145
  */
159
146
  async createWorkflowCardWithNote(workflowId, personId, noteData) {
147
+ this.debugLog('workflows.createWorkflowCardWithNote', { workflowId, personId, noteData });
160
148
  const workflowCard = await this.createWorkflowCard(workflowId, personId);
161
149
  const note = await this.createWorkflowCardNote(personId, workflowCard.id, noteData);
162
150
  return { workflowCard, note };
@@ -165,48 +153,56 @@ class WorkflowsModule extends planning_center_base_ts_1.BaseModule {
165
153
  * Move a workflow card back to the previous step
166
154
  */
167
155
  async goBackWorkflowCard(personId, workflowCardId) {
156
+ this.debugLog('workflows.goBackWorkflowCard', { personId, workflowCardId });
168
157
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/go_back`, {});
169
158
  }
170
159
  /**
171
160
  * Move a workflow card to the next step
172
161
  */
173
162
  async promoteWorkflowCard(personId, workflowCardId) {
163
+ this.debugLog('workflows.promoteWorkflowCard', { personId, workflowCardId });
174
164
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/promote`, {});
175
165
  }
176
166
  /**
177
167
  * Remove a workflow card
178
168
  */
179
169
  async removeWorkflowCard(personId, workflowCardId) {
170
+ this.debugLog('workflows.removeWorkflowCard', { personId, workflowCardId });
180
171
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/remove`, {});
181
172
  }
182
173
  /**
183
174
  * Restore a workflow card
184
175
  */
185
176
  async restoreWorkflowCard(personId, workflowCardId) {
177
+ this.debugLog('workflows.restoreWorkflowCard', { personId, workflowCardId });
186
178
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/restore`, {});
187
179
  }
188
180
  /**
189
181
  * Send an email to the subject of the workflow card
190
182
  */
191
183
  async sendEmailWorkflowCard(personId, workflowCardId, data) {
184
+ this.debugLog('workflows.sendEmailWorkflowCard', { personId, workflowCardId, data });
192
185
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/send_email`, data);
193
186
  }
194
187
  /**
195
188
  * Move a workflow card to the next step without completing the current step
196
189
  */
197
190
  async skipStepWorkflowCard(personId, workflowCardId) {
191
+ this.debugLog('workflows.skipStepWorkflowCard', { personId, workflowCardId });
198
192
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/skip_step`, {});
199
193
  }
200
194
  /**
201
195
  * Snooze a workflow card for a specific duration
202
196
  */
203
197
  async snoozeWorkflowCard(personId, workflowCardId, data) {
198
+ this.debugLog('workflows.snoozeWorkflowCard', { personId, workflowCardId, data });
204
199
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/snooze`, data);
205
200
  }
206
201
  /**
207
202
  * Unsnooze a workflow card
208
203
  */
209
204
  async unsnoozeWorkflowCard(personId, workflowCardId) {
205
+ this.debugLog('workflows.unsnoozeWorkflowCard', { personId, workflowCardId });
210
206
  return this.createResource(`/people/${personId}/workflow_cards/${workflowCardId}/unsnooze`, {});
211
207
  }
212
208
  /**
@@ -214,7 +210,8 @@ class WorkflowsModule extends planning_center_base_ts_1.BaseModule {
214
210
  */
215
211
  formatNoteTemplate(template, variables) {
216
212
  return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
217
- return variables[key] || match;
213
+ const value = variables[key];
214
+ return value !== undefined ? String(value) : match;
218
215
  });
219
216
  }
220
217
  }
@@ -4,16 +4,20 @@
4
4
  * This module provides utilities for optimizing performance when working
5
5
  * with large datasets and high-volume API operations.
6
6
  */
7
- import type { PcoClientState } from './core';
8
- import type { EmailResource, PersonResource, PhoneNumberResource } from './types';
7
+ import type { PcoClient } from './client';
8
+ import type { EmailResource, PersonResource, PhoneNumberResource, PeopleList } from './types';
9
+ import type { PersonListOptions, PersonWhereClause } from './types/api-options';
9
10
  /**
10
- * Process items in batches to avoid overwhelming the API
11
+ * Process items in batches to avoid overwhelming the API.
12
+ * Pass `client` in options to log batch progress when debug is enabled.
11
13
  */
12
- export declare function processInBatches<T, R>(items: T[], batchSize: number, processor: (batch: T[]) => Promise<R[]>): Promise<R[]>;
14
+ export declare function processInBatches<T, R>(items: T[], batchSize: number, processor: (batch: T[]) => Promise<R[]>, options?: {
15
+ client?: PcoClient;
16
+ }): Promise<R[]>;
13
17
  /**
14
18
  * Batch fetch person details with related data
15
19
  */
16
- export declare function batchFetchPersonDetails(client: PcoClientState, personIds: string[], options?: {
20
+ export declare function batchFetchPersonDetails(client: PcoClient, personIds: string[], options?: {
17
21
  includeEmails?: boolean;
18
22
  includePhones?: boolean;
19
23
  batchSize?: number;
@@ -35,11 +39,11 @@ export declare class ApiCache {
35
39
  /**
36
40
  * Cached version of getPeople with configurable TTL
37
41
  */
38
- export declare function getCachedPeople(client: PcoClientState, cache: ApiCache, params?: any, ttlMs?: number): Promise<any>;
42
+ export declare function getCachedPeople(client: PcoClient, cache: ApiCache, params?: PersonListOptions, ttlMs?: number): Promise<PeopleList>;
39
43
  /**
40
44
  * Efficiently fetch all pages of data with progress tracking
41
45
  */
42
- export declare function fetchAllPages<T>(client: PcoClientState, fetchFunction: (page: number, perPage: number) => Promise<{
46
+ export declare function fetchAllPages<T>(client: PcoClient, fetchFunction: (page: number, perPage: number) => Promise<{
43
47
  data: T[];
44
48
  links?: {
45
49
  next?: string;
@@ -55,16 +59,16 @@ export declare function fetchAllPages<T>(client: PcoClientState, fetchFunction:
55
59
  /**
56
60
  * Stream large datasets with backpressure control
57
61
  */
58
- export declare function streamPeopleData(client: PcoClientState, options?: {
62
+ export declare function streamPeopleData(client: PcoClient, options?: {
59
63
  perPage?: number;
60
64
  maxConcurrent?: number;
61
- where?: Record<string, any>;
65
+ where?: PersonWhereClause;
62
66
  include?: string[];
63
67
  }): AsyncGenerator<PersonResource[], void, unknown>;
64
68
  /**
65
69
  * Process large datasets without loading everything into memory
66
70
  */
67
- export declare function processLargeDataset<T, R>(client: PcoClientState, fetchFunction: (page: number, perPage: number) => Promise<{
71
+ export declare function processLargeDataset<T, R>(client: PcoClient, fetchFunction: (page: number, perPage: number) => Promise<{
68
72
  data: T[];
69
73
  links?: {
70
74
  next?: string;
@@ -14,17 +14,29 @@ exports.fetchAllPages = fetchAllPages;
14
14
  exports.streamPeopleData = streamPeopleData;
15
15
  exports.processLargeDataset = processLargeDataset;
16
16
  exports.monitorPerformance = monitorPerformance;
17
- const people_1 = require("./people");
17
+ const planning_center_base_ts_1 = require("@rachelallyson/planning-center-base-ts");
18
18
  // ===== Batch Processing =====
19
19
  /**
20
- * Process items in batches to avoid overwhelming the API
20
+ * Process items in batches to avoid overwhelming the API.
21
+ * Pass `client` in options to log batch progress when debug is enabled.
21
22
  */
22
- async function processInBatches(items, batchSize, processor) {
23
+ async function processInBatches(items, batchSize, processor, options) {
24
+ const logger = options?.client && typeof options.client.getConfig === 'function'
25
+ ? (0, planning_center_base_ts_1.createDebugLogger)(options.client.getConfig())
26
+ : null;
27
+ if (logger?.enabled) {
28
+ logger.log('performance.processInBatches', { itemCount: items.length, batchSize, batchCount: Math.ceil(items.length / batchSize) });
29
+ }
23
30
  const results = [];
24
31
  for (let i = 0; i < items.length; i += batchSize) {
25
32
  const batch = items.slice(i, i + batchSize);
33
+ const batchIndex = Math.floor(i / batchSize) + 1;
34
+ if (logger?.enabled)
35
+ logger.log('performance.processInBatches batch start', { batchIndex, batchSize: batch.length });
26
36
  const batchResults = await processor(batch);
27
37
  results.push(...batchResults);
38
+ if (logger?.enabled)
39
+ logger.log('performance.processInBatches batch complete', { batchIndex, resultCount: batchResults.length, totalSoFar: results.length });
28
40
  // Add a small delay between batches to respect rate limits
29
41
  if (i + batchSize < items.length) {
30
42
  await new Promise(resolve => setTimeout(resolve, 100));
@@ -36,31 +48,35 @@ async function processInBatches(items, batchSize, processor) {
36
48
  * Batch fetch person details with related data
37
49
  */
38
50
  async function batchFetchPersonDetails(client, personIds, options = {}) {
51
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(typeof client.getConfig === 'function'
52
+ ? client.getConfig()
53
+ : undefined);
54
+ if (logger.enabled)
55
+ logger.log('performance.batchFetchPersonDetails', { personCount: personIds.length, options });
39
56
  const { batchSize = 10, includeEmails = true, includePhones = true, } = options;
40
57
  const results = new Map();
41
58
  await processInBatches(personIds, batchSize, async (batch) => {
42
59
  const batchResults = await Promise.all(batch.map(async (personId) => {
43
- const personPromise = (0, people_1.getPeople)(client, {
44
- per_page: 1,
45
- where: { id: personId },
46
- });
47
- const promises_array = [personPromise];
48
- if (includeEmails) {
49
- promises_array.push((0, people_1.getPersonEmails)(client, personId));
50
- }
51
- if (includePhones) {
52
- promises_array.push((0, people_1.getPersonPhoneNumbers)(client, personId));
53
- }
54
- const responses = await Promise.all(promises_array);
55
- const person = responses[0].data[0];
60
+ const personPromise = client.people.getById(personId);
61
+ const emailPromise = includeEmails ? client.people.getEmails(personId) : null;
62
+ const phonePromise = includePhones ? client.people.getPhoneNumbers(personId) : null;
63
+ const promises = [personPromise];
64
+ if (emailPromise)
65
+ promises.push(emailPromise);
66
+ if (phonePromise)
67
+ promises.push(phonePromise);
68
+ const responses = await Promise.all(promises);
69
+ const person = responses[0];
56
70
  if (!person)
57
71
  return null;
58
72
  const result = { person };
59
- if (includeEmails) {
60
- result.emails = responses[1]?.data || [];
73
+ if (includeEmails && emailPromise) {
74
+ const emailsResponse = await emailPromise;
75
+ result.emails = emailsResponse.data || [];
61
76
  }
62
- if (includePhones) {
63
- result.phoneNumbers = responses[includeEmails ? 2 : 1]?.data || [];
77
+ if (includePhones && phonePromise) {
78
+ const phonesResponse = await phonePromise;
79
+ result.phoneNumbers = phonesResponse.data || [];
64
80
  }
65
81
  return { personId, result };
66
82
  }));
@@ -70,7 +86,7 @@ async function batchFetchPersonDetails(client, personIds, options = {}) {
70
86
  }
71
87
  });
72
88
  return batchResults; // Return for processInBatches
73
- });
89
+ }, { client });
74
90
  return results;
75
91
  }
76
92
  // ===== Caching =====
@@ -111,12 +127,17 @@ exports.ApiCache = ApiCache;
111
127
  * Cached version of getPeople with configurable TTL
112
128
  */
113
129
  async function getCachedPeople(client, cache, params = {}, ttlMs = 300000) {
130
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(typeof client.getConfig === 'function'
131
+ ? client.getConfig()
132
+ : undefined);
133
+ if (logger.enabled)
134
+ logger.log('performance.getCachedPeople', { params, ttlMs });
114
135
  const cacheKey = `people:${JSON.stringify(params)}`;
115
136
  const cached = cache.get(cacheKey);
116
137
  if (cached) {
117
138
  return cached;
118
139
  }
119
- const result = await (0, people_1.getPeople)(client, params);
140
+ const result = await client.people.getAll(params);
120
141
  cache.set(cacheKey, result, ttlMs);
121
142
  return result;
122
143
  }
@@ -125,6 +146,11 @@ async function getCachedPeople(client, cache, params = {}, ttlMs = 300000) {
125
146
  * Efficiently fetch all pages of data with progress tracking
126
147
  */
127
148
  async function fetchAllPages(client, fetchFunction, options = {}) {
149
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(typeof client.getConfig === 'function'
150
+ ? client.getConfig()
151
+ : undefined);
152
+ if (logger.enabled)
153
+ logger.log('performance.fetchAllPages', { options });
128
154
  const { maxPages = 1000, onProgress, perPage = 100 } = options;
129
155
  const allData = [];
130
156
  let page = 1;
@@ -152,6 +178,11 @@ async function fetchAllPages(client, fetchFunction, options = {}) {
152
178
  * Stream large datasets with backpressure control
153
179
  */
154
180
  async function* streamPeopleData(client, options = {}) {
181
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(typeof client.getConfig === 'function'
182
+ ? client.getConfig()
183
+ : undefined);
184
+ if (logger.enabled)
185
+ logger.log('performance.streamPeopleData', { options });
155
186
  const { include = [], maxConcurrent = 3, perPage = 50, where = {} } = options;
156
187
  let page = 1;
157
188
  let hasMore = true;
@@ -159,10 +190,10 @@ async function* streamPeopleData(client, options = {}) {
159
190
  while (hasMore) {
160
191
  await semaphore.acquire();
161
192
  try {
162
- const response = await (0, people_1.getPeople)(client, {
163
- include,
193
+ const response = await client.people.getPage({
194
+ include: include,
164
195
  page,
165
- per_page: perPage,
196
+ perPage,
166
197
  where,
167
198
  });
168
199
  yield response.data;
@@ -203,6 +234,11 @@ class Semaphore {
203
234
  * Process large datasets without loading everything into memory
204
235
  */
205
236
  async function processLargeDataset(client, fetchFunction, processor, options = {}) {
237
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(typeof client.getConfig === 'function'
238
+ ? client.getConfig()
239
+ : undefined);
240
+ if (logger.enabled)
241
+ logger.log('performance.processLargeDataset', { options });
206
242
  const { maxMemoryItems = 1000, onBatchProcessed, perPage = 100 } = options;
207
243
  const allResults = [];
208
244
  let page = 1;
@@ -37,6 +37,7 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  })();
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.RequestRecorder = void 0;
40
+ const planning_center_base_ts_1 = require("@rachelallyson/planning-center-base-ts");
40
41
  const fs = __importStar(require("fs"));
41
42
  const path = __importStar(require("path"));
42
43
  class RequestRecorder {
@@ -133,7 +134,11 @@ class RequestRecorder {
133
134
  fs.writeFileSync(this.config.recordPath, JSON.stringify(session, null, 2));
134
135
  }
135
136
  catch (error) {
136
- console.error('Failed to save recording session:', error);
137
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(this.config.getConfig?.());
138
+ if (logger.enabled)
139
+ logger.log('recorder failed to save recording session', { error: String(error) });
140
+ else
141
+ console.error('Failed to save recording session:', error);
137
142
  }
138
143
  }
139
144
  /**
@@ -148,7 +153,11 @@ class RequestRecorder {
148
153
  return JSON.parse(content);
149
154
  }
150
155
  catch (error) {
151
- console.error('Failed to load recording session:', error);
156
+ const logger = (0, planning_center_base_ts_1.createDebugLogger)(this.config.getConfig?.());
157
+ if (logger.enabled)
158
+ logger.log('recorder failed to load recording session', { error: String(error) });
159
+ else
160
+ console.error('Failed to load recording session:', error);
152
161
  return null;
153
162
  }
154
163
  }
@@ -1,21 +1,23 @@
1
1
  /**
2
2
  * Simplified Mock Response Builders for Testing
3
+ *
4
+ * Builders return flattened shape (same as API): attributes and relationships at top level.
3
5
  */
4
6
  export declare class SimpleMockResponseBuilder {
5
7
  /**
6
- * Build a simple mock person resource
8
+ * Build a simple mock person resource (flattened shape)
7
9
  */
8
10
  static person(overrides?: any): any;
9
11
  /**
10
- * Build a simple mock email resource
12
+ * Build a simple mock email resource (flattened shape)
11
13
  */
12
14
  static email(overrides?: any): any;
13
15
  /**
14
- * Build a simple mock phone number resource
16
+ * Build a simple mock phone number resource (flattened shape)
15
17
  */
16
18
  static phoneNumber(overrides?: any): any;
17
19
  /**
18
- * Build a simple mock workflow resource
20
+ * Build a simple mock workflow resource (flattened shape)
19
21
  */
20
22
  static workflow(overrides?: any): any;
21
23
  /**
@@ -1,85 +1,72 @@
1
1
  "use strict";
2
2
  /**
3
3
  * Simplified Mock Response Builders for Testing
4
+ *
5
+ * Builders return flattened shape (same as API): attributes and relationships at top level.
4
6
  */
5
7
  Object.defineProperty(exports, "__esModule", { value: true });
6
8
  exports.SimpleMockResponseBuilder = void 0;
7
9
  class SimpleMockResponseBuilder {
8
10
  /**
9
- * Build a simple mock person resource
11
+ * Build a simple mock person resource (flattened shape)
10
12
  */
11
13
  static person(overrides = {}) {
14
+ const id = overrides.id || `person_${Date.now()}`;
12
15
  return {
13
16
  type: 'Person',
14
- id: overrides.id || `person_${Date.now()}`,
15
- attributes: {
16
- id: overrides.id || `person_${Date.now()}`,
17
- first_name: overrides.first_name || 'John',
18
- last_name: overrides.last_name || 'Doe',
19
- status: 'active',
20
- ...overrides,
21
- },
22
- relationships: {
23
- emails: { data: [] },
24
- phone_numbers: { data: [] },
25
- field_data: { data: [] },
26
- workflow_cards: { data: [] },
27
- household: { data: null },
28
- },
17
+ id,
18
+ first_name: overrides.first_name ?? 'John',
19
+ last_name: overrides.last_name ?? 'Doe',
20
+ status: 'active',
21
+ ...overrides,
22
+ emails: [],
23
+ phone_numbers: [],
24
+ field_data: [],
25
+ workflow_cards: [],
26
+ household: null,
29
27
  };
30
28
  }
31
29
  /**
32
- * Build a simple mock email resource
30
+ * Build a simple mock email resource (flattened shape)
33
31
  */
34
32
  static email(overrides = {}) {
33
+ const id = overrides.id || `email_${Date.now()}`;
35
34
  return {
36
35
  type: 'Email',
37
- id: overrides.id || `email_${Date.now()}`,
38
- attributes: {
39
- id: overrides.id || `email_${Date.now()}`,
40
- address: overrides.address || 'john@example.com',
41
- location: 'Home',
42
- primary: true,
43
- ...overrides,
44
- },
45
- relationships: {
46
- person: { data: { type: 'Person', id: 'person_123' } },
47
- },
36
+ id,
37
+ address: overrides.address ?? 'john@gmail.com',
38
+ location: 'Home',
39
+ primary: true,
40
+ ...overrides,
41
+ person: { type: 'Person', id: 'person_123' },
48
42
  };
49
43
  }
50
44
  /**
51
- * Build a simple mock phone number resource
45
+ * Build a simple mock phone number resource (flattened shape)
52
46
  */
53
47
  static phoneNumber(overrides = {}) {
48
+ const id = overrides.id || `phone_${Date.now()}`;
54
49
  return {
55
50
  type: 'PhoneNumber',
56
- id: overrides.id || `phone_${Date.now()}`,
57
- attributes: {
58
- id: overrides.id || `phone_${Date.now()}`,
59
- number: overrides.number || '555-1234',
60
- location: 'Mobile',
61
- primary: true,
62
- ...overrides,
63
- },
64
- relationships: {
65
- person: { data: { type: 'Person', id: 'person_123' } },
66
- },
51
+ id,
52
+ number: overrides.number ?? '555-1234',
53
+ location: 'Mobile',
54
+ primary: true,
55
+ ...overrides,
56
+ person: { type: 'Person', id: 'person_123' },
67
57
  };
68
58
  }
69
59
  /**
70
- * Build a simple mock workflow resource
60
+ * Build a simple mock workflow resource (flattened shape)
71
61
  */
72
62
  static workflow(overrides = {}) {
63
+ const id = overrides.id || `workflow_${Date.now()}`;
73
64
  return {
74
65
  type: 'Workflow',
75
- id: overrides.id || `workflow_${Date.now()}`,
76
- attributes: {
77
- id: overrides.id || `workflow_${Date.now()}`,
78
- name: overrides.name || 'New Member Workflow',
79
- description: overrides.description || 'Workflow for new members',
80
- ...overrides,
81
- },
82
- relationships: {},
66
+ id,
67
+ name: overrides.name ?? 'New Member Workflow',
68
+ description: overrides.description ?? 'Workflow for new members',
69
+ ...overrides,
83
70
  };
84
71
  }
85
72
  /**
@@ -141,6 +141,10 @@ export interface RecordingConfig {
141
141
  filter?: (endpoint: string, method: string) => boolean;
142
142
  /** Transform recorded responses */
143
143
  transform?: (response: any) => any;
144
+ /** Optional getConfig for debug logging (e.g. when recording client has debug) */
145
+ getConfig?: () => {
146
+ debug?: boolean | import('@rachelallyson/planning-center-base-ts').PcoDebugOptions;
147
+ };
144
148
  }
145
149
  export interface RecordedRequest {
146
150
  endpoint: string;