@memberjunction/connector-openwater 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OpenWaterConnector.d.ts +172 -0
- package/dist/OpenWaterConnector.js +903 -0
- package/dist/OpenWaterConnector.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 +38 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { type UserInfo } from '@memberjunction/core';
|
|
2
|
+
import type { MJCompanyIntegrationEntity, MJIntegrationObjectEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import { BaseRESTIntegrationConnector, type RESTAuthContext, type RESTResponse, type PaginationState, type PaginationType, type ConnectionTestResult, type DefaultIntegrationConfig, type FetchContext, type FetchBatchResult, type RateLimitPolicy, type CreateRecordContext, type UpdateRecordContext, type DeleteRecordContext, type CRUDResult } from '@memberjunction/integration-engine';
|
|
4
|
+
/**
|
|
5
|
+
* Resolved OpenWater connection configuration. ClientKey + ApiKey are required;
|
|
6
|
+
* OrganizationCode + BaseURL are optional.
|
|
7
|
+
*/
|
|
8
|
+
export interface OpenWaterConnectionConfig {
|
|
9
|
+
/** X-ClientKey header value. */
|
|
10
|
+
ClientKey: string;
|
|
11
|
+
/** X-ApiKey header value (the secret). */
|
|
12
|
+
ApiKey: string;
|
|
13
|
+
/** X-OrganizationCode header value (optional, multi-org tenants). */
|
|
14
|
+
OrganizationCode?: string;
|
|
15
|
+
/** API base URL. Defaults to the OpenWater public API host. */
|
|
16
|
+
BaseURL?: string;
|
|
17
|
+
/** Maximum retries for rate-limited / transient failures. Default 3. */
|
|
18
|
+
MaxRetries?: number;
|
|
19
|
+
/** HTTP request timeout in milliseconds. Default 30000. */
|
|
20
|
+
RequestTimeoutMs?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare class OpenWaterConnector extends BaseRESTIntegrationConnector {
|
|
23
|
+
private authState;
|
|
24
|
+
get IntegrationName(): string;
|
|
25
|
+
get SupportsCreate(): boolean;
|
|
26
|
+
get SupportsUpdate(): boolean;
|
|
27
|
+
get SupportsDelete(): boolean;
|
|
28
|
+
/** OpenWater's modest enterprise throughput; engine runs an AIMD token bucket from this. */
|
|
29
|
+
get RateLimitPolicy(): RateLimitPolicy;
|
|
30
|
+
/** Parse a Retry-After header (seconds, or an HTTP-date) into milliseconds. */
|
|
31
|
+
ExtractRetryAfterMs(error: unknown): number | undefined;
|
|
32
|
+
private ReadRetryAfterHeader;
|
|
33
|
+
protected Authenticate(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<RESTAuthContext>;
|
|
34
|
+
/** Dual custom-header auth: X-ClientKey + X-ApiKey on every request; X-OrganizationCode when present. */
|
|
35
|
+
protected BuildHeaders(auth: RESTAuthContext): Record<string, string>;
|
|
36
|
+
protected MakeHTTPRequest(auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
|
|
37
|
+
/**
|
|
38
|
+
* OpenWater v2 list endpoints return a paged envelope { records: [...], pageIndex, pageSize,
|
|
39
|
+
* totalRecords } or a bare array. NormalizeResponse unwraps to the record array.
|
|
40
|
+
*/
|
|
41
|
+
protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
|
|
42
|
+
/**
|
|
43
|
+
* PageNumber pagination over OpenWater's pageIndex/pageSize. Advances pageIndex until a
|
|
44
|
+
* short/empty page (records.length < requested pageSize) signals the last page.
|
|
45
|
+
*/
|
|
46
|
+
protected ExtractPaginationInfo(rawBody: unknown, paginationType: PaginationType, currentPage: number, currentOffset: number, pageSize: number): PaginationState;
|
|
47
|
+
private ReadTotalRecords;
|
|
48
|
+
/**
|
|
49
|
+
* OpenWater uses page=/pageSize= by default in the base loop, but the API's param names are
|
|
50
|
+
* pageIndex/pageSize. Override to emit the vendor's actual param names.
|
|
51
|
+
*/
|
|
52
|
+
protected BuildPaginatedURL(basePath: string, obj: MJIntegrationObjectEntity, page: number, offset: number, cursor?: string, effectivePageSize?: number): string;
|
|
53
|
+
protected GetBaseURL(_companyIntegration: MJCompanyIntegrationEntity, auth: RESTAuthContext): string;
|
|
54
|
+
TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
|
|
55
|
+
FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
|
|
56
|
+
CreateRecord(ctx: CreateRecordContext): Promise<CRUDResult>;
|
|
57
|
+
UpdateRecord(ctx: UpdateRecordContext): Promise<CRUDResult>;
|
|
58
|
+
DeleteRecord(ctx: DeleteRecordContext): Promise<CRUDResult>;
|
|
59
|
+
/**
|
|
60
|
+
* Session create — Models.Session.CreateRequest requires {programId, typeId, name}. The synced
|
|
61
|
+
* list-model carries typeName (string), not typeId (int). Resolve typeId from an explicit typeId
|
|
62
|
+
* attribute when supplied; otherwise look it up by name against the SessionType IO (which is
|
|
63
|
+
* program-scoped, so we match within the record's programId).
|
|
64
|
+
*/
|
|
65
|
+
private CreateSession;
|
|
66
|
+
/**
|
|
67
|
+
* JudgeAssignment create — Models.JudgeAssignment.AssignJudgeToRoundRequest requires
|
|
68
|
+
* {judgeUserId, roundId}. judgeUserId <- the synced userId; roundId from the create attributes'
|
|
69
|
+
* round context (tagged onto the synced record by the AccessPath walk, or passed explicitly).
|
|
70
|
+
* CreateIDLocation='n/a' → there is no body id; the stable identity is the (roundId, judgeUserId)
|
|
71
|
+
* pair, so BuildCreatedResult is fed the synthetic composite id roundId|judgeUserId.
|
|
72
|
+
*/
|
|
73
|
+
private CreateJudgeAssignment;
|
|
74
|
+
private DeleteJudgeAssignment;
|
|
75
|
+
/**
|
|
76
|
+
* ScheduleTimeSlot create — Models.ScheduleTimeSlot.CreateRequest requires
|
|
77
|
+
* {name, code, startTime, endTime, scheduleDayIds}. The read-side IOF is availableOnlyInDayIds;
|
|
78
|
+
* map it (or an explicit scheduleDayIds) into scheduleDayIds. The path is program-scoped, so the
|
|
79
|
+
* generic path is bypassed and the {programId} template is filled from the attributes.
|
|
80
|
+
*/
|
|
81
|
+
private CreateScheduleTimeSlot;
|
|
82
|
+
/**
|
|
83
|
+
* ScheduleTimeSlot update — Models.ScheduleTimeSlot.UpdateRequest mirrors the create shape and
|
|
84
|
+
* also requires scheduleDayIds (mapped from availableOnlyInDayIds). The update path is keyed by
|
|
85
|
+
* the time-slot id (not program-scoped): PATCH /v2/Programs/Scheduler/TimeSlots/{scheduleTimeSlotId}.
|
|
86
|
+
*/
|
|
87
|
+
private UpdateScheduleTimeSlot;
|
|
88
|
+
/** Shared body for ScheduleTimeSlot create/update: maps availableOnlyInDayIds -> scheduleDayIds. */
|
|
89
|
+
private BuildTimeSlotBody;
|
|
90
|
+
/** Resolve a SessionType id: explicit typeId attribute, else lookup by typeName in the SessionType IO. */
|
|
91
|
+
private ResolveSessionTypeId;
|
|
92
|
+
/** POST a hand-built create body and route the result through BuildCreatedResult (id from body). */
|
|
93
|
+
private PostCreate;
|
|
94
|
+
private RequireNumber;
|
|
95
|
+
/** First parseable number among candidate keys (case-tolerant), or null. */
|
|
96
|
+
private FirstNumber;
|
|
97
|
+
private CopyOptional;
|
|
98
|
+
private FailedResult;
|
|
99
|
+
/**
|
|
100
|
+
* Flat/door fetch with incremental watermark applied. Reuses the base pagination loop by
|
|
101
|
+
* temporarily folding the watermark param into the IO's DefaultQueryParams-equivalent via a
|
|
102
|
+
* one-shot manual paginated loop (so the watermark rides every page request).
|
|
103
|
+
*/
|
|
104
|
+
private FetchDoor;
|
|
105
|
+
/**
|
|
106
|
+
* Walks the per-IO AccessPath: query the door, descend the nesting segments to the leaf parent
|
|
107
|
+
* ids, then fetch the entry path once per parent (id in path template or query param), unioning
|
|
108
|
+
* any alternativePaths. An `embedded-array` access path emits records straight from the door.
|
|
109
|
+
*/
|
|
110
|
+
private FetchViaAccessPath;
|
|
111
|
+
/** Fetch all pages of a door collection (used to enumerate parent ids / embedded children). */
|
|
112
|
+
private FetchDoorRows;
|
|
113
|
+
/**
|
|
114
|
+
* Generic paginated leaf fetch. Loops pageIndex until a short/empty page (or the batch cap when
|
|
115
|
+
* `ctx` is supplied), tracking the max watermark seen across the IO's IncrementalWatermarkField.
|
|
116
|
+
* `forceFullScan` ignores the batch cap (used when enumerating door parents).
|
|
117
|
+
*/
|
|
118
|
+
private PaginateLeaf;
|
|
119
|
+
/** Reads and validates AccessPath from the IO's Configuration JSON; null when absent. */
|
|
120
|
+
private ParseAccessPath;
|
|
121
|
+
/**
|
|
122
|
+
* Descends the door rows along the nesting segments to the list of parent ids that get injected
|
|
123
|
+
* into the leaf entry path. For `rounds[]` this yields each round's id; for a direct programId
|
|
124
|
+
* parent (no nesting) it yields each door row's `id`.
|
|
125
|
+
*/
|
|
126
|
+
private DescendToParentIDs;
|
|
127
|
+
/** Walks the door rows down a chain of (array) field segments, returning the leaf object nodes. */
|
|
128
|
+
private WalkSegments;
|
|
129
|
+
/** For embedded-array access paths: emit the nested records directly from the door payload. */
|
|
130
|
+
private ExtractEmbedded;
|
|
131
|
+
/**
|
|
132
|
+
* Injects a parent id into an entry path: as a query param (?<parentParamName>=) when
|
|
133
|
+
* parentParamIn='query' (the roundId-gated endpoints, which 400 without it), otherwise into the
|
|
134
|
+
* {parentParamName} path template. Returns null when a path template var is present but unset
|
|
135
|
+
* (so an alternativePath that uses a different var is skipped, not mis-substituted).
|
|
136
|
+
*/
|
|
137
|
+
private InjectParentID;
|
|
138
|
+
/** Builds the incremental watermark query fragment (e.g. lastModifiedSinceUtc=2026-01-01T...). */
|
|
139
|
+
private BuildWatermarkParam;
|
|
140
|
+
private AppendQuery;
|
|
141
|
+
/**
|
|
142
|
+
* Builds an ExternalRecord. Fields carries the FULL source record (custom-column pass-through);
|
|
143
|
+
* runs the TransformRecord-preserving pipeline; resolves the ExternalID from the declared PK
|
|
144
|
+
* (composite-aware) with a content-hash fallback for partial/missing keys.
|
|
145
|
+
*/
|
|
146
|
+
private BuildExternalRecord;
|
|
147
|
+
private PrimaryKeyNames;
|
|
148
|
+
/** Deterministic fallback identity for partial/missing keys (FNV-1a over the canonical JSON). */
|
|
149
|
+
private ContentHash;
|
|
150
|
+
GetDefaultConfiguration(): DefaultIntegrationConfig;
|
|
151
|
+
private GetAuth;
|
|
152
|
+
private ParseConfig;
|
|
153
|
+
private ParseConfigFromCredential;
|
|
154
|
+
/** Overlay non-secret config (BaseURL / OrganizationCode) from the CompanyIntegration JSON onto a credential-derived config. */
|
|
155
|
+
private MergeConfigJson;
|
|
156
|
+
/**
|
|
157
|
+
* Resolves the connection config from a credential / configuration value bag. ClientKey + ApiKey
|
|
158
|
+
* are required unless `lenient` (used when overlaying optional config JSON onto a credential).
|
|
159
|
+
*/
|
|
160
|
+
private ExtractConfig;
|
|
161
|
+
private ExecuteFetch;
|
|
162
|
+
private BuildRESTResponse;
|
|
163
|
+
private ParseJsonSafely;
|
|
164
|
+
private ShouldRetry;
|
|
165
|
+
private ComputeRetryDelay;
|
|
166
|
+
/** Wraps an error message with the response Status + Headers so ExtractRetryAfterMs can read them. */
|
|
167
|
+
private HttpError;
|
|
168
|
+
private Sleep;
|
|
169
|
+
private StripTrailingSlash;
|
|
170
|
+
}
|
|
171
|
+
/** Tree-shaking prevention — import and call from the module entry point. */
|
|
172
|
+
export declare function LoadOpenWaterConnector(): void;
|
|
@@ -0,0 +1,903 @@
|
|
|
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
|
+
/**
|
|
8
|
+
* OpenWaterConnector — REST integration connector for OpenWater
|
|
9
|
+
* (https://www.getopenwater.com), an awards / grants / abstracts / fellowship
|
|
10
|
+
* submission-and-review platform. The connector targets OpenWater's v2 REST API.
|
|
11
|
+
*
|
|
12
|
+
* Auth — DUAL custom headers on EVERY request (no token exchange; the
|
|
13
|
+
* Account/Authenticate endpoint is out of scope):
|
|
14
|
+
* - X-ClientKey (config: ClientKey)
|
|
15
|
+
* - X-ApiKey (config secret: ApiKey)
|
|
16
|
+
* - X-OrganizationCode (config: OrganizationCode, OPTIONAL)
|
|
17
|
+
*
|
|
18
|
+
* Pagination — PageNumber (pageIndex / pageSize); advance pageIndex until a
|
|
19
|
+
* short/empty page.
|
|
20
|
+
*
|
|
21
|
+
* Incremental — per-IO IncrementalWatermarkField (lastModifiedSinceUtc /
|
|
22
|
+
* createdSinceUtc / deletedSinceUtc / lastModifiedUtc / mostRecentTransactionSinceUtc)
|
|
23
|
+
* formatted into the request query.
|
|
24
|
+
*
|
|
25
|
+
* Nested objects — OpenWater's object universe is larger than its directly-
|
|
26
|
+
* queryable doors. Each nested IO carries an AccessPath in its IntegrationObject
|
|
27
|
+
* Configuration { door, doorPath, parentParamName, nestingSegments[], entryPath,
|
|
28
|
+
* parentParamIn, extractionMode, alternativePaths[] }. FetchChanges WALKS that path:
|
|
29
|
+
* it queries the door, descends to the leaf parent IDs (e.g. Program -> rounds[] ->
|
|
30
|
+
* roundId), then calls the entry path once per parent — injecting the parent id either
|
|
31
|
+
* into the path template ({programId}/{fundId}) or as a query param (roundId-gated
|
|
32
|
+
* JudgeAssignments/Recusals, which 400 without it). An `embedded-array` AccessPath
|
|
33
|
+
* (Rounds) emits records directly from the door payload with no second call.
|
|
34
|
+
*
|
|
35
|
+
* Discovery — credential-free: DiscoverObjects/DiscoverFields/IntrospectSchema use the
|
|
36
|
+
* BaseRESTIntegrationConnector implementations, which read the Declared IO/IOF metadata
|
|
37
|
+
* from the IntegrationEngineBase cache. No catalog is baked into this file.
|
|
38
|
+
*
|
|
39
|
+
* Write — generic per-operation CRUD (Create/Update/Delete read from the IO's
|
|
40
|
+
* CreateAPIPath/Method/BodyShape/IDLocation, Update*, Delete* columns) for the FLAT-body
|
|
41
|
+
* write IOs (Application, JudgeTeam, User, Evaluation, ScheduleDay/Item/Room). THREE IOs
|
|
42
|
+
* declare CreateBodyShape='literal' because their create-request schema needs fields absent
|
|
43
|
+
* from the synced list-model, so CreateRecord is overridden for them (each still routes
|
|
44
|
+
* through BuildCreatedResult; each IO's Configuration.LiteralCreateReason documents the
|
|
45
|
+
* mapping):
|
|
46
|
+
* - Session → POST /v2/Sessions {programId, typeId, name, ...}; typeId resolved
|
|
47
|
+
* from the synced typeName via the SessionType IO (or a typeId input),
|
|
48
|
+
* per Models.Session.CreateRequest.
|
|
49
|
+
* - JudgeAssignment → POST /v2/JudgeAssignments/Round {judgeUserId, roundId}; judgeUserId
|
|
50
|
+
* <- record.userId, roundId from the create attributes' round context,
|
|
51
|
+
* per Models.JudgeAssignment.AssignJudgeToRoundRequest. CreateIDLocation
|
|
52
|
+
* /DeleteIDLocation = 'n/a' (no body id) → synthetic composite identity
|
|
53
|
+
* roundId|judgeUserId. Delete re-uses the same /Round endpoint with the
|
|
54
|
+
* pair as query params (DELETE has no path id).
|
|
55
|
+
* - ScheduleTimeSlot→ POST/PATCH supply scheduleDayIds (from the read-side availableOnlyInDayIds),
|
|
56
|
+
* per Models.ScheduleTimeSlot.Create/UpdateRequest. ScheduleTimeSlot also
|
|
57
|
+
* declares UpdateBodyShape='literal', so UpdateRecord is overridden too.
|
|
58
|
+
* All other write IOs (incl. the lifecycle PATCHes Forwarding/WinnerAssignment/Status, which
|
|
59
|
+
* are NOT in the frozen contract) use the generic per-operation path unchanged. These literal
|
|
60
|
+
* write paths are untestable credential-free → RequiresLiveVerification (T10).
|
|
61
|
+
*/
|
|
62
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
63
|
+
import { Metadata } from '@memberjunction/core';
|
|
64
|
+
import { BaseIntegrationConnector, BaseRESTIntegrationConnector, } from '@memberjunction/integration-engine';
|
|
65
|
+
// ─── Constants ──────────────────────────────────────────────────────────
|
|
66
|
+
// No DEFAULT_BASE_URL: OpenWater is tenant-specific (per-customer host on *.secure-platform.com);
|
|
67
|
+
// the legacy api.getopenwater.com host does NOT resolve. BaseURL is REQUIRED — see GetAuth().
|
|
68
|
+
const DEFAULT_PAGE_SIZE = 100;
|
|
69
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
70
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
71
|
+
/** OpenWater is a modest-throughput enterprise API — keep a conservative sustained rate. */
|
|
72
|
+
const RATE_LIMIT_TOKENS_PER_SEC = 3;
|
|
73
|
+
// ─── Connector ──────────────────────────────────────────────────────────
|
|
74
|
+
let OpenWaterConnector = class OpenWaterConnector extends BaseRESTIntegrationConnector {
|
|
75
|
+
constructor() {
|
|
76
|
+
super(...arguments);
|
|
77
|
+
this.authState = null;
|
|
78
|
+
}
|
|
79
|
+
// ── Identity (three-way invariant axis) ─────────────────────────
|
|
80
|
+
get IntegrationName() { return 'OpenWater'; }
|
|
81
|
+
// ── Capability flags ─────────────────────────────────────────────
|
|
82
|
+
// The per-IO write columns (SupportsCreate/Update/Delete + Create/Update/Delete*
|
|
83
|
+
// metadata) drive the generic CRUD path; these getters report that the connector
|
|
84
|
+
// CAN write so the engine attempts the per-IO verbs the metadata configures.
|
|
85
|
+
get SupportsCreate() { return true; }
|
|
86
|
+
get SupportsUpdate() { return true; }
|
|
87
|
+
get SupportsDelete() { return true; }
|
|
88
|
+
// ── Sync-efficiency hooks ────────────────────────────────────────
|
|
89
|
+
/** OpenWater's modest enterprise throughput; engine runs an AIMD token bucket from this. */
|
|
90
|
+
get RateLimitPolicy() {
|
|
91
|
+
return { TokensPerSec: RATE_LIMIT_TOKENS_PER_SEC };
|
|
92
|
+
}
|
|
93
|
+
/** Parse a Retry-After header (seconds, or an HTTP-date) into milliseconds. */
|
|
94
|
+
ExtractRetryAfterMs(error) {
|
|
95
|
+
const retryAfter = this.ReadRetryAfterHeader(error);
|
|
96
|
+
if (retryAfter == null)
|
|
97
|
+
return undefined;
|
|
98
|
+
const seconds = Number.parseInt(retryAfter, 10);
|
|
99
|
+
if (Number.isFinite(seconds) && seconds > 0)
|
|
100
|
+
return seconds * 1000;
|
|
101
|
+
const when = Date.parse(retryAfter);
|
|
102
|
+
if (Number.isFinite(when)) {
|
|
103
|
+
const delta = when - Date.now();
|
|
104
|
+
return delta > 0 ? delta : 0;
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
ReadRetryAfterHeader(error) {
|
|
109
|
+
if (!error || typeof error !== 'object')
|
|
110
|
+
return undefined;
|
|
111
|
+
const e = error;
|
|
112
|
+
const status = e.Status ?? e.status;
|
|
113
|
+
if (status != null && status !== 429 && status !== 503)
|
|
114
|
+
return undefined;
|
|
115
|
+
const headers = e.Headers ?? e.headers;
|
|
116
|
+
if (!headers)
|
|
117
|
+
return undefined;
|
|
118
|
+
return headers['retry-after'] ?? headers['Retry-After'];
|
|
119
|
+
}
|
|
120
|
+
// ── Auth + transport (abstract methods) ─────────────────────────
|
|
121
|
+
async Authenticate(companyIntegration, contextUser) {
|
|
122
|
+
return this.GetAuth(companyIntegration, contextUser);
|
|
123
|
+
}
|
|
124
|
+
/** Dual custom-header auth: X-ClientKey + X-ApiKey on every request; X-OrganizationCode when present. */
|
|
125
|
+
BuildHeaders(auth) {
|
|
126
|
+
const config = auth.Config;
|
|
127
|
+
const headers = {
|
|
128
|
+
'X-ClientKey': config.ClientKey,
|
|
129
|
+
'X-ApiKey': config.ApiKey,
|
|
130
|
+
'Accept': 'application/json',
|
|
131
|
+
'User-Agent': 'MemberJunction-Integration/1.0',
|
|
132
|
+
};
|
|
133
|
+
if (config.OrganizationCode)
|
|
134
|
+
headers['X-OrganizationCode'] = config.OrganizationCode;
|
|
135
|
+
return headers;
|
|
136
|
+
}
|
|
137
|
+
async MakeHTTPRequest(auth, url, method, headers, body) {
|
|
138
|
+
const config = auth.Config;
|
|
139
|
+
const maxRetries = config.MaxRetries ?? DEFAULT_MAX_RETRIES;
|
|
140
|
+
const timeoutMs = config.RequestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
141
|
+
const effectiveHeaders = { ...headers };
|
|
142
|
+
if (body !== undefined && method !== 'GET' && method !== 'DELETE' && !effectiveHeaders['Content-Type']) {
|
|
143
|
+
effectiveHeaders['Content-Type'] = 'application/json';
|
|
144
|
+
}
|
|
145
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
146
|
+
const response = await this.ExecuteFetch(url, method, effectiveHeaders, body, timeoutMs);
|
|
147
|
+
if (this.ShouldRetry(response.status) && attempt < maxRetries) {
|
|
148
|
+
await this.Sleep(this.ComputeRetryDelay(response, attempt));
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
return this.BuildRESTResponse(response);
|
|
152
|
+
}
|
|
153
|
+
throw new Error(`OpenWater API request failed after ${maxRetries} attempt(s): ${url}`);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* OpenWater v2 list endpoints return a paged envelope { records: [...], pageIndex, pageSize,
|
|
157
|
+
* totalRecords } or a bare array. NormalizeResponse unwraps to the record array.
|
|
158
|
+
*/
|
|
159
|
+
NormalizeResponse(rawBody, responseDataKey) {
|
|
160
|
+
if (rawBody == null)
|
|
161
|
+
return [];
|
|
162
|
+
if (Array.isArray(rawBody))
|
|
163
|
+
return rawBody;
|
|
164
|
+
const body = rawBody;
|
|
165
|
+
if (responseDataKey && Array.isArray(body[responseDataKey])) {
|
|
166
|
+
return body[responseDataKey];
|
|
167
|
+
}
|
|
168
|
+
for (const key of ['records', 'data', 'items', 'results']) {
|
|
169
|
+
if (Array.isArray(body[key]))
|
|
170
|
+
return body[key];
|
|
171
|
+
}
|
|
172
|
+
// A single-object response (e.g. a create echo) becomes a one-element array.
|
|
173
|
+
if (Object.keys(body).length > 0)
|
|
174
|
+
return [body];
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* PageNumber pagination over OpenWater's pageIndex/pageSize. Advances pageIndex until a
|
|
179
|
+
* short/empty page (records.length < requested pageSize) signals the last page.
|
|
180
|
+
*/
|
|
181
|
+
ExtractPaginationInfo(rawBody, paginationType, currentPage, currentOffset, pageSize) {
|
|
182
|
+
if (paginationType === 'None')
|
|
183
|
+
return { HasMore: false };
|
|
184
|
+
const records = this.NormalizeResponse(rawBody, null);
|
|
185
|
+
const effectivePageSize = pageSize > 0 ? pageSize : DEFAULT_PAGE_SIZE;
|
|
186
|
+
const total = this.ReadTotalRecords(rawBody);
|
|
187
|
+
switch (paginationType) {
|
|
188
|
+
case 'PageNumber': {
|
|
189
|
+
// Short page ⇒ done. Otherwise honor a totalRecords hint when the API supplies one.
|
|
190
|
+
const moreByPageSize = records.length >= effectivePageSize;
|
|
191
|
+
// pageIndex is 0-based: after page `currentPage` we've fetched (currentPage+1) pages.
|
|
192
|
+
const fetchedSoFar = (currentPage + 1) * effectivePageSize;
|
|
193
|
+
const hasMore = total != null ? fetchedSoFar < total && records.length > 0 : moreByPageSize;
|
|
194
|
+
return { HasMore: hasMore, NextPage: currentPage + 1 };
|
|
195
|
+
}
|
|
196
|
+
case 'Offset':
|
|
197
|
+
return { HasMore: records.length >= effectivePageSize, NextOffset: currentOffset + records.length };
|
|
198
|
+
case 'Cursor': {
|
|
199
|
+
const body = rawBody;
|
|
200
|
+
const cursor = body?.['nextCursor'] ?? body?.['next_cursor'] ?? body?.['cursor'];
|
|
201
|
+
return { HasMore: typeof cursor === 'string' && cursor.length > 0, NextCursor: typeof cursor === 'string' ? cursor : undefined };
|
|
202
|
+
}
|
|
203
|
+
default:
|
|
204
|
+
return { HasMore: records.length >= effectivePageSize };
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
ReadTotalRecords(rawBody) {
|
|
208
|
+
if (!rawBody || typeof rawBody !== 'object' || Array.isArray(rawBody))
|
|
209
|
+
return null;
|
|
210
|
+
const b = rawBody;
|
|
211
|
+
for (const key of ['totalRecords', 'totalCount', 'total']) {
|
|
212
|
+
const v = b[key];
|
|
213
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
214
|
+
return v;
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* OpenWater uses page=/pageSize= by default in the base loop, but the API's param names are
|
|
220
|
+
* pageIndex/pageSize. Override to emit the vendor's actual param names.
|
|
221
|
+
*/
|
|
222
|
+
BuildPaginatedURL(basePath, obj, page, offset, cursor, effectivePageSize) {
|
|
223
|
+
const pageSize = effectivePageSize ?? obj.DefaultPageSize ?? DEFAULT_PAGE_SIZE;
|
|
224
|
+
const separator = basePath.includes('?') ? '&' : '?';
|
|
225
|
+
switch (obj.PaginationType) {
|
|
226
|
+
case 'PageNumber':
|
|
227
|
+
return `${basePath}${separator}pageIndex=${page}&pageSize=${pageSize}`;
|
|
228
|
+
case 'Offset':
|
|
229
|
+
return `${basePath}${separator}offset=${offset}&pageSize=${pageSize}`;
|
|
230
|
+
case 'Cursor':
|
|
231
|
+
return cursor
|
|
232
|
+
? `${basePath}${separator}cursor=${encodeURIComponent(cursor)}&pageSize=${pageSize}`
|
|
233
|
+
: `${basePath}${separator}pageSize=${pageSize}`;
|
|
234
|
+
default:
|
|
235
|
+
return basePath;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
GetBaseURL(_companyIntegration, auth) {
|
|
239
|
+
return auth.BaseURL;
|
|
240
|
+
}
|
|
241
|
+
// ── Connection test ──────────────────────────────────────────────
|
|
242
|
+
async TestConnection(companyIntegration, contextUser) {
|
|
243
|
+
try {
|
|
244
|
+
const auth = await this.GetAuth(companyIntegration, contextUser, true);
|
|
245
|
+
// Programs is a top-level door present in every OpenWater tenant.
|
|
246
|
+
const url = `${auth.BaseURL}/v2/Programs?pageIndex=0&pageSize=1`;
|
|
247
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
|
|
248
|
+
if (response.Status >= 200 && response.Status < 300) {
|
|
249
|
+
return { Success: true, Message: `Connected to OpenWater at ${auth.BaseURL}` };
|
|
250
|
+
}
|
|
251
|
+
if (response.Status === 401 || response.Status === 403) {
|
|
252
|
+
return { Success: false, Message: `OpenWater rejected the credentials (HTTP ${response.Status}). Verify ClientKey / ApiKey / OrganizationCode.` };
|
|
253
|
+
}
|
|
254
|
+
return { Success: false, Message: `OpenWater responded HTTP ${response.Status}.` };
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
258
|
+
return { Success: false, Message: `OpenWater connection failed: ${message}` };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// NOTE: DiscoverObjects / DiscoverFields / IntrospectSchema are intentionally NOT
|
|
262
|
+
// overridden — the base implementations read the Declared IO/IOF metadata from the
|
|
263
|
+
// IntegrationEngineBase cache (credential-free, no baked catalog in this file).
|
|
264
|
+
// ── Fetch (incremental + nested-graph access-path walk) ─────────
|
|
265
|
+
async FetchChanges(ctx) {
|
|
266
|
+
const obj = this.GetCachedObject(ctx.CompanyIntegration.IntegrationID, ctx.ObjectName);
|
|
267
|
+
const accessPath = this.ParseAccessPath(obj);
|
|
268
|
+
// Depth-0 (directly-queryable door / flat top-level query): delegate to the base
|
|
269
|
+
// flat/pagination path, but layer the incremental watermark query param on top.
|
|
270
|
+
if (!accessPath) {
|
|
271
|
+
return this.FetchDoor(ctx, obj);
|
|
272
|
+
}
|
|
273
|
+
// Depth-N (nested): walk the access path from the door to the leaf records.
|
|
274
|
+
return this.FetchViaAccessPath(ctx, obj, accessPath);
|
|
275
|
+
}
|
|
276
|
+
// ── Literal-create / literal-update overrides (RequiresLiveVerification) ──────────
|
|
277
|
+
//
|
|
278
|
+
// Three IOs declare CreateBodyShape='literal' (Session, JudgeAssignment, ScheduleTimeSlot)
|
|
279
|
+
// because their create-request schema needs fields absent from the synced list-model — the
|
|
280
|
+
// generic flat body would 400/422. ScheduleTimeSlot additionally declares UpdateBodyShape=
|
|
281
|
+
// 'literal'. CreateRecord/UpdateRecord dispatch ONLY those IOs to a hand-built body (read from
|
|
282
|
+
// the OpenAPI create/update-request schema) and delegate every other IO to the generic
|
|
283
|
+
// per-operation column path on the base class. All creates route through BuildCreatedResult.
|
|
284
|
+
async CreateRecord(ctx) {
|
|
285
|
+
switch (ctx.ObjectName) {
|
|
286
|
+
case 'Session': return this.CreateSession(ctx);
|
|
287
|
+
case 'JudgeAssignment': return this.CreateJudgeAssignment(ctx);
|
|
288
|
+
case 'ScheduleTimeSlot': return this.CreateScheduleTimeSlot(ctx);
|
|
289
|
+
default: return super.CreateRecord(ctx);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async UpdateRecord(ctx) {
|
|
293
|
+
// Only ScheduleTimeSlot declares UpdateBodyShape='literal'; everything else is generic.
|
|
294
|
+
if (ctx.ObjectName === 'ScheduleTimeSlot')
|
|
295
|
+
return this.UpdateScheduleTimeSlot(ctx);
|
|
296
|
+
return super.UpdateRecord(ctx);
|
|
297
|
+
}
|
|
298
|
+
async DeleteRecord(ctx) {
|
|
299
|
+
// JudgeAssignment delete has no path id (DeleteIDLocation='n/a'): DELETE /v2/JudgeAssignments/Round
|
|
300
|
+
// with the {roundId, judgeUserId} pair as query params, recovered from the synthetic composite id.
|
|
301
|
+
if (ctx.ObjectName === 'JudgeAssignment')
|
|
302
|
+
return this.DeleteJudgeAssignment(ctx);
|
|
303
|
+
return super.DeleteRecord(ctx);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Session create — Models.Session.CreateRequest requires {programId, typeId, name}. The synced
|
|
307
|
+
* list-model carries typeName (string), not typeId (int). Resolve typeId from an explicit typeId
|
|
308
|
+
* attribute when supplied; otherwise look it up by name against the SessionType IO (which is
|
|
309
|
+
* program-scoped, so we match within the record's programId).
|
|
310
|
+
*/
|
|
311
|
+
async CreateSession(ctx) {
|
|
312
|
+
const a = ctx.Attributes;
|
|
313
|
+
const programId = this.RequireNumber(a, 'programId');
|
|
314
|
+
const typeId = await this.ResolveSessionTypeId(ctx, a, programId);
|
|
315
|
+
if (typeId == null) {
|
|
316
|
+
return this.FailedResult(`Session create: could not resolve a SessionType id from typeId/typeName for programId ${programId}.`);
|
|
317
|
+
}
|
|
318
|
+
const body = {
|
|
319
|
+
programId,
|
|
320
|
+
typeId,
|
|
321
|
+
name: a['name'] ?? a['Name'] ?? '',
|
|
322
|
+
};
|
|
323
|
+
this.CopyOptional(a, body, ['chairUserIds', 'fieldValues']);
|
|
324
|
+
return this.PostCreate(ctx, '/v2/Sessions', body, 'body');
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* JudgeAssignment create — Models.JudgeAssignment.AssignJudgeToRoundRequest requires
|
|
328
|
+
* {judgeUserId, roundId}. judgeUserId <- the synced userId; roundId from the create attributes'
|
|
329
|
+
* round context (tagged onto the synced record by the AccessPath walk, or passed explicitly).
|
|
330
|
+
* CreateIDLocation='n/a' → there is no body id; the stable identity is the (roundId, judgeUserId)
|
|
331
|
+
* pair, so BuildCreatedResult is fed the synthetic composite id roundId|judgeUserId.
|
|
332
|
+
*/
|
|
333
|
+
async CreateJudgeAssignment(ctx) {
|
|
334
|
+
const a = ctx.Attributes;
|
|
335
|
+
const judgeUserId = this.FirstNumber(a, ['judgeUserId', 'userId']);
|
|
336
|
+
const roundId = this.FirstNumber(a, ['roundId']);
|
|
337
|
+
if (judgeUserId == null)
|
|
338
|
+
return this.FailedResult('JudgeAssignment create: missing judgeUserId/userId.');
|
|
339
|
+
if (roundId == null)
|
|
340
|
+
return this.FailedResult('JudgeAssignment create: missing roundId (round context not available).');
|
|
341
|
+
const body = { judgeUserId, roundId };
|
|
342
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
343
|
+
const url = `${auth.BaseURL}/v2/JudgeAssignments/Round`;
|
|
344
|
+
const response = await this.MakeHTTPRequest(auth, url, 'POST', this.BuildHeaders(auth), body);
|
|
345
|
+
if (response.Status >= 200 && response.Status < 300) {
|
|
346
|
+
// No returned id (n/a) — the pair IS the identity. Synthesize it so the create is tracked.
|
|
347
|
+
return this.BuildCreatedResult(`${roundId}|${judgeUserId}`, response.Status, ctx.ObjectName);
|
|
348
|
+
}
|
|
349
|
+
return this.FailedResult(this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on JudgeAssignment create`, response.Status);
|
|
350
|
+
}
|
|
351
|
+
async DeleteJudgeAssignment(ctx) {
|
|
352
|
+
// Recover {roundId, judgeUserId} from the synthetic composite id roundId|judgeUserId.
|
|
353
|
+
const [roundId, judgeUserId] = String(ctx.ExternalID).split('|');
|
|
354
|
+
if (!roundId || !judgeUserId) {
|
|
355
|
+
return this.FailedResult(`JudgeAssignment delete: external id "${ctx.ExternalID}" is not a roundId|judgeUserId pair.`);
|
|
356
|
+
}
|
|
357
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
358
|
+
const url = `${auth.BaseURL}/v2/JudgeAssignments/Round?roundId=${encodeURIComponent(roundId)}&judgeUserId=${encodeURIComponent(judgeUserId)}`;
|
|
359
|
+
const response = await this.MakeHTTPRequest(auth, url, 'DELETE', this.BuildHeaders(auth));
|
|
360
|
+
if (response.Status >= 200 && response.Status < 300) {
|
|
361
|
+
return { Success: true, StatusCode: response.Status, ExternalID: ctx.ExternalID };
|
|
362
|
+
}
|
|
363
|
+
return this.FailedResult(this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on JudgeAssignment delete`, response.Status);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* ScheduleTimeSlot create — Models.ScheduleTimeSlot.CreateRequest requires
|
|
367
|
+
* {name, code, startTime, endTime, scheduleDayIds}. The read-side IOF is availableOnlyInDayIds;
|
|
368
|
+
* map it (or an explicit scheduleDayIds) into scheduleDayIds. The path is program-scoped, so the
|
|
369
|
+
* generic path is bypassed and the {programId} template is filled from the attributes.
|
|
370
|
+
*/
|
|
371
|
+
async CreateScheduleTimeSlot(ctx) {
|
|
372
|
+
const a = ctx.Attributes;
|
|
373
|
+
const programId = this.RequireNumber(a, 'programId');
|
|
374
|
+
const body = this.BuildTimeSlotBody(a);
|
|
375
|
+
return this.PostCreate(ctx, `/v2/Programs/${encodeURIComponent(String(programId))}/Scheduler/TimeSlots`, body, 'body');
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* ScheduleTimeSlot update — Models.ScheduleTimeSlot.UpdateRequest mirrors the create shape and
|
|
379
|
+
* also requires scheduleDayIds (mapped from availableOnlyInDayIds). The update path is keyed by
|
|
380
|
+
* the time-slot id (not program-scoped): PATCH /v2/Programs/Scheduler/TimeSlots/{scheduleTimeSlotId}.
|
|
381
|
+
*/
|
|
382
|
+
async UpdateScheduleTimeSlot(ctx) {
|
|
383
|
+
const body = this.BuildTimeSlotBody(ctx.Attributes);
|
|
384
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
385
|
+
const url = `${auth.BaseURL}/v2/Programs/Scheduler/TimeSlots/${encodeURIComponent(ctx.ExternalID)}`;
|
|
386
|
+
const response = await this.MakeHTTPRequest(auth, url, 'PATCH', this.BuildHeaders(auth), body);
|
|
387
|
+
if (response.Status >= 200 && response.Status < 300) {
|
|
388
|
+
return { Success: true, StatusCode: response.Status, ExternalID: ctx.ExternalID };
|
|
389
|
+
}
|
|
390
|
+
return this.FailedResult(this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on ScheduleTimeSlot update`, response.Status);
|
|
391
|
+
}
|
|
392
|
+
/** Shared body for ScheduleTimeSlot create/update: maps availableOnlyInDayIds -> scheduleDayIds. */
|
|
393
|
+
BuildTimeSlotBody(a) {
|
|
394
|
+
const scheduleDayIds = a['scheduleDayIds'] ?? a['availableOnlyInDayIds'] ?? [];
|
|
395
|
+
return {
|
|
396
|
+
name: a['name'] ?? a['Name'] ?? '',
|
|
397
|
+
code: a['code'] ?? a['Code'] ?? '',
|
|
398
|
+
startTime: a['startTime'] ?? a['StartTime'],
|
|
399
|
+
endTime: a['endTime'] ?? a['EndTime'],
|
|
400
|
+
scheduleDayIds: Array.isArray(scheduleDayIds) ? scheduleDayIds : [],
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
/** Resolve a SessionType id: explicit typeId attribute, else lookup by typeName in the SessionType IO. */
|
|
404
|
+
async ResolveSessionTypeId(ctx, a, programId) {
|
|
405
|
+
const explicit = this.FirstNumber(a, ['typeId']);
|
|
406
|
+
if (explicit != null)
|
|
407
|
+
return explicit;
|
|
408
|
+
const typeName = a['typeName'] ?? a['TypeName'];
|
|
409
|
+
if (typeof typeName !== 'string' || typeName.length === 0)
|
|
410
|
+
return null;
|
|
411
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
412
|
+
const url = `${auth.BaseURL}/v2/Programs/${encodeURIComponent(String(programId))}/SessionTypes`;
|
|
413
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
|
|
414
|
+
if (response.Status < 200 || response.Status >= 300)
|
|
415
|
+
return null;
|
|
416
|
+
const types = this.NormalizeResponse(response.Body, null);
|
|
417
|
+
const match = types.find(t => String(t['name'] ?? t['typeName'] ?? '').toLowerCase() === typeName.toLowerCase());
|
|
418
|
+
if (!match)
|
|
419
|
+
return null;
|
|
420
|
+
const id = match['id'];
|
|
421
|
+
return typeof id === 'number' ? id : (typeof id === 'string' && id.length > 0 ? Number(id) : null);
|
|
422
|
+
}
|
|
423
|
+
/** POST a hand-built create body and route the result through BuildCreatedResult (id from body). */
|
|
424
|
+
async PostCreate(ctx, path, body, idLocation) {
|
|
425
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
426
|
+
const url = `${auth.BaseURL}${path}`;
|
|
427
|
+
const response = await this.MakeHTTPRequest(auth, url, 'POST', this.BuildHeaders(auth), body);
|
|
428
|
+
if (response.Status >= 200 && response.Status < 300) {
|
|
429
|
+
const externalID = this.ExtractIDFromResponse(response, idLocation);
|
|
430
|
+
return this.BuildCreatedResult(externalID, response.Status, ctx.ObjectName);
|
|
431
|
+
}
|
|
432
|
+
return this.FailedResult(this.ExtractErrorMessage(response) ?? `HTTP ${response.Status} on ${ctx.ObjectName} create`, response.Status);
|
|
433
|
+
}
|
|
434
|
+
// ── Literal-write attribute helpers ──────────────────────────────
|
|
435
|
+
RequireNumber(a, key) {
|
|
436
|
+
const v = this.FirstNumber(a, [key]);
|
|
437
|
+
if (v == null)
|
|
438
|
+
throw new Error(`OpenWater write: required numeric attribute "${key}" is missing.`);
|
|
439
|
+
return v;
|
|
440
|
+
}
|
|
441
|
+
/** First parseable number among candidate keys (case-tolerant), or null. */
|
|
442
|
+
FirstNumber(a, keys) {
|
|
443
|
+
for (const key of keys) {
|
|
444
|
+
for (const k of [key, key.charAt(0).toUpperCase() + key.slice(1)]) {
|
|
445
|
+
const v = a[k];
|
|
446
|
+
if (typeof v === 'number' && Number.isFinite(v))
|
|
447
|
+
return v;
|
|
448
|
+
if (typeof v === 'string' && v.length > 0 && Number.isFinite(Number(v)))
|
|
449
|
+
return Number(v);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
CopyOptional(src, dest, keys) {
|
|
455
|
+
for (const k of keys)
|
|
456
|
+
if (src[k] !== undefined)
|
|
457
|
+
dest[k] = src[k];
|
|
458
|
+
}
|
|
459
|
+
FailedResult(message, statusCode = 0) {
|
|
460
|
+
return { Success: false, StatusCode: statusCode, ErrorMessage: message };
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Flat/door fetch with incremental watermark applied. Reuses the base pagination loop by
|
|
464
|
+
* temporarily folding the watermark param into the IO's DefaultQueryParams-equivalent via a
|
|
465
|
+
* one-shot manual paginated loop (so the watermark rides every page request).
|
|
466
|
+
*/
|
|
467
|
+
async FetchDoor(ctx, obj) {
|
|
468
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
469
|
+
const baseURL = this.GetBaseURL(ctx.CompanyIntegration, auth);
|
|
470
|
+
const watermarkParam = this.BuildWatermarkParam(obj, ctx.WatermarkValue);
|
|
471
|
+
const path = this.AppendQuery(obj.APIPath, watermarkParam);
|
|
472
|
+
const fields = this.GetCachedFields(obj.ID);
|
|
473
|
+
const pkFieldNames = this.PrimaryKeyNames(fields);
|
|
474
|
+
const { records, newWatermark, hasMore, nextPage } = await this.PaginateLeaf(auth, baseURL, path, obj, ctx, undefined, watermarkParam);
|
|
475
|
+
return {
|
|
476
|
+
Records: records.map(r => this.BuildExternalRecord(r, obj, fields, pkFieldNames)),
|
|
477
|
+
HasMore: hasMore,
|
|
478
|
+
NextPage: nextPage,
|
|
479
|
+
NewWatermarkValue: newWatermark,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Walks the per-IO AccessPath: query the door, descend the nesting segments to the leaf parent
|
|
484
|
+
* ids, then fetch the entry path once per parent (id in path template or query param), unioning
|
|
485
|
+
* any alternativePaths. An `embedded-array` access path emits records straight from the door.
|
|
486
|
+
*/
|
|
487
|
+
async FetchViaAccessPath(ctx, obj, accessPath) {
|
|
488
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
489
|
+
const baseURL = this.GetBaseURL(ctx.CompanyIntegration, auth);
|
|
490
|
+
const fields = this.GetCachedFields(obj.ID);
|
|
491
|
+
const pkFieldNames = this.PrimaryKeyNames(fields);
|
|
492
|
+
const warnings = [];
|
|
493
|
+
// Pull the door collection (paginated) and descend to the parent leaf values + the door rows.
|
|
494
|
+
const doorRows = await this.FetchDoorRows(auth, baseURL, accessPath.doorPath, obj);
|
|
495
|
+
if (doorRows.length === 0) {
|
|
496
|
+
warnings.push({
|
|
497
|
+
Code: 'ZERO_PARENTS',
|
|
498
|
+
Message: `No "${accessPath.door}" door records available; "${obj.Name}" produced zero records.`,
|
|
499
|
+
Data: { door: accessPath.door, doorPath: accessPath.doorPath },
|
|
500
|
+
});
|
|
501
|
+
return { Records: [], HasMore: false, Warnings: warnings };
|
|
502
|
+
}
|
|
503
|
+
// embedded-array: records are already inside the door payload (e.g. Program.rounds[]).
|
|
504
|
+
if (accessPath.extractionMode === 'embedded-array') {
|
|
505
|
+
const records = this.ExtractEmbedded(doorRows, accessPath.nestingSegments ?? []);
|
|
506
|
+
return {
|
|
507
|
+
Records: records.map(r => this.BuildExternalRecord(r, obj, fields, pkFieldNames)),
|
|
508
|
+
HasMore: false,
|
|
509
|
+
Warnings: warnings,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
const parentIDs = this.DescendToParentIDs(doorRows, accessPath);
|
|
513
|
+
if (parentIDs.length === 0) {
|
|
514
|
+
warnings.push({
|
|
515
|
+
Code: 'ZERO_PARENTS',
|
|
516
|
+
Message: `No "${accessPath.parentParamName}" parent ids reachable via ${accessPath.door} ${(accessPath.nestingSegments ?? []).join('->')}; "${obj.Name}" produced zero records.`,
|
|
517
|
+
Data: { door: accessPath.door, parentParamName: accessPath.parentParamName ?? null },
|
|
518
|
+
});
|
|
519
|
+
return { Records: [], HasMore: false, Warnings: warnings };
|
|
520
|
+
}
|
|
521
|
+
const entryPaths = [accessPath.entryPath, ...(accessPath.alternativePaths ?? [])];
|
|
522
|
+
const parentTagName = accessPath.parentParamName; // e.g. roundId / programId / fundId
|
|
523
|
+
const out = [];
|
|
524
|
+
for (const parentID of parentIDs) {
|
|
525
|
+
for (const entryPath of entryPaths) {
|
|
526
|
+
const leafPath = this.InjectParentID(entryPath, parentID, accessPath);
|
|
527
|
+
if (leafPath == null)
|
|
528
|
+
continue; // template var this entry path doesn't use
|
|
529
|
+
const { records } = await this.PaginateLeaf(auth, baseURL, leafPath, obj, ctx, parentID, '');
|
|
530
|
+
for (const r of records) {
|
|
531
|
+
// Tag the leaf with its parent id (e.g. roundId) when the record doesn't already
|
|
532
|
+
// carry it — makes round/program-scoped objects self-describing for pass-through
|
|
533
|
+
// AND supplies the round context a literal-create write-back (JudgeAssignment) needs.
|
|
534
|
+
if (parentTagName && r[parentTagName] == null)
|
|
535
|
+
r[parentTagName] = parentID;
|
|
536
|
+
out.push(this.BuildExternalRecord(r, obj, fields, pkFieldNames));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return { Records: out, HasMore: false, Warnings: warnings };
|
|
541
|
+
}
|
|
542
|
+
/** Fetch all pages of a door collection (used to enumerate parent ids / embedded children). */
|
|
543
|
+
async FetchDoorRows(auth, baseURL, doorPath, obj) {
|
|
544
|
+
const { records } = await this.PaginateLeaf(auth, baseURL, doorPath, obj, undefined, undefined, '', true);
|
|
545
|
+
return records;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Generic paginated leaf fetch. Loops pageIndex until a short/empty page (or the batch cap when
|
|
549
|
+
* `ctx` is supplied), tracking the max watermark seen across the IO's IncrementalWatermarkField.
|
|
550
|
+
* `forceFullScan` ignores the batch cap (used when enumerating door parents).
|
|
551
|
+
*/
|
|
552
|
+
async PaginateLeaf(auth, baseURL, path, obj, ctx, _parentID, _watermarkParam, forceFullScan = false) {
|
|
553
|
+
const headers = this.BuildHeaders(auth);
|
|
554
|
+
const pageSize = obj.DefaultPageSize && obj.DefaultPageSize > 0 ? obj.DefaultPageSize : DEFAULT_PAGE_SIZE;
|
|
555
|
+
const batchLimit = !forceFullScan && ctx?.BatchSize ? ctx.BatchSize : Number.MAX_SAFE_INTEGER;
|
|
556
|
+
const watermarkField = obj.IncrementalWatermarkField;
|
|
557
|
+
const all = [];
|
|
558
|
+
let page = ctx?.CurrentPage ?? 0;
|
|
559
|
+
let newWatermark = ctx?.WatermarkValue ?? undefined;
|
|
560
|
+
let hasMore = true;
|
|
561
|
+
while (hasMore && all.length < batchLimit) {
|
|
562
|
+
const sep = path.includes('?') ? '&' : '?';
|
|
563
|
+
const usePaging = obj.SupportsPagination && obj.PaginationType !== 'None';
|
|
564
|
+
const url = usePaging
|
|
565
|
+
? `${baseURL}${path}${sep}pageIndex=${page}&pageSize=${pageSize}`
|
|
566
|
+
: `${baseURL}${path}`;
|
|
567
|
+
const response = await this.MakeHTTPRequest(auth, url, 'GET', headers);
|
|
568
|
+
if (response.Status === 403 || response.Status === 401) {
|
|
569
|
+
console.warn(`[OpenWater] HTTP ${response.Status} for "${obj.Name}" at ${url} — skipping.`);
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
if (response.Status < 200 || response.Status >= 300) {
|
|
573
|
+
throw this.HttpError(`OpenWater fetch failed for "${obj.Name}": HTTP ${response.Status}`, response);
|
|
574
|
+
}
|
|
575
|
+
const records = this.NormalizeResponse(response.Body, obj.ResponseDataKey);
|
|
576
|
+
if (records.length === 0)
|
|
577
|
+
break;
|
|
578
|
+
all.push(...records);
|
|
579
|
+
// Track max watermark seen for the incremental cursor (string/ISO-comparable).
|
|
580
|
+
if (watermarkField) {
|
|
581
|
+
for (const r of records) {
|
|
582
|
+
const v = r[watermarkField];
|
|
583
|
+
if (typeof v === 'string' && (newWatermark == null || v > newWatermark))
|
|
584
|
+
newWatermark = v;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (!usePaging)
|
|
588
|
+
break;
|
|
589
|
+
const state = this.ExtractPaginationInfo(response.Body, obj.PaginationType, page, 0, pageSize);
|
|
590
|
+
hasMore = state.HasMore;
|
|
591
|
+
page = state.NextPage ?? page + 1;
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
records: all,
|
|
595
|
+
newWatermark: watermarkField ? newWatermark : undefined,
|
|
596
|
+
hasMore: hasMore && all.length >= batchLimit,
|
|
597
|
+
nextPage: page,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
// ── Access-path helpers ──────────────────────────────────────────
|
|
601
|
+
/** Reads and validates AccessPath from the IO's Configuration JSON; null when absent. */
|
|
602
|
+
ParseAccessPath(obj) {
|
|
603
|
+
if (!obj.Configuration)
|
|
604
|
+
return null;
|
|
605
|
+
try {
|
|
606
|
+
const parsed = JSON.parse(obj.Configuration);
|
|
607
|
+
const ap = parsed.AccessPath;
|
|
608
|
+
if (!ap || !ap.door || !ap.doorPath)
|
|
609
|
+
return null;
|
|
610
|
+
// embedded-array records are sliced from the DOOR payload itself — they have no
|
|
611
|
+
// entryPath by design. Requiring it here made every embedded IO (e.g. Rounds)
|
|
612
|
+
// silently fall back to its non-fetchable "(embedded in ...)" APIPath.
|
|
613
|
+
if (ap.extractionMode !== 'embedded-array' && !ap.entryPath)
|
|
614
|
+
return null;
|
|
615
|
+
return ap;
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
console.warn(`[OpenWater] Invalid Configuration JSON for object "${obj.Name}"`);
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Descends the door rows along the nesting segments to the list of parent ids that get injected
|
|
624
|
+
* into the leaf entry path. For `rounds[]` this yields each round's id; for a direct programId
|
|
625
|
+
* parent (no nesting) it yields each door row's `id`.
|
|
626
|
+
*/
|
|
627
|
+
DescendToParentIDs(doorRows, accessPath) {
|
|
628
|
+
// Only `[]`-suffixed segments are real array descents in the door payload (e.g. `rounds[]`,
|
|
629
|
+
// whose leaf `id` is the roundId). A bare segment (e.g. `transactions`) names the leaf API
|
|
630
|
+
// resource that lives in entryPath, NOT a nested array — those parents are the door rows
|
|
631
|
+
// themselves (the door's own `id` IS the parent id, e.g. programId / fundId).
|
|
632
|
+
const arraySegments = (accessPath.nestingSegments ?? []).filter(s => s.endsWith('[]'));
|
|
633
|
+
const ids = [];
|
|
634
|
+
const seen = new Set();
|
|
635
|
+
const collect = (id) => {
|
|
636
|
+
if (id == null)
|
|
637
|
+
return;
|
|
638
|
+
const s = String(id);
|
|
639
|
+
if (s.length === 0 || seen.has(s))
|
|
640
|
+
return;
|
|
641
|
+
seen.add(s);
|
|
642
|
+
ids.push(s);
|
|
643
|
+
};
|
|
644
|
+
if (arraySegments.length === 0) {
|
|
645
|
+
// Direct parent: the door row's own id is the parent id (e.g. programId, fundId).
|
|
646
|
+
for (const row of doorRows)
|
|
647
|
+
collect(row['id']);
|
|
648
|
+
return ids;
|
|
649
|
+
}
|
|
650
|
+
// Descend nested array segments (e.g. rounds[]), collecting the leaf nodes' ids.
|
|
651
|
+
const nodes = this.WalkSegments(doorRows, arraySegments);
|
|
652
|
+
for (const leaf of nodes)
|
|
653
|
+
collect(leaf['id']);
|
|
654
|
+
return ids;
|
|
655
|
+
}
|
|
656
|
+
/** Walks the door rows down a chain of (array) field segments, returning the leaf object nodes. */
|
|
657
|
+
WalkSegments(doorRows, segments) {
|
|
658
|
+
let nodes = doorRows;
|
|
659
|
+
for (const seg of segments) {
|
|
660
|
+
const key = seg.endsWith('[]') ? seg.slice(0, -2) : seg;
|
|
661
|
+
const next = [];
|
|
662
|
+
for (const node of nodes) {
|
|
663
|
+
const child = node[key];
|
|
664
|
+
if (Array.isArray(child)) {
|
|
665
|
+
for (const c of child)
|
|
666
|
+
if (c && typeof c === 'object')
|
|
667
|
+
next.push(c);
|
|
668
|
+
}
|
|
669
|
+
else if (child && typeof child === 'object') {
|
|
670
|
+
next.push(child);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
nodes = next;
|
|
674
|
+
}
|
|
675
|
+
return nodes;
|
|
676
|
+
}
|
|
677
|
+
/** For embedded-array access paths: emit the nested records directly from the door payload. */
|
|
678
|
+
ExtractEmbedded(doorRows, segments) {
|
|
679
|
+
return this.WalkSegments(doorRows, segments);
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Injects a parent id into an entry path: as a query param (?<parentParamName>=) when
|
|
683
|
+
* parentParamIn='query' (the roundId-gated endpoints, which 400 without it), otherwise into the
|
|
684
|
+
* {parentParamName} path template. Returns null when a path template var is present but unset
|
|
685
|
+
* (so an alternativePath that uses a different var is skipped, not mis-substituted).
|
|
686
|
+
*/
|
|
687
|
+
InjectParentID(entryPath, parentID, accessPath) {
|
|
688
|
+
const paramName = accessPath.parentParamName;
|
|
689
|
+
const encoded = encodeURIComponent(parentID);
|
|
690
|
+
if (accessPath.parentParamIn === 'query' && paramName) {
|
|
691
|
+
const sep = entryPath.includes('?') ? '&' : '?';
|
|
692
|
+
return `${entryPath}${sep}${paramName}=${encoded}`;
|
|
693
|
+
}
|
|
694
|
+
// Path-template injection. Substitute the declared parent param if its placeholder is present.
|
|
695
|
+
if (paramName && entryPath.includes(`{${paramName}}`)) {
|
|
696
|
+
return entryPath.replace(`{${paramName}}`, encoded);
|
|
697
|
+
}
|
|
698
|
+
// A single remaining template var (e.g. {roundId}/{programId} in an alternativePath) also
|
|
699
|
+
// takes the parent id; this keeps roundId-based alternative report paths working.
|
|
700
|
+
const m = entryPath.match(/\{(\w+)\}/);
|
|
701
|
+
if (m)
|
|
702
|
+
return entryPath.replace(m[0], encoded);
|
|
703
|
+
// No template var to fill and not a query param → use as-is (already-flat entry path).
|
|
704
|
+
return entryPath;
|
|
705
|
+
}
|
|
706
|
+
// ── Watermark + record helpers ───────────────────────────────────
|
|
707
|
+
/** Builds the incremental watermark query fragment (e.g. lastModifiedSinceUtc=2026-01-01T...). */
|
|
708
|
+
BuildWatermarkParam(obj, watermarkValue) {
|
|
709
|
+
if (!obj.SupportsIncrementalSync || !obj.IncrementalWatermarkField || !watermarkValue)
|
|
710
|
+
return '';
|
|
711
|
+
return `${obj.IncrementalWatermarkField}=${encodeURIComponent(watermarkValue)}`;
|
|
712
|
+
}
|
|
713
|
+
AppendQuery(path, query) {
|
|
714
|
+
if (!query)
|
|
715
|
+
return path;
|
|
716
|
+
const sep = path.includes('?') ? '&' : '?';
|
|
717
|
+
return `${path}${sep}${query}`;
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Builds an ExternalRecord. Fields carries the FULL source record (custom-column pass-through);
|
|
721
|
+
* runs the TransformRecord-preserving pipeline; resolves the ExternalID from the declared PK
|
|
722
|
+
* (composite-aware) with a content-hash fallback for partial/missing keys.
|
|
723
|
+
*/
|
|
724
|
+
BuildExternalRecord(raw, obj, fields, pkFieldNames) {
|
|
725
|
+
const transformed = this.applyTransformPreservingKeys(raw, obj, fields);
|
|
726
|
+
const allPkPresent = pkFieldNames.length > 0
|
|
727
|
+
&& pkFieldNames.every(name => transformed[name] != null && String(transformed[name]).length > 0);
|
|
728
|
+
const externalID = allPkPresent
|
|
729
|
+
? pkFieldNames.map(name => String(transformed[name])).join('|')
|
|
730
|
+
: this.ContentHash(transformed);
|
|
731
|
+
return { ExternalID: externalID, ObjectType: obj.Name, Fields: transformed };
|
|
732
|
+
}
|
|
733
|
+
PrimaryKeyNames(fields) {
|
|
734
|
+
const pk = fields.filter(f => f.IsPrimaryKey).sort((a, b) => a.Sequence - b.Sequence).map(f => f.Name);
|
|
735
|
+
return pk.length > 0 ? pk : ['id'];
|
|
736
|
+
}
|
|
737
|
+
/** Deterministic fallback identity for partial/missing keys (FNV-1a over the canonical JSON). */
|
|
738
|
+
ContentHash(record) {
|
|
739
|
+
const json = JSON.stringify(record, Object.keys(record).sort());
|
|
740
|
+
let hash = 0x811c9dc5;
|
|
741
|
+
for (let i = 0; i < json.length; i++) {
|
|
742
|
+
hash ^= json.charCodeAt(i);
|
|
743
|
+
hash = Math.imul(hash, 0x01000193);
|
|
744
|
+
}
|
|
745
|
+
return `hash:${(hash >>> 0).toString(16)}`;
|
|
746
|
+
}
|
|
747
|
+
// ── Default config ───────────────────────────────────────────────
|
|
748
|
+
GetDefaultConfiguration() {
|
|
749
|
+
return { DefaultSchemaName: 'OpenWater', DefaultObjects: [] };
|
|
750
|
+
}
|
|
751
|
+
// ─────────────────────────────────────────────────────────────────
|
|
752
|
+
// Private helpers
|
|
753
|
+
// ─────────────────────────────────────────────────────────────────
|
|
754
|
+
async GetAuth(companyIntegration, contextUser, forceRefresh = false) {
|
|
755
|
+
if (!forceRefresh && this.authState)
|
|
756
|
+
return this.authState;
|
|
757
|
+
const config = await this.ParseConfig(companyIntegration, contextUser);
|
|
758
|
+
const baseURL = this.StripTrailingSlash(config.BaseURL ?? '');
|
|
759
|
+
if (!baseURL) {
|
|
760
|
+
// OpenWater is tenant-specific (each customer is white-labeled on its own host, e.g.
|
|
761
|
+
// https://<org>.secure-platform.com). There is NO shared public API host — the legacy
|
|
762
|
+
// default api.getopenwater.com does NOT resolve (NXDOMAIN), so a silent fallback would
|
|
763
|
+
// fail every real connection at DNS. Require the per-tenant BaseURL and fail loudly here.
|
|
764
|
+
throw new Error('OpenWater requires a per-tenant BaseURL — your OpenWater API host, e.g. ' +
|
|
765
|
+
'https://<your-org>.secure-platform.com. There is no shared public default ' +
|
|
766
|
+
'(api.getopenwater.com does not resolve); set Configuration.BaseURL on the connection.');
|
|
767
|
+
}
|
|
768
|
+
this.authState = { Config: { ...config, BaseURL: baseURL }, BaseURL: baseURL };
|
|
769
|
+
return this.authState;
|
|
770
|
+
}
|
|
771
|
+
async ParseConfig(companyIntegration, contextUser) {
|
|
772
|
+
if (companyIntegration.CredentialID) {
|
|
773
|
+
const fromCred = await this.ParseConfigFromCredential(companyIntegration.CredentialID, contextUser);
|
|
774
|
+
if (fromCred)
|
|
775
|
+
return this.MergeConfigJson(fromCred, companyIntegration.Configuration);
|
|
776
|
+
}
|
|
777
|
+
if (companyIntegration.Configuration) {
|
|
778
|
+
const parsed = JSON.parse(companyIntegration.Configuration);
|
|
779
|
+
return this.ExtractConfig(parsed);
|
|
780
|
+
}
|
|
781
|
+
throw new Error('OpenWater connector requires either CredentialID or Configuration JSON');
|
|
782
|
+
}
|
|
783
|
+
async ParseConfigFromCredential(credentialID, contextUser, provider) {
|
|
784
|
+
const md = provider ?? new Metadata();
|
|
785
|
+
const credential = await md.GetEntityObject('MJ: Credentials', contextUser);
|
|
786
|
+
const loaded = await credential.Load(credentialID);
|
|
787
|
+
if (!loaded || !credential.Values)
|
|
788
|
+
return null;
|
|
789
|
+
const values = JSON.parse(credential.Values);
|
|
790
|
+
return this.ExtractConfig(values, true);
|
|
791
|
+
}
|
|
792
|
+
/** Overlay non-secret config (BaseURL / OrganizationCode) from the CompanyIntegration JSON onto a credential-derived config. */
|
|
793
|
+
MergeConfigJson(base, configJson) {
|
|
794
|
+
if (!configJson)
|
|
795
|
+
return base;
|
|
796
|
+
try {
|
|
797
|
+
const extra = this.ExtractConfig(JSON.parse(configJson), false, true);
|
|
798
|
+
return {
|
|
799
|
+
...base,
|
|
800
|
+
BaseURL: extra.BaseURL ?? base.BaseURL,
|
|
801
|
+
OrganizationCode: extra.OrganizationCode ?? base.OrganizationCode,
|
|
802
|
+
ClientKey: extra.ClientKey || base.ClientKey,
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
catch {
|
|
806
|
+
return base;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Resolves the connection config from a credential / configuration value bag. ClientKey + ApiKey
|
|
811
|
+
* are required unless `lenient` (used when overlaying optional config JSON onto a credential).
|
|
812
|
+
*/
|
|
813
|
+
ExtractConfig(values, requireApiKey = true, lenient = false) {
|
|
814
|
+
const get = (...keys) => {
|
|
815
|
+
for (const key of keys) {
|
|
816
|
+
const hit = Object.entries(values).find(([k]) => k.toLowerCase() === key.toLowerCase());
|
|
817
|
+
if (hit && hit[1] != null && String(hit[1]).length > 0)
|
|
818
|
+
return String(hit[1]);
|
|
819
|
+
}
|
|
820
|
+
return undefined;
|
|
821
|
+
};
|
|
822
|
+
const clientKey = get('ClientKey', 'clientKey', 'client_key', 'X-ClientKey');
|
|
823
|
+
const apiKey = get('ApiKey', 'apiKey', 'api_key', 'X-ApiKey');
|
|
824
|
+
const organizationCode = get('OrganizationCode', 'organizationCode', 'organization_code', 'X-OrganizationCode');
|
|
825
|
+
const baseURL = get('BaseURL', 'BaseUrl', 'base_url', 'endpoint');
|
|
826
|
+
if (!lenient) {
|
|
827
|
+
if (!clientKey)
|
|
828
|
+
throw new Error('OpenWater configuration missing required field: ClientKey');
|
|
829
|
+
if (requireApiKey && !apiKey)
|
|
830
|
+
throw new Error('OpenWater configuration missing required field: ApiKey');
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
ClientKey: clientKey ?? '',
|
|
834
|
+
ApiKey: apiKey ?? '',
|
|
835
|
+
OrganizationCode: organizationCode,
|
|
836
|
+
BaseURL: baseURL ? this.StripTrailingSlash(baseURL) : undefined,
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
// ── HTTP helpers ─────────────────────────────────────────────────
|
|
840
|
+
async ExecuteFetch(url, method, headers, body, timeoutMs) {
|
|
841
|
+
const controller = new AbortController();
|
|
842
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
843
|
+
try {
|
|
844
|
+
const requestInit = { method, headers, signal: controller.signal };
|
|
845
|
+
if (body !== undefined && method !== 'GET' && method !== 'DELETE') {
|
|
846
|
+
requestInit.body = JSON.stringify(body);
|
|
847
|
+
}
|
|
848
|
+
return await fetch(url, requestInit);
|
|
849
|
+
}
|
|
850
|
+
finally {
|
|
851
|
+
clearTimeout(timer);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
async BuildRESTResponse(response) {
|
|
855
|
+
const headers = {};
|
|
856
|
+
response.headers.forEach((v, k) => { headers[k.toLowerCase()] = v; });
|
|
857
|
+
const contentType = headers['content-type'] ?? '';
|
|
858
|
+
const body = contentType.includes('application/json')
|
|
859
|
+
? await this.ParseJsonSafely(response)
|
|
860
|
+
: await response.text();
|
|
861
|
+
return { Status: response.status, Body: body, Headers: headers };
|
|
862
|
+
}
|
|
863
|
+
async ParseJsonSafely(response) {
|
|
864
|
+
try {
|
|
865
|
+
return await response.json();
|
|
866
|
+
}
|
|
867
|
+
catch {
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
ShouldRetry(status) {
|
|
872
|
+
return status === 429 || status === 502 || status === 503 || status === 504;
|
|
873
|
+
}
|
|
874
|
+
ComputeRetryDelay(response, attempt) {
|
|
875
|
+
const retryAfter = response.headers.get('retry-after');
|
|
876
|
+
if (retryAfter) {
|
|
877
|
+
const seconds = Number.parseInt(retryAfter, 10);
|
|
878
|
+
if (!Number.isNaN(seconds) && seconds > 0)
|
|
879
|
+
return seconds * 1000;
|
|
880
|
+
}
|
|
881
|
+
return Math.min(Math.pow(2, attempt) * 1000, 15_000);
|
|
882
|
+
}
|
|
883
|
+
/** Wraps an error message with the response Status + Headers so ExtractRetryAfterMs can read them. */
|
|
884
|
+
HttpError(message, response) {
|
|
885
|
+
const err = new Error(message);
|
|
886
|
+
err.Status = response.Status;
|
|
887
|
+
err.Headers = response.Headers;
|
|
888
|
+
return err;
|
|
889
|
+
}
|
|
890
|
+
Sleep(ms) {
|
|
891
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
892
|
+
}
|
|
893
|
+
StripTrailingSlash(url) {
|
|
894
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
OpenWaterConnector = __decorate([
|
|
898
|
+
RegisterClass(BaseIntegrationConnector, '@memberjunction/connector-openwater')
|
|
899
|
+
], OpenWaterConnector);
|
|
900
|
+
export { OpenWaterConnector };
|
|
901
|
+
/** Tree-shaking prevention — import and call from the module entry point. */
|
|
902
|
+
export function LoadOpenWaterConnector() { }
|
|
903
|
+
//# sourceMappingURL=OpenWaterConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenWaterConnector.js","sourceRoot":"","sources":["../src/OpenWaterConnector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * from './OpenWaterConnector.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 './OpenWaterConnector.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,yBAAyB,CAAC;AAExC;oGACoG;AACpG,MAAM,UAAU,iBAAiB,KAAiD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memberjunction/connector-openwater",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MemberJunction OpenWater connector.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"/dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc && tsc-alias -f",
|
|
13
|
+
"test": "vitest run --passWithNoTests"
|
|
14
|
+
},
|
|
15
|
+
"author": "MemberJunction.com",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@memberjunction/core": ">=5.42.0 <6.0.0",
|
|
19
|
+
"@memberjunction/core-entities": ">=5.42.0 <6.0.0",
|
|
20
|
+
"@memberjunction/global": ">=5.42.0 <6.0.0",
|
|
21
|
+
"@memberjunction/integration-engine": ">=5.42.0 <6.0.0"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "24.10.11",
|
|
26
|
+
"tsc-alias": "^1.8.16",
|
|
27
|
+
"typescript": "^5.9.3",
|
|
28
|
+
"vitest": "^4.0.18",
|
|
29
|
+
"@memberjunction/core": "^5.42.0",
|
|
30
|
+
"@memberjunction/core-entities": "^5.42.0",
|
|
31
|
+
"@memberjunction/global": "^5.42.0",
|
|
32
|
+
"@memberjunction/integration-engine": "^5.42.0"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/MemberJunction/Integrations"
|
|
37
|
+
}
|
|
38
|
+
}
|