@rachelallyson/planning-center-people-ts 2.14.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -7
- package/README.md +42 -4
- package/dist/auth.d.ts +1 -1
- package/dist/auth.js +14 -6
- package/dist/client.d.ts +33 -8
- package/dist/client.js +47 -22
- package/dist/core.d.ts +4 -2
- package/dist/core.js +3 -2
- package/dist/error-handling.d.ts +4 -4
- package/dist/error-handling.js +13 -2
- package/dist/error-scenarios.d.ts +11 -7
- package/dist/error-scenarios.js +26 -10
- package/dist/helpers.d.ts +124 -48
- package/dist/helpers.js +236 -93
- package/dist/index.d.ts +9 -7
- package/dist/index.js +31 -72
- package/dist/matching/matcher.d.ts +8 -4
- package/dist/matching/matcher.js +51 -58
- package/dist/matching/scoring.d.ts +9 -6
- package/dist/matching/scoring.js +18 -14
- package/dist/modules/campus.d.ts +31 -36
- package/dist/modules/campus.js +36 -49
- package/dist/modules/contacts.d.ts +33 -29
- package/dist/modules/contacts.js +36 -12
- package/dist/modules/fields.d.ts +39 -55
- package/dist/modules/fields.js +65 -105
- package/dist/modules/forms.d.ts +35 -24
- package/dist/modules/forms.js +41 -23
- package/dist/modules/households.d.ts +17 -19
- package/dist/modules/households.js +25 -34
- package/dist/modules/lists.d.ts +30 -28
- package/dist/modules/lists.js +55 -42
- package/dist/modules/notes.d.ts +32 -30
- package/dist/modules/notes.js +40 -52
- package/dist/modules/people.d.ts +83 -71
- package/dist/modules/people.js +323 -172
- package/dist/modules/reports.d.ts +18 -32
- package/dist/modules/reports.js +28 -40
- package/dist/modules/service-time.d.ts +19 -24
- package/dist/modules/service-time.js +28 -28
- package/dist/modules/workflows.d.ts +42 -47
- package/dist/modules/workflows.js +50 -53
- package/dist/performance.d.ts +14 -10
- package/dist/performance.js +61 -25
- package/dist/testing/recorder.js +11 -2
- package/dist/testing/simple-builders.d.ts +6 -4
- package/dist/testing/simple-builders.js +36 -49
- package/dist/testing/types.d.ts +4 -0
- package/dist/types/api-options.d.ts +380 -0
- package/dist/types/api-options.js +6 -0
- package/dist/types/client.d.ts +4 -2
- package/dist/types/client.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/people.d.ts +47 -9
- package/package.json +7 -7
- package/dist/core/http.d.ts +0 -56
- package/dist/core/http.js +0 -360
- package/dist/core/pagination.d.ts +0 -34
- package/dist/core/pagination.js +0 -178
- package/dist/people/contacts.d.ts +0 -43
- package/dist/people/contacts.js +0 -122
- package/dist/people/core.d.ts +0 -28
- package/dist/people/core.js +0 -69
- package/dist/people/fields.d.ts +0 -68
- package/dist/people/fields.js +0 -305
- package/dist/people/households.d.ts +0 -15
- package/dist/people/households.js +0 -31
- package/dist/people/index.d.ts +0 -8
- package/dist/people/index.js +0 -25
- package/dist/people/lists.d.ts +0 -34
- package/dist/people/lists.js +0 -48
- package/dist/people/notes.d.ts +0 -30
- package/dist/people/notes.js +0 -37
- package/dist/people/organization.d.ts +0 -12
- package/dist/people/organization.js +0 -15
- package/dist/people/workflows.d.ts +0 -37
- package/dist/people/workflows.js +0 -75
package/dist/index.js
CHANGED
|
@@ -15,90 +15,47 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.
|
|
19
|
-
exports.
|
|
20
|
-
exports.createSlowMockClient = exports.createErrorMockClient = exports.createTestClient = exports.createRecordingClient = exports.createMockClient = exports.RequestRecorder = exports.MockResponseBuilder = exports.MockPcoClient = exports.streamPeopleData = exports.processLargeDataset = exports.processInBatches = exports.PerformanceMonitor = exports.monitorPerformance = exports.getCachedPeople = exports.fetchAllPages = exports.batchFetchPersonDetails = exports.ApiCache = exports.AdaptiveRateLimiter = exports.DEFAULT_AGGRESSIVE_RETRY_CONFIG = exports.DEFAULT_INITIAL_RETRY_CONFIG = exports.validatePersonData = exports.validateContactSimilarity = exports.searchPeople = exports.processFileValue = exports.phoneNumbersSimilar = exports.normalizePhone = void 0;
|
|
18
|
+
exports.getPrimaryContact = exports.getPersonWorkflowCardsWithNotes = exports.getPeopleByHousehold = exports.getOrganizationInfo = exports.getListsWithCategories = exports.getFilename = exports.getFileExtension = exports.getCompletePersonProfile = exports.formatPersonName = exports.formatDate = exports.extractFileUrl = exports.extractEmailDomain = exports.exportAllPeopleData = exports.emailDomainsMatch = exports.DEFAULT_TRUST_WINDOW = exports.createWorkflowCardWithNote = exports.createPersonWithContact = exports.calculateTrust = exports.calculateAge = exports.withTimeout = exports.TIMEOUT_CONFIG = exports.retryWithExponentialBackoff = exports.executeBulkOperation = exports.DEFAULT_RETRY_CONFIG = exports.createErrorReport = exports.classifyError = exports.CircuitBreaker = exports.attemptRecovery = exports.withErrorBoundary = exports.shouldNotRetry = exports.retryWithBackoff = exports.PcoError = exports.handleValidationError = exports.handleTimeoutError = exports.handleNetworkError = exports.ErrorSeverity = exports.ErrorCategory = exports.PcoRateLimiter = exports.PcoApiError = exports.hasRefreshTokenCapability = exports.updateClientTokens = exports.refreshAccessToken = exports.attemptTokenRefresh = exports.getRateLimitInfo = exports.createPcoClient = exports.formatDebugEvent = exports.createDebugLogger = exports.attachDebugListener = exports.PcoClientManager = exports.PcoClient = void 0;
|
|
19
|
+
exports.createSlowMockClient = exports.createErrorMockClient = exports.createTestClient = exports.createRecordingClient = exports.createMockClient = exports.RequestRecorder = exports.MockResponseBuilder = exports.MockPcoClient = exports.streamPeopleData = exports.processLargeDataset = exports.processInBatches = exports.PerformanceMonitor = exports.monitorPerformance = exports.getCachedPeople = exports.fetchAllPages = exports.batchFetchPersonDetails = exports.ApiCache = exports.AdaptiveRateLimiter = exports.DEFAULT_AGGRESSIVE_RETRY_CONFIG = exports.DEFAULT_INITIAL_RETRY_CONFIG = exports.createIncludedLookup = exports.resolveIncluded = exports.findIncluded = exports.validatePersonData = exports.validateContactSimilarity = exports.searchPeople = exports.processFileValue = exports.phoneNumbersSimilar = exports.normalizePhone = exports.normalizeEmail = exports.isValidPhone = exports.isValidEmail = exports.isFileUrl = exports.isFileUpload = void 0;
|
|
21
20
|
// Main client class
|
|
22
21
|
var client_1 = require("./client");
|
|
23
22
|
Object.defineProperty(exports, "PcoClient", { enumerable: true, get: function () { return client_1.PcoClient; } });
|
|
24
23
|
// Client manager for caching and lifecycle management
|
|
25
24
|
var client_manager_1 = require("./client-manager");
|
|
26
25
|
Object.defineProperty(exports, "PcoClientManager", { enumerable: true, get: function () { return client_manager_1.PcoClientManager; } });
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
// Debug (turn logs on/off, see everything that happens — from base, shared across PCO packages)
|
|
27
|
+
var planning_center_base_ts_1 = require("@rachelallyson/planning-center-base-ts");
|
|
28
|
+
Object.defineProperty(exports, "attachDebugListener", { enumerable: true, get: function () { return planning_center_base_ts_1.attachDebugListener; } });
|
|
29
|
+
Object.defineProperty(exports, "createDebugLogger", { enumerable: true, get: function () { return planning_center_base_ts_1.createDebugLogger; } });
|
|
30
|
+
Object.defineProperty(exports, "formatDebugEvent", { enumerable: true, get: function () { return planning_center_base_ts_1.formatDebugEvent; } });
|
|
31
|
+
// ===== Core Functions (for testing and advanced usage) =====
|
|
30
32
|
var core_1 = require("./core");
|
|
31
33
|
Object.defineProperty(exports, "createPcoClient", { enumerable: true, get: function () { return core_1.createPcoClient; } });
|
|
32
|
-
Object.defineProperty(exports, "del", { enumerable: true, get: function () { return core_1.del; } });
|
|
33
|
-
Object.defineProperty(exports, "getAllPages", { enumerable: true, get: function () { return core_1.getAllPages; } });
|
|
34
|
-
Object.defineProperty(exports, "getList", { enumerable: true, get: function () { return core_1.getList; } });
|
|
35
34
|
Object.defineProperty(exports, "getRateLimitInfo", { enumerable: true, get: function () { return core_1.getRateLimitInfo; } });
|
|
36
|
-
|
|
37
|
-
Object.defineProperty(exports, "patch", { enumerable: true, get: function () { return core_1.patch; } });
|
|
38
|
-
Object.defineProperty(exports, "post", { enumerable: true, get: function () { return core_1.post; } });
|
|
35
|
+
// ===== Auth Functions =====
|
|
39
36
|
var auth_1 = require("./auth");
|
|
40
37
|
Object.defineProperty(exports, "attemptTokenRefresh", { enumerable: true, get: function () { return auth_1.attemptTokenRefresh; } });
|
|
41
|
-
Object.defineProperty(exports, "hasRefreshTokenCapability", { enumerable: true, get: function () { return auth_1.hasRefreshTokenCapability; } });
|
|
42
38
|
Object.defineProperty(exports, "refreshAccessToken", { enumerable: true, get: function () { return auth_1.refreshAccessToken; } });
|
|
43
39
|
Object.defineProperty(exports, "updateClientTokens", { enumerable: true, get: function () { return auth_1.updateClientTokens; } });
|
|
40
|
+
Object.defineProperty(exports, "hasRefreshTokenCapability", { enumerable: true, get: function () { return auth_1.hasRefreshTokenCapability; } });
|
|
41
|
+
// ===== v1.x Compatibility Exports (Deprecated) =====
|
|
42
|
+
// Export all types for backward compatibility
|
|
43
|
+
__exportStar(require("./types"), exports);
|
|
44
44
|
// Export API error (re-exported from base)
|
|
45
|
-
var planning_center_base_ts_1 = require("@rachelallyson/planning-center-base-ts");
|
|
46
|
-
Object.defineProperty(exports, "PcoApiError", { enumerable: true, get: function () { return planning_center_base_ts_1.PcoApiError; } });
|
|
47
45
|
var planning_center_base_ts_2 = require("@rachelallyson/planning-center-base-ts");
|
|
48
|
-
Object.defineProperty(exports, "
|
|
46
|
+
Object.defineProperty(exports, "PcoApiError", { enumerable: true, get: function () { return planning_center_base_ts_2.PcoApiError; } });
|
|
49
47
|
var planning_center_base_ts_3 = require("@rachelallyson/planning-center-base-ts");
|
|
50
|
-
Object.defineProperty(exports, "
|
|
51
|
-
|
|
52
|
-
Object.defineProperty(exports, "
|
|
53
|
-
Object.defineProperty(exports, "
|
|
54
|
-
Object.defineProperty(exports, "
|
|
55
|
-
Object.defineProperty(exports, "
|
|
56
|
-
Object.defineProperty(exports, "
|
|
57
|
-
Object.defineProperty(exports, "
|
|
58
|
-
Object.defineProperty(exports, "
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Object.defineProperty(exports, "createFieldDefinition", { enumerable: true, get: function () { return people_1.createFieldDefinition; } });
|
|
62
|
-
Object.defineProperty(exports, "createFieldOption", { enumerable: true, get: function () { return people_1.createFieldOption; } });
|
|
63
|
-
Object.defineProperty(exports, "createPerson", { enumerable: true, get: function () { return people_1.createPerson; } });
|
|
64
|
-
Object.defineProperty(exports, "createPersonAddress", { enumerable: true, get: function () { return people_1.createPersonAddress; } });
|
|
65
|
-
Object.defineProperty(exports, "createPersonEmail", { enumerable: true, get: function () { return people_1.createPersonEmail; } });
|
|
66
|
-
Object.defineProperty(exports, "createPersonFieldData", { enumerable: true, get: function () { return people_1.createPersonFieldData; } });
|
|
67
|
-
Object.defineProperty(exports, "createPersonPhoneNumber", { enumerable: true, get: function () { return people_1.createPersonPhoneNumber; } });
|
|
68
|
-
Object.defineProperty(exports, "createPersonSocialProfile", { enumerable: true, get: function () { return people_1.createPersonSocialProfile; } });
|
|
69
|
-
Object.defineProperty(exports, "createWorkflowCard", { enumerable: true, get: function () { return people_1.createWorkflowCard; } });
|
|
70
|
-
Object.defineProperty(exports, "createWorkflowCardNote", { enumerable: true, get: function () { return people_1.createWorkflowCardNote; } });
|
|
71
|
-
Object.defineProperty(exports, "deleteFieldDefinition", { enumerable: true, get: function () { return people_1.deleteFieldDefinition; } });
|
|
72
|
-
Object.defineProperty(exports, "deletePerson", { enumerable: true, get: function () { return people_1.deletePerson; } });
|
|
73
|
-
Object.defineProperty(exports, "deletePersonFieldData", { enumerable: true, get: function () { return people_1.deletePersonFieldData; } });
|
|
74
|
-
Object.defineProperty(exports, "deleteSocialProfile", { enumerable: true, get: function () { return people_1.deleteSocialProfile; } });
|
|
75
|
-
Object.defineProperty(exports, "getFieldDefinitions", { enumerable: true, get: function () { return people_1.getFieldDefinitions; } });
|
|
76
|
-
Object.defineProperty(exports, "getFieldOptions", { enumerable: true, get: function () { return people_1.getFieldOptions; } });
|
|
77
|
-
Object.defineProperty(exports, "getHousehold", { enumerable: true, get: function () { return people_1.getHousehold; } });
|
|
78
|
-
Object.defineProperty(exports, "getHouseholds", { enumerable: true, get: function () { return people_1.getHouseholds; } });
|
|
79
|
-
Object.defineProperty(exports, "getTabs", { enumerable: true, get: function () { return people_1.getTabs; } });
|
|
80
|
-
Object.defineProperty(exports, "getTab", { enumerable: true, get: function () { return people_1.getTab; } });
|
|
81
|
-
Object.defineProperty(exports, "getListById", { enumerable: true, get: function () { return people_1.getListById; } });
|
|
82
|
-
Object.defineProperty(exports, "getListCategories", { enumerable: true, get: function () { return people_1.getListCategories; } });
|
|
83
|
-
Object.defineProperty(exports, "getLists", { enumerable: true, get: function () { return people_1.getLists; } });
|
|
84
|
-
Object.defineProperty(exports, "runList", { enumerable: true, get: function () { return people_1.runList; } });
|
|
85
|
-
Object.defineProperty(exports, "getNote", { enumerable: true, get: function () { return people_1.getNote; } });
|
|
86
|
-
Object.defineProperty(exports, "getNoteCategories", { enumerable: true, get: function () { return people_1.getNoteCategories; } });
|
|
87
|
-
Object.defineProperty(exports, "getNotes", { enumerable: true, get: function () { return people_1.getNotes; } });
|
|
88
|
-
Object.defineProperty(exports, "getOrganization", { enumerable: true, get: function () { return people_1.getOrganization; } });
|
|
89
|
-
Object.defineProperty(exports, "getPeople", { enumerable: true, get: function () { return people_1.getPeople; } });
|
|
90
|
-
Object.defineProperty(exports, "getPerson", { enumerable: true, get: function () { return people_1.getPerson; } });
|
|
91
|
-
Object.defineProperty(exports, "getPersonAddresses", { enumerable: true, get: function () { return people_1.getPersonAddresses; } });
|
|
92
|
-
Object.defineProperty(exports, "getPersonEmails", { enumerable: true, get: function () { return people_1.getPersonEmails; } });
|
|
93
|
-
Object.defineProperty(exports, "getPersonFieldData", { enumerable: true, get: function () { return people_1.getPersonFieldData; } });
|
|
94
|
-
Object.defineProperty(exports, "getPersonPhoneNumbers", { enumerable: true, get: function () { return people_1.getPersonPhoneNumbers; } });
|
|
95
|
-
Object.defineProperty(exports, "getPersonSocialProfiles", { enumerable: true, get: function () { return people_1.getPersonSocialProfiles; } });
|
|
96
|
-
Object.defineProperty(exports, "getWorkflow", { enumerable: true, get: function () { return people_1.getWorkflow; } });
|
|
97
|
-
Object.defineProperty(exports, "getWorkflowCardNotes", { enumerable: true, get: function () { return people_1.getWorkflowCardNotes; } });
|
|
98
|
-
Object.defineProperty(exports, "getWorkflowCards", { enumerable: true, get: function () { return people_1.getWorkflowCards; } });
|
|
99
|
-
Object.defineProperty(exports, "getWorkflows", { enumerable: true, get: function () { return people_1.getWorkflows; } });
|
|
100
|
-
Object.defineProperty(exports, "updatePerson", { enumerable: true, get: function () { return people_1.updatePerson; } });
|
|
101
|
-
Object.defineProperty(exports, "updatePersonAddress", { enumerable: true, get: function () { return people_1.updatePersonAddress; } });
|
|
48
|
+
Object.defineProperty(exports, "PcoRateLimiter", { enumerable: true, get: function () { return planning_center_base_ts_3.PcoRateLimiter; } });
|
|
49
|
+
var planning_center_base_ts_4 = require("@rachelallyson/planning-center-base-ts");
|
|
50
|
+
Object.defineProperty(exports, "ErrorCategory", { enumerable: true, get: function () { return planning_center_base_ts_4.ErrorCategory; } });
|
|
51
|
+
Object.defineProperty(exports, "ErrorSeverity", { enumerable: true, get: function () { return planning_center_base_ts_4.ErrorSeverity; } });
|
|
52
|
+
Object.defineProperty(exports, "handleNetworkError", { enumerable: true, get: function () { return planning_center_base_ts_4.handleNetworkError; } });
|
|
53
|
+
Object.defineProperty(exports, "handleTimeoutError", { enumerable: true, get: function () { return planning_center_base_ts_4.handleTimeoutError; } });
|
|
54
|
+
Object.defineProperty(exports, "handleValidationError", { enumerable: true, get: function () { return planning_center_base_ts_4.handleValidationError; } });
|
|
55
|
+
Object.defineProperty(exports, "PcoError", { enumerable: true, get: function () { return planning_center_base_ts_4.PcoError; } });
|
|
56
|
+
Object.defineProperty(exports, "retryWithBackoff", { enumerable: true, get: function () { return planning_center_base_ts_4.retryWithBackoff; } });
|
|
57
|
+
Object.defineProperty(exports, "shouldNotRetry", { enumerable: true, get: function () { return planning_center_base_ts_4.shouldNotRetry; } });
|
|
58
|
+
Object.defineProperty(exports, "withErrorBoundary", { enumerable: true, get: function () { return planning_center_base_ts_4.withErrorBoundary; } });
|
|
102
59
|
// ===== Enhanced Error Handling =====
|
|
103
60
|
var error_scenarios_1 = require("./error-scenarios");
|
|
104
61
|
Object.defineProperty(exports, "attemptRecovery", { enumerable: true, get: function () { return error_scenarios_1.attemptRecovery; } });
|
|
@@ -112,7 +69,6 @@ Object.defineProperty(exports, "TIMEOUT_CONFIG", { enumerable: true, get: functi
|
|
|
112
69
|
Object.defineProperty(exports, "withTimeout", { enumerable: true, get: function () { return error_scenarios_1.withTimeout; } });
|
|
113
70
|
// ===== Helper Functions =====
|
|
114
71
|
var helpers_1 = require("./helpers");
|
|
115
|
-
Object.defineProperty(exports, "buildQueryParams", { enumerable: true, get: function () { return helpers_1.buildQueryParams; } });
|
|
116
72
|
Object.defineProperty(exports, "calculateAge", { enumerable: true, get: function () { return helpers_1.calculateAge; } });
|
|
117
73
|
Object.defineProperty(exports, "calculateTrust", { enumerable: true, get: function () { return helpers_1.calculateTrust; } });
|
|
118
74
|
Object.defineProperty(exports, "createPersonWithContact", { enumerable: true, get: function () { return helpers_1.createPersonWithContact; } });
|
|
@@ -143,10 +99,13 @@ Object.defineProperty(exports, "processFileValue", { enumerable: true, get: func
|
|
|
143
99
|
Object.defineProperty(exports, "searchPeople", { enumerable: true, get: function () { return helpers_1.searchPeople; } });
|
|
144
100
|
Object.defineProperty(exports, "validateContactSimilarity", { enumerable: true, get: function () { return helpers_1.validateContactSimilarity; } });
|
|
145
101
|
Object.defineProperty(exports, "validatePersonData", { enumerable: true, get: function () { return helpers_1.validatePersonData; } });
|
|
102
|
+
Object.defineProperty(exports, "findIncluded", { enumerable: true, get: function () { return helpers_1.findIncluded; } });
|
|
103
|
+
Object.defineProperty(exports, "resolveIncluded", { enumerable: true, get: function () { return helpers_1.resolveIncluded; } });
|
|
104
|
+
Object.defineProperty(exports, "createIncludedLookup", { enumerable: true, get: function () { return helpers_1.createIncludedLookup; } });
|
|
146
105
|
// ===== Matching Configuration =====
|
|
147
|
-
var
|
|
148
|
-
Object.defineProperty(exports, "DEFAULT_INITIAL_RETRY_CONFIG", { enumerable: true, get: function () { return
|
|
149
|
-
Object.defineProperty(exports, "DEFAULT_AGGRESSIVE_RETRY_CONFIG", { enumerable: true, get: function () { return
|
|
106
|
+
var people_1 = require("./modules/people");
|
|
107
|
+
Object.defineProperty(exports, "DEFAULT_INITIAL_RETRY_CONFIG", { enumerable: true, get: function () { return people_1.DEFAULT_INITIAL_RETRY_CONFIG; } });
|
|
108
|
+
Object.defineProperty(exports, "DEFAULT_AGGRESSIVE_RETRY_CONFIG", { enumerable: true, get: function () { return people_1.DEFAULT_AGGRESSIVE_RETRY_CONFIG; } });
|
|
150
109
|
// ===== Performance Optimization =====
|
|
151
110
|
var performance_1 = require("./performance");
|
|
152
111
|
Object.defineProperty(exports, "AdaptiveRateLimiter", { enumerable: true, get: function () { return performance_1.AdaptiveRateLimiter; } });
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* v2.0.0 Person Matching Logic
|
|
3
3
|
*/
|
|
4
|
+
import type { PcoClientConfig } from '@rachelallyson/planning-center-base-ts';
|
|
4
5
|
import type { PeopleModule } from '../modules/people';
|
|
5
|
-
import type {
|
|
6
|
+
import type { FlattenedPersonResource } from '../types';
|
|
6
7
|
import { PersonMatchOptions } from '../modules/people';
|
|
7
8
|
export interface MatchResult {
|
|
8
|
-
person:
|
|
9
|
+
person: FlattenedPersonResource;
|
|
9
10
|
score: number;
|
|
10
11
|
reason: string;
|
|
11
12
|
isVerifiedContactMatch?: boolean;
|
|
@@ -14,7 +15,10 @@ export declare class PersonMatcher {
|
|
|
14
15
|
private peopleModule;
|
|
15
16
|
private strategies;
|
|
16
17
|
private scorer;
|
|
17
|
-
|
|
18
|
+
private getConfig?;
|
|
19
|
+
constructor(peopleModule: PeopleModule, getConfig?: () => PcoClientConfig);
|
|
20
|
+
/** Log only when client config has debug enabled; no-op otherwise */
|
|
21
|
+
private debugLog;
|
|
18
22
|
/**
|
|
19
23
|
* Resolve retry configuration from options, with defaults
|
|
20
24
|
*/
|
|
@@ -34,7 +38,7 @@ export declare class PersonMatcher {
|
|
|
34
38
|
* @param options.retryConfig - Configuration for retry logic to handle PCO contact verification delays
|
|
35
39
|
* @param options.searchStrategy - 'single' for standard search, 'multi-step' for trying multiple strategies
|
|
36
40
|
*/
|
|
37
|
-
findOrCreate(options: PersonMatchOptions): Promise<
|
|
41
|
+
findOrCreate(options: PersonMatchOptions): Promise<FlattenedPersonResource>;
|
|
38
42
|
/**
|
|
39
43
|
* Final aggressive search before creating a new person
|
|
40
44
|
*
|
package/dist/matching/matcher.js
CHANGED
|
@@ -4,15 +4,23 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PersonMatcher = void 0;
|
|
7
|
+
const planning_center_base_ts_1 = require("@rachelallyson/planning-center-base-ts");
|
|
7
8
|
const people_1 = require("../modules/people");
|
|
8
9
|
const strategies_1 = require("./strategies");
|
|
9
10
|
const scoring_1 = require("./scoring");
|
|
10
11
|
const helpers_1 = require("../helpers");
|
|
11
12
|
class PersonMatcher {
|
|
12
|
-
constructor(peopleModule) {
|
|
13
|
+
constructor(peopleModule, getConfig) {
|
|
13
14
|
this.peopleModule = peopleModule;
|
|
15
|
+
this.getConfig = getConfig;
|
|
14
16
|
this.strategies = new strategies_1.MatchStrategies();
|
|
15
|
-
this.scorer = new scoring_1.MatchScorer(peopleModule);
|
|
17
|
+
this.scorer = new scoring_1.MatchScorer(peopleModule, getConfig);
|
|
18
|
+
}
|
|
19
|
+
/** Log only when client config has debug enabled; no-op otherwise */
|
|
20
|
+
debugLog(message, data) {
|
|
21
|
+
const logger = (0, planning_center_base_ts_1.createDebugLogger)(this.getConfig?.());
|
|
22
|
+
if (logger.enabled)
|
|
23
|
+
logger.log(message, data);
|
|
16
24
|
}
|
|
17
25
|
/**
|
|
18
26
|
* Resolve retry configuration from options, with defaults
|
|
@@ -101,7 +109,7 @@ class PersonMatcher {
|
|
|
101
109
|
async findWithAggressiveRetry(options) {
|
|
102
110
|
const { matchStrategy = 'fuzzy', searchStrategy = 'single', retryConfigs } = options;
|
|
103
111
|
const aggressiveConfig = this.resolveRetryConfig(undefined, retryConfigs?.aggressive, people_1.DEFAULT_AGGRESSIVE_RETRY_CONFIG);
|
|
104
|
-
|
|
112
|
+
this.debugLog(`findOrCreate aggressive final search before create`, {
|
|
105
113
|
maxWaitTime: aggressiveConfig.maxWaitTime,
|
|
106
114
|
maxRetries: aggressiveConfig.maxRetries,
|
|
107
115
|
});
|
|
@@ -116,7 +124,7 @@ class PersonMatcher {
|
|
|
116
124
|
match = await this.findMatch({ ...options, matchStrategy });
|
|
117
125
|
}
|
|
118
126
|
if (match) {
|
|
119
|
-
|
|
127
|
+
this.debugLog(`findOrCreate aggressive search found person (would have created duplicate)`, {
|
|
120
128
|
personId: match.person.id,
|
|
121
129
|
attempt,
|
|
122
130
|
totalWaitTime,
|
|
@@ -125,7 +133,7 @@ class PersonMatcher {
|
|
|
125
133
|
}
|
|
126
134
|
}
|
|
127
135
|
catch (error) {
|
|
128
|
-
|
|
136
|
+
this.debugLog(`findOrCreate aggressive search attempt ${attempt} failed`, { error: String(error) });
|
|
129
137
|
}
|
|
130
138
|
// Don't wait on the last attempt
|
|
131
139
|
if (attempt === aggressiveConfig.maxRetries) {
|
|
@@ -139,7 +147,7 @@ class PersonMatcher {
|
|
|
139
147
|
totalWaitTime += delay;
|
|
140
148
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
141
149
|
}
|
|
142
|
-
|
|
150
|
+
this.debugLog(`findOrCreate aggressive search completed - no match found, safe to create`, {
|
|
143
151
|
totalWaitTime,
|
|
144
152
|
maxRetries: aggressiveConfig.maxRetries,
|
|
145
153
|
});
|
|
@@ -172,7 +180,7 @@ class PersonMatcher {
|
|
|
172
180
|
}
|
|
173
181
|
const match = await this.findMatch(searchOptions);
|
|
174
182
|
if (match) {
|
|
175
|
-
|
|
183
|
+
this.debugLog(`findOrCreate multi-step search found match using ${strategy.description}`, {
|
|
176
184
|
personId: match.person.id,
|
|
177
185
|
score: match.score,
|
|
178
186
|
reason: match.reason,
|
|
@@ -182,7 +190,7 @@ class PersonMatcher {
|
|
|
182
190
|
}
|
|
183
191
|
catch (error) {
|
|
184
192
|
// Log but continue to next strategy
|
|
185
|
-
|
|
193
|
+
this.debugLog(`findOrCreate multi-step strategy "${strategy.description}" failed`, { error: String(error) });
|
|
186
194
|
}
|
|
187
195
|
}
|
|
188
196
|
return null;
|
|
@@ -226,7 +234,7 @@ class PersonMatcher {
|
|
|
226
234
|
}
|
|
227
235
|
// Log success if we had to retry
|
|
228
236
|
if (attempt > 1) {
|
|
229
|
-
|
|
237
|
+
this.debugLog(`findOrCreate found person after ${attempt} attempts (waited ${totalWaitTime}ms)`, {
|
|
230
238
|
personId: person.id,
|
|
231
239
|
attempt,
|
|
232
240
|
totalWaitTime,
|
|
@@ -250,7 +258,7 @@ class PersonMatcher {
|
|
|
250
258
|
);
|
|
251
259
|
// Check if we've exceeded max wait time
|
|
252
260
|
if (totalWaitTime + delay > maxWaitTime) {
|
|
253
|
-
|
|
261
|
+
this.debugLog(`findOrCreate max wait time (${maxWaitTime}ms) exceeded, stopping retries`, {
|
|
254
262
|
attempt,
|
|
255
263
|
totalWaitTime,
|
|
256
264
|
remainingDelay: maxWaitTime - totalWaitTime
|
|
@@ -259,7 +267,7 @@ class PersonMatcher {
|
|
|
259
267
|
}
|
|
260
268
|
totalWaitTime += delay;
|
|
261
269
|
// Log retry attempt
|
|
262
|
-
|
|
270
|
+
this.debugLog(`findOrCreate attempt ${attempt} failed, retrying in ${delay}ms`, {
|
|
263
271
|
attempt,
|
|
264
272
|
delay,
|
|
265
273
|
totalWaitTime,
|
|
@@ -284,18 +292,15 @@ class PersonMatcher {
|
|
|
284
292
|
// Search by email (with normalization and validation)
|
|
285
293
|
if (email) {
|
|
286
294
|
// Validate email format to avoid wasted API calls
|
|
287
|
-
if (
|
|
288
|
-
console.warn('Invalid email format, skipping email search:', email);
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
295
|
+
if ((0, helpers_1.isValidEmail)(email)) {
|
|
291
296
|
try {
|
|
292
297
|
// Normalize email before search to improve PCO search results
|
|
293
298
|
const normalizedEmail = (0, helpers_1.normalizeEmail)(email);
|
|
294
299
|
const emailResults = await this.peopleModule.search({ email: normalizedEmail });
|
|
295
300
|
emailPhoneMatches.push(...emailResults.data);
|
|
296
301
|
}
|
|
297
|
-
catch
|
|
298
|
-
|
|
302
|
+
catch {
|
|
303
|
+
// Email search failed, continue without email results
|
|
299
304
|
}
|
|
300
305
|
}
|
|
301
306
|
}
|
|
@@ -307,8 +312,8 @@ class PersonMatcher {
|
|
|
307
312
|
const phoneResults = await this.peopleModule.search({ phone: normalizedPhone });
|
|
308
313
|
emailPhoneMatches.push(...phoneResults.data);
|
|
309
314
|
}
|
|
310
|
-
catch
|
|
311
|
-
|
|
315
|
+
catch {
|
|
316
|
+
// Phone search failed, continue without phone results
|
|
312
317
|
}
|
|
313
318
|
}
|
|
314
319
|
// Remove duplicates
|
|
@@ -342,7 +347,7 @@ class PersonMatcher {
|
|
|
342
347
|
nameOnlyMatches.push(...nameResults.data);
|
|
343
348
|
}
|
|
344
349
|
catch (error) {
|
|
345
|
-
|
|
350
|
+
this.debugLog('findMatch name search failed', { error: String(error) });
|
|
346
351
|
}
|
|
347
352
|
}
|
|
348
353
|
}
|
|
@@ -407,7 +412,6 @@ class PersonMatcher {
|
|
|
407
412
|
*/
|
|
408
413
|
async findMatchByNameWithContactValidation(firstName, lastName, searchEmail, searchPhone, validationStrategy, options) {
|
|
409
414
|
try {
|
|
410
|
-
console.log(`[PERSON_MATCH] Attempting name-based search fallback for ${firstName} ${lastName}`);
|
|
411
415
|
const nameResults = await this.peopleModule.search({
|
|
412
416
|
name: `${firstName} ${lastName}`
|
|
413
417
|
});
|
|
@@ -420,11 +424,6 @@ class PersonMatcher {
|
|
|
420
424
|
if (isValid) {
|
|
421
425
|
const score = await this.scorer.scoreMatch(candidate, options);
|
|
422
426
|
const reason = await this.scorer.getMatchReason(candidate, options);
|
|
423
|
-
console.log(`[PERSON_MATCH] Name-based search found validated match`, {
|
|
424
|
-
personId: candidate.id,
|
|
425
|
-
validationStrategy,
|
|
426
|
-
score,
|
|
427
|
-
});
|
|
428
427
|
return {
|
|
429
428
|
person: candidate,
|
|
430
429
|
score,
|
|
@@ -433,14 +432,9 @@ class PersonMatcher {
|
|
|
433
432
|
};
|
|
434
433
|
}
|
|
435
434
|
}
|
|
436
|
-
console.log(`[PERSON_MATCH] Name-based search found candidates but none passed contact validation`, {
|
|
437
|
-
candidateCount: nameResults.data.length,
|
|
438
|
-
validationStrategy,
|
|
439
|
-
});
|
|
440
435
|
return null;
|
|
441
436
|
}
|
|
442
|
-
catch
|
|
443
|
-
console.warn('[PERSON_MATCH] Name-based search fallback failed:', error);
|
|
437
|
+
catch {
|
|
444
438
|
return null;
|
|
445
439
|
}
|
|
446
440
|
}
|
|
@@ -451,8 +445,8 @@ class PersonMatcher {
|
|
|
451
445
|
try {
|
|
452
446
|
// Get person's contact info
|
|
453
447
|
const [personEmails, personPhones] = await Promise.all([
|
|
454
|
-
this.peopleModule.getEmails(candidate.id).then(r => r.data?.map(e => e.
|
|
455
|
-
this.peopleModule.getPhoneNumbers(candidate.id).then(r => r.data?.map(p => p.
|
|
448
|
+
this.peopleModule.getEmails(candidate.id).then(r => r.data?.map(e => e.address || '').filter(Boolean) || []).catch(() => []),
|
|
449
|
+
this.peopleModule.getPhoneNumbers(candidate.id).then(r => r.data?.map(p => p.number || '').filter(Boolean) || []).catch(() => []),
|
|
456
450
|
]);
|
|
457
451
|
switch (validationStrategy) {
|
|
458
452
|
case 'strict':
|
|
@@ -490,7 +484,7 @@ class PersonMatcher {
|
|
|
490
484
|
}
|
|
491
485
|
}
|
|
492
486
|
catch (error) {
|
|
493
|
-
|
|
487
|
+
this.debugLog(`findMatch contact validation failed for person ${candidate.id}`, { error: String(error) });
|
|
494
488
|
return false;
|
|
495
489
|
}
|
|
496
490
|
}
|
|
@@ -508,7 +502,7 @@ class PersonMatcher {
|
|
|
508
502
|
candidates.push(...emailMatches.data);
|
|
509
503
|
}
|
|
510
504
|
catch (error) {
|
|
511
|
-
|
|
505
|
+
this.debugLog('findMatch email search failed', { error: String(error) });
|
|
512
506
|
}
|
|
513
507
|
}
|
|
514
508
|
// Strategy 2: Exact phone match
|
|
@@ -518,7 +512,7 @@ class PersonMatcher {
|
|
|
518
512
|
candidates.push(...phoneMatches.data);
|
|
519
513
|
}
|
|
520
514
|
catch (error) {
|
|
521
|
-
|
|
515
|
+
this.debugLog('findMatch phone search failed', { error: String(error) });
|
|
522
516
|
}
|
|
523
517
|
}
|
|
524
518
|
// Strategy 3: Name-based search
|
|
@@ -530,7 +524,7 @@ class PersonMatcher {
|
|
|
530
524
|
candidates.push(...nameMatches.data);
|
|
531
525
|
}
|
|
532
526
|
catch (error) {
|
|
533
|
-
|
|
527
|
+
this.debugLog('findMatch name search failed', { error: String(error) });
|
|
534
528
|
}
|
|
535
529
|
}
|
|
536
530
|
// Strategy 4: Broader search if no exact matches
|
|
@@ -542,7 +536,7 @@ class PersonMatcher {
|
|
|
542
536
|
candidates.push(...broadMatches.data);
|
|
543
537
|
}
|
|
544
538
|
catch (error) {
|
|
545
|
-
|
|
539
|
+
this.debugLog('findMatch broad search failed', { error: String(error) });
|
|
546
540
|
}
|
|
547
541
|
}
|
|
548
542
|
// Remove duplicates based on person ID
|
|
@@ -558,7 +552,7 @@ class PersonMatcher {
|
|
|
558
552
|
try {
|
|
559
553
|
const personEmails = await this.peopleModule.getEmails(person.id);
|
|
560
554
|
const normalizedSearchEmail = (0, helpers_1.normalizeEmail)(email);
|
|
561
|
-
const emails = personEmails.data?.map(e => (0, helpers_1.normalizeEmail)(e.
|
|
555
|
+
const emails = personEmails.data?.map(e => (0, helpers_1.normalizeEmail)(e.address || '')).filter(Boolean) || [];
|
|
562
556
|
return emails.includes(normalizedSearchEmail);
|
|
563
557
|
}
|
|
564
558
|
catch {
|
|
@@ -572,7 +566,7 @@ class PersonMatcher {
|
|
|
572
566
|
try {
|
|
573
567
|
const personPhones = await this.peopleModule.getPhoneNumbers(person.id);
|
|
574
568
|
const normalizedSearchPhone = (0, helpers_1.normalizePhone)(phone);
|
|
575
|
-
const phones = personPhones.data?.map(p => (0, helpers_1.normalizePhone)(p.
|
|
569
|
+
const phones = personPhones.data?.map(p => (0, helpers_1.normalizePhone)(p.number || '')).filter(Boolean) || [];
|
|
576
570
|
return phones.includes(normalizedSearchPhone);
|
|
577
571
|
}
|
|
578
572
|
catch {
|
|
@@ -597,7 +591,7 @@ class PersonMatcher {
|
|
|
597
591
|
}
|
|
598
592
|
}
|
|
599
593
|
catch (error) {
|
|
600
|
-
|
|
594
|
+
this.debugLog(`addMissingContactInfo failed to add email for person ${person.id}`, { error: String(error) });
|
|
601
595
|
}
|
|
602
596
|
}
|
|
603
597
|
// Check and add phone if provided and missing
|
|
@@ -613,7 +607,7 @@ class PersonMatcher {
|
|
|
613
607
|
}
|
|
614
608
|
}
|
|
615
609
|
catch (error) {
|
|
616
|
-
|
|
610
|
+
this.debugLog(`addMissingContactInfo failed to add phone for person ${person.id}`, { error: String(error) });
|
|
617
611
|
}
|
|
618
612
|
}
|
|
619
613
|
}
|
|
@@ -629,7 +623,7 @@ class PersonMatcher {
|
|
|
629
623
|
return candidates;
|
|
630
624
|
}
|
|
631
625
|
return candidates.filter(person => {
|
|
632
|
-
const birthdate = person.
|
|
626
|
+
const birthdate = person.birthdate;
|
|
633
627
|
return (0, helpers_1.matchesAgeCriteria)(birthdate, {
|
|
634
628
|
agePreference: options.agePreference,
|
|
635
629
|
minAge: options.minAge,
|
|
@@ -648,11 +642,14 @@ class PersonMatcher {
|
|
|
648
642
|
throw new Error('First name is required to create a person');
|
|
649
643
|
}
|
|
650
644
|
// Create basic person data (only name fields)
|
|
645
|
+
// Use camelCase as expected by PersonCreateOptions
|
|
651
646
|
const personData = {};
|
|
652
647
|
if (options.firstName)
|
|
653
|
-
personData.
|
|
648
|
+
personData.firstName = options.firstName;
|
|
654
649
|
if (options.lastName)
|
|
655
|
-
personData.
|
|
650
|
+
personData.lastName = options.lastName;
|
|
651
|
+
// Status is required by the API
|
|
652
|
+
personData.status = 'active';
|
|
656
653
|
// Create the person first
|
|
657
654
|
const person = await this.peopleModule.create(personData);
|
|
658
655
|
// Add email contact if provided
|
|
@@ -665,7 +662,7 @@ class PersonMatcher {
|
|
|
665
662
|
});
|
|
666
663
|
}
|
|
667
664
|
catch (error) {
|
|
668
|
-
|
|
665
|
+
this.debugLog(`createPerson failed to create email for person ${person.id}`, { error: String(error) });
|
|
669
666
|
}
|
|
670
667
|
}
|
|
671
668
|
// Add phone contact if provided
|
|
@@ -678,19 +675,15 @@ class PersonMatcher {
|
|
|
678
675
|
});
|
|
679
676
|
}
|
|
680
677
|
catch (error) {
|
|
681
|
-
|
|
678
|
+
this.debugLog(`createPerson failed to create phone for person ${person.id}`, { error: String(error) });
|
|
682
679
|
}
|
|
683
680
|
}
|
|
684
681
|
// Set campus if provided
|
|
685
682
|
if (options.campusId) {
|
|
686
|
-
|
|
687
|
-
await this.peopleModule.setPrimaryCampus(person.id, options.campusId);
|
|
688
|
-
}
|
|
689
|
-
catch (error) {
|
|
690
|
-
console.warn(`Failed to set campus for person ${person.id}:`, error);
|
|
691
|
-
}
|
|
683
|
+
await this.peopleModule.setPrimaryCampus(person.id, options.campusId);
|
|
692
684
|
}
|
|
693
|
-
|
|
685
|
+
// Return the flattened person resource to match the type expected by the rest of the code
|
|
686
|
+
return this.peopleModule.getById(person.id);
|
|
694
687
|
}
|
|
695
688
|
/**
|
|
696
689
|
* Get all potential matches with detailed scoring
|
|
@@ -706,7 +699,7 @@ class PersonMatcher {
|
|
|
706
699
|
emailPhoneMatches.push(...emailResults.data);
|
|
707
700
|
}
|
|
708
701
|
catch (error) {
|
|
709
|
-
|
|
702
|
+
this.debugLog('findMatch email search failed', { error: String(error) });
|
|
710
703
|
}
|
|
711
704
|
}
|
|
712
705
|
if (phone) {
|
|
@@ -715,7 +708,7 @@ class PersonMatcher {
|
|
|
715
708
|
emailPhoneMatches.push(...phoneResults.data);
|
|
716
709
|
}
|
|
717
710
|
catch (error) {
|
|
718
|
-
|
|
711
|
+
this.debugLog('findMatch phone search failed', { error: String(error) });
|
|
719
712
|
}
|
|
720
713
|
}
|
|
721
714
|
const uniqueEmailPhoneMatches = emailPhoneMatches.filter((person, index, self) => index === self.findIndex(p => p.id === person.id));
|
|
@@ -742,7 +735,7 @@ class PersonMatcher {
|
|
|
742
735
|
nameOnlyMatches.push(...nameResults.data);
|
|
743
736
|
}
|
|
744
737
|
catch (error) {
|
|
745
|
-
|
|
738
|
+
this.debugLog('findMatch name search failed', { error: String(error) });
|
|
746
739
|
}
|
|
747
740
|
}
|
|
748
741
|
}
|
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* v2.0.0 Person Match Scoring
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { PcoClientConfig } from '@rachelallyson/planning-center-base-ts';
|
|
5
|
+
import type { FlattenedPersonResource } from '../types';
|
|
5
6
|
import type { PersonMatchOptions, PeopleModule } from '../modules/people';
|
|
6
7
|
export declare class MatchScorer {
|
|
7
8
|
private peopleModule;
|
|
8
|
-
|
|
9
|
+
private getConfig?;
|
|
10
|
+
constructor(peopleModule: PeopleModule, getConfig?: () => PcoClientConfig);
|
|
11
|
+
private debugLog;
|
|
9
12
|
/**
|
|
10
13
|
* Score a person match based on various criteria
|
|
11
14
|
*/
|
|
12
|
-
scoreMatch(person:
|
|
15
|
+
scoreMatch(person: FlattenedPersonResource, options: PersonMatchOptions): Promise<number>;
|
|
13
16
|
/**
|
|
14
17
|
* Get a human-readable reason for the match
|
|
15
18
|
*/
|
|
16
|
-
getMatchReason(person:
|
|
19
|
+
getMatchReason(person: FlattenedPersonResource, options: PersonMatchOptions): Promise<string>;
|
|
17
20
|
/**
|
|
18
21
|
* Score email matching - verifies actual email matches
|
|
19
22
|
*/
|
|
20
|
-
scoreEmailMatch(person:
|
|
23
|
+
scoreEmailMatch(person: FlattenedPersonResource, email: string): Promise<number>;
|
|
21
24
|
/**
|
|
22
25
|
* Score phone matching - verifies actual phone matches
|
|
23
26
|
*/
|
|
24
|
-
scorePhoneMatch(person:
|
|
27
|
+
scorePhoneMatch(person: FlattenedPersonResource, phone: string): Promise<number>;
|
|
25
28
|
/**
|
|
26
29
|
* Score name matching - only exact matches
|
|
27
30
|
*/
|