@memberjunction/connector-magnetmail 3.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/MagnetMailConnector.d.ts +182 -0
- package/dist/MagnetMailConnector.js +795 -0
- package/dist/MagnetMailConnector.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 +44 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { type UserInfo } from '@memberjunction/core';
|
|
2
|
+
import type { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import { BaseRESTIntegrationConnector, type RESTAuthContext, type RESTResponse, type PaginationState, type PaginationType, type ConnectionTestResult, type FetchContext, type FetchBatchResult, type CreateRecordContext, type UpdateRecordContext, type CRUDResult, type SourceSchemaInfo } from '@memberjunction/integration-engine';
|
|
4
|
+
/** Non-secret + secret connection settings, resolved from the credential store and Configuration JSON. */
|
|
5
|
+
interface MagnetMailConfig {
|
|
6
|
+
Username: string;
|
|
7
|
+
Password: string;
|
|
8
|
+
Endpoint: string;
|
|
9
|
+
Namespace: string;
|
|
10
|
+
SessionTTLMs: number;
|
|
11
|
+
}
|
|
12
|
+
/** Auth context carried through every request. SessionID + UserId feed the <mmAuthHeader> SOAP header. */
|
|
13
|
+
export interface MagnetMailAuthContext extends RESTAuthContext {
|
|
14
|
+
/** AuthenticationResult.sessionId — the mmAuthHeader session token. */
|
|
15
|
+
SessionID: string;
|
|
16
|
+
/** AuthenticationResult.user_id — the mmAuthHeader account-scope id (NOT the login username). */
|
|
17
|
+
UserId: string;
|
|
18
|
+
/** Resolved SOAP endpoint URL. */
|
|
19
|
+
Endpoint: string;
|
|
20
|
+
/** Resolved SOAP target namespace. */
|
|
21
|
+
Namespace: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The structured SOAP request the connector hands to {@link MagnetMailConnector.MakeHTTPRequest} as its
|
|
25
|
+
* `body`. MakeHTTPRequest is where the SOAP 1.1 envelope is actually built (per the task contract), from
|
|
26
|
+
* this descriptor + the auth context — so tests that mock MakeHTTPRequest capture the meaningful wire
|
|
27
|
+
* intent (action + args) and the envelope XML itself is unit-tested via {@link buildSoapEnvelope}.
|
|
28
|
+
*/
|
|
29
|
+
export interface SoapRequest {
|
|
30
|
+
/** SOAP operation name (== body element name == SOAPAction suffix). */
|
|
31
|
+
Action: string;
|
|
32
|
+
/** Operation body arguments (may nest objects / arrays; rendered recursively). */
|
|
33
|
+
Args: Record<string, unknown>;
|
|
34
|
+
/** Whether to emit the <mmAuthHeader> SOAP header (false only for the Authenticate call). */
|
|
35
|
+
IncludeAuthHeader: boolean;
|
|
36
|
+
/** Optional wrapper element the args nest inside (e.g. `criteria` for search operations). */
|
|
37
|
+
WrapperElement?: string | null;
|
|
38
|
+
}
|
|
39
|
+
/** Cached session state. */
|
|
40
|
+
interface CachedSession {
|
|
41
|
+
Auth: MagnetMailAuthContext;
|
|
42
|
+
CreatedAt: number;
|
|
43
|
+
TTLMs: number;
|
|
44
|
+
}
|
|
45
|
+
export declare class MagnetMailConnector extends BaseRESTIntegrationConnector {
|
|
46
|
+
/** Cached session token (protected so the mocked test subclass can seed it without a live auth call). */
|
|
47
|
+
protected cachedSession: CachedSession | null;
|
|
48
|
+
/** Verbatim MJ: Integrations.Name (three-way identity invariant). */
|
|
49
|
+
get IntegrationName(): string;
|
|
50
|
+
/** Vendor supports create (addRecipient / addGroup / createMagnetMailMessage / …) — wired via SOAP override. */
|
|
51
|
+
get SupportsCreate(): boolean;
|
|
52
|
+
/** Vendor supports update (editRecipient / editMagnetMailMessage) — wired via SOAP override. */
|
|
53
|
+
get SupportsUpdate(): boolean;
|
|
54
|
+
/** NO delete/remove operation exists anywhere in the 55-operation WSDL surface — honestly false. */
|
|
55
|
+
get SupportsDelete(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* The WSDL is a fixed, versionless surface fetched once at build — NOT a live per-credential describe
|
|
58
|
+
* endpoint. Keep the base default so the comprehensive-refresh deactivation path never disables
|
|
59
|
+
* Declared IO/IOF rows on absence.
|
|
60
|
+
*/
|
|
61
|
+
get DiscoveryIsAuthoritative(): boolean;
|
|
62
|
+
TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
|
|
63
|
+
/** Two-step SOAP session auth with TTL caching. Returns the mmAuthHeader session context. */
|
|
64
|
+
protected Authenticate(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<MagnetMailAuthContext>;
|
|
65
|
+
/** Content-type headers for a SOAP 1.1 POST. The per-operation SOAPAction is added in MakeHTTPRequest. */
|
|
66
|
+
protected BuildHeaders(_auth: RESTAuthContext): Record<string, string>;
|
|
67
|
+
/** The SOAP endpoint URL. For SOAP the operation is in the SOAPAction + body, not the path. */
|
|
68
|
+
protected GetBaseURL(_companyIntegration: MJCompanyIntegrationEntity, auth: RESTAuthContext): string;
|
|
69
|
+
/**
|
|
70
|
+
* The SOAP transport boundary. `body` MUST be a {@link SoapRequest}; MakeHTTPRequest builds the SOAP
|
|
71
|
+
* 1.1 envelope from it (+ the auth context's <mmAuthHeader>), POSTs with `Content-Type: text/xml` and
|
|
72
|
+
* `SOAPAction: "<namespace><action>"`, and parses the XML response into a JS object (faults surfaced
|
|
73
|
+
* as `Body._soapFault`). Test subclasses override this to capture the request and return canned bodies.
|
|
74
|
+
*/
|
|
75
|
+
protected MakeHTTPRequest(auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
|
|
76
|
+
/**
|
|
77
|
+
* Strips the SOAP `<{action}Response>` / `<{action}Result>` envelope, then locates the record set.
|
|
78
|
+
* When `responseDataKey` (the XSD record-type name, e.g. `Recipient`) is given it is deep-found —
|
|
79
|
+
* which also transparently descends any `AccessPath` nesting (`RecipientSuppressionList` →
|
|
80
|
+
* `ArrayOfRecipient` → `Recipient`) without the connector needing to hard-code the path. A single
|
|
81
|
+
* record object is returned as a one-element array; a missing/nil set as `[]`.
|
|
82
|
+
*/
|
|
83
|
+
protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
|
|
84
|
+
/**
|
|
85
|
+
* SOAP has no envelope-level pagination metadata; HasMore is inferred from whether a FULL page came
|
|
86
|
+
* back (record count == pageSize). Operations declared `PaginationType: None` never take page args and
|
|
87
|
+
* always report a single page.
|
|
88
|
+
*/
|
|
89
|
+
protected ExtractPaginationInfo(rawBody: unknown, paginationType: PaginationType, currentPage: number, currentOffset: number, pageSize: number): PaginationState;
|
|
90
|
+
/**
|
|
91
|
+
* Never-shrink SAMPLE-UNION: enrich each object's DECLARED (WSDL/metadata) field set with fields
|
|
92
|
+
* observed by live SAMPLING (`DiscoverFieldsViaFetch`), so a tenant's custom/undeclared columns are
|
|
93
|
+
* captured at connection time without ever losing or narrowing a declared field. Declared attributes
|
|
94
|
+
* stay authoritative; sampling only fills gaps, widens capacities, and appends undeclared columns
|
|
95
|
+
* (`mergeDeclaredWithSampledFields` — max(declared, sampled)). Per object, parallel + best-effort: a
|
|
96
|
+
* sampling failure for one object never fails introspection (its declared fields stand). Connector-
|
|
97
|
+
* agnostic wiring — no MagnetMail-specific logic here.
|
|
98
|
+
*/
|
|
99
|
+
IntrospectSchema(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<SourceSchemaInfo>;
|
|
100
|
+
/**
|
|
101
|
+
* SOAP read for one object. Reads the list SOAP operation from the IO's Configuration (`ListOperation`
|
|
102
|
+
* / `SoapListAction`), applies pageNumber/pageCount when the object supports pagination, and the
|
|
103
|
+
* incremental date-range param when SupportsIncrementalSync. Fetches ONE page per call; the engine
|
|
104
|
+
* loops on HasMore + NextPage. Full-record pass-through: every source key reaches Fields.
|
|
105
|
+
*/
|
|
106
|
+
FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
|
|
107
|
+
/**
|
|
108
|
+
* SOAP create. Reads the mutation SOAP action from Configuration.CreateOperation, builds a `literal`
|
|
109
|
+
* SOAP envelope, POSTs it, and routes the result through BuildCreatedResult so a 2xx with no record ID
|
|
110
|
+
* fails LOUDLY (never a silent record-loss / duplicate-on-next-sync).
|
|
111
|
+
*/
|
|
112
|
+
CreateRecord(ctx: CreateRecordContext): Promise<CRUDResult>;
|
|
113
|
+
/**
|
|
114
|
+
* SOAP update. Reads the mutation SOAP action from Configuration.UpdateOperation, injects the target
|
|
115
|
+
* ExternalID into the body under the object's primary-key field name, and POSTs the `literal` envelope.
|
|
116
|
+
*/
|
|
117
|
+
UpdateRecord(ctx: UpdateRecordContext): Promise<CRUDResult>;
|
|
118
|
+
/** Builds a SOAP 1.1 envelope with the optional <mmAuthHeader> header and the operation body. */
|
|
119
|
+
protected buildSoapEnvelope(auth: MagnetMailAuthContext, request: SoapRequest): string;
|
|
120
|
+
/** Renders args as XML child elements, recursing into nested objects/arrays; nulls are skipped. */
|
|
121
|
+
protected renderArgs(args: Record<string, unknown>, indent?: string): string;
|
|
122
|
+
private renderXmlValue;
|
|
123
|
+
/** Parses a SOAP response envelope into a normalized RESTResponse (Body = parsed <soap:Body> content). */
|
|
124
|
+
protected parseSoapResponse(xml: string, status: number, headers: Record<string, string>): RESTResponse;
|
|
125
|
+
/** Recursively converts an XML fragment's inner content into a JS value (object / array / scalar). */
|
|
126
|
+
protected xmlToObject(xml: string): unknown;
|
|
127
|
+
private extractChildren;
|
|
128
|
+
/** Returns the inner content of the first element with the given LOCAL name (namespace-agnostic). */
|
|
129
|
+
private extractElementInner;
|
|
130
|
+
private coerceScalar;
|
|
131
|
+
/** Returns the parsed SOAP fault ({faultcode, faultstring}) if present, else null. */
|
|
132
|
+
protected extractSoapFault(body: unknown): {
|
|
133
|
+
faultcode: string;
|
|
134
|
+
faultstring: string;
|
|
135
|
+
} | null;
|
|
136
|
+
/**
|
|
137
|
+
* Reads the vendor's IN-BAND error signal from a mutation response body (SaveResult / *Result wrapper).
|
|
138
|
+
* Per the frozen contract's ErrorResponseShape: a 200/literal SOAP body can signal failure via `error`
|
|
139
|
+
* (s:double, 0 = success by convention), an `errorObj` (tns:Error: errorCode/errorMessage/errorDetails/…),
|
|
140
|
+
* and/or a human `msg` — a SOAP Fault is NOT the only failure signal this API uses. Returns a
|
|
141
|
+
* human-readable message when the body signals an error, else null.
|
|
142
|
+
*/
|
|
143
|
+
protected extractInBandError(body: unknown): string | null;
|
|
144
|
+
/** Throws a descriptive error when a response carries a SOAP fault, and invalidates the session. */
|
|
145
|
+
protected throwOnSoapFault(response: RESTResponse, action: string): void;
|
|
146
|
+
private isSessionValid;
|
|
147
|
+
private preAuthContext;
|
|
148
|
+
/** Resolves connection config from the credential store (secrets) + Configuration JSON (overrides). */
|
|
149
|
+
protected ParseConfig(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<MagnetMailConfig>;
|
|
150
|
+
private loadCredentialValues;
|
|
151
|
+
private normalizeConfig;
|
|
152
|
+
private buildFetchArgs;
|
|
153
|
+
/** Max record-side watermark value in the batch, or undefined when not incremental / no field present. */
|
|
154
|
+
private computeWatermark;
|
|
155
|
+
private formatWatermark;
|
|
156
|
+
private toRecordArray;
|
|
157
|
+
/** Descends `Response`/`Result` wrapper elements to expose the inner payload. */
|
|
158
|
+
protected unwrapSoapResult(body: unknown): unknown;
|
|
159
|
+
/** Depth-first search for the first value under `key` anywhere in the object tree. */
|
|
160
|
+
private deepFindKey;
|
|
161
|
+
private firstArrayValue;
|
|
162
|
+
private recordCount;
|
|
163
|
+
private readNestedString;
|
|
164
|
+
/**
|
|
165
|
+
* §4 identity: uses the declared PK when every component is present + non-empty, else a deterministic
|
|
166
|
+
* content hash (so PK-less / partial-key records stay syncable + dedupable). Full-record pass-through:
|
|
167
|
+
* Fields carries the complete source record (with the synthetic id stamped into a single empty PK).
|
|
168
|
+
*/
|
|
169
|
+
private buildExternalRecord;
|
|
170
|
+
private primaryKeyFieldNames;
|
|
171
|
+
private extractMutationId;
|
|
172
|
+
private buildCRUDError;
|
|
173
|
+
private readIOConfig;
|
|
174
|
+
private readConfigString;
|
|
175
|
+
private headersToObject;
|
|
176
|
+
private escapeXml;
|
|
177
|
+
private decodeXml;
|
|
178
|
+
private escapeRegex;
|
|
179
|
+
}
|
|
180
|
+
/** Tree-shaking prevention — import and call from the package entry point. */
|
|
181
|
+
export declare function LoadMagnetMailConnector(): void;
|
|
182
|
+
export {};
|
|
@@ -0,0 +1,795 @@
|
|
|
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
|
+
* MagnetMailConnector — Higher Logic Marketing Enterprise (formerly Real Magnet / MagnetMail).
|
|
9
|
+
*
|
|
10
|
+
* Legacy SOAP/XML email-marketing platform (`mmapi.asmx`, WSDL document/literal, 55 operations).
|
|
11
|
+
* SOAP rides over HTTP here: this connector extends BaseRESTIntegrationConnector (the ONLY protocol
|
|
12
|
+
* bases the engine exports are BaseIntegrationConnector + BaseRESTIntegrationConnector — there is no
|
|
13
|
+
* BaseSOAPIntegrationConnector) and implements the SOAP 1.1 protocol over the REST base's HTTP seam.
|
|
14
|
+
*
|
|
15
|
+
* WHY the read/write paths are overridden (genuinely idiosyncratic, per the CRUD-routing rule):
|
|
16
|
+
* - Every operation is a POST to the SAME endpoint (`/mmapi.asmx`); the operation is selected by the
|
|
17
|
+
* `SOAPAction` header + the body element, NOT by the URL. The base's generic GET-based read loop and
|
|
18
|
+
* REST-body CRUD cannot express that, so FetchChanges / CreateRecord / UpdateRecord are overridden to
|
|
19
|
+
* build SOAP envelopes. `CreateBodyShape/UpdateBodyShape = 'literal'` in the frozen metadata is the
|
|
20
|
+
* explicit "the connector builds the envelope" signal.
|
|
21
|
+
*
|
|
22
|
+
* Auth (two-step SESSION token — no crypto, so auth-helpers do not apply: this is a plaintext
|
|
23
|
+
* credential-for-session-token exchange over TLS, with no signing/hashing/JWT primitive to delegate):
|
|
24
|
+
* 1. POST `Authenticate(username, password)` to the shared endpoint (NO <mmAuthHeader> on this one call).
|
|
25
|
+
* 2. Read `AuthenticationResult.sessionId` + `.user_id`.
|
|
26
|
+
* 3. Attach BOTH verbatim in the <mmAuthHeader> SOAP HEADER (ns http://www.magnetmail.net/) of every
|
|
27
|
+
* subsequent operation. The session is cached for a TTL and re-obtained on expiry.
|
|
28
|
+
*
|
|
29
|
+
* The per-object SOAP OPERATION name (list/create/update) is read from the IntegrationObject's
|
|
30
|
+
* `Configuration` JSON (`ListOperation` / `CreateOperation` / `UpdateOperation`) — the catalog is NEVER
|
|
31
|
+
* baked into this code (connector-code-conventions § "NEVER bake a catalog"). See CODE_REPORT.md for the
|
|
32
|
+
* frozen-metadata gap where those Configuration keys are not yet emitted.
|
|
33
|
+
*
|
|
34
|
+
* NOTE: the WSDL is a FIXED, versionless surface fetched once at build time — NOT a live per-credential
|
|
35
|
+
* describe endpoint — so DiscoveryIsAuthoritative stays false (never disable Declared rows on absence).
|
|
36
|
+
*/
|
|
37
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
38
|
+
import { Metadata } from '@memberjunction/core';
|
|
39
|
+
import { z } from 'zod';
|
|
40
|
+
import { BaseIntegrationConnector, BaseRESTIntegrationConnector, computeContentHash, serializeKeyValue, } from '@memberjunction/integration-engine';
|
|
41
|
+
import { mergeDeclaredWithSampledFields } from '@memberjunction/connector-schema-merge';
|
|
42
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
43
|
+
const DEFAULT_ENDPOINT = 'https://hlma-apie1.magnetmail.net/mmapi.asmx';
|
|
44
|
+
const DEFAULT_NAMESPACE = 'http://www.magnetmail.net/';
|
|
45
|
+
const DEFAULT_SESSION_TTL_MS = 25 * 60 * 1000;
|
|
46
|
+
/** Zod schema for the resolved config (post key-normalization). */
|
|
47
|
+
const ConfigSchema = z.object({
|
|
48
|
+
Username: z.string().min(1, 'MagnetMail username is required'),
|
|
49
|
+
Password: z.string().min(1, 'MagnetMail password is required'),
|
|
50
|
+
Endpoint: z.string().min(1),
|
|
51
|
+
Namespace: z.string().min(1),
|
|
52
|
+
SessionTTLMs: z.number().positive(),
|
|
53
|
+
});
|
|
54
|
+
// ─── Connector ───────────────────────────────────────────────────────
|
|
55
|
+
let MagnetMailConnector = class MagnetMailConnector extends BaseRESTIntegrationConnector {
|
|
56
|
+
constructor() {
|
|
57
|
+
super(...arguments);
|
|
58
|
+
/** Cached session token (protected so the mocked test subclass can seed it without a live auth call). */
|
|
59
|
+
this.cachedSession = null;
|
|
60
|
+
}
|
|
61
|
+
// ── Identity + capabilities ──────────────────────────────────────
|
|
62
|
+
/** Verbatim MJ: Integrations.Name (three-way identity invariant). */
|
|
63
|
+
get IntegrationName() { return 'magnetmail'; }
|
|
64
|
+
/** Vendor supports create (addRecipient / addGroup / createMagnetMailMessage / …) — wired via SOAP override. */
|
|
65
|
+
get SupportsCreate() { return true; }
|
|
66
|
+
/** Vendor supports update (editRecipient / editMagnetMailMessage) — wired via SOAP override. */
|
|
67
|
+
get SupportsUpdate() { return true; }
|
|
68
|
+
/** NO delete/remove operation exists anywhere in the 55-operation WSDL surface — honestly false. */
|
|
69
|
+
get SupportsDelete() { return false; }
|
|
70
|
+
/**
|
|
71
|
+
* The WSDL is a fixed, versionless surface fetched once at build — NOT a live per-credential describe
|
|
72
|
+
* endpoint. Keep the base default so the comprehensive-refresh deactivation path never disables
|
|
73
|
+
* Declared IO/IOF rows on absence.
|
|
74
|
+
*/
|
|
75
|
+
get DiscoveryIsAuthoritative() { return false; }
|
|
76
|
+
// ── TestConnection (abstract on BaseIntegrationConnector) ─────────
|
|
77
|
+
async TestConnection(companyIntegration, contextUser) {
|
|
78
|
+
try {
|
|
79
|
+
const auth = await this.Authenticate(companyIntegration, contextUser);
|
|
80
|
+
return {
|
|
81
|
+
Success: true,
|
|
82
|
+
Message: `Authenticated to MagnetMail (user_id=${auth.UserId})`,
|
|
83
|
+
ServerVersion: 'MagnetMail mmapi.asmx (SOAP 1.1)',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
88
|
+
const authFailure = /fault|authenticat|unauthor|session|invalid/i.test(message);
|
|
89
|
+
return {
|
|
90
|
+
Success: false,
|
|
91
|
+
Message: authFailure
|
|
92
|
+
? `MagnetMail authentication failed: ${message}`
|
|
93
|
+
: `MagnetMail connection error: ${message}`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// ── Auth (abstract on BaseRESTIntegrationConnector) ───────────────
|
|
98
|
+
/** Two-step SOAP session auth with TTL caching. Returns the mmAuthHeader session context. */
|
|
99
|
+
async Authenticate(companyIntegration, contextUser) {
|
|
100
|
+
if (this.isSessionValid())
|
|
101
|
+
return this.cachedSession.Auth;
|
|
102
|
+
const config = await this.ParseConfig(companyIntegration, contextUser);
|
|
103
|
+
const preAuth = this.preAuthContext(config);
|
|
104
|
+
const request = {
|
|
105
|
+
Action: 'Authenticate',
|
|
106
|
+
Args: { username: config.Username, password: config.Password },
|
|
107
|
+
IncludeAuthHeader: false,
|
|
108
|
+
};
|
|
109
|
+
const response = await this.MakeHTTPRequest(preAuth, config.Endpoint, 'POST', this.BuildHeaders(preAuth), request);
|
|
110
|
+
this.throwOnSoapFault(response, 'Authenticate');
|
|
111
|
+
const result = this.unwrapSoapResult(response.Body);
|
|
112
|
+
const sessionId = this.readNestedString(result, 'sessionId') ?? this.readNestedString(result, 'AuthenticateResult');
|
|
113
|
+
const userId = this.readNestedString(result, 'user_id') ?? '';
|
|
114
|
+
if (!sessionId) {
|
|
115
|
+
throw new Error('MagnetMail Authenticate returned no sessionId');
|
|
116
|
+
}
|
|
117
|
+
const auth = {
|
|
118
|
+
SessionID: sessionId,
|
|
119
|
+
UserId: userId,
|
|
120
|
+
Endpoint: config.Endpoint,
|
|
121
|
+
Namespace: config.Namespace,
|
|
122
|
+
};
|
|
123
|
+
this.cachedSession = { Auth: auth, CreatedAt: Date.now(), TTLMs: config.SessionTTLMs };
|
|
124
|
+
return auth;
|
|
125
|
+
}
|
|
126
|
+
/** Content-type headers for a SOAP 1.1 POST. The per-operation SOAPAction is added in MakeHTTPRequest. */
|
|
127
|
+
BuildHeaders(_auth) {
|
|
128
|
+
return {
|
|
129
|
+
'Content-Type': 'text/xml; charset=utf-8',
|
|
130
|
+
'Accept': 'text/xml',
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** The SOAP endpoint URL. For SOAP the operation is in the SOAPAction + body, not the path. */
|
|
134
|
+
GetBaseURL(_companyIntegration, auth) {
|
|
135
|
+
return auth.Endpoint ?? DEFAULT_ENDPOINT;
|
|
136
|
+
}
|
|
137
|
+
// ── HTTP transport — builds + POSTs the SOAP envelope ─────────────
|
|
138
|
+
/**
|
|
139
|
+
* The SOAP transport boundary. `body` MUST be a {@link SoapRequest}; MakeHTTPRequest builds the SOAP
|
|
140
|
+
* 1.1 envelope from it (+ the auth context's <mmAuthHeader>), POSTs with `Content-Type: text/xml` and
|
|
141
|
+
* `SOAPAction: "<namespace><action>"`, and parses the XML response into a JS object (faults surfaced
|
|
142
|
+
* as `Body._soapFault`). Test subclasses override this to capture the request and return canned bodies.
|
|
143
|
+
*/
|
|
144
|
+
async MakeHTTPRequest(auth, url, method, headers, body) {
|
|
145
|
+
const soapAuth = auth;
|
|
146
|
+
const request = body;
|
|
147
|
+
if (!request || typeof request.Action !== 'string') {
|
|
148
|
+
throw new Error('MagnetMailConnector.MakeHTTPRequest requires a SoapRequest body (Action + Args)');
|
|
149
|
+
}
|
|
150
|
+
const envelope = this.buildSoapEnvelope(soapAuth, request);
|
|
151
|
+
const soapAction = `${soapAuth.Namespace ?? DEFAULT_NAMESPACE}${request.Action}`;
|
|
152
|
+
const reqHeaders = { ...headers, 'SOAPAction': `"${soapAction}"` };
|
|
153
|
+
const httpResponse = await fetch(url, { method, headers: reqHeaders, body: envelope });
|
|
154
|
+
const text = await httpResponse.text();
|
|
155
|
+
return this.parseSoapResponse(text, httpResponse.status, this.headersToObject(httpResponse.headers));
|
|
156
|
+
}
|
|
157
|
+
// ── NormalizeResponse (abstract) — strip <action>Result wrapper ───
|
|
158
|
+
/**
|
|
159
|
+
* Strips the SOAP `<{action}Response>` / `<{action}Result>` envelope, then locates the record set.
|
|
160
|
+
* When `responseDataKey` (the XSD record-type name, e.g. `Recipient`) is given it is deep-found —
|
|
161
|
+
* which also transparently descends any `AccessPath` nesting (`RecipientSuppressionList` →
|
|
162
|
+
* `ArrayOfRecipient` → `Recipient`) without the connector needing to hard-code the path. A single
|
|
163
|
+
* record object is returned as a one-element array; a missing/nil set as `[]`.
|
|
164
|
+
*/
|
|
165
|
+
NormalizeResponse(rawBody, responseDataKey) {
|
|
166
|
+
if (rawBody == null)
|
|
167
|
+
return [];
|
|
168
|
+
const unwrapped = this.unwrapSoapResult(rawBody);
|
|
169
|
+
if (unwrapped == null)
|
|
170
|
+
return [];
|
|
171
|
+
let target = unwrapped;
|
|
172
|
+
if (responseDataKey) {
|
|
173
|
+
const found = this.deepFindKey(unwrapped, responseDataKey);
|
|
174
|
+
if (found === undefined)
|
|
175
|
+
return []; // declared record type absent → no records
|
|
176
|
+
target = found;
|
|
177
|
+
}
|
|
178
|
+
else if (unwrapped && typeof unwrapped === 'object' && !Array.isArray(unwrapped)) {
|
|
179
|
+
const arr = this.firstArrayValue(unwrapped);
|
|
180
|
+
if (arr)
|
|
181
|
+
target = arr;
|
|
182
|
+
}
|
|
183
|
+
return this.toRecordArray(target);
|
|
184
|
+
}
|
|
185
|
+
// ── ExtractPaginationInfo (abstract) — pageNumber/pageCount ───────
|
|
186
|
+
/**
|
|
187
|
+
* SOAP has no envelope-level pagination metadata; HasMore is inferred from whether a FULL page came
|
|
188
|
+
* back (record count == pageSize). Operations declared `PaginationType: None` never take page args and
|
|
189
|
+
* always report a single page.
|
|
190
|
+
*/
|
|
191
|
+
ExtractPaginationInfo(rawBody, paginationType, currentPage, currentOffset, pageSize) {
|
|
192
|
+
if (paginationType === 'None')
|
|
193
|
+
return { HasMore: false };
|
|
194
|
+
const count = this.recordCount(rawBody);
|
|
195
|
+
const hasMore = pageSize > 0 && count >= pageSize;
|
|
196
|
+
if (paginationType === 'Offset') {
|
|
197
|
+
return { HasMore: hasMore, NextOffset: currentOffset + count };
|
|
198
|
+
}
|
|
199
|
+
// PageNumber (MagnetMail's pageNumber/pageCount) and any other page-style: advance the page number.
|
|
200
|
+
return { HasMore: hasMore, NextPage: currentPage + 1 };
|
|
201
|
+
}
|
|
202
|
+
// ── IntrospectSchema (declared + sampled field union) ─────────────
|
|
203
|
+
/**
|
|
204
|
+
* Never-shrink SAMPLE-UNION: enrich each object's DECLARED (WSDL/metadata) field set with fields
|
|
205
|
+
* observed by live SAMPLING (`DiscoverFieldsViaFetch`), so a tenant's custom/undeclared columns are
|
|
206
|
+
* captured at connection time without ever losing or narrowing a declared field. Declared attributes
|
|
207
|
+
* stay authoritative; sampling only fills gaps, widens capacities, and appends undeclared columns
|
|
208
|
+
* (`mergeDeclaredWithSampledFields` — max(declared, sampled)). Per object, parallel + best-effort: a
|
|
209
|
+
* sampling failure for one object never fails introspection (its declared fields stand). Connector-
|
|
210
|
+
* agnostic wiring — no MagnetMail-specific logic here.
|
|
211
|
+
*/
|
|
212
|
+
async IntrospectSchema(companyIntegration, contextUser) {
|
|
213
|
+
const schema = await super.IntrospectSchema(companyIntegration, contextUser);
|
|
214
|
+
await Promise.all(schema.Objects.map(async (obj) => {
|
|
215
|
+
try {
|
|
216
|
+
const sampled = await this.DiscoverFieldsViaFetch(companyIntegration, obj.ExternalName, contextUser);
|
|
217
|
+
obj.Fields = mergeDeclaredWithSampledFields(obj.Fields, sampled);
|
|
218
|
+
}
|
|
219
|
+
catch { /* best-effort — declared fields remain authoritative on a sampling failure */ }
|
|
220
|
+
}));
|
|
221
|
+
return schema;
|
|
222
|
+
}
|
|
223
|
+
// ── FetchChanges (SOAP read) ──────────────────────────────────────
|
|
224
|
+
/**
|
|
225
|
+
* SOAP read for one object. Reads the list SOAP operation from the IO's Configuration (`ListOperation`
|
|
226
|
+
* / `SoapListAction`), applies pageNumber/pageCount when the object supports pagination, and the
|
|
227
|
+
* incremental date-range param when SupportsIncrementalSync. Fetches ONE page per call; the engine
|
|
228
|
+
* loops on HasMore + NextPage. Full-record pass-through: every source key reaches Fields.
|
|
229
|
+
*/
|
|
230
|
+
async FetchChanges(ctx) {
|
|
231
|
+
const obj = this.GetCachedObject(ctx.CompanyIntegration.IntegrationID, ctx.ObjectName);
|
|
232
|
+
const fields = this.GetCachedFields(obj.ID);
|
|
233
|
+
const cfg = this.readIOConfig(obj);
|
|
234
|
+
const listOp = this.readConfigString(cfg, 'ListOperation') ?? this.readConfigString(cfg, 'SoapListAction');
|
|
235
|
+
if (!listOp) {
|
|
236
|
+
// The list SOAP operation isn't wired in this IO's Configuration. Surface it loudly instead of
|
|
237
|
+
// silently returning nothing (see CODE_REPORT.md — frozen-metadata operation-mapping gap).
|
|
238
|
+
return {
|
|
239
|
+
Records: [],
|
|
240
|
+
HasMore: false,
|
|
241
|
+
Warnings: [{
|
|
242
|
+
Code: 'NO_LIST_OPERATION',
|
|
243
|
+
Message: `"${obj.Name}": no SOAP list operation in Configuration (expected Configuration.ListOperation). ` +
|
|
244
|
+
`Cannot fetch until the operation is wired.`,
|
|
245
|
+
Data: { object: obj.Name },
|
|
246
|
+
}],
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
|
|
250
|
+
const page = ctx.CurrentPage ?? 1;
|
|
251
|
+
const offset = ctx.CurrentOffset ?? 0;
|
|
252
|
+
const pageSize = obj.DefaultPageSize && obj.DefaultPageSize > 0 ? obj.DefaultPageSize : Math.max(1, ctx.BatchSize);
|
|
253
|
+
const args = this.buildFetchArgs(obj, cfg, ctx, page, pageSize);
|
|
254
|
+
const wrapper = this.readConfigString(cfg, 'CriteriaWrapper');
|
|
255
|
+
const request = { Action: listOp, Args: args, IncludeAuthHeader: true, WrapperElement: wrapper };
|
|
256
|
+
const response = await this.MakeHTTPRequest(auth, auth.Endpoint, 'POST', this.BuildHeaders(auth), request);
|
|
257
|
+
this.throwOnSoapFault(response, listOp);
|
|
258
|
+
const rawRecords = this.NormalizeResponse(response.Body, obj.ResponseDataKey);
|
|
259
|
+
const pkFieldNames = this.primaryKeyFieldNames(fields);
|
|
260
|
+
const records = rawRecords.map(r => this.buildExternalRecord(this.applyTransformPreservingKeys(r, obj, fields), ctx.ObjectName, pkFieldNames));
|
|
261
|
+
const pagination = this.ExtractPaginationInfo(response.Body, obj.PaginationType, page, offset, pageSize);
|
|
262
|
+
const newWatermark = this.computeWatermark(obj, cfg, rawRecords);
|
|
263
|
+
return {
|
|
264
|
+
Records: records,
|
|
265
|
+
HasMore: pagination.HasMore,
|
|
266
|
+
NextPage: pagination.NextPage,
|
|
267
|
+
NextOffset: pagination.NextOffset,
|
|
268
|
+
NewWatermarkValue: newWatermark,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
// ── CRUD (SOAP mutation envelopes) ────────────────────────────────
|
|
272
|
+
/**
|
|
273
|
+
* SOAP create. Reads the mutation SOAP action from Configuration.CreateOperation, builds a `literal`
|
|
274
|
+
* SOAP envelope, POSTs it, and routes the result through BuildCreatedResult so a 2xx with no record ID
|
|
275
|
+
* fails LOUDLY (never a silent record-loss / duplicate-on-next-sync).
|
|
276
|
+
*/
|
|
277
|
+
async CreateRecord(ctx) {
|
|
278
|
+
const ci = ctx.CompanyIntegration;
|
|
279
|
+
const contextUser = ctx.ContextUser;
|
|
280
|
+
const obj = this.GetCachedObject(ci.IntegrationID, ctx.ObjectName);
|
|
281
|
+
if (!obj.CreateAPIPath || !obj.CreateMethod) {
|
|
282
|
+
throw new Error(`CreateRecord not supported for "${ctx.ObjectName}": CreateAPIPath / CreateMethod not configured on IntegrationObject.`);
|
|
283
|
+
}
|
|
284
|
+
const cfg = this.readIOConfig(obj);
|
|
285
|
+
const action = this.readConfigString(cfg, 'CreateOperation');
|
|
286
|
+
if (!action) {
|
|
287
|
+
return {
|
|
288
|
+
Success: false,
|
|
289
|
+
StatusCode: 400,
|
|
290
|
+
ErrorMessage: `CreateRecord for "${ctx.ObjectName}": Configuration.CreateOperation (SOAP action) not configured.`,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
try {
|
|
294
|
+
const auth = await this.Authenticate(ci, contextUser);
|
|
295
|
+
const request = { Action: action, Args: ctx.Attributes, IncludeAuthHeader: true };
|
|
296
|
+
const response = await this.MakeHTTPRequest(auth, auth.Endpoint, 'POST', this.BuildHeaders(auth), request);
|
|
297
|
+
this.throwOnSoapFault(response, action);
|
|
298
|
+
// A 200/literal SOAP body can STILL signal failure in-band (SaveResult.error/errorObj/msg) — a SOAP
|
|
299
|
+
// Fault is not the only failure signal this API uses (frozen contract ErrorResponseShape). Detect it
|
|
300
|
+
// BEFORE trusting the id, so a create is never counted as success on a vendor-signalled error.
|
|
301
|
+
const inBandError = this.extractInBandError(response.Body);
|
|
302
|
+
if (inBandError) {
|
|
303
|
+
return { Success: false, StatusCode: response.Status, ErrorMessage: `CreateRecord failed for ${ctx.ObjectName}: ${inBandError}` };
|
|
304
|
+
}
|
|
305
|
+
const externalID = this.extractMutationId(response.Body, obj);
|
|
306
|
+
return this.BuildCreatedResult(externalID, response.Status, ctx.ObjectName);
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
return this.buildCRUDError(err, 'CreateRecord', ctx.ObjectName);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* SOAP update. Reads the mutation SOAP action from Configuration.UpdateOperation, injects the target
|
|
314
|
+
* ExternalID into the body under the object's primary-key field name, and POSTs the `literal` envelope.
|
|
315
|
+
*/
|
|
316
|
+
async UpdateRecord(ctx) {
|
|
317
|
+
const ci = ctx.CompanyIntegration;
|
|
318
|
+
const contextUser = ctx.ContextUser;
|
|
319
|
+
const obj = this.GetCachedObject(ci.IntegrationID, ctx.ObjectName);
|
|
320
|
+
if (!obj.UpdateAPIPath || !obj.UpdateMethod) {
|
|
321
|
+
throw new Error(`UpdateRecord not supported for "${ctx.ObjectName}": UpdateAPIPath / UpdateMethod not configured on IntegrationObject.`);
|
|
322
|
+
}
|
|
323
|
+
const cfg = this.readIOConfig(obj);
|
|
324
|
+
const action = this.readConfigString(cfg, 'UpdateOperation');
|
|
325
|
+
if (!action) {
|
|
326
|
+
return {
|
|
327
|
+
Success: false,
|
|
328
|
+
StatusCode: 400,
|
|
329
|
+
ErrorMessage: `UpdateRecord for "${ctx.ObjectName}": Configuration.UpdateOperation (SOAP action) not configured.`,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
const auth = await this.Authenticate(ci, contextUser);
|
|
334
|
+
const fields = this.GetCachedFields(obj.ID);
|
|
335
|
+
const pkName = this.primaryKeyFieldNames(fields)[0];
|
|
336
|
+
const args = { ...ctx.Attributes };
|
|
337
|
+
if (pkName && args[pkName] === undefined)
|
|
338
|
+
args[pkName] = ctx.ExternalID;
|
|
339
|
+
const request = { Action: action, Args: args, IncludeAuthHeader: true };
|
|
340
|
+
const response = await this.MakeHTTPRequest(auth, auth.Endpoint, 'POST', this.BuildHeaders(auth), request);
|
|
341
|
+
this.throwOnSoapFault(response, action);
|
|
342
|
+
// In-band error check (same rationale as CreateRecord): an edit* response can carry error/errorObj/msg
|
|
343
|
+
// inside a structurally-successful 200 body.
|
|
344
|
+
const inBandError = this.extractInBandError(response.Body);
|
|
345
|
+
if (inBandError) {
|
|
346
|
+
return { Success: false, StatusCode: response.Status, ErrorMessage: `UpdateRecord failed for ${ctx.ObjectName}: ${inBandError}` };
|
|
347
|
+
}
|
|
348
|
+
return { Success: true, StatusCode: response.Status, ExternalID: ctx.ExternalID };
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
return this.buildCRUDError(err, 'UpdateRecord', ctx.ObjectName);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// ── SOAP envelope building ────────────────────────────────────────
|
|
355
|
+
/** Builds a SOAP 1.1 envelope with the optional <mmAuthHeader> header and the operation body. */
|
|
356
|
+
buildSoapEnvelope(auth, request) {
|
|
357
|
+
const ns = auth.Namespace ?? DEFAULT_NAMESPACE;
|
|
358
|
+
const header = request.IncludeAuthHeader
|
|
359
|
+
? ` <soap:Header>\n <mmAuthHeader xmlns="${ns}">\n` +
|
|
360
|
+
` <sessionId>${this.escapeXml(auth.SessionID ?? '')}</sessionId>\n` +
|
|
361
|
+
` <user_id>${this.escapeXml(auth.UserId ?? '')}</user_id>\n` +
|
|
362
|
+
` </mmAuthHeader>\n </soap:Header>\n`
|
|
363
|
+
: '';
|
|
364
|
+
const argsXml = this.renderArgs(request.Args);
|
|
365
|
+
const inner = request.WrapperElement
|
|
366
|
+
? ` <${request.WrapperElement}>\n${argsXml}\n </${request.WrapperElement}>`
|
|
367
|
+
: argsXml;
|
|
368
|
+
return `<?xml version="1.0" encoding="utf-8"?>\n` +
|
|
369
|
+
`<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">\n` +
|
|
370
|
+
`${header} <soap:Body>\n` +
|
|
371
|
+
` <${request.Action} xmlns="${ns}">\n` +
|
|
372
|
+
`${inner}\n` +
|
|
373
|
+
` </${request.Action}>\n` +
|
|
374
|
+
` </soap:Body>\n` +
|
|
375
|
+
`</soap:Envelope>`;
|
|
376
|
+
}
|
|
377
|
+
/** Renders args as XML child elements, recursing into nested objects/arrays; nulls are skipped. */
|
|
378
|
+
renderArgs(args, indent = ' ') {
|
|
379
|
+
const parts = [];
|
|
380
|
+
for (const [key, value] of Object.entries(args)) {
|
|
381
|
+
const rendered = this.renderXmlValue(key, value, indent);
|
|
382
|
+
if (rendered)
|
|
383
|
+
parts.push(rendered);
|
|
384
|
+
}
|
|
385
|
+
return parts.join('\n');
|
|
386
|
+
}
|
|
387
|
+
renderXmlValue(key, value, indent) {
|
|
388
|
+
if (value == null)
|
|
389
|
+
return '';
|
|
390
|
+
if (Array.isArray(value)) {
|
|
391
|
+
return value
|
|
392
|
+
.map(item => this.renderXmlValue(key, item, indent))
|
|
393
|
+
.filter(s => s.length > 0)
|
|
394
|
+
.join('\n');
|
|
395
|
+
}
|
|
396
|
+
if (typeof value === 'object') {
|
|
397
|
+
const children = this.renderArgs(value, indent + ' ');
|
|
398
|
+
return `${indent}<${key}>\n${children}\n${indent}</${key}>`;
|
|
399
|
+
}
|
|
400
|
+
return `${indent}<${key}>${this.escapeXml(String(value))}</${key}>`;
|
|
401
|
+
}
|
|
402
|
+
// ── SOAP response parsing (XML → JS) ──────────────────────────────
|
|
403
|
+
/** Parses a SOAP response envelope into a normalized RESTResponse (Body = parsed <soap:Body> content). */
|
|
404
|
+
parseSoapResponse(xml, status, headers) {
|
|
405
|
+
const bodyInner = this.extractElementInner(xml, 'Body') ?? xml;
|
|
406
|
+
const fault = this.extractElementInner(bodyInner, 'Fault');
|
|
407
|
+
if (fault) {
|
|
408
|
+
return {
|
|
409
|
+
Status: status && status >= 400 ? status : 500,
|
|
410
|
+
Body: {
|
|
411
|
+
_soapFault: {
|
|
412
|
+
faultcode: this.extractElementInner(fault, 'faultcode')?.trim() ?? 'UNKNOWN',
|
|
413
|
+
faultstring: this.extractElementInner(fault, 'faultstring')?.trim() ?? 'unknown SOAP fault',
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
Headers: headers,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
return { Status: status, Body: this.xmlToObject(bodyInner), Headers: headers };
|
|
420
|
+
}
|
|
421
|
+
/** Recursively converts an XML fragment's inner content into a JS value (object / array / scalar). */
|
|
422
|
+
xmlToObject(xml) {
|
|
423
|
+
const normalized = xml.replace(/<(\w+(?::\w+)?)((?:\s[^>]*?)?)\/>/g, '<$1></$1>');
|
|
424
|
+
const children = this.extractChildren(normalized);
|
|
425
|
+
if (children.length === 0) {
|
|
426
|
+
return this.coerceScalar(normalized.trim());
|
|
427
|
+
}
|
|
428
|
+
const obj = {};
|
|
429
|
+
for (const child of children) {
|
|
430
|
+
const value = this.xmlToObject(child.inner);
|
|
431
|
+
const existing = obj[child.tag];
|
|
432
|
+
if (existing === undefined) {
|
|
433
|
+
obj[child.tag] = value;
|
|
434
|
+
}
|
|
435
|
+
else if (Array.isArray(existing)) {
|
|
436
|
+
existing.push(value);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
obj[child.tag] = [existing, value];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return obj;
|
|
443
|
+
}
|
|
444
|
+
extractChildren(xml) {
|
|
445
|
+
const results = [];
|
|
446
|
+
const regex = /<(?:\w+:)?(\w+)(?:\s[^>]*)?>([\s\S]*?)<\/(?:\w+:)?\1>/g;
|
|
447
|
+
let match;
|
|
448
|
+
while ((match = regex.exec(xml)) !== null) {
|
|
449
|
+
results.push({ tag: match[1], inner: match[2] });
|
|
450
|
+
}
|
|
451
|
+
return results;
|
|
452
|
+
}
|
|
453
|
+
/** Returns the inner content of the first element with the given LOCAL name (namespace-agnostic). */
|
|
454
|
+
extractElementInner(xml, localName) {
|
|
455
|
+
const re = new RegExp(`<(?:\\w+:)?${this.escapeRegex(localName)}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/(?:\\w+:)?${this.escapeRegex(localName)}>`, 'i');
|
|
456
|
+
const m = xml.match(re);
|
|
457
|
+
return m ? m[1] : null;
|
|
458
|
+
}
|
|
459
|
+
coerceScalar(raw) {
|
|
460
|
+
if (raw === '')
|
|
461
|
+
return null;
|
|
462
|
+
if (raw === 'true')
|
|
463
|
+
return true;
|
|
464
|
+
if (raw === 'false')
|
|
465
|
+
return false;
|
|
466
|
+
if (/^-?\d+$/.test(raw))
|
|
467
|
+
return parseInt(raw, 10);
|
|
468
|
+
if (/^-?\d+\.\d+$/.test(raw))
|
|
469
|
+
return parseFloat(raw);
|
|
470
|
+
return this.decodeXml(raw);
|
|
471
|
+
}
|
|
472
|
+
// ── Fault handling ────────────────────────────────────────────────
|
|
473
|
+
/** Returns the parsed SOAP fault ({faultcode, faultstring}) if present, else null. */
|
|
474
|
+
extractSoapFault(body) {
|
|
475
|
+
if (body && typeof body === 'object') {
|
|
476
|
+
const f = body._soapFault;
|
|
477
|
+
if (f && typeof f === 'object') {
|
|
478
|
+
const rec = f;
|
|
479
|
+
return {
|
|
480
|
+
faultcode: String(rec.faultcode ?? 'UNKNOWN'),
|
|
481
|
+
faultstring: String(rec.faultstring ?? 'unknown SOAP fault'),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Reads the vendor's IN-BAND error signal from a mutation response body (SaveResult / *Result wrapper).
|
|
489
|
+
* Per the frozen contract's ErrorResponseShape: a 200/literal SOAP body can signal failure via `error`
|
|
490
|
+
* (s:double, 0 = success by convention), an `errorObj` (tns:Error: errorCode/errorMessage/errorDetails/…),
|
|
491
|
+
* and/or a human `msg` — a SOAP Fault is NOT the only failure signal this API uses. Returns a
|
|
492
|
+
* human-readable message when the body signals an error, else null.
|
|
493
|
+
*/
|
|
494
|
+
extractInBandError(body) {
|
|
495
|
+
const result = this.unwrapSoapResult(body);
|
|
496
|
+
if (!result || typeof result !== 'object' || Array.isArray(result))
|
|
497
|
+
return null;
|
|
498
|
+
const rec = result;
|
|
499
|
+
// errorObj (tns:Error) present with substance → failure.
|
|
500
|
+
const errObj = rec.errorObj;
|
|
501
|
+
if (errObj && typeof errObj === 'object' && !Array.isArray(errObj)) {
|
|
502
|
+
const eo = errObj;
|
|
503
|
+
const substantive = (v) => v != null && String(v).trim().length > 0 && String(v).trim() !== '0';
|
|
504
|
+
if ([eo.errorNumber, eo.errorCode, eo.errorMessage, eo.errorDetails, eo.errorType].some(substantive)) {
|
|
505
|
+
const msg = [eo.errorMessage, eo.errorDetails].find(v => v != null && String(v).trim().length > 0);
|
|
506
|
+
return String(msg ?? `errorCode=${eo.errorCode ?? eo.errorNumber ?? 'unknown'}`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
// Numeric `error` flag: null/absent/0 = success; anything else = failure.
|
|
510
|
+
const errFlag = rec.error;
|
|
511
|
+
if (errFlag != null) {
|
|
512
|
+
const n = typeof errFlag === 'number' ? errFlag : Number(String(errFlag));
|
|
513
|
+
if (Number.isFinite(n) && n !== 0) {
|
|
514
|
+
const humanMsg = typeof rec.msg === 'string' && rec.msg.trim().length > 0 ? rec.msg.trim() : undefined;
|
|
515
|
+
return humanMsg ?? `vendor error flag=${n}`;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
/** Throws a descriptive error when a response carries a SOAP fault, and invalidates the session. */
|
|
521
|
+
throwOnSoapFault(response, action) {
|
|
522
|
+
const fault = this.extractSoapFault(response.Body);
|
|
523
|
+
if (fault) {
|
|
524
|
+
this.cachedSession = null; // a fault may be an expired session — force re-auth next call
|
|
525
|
+
throw new Error(`MagnetMail SOAP Fault on ${action} [${fault.faultcode}]: ${fault.faultstring}`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
// ── Config / session helpers ──────────────────────────────────────
|
|
529
|
+
isSessionValid() {
|
|
530
|
+
if (!this.cachedSession)
|
|
531
|
+
return false;
|
|
532
|
+
return Date.now() - this.cachedSession.CreatedAt < this.cachedSession.TTLMs;
|
|
533
|
+
}
|
|
534
|
+
preAuthContext(config) {
|
|
535
|
+
return { SessionID: '', UserId: '', Endpoint: config.Endpoint, Namespace: config.Namespace };
|
|
536
|
+
}
|
|
537
|
+
/** Resolves connection config from the credential store (secrets) + Configuration JSON (overrides). */
|
|
538
|
+
async ParseConfig(companyIntegration, contextUser) {
|
|
539
|
+
const raw = {};
|
|
540
|
+
if (companyIntegration.CredentialID) {
|
|
541
|
+
Object.assign(raw, await this.loadCredentialValues(companyIntegration.CredentialID, contextUser));
|
|
542
|
+
}
|
|
543
|
+
if (companyIntegration.Configuration) {
|
|
544
|
+
try {
|
|
545
|
+
Object.assign(raw, JSON.parse(companyIntegration.Configuration));
|
|
546
|
+
}
|
|
547
|
+
catch {
|
|
548
|
+
// non-fatal: fall through to whatever the credential store provided
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return this.normalizeConfig(raw);
|
|
552
|
+
}
|
|
553
|
+
async loadCredentialValues(credentialID, contextUser) {
|
|
554
|
+
const md = new Metadata();
|
|
555
|
+
const credential = await md.GetEntityObject('MJ: Credentials', contextUser);
|
|
556
|
+
const loaded = await credential.Load(credentialID);
|
|
557
|
+
if (!loaded || !credential.Values)
|
|
558
|
+
return {};
|
|
559
|
+
try {
|
|
560
|
+
return JSON.parse(credential.Values);
|
|
561
|
+
}
|
|
562
|
+
catch {
|
|
563
|
+
return {};
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
normalizeConfig(raw) {
|
|
567
|
+
const pick = (...keys) => {
|
|
568
|
+
for (const key of keys) {
|
|
569
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
570
|
+
if (k.toLowerCase() === key.toLowerCase() && typeof v === 'string' && v.length > 0)
|
|
571
|
+
return v;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return undefined;
|
|
575
|
+
};
|
|
576
|
+
const candidate = {
|
|
577
|
+
Username: pick('username', 'user', 'userId', 'user_id', 'login') ?? '',
|
|
578
|
+
Password: pick('password', 'pass', 'pwd') ?? '',
|
|
579
|
+
Endpoint: pick('endpoint', 'url') ?? DEFAULT_ENDPOINT,
|
|
580
|
+
Namespace: pick('namespace', 'ns') ?? DEFAULT_NAMESPACE,
|
|
581
|
+
SessionTTLMs: typeof raw.SessionTTLMs === 'number' ? raw.SessionTTLMs : DEFAULT_SESSION_TTL_MS,
|
|
582
|
+
};
|
|
583
|
+
const parsed = ConfigSchema.safeParse(candidate);
|
|
584
|
+
if (!parsed.success) {
|
|
585
|
+
throw new Error(`MagnetMail configuration invalid: ${parsed.error.issues.map(i => i.message).join('; ')}`);
|
|
586
|
+
}
|
|
587
|
+
return candidate;
|
|
588
|
+
}
|
|
589
|
+
// ── Fetch-arg + watermark helpers ─────────────────────────────────
|
|
590
|
+
buildFetchArgs(obj, cfg, ctx, page, pageSize) {
|
|
591
|
+
const args = {};
|
|
592
|
+
const extraArgs = cfg.ExtraArgs;
|
|
593
|
+
if (extraArgs && typeof extraArgs === 'object' && !Array.isArray(extraArgs)) {
|
|
594
|
+
Object.assign(args, extraArgs);
|
|
595
|
+
}
|
|
596
|
+
if (obj.SupportsPagination && obj.PaginationType !== 'None') {
|
|
597
|
+
const pageParam = this.readConfigString(cfg, 'PageNumberParam') ?? 'pageNumber';
|
|
598
|
+
const sizeParam = this.readConfigString(cfg, 'PageCountParam') ?? 'pageCount';
|
|
599
|
+
args[pageParam] = page;
|
|
600
|
+
args[sizeParam] = pageSize;
|
|
601
|
+
}
|
|
602
|
+
if (obj.SupportsIncrementalSync && ctx.WatermarkValue && obj.IncrementalWatermarkField) {
|
|
603
|
+
args[obj.IncrementalWatermarkField] = this.formatWatermark(ctx.WatermarkValue);
|
|
604
|
+
const toParam = this.readConfigString(cfg, 'WatermarkToParam');
|
|
605
|
+
if (toParam)
|
|
606
|
+
args[toParam] = this.formatWatermark(new Date().toISOString());
|
|
607
|
+
}
|
|
608
|
+
return args;
|
|
609
|
+
}
|
|
610
|
+
/** Max record-side watermark value in the batch, or undefined when not incremental / no field present. */
|
|
611
|
+
computeWatermark(obj, cfg, records) {
|
|
612
|
+
if (!obj.SupportsIncrementalSync)
|
|
613
|
+
return undefined;
|
|
614
|
+
const valueField = this.readConfigString(cfg, 'WatermarkValueField') ?? obj.IncrementalWatermarkField;
|
|
615
|
+
if (!valueField)
|
|
616
|
+
return undefined;
|
|
617
|
+
let max;
|
|
618
|
+
for (const record of records) {
|
|
619
|
+
const v = record[valueField];
|
|
620
|
+
if (v != null) {
|
|
621
|
+
const s = String(v);
|
|
622
|
+
if (!max || s > max)
|
|
623
|
+
max = s;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return max;
|
|
627
|
+
}
|
|
628
|
+
formatWatermark(watermark) {
|
|
629
|
+
if (/^\d+$/.test(watermark)) {
|
|
630
|
+
const asNum = Number(watermark);
|
|
631
|
+
if (Number.isFinite(asNum) && asNum > 100000000000)
|
|
632
|
+
return new Date(asNum).toISOString();
|
|
633
|
+
}
|
|
634
|
+
return watermark;
|
|
635
|
+
}
|
|
636
|
+
// ── Record + response shaping helpers ─────────────────────────────
|
|
637
|
+
toRecordArray(target) {
|
|
638
|
+
if (target == null)
|
|
639
|
+
return [];
|
|
640
|
+
if (Array.isArray(target)) {
|
|
641
|
+
return target.filter(x => x != null && typeof x === 'object');
|
|
642
|
+
}
|
|
643
|
+
if (typeof target === 'object')
|
|
644
|
+
return [target];
|
|
645
|
+
return [];
|
|
646
|
+
}
|
|
647
|
+
/** Descends `Response`/`Result` wrapper elements to expose the inner payload. */
|
|
648
|
+
unwrapSoapResult(body) {
|
|
649
|
+
let current = body;
|
|
650
|
+
for (let depth = 0; depth < 6; depth++) {
|
|
651
|
+
if (!current || typeof current !== 'object' || Array.isArray(current))
|
|
652
|
+
return current;
|
|
653
|
+
const keys = Object.keys(current);
|
|
654
|
+
const wrapperKey = keys.find(k => /(?:Response|Result)$/i.test(k));
|
|
655
|
+
if (!wrapperKey || keys.length === 0)
|
|
656
|
+
return current;
|
|
657
|
+
current = current[wrapperKey];
|
|
658
|
+
}
|
|
659
|
+
return current;
|
|
660
|
+
}
|
|
661
|
+
/** Depth-first search for the first value under `key` anywhere in the object tree. */
|
|
662
|
+
deepFindKey(body, key) {
|
|
663
|
+
if (!body || typeof body !== 'object')
|
|
664
|
+
return undefined;
|
|
665
|
+
if (Array.isArray(body)) {
|
|
666
|
+
for (const item of body) {
|
|
667
|
+
const found = this.deepFindKey(item, key);
|
|
668
|
+
if (found !== undefined)
|
|
669
|
+
return found;
|
|
670
|
+
}
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
const rec = body;
|
|
674
|
+
if (key in rec)
|
|
675
|
+
return rec[key];
|
|
676
|
+
for (const value of Object.values(rec)) {
|
|
677
|
+
const found = this.deepFindKey(value, key);
|
|
678
|
+
if (found !== undefined)
|
|
679
|
+
return found;
|
|
680
|
+
}
|
|
681
|
+
return undefined;
|
|
682
|
+
}
|
|
683
|
+
firstArrayValue(body) {
|
|
684
|
+
for (const value of Object.values(body)) {
|
|
685
|
+
if (Array.isArray(value))
|
|
686
|
+
return value;
|
|
687
|
+
if (value && typeof value === 'object') {
|
|
688
|
+
const nested = this.firstArrayValue(value);
|
|
689
|
+
if (nested)
|
|
690
|
+
return nested;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
recordCount(rawBody) {
|
|
696
|
+
const unwrapped = this.unwrapSoapResult(rawBody);
|
|
697
|
+
if (Array.isArray(unwrapped))
|
|
698
|
+
return unwrapped.length;
|
|
699
|
+
if (unwrapped && typeof unwrapped === 'object') {
|
|
700
|
+
const arr = this.firstArrayValue(unwrapped);
|
|
701
|
+
if (arr)
|
|
702
|
+
return arr.length;
|
|
703
|
+
return Object.keys(unwrapped).length > 0 ? 1 : 0;
|
|
704
|
+
}
|
|
705
|
+
return 0;
|
|
706
|
+
}
|
|
707
|
+
readNestedString(body, key) {
|
|
708
|
+
const v = this.deepFindKey(body, key);
|
|
709
|
+
return v == null ? undefined : String(v);
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* §4 identity: uses the declared PK when every component is present + non-empty, else a deterministic
|
|
713
|
+
* content hash (so PK-less / partial-key records stay syncable + dedupable). Full-record pass-through:
|
|
714
|
+
* Fields carries the complete source record (with the synthetic id stamped into a single empty PK).
|
|
715
|
+
*/
|
|
716
|
+
buildExternalRecord(raw, objectType, pkFieldNames) {
|
|
717
|
+
const allPkPresent = pkFieldNames.length > 0
|
|
718
|
+
&& pkFieldNames.every(name => raw[name] != null && serializeKeyValue(raw[name]).length > 0);
|
|
719
|
+
const resolvedID = allPkPresent
|
|
720
|
+
? pkFieldNames.map(name => serializeKeyValue(raw[name])).join('|')
|
|
721
|
+
: computeContentHash(raw);
|
|
722
|
+
let fields = raw;
|
|
723
|
+
if (!allPkPresent && pkFieldNames.length === 1
|
|
724
|
+
&& (raw[pkFieldNames[0]] == null || serializeKeyValue(raw[pkFieldNames[0]]).length === 0)) {
|
|
725
|
+
fields = { ...raw, [pkFieldNames[0]]: resolvedID };
|
|
726
|
+
}
|
|
727
|
+
return { ExternalID: resolvedID, ObjectType: objectType, Fields: fields };
|
|
728
|
+
}
|
|
729
|
+
primaryKeyFieldNames(fields) {
|
|
730
|
+
const pk = fields.filter(f => f.IsPrimaryKey).sort((a, b) => a.Sequence - b.Sequence).map(f => f.Name);
|
|
731
|
+
return pk.length > 0 ? pk : ['id'];
|
|
732
|
+
}
|
|
733
|
+
extractMutationId(body, obj) {
|
|
734
|
+
const result = this.unwrapSoapResult(body);
|
|
735
|
+
// SaveResult.id is the documented create-id location; also try the object's PK field name.
|
|
736
|
+
const fromId = this.readNestedString(result, 'id') ?? this.readNestedString(result, 'ID');
|
|
737
|
+
if (fromId)
|
|
738
|
+
return fromId;
|
|
739
|
+
const fields = this.GetCachedFields(obj.ID);
|
|
740
|
+
const pkName = this.primaryKeyFieldNames(fields)[0];
|
|
741
|
+
return pkName ? this.readNestedString(result, pkName) : undefined;
|
|
742
|
+
}
|
|
743
|
+
buildCRUDError(err, operation, objectName) {
|
|
744
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
745
|
+
return { Success: false, ErrorMessage: `${operation} failed for ${objectName}: ${message}`, StatusCode: 500 };
|
|
746
|
+
}
|
|
747
|
+
// ── IO Configuration JSON readers ─────────────────────────────────
|
|
748
|
+
readIOConfig(obj) {
|
|
749
|
+
if (!obj.Configuration)
|
|
750
|
+
return {};
|
|
751
|
+
try {
|
|
752
|
+
const parsed = JSON.parse(obj.Configuration);
|
|
753
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
754
|
+
}
|
|
755
|
+
catch {
|
|
756
|
+
return {};
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
readConfigString(cfg, key) {
|
|
760
|
+
const v = cfg[key];
|
|
761
|
+
return typeof v === 'string' && v.trim().length > 0 ? v.trim() : null;
|
|
762
|
+
}
|
|
763
|
+
// ── XML utils ─────────────────────────────────────────────────────
|
|
764
|
+
headersToObject(headers) {
|
|
765
|
+
const out = {};
|
|
766
|
+
headers.forEach((value, key) => { out[key.toLowerCase()] = value; });
|
|
767
|
+
return out;
|
|
768
|
+
}
|
|
769
|
+
escapeXml(value) {
|
|
770
|
+
return value
|
|
771
|
+
.replace(/&/g, '&')
|
|
772
|
+
.replace(/</g, '<')
|
|
773
|
+
.replace(/>/g, '>')
|
|
774
|
+
.replace(/"/g, '"')
|
|
775
|
+
.replace(/'/g, ''');
|
|
776
|
+
}
|
|
777
|
+
decodeXml(value) {
|
|
778
|
+
return value
|
|
779
|
+
.replace(/</g, '<')
|
|
780
|
+
.replace(/>/g, '>')
|
|
781
|
+
.replace(/"/g, '"')
|
|
782
|
+
.replace(/'/g, "'")
|
|
783
|
+
.replace(/&/g, '&');
|
|
784
|
+
}
|
|
785
|
+
escapeRegex(value) {
|
|
786
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
MagnetMailConnector = __decorate([
|
|
790
|
+
RegisterClass(BaseIntegrationConnector, 'MagnetMailConnector')
|
|
791
|
+
], MagnetMailConnector);
|
|
792
|
+
export { MagnetMailConnector };
|
|
793
|
+
/** Tree-shaking prevention — import and call from the package entry point. */
|
|
794
|
+
export function LoadMagnetMailConnector() { }
|
|
795
|
+
//# sourceMappingURL=MagnetMailConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagnetMailConnector.js","sourceRoot":"","sources":["../src/MagnetMailConnector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export * from './MagnetMailConnector.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 './MagnetMailConnector.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,0BAA0B,CAAC;AAEzC;oGACoG;AACpG,MAAM,UAAU,iBAAiB,KAAiD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memberjunction/connector-magnetmail",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "MemberJunction MagnetMail 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
|
+
"@memberjunction/integration-engine-base": ">=5.42.0 <6.0.0"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@memberjunction/connector-schema-merge": "^1.0.0",
|
|
26
|
+
"zod": "~3.24.4"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "24.10.11",
|
|
30
|
+
"tsc-alias": "^1.8.16",
|
|
31
|
+
"typescript": "^5.9.3",
|
|
32
|
+
"vitest": "^4.0.18",
|
|
33
|
+
"@memberjunction/core": "^5.42.0",
|
|
34
|
+
"@memberjunction/core-entities": "^5.42.0",
|
|
35
|
+
"@memberjunction/global": "^5.42.0",
|
|
36
|
+
"@memberjunction/integration-engine": "^5.42.0",
|
|
37
|
+
"@memberjunction/integration-engine-base": "^5.42.0",
|
|
38
|
+
"@memberjunction/connector-schema-merge": "^1.0.0"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/MemberJunction/Integrations"
|
|
43
|
+
}
|
|
44
|
+
}
|