@memberjunction/integration-connectors 0.0.1 → 5.8.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 CHANGED
@@ -1,45 +1,124 @@
1
1
  # @memberjunction/integration-connectors
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ Concrete integration connectors for the MemberJunction Integration Engine. This package provides four connectors that implement `BaseIntegrationConnector` from `@memberjunction/integration-engine`.
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ ## Connectors
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ ### RelationalDBConnector (Base Class)
8
8
 
9
- ## Purpose
9
+ Abstract base class for connectors that read from SQL Server databases via the `mssql` package. Provides shared logic for connection management, object/field discovery, and batched record fetching with watermark support.
10
10
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@memberjunction/integration-connectors`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
11
+ **Configuration JSON:**
12
+ ```json
13
+ {
14
+ "server": "your-sql-server",
15
+ "database": "YourDatabase",
16
+ "user": "username",
17
+ "password": "password"
18
+ }
19
+ ```
15
20
 
16
- ## What is OIDC Trusted Publishing?
21
+ **Shared capabilities:**
22
+ - `TestConnection` — runs `SELECT @@VERSION` to verify connectivity
23
+ - `DiscoverObjects` — queries `INFORMATION_SCHEMA.TABLES` for all base tables
24
+ - `DiscoverFields` — queries `INFORMATION_SCHEMA.COLUMNS` for a given table
25
+ - `FetchChangesFromTable` — parameterized incremental fetch with watermark filtering and batch limiting
26
+ - Connection pool caching per server+database pair
17
27
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
28
+ ### HubSpotConnector
19
29
 
20
- ## Setup Instructions
30
+ Reads from MockHubSpot database tables: `hs_Contacts`, `hs_Companies`, `hs_Deals`, `hs_Owners`.
21
31
 
22
- To properly configure OIDC trusted publishing for this package:
32
+ **Registration:** `@RegisterClass(BaseIntegrationConnector, 'HubSpotConnector')`
23
33
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
34
+ **Default field mappings:**
35
+ | Source Object | Target Entity | Mappings |
36
+ |---|---|---|
37
+ | `hs_Contacts` | Contacts | email→Email (key), firstname→FirstName, lastname→LastName, phone→Phone, company→CompanyName, lifecyclestage→Status |
38
+ | `hs_Companies` | Companies | name→Name (key), domain→Website, industry→Industry, city→City, state→State |
39
+ | `hs_Deals` | — | No default mappings |
28
40
 
29
- ## DO NOT USE THIS PACKAGE
41
+ **To swap for real HubSpot API:** Replace `RelationalDBConnector` with direct HTTP calls to the HubSpot V3 API. The `FetchChanges` method would use the HubSpot Search API with `lastmodifieddate` filters, and `Configuration` would store an API key or OAuth tokens instead of database credentials.
30
42
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
43
+ ### SalesforceConnector
36
44
 
37
- ## More Information
45
+ Reads from MockSalesforce database tables: `sf_Contact`, `sf_Account`, `sf_Opportunity`, `sf_User`.
38
46
 
39
- For more details about npm's trusted publishing feature, see:
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)
47
+ **Registration:** `@RegisterClass(BaseIntegrationConnector, 'SalesforceConnector')`
42
48
 
43
- ---
49
+ **Default field mappings:**
50
+ | Source Object | Target Entity | Mappings |
51
+ |---|---|---|
52
+ | `sf_Contact` | Contacts | Email→Email (key), FirstName→FirstName, LastName→LastName, Phone→Phone, Title→Title, Department→Department |
53
+ | `sf_Account` | Companies | Name→Name (key), Industry→Industry, BillingCity→City, BillingState→State, Phone→Phone |
44
54
 
45
- **Maintained for OIDC setup purposes only**
55
+ **To swap for real Salesforce API:** Replace `RelationalDBConnector` with `jsforce` or direct REST calls to the Salesforce SOQL API. Use `SystemModstamp` for watermarks and the Salesforce Bulk API for large datasets.
56
+
57
+ ### YourMembershipConnector
58
+
59
+ Reads from MockYourMembership database tables: `ym_Members`, `ym_Events`, `ym_EventRegistrations`, `ym_Chapters`, `ym_MembershipLevels`.
60
+
61
+ **Registration:** `@RegisterClass(BaseIntegrationConnector, 'YourMembershipConnector')`
62
+
63
+ **Default field mappings:**
64
+ | Source Object | Target Entity | Mappings |
65
+ |---|---|---|
66
+ | `ym_Members` | Contacts | email→Email (key), first_name→FirstName, last_name→LastName, phone→Phone, status→Status |
67
+
68
+ ### FileFeedConnector
69
+
70
+ Reads data from local CSV files. Always performs a full load (no incremental sync support).
71
+
72
+ **Registration:** `@RegisterClass(BaseIntegrationConnector, 'FileFeedConnector')`
73
+
74
+ **Configuration JSON:**
75
+ ```json
76
+ {
77
+ "storagePath": "/absolute/path/to/file.csv",
78
+ "fileType": "csv"
79
+ }
80
+ ```
81
+
82
+ **Capabilities:**
83
+ - `TestConnection` — checks that the file exists on disk
84
+ - `DiscoverObjects` — returns the file name as the single available object
85
+ - `DiscoverFields` — parses the CSV header row
86
+ - `FetchChanges` — parses all data rows into `ExternalRecord[]` (watermark is ignored)
87
+
88
+ **CSV parsing rules:**
89
+ - First row is treated as the header
90
+ - Supports quoted fields with commas inside
91
+ - Supports escaped quotes (`""`) inside quoted fields
92
+ - Empty values are mapped to `null`
93
+
94
+ ## Building
95
+
96
+ ```bash
97
+ cd packages/Integration/connectors
98
+ npm run build
99
+ ```
100
+
101
+ ## Testing
102
+
103
+ Tests are integration tests that connect to the mock SQL Server databases.
104
+
105
+ ```bash
106
+ cd packages/Integration/connectors
107
+ npm run test # single run
108
+ npm run test:watch # watch mode
109
+ ```
110
+
111
+ ## Architecture
112
+
113
+ ```
114
+ src/
115
+ index.ts # Package exports
116
+ RelationalDBConnector.ts # Base class for SQL-based connectors
117
+ HubSpotConnector.ts # HubSpot mock connector
118
+ SalesforceConnector.ts # Salesforce mock connector
119
+ YourMembershipConnector.ts # YourMembership mock connector
120
+ FileFeedConnector.ts # CSV file connector
121
+ __tests__/ # Integration tests
122
+ test-fixtures/
123
+ sample-contacts.csv # 100-row sample for FileFeed testing
124
+ ```
@@ -0,0 +1,64 @@
1
+ import type { UserInfo } from '@memberjunction/core';
2
+ import type { MJCompanyIntegrationEntity } from '@memberjunction/core-entities';
3
+ import { BaseIntegrationConnector, type ConnectionTestResult, type ExternalObjectSchema, type ExternalFieldSchema, type FetchContext, type FetchBatchResult } from '@memberjunction/integration-engine';
4
+ /**
5
+ * Connector for file-based data feeds (CSV).
6
+ * Reads data from local CSV files. Always performs a full load (no incremental sync).
7
+ * Supports quoted fields with commas inside and empty values mapped to null.
8
+ */
9
+ export declare class FileFeedConnector extends BaseIntegrationConnector {
10
+ /**
11
+ * Tests connectivity by checking that the configured file exists on disk.
12
+ * @param companyIntegration - The entity with Configuration JSON containing storagePath
13
+ * @param _contextUser - User context for authorization
14
+ * @returns Success if the file exists, failure otherwise
15
+ */
16
+ TestConnection(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ConnectionTestResult>;
17
+ /**
18
+ * Discovers available objects by returning the file name as the single object.
19
+ * @param companyIntegration - The entity with Configuration JSON
20
+ * @param _contextUser - User context for authorization
21
+ * @returns Array with one entry for the configured file
22
+ */
23
+ DiscoverObjects(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ExternalObjectSchema[]>;
24
+ /**
25
+ * Discovers fields by parsing the CSV header row.
26
+ * @param companyIntegration - The entity with Configuration JSON
27
+ * @param _objectName - Object name (file name), not used since we only have one file
28
+ * @param _contextUser - User context for authorization
29
+ * @returns Array of field schemas from the CSV header
30
+ */
31
+ DiscoverFields(companyIntegration: MJCompanyIntegrationEntity, _objectName: string, _contextUser: UserInfo): Promise<ExternalFieldSchema[]>;
32
+ /**
33
+ * Fetches all records from the CSV file as a full load.
34
+ * CSV files do not support incremental sync — watermark is ignored.
35
+ * @param ctx - Fetch context (watermark is always ignored for file feeds)
36
+ * @returns All records from the CSV file in a single batch
37
+ */
38
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
39
+ /**
40
+ * Parses the Configuration JSON to extract file feed settings.
41
+ * @param companyIntegration - The entity containing Configuration JSON
42
+ * @returns Parsed file feed configuration
43
+ */
44
+ private parseConfig;
45
+ /**
46
+ * Parses an array of CSV data lines into ExternalRecord objects.
47
+ * @param lines - CSV data lines (excluding header)
48
+ * @param headers - Column header names
49
+ * @param objectName - Object type name for the records
50
+ * @returns Array of ExternalRecord objects
51
+ */
52
+ private parseDataLines;
53
+ }
54
+ /**
55
+ * Parses a single CSV line handling quoted fields with commas.
56
+ * Supports:
57
+ * - Unquoted fields separated by commas
58
+ * - Quoted fields that may contain commas
59
+ * - Escaped quotes ("") inside quoted fields
60
+ * @param line - A single CSV line to parse
61
+ * @returns Array of field values
62
+ */
63
+ export declare function parseCsvLine(line: string): string[];
64
+ //# sourceMappingURL=FileFeedConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileFeedConnector.d.ts","sourceRoot":"","sources":["../src/FileFeedConnector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EACH,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAExB,MAAM,oCAAoC,CAAC;AAY5C;;;;GAIG;AACH,qBACa,iBAAkB,SAAQ,wBAAwB;IAC3D;;;;;OAKG;IACU,cAAc,CACvB,kBAAkB,EAAE,0BAA0B,EAC9C,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,oBAAoB,CAAC;IAahC;;;;;OAKG;IACU,eAAe,CACxB,kBAAkB,EAAE,0BAA0B,EAC9C,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAalC;;;;;;OAMG;IACU,cAAc,CACvB,kBAAkB,EAAE,0BAA0B,EAC9C,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAmBjC;;;;;OAKG;IACU,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAcvE;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAiBnB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;CAsBzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqCnD"}
@@ -0,0 +1,190 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { BaseIntegrationConnector, } from '@memberjunction/integration-engine';
9
+ import * as fs from 'node:fs';
10
+ import * as path from 'node:path';
11
+ /**
12
+ * Connector for file-based data feeds (CSV).
13
+ * Reads data from local CSV files. Always performs a full load (no incremental sync).
14
+ * Supports quoted fields with commas inside and empty values mapped to null.
15
+ */
16
+ let FileFeedConnector = class FileFeedConnector extends BaseIntegrationConnector {
17
+ /**
18
+ * Tests connectivity by checking that the configured file exists on disk.
19
+ * @param companyIntegration - The entity with Configuration JSON containing storagePath
20
+ * @param _contextUser - User context for authorization
21
+ * @returns Success if the file exists, failure otherwise
22
+ */
23
+ async TestConnection(companyIntegration, _contextUser) {
24
+ try {
25
+ const config = this.parseConfig(companyIntegration);
26
+ if (!fs.existsSync(config.StoragePath)) {
27
+ return { Success: false, Message: `File not found: ${config.StoragePath}` };
28
+ }
29
+ return { Success: true, Message: `File exists: ${config.StoragePath}` };
30
+ }
31
+ catch (err) {
32
+ const message = err instanceof Error ? err.message : String(err);
33
+ return { Success: false, Message: `Configuration error: ${message}` };
34
+ }
35
+ }
36
+ /**
37
+ * Discovers available objects by returning the file name as the single object.
38
+ * @param companyIntegration - The entity with Configuration JSON
39
+ * @param _contextUser - User context for authorization
40
+ * @returns Array with one entry for the configured file
41
+ */
42
+ async DiscoverObjects(companyIntegration, _contextUser) {
43
+ const config = this.parseConfig(companyIntegration);
44
+ const fileName = path.basename(config.StoragePath);
45
+ return [
46
+ {
47
+ Name: fileName,
48
+ Label: fileName,
49
+ SupportsIncrementalSync: false,
50
+ SupportsWrite: false,
51
+ },
52
+ ];
53
+ }
54
+ /**
55
+ * Discovers fields by parsing the CSV header row.
56
+ * @param companyIntegration - The entity with Configuration JSON
57
+ * @param _objectName - Object name (file name), not used since we only have one file
58
+ * @param _contextUser - User context for authorization
59
+ * @returns Array of field schemas from the CSV header
60
+ */
61
+ async DiscoverFields(companyIntegration, _objectName, _contextUser) {
62
+ const config = this.parseConfig(companyIntegration);
63
+ const content = fs.readFileSync(config.StoragePath, 'utf-8');
64
+ const firstLine = content.split('\n')[0]?.trim();
65
+ if (!firstLine) {
66
+ return [];
67
+ }
68
+ const headers = parseCsvLine(firstLine);
69
+ return headers.map((header) => ({
70
+ Name: header,
71
+ Label: header,
72
+ DataType: 'string',
73
+ IsRequired: false,
74
+ IsUniqueKey: false,
75
+ IsReadOnly: true,
76
+ }));
77
+ }
78
+ /**
79
+ * Fetches all records from the CSV file as a full load.
80
+ * CSV files do not support incremental sync — watermark is ignored.
81
+ * @param ctx - Fetch context (watermark is always ignored for file feeds)
82
+ * @returns All records from the CSV file in a single batch
83
+ */
84
+ async FetchChanges(ctx) {
85
+ const config = this.parseConfig(ctx.CompanyIntegration);
86
+ const content = fs.readFileSync(config.StoragePath, 'utf-8');
87
+ const lines = content.split('\n').filter((line) => line.trim().length > 0);
88
+ if (lines.length < 2) {
89
+ return { Records: [], HasMore: false };
90
+ }
91
+ const headers = parseCsvLine(lines[0]);
92
+ const records = this.parseDataLines(lines.slice(1), headers, ctx.ObjectName);
93
+ return { Records: records, HasMore: false };
94
+ }
95
+ /**
96
+ * Parses the Configuration JSON to extract file feed settings.
97
+ * @param companyIntegration - The entity containing Configuration JSON
98
+ * @returns Parsed file feed configuration
99
+ */
100
+ parseConfig(companyIntegration) {
101
+ const configJson = companyIntegration.Get('Configuration');
102
+ if (!configJson) {
103
+ throw new Error('CompanyIntegration.Configuration is null or empty');
104
+ }
105
+ const parsed = JSON.parse(configJson);
106
+ const storagePath = parsed['storagePath'];
107
+ const fileType = parsed['fileType'] ?? 'csv';
108
+ if (!storagePath) {
109
+ throw new Error('Configuration JSON must contain a storagePath field');
110
+ }
111
+ return { StoragePath: storagePath, FileType: fileType };
112
+ }
113
+ /**
114
+ * Parses an array of CSV data lines into ExternalRecord objects.
115
+ * @param lines - CSV data lines (excluding header)
116
+ * @param headers - Column header names
117
+ * @param objectName - Object type name for the records
118
+ * @returns Array of ExternalRecord objects
119
+ */
120
+ parseDataLines(lines, headers, objectName) {
121
+ return lines.map((line, index) => {
122
+ const values = parseCsvLine(line);
123
+ const fields = {};
124
+ for (let i = 0; i < headers.length; i++) {
125
+ const rawValue = i < values.length ? values[i] : '';
126
+ fields[headers[i]] = rawValue === '' ? null : rawValue;
127
+ }
128
+ return {
129
+ ExternalID: String(index + 1),
130
+ ObjectType: objectName,
131
+ Fields: fields,
132
+ IsDeleted: false,
133
+ };
134
+ });
135
+ }
136
+ };
137
+ FileFeedConnector = __decorate([
138
+ RegisterClass(BaseIntegrationConnector, 'FileFeedConnector')
139
+ ], FileFeedConnector);
140
+ export { FileFeedConnector };
141
+ /**
142
+ * Parses a single CSV line handling quoted fields with commas.
143
+ * Supports:
144
+ * - Unquoted fields separated by commas
145
+ * - Quoted fields that may contain commas
146
+ * - Escaped quotes ("") inside quoted fields
147
+ * @param line - A single CSV line to parse
148
+ * @returns Array of field values
149
+ */
150
+ export function parseCsvLine(line) {
151
+ const fields = [];
152
+ let current = '';
153
+ let inQuotes = false;
154
+ let i = 0;
155
+ while (i < line.length) {
156
+ const char = line[i];
157
+ if (inQuotes) {
158
+ if (char === '"' && i + 1 < line.length && line[i + 1] === '"') {
159
+ current += '"';
160
+ i += 2;
161
+ }
162
+ else if (char === '"') {
163
+ inQuotes = false;
164
+ i++;
165
+ }
166
+ else {
167
+ current += char;
168
+ i++;
169
+ }
170
+ }
171
+ else {
172
+ if (char === '"') {
173
+ inQuotes = true;
174
+ i++;
175
+ }
176
+ else if (char === ',') {
177
+ fields.push(current.trim());
178
+ current = '';
179
+ i++;
180
+ }
181
+ else {
182
+ current += char;
183
+ i++;
184
+ }
185
+ }
186
+ }
187
+ fields.push(current.trim());
188
+ return fields;
189
+ }
190
+ //# sourceMappingURL=FileFeedConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileFeedConnector.js","sourceRoot":"","sources":["../src/FileFeedConnector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { type FetchContext, type FetchBatchResult, type DefaultFieldMapping } from '@memberjunction/integration-engine';
2
+ import { RelationalDBConnector } from './RelationalDBConnector.js';
3
+ /**
4
+ * Connector for HubSpot CRM data, backed by the mock_data database (hs schema).
5
+ * Reads from hs.contacts, hs.companies, and hs.deals tables.
6
+ * Provides default field mappings for contacts and companies to MJ entities.
7
+ */
8
+ export declare class HubSpotConnector extends RelationalDBConnector {
9
+ /**
10
+ * Fetches a batch of changed records from the specified HubSpot object table.
11
+ * Uses lastmodifieddate for watermark-based incremental sync.
12
+ * @param ctx - Fetch context with integration, object, watermark, and batch details
13
+ * @returns Batch of HubSpot records with pagination info
14
+ */
15
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
16
+ /**
17
+ * Returns suggested default field mappings for known HubSpot objects to MJ entities.
18
+ * @param objectName - HubSpot object name (e.g., "contacts")
19
+ * @param entityName - Target MJ entity name (e.g., "Contacts")
20
+ * @returns Array of default field mappings
21
+ */
22
+ GetDefaultFieldMappings(objectName: string, _entityName: string): DefaultFieldMapping[];
23
+ /**
24
+ * Gets the primary key column for a HubSpot table.
25
+ * @param objectName - Table name
26
+ * @returns Column name for the primary key
27
+ */
28
+ private getIdField;
29
+ /**
30
+ * Gets the soft-delete flag column for a HubSpot table, if one exists.
31
+ * Currently only the contacts table has an is_deleted column.
32
+ * @param objectName - Table name
33
+ * @returns Column name for the deleted flag, or undefined if not applicable
34
+ */
35
+ private getDeletedField;
36
+ /** Default field mappings: hs_Contacts -> Contacts */
37
+ private getContactMappings;
38
+ /** Default field mappings: hs_Companies -> Companies */
39
+ private getCompanyMappings;
40
+ }
41
+ //# sourceMappingURL=HubSpotConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HubSpotConnector.d.ts","sourceRoot":"","sources":["../src/HubSpotConnector.ts"],"names":[],"mappings":"AACA,OAAO,EAEH,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAC3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAanE;;;;GAIG;AACH,qBACa,gBAAiB,SAAQ,qBAAqB;IACvD;;;;;OAKG;IACU,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAMvE;;;;;OAKG;IACa,uBAAuB,CACnC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACpB,mBAAmB,EAAE;IAWxB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IASlB;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAOvB,sDAAsD;IACtD,OAAO,CAAC,kBAAkB;IAW1B,wDAAwD;IACxD,OAAO,CAAC,kBAAkB;CAS7B"}
@@ -0,0 +1,104 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { BaseIntegrationConnector, } from '@memberjunction/integration-engine';
9
+ import { RelationalDBConnector } from './RelationalDBConnector.js';
10
+ /** Primary key column used for contacts table */
11
+ const HS_CONTACTS_ID = 'vid';
12
+ /** Primary key column used for companies table */
13
+ const HS_COMPANIES_ID = 'companyId';
14
+ /** Primary key column used for deals table */
15
+ const HS_DEALS_ID = 'dealId';
16
+ /** Modification timestamp column used across all HubSpot mock tables */
17
+ const HS_MODIFIED_FIELD = 'lastmodifieddate';
18
+ /** Soft-delete flag column on hs.contacts (added by incremental changes migration) */
19
+ const HS_CONTACTS_DELETED_FIELD = 'is_deleted';
20
+ /**
21
+ * Connector for HubSpot CRM data, backed by the mock_data database (hs schema).
22
+ * Reads from hs.contacts, hs.companies, and hs.deals tables.
23
+ * Provides default field mappings for contacts and companies to MJ entities.
24
+ */
25
+ let HubSpotConnector = class HubSpotConnector extends RelationalDBConnector {
26
+ /**
27
+ * Fetches a batch of changed records from the specified HubSpot object table.
28
+ * Uses lastmodifieddate for watermark-based incremental sync.
29
+ * @param ctx - Fetch context with integration, object, watermark, and batch details
30
+ * @returns Batch of HubSpot records with pagination info
31
+ */
32
+ async FetchChanges(ctx) {
33
+ const idField = this.getIdField(ctx.ObjectName);
34
+ const deletedField = this.getDeletedField(ctx.ObjectName);
35
+ return this.FetchChangesFromTable(ctx, idField, HS_MODIFIED_FIELD, deletedField);
36
+ }
37
+ /**
38
+ * Returns suggested default field mappings for known HubSpot objects to MJ entities.
39
+ * @param objectName - HubSpot object name (e.g., "contacts")
40
+ * @param entityName - Target MJ entity name (e.g., "Contacts")
41
+ * @returns Array of default field mappings
42
+ */
43
+ GetDefaultFieldMappings(objectName, _entityName) {
44
+ switch (objectName) {
45
+ case 'contacts':
46
+ return this.getContactMappings();
47
+ case 'companies':
48
+ return this.getCompanyMappings();
49
+ default:
50
+ return [];
51
+ }
52
+ }
53
+ /**
54
+ * Gets the primary key column for a HubSpot table.
55
+ * @param objectName - Table name
56
+ * @returns Column name for the primary key
57
+ */
58
+ getIdField(objectName) {
59
+ switch (objectName) {
60
+ case 'contacts': return HS_CONTACTS_ID;
61
+ case 'companies': return HS_COMPANIES_ID;
62
+ case 'deals': return HS_DEALS_ID;
63
+ default: return HS_CONTACTS_ID;
64
+ }
65
+ }
66
+ /**
67
+ * Gets the soft-delete flag column for a HubSpot table, if one exists.
68
+ * Currently only the contacts table has an is_deleted column.
69
+ * @param objectName - Table name
70
+ * @returns Column name for the deleted flag, or undefined if not applicable
71
+ */
72
+ getDeletedField(objectName) {
73
+ switch (objectName) {
74
+ case 'contacts': return HS_CONTACTS_DELETED_FIELD;
75
+ default: return undefined;
76
+ }
77
+ }
78
+ /** Default field mappings: hs_Contacts -> Contacts */
79
+ getContactMappings() {
80
+ return [
81
+ { SourceFieldName: 'email', DestinationFieldName: 'Email', IsKeyField: true },
82
+ { SourceFieldName: 'firstname', DestinationFieldName: 'FirstName' },
83
+ { SourceFieldName: 'lastname', DestinationFieldName: 'LastName' },
84
+ { SourceFieldName: 'phone', DestinationFieldName: 'Phone' },
85
+ { SourceFieldName: 'company', DestinationFieldName: 'CompanyName' },
86
+ { SourceFieldName: 'lifecyclestage', DestinationFieldName: 'Status' },
87
+ ];
88
+ }
89
+ /** Default field mappings: hs_Companies -> Companies */
90
+ getCompanyMappings() {
91
+ return [
92
+ { SourceFieldName: 'name', DestinationFieldName: 'Name', IsKeyField: true },
93
+ { SourceFieldName: 'domain', DestinationFieldName: 'Website' },
94
+ { SourceFieldName: 'industry', DestinationFieldName: 'Industry' },
95
+ { SourceFieldName: 'city', DestinationFieldName: 'City' },
96
+ { SourceFieldName: 'state', DestinationFieldName: 'State' },
97
+ ];
98
+ }
99
+ };
100
+ HubSpotConnector = __decorate([
101
+ RegisterClass(BaseIntegrationConnector, 'HubSpotConnector')
102
+ ], HubSpotConnector);
103
+ export { HubSpotConnector };
104
+ //# sourceMappingURL=HubSpotConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HubSpotConnector.js","sourceRoot":"","sources":["../src/HubSpotConnector.ts"],"names":[],"mappings":"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"}