@rachelallyson/planning-center-people-ts 2.3.1 → 2.5.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 +179 -0
- package/dist/core/http.js +21 -5
- package/dist/helpers.d.ts +25 -0
- package/dist/helpers.js +69 -0
- package/dist/matching/matcher.d.ts +4 -0
- package/dist/matching/matcher.js +25 -1
- package/dist/matching/scoring.d.ts +5 -1
- package/dist/matching/scoring.js +83 -15
- package/dist/modules/people.d.ts +93 -9
- package/dist/modules/people.js +203 -6
- package/dist/types/client.d.ts +11 -1
- package/dist/types/people.d.ts +6 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,185 @@ 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.5.0] - 2025-01-10
|
|
9
|
+
|
|
10
|
+
### 🎯 **NEW FEATURES - Person Relationship Management & Token Refresh Fix**
|
|
11
|
+
|
|
12
|
+
This release introduces comprehensive person relationship management endpoints and fixes critical token refresh issues, significantly enhancing the library's functionality and reliability.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
#### **👥 Person Relationship Management**
|
|
17
|
+
|
|
18
|
+
- **🏢 Campus Management**: Complete campus assignment and retrieval system
|
|
19
|
+
- `getPrimaryCampus(personId)` - Get person's current campus
|
|
20
|
+
- `setPrimaryCampus(personId, campusId)` - Assign/update person's campus
|
|
21
|
+
- `removePrimaryCampus(personId)` - Remove campus assignment
|
|
22
|
+
- `getByCampus(campusId, options)` - Get all people in a campus
|
|
23
|
+
|
|
24
|
+
- **🏠 Household Management**: Full household membership system
|
|
25
|
+
- `getHousehold(personId)` - Get person's household
|
|
26
|
+
- `setHousehold(personId, householdId)` - Assign person to household
|
|
27
|
+
- `removeFromHousehold(personId)` - Remove person from household
|
|
28
|
+
- `getHouseholdMembers(householdId, options)` - Get all household members
|
|
29
|
+
|
|
30
|
+
- **📋 Related Data Access**: Comprehensive access to person-related data
|
|
31
|
+
- `getWorkflowCards(personId, options)` - Get person's workflow cards
|
|
32
|
+
- `getNotes(personId, options)` - Get person's notes
|
|
33
|
+
- `getFieldData(personId, options)` - Get person's field data
|
|
34
|
+
- `getSocialProfiles(personId, options)` - Get person's social profiles
|
|
35
|
+
|
|
36
|
+
#### **🔧 Enhanced Type System**
|
|
37
|
+
|
|
38
|
+
- **📝 Complete PersonRelationships**: Updated interface with all available relationships
|
|
39
|
+
- **🏷️ Type Safety**: Full TypeScript support for all relationship operations
|
|
40
|
+
- **🛡️ Null Handling**: Proper handling of optional relationships
|
|
41
|
+
- **📊 Resource Validation**: Enhanced relationship data validation
|
|
42
|
+
|
|
43
|
+
#### **🔐 Token Refresh Fix**
|
|
44
|
+
|
|
45
|
+
- **🚫 Fixed 401 Unauthorized**: Resolved token refresh failures by including client credentials
|
|
46
|
+
- **🔑 Client Credentials Support**: Added support for `clientId` and `clientSecret` in OAuth config
|
|
47
|
+
- **🌍 Environment Variables**: Support for `PCO_APP_ID` and `PCO_APP_SECRET` environment variables
|
|
48
|
+
- **🔄 Standardized Implementation**: Consistent token refresh across all HTTP clients
|
|
49
|
+
- **🛡️ Enhanced Error Handling**: Better error messages for token refresh failures
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **🔐 Token Refresh 401 Errors**: Fixed "Token refresh failed: 401 Unauthorized" by including required client credentials
|
|
54
|
+
- **🏗️ Missing Auth Types**: Added missing `BasicAuth` type to v2.0.0 client configuration
|
|
55
|
+
- **🔄 Inconsistent Implementations**: Standardized token refresh across `auth.ts` and `http.ts`
|
|
56
|
+
- **📝 Type Definitions**: Enhanced `PersonRelationships` interface with all available relationships
|
|
57
|
+
|
|
58
|
+
### Usage Examples
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Campus Management
|
|
62
|
+
const campus = await client.people.getPrimaryCampus('person-123');
|
|
63
|
+
await client.people.setPrimaryCampus('person-123', 'campus-456');
|
|
64
|
+
|
|
65
|
+
// Household Management
|
|
66
|
+
const household = await client.people.getHousehold('person-123');
|
|
67
|
+
await client.people.setHousehold('person-123', 'household-789');
|
|
68
|
+
|
|
69
|
+
// Related Data Access
|
|
70
|
+
const workflowCards = await client.people.getWorkflowCards('person-123');
|
|
71
|
+
const notes = await client.people.getNotes('person-123');
|
|
72
|
+
const fieldData = await client.people.getFieldData('person-123');
|
|
73
|
+
|
|
74
|
+
// Token Refresh with Client Credentials
|
|
75
|
+
const client = new PcoClient({
|
|
76
|
+
auth: {
|
|
77
|
+
type: 'oauth',
|
|
78
|
+
accessToken: 'your-token',
|
|
79
|
+
refreshToken: 'your-refresh-token',
|
|
80
|
+
clientId: 'your-app-id', // NEW: Client credentials
|
|
81
|
+
clientSecret: 'your-app-secret', // NEW: Client credentials
|
|
82
|
+
onRefresh: async (tokens) => { /* handle refresh */ },
|
|
83
|
+
onRefreshFailure: async (error) => { /* handle failure */ }
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Migration Guide
|
|
89
|
+
|
|
90
|
+
**From Direct API Calls:**
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Before: Complex direct API calls
|
|
94
|
+
const response = await client.httpClient.request({
|
|
95
|
+
method: 'PATCH',
|
|
96
|
+
endpoint: `/people/${personId}`,
|
|
97
|
+
data: { /* complex JSON structure */ }
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// After: Simple, intuitive methods
|
|
101
|
+
await client.people.setPrimaryCampus(personId, campusId);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Token Refresh Configuration:**
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Add client credentials to your OAuth configuration
|
|
108
|
+
const client = new PcoClient({
|
|
109
|
+
auth: {
|
|
110
|
+
type: 'oauth',
|
|
111
|
+
accessToken: 'your-token',
|
|
112
|
+
refreshToken: 'your-refresh-token',
|
|
113
|
+
clientId: process.env.PCO_APP_ID, // NEW
|
|
114
|
+
clientSecret: process.env.PCO_APP_SECRET, // NEW
|
|
115
|
+
onRefresh: async (tokens) => { /* save tokens */ },
|
|
116
|
+
onRefreshFailure: async (error) => { /* handle failure */ }
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## [2.4.0] - 2025-01-10
|
|
122
|
+
|
|
123
|
+
### 🎯 **NEW FEATURES - Age Preference Matching & Exact Name Matching**
|
|
124
|
+
|
|
125
|
+
This release introduces intelligent age-based person matching and precise name matching capabilities to enhance person discovery and reduce false positives.
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
|
|
129
|
+
#### **👥 Age Preference Matching**
|
|
130
|
+
|
|
131
|
+
- **🎂 Age-Based Filtering**: New `agePreference` option to prefer adults or children
|
|
132
|
+
- **📅 Age Range Matching**: Support for `minAge` and `maxAge` parameters for precise age targeting
|
|
133
|
+
- **🗓️ Birth Year Matching**: `birthYear` parameter for matching people born in specific years
|
|
134
|
+
- **🧮 Smart Age Calculation**: Enhanced age calculation with timezone-safe date handling
|
|
135
|
+
- **📊 Age-Based Scoring**: Age matching contributes 15% to overall match score for better accuracy
|
|
136
|
+
|
|
137
|
+
#### **🎯 Exact Name Matching**
|
|
138
|
+
|
|
139
|
+
- **✅ Precise Name Matching**: Only matches exact names, eliminating false positives from similar names
|
|
140
|
+
- **🔤 Case-Insensitive**: Maintains case-insensitive matching while ensuring exact character matching
|
|
141
|
+
- **⚡ Performance Optimized**: Simple string comparison for faster matching than fuzzy algorithms
|
|
142
|
+
- **🛡️ Reduced False Positives**: Prevents matching "Jon" when searching for "John"
|
|
143
|
+
|
|
144
|
+
#### **🔧 Enhanced Matching System**
|
|
145
|
+
|
|
146
|
+
- **📈 Improved Scoring Algorithm**: Updated scoring weights for better match prioritization
|
|
147
|
+
- **🎯 Candidate Filtering**: Age-based pre-filtering before scoring for more relevant results
|
|
148
|
+
- **📝 Enhanced Match Reasons**: More descriptive match explanations including age-based reasons
|
|
149
|
+
- **🧪 Comprehensive Testing**: 30+ new test cases covering age preferences and exact name matching
|
|
150
|
+
|
|
151
|
+
### Usage Examples
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
// Age preference matching
|
|
155
|
+
const adultPerson = await client.people.findOrCreate({
|
|
156
|
+
firstName: 'Jane',
|
|
157
|
+
lastName: 'Smith',
|
|
158
|
+
agePreference: 'adults', // Prefer 18+ years old
|
|
159
|
+
matchStrategy: 'fuzzy'
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Age range matching
|
|
163
|
+
const youngAdult = await client.people.findOrCreate({
|
|
164
|
+
firstName: 'Alice',
|
|
165
|
+
lastName: 'Brown',
|
|
166
|
+
minAge: 20,
|
|
167
|
+
maxAge: 30,
|
|
168
|
+
matchStrategy: 'fuzzy'
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Birth year matching
|
|
172
|
+
const millennial = await client.people.findOrCreate({
|
|
173
|
+
firstName: 'David',
|
|
174
|
+
lastName: 'Wilson',
|
|
175
|
+
birthYear: 1990,
|
|
176
|
+
matchStrategy: 'fuzzy'
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Technical Details
|
|
181
|
+
|
|
182
|
+
- **New Helper Functions**: `calculateAgeSafe()`, `isAdult()`, `isChild()`, `matchesAgeCriteria()`
|
|
183
|
+
- **Enhanced PersonMatchOptions**: Added `agePreference`, `minAge`, `maxAge`, `birthYear` properties
|
|
184
|
+
- **Updated Scoring System**: Age matching now contributes 15% to overall match score
|
|
185
|
+
- **Backward Compatibility**: All existing functionality remains unchanged
|
|
186
|
+
|
|
8
187
|
## [2.3.1] - 2025-01-10
|
|
9
188
|
|
|
10
189
|
### 🐛 **BUG FIXES & STABILITY IMPROVEMENTS**
|
package/dist/core/http.js
CHANGED
|
@@ -191,6 +191,11 @@ class PcoHttpClient {
|
|
|
191
191
|
else if (this.config.auth.type === 'oauth') {
|
|
192
192
|
headers.Authorization = `Bearer ${this.config.auth.accessToken}`;
|
|
193
193
|
}
|
|
194
|
+
else if (this.config.auth.type === 'basic') {
|
|
195
|
+
// Basic auth with app credentials
|
|
196
|
+
const credentials = Buffer.from(`${this.config.auth.appId}:${this.config.auth.appSecret}`).toString('base64');
|
|
197
|
+
headers.Authorization = `Basic ${credentials}`;
|
|
198
|
+
}
|
|
194
199
|
}
|
|
195
200
|
getResourceTypeFromEndpoint(endpoint) {
|
|
196
201
|
// Extract resource type from endpoint
|
|
@@ -224,18 +229,29 @@ class PcoHttpClient {
|
|
|
224
229
|
}
|
|
225
230
|
const baseURL = this.config.baseURL || 'https://api.planningcenteronline.com/people/v2';
|
|
226
231
|
const tokenUrl = baseURL.replace('/people/v2', '/oauth/token');
|
|
232
|
+
// Prepare the request body for token refresh
|
|
233
|
+
const body = new URLSearchParams({
|
|
234
|
+
grant_type: 'refresh_token',
|
|
235
|
+
refresh_token: this.config.auth.refreshToken,
|
|
236
|
+
});
|
|
237
|
+
// Add client credentials if available from the config or environment
|
|
238
|
+
const clientId = this.config.auth.clientId || process.env.PCO_APP_ID;
|
|
239
|
+
const clientSecret = this.config.auth.clientSecret || process.env.PCO_APP_SECRET;
|
|
240
|
+
if (clientId && clientSecret) {
|
|
241
|
+
body.append('client_id', clientId);
|
|
242
|
+
body.append('client_secret', clientSecret);
|
|
243
|
+
}
|
|
227
244
|
const response = await fetch(tokenUrl, {
|
|
228
245
|
method: 'POST',
|
|
229
246
|
headers: {
|
|
230
247
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
248
|
+
'Accept': 'application/json',
|
|
231
249
|
},
|
|
232
|
-
body:
|
|
233
|
-
grant_type: 'refresh_token',
|
|
234
|
-
refresh_token: this.config.auth.refreshToken,
|
|
235
|
-
}),
|
|
250
|
+
body: body.toString(),
|
|
236
251
|
});
|
|
237
252
|
if (!response.ok) {
|
|
238
|
-
|
|
253
|
+
const errorData = await response.json().catch(() => ({}));
|
|
254
|
+
throw new Error(`Token refresh failed: ${response.status} ${response.statusText}. ${JSON.stringify(errorData)}`);
|
|
239
255
|
}
|
|
240
256
|
const tokens = await response.json();
|
|
241
257
|
// Update the config with new tokens
|
package/dist/helpers.d.ts
CHANGED
|
@@ -15,6 +15,31 @@ export declare function buildQueryParams(params?: {
|
|
|
15
15
|
* Calculate age from birthdate string
|
|
16
16
|
*/
|
|
17
17
|
export declare function calculateAge(birthdate: string): number;
|
|
18
|
+
/**
|
|
19
|
+
* Calculate age from birthdate string, handling invalid dates
|
|
20
|
+
*/
|
|
21
|
+
export declare function calculateAgeSafe(birthdate: string | undefined): number | null;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a person is an adult (18+ years old)
|
|
24
|
+
*/
|
|
25
|
+
export declare function isAdult(birthdate: string | undefined): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a person is a child (under 18 years old)
|
|
28
|
+
*/
|
|
29
|
+
export declare function isChild(birthdate: string | undefined): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a person's age matches the given criteria
|
|
32
|
+
*/
|
|
33
|
+
export declare function matchesAgeCriteria(birthdate: string | undefined, criteria: {
|
|
34
|
+
agePreference?: 'adults' | 'children' | 'any';
|
|
35
|
+
minAge?: number;
|
|
36
|
+
maxAge?: number;
|
|
37
|
+
birthYear?: number;
|
|
38
|
+
}): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Calculate birth year from age
|
|
41
|
+
*/
|
|
42
|
+
export declare function calculateBirthYearFromAge(age: number): number;
|
|
18
43
|
/**
|
|
19
44
|
* Validate email format
|
|
20
45
|
*/
|
package/dist/helpers.js
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildQueryParams = buildQueryParams;
|
|
4
4
|
exports.calculateAge = calculateAge;
|
|
5
|
+
exports.calculateAgeSafe = calculateAgeSafe;
|
|
6
|
+
exports.isAdult = isAdult;
|
|
7
|
+
exports.isChild = isChild;
|
|
8
|
+
exports.matchesAgeCriteria = matchesAgeCriteria;
|
|
9
|
+
exports.calculateBirthYearFromAge = calculateBirthYearFromAge;
|
|
5
10
|
exports.isValidEmail = isValidEmail;
|
|
6
11
|
exports.isValidPhone = isValidPhone;
|
|
7
12
|
exports.formatPersonName = formatPersonName;
|
|
@@ -61,6 +66,70 @@ function calculateAge(birthdate) {
|
|
|
61
66
|
}
|
|
62
67
|
return age;
|
|
63
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Calculate age from birthdate string, handling invalid dates
|
|
71
|
+
*/
|
|
72
|
+
function calculateAgeSafe(birthdate) {
|
|
73
|
+
if (!birthdate)
|
|
74
|
+
return null;
|
|
75
|
+
try {
|
|
76
|
+
const birth = new Date(birthdate);
|
|
77
|
+
if (isNaN(birth.getTime()))
|
|
78
|
+
return null;
|
|
79
|
+
return calculateAge(birthdate);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a person is an adult (18+ years old)
|
|
87
|
+
*/
|
|
88
|
+
function isAdult(birthdate) {
|
|
89
|
+
const age = calculateAgeSafe(birthdate);
|
|
90
|
+
return age !== null && age >= 18;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if a person is a child (under 18 years old)
|
|
94
|
+
*/
|
|
95
|
+
function isChild(birthdate) {
|
|
96
|
+
const age = calculateAgeSafe(birthdate);
|
|
97
|
+
return age !== null && age < 18;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if a person's age matches the given criteria
|
|
101
|
+
*/
|
|
102
|
+
function matchesAgeCriteria(birthdate, criteria) {
|
|
103
|
+
const age = calculateAgeSafe(birthdate);
|
|
104
|
+
// If no birthdate, only match if preference is 'any'
|
|
105
|
+
if (age === null) {
|
|
106
|
+
return criteria.agePreference === 'any' || criteria.agePreference === undefined;
|
|
107
|
+
}
|
|
108
|
+
// Check age preference
|
|
109
|
+
if (criteria.agePreference === 'adults' && age < 18)
|
|
110
|
+
return false;
|
|
111
|
+
if (criteria.agePreference === 'children' && age >= 18)
|
|
112
|
+
return false;
|
|
113
|
+
// Check age range
|
|
114
|
+
if (criteria.minAge !== undefined && age < criteria.minAge)
|
|
115
|
+
return false;
|
|
116
|
+
if (criteria.maxAge !== undefined && age > criteria.maxAge)
|
|
117
|
+
return false;
|
|
118
|
+
// Check birth year
|
|
119
|
+
if (criteria.birthYear !== undefined) {
|
|
120
|
+
const birthYear = new Date(birthdate).getFullYear();
|
|
121
|
+
if (birthYear !== criteria.birthYear)
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Calculate birth year from age
|
|
128
|
+
*/
|
|
129
|
+
function calculateBirthYearFromAge(age) {
|
|
130
|
+
const currentYear = new Date().getFullYear();
|
|
131
|
+
return currentYear - age;
|
|
132
|
+
}
|
|
64
133
|
/**
|
|
65
134
|
* Validate email format
|
|
66
135
|
*/
|
package/dist/matching/matcher.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PersonMatcher = void 0;
|
|
7
7
|
const strategies_1 = require("./strategies");
|
|
8
8
|
const scoring_1 = require("./scoring");
|
|
9
|
+
const helpers_1 = require("../helpers");
|
|
9
10
|
class PersonMatcher {
|
|
10
11
|
constructor(peopleModule) {
|
|
11
12
|
this.peopleModule = peopleModule;
|
|
@@ -102,7 +103,30 @@ class PersonMatcher {
|
|
|
102
103
|
}
|
|
103
104
|
// Remove duplicates based on person ID
|
|
104
105
|
const uniqueCandidates = candidates.filter((person, index, self) => index === self.findIndex(p => p.id === person.id));
|
|
105
|
-
|
|
106
|
+
// Filter by age preferences if specified
|
|
107
|
+
const ageFilteredCandidates = this.filterByAgePreferences(uniqueCandidates, options);
|
|
108
|
+
return ageFilteredCandidates;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Filter candidates by age preferences
|
|
112
|
+
*/
|
|
113
|
+
filterByAgePreferences(candidates, options) {
|
|
114
|
+
// If no age criteria specified, return all candidates
|
|
115
|
+
if (!options.agePreference &&
|
|
116
|
+
options.minAge === undefined &&
|
|
117
|
+
options.maxAge === undefined &&
|
|
118
|
+
options.birthYear === undefined) {
|
|
119
|
+
return candidates;
|
|
120
|
+
}
|
|
121
|
+
return candidates.filter(person => {
|
|
122
|
+
const birthdate = person.attributes?.birthdate;
|
|
123
|
+
return (0, helpers_1.matchesAgeCriteria)(birthdate, {
|
|
124
|
+
agePreference: options.agePreference,
|
|
125
|
+
minAge: options.minAge,
|
|
126
|
+
maxAge: options.maxAge,
|
|
127
|
+
birthYear: options.birthYear
|
|
128
|
+
});
|
|
129
|
+
});
|
|
106
130
|
}
|
|
107
131
|
/**
|
|
108
132
|
* Create a new person
|
|
@@ -21,9 +21,13 @@ export declare class MatchScorer {
|
|
|
21
21
|
*/
|
|
22
22
|
private scorePhoneMatch;
|
|
23
23
|
/**
|
|
24
|
-
* Score name matching
|
|
24
|
+
* Score name matching - only exact matches
|
|
25
25
|
*/
|
|
26
26
|
private scoreNameMatch;
|
|
27
|
+
/**
|
|
28
|
+
* Score age matching
|
|
29
|
+
*/
|
|
30
|
+
private scoreAgeMatch;
|
|
27
31
|
/**
|
|
28
32
|
* Score additional criteria
|
|
29
33
|
*/
|
package/dist/matching/scoring.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.MatchScorer = void 0;
|
|
7
|
+
const helpers_1 = require("../helpers");
|
|
7
8
|
class MatchScorer {
|
|
8
9
|
/**
|
|
9
10
|
* Score a person match based on various criteria
|
|
@@ -14,14 +15,14 @@ class MatchScorer {
|
|
|
14
15
|
// Email matching (highest weight)
|
|
15
16
|
if (options.email) {
|
|
16
17
|
const emailScore = this.scoreEmailMatch(person, options.email);
|
|
17
|
-
totalScore += emailScore * 0.
|
|
18
|
-
maxScore += 0.
|
|
18
|
+
totalScore += emailScore * 0.35;
|
|
19
|
+
maxScore += 0.35;
|
|
19
20
|
}
|
|
20
21
|
// Phone matching (high weight)
|
|
21
22
|
if (options.phone) {
|
|
22
23
|
const phoneScore = this.scorePhoneMatch(person, options.phone);
|
|
23
|
-
totalScore += phoneScore * 0.
|
|
24
|
-
maxScore += 0.
|
|
24
|
+
totalScore += phoneScore * 0.25;
|
|
25
|
+
maxScore += 0.25;
|
|
25
26
|
}
|
|
26
27
|
// Name matching (medium weight)
|
|
27
28
|
if (options.firstName || options.lastName) {
|
|
@@ -29,10 +30,14 @@ class MatchScorer {
|
|
|
29
30
|
totalScore += nameScore * 0.2;
|
|
30
31
|
maxScore += 0.2;
|
|
31
32
|
}
|
|
33
|
+
// Age matching (medium weight)
|
|
34
|
+
const ageScore = this.scoreAgeMatch(person, options);
|
|
35
|
+
totalScore += ageScore * 0.15;
|
|
36
|
+
maxScore += 0.15;
|
|
32
37
|
// Additional criteria (lower weight)
|
|
33
38
|
const additionalScore = this.scoreAdditionalCriteria(person, options);
|
|
34
|
-
totalScore += additionalScore * 0.
|
|
35
|
-
maxScore += 0.
|
|
39
|
+
totalScore += additionalScore * 0.05;
|
|
40
|
+
maxScore += 0.05;
|
|
36
41
|
return maxScore > 0 ? totalScore / maxScore : 0;
|
|
37
42
|
}
|
|
38
43
|
/**
|
|
@@ -51,8 +56,24 @@ class MatchScorer {
|
|
|
51
56
|
if (nameScore > 0.8) {
|
|
52
57
|
reasons.push('exact name match');
|
|
53
58
|
}
|
|
54
|
-
else if (nameScore > 0
|
|
55
|
-
reasons.push('
|
|
59
|
+
else if (nameScore > 0) {
|
|
60
|
+
reasons.push('partial name match');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Add age-based match reasons
|
|
64
|
+
const ageScore = this.scoreAgeMatch(person, options);
|
|
65
|
+
if (ageScore > 0.8) {
|
|
66
|
+
const age = (0, helpers_1.calculateAgeSafe)(person.attributes?.birthdate);
|
|
67
|
+
if (age !== null) {
|
|
68
|
+
if (options.agePreference === 'adults') {
|
|
69
|
+
reasons.push('adult age match');
|
|
70
|
+
}
|
|
71
|
+
else if (options.agePreference === 'children') {
|
|
72
|
+
reasons.push('child age match');
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
reasons.push(`age ${age} match`);
|
|
76
|
+
}
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
if (reasons.length === 0) {
|
|
@@ -79,25 +100,72 @@ class MatchScorer {
|
|
|
79
100
|
return 0;
|
|
80
101
|
}
|
|
81
102
|
/**
|
|
82
|
-
* Score name matching
|
|
103
|
+
* Score name matching - only exact matches
|
|
83
104
|
*/
|
|
84
105
|
scoreNameMatch(person, options) {
|
|
85
106
|
const attrs = person.attributes;
|
|
86
107
|
if (!attrs)
|
|
87
108
|
return 0;
|
|
88
109
|
let score = 0;
|
|
89
|
-
// First name matching
|
|
110
|
+
// First name matching - exact match only
|
|
90
111
|
if (options.firstName && attrs.first_name) {
|
|
91
|
-
const
|
|
92
|
-
score +=
|
|
112
|
+
const firstNameMatch = options.firstName.toLowerCase() === attrs.first_name.toLowerCase();
|
|
113
|
+
score += firstNameMatch ? 0.5 : 0;
|
|
93
114
|
}
|
|
94
|
-
// Last name matching
|
|
115
|
+
// Last name matching - exact match only
|
|
95
116
|
if (options.lastName && attrs.last_name) {
|
|
96
|
-
const
|
|
97
|
-
score +=
|
|
117
|
+
const lastNameMatch = options.lastName.toLowerCase() === attrs.last_name.toLowerCase();
|
|
118
|
+
score += lastNameMatch ? 0.5 : 0;
|
|
98
119
|
}
|
|
99
120
|
return score;
|
|
100
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Score age matching
|
|
124
|
+
*/
|
|
125
|
+
scoreAgeMatch(person, options) {
|
|
126
|
+
const birthdate = person.attributes?.birthdate;
|
|
127
|
+
// If no age criteria specified, return neutral score
|
|
128
|
+
if (!options.agePreference &&
|
|
129
|
+
options.minAge === undefined &&
|
|
130
|
+
options.maxAge === undefined &&
|
|
131
|
+
options.birthYear === undefined) {
|
|
132
|
+
return 0.5; // Neutral score
|
|
133
|
+
}
|
|
134
|
+
// If no birthdate available, return low score
|
|
135
|
+
if (!birthdate) {
|
|
136
|
+
return 0.1;
|
|
137
|
+
}
|
|
138
|
+
// Check if person matches age criteria
|
|
139
|
+
const matches = (0, helpers_1.matchesAgeCriteria)(birthdate, {
|
|
140
|
+
agePreference: options.agePreference,
|
|
141
|
+
minAge: options.minAge,
|
|
142
|
+
maxAge: options.maxAge,
|
|
143
|
+
birthYear: options.birthYear
|
|
144
|
+
});
|
|
145
|
+
if (!matches) {
|
|
146
|
+
return 0; // No match
|
|
147
|
+
}
|
|
148
|
+
// Calculate bonus score based on how well the age matches
|
|
149
|
+
const age = (0, helpers_1.calculateAgeSafe)(birthdate);
|
|
150
|
+
if (age === null)
|
|
151
|
+
return 0.5;
|
|
152
|
+
let bonusScore = 0;
|
|
153
|
+
// Bonus for exact age range match
|
|
154
|
+
if (options.minAge !== undefined && options.maxAge !== undefined) {
|
|
155
|
+
if (age >= options.minAge && age <= options.maxAge) {
|
|
156
|
+
bonusScore += 0.3;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Bonus for exact birth year match
|
|
160
|
+
if (options.birthYear !== undefined) {
|
|
161
|
+
const birthYear = new Date(birthdate).getFullYear();
|
|
162
|
+
if (birthYear === options.birthYear) {
|
|
163
|
+
bonusScore += 0.4;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Base score for matching criteria
|
|
167
|
+
return Math.min(0.6 + bonusScore, 1.0);
|
|
168
|
+
}
|
|
101
169
|
/**
|
|
102
170
|
* Score additional criteria
|
|
103
171
|
*/
|
package/dist/modules/people.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { PcoHttpClient } from '../core/http';
|
|
|
6
6
|
import type { PaginationHelper } from '../core/pagination';
|
|
7
7
|
import type { PcoEventEmitter } from '../monitoring';
|
|
8
8
|
import type { PaginationOptions, PaginationResult } from '../core/pagination';
|
|
9
|
-
import type { PersonResource, EmailResource, EmailAttributes, PhoneNumberResource, PhoneNumberAttributes, AddressResource, AddressAttributes, SocialProfileResource, SocialProfileAttributes } from '../types';
|
|
9
|
+
import type { PersonResource, EmailResource, EmailAttributes, PhoneNumberResource, PhoneNumberAttributes, AddressResource, AddressAttributes, SocialProfileResource, SocialProfileAttributes, CampusResource, HouseholdResource } from '../types';
|
|
10
10
|
export interface PeopleListOptions {
|
|
11
11
|
where?: Record<string, any>;
|
|
12
12
|
include?: string[];
|
|
@@ -50,6 +50,10 @@ export interface PersonMatchOptions {
|
|
|
50
50
|
matchStrategy?: 'exact' | 'fuzzy' | 'aggressive';
|
|
51
51
|
campus?: string;
|
|
52
52
|
createIfNotFound?: boolean;
|
|
53
|
+
agePreference?: 'adults' | 'children' | 'any';
|
|
54
|
+
minAge?: number;
|
|
55
|
+
maxAge?: number;
|
|
56
|
+
birthYear?: number;
|
|
53
57
|
}
|
|
54
58
|
export declare class PeopleModule extends BaseModule {
|
|
55
59
|
private personMatcher;
|
|
@@ -82,6 +86,94 @@ export declare class PeopleModule extends BaseModule {
|
|
|
82
86
|
* Delete a person
|
|
83
87
|
*/
|
|
84
88
|
delete(id: string): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Get a person's primary campus
|
|
91
|
+
*/
|
|
92
|
+
getPrimaryCampus(personId: string): Promise<CampusResource | null>;
|
|
93
|
+
/**
|
|
94
|
+
* Set a person's primary campus
|
|
95
|
+
*/
|
|
96
|
+
setPrimaryCampus(personId: string, campusId: string): Promise<PersonResource>;
|
|
97
|
+
/**
|
|
98
|
+
* Remove a person's primary campus
|
|
99
|
+
*/
|
|
100
|
+
removePrimaryCampus(personId: string): Promise<PersonResource>;
|
|
101
|
+
/**
|
|
102
|
+
* Get a person's household
|
|
103
|
+
*/
|
|
104
|
+
getHousehold(personId: string): Promise<HouseholdResource | null>;
|
|
105
|
+
/**
|
|
106
|
+
* Set a person's household
|
|
107
|
+
*/
|
|
108
|
+
setHousehold(personId: string, householdId: string): Promise<PersonResource>;
|
|
109
|
+
/**
|
|
110
|
+
* Remove a person from their household
|
|
111
|
+
*/
|
|
112
|
+
removeFromHousehold(personId: string): Promise<PersonResource>;
|
|
113
|
+
/**
|
|
114
|
+
* Get all people in a specific household
|
|
115
|
+
*/
|
|
116
|
+
getHouseholdMembers(householdId: string, options?: PeopleListOptions): Promise<{
|
|
117
|
+
data: PersonResource[];
|
|
118
|
+
meta?: any;
|
|
119
|
+
links?: any;
|
|
120
|
+
}>;
|
|
121
|
+
/**
|
|
122
|
+
* Get people by campus
|
|
123
|
+
*/
|
|
124
|
+
getByCampus(campusId: string, options?: PeopleListOptions): Promise<{
|
|
125
|
+
data: PersonResource[];
|
|
126
|
+
meta?: any;
|
|
127
|
+
links?: any;
|
|
128
|
+
}>;
|
|
129
|
+
/**
|
|
130
|
+
* Get a person's workflow cards
|
|
131
|
+
*/
|
|
132
|
+
getWorkflowCards(personId: string, options?: {
|
|
133
|
+
include?: string[];
|
|
134
|
+
perPage?: number;
|
|
135
|
+
page?: number;
|
|
136
|
+
}): Promise<{
|
|
137
|
+
data: any[];
|
|
138
|
+
meta?: any;
|
|
139
|
+
links?: any;
|
|
140
|
+
}>;
|
|
141
|
+
/**
|
|
142
|
+
* Get a person's notes
|
|
143
|
+
*/
|
|
144
|
+
getNotes(personId: string, options?: {
|
|
145
|
+
include?: string[];
|
|
146
|
+
perPage?: number;
|
|
147
|
+
page?: number;
|
|
148
|
+
}): Promise<{
|
|
149
|
+
data: any[];
|
|
150
|
+
meta?: any;
|
|
151
|
+
links?: any;
|
|
152
|
+
}>;
|
|
153
|
+
/**
|
|
154
|
+
* Get a person's field data
|
|
155
|
+
*/
|
|
156
|
+
getFieldData(personId: string, options?: {
|
|
157
|
+
include?: string[];
|
|
158
|
+
perPage?: number;
|
|
159
|
+
page?: number;
|
|
160
|
+
}): Promise<{
|
|
161
|
+
data: any[];
|
|
162
|
+
meta?: any;
|
|
163
|
+
links?: any;
|
|
164
|
+
}>;
|
|
165
|
+
/**
|
|
166
|
+
* Get a person's social profiles
|
|
167
|
+
*/
|
|
168
|
+
getSocialProfiles(personId: string, options?: {
|
|
169
|
+
include?: string[];
|
|
170
|
+
perPage?: number;
|
|
171
|
+
page?: number;
|
|
172
|
+
}): Promise<{
|
|
173
|
+
data: any[];
|
|
174
|
+
meta?: any;
|
|
175
|
+
links?: any;
|
|
176
|
+
}>;
|
|
85
177
|
/**
|
|
86
178
|
* Find or create a person with smart matching
|
|
87
179
|
*/
|
|
@@ -160,14 +252,6 @@ export declare class PeopleModule extends BaseModule {
|
|
|
160
252
|
* Delete a person's address
|
|
161
253
|
*/
|
|
162
254
|
deleteAddress(personId: string, addressId: string): Promise<void>;
|
|
163
|
-
/**
|
|
164
|
-
* Get person's social profiles
|
|
165
|
-
*/
|
|
166
|
-
getSocialProfiles(personId: string): Promise<{
|
|
167
|
-
data: SocialProfileResource[];
|
|
168
|
-
meta?: any;
|
|
169
|
-
links?: any;
|
|
170
|
-
}>;
|
|
171
255
|
/**
|
|
172
256
|
* Add a social profile to a person
|
|
173
257
|
*/
|
package/dist/modules/people.js
CHANGED
|
@@ -75,6 +75,209 @@ class PeopleModule extends base_1.BaseModule {
|
|
|
75
75
|
async delete(id) {
|
|
76
76
|
return this.deleteResource(`/people/${id}`);
|
|
77
77
|
}
|
|
78
|
+
// ===== Relationship Management =====
|
|
79
|
+
/**
|
|
80
|
+
* Get a person's primary campus
|
|
81
|
+
*/
|
|
82
|
+
async getPrimaryCampus(personId) {
|
|
83
|
+
const person = await this.getById(personId, ['primary_campus']);
|
|
84
|
+
const campusData = person.relationships?.primary_campus?.data;
|
|
85
|
+
if (!campusData || Array.isArray(campusData) || !campusData.id) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
// Get the full campus resource
|
|
89
|
+
return this.httpClient.request({
|
|
90
|
+
method: 'GET',
|
|
91
|
+
endpoint: `/campuses/${campusData.id}`
|
|
92
|
+
}).then(response => response.data);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Set a person's primary campus
|
|
96
|
+
*/
|
|
97
|
+
async setPrimaryCampus(personId, campusId) {
|
|
98
|
+
return this.httpClient.request({
|
|
99
|
+
method: 'PATCH',
|
|
100
|
+
endpoint: `/people/${personId}`,
|
|
101
|
+
data: {
|
|
102
|
+
data: {
|
|
103
|
+
type: 'Person',
|
|
104
|
+
id: personId,
|
|
105
|
+
attributes: {
|
|
106
|
+
primary_campus_id: campusId
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}).then(response => response.data);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Remove a person's primary campus
|
|
114
|
+
*/
|
|
115
|
+
async removePrimaryCampus(personId) {
|
|
116
|
+
return this.httpClient.request({
|
|
117
|
+
method: 'PATCH',
|
|
118
|
+
endpoint: `/people/${personId}`,
|
|
119
|
+
data: {
|
|
120
|
+
data: {
|
|
121
|
+
type: 'Person',
|
|
122
|
+
id: personId,
|
|
123
|
+
attributes: {
|
|
124
|
+
primary_campus_id: null
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}).then(response => response.data);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get a person's household
|
|
132
|
+
*/
|
|
133
|
+
async getHousehold(personId) {
|
|
134
|
+
const person = await this.getById(personId, ['household']);
|
|
135
|
+
const householdData = person.relationships?.household?.data;
|
|
136
|
+
if (!householdData || Array.isArray(householdData) || !householdData.id) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
// Get the full household resource
|
|
140
|
+
return this.httpClient.request({
|
|
141
|
+
method: 'GET',
|
|
142
|
+
endpoint: `/households/${householdData.id}`
|
|
143
|
+
}).then(response => response.data);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Set a person's household
|
|
147
|
+
*/
|
|
148
|
+
async setHousehold(personId, householdId) {
|
|
149
|
+
return this.httpClient.request({
|
|
150
|
+
method: 'PATCH',
|
|
151
|
+
endpoint: `/people/${personId}`,
|
|
152
|
+
data: {
|
|
153
|
+
data: {
|
|
154
|
+
type: 'Person',
|
|
155
|
+
id: personId,
|
|
156
|
+
attributes: {
|
|
157
|
+
household_id: householdId
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}).then(response => response.data);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Remove a person from their household
|
|
165
|
+
*/
|
|
166
|
+
async removeFromHousehold(personId) {
|
|
167
|
+
return this.httpClient.request({
|
|
168
|
+
method: 'PATCH',
|
|
169
|
+
endpoint: `/people/${personId}`,
|
|
170
|
+
data: {
|
|
171
|
+
data: {
|
|
172
|
+
type: 'Person',
|
|
173
|
+
id: personId,
|
|
174
|
+
attributes: {
|
|
175
|
+
household_id: null
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}).then(response => response.data);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get all people in a specific household
|
|
183
|
+
*/
|
|
184
|
+
async getHouseholdMembers(householdId, options = {}) {
|
|
185
|
+
const params = {
|
|
186
|
+
'where[household_id]': householdId
|
|
187
|
+
};
|
|
188
|
+
if (options.include) {
|
|
189
|
+
params.include = options.include.join(',');
|
|
190
|
+
}
|
|
191
|
+
if (options.perPage) {
|
|
192
|
+
params.per_page = options.perPage;
|
|
193
|
+
}
|
|
194
|
+
if (options.page) {
|
|
195
|
+
params.page = options.page;
|
|
196
|
+
}
|
|
197
|
+
return this.getList('/people', params);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get people by campus
|
|
201
|
+
*/
|
|
202
|
+
async getByCampus(campusId, options = {}) {
|
|
203
|
+
const params = {
|
|
204
|
+
'where[primary_campus_id]': campusId
|
|
205
|
+
};
|
|
206
|
+
if (options.include) {
|
|
207
|
+
params.include = options.include.join(',');
|
|
208
|
+
}
|
|
209
|
+
if (options.perPage) {
|
|
210
|
+
params.per_page = options.perPage;
|
|
211
|
+
}
|
|
212
|
+
if (options.page) {
|
|
213
|
+
params.page = options.page;
|
|
214
|
+
}
|
|
215
|
+
return this.getList('/people', params);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get a person's workflow cards
|
|
219
|
+
*/
|
|
220
|
+
async getWorkflowCards(personId, options = {}) {
|
|
221
|
+
const params = {};
|
|
222
|
+
if (options.include) {
|
|
223
|
+
params.include = options.include.join(',');
|
|
224
|
+
}
|
|
225
|
+
if (options.perPage) {
|
|
226
|
+
params.per_page = options.perPage;
|
|
227
|
+
}
|
|
228
|
+
if (options.page) {
|
|
229
|
+
params.page = options.page;
|
|
230
|
+
}
|
|
231
|
+
return this.getList(`/people/${personId}/workflow_cards`, params);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Get a person's notes
|
|
235
|
+
*/
|
|
236
|
+
async getNotes(personId, options = {}) {
|
|
237
|
+
const params = {};
|
|
238
|
+
if (options.include) {
|
|
239
|
+
params.include = options.include.join(',');
|
|
240
|
+
}
|
|
241
|
+
if (options.perPage) {
|
|
242
|
+
params.per_page = options.perPage;
|
|
243
|
+
}
|
|
244
|
+
if (options.page) {
|
|
245
|
+
params.page = options.page;
|
|
246
|
+
}
|
|
247
|
+
return this.getList(`/people/${personId}/notes`, params);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get a person's field data
|
|
251
|
+
*/
|
|
252
|
+
async getFieldData(personId, options = {}) {
|
|
253
|
+
const params = {};
|
|
254
|
+
if (options.include) {
|
|
255
|
+
params.include = options.include.join(',');
|
|
256
|
+
}
|
|
257
|
+
if (options.perPage) {
|
|
258
|
+
params.per_page = options.perPage;
|
|
259
|
+
}
|
|
260
|
+
if (options.page) {
|
|
261
|
+
params.page = options.page;
|
|
262
|
+
}
|
|
263
|
+
return this.getList(`/people/${personId}/field_data`, params);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get a person's social profiles
|
|
267
|
+
*/
|
|
268
|
+
async getSocialProfiles(personId, options = {}) {
|
|
269
|
+
const params = {};
|
|
270
|
+
if (options.include) {
|
|
271
|
+
params.include = options.include.join(',');
|
|
272
|
+
}
|
|
273
|
+
if (options.perPage) {
|
|
274
|
+
params.per_page = options.perPage;
|
|
275
|
+
}
|
|
276
|
+
if (options.page) {
|
|
277
|
+
params.page = options.page;
|
|
278
|
+
}
|
|
279
|
+
return this.getList(`/people/${personId}/social_profiles`, params);
|
|
280
|
+
}
|
|
78
281
|
/**
|
|
79
282
|
* Find or create a person with smart matching
|
|
80
283
|
*/
|
|
@@ -176,12 +379,6 @@ class PeopleModule extends base_1.BaseModule {
|
|
|
176
379
|
async deleteAddress(personId, addressId) {
|
|
177
380
|
return this.deleteResource(`/people/${personId}/addresses/${addressId}`);
|
|
178
381
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Get person's social profiles
|
|
181
|
-
*/
|
|
182
|
-
async getSocialProfiles(personId) {
|
|
183
|
-
return this.getList(`/people/${personId}/social_profiles`);
|
|
184
|
-
}
|
|
185
382
|
/**
|
|
186
383
|
* Add a social profile to a person
|
|
187
384
|
*/
|
package/dist/types/client.d.ts
CHANGED
|
@@ -16,9 +16,19 @@ export interface OAuthAuth {
|
|
|
16
16
|
refreshToken: string;
|
|
17
17
|
}) => void | Promise<void>;
|
|
18
18
|
onRefreshFailure: (error: Error) => void | Promise<void>;
|
|
19
|
+
/** Client ID for token refresh (optional, can use environment variable PCO_APP_ID) */
|
|
20
|
+
clientId?: string;
|
|
21
|
+
/** Client Secret for token refresh (optional, can use environment variable PCO_APP_SECRET) */
|
|
22
|
+
clientSecret?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Authentication configuration for Basic Auth with app credentials */
|
|
25
|
+
export interface BasicAuth {
|
|
26
|
+
type: 'basic';
|
|
27
|
+
appId: string;
|
|
28
|
+
appSecret: string;
|
|
19
29
|
}
|
|
20
30
|
/** Union type for authentication configurations */
|
|
21
|
-
export type PcoAuthConfig = PersonalAccessTokenAuth | OAuthAuth;
|
|
31
|
+
export type PcoAuthConfig = PersonalAccessTokenAuth | OAuthAuth | BasicAuth;
|
|
22
32
|
export interface PcoClientConfig {
|
|
23
33
|
/** Authentication configuration */
|
|
24
34
|
auth: PcoAuthConfig;
|
package/dist/types/people.d.ts
CHANGED
|
@@ -39,8 +39,14 @@ export interface PersonAttributes extends Attributes {
|
|
|
39
39
|
export interface PersonRelationships {
|
|
40
40
|
emails?: Relationship;
|
|
41
41
|
phone_numbers?: Relationship;
|
|
42
|
+
addresses?: Relationship;
|
|
43
|
+
household?: Relationship;
|
|
42
44
|
primary_campus?: Relationship;
|
|
43
45
|
gender?: Relationship;
|
|
46
|
+
workflow_cards?: Relationship;
|
|
47
|
+
notes?: Relationship;
|
|
48
|
+
field_data?: Relationship;
|
|
49
|
+
social_profiles?: Relationship;
|
|
44
50
|
}
|
|
45
51
|
export interface PersonResource extends ResourceObject<'Person', PersonAttributes, PersonRelationships> {
|
|
46
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rachelallyson/planning-center-people-ts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.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",
|