@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.
- package/README.md +142 -28
- package/dist/BaseIntegrationConnector.d.ts +177 -0
- package/dist/BaseIntegrationConnector.d.ts.map +1 -0
- package/dist/BaseIntegrationConnector.js +110 -0
- package/dist/BaseIntegrationConnector.js.map +1 -0
- package/dist/BaseRESTIntegrationConnector.d.ts +222 -0
- package/dist/BaseRESTIntegrationConnector.d.ts.map +1 -0
- package/dist/BaseRESTIntegrationConnector.js +482 -0
- package/dist/BaseRESTIntegrationConnector.js.map +1 -0
- package/dist/ConnectorFactory.d.ts +28 -0
- package/dist/ConnectorFactory.d.ts.map +1 -0
- package/dist/ConnectorFactory.js +42 -0
- package/dist/ConnectorFactory.js.map +1 -0
- package/dist/FieldMappingEngine.d.ts +94 -0
- package/dist/FieldMappingEngine.d.ts.map +1 -0
- package/dist/FieldMappingEngine.js +250 -0
- package/dist/FieldMappingEngine.js.map +1 -0
- package/dist/IntegrationEngine.d.ts +173 -0
- package/dist/IntegrationEngine.d.ts.map +1 -0
- package/dist/IntegrationEngine.js +677 -0
- package/dist/IntegrationEngine.js.map +1 -0
- package/dist/MatchEngine.d.ts +51 -0
- package/dist/MatchEngine.d.ts.map +1 -0
- package/dist/MatchEngine.js +129 -0
- package/dist/MatchEngine.js.map +1 -0
- package/dist/RetryRunner.d.ts +27 -0
- package/dist/RetryRunner.d.ts.map +1 -0
- package/dist/RetryRunner.js +59 -0
- package/dist/RetryRunner.js.map +1 -0
- package/dist/WatermarkService.d.ts +44 -0
- package/dist/WatermarkService.d.ts.map +1 -0
- package/dist/WatermarkService.js +97 -0
- package/dist/WatermarkService.js.map +1 -0
- package/dist/entity-types.d.ts +90 -0
- package/dist/entity-types.d.ts.map +1 -0
- package/dist/entity-types.js +13 -0
- package/dist/entity-types.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/transforms.d.ts +75 -0
- package/dist/transforms.d.ts.map +1 -0
- package/dist/transforms.js +2 -0
- package/dist/transforms.js.map +1 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +44 -0
- package/dist/types.js.map +1 -0
- package/package.json +30 -7
package/README.md
CHANGED
|
@@ -1,45 +1,159 @@
|
|
|
1
1
|
# @memberjunction/integration-engine
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MemberJunction Integration Engine — orchestration, field mapping, and connector framework for synchronizing external systems with MJ entities.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
The integration engine follows a pipeline architecture:
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
```
|
|
10
|
+
External System → Connector → FieldMappingEngine → MatchEngine → MJ Entity Persistence
|
|
11
|
+
```
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
### Core Components
|
|
14
|
+
|
|
15
|
+
| Component | Responsibility |
|
|
16
|
+
|-----------|---------------|
|
|
17
|
+
| `BaseIntegrationConnector` | Abstract base for external system connectors |
|
|
18
|
+
| `ConnectorFactory` | Resolves connector instances via MJGlobal.ClassFactory |
|
|
19
|
+
| `FieldMappingEngine` | Applies field-level transformations from external→MJ fields |
|
|
20
|
+
| `MatchEngine` | Determines Create/Update/Delete/Skip for each record |
|
|
21
|
+
| `WatermarkService` | Manages incremental sync watermarks |
|
|
22
|
+
| `IntegrationOrchestrator` | Top-level coordinator that runs end-to-end sync |
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { IntegrationOrchestrator } from '@memberjunction/integration-engine';
|
|
28
|
+
|
|
29
|
+
const orchestrator = new IntegrationOrchestrator();
|
|
30
|
+
const result = await orchestrator.RunSync(companyIntegrationID, contextUser, 'Manual');
|
|
31
|
+
|
|
32
|
+
console.log(`Processed: ${result.RecordsProcessed}`);
|
|
33
|
+
console.log(`Created: ${result.RecordsCreated}, Updated: ${result.RecordsUpdated}`);
|
|
34
|
+
console.log(`Errors: ${result.RecordsErrored}`);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Creating a Custom Connector
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
41
|
+
import {
|
|
42
|
+
BaseIntegrationConnector,
|
|
43
|
+
ConnectionTestResult,
|
|
44
|
+
ExternalObjectSchema,
|
|
45
|
+
ExternalFieldSchema,
|
|
46
|
+
FetchContext,
|
|
47
|
+
FetchBatchResult,
|
|
48
|
+
} from '@memberjunction/integration-engine';
|
|
8
49
|
|
|
9
|
-
|
|
50
|
+
@RegisterClass(BaseIntegrationConnector, 'HubSpotConnector')
|
|
51
|
+
export class HubSpotConnector extends BaseIntegrationConnector {
|
|
52
|
+
async TestConnection(companyIntegration, contextUser): Promise<ConnectionTestResult> {
|
|
53
|
+
// Test HubSpot API connectivity
|
|
54
|
+
}
|
|
10
55
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
56
|
+
async DiscoverObjects(companyIntegration, contextUser): Promise<ExternalObjectSchema[]> {
|
|
57
|
+
// Return available HubSpot objects (Contacts, Companies, Deals, etc.)
|
|
58
|
+
}
|
|
15
59
|
|
|
16
|
-
|
|
60
|
+
async DiscoverFields(companyIntegration, objectName, contextUser): Promise<ExternalFieldSchema[]> {
|
|
61
|
+
// Return fields for a specific HubSpot object
|
|
62
|
+
}
|
|
17
63
|
|
|
18
|
-
|
|
64
|
+
async FetchChanges(ctx: FetchContext): Promise<FetchBatchResult> {
|
|
65
|
+
// Fetch changed records using HubSpot's API with watermark-based pagination
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
19
69
|
|
|
20
|
-
##
|
|
70
|
+
## Transform Types
|
|
21
71
|
|
|
22
|
-
|
|
72
|
+
The `FieldMappingEngine` supports 9 transform types configured via JSON in the `TransformPipeline` field:
|
|
23
73
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
74
|
+
| Type | Description | Config |
|
|
75
|
+
|------|-------------|--------|
|
|
76
|
+
| `direct` | Pass-through with optional default | `{ DefaultValue?: unknown }` |
|
|
77
|
+
| `regex` | Regex find/replace | `{ Pattern, Replacement, Flags? }` |
|
|
78
|
+
| `split` | Split string, extract by index | `{ Delimiter, Index }` |
|
|
79
|
+
| `combine` | Merge multiple fields | `{ SourceFields, Separator }` |
|
|
80
|
+
| `lookup` | Case-insensitive value mapping | `{ Map, Default? }` |
|
|
81
|
+
| `format` | Date/number formatting | `{ FormatString, FormatType }` |
|
|
82
|
+
| `coerce` | Type conversion | `{ TargetType: 'string'|'number'|'boolean'|'date' }` |
|
|
83
|
+
| `substring` | Extract portion of string | `{ Start, Length? }` |
|
|
84
|
+
| `custom` | JavaScript expression | `{ Expression }` |
|
|
28
85
|
|
|
29
|
-
|
|
86
|
+
### Transform Pipeline Example
|
|
30
87
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
88
|
+
```json
|
|
89
|
+
[
|
|
90
|
+
{ "Type": "regex", "Config": { "Pattern": "[^0-9]", "Replacement": "", "Flags": "g" } },
|
|
91
|
+
{ "Type": "substring", "Config": { "Start": 0, "Length": 3 } }
|
|
92
|
+
]
|
|
93
|
+
```
|
|
36
94
|
|
|
37
|
-
|
|
95
|
+
This pipeline strips non-numeric characters then extracts the first 3 digits (e.g., area code from phone number).
|
|
38
96
|
|
|
39
|
-
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
97
|
+
### Error Handling
|
|
42
98
|
|
|
43
|
-
|
|
99
|
+
Each transform step can specify `OnError`:
|
|
100
|
+
- `"Fail"` (default) — throws, halting the record
|
|
101
|
+
- `"Skip"` — skips the field entirely
|
|
102
|
+
- `"Null"` — sets the field to null
|
|
44
103
|
|
|
45
|
-
|
|
104
|
+
## API Reference
|
|
105
|
+
|
|
106
|
+
### Notifications
|
|
107
|
+
|
|
108
|
+
After a sync completes or fails, an optional `onNotification` callback receives a `SyncNotification` with pre-formatted subject and body text suitable for email delivery:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const result = await orchestrator.RunSync(
|
|
112
|
+
companyIntegrationID, contextUser, 'Scheduled',
|
|
113
|
+
undefined, // onProgress
|
|
114
|
+
(notification) => {
|
|
115
|
+
if (notification.Severity !== 'Info') {
|
|
116
|
+
emailService.send({
|
|
117
|
+
to: 'ops@example.com',
|
|
118
|
+
subject: notification.Subject,
|
|
119
|
+
text: notification.Body,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**SyncNotification** properties:
|
|
127
|
+
- `Event`: `'SyncCompleted'` | `'SyncCompletedWithErrors'` | `'SyncFailed'`
|
|
128
|
+
- `Severity`: `'Info'` | `'Warning'` | `'Error'`
|
|
129
|
+
- `Subject` / `Body`: human-readable text ready for email
|
|
130
|
+
- `Result`: the full `SyncResult` for programmatic access
|
|
131
|
+
|
|
132
|
+
### IntegrationOrchestrator
|
|
133
|
+
|
|
134
|
+
- `RunSync(companyIntegrationID, contextUser, triggerType?, onProgress?, onNotification?)` — Executes a full sync run
|
|
135
|
+
|
|
136
|
+
### FieldMappingEngine
|
|
137
|
+
|
|
138
|
+
- `Apply(records, fieldMaps, entityName)` — Maps external records to MJ entity fields
|
|
139
|
+
|
|
140
|
+
### MatchEngine
|
|
141
|
+
|
|
142
|
+
- `Resolve(records, entityMap, fieldMaps, contextUser)` — Resolves Create/Update/Delete/Skip
|
|
143
|
+
|
|
144
|
+
### WatermarkService
|
|
145
|
+
|
|
146
|
+
- `Load(entityMapID, contextUser)` — Loads current watermark
|
|
147
|
+
- `Update(entityMapID, newValue, contextUser)` — Updates or creates watermark
|
|
148
|
+
|
|
149
|
+
### ConnectorFactory
|
|
150
|
+
|
|
151
|
+
- `Resolve(integration, sourceTypes)` — Creates connector instance via ClassFactory
|
|
152
|
+
|
|
153
|
+
### BaseIntegrationConnector (abstract)
|
|
154
|
+
|
|
155
|
+
- `TestConnection(companyIntegration, contextUser)` — Tests external system connectivity
|
|
156
|
+
- `DiscoverObjects(companyIntegration, contextUser)` — Lists available external objects
|
|
157
|
+
- `DiscoverFields(companyIntegration, objectName, contextUser)` — Lists fields on an object
|
|
158
|
+
- `FetchChanges(ctx)` — Fetches a batch of changed records
|
|
159
|
+
- `GetDefaultFieldMappings(objectName, entityName)` — Suggests default mappings
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { UserInfo } from '@memberjunction/core';
|
|
2
|
+
import type { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import type { ExternalRecord, DefaultFieldMapping, SourceSchemaInfo } from './types.js';
|
|
4
|
+
/** Result of testing a connection to an external system */
|
|
5
|
+
export interface ConnectionTestResult {
|
|
6
|
+
/** Whether the connection was successful */
|
|
7
|
+
Success: boolean;
|
|
8
|
+
/** Human-readable status message */
|
|
9
|
+
Message: string;
|
|
10
|
+
/** Server or API version reported by the external system */
|
|
11
|
+
ServerVersion?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Schema description of an object/table in an external system */
|
|
14
|
+
export interface ExternalObjectSchema {
|
|
15
|
+
/** API name of the object (e.g., "Contact", "Account") */
|
|
16
|
+
Name: string;
|
|
17
|
+
/** Human-readable label */
|
|
18
|
+
Label: string;
|
|
19
|
+
/** Human-readable description of the object's purpose */
|
|
20
|
+
Description?: string;
|
|
21
|
+
/** Whether this object supports incremental sync via watermarks */
|
|
22
|
+
SupportsIncrementalSync: boolean;
|
|
23
|
+
/** Whether this object can be created/updated from MJ (push) */
|
|
24
|
+
SupportsWrite: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** Schema description of a single field on an external object */
|
|
27
|
+
export interface ExternalFieldSchema {
|
|
28
|
+
/** API name of the field */
|
|
29
|
+
Name: string;
|
|
30
|
+
/** Human-readable label */
|
|
31
|
+
Label: string;
|
|
32
|
+
/** Human-readable description of the field's purpose */
|
|
33
|
+
Description?: string;
|
|
34
|
+
/** Field data type in the external system */
|
|
35
|
+
DataType: string;
|
|
36
|
+
/** Whether the field is required */
|
|
37
|
+
IsRequired: boolean;
|
|
38
|
+
/** Whether the field is a unique identifier */
|
|
39
|
+
IsUniqueKey: boolean;
|
|
40
|
+
/** Whether the field is read-only */
|
|
41
|
+
IsReadOnly: boolean;
|
|
42
|
+
/** Whether this field is a foreign key */
|
|
43
|
+
IsForeignKey?: boolean;
|
|
44
|
+
/** If FK, which source object it references */
|
|
45
|
+
ForeignKeyTarget?: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** Context passed to FetchChanges for incremental data retrieval */
|
|
48
|
+
export interface FetchContext {
|
|
49
|
+
/** The company integration entity providing connection details */
|
|
50
|
+
CompanyIntegration: MJCompanyIntegrationEntity;
|
|
51
|
+
/** External object name to fetch from */
|
|
52
|
+
ObjectName: string;
|
|
53
|
+
/** Current watermark value for incremental fetch, or null for full fetch */
|
|
54
|
+
WatermarkValue: string | null;
|
|
55
|
+
/** Maximum number of records to fetch in a single batch */
|
|
56
|
+
BatchSize: number;
|
|
57
|
+
/** User context for authorization */
|
|
58
|
+
ContextUser: UserInfo;
|
|
59
|
+
}
|
|
60
|
+
/** Result of a FetchChanges call, containing a batch of records */
|
|
61
|
+
export interface FetchBatchResult {
|
|
62
|
+
/** Records retrieved in this batch */
|
|
63
|
+
Records: ExternalRecord[];
|
|
64
|
+
/** Whether there are more records to fetch after this batch */
|
|
65
|
+
HasMore: boolean;
|
|
66
|
+
/** Updated watermark value after this batch */
|
|
67
|
+
NewWatermarkValue?: string;
|
|
68
|
+
}
|
|
69
|
+
/** Configurable timeout values for connector operations */
|
|
70
|
+
export interface OperationTimeouts {
|
|
71
|
+
/** Timeout for TestConnection in milliseconds. Default: 5000 */
|
|
72
|
+
TestConnectionMs: number;
|
|
73
|
+
/** Timeout for DiscoverObjects in milliseconds. Default: 10000 */
|
|
74
|
+
DiscoverObjectsMs: number;
|
|
75
|
+
/** Timeout for DiscoverFields in milliseconds. Default: 10000 */
|
|
76
|
+
DiscoverFieldsMs: number;
|
|
77
|
+
/** Timeout for FetchChanges in milliseconds. Default: 30000 */
|
|
78
|
+
FetchChangesMs: number;
|
|
79
|
+
}
|
|
80
|
+
/** Default timeout values for connector operations */
|
|
81
|
+
export declare const DEFAULT_OPERATION_TIMEOUTS: OperationTimeouts;
|
|
82
|
+
/**
|
|
83
|
+
* Wraps a promise with a timeout. Rejects with a timeout error if the
|
|
84
|
+
* promise does not resolve within the specified duration.
|
|
85
|
+
*
|
|
86
|
+
* @param promise - The promise to wrap
|
|
87
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
88
|
+
* @param operationName - Name of the operation for error messaging
|
|
89
|
+
* @returns The result of the promise
|
|
90
|
+
* @throws Error if the operation times out
|
|
91
|
+
*/
|
|
92
|
+
export declare function WithTimeout<T>(promise: Promise<T>, timeoutMs: number, operationName: string): Promise<T>;
|
|
93
|
+
/** Proposed default configuration for a quick-start setup */
|
|
94
|
+
export interface DefaultObjectConfig {
|
|
95
|
+
/** Source object name in the external system */
|
|
96
|
+
SourceObjectName: string;
|
|
97
|
+
/** Proposed target table name in the MJ database */
|
|
98
|
+
TargetTableName: string;
|
|
99
|
+
/** Proposed MJ entity name */
|
|
100
|
+
TargetEntityName: string;
|
|
101
|
+
/** Whether to enable sync by default */
|
|
102
|
+
SyncEnabled: boolean;
|
|
103
|
+
/** Proposed field mappings */
|
|
104
|
+
FieldMappings: DefaultFieldMapping[];
|
|
105
|
+
}
|
|
106
|
+
/** Full default configuration returned by a connector for quick setup */
|
|
107
|
+
export interface DefaultIntegrationConfig {
|
|
108
|
+
/** Proposed DB schema name for new tables (e.g., "YourMembership", "HubSpot") */
|
|
109
|
+
DefaultSchemaName: string;
|
|
110
|
+
/** Objects to sync by default with proposed table/entity names */
|
|
111
|
+
DefaultObjects: DefaultObjectConfig[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Abstract base class for integration connectors.
|
|
115
|
+
* Each external system (HubSpot, Salesforce, etc.) implements this class
|
|
116
|
+
* to provide system-specific data access and discovery.
|
|
117
|
+
*/
|
|
118
|
+
export declare abstract class BaseIntegrationConnector {
|
|
119
|
+
/**
|
|
120
|
+
* Tests connectivity to the external system.
|
|
121
|
+
* @param companyIntegration - The company integration entity with connection credentials
|
|
122
|
+
* @param contextUser - User context for authorization
|
|
123
|
+
* @returns Connection test result with success/failure and message
|
|
124
|
+
*/
|
|
125
|
+
abstract TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
|
|
126
|
+
/**
|
|
127
|
+
* Discovers available objects/tables in the external system.
|
|
128
|
+
* @param companyIntegration - The company integration entity with connection credentials
|
|
129
|
+
* @param contextUser - User context for authorization
|
|
130
|
+
* @returns Array of object schemas available for integration
|
|
131
|
+
*/
|
|
132
|
+
abstract DiscoverObjects(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ExternalObjectSchema[]>;
|
|
133
|
+
/**
|
|
134
|
+
* Discovers fields on a specific external object.
|
|
135
|
+
* @param companyIntegration - The company integration entity with connection credentials
|
|
136
|
+
* @param objectName - Name of the external object to inspect
|
|
137
|
+
* @param contextUser - User context for authorization
|
|
138
|
+
* @returns Array of field schemas for the specified object
|
|
139
|
+
*/
|
|
140
|
+
abstract DiscoverFields(companyIntegration: MJCompanyIntegrationEntity, objectName: string, contextUser: UserInfo): Promise<ExternalFieldSchema[]>;
|
|
141
|
+
/**
|
|
142
|
+
* Fetches a batch of changed records from the external system.
|
|
143
|
+
* Supports incremental fetching via watermarks.
|
|
144
|
+
* @param ctx - Context containing connection info, object name, and watermark
|
|
145
|
+
* @returns Batch of external records with pagination info
|
|
146
|
+
*/
|
|
147
|
+
abstract FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
|
|
148
|
+
/**
|
|
149
|
+
* Returns suggested default field mappings for an external object to MJ entity.
|
|
150
|
+
* Override in subclasses to provide intelligent defaults.
|
|
151
|
+
* @param _objectName - Name of the external object
|
|
152
|
+
* @param _entityName - Name of the target MJ entity
|
|
153
|
+
* @returns Array of default field mappings (empty by default)
|
|
154
|
+
*/
|
|
155
|
+
GetDefaultFieldMappings(_objectName: string, _entityName: string): DefaultFieldMapping[];
|
|
156
|
+
/**
|
|
157
|
+
* Returns a proposed default configuration for quick setup.
|
|
158
|
+
* Override in subclasses to provide connector-specific defaults
|
|
159
|
+
* including schema name, objects to sync, and field mappings.
|
|
160
|
+
* Returns null by default (no quick setup available).
|
|
161
|
+
*/
|
|
162
|
+
GetDefaultConfiguration(): DefaultIntegrationConfig | null;
|
|
163
|
+
/**
|
|
164
|
+
* Introspects the source system's schema — returns metadata about available
|
|
165
|
+
* objects, their fields, primary keys, and foreign key relationships.
|
|
166
|
+
* Used by the Schema Builder to generate local DDL.
|
|
167
|
+
*
|
|
168
|
+
* Default implementation builds SourceSchemaInfo from DiscoverObjects + DiscoverFields.
|
|
169
|
+
* Override in subclasses for richer metadata (e.g., FK relationships, type details).
|
|
170
|
+
*
|
|
171
|
+
* @param companyIntegration - The company integration entity with connection credentials
|
|
172
|
+
* @param contextUser - User context for authorization
|
|
173
|
+
* @returns Full schema info for all source objects
|
|
174
|
+
*/
|
|
175
|
+
IntrospectSchema(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<SourceSchemaInfo>;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=BaseIntegrationConnector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseIntegrationConnector.d.ts","sourceRoot":"","sources":["../src/BaseIntegrationConnector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/** Default timeout values for connector operations */
|
|
2
|
+
export const DEFAULT_OPERATION_TIMEOUTS = {
|
|
3
|
+
TestConnectionMs: 5000,
|
|
4
|
+
DiscoverObjectsMs: 10000,
|
|
5
|
+
DiscoverFieldsMs: 10000,
|
|
6
|
+
FetchChangesMs: 30000,
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Wraps a promise with a timeout. Rejects with a timeout error if the
|
|
10
|
+
* promise does not resolve within the specified duration.
|
|
11
|
+
*
|
|
12
|
+
* @param promise - The promise to wrap
|
|
13
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
14
|
+
* @param operationName - Name of the operation for error messaging
|
|
15
|
+
* @returns The result of the promise
|
|
16
|
+
* @throws Error if the operation times out
|
|
17
|
+
*/
|
|
18
|
+
export async function WithTimeout(promise, timeoutMs, operationName) {
|
|
19
|
+
let timeoutHandle;
|
|
20
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
21
|
+
timeoutHandle = setTimeout(() => {
|
|
22
|
+
reject(new Error(`Operation '${operationName}' timed out after ${timeoutMs}ms`));
|
|
23
|
+
}, timeoutMs);
|
|
24
|
+
});
|
|
25
|
+
try {
|
|
26
|
+
const result = await Promise.race([promise, timeoutPromise]);
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
if (timeoutHandle !== undefined) {
|
|
31
|
+
clearTimeout(timeoutHandle);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Abstract base class for integration connectors.
|
|
37
|
+
* Each external system (HubSpot, Salesforce, etc.) implements this class
|
|
38
|
+
* to provide system-specific data access and discovery.
|
|
39
|
+
*/
|
|
40
|
+
export class BaseIntegrationConnector {
|
|
41
|
+
/**
|
|
42
|
+
* Returns suggested default field mappings for an external object to MJ entity.
|
|
43
|
+
* Override in subclasses to provide intelligent defaults.
|
|
44
|
+
* @param _objectName - Name of the external object
|
|
45
|
+
* @param _entityName - Name of the target MJ entity
|
|
46
|
+
* @returns Array of default field mappings (empty by default)
|
|
47
|
+
*/
|
|
48
|
+
GetDefaultFieldMappings(_objectName, _entityName) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns a proposed default configuration for quick setup.
|
|
53
|
+
* Override in subclasses to provide connector-specific defaults
|
|
54
|
+
* including schema name, objects to sync, and field mappings.
|
|
55
|
+
* Returns null by default (no quick setup available).
|
|
56
|
+
*/
|
|
57
|
+
GetDefaultConfiguration() {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Introspects the source system's schema — returns metadata about available
|
|
62
|
+
* objects, their fields, primary keys, and foreign key relationships.
|
|
63
|
+
* Used by the Schema Builder to generate local DDL.
|
|
64
|
+
*
|
|
65
|
+
* Default implementation builds SourceSchemaInfo from DiscoverObjects + DiscoverFields.
|
|
66
|
+
* Override in subclasses for richer metadata (e.g., FK relationships, type details).
|
|
67
|
+
*
|
|
68
|
+
* @param companyIntegration - The company integration entity with connection credentials
|
|
69
|
+
* @param contextUser - User context for authorization
|
|
70
|
+
* @returns Full schema info for all source objects
|
|
71
|
+
*/
|
|
72
|
+
async IntrospectSchema(companyIntegration, contextUser) {
|
|
73
|
+
const objects = await this.DiscoverObjects(companyIntegration, contextUser);
|
|
74
|
+
const result = { Objects: [] };
|
|
75
|
+
for (const obj of objects) {
|
|
76
|
+
let fields;
|
|
77
|
+
try {
|
|
78
|
+
fields = await this.DiscoverFields(companyIntegration, obj.Name, contextUser);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
82
|
+
console.warn(`WARNING: Skipping object "${obj.Name}" — DiscoverFields failed: ${msg}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
result.Objects.push({
|
|
86
|
+
ExternalName: obj.Name,
|
|
87
|
+
ExternalLabel: obj.Label,
|
|
88
|
+
Description: obj.Description,
|
|
89
|
+
Fields: fields.map(f => ({
|
|
90
|
+
Name: f.Name,
|
|
91
|
+
Label: f.Label,
|
|
92
|
+
Description: f.Description,
|
|
93
|
+
SourceType: f.DataType,
|
|
94
|
+
IsRequired: f.IsRequired,
|
|
95
|
+
MaxLength: null,
|
|
96
|
+
Precision: null,
|
|
97
|
+
Scale: null,
|
|
98
|
+
DefaultValue: null,
|
|
99
|
+
IsPrimaryKey: f.IsUniqueKey,
|
|
100
|
+
IsForeignKey: f.IsForeignKey ?? false,
|
|
101
|
+
ForeignKeyTarget: f.ForeignKeyTarget ?? null,
|
|
102
|
+
})),
|
|
103
|
+
PrimaryKeyFields: fields.filter(f => f.IsUniqueKey).map(f => f.Name),
|
|
104
|
+
Relationships: [],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=BaseIntegrationConnector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseIntegrationConnector.js","sourceRoot":"","sources":["../src/BaseIntegrationConnector.ts"],"names":[],"mappings":"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"}
|