@memberjunction/connector-higher-logic-thrive-community 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,205 @@
1
+ import { type UserInfo } from '@memberjunction/core';
2
+ import type { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
3
+ import { BaseRESTIntegrationConnector, type RESTAuthContext, type RESTResponse, type PaginationState, type PaginationType, type ConnectionTestResult, type FetchContext, type FetchBatchResult, type RateLimitPolicy, type CreateRecordContext, type DeleteRecordContext, type CRUDResult, type SourceSchemaInfo } from '@memberjunction/integration-engine';
4
+ /** The four real vendor pagination schemes, derived from the per-IO Configuration.paginationDetail. */
5
+ type PageScheme = 'none' | 'seek-key' | 'continuation-token' | 'marker-direction' | 'offset';
6
+ /**
7
+ * Higher Logic Thrive Community connector — extends BaseRESTIntegrationConnector (REST/JSON RPC over HTTP).
8
+ *
9
+ * Discovery + generic per-operation CRUD are inherited; this class supplies the Higher Logic protocol
10
+ * surface: two-step token auth, region-selected base URL, the four real pagination schemes (over GET and
11
+ * POST), the HelpPage response-envelope normalizer, watermark incremental for EventRegistrants, connection
12
+ * testing, and the §7/§10 sync-efficiency hooks the frozen contract evidences.
13
+ */
14
+ export declare class HigherLogicThriveCommunityConnector extends BaseRESTIntegrationConnector {
15
+ /** Cached auth for the lifetime of a single sync run (the token is presented on every call). */
16
+ private cachedAuth;
17
+ /** Verbatim `MJ: Integrations.Name`. Load-bearing: the T1 three-way name check compares this === metadata Name. */
18
+ get IntegrationName(): string;
19
+ get SupportsCreate(): boolean;
20
+ get SupportsUpdate(): boolean;
21
+ get SupportsDelete(): boolean;
22
+ /**
23
+ * Discovery is NON-authoritative. There is NO complete-gamut describe endpoint in the 236-operation
24
+ * catalog; per-tenant custom Demographics + AutomationRules fieldLists flow through runtime discovery +
25
+ * the framework's custom-column capture. Absence in a refresh proves nothing → never deactivate. Matches
26
+ * Configuration.DiscoveryIsAuthoritative=false in the frozen contract.
27
+ */
28
+ get DiscoveryIsAuthoritative(): boolean;
29
+ /**
30
+ * From Configuration.RateLimitGuidance: ~180–240 calls/minute (~3–4 req/s) acceptable-use guidance;
31
+ * NO hard server-enforced numeric limit is documented (excessive usage risks IP blocking, not a
32
+ * deterministic 429). This is a conservative self-imposed client throttle, not a metadata-enforced
33
+ * hard constraint (hence Integration.BatchMaxRequestCount/WaitTime are null).
34
+ */
35
+ get RateLimitPolicy(): RateLimitPolicy | null;
36
+ /** Conservative in-flight cap — the per-minute budget (not concurrency) is the real ceiling. */
37
+ get MaxConcurrencyHint(): number | null;
38
+ /**
39
+ * No-watermark objects resume by their StableOrderingKey — read from the IO metadata (the extractor
40
+ * emits it, typically the `<Object>Key` PK). Returns null when the object declares no stable key or the
41
+ * cache is unavailable (unit-test context).
42
+ */
43
+ StableOrderingKey(objectName: string): string | null;
44
+ /**
45
+ * Sample-union enrichment (MJ connector standard): the Declared metadata is HelpPage-derived and misses
46
+ * a tenant's custom demographic / automation-rule fields. After cache-driven introspection, sample each
47
+ * object's live read shape and UNION it into the declared field set — never-shrink, declared-wins.
48
+ * Override IntrospectSchema (NOT DiscoverFields — that recurses into DiscoverFieldsViaFetch's fallback).
49
+ */
50
+ IntrospectSchema(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<SourceSchemaInfo>;
51
+ /**
52
+ * Two-step login-for-token. When the credential carries a pre-issued Token (or the OIDC-API-auth token
53
+ * slot) it is used directly; otherwise POST the Login operation with the IAM Key + IAM Password and read
54
+ * the returned AuthToken.Token. Cached for the run. No inline crypto — the "signing" is the vendor's
55
+ * own token exchange over the transport hook.
56
+ */
57
+ protected Authenticate(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<RESTAuthContext>;
58
+ /**
59
+ * Presents the Login-issued token on every request. The EXACT header scheme is vendor-undocumented
60
+ * (see Configuration.AuthHeaderPatternNote) — defaults to `Authorization: Bearer <token>` and is fully
61
+ * overridable by data (AuthHeaderName / AuthHeaderScheme on the credential) so a live-verified scheme
62
+ * can be applied without a code change. RequiresLiveVerification.
63
+ */
64
+ protected BuildHeaders(auth: RESTAuthContext): Record<string, string>;
65
+ /** HTTP transport (fetch). Owns the wire boundary; test subclasses override this to capture requests. */
66
+ protected MakeHTTPRequest(_auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
67
+ /**
68
+ * Strips the HelpPage response envelope to the per-object record array. The Community API returns three
69
+ * shapes: a BARE array (e.g. EventRegistrantConcise[]), a `{ RecordCount, <Plural>Data: [...] }` page
70
+ * wrapper (e.g. DiscussionPostPage), or a `{ <Plural>: [...], HasMore…, Next, Previous }` seek envelope.
71
+ * When ResponseDataKey is set it wins; otherwise the array property is auto-detected (the sole/first
72
+ * array-valued property), falling back to a single record wrapped as `[record]`.
73
+ */
74
+ protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
75
+ /**
76
+ * Envelope-based pagination signal. Higher Logic seek-key responses MAY carry a `HasMore…` boolean and
77
+ * a `Next` cursor; page wrappers carry `RecordCount`. This reads those when present. The primary
78
+ * next-cursor for continuation-token / seek-key / marker schemes is CLIENT-DERIVED from the last record
79
+ * (the envelope echoes no token) — computed in the FetchChanges loop, which OR-combines this envelope
80
+ * signal with a record-count heuristic. currentPage/offset are used for the Offset window.
81
+ */
82
+ protected ExtractPaginationInfo(rawBody: unknown, paginationType: PaginationType, _currentPage: number, currentOffset: number, pageSize: number): PaginationState;
83
+ /**
84
+ * Region-selected base host + `/api` (the `api/v2.0/...` operation prefix = this base + the metadata
85
+ * APIPath `/v2.0/...`). An explicit Configuration/credential BaseURL override (sandbox / mock) wins so
86
+ * the connector can be redirected by data alone. NO tenant-specific host is ever baked in.
87
+ */
88
+ protected GetBaseURL(companyIntegration: MJCompanyIntegrationEntity, auth: RESTAuthContext): string;
89
+ /**
90
+ * OVERRIDDEN: the Community API is genuinely idiosyncratic for reads — four distinct pagination schemes,
91
+ * two of them over a POST request body (offset StartRecord/EndRecord, marker-direction Marker/Direction),
92
+ * and a CLIENT-DERIVED continuation token (the envelope echoes none, so the next token is the last row's
93
+ * key field). None of this is expressible through the base's GET-only, object-agnostic pagination loop.
94
+ * A directly-queryable object (empty accessPath.nesting) is the depth-0 case handled here; the frozen
95
+ * contract shows all read doors at depth-0 (no path template vars), so no parent-path walk is needed —
96
+ * parent SCOPE query params (communityKey, calendarEventKey, …) are injected from CompanyIntegration
97
+ * Configuration.objectParams where a tenant supplies them.
98
+ */
99
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
100
+ /** Derives the per-IO pagination scheme + params + read verb from Configuration.paginationDetail/accessPath. */
101
+ private describePagination;
102
+ /** Builds one paginated read request (URL + method + optional POST body) for the current page. */
103
+ private buildReadRequest;
104
+ /** Computes the next page's cursor/offset + whether more remain, combining the envelope signal with the record-derived cursor. */
105
+ private computeNextPage;
106
+ /** Derives the continuation cursor VALUE from the last record per scheme (seek-key / continuation / marker). */
107
+ private lastRecordCursor;
108
+ /** Per-scheme default page size. */
109
+ protected pageSizeForScheme(scheme: PageScheme): number;
110
+ /** POSTs the Login operation and reads the returned AuthToken.Token. */
111
+ private loginForToken;
112
+ /** Reads the AuthToken.Token (or a bare `Token`) from a Login response body. */
113
+ private readTokenFromLogin;
114
+ /** Resolves the tenant region from Configuration/credential; defaults to US. */
115
+ private resolveRegion;
116
+ /** Reads an explicit full base-URL override from Configuration/credential (sandbox / mock). */
117
+ private resolveBaseURLOverride;
118
+ /**
119
+ * OVERRIDDEN for one idiosyncrasy: nested create paths carry parent template vars filled from the
120
+ * record's own attributes (e.g. `/v2.0/Blogs/AddComment?blogKey={parent}`,
121
+ * `/v2.0/ResourceLibrary/PostDocument?libraryKey={parent}`, the join-key vars on
122
+ * `/v2.0/Volunteer/VolunteerForOpportunity?volunteerOpportunityKey={volunteerOpportunityKey}`). Everything
123
+ * else matches the generic path. Action-style creates whose IDLocation is `n/a` (a join with no returned
124
+ * record id) derive their identity from the join-key attributes so BuildCreatedResult still succeeds
125
+ * honestly rather than failing on an empty id. Multipart ResourceLibrary uploads are best-effort here
126
+ * (RequiresLiveVerification).
127
+ */
128
+ CreateRecord(ctx: CreateRecordContext): Promise<CRUDResult>;
129
+ /**
130
+ * OVERRIDDEN for one idiosyncrasy: Volunteers.DeleteAPIPath templates named vars
131
+ * (`{volunteerOpportunityKey}`, `{comments}`), not the base's `{id}`/`{ID}`/`{ExternalID}` sentinel —
132
+ * DeleteRecordContext carries only a single ExternalID, so the generic SubstituteIDInPath can never fill
133
+ * them. ExternalID for Volunteers is the composite `<volunteerOpportunityKey>|<own key>` synthesized in
134
+ * CreateRecord above; split it back apart here. Everything else delegates to the generic path.
135
+ */
136
+ DeleteRecord(ctx: DeleteRecordContext): Promise<CRUDResult>;
137
+ /**
138
+ * Tests the connection by exercising the auth flow (token exchange) + a lightweight read. A successful
139
+ * Authenticate proves the credential + region resolve; a 2xx read proves the token is accepted. 401/403
140
+ * → auth failure; other non-2xx → error.
141
+ */
142
+ TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
143
+ /** Reads the Higher Logic credential from the linked Credential entity, or the Configuration JSON fallback. */
144
+ private loadCredentials;
145
+ /** Loads a credential row and parses its Values JSON. */
146
+ private loadFromCredentialEntity;
147
+ /** Extracts Higher Logic credential fields from a credential/config JSON string. */
148
+ private parseCredentialJson;
149
+ /** Substitutes `{var}` tokens in a create path from the record's own attributes (nested/parent-scoped creates). */
150
+ private substitutePathVarsFromAttributes;
151
+ /** Finds the first `<X>Key`-shaped attribute value (a parent key) for a `{parent}` sentinel substitution. */
152
+ private firstParentKeyValue;
153
+ /** Builds a composite identity from the object's PK attributes (for action/join creates with no returned id). */
154
+ private joinKeyIdentity;
155
+ /**
156
+ * Volunteers-specific identity: `<volunteerOpportunityKey>|<VolunteerOpportunityVolunteerKey>`. Unlike
157
+ * joinKeyIdentity (PK fields only), this ALSO carries the opportunity key so DeleteRecord (withdraw) can
158
+ * rebuild the vendor's `{volunteerOpportunityKey}` path var without a second read round-trip.
159
+ */
160
+ private volunteerJoinIdentity;
161
+ /** Joins a base URL and a path (mirrors the base's private BuildFullURL). */
162
+ private joinURL;
163
+ /** Appends a query-param map to a URL, encoding keys + values (skips empty values). */
164
+ private appendQuery;
165
+ /** Throws a descriptive error on a non-2xx (403 is handled by the caller as a skip). */
166
+ private assert2xx;
167
+ /** Tracks the maximum watermark value seen (string compare on ISO-datetime / key fields). */
168
+ private trackWatermark;
169
+ /** Returns the later of two watermark strings (null-safe). */
170
+ private laterWatermark;
171
+ /** PK field names in Sequence order (falls back to ['ID'] when unmarked). */
172
+ private pkFieldNames;
173
+ /**
174
+ * Builds an ExternalRecord with the FULL source record in Fields (full-record pass-through — the
175
+ * framework's custom-column capture diffs keys(Fields) against the field maps). ExternalID is the
176
+ * composite PK when every component is present + non-empty, else empty (the base ToExternalRecord's
177
+ * content-hash fallback is not reachable here, so a keyless row keeps its raw shape).
178
+ */
179
+ private buildExternalRecord;
180
+ /** Reads CompanyIntegration.Configuration.objectParams[objectName] as a string→string scope-param map. */
181
+ private readObjectScopeParams;
182
+ /** Reads the accessPath.door_args array from an IO's Configuration (the operation's accepted params). */
183
+ private objectDoorArgs;
184
+ /** Parses an IntegrationObject's Configuration JSON (tolerant of absent/invalid). */
185
+ private parseObjectConfig;
186
+ /** Gets an IO from the cache without throwing (used by StableOrderingKey, which may be called early). */
187
+ private tryGetCachedObject;
188
+ /** Reads a trimmed string value from a CompanyIntegration's Configuration JSON. */
189
+ private readConfigString;
190
+ /** Reads a boolean flag from a CompanyIntegration's Configuration JSON. */
191
+ private readConfigFlag;
192
+ /** Returns the first present, non-empty string among the given keys. */
193
+ private readString;
194
+ /** Reads a string value, PRESERVING an explicit empty string (key present) — undefined only when absent. */
195
+ private readStringAllowEmpty;
196
+ /** Reads a string from a record, coercing number keys to strings. */
197
+ private readRecordString;
198
+ /** Returns the first present numeric value among the given keys. */
199
+ private readNumber;
200
+ /** Returns the first present boolean value on a key whose name starts with `prefix`. */
201
+ private readBooleanStartsWith;
202
+ /** Reads a nested string value via a key path (tolerant of absent/invalid). */
203
+ private readNestedString;
204
+ }
205
+ export {};
@@ -0,0 +1,870 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { Metadata } from '@memberjunction/core';
9
+ import { IntegrationEngineBase } from '@memberjunction/integration-engine-base';
10
+ import { BaseIntegrationConnector, BaseRESTIntegrationConnector, } from '@memberjunction/integration-engine';
11
+ import { mergeDeclaredWithSampledFields } from '@memberjunction/connector-schema-merge';
12
+ // ─── Constants ────────────────────────────────────────────────────────
13
+ /** Fixed regional hosts (vendor-documented, tenant-AGNOSTIC — the tenant is identified by the token). */
14
+ const REGIONAL_HOSTS = {
15
+ US: 'https://api.connectedcommunity.org',
16
+ Canada: 'https://api.onlinecommunity.ca',
17
+ };
18
+ /** US mirror host (selected when Configuration.useMirrorHost is true). */
19
+ const US_MIRROR_HOST = 'https://api.higherlogic.com';
20
+ /** Login operation (relative to base host + `/api`). */
21
+ const LOGIN_PATH = '/v2.0/Authentication/Login';
22
+ /** Conservative page sizes per scheme (the vendor documents no hard limits; these are safe defaults). */
23
+ const DEFAULT_SEEK_LIMIT = 100;
24
+ const DEFAULT_CONTINUATION_MAX = 100;
25
+ const DEFAULT_MARKER_COUNT = 25; // DataFeed NumberToReturn caps at 25
26
+ const DEFAULT_OFFSET_WINDOW = 50; // CommunityMembers StartRecord/EndRecord default window
27
+ // ─── HigherLogicThriveCommunityConnector ─────────────────────────────────
28
+ /**
29
+ * Higher Logic Thrive Community connector — extends BaseRESTIntegrationConnector (REST/JSON RPC over HTTP).
30
+ *
31
+ * Discovery + generic per-operation CRUD are inherited; this class supplies the Higher Logic protocol
32
+ * surface: two-step token auth, region-selected base URL, the four real pagination schemes (over GET and
33
+ * POST), the HelpPage response-envelope normalizer, watermark incremental for EventRegistrants, connection
34
+ * testing, and the §7/§10 sync-efficiency hooks the frozen contract evidences.
35
+ */
36
+ // Catalog convention: registration key == npm package name (what instance
37
+ // discovery reports and the catalog resolves installed state by).
38
+ let HigherLogicThriveCommunityConnector = class HigherLogicThriveCommunityConnector extends BaseRESTIntegrationConnector {
39
+ constructor() {
40
+ super(...arguments);
41
+ /** Cached auth for the lifetime of a single sync run (the token is presented on every call). */
42
+ this.cachedAuth = null;
43
+ }
44
+ // ── Identity (T1 three-way invariant) ────────────────────────────
45
+ /** Verbatim `MJ: Integrations.Name`. Load-bearing: the T1 three-way name check compares this === metadata Name. */
46
+ get IntegrationName() {
47
+ return 'higherlogic-thrive';
48
+ }
49
+ // ── Capability getters (kept in lockstep with the per-op metadata columns) ──
50
+ get SupportsCreate() { return true; }
51
+ get SupportsUpdate() { return true; }
52
+ get SupportsDelete() { return true; }
53
+ /**
54
+ * Discovery is NON-authoritative. There is NO complete-gamut describe endpoint in the 236-operation
55
+ * catalog; per-tenant custom Demographics + AutomationRules fieldLists flow through runtime discovery +
56
+ * the framework's custom-column capture. Absence in a refresh proves nothing → never deactivate. Matches
57
+ * Configuration.DiscoveryIsAuthoritative=false in the frozen contract.
58
+ */
59
+ get DiscoveryIsAuthoritative() {
60
+ return false;
61
+ }
62
+ // ── Sync-efficiency hooks (§7/§10 — from frozen-contract Configuration facts) ──
63
+ /**
64
+ * From Configuration.RateLimitGuidance: ~180–240 calls/minute (~3–4 req/s) acceptable-use guidance;
65
+ * NO hard server-enforced numeric limit is documented (excessive usage risks IP blocking, not a
66
+ * deterministic 429). This is a conservative self-imposed client throttle, not a metadata-enforced
67
+ * hard constraint (hence Integration.BatchMaxRequestCount/WaitTime are null).
68
+ */
69
+ get RateLimitPolicy() {
70
+ return { TokensPerSec: 3, Burst: 6 };
71
+ }
72
+ /** Conservative in-flight cap — the per-minute budget (not concurrency) is the real ceiling. */
73
+ get MaxConcurrencyHint() { return 2; }
74
+ /**
75
+ * No-watermark objects resume by their StableOrderingKey — read from the IO metadata (the extractor
76
+ * emits it, typically the `<Object>Key` PK). Returns null when the object declares no stable key or the
77
+ * cache is unavailable (unit-test context).
78
+ */
79
+ StableOrderingKey(objectName) {
80
+ const obj = this.tryGetCachedObject(objectName);
81
+ if (!obj)
82
+ return null;
83
+ const declared = obj.StableOrderingKey;
84
+ if (declared && declared.trim().length > 0)
85
+ return declared.trim();
86
+ const pk = this.GetCachedFields(obj.ID).find(f => f.IsPrimaryKey);
87
+ return pk?.Name ?? null;
88
+ }
89
+ /**
90
+ * Sample-union enrichment (MJ connector standard): the Declared metadata is HelpPage-derived and misses
91
+ * a tenant's custom demographic / automation-rule fields. After cache-driven introspection, sample each
92
+ * object's live read shape and UNION it into the declared field set — never-shrink, declared-wins.
93
+ * Override IntrospectSchema (NOT DiscoverFields — that recurses into DiscoverFieldsViaFetch's fallback).
94
+ */
95
+ async IntrospectSchema(companyIntegration, contextUser) {
96
+ const info = await super.IntrospectSchema(companyIntegration, contextUser);
97
+ await Promise.all(info.Objects.map(async (obj) => {
98
+ try {
99
+ const sampled = await this.DiscoverFieldsViaFetch(companyIntegration, obj.ExternalName, contextUser);
100
+ obj.Fields = mergeDeclaredWithSampledFields(obj.Fields, sampled);
101
+ }
102
+ catch {
103
+ /* best-effort — a sample failure leaves the declared fields as-is */
104
+ }
105
+ }));
106
+ return info;
107
+ }
108
+ // ── Abstract REST hooks ──────────────────────────────────────────
109
+ /**
110
+ * Two-step login-for-token. When the credential carries a pre-issued Token (or the OIDC-API-auth token
111
+ * slot) it is used directly; otherwise POST the Login operation with the IAM Key + IAM Password and read
112
+ * the returned AuthToken.Token. Cached for the run. No inline crypto — the "signing" is the vendor's
113
+ * own token exchange over the transport hook.
114
+ */
115
+ async Authenticate(companyIntegration, contextUser) {
116
+ if (this.cachedAuth)
117
+ return this.cachedAuth;
118
+ const creds = await this.loadCredentials(companyIntegration, contextUser);
119
+ const region = this.resolveRegion(companyIntegration, creds);
120
+ const baseURLOverride = this.resolveBaseURLOverride(companyIntegration, creds);
121
+ const authHeaderName = creds.AuthHeaderName?.trim() || 'Authorization';
122
+ const authHeaderScheme = creds.AuthHeaderScheme != null ? creds.AuthHeaderScheme.trim() : 'Bearer';
123
+ let token = creds.Token?.trim();
124
+ if (!token) {
125
+ token = await this.loginForToken(creds, region, baseURLOverride);
126
+ }
127
+ this.cachedAuth = {
128
+ Token: token,
129
+ Region: region,
130
+ BaseURLOverride: baseURLOverride ?? undefined,
131
+ AuthHeaderName: authHeaderName,
132
+ AuthHeaderScheme: authHeaderScheme,
133
+ };
134
+ return this.cachedAuth;
135
+ }
136
+ /**
137
+ * Presents the Login-issued token on every request. The EXACT header scheme is vendor-undocumented
138
+ * (see Configuration.AuthHeaderPatternNote) — defaults to `Authorization: Bearer <token>` and is fully
139
+ * overridable by data (AuthHeaderName / AuthHeaderScheme on the credential) so a live-verified scheme
140
+ * can be applied without a code change. RequiresLiveVerification.
141
+ */
142
+ BuildHeaders(auth) {
143
+ const ctx = auth;
144
+ const value = ctx.AuthHeaderScheme.length > 0 ? `${ctx.AuthHeaderScheme} ${ctx.Token}` : ctx.Token;
145
+ return {
146
+ [ctx.AuthHeaderName]: value,
147
+ 'Content-Type': 'application/json',
148
+ 'Accept': 'application/json',
149
+ };
150
+ }
151
+ /** HTTP transport (fetch). Owns the wire boundary; test subclasses override this to capture requests. */
152
+ async MakeHTTPRequest(_auth, url, method, headers, body) {
153
+ const response = await fetch(url, {
154
+ method,
155
+ headers,
156
+ body: body !== undefined ? JSON.stringify(body) : undefined,
157
+ });
158
+ const respHeaders = {};
159
+ response.headers.forEach((v, k) => { respHeaders[k.toLowerCase()] = v; });
160
+ const text = await response.text();
161
+ let parsed = null;
162
+ if (text.length > 0) {
163
+ try {
164
+ parsed = JSON.parse(text);
165
+ }
166
+ catch {
167
+ parsed = text;
168
+ }
169
+ }
170
+ return { Status: response.status, Body: parsed, Headers: respHeaders };
171
+ }
172
+ /**
173
+ * Strips the HelpPage response envelope to the per-object record array. The Community API returns three
174
+ * shapes: a BARE array (e.g. EventRegistrantConcise[]), a `{ RecordCount, <Plural>Data: [...] }` page
175
+ * wrapper (e.g. DiscussionPostPage), or a `{ <Plural>: [...], HasMore…, Next, Previous }` seek envelope.
176
+ * When ResponseDataKey is set it wins; otherwise the array property is auto-detected (the sole/first
177
+ * array-valued property), falling back to a single record wrapped as `[record]`.
178
+ */
179
+ NormalizeResponse(rawBody, responseDataKey) {
180
+ if (rawBody == null)
181
+ return [];
182
+ if (Array.isArray(rawBody))
183
+ return rawBody;
184
+ if (typeof rawBody !== 'object')
185
+ return [];
186
+ const body = rawBody;
187
+ if (responseDataKey) {
188
+ const arr = body[responseDataKey];
189
+ if (Array.isArray(arr))
190
+ return arr;
191
+ const one = body[responseDataKey];
192
+ if (one && typeof one === 'object' && !Array.isArray(one))
193
+ return [one];
194
+ }
195
+ // Auto-detect: the first array-valued property is the record collection (…Data / <Plural>).
196
+ for (const v of Object.values(body)) {
197
+ if (Array.isArray(v))
198
+ return v;
199
+ }
200
+ // No array property → treat the object itself as a single record (get-one shape).
201
+ return [body];
202
+ }
203
+ /**
204
+ * Envelope-based pagination signal. Higher Logic seek-key responses MAY carry a `HasMore…` boolean and
205
+ * a `Next` cursor; page wrappers carry `RecordCount`. This reads those when present. The primary
206
+ * next-cursor for continuation-token / seek-key / marker schemes is CLIENT-DERIVED from the last record
207
+ * (the envelope echoes no token) — computed in the FetchChanges loop, which OR-combines this envelope
208
+ * signal with a record-count heuristic. currentPage/offset are used for the Offset window.
209
+ */
210
+ ExtractPaginationInfo(rawBody, paginationType, _currentPage, currentOffset, pageSize) {
211
+ if (!rawBody || typeof rawBody !== 'object')
212
+ return { HasMore: false };
213
+ const body = rawBody;
214
+ const total = this.readNumber(body, ['RecordCount', 'TotalRecords', 'TotalCount', 'Count']);
215
+ if (paginationType === 'Offset') {
216
+ const seen = currentOffset + pageSize;
217
+ const hasMore = total != null ? seen < total : false;
218
+ return { HasMore: hasMore, NextOffset: seen, TotalRecords: total ?? undefined };
219
+ }
220
+ if (paginationType === 'Cursor') {
221
+ const nextCursor = this.readString(body, ['Next', 'NextContinuationToken', 'continuationToken', 'ContinuationToken']);
222
+ const hasMoreFlag = this.readBooleanStartsWith(body, 'HasMore');
223
+ if (nextCursor)
224
+ return { HasMore: true, NextCursor: nextCursor, TotalRecords: total ?? undefined };
225
+ if (hasMoreFlag === true)
226
+ return { HasMore: true, TotalRecords: total ?? undefined };
227
+ if (hasMoreFlag === false)
228
+ return { HasMore: false, TotalRecords: total ?? undefined };
229
+ return { HasMore: false, TotalRecords: total ?? undefined };
230
+ }
231
+ return { HasMore: false, TotalRecords: total ?? undefined };
232
+ }
233
+ /**
234
+ * Region-selected base host + `/api` (the `api/v2.0/...` operation prefix = this base + the metadata
235
+ * APIPath `/v2.0/...`). An explicit Configuration/credential BaseURL override (sandbox / mock) wins so
236
+ * the connector can be redirected by data alone. NO tenant-specific host is ever baked in.
237
+ */
238
+ GetBaseURL(companyIntegration, auth) {
239
+ const ctx = auth;
240
+ if (ctx.BaseURLOverride)
241
+ return `${ctx.BaseURLOverride.replace(/\/+$/, '')}`;
242
+ const host = ctx.Region === 'US' && this.readConfigFlag(companyIntegration, 'useMirrorHost')
243
+ ? US_MIRROR_HOST
244
+ : REGIONAL_HOSTS[ctx.Region];
245
+ return `${host}/api`;
246
+ }
247
+ // ── FetchChanges override — the vendor's four pagination schemes over GET + POST ──
248
+ /**
249
+ * OVERRIDDEN: the Community API is genuinely idiosyncratic for reads — four distinct pagination schemes,
250
+ * two of them over a POST request body (offset StartRecord/EndRecord, marker-direction Marker/Direction),
251
+ * and a CLIENT-DERIVED continuation token (the envelope echoes none, so the next token is the last row's
252
+ * key field). None of this is expressible through the base's GET-only, object-agnostic pagination loop.
253
+ * A directly-queryable object (empty accessPath.nesting) is the depth-0 case handled here; the frozen
254
+ * contract shows all read doors at depth-0 (no path template vars), so no parent-path walk is needed —
255
+ * parent SCOPE query params (communityKey, calendarEventKey, …) are injected from CompanyIntegration
256
+ * Configuration.objectParams where a tenant supplies them.
257
+ */
258
+ async FetchChanges(ctx) {
259
+ const obj = this.GetCachedObject(ctx.CompanyIntegration.IntegrationID, ctx.ObjectName);
260
+ const fields = this.GetCachedFields(obj.ID);
261
+ const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
262
+ const baseURL = this.GetBaseURL(ctx.CompanyIntegration, auth);
263
+ const headers = this.BuildHeaders(auth);
264
+ const desc = this.describePagination(obj);
265
+ const pkFieldNames = this.pkFieldNames(fields);
266
+ const scopeParams = this.readObjectScopeParams(ctx.CompanyIntegration, obj.Name);
267
+ const wmField = obj.SupportsIncrementalSync ? (obj.IncrementalWatermarkField ?? null) : null;
268
+ const batchLimit = ctx.BatchSize && ctx.BatchSize > 0 ? ctx.BatchSize : Number.MAX_SAFE_INTEGER;
269
+ const pageSize = this.pageSizeForScheme(desc.Scheme);
270
+ const out = [];
271
+ const warnings = [];
272
+ let cursor = ctx.CurrentCursor;
273
+ let offset = ctx.CurrentOffset ?? 0;
274
+ let hasMore = true;
275
+ let maxWatermark = null;
276
+ let fullyDrained = true;
277
+ while (hasMore && out.length < batchLimit) {
278
+ const remaining = Math.max(1, batchLimit - out.length);
279
+ const req = this.buildReadRequest(obj, baseURL, desc, cursor, offset, Math.min(pageSize, remaining), scopeParams, ctx, wmField);
280
+ const response = await this.MakeHTTPRequest(auth, req.URL, req.Method, headers, req.Body);
281
+ if (response.Status === 403) {
282
+ warnings.push({ Code: 'FORBIDDEN', Message: `"${obj.Name}": HTTP 403 — insufficient API entitlement; skipping.`, Data: { object: obj.Name } });
283
+ break;
284
+ }
285
+ this.assert2xx(response, req.URL, obj.Name);
286
+ const raw = this.NormalizeResponse(response.Body, obj.ResponseDataKey);
287
+ if (raw.length === 0) {
288
+ hasMore = false;
289
+ break;
290
+ }
291
+ for (const r of raw) {
292
+ out.push(this.buildExternalRecord(this.applyTransformPreservingKeys(r, obj, fields), obj.Name, pkFieldNames));
293
+ maxWatermark = this.trackWatermark(maxWatermark, r, wmField);
294
+ }
295
+ const next = this.computeNextPage(desc, response.Body, raw, obj, pkFieldNames, offset, pageSize);
296
+ // Break on a non-advancing cursor (broken/exhausted paging) to avoid an infinite loop.
297
+ if (next.HasMore && desc.Scheme !== 'offset' && next.NextCursor != null && next.NextCursor === cursor) {
298
+ hasMore = false;
299
+ break;
300
+ }
301
+ hasMore = next.HasMore;
302
+ cursor = next.NextCursor ?? cursor;
303
+ offset = next.NextOffset ?? offset;
304
+ if (hasMore && out.length >= batchLimit) {
305
+ fullyDrained = false;
306
+ }
307
+ }
308
+ const result = {
309
+ Records: out,
310
+ HasMore: hasMore,
311
+ NextCursor: cursor,
312
+ NextOffset: desc.Scheme === 'offset' ? offset : undefined,
313
+ Warnings: warnings.length > 0 ? warnings : undefined,
314
+ };
315
+ // Advance the watermark ONLY on full drain (partial batch resumes from the same point next call).
316
+ if (!hasMore && fullyDrained && wmField && maxWatermark) {
317
+ result.NewWatermarkValue = this.laterWatermark(ctx.WatermarkValue, maxWatermark);
318
+ }
319
+ return result;
320
+ }
321
+ // ── Pagination internals ─────────────────────────────────────────
322
+ /** Derives the per-IO pagination scheme + params + read verb from Configuration.paginationDetail/accessPath. */
323
+ describePagination(obj) {
324
+ const cfg = this.parseObjectConfig(obj);
325
+ const detail = (cfg?.paginationDetail ?? null);
326
+ const params = Array.isArray(detail?.params) ? detail.params.filter((p) => typeof p === 'string') : [];
327
+ const declaredReadMethod = this.readNestedString(cfg, ['accessPath', 'readMethod']);
328
+ let scheme = 'none';
329
+ if (obj.SupportsPagination && obj.PaginationType !== 'None') {
330
+ if (params.some(p => /^StartRecord$/i.test(p)) && params.some(p => /^EndRecord$/i.test(p)))
331
+ scheme = 'offset';
332
+ else if (params.some(p => /^Marker$/i.test(p)) && params.some(p => /^Direction$/i.test(p)))
333
+ scheme = 'marker-direction';
334
+ else if (params.some(p => /^continuationToken$/i.test(p)))
335
+ scheme = 'continuation-token';
336
+ else if (params.some(p => /^after.+Key$/i.test(p)))
337
+ scheme = 'seek-key';
338
+ else
339
+ scheme = 'none';
340
+ }
341
+ const readMethod = declaredReadMethod?.toUpperCase() === 'POST' || scheme === 'offset' || scheme === 'marker-direction'
342
+ ? 'POST'
343
+ : 'GET';
344
+ return { Scheme: scheme, Params: params, ReadMethod: readMethod };
345
+ }
346
+ /** Builds one paginated read request (URL + method + optional POST body) for the current page. */
347
+ buildReadRequest(obj, baseURL, desc, cursor, offset, pageSize, scopeParams, ctx, wmField) {
348
+ const path = this.joinURL(baseURL, obj.APIPath);
349
+ const watermark = wmField ? (ctx.WatermarkValue ?? undefined) : undefined;
350
+ if (desc.ReadMethod === 'POST') {
351
+ const body = { ...scopeParams };
352
+ if (desc.Scheme === 'offset') {
353
+ body.StartRecord = offset + 1;
354
+ body.EndRecord = offset + pageSize;
355
+ }
356
+ else if (desc.Scheme === 'marker-direction') {
357
+ if (cursor)
358
+ body.Marker = cursor;
359
+ body.Direction = 'down';
360
+ body.NumberToReturn = pageSize;
361
+ }
362
+ return { URL: path, Method: 'POST', Body: body };
363
+ }
364
+ // GET — query params.
365
+ const query = { ...scopeParams };
366
+ if (desc.Scheme === 'seek-key') {
367
+ const afterParam = desc.Params.find(p => /^after.+Key$/i.test(p));
368
+ if (afterParam && cursor)
369
+ query[afterParam] = cursor;
370
+ query.limit = String(pageSize);
371
+ }
372
+ else if (desc.Scheme === 'continuation-token') {
373
+ if (cursor)
374
+ query.continuationToken = cursor;
375
+ query.maxRecords = String(pageSize);
376
+ }
377
+ else {
378
+ // None: apply a cap param when the operation documents one (from the accepted door_args).
379
+ const capParam = this.objectDoorArgs(obj).find(p => /^(maxRecords|maxResults|maxToRetrieve|numberToReturn)$/i.test(p));
380
+ if (capParam)
381
+ query[capParam] = String(pageSize);
382
+ }
383
+ // Server-side incremental: EventRegistrants documents a real `modifiedDateTime` watermark param.
384
+ if (watermark && wmField && this.objectDoorArgs(obj).some(a => /^modifiedDateTime$/i.test(a))) {
385
+ query.modifiedDateTime = watermark;
386
+ }
387
+ return { URL: this.appendQuery(path, query), Method: 'GET' };
388
+ }
389
+ /** Computes the next page's cursor/offset + whether more remain, combining the envelope signal with the record-derived cursor. */
390
+ computeNextPage(desc, rawBody, records, obj, pkFieldNames, offset, pageSize) {
391
+ if (desc.Scheme === 'none')
392
+ return { HasMore: false };
393
+ const envelope = this.ExtractPaginationInfo(rawBody, obj.PaginationType, 1, offset, pageSize);
394
+ if (desc.Scheme === 'offset') {
395
+ const full = records.length >= pageSize;
396
+ return { HasMore: envelope.HasMore || full, NextOffset: offset + records.length };
397
+ }
398
+ // Cursor family — the next token is the last record's key field (envelope echoes none).
399
+ const derived = this.lastRecordCursor(desc, records, pkFieldNames);
400
+ const full = records.length >= pageSize;
401
+ const nextCursor = envelope.NextCursor ?? derived;
402
+ const hasMore = (envelope.HasMore || full) && nextCursor != null;
403
+ return { HasMore: hasMore, NextCursor: nextCursor };
404
+ }
405
+ /** Derives the continuation cursor VALUE from the last record per scheme (seek-key / continuation / marker). */
406
+ lastRecordCursor(desc, records, pkFieldNames) {
407
+ if (records.length === 0)
408
+ return undefined;
409
+ const last = records[records.length - 1];
410
+ if (desc.Scheme === 'marker-direction')
411
+ return this.readRecordString(last, ['Marker']);
412
+ if (desc.Scheme === 'seek-key') {
413
+ const afterParam = desc.Params.find(p => /^after.+Key$/i.test(p));
414
+ const keyName = afterParam ? afterParam.replace(/^after/i, '') : undefined; // afterContactKey → ContactKey
415
+ const candidates = [keyName, ...pkFieldNames].filter((k) => !!k);
416
+ return this.readRecordString(last, candidates);
417
+ }
418
+ // continuation-token — the object's PK field is the documented first-field continuation key.
419
+ return this.readRecordString(last, pkFieldNames);
420
+ }
421
+ /** Per-scheme default page size. */
422
+ pageSizeForScheme(scheme) {
423
+ switch (scheme) {
424
+ case 'seek-key': return DEFAULT_SEEK_LIMIT;
425
+ case 'continuation-token': return DEFAULT_CONTINUATION_MAX;
426
+ case 'marker-direction': return DEFAULT_MARKER_COUNT;
427
+ case 'offset': return DEFAULT_OFFSET_WINDOW;
428
+ default: return DEFAULT_SEEK_LIMIT;
429
+ }
430
+ }
431
+ // ── Auth internals ───────────────────────────────────────────────
432
+ /** POSTs the Login operation and reads the returned AuthToken.Token. */
433
+ async loginForToken(creds, region, baseURLOverride) {
434
+ if (!creds.IAMKey || !creds.IAMPassword) {
435
+ throw new Error('Higher Logic credential incomplete: provide an IAM Key + IAM Password (the Login Username/Password), ' +
436
+ 'or a pre-issued Token. SSO (SAML/OIDC/OAuth2-code) is end-user login and is NOT the connector auth path.');
437
+ }
438
+ const host = baseURLOverride ? baseURLOverride.replace(/\/+$/, '') : `${REGIONAL_HOSTS[region]}/api`;
439
+ const url = this.joinURL(host, LOGIN_PATH);
440
+ const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' };
441
+ const preAuth = { Token: '', Region: region, AuthHeaderName: 'Authorization', AuthHeaderScheme: 'Bearer' };
442
+ const response = await this.MakeHTTPRequest(preAuth, url, 'POST', headers, {
443
+ Username: creds.IAMKey,
444
+ Password: creds.IAMPassword,
445
+ });
446
+ if (response.Status < 200 || response.Status >= 300) {
447
+ throw new Error(`Higher Logic Login failed: HTTP ${response.Status}. Check the IAM Key + IAM Password and region.`);
448
+ }
449
+ const token = this.readTokenFromLogin(response.Body);
450
+ if (!token) {
451
+ throw new Error('Higher Logic Login returned HTTP 2xx but no AuthToken.Token was present in the response body.');
452
+ }
453
+ return token;
454
+ }
455
+ /** Reads the AuthToken.Token (or a bare `Token`) from a Login response body. */
456
+ readTokenFromLogin(body) {
457
+ if (!body || typeof body !== 'object')
458
+ return undefined;
459
+ const b = body;
460
+ const direct = this.readString(b, ['Token', 'token', 'AuthToken', 'authToken', 'AccessToken', 'accessToken']);
461
+ if (direct)
462
+ return direct;
463
+ const nested = b.AuthToken ?? b.authToken;
464
+ if (nested && typeof nested === 'object') {
465
+ return this.readString(nested, ['Token', 'token']);
466
+ }
467
+ return undefined;
468
+ }
469
+ /** Resolves the tenant region from Configuration/credential; defaults to US. */
470
+ resolveRegion(companyIntegration, creds) {
471
+ const raw = (this.readConfigString(companyIntegration, 'region') ?? creds.Region ?? 'US').toString().trim().toLowerCase();
472
+ return raw === 'canada' || raw === 'ca' ? 'Canada' : 'US';
473
+ }
474
+ /** Reads an explicit full base-URL override from Configuration/credential (sandbox / mock). */
475
+ resolveBaseURLOverride(companyIntegration, creds) {
476
+ const raw = this.readConfigString(companyIntegration, 'BaseURL') ?? this.readConfigString(companyIntegration, 'baseURL') ?? creds.BaseURL;
477
+ if (raw && /^https?:\/\//i.test(raw.trim()))
478
+ return raw.trim();
479
+ return null;
480
+ }
481
+ // ── CRUD ──────────────────────────────────────────────────────────
482
+ //
483
+ // Update / Delete / Get use the INHERITED generic per-operation path (the per-IO Update*/Delete* columns +
484
+ // the base's {id} path substitution / body-ID handling). CreateRecord is overridden ONLY to substitute
485
+ // PARENT template vars into the create path (the base doesn't fill `{parent}`/`{blogKey}`/…), preserving
486
+ // the wrapped/flat body build and the loud-on-empty-id BuildCreatedResult contract.
487
+ /**
488
+ * OVERRIDDEN for one idiosyncrasy: nested create paths carry parent template vars filled from the
489
+ * record's own attributes (e.g. `/v2.0/Blogs/AddComment?blogKey={parent}`,
490
+ * `/v2.0/ResourceLibrary/PostDocument?libraryKey={parent}`, the join-key vars on
491
+ * `/v2.0/Volunteer/VolunteerForOpportunity?volunteerOpportunityKey={volunteerOpportunityKey}`). Everything
492
+ * else matches the generic path. Action-style creates whose IDLocation is `n/a` (a join with no returned
493
+ * record id) derive their identity from the join-key attributes so BuildCreatedResult still succeeds
494
+ * honestly rather than failing on an empty id. Multipart ResourceLibrary uploads are best-effort here
495
+ * (RequiresLiveVerification).
496
+ */
497
+ async CreateRecord(ctx) {
498
+ const ci = ctx.CompanyIntegration;
499
+ const contextUser = ctx.ContextUser;
500
+ const obj = this.GetCachedObject(ci.IntegrationID, ctx.ObjectName);
501
+ if (!obj.CreateAPIPath || !obj.CreateMethod) {
502
+ return super.CreateRecord(ctx); // delegate the "not configured" error consistently
503
+ }
504
+ const auth = await this.Authenticate(ci, contextUser);
505
+ const baseURL = this.GetBaseURL(ci, auth);
506
+ const headers = this.BuildHeaders(auth);
507
+ const path = this.substitutePathVarsFromAttributes(obj.CreateAPIPath, ctx.Attributes);
508
+ const url = this.joinURL(baseURL, path);
509
+ const body = this.BuildOperationBody(ctx.Attributes, obj.CreateBodyShape, obj.CreateBodyKey);
510
+ const response = await this.MakeHTTPRequest(auth, url, obj.CreateMethod, headers, body);
511
+ if (response.Status >= 200 && response.Status < 300) {
512
+ let externalID = this.ExtractIDFromResponse(response, obj.CreateIDLocation);
513
+ if (!externalID && obj.CreateIDLocation === 'n/a') {
514
+ // Volunteers' withdraw-from-opportunity delete needs the opportunity key back (the vendor's
515
+ // 204-No-Content create response carries none), so its identity is a composite
516
+ // `<volunteerOpportunityKey>|<own key>` rather than the bare joinKeyIdentity() — DeleteRecord
517
+ // below splits it back apart to rebuild the withdraw URL.
518
+ externalID = ctx.ObjectName === 'Volunteers'
519
+ ? this.volunteerJoinIdentity(ctx.Attributes)
520
+ : this.joinKeyIdentity(obj, ctx.Attributes); // action/join create — identity = key pair
521
+ }
522
+ return this.BuildCreatedResult(externalID, response.Status, ctx.ObjectName);
523
+ }
524
+ return {
525
+ Success: false,
526
+ StatusCode: response.Status,
527
+ ErrorMessage: this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on create`,
528
+ };
529
+ }
530
+ /**
531
+ * OVERRIDDEN for one idiosyncrasy: Volunteers.DeleteAPIPath templates named vars
532
+ * (`{volunteerOpportunityKey}`, `{comments}`), not the base's `{id}`/`{ID}`/`{ExternalID}` sentinel —
533
+ * DeleteRecordContext carries only a single ExternalID, so the generic SubstituteIDInPath can never fill
534
+ * them. ExternalID for Volunteers is the composite `<volunteerOpportunityKey>|<own key>` synthesized in
535
+ * CreateRecord above; split it back apart here. Everything else delegates to the generic path.
536
+ */
537
+ async DeleteRecord(ctx) {
538
+ if (ctx.ObjectName !== 'Volunteers')
539
+ return super.DeleteRecord(ctx);
540
+ const ci = ctx.CompanyIntegration;
541
+ const contextUser = ctx.ContextUser;
542
+ const obj = this.GetCachedObject(ci.IntegrationID, ctx.ObjectName);
543
+ if (!obj.DeleteAPIPath || !obj.DeleteMethod)
544
+ return super.DeleteRecord(ctx);
545
+ const [volunteerOpportunityKey] = String(ctx.ExternalID ?? '').split('|');
546
+ const auth = await this.Authenticate(ci, contextUser);
547
+ const baseURL = this.GetBaseURL(ci, auth);
548
+ const headers = this.BuildHeaders(auth);
549
+ const path = obj.DeleteAPIPath
550
+ .replace(/\{volunteerOpportunityKey\}/g, encodeURIComponent(volunteerOpportunityKey ?? ''))
551
+ .replace(/\{comments\}/g, '');
552
+ const url = this.joinURL(baseURL, path);
553
+ const response = await this.MakeHTTPRequest(auth, url, obj.DeleteMethod, headers);
554
+ if (response.Status >= 200 && response.Status < 300) {
555
+ return { Success: true, StatusCode: response.Status };
556
+ }
557
+ return {
558
+ Success: false,
559
+ StatusCode: response.Status,
560
+ ErrorMessage: this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on delete`,
561
+ };
562
+ }
563
+ // ── Connection test ──────────────────────────────────────────────
564
+ /**
565
+ * Tests the connection by exercising the auth flow (token exchange) + a lightweight read. A successful
566
+ * Authenticate proves the credential + region resolve; a 2xx read proves the token is accepted. 401/403
567
+ * → auth failure; other non-2xx → error.
568
+ */
569
+ async TestConnection(companyIntegration, contextUser) {
570
+ try {
571
+ const auth = await this.Authenticate(companyIntegration, contextUser);
572
+ const baseURL = this.GetBaseURL(companyIntegration, auth);
573
+ const headers = this.BuildHeaders(auth);
574
+ const url = this.joinURL(baseURL, '/v2.0/Communities/GetMyCommunities');
575
+ const response = await this.MakeHTTPRequest(auth, url, 'GET', headers);
576
+ if (response.Status >= 200 && response.Status < 300) {
577
+ return { Success: true, Message: 'Higher Logic Thrive Community connection successful.' };
578
+ }
579
+ if (response.Status === 401 || response.Status === 403) {
580
+ return { Success: false, Message: `Higher Logic authentication failed (HTTP ${response.Status}). Check the IAM Key + IAM Password / token and region.` };
581
+ }
582
+ return { Success: false, Message: `Higher Logic connection test returned HTTP ${response.Status}.` };
583
+ }
584
+ catch (err) {
585
+ const msg = err instanceof Error ? err.message : String(err);
586
+ return { Success: false, Message: `Higher Logic connection test error: ${msg}` };
587
+ }
588
+ }
589
+ // ── Credential loading ───────────────────────────────────────────
590
+ /** Reads the Higher Logic credential from the linked Credential entity, or the Configuration JSON fallback. */
591
+ async loadCredentials(companyIntegration, contextUser) {
592
+ let creds = null;
593
+ if (companyIntegration.CredentialID) {
594
+ creds = await this.loadFromCredentialEntity(companyIntegration.CredentialID, contextUser);
595
+ }
596
+ const configCreds = companyIntegration.Configuration ? this.parseCredentialJson(companyIntegration.Configuration) : null;
597
+ if (!creds && !configCreds) {
598
+ throw new Error('No Higher Logic credential found. Attach a credential carrying the IAM Key + IAM Password ' +
599
+ '(or a pre-issued Token), or set the connection Configuration JSON.');
600
+ }
601
+ return { ...(configCreds ?? {}), ...(creds ?? {}) };
602
+ }
603
+ /** Loads a credential row and parses its Values JSON. */
604
+ async loadFromCredentialEntity(credentialID, contextUser, provider) {
605
+ const md = provider ?? new Metadata();
606
+ const credential = await md.GetEntityObject('MJ: Credentials', contextUser);
607
+ const loaded = await credential.Load(credentialID);
608
+ if (!loaded || !credential.Values)
609
+ return null;
610
+ return this.parseCredentialJson(credential.Values);
611
+ }
612
+ /** Extracts Higher Logic credential fields from a credential/config JSON string. */
613
+ parseCredentialJson(json) {
614
+ try {
615
+ const parsed = JSON.parse(json);
616
+ const region = this.readString(parsed, ['region', 'Region']);
617
+ return {
618
+ IAMKey: this.readString(parsed, ['IAMKey', 'iamKey', 'iam_key', 'Username', 'username', 'IAMKeyEnv']),
619
+ IAMPassword: this.readString(parsed, ['IAMPassword', 'iamPassword', 'iam_password', 'Password', 'password']),
620
+ Token: this.readString(parsed, ['Token', 'token', 'AuthToken', 'authToken']),
621
+ Region: region === 'Canada' || region === 'canada' || region === 'ca' ? 'Canada' : region === 'US' || region === 'us' ? 'US' : undefined,
622
+ BaseURL: this.readString(parsed, ['BaseURL', 'baseURL', 'BaseUrl', 'baseUrl']),
623
+ AuthHeaderName: this.readString(parsed, ['AuthHeaderName', 'authHeaderName']),
624
+ // Scheme may legitimately be an EMPTY string (raw token, no `Bearer ` prefix) — preserve it.
625
+ AuthHeaderScheme: this.readStringAllowEmpty(parsed, ['AuthHeaderScheme', 'authHeaderScheme']),
626
+ };
627
+ }
628
+ catch {
629
+ return null;
630
+ }
631
+ }
632
+ // ── Helpers ──────────────────────────────────────────────────────
633
+ /** Substitutes `{var}` tokens in a create path from the record's own attributes (nested/parent-scoped creates). */
634
+ substitutePathVarsFromAttributes(path, attributes) {
635
+ return path.replace(/\{(\w+)\}/g, (match, name) => {
636
+ // Support the generic `{parent}` sentinel by trying the object's obvious parent-key attributes.
637
+ const direct = attributes[name];
638
+ if (direct != null && String(direct).length > 0)
639
+ return encodeURIComponent(String(direct));
640
+ if (name === 'parent') {
641
+ const parentVal = this.firstParentKeyValue(attributes);
642
+ if (parentVal)
643
+ return encodeURIComponent(parentVal);
644
+ }
645
+ return match;
646
+ });
647
+ }
648
+ /** Finds the first `<X>Key`-shaped attribute value (a parent key) for a `{parent}` sentinel substitution. */
649
+ firstParentKeyValue(attributes) {
650
+ for (const [k, v] of Object.entries(attributes)) {
651
+ if (/Key$/.test(k) && v != null && String(v).length > 0)
652
+ return String(v);
653
+ }
654
+ return null;
655
+ }
656
+ /** Builds a composite identity from the object's PK attributes (for action/join creates with no returned id). */
657
+ joinKeyIdentity(obj, attributes) {
658
+ const pk = this.pkFieldNames(this.GetCachedFields(obj.ID));
659
+ const parts = pk.map(n => attributes[n]).filter(v => v != null && String(v).length > 0).map(v => String(v));
660
+ return parts.length > 0 ? parts.join('|') : undefined;
661
+ }
662
+ /**
663
+ * Volunteers-specific identity: `<volunteerOpportunityKey>|<VolunteerOpportunityVolunteerKey>`. Unlike
664
+ * joinKeyIdentity (PK fields only), this ALSO carries the opportunity key so DeleteRecord (withdraw) can
665
+ * rebuild the vendor's `{volunteerOpportunityKey}` path var without a second read round-trip.
666
+ */
667
+ volunteerJoinIdentity(attributes) {
668
+ const oppKey = attributes['volunteerOpportunityKey'] ?? attributes['VolunteerOpportunityKey'];
669
+ const ownKey = attributes['VolunteerOpportunityVolunteerKey'];
670
+ if (oppKey == null || String(oppKey).length === 0)
671
+ return undefined;
672
+ return `${String(oppKey)}|${ownKey != null ? String(ownKey) : ''}`;
673
+ }
674
+ /** Joins a base URL and a path (mirrors the base's private BuildFullURL). */
675
+ joinURL(baseURL, apiPath) {
676
+ const base = baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL;
677
+ const path = apiPath.startsWith('/') ? apiPath : `/${apiPath}`;
678
+ return `${base}${path}`;
679
+ }
680
+ /** Appends a query-param map to a URL, encoding keys + values (skips empty values). */
681
+ appendQuery(url, params) {
682
+ const entries = Object.entries(params).filter(([, v]) => v != null && String(v).length > 0);
683
+ if (entries.length === 0)
684
+ return url;
685
+ const sep = url.includes('?') ? '&' : '?';
686
+ const qs = entries.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');
687
+ return `${url}${sep}${qs}`;
688
+ }
689
+ /** Throws a descriptive error on a non-2xx (403 is handled by the caller as a skip). */
690
+ assert2xx(response, url, objectName) {
691
+ if (response.Status < 200 || response.Status >= 300) {
692
+ throw new Error(`[higherlogic-thrive] fetch of "${objectName}" failed: HTTP ${response.Status} from ${url}`);
693
+ }
694
+ }
695
+ /** Tracks the maximum watermark value seen (string compare on ISO-datetime / key fields). */
696
+ trackWatermark(current, record, wmField) {
697
+ if (!wmField)
698
+ return current;
699
+ const v = record[wmField];
700
+ if (v == null)
701
+ return current;
702
+ const s = String(v);
703
+ if (s.length === 0)
704
+ return current;
705
+ if (current == null || s > current)
706
+ return s;
707
+ return current;
708
+ }
709
+ /** Returns the later of two watermark strings (null-safe). */
710
+ laterWatermark(existing, candidate) {
711
+ if (existing == null)
712
+ return candidate;
713
+ return candidate > existing ? candidate : existing;
714
+ }
715
+ /** PK field names in Sequence order (falls back to ['ID'] when unmarked). */
716
+ pkFieldNames(fields) {
717
+ const pk = fields.filter(f => f.IsPrimaryKey).sort((a, b) => a.Sequence - b.Sequence).map(f => f.Name);
718
+ return pk.length > 0 ? pk : ['ID'];
719
+ }
720
+ /**
721
+ * Builds an ExternalRecord with the FULL source record in Fields (full-record pass-through — the
722
+ * framework's custom-column capture diffs keys(Fields) against the field maps). ExternalID is the
723
+ * composite PK when every component is present + non-empty, else empty (the base ToExternalRecord's
724
+ * content-hash fallback is not reachable here, so a keyless row keeps its raw shape).
725
+ */
726
+ buildExternalRecord(raw, objectType, pkFieldNames) {
727
+ const allPresent = pkFieldNames.length > 0 && pkFieldNames.every(n => raw[n] != null && String(raw[n]).length > 0);
728
+ const externalID = allPresent ? pkFieldNames.map(n => String(raw[n])).join('|') : '';
729
+ return { ExternalID: externalID, ObjectType: objectType, Fields: raw };
730
+ }
731
+ /** Reads CompanyIntegration.Configuration.objectParams[objectName] as a string→string scope-param map. */
732
+ readObjectScopeParams(companyIntegration, objectName) {
733
+ if (!companyIntegration.Configuration)
734
+ return {};
735
+ try {
736
+ const cfg = JSON.parse(companyIntegration.Configuration);
737
+ const op = cfg.objectParams;
738
+ if (!op || typeof op !== 'object')
739
+ return {};
740
+ const forObj = op[objectName];
741
+ if (!forObj || typeof forObj !== 'object')
742
+ return {};
743
+ const out = {};
744
+ for (const [k, v] of Object.entries(forObj)) {
745
+ if (v != null && (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean'))
746
+ out[k] = String(v);
747
+ }
748
+ return out;
749
+ }
750
+ catch {
751
+ return {};
752
+ }
753
+ }
754
+ /** Reads the accessPath.door_args array from an IO's Configuration (the operation's accepted params). */
755
+ objectDoorArgs(obj) {
756
+ const cfg = this.parseObjectConfig(obj);
757
+ const ap = cfg?.accessPath;
758
+ return Array.isArray(ap?.door_args) ? ap.door_args.filter((a) => typeof a === 'string') : [];
759
+ }
760
+ /** Parses an IntegrationObject's Configuration JSON (tolerant of absent/invalid). */
761
+ parseObjectConfig(obj) {
762
+ const raw = obj.Configuration;
763
+ if (!raw || typeof raw !== 'string')
764
+ return null;
765
+ try {
766
+ return JSON.parse(raw);
767
+ }
768
+ catch {
769
+ return null;
770
+ }
771
+ }
772
+ /** Gets an IO from the cache without throwing (used by StableOrderingKey, which may be called early). */
773
+ tryGetCachedObject(objectName) {
774
+ try {
775
+ const integ = IntegrationEngineBase.Instance.GetIntegrationByName(this.IntegrationName);
776
+ if (!integ)
777
+ return null;
778
+ return IntegrationEngineBase.Instance.GetIntegrationObject(integ.ID, objectName) ?? null;
779
+ }
780
+ catch {
781
+ return null;
782
+ }
783
+ }
784
+ /** Reads a trimmed string value from a CompanyIntegration's Configuration JSON. */
785
+ readConfigString(companyIntegration, key) {
786
+ if (!companyIntegration.Configuration)
787
+ return null;
788
+ try {
789
+ const cfg = JSON.parse(companyIntegration.Configuration);
790
+ const v = cfg[key];
791
+ return typeof v === 'string' && v.trim().length > 0 ? v.trim() : null;
792
+ }
793
+ catch {
794
+ return null;
795
+ }
796
+ }
797
+ /** Reads a boolean flag from a CompanyIntegration's Configuration JSON. */
798
+ readConfigFlag(companyIntegration, key) {
799
+ if (!companyIntegration.Configuration)
800
+ return false;
801
+ try {
802
+ const cfg = JSON.parse(companyIntegration.Configuration);
803
+ return cfg[key] === true || cfg[key] === 'true';
804
+ }
805
+ catch {
806
+ return false;
807
+ }
808
+ }
809
+ /** Returns the first present, non-empty string among the given keys. */
810
+ readString(obj, keys) {
811
+ for (const k of keys) {
812
+ const v = obj[k];
813
+ if (typeof v === 'string' && v.length > 0)
814
+ return v;
815
+ }
816
+ return undefined;
817
+ }
818
+ /** Reads a string value, PRESERVING an explicit empty string (key present) — undefined only when absent. */
819
+ readStringAllowEmpty(obj, keys) {
820
+ for (const k of keys) {
821
+ const v = obj[k];
822
+ if (typeof v === 'string')
823
+ return v;
824
+ }
825
+ return undefined;
826
+ }
827
+ /** Reads a string from a record, coercing number keys to strings. */
828
+ readRecordString(record, keys) {
829
+ for (const k of keys) {
830
+ const v = record[k];
831
+ if (typeof v === 'string' && v.length > 0)
832
+ return v;
833
+ if (typeof v === 'number')
834
+ return String(v);
835
+ }
836
+ return undefined;
837
+ }
838
+ /** Returns the first present numeric value among the given keys. */
839
+ readNumber(obj, keys) {
840
+ for (const k of keys) {
841
+ const v = obj[k];
842
+ if (typeof v === 'number' && Number.isFinite(v))
843
+ return v;
844
+ }
845
+ return null;
846
+ }
847
+ /** Returns the first present boolean value on a key whose name starts with `prefix`. */
848
+ readBooleanStartsWith(obj, prefix) {
849
+ for (const [k, v] of Object.entries(obj)) {
850
+ if (k.startsWith(prefix) && typeof v === 'boolean')
851
+ return v;
852
+ }
853
+ return undefined;
854
+ }
855
+ /** Reads a nested string value via a key path (tolerant of absent/invalid). */
856
+ readNestedString(obj, path) {
857
+ let cur = obj;
858
+ for (const p of path) {
859
+ if (!cur || typeof cur !== 'object')
860
+ return undefined;
861
+ cur = cur[p];
862
+ }
863
+ return typeof cur === 'string' && cur.length > 0 ? cur : undefined;
864
+ }
865
+ };
866
+ HigherLogicThriveCommunityConnector = __decorate([
867
+ RegisterClass(BaseIntegrationConnector, '@memberjunction/connector-higher-logic-thrive-community')
868
+ ], HigherLogicThriveCommunityConnector);
869
+ export { HigherLogicThriveCommunityConnector };
870
+ //# sourceMappingURL=HigherLogicThriveCommunityConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HigherLogicThriveCommunityConnector.js","sourceRoot":"","sources":["../src/HigherLogicThriveCommunityConnector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './HigherLogicThriveCommunityConnector.js';
2
+ /** Open App bootstrap entry: importing this module ran the connector's @RegisterClass decorator;
3
+ * this no-op satisfies the loader's required startupExport and forces the import at MJAPI boot. */
4
+ export declare function registerConnector(): void;
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './HigherLogicThriveCommunityConnector.js';
2
+ /** Open App bootstrap entry: importing this module ran the connector's @RegisterClass decorator;
3
+ * this no-op satisfies the loader's required startupExport and forces the import at MJAPI boot. */
4
+ export function registerConnector() { }
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0CAA0C,CAAC;AAEzD;oGACoG;AACpG,MAAM,UAAU,iBAAiB,KAAiD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@memberjunction/connector-higher-logic-thrive-community",
3
+ "version": "0.2.0",
4
+ "private": false,
5
+ "description": "MemberJunction HigherLogicThriveCommunity connector.",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "/dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc && tsc-alias -f",
14
+ "test": "vitest run"
15
+ },
16
+ "author": "MemberJunction.com",
17
+ "license": "ISC",
18
+ "peerDependencies": {
19
+ "@memberjunction/core": ">=5.43.0 <6.0.0",
20
+ "@memberjunction/core-entities": ">=5.43.0 <6.0.0",
21
+ "@memberjunction/global": ">=5.43.0 <6.0.0",
22
+ "@memberjunction/integration-engine": ">=5.43.0 <6.0.0"
23
+ },
24
+ "dependencies": {
25
+ "zod": "~3.24.4",
26
+ "@memberjunction/connector-schema-merge": "^1.0.1"
27
+ },
28
+ "devDependencies": {
29
+ "@memberjunction/core": "^5.43.0",
30
+ "@memberjunction/core-entities": "^5.43.0",
31
+ "@memberjunction/global": "^5.43.0",
32
+ "@memberjunction/integration-engine": "^5.43.0",
33
+ "@types/node": "24.10.11",
34
+ "tsc-alias": "^1.8.16",
35
+ "typescript": "^5.9.3",
36
+ "vitest": "^4.0.18"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/MemberJunction/Integrations"
41
+ }
42
+ }