@memberjunction/integration-connectors 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.
@@ -0,0 +1,446 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { Metadata } from '@memberjunction/core';
9
+ import { BaseIntegrationConnector, BaseRESTIntegrationConnector, } from '@memberjunction/integration-engine';
10
+ // ─── Constants ────────────────────────────────────────────────────────
11
+ const HUBSPOT_API_BASE = 'https://api.hubapi.com';
12
+ const DEFAULT_API_VERSION = 'v3';
13
+ /** Maximum retries for rate-limited or failed requests */
14
+ const MAX_RETRIES = 5;
15
+ /** HTTP request timeout in milliseconds */
16
+ const REQUEST_TIMEOUT_MS = 30000;
17
+ /** Minimum milliseconds between API requests (HubSpot: 100 req/10s for private apps) */
18
+ const MIN_REQUEST_INTERVAL_MS = 100;
19
+ /**
20
+ * Known properties to request per object type. HubSpot's list endpoint
21
+ * only returns a handful of default properties unless you explicitly
22
+ * specify which properties to include via the `properties` query param.
23
+ */
24
+ const HUBSPOT_PROPERTIES = {
25
+ contacts: [
26
+ 'email', 'firstname', 'lastname', 'phone', 'mobilephone', 'company',
27
+ 'jobtitle', 'lifecyclestage', 'hs_lead_status', 'address', 'city',
28
+ 'state', 'zip', 'country', 'website', 'industry',
29
+ 'annualrevenue', 'numberofemployees', 'hs_object_id',
30
+ 'createdate', 'lastmodifieddate', 'associatedcompanyid',
31
+ 'notes_last_contacted', 'notes_last_updated', 'hs_email_optout',
32
+ ],
33
+ companies: [
34
+ 'name', 'domain', 'industry', 'phone', 'address', 'address2',
35
+ 'city', 'state', 'zip', 'country', 'website', 'description',
36
+ 'numberofemployees', 'annualrevenue', 'lifecyclestage',
37
+ 'type', 'hs_object_id', 'createdate', 'hs_lastmodifieddate',
38
+ 'founded_year', 'is_public',
39
+ ],
40
+ deals: [
41
+ 'dealname', 'amount', 'dealstage', 'pipeline', 'closedate',
42
+ 'createdate', 'hs_object_id', 'hs_lastmodifieddate',
43
+ 'dealtype', 'description', 'hs_deal_stage_probability',
44
+ 'hs_projected_amount', 'hs_priority', 'hubspot_owner_id',
45
+ 'notes_last_contacted', 'num_associated_contacts',
46
+ ],
47
+ tickets: [
48
+ 'subject', 'content', 'hs_pipeline', 'hs_pipeline_stage',
49
+ 'hs_ticket_priority', 'hs_ticket_category', 'createdate',
50
+ 'hs_lastmodifieddate', 'hs_object_id', 'closed_date',
51
+ 'source_type', 'hubspot_owner_id',
52
+ ],
53
+ products: [
54
+ 'name', 'description', 'price', 'hs_cost_of_goods_sold',
55
+ 'hs_recurring_billing_period', 'hs_sku', 'tax',
56
+ 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
57
+ ],
58
+ line_items: [
59
+ 'name', 'description', 'quantity', 'price', 'amount',
60
+ 'discount', 'tax', 'hs_product_id', 'hs_line_item_currency_code',
61
+ 'hs_sku', 'hs_cost_of_goods_sold', 'hs_recurring_billing_period',
62
+ 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
63
+ ],
64
+ quotes: [
65
+ 'hs_title', 'hs_expiration_date', 'hs_status', 'hs_quote_amount',
66
+ 'hs_currency', 'hs_sender_firstname', 'hs_sender_lastname',
67
+ 'hs_sender_email', 'hs_sender_company_name', 'hs_language',
68
+ 'hs_locale', 'hs_slug', 'hs_public_url_key',
69
+ 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
70
+ ],
71
+ calls: [
72
+ 'hs_call_title', 'hs_call_body', 'hs_call_status',
73
+ 'hs_call_direction', 'hs_call_duration', 'hs_call_from_number',
74
+ 'hs_call_to_number', 'hs_call_disposition',
75
+ 'hs_call_recording_url', 'hubspot_owner_id',
76
+ 'hs_timestamp', 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
77
+ ],
78
+ emails: [
79
+ 'hs_email_subject', 'hs_email_text', 'hs_email_html',
80
+ 'hs_email_status', 'hs_email_direction',
81
+ 'hs_email_sender_email', 'hs_email_sender_firstname',
82
+ 'hs_email_sender_lastname', 'hs_email_to_email',
83
+ 'hubspot_owner_id',
84
+ 'hs_timestamp', 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
85
+ ],
86
+ notes: [
87
+ 'hs_note_body', 'hs_timestamp', 'hubspot_owner_id',
88
+ 'hs_attachment_ids', 'hs_body_preview', 'hs_body_preview_is_truncated',
89
+ 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
90
+ ],
91
+ tasks: [
92
+ 'hs_task_subject', 'hs_task_body', 'hs_task_status',
93
+ 'hs_task_priority', 'hs_task_type', 'hs_timestamp',
94
+ 'hs_task_completion_date', 'hs_queue_membership_ids',
95
+ 'hubspot_owner_id',
96
+ 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
97
+ ],
98
+ meetings: [
99
+ 'hs_meeting_title', 'hs_meeting_body', 'hs_meeting_start_time',
100
+ 'hs_meeting_end_time', 'hs_meeting_outcome', 'hs_meeting_location',
101
+ 'hs_meeting_external_url', 'hs_internal_meeting_notes',
102
+ 'hs_activity_type', 'hubspot_owner_id',
103
+ 'hs_timestamp', 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
104
+ ],
105
+ feedback_submissions: [
106
+ 'hs_survey_id', 'hs_survey_name', 'hs_survey_type',
107
+ 'hs_submission_name', 'hs_content', 'hs_response_group',
108
+ 'hs_sentiment', 'hs_survey_channel',
109
+ 'hs_timestamp', 'createdate', 'hs_lastmodifieddate', 'hs_object_id',
110
+ ],
111
+ };
112
+ // ─── Connector ────────────────────────────────────────────────────────
113
+ /**
114
+ * Connector for HubSpot CRM via the HubSpot REST API v3.
115
+ *
116
+ * Extends BaseRESTIntegrationConnector to leverage metadata-driven object/field
117
+ * discovery from IntegrationEngineBase cache and generic pagination handling.
118
+ *
119
+ * Uses Bearer token authentication (private app key or OAuth access token).
120
+ * Supports cursor-based pagination and automatic response flattening.
121
+ *
122
+ * DATA SAFETY: This connector is READ-ONLY. It never writes data back to HubSpot.
123
+ */
124
+ let HubSpotConnector = class HubSpotConnector extends BaseRESTIntegrationConnector {
125
+ constructor() {
126
+ super(...arguments);
127
+ /** Timestamp of the last API request, used for throttling */
128
+ this.lastRequestTime = 0;
129
+ }
130
+ // ─── Abstract method implementations (BaseRESTIntegrationConnector) ──
131
+ async Authenticate(companyIntegration) {
132
+ const credentials = await this.LoadCredentials(companyIntegration);
133
+ const auth = {
134
+ Token: credentials.AccessToken,
135
+ Credentials: credentials,
136
+ };
137
+ return auth;
138
+ }
139
+ BuildHeaders(auth) {
140
+ return {
141
+ 'Authorization': `Bearer ${auth.Token}`,
142
+ 'Accept': 'application/json',
143
+ };
144
+ }
145
+ async MakeHTTPRequest(_auth, url, method, headers, _body) {
146
+ // Throttle: ensure minimum interval between requests
147
+ const elapsed = Date.now() - this.lastRequestTime;
148
+ if (elapsed < MIN_REQUEST_INTERVAL_MS) {
149
+ await this.Sleep(MIN_REQUEST_INTERVAL_MS - elapsed);
150
+ }
151
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
152
+ const response = await this.FetchWithTimeout(url, method, headers);
153
+ this.lastRequestTime = Date.now();
154
+ if (response.status === 429) {
155
+ const delayMs = this.CalculateRetryDelay(response, attempt);
156
+ console.warn(`[HubSpot] Rate limited (429), retrying in ${delayMs}ms ` +
157
+ `(attempt ${attempt + 1}/${MAX_RETRIES})`);
158
+ await this.Sleep(delayMs);
159
+ continue;
160
+ }
161
+ const body = await response.json();
162
+ return this.BuildRESTResponse(response, body);
163
+ }
164
+ throw new Error(`HubSpot API request failed after ${MAX_RETRIES} retries: ${url}`);
165
+ }
166
+ NormalizeResponse(rawBody, responseDataKey) {
167
+ const body = rawBody;
168
+ // Extract the records array using the responseDataKey (typically "results")
169
+ let records;
170
+ if (responseDataKey != null) {
171
+ const data = body[responseDataKey];
172
+ if (!data || !Array.isArray(data))
173
+ return [];
174
+ records = data;
175
+ }
176
+ else if (Array.isArray(rawBody)) {
177
+ records = rawBody;
178
+ }
179
+ else {
180
+ return [];
181
+ }
182
+ // Flatten HubSpot's nested { id, properties: {...}, createdAt, updatedAt, archived }
183
+ return records.map(r => this.FlattenHubSpotRecord(r));
184
+ }
185
+ ExtractPaginationInfo(rawBody, _paginationType, _currentPage, _currentOffset, _pageSize) {
186
+ const body = rawBody;
187
+ const paging = body['paging'];
188
+ const nextCursor = paging?.next?.after;
189
+ if (nextCursor) {
190
+ return { HasMore: true, NextCursor: nextCursor };
191
+ }
192
+ return { HasMore: false };
193
+ }
194
+ GetBaseURL(_companyIntegration) {
195
+ return HUBSPOT_API_BASE;
196
+ }
197
+ // ─── HubSpot-specific pagination ─────────────────────────────────
198
+ /**
199
+ * Overrides base pagination URL building to use HubSpot's parameter names.
200
+ * HubSpot uses `after` for cursor pagination (not `cursor`), and needs
201
+ * `limit` instead of `pageSize`. Also appends `properties` query param.
202
+ */
203
+ BuildPaginatedURL(basePath, obj, _page, _offset, cursor) {
204
+ const separator = basePath.includes('?') ? '&' : '?';
205
+ const objectName = this.ExtractObjectNameFromPath(basePath);
206
+ const propertiesParam = this.BuildPropertiesParam(objectName);
207
+ if (cursor) {
208
+ return `${basePath}${separator}limit=${obj.DefaultPageSize}&after=${encodeURIComponent(cursor)}${propertiesParam}`;
209
+ }
210
+ return `${basePath}${separator}limit=${obj.DefaultPageSize}${propertiesParam}`;
211
+ }
212
+ // ─── TestConnection ─────────────────────────────────────────────
213
+ /** Tests connectivity by authenticating and fetching 1 contact. */
214
+ async TestConnection(companyIntegration, _contextUser) {
215
+ try {
216
+ const auth = await this.Authenticate(companyIntegration);
217
+ const headers = this.BuildHeaders(auth);
218
+ const response = await this.MakeHTTPRequest(auth, `${HUBSPOT_API_BASE}/crm/v3/objects/contacts?limit=1`, 'GET', headers);
219
+ if (response.Status >= 200 && response.Status < 300) {
220
+ const hubSpotAuth = auth;
221
+ return {
222
+ Success: true,
223
+ Message: 'Successfully connected to HubSpot CRM API',
224
+ ServerVersion: `HubSpot CRM API ${hubSpotAuth.Credentials.ApiVersion}`,
225
+ };
226
+ }
227
+ const bodyPreview = typeof response.Body === 'string'
228
+ ? response.Body.slice(0, 500)
229
+ : JSON.stringify(response.Body).slice(0, 500);
230
+ return {
231
+ Success: false,
232
+ Message: `HubSpot API returned ${response.Status}: ${bodyPreview}`,
233
+ };
234
+ }
235
+ catch (err) {
236
+ const message = err instanceof Error ? err.message : String(err);
237
+ return { Success: false, Message: `Connection failed: ${message}` };
238
+ }
239
+ }
240
+ // ─── GetDefaultFieldMappings ──────────────────────────────────
241
+ GetDefaultFieldMappings(objectName, _entityName) {
242
+ switch (objectName) {
243
+ case 'contacts':
244
+ return [
245
+ { SourceFieldName: 'email', DestinationFieldName: 'Email', IsKeyField: true },
246
+ { SourceFieldName: 'firstname', DestinationFieldName: 'FirstName' },
247
+ { SourceFieldName: 'lastname', DestinationFieldName: 'LastName' },
248
+ { SourceFieldName: 'phone', DestinationFieldName: 'Phone' },
249
+ { SourceFieldName: 'company', DestinationFieldName: 'CompanyName' },
250
+ { SourceFieldName: 'lifecyclestage', DestinationFieldName: 'Status' },
251
+ ];
252
+ case 'companies':
253
+ return [
254
+ { SourceFieldName: 'name', DestinationFieldName: 'Name', IsKeyField: true },
255
+ { SourceFieldName: 'domain', DestinationFieldName: 'Website' },
256
+ { SourceFieldName: 'industry', DestinationFieldName: 'Industry' },
257
+ { SourceFieldName: 'city', DestinationFieldName: 'City' },
258
+ { SourceFieldName: 'state', DestinationFieldName: 'State' },
259
+ ];
260
+ case 'deals':
261
+ return [
262
+ { SourceFieldName: 'dealname', DestinationFieldName: 'Name', IsKeyField: true },
263
+ { SourceFieldName: 'amount', DestinationFieldName: 'Amount' },
264
+ { SourceFieldName: 'dealstage', DestinationFieldName: 'Stage' },
265
+ { SourceFieldName: 'closedate', DestinationFieldName: 'CloseDate' },
266
+ { SourceFieldName: 'pipeline', DestinationFieldName: 'Pipeline' },
267
+ ];
268
+ default:
269
+ return [];
270
+ }
271
+ }
272
+ // ─── Default Configuration ──────────────────────────────────────
273
+ GetDefaultConfiguration() {
274
+ return {
275
+ DefaultSchemaName: 'HubSpot',
276
+ DefaultObjects: [], // Objects are auto-discovered from metadata via DiscoverObjects
277
+ };
278
+ }
279
+ // ─── Schema Discovery Helpers ────────────────────────────────────
280
+ /** Converts a HubSpot property definition to ExternalFieldSchema format */
281
+ MapPropertyToField(prop) {
282
+ return {
283
+ Name: prop.name,
284
+ Label: prop.label || prop.name,
285
+ DataType: this.MapHubSpotType(prop.type, prop.fieldType),
286
+ IsRequired: false, // HubSpot doesn't expose required via properties API
287
+ IsUniqueKey: prop.hasUniqueValue,
288
+ IsReadOnly: prop.calculated || (prop.modificationMetadata?.readOnlyValue ?? false),
289
+ };
290
+ }
291
+ /** Maps HubSpot type + fieldType to a simplified data type string */
292
+ MapHubSpotType(type, fieldType) {
293
+ switch (type) {
294
+ case 'string':
295
+ if (fieldType === 'textarea')
296
+ return 'text';
297
+ if (fieldType === 'html')
298
+ return 'html';
299
+ return 'string';
300
+ case 'number':
301
+ return 'number';
302
+ case 'date':
303
+ case 'datetime':
304
+ return 'datetime';
305
+ case 'bool':
306
+ return 'boolean';
307
+ case 'enumeration':
308
+ return 'enum';
309
+ default:
310
+ return type;
311
+ }
312
+ }
313
+ // ─── Credential management ────────────────────────────────────
314
+ /**
315
+ * Reads credentials from CompanyIntegration.CredentialID -> Credential.Values JSON,
316
+ * or falls back to CompanyIntegration Configuration JSON for backwards compat.
317
+ */
318
+ async LoadCredentials(companyIntegration) {
319
+ // Try loading from linked Credential entity first
320
+ const credentialID = companyIntegration.Get('CredentialID');
321
+ if (credentialID) {
322
+ const creds = await this.LoadFromCredentialEntity(credentialID);
323
+ if (creds)
324
+ return creds;
325
+ }
326
+ // Fallback: read from CompanyIntegration Configuration JSON
327
+ const configJson = companyIntegration.Get('Configuration');
328
+ if (configJson) {
329
+ const creds = this.ParseCredentialJson(configJson);
330
+ if (creds)
331
+ return creds;
332
+ }
333
+ throw new Error('No HubSpot credentials found. Attach a credential with an accessToken or apiKey, ' +
334
+ 'or set Configuration JSON on the CompanyIntegration.');
335
+ }
336
+ /** Loads credentials from a Credential entity by ID. */
337
+ async LoadFromCredentialEntity(credentialID) {
338
+ const md = new Metadata();
339
+ const credential = await md.GetEntityObject('MJ: Credentials');
340
+ const loaded = await credential.Load(credentialID);
341
+ if (!loaded || !credential.Values)
342
+ return null;
343
+ return this.ParseCredentialJson(credential.Values);
344
+ }
345
+ /** Parses a JSON string to extract HubSpot credentials. Returns null if no token found. */
346
+ ParseCredentialJson(json) {
347
+ try {
348
+ const parsed = JSON.parse(json);
349
+ const token = parsed['accessToken'] ?? parsed['AccessToken'] ?? parsed['apiKey'] ?? parsed['ApiKey'];
350
+ if (token) {
351
+ return {
352
+ AccessToken: token,
353
+ ApiVersion: parsed['apiVersion'] ?? DEFAULT_API_VERSION,
354
+ };
355
+ }
356
+ return null;
357
+ }
358
+ catch {
359
+ return null;
360
+ }
361
+ }
362
+ // ─── Response flattening ─────────────────────────────────────────
363
+ /**
364
+ * Flattens a HubSpot CRM record from the nested format:
365
+ * { id, properties: { field1, field2 }, createdAt, updatedAt, archived }
366
+ * into a flat record with all properties at the top level,
367
+ * plus system fields (hs_object_id, createdAt, updatedAt, archived).
368
+ */
369
+ FlattenHubSpotRecord(record) {
370
+ const properties = record['properties'];
371
+ const result = {};
372
+ // Add flattened properties first
373
+ if (properties) {
374
+ for (const [key, value] of Object.entries(properties)) {
375
+ result[key] = value;
376
+ }
377
+ }
378
+ // Add system fields (these override any conflicting property names)
379
+ result['hs_object_id'] = record['id'];
380
+ result['createdAt'] = record['createdAt'];
381
+ result['updatedAt'] = record['updatedAt'];
382
+ result['archived'] = record['archived'];
383
+ return result;
384
+ }
385
+ // ─── URL helpers ─────────────────────────────────────────────────
386
+ /**
387
+ * Extracts the HubSpot object name from an API path.
388
+ * E.g., "/crm/v3/objects/contacts" -> "contacts"
389
+ */
390
+ ExtractObjectNameFromPath(path) {
391
+ // Remove query string
392
+ const pathOnly = path.split('?')[0];
393
+ // Get the last path segment
394
+ const segments = pathOnly.split('/').filter(s => s.length > 0);
395
+ return segments[segments.length - 1] ?? '';
396
+ }
397
+ /**
398
+ * Builds the `properties` query parameter for a HubSpot object type.
399
+ * Returns empty string if no properties are configured for the object.
400
+ */
401
+ BuildPropertiesParam(objectName) {
402
+ const properties = HUBSPOT_PROPERTIES[objectName];
403
+ if (properties && properties.length > 0) {
404
+ return `&properties=${properties.join(',')}`;
405
+ }
406
+ return '';
407
+ }
408
+ // ─── HTTP helpers ────────────────────────────────────────────────
409
+ /** Executes an HTTP request with a timeout. */
410
+ async FetchWithTimeout(url, method, headers) {
411
+ const controller = new AbortController();
412
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
413
+ try {
414
+ return await fetch(url, { method, headers, signal: controller.signal });
415
+ }
416
+ catch (err) {
417
+ if (err instanceof Error && err.name === 'AbortError') {
418
+ throw new Error(`HubSpot API request timed out after ${REQUEST_TIMEOUT_MS / 1000}s: ${url}`);
419
+ }
420
+ throw err;
421
+ }
422
+ finally {
423
+ clearTimeout(timeoutId);
424
+ }
425
+ }
426
+ /** Calculates retry delay from Retry-After header or exponential backoff. */
427
+ CalculateRetryDelay(response, attempt) {
428
+ const retryAfter = parseInt(response.headers.get('Retry-After') ?? '0', 10);
429
+ return retryAfter > 0 ? retryAfter * 1000 : Math.min(1000 * Math.pow(2, attempt), 30000);
430
+ }
431
+ /** Converts a fetch Response + parsed body into a RESTResponse. */
432
+ BuildRESTResponse(response, body) {
433
+ const headers = {};
434
+ response.headers.forEach((v, k) => { headers[k.toLowerCase()] = v; });
435
+ return { Status: response.status, Body: body, Headers: headers };
436
+ }
437
+ /** Returns a promise that resolves after the specified number of milliseconds. */
438
+ Sleep(ms) {
439
+ return new Promise(resolve => setTimeout(resolve, ms));
440
+ }
441
+ };
442
+ HubSpotConnector = __decorate([
443
+ RegisterClass(BaseIntegrationConnector, 'HubSpotConnector')
444
+ ], HubSpotConnector);
445
+ export { HubSpotConnector };
446
+ //# sourceMappingURL=HubSpotConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HubSpotConnector.js","sourceRoot":"","sources":["../src/HubSpotConnector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
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, type ExternalRecord } from '@memberjunction/integration-engine';
4
+ import sql from 'mssql';
5
+ /** Connection configuration parsed from CompanyIntegration.Configuration JSON */
6
+ export interface ConnectionConfig {
7
+ /** SQL Server hostname */
8
+ Server: string;
9
+ /** Database name */
10
+ Database: string;
11
+ /** Database user */
12
+ User: string;
13
+ /** Database password */
14
+ Password: string;
15
+ /** Database schema (e.g., 'hs', 'sf', 'ym'). Defaults to 'dbo'. */
16
+ Schema: string;
17
+ }
18
+ /**
19
+ * Abstract base class for connectors that read from relational databases via mssql.
20
+ * Handles connection management, object/field discovery, and connection testing.
21
+ * Subclasses must implement FetchChanges to define record extraction logic.
22
+ */
23
+ export declare abstract class RelationalDBConnector extends BaseIntegrationConnector {
24
+ /** Cache of open connection pools keyed by "server|database" */
25
+ private poolCache;
26
+ /**
27
+ * Parses the Configuration JSON on a CompanyIntegration to extract connection details.
28
+ * @param companyIntegration - The entity containing Configuration JSON
29
+ * @returns Parsed connection configuration
30
+ * @throws Error if Configuration is missing or malformed
31
+ */
32
+ protected ParseConnectionConfig(companyIntegration: MJCompanyIntegrationEntity): ConnectionConfig;
33
+ /**
34
+ * Opens or reuses a mssql ConnectionPool for the given configuration.
35
+ * Pools are cached by server+database to avoid redundant connections.
36
+ * @param config - Connection configuration
37
+ * @returns An open ConnectionPool
38
+ */
39
+ protected GetPool(config: ConnectionConfig): Promise<sql.ConnectionPool>;
40
+ /**
41
+ * Tests connectivity to the source database by running SELECT 1.
42
+ * @param companyIntegration - The company integration with connection configuration
43
+ * @param _contextUser - User context for authorization
44
+ * @returns Connection test result with success/failure and message
45
+ */
46
+ TestConnection(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ConnectionTestResult>;
47
+ /**
48
+ * Discovers all user tables in the source database via INFORMATION_SCHEMA.
49
+ * @param companyIntegration - The company integration with connection configuration
50
+ * @param _contextUser - User context for authorization
51
+ * @returns Array of object schemas for each table found
52
+ */
53
+ DiscoverObjects(companyIntegration: MJCompanyIntegrationEntity, _contextUser: UserInfo): Promise<ExternalObjectSchema[]>;
54
+ /**
55
+ * Discovers columns on a specific table via INFORMATION_SCHEMA.COLUMNS.
56
+ * @param companyIntegration - The company integration with connection configuration
57
+ * @param objectName - Table name to inspect
58
+ * @param _contextUser - User context for authorization
59
+ * @returns Array of field schemas for the specified table
60
+ */
61
+ DiscoverFields(companyIntegration: MJCompanyIntegrationEntity, objectName: string, _contextUser: UserInfo): Promise<ExternalFieldSchema[]>;
62
+ /**
63
+ * Converts a row from INFORMATION_SCHEMA.COLUMNS to an ExternalFieldSchema.
64
+ * @param row - Column metadata row
65
+ * @returns Mapped field schema
66
+ */
67
+ private mapColumnToFieldSchema;
68
+ /**
69
+ * Builds an ExternalRecord from a SQL result row.
70
+ * @param row - Raw database row
71
+ * @param idField - Column name to use as ExternalID
72
+ * @param objectType - Object type name for the record
73
+ * @param modifiedAtField - Column name for the modification timestamp
74
+ * @param deletedField - Column name for the deleted flag (optional)
75
+ * @returns An ExternalRecord
76
+ */
77
+ protected BuildExternalRecord(row: Record<string, unknown>, idField: string, objectType: string, modifiedAtField: string, deletedField?: string): ExternalRecord;
78
+ /**
79
+ * Fetches changed records from a table, ordered by a modification timestamp column.
80
+ * Applies watermark filtering and batch size limiting.
81
+ * @param ctx - Fetch context with integration, object, watermark, and batch details
82
+ * @param idField - Column name for the primary key
83
+ * @param modifiedAtField - Column name for the modification timestamp
84
+ * @param deletedField - Column name for the deleted flag (optional)
85
+ * @returns Batch of external records with pagination info
86
+ */
87
+ protected FetchChangesFromTable(ctx: FetchContext, idField: string, modifiedAtField: string, deletedField?: string): Promise<FetchBatchResult>;
88
+ /**
89
+ * Extracts the full-precision watermark string from the last row's __mj_raw_ts column.
90
+ * Uses CONVERT(varchar, ..., 126) output which preserves datetimeoffset(7) precision,
91
+ * avoiding the sub-millisecond truncation that JavaScript Date introduces.
92
+ * @param rows - Array of database rows containing __mj_raw_ts
93
+ * @returns Full-precision datetimeoffset string, or undefined
94
+ */
95
+ private extractRawWatermark;
96
+ /**
97
+ * Closes all cached connection pools. Call during cleanup/shutdown.
98
+ */
99
+ CloseAllPools(): Promise<void>;
100
+ }
101
+ //# sourceMappingURL=RelationalDBConnector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelationalDBConnector.d.ts","sourceRoot":"","sources":["../src/RelationalDBConnector.ts"],"names":[],"mappings":"AAAA,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,EACrB,KAAK,cAAc,EACtB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,GAAG,MAAM,OAAO,CAAC;AAExB,iFAAiF;AACjF,MAAM,WAAW,gBAAgB;IAC7B,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,8BAAsB,qBAAsB,SAAQ,wBAAwB;IACxE,gEAAgE;IAChE,OAAO,CAAC,SAAS,CAAyC;IAE1D;;;;;OAKG;IACH,SAAS,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,0BAA0B,GAAG,gBAAgB;IAsBjG;;;;;OAKG;cACa,OAAO,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAuB9E;;;;;OAKG;IACU,cAAc,CACvB,kBAAkB,EAAE,0BAA0B,EAC9C,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,oBAAoB,CAAC;IAoBhC;;;;;OAKG;IACU,eAAe,CACxB,kBAAkB,EAAE,0BAA0B,EAC9C,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAkBlC;;;;;;OAMG;IACU,cAAc,CACvB,kBAAkB,EAAE,0BAA0B,EAC9C,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,QAAQ,GACvB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAkBjC;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAW9B;;;;;;;;OAQG;IACH,SAAS,CAAC,mBAAmB,CACzB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,GACtB,cAAc;IAcjB;;;;;;;;OAQG;cACa,qBAAqB,CACjC,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,YAAY,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,CAAC;IAsC5B;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAM3B;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ9C"}