@memberjunction/integration-connectors 5.8.0 → 5.10.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.
@@ -1,6 +1,7 @@
1
- import type { UserInfo } from '@memberjunction/core';
1
+ import { type UserInfo } from '@memberjunction/core';
2
2
  import type { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
3
- import { BaseIntegrationConnector, type ConnectionTestResult, type ExternalObjectSchema, type ExternalFieldSchema, type FetchContext, type FetchBatchResult, type DefaultFieldMapping } from '@memberjunction/integration-engine';
3
+ import { BaseRESTIntegrationConnector, type RESTAuthContext, type RESTResponse, type PaginationState, type PaginationType, type ConnectionTestResult, type FetchContext, type FetchBatchResult, type DefaultFieldMapping, type DefaultIntegrationConfig } from '@memberjunction/integration-engine';
4
+ import type { MJIntegrationObjectEntity } from '@memberjunction/core-entities';
4
5
  /** Connection configuration parsed from CompanyIntegration.Configuration JSON */
5
6
  export interface YMConnectionConfig {
6
7
  /** YM client/site identifier (integer) */
@@ -13,6 +14,9 @@ export interface YMConnectionConfig {
13
14
  /**
14
15
  * Connector for the YourMembership (YM) AMS REST API.
15
16
  *
17
+ * Extends BaseRESTIntegrationConnector to leverage metadata-driven object/field
18
+ * discovery from IntegrationEngineBase cache and generic pagination handling.
19
+ *
16
20
  * Auth flow:
17
21
  * 1. POST /Ams/Authenticate with credentials + ClientID
18
22
  * 2. Receive SessionId
@@ -20,13 +24,87 @@ export interface YMConnectionConfig {
20
24
  *
21
25
  * Configuration JSON: { "ClientID": "25363", "APIKey": "...", "APIPassword": "..." }
22
26
  */
23
- export declare class YourMembershipConnector extends BaseIntegrationConnector {
27
+ export declare class YourMembershipConnector extends BaseRESTIntegrationConnector {
24
28
  /** Session cache keyed by ClientID */
25
29
  private sessionCache;
30
+ /** Timestamp of the last API request, used for throttling */
31
+ private lastRequestTime;
32
+ protected Authenticate(companyIntegration: MJCompanyIntegrationEntity): Promise<RESTAuthContext>;
33
+ protected BuildHeaders(auth: RESTAuthContext): Record<string, string>;
34
+ protected MakeHTTPRequest(auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, _body?: unknown): Promise<RESTResponse>;
35
+ protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
36
+ protected ExtractPaginationInfo(rawBody: unknown, paginationType: PaginationType, currentPage: number, currentOffset: number, pageSize: number): PaginationState;
37
+ protected GetBaseURL(companyIntegration: MJCompanyIntegrationEntity): string;
38
+ /**
39
+ * Overrides base pagination URL building to use YM's expected parameter names:
40
+ * - PageNumber type: `PageNumber` / `PageSize` (not `page` / `pageSize`)
41
+ * - Offset type: `OffSet` (not `offset`); no explicit limit param — YM uses
42
+ * its own default batch size (~200 records)
43
+ */
44
+ protected BuildPaginatedURL(basePath: string, obj: MJIntegrationObjectEntity, page: number, offset: number, cursor?: string): string;
45
+ /**
46
+ * Overrides base FetchChanges to handle YM-specific edge cases:
47
+ * - Groups/GroupTypes: nested GroupTypeList response needs custom flattening
48
+ * - Members: client-side watermark filtering + selective detail enrichment
49
+ *
50
+ * The MemberList API returns all members every time (no server-side date filter),
51
+ * but each record includes a `LastUpdated` field. We pull the full list, filter
52
+ * to only records changed since the watermark, and only call the expensive
53
+ * per-member detail endpoint for those changed records.
54
+ */
55
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
56
+ /**
57
+ * Filters the full member list to only records changed since the watermark,
58
+ * then enriches only those changed records via the detail endpoint.
59
+ * Returns a new watermark based on the latest LastUpdated value seen.
60
+ */
61
+ private FetchMembersWithWatermark;
62
+ /**
63
+ * Filters records by comparing a date field against a watermark timestamp.
64
+ * Returns only records where the date field is newer than the watermark,
65
+ * plus the latest date value seen (to use as the next watermark).
66
+ */
67
+ private FilterByWatermark;
68
+ /** Tests connectivity by authenticating and fetching ClientConfig. */
69
+ TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
70
+ /** Returns suggested default configuration for YM integration setup. */
71
+ GetDefaultConfiguration(): DefaultIntegrationConfig;
72
+ /** Returns suggested default field mappings for common YM objects to MJ entities. */
73
+ GetDefaultFieldMappings(objectName: string, _entityName: string): DefaultFieldMapping[];
74
+ /**
75
+ * Fetches Groups or GroupTypes, which have a nested structure:
76
+ * GroupTypeList → Groups. When objectName is 'GroupTypes', returns just
77
+ * the type entries. When 'Groups', flattens into individual group records.
78
+ */
79
+ private FetchGroups;
80
+ /** Builds ExternalRecords for GroupType entries only. */
81
+ private BuildGroupTypeRecords;
82
+ /** Flattens nested GroupTypeList → Groups into flat group records. */
83
+ private FlattenGroupRecords;
84
+ /**
85
+ * Enriches Members records with full profile data from the detail endpoint.
86
+ * The list endpoint returns sparse data (name, email); the detail endpoint
87
+ * returns full address, phone, custom fields, etc.
88
+ */
89
+ private EnrichMembersWithDetails;
90
+ /**
91
+ * Fetches full detail data for a single member and merges it.
92
+ * Detail endpoint returns camelCase + nested objects; we normalize to flat PascalCase.
93
+ */
94
+ private EnrichSingleMember;
95
+ /**
96
+ * Maps the Members detail endpoint response to our flat PascalCase schema.
97
+ * Detail endpoint returns: { firstName, lastName, emailAddress, primaryAddress: { ... } }
98
+ * We need: { FirstName, LastName, EmailAddr, Phone, Address1, ... }
99
+ */
100
+ private NormalizeMemberDetail;
26
101
  /**
27
- * Parses the Configuration JSON from a CompanyIntegration entity.
102
+ * Parses credentials from CompanyIntegration.CredentialID (preferred) or
103
+ * falls back to CompanyIntegration.Configuration JSON for backwards compat.
28
104
  */
29
- protected ParseConfig(companyIntegration: MJCompanyIntegrationEntity): YMConnectionConfig;
105
+ protected ParseConfig(companyIntegration: MJCompanyIntegrationEntity, contextUser?: UserInfo): Promise<YMConnectionConfig>;
106
+ private LoadFromCredential;
107
+ private ParseConfigJson;
30
108
  /** Obtains or reuses a YM session for the given credentials. */
31
109
  protected GetSession(config: YMConnectionConfig): Promise<string>;
32
110
  /** Creates a new YM session via the Authenticate endpoint. */
@@ -34,43 +112,32 @@ export declare class YourMembershipConnector extends BaseIntegrationConnector {
34
112
  /** Invalidates a cached session so the next request re-authenticates. */
35
113
  protected InvalidateSession(clientId: string): void;
36
114
  /**
37
- * Makes a GET request to a YM API endpoint using session auth.
38
- * Retries once on 401 (session expiry).
115
+ * Makes a direct YM API request using the connector's auth and URL conventions.
116
+ * Used for YM-specific calls (Groups, detail enrichment, TestConnection)
117
+ * that bypass the base class's metadata-driven flow.
39
118
  */
40
- protected MakeRequest(config: YMConnectionConfig, endpoint: string, queryParams?: Record<string, string>): Promise<Record<string, unknown>>;
41
- private FetchWithSession;
42
- private BuildUrl;
119
+ private MakeYMRequest;
120
+ /** Executes an HTTP request with a timeout. */
121
+ private FetchWithTimeout;
122
+ /** Wraps response.json() with a timeout to prevent indefinite hangs. */
123
+ private JsonWithTimeout;
124
+ /** Refreshes session after 401 or timeout, updating headers in-place. */
125
+ private RefreshSession;
126
+ /** Checks if an error is a timeout/abort error. */
127
+ private IsTimeoutError;
128
+ /** Calculates retry delay from Retry-After header or exponential backoff. */
129
+ private CalculateRetryDelay;
130
+ /** Converts a fetch Response + parsed body into a RESTResponse. */
131
+ private BuildRESTResponse;
132
+ private Sleep;
133
+ /** Checks for YM API-level errors in the response envelope. */
43
134
  private CheckResponseError;
44
- /** Tests connectivity by authenticating and fetching ClientConfig. */
45
- TestConnection(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ConnectionTestResult>;
46
- /** Returns all known YM object types available for integration. */
47
- DiscoverObjects(_companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ExternalObjectSchema[]>;
48
- /** Returns the known field schema for a YM object. */
49
- DiscoverFields(_companyIntegration: MJCompanyIntegrationEntity, objectName: string, _contextUser: UserInfo): Promise<ExternalFieldSchema[]>;
135
+ /** Filters out YM API metadata keys that shouldn't be stored as field data. */
136
+ private FilterMetadataKeys;
50
137
  /**
51
- * Fetches a batch of records from a YM API endpoint.
52
- *
53
- * For paginated endpoints (Members, Events, Certifications), uses
54
- * PageSize/PageNumber. The watermark tracks the current page number
55
- * for resuming large fetches across batches.
56
- *
57
- * For non-paginated endpoints (MemberTypes, Memberships, Groups, Products),
58
- * fetches all data in one call.
138
+ * Estimates record count from a raw response body.
139
+ * Used by ExtractPaginationInfo to determine if more pages exist.
59
140
  */
60
- FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
61
- /** Fetches data from a paginated YM endpoint. Watermark = page number. */
62
- private FetchPaginated;
63
- /** Fetches all data from a non-paginated endpoint in a single request. */
64
- private FetchAll;
65
- /** Fetches endpoints that return a raw JSON array (e.g., Products). */
66
- private FetchRawArray;
67
- /**
68
- * Fetches Groups, which have a nested structure: GroupTypeList → Groups.
69
- * Flattens into individual group records with the GroupType name attached.
70
- */
71
- private FetchGroups;
72
- /** Returns suggested default field mappings for YM objects to MJ entities. */
73
- GetDefaultFieldMappings(objectName: string, _entityName: string): DefaultFieldMapping[];
74
- private BuildRecord;
141
+ private EstimateRecordCount;
75
142
  }
76
143
  //# sourceMappingURL=YourMembershipConnector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"YourMembershipConnector.d.ts","sourceRoot":"","sources":["../src/YourMembershipConnector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EACH,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAErB,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAI5C,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IAC/B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;CACvB;AA+MD;;;;;;;;;GASG;AACH,qBACa,uBAAwB,SAAQ,wBAAwB;IACjE,sCAAsC;IACtC,OAAO,CAAC,YAAY,CAAgC;IAIpD;;OAEG;IACH,SAAS,CAAC,WAAW,CAAC,kBAAkB,EAAE,0BAA0B,GAAG,kBAAkB;IAoBzF,gEAAgE;cAChD,UAAU,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQvE,8DAA8D;YAChD,aAAa;IAsC3B,yEAAyE;IACzE,SAAS,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAMnD;;;OAGG;cACa,WAAW,CACvB,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAqBrB,gBAAgB;IAO9B,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,kBAAkB;IAS1B,sEAAsE;IACzD,cAAc,CACvB,kBAAkB,EAAE,0BAA0B,EAC9C,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,oBAAoB,CAAC;IAkBhC,mEAAmE;IACtD,eAAe,CACxB,mBAAmB,EAAE,0BAA0B,EAC/C,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,oBAAoB,EAAE,CAAC;IASlC,sDAAsD;IACzC,cAAc,CACvB,mBAAmB,EAAE,0BAA0B,EAC/C,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAIjC;;;;;;;;;OASG;IACU,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuBvE,0EAA0E;YAC5D,cAAc;IA+B5B,0EAA0E;YAC5D,QAAQ;IAmBtB,uEAAuE;YACzD,aAAa;IAyB3B;;;OAGG;YACW,WAAW;IA4BzB,8EAA8E;IAC9D,uBAAuB,CACnC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACpB,mBAAmB,EAAE;IAyBxB,OAAO,CAAC,WAAW;CAYtB"}
1
+ {"version":3,"file":"YourMembershipConnector.d.ts","sourceRoot":"","sources":["../src/YourMembershipConnector.ts"],"names":[],"mappings":"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"}