@memberjunction/integration-engine 0.0.1 → 5.9.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.
Files changed (50) hide show
  1. package/README.md +142 -28
  2. package/dist/BaseIntegrationConnector.d.ts +177 -0
  3. package/dist/BaseIntegrationConnector.d.ts.map +1 -0
  4. package/dist/BaseIntegrationConnector.js +110 -0
  5. package/dist/BaseIntegrationConnector.js.map +1 -0
  6. package/dist/BaseRESTIntegrationConnector.d.ts +222 -0
  7. package/dist/BaseRESTIntegrationConnector.d.ts.map +1 -0
  8. package/dist/BaseRESTIntegrationConnector.js +482 -0
  9. package/dist/BaseRESTIntegrationConnector.js.map +1 -0
  10. package/dist/ConnectorFactory.d.ts +28 -0
  11. package/dist/ConnectorFactory.d.ts.map +1 -0
  12. package/dist/ConnectorFactory.js +42 -0
  13. package/dist/ConnectorFactory.js.map +1 -0
  14. package/dist/FieldMappingEngine.d.ts +94 -0
  15. package/dist/FieldMappingEngine.d.ts.map +1 -0
  16. package/dist/FieldMappingEngine.js +250 -0
  17. package/dist/FieldMappingEngine.js.map +1 -0
  18. package/dist/IntegrationEngine.d.ts +173 -0
  19. package/dist/IntegrationEngine.d.ts.map +1 -0
  20. package/dist/IntegrationEngine.js +677 -0
  21. package/dist/IntegrationEngine.js.map +1 -0
  22. package/dist/MatchEngine.d.ts +51 -0
  23. package/dist/MatchEngine.d.ts.map +1 -0
  24. package/dist/MatchEngine.js +129 -0
  25. package/dist/MatchEngine.js.map +1 -0
  26. package/dist/RetryRunner.d.ts +27 -0
  27. package/dist/RetryRunner.d.ts.map +1 -0
  28. package/dist/RetryRunner.js +59 -0
  29. package/dist/RetryRunner.js.map +1 -0
  30. package/dist/WatermarkService.d.ts +44 -0
  31. package/dist/WatermarkService.d.ts.map +1 -0
  32. package/dist/WatermarkService.js +97 -0
  33. package/dist/WatermarkService.js.map +1 -0
  34. package/dist/entity-types.d.ts +90 -0
  35. package/dist/entity-types.d.ts.map +1 -0
  36. package/dist/entity-types.js +13 -0
  37. package/dist/entity-types.js.map +1 -0
  38. package/dist/index.d.ts +16 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +19 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/transforms.d.ts +75 -0
  43. package/dist/transforms.d.ts.map +1 -0
  44. package/dist/transforms.js +2 -0
  45. package/dist/transforms.js.map +1 -0
  46. package/dist/types.d.ts +196 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +44 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +30 -7
@@ -0,0 +1,222 @@
1
+ import { type UserInfo } from '@memberjunction/core';
2
+ import type { MJCompanyIntegrationEntity, MJIntegrationObjectEntity } from '@memberjunction/core-entities';
3
+ import { BaseIntegrationConnector, type ExternalObjectSchema, type ExternalFieldSchema, type FetchContext, type FetchBatchResult } from './BaseIntegrationConnector.js';
4
+ import type { SourceSchemaInfo } from './types.js';
5
+ /** Authentication context returned by Authenticate(). Concrete connectors extend this. */
6
+ export interface RESTAuthContext {
7
+ /** Bearer or session token */
8
+ Token?: string;
9
+ /** Session ID for session-based APIs */
10
+ SessionID?: string;
11
+ /** When the auth token expires */
12
+ ExpiresAt?: Date;
13
+ /** Allow connector-specific auth properties */
14
+ [key: string]: unknown;
15
+ }
16
+ /** Normalized HTTP response from MakeHTTPRequest() */
17
+ export interface RESTResponse {
18
+ /** HTTP status code */
19
+ Status: number;
20
+ /** Parsed response body */
21
+ Body: unknown;
22
+ /** Response headers (lowercase keys) */
23
+ Headers: Record<string, string>;
24
+ }
25
+ /** Pagination state extracted from a vendor response */
26
+ export interface PaginationState {
27
+ /** Whether more pages remain */
28
+ HasMore: boolean;
29
+ /** Opaque cursor for cursor-based pagination */
30
+ NextCursor?: string;
31
+ /** Numeric offset for offset-based pagination */
32
+ NextOffset?: number;
33
+ /** Page number for page-based pagination */
34
+ NextPage?: number;
35
+ /** Total records reported by the API, if available */
36
+ TotalRecords?: number;
37
+ }
38
+ /** Pagination type values matching MJIntegrationObjectEntity.PaginationType */
39
+ export type PaginationType = 'Cursor' | 'None' | 'Offset' | 'PageNumber';
40
+ /**
41
+ * Abstract base class for REST API integration connectors.
42
+ *
43
+ * Implements the generic REST sync pattern: reads IntegrationObject/Field
44
+ * metadata from the MJ database, handles pagination, template variable
45
+ * resolution (per-parent iteration), and converts raw API responses to
46
+ * ExternalRecord format.
47
+ *
48
+ * Concrete connectors (YourMembership, Salesforce, HubSpot, etc.) extend
49
+ * this class and implement only auth, HTTP transport, and response normalization.
50
+ */
51
+ export declare abstract class BaseRESTIntegrationConnector extends BaseIntegrationConnector {
52
+ /**
53
+ * Authenticate with the external system and return an auth context.
54
+ * Called once per FetchChanges invocation; the returned context is
55
+ * passed to BuildHeaders and MakeHTTPRequest for every request.
56
+ */
57
+ protected abstract Authenticate(companyIntegration: MJCompanyIntegrationEntity): Promise<RESTAuthContext>;
58
+ /**
59
+ * Build HTTP headers for an API request, including auth headers.
60
+ * Called before every HTTP request.
61
+ */
62
+ protected abstract BuildHeaders(auth: RESTAuthContext): Record<string, string>;
63
+ /**
64
+ * Execute an HTTP request. The concrete connector owns the transport
65
+ * layer (fetch, axios, got, etc.).
66
+ */
67
+ protected abstract MakeHTTPRequest(auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
68
+ /**
69
+ * Extract the data array from the vendor-specific response envelope.
70
+ * @param rawBody - The parsed response body
71
+ * @param responseDataKey - The key to extract data from, or null for root-level arrays
72
+ * @returns Array of raw record objects
73
+ */
74
+ protected abstract NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
75
+ /**
76
+ * Extract pagination state from the vendor-specific response.
77
+ * @param rawBody - The parsed response body
78
+ * @param paginationType - The pagination strategy for this object
79
+ * @param currentPage - Current page number (1-based)
80
+ * @param currentOffset - Current record offset
81
+ * @param pageSize - Page size used in the request
82
+ * @returns Pagination state indicating whether more data is available
83
+ */
84
+ protected abstract ExtractPaginationInfo(rawBody: unknown, paginationType: PaginationType, currentPage: number, currentOffset: number, pageSize: number): PaginationState;
85
+ /**
86
+ * Get the base URL for API requests (e.g., "https://api.example.com/v1").
87
+ * Combined with the object's APIPath to form the full request URL.
88
+ */
89
+ protected abstract GetBaseURL(companyIntegration: MJCompanyIntegrationEntity): string;
90
+ /**
91
+ * Discovers available objects from the IntegrationEngineBase cache.
92
+ */
93
+ DiscoverObjects(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ExternalObjectSchema[]>;
94
+ /**
95
+ * Discovers fields for a specific object from the IntegrationEngineBase cache.
96
+ */
97
+ DiscoverFields(companyIntegration: MJCompanyIntegrationEntity, objectName: string, _contextUser: UserInfo): Promise<ExternalFieldSchema[]>;
98
+ /**
99
+ * Builds SourceSchemaInfo from IntegrationEngineBase cached metadata.
100
+ * Provides richer metadata than the base class implementation, including
101
+ * FK relationships derived from RelatedIntegrationObjectID.
102
+ */
103
+ IntrospectSchema(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<SourceSchemaInfo>;
104
+ /**
105
+ * Fetches records from the external REST API using metadata-driven configuration.
106
+ * Handles both flat endpoints and template-variable (per-parent) endpoints.
107
+ */
108
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
109
+ /**
110
+ * Fetches records from a flat endpoint (no template variable substitution).
111
+ */
112
+ private FetchFlat;
113
+ /**
114
+ * Fetches records from a template-variable endpoint by iterating over parent records.
115
+ * Identifies the parent object from FK field metadata, loads parent IDs from the
116
+ * local database, then fetches child records per parent.
117
+ */
118
+ private FetchWithTemplateVars;
119
+ /**
120
+ * Resolves which template variable maps to which FK field + parent object.
121
+ *
122
+ * Resolution strategy (in order):
123
+ * 1. Explicit: FK field with RelatedIntegrationObjectID that matches a template var name
124
+ * 2. PK fallback: finds a sibling integration object whose primary key field name
125
+ * matches the template var, allowing resolution without explicit FK metadata
126
+ *
127
+ * Returns null if no match is found by either strategy.
128
+ */
129
+ private ResolveParentInfo;
130
+ /**
131
+ * Fallback resolution: finds a sibling integration object whose primary key
132
+ * field name matches one of the template variables (case-insensitive).
133
+ * E.g., {ProfileID} matches Members object which has PK field "ProfileID".
134
+ */
135
+ private ResolveParentByPKMatch;
136
+ /**
137
+ * Loads parent record IDs from the local MJ database.
138
+ * Uses IntegrationEngineBase cache for object/field metadata lookups,
139
+ * then queries the MJ entity via RunView for actual synced record IDs.
140
+ */
141
+ private LoadParentIDs;
142
+ /**
143
+ * Fetches records from a single URL with pagination support.
144
+ * Loops through pages until no more data or maxRecords is reached.
145
+ */
146
+ private FetchWithPagination;
147
+ /**
148
+ * Fetches a single non-paginated page.
149
+ */
150
+ private FetchSinglePage;
151
+ /**
152
+ * Iterates through paginated responses until exhausted or maxRecords is reached.
153
+ */
154
+ private FetchPaginatedLoop;
155
+ /**
156
+ * Combines baseURL and apiPath into a full URL.
157
+ */
158
+ private BuildFullURL;
159
+ /**
160
+ * Appends pagination parameters to a URL based on the object's PaginationType.
161
+ * Override in subclasses to use vendor-specific parameter names.
162
+ */
163
+ protected BuildPaginatedURL(basePath: string, obj: MJIntegrationObjectEntity, page: number, offset: number, cursor?: string): string;
164
+ /**
165
+ * Appends default query parameters from the IntegrationObject metadata.
166
+ * DefaultQueryParams is stored as a JSON object like {"key": "value"}.
167
+ * Automatically skips params whose key (case-insensitive) already appears
168
+ * in the URL to avoid duplicates with pagination params.
169
+ */
170
+ protected AppendDefaultQueryParams(url: string, obj: MJIntegrationObjectEntity): string;
171
+ /**
172
+ * Extracts query parameter keys from a URL, returned as a Set of lowercase strings.
173
+ * Used to detect duplicates between pagination params and DefaultQueryParams.
174
+ */
175
+ private ExtractURLParamKeys;
176
+ /**
177
+ * Detects template variables in an API path. Template variables use
178
+ * the format {VariableName} (e.g., "/profiles/{ProfileID}/events").
179
+ */
180
+ private DetectTemplateVars;
181
+ /**
182
+ * Substitutes a single template variable in a path.
183
+ */
184
+ private SubstituteTemplateVars;
185
+ /**
186
+ * Gets an IntegrationObject from the engine's cache by integration ID and object name.
187
+ * Throws if not found.
188
+ */
189
+ private GetCachedObject;
190
+ /**
191
+ * Gets IntegrationObjectField records from the engine's cache for a given object ID.
192
+ * Returns only active fields sorted by Sequence.
193
+ */
194
+ private GetCachedFields;
195
+ /**
196
+ * Converts a raw API record object to the ExternalRecord format.
197
+ */
198
+ private ToExternalRecord;
199
+ /**
200
+ * Finds the primary key field name from a set of IntegrationObjectField records.
201
+ * Falls back to "ID" if no PK field is explicitly marked.
202
+ */
203
+ private FindPrimaryKeyFieldName;
204
+ /**
205
+ * Converts an IntegrationObjectFieldEntity to the ExternalFieldSchema format.
206
+ */
207
+ private FieldEntityToSchema;
208
+ /**
209
+ * Builds a SourceObjectInfo from an IntegrationObject and its fields.
210
+ * Resolves FK relationships using the RelatedIntegrationObjectID.
211
+ */
212
+ private BuildSourceObjectInfo;
213
+ /**
214
+ * Builds SourceRelationshipInfo entries from FK fields.
215
+ */
216
+ private BuildRelationships;
217
+ /**
218
+ * Validates an HTTP response and throws a descriptive error on non-2xx status.
219
+ */
220
+ private ValidateHTTPResponse;
221
+ }
222
+ //# sourceMappingURL=BaseRESTIntegrationConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseRESTIntegrationConnector.d.ts","sourceRoot":"","sources":["../src/BaseRESTIntegrationConnector.ts"],"names":[],"mappings":"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"}