@memberjunction/connector-wild-apricot 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,190 @@
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 FetchContext, type FetchBatchResult, type RateLimitPolicy, type SourceSchemaInfo } from '@memberjunction/integration-engine';
4
+ /**
5
+ * Wild Apricot membership-management connector (Admin API v2.3).
6
+ *
7
+ * ── AUTH ──────────────────────────────────────────────────────────────────
8
+ * OAuth 2.0 `client_credentials`. The admin API Key is sent as the HTTP-Basic
9
+ * USERNAME (empty password) on `POST https://oauth.wildapricot.org/auth/token`
10
+ * with `grant_type=client_credentials&scope=auto`. Both the Basic token-endpoint
11
+ * header AND the resulting `Authorization: Bearer <access_token>` header are built
12
+ * via the shared auth-helpers ({@link OAuth2TokenManager} with `UseBasicAuth:true`)
13
+ * — no inline base64/crypto lives in this connector. The access token is cached +
14
+ * auto-refreshed by the manager; the `client_credentials` grant returns no refresh
15
+ * token, so expiry re-mints via the same API key (per Configuration.TokenRefreshStrategy).
16
+ *
17
+ * ── TENANT ANCHOR (accountId) ───────────────────────────────────────────────
18
+ * Every data path is `/accounts/{accountId}/…`. The accountId is a per-tenant anchor,
19
+ * NOT a synced parent record: {@link TestConnection} / {@link Authenticate} resolve it
20
+ * by issuing `GET /v2.3/accounts` (no id in path) and taking the first account's Id when
21
+ * the credential omits AccountId (Configuration.accountIdDiscovery). It is cached on the
22
+ * auth context and substituted into `{accountId}` in {@link MakeHTTPRequest}. It is
23
+ * per-tenant config — NEVER hardcoded.
24
+ *
25
+ * ── DISCOVERY (mechanism only — NO baked catalog) ───────────────────────────
26
+ * Wild Apricot's object/field universe is credential-free-documented (public OpenAPI
27
+ * 9.14.0), so it is seeded as Declared metadata in the integration file. This connector
28
+ * therefore carries NO `WILD_APRICOT_OBJECTS` catalog constant (the deprecated
29
+ * connector's anti-pattern): {@link DiscoverObjects}/{@link DiscoverFields} inherit the
30
+ * base cache-driven implementation that reads the Declared metadata. That is the
31
+ * sanctioned "case-1 → Declared metadata" mechanism.
32
+ *
33
+ * ── CRUD ────────────────────────────────────────────────────────────────────
34
+ * Generic per-operation CRUD from {@link BaseRESTIntegrationConnector} (reads
35
+ * Create/Update/Delete APIPath/Method/BodyShape/IDLocation off each IO row) is used
36
+ * as-is; create fails LOUDLY on an empty response ID via `BuildCreatedResult`. No CRUD
37
+ * verb is re-implemented here.
38
+ *
39
+ * ── PAGINATION ──────────────────────────────────────────────────────────────
40
+ * Offset pagination via Wild Apricot's `$top`/`$skip` params (NOT the base's
41
+ * `limit`/`offset`), clamped to a 100-item max page per spec — {@link BuildPaginatedURL}
42
+ * + {@link ExtractPaginationInfo} are overridden for the vendor param names.
43
+ *
44
+ * ── THE ONE IDIOSYNCRATIC OVERRIDE: async Contacts list ─────────────────────
45
+ * `GET /accounts/{accountId}/contacts` defaults to ASYNC: it returns a `ResultId`
46
+ * that must be polled (`?resultId=<ResultId>`) until `State=Complete`, then the same
47
+ * URL returns the `Contacts` array. {@link FetchChanges} overrides ONLY the `Contact`
48
+ * object to run that request→poll→collect flow (bounded poll timeout); every other
49
+ * object delegates to the base flat/nested paginated fetch. See {@link FetchContacts}.
50
+ */
51
+ export declare class WildApricotConnector extends BaseRESTIntegrationConnector {
52
+ /** Cached OAuth2 token manager (one per connector instance; the manager caches + refreshes the token). */
53
+ private tokenManager;
54
+ /** Cached tenant anchor accountId, resolved once per instance (per-tenant, never hardcoded). */
55
+ private cachedAccountId;
56
+ /** Verbatim three-way invariant name: IntegrationName getter === MJ: Integrations.Name. */
57
+ get IntegrationName(): string;
58
+ /**
59
+ * IntrospectSchema — pure WIRING of MJ's existing sampler into the declared catalog (the connector
60
+ * sample-union standard; see CONNECTOR_DISCOVERY_STANDARD.md). This connector adds NO discovery,
61
+ * merge, or sync logic — it only wires `DiscoverFieldsViaFetch` (MJ's sampler) into IntrospectSchema.
62
+ *
63
+ * `super.IntrospectSchema` yields the cache-driven Declared catalog (no measured widths). For each
64
+ * object we then call MJ's `DiscoverFieldsViaFetch` — MJ's own read-path sampler that measures real
65
+ * field widths and surfaces custom columns — and the shared PURE `mergeDeclaredWithSampledFields`
66
+ * unions the two by field name (adopt MJ's measured width; append MJ-discovered custom columns). MJ
67
+ * owns everything else (measurement, type/PK inference, persistence, reconcile, sync).
68
+ *
69
+ * Recursion note: `DiscoverFieldsViaFetch` falls back to the UNCHANGED `DiscoverFields` (cache-driven)
70
+ * when the read path can't run — never back into THIS method — so there is no infinite recursion.
71
+ * This connector does NOT override `DiscoverFields` to call any ViaFetch/ViaStream.
72
+ *
73
+ * Robustness: objects are sampled IN PARALLEL under a small bounded pool; any per-object failure
74
+ * keeps that object's declared fields, so a single bad sample never breaks introspection.
75
+ */
76
+ IntrospectSchema(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<SourceSchemaInfo>;
77
+ get SupportsCreate(): boolean;
78
+ get SupportsUpdate(): boolean;
79
+ get SupportsDelete(): boolean;
80
+ /**
81
+ * Documented rate-limit policy (Configuration.RateLimitDetail). The general ceiling is
82
+ * 400 requests/min (≈6.67/s) for "other request types"; the two Contacts-specific
83
+ * ceilings (list=40/min, by-id=120/min) are lower, so the engine's AIMD bucket starts
84
+ * from the CONSERVATIVE general rate and backs off further on a 429 (honored via
85
+ * ExtractRetryAfterMs). Burst kept modest to respect the per-minute windows.
86
+ */
87
+ get RateLimitPolicy(): RateLimitPolicy | null;
88
+ /** Parses Wild Apricot's 429 Retry-After (seconds) into ms so the AIMD bucket waits the full window. */
89
+ ExtractRetryAfterMs(error: unknown): number | undefined;
90
+ /**
91
+ * Mints/refreshes the bearer token via the shared OAuth2 manager, then resolves the
92
+ * tenant accountId (from the credential config, else auto-discovered via GET /accounts).
93
+ * Returns the bearer token + accountId on the auth context.
94
+ */
95
+ protected Authenticate(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<WildApricotAuthContext>;
96
+ /** Bearer header for API calls, built from the manager-minted token. No inline crypto. */
97
+ protected BuildHeaders(auth: WildApricotAuthContext): Record<string, string>;
98
+ /** Base URL: host + versioned path segment (e.g. https://api.wildapricot.org/v2.3). */
99
+ protected GetBaseURL(_companyIntegration: MJCompanyIntegrationEntity, auth: WildApricotAuthContext): string;
100
+ /**
101
+ * Executes an HTTP request via fetch. Substitutes the resolved `{accountId}` tenant anchor
102
+ * into the URL (the base leaves it as a template var; here it becomes the concrete tenant id)
103
+ * and parses JSON responses. The concrete connector owns the transport seam so tests override it.
104
+ */
105
+ protected MakeHTTPRequest(auth: WildApricotAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
106
+ /**
107
+ * Extracts the record array from a Wild Apricot response. ResponseDataKey is null in the
108
+ * Declared metadata because the wrapper key varies by endpoint (e.g. `Contacts`, `Events`,
109
+ * `Invoices`) and some endpoints return a bare array. So: honor an explicit key when set,
110
+ * else return a root-level array, else unwrap the first array-valued property of an object,
111
+ * else wrap a single object. This handles both wrapped-collection and bare-array shapes.
112
+ */
113
+ protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
114
+ /**
115
+ * Wild Apricot uses OData-style `$top`/`$skip` Offset pagination (NOT the base's `limit`/`offset`).
116
+ * `$top` is clamped to 100 per spec ("more than 100 → maximum 100 items returned"). Overridden
117
+ * here so the vendor param names + the 100 clamp are honored.
118
+ */
119
+ protected BuildPaginatedURL(basePath: string, obj: MJIntegrationObjectEntity, _page: number, offset: number, _cursor?: string, effectivePageSize?: number): string;
120
+ /**
121
+ * Offset pagination termination: Wild Apricot list endpoints return fewer than `$top` items on
122
+ * the final page (and none past the end). More pages remain only when a FULL page came back.
123
+ */
124
+ protected ExtractPaginationInfo(rawBody: unknown, _paginationType: PaginationType, _currentPage: number, currentOffset: number, pageSize: number): PaginationState;
125
+ /**
126
+ * Tests connectivity by minting a token and listing accounts (GET /accounts). When the credential
127
+ * omits AccountId, the first account's Id is adopted as the tenant anchor (Configuration.accountIdDiscovery).
128
+ */
129
+ TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
130
+ /**
131
+ * Fetches records. Only the `Contact` object is idiosyncratic — its list endpoint is ASYNC:
132
+ * the request returns a `ResultId` which must be polled until `State=Complete`. All other
133
+ * objects use the generic base flat/nested paginated fetch unchanged.
134
+ */
135
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
136
+ /**
137
+ * Contacts async list flow (the single documented idiosyncrasy):
138
+ * 1. GET /accounts/{accountId}/contacts?$async=true&$skip&$top → 200/202 with a ResultId.
139
+ * 2. Poll GET /accounts/{accountId}/contacts?resultId=<ResultId> until State='Complete'
140
+ * (or the poll budget below is exhausted), then read the Contacts array.
141
+ * Incremental narrowing: when a watermark is present it is applied as a `$filter` on the
142
+ * documented cursor field (ProfileLastUpdated). Bounded by POLL_MAX_ATTEMPTS × POLL_INTERVAL_MS
143
+ * so a stuck async job can never hang the sync. Watermark persists on full-page success only.
144
+ */
145
+ private FetchContacts;
146
+ /**
147
+ * Resolves the async Contacts response: if a ResultId is present, polls the same endpoint with
148
+ * `?resultId=<id>` until State='Complete' (bounded), then returns the Contacts array. If the
149
+ * initial response already carried the Contacts array synchronously, returns it directly.
150
+ */
151
+ private ResolveAsyncContacts;
152
+ /** Substitutes the resolved `{accountId}` tenant anchor into a URL (case-insensitive on the var name). */
153
+ private SubstituteAccountId;
154
+ /**
155
+ * Resolves the tenant accountId: prefers the credential-configured value, else issues
156
+ * GET /accounts and adopts the first account's Id. Cached per instance. NEVER hardcoded.
157
+ */
158
+ private ResolveAccountId;
159
+ /** Finds the first array-valued property of an object (a wrapped collection under a vendor key). */
160
+ private FindArrayInObject;
161
+ /** Reads the async-result State ('Complete'/'Processing'/'Failed'/…) from a poll body, tolerant of shape. */
162
+ private ReadState;
163
+ /** Builds a Contact record identity from its declared PK (falls back to a common id key, then a content hash). */
164
+ private BuildContactIdentity;
165
+ /** Max watermark value across a record batch (ISO8601 string comparison), never below the current one. */
166
+ private MaxWatermark;
167
+ /** Throws a descriptive error on a non-2xx contacts response (202 Accepted is treated as OK for the async kick-off). */
168
+ private AssertContactsOK;
169
+ /** Reads headers off an error-like object (for Retry-After parsing). */
170
+ private ExtractErrorHeaders;
171
+ /** Whether an error indicates a 429 rate-limit. */
172
+ private IsRateLimitError;
173
+ /**
174
+ * Resolves the API key + tenant config from the linked Credential entity, falling back to the
175
+ * CompanyIntegration.Configuration / APIKey. The credential bytes never leave this scope.
176
+ */
177
+ private LoadCredentials;
178
+ /** Loads credential fields from a Credential entity's Values JSON. */
179
+ private LoadFromCredentialEntity;
180
+ /** Parses a JSON string into credential/config fields (tolerant of casing/aliases). */
181
+ private ParseConfigJson;
182
+ }
183
+ /** Auth context: resolved bearer token + tenant accountId + non-secret host/version overrides. */
184
+ interface WildApricotAuthContext extends RESTAuthContext {
185
+ Token: string;
186
+ AccountId: string;
187
+ BaseHost?: string;
188
+ ApiVersion?: string;
189
+ }
190
+ export {};
@@ -0,0 +1,620 @@
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 { BaseIntegrationConnector, BaseRESTIntegrationConnector, OAuth2TokenManager, } from '@memberjunction/integration-engine';
10
+ import { mergeDeclaredWithSampledFields } from '@memberjunction/connector-schema-merge';
11
+ import { z } from 'zod';
12
+ /**
13
+ * Wild Apricot membership-management connector (Admin API v2.3).
14
+ *
15
+ * ── AUTH ──────────────────────────────────────────────────────────────────
16
+ * OAuth 2.0 `client_credentials`. The admin API Key is sent as the HTTP-Basic
17
+ * USERNAME (empty password) on `POST https://oauth.wildapricot.org/auth/token`
18
+ * with `grant_type=client_credentials&scope=auto`. Both the Basic token-endpoint
19
+ * header AND the resulting `Authorization: Bearer <access_token>` header are built
20
+ * via the shared auth-helpers ({@link OAuth2TokenManager} with `UseBasicAuth:true`)
21
+ * — no inline base64/crypto lives in this connector. The access token is cached +
22
+ * auto-refreshed by the manager; the `client_credentials` grant returns no refresh
23
+ * token, so expiry re-mints via the same API key (per Configuration.TokenRefreshStrategy).
24
+ *
25
+ * ── TENANT ANCHOR (accountId) ───────────────────────────────────────────────
26
+ * Every data path is `/accounts/{accountId}/…`. The accountId is a per-tenant anchor,
27
+ * NOT a synced parent record: {@link TestConnection} / {@link Authenticate} resolve it
28
+ * by issuing `GET /v2.3/accounts` (no id in path) and taking the first account's Id when
29
+ * the credential omits AccountId (Configuration.accountIdDiscovery). It is cached on the
30
+ * auth context and substituted into `{accountId}` in {@link MakeHTTPRequest}. It is
31
+ * per-tenant config — NEVER hardcoded.
32
+ *
33
+ * ── DISCOVERY (mechanism only — NO baked catalog) ───────────────────────────
34
+ * Wild Apricot's object/field universe is credential-free-documented (public OpenAPI
35
+ * 9.14.0), so it is seeded as Declared metadata in the integration file. This connector
36
+ * therefore carries NO `WILD_APRICOT_OBJECTS` catalog constant (the deprecated
37
+ * connector's anti-pattern): {@link DiscoverObjects}/{@link DiscoverFields} inherit the
38
+ * base cache-driven implementation that reads the Declared metadata. That is the
39
+ * sanctioned "case-1 → Declared metadata" mechanism.
40
+ *
41
+ * ── CRUD ────────────────────────────────────────────────────────────────────
42
+ * Generic per-operation CRUD from {@link BaseRESTIntegrationConnector} (reads
43
+ * Create/Update/Delete APIPath/Method/BodyShape/IDLocation off each IO row) is used
44
+ * as-is; create fails LOUDLY on an empty response ID via `BuildCreatedResult`. No CRUD
45
+ * verb is re-implemented here.
46
+ *
47
+ * ── PAGINATION ──────────────────────────────────────────────────────────────
48
+ * Offset pagination via Wild Apricot's `$top`/`$skip` params (NOT the base's
49
+ * `limit`/`offset`), clamped to a 100-item max page per spec — {@link BuildPaginatedURL}
50
+ * + {@link ExtractPaginationInfo} are overridden for the vendor param names.
51
+ *
52
+ * ── THE ONE IDIOSYNCRATIC OVERRIDE: async Contacts list ─────────────────────
53
+ * `GET /accounts/{accountId}/contacts` defaults to ASYNC: it returns a `ResultId`
54
+ * that must be polled (`?resultId=<ResultId>`) until `State=Complete`, then the same
55
+ * URL returns the `Contacts` array. {@link FetchChanges} overrides ONLY the `Contact`
56
+ * object to run that request→poll→collect flow (bounded poll timeout); every other
57
+ * object delegates to the base flat/nested paginated fetch. See {@link FetchContacts}.
58
+ */
59
+ let WildApricotConnector = class WildApricotConnector extends BaseRESTIntegrationConnector {
60
+ constructor() {
61
+ super(...arguments);
62
+ /** Cached OAuth2 token manager (one per connector instance; the manager caches + refreshes the token). */
63
+ this.tokenManager = new OAuth2TokenManager();
64
+ /** Cached tenant anchor accountId, resolved once per instance (per-tenant, never hardcoded). */
65
+ this.cachedAccountId = null;
66
+ }
67
+ /** Verbatim three-way invariant name: IntegrationName getter === MJ: Integrations.Name. */
68
+ get IntegrationName() {
69
+ return 'Wild Apricot';
70
+ }
71
+ /**
72
+ * IntrospectSchema — pure WIRING of MJ's existing sampler into the declared catalog (the connector
73
+ * sample-union standard; see CONNECTOR_DISCOVERY_STANDARD.md). This connector adds NO discovery,
74
+ * merge, or sync logic — it only wires `DiscoverFieldsViaFetch` (MJ's sampler) into IntrospectSchema.
75
+ *
76
+ * `super.IntrospectSchema` yields the cache-driven Declared catalog (no measured widths). For each
77
+ * object we then call MJ's `DiscoverFieldsViaFetch` — MJ's own read-path sampler that measures real
78
+ * field widths and surfaces custom columns — and the shared PURE `mergeDeclaredWithSampledFields`
79
+ * unions the two by field name (adopt MJ's measured width; append MJ-discovered custom columns). MJ
80
+ * owns everything else (measurement, type/PK inference, persistence, reconcile, sync).
81
+ *
82
+ * Recursion note: `DiscoverFieldsViaFetch` falls back to the UNCHANGED `DiscoverFields` (cache-driven)
83
+ * when the read path can't run — never back into THIS method — so there is no infinite recursion.
84
+ * This connector does NOT override `DiscoverFields` to call any ViaFetch/ViaStream.
85
+ *
86
+ * Robustness: objects are sampled IN PARALLEL under a small bounded pool; any per-object failure
87
+ * keeps that object's declared fields, so a single bad sample never breaks introspection.
88
+ */
89
+ async IntrospectSchema(companyIntegration, contextUser) {
90
+ const schema = await super.IntrospectSchema(companyIntegration, contextUser);
91
+ await runBounded(schema.Objects, 8, async (obj) => {
92
+ try {
93
+ const sampled = await this.DiscoverFieldsViaFetch(companyIntegration, obj.ExternalName, contextUser);
94
+ obj.Fields = mergeDeclaredWithSampledFields(obj.Fields, sampled);
95
+ }
96
+ catch {
97
+ // Keep this object's declared fields — sampling is best-effort and never breaks introspection.
98
+ }
99
+ });
100
+ return schema;
101
+ }
102
+ // ─── Capability surface ──────────────────────────────────────────────────
103
+ // Wild Apricot supports create/update/delete on many objects; the ACTUAL per-verb
104
+ // support is metadata-driven (each IO's Create/Update/Delete columns), and the base's
105
+ // generic CRUD throws for any verb whose columns are null. These getters declare the
106
+ // connector is capable so the engine offers the write surface.
107
+ get SupportsCreate() { return true; }
108
+ get SupportsUpdate() { return true; }
109
+ get SupportsDelete() { return true; }
110
+ /**
111
+ * Documented rate-limit policy (Configuration.RateLimitDetail). The general ceiling is
112
+ * 400 requests/min (≈6.67/s) for "other request types"; the two Contacts-specific
113
+ * ceilings (list=40/min, by-id=120/min) are lower, so the engine's AIMD bucket starts
114
+ * from the CONSERVATIVE general rate and backs off further on a 429 (honored via
115
+ * ExtractRetryAfterMs). Burst kept modest to respect the per-minute windows.
116
+ */
117
+ get RateLimitPolicy() {
118
+ return { TokensPerSec: 6, Burst: 6, ThrottleBackoffFactor: 0.5 };
119
+ }
120
+ /** Parses Wild Apricot's 429 Retry-After (seconds) into ms so the AIMD bucket waits the full window. */
121
+ ExtractRetryAfterMs(error) {
122
+ // Wild Apricot returns HTTP 429 "wait for a minute"; when a Retry-After header is present we honor it.
123
+ const headers = this.ExtractErrorHeaders(error);
124
+ const retryAfter = headers?.['retry-after'];
125
+ if (retryAfter) {
126
+ const secs = Number(retryAfter);
127
+ if (Number.isFinite(secs) && secs >= 0)
128
+ return Math.round(secs * 1000);
129
+ }
130
+ // No header → the documented guidance is "wait for a minute" on a 429.
131
+ if (this.IsRateLimitError(error))
132
+ return 60_000;
133
+ return undefined;
134
+ }
135
+ // ─── Auth + transport (BaseRESTIntegrationConnector abstracts) ────────────
136
+ /**
137
+ * Mints/refreshes the bearer token via the shared OAuth2 manager, then resolves the
138
+ * tenant accountId (from the credential config, else auto-discovered via GET /accounts).
139
+ * Returns the bearer token + accountId on the auth context.
140
+ */
141
+ async Authenticate(companyIntegration, contextUser) {
142
+ const creds = await this.LoadCredentials(companyIntegration, contextUser);
143
+ const token = await this.tokenManager.GetAccessToken({
144
+ TokenURL: creds.TokenUrl,
145
+ ClientId: creds.ApiKey, // API key is the Basic-auth USERNAME …
146
+ ClientSecret: '', // … with an EMPTY password.
147
+ Scopes: 'auto',
148
+ UseBasicAuth: true, // → Authorization: Basic base64(apiKey:) — built by the helper, no inline crypto.
149
+ }, 'client_credentials');
150
+ const accountId = await this.ResolveAccountId(creds, token.AccessToken);
151
+ return {
152
+ Token: token.AccessToken,
153
+ AccountId: accountId,
154
+ BaseHost: creds.BaseHost,
155
+ ApiVersion: creds.ApiVersion,
156
+ };
157
+ }
158
+ /** Bearer header for API calls, built from the manager-minted token. No inline crypto. */
159
+ BuildHeaders(auth) {
160
+ return {
161
+ 'Authorization': `Bearer ${auth.Token}`,
162
+ 'Accept': 'application/json',
163
+ };
164
+ }
165
+ /** Base URL: host + versioned path segment (e.g. https://api.wildapricot.org/v2.3). */
166
+ GetBaseURL(_companyIntegration, auth) {
167
+ const host = auth.BaseHost ?? WILDAPRICOT_API_HOST;
168
+ const version = auth.ApiVersion ?? DEFAULT_API_VERSION;
169
+ return `${host.replace(/\/+$/, '')}/${version}`;
170
+ }
171
+ /**
172
+ * Executes an HTTP request via fetch. Substitutes the resolved `{accountId}` tenant anchor
173
+ * into the URL (the base leaves it as a template var; here it becomes the concrete tenant id)
174
+ * and parses JSON responses. The concrete connector owns the transport seam so tests override it.
175
+ */
176
+ async MakeHTTPRequest(auth, url, method, headers, body) {
177
+ const resolvedUrl = this.SubstituteAccountId(url, auth.AccountId);
178
+ const init = { method, headers };
179
+ if (body !== undefined && method !== 'GET' && method !== 'HEAD') {
180
+ init.body = typeof body === 'string' ? body : JSON.stringify(body);
181
+ init.headers['Content-Type'] = 'application/json';
182
+ }
183
+ const response = await fetch(resolvedUrl, init);
184
+ const responseHeaders = {};
185
+ response.headers.forEach((value, key) => { responseHeaders[key.toLowerCase()] = value; });
186
+ const text = await response.text();
187
+ let parsed = text;
188
+ const contentType = responseHeaders['content-type'] ?? '';
189
+ if (contentType.includes('json') || (text.length > 0 && (text[0] === '{' || text[0] === '['))) {
190
+ try {
191
+ parsed = JSON.parse(text);
192
+ }
193
+ catch {
194
+ parsed = text;
195
+ }
196
+ }
197
+ return { Status: response.status, Body: parsed, Headers: responseHeaders };
198
+ }
199
+ /**
200
+ * Extracts the record array from a Wild Apricot response. ResponseDataKey is null in the
201
+ * Declared metadata because the wrapper key varies by endpoint (e.g. `Contacts`, `Events`,
202
+ * `Invoices`) and some endpoints return a bare array. So: honor an explicit key when set,
203
+ * else return a root-level array, else unwrap the first array-valued property of an object,
204
+ * else wrap a single object. This handles both wrapped-collection and bare-array shapes.
205
+ */
206
+ NormalizeResponse(rawBody, responseDataKey) {
207
+ if (responseDataKey && isRecord(rawBody)) {
208
+ const inner = rawBody[responseDataKey];
209
+ if (Array.isArray(inner))
210
+ return inner.filter(isRecord);
211
+ }
212
+ if (Array.isArray(rawBody))
213
+ return rawBody.filter(isRecord);
214
+ if (isRecord(rawBody)) {
215
+ const arr = this.FindArrayInObject(rawBody);
216
+ if (arr.length > 0)
217
+ return arr.filter(isRecord);
218
+ return [rawBody];
219
+ }
220
+ return [];
221
+ }
222
+ /**
223
+ * Wild Apricot uses OData-style `$top`/`$skip` Offset pagination (NOT the base's `limit`/`offset`).
224
+ * `$top` is clamped to 100 per spec ("more than 100 → maximum 100 items returned"). Overridden
225
+ * here so the vendor param names + the 100 clamp are honored.
226
+ */
227
+ BuildPaginatedURL(basePath, obj, _page, offset, _cursor, effectivePageSize) {
228
+ const pageSize = Math.min(effectivePageSize ?? obj.DefaultPageSize ?? WILDAPRICOT_MAX_PAGE_SIZE, WILDAPRICOT_MAX_PAGE_SIZE);
229
+ const separator = basePath.includes('?') ? '&' : '?';
230
+ return `${basePath}${separator}$skip=${offset}&$top=${pageSize}`;
231
+ }
232
+ /**
233
+ * Offset pagination termination: Wild Apricot list endpoints return fewer than `$top` items on
234
+ * the final page (and none past the end). More pages remain only when a FULL page came back.
235
+ */
236
+ ExtractPaginationInfo(rawBody, _paginationType, _currentPage, currentOffset, pageSize) {
237
+ const records = this.NormalizeResponse(rawBody, null);
238
+ const count = records.length;
239
+ const hasMore = pageSize > 0 && count >= pageSize;
240
+ return {
241
+ HasMore: hasMore,
242
+ NextOffset: currentOffset + count,
243
+ };
244
+ }
245
+ // ─── TestConnection (auto-discovers the accountId) ────────────────────────
246
+ /**
247
+ * Tests connectivity by minting a token and listing accounts (GET /accounts). When the credential
248
+ * omits AccountId, the first account's Id is adopted as the tenant anchor (Configuration.accountIdDiscovery).
249
+ */
250
+ async TestConnection(companyIntegration, contextUser) {
251
+ try {
252
+ const auth = await this.Authenticate(companyIntegration, contextUser);
253
+ const url = `${this.GetBaseURL(companyIntegration, auth)}/accounts`;
254
+ const response = await this.MakeHTTPRequest(auth, url, 'GET', this.BuildHeaders(auth));
255
+ if (response.Status === 401 || response.Status === 403) {
256
+ return { Success: false, Message: `Wild Apricot authentication failed (HTTP ${response.Status}) — check the API key.` };
257
+ }
258
+ if (response.Status < 200 || response.Status >= 300) {
259
+ return { Success: false, Message: `Wild Apricot /accounts returned HTTP ${response.Status}.` };
260
+ }
261
+ const accounts = this.NormalizeResponse(response.Body, null);
262
+ return {
263
+ Success: true,
264
+ Message: `Connected to Wild Apricot account ${auth.AccountId}; ${accounts.length} account(s) accessible to this API key.`,
265
+ };
266
+ }
267
+ catch (err) {
268
+ const message = err instanceof Error ? err.message : String(err);
269
+ return { Success: false, Message: `Wild Apricot connection error: ${message}` };
270
+ }
271
+ }
272
+ // ─── THE idiosyncratic override: async Contacts list ──────────────────────
273
+ /**
274
+ * Fetches records. Only the `Contact` object is idiosyncratic — its list endpoint is ASYNC:
275
+ * the request returns a `ResultId` which must be polled until `State=Complete`. All other
276
+ * objects use the generic base flat/nested paginated fetch unchanged.
277
+ */
278
+ async FetchChanges(ctx) {
279
+ if (ctx.ObjectName === CONTACT_OBJECT_NAME) {
280
+ return this.FetchContacts(ctx);
281
+ }
282
+ return super.FetchChanges(ctx);
283
+ }
284
+ /**
285
+ * Contacts async list flow (the single documented idiosyncrasy):
286
+ * 1. GET /accounts/{accountId}/contacts?$async=true&$skip&$top → 200/202 with a ResultId.
287
+ * 2. Poll GET /accounts/{accountId}/contacts?resultId=<ResultId> until State='Complete'
288
+ * (or the poll budget below is exhausted), then read the Contacts array.
289
+ * Incremental narrowing: when a watermark is present it is applied as a `$filter` on the
290
+ * documented cursor field (ProfileLastUpdated). Bounded by POLL_MAX_ATTEMPTS × POLL_INTERVAL_MS
291
+ * so a stuck async job can never hang the sync. Watermark persists on full-page success only.
292
+ */
293
+ async FetchContacts(ctx) {
294
+ const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
295
+ const obj = this.GetCachedObject(ctx.CompanyIntegration.IntegrationID, ctx.ObjectName);
296
+ const fields = this.GetCachedFields(obj.ID);
297
+ const pkFieldNames = fields.filter(f => f.IsPrimaryKey).map(f => f.Name);
298
+ const effectivePk = pkFieldNames.length > 0 ? pkFieldNames : ['Id'];
299
+ const offset = ctx.CurrentOffset ?? 0;
300
+ const pageSize = Math.min(ctx.BatchSize && ctx.BatchSize > 0 ? ctx.BatchSize : WILDAPRICOT_MAX_PAGE_SIZE, WILDAPRICOT_MAX_PAGE_SIZE);
301
+ const base = `${this.GetBaseURL(ctx.CompanyIntegration, auth)}${obj.APIPath}`;
302
+ // Build the OData query string with LITERAL $-prefixed param names (not URLSearchParams, which
303
+ // percent-encodes `$` → `%24`), keeping it consistent with BuildPaginatedURL's $skip/$top.
304
+ const queryParts = [`$async=true`, `$skip=${offset}`, `$top=${pageSize}`];
305
+ if (ctx.WatermarkValue && obj.IncrementalWatermarkField) {
306
+ // Documented incremental strategy: $filter on ProfileLastUpdated (ISO8601 comparison).
307
+ queryParts.push(`$filter=${encodeURIComponent(`${obj.IncrementalWatermarkField} ge ${ctx.WatermarkValue}`)}`);
308
+ }
309
+ const requestUrl = `${base}?${queryParts.join('&')}`;
310
+ // Step 1: kick off the async query.
311
+ const start = await this.MakeHTTPRequest(auth, requestUrl, 'GET', this.BuildHeaders(auth));
312
+ this.AssertContactsOK(start, 'start async contacts query');
313
+ const records = await this.ResolveAsyncContacts(auth, base, start.Body);
314
+ // Step 2: emit with FULL-RECORD pass-through (Fields = raw source record).
315
+ const out = records.map(raw => ({
316
+ ExternalID: this.BuildContactIdentity(raw, effectivePk),
317
+ ObjectType: ctx.ObjectName,
318
+ Fields: raw,
319
+ }));
320
+ const hasMore = records.length >= pageSize;
321
+ const result = {
322
+ Records: out,
323
+ HasMore: hasMore,
324
+ NextOffset: offset + records.length,
325
+ };
326
+ // Persist the max watermark seen on this (full-page-success) batch.
327
+ if (obj.IncrementalWatermarkField) {
328
+ const maxWatermark = this.MaxWatermark(records, obj.IncrementalWatermarkField, ctx.WatermarkValue);
329
+ if (maxWatermark)
330
+ result.NewWatermarkValue = maxWatermark;
331
+ }
332
+ return result;
333
+ }
334
+ /**
335
+ * Resolves the async Contacts response: if a ResultId is present, polls the same endpoint with
336
+ * `?resultId=<id>` until State='Complete' (bounded), then returns the Contacts array. If the
337
+ * initial response already carried the Contacts array synchronously, returns it directly.
338
+ */
339
+ async ResolveAsyncContacts(auth, baseUrl, firstBody) {
340
+ const parsed = AsyncContactsSchema.safeParse(firstBody);
341
+ const resultId = parsed.success ? parsed.data.ResultId : undefined;
342
+ // Synchronous shape: the body already carries the Contacts array (no polling needed).
343
+ if (!resultId) {
344
+ return this.NormalizeResponse(firstBody, 'Contacts');
345
+ }
346
+ const pollUrl = `${baseUrl}?resultId=${encodeURIComponent(resultId)}`;
347
+ for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {
348
+ const poll = await this.MakeHTTPRequest(auth, pollUrl, 'GET', this.BuildHeaders(auth));
349
+ this.AssertContactsOK(poll, 'poll async contacts result');
350
+ const state = this.ReadState(poll.Body);
351
+ if (state === 'Complete') {
352
+ return this.NormalizeResponse(poll.Body, 'Contacts');
353
+ }
354
+ if (state === 'Failed') {
355
+ throw new Error(`Wild Apricot async contacts query failed (ResultId ${resultId}).`);
356
+ }
357
+ await delay(POLL_INTERVAL_MS);
358
+ }
359
+ throw new Error(`Wild Apricot async contacts query did not complete within ${(POLL_MAX_ATTEMPTS * POLL_INTERVAL_MS) / 1000}s ` +
360
+ `(ResultId ${resultId}) — poll timeout.`);
361
+ }
362
+ // ─── Helpers ──────────────────────────────────────────────────────────────
363
+ /** Substitutes the resolved `{accountId}` tenant anchor into a URL (case-insensitive on the var name). */
364
+ SubstituteAccountId(url, accountId) {
365
+ return url.replace(/\{accountId\}/gi, encodeURIComponent(accountId));
366
+ }
367
+ /**
368
+ * Resolves the tenant accountId: prefers the credential-configured value, else issues
369
+ * GET /accounts and adopts the first account's Id. Cached per instance. NEVER hardcoded.
370
+ */
371
+ async ResolveAccountId(creds, token) {
372
+ if (creds.AccountId)
373
+ return creds.AccountId;
374
+ if (this.cachedAccountId)
375
+ return this.cachedAccountId;
376
+ const host = creds.BaseHost ?? WILDAPRICOT_API_HOST;
377
+ const version = creds.ApiVersion ?? DEFAULT_API_VERSION;
378
+ const url = `${host.replace(/\/+$/, '')}/${version}/accounts`;
379
+ // Auth is not yet fully assembled (that's what we're resolving), so build a minimal context.
380
+ const bootstrapAuth = { Token: token, AccountId: '', BaseHost: creds.BaseHost, ApiVersion: creds.ApiVersion };
381
+ const response = await this.MakeHTTPRequest(bootstrapAuth, url, 'GET', this.BuildHeaders(bootstrapAuth));
382
+ if (response.Status < 200 || response.Status >= 300) {
383
+ throw new Error(`Wild Apricot account auto-discovery failed: GET /accounts returned HTTP ${response.Status}.`);
384
+ }
385
+ const accounts = this.NormalizeResponse(response.Body, null);
386
+ const first = accounts[0];
387
+ const id = first ? first['Id'] ?? first['id'] : undefined;
388
+ if (id == null) {
389
+ throw new Error('Wild Apricot account auto-discovery returned no accounts for this API key.');
390
+ }
391
+ this.cachedAccountId = String(id);
392
+ return this.cachedAccountId;
393
+ }
394
+ /** Finds the first array-valued property of an object (a wrapped collection under a vendor key). */
395
+ FindArrayInObject(obj) {
396
+ for (const v of Object.values(obj)) {
397
+ if (Array.isArray(v))
398
+ return v;
399
+ }
400
+ return [];
401
+ }
402
+ /** Reads the async-result State ('Complete'/'Processing'/'Failed'/…) from a poll body, tolerant of shape. */
403
+ ReadState(body) {
404
+ if (!isRecord(body))
405
+ return undefined;
406
+ const state = body['State'] ?? body['state'];
407
+ return typeof state === 'string' ? state : undefined;
408
+ }
409
+ /** Builds a Contact record identity from its declared PK (falls back to a common id key, then a content hash). */
410
+ BuildContactIdentity(raw, pkFieldNames) {
411
+ const parts = pkFieldNames.map(name => raw[name]).filter(v => v != null && String(v).length > 0);
412
+ if (parts.length === pkFieldNames.length && parts.length > 0) {
413
+ return parts.map(v => String(v)).join('|');
414
+ }
415
+ for (const k of ['Id', 'id', 'ID']) {
416
+ const v = raw[k];
417
+ if (v != null && String(v).length > 0)
418
+ return String(v);
419
+ }
420
+ return stableHash(raw);
421
+ }
422
+ /** Max watermark value across a record batch (ISO8601 string comparison), never below the current one. */
423
+ MaxWatermark(records, field, current) {
424
+ let max = current ?? '';
425
+ for (const r of records) {
426
+ const v = r[field];
427
+ if (typeof v === 'string' && v > max)
428
+ max = v;
429
+ }
430
+ return max.length > 0 && max !== (current ?? '') ? max : undefined;
431
+ }
432
+ /** Throws a descriptive error on a non-2xx contacts response (202 Accepted is treated as OK for the async kick-off). */
433
+ AssertContactsOK(response, action) {
434
+ if (response.Status === 202)
435
+ return;
436
+ if (response.Status < 200 || response.Status >= 300) {
437
+ throw new Error(`Wild Apricot failed to ${action}: HTTP ${response.Status}`);
438
+ }
439
+ }
440
+ /** Reads headers off an error-like object (for Retry-After parsing). */
441
+ ExtractErrorHeaders(error) {
442
+ if (isRecord(error)) {
443
+ const headers = error['Headers'] ?? error['headers'];
444
+ if (isRecord(headers)) {
445
+ const out = {};
446
+ for (const [k, v] of Object.entries(headers)) {
447
+ if (typeof v === 'string')
448
+ out[k.toLowerCase()] = v;
449
+ }
450
+ return out;
451
+ }
452
+ }
453
+ return undefined;
454
+ }
455
+ /** Whether an error indicates a 429 rate-limit. */
456
+ IsRateLimitError(error) {
457
+ if (isRecord(error)) {
458
+ const status = error['Status'] ?? error['status'] ?? error['StatusCode'];
459
+ if (status === 429)
460
+ return true;
461
+ }
462
+ const msg = error instanceof Error ? error.message : String(error ?? '');
463
+ return /\b429\b/.test(msg);
464
+ }
465
+ /**
466
+ * Resolves the API key + tenant config from the linked Credential entity, falling back to the
467
+ * CompanyIntegration.Configuration / APIKey. The credential bytes never leave this scope.
468
+ */
469
+ async LoadCredentials(companyIntegration, contextUser) {
470
+ let apiKey;
471
+ let accountId;
472
+ let tokenUrl;
473
+ let baseHost;
474
+ let apiVersion;
475
+ if (companyIntegration.CredentialID) {
476
+ const fromCred = await this.LoadFromCredentialEntity(companyIntegration.CredentialID, contextUser);
477
+ if (fromCred) {
478
+ apiKey = fromCred.ApiKey || apiKey;
479
+ accountId = fromCred.AccountId || accountId;
480
+ tokenUrl = fromCred.TokenUrl || tokenUrl;
481
+ baseHost = fromCred.BaseHost || baseHost;
482
+ apiVersion = fromCred.ApiVersion || apiVersion;
483
+ }
484
+ }
485
+ // Non-secret tenant config lives on Configuration JSON (AccountId, tokenUrl, host, version).
486
+ const configJson = companyIntegration.Configuration;
487
+ if (configJson) {
488
+ const fromConfig = this.ParseConfigJson(configJson);
489
+ if (fromConfig) {
490
+ apiKey = apiKey ?? fromConfig.ApiKey;
491
+ accountId = accountId ?? fromConfig.AccountId;
492
+ tokenUrl = tokenUrl ?? fromConfig.TokenUrl;
493
+ baseHost = baseHost ?? fromConfig.BaseHost;
494
+ apiVersion = apiVersion ?? fromConfig.ApiVersion;
495
+ }
496
+ }
497
+ // Legacy fallback: the API key may live on CompanyIntegration.APIKey.
498
+ apiKey = apiKey ?? companyIntegration.APIKey ?? undefined;
499
+ if (!apiKey) {
500
+ throw new Error('No Wild Apricot API key found — set the admin API Key on the credential, Configuration JSON, or CompanyIntegration.APIKey.');
501
+ }
502
+ return {
503
+ ApiKey: apiKey,
504
+ AccountId: accountId,
505
+ TokenUrl: tokenUrl ?? WILDAPRICOT_TOKEN_URL,
506
+ BaseHost: baseHost,
507
+ ApiVersion: apiVersion,
508
+ };
509
+ }
510
+ /** Loads credential fields from a Credential entity's Values JSON. */
511
+ async LoadFromCredentialEntity(credentialID, contextUser, provider) {
512
+ const md = provider ?? new Metadata();
513
+ const credential = await md.GetEntityObject('MJ: Credentials', contextUser);
514
+ const loaded = await credential.Load(credentialID);
515
+ if (!loaded || !credential.Values)
516
+ return null;
517
+ return this.ParseConfigJson(credential.Values);
518
+ }
519
+ /** Parses a JSON string into credential/config fields (tolerant of casing/aliases). */
520
+ ParseConfigJson(json) {
521
+ try {
522
+ const result = WildApricotConfigSchema.safeParse(JSON.parse(json));
523
+ if (!result.success)
524
+ return null;
525
+ const p = result.data;
526
+ const apiKey = p.ApiKey ?? p.apiKey ?? p.APIKey ?? p.Key ?? p.Token ?? p.token;
527
+ const accountId = p.AccountId ?? p.accountId ?? p.AccountID;
528
+ const tokenUrl = p.tokenUrl ?? p.TokenUrl ?? p.tokenURL;
529
+ const baseHost = p.apiBaseUrl ?? p.BaseURL ?? p.baseHost;
530
+ const apiVersion = p.ApiVersion ?? p.apiVersion;
531
+ return {
532
+ ApiKey: apiKey ?? '',
533
+ AccountId: accountId != null ? String(accountId) : undefined,
534
+ TokenUrl: tokenUrl ?? WILDAPRICOT_TOKEN_URL,
535
+ BaseHost: baseHost,
536
+ ApiVersion: apiVersion,
537
+ };
538
+ }
539
+ catch {
540
+ return null;
541
+ }
542
+ }
543
+ };
544
+ WildApricotConnector = __decorate([
545
+ RegisterClass(BaseIntegrationConnector, '@memberjunction/connector-wild-apricot')
546
+ ], WildApricotConnector);
547
+ export { WildApricotConnector };
548
+ // ─── Module-level constants + helpers (mechanism, NOT a catalog) ──────────────
549
+ /** Wild Apricot API host root; the version segment (/v2.3) + tenant paths are appended at runtime. */
550
+ const WILDAPRICOT_API_HOST = 'https://api.wildapricot.org';
551
+ /** OAuth2 token endpoint (client_credentials). */
552
+ const WILDAPRICOT_TOKEN_URL = 'https://oauth.wildapricot.org/auth/token';
553
+ /** Default API version path segment. */
554
+ const DEFAULT_API_VERSION = 'v2.3';
555
+ /** Max page size — `$top` above 100 is silently clamped to 100 per spec. */
556
+ const WILDAPRICOT_MAX_PAGE_SIZE = 100;
557
+ /** The single object whose list endpoint is async (request → ResultId → poll). */
558
+ const CONTACT_OBJECT_NAME = 'Contact';
559
+ /** Async-contacts poll bounds: attempts × interval caps total wait so a stuck job cannot hang the sync. */
560
+ const POLL_MAX_ATTEMPTS = 60;
561
+ const POLL_INTERVAL_MS = 1000;
562
+ /** Zod schema for the credential/Configuration JSON shape (tolerant of casing aliases). */
563
+ const WildApricotConfigSchema = z.object({
564
+ ApiKey: z.string().optional(),
565
+ apiKey: z.string().optional(),
566
+ APIKey: z.string().optional(),
567
+ Key: z.string().optional(),
568
+ Token: z.string().optional(),
569
+ token: z.string().optional(),
570
+ AccountId: z.union([z.string(), z.number()]).optional(),
571
+ accountId: z.union([z.string(), z.number()]).optional(),
572
+ AccountID: z.union([z.string(), z.number()]).optional(),
573
+ tokenUrl: z.string().optional(),
574
+ TokenUrl: z.string().optional(),
575
+ tokenURL: z.string().optional(),
576
+ apiBaseUrl: z.string().optional(),
577
+ BaseURL: z.string().optional(),
578
+ baseHost: z.string().optional(),
579
+ ApiVersion: z.string().optional(),
580
+ apiVersion: z.string().optional(),
581
+ }).passthrough();
582
+ /** Zod schema for the async-contacts kick-off response (carries a ResultId to poll). */
583
+ const AsyncContactsSchema = z.object({
584
+ ResultId: z.string().optional(),
585
+ State: z.string().optional(),
586
+ }).passthrough();
587
+ /** Narrows an unknown value to a plain record. */
588
+ function isRecord(v) {
589
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
590
+ }
591
+ /** Small deterministic hash for record-identity fallback (FNV-1a, hex). */
592
+ function stableHash(record) {
593
+ const json = JSON.stringify(record, Object.keys(record).sort());
594
+ let h = 0x811c9dc5;
595
+ for (let i = 0; i < json.length; i++) {
596
+ h ^= json.charCodeAt(i);
597
+ h = Math.imul(h, 0x01000193);
598
+ }
599
+ return (h >>> 0).toString(16);
600
+ }
601
+ /** Awaits `ms` milliseconds (poll interval). */
602
+ function delay(ms) {
603
+ return new Promise(resolve => setTimeout(resolve, ms));
604
+ }
605
+ /**
606
+ * Minimal bounded promise-pool: runs `worker` over `items` with at most `limit` in flight.
607
+ * (BaseRESTIntegrationConnector.RunBounded is private, so the sample-union override brings its own
608
+ * tiny pool — this is local plumbing, NOT a shared framework artifact.)
609
+ */
610
+ async function runBounded(items, limit, worker) {
611
+ const queue = [...items];
612
+ const size = Math.max(1, Math.min(limit, queue.length));
613
+ const runners = Array.from({ length: size }, async () => {
614
+ for (let next = queue.shift(); next !== undefined; next = queue.shift()) {
615
+ await worker(next);
616
+ }
617
+ });
618
+ await Promise.all(runners);
619
+ }
620
+ //# sourceMappingURL=WildApricotConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WildApricotConnector.js","sourceRoot":"","sources":["../src/WildApricotConnector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './WildApricotConnector.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 './WildApricotConnector.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,2BAA2B,CAAC;AAE1C;oGACoG;AACpG,MAAM,UAAU,iBAAiB,KAAiD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@memberjunction/connector-wild-apricot",
3
+ "version": "1.2.0",
4
+ "private": false,
5
+ "description": "MemberJunction WildApricot 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 --passWithNoTests"
15
+ },
16
+ "author": "MemberJunction.com",
17
+ "license": "ISC",
18
+ "peerDependencies": {
19
+ "@memberjunction/core": ">=5.42.0 <6.0.0",
20
+ "@memberjunction/core-entities": ">=5.42.0 <6.0.0",
21
+ "@memberjunction/global": ">=5.42.0 <6.0.0",
22
+ "@memberjunction/integration-engine": ">=5.42.0 <6.0.0"
23
+ },
24
+ "dependencies": {
25
+ "@memberjunction/connector-schema-merge": "^1.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "24.10.11",
29
+ "tsc-alias": "^1.8.16",
30
+ "typescript": "^5.9.3",
31
+ "vitest": "^4.0.18",
32
+ "@memberjunction/core": "^5.42.0",
33
+ "@memberjunction/core-entities": "^5.42.0",
34
+ "@memberjunction/global": "^5.42.0",
35
+ "@memberjunction/integration-engine": "^5.42.0",
36
+ "@memberjunction/connector-schema-merge": "^1.0.0"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/MemberJunction/Integrations"
41
+ }
42
+ }