@rachelallyson/planning-center-people-ts 2.0.0 → 2.2.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,148 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.2.0] - 2025-01-17
9
+
10
+ ### 🏢 **NEW FEATURE - Campus Management Support**
11
+
12
+ This release adds comprehensive Campus management functionality to the Planning Center People API client.
13
+
14
+ ### Added
15
+
16
+ #### **🏢 Campus Module**
17
+
18
+ - **Complete Campus CRUD Operations**: Create, read, update, and delete campuses
19
+ - **Campus-Specific Operations**: Get campus lists and service times
20
+ - **Type-Safe Campus Resource**: Full TypeScript support for campus attributes and relationships
21
+ - **Pagination Support**: Automatic pagination for campus listings
22
+
23
+ #### **📋 Campus Operations**
24
+
25
+ - `client.campus.getAll()` - Get all campuses with filtering and pagination
26
+ - `client.campus.getById(id, include?)` - Get specific campus by ID
27
+ - `client.campus.create(data)` - Create new campus
28
+ - `client.campus.update(id, data)` - Update existing campus
29
+ - `client.campus.delete(id)` - Delete campus
30
+ - `client.campus.getLists(campusId)` - Get lists for a specific campus
31
+ - `client.campus.getServiceTimes(campusId)` - Get service times for a specific campus
32
+ - `client.campus.getAllPagesPaginated()` - Get all campuses with automatic pagination
33
+
34
+ #### **🏗️ Campus Resource Structure**
35
+
36
+ - **Location Data**: `latitude`, `longitude`, `street`, `city`, `state`, `zip`, `country`
37
+ - **Contact Information**: `phone_number`, `website`
38
+ - **Settings**: `twenty_four_hour_time`, `date_format`, `church_center_enabled`
39
+ - **Metadata**: `description`, `created_at`, `updated_at`
40
+
41
+ ### Documentation
42
+
43
+ - **Updated README.md** with Campus Management examples
44
+ - **Updated EXAMPLES.md** with comprehensive Campus usage patterns
45
+ - **Updated API_REFERENCE.md** with complete Campus Module documentation
46
+ - **Added Campus types** to resource types documentation
47
+
48
+ ### Testing
49
+
50
+ - **Integration Tests**: Complete test suite for Campus operations
51
+ - **Type Safety**: Full TypeScript coverage for Campus resources
52
+ - **Error Handling**: Comprehensive error handling for Campus operations
53
+
54
+ ### Example Usage
55
+
56
+ ```typescript
57
+ import { PcoClient } from '@rachelallyson/planning-center-people-ts';
58
+
59
+ const client = new PcoClient({
60
+ auth: {
61
+ type: 'personal_access_token',
62
+ personalAccessToken: 'your-token'
63
+ }
64
+ });
65
+
66
+ // Get all campuses
67
+ const campuses = await client.campus.getAll();
68
+
69
+ // Create new campus
70
+ const newCampus = await client.campus.create({
71
+ description: 'Main Campus',
72
+ street: '123 Church Street',
73
+ city: 'Anytown',
74
+ state: 'CA',
75
+ zip: '12345',
76
+ country: 'US',
77
+ phone_number: '555-123-4567',
78
+ website: 'https://maincampus.example.com',
79
+ twenty_four_hour_time: false,
80
+ date_format: 1,
81
+ church_center_enabled: true
82
+ });
83
+
84
+ // Get campus-specific data
85
+ const campusLists = await client.campus.getLists('campus-id');
86
+ const serviceTimes = await client.campus.getServiceTimes('campus-id');
87
+ ```
88
+
89
+ ## [2.1.0] - 2025-01-17
90
+
91
+ ### 🔒 **SECURITY RELEASE - Required Refresh Token Handling**
92
+
93
+ This release addresses a critical security issue where OAuth 2.0 clients could lose access when tokens expire without proper refresh handling.
94
+
95
+ ### Breaking Changes
96
+
97
+ - **OAuth 2.0 Authentication**: `onRefresh` and `onRefreshFailure` callbacks are now **required** for OAuth configurations
98
+ - **Type Safety**: Enhanced type-safe authentication configuration prevents invalid configurations at compile time
99
+
100
+ ### Security
101
+
102
+ - **CRITICAL**: OAuth 2.0 authentication now requires refresh token handling to prevent token loss
103
+ - **BREAKING**: Type-safe authentication configuration enforces required fields
104
+ - Enhanced token refresh implementation with proper error handling
105
+ - Improved authentication type safety with union types
106
+
107
+ ### Fixed
108
+
109
+ - Fixed person matching to properly handle default fuzzy strategy
110
+ - Fixed mock client to support createWithContacts method
111
+ - Fixed event system tests to work with mock client
112
+ - Fixed phone number builder in mock response builder
113
+
114
+ ### Migration from v2.0.0
115
+
116
+ **Before (v2.0.0):**
117
+
118
+ ```typescript
119
+ const client = new PcoClient({
120
+ auth: {
121
+ type: 'oauth',
122
+ accessToken: 'access-token',
123
+ refreshToken: 'refresh-token'
124
+ // Missing required callbacks - this will now cause TypeScript errors
125
+ }
126
+ });
127
+ ```
128
+
129
+ **After (v2.1.0):**
130
+
131
+ ```typescript
132
+ const client = new PcoClient({
133
+ auth: {
134
+ type: 'oauth',
135
+ accessToken: 'access-token',
136
+ refreshToken: 'refresh-token',
137
+ // REQUIRED: Handle token refresh to prevent token loss
138
+ onRefresh: async (tokens) => {
139
+ await saveTokensToDatabase(userId, tokens);
140
+ },
141
+ // REQUIRED: Handle refresh failures
142
+ onRefreshFailure: async (error) => {
143
+ console.error('Token refresh failed:', error.message);
144
+ await clearUserTokens(userId);
145
+ }
146
+ }
147
+ });
148
+ ```
149
+
8
150
  ## [2.0.0] - 2025-01-17
9
151
 
10
152
  ### 🚀 **MAJOR RELEASE - Complete API Redesign**
@@ -120,6 +262,10 @@ const person = await client.people.create({ first_name: 'John', last_name: 'Doe'
120
262
  - **Error Handling**: Improved error handling and retry logic
121
263
  - **Rate Limiting**: Fixed rate limiting edge cases
122
264
  - **Authentication**: Resolved token refresh and persistence issues
265
+ - Fixed person matching to properly handle default fuzzy strategy
266
+ - Fixed mock client to support createWithContacts method
267
+ - Fixed event system tests to work with mock client
268
+ - Fixed phone number builder in mock response builder
123
269
 
124
270
  ## [1.1.0] - 2025-10-08
125
271
 
@@ -119,9 +119,9 @@ class PcoClientManager {
119
119
  // Create a hash of the configuration
120
120
  const configStr = JSON.stringify({
121
121
  authType: config.auth.type,
122
- hasAccessToken: !!config.auth.accessToken,
123
- hasRefreshToken: !!config.auth.refreshToken,
124
- hasPersonalAccessToken: !!config.auth.personalAccessToken,
122
+ hasAccessToken: config.auth.type === 'oauth' ? !!config.auth.accessToken : false,
123
+ hasRefreshToken: config.auth.type === 'oauth' ? !!config.auth.refreshToken : false,
124
+ hasPersonalAccessToken: config.auth.type === 'personal_access_token' ? !!config.auth.personalAccessToken : false,
125
125
  baseURL: config.baseURL,
126
126
  timeout: config.timeout,
127
127
  });
@@ -139,11 +139,17 @@ class PcoClientManager {
139
139
  */
140
140
  hasConfigChanged(oldConfig, newConfig) {
141
141
  // Compare key configuration properties
142
- return (oldConfig.auth.type !== newConfig.auth.type ||
143
- oldConfig.auth.accessToken !== newConfig.auth.accessToken ||
144
- oldConfig.auth.refreshToken !== newConfig.auth.refreshToken ||
145
- oldConfig.auth.personalAccessToken !== newConfig.auth.personalAccessToken ||
146
- oldConfig.baseURL !== newConfig.baseURL ||
142
+ if (oldConfig.auth.type !== newConfig.auth.type) {
143
+ return true;
144
+ }
145
+ if (oldConfig.auth.type === 'oauth' && newConfig.auth.type === 'oauth') {
146
+ return (oldConfig.auth.accessToken !== newConfig.auth.accessToken ||
147
+ oldConfig.auth.refreshToken !== newConfig.auth.refreshToken);
148
+ }
149
+ if (oldConfig.auth.type === 'personal_access_token' && newConfig.auth.type === 'personal_access_token') {
150
+ return oldConfig.auth.personalAccessToken !== newConfig.auth.personalAccessToken;
151
+ }
152
+ return (oldConfig.baseURL !== newConfig.baseURL ||
147
153
  oldConfig.timeout !== newConfig.timeout);
148
154
  }
149
155
  }
package/dist/client.d.ts CHANGED
@@ -10,6 +10,7 @@ import { ContactsModule } from './modules/contacts';
10
10
  import { HouseholdsModule } from './modules/households';
11
11
  import { NotesModule } from './modules/notes';
12
12
  import { ListsModule } from './modules/lists';
13
+ import { CampusModule } from './modules/campus';
13
14
  import { BatchExecutor } from './batch';
14
15
  export declare class PcoClient implements EventEmitter {
15
16
  people: PeopleModule;
@@ -19,6 +20,7 @@ export declare class PcoClient implements EventEmitter {
19
20
  households: HouseholdsModule;
20
21
  notes: NotesModule;
21
22
  lists: ListsModule;
23
+ campus: CampusModule;
22
24
  batch: BatchExecutor;
23
25
  private httpClient;
24
26
  private paginationHelper;
package/dist/client.js CHANGED
@@ -14,6 +14,7 @@ const contacts_1 = require("./modules/contacts");
14
14
  const households_1 = require("./modules/households");
15
15
  const notes_1 = require("./modules/notes");
16
16
  const lists_1 = require("./modules/lists");
17
+ const campus_1 = require("./modules/campus");
17
18
  const batch_1 = require("./batch");
18
19
  class PcoClient {
19
20
  constructor(config) {
@@ -29,6 +30,7 @@ class PcoClient {
29
30
  this.households = new households_1.HouseholdsModule(this.httpClient, this.paginationHelper, this.eventEmitter);
30
31
  this.notes = new notes_1.NotesModule(this.httpClient, this.paginationHelper, this.eventEmitter);
31
32
  this.lists = new lists_1.ListsModule(this.httpClient, this.paginationHelper, this.eventEmitter);
33
+ this.campus = new campus_1.CampusModule(this.httpClient, this.paginationHelper, this.eventEmitter);
32
34
  this.batch = new batch_1.BatchExecutor(this, this.eventEmitter);
33
35
  // Set up event handlers from config
34
36
  this.setupEventHandlers();
@@ -31,6 +31,7 @@ export declare class PcoHttpClient {
31
31
  private addAuthentication;
32
32
  private getResourceTypeFromEndpoint;
33
33
  private extractHeaders;
34
+ private attemptTokenRefresh;
34
35
  private updateRateLimitTracking;
35
36
  getPerformanceMetrics(): Record<string, {
36
37
  count: number;
package/dist/core/http.js CHANGED
@@ -7,7 +7,6 @@ exports.PcoHttpClient = void 0;
7
7
  const monitoring_1 = require("../monitoring");
8
8
  const rate_limiter_1 = require("../rate-limiter");
9
9
  const api_error_1 = require("../api-error");
10
- const auth_1 = require("../auth");
11
10
  class PcoHttpClient {
12
11
  constructor(config, eventEmitter) {
13
12
  this.config = config;
@@ -139,20 +138,15 @@ class PcoHttpClient {
139
138
  // Handle other errors
140
139
  if (!response.ok) {
141
140
  // Handle 401 errors with token refresh if available
142
- // Convert v2.0 config to v1.x format for auth functions
143
- const v1Config = {
144
- refreshToken: this.config.auth.refreshToken,
145
- onTokenRefresh: this.config.auth.onRefresh,
146
- onTokenRefreshFailure: this.config.auth.onRefreshFailure,
147
- };
148
- const clientState = { config: v1Config, rateLimiter: this.rateLimiter };
149
- if (response.status === 401 && (0, auth_1.hasRefreshTokenCapability)(clientState)) {
141
+ if (response.status === 401 && this.config.auth.type === 'oauth') {
150
142
  try {
151
- await (0, auth_1.attemptTokenRefresh)(clientState, () => this.makeRequest(options, requestId));
143
+ await this.attemptTokenRefresh();
152
144
  return this.makeRequest(options, requestId);
153
145
  }
154
146
  catch (refreshError) {
155
147
  console.warn('Token refresh failed:', refreshError);
148
+ // Call the onRefreshFailure callback
149
+ await this.config.auth.onRefreshFailure(refreshError);
156
150
  }
157
151
  }
158
152
  let errorData;
@@ -189,12 +183,12 @@ class PcoHttpClient {
189
183
  }
190
184
  }
191
185
  addAuthentication(headers) {
192
- if (this.config.auth.personalAccessToken) {
186
+ if (this.config.auth.type === 'personal_access_token') {
193
187
  // Personal Access Tokens use HTTP Basic Auth format: app_id:secret
194
188
  // The personalAccessToken should be in the format "app_id:secret"
195
189
  headers.Authorization = `Basic ${Buffer.from(this.config.auth.personalAccessToken).toString('base64')}`;
196
190
  }
197
- else if (this.config.auth.accessToken) {
191
+ else if (this.config.auth.type === 'oauth') {
198
192
  headers.Authorization = `Bearer ${this.config.auth.accessToken}`;
199
193
  }
200
194
  }
@@ -224,6 +218,35 @@ class PcoHttpClient {
224
218
  });
225
219
  return headers;
226
220
  }
221
+ async attemptTokenRefresh() {
222
+ if (this.config.auth.type !== 'oauth') {
223
+ throw new Error('Token refresh is only available for OAuth authentication');
224
+ }
225
+ const baseURL = this.config.baseURL || 'https://api.planningcenteronline.com/people/v2';
226
+ const tokenUrl = baseURL.replace('/people/v2', '/oauth/token');
227
+ const response = await fetch(tokenUrl, {
228
+ method: 'POST',
229
+ headers: {
230
+ 'Content-Type': 'application/x-www-form-urlencoded',
231
+ },
232
+ body: new URLSearchParams({
233
+ grant_type: 'refresh_token',
234
+ refresh_token: this.config.auth.refreshToken,
235
+ }),
236
+ });
237
+ if (!response.ok) {
238
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText}`);
239
+ }
240
+ const tokens = await response.json();
241
+ // Update the config with new tokens
242
+ this.config.auth.accessToken = tokens.access_token;
243
+ this.config.auth.refreshToken = tokens.refresh_token;
244
+ // Call the onRefresh callback
245
+ await this.config.auth.onRefresh({
246
+ accessToken: tokens.access_token,
247
+ refreshToken: tokens.refresh_token,
248
+ });
249
+ }
227
250
  updateRateLimitTracking(endpoint, headers) {
228
251
  const limit = headers['x-pco-api-request-rate-limit'];
229
252
  const remaining = headers['x-pco-api-request-rate-count'];
package/dist/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  export { PcoClient } from './client';
2
2
  export { PcoClientManager } from './client-manager';
3
- export type { PcoClientConfig } from './types/client';
3
+ export type { PcoClientConfig, PcoAuthConfig, PersonalAccessTokenAuth, OAuthAuth } from './types/client';
4
4
  export type { PcoEvent, EventHandler, EventType } from './types/events';
5
5
  export type { BatchOperation, BatchResult, BatchOptions, BatchSummary } from './types/batch';
6
6
  export type { Paginated, Relationship, ResourceIdentifier, ResourceObject, } from './types';
7
7
  export type { PersonResource, PersonAttributes, PersonSingle, PeopleList, EmailResource, EmailAttributes, PhoneNumberResource, PhoneNumberAttributes, AddressResource, AddressAttributes, SocialProfileResource, SocialProfileAttributes, } from './types';
8
8
  export type { FieldDefinitionResource, FieldDefinitionAttributes, FieldDatumResource, FieldDatumAttributes, FieldOptionResource, FieldOptionAttributes, TabResource, TabAttributes, } from './types';
9
9
  export type { WorkflowResource, WorkflowAttributes, WorkflowCardResource, WorkflowCardAttributes, WorkflowCardNoteResource, WorkflowCardNoteAttributes, } from './types';
10
- export type { HouseholdResource, HouseholdAttributes, NoteResource, NoteAttributes, ListResource, ListAttributes, OrganizationResource, OrganizationAttributes, } from './types';
10
+ export type { HouseholdResource, HouseholdAttributes, NoteResource, NoteAttributes, ListResource, ListAttributes, OrganizationResource, OrganizationAttributes, CampusResource, CampusAttributes, CampusesList, } from './types';
11
11
  export * from './types';
12
12
  export type { PcoClientConfig as PcoClientConfigV1, PcoClientState } from './core';
13
13
  export { createPcoClient, del, getAllPages, getList, getRateLimitInfo, getSingle, patch, post, } from './core';
@@ -0,0 +1,63 @@
1
+ import { BaseModule } from './base';
2
+ import type { PcoHttpClient } from '../core/http';
3
+ import type { PaginationHelper } from '../core/pagination';
4
+ import type { PcoEventEmitter } from '../monitoring';
5
+ import type { PaginationOptions, PaginationResult } from '../core/pagination';
6
+ import type { CampusResource, CampusAttributes, CampusesList } from '../types';
7
+ /**
8
+ * Campus module for managing campus-related operations
9
+ */
10
+ export declare class CampusModule extends BaseModule {
11
+ constructor(httpClient: PcoHttpClient, paginationHelper: PaginationHelper, eventEmitter: PcoEventEmitter);
12
+ /**
13
+ * Get all campuses
14
+ */
15
+ getAll(params?: {
16
+ where?: Record<string, any>;
17
+ include?: string[];
18
+ per_page?: number;
19
+ page?: number;
20
+ }): Promise<CampusesList>;
21
+ /**
22
+ * Get a specific campus by ID
23
+ */
24
+ getById(id: string, include?: string[]): Promise<CampusResource>;
25
+ /**
26
+ * Create a new campus
27
+ */
28
+ create(data: CampusAttributes): Promise<CampusResource>;
29
+ /**
30
+ * Update an existing campus
31
+ */
32
+ update(id: string, data: Partial<CampusAttributes>): Promise<CampusResource>;
33
+ /**
34
+ * Delete a campus
35
+ */
36
+ delete(id: string): Promise<void>;
37
+ /**
38
+ * Get lists for a specific campus
39
+ */
40
+ getLists(campusId: string, params?: {
41
+ where?: Record<string, any>;
42
+ include?: string[];
43
+ per_page?: number;
44
+ page?: number;
45
+ }): Promise<any>;
46
+ /**
47
+ * Get service times for a specific campus
48
+ */
49
+ getServiceTimes(campusId: string, params?: {
50
+ where?: Record<string, any>;
51
+ include?: string[];
52
+ per_page?: number;
53
+ page?: number;
54
+ }): Promise<any>;
55
+ /**
56
+ * Get all campuses with pagination support
57
+ */
58
+ getAllPagesPaginated(params?: {
59
+ where?: Record<string, any>;
60
+ include?: string[];
61
+ per_page?: number;
62
+ }, paginationOptions?: PaginationOptions): Promise<PaginationResult<CampusResource>>;
63
+ }
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CampusModule = void 0;
4
+ const base_1 = require("./base");
5
+ /**
6
+ * Campus module for managing campus-related operations
7
+ */
8
+ class CampusModule extends base_1.BaseModule {
9
+ constructor(httpClient, paginationHelper, eventEmitter) {
10
+ super(httpClient, paginationHelper, eventEmitter);
11
+ }
12
+ /**
13
+ * Get all campuses
14
+ */
15
+ async getAll(params) {
16
+ return this.getList('/campuses', params);
17
+ }
18
+ /**
19
+ * Get a specific campus by ID
20
+ */
21
+ async getById(id, include) {
22
+ const params = {};
23
+ if (include) {
24
+ params.include = include.join(',');
25
+ }
26
+ return this.getSingle(`/campuses/${id}`, params);
27
+ }
28
+ /**
29
+ * Create a new campus
30
+ */
31
+ async create(data) {
32
+ return this.createResource('/campuses', data);
33
+ }
34
+ /**
35
+ * Update an existing campus
36
+ */
37
+ async update(id, data) {
38
+ return this.updateResource(`/campuses/${id}`, data);
39
+ }
40
+ /**
41
+ * Delete a campus
42
+ */
43
+ async delete(id) {
44
+ return this.deleteResource(`/campuses/${id}`);
45
+ }
46
+ /**
47
+ * Get lists for a specific campus
48
+ */
49
+ async getLists(campusId, params) {
50
+ return this.getList(`/campuses/${campusId}/lists`, params);
51
+ }
52
+ /**
53
+ * Get service times for a specific campus
54
+ */
55
+ async getServiceTimes(campusId, params) {
56
+ return this.getList(`/campuses/${campusId}/service_times`, params);
57
+ }
58
+ /**
59
+ * Get all campuses with pagination support
60
+ */
61
+ async getAllPagesPaginated(params, paginationOptions) {
62
+ const queryParams = {};
63
+ if (params?.where) {
64
+ Object.entries(params.where).forEach(([key, value]) => {
65
+ queryParams[`where[${key}]`] = value;
66
+ });
67
+ }
68
+ if (params?.include) {
69
+ queryParams.include = params.include.join(',');
70
+ }
71
+ if (params?.per_page) {
72
+ queryParams.per_page = params.per_page;
73
+ }
74
+ return this.getAllPages('/campuses', queryParams, paginationOptions);
75
+ }
76
+ }
77
+ exports.CampusModule = CampusModule;
@@ -181,6 +181,9 @@ function createTestClient(overrides = {}) {
181
181
  auth: {
182
182
  type: 'oauth',
183
183
  accessToken: 'test-token',
184
+ refreshToken: 'test-refresh-token',
185
+ onRefresh: async () => { },
186
+ onRefreshFailure: async () => { },
184
187
  },
185
188
  };
186
189
  const defaultMockConfig = {
@@ -239,6 +242,9 @@ function createErrorMockClient(errorType = 'network') {
239
242
  auth: {
240
243
  type: 'oauth',
241
244
  accessToken: 'test-token',
245
+ refreshToken: 'test-refresh-token',
246
+ onRefresh: async () => { },
247
+ onRefreshFailure: async () => { },
242
248
  },
243
249
  };
244
250
  const errorMockConfig = {
@@ -260,6 +266,9 @@ function createSlowMockClient(delayMs = 1000) {
260
266
  auth: {
261
267
  type: 'oauth',
262
268
  accessToken: 'test-token',
269
+ refreshToken: 'test-refresh-token',
270
+ onRefresh: async () => { },
271
+ onRefreshFailure: async () => { },
263
272
  },
264
273
  };
265
274
  const slowMockConfig = {
@@ -1,19 +1,27 @@
1
1
  /**
2
2
  * v2.0.0 Client Configuration Types
3
3
  */
4
+ /** Authentication configuration for Personal Access Token */
5
+ export interface PersonalAccessTokenAuth {
6
+ type: 'personal_access_token';
7
+ personalAccessToken: string;
8
+ }
9
+ /** Authentication configuration for OAuth 2.0 with required refresh handling */
10
+ export interface OAuthAuth {
11
+ type: 'oauth';
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ onRefresh: (tokens: {
15
+ accessToken: string;
16
+ refreshToken: string;
17
+ }) => void | Promise<void>;
18
+ onRefreshFailure: (error: Error) => void | Promise<void>;
19
+ }
20
+ /** Union type for authentication configurations */
21
+ export type PcoAuthConfig = PersonalAccessTokenAuth | OAuthAuth;
4
22
  export interface PcoClientConfig {
5
23
  /** Authentication configuration */
6
- auth: {
7
- type: 'oauth' | 'personal_access_token';
8
- accessToken?: string;
9
- refreshToken?: string;
10
- personalAccessToken?: string;
11
- onRefresh?: (tokens: {
12
- accessToken: string;
13
- refreshToken?: string;
14
- }) => void | Promise<void>;
15
- onRefreshFailure?: (error: Error) => void | Promise<void>;
16
- };
24
+ auth: PcoAuthConfig;
17
25
  /** Caching configuration */
18
26
  caching?: {
19
27
  fieldDefinitions?: boolean;
@@ -376,4 +376,28 @@ export interface OrganizationStatisticResource extends ResourceObject<'Organizat
376
376
  }
377
377
  export type OrganizationStatisticsList = Paginated<OrganizationStatisticResource>;
378
378
  export type OrganizationStatisticSingle = Response<OrganizationStatisticResource>;
379
- export type PeopleIncluded = EmailResource | AddressResource | PhoneNumberResource | HouseholdResource | SocialProfileResource | FieldDatumResource | TabResource;
379
+ export interface CampusAttributes extends Attributes {
380
+ latitude?: number;
381
+ longitude?: number;
382
+ description?: string;
383
+ street?: string;
384
+ city?: string;
385
+ state?: string;
386
+ zip?: string;
387
+ country?: string;
388
+ phone_number?: string;
389
+ website?: string;
390
+ twenty_four_hour_time?: boolean;
391
+ date_format?: number;
392
+ church_center_enabled?: boolean;
393
+ created_at?: string;
394
+ updated_at?: string;
395
+ }
396
+ export interface CampusRelationships {
397
+ organization?: Relationship;
398
+ }
399
+ export interface CampusResource extends ResourceObject<'Campus', CampusAttributes, CampusRelationships> {
400
+ }
401
+ export type CampusesList = Paginated<CampusResource>;
402
+ export type CampusSingle = Response<CampusResource>;
403
+ export type PeopleIncluded = EmailResource | AddressResource | PhoneNumberResource | HouseholdResource | SocialProfileResource | FieldDatumResource | TabResource | CampusResource;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rachelallyson/planning-center-people-ts",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "A strictly typed TypeScript client for Planning Center Online People API with smart matching, batch operations, and enhanced developer experience",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",