@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.
- package/dist/HigherLogicThriveCommunityConnector.d.ts +205 -0
- package/dist/HigherLogicThriveCommunityConnector.js +870 -0
- package/dist/HigherLogicThriveCommunityConnector.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|