@memberjunction/server 5.16.0 → 5.18.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.
@@ -10,560 +10,3843 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { Resolver, Query, Arg, Ctx, ObjectType, Field, InputType } from "type-graphql";
14
- import { Metadata, LogError } from "@memberjunction/core";
15
- import { ConnectorFactory } from "@memberjunction/integration-engine";
16
- import { SchemaBuilder, TypeMapper } from "@memberjunction/integration-schema-builder";
13
+ var IntegrationDiscoveryResolver_1;
14
+ import { Resolver, Query, Mutation, Arg, Ctx, ObjectType, Field, InputType } from "type-graphql";
15
+ import { CompositeKey, Metadata, RunView, LogError } from "@memberjunction/core";
16
+ import { CronExpressionHelper } from "@memberjunction/scheduling-engine";
17
+ import { ConnectorFactory, IntegrationEngine } from "@memberjunction/integration-engine";
18
+ import { SchemaBuilder, TypeMapper, SchemaEvolution } from "@memberjunction/integration-schema-builder";
19
+ import { RuntimeSchemaManager } from "@memberjunction/schema-engine";
17
20
  import { ResolverBase } from "../generic/ResolverBase.js";
18
- // --- Output Types ---
19
- let ExternalObjectOutput = class ExternalObjectOutput {
21
+ import { UserCache } from "@memberjunction/sqlserver-dataprovider";
22
+ // ─── RSU Pipeline Output Types ──────────────────────────────────────────────
23
+ let RSUStepOutput = class RSUStepOutput {
20
24
  };
21
25
  __decorate([
22
26
  Field(),
23
27
  __metadata("design:type", String)
24
- ], ExternalObjectOutput.prototype, "Name", void 0);
28
+ ], RSUStepOutput.prototype, "Name", void 0);
25
29
  __decorate([
26
30
  Field(),
27
31
  __metadata("design:type", String)
28
- ], ExternalObjectOutput.prototype, "Label", void 0);
32
+ ], RSUStepOutput.prototype, "Status", void 0);
29
33
  __decorate([
30
34
  Field(),
31
- __metadata("design:type", Boolean)
32
- ], ExternalObjectOutput.prototype, "SupportsIncrementalSync", void 0);
35
+ __metadata("design:type", Number)
36
+ ], RSUStepOutput.prototype, "DurationMs", void 0);
33
37
  __decorate([
34
38
  Field(),
35
- __metadata("design:type", Boolean)
36
- ], ExternalObjectOutput.prototype, "SupportsWrite", void 0);
37
- ExternalObjectOutput = __decorate([
39
+ __metadata("design:type", String)
40
+ ], RSUStepOutput.prototype, "Message", void 0);
41
+ RSUStepOutput = __decorate([
38
42
  ObjectType()
39
- ], ExternalObjectOutput);
40
- let DiscoverObjectsOutput = class DiscoverObjectsOutput {
43
+ ], RSUStepOutput);
44
+ let ApplySchemaOutput = class ApplySchemaOutput {
41
45
  };
42
46
  __decorate([
43
47
  Field(),
44
48
  __metadata("design:type", Boolean)
45
- ], DiscoverObjectsOutput.prototype, "Success", void 0);
49
+ ], ApplySchemaOutput.prototype, "Success", void 0);
46
50
  __decorate([
47
51
  Field(),
48
52
  __metadata("design:type", String)
49
- ], DiscoverObjectsOutput.prototype, "Message", void 0);
53
+ ], ApplySchemaOutput.prototype, "Message", void 0);
50
54
  __decorate([
51
- Field(() => [ExternalObjectOutput], { nullable: true }),
55
+ Field(() => [RSUStepOutput], { nullable: true }),
52
56
  __metadata("design:type", Array)
53
- ], DiscoverObjectsOutput.prototype, "Objects", void 0);
54
- DiscoverObjectsOutput = __decorate([
57
+ ], ApplySchemaOutput.prototype, "Steps", void 0);
58
+ __decorate([
59
+ Field({ nullable: true }),
60
+ __metadata("design:type", String)
61
+ ], ApplySchemaOutput.prototype, "MigrationFilePath", void 0);
62
+ __decorate([
63
+ Field({ nullable: true }),
64
+ __metadata("design:type", Number)
65
+ ], ApplySchemaOutput.prototype, "EntitiesProcessed", void 0);
66
+ __decorate([
67
+ Field({ nullable: true }),
68
+ __metadata("design:type", Boolean)
69
+ ], ApplySchemaOutput.prototype, "GitCommitSuccess", void 0);
70
+ __decorate([
71
+ Field({ nullable: true }),
72
+ __metadata("design:type", Boolean)
73
+ ], ApplySchemaOutput.prototype, "APIRestarted", void 0);
74
+ __decorate([
75
+ Field(() => [String], { nullable: true }),
76
+ __metadata("design:type", Array)
77
+ ], ApplySchemaOutput.prototype, "Warnings", void 0);
78
+ ApplySchemaOutput = __decorate([
55
79
  ObjectType()
56
- ], DiscoverObjectsOutput);
57
- let ExternalFieldOutput = class ExternalFieldOutput {
80
+ ], ApplySchemaOutput);
81
+ let ApplySchemaBatchItemInput = class ApplySchemaBatchItemInput {
58
82
  };
59
83
  __decorate([
60
84
  Field(),
61
85
  __metadata("design:type", String)
62
- ], ExternalFieldOutput.prototype, "Name", void 0);
86
+ ], ApplySchemaBatchItemInput.prototype, "CompanyIntegrationID", void 0);
63
87
  __decorate([
64
- Field(),
88
+ Field(() => [SchemaPreviewObjectInput]),
89
+ __metadata("design:type", Array)
90
+ ], ApplySchemaBatchItemInput.prototype, "Objects", void 0);
91
+ ApplySchemaBatchItemInput = __decorate([
92
+ InputType()
93
+ ], ApplySchemaBatchItemInput);
94
+ // ─── Apply All Input/Output Types ───────────────────────────────────────────
95
+ let SourceObjectInput = class SourceObjectInput {
96
+ };
97
+ __decorate([
98
+ Field({ description: 'Source object ID (IntegrationObject.ID)' }),
65
99
  __metadata("design:type", String)
66
- ], ExternalFieldOutput.prototype, "Label", void 0);
100
+ ], SourceObjectInput.prototype, "SourceObjectID", void 0);
101
+ __decorate([
102
+ Field(() => [String], { nullable: true, description: 'Optional field selection. Empty/null = all fields (including any new ones). Only specified fields get field maps.' }),
103
+ __metadata("design:type", Array)
104
+ ], SourceObjectInput.prototype, "Fields", void 0);
105
+ SourceObjectInput = __decorate([
106
+ InputType()
107
+ ], SourceObjectInput);
108
+ let ApplyAllInput = class ApplyAllInput {
109
+ };
67
110
  __decorate([
68
111
  Field(),
69
112
  __metadata("design:type", String)
70
- ], ExternalFieldOutput.prototype, "DataType", void 0);
113
+ ], ApplyAllInput.prototype, "CompanyIntegrationID", void 0);
71
114
  __decorate([
72
- Field(),
73
- __metadata("design:type", Boolean)
74
- ], ExternalFieldOutput.prototype, "IsRequired", void 0);
115
+ Field(() => [SourceObjectInput]),
116
+ __metadata("design:type", Array)
117
+ ], ApplyAllInput.prototype, "SourceObjects", void 0);
75
118
  __decorate([
76
- Field(),
119
+ Field({ nullable: true }),
120
+ __metadata("design:type", String)
121
+ ], ApplyAllInput.prototype, "CronExpression", void 0);
122
+ __decorate([
123
+ Field({ nullable: true }),
124
+ __metadata("design:type", String)
125
+ ], ApplyAllInput.prototype, "ScheduleTimezone", void 0);
126
+ __decorate([
127
+ Field(() => Boolean, { nullable: true, defaultValue: true, description: 'If false, skips the sync step after schema + entity maps are created' }),
77
128
  __metadata("design:type", Boolean)
78
- ], ExternalFieldOutput.prototype, "IsUniqueKey", void 0);
129
+ ], ApplyAllInput.prototype, "StartSync", void 0);
79
130
  __decorate([
80
- Field(),
131
+ Field(() => Boolean, { nullable: true, defaultValue: false, description: 'If true, ignores watermarks and does a full re-fetch' }),
81
132
  __metadata("design:type", Boolean)
82
- ], ExternalFieldOutput.prototype, "IsReadOnly", void 0);
83
- ExternalFieldOutput = __decorate([
84
- ObjectType()
85
- ], ExternalFieldOutput);
86
- let DiscoverFieldsOutput = class DiscoverFieldsOutput {
133
+ ], ApplyAllInput.prototype, "FullSync", void 0);
134
+ __decorate([
135
+ Field({ nullable: true, defaultValue: 'created', description: 'Sync scope: "created" = only newly created entity maps, "all" = all maps for the connector' }),
136
+ __metadata("design:type", String)
137
+ ], ApplyAllInput.prototype, "SyncScope", void 0);
138
+ ApplyAllInput = __decorate([
139
+ InputType()
140
+ ], ApplyAllInput);
141
+ let ApplyAllEntityMapCreated = class ApplyAllEntityMapCreated {
87
142
  };
88
143
  __decorate([
89
144
  Field(),
90
- __metadata("design:type", Boolean)
91
- ], DiscoverFieldsOutput.prototype, "Success", void 0);
145
+ __metadata("design:type", String)
146
+ ], ApplyAllEntityMapCreated.prototype, "SourceObjectName", void 0);
92
147
  __decorate([
93
148
  Field(),
94
149
  __metadata("design:type", String)
95
- ], DiscoverFieldsOutput.prototype, "Message", void 0);
150
+ ], ApplyAllEntityMapCreated.prototype, "EntityName", void 0);
96
151
  __decorate([
97
- Field(() => [ExternalFieldOutput], { nullable: true }),
98
- __metadata("design:type", Array)
99
- ], DiscoverFieldsOutput.prototype, "Fields", void 0);
100
- DiscoverFieldsOutput = __decorate([
152
+ Field(),
153
+ __metadata("design:type", String)
154
+ ], ApplyAllEntityMapCreated.prototype, "EntityMapID", void 0);
155
+ __decorate([
156
+ Field(),
157
+ __metadata("design:type", Number)
158
+ ], ApplyAllEntityMapCreated.prototype, "FieldMapCount", void 0);
159
+ ApplyAllEntityMapCreated = __decorate([
101
160
  ObjectType()
102
- ], DiscoverFieldsOutput);
103
- let ConnectionTestOutput = class ConnectionTestOutput {
161
+ ], ApplyAllEntityMapCreated);
162
+ let ApplyAllOutput = class ApplyAllOutput {
104
163
  };
105
164
  __decorate([
106
165
  Field(),
107
166
  __metadata("design:type", Boolean)
108
- ], ConnectionTestOutput.prototype, "Success", void 0);
167
+ ], ApplyAllOutput.prototype, "Success", void 0);
109
168
  __decorate([
110
169
  Field(),
111
170
  __metadata("design:type", String)
112
- ], ConnectionTestOutput.prototype, "Message", void 0);
171
+ ], ApplyAllOutput.prototype, "Message", void 0);
113
172
  __decorate([
114
- Field(() => String, { nullable: true }),
173
+ Field(() => [RSUStepOutput], { nullable: true }),
174
+ __metadata("design:type", Array)
175
+ ], ApplyAllOutput.prototype, "Steps", void 0);
176
+ __decorate([
177
+ Field(() => [ApplyAllEntityMapCreated], { nullable: true }),
178
+ __metadata("design:type", Array)
179
+ ], ApplyAllOutput.prototype, "EntityMapsCreated", void 0);
180
+ __decorate([
181
+ Field({ nullable: true }),
115
182
  __metadata("design:type", String)
116
- ], ConnectionTestOutput.prototype, "ServerVersion", void 0);
117
- ConnectionTestOutput = __decorate([
118
- ObjectType()
119
- ], ConnectionTestOutput);
120
- // --- Preview Data Types ---
121
- let PreviewRecordOutput = class PreviewRecordOutput {
122
- };
183
+ ], ApplyAllOutput.prototype, "SyncRunID", void 0);
123
184
  __decorate([
124
- Field(() => String),
185
+ Field({ nullable: true }),
125
186
  __metadata("design:type", String)
126
- ], PreviewRecordOutput.prototype, "Data", void 0);
127
- PreviewRecordOutput = __decorate([
187
+ ], ApplyAllOutput.prototype, "ScheduledJobID", void 0);
188
+ __decorate([
189
+ Field({ nullable: true }),
190
+ __metadata("design:type", Boolean)
191
+ ], ApplyAllOutput.prototype, "GitCommitSuccess", void 0);
192
+ __decorate([
193
+ Field({ nullable: true }),
194
+ __metadata("design:type", Boolean)
195
+ ], ApplyAllOutput.prototype, "APIRestarted", void 0);
196
+ __decorate([
197
+ Field(() => [String], { nullable: true }),
198
+ __metadata("design:type", Array)
199
+ ], ApplyAllOutput.prototype, "Warnings", void 0);
200
+ ApplyAllOutput = __decorate([
128
201
  ObjectType()
129
- ], PreviewRecordOutput);
130
- let PreviewDataOutput = class PreviewDataOutput {
202
+ ], ApplyAllOutput);
203
+ let ApplySchemaBatchItemOutput = class ApplySchemaBatchItemOutput {
131
204
  };
205
+ __decorate([
206
+ Field(),
207
+ __metadata("design:type", String)
208
+ ], ApplySchemaBatchItemOutput.prototype, "CompanyIntegrationID", void 0);
132
209
  __decorate([
133
210
  Field(),
134
211
  __metadata("design:type", Boolean)
135
- ], PreviewDataOutput.prototype, "Success", void 0);
212
+ ], ApplySchemaBatchItemOutput.prototype, "Success", void 0);
136
213
  __decorate([
137
214
  Field(),
138
215
  __metadata("design:type", String)
139
- ], PreviewDataOutput.prototype, "Message", void 0);
216
+ ], ApplySchemaBatchItemOutput.prototype, "Message", void 0);
140
217
  __decorate([
141
- Field(() => [PreviewRecordOutput], { nullable: true }),
218
+ Field(() => [String], { nullable: true }),
142
219
  __metadata("design:type", Array)
143
- ], PreviewDataOutput.prototype, "Records", void 0);
144
- PreviewDataOutput = __decorate([
220
+ ], ApplySchemaBatchItemOutput.prototype, "Warnings", void 0);
221
+ ApplySchemaBatchItemOutput = __decorate([
145
222
  ObjectType()
146
- ], PreviewDataOutput);
147
- // --- Schema Preview Types ---
148
- let SchemaPreviewObjectInput = class SchemaPreviewObjectInput {
223
+ ], ApplySchemaBatchItemOutput);
224
+ let ApplySchemaBatchOutput = class ApplySchemaBatchOutput {
149
225
  };
150
226
  __decorate([
151
227
  Field(),
152
- __metadata("design:type", String)
153
- ], SchemaPreviewObjectInput.prototype, "SourceObjectName", void 0);
228
+ __metadata("design:type", Boolean)
229
+ ], ApplySchemaBatchOutput.prototype, "Success", void 0);
154
230
  __decorate([
155
231
  Field(),
156
232
  __metadata("design:type", String)
157
- ], SchemaPreviewObjectInput.prototype, "SchemaName", void 0);
233
+ ], ApplySchemaBatchOutput.prototype, "Message", void 0);
234
+ __decorate([
235
+ Field(() => [ApplySchemaBatchItemOutput]),
236
+ __metadata("design:type", Array)
237
+ ], ApplySchemaBatchOutput.prototype, "Items", void 0);
238
+ __decorate([
239
+ Field(() => [RSUStepOutput], { nullable: true }),
240
+ __metadata("design:type", Array)
241
+ ], ApplySchemaBatchOutput.prototype, "Steps", void 0);
242
+ __decorate([
243
+ Field({ nullable: true }),
244
+ __metadata("design:type", Boolean)
245
+ ], ApplySchemaBatchOutput.prototype, "GitCommitSuccess", void 0);
246
+ __decorate([
247
+ Field({ nullable: true }),
248
+ __metadata("design:type", Boolean)
249
+ ], ApplySchemaBatchOutput.prototype, "APIRestarted", void 0);
250
+ ApplySchemaBatchOutput = __decorate([
251
+ ObjectType()
252
+ ], ApplySchemaBatchOutput);
253
+ // ─── Apply All Batch Input/Output Types ──────────────────────────────────────
254
+ let ApplyAllBatchConnectorInput = class ApplyAllBatchConnectorInput {
255
+ };
158
256
  __decorate([
159
257
  Field(),
160
258
  __metadata("design:type", String)
161
- ], SchemaPreviewObjectInput.prototype, "TableName", void 0);
259
+ ], ApplyAllBatchConnectorInput.prototype, "CompanyIntegrationID", void 0);
162
260
  __decorate([
163
- Field(),
261
+ Field(() => [SourceObjectInput]),
262
+ __metadata("design:type", Array)
263
+ ], ApplyAllBatchConnectorInput.prototype, "SourceObjects", void 0);
264
+ __decorate([
265
+ Field({ nullable: true }),
164
266
  __metadata("design:type", String)
165
- ], SchemaPreviewObjectInput.prototype, "EntityName", void 0);
166
- SchemaPreviewObjectInput = __decorate([
267
+ ], ApplyAllBatchConnectorInput.prototype, "CronExpression", void 0);
268
+ __decorate([
269
+ Field({ nullable: true }),
270
+ __metadata("design:type", String)
271
+ ], ApplyAllBatchConnectorInput.prototype, "ScheduleTimezone", void 0);
272
+ ApplyAllBatchConnectorInput = __decorate([
167
273
  InputType()
168
- ], SchemaPreviewObjectInput);
169
- let SchemaPreviewFileOutput = class SchemaPreviewFileOutput {
274
+ ], ApplyAllBatchConnectorInput);
275
+ let ApplyAllBatchInput = class ApplyAllBatchInput {
170
276
  };
171
277
  __decorate([
172
- Field(),
278
+ Field(() => [ApplyAllBatchConnectorInput]),
279
+ __metadata("design:type", Array)
280
+ ], ApplyAllBatchInput.prototype, "Connectors", void 0);
281
+ __decorate([
282
+ Field(() => Boolean, { nullable: true, defaultValue: true, description: 'If false, skips sync after schema + entity maps' }),
283
+ __metadata("design:type", Boolean)
284
+ ], ApplyAllBatchInput.prototype, "StartSync", void 0);
285
+ __decorate([
286
+ Field(() => Boolean, { nullable: true, defaultValue: false, description: 'If true, ignores watermarks and does a full re-fetch' }),
287
+ __metadata("design:type", Boolean)
288
+ ], ApplyAllBatchInput.prototype, "FullSync", void 0);
289
+ __decorate([
290
+ Field({ nullable: true, defaultValue: 'created', description: 'Sync scope: "created" = only newly created entity maps, "all" = all maps for the connector' }),
173
291
  __metadata("design:type", String)
174
- ], SchemaPreviewFileOutput.prototype, "FilePath", void 0);
292
+ ], ApplyAllBatchInput.prototype, "SyncScope", void 0);
293
+ ApplyAllBatchInput = __decorate([
294
+ InputType()
295
+ ], ApplyAllBatchInput);
296
+ let ApplyAllBatchConnectorResult = class ApplyAllBatchConnectorResult {
297
+ };
175
298
  __decorate([
176
299
  Field(),
177
300
  __metadata("design:type", String)
178
- ], SchemaPreviewFileOutput.prototype, "Content", void 0);
301
+ ], ApplyAllBatchConnectorResult.prototype, "CompanyIntegrationID", void 0);
179
302
  __decorate([
180
303
  Field(),
181
304
  __metadata("design:type", String)
182
- ], SchemaPreviewFileOutput.prototype, "Description", void 0);
183
- SchemaPreviewFileOutput = __decorate([
184
- ObjectType()
185
- ], SchemaPreviewFileOutput);
186
- let SchemaPreviewOutput = class SchemaPreviewOutput {
187
- };
305
+ ], ApplyAllBatchConnectorResult.prototype, "IntegrationName", void 0);
188
306
  __decorate([
189
307
  Field(),
190
308
  __metadata("design:type", Boolean)
191
- ], SchemaPreviewOutput.prototype, "Success", void 0);
309
+ ], ApplyAllBatchConnectorResult.prototype, "Success", void 0);
192
310
  __decorate([
193
311
  Field(),
194
312
  __metadata("design:type", String)
195
- ], SchemaPreviewOutput.prototype, "Message", void 0);
313
+ ], ApplyAllBatchConnectorResult.prototype, "Message", void 0);
196
314
  __decorate([
197
- Field(() => [SchemaPreviewFileOutput], { nullable: true }),
315
+ Field(() => [ApplyAllEntityMapCreated], { nullable: true }),
198
316
  __metadata("design:type", Array)
199
- ], SchemaPreviewOutput.prototype, "Files", void 0);
317
+ ], ApplyAllBatchConnectorResult.prototype, "EntityMapsCreated", void 0);
318
+ __decorate([
319
+ Field({ nullable: true }),
320
+ __metadata("design:type", String)
321
+ ], ApplyAllBatchConnectorResult.prototype, "SyncRunID", void 0);
322
+ __decorate([
323
+ Field({ nullable: true }),
324
+ __metadata("design:type", String)
325
+ ], ApplyAllBatchConnectorResult.prototype, "ScheduledJobID", void 0);
200
326
  __decorate([
201
327
  Field(() => [String], { nullable: true }),
202
328
  __metadata("design:type", Array)
203
- ], SchemaPreviewOutput.prototype, "Warnings", void 0);
204
- SchemaPreviewOutput = __decorate([
329
+ ], ApplyAllBatchConnectorResult.prototype, "Warnings", void 0);
330
+ ApplyAllBatchConnectorResult = __decorate([
205
331
  ObjectType()
206
- ], SchemaPreviewOutput);
207
- // --- Default Configuration Types ---
208
- let DefaultFieldMappingOutput = class DefaultFieldMappingOutput {
332
+ ], ApplyAllBatchConnectorResult);
333
+ let ApplyAllBatchOutput = class ApplyAllBatchOutput {
209
334
  };
210
335
  __decorate([
211
336
  Field(),
212
- __metadata("design:type", String)
213
- ], DefaultFieldMappingOutput.prototype, "SourceFieldName", void 0);
337
+ __metadata("design:type", Boolean)
338
+ ], ApplyAllBatchOutput.prototype, "Success", void 0);
214
339
  __decorate([
215
340
  Field(),
216
341
  __metadata("design:type", String)
217
- ], DefaultFieldMappingOutput.prototype, "DestinationFieldName", void 0);
342
+ ], ApplyAllBatchOutput.prototype, "Message", void 0);
343
+ __decorate([
344
+ Field(() => [ApplyAllBatchConnectorResult]),
345
+ __metadata("design:type", Array)
346
+ ], ApplyAllBatchOutput.prototype, "ConnectorResults", void 0);
347
+ __decorate([
348
+ Field(() => [RSUStepOutput], { nullable: true }),
349
+ __metadata("design:type", Array)
350
+ ], ApplyAllBatchOutput.prototype, "PipelineSteps", void 0);
218
351
  __decorate([
219
352
  Field({ nullable: true }),
220
353
  __metadata("design:type", Boolean)
221
- ], DefaultFieldMappingOutput.prototype, "IsKeyField", void 0);
222
- DefaultFieldMappingOutput = __decorate([
354
+ ], ApplyAllBatchOutput.prototype, "GitCommitSuccess", void 0);
355
+ __decorate([
356
+ Field({ nullable: true }),
357
+ __metadata("design:type", Boolean)
358
+ ], ApplyAllBatchOutput.prototype, "APIRestarted", void 0);
359
+ __decorate([
360
+ Field(),
361
+ __metadata("design:type", Number)
362
+ ], ApplyAllBatchOutput.prototype, "SuccessCount", void 0);
363
+ __decorate([
364
+ Field(),
365
+ __metadata("design:type", Number)
366
+ ], ApplyAllBatchOutput.prototype, "FailureCount", void 0);
367
+ ApplyAllBatchOutput = __decorate([
223
368
  ObjectType()
224
- ], DefaultFieldMappingOutput);
225
- let DefaultObjectConfigOutput = class DefaultObjectConfigOutput {
369
+ ], ApplyAllBatchOutput);
370
+ // ─── Delete Connection Output ────────────────────────────────────────────────
371
+ let DeleteConnectionOutput = class DeleteConnectionOutput {
226
372
  };
227
373
  __decorate([
228
374
  Field(),
229
- __metadata("design:type", String)
230
- ], DefaultObjectConfigOutput.prototype, "SourceObjectName", void 0);
375
+ __metadata("design:type", Boolean)
376
+ ], DeleteConnectionOutput.prototype, "Success", void 0);
231
377
  __decorate([
232
378
  Field(),
233
379
  __metadata("design:type", String)
234
- ], DefaultObjectConfigOutput.prototype, "TargetTableName", void 0);
380
+ ], DeleteConnectionOutput.prototype, "Message", void 0);
381
+ __decorate([
382
+ Field({ nullable: true }),
383
+ __metadata("design:type", Number)
384
+ ], DeleteConnectionOutput.prototype, "EntityMapsDeleted", void 0);
385
+ __decorate([
386
+ Field({ nullable: true }),
387
+ __metadata("design:type", Number)
388
+ ], DeleteConnectionOutput.prototype, "FieldMapsDeleted", void 0);
389
+ __decorate([
390
+ Field({ nullable: true }),
391
+ __metadata("design:type", Number)
392
+ ], DeleteConnectionOutput.prototype, "SchedulesDeleted", void 0);
393
+ DeleteConnectionOutput = __decorate([
394
+ ObjectType()
395
+ ], DeleteConnectionOutput);
396
+ // ─── Schema Evolution Output ─────────────────────────────────────────────────
397
+ let SchemaEvolutionOutput = class SchemaEvolutionOutput {
398
+ };
399
+ __decorate([
400
+ Field(),
401
+ __metadata("design:type", Boolean)
402
+ ], SchemaEvolutionOutput.prototype, "Success", void 0);
235
403
  __decorate([
236
404
  Field(),
237
405
  __metadata("design:type", String)
238
- ], DefaultObjectConfigOutput.prototype, "TargetEntityName", void 0);
406
+ ], SchemaEvolutionOutput.prototype, "Message", void 0);
239
407
  __decorate([
240
408
  Field(),
241
409
  __metadata("design:type", Boolean)
242
- ], DefaultObjectConfigOutput.prototype, "SyncEnabled", void 0);
410
+ ], SchemaEvolutionOutput.prototype, "HasChanges", void 0);
243
411
  __decorate([
244
- Field(() => [DefaultFieldMappingOutput]),
412
+ Field({ nullable: true }),
413
+ __metadata("design:type", Number)
414
+ ], SchemaEvolutionOutput.prototype, "AddedColumns", void 0);
415
+ __decorate([
416
+ Field({ nullable: true }),
417
+ __metadata("design:type", Number)
418
+ ], SchemaEvolutionOutput.prototype, "ModifiedColumns", void 0);
419
+ __decorate([
420
+ Field(() => [RSUStepOutput], { nullable: true }),
245
421
  __metadata("design:type", Array)
246
- ], DefaultObjectConfigOutput.prototype, "FieldMappings", void 0);
247
- DefaultObjectConfigOutput = __decorate([
422
+ ], SchemaEvolutionOutput.prototype, "Steps", void 0);
423
+ __decorate([
424
+ Field({ nullable: true }),
425
+ __metadata("design:type", Boolean)
426
+ ], SchemaEvolutionOutput.prototype, "GitCommitSuccess", void 0);
427
+ __decorate([
428
+ Field({ nullable: true }),
429
+ __metadata("design:type", Boolean)
430
+ ], SchemaEvolutionOutput.prototype, "APIRestarted", void 0);
431
+ __decorate([
432
+ Field(() => [String], { nullable: true }),
433
+ __metadata("design:type", Array)
434
+ ], SchemaEvolutionOutput.prototype, "Warnings", void 0);
435
+ SchemaEvolutionOutput = __decorate([
248
436
  ObjectType()
249
- ], DefaultObjectConfigOutput);
250
- let DefaultConfigOutput = class DefaultConfigOutput {
437
+ ], SchemaEvolutionOutput);
438
+ // ─── Connector Capabilities Output Type ─────────────────────────────────────
439
+ let ConnectorCapabilitiesOutput = class ConnectorCapabilitiesOutput {
251
440
  };
252
441
  __decorate([
253
442
  Field(),
254
443
  __metadata("design:type", Boolean)
255
- ], DefaultConfigOutput.prototype, "Success", void 0);
444
+ ], ConnectorCapabilitiesOutput.prototype, "Success", void 0);
256
445
  __decorate([
257
446
  Field(),
258
447
  __metadata("design:type", String)
259
- ], DefaultConfigOutput.prototype, "Message", void 0);
448
+ ], ConnectorCapabilitiesOutput.prototype, "Message", void 0);
260
449
  __decorate([
261
450
  Field({ nullable: true }),
262
- __metadata("design:type", String)
263
- ], DefaultConfigOutput.prototype, "DefaultSchemaName", void 0);
451
+ __metadata("design:type", Boolean)
452
+ ], ConnectorCapabilitiesOutput.prototype, "SupportsGet", void 0);
264
453
  __decorate([
265
- Field(() => [DefaultObjectConfigOutput], { nullable: true }),
266
- __metadata("design:type", Array)
267
- ], DefaultConfigOutput.prototype, "DefaultObjects", void 0);
268
- DefaultConfigOutput = __decorate([
454
+ Field({ nullable: true }),
455
+ __metadata("design:type", Boolean)
456
+ ], ConnectorCapabilitiesOutput.prototype, "SupportsCreate", void 0);
457
+ __decorate([
458
+ Field({ nullable: true }),
459
+ __metadata("design:type", Boolean)
460
+ ], ConnectorCapabilitiesOutput.prototype, "SupportsUpdate", void 0);
461
+ __decorate([
462
+ Field({ nullable: true }),
463
+ __metadata("design:type", Boolean)
464
+ ], ConnectorCapabilitiesOutput.prototype, "SupportsDelete", void 0);
465
+ __decorate([
466
+ Field({ nullable: true }),
467
+ __metadata("design:type", Boolean)
468
+ ], ConnectorCapabilitiesOutput.prototype, "SupportsSearch", void 0);
469
+ ConnectorCapabilitiesOutput = __decorate([
470
+ ObjectType()
471
+ ], ConnectorCapabilitiesOutput);
472
+ // --- Connector Discovery Output Types ---
473
+ let ConnectorInfoOutput = class ConnectorInfoOutput {
474
+ };
475
+ __decorate([
476
+ Field(),
477
+ __metadata("design:type", String)
478
+ ], ConnectorInfoOutput.prototype, "IntegrationID", void 0);
479
+ __decorate([
480
+ Field(),
481
+ __metadata("design:type", String)
482
+ ], ConnectorInfoOutput.prototype, "Name", void 0);
483
+ __decorate([
484
+ Field({ nullable: true }),
485
+ __metadata("design:type", String)
486
+ ], ConnectorInfoOutput.prototype, "Description", void 0);
487
+ __decorate([
488
+ Field({ nullable: true }),
489
+ __metadata("design:type", String)
490
+ ], ConnectorInfoOutput.prototype, "ClassName", void 0);
491
+ __decorate([
492
+ Field(),
493
+ __metadata("design:type", Boolean)
494
+ ], ConnectorInfoOutput.prototype, "IsActive", void 0);
495
+ ConnectorInfoOutput = __decorate([
496
+ ObjectType()
497
+ ], ConnectorInfoOutput);
498
+ let DiscoverConnectorsOutput = class DiscoverConnectorsOutput {
499
+ };
500
+ __decorate([
501
+ Field(),
502
+ __metadata("design:type", Boolean)
503
+ ], DiscoverConnectorsOutput.prototype, "Success", void 0);
504
+ __decorate([
505
+ Field(),
506
+ __metadata("design:type", String)
507
+ ], DiscoverConnectorsOutput.prototype, "Message", void 0);
508
+ __decorate([
509
+ Field(() => [ConnectorInfoOutput], { nullable: true }),
510
+ __metadata("design:type", Array)
511
+ ], DiscoverConnectorsOutput.prototype, "Connectors", void 0);
512
+ DiscoverConnectorsOutput = __decorate([
513
+ ObjectType()
514
+ ], DiscoverConnectorsOutput);
515
+ // --- Field Map List Output Types ---
516
+ let FieldMapSummaryOutput = class FieldMapSummaryOutput {
517
+ };
518
+ __decorate([
519
+ Field(),
520
+ __metadata("design:type", String)
521
+ ], FieldMapSummaryOutput.prototype, "ID", void 0);
522
+ __decorate([
523
+ Field(),
524
+ __metadata("design:type", String)
525
+ ], FieldMapSummaryOutput.prototype, "EntityMapID", void 0);
526
+ __decorate([
527
+ Field({ nullable: true }),
528
+ __metadata("design:type", String)
529
+ ], FieldMapSummaryOutput.prototype, "SourceFieldName", void 0);
530
+ __decorate([
531
+ Field({ nullable: true }),
532
+ __metadata("design:type", String)
533
+ ], FieldMapSummaryOutput.prototype, "DestinationFieldName", void 0);
534
+ __decorate([
535
+ Field({ nullable: true }),
536
+ __metadata("design:type", String)
537
+ ], FieldMapSummaryOutput.prototype, "Status", void 0);
538
+ FieldMapSummaryOutput = __decorate([
539
+ ObjectType()
540
+ ], FieldMapSummaryOutput);
541
+ let ListFieldMapsOutput = class ListFieldMapsOutput {
542
+ };
543
+ __decorate([
544
+ Field(),
545
+ __metadata("design:type", Boolean)
546
+ ], ListFieldMapsOutput.prototype, "Success", void 0);
547
+ __decorate([
548
+ Field(),
549
+ __metadata("design:type", String)
550
+ ], ListFieldMapsOutput.prototype, "Message", void 0);
551
+ __decorate([
552
+ Field(() => [FieldMapSummaryOutput], { nullable: true }),
553
+ __metadata("design:type", Array)
554
+ ], ListFieldMapsOutput.prototype, "FieldMaps", void 0);
555
+ ListFieldMapsOutput = __decorate([
556
+ ObjectType()
557
+ ], ListFieldMapsOutput);
558
+ // --- Output Types ---
559
+ let ExternalObjectOutput = class ExternalObjectOutput {
560
+ };
561
+ __decorate([
562
+ Field({ nullable: true }),
563
+ __metadata("design:type", String)
564
+ ], ExternalObjectOutput.prototype, "ID", void 0);
565
+ __decorate([
566
+ Field(),
567
+ __metadata("design:type", String)
568
+ ], ExternalObjectOutput.prototype, "Name", void 0);
569
+ __decorate([
570
+ Field(),
571
+ __metadata("design:type", String)
572
+ ], ExternalObjectOutput.prototype, "Label", void 0);
573
+ __decorate([
574
+ Field(),
575
+ __metadata("design:type", Boolean)
576
+ ], ExternalObjectOutput.prototype, "SupportsIncrementalSync", void 0);
577
+ __decorate([
578
+ Field(),
579
+ __metadata("design:type", Boolean)
580
+ ], ExternalObjectOutput.prototype, "SupportsWrite", void 0);
581
+ ExternalObjectOutput = __decorate([
582
+ ObjectType()
583
+ ], ExternalObjectOutput);
584
+ let DiscoverObjectsOutput = class DiscoverObjectsOutput {
585
+ };
586
+ __decorate([
587
+ Field(),
588
+ __metadata("design:type", Boolean)
589
+ ], DiscoverObjectsOutput.prototype, "Success", void 0);
590
+ __decorate([
591
+ Field(),
592
+ __metadata("design:type", String)
593
+ ], DiscoverObjectsOutput.prototype, "Message", void 0);
594
+ __decorate([
595
+ Field(() => [ExternalObjectOutput], { nullable: true }),
596
+ __metadata("design:type", Array)
597
+ ], DiscoverObjectsOutput.prototype, "Objects", void 0);
598
+ DiscoverObjectsOutput = __decorate([
599
+ ObjectType()
600
+ ], DiscoverObjectsOutput);
601
+ let ExternalFieldOutput = class ExternalFieldOutput {
602
+ };
603
+ __decorate([
604
+ Field(),
605
+ __metadata("design:type", String)
606
+ ], ExternalFieldOutput.prototype, "Name", void 0);
607
+ __decorate([
608
+ Field(),
609
+ __metadata("design:type", String)
610
+ ], ExternalFieldOutput.prototype, "Label", void 0);
611
+ __decorate([
612
+ Field(),
613
+ __metadata("design:type", String)
614
+ ], ExternalFieldOutput.prototype, "DataType", void 0);
615
+ __decorate([
616
+ Field(),
617
+ __metadata("design:type", Boolean)
618
+ ], ExternalFieldOutput.prototype, "IsRequired", void 0);
619
+ __decorate([
620
+ Field(),
621
+ __metadata("design:type", Boolean)
622
+ ], ExternalFieldOutput.prototype, "IsUniqueKey", void 0);
623
+ __decorate([
624
+ Field(),
625
+ __metadata("design:type", Boolean)
626
+ ], ExternalFieldOutput.prototype, "IsReadOnly", void 0);
627
+ ExternalFieldOutput = __decorate([
628
+ ObjectType()
629
+ ], ExternalFieldOutput);
630
+ let DiscoverFieldsOutput = class DiscoverFieldsOutput {
631
+ };
632
+ __decorate([
633
+ Field(),
634
+ __metadata("design:type", Boolean)
635
+ ], DiscoverFieldsOutput.prototype, "Success", void 0);
636
+ __decorate([
637
+ Field(),
638
+ __metadata("design:type", String)
639
+ ], DiscoverFieldsOutput.prototype, "Message", void 0);
640
+ __decorate([
641
+ Field(() => [ExternalFieldOutput], { nullable: true }),
642
+ __metadata("design:type", Array)
643
+ ], DiscoverFieldsOutput.prototype, "Fields", void 0);
644
+ DiscoverFieldsOutput = __decorate([
645
+ ObjectType()
646
+ ], DiscoverFieldsOutput);
647
+ let ConnectionTestOutput = class ConnectionTestOutput {
648
+ };
649
+ __decorate([
650
+ Field(),
651
+ __metadata("design:type", Boolean)
652
+ ], ConnectionTestOutput.prototype, "Success", void 0);
653
+ __decorate([
654
+ Field(),
655
+ __metadata("design:type", String)
656
+ ], ConnectionTestOutput.prototype, "Message", void 0);
657
+ __decorate([
658
+ Field(() => String, { nullable: true }),
659
+ __metadata("design:type", String)
660
+ ], ConnectionTestOutput.prototype, "ServerVersion", void 0);
661
+ ConnectionTestOutput = __decorate([
662
+ ObjectType()
663
+ ], ConnectionTestOutput);
664
+ // --- Preview Data Types ---
665
+ let PreviewRecordOutput = class PreviewRecordOutput {
666
+ };
667
+ __decorate([
668
+ Field(() => String),
669
+ __metadata("design:type", String)
670
+ ], PreviewRecordOutput.prototype, "Data", void 0);
671
+ PreviewRecordOutput = __decorate([
672
+ ObjectType()
673
+ ], PreviewRecordOutput);
674
+ let PreviewDataOutput = class PreviewDataOutput {
675
+ };
676
+ __decorate([
677
+ Field(),
678
+ __metadata("design:type", Boolean)
679
+ ], PreviewDataOutput.prototype, "Success", void 0);
680
+ __decorate([
681
+ Field(),
682
+ __metadata("design:type", String)
683
+ ], PreviewDataOutput.prototype, "Message", void 0);
684
+ __decorate([
685
+ Field(() => [PreviewRecordOutput], { nullable: true }),
686
+ __metadata("design:type", Array)
687
+ ], PreviewDataOutput.prototype, "Records", void 0);
688
+ PreviewDataOutput = __decorate([
689
+ ObjectType()
690
+ ], PreviewDataOutput);
691
+ // --- Schema Preview Types ---
692
+ let SchemaPreviewObjectInput = class SchemaPreviewObjectInput {
693
+ };
694
+ __decorate([
695
+ Field({ nullable: true, description: 'Source object name. Required if SourceObjectID is not provided.' }),
696
+ __metadata("design:type", String)
697
+ ], SchemaPreviewObjectInput.prototype, "SourceObjectName", void 0);
698
+ __decorate([
699
+ Field({ nullable: true, description: 'Source object ID (IntegrationObject.ID). Takes priority over SourceObjectName when provided.' }),
700
+ __metadata("design:type", String)
701
+ ], SchemaPreviewObjectInput.prototype, "SourceObjectID", void 0);
702
+ __decorate([
703
+ Field(),
704
+ __metadata("design:type", String)
705
+ ], SchemaPreviewObjectInput.prototype, "SchemaName", void 0);
706
+ __decorate([
707
+ Field(),
708
+ __metadata("design:type", String)
709
+ ], SchemaPreviewObjectInput.prototype, "TableName", void 0);
710
+ __decorate([
711
+ Field(),
712
+ __metadata("design:type", String)
713
+ ], SchemaPreviewObjectInput.prototype, "EntityName", void 0);
714
+ __decorate([
715
+ Field(() => [String], { nullable: true, description: 'Optional field selection. If provided, only these source fields are included. Default = all fields.' }),
716
+ __metadata("design:type", Array)
717
+ ], SchemaPreviewObjectInput.prototype, "Fields", void 0);
718
+ SchemaPreviewObjectInput = __decorate([
719
+ InputType()
720
+ ], SchemaPreviewObjectInput);
721
+ let SchemaPreviewFileOutput = class SchemaPreviewFileOutput {
722
+ };
723
+ __decorate([
724
+ Field(),
725
+ __metadata("design:type", String)
726
+ ], SchemaPreviewFileOutput.prototype, "FilePath", void 0);
727
+ __decorate([
728
+ Field(),
729
+ __metadata("design:type", String)
730
+ ], SchemaPreviewFileOutput.prototype, "Content", void 0);
731
+ __decorate([
732
+ Field(),
733
+ __metadata("design:type", String)
734
+ ], SchemaPreviewFileOutput.prototype, "Description", void 0);
735
+ SchemaPreviewFileOutput = __decorate([
736
+ ObjectType()
737
+ ], SchemaPreviewFileOutput);
738
+ let SchemaPreviewOutput = class SchemaPreviewOutput {
739
+ };
740
+ __decorate([
741
+ Field(),
742
+ __metadata("design:type", Boolean)
743
+ ], SchemaPreviewOutput.prototype, "Success", void 0);
744
+ __decorate([
745
+ Field(),
746
+ __metadata("design:type", String)
747
+ ], SchemaPreviewOutput.prototype, "Message", void 0);
748
+ __decorate([
749
+ Field(() => [SchemaPreviewFileOutput], { nullable: true }),
750
+ __metadata("design:type", Array)
751
+ ], SchemaPreviewOutput.prototype, "Files", void 0);
752
+ __decorate([
753
+ Field(() => [String], { nullable: true }),
754
+ __metadata("design:type", Array)
755
+ ], SchemaPreviewOutput.prototype, "Warnings", void 0);
756
+ SchemaPreviewOutput = __decorate([
757
+ ObjectType()
758
+ ], SchemaPreviewOutput);
759
+ // --- Default Configuration Types ---
760
+ let DefaultFieldMappingOutput = class DefaultFieldMappingOutput {
761
+ };
762
+ __decorate([
763
+ Field(),
764
+ __metadata("design:type", String)
765
+ ], DefaultFieldMappingOutput.prototype, "SourceFieldName", void 0);
766
+ __decorate([
767
+ Field(),
768
+ __metadata("design:type", String)
769
+ ], DefaultFieldMappingOutput.prototype, "DestinationFieldName", void 0);
770
+ __decorate([
771
+ Field({ nullable: true }),
772
+ __metadata("design:type", Boolean)
773
+ ], DefaultFieldMappingOutput.prototype, "IsKeyField", void 0);
774
+ DefaultFieldMappingOutput = __decorate([
775
+ ObjectType()
776
+ ], DefaultFieldMappingOutput);
777
+ let DefaultObjectConfigOutput = class DefaultObjectConfigOutput {
778
+ };
779
+ __decorate([
780
+ Field(),
781
+ __metadata("design:type", String)
782
+ ], DefaultObjectConfigOutput.prototype, "SourceObjectName", void 0);
783
+ __decorate([
784
+ Field(),
785
+ __metadata("design:type", String)
786
+ ], DefaultObjectConfigOutput.prototype, "TargetTableName", void 0);
787
+ __decorate([
788
+ Field(),
789
+ __metadata("design:type", String)
790
+ ], DefaultObjectConfigOutput.prototype, "TargetEntityName", void 0);
791
+ __decorate([
792
+ Field(),
793
+ __metadata("design:type", Boolean)
794
+ ], DefaultObjectConfigOutput.prototype, "SyncEnabled", void 0);
795
+ __decorate([
796
+ Field(() => [DefaultFieldMappingOutput]),
797
+ __metadata("design:type", Array)
798
+ ], DefaultObjectConfigOutput.prototype, "FieldMappings", void 0);
799
+ DefaultObjectConfigOutput = __decorate([
800
+ ObjectType()
801
+ ], DefaultObjectConfigOutput);
802
+ let DefaultConfigOutput = class DefaultConfigOutput {
803
+ };
804
+ __decorate([
805
+ Field(),
806
+ __metadata("design:type", Boolean)
807
+ ], DefaultConfigOutput.prototype, "Success", void 0);
808
+ __decorate([
809
+ Field(),
810
+ __metadata("design:type", String)
811
+ ], DefaultConfigOutput.prototype, "Message", void 0);
812
+ __decorate([
813
+ Field({ nullable: true }),
814
+ __metadata("design:type", String)
815
+ ], DefaultConfigOutput.prototype, "DefaultSchemaName", void 0);
816
+ __decorate([
817
+ Field(() => [DefaultObjectConfigOutput], { nullable: true }),
818
+ __metadata("design:type", Array)
819
+ ], DefaultConfigOutput.prototype, "DefaultObjects", void 0);
820
+ DefaultConfigOutput = __decorate([
269
821
  ObjectType()
270
822
  ], DefaultConfigOutput);
823
+ // ─── Integration Management Input/Output Types ─────────────────────────────
824
+ let CreateConnectionInput = class CreateConnectionInput {
825
+ };
826
+ __decorate([
827
+ Field(),
828
+ __metadata("design:type", String)
829
+ ], CreateConnectionInput.prototype, "IntegrationID", void 0);
830
+ __decorate([
831
+ Field(),
832
+ __metadata("design:type", String)
833
+ ], CreateConnectionInput.prototype, "CompanyID", void 0);
834
+ __decorate([
835
+ Field(),
836
+ __metadata("design:type", String)
837
+ ], CreateConnectionInput.prototype, "CredentialTypeID", void 0);
838
+ __decorate([
839
+ Field(),
840
+ __metadata("design:type", String)
841
+ ], CreateConnectionInput.prototype, "CredentialName", void 0);
842
+ __decorate([
843
+ Field(),
844
+ __metadata("design:type", String)
845
+ ], CreateConnectionInput.prototype, "CredentialValues", void 0);
846
+ __decorate([
847
+ Field({ nullable: true }),
848
+ __metadata("design:type", String)
849
+ ], CreateConnectionInput.prototype, "ExternalSystemID", void 0);
850
+ __decorate([
851
+ Field({ nullable: true }),
852
+ __metadata("design:type", String)
853
+ ], CreateConnectionInput.prototype, "Configuration", void 0);
854
+ CreateConnectionInput = __decorate([
855
+ InputType()
856
+ ], CreateConnectionInput);
857
+ let CreateConnectionOutput = class CreateConnectionOutput {
858
+ };
859
+ __decorate([
860
+ Field(),
861
+ __metadata("design:type", Boolean)
862
+ ], CreateConnectionOutput.prototype, "Success", void 0);
863
+ __decorate([
864
+ Field(),
865
+ __metadata("design:type", String)
866
+ ], CreateConnectionOutput.prototype, "Message", void 0);
867
+ __decorate([
868
+ Field({ nullable: true }),
869
+ __metadata("design:type", String)
870
+ ], CreateConnectionOutput.prototype, "CompanyIntegrationID", void 0);
871
+ __decorate([
872
+ Field({ nullable: true }),
873
+ __metadata("design:type", String)
874
+ ], CreateConnectionOutput.prototype, "CredentialID", void 0);
875
+ __decorate([
876
+ Field({ nullable: true }),
877
+ __metadata("design:type", Boolean)
878
+ ], CreateConnectionOutput.prototype, "ConnectionTestSuccess", void 0);
879
+ __decorate([
880
+ Field({ nullable: true }),
881
+ __metadata("design:type", String)
882
+ ], CreateConnectionOutput.prototype, "ConnectionTestMessage", void 0);
883
+ CreateConnectionOutput = __decorate([
884
+ ObjectType()
885
+ ], CreateConnectionOutput);
886
+ let MutationResultOutput = class MutationResultOutput {
887
+ };
888
+ __decorate([
889
+ Field(),
890
+ __metadata("design:type", Boolean)
891
+ ], MutationResultOutput.prototype, "Success", void 0);
892
+ __decorate([
893
+ Field(),
894
+ __metadata("design:type", String)
895
+ ], MutationResultOutput.prototype, "Message", void 0);
896
+ MutationResultOutput = __decorate([
897
+ ObjectType()
898
+ ], MutationResultOutput);
899
+ let FieldMapInput = class FieldMapInput {
900
+ };
901
+ __decorate([
902
+ Field(),
903
+ __metadata("design:type", String)
904
+ ], FieldMapInput.prototype, "SourceFieldName", void 0);
905
+ __decorate([
906
+ Field(),
907
+ __metadata("design:type", String)
908
+ ], FieldMapInput.prototype, "DestinationFieldName", void 0);
909
+ __decorate([
910
+ Field({ nullable: true, defaultValue: false }),
911
+ __metadata("design:type", Boolean)
912
+ ], FieldMapInput.prototype, "IsKeyField", void 0);
913
+ __decorate([
914
+ Field({ nullable: true, defaultValue: false }),
915
+ __metadata("design:type", Boolean)
916
+ ], FieldMapInput.prototype, "IsRequired", void 0);
917
+ FieldMapInput = __decorate([
918
+ InputType()
919
+ ], FieldMapInput);
920
+ let EntityMapInput = class EntityMapInput {
921
+ };
922
+ __decorate([
923
+ Field(),
924
+ __metadata("design:type", String)
925
+ ], EntityMapInput.prototype, "ExternalObjectName", void 0);
926
+ __decorate([
927
+ Field({ nullable: true }),
928
+ __metadata("design:type", String)
929
+ ], EntityMapInput.prototype, "EntityName", void 0);
930
+ __decorate([
931
+ Field({ nullable: true }),
932
+ __metadata("design:type", String)
933
+ ], EntityMapInput.prototype, "EntityID", void 0);
934
+ __decorate([
935
+ Field({ nullable: true, defaultValue: 'Pull' }),
936
+ __metadata("design:type", String)
937
+ ], EntityMapInput.prototype, "SyncDirection", void 0);
938
+ __decorate([
939
+ Field({ nullable: true, defaultValue: 0 }),
940
+ __metadata("design:type", Number)
941
+ ], EntityMapInput.prototype, "Priority", void 0);
942
+ __decorate([
943
+ Field(() => [FieldMapInput], { nullable: true }),
944
+ __metadata("design:type", Array)
945
+ ], EntityMapInput.prototype, "FieldMaps", void 0);
946
+ EntityMapInput = __decorate([
947
+ InputType()
948
+ ], EntityMapInput);
949
+ let EntityMapCreatedOutput = class EntityMapCreatedOutput {
950
+ };
951
+ __decorate([
952
+ Field(),
953
+ __metadata("design:type", String)
954
+ ], EntityMapCreatedOutput.prototype, "EntityMapID", void 0);
955
+ __decorate([
956
+ Field(),
957
+ __metadata("design:type", String)
958
+ ], EntityMapCreatedOutput.prototype, "ExternalObjectName", void 0);
959
+ __decorate([
960
+ Field(),
961
+ __metadata("design:type", Number)
962
+ ], EntityMapCreatedOutput.prototype, "FieldMapCount", void 0);
963
+ EntityMapCreatedOutput = __decorate([
964
+ ObjectType()
965
+ ], EntityMapCreatedOutput);
966
+ let CreateEntityMapsOutput = class CreateEntityMapsOutput {
967
+ };
968
+ __decorate([
969
+ Field(),
970
+ __metadata("design:type", Boolean)
971
+ ], CreateEntityMapsOutput.prototype, "Success", void 0);
972
+ __decorate([
973
+ Field(),
974
+ __metadata("design:type", String)
975
+ ], CreateEntityMapsOutput.prototype, "Message", void 0);
976
+ __decorate([
977
+ Field(() => [EntityMapCreatedOutput], { nullable: true }),
978
+ __metadata("design:type", Array)
979
+ ], CreateEntityMapsOutput.prototype, "Created", void 0);
980
+ CreateEntityMapsOutput = __decorate([
981
+ ObjectType()
982
+ ], CreateEntityMapsOutput);
983
+ let StartSyncOutput = class StartSyncOutput {
984
+ };
985
+ __decorate([
986
+ Field(),
987
+ __metadata("design:type", Boolean)
988
+ ], StartSyncOutput.prototype, "Success", void 0);
989
+ __decorate([
990
+ Field(),
991
+ __metadata("design:type", String)
992
+ ], StartSyncOutput.prototype, "Message", void 0);
993
+ __decorate([
994
+ Field({ nullable: true }),
995
+ __metadata("design:type", String)
996
+ ], StartSyncOutput.prototype, "RunID", void 0);
997
+ StartSyncOutput = __decorate([
998
+ ObjectType()
999
+ ], StartSyncOutput);
1000
+ let CreateScheduleInput = class CreateScheduleInput {
1001
+ };
1002
+ __decorate([
1003
+ Field(),
1004
+ __metadata("design:type", String)
1005
+ ], CreateScheduleInput.prototype, "CompanyIntegrationID", void 0);
1006
+ __decorate([
1007
+ Field(),
1008
+ __metadata("design:type", String)
1009
+ ], CreateScheduleInput.prototype, "Name", void 0);
1010
+ __decorate([
1011
+ Field(),
1012
+ __metadata("design:type", String)
1013
+ ], CreateScheduleInput.prototype, "CronExpression", void 0);
1014
+ __decorate([
1015
+ Field({ nullable: true }),
1016
+ __metadata("design:type", String)
1017
+ ], CreateScheduleInput.prototype, "Timezone", void 0);
1018
+ __decorate([
1019
+ Field({ nullable: true }),
1020
+ __metadata("design:type", String)
1021
+ ], CreateScheduleInput.prototype, "Description", void 0);
1022
+ CreateScheduleInput = __decorate([
1023
+ InputType()
1024
+ ], CreateScheduleInput);
1025
+ let CreateScheduleOutput = class CreateScheduleOutput {
1026
+ };
1027
+ __decorate([
1028
+ Field(),
1029
+ __metadata("design:type", Boolean)
1030
+ ], CreateScheduleOutput.prototype, "Success", void 0);
1031
+ __decorate([
1032
+ Field(),
1033
+ __metadata("design:type", String)
1034
+ ], CreateScheduleOutput.prototype, "Message", void 0);
1035
+ __decorate([
1036
+ Field({ nullable: true }),
1037
+ __metadata("design:type", String)
1038
+ ], CreateScheduleOutput.prototype, "ScheduledJobID", void 0);
1039
+ CreateScheduleOutput = __decorate([
1040
+ ObjectType()
1041
+ ], CreateScheduleOutput);
1042
+ let ScheduleSummaryOutput = class ScheduleSummaryOutput {
1043
+ };
1044
+ __decorate([
1045
+ Field(),
1046
+ __metadata("design:type", String)
1047
+ ], ScheduleSummaryOutput.prototype, "ID", void 0);
1048
+ __decorate([
1049
+ Field(),
1050
+ __metadata("design:type", String)
1051
+ ], ScheduleSummaryOutput.prototype, "Name", void 0);
1052
+ __decorate([
1053
+ Field({ nullable: true }),
1054
+ __metadata("design:type", String)
1055
+ ], ScheduleSummaryOutput.prototype, "Status", void 0);
1056
+ __decorate([
1057
+ Field({ nullable: true }),
1058
+ __metadata("design:type", String)
1059
+ ], ScheduleSummaryOutput.prototype, "CronExpression", void 0);
1060
+ __decorate([
1061
+ Field({ nullable: true }),
1062
+ __metadata("design:type", String)
1063
+ ], ScheduleSummaryOutput.prototype, "Timezone", void 0);
1064
+ __decorate([
1065
+ Field({ nullable: true }),
1066
+ __metadata("design:type", String)
1067
+ ], ScheduleSummaryOutput.prototype, "NextRunAt", void 0);
1068
+ __decorate([
1069
+ Field({ nullable: true }),
1070
+ __metadata("design:type", String)
1071
+ ], ScheduleSummaryOutput.prototype, "LastRunAt", void 0);
1072
+ __decorate([
1073
+ Field({ nullable: true }),
1074
+ __metadata("design:type", Number)
1075
+ ], ScheduleSummaryOutput.prototype, "RunCount", void 0);
1076
+ __decorate([
1077
+ Field({ nullable: true }),
1078
+ __metadata("design:type", Number)
1079
+ ], ScheduleSummaryOutput.prototype, "SuccessCount", void 0);
1080
+ __decorate([
1081
+ Field({ nullable: true }),
1082
+ __metadata("design:type", Number)
1083
+ ], ScheduleSummaryOutput.prototype, "FailureCount", void 0);
1084
+ ScheduleSummaryOutput = __decorate([
1085
+ ObjectType()
1086
+ ], ScheduleSummaryOutput);
1087
+ let ListSchedulesOutput = class ListSchedulesOutput {
1088
+ };
1089
+ __decorate([
1090
+ Field(),
1091
+ __metadata("design:type", Boolean)
1092
+ ], ListSchedulesOutput.prototype, "Success", void 0);
1093
+ __decorate([
1094
+ Field(),
1095
+ __metadata("design:type", String)
1096
+ ], ListSchedulesOutput.prototype, "Message", void 0);
1097
+ __decorate([
1098
+ Field(() => [ScheduleSummaryOutput], { nullable: true }),
1099
+ __metadata("design:type", Array)
1100
+ ], ListSchedulesOutput.prototype, "Schedules", void 0);
1101
+ ListSchedulesOutput = __decorate([
1102
+ ObjectType()
1103
+ ], ListSchedulesOutput);
1104
+ let EntityMapUpdateInput = class EntityMapUpdateInput {
1105
+ };
1106
+ __decorate([
1107
+ Field(),
1108
+ __metadata("design:type", String)
1109
+ ], EntityMapUpdateInput.prototype, "EntityMapID", void 0);
1110
+ __decorate([
1111
+ Field({ nullable: true }),
1112
+ __metadata("design:type", String)
1113
+ ], EntityMapUpdateInput.prototype, "SyncDirection", void 0);
1114
+ __decorate([
1115
+ Field({ nullable: true }),
1116
+ __metadata("design:type", Number)
1117
+ ], EntityMapUpdateInput.prototype, "Priority", void 0);
1118
+ __decorate([
1119
+ Field({ nullable: true }),
1120
+ __metadata("design:type", String)
1121
+ ], EntityMapUpdateInput.prototype, "Status", void 0);
1122
+ EntityMapUpdateInput = __decorate([
1123
+ InputType()
1124
+ ], EntityMapUpdateInput);
1125
+ let EntityMapSummaryOutput = class EntityMapSummaryOutput {
1126
+ };
1127
+ __decorate([
1128
+ Field(),
1129
+ __metadata("design:type", String)
1130
+ ], EntityMapSummaryOutput.prototype, "ID", void 0);
1131
+ __decorate([
1132
+ Field({ nullable: true }),
1133
+ __metadata("design:type", String)
1134
+ ], EntityMapSummaryOutput.prototype, "EntityID", void 0);
1135
+ __decorate([
1136
+ Field({ nullable: true }),
1137
+ __metadata("design:type", String)
1138
+ ], EntityMapSummaryOutput.prototype, "Entity", void 0);
1139
+ __decorate([
1140
+ Field({ nullable: true }),
1141
+ __metadata("design:type", String)
1142
+ ], EntityMapSummaryOutput.prototype, "ExternalObjectName", void 0);
1143
+ __decorate([
1144
+ Field({ nullable: true }),
1145
+ __metadata("design:type", String)
1146
+ ], EntityMapSummaryOutput.prototype, "SyncDirection", void 0);
1147
+ __decorate([
1148
+ Field({ nullable: true }),
1149
+ __metadata("design:type", Number)
1150
+ ], EntityMapSummaryOutput.prototype, "Priority", void 0);
1151
+ __decorate([
1152
+ Field({ nullable: true }),
1153
+ __metadata("design:type", String)
1154
+ ], EntityMapSummaryOutput.prototype, "Status", void 0);
1155
+ EntityMapSummaryOutput = __decorate([
1156
+ ObjectType()
1157
+ ], EntityMapSummaryOutput);
1158
+ let ListEntityMapsOutput = class ListEntityMapsOutput {
1159
+ };
1160
+ __decorate([
1161
+ Field(),
1162
+ __metadata("design:type", Boolean)
1163
+ ], ListEntityMapsOutput.prototype, "Success", void 0);
1164
+ __decorate([
1165
+ Field(),
1166
+ __metadata("design:type", String)
1167
+ ], ListEntityMapsOutput.prototype, "Message", void 0);
1168
+ __decorate([
1169
+ Field(() => [EntityMapSummaryOutput], { nullable: true }),
1170
+ __metadata("design:type", Array)
1171
+ ], ListEntityMapsOutput.prototype, "EntityMaps", void 0);
1172
+ ListEntityMapsOutput = __decorate([
1173
+ ObjectType()
1174
+ ], ListEntityMapsOutput);
1175
+ let IntegrationStatusOutput = class IntegrationStatusOutput {
1176
+ };
1177
+ __decorate([
1178
+ Field(),
1179
+ __metadata("design:type", Boolean)
1180
+ ], IntegrationStatusOutput.prototype, "Success", void 0);
1181
+ __decorate([
1182
+ Field(),
1183
+ __metadata("design:type", String)
1184
+ ], IntegrationStatusOutput.prototype, "Message", void 0);
1185
+ __decorate([
1186
+ Field({ nullable: true }),
1187
+ __metadata("design:type", Boolean)
1188
+ ], IntegrationStatusOutput.prototype, "IsActive", void 0);
1189
+ __decorate([
1190
+ Field({ nullable: true }),
1191
+ __metadata("design:type", String)
1192
+ ], IntegrationStatusOutput.prototype, "IntegrationName", void 0);
1193
+ __decorate([
1194
+ Field({ nullable: true }),
1195
+ __metadata("design:type", String)
1196
+ ], IntegrationStatusOutput.prototype, "CompanyIntegrationID", void 0);
1197
+ __decorate([
1198
+ Field({ nullable: true }),
1199
+ __metadata("design:type", Number)
1200
+ ], IntegrationStatusOutput.prototype, "TotalEntityMaps", void 0);
1201
+ __decorate([
1202
+ Field({ nullable: true }),
1203
+ __metadata("design:type", Number)
1204
+ ], IntegrationStatusOutput.prototype, "ActiveEntityMaps", void 0);
1205
+ __decorate([
1206
+ Field({ nullable: true }),
1207
+ __metadata("design:type", String)
1208
+ ], IntegrationStatusOutput.prototype, "LastRunStatus", void 0);
1209
+ __decorate([
1210
+ Field({ nullable: true }),
1211
+ __metadata("design:type", String)
1212
+ ], IntegrationStatusOutput.prototype, "LastRunStartedAt", void 0);
1213
+ __decorate([
1214
+ Field({ nullable: true }),
1215
+ __metadata("design:type", String)
1216
+ ], IntegrationStatusOutput.prototype, "LastRunEndedAt", void 0);
1217
+ __decorate([
1218
+ Field({ nullable: true }),
1219
+ __metadata("design:type", Boolean)
1220
+ ], IntegrationStatusOutput.prototype, "ScheduleEnabled", void 0);
1221
+ __decorate([
1222
+ Field({ nullable: true }),
1223
+ __metadata("design:type", Boolean)
1224
+ ], IntegrationStatusOutput.prototype, "RSUEnabled", void 0);
1225
+ __decorate([
1226
+ Field({ nullable: true }),
1227
+ __metadata("design:type", Boolean)
1228
+ ], IntegrationStatusOutput.prototype, "RSURunning", void 0);
1229
+ __decorate([
1230
+ Field({ nullable: true }),
1231
+ __metadata("design:type", Boolean)
1232
+ ], IntegrationStatusOutput.prototype, "RSUOutOfSync", void 0);
1233
+ __decorate([
1234
+ Field({ nullable: true }),
1235
+ __metadata("design:type", String)
1236
+ ], IntegrationStatusOutput.prototype, "RSULastRunAt", void 0);
1237
+ __decorate([
1238
+ Field({ nullable: true }),
1239
+ __metadata("design:type", String)
1240
+ ], IntegrationStatusOutput.prototype, "RSULastRunResult", void 0);
1241
+ IntegrationStatusOutput = __decorate([
1242
+ ObjectType()
1243
+ ], IntegrationStatusOutput);
1244
+ let SyncRunEntityDetail = class SyncRunEntityDetail {
1245
+ };
1246
+ __decorate([
1247
+ Field(),
1248
+ __metadata("design:type", String)
1249
+ ], SyncRunEntityDetail.prototype, "EntityName", void 0);
1250
+ __decorate([
1251
+ Field(),
1252
+ __metadata("design:type", Number)
1253
+ ], SyncRunEntityDetail.prototype, "InsertCount", void 0);
1254
+ __decorate([
1255
+ Field(),
1256
+ __metadata("design:type", Number)
1257
+ ], SyncRunEntityDetail.prototype, "UpdateCount", void 0);
1258
+ __decorate([
1259
+ Field(),
1260
+ __metadata("design:type", Number)
1261
+ ], SyncRunEntityDetail.prototype, "SkipCount", void 0);
1262
+ __decorate([
1263
+ Field(),
1264
+ __metadata("design:type", Number)
1265
+ ], SyncRunEntityDetail.prototype, "ErrorCount", void 0);
1266
+ SyncRunEntityDetail = __decorate([
1267
+ ObjectType()
1268
+ ], SyncRunEntityDetail);
1269
+ let SyncRunSummaryOutput = class SyncRunSummaryOutput {
1270
+ };
1271
+ __decorate([
1272
+ Field(),
1273
+ __metadata("design:type", String)
1274
+ ], SyncRunSummaryOutput.prototype, "ID", void 0);
1275
+ __decorate([
1276
+ Field({ nullable: true }),
1277
+ __metadata("design:type", String)
1278
+ ], SyncRunSummaryOutput.prototype, "Status", void 0);
1279
+ __decorate([
1280
+ Field({ nullable: true }),
1281
+ __metadata("design:type", String)
1282
+ ], SyncRunSummaryOutput.prototype, "StartedAt", void 0);
1283
+ __decorate([
1284
+ Field({ nullable: true }),
1285
+ __metadata("design:type", String)
1286
+ ], SyncRunSummaryOutput.prototype, "EndedAt", void 0);
1287
+ __decorate([
1288
+ Field({ nullable: true }),
1289
+ __metadata("design:type", Number)
1290
+ ], SyncRunSummaryOutput.prototype, "TotalRecords", void 0);
1291
+ __decorate([
1292
+ Field({ nullable: true }),
1293
+ __metadata("design:type", String)
1294
+ ], SyncRunSummaryOutput.prototype, "RunByUserID", void 0);
1295
+ __decorate([
1296
+ Field(() => [SyncRunEntityDetail], { nullable: true }),
1297
+ __metadata("design:type", Array)
1298
+ ], SyncRunSummaryOutput.prototype, "EntityDetails", void 0);
1299
+ SyncRunSummaryOutput = __decorate([
1300
+ ObjectType()
1301
+ ], SyncRunSummaryOutput);
1302
+ let SyncHistoryOutput = class SyncHistoryOutput {
1303
+ };
1304
+ __decorate([
1305
+ Field(),
1306
+ __metadata("design:type", Boolean)
1307
+ ], SyncHistoryOutput.prototype, "Success", void 0);
1308
+ __decorate([
1309
+ Field(),
1310
+ __metadata("design:type", String)
1311
+ ], SyncHistoryOutput.prototype, "Message", void 0);
1312
+ __decorate([
1313
+ Field(() => [SyncRunSummaryOutput], { nullable: true }),
1314
+ __metadata("design:type", Array)
1315
+ ], SyncHistoryOutput.prototype, "Runs", void 0);
1316
+ SyncHistoryOutput = __decorate([
1317
+ ObjectType()
1318
+ ], SyncHistoryOutput);
1319
+ let OperationProgressOutput = class OperationProgressOutput {
1320
+ };
1321
+ __decorate([
1322
+ Field(),
1323
+ __metadata("design:type", Boolean)
1324
+ ], OperationProgressOutput.prototype, "Success", void 0);
1325
+ __decorate([
1326
+ Field(),
1327
+ __metadata("design:type", String)
1328
+ ], OperationProgressOutput.prototype, "Message", void 0);
1329
+ __decorate([
1330
+ Field({ nullable: true }),
1331
+ __metadata("design:type", String)
1332
+ ], OperationProgressOutput.prototype, "OperationType", void 0);
1333
+ __decorate([
1334
+ Field({ nullable: true }),
1335
+ __metadata("design:type", Boolean)
1336
+ ], OperationProgressOutput.prototype, "IsRunning", void 0);
1337
+ __decorate([
1338
+ Field({ nullable: true }),
1339
+ __metadata("design:type", String)
1340
+ ], OperationProgressOutput.prototype, "CurrentEntity", void 0);
1341
+ __decorate([
1342
+ Field({ nullable: true }),
1343
+ __metadata("design:type", Number)
1344
+ ], OperationProgressOutput.prototype, "EntityMapsTotal", void 0);
1345
+ __decorate([
1346
+ Field({ nullable: true }),
1347
+ __metadata("design:type", Number)
1348
+ ], OperationProgressOutput.prototype, "EntityMapsCompleted", void 0);
1349
+ __decorate([
1350
+ Field({ nullable: true }),
1351
+ __metadata("design:type", Number)
1352
+ ], OperationProgressOutput.prototype, "RecordsProcessed", void 0);
1353
+ __decorate([
1354
+ Field({ nullable: true }),
1355
+ __metadata("design:type", Number)
1356
+ ], OperationProgressOutput.prototype, "RecordsCreated", void 0);
1357
+ __decorate([
1358
+ Field({ nullable: true }),
1359
+ __metadata("design:type", Number)
1360
+ ], OperationProgressOutput.prototype, "RecordsUpdated", void 0);
1361
+ __decorate([
1362
+ Field({ nullable: true }),
1363
+ __metadata("design:type", Number)
1364
+ ], OperationProgressOutput.prototype, "RecordsErrored", void 0);
1365
+ __decorate([
1366
+ Field({ nullable: true }),
1367
+ __metadata("design:type", String)
1368
+ ], OperationProgressOutput.prototype, "RSUStep", void 0);
1369
+ __decorate([
1370
+ Field({ nullable: true }),
1371
+ __metadata("design:type", Boolean)
1372
+ ], OperationProgressOutput.prototype, "RSURunning", void 0);
1373
+ __decorate([
1374
+ Field({ nullable: true }),
1375
+ __metadata("design:type", Number)
1376
+ ], OperationProgressOutput.prototype, "ElapsedMs", void 0);
1377
+ __decorate([
1378
+ Field({ nullable: true }),
1379
+ __metadata("design:type", String)
1380
+ ], OperationProgressOutput.prototype, "StartedAt", void 0);
1381
+ OperationProgressOutput = __decorate([
1382
+ ObjectType()
1383
+ ], OperationProgressOutput);
1384
+ // Sync progress is now tracked inside IntegrationEngine itself via IntegrationEngine.GetSyncProgress()
1385
+ let ConnectionSummaryOutput = class ConnectionSummaryOutput {
1386
+ };
1387
+ __decorate([
1388
+ Field(),
1389
+ __metadata("design:type", String)
1390
+ ], ConnectionSummaryOutput.prototype, "ID", void 0);
1391
+ __decorate([
1392
+ Field(),
1393
+ __metadata("design:type", String)
1394
+ ], ConnectionSummaryOutput.prototype, "IntegrationName", void 0);
1395
+ __decorate([
1396
+ Field(),
1397
+ __metadata("design:type", String)
1398
+ ], ConnectionSummaryOutput.prototype, "IntegrationID", void 0);
1399
+ __decorate([
1400
+ Field(),
1401
+ __metadata("design:type", String)
1402
+ ], ConnectionSummaryOutput.prototype, "CompanyID", void 0);
1403
+ __decorate([
1404
+ Field({ nullable: true }),
1405
+ __metadata("design:type", String)
1406
+ ], ConnectionSummaryOutput.prototype, "Company", void 0);
1407
+ __decorate([
1408
+ Field(),
1409
+ __metadata("design:type", Boolean)
1410
+ ], ConnectionSummaryOutput.prototype, "IsActive", void 0);
1411
+ __decorate([
1412
+ Field(),
1413
+ __metadata("design:type", Boolean)
1414
+ ], ConnectionSummaryOutput.prototype, "ScheduleEnabled", void 0);
1415
+ __decorate([
1416
+ Field({ nullable: true }),
1417
+ __metadata("design:type", String)
1418
+ ], ConnectionSummaryOutput.prototype, "CronExpression", void 0);
1419
+ __decorate([
1420
+ Field(),
1421
+ __metadata("design:type", String)
1422
+ ], ConnectionSummaryOutput.prototype, "CreatedAt", void 0);
1423
+ ConnectionSummaryOutput = __decorate([
1424
+ ObjectType()
1425
+ ], ConnectionSummaryOutput);
1426
+ let ListConnectionsOutput = class ListConnectionsOutput {
1427
+ };
1428
+ __decorate([
1429
+ Field(),
1430
+ __metadata("design:type", Boolean)
1431
+ ], ListConnectionsOutput.prototype, "Success", void 0);
1432
+ __decorate([
1433
+ Field(),
1434
+ __metadata("design:type", String)
1435
+ ], ListConnectionsOutput.prototype, "Message", void 0);
1436
+ __decorate([
1437
+ Field(() => [ConnectionSummaryOutput], { nullable: true }),
1438
+ __metadata("design:type", Array)
1439
+ ], ListConnectionsOutput.prototype, "Connections", void 0);
1440
+ ListConnectionsOutput = __decorate([
1441
+ ObjectType()
1442
+ ], ListConnectionsOutput);
271
1443
  // --- Resolver ---
1444
+ // ── Validation helpers for entity map union types ──────────────────────
1445
+ const VALID_SYNC_DIRECTIONS = ['Bidirectional', 'Pull', 'Push'];
1446
+ function isValidSyncDirection(value) {
1447
+ return VALID_SYNC_DIRECTIONS.includes(value);
1448
+ }
1449
+ const VALID_ENTITY_MAP_STATUSES = ['Active', 'Inactive'];
1450
+ function isValidEntityMapStatus(value) {
1451
+ return VALID_ENTITY_MAP_STATUSES.includes(value);
1452
+ }
272
1453
  /**
273
1454
  * GraphQL resolver for integration discovery operations.
274
1455
  * Provides endpoints to test connections, discover objects, and discover fields
275
1456
  * on external systems via their registered connectors.
276
1457
  */
277
1458
  let IntegrationDiscoveryResolver = class IntegrationDiscoveryResolver extends ResolverBase {
1459
+ static { IntegrationDiscoveryResolver_1 = this; }
1460
+ /**
1461
+ * Lists all registered integration connectors (active by default).
1462
+ * Useful for populating connector selection UIs.
1463
+ */
1464
+ async IntegrationDiscoverConnectors(companyID, ctx) {
1465
+ try {
1466
+ const user = this.getAuthenticatedUser(ctx);
1467
+ const rv = new RunView();
1468
+ const result = await rv.RunView({
1469
+ EntityName: 'MJ: Integrations',
1470
+ ExtraFilter: '',
1471
+ OrderBy: 'Name',
1472
+ ResultType: 'entity_object'
1473
+ }, user);
1474
+ if (!result.Success)
1475
+ return { Success: false, Message: result.ErrorMessage || 'Query failed' };
1476
+ return {
1477
+ Success: true,
1478
+ Message: `${result.Results.length} connectors available`,
1479
+ Connectors: result.Results
1480
+ .map(r => ({
1481
+ IntegrationID: r.ID,
1482
+ Name: r.Name,
1483
+ Description: r.Description,
1484
+ ClassName: r.ClassName,
1485
+ IsActive: true
1486
+ }))
1487
+ };
1488
+ }
1489
+ catch (e) {
1490
+ LogError(`IntegrationDiscoverConnectors error: ${e}`);
1491
+ return { Success: false, Message: this.formatError(e) };
1492
+ }
1493
+ }
1494
+ /**
1495
+ * Discovers available objects/tables in the external system.
1496
+ */
1497
+ async IntegrationDiscoverObjects(companyIntegrationID, ctx) {
1498
+ try {
1499
+ const user = this.getAuthenticatedUser(ctx);
1500
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1501
+ // Cast through unknown to bridge duplicate package type declarations
1502
+ // (integration-engine resolves its own node_modules copies of core/core-entities)
1503
+ const discoverObjects = connector.DiscoverObjects.bind(connector);
1504
+ const objects = await discoverObjects(companyIntegration, user);
1505
+ return {
1506
+ Success: true,
1507
+ Message: `Discovered ${objects.length} objects`,
1508
+ Objects: objects.map(o => ({
1509
+ ID: o.ID,
1510
+ Name: o.Name,
1511
+ Label: o.Label,
1512
+ SupportsIncrementalSync: o.SupportsIncrementalSync,
1513
+ SupportsWrite: o.SupportsWrite
1514
+ }))
1515
+ };
1516
+ }
1517
+ catch (e) {
1518
+ return this.handleDiscoveryError(e);
1519
+ }
1520
+ }
1521
+ /**
1522
+ * Discovers fields on a specific external object.
1523
+ */
1524
+ async IntegrationDiscoverFields(companyIntegrationID, objectName, ctx) {
1525
+ try {
1526
+ const user = this.getAuthenticatedUser(ctx);
1527
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1528
+ // Cast through unknown to bridge duplicate package type declarations
1529
+ const discoverFields = connector.DiscoverFields.bind(connector);
1530
+ const fields = await discoverFields(companyIntegration, objectName, user);
1531
+ return {
1532
+ Success: true,
1533
+ Message: `Discovered ${fields.length} fields on "${objectName}"`,
1534
+ Fields: fields.map(f => ({
1535
+ Name: f.Name,
1536
+ Label: f.Label,
1537
+ DataType: f.DataType,
1538
+ IsRequired: f.IsRequired,
1539
+ IsUniqueKey: f.IsUniqueKey,
1540
+ IsReadOnly: f.IsReadOnly
1541
+ }))
1542
+ };
1543
+ }
1544
+ catch (e) {
1545
+ return this.handleDiscoveryError(e);
1546
+ }
1547
+ }
1548
+ /**
1549
+ * Tests connectivity to the external system.
1550
+ */
1551
+ async IntegrationTestConnection(companyIntegrationID, ctx) {
1552
+ try {
1553
+ const user = this.getAuthenticatedUser(ctx);
1554
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1555
+ // Cast through unknown to bridge duplicate package type declarations
1556
+ const testConnection = connector.TestConnection.bind(connector);
1557
+ const result = await testConnection(companyIntegration, user);
1558
+ return {
1559
+ Success: result.Success,
1560
+ Message: result.Message,
1561
+ ServerVersion: result.ServerVersion
1562
+ };
1563
+ }
1564
+ catch (e) {
1565
+ LogError(`IntegrationTestConnection error: ${this.formatError(e)}`);
1566
+ return {
1567
+ Success: false,
1568
+ Message: `Error: ${this.formatError(e)}`
1569
+ };
1570
+ }
1571
+ }
1572
+ /**
1573
+ * Returns the connector's default configuration for quick setup.
1574
+ * Not all connectors provide defaults — returns Success: false if unavailable.
1575
+ */
1576
+ async IntegrationGetDefaultConfig(companyIntegrationID, ctx) {
1577
+ try {
1578
+ const user = this.getAuthenticatedUser(ctx);
1579
+ const { connector } = await this.resolveConnector(companyIntegrationID, user);
1580
+ const config = connector.GetDefaultConfiguration();
1581
+ if (!config) {
1582
+ return {
1583
+ Success: false,
1584
+ Message: 'This connector does not provide a default configuration'
1585
+ };
1586
+ }
1587
+ return {
1588
+ Success: true,
1589
+ Message: `Default configuration with ${config.DefaultObjects.length} objects`,
1590
+ DefaultSchemaName: config.DefaultSchemaName,
1591
+ DefaultObjects: config.DefaultObjects.map(o => ({
1592
+ SourceObjectName: o.SourceObjectName,
1593
+ TargetTableName: o.TargetTableName,
1594
+ TargetEntityName: o.TargetEntityName,
1595
+ SyncEnabled: o.SyncEnabled,
1596
+ FieldMappings: o.FieldMappings.map(f => ({
1597
+ SourceFieldName: f.SourceFieldName,
1598
+ DestinationFieldName: f.DestinationFieldName,
1599
+ IsKeyField: f.IsKeyField
1600
+ }))
1601
+ }))
1602
+ };
1603
+ }
1604
+ catch (e) {
1605
+ LogError(`IntegrationGetDefaultConfig error: ${this.formatError(e)}`);
1606
+ return {
1607
+ Success: false,
1608
+ Message: `Error: ${this.formatError(e)}`
1609
+ };
1610
+ }
1611
+ }
1612
+ /**
1613
+ * Generates a DDL preview for creating tables from discovered external objects.
1614
+ * Introspects the source schema and runs SchemaBuilder to produce migration SQL.
1615
+ */
1616
+ async IntegrationSchemaPreview(companyIntegrationID, objects, platform, ctx) {
1617
+ try {
1618
+ const user = this.getAuthenticatedUser(ctx);
1619
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1620
+ // Introspect schema from the external system
1621
+ const introspect = connector.IntrospectSchema.bind(connector);
1622
+ const sourceSchema = await introspect(companyIntegration, user);
1623
+ await this.resolveObjectInputs(objects, sourceSchema, user);
1624
+ const requestedNames = new Set(objects.map(o => o.SourceObjectName));
1625
+ const filteredSchema = {
1626
+ Objects: sourceSchema.Objects.filter(o => requestedNames.has(o.ExternalName))
1627
+ };
1628
+ const validatedPlatform = this.validatePlatform(platform);
1629
+ const targetConfigs = this.buildTargetConfigs(objects, filteredSchema, validatedPlatform, connector);
1630
+ // Run SchemaBuilder
1631
+ const input = {
1632
+ SourceSchema: filteredSchema,
1633
+ TargetConfigs: targetConfigs,
1634
+ Platform: validatedPlatform,
1635
+ MJVersion: process.env.MJ_VERSION ?? '5.11.0',
1636
+ SourceType: companyIntegration.Integration,
1637
+ AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
1638
+ MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
1639
+ MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
1640
+ ExistingTables: this.buildExistingTables(targetConfigs),
1641
+ EntitySettingsForTargets: {}
1642
+ };
1643
+ const builder = new SchemaBuilder();
1644
+ const output = builder.BuildSchema(input);
1645
+ if (output.Errors.length > 0) {
1646
+ return {
1647
+ Success: false,
1648
+ Message: `Schema generation failed: ${output.Errors.join('; ')}`,
1649
+ Warnings: output.Warnings
1650
+ };
1651
+ }
1652
+ const allFiles = [
1653
+ ...output.MigrationFiles,
1654
+ ...(output.AdditionalSchemaInfoUpdate ? [output.AdditionalSchemaInfoUpdate] : []),
1655
+ ...output.MetadataFiles
1656
+ ];
1657
+ return {
1658
+ Success: true,
1659
+ Message: `Generated ${allFiles.length} files`,
1660
+ Files: allFiles.map(f => ({
1661
+ FilePath: f.FilePath,
1662
+ Content: f.Content,
1663
+ Description: f.Description
1664
+ })),
1665
+ Warnings: output.Warnings.length > 0 ? output.Warnings : undefined
1666
+ };
1667
+ }
1668
+ catch (e) {
1669
+ LogError(`IntegrationSchemaPreview error: ${this.formatError(e)}`);
1670
+ return {
1671
+ Success: false,
1672
+ Message: `Error: ${this.formatError(e)}`
1673
+ };
1674
+ }
1675
+ }
1676
+ /**
1677
+ * Fetches a small sample of records from an external object for preview purposes.
1678
+ * Uses the connector's FetchChanges with a small batch size and no watermark.
1679
+ */
1680
+ async IntegrationPreviewData(companyIntegrationID, objectName, limit, ctx) {
1681
+ try {
1682
+ const user = this.getAuthenticatedUser(ctx);
1683
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1684
+ const fetchChanges = connector.FetchChanges.bind(connector);
1685
+ const result = await fetchChanges({
1686
+ CompanyIntegration: companyIntegration,
1687
+ ObjectName: objectName,
1688
+ WatermarkValue: null,
1689
+ BatchSize: Math.min(limit, 10),
1690
+ ContextUser: user
1691
+ });
1692
+ const truncated = result.Records.slice(0, limit);
1693
+ return {
1694
+ Success: true,
1695
+ Message: `Fetched ${truncated.length} preview records${result.Records.length > limit ? ` (truncated from ${result.Records.length})` : ''}`,
1696
+ Records: truncated.map(r => ({
1697
+ Data: JSON.stringify(r.Fields)
1698
+ }))
1699
+ };
1700
+ }
1701
+ catch (e) {
1702
+ LogError(`IntegrationPreviewData error: ${this.formatError(e)}`);
1703
+ return {
1704
+ Success: false,
1705
+ Message: `Error: ${this.formatError(e)}`
1706
+ };
1707
+ }
1708
+ }
1709
+ // --- Private Helpers ---
1710
+ buildTargetConfigs(objects, sourceSchema, platform, connector) {
1711
+ const mapper = new TypeMapper();
1712
+ // Build a lookup from the connector's static metadata for descriptions.
1713
+ // DB entities may not have Description populated yet on first run,
1714
+ // but the connector's GetIntegrationObjects() always has them.
1715
+ const connectorDescriptions = this.buildDescriptionLookup(connector);
1716
+ return objects.map(obj => {
1717
+ const sourceObj = sourceSchema.Objects.find(o => o.ExternalName.toLowerCase() === obj.SourceObjectName.toLowerCase());
1718
+ const objDescriptions = connectorDescriptions.get(obj.SourceObjectName.toLowerCase());
1719
+ // Filter fields if caller specified a subset
1720
+ const selectedFieldSet = obj.Fields?.length
1721
+ ? new Set(obj.Fields.map(f => f.toLowerCase()))
1722
+ : null;
1723
+ const sourceFields = (sourceObj?.Fields ?? []).filter(f => !selectedFieldSet || selectedFieldSet.has(f.Name.toLowerCase()) || f.IsPrimaryKey);
1724
+ const columns = sourceFields.map(f => ({
1725
+ SourceFieldName: f.Name,
1726
+ TargetColumnName: f.Name.replace(/[^A-Za-z0-9_]/g, '_'),
1727
+ TargetSqlType: mapper.MapSourceType(f.SourceType, platform, f),
1728
+ IsNullable: !f.IsRequired,
1729
+ MaxLength: f.MaxLength,
1730
+ Precision: f.Precision,
1731
+ Scale: f.Scale,
1732
+ DefaultValue: f.DefaultValue,
1733
+ Description: f.Description ?? objDescriptions?.fields.get(f.Name.toLowerCase()),
1734
+ }));
1735
+ const primaryKeyFields = (sourceObj?.Fields ?? [])
1736
+ .filter(f => f.IsPrimaryKey)
1737
+ .map(f => f.Name.replace(/[^A-Za-z0-9_]/g, '_'));
1738
+ return {
1739
+ SourceObjectName: obj.SourceObjectName,
1740
+ SchemaName: obj.SchemaName,
1741
+ TableName: obj.TableName,
1742
+ EntityName: obj.EntityName,
1743
+ Description: sourceObj?.Description ?? objDescriptions?.objectDescription,
1744
+ Columns: columns,
1745
+ PrimaryKeyFields: primaryKeyFields.length > 0 ? primaryKeyFields : ['ID'],
1746
+ SoftForeignKeys: []
1747
+ };
1748
+ });
1749
+ }
1750
+ /** Builds a lookup of object name → { objectDescription, fields: fieldName → description } from the connector's static metadata. */
1751
+ /** Build ExistingTableInfo[] from MJ Metadata for tables that already exist in the target schemas. */
1752
+ buildExistingTables(targetConfigs) {
1753
+ const md = new Metadata();
1754
+ const result = [];
1755
+ for (const config of targetConfigs) {
1756
+ const entity = md.Entities.find(e => e.SchemaName.toLowerCase() === config.SchemaName.toLowerCase() &&
1757
+ e.BaseTable.toLowerCase() === config.TableName.toLowerCase());
1758
+ if (entity) {
1759
+ result.push({
1760
+ SchemaName: config.SchemaName,
1761
+ TableName: config.TableName,
1762
+ Columns: entity.Fields.map(f => ({
1763
+ Name: f.Name,
1764
+ SqlType: f.SQLFullType || 'NVARCHAR(MAX)',
1765
+ IsNullable: f.AllowsNull,
1766
+ MaxLength: f.MaxLength,
1767
+ Precision: f.Precision,
1768
+ Scale: f.Scale,
1769
+ }))
1770
+ });
1771
+ }
1772
+ }
1773
+ return result;
1774
+ }
1775
+ buildDescriptionLookup(connector) {
1776
+ const result = new Map();
1777
+ if (!connector)
1778
+ return result;
1779
+ const staticObjects = connector.GetIntegrationObjects();
1780
+ for (const obj of staticObjects) {
1781
+ const fieldMap = new Map();
1782
+ for (const f of obj.Fields) {
1783
+ if (f.Description)
1784
+ fieldMap.set(f.Name.toLowerCase(), f.Description);
1785
+ }
1786
+ result.set(obj.Name.toLowerCase(), { objectDescription: obj.Description, fields: fieldMap });
1787
+ }
1788
+ return result;
1789
+ }
1790
+ /**
1791
+ * Resolves source object IDs to exact names from the DB, and normalizes names
1792
+ * to match the source schema's ExternalName casing. Call once at each entry point.
1793
+ */
1794
+ async resolveSourceObjectNames(ids, names, sourceSchema, integrationID, user) {
1795
+ // If IDs provided, resolve them to names from IntegrationObject records
1796
+ if (ids && ids.length > 0) {
1797
+ const rv = new RunView();
1798
+ const result = await rv.RunView({
1799
+ EntityName: 'MJ: Integration Objects',
1800
+ ExtraFilter: ids.map(id => `ID='${id}'`).join(' OR '),
1801
+ ResultType: 'simple',
1802
+ Fields: ['ID', 'Name'],
1803
+ }, user);
1804
+ if (result.Success) {
1805
+ return result.Results.map(r => r.Name);
1806
+ }
1807
+ }
1808
+ // Otherwise normalize provided names against source schema casing
1809
+ if (names && names.length > 0) {
1810
+ const nameMap = new Map(sourceSchema.Objects.map(o => [o.ExternalName.toLowerCase(), o.ExternalName]));
1811
+ return names.map(n => nameMap.get(n.toLowerCase()) ?? n);
1812
+ }
1813
+ return [];
1814
+ }
1815
+ /**
1816
+ * Resolves SourceObjectID/SourceObjectName on SchemaPreviewObjectInput array.
1817
+ * Mutates the objects in place — sets SourceObjectName from ID if provided.
1818
+ */
1819
+ async resolveObjectInputs(objects, sourceSchema, user) {
1820
+ const idsToResolve = objects.filter(o => o.SourceObjectID && !o.SourceObjectName).map(o => o.SourceObjectID);
1821
+ if (idsToResolve.length > 0) {
1822
+ const rv = new RunView();
1823
+ const result = await rv.RunView({
1824
+ EntityName: 'MJ: Integration Objects',
1825
+ ExtraFilter: idsToResolve.map(id => `ID='${id}'`).join(' OR '),
1826
+ ResultType: 'simple',
1827
+ Fields: ['ID', 'Name'],
1828
+ }, user);
1829
+ if (result.Success) {
1830
+ const idToName = new Map(result.Results.map(r => [r.ID.toUpperCase(), r.Name]));
1831
+ for (const obj of objects) {
1832
+ if (obj.SourceObjectID) {
1833
+ const resolved = idToName.get(obj.SourceObjectID.toUpperCase());
1834
+ if (resolved)
1835
+ obj.SourceObjectName = resolved;
1836
+ }
1837
+ }
1838
+ }
1839
+ }
1840
+ // Normalize remaining names to match source schema casing
1841
+ const nameMap = new Map(sourceSchema.Objects.map(o => [o.ExternalName.toLowerCase(), o.ExternalName]));
1842
+ for (const obj of objects) {
1843
+ if (obj.SourceObjectName) {
1844
+ const exact = nameMap.get(obj.SourceObjectName.toLowerCase());
1845
+ if (exact)
1846
+ obj.SourceObjectName = exact;
1847
+ }
1848
+ }
1849
+ }
1850
+ getAuthenticatedUser(ctx) {
1851
+ const user = ctx.userPayload.userRecord;
1852
+ if (!user) {
1853
+ throw new Error("User is not authenticated");
1854
+ }
1855
+ return user;
1856
+ }
1857
+ /** Get system user for server-side operations that need elevated permissions (cascade deletes, etc.) */
1858
+ getSystemUser() {
1859
+ const sysUser = UserCache.Instance.GetSystemUser();
1860
+ if (!sysUser)
1861
+ throw new Error('System user not available');
1862
+ return sysUser;
1863
+ }
1864
+ /**
1865
+ * Loads the CompanyIntegration + its parent Integration, then resolves the
1866
+ * appropriate connector via ConnectorFactory.
1867
+ *
1868
+ * NOTE: Entity objects loaded here come from the MJServer's copy of core-entities.
1869
+ * The integration-engine package may resolve its own copy of core-entities, causing
1870
+ * TypeScript nominal type mismatches. At runtime the objects are structurally identical,
1871
+ * so we cast through `unknown` at the boundary calls.
1872
+ */
1873
+ async resolveConnector(companyIntegrationID, contextUser) {
1874
+ const md = new Metadata();
1875
+ // Load the CompanyIntegration record
1876
+ const companyIntegration = await md.GetEntityObject('MJ: Company Integrations', contextUser);
1877
+ const loaded = await companyIntegration.Load(companyIntegrationID);
1878
+ if (!loaded) {
1879
+ throw new Error(`CompanyIntegration with ID "${companyIntegrationID}" not found`);
1880
+ }
1881
+ // Load the parent Integration record
1882
+ const integration = await md.GetEntityObject('MJ: Integrations', contextUser);
1883
+ const integrationLoaded = await integration.Load(companyIntegration.IntegrationID);
1884
+ if (!integrationLoaded) {
1885
+ throw new Error(`Integration with ID "${companyIntegration.IntegrationID}" not found`);
1886
+ }
1887
+ // ConnectorFactory.Resolve expects MJIntegrationEntity, which is the same type loaded above.
1888
+ // Both this file and ConnectorFactory import from @memberjunction/core-entities.
1889
+ const connector = ConnectorFactory.Resolve(integration);
1890
+ return { connector, companyIntegration };
1891
+ }
1892
+ handleDiscoveryError(e) {
1893
+ LogError(`Integration discovery error: ${this.formatError(e)}`);
1894
+ return {
1895
+ Success: false,
1896
+ Message: `Error: ${this.formatError(e)}`
1897
+ };
1898
+ }
1899
+ formatError(e) {
1900
+ return e instanceof Error ? e.message : String(e);
1901
+ }
1902
+ static { this.VALID_PLATFORMS = new Set(['sqlserver', 'postgresql']); }
1903
+ /** Validates and narrows a platform string to the supported union type. */
1904
+ validatePlatform(platform) {
1905
+ if (!IntegrationDiscoveryResolver_1.VALID_PLATFORMS.has(platform)) {
1906
+ throw new Error(`Unsupported platform "${platform}". Must be one of: ${[...IntegrationDiscoveryResolver_1.VALID_PLATFORMS].join(', ')}`);
1907
+ }
1908
+ return platform;
1909
+ }
1910
+ // ── CONNECTION TEST HELPERS ────────────────────────────────────────────
1911
+ /**
1912
+ * Tests connectivity for a given CompanyIntegration, reusing the same pattern as IntegrationTestConnection.
1913
+ */
1914
+ async testConnectionForCI(companyIntegrationID, user) {
1915
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
1916
+ const testFn = connector.TestConnection.bind(connector);
1917
+ return testFn(companyIntegration, user);
1918
+ }
1919
+ /**
1920
+ * Rolls back a freshly created connection by deleting both the CompanyIntegration and Credential records.
1921
+ */
1922
+ async rollbackCreatedConnection(ci, credential) {
1923
+ try {
1924
+ await ci.Delete();
1925
+ }
1926
+ catch (e) {
1927
+ LogError(`Rollback: failed to delete CompanyIntegration: ${this.formatError(e)}`);
1928
+ }
1929
+ try {
1930
+ await credential.Delete();
1931
+ }
1932
+ catch (e) {
1933
+ LogError(`Rollback: failed to delete Credential: ${this.formatError(e)}`);
1934
+ }
1935
+ }
1936
+ /**
1937
+ * Snapshots the current credential Values for a given credential ID so they can be restored on rollback.
1938
+ */
1939
+ async snapshotCredentialValues(credentialID, user) {
1940
+ if (!credentialID)
1941
+ return undefined;
1942
+ const md = new Metadata();
1943
+ const credential = await md.GetEntityObject('MJ: Credentials', user);
1944
+ const loaded = await credential.InnerLoad(CompositeKey.FromID(credentialID));
1945
+ return loaded ? credential.Values : undefined;
1946
+ }
1947
+ /**
1948
+ * Reverts an update to a CompanyIntegration by restoring old configuration, externalSystemID,
1949
+ * and credential values.
1950
+ */
1951
+ async revertUpdateConnection(ci, oldConfiguration, oldExternalSystemID, oldCredentialValues, user) {
1952
+ try {
1953
+ // Revert CI fields
1954
+ let dirty = false;
1955
+ if (oldConfiguration !== undefined) {
1956
+ ci.Configuration = oldConfiguration;
1957
+ dirty = true;
1958
+ }
1959
+ if (oldExternalSystemID !== undefined) {
1960
+ ci.ExternalSystemID = oldExternalSystemID;
1961
+ dirty = true;
1962
+ }
1963
+ if (dirty)
1964
+ await ci.Save();
1965
+ // Revert credential values
1966
+ if (oldCredentialValues !== undefined && ci.CredentialID) {
1967
+ const md = new Metadata();
1968
+ const credential = await md.GetEntityObject('MJ: Credentials', user);
1969
+ const loaded = await credential.InnerLoad(CompositeKey.FromID(ci.CredentialID));
1970
+ if (loaded) {
1971
+ credential.Values = oldCredentialValues;
1972
+ await credential.Save();
1973
+ }
1974
+ }
1975
+ }
1976
+ catch (e) {
1977
+ LogError(`Revert update connection failed: ${this.formatError(e)}`);
1978
+ }
1979
+ }
1980
+ // ── CONNECTION LIFECYCLE ─────────────────────────────────────────────
1981
+ /**
1982
+ * Lists all CompanyIntegrations (optionally filtered by active status).
1983
+ * Returns key fields for dashboard display without requiring a raw RunView call.
1984
+ */
1985
+ async IntegrationListConnections(activeOnly, companyID, ctx) {
1986
+ try {
1987
+ const user = this.getAuthenticatedUser(ctx);
1988
+ const rv = new RunView();
1989
+ const filters = [];
1990
+ if (activeOnly)
1991
+ filters.push('IsActive=1');
1992
+ if (companyID)
1993
+ filters.push(`CompanyID='${companyID}'`);
1994
+ const filter = filters.join(' AND ');
1995
+ const result = await rv.RunView({
1996
+ EntityName: 'MJ: Company Integrations',
1997
+ ExtraFilter: filter,
1998
+ OrderBy: 'Integration ASC',
1999
+ ResultType: 'simple',
2000
+ Fields: [
2001
+ 'ID', 'Integration', 'IntegrationID', 'CompanyID', 'Company',
2002
+ 'IsActive', 'ScheduleEnabled', 'CronExpression',
2003
+ 'ExternalSystemID', '__mj_CreatedAt'
2004
+ ]
2005
+ }, user);
2006
+ if (!result.Success)
2007
+ return { Success: false, Message: result.ErrorMessage || 'Query failed' };
2008
+ return {
2009
+ Success: true,
2010
+ Message: `${result.Results.length} connections`,
2011
+ Connections: result.Results.map(ci => ({
2012
+ ID: ci.ID,
2013
+ IntegrationName: ci.Integration,
2014
+ IntegrationID: ci.IntegrationID,
2015
+ CompanyID: ci.CompanyID,
2016
+ Company: ci.Company,
2017
+ IsActive: ci.IsActive,
2018
+ ScheduleEnabled: ci.ScheduleEnabled ?? false,
2019
+ CronExpression: ci.CronExpression ?? undefined,
2020
+ CreatedAt: ci.__mj_CreatedAt?.toISOString() ?? '',
2021
+ }))
2022
+ };
2023
+ }
2024
+ catch (e) {
2025
+ LogError(`IntegrationListConnections error: ${e}`);
2026
+ return { Success: false, Message: this.formatError(e) };
2027
+ }
2028
+ }
2029
+ /**
2030
+ * Creates a CompanyIntegration with a linked Credential entity for encrypted credential storage.
2031
+ */
2032
+ async IntegrationCreateConnection(input, testConnection, ctx) {
2033
+ try {
2034
+ const user = this.getAuthenticatedUser(ctx);
2035
+ const md = new Metadata();
2036
+ // 1. Create Credential record with encrypted values
2037
+ const credential = await md.GetEntityObject('MJ: Credentials', user);
2038
+ credential.NewRecord();
2039
+ credential.CredentialTypeID = input.CredentialTypeID;
2040
+ credential.Name = input.CredentialName;
2041
+ credential.Values = input.CredentialValues;
2042
+ credential.IsActive = true;
2043
+ const credSaved = await credential.Save();
2044
+ if (!credSaved) {
2045
+ const err = credential.LatestResult?.Message || 'Unknown error';
2046
+ return { Success: false, Message: `Failed to create Credential: ${err}` };
2047
+ }
2048
+ const credentialID = credential.ID;
2049
+ // 2. Create CompanyIntegration linked to the Credential
2050
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2051
+ ci.NewRecord();
2052
+ ci.IntegrationID = input.IntegrationID;
2053
+ ci.CompanyID = input.CompanyID;
2054
+ ci.CredentialID = credentialID;
2055
+ ci.IsActive = true;
2056
+ ci.Name = input.CredentialName; // Name is required on CompanyIntegration
2057
+ if (input.ExternalSystemID)
2058
+ ci.ExternalSystemID = input.ExternalSystemID;
2059
+ if (input.Configuration)
2060
+ ci.Configuration = input.Configuration;
2061
+ const saved = await ci.Save();
2062
+ if (!saved) {
2063
+ const validationErrors = ci.LatestResult?.Message || 'Unknown validation error';
2064
+ return { Success: false, Message: `Failed to save CompanyIntegration: ${validationErrors}` };
2065
+ }
2066
+ // 3. Optionally test the connection; rollback on failure
2067
+ if (testConnection) {
2068
+ const testResult = await this.testConnectionForCI(ci.ID, user);
2069
+ if (!testResult.Success) {
2070
+ await this.rollbackCreatedConnection(ci, credential);
2071
+ return {
2072
+ Success: false,
2073
+ Message: `Connection test failed: ${testResult.Message}. Connection was not saved.`,
2074
+ ConnectionTestSuccess: false,
2075
+ ConnectionTestMessage: testResult.Message
2076
+ };
2077
+ }
2078
+ return {
2079
+ Success: true,
2080
+ Message: 'Connection created and test passed',
2081
+ CompanyIntegrationID: ci.ID,
2082
+ CredentialID: credentialID,
2083
+ ConnectionTestSuccess: true,
2084
+ ConnectionTestMessage: testResult.Message
2085
+ };
2086
+ }
2087
+ return {
2088
+ Success: true,
2089
+ Message: 'Connection created',
2090
+ CompanyIntegrationID: ci.ID,
2091
+ CredentialID: credentialID
2092
+ };
2093
+ }
2094
+ catch (e) {
2095
+ LogError(`IntegrationCreateConnection error: ${e}`);
2096
+ return { Success: false, Message: this.formatError(e) };
2097
+ }
2098
+ }
2099
+ /**
2100
+ * Updates credential values and/or configuration on an existing CompanyIntegration.
2101
+ */
2102
+ async IntegrationUpdateConnection(companyIntegrationID, credentialValues, configuration, externalSystemID, testConnection, ctx) {
2103
+ try {
2104
+ const user = this.getAuthenticatedUser(ctx);
2105
+ const md = new Metadata();
2106
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2107
+ const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2108
+ if (!loaded)
2109
+ return { Success: false, Message: 'CompanyIntegration not found' };
2110
+ // Snapshot old values for rollback if testConnection is requested
2111
+ const oldCredentialValues = credentialValues ? await this.snapshotCredentialValues(ci.CredentialID, user) : undefined;
2112
+ const oldConfiguration = ci.Configuration;
2113
+ const oldExternalSystemID = ci.ExternalSystemID;
2114
+ // Update linked Credential values if provided
2115
+ if (credentialValues) {
2116
+ const credentialID = ci.CredentialID;
2117
+ if (!credentialID) {
2118
+ return { Success: false, Message: 'No linked Credential — use IntegrationCreateConnection first' };
2119
+ }
2120
+ const credential = await md.GetEntityObject('MJ: Credentials', user);
2121
+ const credLoaded = await credential.InnerLoad(CompositeKey.FromID(credentialID));
2122
+ if (!credLoaded)
2123
+ return { Success: false, Message: 'Linked Credential not found' };
2124
+ credential.Values = credentialValues;
2125
+ if (!await credential.Save())
2126
+ return { Success: false, Message: 'Failed to update Credential' };
2127
+ }
2128
+ let dirty = false;
2129
+ if (configuration !== undefined && configuration !== null) {
2130
+ ci.Configuration = configuration;
2131
+ dirty = true;
2132
+ }
2133
+ if (externalSystemID !== undefined && externalSystemID !== null) {
2134
+ ci.ExternalSystemID = externalSystemID;
2135
+ dirty = true;
2136
+ }
2137
+ if (dirty && !await ci.Save())
2138
+ return { Success: false, Message: 'Failed to save CompanyIntegration' };
2139
+ // Optionally test the connection; revert on failure
2140
+ if (testConnection) {
2141
+ const testResult = await this.testConnectionForCI(companyIntegrationID, user);
2142
+ if (!testResult.Success) {
2143
+ await this.revertUpdateConnection(ci, oldConfiguration, oldExternalSystemID, oldCredentialValues, user);
2144
+ return { Success: false, Message: `Connection test failed: ${testResult.Message}. Changes have been reverted.` };
2145
+ }
2146
+ return { Success: true, Message: 'Updated and connection test passed' };
2147
+ }
2148
+ return { Success: true, Message: 'Updated' };
2149
+ }
2150
+ catch (e) {
2151
+ LogError(`IntegrationUpdateConnection error: ${e}`);
2152
+ return { Success: false, Message: this.formatError(e) };
2153
+ }
2154
+ }
2155
+ /**
2156
+ * Soft-deletes a CompanyIntegration by setting IsActive=false.
2157
+ */
2158
+ async IntegrationDeactivateConnection(companyIntegrationID, ctx) {
2159
+ try {
2160
+ const user = this.getAuthenticatedUser(ctx);
2161
+ const md = new Metadata();
2162
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2163
+ const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2164
+ if (!loaded)
2165
+ return { Success: false, Message: 'CompanyIntegration not found' };
2166
+ ci.IsActive = false;
2167
+ if (!await ci.Save())
2168
+ return { Success: false, Message: 'Failed to deactivate' };
2169
+ return { Success: true, Message: 'Deactivated' };
2170
+ }
2171
+ catch (e) {
2172
+ LogError(`IntegrationDeactivateConnection error: ${e}`);
2173
+ return { Success: false, Message: this.formatError(e) };
2174
+ }
2175
+ }
2176
+ /**
2177
+ * Reactivates a previously deactivated CompanyIntegration by setting IsActive=true.
2178
+ */
2179
+ async IntegrationReactivateConnection(companyIntegrationID, ctx) {
2180
+ try {
2181
+ const user = this.getAuthenticatedUser(ctx);
2182
+ const md = new Metadata();
2183
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2184
+ const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2185
+ if (!loaded)
2186
+ return { Success: false, Message: 'CompanyIntegration not found' };
2187
+ ci.IsActive = true;
2188
+ if (!await ci.Save())
2189
+ return { Success: false, Message: `Failed to reactivate: ${ci.LatestResult?.Message ?? 'Unknown error'}` };
2190
+ return { Success: true, Message: 'Reactivated' };
2191
+ }
2192
+ catch (e) {
2193
+ LogError(`IntegrationReactivateConnection error: ${e}`);
2194
+ return { Success: false, Message: this.formatError(e) };
2195
+ }
2196
+ }
2197
+ // ── ENTITY MAPS ─────────────────────────────────────────────────────
2198
+ /**
2199
+ * Batch creates entity maps by entity name (resolved by lookup).
2200
+ * Call AFTER the schema pipeline has created the target entities.
2201
+ */
2202
+ async IntegrationCreateEntityMaps(companyIntegrationID, entityMaps, ctx) {
2203
+ try {
2204
+ const user = this.getAuthenticatedUser(ctx);
2205
+ const md = new Metadata();
2206
+ // Batch resolve entity names → IDs using cached Metadata
2207
+ const namesToResolve = entityMaps.filter(m => m.EntityName && !m.EntityID).map(m => m.EntityName);
2208
+ const nameToID = new Map();
2209
+ if (namesToResolve.length > 0) {
2210
+ const uniqueNames = [...new Set(namesToResolve)];
2211
+ for (const name of uniqueNames) {
2212
+ const entity = md.EntityByName(name);
2213
+ if (entity) {
2214
+ nameToID.set(name, entity.ID);
2215
+ }
2216
+ }
2217
+ const unresolved = uniqueNames.filter(n => !nameToID.has(n));
2218
+ if (unresolved.length > 0) {
2219
+ return {
2220
+ Success: false,
2221
+ Message: `Entities not found: ${unresolved.join(', ')}. Run the schema pipeline first.`
2222
+ };
2223
+ }
2224
+ }
2225
+ const created = [];
2226
+ for (const mapDef of entityMaps) {
2227
+ const entityID = mapDef.EntityID || nameToID.get(mapDef.EntityName || '');
2228
+ if (!entityID) {
2229
+ return { Success: false, Message: `No EntityID or EntityName for "${mapDef.ExternalObjectName}"`, Created: created };
2230
+ }
2231
+ const em = await md.GetEntityObject('MJ: Company Integration Entity Maps', user);
2232
+ em.NewRecord();
2233
+ em.CompanyIntegrationID = companyIntegrationID;
2234
+ em.ExternalObjectName = mapDef.ExternalObjectName;
2235
+ em.EntityID = entityID;
2236
+ const syncDir = mapDef.SyncDirection || 'Pull';
2237
+ if (!isValidSyncDirection(syncDir)) {
2238
+ return { Success: false, Message: `Invalid SyncDirection "${syncDir}" for "${mapDef.ExternalObjectName}". Must be one of: ${VALID_SYNC_DIRECTIONS.join(', ')}`, Created: created };
2239
+ }
2240
+ em.SyncDirection = syncDir;
2241
+ em.Priority = mapDef.Priority || 0;
2242
+ em.Status = 'Active';
2243
+ if (!await em.Save()) {
2244
+ return { Success: false, Message: `Failed to create map for ${mapDef.ExternalObjectName}`, Created: created };
2245
+ }
2246
+ const entityMapID = em.ID;
2247
+ // Create field maps if provided
2248
+ if (mapDef.FieldMaps) {
2249
+ for (const fmDef of mapDef.FieldMaps) {
2250
+ const fm = await md.GetEntityObject('MJ: Company Integration Field Maps', user);
2251
+ fm.NewRecord();
2252
+ fm.EntityMapID = entityMapID;
2253
+ fm.SourceFieldName = fmDef.SourceFieldName;
2254
+ fm.DestinationFieldName = fmDef.DestinationFieldName;
2255
+ fm.IsKeyField = fmDef.IsKeyField || false;
2256
+ fm.IsRequired = fmDef.IsRequired || false;
2257
+ fm.Status = 'Active';
2258
+ await fm.Save();
2259
+ }
2260
+ }
2261
+ created.push({
2262
+ EntityMapID: entityMapID,
2263
+ ExternalObjectName: mapDef.ExternalObjectName,
2264
+ FieldMapCount: mapDef.FieldMaps?.length || 0
2265
+ });
2266
+ }
2267
+ return { Success: true, Message: `Created ${created.length} entity maps`, Created: created };
2268
+ }
2269
+ catch (e) {
2270
+ LogError(`IntegrationCreateEntityMaps error: ${e}`);
2271
+ return { Success: false, Message: this.formatError(e) };
2272
+ }
2273
+ }
2274
+ // ── SCHEMA EXECUTION ────────────────────────────────────────────────
2275
+ /**
2276
+ * Generates schema artifacts from connector introspection and runs the full
2277
+ * RSU pipeline: write migration file → execute SQL → run CodeGen →
2278
+ * compile TypeScript → restart MJAPI → git commit (if enabled).
2279
+ *
2280
+ * Replaces the old two-step IntegrationSchemaPreview + IntegrationWriteSchemaFiles
2281
+ * pattern. Use IntegrationSchemaPreview to preview generated SQL without applying.
2282
+ */
2283
+ async IntegrationApplySchema(companyIntegrationID, objects, platform, skipGitCommit, skipRestart, ctx) {
2284
+ try {
2285
+ const user = this.getAuthenticatedUser(ctx);
2286
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
2287
+ const introspect = connector.IntrospectSchema.bind(connector);
2288
+ const sourceSchema = await introspect(companyIntegration, user);
2289
+ await this.resolveObjectInputs(objects, sourceSchema, user);
2290
+ const requestedNames = new Set(objects.map(o => o.SourceObjectName));
2291
+ const filteredSchema = {
2292
+ Objects: sourceSchema.Objects.filter(o => requestedNames.has(o.ExternalName))
2293
+ };
2294
+ const validatedPlatform = this.validatePlatform(platform);
2295
+ const targetConfigs = this.buildTargetConfigs(objects, filteredSchema, validatedPlatform, connector);
2296
+ const input = {
2297
+ SourceSchema: filteredSchema,
2298
+ TargetConfigs: targetConfigs,
2299
+ Platform: validatedPlatform,
2300
+ MJVersion: process.env.MJ_VERSION ?? '5.11.0',
2301
+ SourceType: companyIntegration.Integration,
2302
+ AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
2303
+ MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
2304
+ MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
2305
+ ExistingTables: this.buildExistingTables(targetConfigs),
2306
+ EntitySettingsForTargets: {}
2307
+ };
2308
+ const builder = new SchemaBuilder();
2309
+ const { SchemaOutput, PipelineResult } = await builder.RunSchemaPipeline(input, {
2310
+ SkipGitCommit: skipGitCommit,
2311
+ SkipRestart: skipRestart,
2312
+ });
2313
+ return {
2314
+ Success: PipelineResult.Success,
2315
+ Message: PipelineResult.Success
2316
+ ? `Schema applied — ${PipelineResult.EntitiesProcessed ?? 0} entities processed`
2317
+ : `Pipeline failed at '${PipelineResult.ErrorStep}': ${PipelineResult.ErrorMessage}`,
2318
+ Steps: PipelineResult.Steps.map((s) => ({
2319
+ Name: s.Name,
2320
+ Status: s.Status,
2321
+ DurationMs: s.DurationMs,
2322
+ Message: s.Message,
2323
+ })),
2324
+ MigrationFilePath: PipelineResult.MigrationFilePath,
2325
+ EntitiesProcessed: PipelineResult.EntitiesProcessed,
2326
+ GitCommitSuccess: PipelineResult.GitCommitSuccess,
2327
+ APIRestarted: PipelineResult.APIRestarted,
2328
+ Warnings: SchemaOutput.Warnings.length > 0 ? SchemaOutput.Warnings : undefined,
2329
+ };
2330
+ }
2331
+ catch (e) {
2332
+ LogError(`IntegrationApplySchema error: ${e}`);
2333
+ return { Success: false, Message: this.formatError(e) };
2334
+ }
2335
+ }
2336
+ /**
2337
+ * Batch apply schema for multiple connectors in one RSU pipeline run.
2338
+ * Each item specifies a companyIntegrationID + source objects to create tables for.
2339
+ * All migrations run sequentially, then ONE CodeGen, ONE compile, ONE git PR, ONE restart.
2340
+ */
2341
+ async IntegrationApplySchemaBatch(items, platform, skipGitCommit, skipRestart, ctx) {
2342
+ try {
2343
+ const user = this.getAuthenticatedUser(ctx);
2344
+ const validatedPlatform = this.validatePlatform(platform);
2345
+ const pipelineInputs = [];
2346
+ const itemResults = [];
2347
+ // Phase 1: Build schema artifacts for each connector's objects
2348
+ for (const item of items) {
2349
+ try {
2350
+ const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(item.CompanyIntegrationID, item.Objects, validatedPlatform, user, skipGitCommit, skipRestart);
2351
+ pipelineInputs.push(rsuInput);
2352
+ itemResults.push({
2353
+ CompanyIntegrationID: item.CompanyIntegrationID,
2354
+ Success: true,
2355
+ Message: `Schema generated for ${item.Objects.length} object(s)`,
2356
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
2357
+ });
2358
+ }
2359
+ catch (e) {
2360
+ itemResults.push({
2361
+ CompanyIntegrationID: item.CompanyIntegrationID,
2362
+ Success: false,
2363
+ Message: this.formatError(e),
2364
+ });
2365
+ }
2366
+ }
2367
+ // Phase 2: Run all successful migrations through one pipeline batch
2368
+ if (pipelineInputs.length === 0) {
2369
+ return { Success: false, Message: 'No valid schema inputs to process', Items: itemResults };
2370
+ }
2371
+ const rsm = RuntimeSchemaManager.Instance;
2372
+ const batchResult = await rsm.RunPipelineBatch(pipelineInputs);
2373
+ return {
2374
+ Success: batchResult.SuccessCount > 0,
2375
+ Message: `Batch complete: ${batchResult.SuccessCount} succeeded, ${batchResult.FailureCount} failed`,
2376
+ Items: itemResults,
2377
+ Steps: batchResult.Results[0]?.Steps.map((s) => ({
2378
+ Name: s.Name, Status: s.Status, DurationMs: s.DurationMs, Message: s.Message,
2379
+ })),
2380
+ GitCommitSuccess: batchResult.Results[0]?.GitCommitSuccess,
2381
+ APIRestarted: batchResult.Results[0]?.APIRestarted,
2382
+ };
2383
+ }
2384
+ catch (e) {
2385
+ LogError(`IntegrationApplySchemaBatch error: ${e}`);
2386
+ return { Success: false, Message: this.formatError(e), Items: [] };
2387
+ }
2388
+ }
2389
+ // ── APPLY ALL (Full Automatic Flow) ──────────────────────────────────
2390
+ /**
2391
+ * Full automatic "Apply All" flow for MJ integrations.
2392
+ * 1. Auto-generates schema/table names from the integration name + source object names
2393
+ * 2. Builds DDL + additionalSchemaInfo
2394
+ * 3. Runs RSU pipeline (migration → CodeGen → compile → git → restart)
2395
+ * 4. Creates CompanyIntegrationEntityMap records for each object
2396
+ * 5. Creates CompanyIntegrationFieldMap records for each field (1:1 mapping)
2397
+ * 6. Starts sync for the integration
2398
+ */
2399
+ async IntegrationApplyAll(input, platform, skipGitCommit, skipRestart, ctx) {
2400
+ try {
2401
+ const user = this.getAuthenticatedUser(ctx);
2402
+ const validatedPlatform = this.validatePlatform(platform);
2403
+ // Step 1: Resolve connector and derive schema name
2404
+ const { connector, companyIntegration } = await this.resolveConnector(input.CompanyIntegrationID, user);
2405
+ const schemaName = this.deriveSchemaName(companyIntegration.Integration);
2406
+ // Step 2: Resolve object IDs to names, build inputs with per-object Fields
2407
+ const sourceSchema = await connector.IntrospectSchema.bind(connector)(companyIntegration, user);
2408
+ const objectIDs = input.SourceObjects.map(so => so.SourceObjectID);
2409
+ const resolvedNames = await this.resolveSourceObjectNames(objectIDs, undefined, sourceSchema, companyIntegration.IntegrationID, user);
2410
+ // Build SchemaPreviewObjectInput with Fields carried from SourceObjectInput
2411
+ const fieldsByID = new Map(input.SourceObjects.map(so => [so.SourceObjectID, so.Fields]));
2412
+ const objects = resolvedNames.map((name, i) => {
2413
+ const obj = new SchemaPreviewObjectInput();
2414
+ obj.SourceObjectName = name;
2415
+ obj.SchemaName = schemaName;
2416
+ obj.TableName = name.replace(/[^A-Za-z0-9_]/g, '_');
2417
+ obj.EntityName = name.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/_/g, ' ');
2418
+ obj.Fields = fieldsByID.get(objectIDs[i]) ?? undefined;
2419
+ return obj;
2420
+ });
2421
+ // Step 3: Build schema and RSU pipeline input
2422
+ const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(input.CompanyIntegrationID, objects, validatedPlatform, user, skipGitCommit, skipRestart);
2423
+ // Step 4: Inject integration post-restart payload into RSU input.
2424
+ const { join } = await import('node:path');
2425
+ const rsuWorkDir = process.env.RSU_WORK_DIR || process.cwd();
2426
+ const pendingWorkDir = join(rsuWorkDir, '.rsu_pending');
2427
+ const pendingFilePath = join(pendingWorkDir, `${Date.now()}.json`);
2428
+ // Build per-object field map for pending file (null = all fields)
2429
+ const sourceObjectFields = {};
2430
+ for (const so of input.SourceObjects) {
2431
+ const resolvedName = resolvedNames[objectIDs.indexOf(so.SourceObjectID)];
2432
+ if (resolvedName)
2433
+ sourceObjectFields[resolvedName] = so.Fields ?? null;
2434
+ }
2435
+ const pendingPayload = {
2436
+ CompanyIntegrationID: input.CompanyIntegrationID,
2437
+ SourceObjectNames: resolvedNames,
2438
+ SourceObjectFields: sourceObjectFields,
2439
+ SchemaName: schemaName,
2440
+ CronExpression: input.CronExpression,
2441
+ ScheduleTimezone: input.ScheduleTimezone,
2442
+ StartSync: input.StartSync,
2443
+ FullSync: input.FullSync ?? false,
2444
+ SyncScope: input.SyncScope ?? 'created',
2445
+ CreatedAt: new Date().toISOString(),
2446
+ };
2447
+ rsuInput.PostRestartFiles = [
2448
+ { Path: pendingFilePath, Content: JSON.stringify(pendingPayload, null, 2) }
2449
+ ];
2450
+ // Step 5: Run pipeline (restart kills process at the end)
2451
+ const rsm = RuntimeSchemaManager.Instance;
2452
+ const batchResult = await rsm.RunPipelineBatch([rsuInput]);
2453
+ const migrationSucceeded = batchResult.SuccessCount > 0;
2454
+ const pipelineSteps = batchResult.Results[0]?.Steps.map((s) => ({
2455
+ Name: s.Name, Status: s.Status, DurationMs: s.DurationMs, Message: s.Message,
2456
+ }));
2457
+ // If pipeline failed, clean up pending file and return error
2458
+ if (!migrationSucceeded) {
2459
+ try {
2460
+ (await import('node:fs')).unlinkSync(pendingFilePath);
2461
+ }
2462
+ catch { /* may not exist */ }
2463
+ return {
2464
+ Success: false,
2465
+ Message: `Pipeline failed: ${batchResult.Results[0]?.ErrorMessage ?? 'unknown error'}`,
2466
+ Steps: pipelineSteps,
2467
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
2468
+ };
2469
+ }
2470
+ // If we get here, pipeline succeeded but restart may or may not have happened yet.
2471
+ // If restart happened, this code never executes (process died).
2472
+ // If skipRestart=true, we can do entity maps now.
2473
+ if (skipRestart) {
2474
+ await Metadata.Provider.Refresh();
2475
+ const entityMapsCreated = await this.createEntityAndFieldMaps(input.CompanyIntegrationID, objects, connector, companyIntegration, schemaName, user);
2476
+ const createdMapIDs = entityMapsCreated.map(em => em.EntityMapID).filter(Boolean);
2477
+ const scopedMapIDs = input.SyncScope === 'all' ? undefined : createdMapIDs;
2478
+ const syncRunID = input.StartSync !== false
2479
+ ? await this.startSyncAfterApply(input.CompanyIntegrationID, user, scopedMapIDs, input.FullSync)
2480
+ : null;
2481
+ // Create schedule if requested
2482
+ let scheduledJobID;
2483
+ if (input.CronExpression) {
2484
+ try {
2485
+ scheduledJobID = await this.createScheduleForConnector(input.CompanyIntegrationID, companyIntegration.Integration, input.CronExpression, input.ScheduleTimezone, user) ?? undefined;
2486
+ }
2487
+ catch (schedErr) {
2488
+ console.warn(`[Integration] Schedule creation failed: ${schedErr}`);
2489
+ }
2490
+ }
2491
+ try {
2492
+ (await import('node:fs')).unlinkSync(pendingFilePath);
2493
+ }
2494
+ catch { /* already consumed */ }
2495
+ return {
2496
+ Success: true,
2497
+ Message: `Applied ${objects.length} object(s) — ${entityMapsCreated.length} entity maps created${syncRunID ? ', sync started' : ''}${scheduledJobID ? ', schedule created' : ''}`,
2498
+ Steps: pipelineSteps,
2499
+ EntityMapsCreated: entityMapsCreated,
2500
+ SyncRunID: syncRunID ?? undefined,
2501
+ ScheduledJobID: scheduledJobID,
2502
+ GitCommitSuccess: batchResult.Results[0]?.GitCommitSuccess,
2503
+ APIRestarted: false,
2504
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
2505
+ };
2506
+ }
2507
+ // If restart is enabled, this return may or may not execute
2508
+ // (depends on whether PM2 kills process before GraphQL response is sent)
2509
+ return {
2510
+ Success: true,
2511
+ Message: `Applied ${objects.length} object(s) — entity maps will be created after restart`,
2512
+ Steps: pipelineSteps,
2513
+ GitCommitSuccess: batchResult.Results[0]?.GitCommitSuccess,
2514
+ APIRestarted: true,
2515
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
2516
+ };
2517
+ }
2518
+ catch (e) {
2519
+ LogError(`IntegrationApplyAll error: ${e}`);
2520
+ return { Success: false, Message: this.formatError(e) };
2521
+ }
2522
+ }
2523
+ /** Derives a SQL-safe schema name from the integration name (e.g., "HubSpot" → "hubspot"). */
2524
+ deriveSchemaName(integrationName) {
2525
+ return (integrationName || 'integration').toLowerCase().replace(/[^a-z0-9_]/g, '_');
2526
+ }
2527
+ /** Builds SchemaPreviewObjectInput[] from source object name strings, using auto-derived schema/table names. */
2528
+ buildObjectInputsFromNames(sourceObjectNames, schemaName) {
2529
+ return sourceObjectNames.map(name => {
2530
+ const obj = new SchemaPreviewObjectInput();
2531
+ obj.SourceObjectName = name;
2532
+ obj.SchemaName = schemaName;
2533
+ obj.TableName = name.replace(/[^A-Za-z0-9_]/g, '_');
2534
+ obj.EntityName = name.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/_/g, ' ');
2535
+ return obj;
2536
+ });
2537
+ }
278
2538
  /**
279
- * Discovers available objects/tables in the external system.
2539
+ * After pipeline success, creates CompanyIntegrationEntityMap + CompanyIntegrationFieldMap
2540
+ * records for each source object by matching schema + table name to newly created entities.
280
2541
  */
281
- async IntegrationDiscoverObjects(companyIntegrationID, ctx) {
2542
+ async createEntityAndFieldMaps(companyIntegrationID, objects, connector, companyIntegration, schemaName, user) {
2543
+ const md = new Metadata();
2544
+ const results = [];
2545
+ for (const obj of objects) {
2546
+ const entityMapResult = await this.createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, md);
2547
+ if (entityMapResult) {
2548
+ results.push(entityMapResult);
2549
+ }
2550
+ }
2551
+ return results;
2552
+ }
2553
+ /** Creates a single entity map + field maps for one source object. */
2554
+ async createSingleEntityMap(companyIntegrationID, obj, connector, companyIntegration, schemaName, user, md) {
2555
+ // Find the entity by schema + table name
2556
+ const entityInfo = md.Entities.find(e => e.SchemaName.toLowerCase() === schemaName.toLowerCase()
2557
+ && e.BaseTable.toLowerCase() === obj.TableName.toLowerCase());
2558
+ if (!entityInfo) {
2559
+ LogError(`IntegrationApplyAll: entity not found for ${schemaName}.${obj.TableName}`);
2560
+ return null;
2561
+ }
2562
+ // Create entity map
2563
+ const em = await md.GetEntityObject('MJ: Company Integration Entity Maps', user);
2564
+ em.NewRecord();
2565
+ em.CompanyIntegrationID = companyIntegrationID;
2566
+ em.ExternalObjectName = obj.SourceObjectName;
2567
+ em.EntityID = entityInfo.ID;
2568
+ em.SyncDirection = 'Pull';
2569
+ em.Priority = 0;
2570
+ em.Status = 'Active';
2571
+ em.SyncEnabled = true;
2572
+ if (!await em.Save()) {
2573
+ LogError(`IntegrationApplyAll: failed to save entity map for ${obj.SourceObjectName}`);
2574
+ return null;
2575
+ }
2576
+ // Discover fields from the source and create 1:1 field maps
2577
+ const fieldMapCount = await this.createFieldMapsForEntityMap(em.ID, obj.SourceObjectName, connector, companyIntegration, user, md);
2578
+ return {
2579
+ SourceObjectName: obj.SourceObjectName,
2580
+ EntityName: entityInfo.Name,
2581
+ EntityMapID: em.ID,
2582
+ FieldMapCount: fieldMapCount,
2583
+ };
2584
+ }
2585
+ /** Discovers fields from the source object and creates 1:1 field maps. */
2586
+ async createFieldMapsForEntityMap(entityMapID, sourceObjectName, connector, companyIntegration, user, md) {
2587
+ let fieldCount = 0;
2588
+ try {
2589
+ const discoverFields = connector.DiscoverFields.bind(connector);
2590
+ const fields = await discoverFields(companyIntegration, sourceObjectName, user);
2591
+ for (const field of fields) {
2592
+ const fm = await md.GetEntityObject('MJ: Company Integration Field Maps', user);
2593
+ fm.NewRecord();
2594
+ fm.EntityMapID = entityMapID;
2595
+ fm.SourceFieldName = field.Name;
2596
+ fm.DestinationFieldName = field.Name.replace(/[^A-Za-z0-9_]/g, '_');
2597
+ fm.IsKeyField = field.IsUniqueKey;
2598
+ fm.IsRequired = field.IsRequired;
2599
+ fm.Direction = 'SourceToDest';
2600
+ fm.Status = 'Active';
2601
+ fm.Priority = 0;
2602
+ if (await fm.Save()) {
2603
+ fieldCount++;
2604
+ }
2605
+ }
2606
+ }
2607
+ catch (e) {
2608
+ LogError(`IntegrationApplyAll: failed to discover/create field maps for ${sourceObjectName}: ${this.formatError(e)}`);
2609
+ }
2610
+ return fieldCount;
2611
+ }
2612
+ /** Starts sync after a successful apply-all pipeline, returning the run ID if available. */
2613
+ async startSyncAfterApply(companyIntegrationID, user, entityMapIDs, fullSync) {
2614
+ try {
2615
+ await IntegrationEngine.Instance.Config(false, user);
2616
+ const options = {};
2617
+ if (entityMapIDs?.length)
2618
+ options.EntityMapIDs = entityMapIDs;
2619
+ if (fullSync)
2620
+ options.FullSync = true;
2621
+ const finalOptions = Object.keys(options).length > 0 ? options : undefined;
2622
+ const syncPromise = IntegrationEngine.Instance.RunSync(companyIntegrationID, user, 'Manual', undefined, undefined, finalOptions);
2623
+ // Fire and forget — don't block the response
2624
+ syncPromise.catch(err => {
2625
+ LogError(`IntegrationApplyAll: background sync failed for ${companyIntegrationID}: ${err}`);
2626
+ });
2627
+ // Small delay to let the run record get created
2628
+ await new Promise(resolve => setTimeout(resolve, 200));
2629
+ const rv = new RunView();
2630
+ const runResult = await rv.RunView({
2631
+ EntityName: 'MJ: Company Integration Runs',
2632
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}' AND Status='In Progress'`,
2633
+ OrderBy: '__mj_CreatedAt DESC',
2634
+ MaxRows: 1,
2635
+ ResultType: 'simple',
2636
+ Fields: ['ID']
2637
+ }, user);
2638
+ return (runResult.Success && runResult.Results.length > 0) ? runResult.Results[0].ID : null;
2639
+ }
2640
+ catch (e) {
2641
+ LogError(`IntegrationApplyAll: sync start failed: ${this.formatError(e)}`);
2642
+ return null;
2643
+ }
2644
+ }
2645
+ /**
2646
+ * Build schema artifacts for a single connector's objects.
2647
+ * Shared by IntegrationApplySchema (single) and IntegrationApplySchemaBatch (batch).
2648
+ */
2649
+ async buildSchemaForConnector(companyIntegrationID, objects, platform, user, skipGitCommit, skipRestart) {
2650
+ const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
2651
+ const introspect = connector.IntrospectSchema.bind(connector);
2652
+ const sourceSchema = await introspect(companyIntegration, user);
2653
+ // Normalize names to match source schema casing
2654
+ const nameMap = new Map(sourceSchema.Objects.map(o => [o.ExternalName.toLowerCase(), o.ExternalName]));
2655
+ for (const obj of objects) {
2656
+ const exact = nameMap.get(obj.SourceObjectName.toLowerCase());
2657
+ if (exact)
2658
+ obj.SourceObjectName = exact;
2659
+ }
2660
+ const requestedNames = new Set(objects.map(o => o.SourceObjectName));
2661
+ const filteredSchema = {
2662
+ Objects: sourceSchema.Objects.filter(o => requestedNames.has(o.ExternalName))
2663
+ };
2664
+ const targetConfigs = this.buildTargetConfigs(objects, filteredSchema, platform, connector);
2665
+ const input = {
2666
+ SourceSchema: filteredSchema,
2667
+ TargetConfigs: targetConfigs,
2668
+ Platform: platform,
2669
+ MJVersion: process.env.MJ_VERSION ?? '5.11.0',
2670
+ SourceType: companyIntegration.Integration,
2671
+ AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
2672
+ MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
2673
+ MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
2674
+ ExistingTables: this.buildExistingTables(targetConfigs),
2675
+ EntitySettingsForTargets: {}
2676
+ };
2677
+ const builder = new SchemaBuilder();
2678
+ const schemaOutput = builder.BuildSchema(input);
2679
+ if (schemaOutput.Errors.length > 0) {
2680
+ throw new Error(`Schema generation failed: ${schemaOutput.Errors.join('; ')}`);
2681
+ }
2682
+ const rsuInput = builder.BuildRSUInput(schemaOutput, input, { SkipGitCommit: skipGitCommit, SkipRestart: skipRestart });
2683
+ return { schemaOutput, rsuInput };
2684
+ }
2685
+ // ── SYNC ────────────────────────────────────────────────────────────
2686
+ /**
2687
+ * Starts an async integration sync. Returns immediately with the run ID.
2688
+ * Sends a webhook to the registered callback when complete.
2689
+ */
2690
+ async IntegrationStartSync(companyIntegrationID, webhookURL, fullSync, entityMapIDs, ctx) {
282
2691
  try {
283
2692
  const user = this.getAuthenticatedUser(ctx);
284
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
285
- // Cast through unknown to bridge duplicate package type declarations
286
- // (integration-engine resolves its own node_modules copies of core/core-entities)
287
- const discoverObjects = connector.DiscoverObjects.bind(connector);
288
- const objects = await discoverObjects(companyIntegration, user);
2693
+ await IntegrationEngine.Instance.Config(false, user);
2694
+ const syncOptions = {};
2695
+ if (fullSync)
2696
+ syncOptions.FullSync = true;
2697
+ if (entityMapIDs?.length)
2698
+ syncOptions.EntityMapIDs = entityMapIDs;
2699
+ // Fire and forget — progress is tracked inside IntegrationEngine
2700
+ const syncPromise = IntegrationEngine.Instance.RunSync(companyIntegrationID, user, 'Manual', undefined, undefined, Object.keys(syncOptions).length > 0 ? syncOptions : undefined);
2701
+ syncPromise
2702
+ .then(async (result) => {
2703
+ if (webhookURL) {
2704
+ await this.sendWebhook(webhookURL, {
2705
+ event: result.Success ? 'sync_complete' : 'sync_failed',
2706
+ companyIntegrationID,
2707
+ success: result.Success,
2708
+ recordsProcessed: result.RecordsProcessed,
2709
+ recordsCreated: result.RecordsCreated,
2710
+ recordsUpdated: result.RecordsUpdated,
2711
+ recordsErrored: result.RecordsErrored,
2712
+ errorCount: result.Errors.length
2713
+ });
2714
+ }
2715
+ })
2716
+ .catch(async (err) => {
2717
+ console.error(`[Integration] Background sync failed for ${companyIntegrationID}:`, err);
2718
+ if (webhookURL) {
2719
+ await this.sendWebhook(webhookURL, {
2720
+ event: 'sync_failed',
2721
+ companyIntegrationID,
2722
+ success: false,
2723
+ error: err instanceof Error ? err.message : String(err)
2724
+ });
2725
+ }
2726
+ });
2727
+ // Small delay to let the run record get created
2728
+ await new Promise(resolve => setTimeout(resolve, 200));
2729
+ const rv = new RunView();
2730
+ const runResult = await rv.RunView({
2731
+ EntityName: 'MJ: Company Integration Runs',
2732
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}' AND Status='In Progress'`,
2733
+ OrderBy: '__mj_CreatedAt DESC',
2734
+ MaxRows: 1,
2735
+ ResultType: 'simple',
2736
+ Fields: ['ID', 'Status', 'StartedAt']
2737
+ }, user);
2738
+ const run = runResult.Success && runResult.Results.length > 0 ? runResult.Results[0] : null;
289
2739
  return {
290
2740
  Success: true,
291
- Message: `Discovered ${objects.length} objects`,
292
- Objects: objects.map(o => ({
293
- Name: o.Name,
294
- Label: o.Label,
295
- SupportsIncrementalSync: o.SupportsIncrementalSync,
296
- SupportsWrite: o.SupportsWrite
297
- }))
2741
+ Message: 'Sync started',
2742
+ RunID: run?.ID
298
2743
  };
299
2744
  }
300
2745
  catch (e) {
301
- return this.handleDiscoveryError(e);
2746
+ LogError(`IntegrationStartSync error: ${e}`);
2747
+ return { Success: false, Message: this.formatError(e) };
302
2748
  }
303
2749
  }
304
2750
  /**
305
- * Discovers fields on a specific external object.
2751
+ * Cancels a running sync by marking its status as Cancelled.
306
2752
  */
307
- async IntegrationDiscoverFields(companyIntegrationID, objectName, ctx) {
2753
+ async IntegrationCancelSync(companyIntegrationID, ctx) {
2754
+ try {
2755
+ this.getAuthenticatedUser(ctx);
2756
+ // Signal the engine to abort the running sync
2757
+ const cancelled = IntegrationEngine.CancelSync(companyIntegrationID);
2758
+ if (!cancelled) {
2759
+ return { Success: false, Message: 'No active sync found for this connector' };
2760
+ }
2761
+ return { Success: true, Message: 'Sync cancellation signalled — will stop after current batch completes' };
2762
+ }
2763
+ catch (e) {
2764
+ LogError(`IntegrationCancelSync error: ${e}`);
2765
+ return { Success: false, Message: this.formatError(e) };
2766
+ }
2767
+ }
2768
+ // ── SCHEDULE ────────────────────────────────────────────────────────
2769
+ async IntegrationCreateSchedule(input, ctx) {
308
2770
  try {
309
2771
  const user = this.getAuthenticatedUser(ctx);
310
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
311
- // Cast through unknown to bridge duplicate package type declarations
312
- const discoverFields = connector.DiscoverFields.bind(connector);
313
- const fields = await discoverFields(companyIntegration, objectName, user);
2772
+ const md = new Metadata();
2773
+ const rv = new RunView();
2774
+ // Find IntegrationSync job type
2775
+ const jobTypeResult = await rv.RunView({
2776
+ EntityName: 'MJ: Scheduled Job Types',
2777
+ ExtraFilter: `DriverClass='IntegrationSyncScheduledJobDriver'`,
2778
+ MaxRows: 1,
2779
+ ResultType: 'simple',
2780
+ Fields: ['ID']
2781
+ }, user);
2782
+ if (!jobTypeResult.Success || jobTypeResult.Results.length === 0) {
2783
+ return { Success: false, Message: 'IntegrationSync scheduled job type not found' };
2784
+ }
2785
+ const jobTypeID = jobTypeResult.Results[0].ID;
2786
+ const job = await md.GetEntityObject('MJ: Scheduled Jobs', user);
2787
+ job.NewRecord();
2788
+ job.JobTypeID = jobTypeID;
2789
+ job.Name = input.Name;
2790
+ if (input.Description)
2791
+ job.Description = input.Description;
2792
+ job.CronExpression = input.CronExpression;
2793
+ job.Timezone = input.Timezone || 'UTC';
2794
+ job.Status = 'Active';
2795
+ job.OwnerUserID = user.ID;
2796
+ job.Configuration = JSON.stringify({ CompanyIntegrationID: input.CompanyIntegrationID });
2797
+ job.NextRunAt = CronExpressionHelper.GetNextRunTime(input.CronExpression, input.Timezone || 'UTC');
2798
+ if (!await job.Save())
2799
+ return { Success: false, Message: 'Failed to create schedule' };
2800
+ // Link to CompanyIntegration
2801
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
2802
+ const ciLoaded = await ci.InnerLoad(CompositeKey.FromID(input.CompanyIntegrationID));
2803
+ if (ciLoaded) {
2804
+ ci.ScheduleEnabled = true;
2805
+ ci.ScheduleType = 'Cron';
2806
+ ci.CronExpression = input.CronExpression;
2807
+ await ci.Save();
2808
+ }
2809
+ return { Success: true, Message: 'Schedule created', ScheduledJobID: job.ID };
2810
+ }
2811
+ catch (e) {
2812
+ LogError(`IntegrationCreateSchedule error: ${e}`);
2813
+ return { Success: false, Message: this.formatError(e) };
2814
+ }
2815
+ }
2816
+ async IntegrationUpdateSchedule(scheduledJobID, cronExpression, timezone, name, ctx) {
2817
+ try {
2818
+ const user = this.getAuthenticatedUser(ctx);
2819
+ const md = new Metadata();
2820
+ const job = await md.GetEntityObject('MJ: Scheduled Jobs', user);
2821
+ const loaded = await job.InnerLoad(CompositeKey.FromID(scheduledJobID));
2822
+ if (!loaded)
2823
+ return { Success: false, Message: 'ScheduledJob not found' };
2824
+ if (cronExpression)
2825
+ job.CronExpression = cronExpression;
2826
+ if (timezone)
2827
+ job.Timezone = timezone;
2828
+ if (name)
2829
+ job.Name = name;
2830
+ if (cronExpression || timezone) {
2831
+ job.NextRunAt = CronExpressionHelper.GetNextRunTime(job.CronExpression, job.Timezone || 'UTC');
2832
+ }
2833
+ if (!await job.Save())
2834
+ return { Success: false, Message: 'Failed to update' };
2835
+ return { Success: true, Message: 'Updated' };
2836
+ }
2837
+ catch (e) {
2838
+ LogError(`IntegrationUpdateSchedule error: ${e}`);
2839
+ return { Success: false, Message: this.formatError(e) };
2840
+ }
2841
+ }
2842
+ async IntegrationToggleSchedule(scheduledJobID, enabled, ctx) {
2843
+ try {
2844
+ this.getAuthenticatedUser(ctx); // verify caller is authenticated
2845
+ const sysUser = this.getSystemUser();
2846
+ const md = new Metadata();
2847
+ const job = await md.GetEntityObject('MJ: Scheduled Jobs', sysUser);
2848
+ const loaded = await job.InnerLoad(CompositeKey.FromID(scheduledJobID));
2849
+ if (!loaded)
2850
+ return { Success: false, Message: 'ScheduledJob not found' };
2851
+ job.Status = enabled ? 'Active' : 'Paused';
2852
+ if (!await job.Save()) {
2853
+ const err = job.LatestResult?.Message || 'Unknown error';
2854
+ return { Success: false, Message: `Failed to toggle: ${err}` };
2855
+ }
2856
+ return { Success: true, Message: enabled ? 'Activated' : 'Paused' };
2857
+ }
2858
+ catch (e) {
2859
+ LogError(`IntegrationToggleSchedule error: ${e}`);
2860
+ return { Success: false, Message: this.formatError(e) };
2861
+ }
2862
+ }
2863
+ async IntegrationDeleteSchedule(scheduledJobID, companyIntegrationID, ctx) {
2864
+ try {
2865
+ this.getAuthenticatedUser(ctx); // verify caller is authenticated
2866
+ const sysUser = this.getSystemUser(); // use system user for delete operations
2867
+ const md = new Metadata();
2868
+ // Unlink from CI if provided
2869
+ if (companyIntegrationID) {
2870
+ const ci = await md.GetEntityObject('MJ: Company Integrations', sysUser);
2871
+ const ciLoaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
2872
+ if (ciLoaded) {
2873
+ ci.ScheduleEnabled = false;
2874
+ ci.CronExpression = null;
2875
+ await ci.Save();
2876
+ }
2877
+ }
2878
+ const rv = new RunView();
2879
+ // Clear ScheduledJobID on any CompanyIntegration that references this job
2880
+ const ciResult = await rv.RunView({
2881
+ EntityName: 'MJ: Company Integrations',
2882
+ ExtraFilter: `ScheduledJobID='${scheduledJobID}'`,
2883
+ ResultType: 'entity_object',
2884
+ }, sysUser);
2885
+ if (ciResult.Success) {
2886
+ for (const refCI of ciResult.Results) {
2887
+ refCI.ScheduledJobID = null;
2888
+ refCI.ScheduleEnabled = false;
2889
+ refCI.CronExpression = null;
2890
+ await refCI.Save();
2891
+ }
2892
+ }
2893
+ // Null out ScheduledJobRunID on CompanyIntegrationRuns that reference this job's runs
2894
+ const jobRunsResult = await rv.RunView({
2895
+ EntityName: 'MJ: Scheduled Job Runs',
2896
+ ExtraFilter: `ScheduledJobID='${scheduledJobID}'`,
2897
+ ResultType: 'entity_object',
2898
+ }, sysUser);
2899
+ if (jobRunsResult.Success) {
2900
+ for (const jr of jobRunsResult.Results) {
2901
+ // Find CompanyIntegrationRuns referencing this job run and null the FK
2902
+ const ciRunsResult = await rv.RunView({
2903
+ EntityName: 'MJ: Company Integration Runs',
2904
+ ExtraFilter: `ScheduledJobRunID='${jr.ID}'`,
2905
+ ResultType: 'entity_object',
2906
+ }, sysUser);
2907
+ if (ciRunsResult.Success) {
2908
+ for (const ciRun of ciRunsResult.Results) {
2909
+ ciRun.ScheduledJobRunID = null;
2910
+ await ciRun.Save();
2911
+ }
2912
+ }
2913
+ }
2914
+ }
2915
+ // Now delete job runs + job in a transaction
2916
+ const tg = await Metadata.Provider.CreateTransactionGroup();
2917
+ if (jobRunsResult.Success) {
2918
+ for (const run of jobRunsResult.Results) {
2919
+ run.TransactionGroup = tg;
2920
+ await run.Delete();
2921
+ }
2922
+ }
2923
+ const job = await md.GetEntityObject('MJ: Scheduled Jobs', sysUser);
2924
+ const loaded = await job.InnerLoad(CompositeKey.FromID(scheduledJobID));
2925
+ if (!loaded)
2926
+ return { Success: false, Message: 'ScheduledJob not found' };
2927
+ job.TransactionGroup = tg;
2928
+ await job.Delete();
2929
+ const deleted = await tg.Submit();
2930
+ if (!deleted) {
2931
+ const err = job.LatestResult?.Message || 'Unknown error';
2932
+ return { Success: false, Message: `Failed to delete: ${err}` };
2933
+ }
2934
+ return { Success: true, Message: `Deleted (${jobRunsResult.Results?.length ?? 0} runs removed)` };
2935
+ }
2936
+ catch (e) {
2937
+ LogError(`IntegrationDeleteSchedule error: ${e}`);
2938
+ return { Success: false, Message: this.formatError(e) };
2939
+ }
2940
+ }
2941
+ async IntegrationListSchedules(companyIntegrationID, ctx) {
2942
+ try {
2943
+ const user = this.getAuthenticatedUser(ctx);
2944
+ const rv = new RunView();
2945
+ const result = await rv.RunView({
2946
+ EntityName: 'MJ: Scheduled Jobs',
2947
+ ExtraFilter: `Configuration LIKE '%"CompanyIntegrationID":"${companyIntegrationID}"%'`,
2948
+ OrderBy: '__mj_CreatedAt DESC',
2949
+ ResultType: 'simple',
2950
+ Fields: ['ID', 'Name', 'Status', 'CronExpression', 'Timezone', 'NextRunAt', 'LastRunAt', 'RunCount', 'SuccessCount', 'FailureCount']
2951
+ }, user);
2952
+ if (!result.Success)
2953
+ return { Success: false, Message: result.ErrorMessage || 'Query failed' };
314
2954
  return {
315
2955
  Success: true,
316
- Message: `Discovered ${fields.length} fields on "${objectName}"`,
317
- Fields: fields.map(f => ({
318
- Name: f.Name,
319
- Label: f.Label,
320
- DataType: f.DataType,
321
- IsRequired: f.IsRequired,
322
- IsUniqueKey: f.IsUniqueKey,
323
- IsReadOnly: f.IsReadOnly
2956
+ Message: `${result.Results.length} schedule(s)`,
2957
+ Schedules: result.Results.map(r => ({
2958
+ ID: r.ID,
2959
+ Name: r.Name,
2960
+ Status: r.Status,
2961
+ CronExpression: r.CronExpression,
2962
+ Timezone: r.Timezone,
2963
+ NextRunAt: r.NextRunAt ?? undefined,
2964
+ LastRunAt: r.LastRunAt ?? undefined,
2965
+ RunCount: r.RunCount,
2966
+ SuccessCount: r.SuccessCount,
2967
+ FailureCount: r.FailureCount,
324
2968
  }))
325
2969
  };
326
2970
  }
327
2971
  catch (e) {
328
- return this.handleDiscoveryError(e);
2972
+ LogError(`IntegrationListSchedules error: ${e}`);
2973
+ return { Success: false, Message: this.formatError(e) };
329
2974
  }
330
2975
  }
331
- /**
332
- * Tests connectivity to the external system.
333
- */
334
- async IntegrationTestConnection(companyIntegrationID, ctx) {
2976
+ // ── ENTITY MAP MANAGEMENT ──────────────────────────────────────────
2977
+ async IntegrationListEntityMaps(companyIntegrationID, ctx) {
335
2978
  try {
336
2979
  const user = this.getAuthenticatedUser(ctx);
337
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
338
- // Cast through unknown to bridge duplicate package type declarations
339
- const testConnection = connector.TestConnection.bind(connector);
340
- const result = await testConnection(companyIntegration, user);
2980
+ const rv = new RunView();
2981
+ const result = await rv.RunView({
2982
+ EntityName: 'MJ: Company Integration Entity Maps',
2983
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
2984
+ OrderBy: 'Priority ASC',
2985
+ ResultType: 'simple',
2986
+ Fields: ['ID', 'EntityID', 'Entity', 'ExternalObjectName', 'SyncDirection', 'Priority', 'Status']
2987
+ }, user);
2988
+ if (!result.Success)
2989
+ return { Success: false, Message: result.ErrorMessage || 'Query failed' };
341
2990
  return {
342
- Success: result.Success,
343
- Message: result.Message,
344
- ServerVersion: result.ServerVersion
2991
+ Success: true,
2992
+ Message: `${result.Results.length} entity maps`,
2993
+ EntityMaps: result.Results
345
2994
  };
346
2995
  }
347
2996
  catch (e) {
348
- const error = e;
349
- LogError(`IntegrationTestConnection error: ${error}`);
2997
+ LogError(`IntegrationListEntityMaps error: ${e}`);
2998
+ return { Success: false, Message: this.formatError(e) };
2999
+ }
3000
+ }
3001
+ async IntegrationListFieldMaps(entityMapID, ctx) {
3002
+ try {
3003
+ const user = this.getAuthenticatedUser(ctx);
3004
+ const rv = new RunView();
3005
+ const result = await rv.RunView({
3006
+ EntityName: 'MJ: Company Integration Field Maps',
3007
+ ExtraFilter: `EntityMapID='${entityMapID}'`,
3008
+ OrderBy: 'SourceFieldName',
3009
+ ResultType: 'simple',
3010
+ Fields: ['ID', 'EntityMapID', 'SourceFieldName', 'DestinationFieldName', 'Status']
3011
+ }, user);
3012
+ if (!result.Success)
3013
+ return { Success: false, Message: result.ErrorMessage || 'Query failed' };
350
3014
  return {
351
- Success: false,
352
- Message: `Error: ${error.message}`
3015
+ Success: true,
3016
+ Message: `${result.Results.length} field maps`,
3017
+ FieldMaps: result.Results
3018
+ };
3019
+ }
3020
+ catch (e) {
3021
+ LogError(`IntegrationListFieldMaps error: ${e}`);
3022
+ return { Success: false, Message: this.formatError(e) };
3023
+ }
3024
+ }
3025
+ async IntegrationUpdateEntityMaps(updates, ctx) {
3026
+ try {
3027
+ const user = this.getAuthenticatedUser(ctx);
3028
+ const md = new Metadata();
3029
+ const errors = [];
3030
+ for (const update of updates) {
3031
+ const em = await md.GetEntityObject('MJ: Company Integration Entity Maps', user);
3032
+ const loaded = await em.InnerLoad(CompositeKey.FromID(update.EntityMapID));
3033
+ if (!loaded) {
3034
+ errors.push(`${update.EntityMapID}: not found`);
3035
+ continue;
3036
+ }
3037
+ if (update.SyncDirection != null) {
3038
+ if (!isValidSyncDirection(update.SyncDirection)) {
3039
+ errors.push(`${update.EntityMapID}: invalid SyncDirection "${update.SyncDirection}"`);
3040
+ continue;
3041
+ }
3042
+ em.SyncDirection = update.SyncDirection;
3043
+ }
3044
+ if (update.Priority != null)
3045
+ em.Priority = update.Priority;
3046
+ if (update.Status != null) {
3047
+ if (!isValidEntityMapStatus(update.Status)) {
3048
+ errors.push(`${update.EntityMapID}: invalid Status "${update.Status}"`);
3049
+ continue;
3050
+ }
3051
+ em.Status = update.Status;
3052
+ }
3053
+ if (!await em.Save())
3054
+ errors.push(`${update.EntityMapID}: failed to save`);
3055
+ }
3056
+ if (errors.length > 0)
3057
+ return { Success: false, Message: `Errors: ${errors.join('; ')}` };
3058
+ return { Success: true, Message: `Updated ${updates.length} entity maps` };
3059
+ }
3060
+ catch (e) {
3061
+ LogError(`IntegrationUpdateEntityMaps error: ${e}`);
3062
+ return { Success: false, Message: this.formatError(e) };
3063
+ }
3064
+ }
3065
+ async IntegrationDeleteEntityMaps(entityMapIDs, ctx) {
3066
+ try {
3067
+ this.getAuthenticatedUser(ctx);
3068
+ const sysUser = this.getSystemUser();
3069
+ const md = new Metadata();
3070
+ const rv = new RunView();
3071
+ const tg = await Metadata.Provider.CreateTransactionGroup();
3072
+ const errors = [];
3073
+ for (const entityMapID of entityMapIDs) {
3074
+ const em = await md.GetEntityObject('MJ: Company Integration Entity Maps', sysUser);
3075
+ const loaded = await em.InnerLoad(CompositeKey.FromID(entityMapID));
3076
+ if (!loaded) {
3077
+ errors.push(`${entityMapID}: not found`);
3078
+ continue;
3079
+ }
3080
+ // Delete field maps
3081
+ const fmResult = await rv.RunView({
3082
+ EntityName: 'MJ: Company Integration Field Maps',
3083
+ ExtraFilter: `EntityMapID='${entityMapID}'`,
3084
+ ResultType: 'entity_object'
3085
+ }, sysUser);
3086
+ if (fmResult.Success) {
3087
+ for (const fm of fmResult.Results) {
3088
+ fm.TransactionGroup = tg;
3089
+ await fm.Delete();
3090
+ }
3091
+ }
3092
+ // Delete watermarks
3093
+ const wmResult = await rv.RunView({
3094
+ EntityName: 'MJ: Company Integration Sync Watermarks',
3095
+ ExtraFilter: `EntityMapID='${entityMapID}'`,
3096
+ ResultType: 'entity_object'
3097
+ }, sysUser);
3098
+ if (wmResult.Success) {
3099
+ for (const wm of wmResult.Results) {
3100
+ wm.TransactionGroup = tg;
3101
+ await wm.Delete();
3102
+ }
3103
+ }
3104
+ // Delete record maps for THIS entity only (filter by CI + EntityID)
3105
+ const rmResult = await rv.RunView({
3106
+ EntityName: 'MJ: Company Integration Record Maps',
3107
+ ExtraFilter: `CompanyIntegrationID='${em.CompanyIntegrationID}' AND EntityID='${em.EntityID}'`,
3108
+ ResultType: 'entity_object'
3109
+ }, sysUser);
3110
+ if (rmResult.Success) {
3111
+ for (const rm of rmResult.Results) {
3112
+ rm.TransactionGroup = tg;
3113
+ await rm.Delete();
3114
+ }
3115
+ }
3116
+ em.TransactionGroup = tg;
3117
+ await em.Delete();
3118
+ }
3119
+ const submitted = await tg.Submit();
3120
+ if (!submitted)
3121
+ return { Success: false, Message: 'Transaction failed — all deletes rolled back' };
3122
+ if (errors.length > 0)
3123
+ return { Success: false, Message: `Partial: ${errors.join('; ')}` };
3124
+ return { Success: true, Message: `Deleted ${entityMapIDs.length} entity maps (with field maps, watermarks, record maps)` };
3125
+ }
3126
+ catch (e) {
3127
+ LogError(`IntegrationDeleteEntityMaps error: ${e}`);
3128
+ return { Success: false, Message: this.formatError(e) };
3129
+ }
3130
+ }
3131
+ // ── OPERATION PROGRESS (polling) ──────────────────────────────────
3132
+ async IntegrationGetRSUProgress(ctx) {
3133
+ try {
3134
+ this.getAuthenticatedUser(ctx);
3135
+ const rsm = RuntimeSchemaManager.Instance;
3136
+ const rsuStatus = rsm.GetStatus();
3137
+ if (rsuStatus.Running) {
3138
+ return {
3139
+ Success: true,
3140
+ Message: 'RSU pipeline in progress',
3141
+ OperationType: 'rsu',
3142
+ IsRunning: true,
3143
+ RSURunning: true,
3144
+ RSUStep: rsuStatus.LastRunResult ?? 'running',
3145
+ StartedAt: rsuStatus.LastRunAt?.toISOString(),
3146
+ ElapsedMs: rsuStatus.LastRunAt ? Date.now() - rsuStatus.LastRunAt.getTime() : undefined,
3147
+ };
3148
+ }
3149
+ return { Success: true, Message: 'No RSU pipeline running', OperationType: 'none', IsRunning: false };
3150
+ }
3151
+ catch (e) {
3152
+ return { Success: false, Message: this.formatError(e) };
3153
+ }
3154
+ }
3155
+ async IntegrationGetSyncProgress(companyIntegrationID, ctx) {
3156
+ try {
3157
+ this.getAuthenticatedUser(ctx);
3158
+ const syncProgress = IntegrationEngine.GetSyncProgress(companyIntegrationID);
3159
+ if (syncProgress) {
3160
+ return {
3161
+ Success: true,
3162
+ Message: `Sync in progress (${syncProgress.TriggerType})`,
3163
+ OperationType: 'sync',
3164
+ IsRunning: true,
3165
+ CurrentEntity: syncProgress.CurrentEntity,
3166
+ EntityMapsTotal: syncProgress.EntityMapsTotal,
3167
+ EntityMapsCompleted: syncProgress.EntityMapsCompleted,
3168
+ RecordsProcessed: syncProgress.RecordsProcessed,
3169
+ RecordsCreated: syncProgress.RecordsCreated,
3170
+ RecordsUpdated: syncProgress.RecordsUpdated,
3171
+ RecordsErrored: syncProgress.RecordsErrored,
3172
+ StartedAt: syncProgress.StartedAt.toISOString(),
3173
+ ElapsedMs: Date.now() - syncProgress.StartedAt.getTime(),
3174
+ };
3175
+ }
3176
+ return { Success: true, Message: 'No sync running for this connector', OperationType: 'none', IsRunning: false };
3177
+ }
3178
+ catch (e) {
3179
+ return { Success: false, Message: this.formatError(e) };
3180
+ }
3181
+ }
3182
+ // ── STATUS & HISTORY (not polling — for page loads) ─────────────────
3183
+ async IntegrationGetStatus(companyIntegrationID, ctx) {
3184
+ try {
3185
+ const user = this.getAuthenticatedUser(ctx);
3186
+ const md = new Metadata();
3187
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
3188
+ const loaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
3189
+ if (!loaded)
3190
+ return { Success: false, Message: 'Not found' };
3191
+ const rv = new RunView();
3192
+ const [mapsResult, runsResult] = await rv.RunViews([
3193
+ {
3194
+ EntityName: 'MJ: Company Integration Entity Maps',
3195
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3196
+ ResultType: 'simple',
3197
+ Fields: ['ID', 'Status']
3198
+ },
3199
+ {
3200
+ EntityName: 'MJ: Company Integration Runs',
3201
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3202
+ OrderBy: 'StartedAt DESC',
3203
+ MaxRows: 1,
3204
+ ResultType: 'simple',
3205
+ Fields: ['ID', 'Status', 'StartedAt', 'EndedAt', 'TotalRecords']
3206
+ }
3207
+ ], user);
3208
+ const maps = mapsResult.Success ? mapsResult.Results : [];
3209
+ const lastRun = runsResult.Success && runsResult.Results.length > 0
3210
+ ? runsResult.Results[0]
3211
+ : null;
3212
+ // RSU pipeline state
3213
+ const rsuStatus = RuntimeSchemaManager.Instance.GetStatus();
3214
+ return {
3215
+ Success: true,
3216
+ Message: 'OK',
3217
+ IsActive: ci.IsActive ?? false,
3218
+ IntegrationName: ci.Integration,
3219
+ CompanyIntegrationID: companyIntegrationID,
3220
+ TotalEntityMaps: maps.length,
3221
+ ActiveEntityMaps: maps.filter(m => m.Status === 'Active').length,
3222
+ LastRunStatus: lastRun?.Status,
3223
+ LastRunStartedAt: lastRun?.StartedAt,
3224
+ LastRunEndedAt: lastRun?.EndedAt,
3225
+ ScheduleEnabled: ci.ScheduleEnabled,
3226
+ RSUEnabled: rsuStatus.Enabled,
3227
+ RSURunning: rsuStatus.Running,
3228
+ RSUOutOfSync: rsuStatus.OutOfSync,
3229
+ RSULastRunAt: rsuStatus.LastRunAt?.toISOString(),
3230
+ RSULastRunResult: rsuStatus.LastRunResult,
3231
+ };
3232
+ }
3233
+ catch (e) {
3234
+ LogError(`IntegrationGetStatus error: ${e}`);
3235
+ return { Success: false, Message: this.formatError(e) };
3236
+ }
3237
+ }
3238
+ async IntegrationGetSyncHistory(companyIntegrationID, limit, ctx) {
3239
+ try {
3240
+ const user = this.getAuthenticatedUser(ctx);
3241
+ const rv = new RunView();
3242
+ const result = await rv.RunView({
3243
+ EntityName: 'MJ: Company Integration Runs',
3244
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3245
+ OrderBy: 'StartedAt DESC',
3246
+ MaxRows: limit,
3247
+ ResultType: 'simple',
3248
+ Fields: ['ID', 'Status', 'StartedAt', 'EndedAt', 'TotalRecords', 'RunByUserID']
3249
+ }, user);
3250
+ if (!result.Success)
3251
+ return { Success: false, Message: result.ErrorMessage || 'Query failed' };
3252
+ return {
3253
+ Success: true,
3254
+ Message: `${result.Results.length} runs`,
3255
+ Runs: result.Results
353
3256
  };
354
3257
  }
3258
+ catch (e) {
3259
+ LogError(`IntegrationGetSyncHistory error: ${e}`);
3260
+ return { Success: false, Message: this.formatError(e) };
3261
+ }
355
3262
  }
3263
+ // ── CONNECTOR CAPABILITIES ──────────────────────────────────────────
356
3264
  /**
357
- * Returns the connector's default configuration for quick setup.
358
- * Not all connectors provide defaults returns Success: false if unavailable.
3265
+ * Returns the CRUD capability flags for the connector bound to a CompanyIntegration.
3266
+ * Use this to determine which operations (Create/Update/Delete/Search) are supported
3267
+ * before attempting point-action calls.
359
3268
  */
360
- async IntegrationGetDefaultConfig(companyIntegrationID, ctx) {
3269
+ async IntegrationGetConnectorCapabilities(companyIntegrationID, ctx) {
361
3270
  try {
362
3271
  const user = this.getAuthenticatedUser(ctx);
363
3272
  const { connector } = await this.resolveConnector(companyIntegrationID, user);
364
- const config = connector.GetDefaultConfiguration();
365
- if (!config) {
3273
+ return {
3274
+ Success: true,
3275
+ Message: 'OK',
3276
+ SupportsGet: connector.SupportsGet,
3277
+ SupportsCreate: connector.SupportsCreate,
3278
+ SupportsUpdate: connector.SupportsUpdate,
3279
+ SupportsDelete: connector.SupportsDelete,
3280
+ SupportsSearch: connector.SupportsSearch,
3281
+ };
3282
+ }
3283
+ catch (e) {
3284
+ LogError(`IntegrationGetConnectorCapabilities error: ${e}`);
3285
+ return { Success: false, Message: this.formatError(e) };
3286
+ }
3287
+ }
3288
+ // ── APPLY ALL BATCH ─────────────────────────────────────────────────
3289
+ /**
3290
+ * Batch "Apply All" for multiple connectors in a single RSU pipeline run.
3291
+ * For each connector: introspect → build schema → collect RSU input.
3292
+ * Then run ONE pipeline batch for all connectors.
3293
+ * Post-pipeline: create entity/field maps and start sync for each success.
3294
+ */
3295
+ async IntegrationApplyAllBatch(input, platform, skipGitCommit, skipRestart, ctx) {
3296
+ try {
3297
+ const user = this.getAuthenticatedUser(ctx);
3298
+ const validatedPlatform = this.validatePlatform(platform);
3299
+ // Phase 1: Build schema for each connector in parallel
3300
+ const buildResults = await Promise.allSettled(input.Connectors.map(async (connInput) => {
3301
+ const { connector, companyIntegration } = await this.resolveConnector(connInput.CompanyIntegrationID, user);
3302
+ const schemaName = this.deriveSchemaName(companyIntegration.Integration);
3303
+ // Resolve object IDs to names with per-object Fields
3304
+ const sourceSchema = await connector.IntrospectSchema.bind(connector)(companyIntegration, user);
3305
+ const objectIDs = connInput.SourceObjects.map(so => so.SourceObjectID);
3306
+ const resolvedNames = await this.resolveSourceObjectNames(objectIDs, undefined, sourceSchema, companyIntegration.IntegrationID, user);
3307
+ const fieldsByID = new Map(connInput.SourceObjects.map(so => [so.SourceObjectID, so.Fields]));
3308
+ const objects = resolvedNames.map((name, i) => {
3309
+ const obj = new SchemaPreviewObjectInput();
3310
+ obj.SourceObjectName = name;
3311
+ obj.SchemaName = schemaName;
3312
+ obj.TableName = name.replace(/[^A-Za-z0-9_]/g, '_');
3313
+ obj.EntityName = name.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/_/g, ' ');
3314
+ obj.Fields = fieldsByID.get(objectIDs[i]) ?? undefined;
3315
+ return obj;
3316
+ });
3317
+ const { schemaOutput, rsuInput } = await this.buildSchemaForConnector(connInput.CompanyIntegrationID, objects, validatedPlatform, user, skipGitCommit, skipRestart);
3318
+ // Build per-object field map for pending file
3319
+ const sourceObjectFields = {};
3320
+ for (const so of connInput.SourceObjects) {
3321
+ const resolvedName = resolvedNames[objectIDs.indexOf(so.SourceObjectID)];
3322
+ if (resolvedName)
3323
+ sourceObjectFields[resolvedName] = so.Fields ?? null;
3324
+ }
3325
+ // Inject post-restart pending work payload
3326
+ const { join } = await import('node:path');
3327
+ const rsuWorkDir = process.env.RSU_WORK_DIR || process.cwd();
3328
+ const pendingWorkDir = join(rsuWorkDir, '.rsu_pending');
3329
+ const pendingFilePath = join(pendingWorkDir, `${Date.now()}_${connInput.CompanyIntegrationID}.json`);
3330
+ const pendingPayload = {
3331
+ CompanyIntegrationID: connInput.CompanyIntegrationID,
3332
+ SourceObjectNames: resolvedNames,
3333
+ SourceObjectFields: sourceObjectFields,
3334
+ SchemaName: schemaName,
3335
+ CronExpression: connInput.CronExpression,
3336
+ ScheduleTimezone: connInput.ScheduleTimezone,
3337
+ StartSync: input.StartSync,
3338
+ FullSync: input.FullSync ?? false,
3339
+ SyncScope: input.SyncScope ?? 'created',
3340
+ CreatedAt: new Date().toISOString(),
3341
+ };
3342
+ rsuInput.PostRestartFiles = [
3343
+ { Path: pendingFilePath, Content: JSON.stringify(pendingPayload, null, 2) }
3344
+ ];
3345
+ return {
3346
+ connInput,
3347
+ connector,
3348
+ companyIntegration,
3349
+ schemaName,
3350
+ objects,
3351
+ schemaOutput,
3352
+ rsuInput,
3353
+ pendingFilePath,
3354
+ };
3355
+ }));
3356
+ // Separate successes and failures
3357
+ const successfulBuilds = [];
3358
+ const connectorResults = [];
3359
+ for (let i = 0; i < buildResults.length; i++) {
3360
+ const result = buildResults[i];
3361
+ const connInput = input.Connectors[i];
3362
+ if (result.status === 'fulfilled') {
3363
+ successfulBuilds.push(result.value);
3364
+ }
3365
+ else {
3366
+ LogError(`IntegrationApplyAllBatch: build failed for ${connInput.CompanyIntegrationID}: ${result.reason}`);
3367
+ connectorResults.push({
3368
+ CompanyIntegrationID: connInput.CompanyIntegrationID,
3369
+ IntegrationName: 'Unknown',
3370
+ Success: false,
3371
+ Message: result.reason instanceof Error ? result.reason.message : String(result.reason),
3372
+ });
3373
+ }
3374
+ }
3375
+ if (successfulBuilds.length === 0) {
366
3376
  return {
367
3377
  Success: false,
368
- Message: 'This connector does not provide a default configuration'
3378
+ Message: 'All connectors failed during schema build phase',
3379
+ ConnectorResults: connectorResults,
3380
+ SuccessCount: 0,
3381
+ FailureCount: connectorResults.length,
3382
+ };
3383
+ }
3384
+ // Phase 2: Run all successful RSU inputs through one pipeline batch
3385
+ const pipelineInputs = successfulBuilds.map(b => b.rsuInput);
3386
+ const rsm = RuntimeSchemaManager.Instance;
3387
+ const batchResult = await rsm.RunPipelineBatch(pipelineInputs);
3388
+ // Phase 3: Post-pipeline — create entity maps, field maps, schedules for each success
3389
+ for (let i = 0; i < successfulBuilds.length; i++) {
3390
+ const build = successfulBuilds[i];
3391
+ const pipelineResult = batchResult.Results[i];
3392
+ const integrationName = build.companyIntegration.Integration;
3393
+ if (!pipelineResult || !pipelineResult.Success) {
3394
+ connectorResults.push({
3395
+ CompanyIntegrationID: build.connInput.CompanyIntegrationID,
3396
+ IntegrationName: integrationName,
3397
+ Success: false,
3398
+ Message: pipelineResult?.ErrorMessage ?? 'Pipeline failed',
3399
+ Warnings: build.schemaOutput.Warnings.length > 0 ? build.schemaOutput.Warnings : undefined,
3400
+ });
3401
+ // Clean up pending file on failure
3402
+ try {
3403
+ (await import('node:fs')).unlinkSync(build.pendingFilePath);
3404
+ }
3405
+ catch { /* may not exist */ }
3406
+ continue;
3407
+ }
3408
+ const connResult = {
3409
+ CompanyIntegrationID: build.connInput.CompanyIntegrationID,
3410
+ IntegrationName: integrationName,
3411
+ Success: true,
3412
+ Message: `Applied ${build.objects.length} object(s)`,
3413
+ Warnings: build.schemaOutput.Warnings.length > 0 ? build.schemaOutput.Warnings : undefined,
369
3414
  };
3415
+ if (skipRestart) {
3416
+ // Entity maps, field maps, sync
3417
+ await Metadata.Provider.Refresh();
3418
+ const entityMapsCreated = await this.createEntityAndFieldMaps(build.connInput.CompanyIntegrationID, build.objects, build.connector, build.companyIntegration, build.schemaName, user);
3419
+ connResult.EntityMapsCreated = entityMapsCreated;
3420
+ const createdMapIDs = entityMapsCreated.map(em => em.EntityMapID).filter(Boolean);
3421
+ const scopedMapIDs = input.SyncScope === 'all' ? undefined : createdMapIDs;
3422
+ const syncRunID = input.StartSync !== false
3423
+ ? await this.startSyncAfterApply(build.connInput.CompanyIntegrationID, user, scopedMapIDs, input.FullSync)
3424
+ : null;
3425
+ if (syncRunID)
3426
+ connResult.SyncRunID = syncRunID;
3427
+ // Create schedule if CronExpression provided
3428
+ if (build.connInput.CronExpression) {
3429
+ const scheduleResult = await this.createScheduleForConnector(build.connInput.CompanyIntegrationID, integrationName, build.connInput.CronExpression, build.connInput.ScheduleTimezone, user);
3430
+ if (scheduleResult)
3431
+ connResult.ScheduledJobID = scheduleResult;
3432
+ }
3433
+ // Clean up pending file
3434
+ try {
3435
+ (await import('node:fs')).unlinkSync(build.pendingFilePath);
3436
+ }
3437
+ catch { /* already consumed */ }
3438
+ connResult.Message = `Applied ${build.objects.length} object(s) — ${entityMapsCreated.length} entity maps created${syncRunID ? ', sync started' : ''}`;
3439
+ }
3440
+ connectorResults.push(connResult);
370
3441
  }
3442
+ const pipelineSteps = batchResult.Results[0]?.Steps.map((s) => ({
3443
+ Name: s.Name, Status: s.Status, DurationMs: s.DurationMs, Message: s.Message,
3444
+ }));
3445
+ const successCount = connectorResults.filter(r => r.Success).length;
3446
+ const failureCount = connectorResults.filter(r => !r.Success).length;
371
3447
  return {
372
- Success: true,
373
- Message: `Default configuration with ${config.DefaultObjects.length} objects`,
374
- DefaultSchemaName: config.DefaultSchemaName,
375
- DefaultObjects: config.DefaultObjects.map(o => ({
376
- SourceObjectName: o.SourceObjectName,
377
- TargetTableName: o.TargetTableName,
378
- TargetEntityName: o.TargetEntityName,
379
- SyncEnabled: o.SyncEnabled,
380
- FieldMappings: o.FieldMappings.map(f => ({
381
- SourceFieldName: f.SourceFieldName,
382
- DestinationFieldName: f.DestinationFieldName,
383
- IsKeyField: f.IsKeyField
384
- }))
385
- }))
3448
+ Success: successCount > 0,
3449
+ Message: `Batch complete: ${successCount} succeeded, ${failureCount} failed`,
3450
+ ConnectorResults: connectorResults,
3451
+ PipelineSteps: pipelineSteps,
3452
+ GitCommitSuccess: batchResult.Results[0]?.GitCommitSuccess,
3453
+ APIRestarted: batchResult.Results[0]?.APIRestarted,
3454
+ SuccessCount: successCount,
3455
+ FailureCount: failureCount,
386
3456
  };
387
3457
  }
388
3458
  catch (e) {
389
- const error = e;
390
- LogError(`IntegrationGetDefaultConfig error: ${error}`);
3459
+ LogError(`IntegrationApplyAllBatch error: ${e}`);
391
3460
  return {
392
- Success: false,
393
- Message: `Error: ${error.message}`
3461
+ Success: false, Message: this.formatError(e),
3462
+ ConnectorResults: [], SuccessCount: 0, FailureCount: 0,
394
3463
  };
395
3464
  }
396
3465
  }
3466
+ /** Helper: creates a schedule for a connector, returns ScheduledJobID or null. */
3467
+ async createScheduleForConnector(companyIntegrationID, integrationName, cronExpression, timezone, user) {
3468
+ try {
3469
+ const md = new Metadata();
3470
+ const rv = new RunView();
3471
+ // Find IntegrationSync job type
3472
+ const jobTypeResult = await rv.RunView({
3473
+ EntityName: 'MJ: Scheduled Job Types',
3474
+ ExtraFilter: `DriverClass='IntegrationSyncScheduledJobDriver'`,
3475
+ MaxRows: 1,
3476
+ ResultType: 'simple',
3477
+ Fields: ['ID']
3478
+ }, user);
3479
+ if (!jobTypeResult.Success || jobTypeResult.Results.length === 0) {
3480
+ LogError('IntegrationApplyAllBatch: IntegrationSync scheduled job type not found');
3481
+ return null;
3482
+ }
3483
+ const jobTypeID = jobTypeResult.Results[0].ID;
3484
+ const job = await md.GetEntityObject('MJ: Scheduled Jobs', user);
3485
+ job.NewRecord();
3486
+ job.JobTypeID = jobTypeID;
3487
+ job.Name = `${integrationName} Sync`;
3488
+ job.CronExpression = cronExpression;
3489
+ job.Timezone = timezone || 'UTC';
3490
+ job.Status = 'Active';
3491
+ job.OwnerUserID = user.ID;
3492
+ job.Configuration = JSON.stringify({ CompanyIntegrationID: companyIntegrationID });
3493
+ if (!await job.Save())
3494
+ return null;
3495
+ // Link to CompanyIntegration
3496
+ const ci = await md.GetEntityObject('MJ: Company Integrations', user);
3497
+ const ciLoaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
3498
+ if (ciLoaded) {
3499
+ ci.ScheduleEnabled = true;
3500
+ ci.ScheduleType = 'Cron';
3501
+ ci.CronExpression = cronExpression;
3502
+ await ci.Save();
3503
+ }
3504
+ return job.ID;
3505
+ }
3506
+ catch (e) {
3507
+ LogError(`IntegrationApplyAllBatch: schedule creation failed: ${this.formatError(e)}`);
3508
+ return null;
3509
+ }
3510
+ }
3511
+ // ── DELETE CONNECTION ────────────────────────────────────────────────
397
3512
  /**
398
- * Generates a DDL preview for creating tables from discovered external objects.
399
- * Introspects the source schema and runs SchemaBuilder to produce migration SQL.
3513
+ * Hard-deletes a CompanyIntegration and all associated entity maps, field maps,
3514
+ * and scheduled jobs. Does NOT drop database tables (flagged for future).
400
3515
  */
401
- async IntegrationSchemaPreview(companyIntegrationID, objects, platform, ctx) {
3516
+ async IntegrationDeleteConnection(companyIntegrationID, deleteData, ctx) {
3517
+ try {
3518
+ this.getAuthenticatedUser(ctx); // verify caller is authenticated
3519
+ const sysUser = this.getSystemUser(); // use system user for cascade delete
3520
+ const md = new Metadata();
3521
+ const rv = new RunView();
3522
+ // Step 1: Load CompanyIntegration
3523
+ const ci = await md.GetEntityObject('MJ: Company Integrations', sysUser);
3524
+ const ciLoaded = await ci.InnerLoad(CompositeKey.FromID(companyIntegrationID));
3525
+ if (!ciLoaded)
3526
+ return { Success: false, Message: 'CompanyIntegration not found' };
3527
+ // Cascade delete in FK-safe order using TransactionGroup
3528
+ const tg = await Metadata.Provider.CreateTransactionGroup();
3529
+ let fieldMapsDeleted = 0;
3530
+ let entityMapsDeleted = 0;
3531
+ let schedulesDeleted = 0;
3532
+ // Step 2: Null out ScheduledJobRunID on CompanyIntegrationRuns (break FK before deleting job runs)
3533
+ const ciRunsResult = await rv.RunView({
3534
+ EntityName: 'MJ: Company Integration Runs',
3535
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3536
+ ResultType: 'entity_object'
3537
+ }, sysUser);
3538
+ if (ciRunsResult.Success) {
3539
+ for (const ciRun of ciRunsResult.Results) {
3540
+ if (ciRun.ScheduledJobRunID) {
3541
+ ciRun.ScheduledJobRunID = null;
3542
+ await ciRun.Save();
3543
+ }
3544
+ }
3545
+ }
3546
+ // Step 3: Delete scheduled job runs + jobs (reference CI via Configuration JSON)
3547
+ const jobsResult = await rv.RunView({
3548
+ EntityName: 'MJ: Scheduled Jobs',
3549
+ ExtraFilter: `Configuration LIKE '%${companyIntegrationID}%'`,
3550
+ ResultType: 'entity_object'
3551
+ }, sysUser);
3552
+ if (jobsResult.Success) {
3553
+ for (const job of jobsResult.Results) {
3554
+ try {
3555
+ const config = JSON.parse(job.Configuration || '{}');
3556
+ if (config.CompanyIntegrationID === companyIntegrationID) {
3557
+ const jobRunsResult = await rv.RunView({
3558
+ EntityName: 'MJ: Scheduled Job Runs',
3559
+ ExtraFilter: `ScheduledJobID='${job.ID}'`,
3560
+ ResultType: 'entity_object'
3561
+ }, sysUser);
3562
+ if (jobRunsResult.Success) {
3563
+ for (const jr of jobRunsResult.Results) {
3564
+ jr.TransactionGroup = tg;
3565
+ await jr.Delete();
3566
+ }
3567
+ }
3568
+ job.TransactionGroup = tg;
3569
+ await job.Delete();
3570
+ schedulesDeleted++;
3571
+ }
3572
+ }
3573
+ catch { /* skip invalid config */ }
3574
+ }
3575
+ }
3576
+ // Step 4: Delete run details then runs (reuse ciRunsResult from Step 2)
3577
+ if (ciRunsResult.Success) {
3578
+ for (const run of ciRunsResult.Results) {
3579
+ // Delete run details first
3580
+ const detailsResult = await rv.RunView({
3581
+ EntityName: 'MJ: Company Integration Run Details',
3582
+ ExtraFilter: `CompanyIntegrationRunID='${run.ID}'`,
3583
+ ResultType: 'entity_object'
3584
+ }, sysUser);
3585
+ if (detailsResult.Success) {
3586
+ for (const detail of detailsResult.Results) {
3587
+ detail.TransactionGroup = tg;
3588
+ await detail.Delete();
3589
+ }
3590
+ }
3591
+ run.TransactionGroup = tg;
3592
+ await run.Delete();
3593
+ }
3594
+ }
3595
+ // Step 4: Delete entity map children (field maps, watermarks, record maps)
3596
+ const entityMapsResult = await rv.RunView({
3597
+ EntityName: 'MJ: Company Integration Entity Maps',
3598
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3599
+ ResultType: 'entity_object'
3600
+ }, sysUser);
3601
+ const entityMaps = entityMapsResult.Success ? entityMapsResult.Results : [];
3602
+ for (const em of entityMaps) {
3603
+ const fmResult = await rv.RunView({
3604
+ EntityName: 'MJ: Company Integration Field Maps',
3605
+ ExtraFilter: `EntityMapID='${em.ID}'`,
3606
+ ResultType: 'entity_object'
3607
+ }, sysUser);
3608
+ if (fmResult.Success) {
3609
+ for (const fm of fmResult.Results) {
3610
+ fm.TransactionGroup = tg;
3611
+ if (await fm.Delete())
3612
+ fieldMapsDeleted++;
3613
+ }
3614
+ }
3615
+ const wmResult = await rv.RunView({
3616
+ EntityName: 'MJ: Company Integration Sync Watermarks',
3617
+ ExtraFilter: `EntityMapID='${em.ID}'`,
3618
+ ResultType: 'entity_object'
3619
+ }, sysUser);
3620
+ if (wmResult.Success) {
3621
+ for (const wm of wmResult.Results) {
3622
+ wm.TransactionGroup = tg;
3623
+ await wm.Delete();
3624
+ }
3625
+ }
3626
+ const rmResult = await rv.RunView({
3627
+ EntityName: 'MJ: Company Integration Record Maps',
3628
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3629
+ ResultType: 'entity_object'
3630
+ }, sysUser);
3631
+ if (rmResult.Success) {
3632
+ for (const rm of rmResult.Results) {
3633
+ rm.TransactionGroup = tg;
3634
+ await rm.Delete();
3635
+ }
3636
+ }
3637
+ }
3638
+ // Step 5: Delete entity maps
3639
+ for (const em of entityMaps) {
3640
+ em.TransactionGroup = tg;
3641
+ if (await em.Delete())
3642
+ entityMapsDeleted++;
3643
+ }
3644
+ // Step 6: Delete employee-company integration links
3645
+ const empResult = await rv.RunView({
3646
+ EntityName: 'MJ: Employee Company Integrations',
3647
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3648
+ ResultType: 'entity_object'
3649
+ }, sysUser);
3650
+ if (empResult.Success) {
3651
+ for (const emp of empResult.Results) {
3652
+ emp.TransactionGroup = tg;
3653
+ await emp.Delete();
3654
+ }
3655
+ }
3656
+ // Step 7: Delete the CompanyIntegration itself
3657
+ ci.TransactionGroup = tg;
3658
+ await ci.Delete();
3659
+ // Submit the transaction
3660
+ const submitted = await tg.Submit();
3661
+ if (!submitted) {
3662
+ return { Success: false, Message: 'Transaction failed — all deletes rolled back' };
3663
+ }
3664
+ if (deleteData) {
3665
+ LogError(`IntegrationDeleteConnection: deleteData=true requested but table deletion not yet implemented for ${companyIntegrationID}`);
3666
+ }
3667
+ return {
3668
+ Success: true,
3669
+ Message: `Deleted connection and all associated records`,
3670
+ EntityMapsDeleted: entityMapsDeleted,
3671
+ FieldMapsDeleted: fieldMapsDeleted,
3672
+ SchedulesDeleted: schedulesDeleted,
3673
+ };
3674
+ }
3675
+ catch (e) {
3676
+ LogError(`IntegrationDeleteConnection error: ${e}`);
3677
+ return { Success: false, Message: this.formatError(e) };
3678
+ }
3679
+ }
3680
+ // ── SCHEMA EVOLUTION ────────────────────────────────────────────────
3681
+ /**
3682
+ * Detects schema changes (new/modified columns) in the external system and
3683
+ * applies ALTER TABLE migrations via the RSU pipeline.
3684
+ * Compares the current connector introspection against existing MJ entities.
3685
+ */
3686
+ async IntegrationSchemaEvolution(companyIntegrationID, platform, skipGitCommit, skipRestart, ctx) {
402
3687
  try {
403
3688
  const user = this.getAuthenticatedUser(ctx);
3689
+ const validatedPlatform = this.validatePlatform(platform);
404
3690
  const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
405
- // Introspect schema from the external system
3691
+ const schemaName = this.deriveSchemaName(companyIntegration.Integration);
3692
+ const md = new Metadata();
3693
+ const rv = new RunView();
3694
+ // Step 1: Get existing entity maps for this CompanyIntegration
3695
+ const entityMapsResult = await rv.RunView({
3696
+ EntityName: 'MJ: Company Integration Entity Maps',
3697
+ ExtraFilter: `CompanyIntegrationID='${companyIntegrationID}'`,
3698
+ ResultType: 'simple',
3699
+ Fields: ['ID', 'ExternalObjectName', 'EntityID']
3700
+ }, user);
3701
+ if (!entityMapsResult.Success || entityMapsResult.Results.length === 0) {
3702
+ return {
3703
+ Success: false, Message: 'No entity maps found — nothing to evolve',
3704
+ HasChanges: false,
3705
+ };
3706
+ }
3707
+ const sourceObjectNames = entityMapsResult.Results.map(em => em.ExternalObjectName);
3708
+ const objects = this.buildObjectInputsFromNames(sourceObjectNames, schemaName);
3709
+ // Step 2: Build ExistingTables from Metadata.Entities matching the schema
3710
+ const existingTables = [];
3711
+ for (const obj of objects) {
3712
+ const entityInfo = md.Entities.find(e => e.SchemaName.toLowerCase() === schemaName.toLowerCase()
3713
+ && e.BaseTable.toLowerCase() === obj.TableName.toLowerCase());
3714
+ if (entityInfo) {
3715
+ existingTables.push({
3716
+ SchemaName: entityInfo.SchemaName,
3717
+ TableName: entityInfo.BaseTable,
3718
+ Columns: entityInfo.Fields.map(f => ({
3719
+ Name: f.Name,
3720
+ SqlType: f.SQLFullType || f.Type,
3721
+ IsNullable: f.AllowsNull,
3722
+ MaxLength: f.MaxLength > 0 ? f.MaxLength : null,
3723
+ Precision: f.Precision > 0 ? f.Precision : null,
3724
+ Scale: f.Scale > 0 ? f.Scale : null,
3725
+ })),
3726
+ });
3727
+ }
3728
+ }
3729
+ // Step 3: Introspect current schema from connector
406
3730
  const introspect = connector.IntrospectSchema.bind(connector);
407
3731
  const sourceSchema = await introspect(companyIntegration, user);
408
- // Filter to only requested objects
409
- const requestedNames = new Set(objects.map(o => o.SourceObjectName));
3732
+ // Normalize names to match source schema casing
3733
+ const nameMap = new Map(sourceSchema.Objects.map(o => [o.ExternalName.toLowerCase(), o.ExternalName]));
3734
+ const normalizedNames = sourceObjectNames.map(n => nameMap.get(n.toLowerCase()) ?? n);
3735
+ // Also normalize the objects array SourceObjectName
3736
+ for (const obj of objects) {
3737
+ const exact = nameMap.get(obj.SourceObjectName.toLowerCase());
3738
+ if (exact)
3739
+ obj.SourceObjectName = exact;
3740
+ }
3741
+ const requestedNames = new Set(normalizedNames);
410
3742
  const filteredSchema = {
411
3743
  Objects: sourceSchema.Objects.filter(o => requestedNames.has(o.ExternalName))
412
3744
  };
413
- // Build target configs from user input + source schema
414
- const targetConfigs = this.buildTargetConfigs(objects, filteredSchema, platform);
415
- // Run SchemaBuilder
416
- const input = {
3745
+ // Step 4: Build target configs and SchemaBuilder input with ExistingTables
3746
+ const targetConfigs = this.buildTargetConfigs(objects, filteredSchema, validatedPlatform, connector);
3747
+ const schemaInput = {
417
3748
  SourceSchema: filteredSchema,
418
3749
  TargetConfigs: targetConfigs,
419
- Platform: platform,
420
- MJVersion: '5.7.0',
3750
+ Platform: validatedPlatform,
3751
+ MJVersion: process.env.MJ_VERSION ?? '5.11.0',
421
3752
  SourceType: companyIntegration.Integration,
422
- AdditionalSchemaInfoPath: 'additionalSchemaInfo.json',
423
- MigrationsDir: 'migrations/v2',
424
- MetadataDir: 'metadata',
425
- ExistingTables: [],
3753
+ AdditionalSchemaInfoPath: process.env.RSU_ADDITIONAL_SCHEMA_INFO_PATH ?? 'additionalSchemaInfo.json',
3754
+ MigrationsDir: process.env.RSU_MIGRATIONS_PATH ?? 'migrations/rsu',
3755
+ MetadataDir: process.env.RSU_METADATA_DIR ?? 'metadata',
3756
+ ExistingTables: existingTables,
426
3757
  EntitySettingsForTargets: {}
427
3758
  };
3759
+ // Step 5: Build schema — SchemaBuilder handles evolution (ALTER TABLE) internally
428
3760
  const builder = new SchemaBuilder();
429
- const output = builder.BuildSchema(input);
430
- if (output.Errors.length > 0) {
3761
+ const schemaOutput = builder.BuildSchema(schemaInput);
3762
+ if (schemaOutput.Errors.length > 0) {
431
3763
  return {
432
3764
  Success: false,
433
- Message: `Schema generation failed: ${output.Errors.join('; ')}`,
434
- Warnings: output.Warnings
3765
+ Message: `Schema evolution failed: ${schemaOutput.Errors.join('; ')}`,
3766
+ HasChanges: false,
3767
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
435
3768
  };
436
3769
  }
437
- const allFiles = [
438
- ...output.MigrationFiles,
439
- ...(output.AdditionalSchemaInfoUpdate ? [output.AdditionalSchemaInfoUpdate] : []),
440
- ...output.MetadataFiles
441
- ];
3770
+ // Step 6: Check if any migration SQL was generated
3771
+ if (schemaOutput.MigrationFiles.length === 0) {
3772
+ return {
3773
+ Success: true,
3774
+ Message: 'No schema changes detected',
3775
+ HasChanges: false,
3776
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
3777
+ };
3778
+ }
3779
+ // Step 7: Count added/modified columns by re-diffing
3780
+ let addedColumns = 0;
3781
+ let modifiedColumns = 0;
3782
+ const evolution = new SchemaEvolution();
3783
+ for (const existing of existingTables) {
3784
+ const config = targetConfigs.find(c => c.SchemaName.toLowerCase() === existing.SchemaName.toLowerCase()
3785
+ && c.TableName.toLowerCase() === existing.TableName.toLowerCase());
3786
+ if (!config)
3787
+ continue;
3788
+ const sourceObj = filteredSchema.Objects.find(o => o.ExternalName.toLowerCase() === config.SourceObjectName.toLowerCase());
3789
+ if (!sourceObj)
3790
+ continue;
3791
+ const diff = evolution.DiffSchema(sourceObj, config, existing, validatedPlatform);
3792
+ addedColumns += diff.AddedColumns.length;
3793
+ modifiedColumns += diff.ModifiedColumns.length;
3794
+ }
3795
+ // Step 8: Run RSU pipeline
3796
+ const rsuInput = builder.BuildRSUInput(schemaOutput, schemaInput, {
3797
+ SkipGitCommit: skipGitCommit,
3798
+ SkipRestart: skipRestart,
3799
+ });
3800
+ const rsm = RuntimeSchemaManager.Instance;
3801
+ const batchResult = await rsm.RunPipelineBatch([rsuInput]);
3802
+ const pipelineResult = batchResult.Results[0];
3803
+ const pipelineSteps = pipelineResult?.Steps.map((s) => ({
3804
+ Name: s.Name, Status: s.Status, DurationMs: s.DurationMs, Message: s.Message,
3805
+ }));
442
3806
  return {
443
- Success: true,
444
- Message: `Generated ${allFiles.length} files`,
445
- Files: allFiles.map(f => ({
446
- FilePath: f.FilePath,
447
- Content: f.Content,
448
- Description: f.Description
449
- })),
450
- Warnings: output.Warnings.length > 0 ? output.Warnings : undefined
3807
+ Success: pipelineResult?.Success ?? false,
3808
+ Message: pipelineResult?.Success
3809
+ ? `Schema evolution applied — ${addedColumns} column(s) added, ${modifiedColumns} column(s) modified`
3810
+ : `Pipeline failed: ${pipelineResult?.ErrorMessage ?? 'unknown error'}`,
3811
+ HasChanges: true,
3812
+ AddedColumns: addedColumns,
3813
+ ModifiedColumns: modifiedColumns,
3814
+ Steps: pipelineSteps,
3815
+ GitCommitSuccess: pipelineResult?.GitCommitSuccess,
3816
+ APIRestarted: pipelineResult?.APIRestarted,
3817
+ Warnings: schemaOutput.Warnings.length > 0 ? schemaOutput.Warnings : undefined,
451
3818
  };
452
3819
  }
453
3820
  catch (e) {
454
- const error = e;
455
- LogError(`IntegrationSchemaPreview error: ${error}`);
456
- return {
457
- Success: false,
458
- Message: `Error: ${error.message}`
459
- };
3821
+ LogError(`IntegrationSchemaEvolution error: ${e}`);
3822
+ return { Success: false, Message: this.formatError(e), HasChanges: false };
460
3823
  }
461
3824
  }
462
- /**
463
- * Fetches a small sample of records from an external object for preview purposes.
464
- * Uses the connector's FetchChanges with a small batch size and no watermark.
465
- */
466
- async IntegrationPreviewData(companyIntegrationID, objectName, limit, ctx) {
3825
+ // ── WEBHOOK HELPER ──────────────────────────────────────────────────
3826
+ async sendWebhook(url, payload) {
467
3827
  try {
468
- const user = this.getAuthenticatedUser(ctx);
469
- const { connector, companyIntegration } = await this.resolveConnector(companyIntegrationID, user);
470
- const fetchChanges = connector.FetchChanges.bind(connector);
471
- const result = await fetchChanges({
472
- CompanyIntegration: companyIntegration,
473
- ObjectName: objectName,
474
- WatermarkValue: null,
475
- BatchSize: Math.min(limit, 10),
476
- ContextUser: user
3828
+ const response = await fetch(url, {
3829
+ method: 'POST',
3830
+ headers: { 'Content-Type': 'application/json' },
3831
+ body: JSON.stringify(payload)
477
3832
  });
478
- return {
479
- Success: true,
480
- Message: `Fetched ${result.Records.length} preview records`,
481
- Records: result.Records.map(r => ({
482
- Data: JSON.stringify(r.Fields)
483
- }))
484
- };
3833
+ if (!response.ok) {
3834
+ console.error(`[Integration] Webhook POST to ${url} returned ${response.status}`);
3835
+ }
485
3836
  }
486
3837
  catch (e) {
487
- const error = e;
488
- LogError(`IntegrationPreviewData error: ${error}`);
489
- return {
490
- Success: false,
491
- Message: `Error: ${error.message}`
492
- };
493
- }
494
- }
495
- // --- Private Helpers ---
496
- buildTargetConfigs(objects, sourceSchema, platform) {
497
- const mapper = new TypeMapper();
498
- return objects.map(obj => {
499
- const sourceObj = sourceSchema.Objects.find(o => o.ExternalName === obj.SourceObjectName);
500
- const columns = (sourceObj?.Fields ?? []).map(f => ({
501
- SourceFieldName: f.Name,
502
- TargetColumnName: f.Name.replace(/[^A-Za-z0-9_]/g, '_'),
503
- TargetSqlType: mapper.MapSourceType(f.SourceType, platform, f),
504
- IsNullable: !f.IsRequired,
505
- MaxLength: f.MaxLength,
506
- Precision: f.Precision,
507
- Scale: f.Scale,
508
- DefaultValue: f.DefaultValue
509
- }));
510
- const primaryKeyFields = (sourceObj?.Fields ?? [])
511
- .filter(f => f.IsPrimaryKey)
512
- .map(f => f.Name.replace(/[^A-Za-z0-9_]/g, '_'));
513
- return {
514
- SourceObjectName: obj.SourceObjectName,
515
- SchemaName: obj.SchemaName,
516
- TableName: obj.TableName,
517
- EntityName: obj.EntityName,
518
- Columns: columns,
519
- PrimaryKeyFields: primaryKeyFields.length > 0 ? primaryKeyFields : ['ID'],
520
- SoftForeignKeys: []
521
- };
522
- });
523
- }
524
- getAuthenticatedUser(ctx) {
525
- const user = ctx.userPayload.userRecord;
526
- if (!user) {
527
- throw new Error("User is not authenticated");
528
- }
529
- return user;
530
- }
531
- /**
532
- * Loads the CompanyIntegration + its parent Integration, then resolves the
533
- * appropriate connector via ConnectorFactory.
534
- *
535
- * NOTE: Entity objects loaded here come from the MJServer's copy of core-entities.
536
- * The integration-engine package may resolve its own copy of core-entities, causing
537
- * TypeScript nominal type mismatches. At runtime the objects are structurally identical,
538
- * so we cast through `unknown` at the boundary calls.
539
- */
540
- async resolveConnector(companyIntegrationID, contextUser) {
541
- const md = new Metadata();
542
- // Load the CompanyIntegration record
543
- const companyIntegration = await md.GetEntityObject('MJ: Company Integrations', contextUser);
544
- const loaded = await companyIntegration.Load(companyIntegrationID);
545
- if (!loaded) {
546
- throw new Error(`CompanyIntegration with ID "${companyIntegrationID}" not found`);
547
- }
548
- // Load the parent Integration record
549
- const integration = await md.GetEntityObject('MJ: Integrations', contextUser);
550
- const integrationLoaded = await integration.Load(companyIntegration.IntegrationID);
551
- if (!integrationLoaded) {
552
- throw new Error(`Integration with ID "${companyIntegration.IntegrationID}" not found`);
3838
+ console.error(`[Integration] Webhook POST to ${url} failed:`, e);
553
3839
  }
554
- // ConnectorFactory expects its own copy of core-entities types — cast through unknown
555
- const connector = ConnectorFactory.Resolve(integration);
556
- return { connector, companyIntegration };
557
- }
558
- handleDiscoveryError(e) {
559
- const error = e;
560
- LogError(`Integration discovery error: ${error}`);
561
- return {
562
- Success: false,
563
- Message: `Error: ${error.message}`
564
- };
565
3840
  }
566
3841
  };
3842
+ __decorate([
3843
+ Query(() => DiscoverConnectorsOutput),
3844
+ __param(0, Arg("companyID", { nullable: true })),
3845
+ __param(1, Ctx()),
3846
+ __metadata("design:type", Function),
3847
+ __metadata("design:paramtypes", [String, Object]),
3848
+ __metadata("design:returntype", Promise)
3849
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationDiscoverConnectors", null);
567
3850
  __decorate([
568
3851
  Query(() => DiscoverObjectsOutput),
569
3852
  __param(0, Arg("companyIntegrationID")),
@@ -617,7 +3900,263 @@ __decorate([
617
3900
  __metadata("design:paramtypes", [String, String, Number, Object]),
618
3901
  __metadata("design:returntype", Promise)
619
3902
  ], IntegrationDiscoveryResolver.prototype, "IntegrationPreviewData", null);
620
- IntegrationDiscoveryResolver = __decorate([
3903
+ __decorate([
3904
+ Query(() => ListConnectionsOutput),
3905
+ __param(0, Arg("activeOnly", { defaultValue: true })),
3906
+ __param(1, Arg("companyID", { nullable: true })),
3907
+ __param(2, Ctx()),
3908
+ __metadata("design:type", Function),
3909
+ __metadata("design:paramtypes", [Boolean, String, Object]),
3910
+ __metadata("design:returntype", Promise)
3911
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationListConnections", null);
3912
+ __decorate([
3913
+ Mutation(() => CreateConnectionOutput),
3914
+ __param(0, Arg("input")),
3915
+ __param(1, Arg("testConnection", () => Boolean, { defaultValue: false })),
3916
+ __param(2, Ctx()),
3917
+ __metadata("design:type", Function),
3918
+ __metadata("design:paramtypes", [CreateConnectionInput, Boolean, Object]),
3919
+ __metadata("design:returntype", Promise)
3920
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationCreateConnection", null);
3921
+ __decorate([
3922
+ Mutation(() => MutationResultOutput),
3923
+ __param(0, Arg("companyIntegrationID")),
3924
+ __param(1, Arg("credentialValues", { nullable: true })),
3925
+ __param(2, Arg("configuration", { nullable: true })),
3926
+ __param(3, Arg("externalSystemID", { nullable: true })),
3927
+ __param(4, Arg("testConnection", () => Boolean, { defaultValue: false })),
3928
+ __param(5, Ctx()),
3929
+ __metadata("design:type", Function),
3930
+ __metadata("design:paramtypes", [String, String, String, String, Boolean, Object]),
3931
+ __metadata("design:returntype", Promise)
3932
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationUpdateConnection", null);
3933
+ __decorate([
3934
+ Mutation(() => MutationResultOutput),
3935
+ __param(0, Arg("companyIntegrationID")),
3936
+ __param(1, Ctx()),
3937
+ __metadata("design:type", Function),
3938
+ __metadata("design:paramtypes", [String, Object]),
3939
+ __metadata("design:returntype", Promise)
3940
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationDeactivateConnection", null);
3941
+ __decorate([
3942
+ Mutation(() => MutationResultOutput),
3943
+ __param(0, Arg("companyIntegrationID")),
3944
+ __param(1, Ctx()),
3945
+ __metadata("design:type", Function),
3946
+ __metadata("design:paramtypes", [String, Object]),
3947
+ __metadata("design:returntype", Promise)
3948
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationReactivateConnection", null);
3949
+ __decorate([
3950
+ Mutation(() => CreateEntityMapsOutput),
3951
+ __param(0, Arg("companyIntegrationID")),
3952
+ __param(1, Arg("entityMaps", () => [EntityMapInput])),
3953
+ __param(2, Ctx()),
3954
+ __metadata("design:type", Function),
3955
+ __metadata("design:paramtypes", [String, Array, Object]),
3956
+ __metadata("design:returntype", Promise)
3957
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationCreateEntityMaps", null);
3958
+ __decorate([
3959
+ Mutation(() => ApplySchemaOutput),
3960
+ __param(0, Arg("companyIntegrationID")),
3961
+ __param(1, Arg("objects", () => [SchemaPreviewObjectInput])),
3962
+ __param(2, Arg("platform", { defaultValue: "sqlserver" })),
3963
+ __param(3, Arg("skipGitCommit", { defaultValue: false })),
3964
+ __param(4, Arg("skipRestart", { defaultValue: false })),
3965
+ __param(5, Ctx()),
3966
+ __metadata("design:type", Function),
3967
+ __metadata("design:paramtypes", [String, Array, String, Boolean, Boolean, Object]),
3968
+ __metadata("design:returntype", Promise)
3969
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationApplySchema", null);
3970
+ __decorate([
3971
+ Mutation(() => ApplySchemaBatchOutput),
3972
+ __param(0, Arg("items", () => [ApplySchemaBatchItemInput])),
3973
+ __param(1, Arg("platform", { defaultValue: "sqlserver" })),
3974
+ __param(2, Arg("skipGitCommit", { defaultValue: false })),
3975
+ __param(3, Arg("skipRestart", { defaultValue: false })),
3976
+ __param(4, Ctx()),
3977
+ __metadata("design:type", Function),
3978
+ __metadata("design:paramtypes", [Array, String, Boolean, Boolean, Object]),
3979
+ __metadata("design:returntype", Promise)
3980
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationApplySchemaBatch", null);
3981
+ __decorate([
3982
+ Mutation(() => ApplyAllOutput),
3983
+ __param(0, Arg("input")),
3984
+ __param(1, Arg("platform", { defaultValue: "sqlserver" })),
3985
+ __param(2, Arg("skipGitCommit", { defaultValue: false })),
3986
+ __param(3, Arg("skipRestart", { defaultValue: false })),
3987
+ __param(4, Ctx()),
3988
+ __metadata("design:type", Function),
3989
+ __metadata("design:paramtypes", [ApplyAllInput, String, Boolean, Boolean, Object]),
3990
+ __metadata("design:returntype", Promise)
3991
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationApplyAll", null);
3992
+ __decorate([
3993
+ Mutation(() => StartSyncOutput),
3994
+ __param(0, Arg("companyIntegrationID")),
3995
+ __param(1, Arg("webhookURL", { nullable: true })),
3996
+ __param(2, Arg("fullSync", () => Boolean, { defaultValue: false, description: 'If true, ignores watermarks and re-fetches all records from the source' })),
3997
+ __param(3, Arg("entityMapIDs", () => [String], { nullable: true, description: 'Optional: sync only these entity maps. If omitted, syncs all maps for the connector.' })),
3998
+ __param(4, Ctx()),
3999
+ __metadata("design:type", Function),
4000
+ __metadata("design:paramtypes", [String, String, Boolean, Array, Object]),
4001
+ __metadata("design:returntype", Promise)
4002
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationStartSync", null);
4003
+ __decorate([
4004
+ Mutation(() => MutationResultOutput),
4005
+ __param(0, Arg("companyIntegrationID")),
4006
+ __param(1, Ctx()),
4007
+ __metadata("design:type", Function),
4008
+ __metadata("design:paramtypes", [String, Object]),
4009
+ __metadata("design:returntype", Promise)
4010
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationCancelSync", null);
4011
+ __decorate([
4012
+ Mutation(() => CreateScheduleOutput),
4013
+ __param(0, Arg("input")),
4014
+ __param(1, Ctx()),
4015
+ __metadata("design:type", Function),
4016
+ __metadata("design:paramtypes", [CreateScheduleInput, Object]),
4017
+ __metadata("design:returntype", Promise)
4018
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationCreateSchedule", null);
4019
+ __decorate([
4020
+ Mutation(() => MutationResultOutput),
4021
+ __param(0, Arg("scheduledJobID")),
4022
+ __param(1, Arg("cronExpression", { nullable: true })),
4023
+ __param(2, Arg("timezone", { nullable: true })),
4024
+ __param(3, Arg("name", { nullable: true })),
4025
+ __param(4, Ctx()),
4026
+ __metadata("design:type", Function),
4027
+ __metadata("design:paramtypes", [String, String, String, String, Object]),
4028
+ __metadata("design:returntype", Promise)
4029
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationUpdateSchedule", null);
4030
+ __decorate([
4031
+ Mutation(() => MutationResultOutput),
4032
+ __param(0, Arg("scheduledJobID")),
4033
+ __param(1, Arg("enabled", () => Boolean)),
4034
+ __param(2, Ctx()),
4035
+ __metadata("design:type", Function),
4036
+ __metadata("design:paramtypes", [String, Boolean, Object]),
4037
+ __metadata("design:returntype", Promise)
4038
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationToggleSchedule", null);
4039
+ __decorate([
4040
+ Mutation(() => MutationResultOutput),
4041
+ __param(0, Arg("scheduledJobID")),
4042
+ __param(1, Arg("companyIntegrationID", { nullable: true })),
4043
+ __param(2, Ctx()),
4044
+ __metadata("design:type", Function),
4045
+ __metadata("design:paramtypes", [String, String, Object]),
4046
+ __metadata("design:returntype", Promise)
4047
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationDeleteSchedule", null);
4048
+ __decorate([
4049
+ Query(() => ListSchedulesOutput),
4050
+ __param(0, Arg("companyIntegrationID")),
4051
+ __param(1, Ctx()),
4052
+ __metadata("design:type", Function),
4053
+ __metadata("design:paramtypes", [String, Object]),
4054
+ __metadata("design:returntype", Promise)
4055
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationListSchedules", null);
4056
+ __decorate([
4057
+ Query(() => ListEntityMapsOutput),
4058
+ __param(0, Arg("companyIntegrationID")),
4059
+ __param(1, Ctx()),
4060
+ __metadata("design:type", Function),
4061
+ __metadata("design:paramtypes", [String, Object]),
4062
+ __metadata("design:returntype", Promise)
4063
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationListEntityMaps", null);
4064
+ __decorate([
4065
+ Query(() => ListFieldMapsOutput),
4066
+ __param(0, Arg("entityMapID")),
4067
+ __param(1, Ctx()),
4068
+ __metadata("design:type", Function),
4069
+ __metadata("design:paramtypes", [String, Object]),
4070
+ __metadata("design:returntype", Promise)
4071
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationListFieldMaps", null);
4072
+ __decorate([
4073
+ Mutation(() => MutationResultOutput),
4074
+ __param(0, Arg("updates", () => [EntityMapUpdateInput])),
4075
+ __param(1, Ctx()),
4076
+ __metadata("design:type", Function),
4077
+ __metadata("design:paramtypes", [Array, Object]),
4078
+ __metadata("design:returntype", Promise)
4079
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationUpdateEntityMaps", null);
4080
+ __decorate([
4081
+ Mutation(() => MutationResultOutput),
4082
+ __param(0, Arg("entityMapIDs", () => [String])),
4083
+ __param(1, Ctx()),
4084
+ __metadata("design:type", Function),
4085
+ __metadata("design:paramtypes", [Array, Object]),
4086
+ __metadata("design:returntype", Promise)
4087
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationDeleteEntityMaps", null);
4088
+ __decorate([
4089
+ Query(() => OperationProgressOutput),
4090
+ __param(0, Ctx()),
4091
+ __metadata("design:type", Function),
4092
+ __metadata("design:paramtypes", [Object]),
4093
+ __metadata("design:returntype", Promise)
4094
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationGetRSUProgress", null);
4095
+ __decorate([
4096
+ Query(() => OperationProgressOutput),
4097
+ __param(0, Arg("companyIntegrationID")),
4098
+ __param(1, Ctx()),
4099
+ __metadata("design:type", Function),
4100
+ __metadata("design:paramtypes", [String, Object]),
4101
+ __metadata("design:returntype", Promise)
4102
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationGetSyncProgress", null);
4103
+ __decorate([
4104
+ Query(() => IntegrationStatusOutput),
4105
+ __param(0, Arg("companyIntegrationID")),
4106
+ __param(1, Ctx()),
4107
+ __metadata("design:type", Function),
4108
+ __metadata("design:paramtypes", [String, Object]),
4109
+ __metadata("design:returntype", Promise)
4110
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationGetStatus", null);
4111
+ __decorate([
4112
+ Query(() => SyncHistoryOutput),
4113
+ __param(0, Arg("companyIntegrationID")),
4114
+ __param(1, Arg("limit", { defaultValue: 20 })),
4115
+ __param(2, Ctx()),
4116
+ __metadata("design:type", Function),
4117
+ __metadata("design:paramtypes", [String, Number, Object]),
4118
+ __metadata("design:returntype", Promise)
4119
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationGetSyncHistory", null);
4120
+ __decorate([
4121
+ Query(() => ConnectorCapabilitiesOutput),
4122
+ __param(0, Arg("companyIntegrationID")),
4123
+ __param(1, Ctx()),
4124
+ __metadata("design:type", Function),
4125
+ __metadata("design:paramtypes", [String, Object]),
4126
+ __metadata("design:returntype", Promise)
4127
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationGetConnectorCapabilities", null);
4128
+ __decorate([
4129
+ Mutation(() => ApplyAllBatchOutput),
4130
+ __param(0, Arg("input")),
4131
+ __param(1, Arg("platform", { defaultValue: "sqlserver" })),
4132
+ __param(2, Arg("skipGitCommit", { defaultValue: false })),
4133
+ __param(3, Arg("skipRestart", { defaultValue: false })),
4134
+ __param(4, Ctx()),
4135
+ __metadata("design:type", Function),
4136
+ __metadata("design:paramtypes", [ApplyAllBatchInput, String, Boolean, Boolean, Object]),
4137
+ __metadata("design:returntype", Promise)
4138
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationApplyAllBatch", null);
4139
+ __decorate([
4140
+ Mutation(() => DeleteConnectionOutput),
4141
+ __param(0, Arg("companyIntegrationID")),
4142
+ __param(1, Arg("deleteData", { defaultValue: false })),
4143
+ __param(2, Ctx()),
4144
+ __metadata("design:type", Function),
4145
+ __metadata("design:paramtypes", [String, Boolean, Object]),
4146
+ __metadata("design:returntype", Promise)
4147
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationDeleteConnection", null);
4148
+ __decorate([
4149
+ Mutation(() => SchemaEvolutionOutput),
4150
+ __param(0, Arg("companyIntegrationID")),
4151
+ __param(1, Arg("platform", { defaultValue: "sqlserver" })),
4152
+ __param(2, Arg("skipGitCommit", { defaultValue: false })),
4153
+ __param(3, Arg("skipRestart", { defaultValue: false })),
4154
+ __param(4, Ctx()),
4155
+ __metadata("design:type", Function),
4156
+ __metadata("design:paramtypes", [String, String, Boolean, Boolean, Object]),
4157
+ __metadata("design:returntype", Promise)
4158
+ ], IntegrationDiscoveryResolver.prototype, "IntegrationSchemaEvolution", null);
4159
+ IntegrationDiscoveryResolver = IntegrationDiscoveryResolver_1 = __decorate([
621
4160
  Resolver()
622
4161
  ], IntegrationDiscoveryResolver);
623
4162
  export { IntegrationDiscoveryResolver };