@memberjunction/server 5.16.0 → 5.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -3
- package/dist/config.d.ts +51 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -0
- package/dist/config.js.map +1 -1
- package/dist/generated/generated.d.ts +46 -46
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +332 -332
- package/dist/generated/generated.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +311 -1
- package/dist/index.js.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts +484 -0
- package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
- package/dist/resolvers/IntegrationDiscoveryResolver.js +3867 -328
- package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
- package/dist/resolvers/RSUResolver.d.ts +89 -0
- package/dist/resolvers/RSUResolver.d.ts.map +1 -0
- package/dist/resolvers/RSUResolver.js +424 -0
- package/dist/resolvers/RSUResolver.js.map +1 -0
- package/package.json +63 -61
- package/src/config.ts +9 -0
- package/src/generated/generated.ts +269 -269
- package/src/index.ts +350 -1
- package/src/resolvers/IntegrationDiscoveryResolver.ts +2970 -39
- package/src/resolvers/RSUResolver.ts +351 -0
|
@@ -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
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
],
|
|
28
|
+
], RSUStepOutput.prototype, "Name", void 0);
|
|
25
29
|
__decorate([
|
|
26
30
|
Field(),
|
|
27
31
|
__metadata("design:type", String)
|
|
28
|
-
],
|
|
32
|
+
], RSUStepOutput.prototype, "Status", void 0);
|
|
29
33
|
__decorate([
|
|
30
34
|
Field(),
|
|
31
|
-
__metadata("design:type",
|
|
32
|
-
],
|
|
35
|
+
__metadata("design:type", Number)
|
|
36
|
+
], RSUStepOutput.prototype, "DurationMs", void 0);
|
|
33
37
|
__decorate([
|
|
34
38
|
Field(),
|
|
35
|
-
__metadata("design:type",
|
|
36
|
-
],
|
|
37
|
-
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], RSUStepOutput.prototype, "Message", void 0);
|
|
41
|
+
RSUStepOutput = __decorate([
|
|
38
42
|
ObjectType()
|
|
39
|
-
],
|
|
40
|
-
let
|
|
43
|
+
], RSUStepOutput);
|
|
44
|
+
let ApplySchemaOutput = class ApplySchemaOutput {
|
|
41
45
|
};
|
|
42
46
|
__decorate([
|
|
43
47
|
Field(),
|
|
44
48
|
__metadata("design:type", Boolean)
|
|
45
|
-
],
|
|
49
|
+
], ApplySchemaOutput.prototype, "Success", void 0);
|
|
46
50
|
__decorate([
|
|
47
51
|
Field(),
|
|
48
52
|
__metadata("design:type", String)
|
|
49
|
-
],
|
|
53
|
+
], ApplySchemaOutput.prototype, "Message", void 0);
|
|
50
54
|
__decorate([
|
|
51
|
-
Field(() => [
|
|
55
|
+
Field(() => [RSUStepOutput], { nullable: true }),
|
|
52
56
|
__metadata("design:type", Array)
|
|
53
|
-
],
|
|
54
|
-
|
|
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
|
-
],
|
|
57
|
-
let
|
|
80
|
+
], ApplySchemaOutput);
|
|
81
|
+
let ApplySchemaBatchItemInput = class ApplySchemaBatchItemInput {
|
|
58
82
|
};
|
|
59
83
|
__decorate([
|
|
60
84
|
Field(),
|
|
61
85
|
__metadata("design:type", String)
|
|
62
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
113
|
+
], ApplyAllInput.prototype, "CompanyIntegrationID", void 0);
|
|
71
114
|
__decorate([
|
|
72
|
-
Field(),
|
|
73
|
-
__metadata("design:type",
|
|
74
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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",
|
|
91
|
-
],
|
|
145
|
+
__metadata("design:type", String)
|
|
146
|
+
], ApplyAllEntityMapCreated.prototype, "SourceObjectName", void 0);
|
|
92
147
|
__decorate([
|
|
93
148
|
Field(),
|
|
94
149
|
__metadata("design:type", String)
|
|
95
|
-
],
|
|
150
|
+
], ApplyAllEntityMapCreated.prototype, "EntityName", void 0);
|
|
96
151
|
__decorate([
|
|
97
|
-
Field(
|
|
98
|
-
__metadata("design:type",
|
|
99
|
-
],
|
|
100
|
-
|
|
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
|
-
],
|
|
103
|
-
let
|
|
161
|
+
], ApplyAllEntityMapCreated);
|
|
162
|
+
let ApplyAllOutput = class ApplyAllOutput {
|
|
104
163
|
};
|
|
105
164
|
__decorate([
|
|
106
165
|
Field(),
|
|
107
166
|
__metadata("design:type", Boolean)
|
|
108
|
-
],
|
|
167
|
+
], ApplyAllOutput.prototype, "Success", void 0);
|
|
109
168
|
__decorate([
|
|
110
169
|
Field(),
|
|
111
170
|
__metadata("design:type", String)
|
|
112
|
-
],
|
|
171
|
+
], ApplyAllOutput.prototype, "Message", void 0);
|
|
113
172
|
__decorate([
|
|
114
|
-
Field(() =>
|
|
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
|
-
],
|
|
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(
|
|
185
|
+
Field({ nullable: true }),
|
|
125
186
|
__metadata("design:type", String)
|
|
126
|
-
],
|
|
127
|
-
|
|
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
|
-
],
|
|
130
|
-
let
|
|
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
|
-
],
|
|
212
|
+
], ApplySchemaBatchItemOutput.prototype, "Success", void 0);
|
|
136
213
|
__decorate([
|
|
137
214
|
Field(),
|
|
138
215
|
__metadata("design:type", String)
|
|
139
|
-
],
|
|
216
|
+
], ApplySchemaBatchItemOutput.prototype, "Message", void 0);
|
|
140
217
|
__decorate([
|
|
141
|
-
Field(() => [
|
|
218
|
+
Field(() => [String], { nullable: true }),
|
|
142
219
|
__metadata("design:type", Array)
|
|
143
|
-
],
|
|
144
|
-
|
|
220
|
+
], ApplySchemaBatchItemOutput.prototype, "Warnings", void 0);
|
|
221
|
+
ApplySchemaBatchItemOutput = __decorate([
|
|
145
222
|
ObjectType()
|
|
146
|
-
],
|
|
147
|
-
|
|
148
|
-
let SchemaPreviewObjectInput = class SchemaPreviewObjectInput {
|
|
223
|
+
], ApplySchemaBatchItemOutput);
|
|
224
|
+
let ApplySchemaBatchOutput = class ApplySchemaBatchOutput {
|
|
149
225
|
};
|
|
150
226
|
__decorate([
|
|
151
227
|
Field(),
|
|
152
|
-
__metadata("design:type",
|
|
153
|
-
],
|
|
228
|
+
__metadata("design:type", Boolean)
|
|
229
|
+
], ApplySchemaBatchOutput.prototype, "Success", void 0);
|
|
154
230
|
__decorate([
|
|
155
231
|
Field(),
|
|
156
232
|
__metadata("design:type", String)
|
|
157
|
-
],
|
|
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
|
-
],
|
|
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
|
-
],
|
|
166
|
-
|
|
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
|
-
],
|
|
169
|
-
let
|
|
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
|
-
],
|
|
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
|
-
],
|
|
301
|
+
], ApplyAllBatchConnectorResult.prototype, "CompanyIntegrationID", void 0);
|
|
179
302
|
__decorate([
|
|
180
303
|
Field(),
|
|
181
304
|
__metadata("design:type", String)
|
|
182
|
-
],
|
|
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
|
-
],
|
|
309
|
+
], ApplyAllBatchConnectorResult.prototype, "Success", void 0);
|
|
192
310
|
__decorate([
|
|
193
311
|
Field(),
|
|
194
312
|
__metadata("design:type", String)
|
|
195
|
-
],
|
|
313
|
+
], ApplyAllBatchConnectorResult.prototype, "Message", void 0);
|
|
196
314
|
__decorate([
|
|
197
|
-
Field(() => [
|
|
315
|
+
Field(() => [ApplyAllEntityMapCreated], { nullable: true }),
|
|
198
316
|
__metadata("design:type", Array)
|
|
199
|
-
],
|
|
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
|
-
],
|
|
204
|
-
|
|
329
|
+
], ApplyAllBatchConnectorResult.prototype, "Warnings", void 0);
|
|
330
|
+
ApplyAllBatchConnectorResult = __decorate([
|
|
205
331
|
ObjectType()
|
|
206
|
-
],
|
|
207
|
-
|
|
208
|
-
let DefaultFieldMappingOutput = class DefaultFieldMappingOutput {
|
|
332
|
+
], ApplyAllBatchConnectorResult);
|
|
333
|
+
let ApplyAllBatchOutput = class ApplyAllBatchOutput {
|
|
209
334
|
};
|
|
210
335
|
__decorate([
|
|
211
336
|
Field(),
|
|
212
|
-
__metadata("design:type",
|
|
213
|
-
],
|
|
337
|
+
__metadata("design:type", Boolean)
|
|
338
|
+
], ApplyAllBatchOutput.prototype, "Success", void 0);
|
|
214
339
|
__decorate([
|
|
215
340
|
Field(),
|
|
216
341
|
__metadata("design:type", String)
|
|
217
|
-
],
|
|
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
|
-
],
|
|
222
|
-
|
|
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
|
-
],
|
|
225
|
-
|
|
369
|
+
], ApplyAllBatchOutput);
|
|
370
|
+
// ─── Delete Connection Output ────────────────────────────────────────────────
|
|
371
|
+
let DeleteConnectionOutput = class DeleteConnectionOutput {
|
|
226
372
|
};
|
|
227
373
|
__decorate([
|
|
228
374
|
Field(),
|
|
229
|
-
__metadata("design:type",
|
|
230
|
-
],
|
|
375
|
+
__metadata("design:type", Boolean)
|
|
376
|
+
], DeleteConnectionOutput.prototype, "Success", void 0);
|
|
231
377
|
__decorate([
|
|
232
378
|
Field(),
|
|
233
379
|
__metadata("design:type", String)
|
|
234
|
-
],
|
|
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
|
-
],
|
|
406
|
+
], SchemaEvolutionOutput.prototype, "Message", void 0);
|
|
239
407
|
__decorate([
|
|
240
408
|
Field(),
|
|
241
409
|
__metadata("design:type", Boolean)
|
|
242
|
-
],
|
|
410
|
+
], SchemaEvolutionOutput.prototype, "HasChanges", void 0);
|
|
243
411
|
__decorate([
|
|
244
|
-
Field(
|
|
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
|
-
],
|
|
247
|
-
|
|
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
|
-
],
|
|
250
|
-
|
|
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
|
-
],
|
|
444
|
+
], ConnectorCapabilitiesOutput.prototype, "Success", void 0);
|
|
256
445
|
__decorate([
|
|
257
446
|
Field(),
|
|
258
447
|
__metadata("design:type", String)
|
|
259
|
-
],
|
|
448
|
+
], ConnectorCapabilitiesOutput.prototype, "Message", void 0);
|
|
260
449
|
__decorate([
|
|
261
450
|
Field({ nullable: true }),
|
|
262
|
-
__metadata("design:type",
|
|
263
|
-
],
|
|
451
|
+
__metadata("design:type", Boolean)
|
|
452
|
+
], ConnectorCapabilitiesOutput.prototype, "SupportsGet", void 0);
|
|
264
453
|
__decorate([
|
|
265
|
-
Field(
|
|
266
|
-
__metadata("design:type",
|
|
267
|
-
],
|
|
268
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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:
|
|
292
|
-
|
|
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
|
-
|
|
2746
|
+
LogError(`IntegrationStartSync error: ${e}`);
|
|
2747
|
+
return { Success: false, Message: this.formatError(e) };
|
|
302
2748
|
}
|
|
303
2749
|
}
|
|
304
2750
|
/**
|
|
305
|
-
*
|
|
2751
|
+
* Cancels a running sync by marking its status as Cancelled.
|
|
306
2752
|
*/
|
|
307
|
-
async
|
|
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
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
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:
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
2972
|
+
LogError(`IntegrationListSchedules error: ${e}`);
|
|
2973
|
+
return { Success: false, Message: this.formatError(e) };
|
|
329
2974
|
}
|
|
330
2975
|
}
|
|
331
|
-
|
|
332
|
-
|
|
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
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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:
|
|
343
|
-
Message: result.
|
|
344
|
-
|
|
2991
|
+
Success: true,
|
|
2992
|
+
Message: `${result.Results.length} entity maps`,
|
|
2993
|
+
EntityMaps: result.Results
|
|
345
2994
|
};
|
|
346
2995
|
}
|
|
347
2996
|
catch (e) {
|
|
348
|
-
|
|
349
|
-
|
|
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:
|
|
352
|
-
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
|
|
358
|
-
*
|
|
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
|
|
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
|
-
|
|
365
|
-
|
|
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: '
|
|
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:
|
|
373
|
-
Message: `
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
390
|
-
LogError(`IntegrationGetDefaultConfig error: ${error}`);
|
|
3459
|
+
LogError(`IntegrationApplyAllBatch error: ${e}`);
|
|
391
3460
|
return {
|
|
392
|
-
Success: false,
|
|
393
|
-
|
|
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
|
-
*
|
|
399
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
//
|
|
409
|
-
const
|
|
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
|
|
414
|
-
const targetConfigs = this.buildTargetConfigs(objects, filteredSchema,
|
|
415
|
-
|
|
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:
|
|
420
|
-
MJVersion: '5.
|
|
3750
|
+
Platform: validatedPlatform,
|
|
3751
|
+
MJVersion: process.env.MJ_VERSION ?? '5.11.0',
|
|
421
3752
|
SourceType: companyIntegration.Integration,
|
|
422
|
-
AdditionalSchemaInfoPath: 'additionalSchemaInfo.json',
|
|
423
|
-
MigrationsDir: 'migrations/
|
|
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
|
|
430
|
-
if (
|
|
3761
|
+
const schemaOutput = builder.BuildSchema(schemaInput);
|
|
3762
|
+
if (schemaOutput.Errors.length > 0) {
|
|
431
3763
|
return {
|
|
432
3764
|
Success: false,
|
|
433
|
-
Message: `Schema
|
|
434
|
-
|
|
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
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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:
|
|
444
|
-
Message:
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
455
|
-
|
|
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
|
-
|
|
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
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|