retold-facto 0.0.4

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.
Files changed (92) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.dockerignore +8 -0
  3. package/.quackage.json +19 -0
  4. package/Dockerfile +26 -0
  5. package/bin/retold-facto.js +909 -0
  6. package/examples/facto-government-data.sqlite +0 -0
  7. package/examples/government-data-catalog.json +137 -0
  8. package/examples/government-data-loader.js +1432 -0
  9. package/package.json +91 -0
  10. package/scripts/facto-download.js +425 -0
  11. package/source/Retold-Facto.js +1042 -0
  12. package/source/services/Retold-Facto-BeaconProvider.js +511 -0
  13. package/source/services/Retold-Facto-CatalogManager.js +1252 -0
  14. package/source/services/Retold-Facto-DataLakeService.js +1642 -0
  15. package/source/services/Retold-Facto-DatasetManager.js +417 -0
  16. package/source/services/Retold-Facto-IngestEngine.js +1315 -0
  17. package/source/services/Retold-Facto-ProjectionEngine.js +3960 -0
  18. package/source/services/Retold-Facto-RecordManager.js +360 -0
  19. package/source/services/Retold-Facto-SchemaManager.js +1110 -0
  20. package/source/services/Retold-Facto-SourceFolderScanner.js +2243 -0
  21. package/source/services/Retold-Facto-SourceManager.js +730 -0
  22. package/source/services/Retold-Facto-StoreConnectionManager.js +441 -0
  23. package/source/services/Retold-Facto-ThroughputMonitor.js +478 -0
  24. package/source/services/web-app/codemirror-entry.js +7 -0
  25. package/source/services/web-app/pict-app/Pict-Application-Facto-Configuration.json +9 -0
  26. package/source/services/web-app/pict-app/Pict-Application-Facto.js +70 -0
  27. package/source/services/web-app/pict-app/Pict-Facto-Bundle.js +11 -0
  28. package/source/services/web-app/pict-app/providers/Pict-Provider-Facto-UI.js +66 -0
  29. package/source/services/web-app/pict-app/providers/Pict-Provider-Facto.js +69 -0
  30. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Catalog.js +93 -0
  31. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Connections.js +42 -0
  32. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Datasets.js +605 -0
  33. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Projections.js +188 -0
  34. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Scanner.js +80 -0
  35. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Schema.js +116 -0
  36. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Sources.js +104 -0
  37. package/source/services/web-app/pict-app/views/PictView-Facto-Catalog.js +526 -0
  38. package/source/services/web-app/pict-app/views/PictView-Facto-Datasets.js +173 -0
  39. package/source/services/web-app/pict-app/views/PictView-Facto-Ingest.js +259 -0
  40. package/source/services/web-app/pict-app/views/PictView-Facto-Layout.js +191 -0
  41. package/source/services/web-app/pict-app/views/PictView-Facto-Projections.js +231 -0
  42. package/source/services/web-app/pict-app/views/PictView-Facto-Records.js +326 -0
  43. package/source/services/web-app/pict-app/views/PictView-Facto-Scanner.js +624 -0
  44. package/source/services/web-app/pict-app/views/PictView-Facto-Sources.js +201 -0
  45. package/source/services/web-app/pict-app/views/PictView-Facto-Throughput.js +456 -0
  46. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full-Configuration.json +14 -0
  47. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full.js +391 -0
  48. package/source/services/web-app/pict-app-full/providers/PictRouter-Facto-Configuration.json +56 -0
  49. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-BottomBar.js +68 -0
  50. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Connections.js +340 -0
  51. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboard.js +149 -0
  52. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboards.js +819 -0
  53. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Datasets.js +178 -0
  54. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-IngestJobs.js +99 -0
  55. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Layout.js +62 -0
  56. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-MappingEditor.js +158 -0
  57. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-ProjectionDetail.js +1120 -0
  58. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Projections.js +172 -0
  59. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-QueryPanel.js +119 -0
  60. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-RecordViewer.js +663 -0
  61. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Records.js +648 -0
  62. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Scanner.js +1017 -0
  63. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDetail.js +1404 -0
  64. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDocEditor.js +1036 -0
  65. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaEditor.js +636 -0
  66. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaResearch.js +357 -0
  67. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceDetail.js +822 -0
  68. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceEditor.js +1036 -0
  69. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceResearch.js +487 -0
  70. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Sources.js +165 -0
  71. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Throughput.js +439 -0
  72. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-TopBar.js +335 -0
  73. package/source/services/web-app/pict-app-full/views/projections/Facto-Projections-Constants.js +71 -0
  74. package/source/services/web-app/web/chart.min.js +20 -0
  75. package/source/services/web-app/web/codemirror-bundle.js +30099 -0
  76. package/source/services/web-app/web/css/facto-themes.css +467 -0
  77. package/source/services/web-app/web/css/facto.css +502 -0
  78. package/source/services/web-app/web/index.html +28 -0
  79. package/source/services/web-app/web/retold-facto.js +12138 -0
  80. package/source/services/web-app/web/retold-facto.js.map +1 -0
  81. package/source/services/web-app/web/retold-facto.min.js +2 -0
  82. package/source/services/web-app/web/retold-facto.min.js.map +1 -0
  83. package/source/services/web-app/web/simple/index.html +17 -0
  84. package/test/Facto_Browser_Integration_tests.js +798 -0
  85. package/test/RetoldFacto_tests.js +4117 -0
  86. package/test/fixtures/weather-readings.csv +17 -0
  87. package/test/fixtures/weather-stations.csv +9 -0
  88. package/test/model/MeadowModel-Extended.json +8497 -0
  89. package/test/model/MeadowModel-PICT.json +1 -0
  90. package/test/model/MeadowModel.json +1355 -0
  91. package/test/model/ddl/Facto.ddl +225 -0
  92. package/test/model/fable-configuration.json +14 -0
@@ -0,0 +1,441 @@
1
+ /**
2
+ * Retold Facto - Store Connection Manager Service
3
+ *
4
+ * Manages external database connections for projection deployment.
5
+ * Provides CRUD endpoints for store connections, connection testing,
6
+ * and available connector type discovery.
7
+ *
8
+ * @author Steven Velozo <steven@velozo.com>
9
+ */
10
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
11
+
12
+ const defaultStoreConnectionManagerOptions = (
13
+ {
14
+ RoutePrefix: '/facto'
15
+ });
16
+
17
+ class RetoldFactoStoreConnectionManager extends libFableServiceProviderBase
18
+ {
19
+ constructor(pFable, pOptions, pServiceHash)
20
+ {
21
+ let tmpOptions = Object.assign({}, defaultStoreConnectionManagerOptions, pOptions);
22
+ super(pFable, tmpOptions, pServiceHash);
23
+
24
+ this.serviceType = 'RetoldFactoStoreConnectionManager';
25
+ }
26
+
27
+ /**
28
+ * Mask sensitive fields (password) in a Config JSON string before sending to client.
29
+ *
30
+ * @param {string} pConfigJSON - Raw Config JSON string
31
+ * @returns {string} Masked Config JSON string
32
+ */
33
+ _maskConfig(pConfigJSON)
34
+ {
35
+ if (!pConfigJSON) return '{}';
36
+ try
37
+ {
38
+ let tmpConfig = JSON.parse(pConfigJSON);
39
+ if (tmpConfig.password)
40
+ {
41
+ tmpConfig.password = '***';
42
+ }
43
+ if (tmpConfig.Password)
44
+ {
45
+ tmpConfig.Password = '***';
46
+ }
47
+ return JSON.stringify(tmpConfig);
48
+ }
49
+ catch (pError)
50
+ {
51
+ return '{}';
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Merge an incoming Config object with the stored one,
57
+ * preserving the actual password if the client sent '***'.
58
+ *
59
+ * @param {object} pNewConfig - The incoming config from the client
60
+ * @param {string} pStoredConfigJSON - The existing stored config JSON
61
+ * @returns {string} Merged config JSON
62
+ */
63
+ _mergeConfig(pNewConfig, pStoredConfigJSON)
64
+ {
65
+ let tmpStored = {};
66
+ try
67
+ {
68
+ tmpStored = JSON.parse(pStoredConfigJSON || '{}');
69
+ }
70
+ catch (pError) { /* ignore parse errors */ }
71
+
72
+ if (pNewConfig.password === '***' && tmpStored.password)
73
+ {
74
+ pNewConfig.password = tmpStored.password;
75
+ }
76
+ if (pNewConfig.Password === '***' && tmpStored.Password)
77
+ {
78
+ pNewConfig.Password = tmpStored.Password;
79
+ }
80
+ return JSON.stringify(pNewConfig);
81
+ }
82
+
83
+ /**
84
+ * Connect REST API routes for store connection management.
85
+ *
86
+ * @param {object} pOratorServiceServer - The Orator service server instance
87
+ */
88
+ connectRoutes(pOratorServiceServer)
89
+ {
90
+ let tmpRoutePrefix = this.options.RoutePrefix;
91
+
92
+ // GET /facto/connections -- list all non-deleted connections
93
+ pOratorServiceServer.doGet(`${tmpRoutePrefix}/connections`,
94
+ (pRequest, pResponse, fNext) =>
95
+ {
96
+ if (!this.fable.DAL || !this.fable.DAL.StoreConnection)
97
+ {
98
+ pResponse.send({ Connections: [] });
99
+ return fNext();
100
+ }
101
+
102
+ let tmpQuery = this.fable.DAL.StoreConnection.query.clone()
103
+ .addFilter('Deleted', 0);
104
+
105
+ this.fable.DAL.StoreConnection.doReads(tmpQuery,
106
+ (pError, pQuery, pRecords) =>
107
+ {
108
+ if (pError)
109
+ {
110
+ this.fable.log.error(`StoreConnectionManager error listing connections: ${pError}`);
111
+ pResponse.send({ Error: pError.message || pError, Connections: [] });
112
+ return fNext();
113
+ }
114
+
115
+ // Mask passwords before sending
116
+ for (let i = 0; i < pRecords.length; i++)
117
+ {
118
+ pRecords[i].Config = this._maskConfig(pRecords[i].Config);
119
+ }
120
+
121
+ pResponse.send({ Count: pRecords.length, Connections: pRecords });
122
+ return fNext();
123
+ });
124
+ });
125
+
126
+ // POST /facto/connection -- create a new connection
127
+ pOratorServiceServer.doPost(`${tmpRoutePrefix}/connection`,
128
+ (pRequest, pResponse, fNext) =>
129
+ {
130
+ if (!this.fable.DAL || !this.fable.DAL.StoreConnection)
131
+ {
132
+ pResponse.send({ Error: 'StoreConnection DAL not initialized' });
133
+ return fNext();
134
+ }
135
+
136
+ let tmpBody = pRequest.body || {};
137
+ let tmpName = tmpBody.Name || 'Untitled Connection';
138
+ let tmpType = tmpBody.Type || 'MySQL';
139
+ let tmpConfig = tmpBody.Config || {};
140
+
141
+ let tmpRecord =
142
+ {
143
+ Name: tmpName,
144
+ Type: tmpType,
145
+ Config: (typeof tmpConfig === 'string') ? tmpConfig : JSON.stringify(tmpConfig),
146
+ Status: 'Untested'
147
+ };
148
+
149
+ let tmpQuery = this.fable.DAL.StoreConnection.query.clone()
150
+ .setIDUser(0)
151
+ .addRecord(tmpRecord);
152
+
153
+ this.fable.DAL.StoreConnection.doCreate(tmpQuery,
154
+ (pError, pQuery, pRecord) =>
155
+ {
156
+ if (pError)
157
+ {
158
+ pResponse.send({ Error: pError.message || pError });
159
+ return fNext();
160
+ }
161
+
162
+ pRecord.Config = this._maskConfig(pRecord.Config);
163
+ pResponse.send({ Success: true, Connection: pRecord });
164
+ return fNext();
165
+ });
166
+ });
167
+
168
+ // GET /facto/connection/:IDStoreConnection -- read a single connection
169
+ pOratorServiceServer.doGet(`${tmpRoutePrefix}/connection/:IDStoreConnection`,
170
+ (pRequest, pResponse, fNext) =>
171
+ {
172
+ if (!this.fable.DAL || !this.fable.DAL.StoreConnection)
173
+ {
174
+ pResponse.send({ Error: 'StoreConnection DAL not initialized' });
175
+ return fNext();
176
+ }
177
+
178
+ let tmpID = parseInt(pRequest.params.IDStoreConnection, 10);
179
+
180
+ let tmpQuery = this.fable.DAL.StoreConnection.query.clone()
181
+ .addFilter('IDStoreConnection', tmpID);
182
+
183
+ this.fable.DAL.StoreConnection.doRead(tmpQuery,
184
+ (pError, pQuery, pRecord) =>
185
+ {
186
+ if (pError)
187
+ {
188
+ pResponse.send({ Error: pError.message || pError });
189
+ return fNext();
190
+ }
191
+ if (!pRecord || !pRecord.IDStoreConnection)
192
+ {
193
+ pResponse.send({ Error: 'Connection not found' });
194
+ return fNext();
195
+ }
196
+
197
+ pRecord.Config = this._maskConfig(pRecord.Config);
198
+ pResponse.send({ Connection: pRecord });
199
+ return fNext();
200
+ });
201
+ });
202
+
203
+ // PUT /facto/connection/:IDStoreConnection -- update a connection
204
+ pOratorServiceServer.doPut(`${tmpRoutePrefix}/connection/:IDStoreConnection`,
205
+ (pRequest, pResponse, fNext) =>
206
+ {
207
+ if (!this.fable.DAL || !this.fable.DAL.StoreConnection)
208
+ {
209
+ pResponse.send({ Error: 'StoreConnection DAL not initialized' });
210
+ return fNext();
211
+ }
212
+
213
+ let tmpID = parseInt(pRequest.params.IDStoreConnection, 10);
214
+ let tmpBody = pRequest.body || {};
215
+
216
+ // First read the existing record to preserve password if masked
217
+ let tmpReadQuery = this.fable.DAL.StoreConnection.query.clone()
218
+ .addFilter('IDStoreConnection', tmpID);
219
+
220
+ this.fable.DAL.StoreConnection.doRead(tmpReadQuery,
221
+ (pReadError, pReadQuery, pExisting) =>
222
+ {
223
+ if (pReadError || !pExisting || !pExisting.IDStoreConnection)
224
+ {
225
+ pResponse.send({ Error: 'Connection not found' });
226
+ return fNext();
227
+ }
228
+
229
+ if (tmpBody.Name !== undefined) pExisting.Name = tmpBody.Name;
230
+ if (tmpBody.Type !== undefined) pExisting.Type = tmpBody.Type;
231
+ if (tmpBody.Config !== undefined)
232
+ {
233
+ let tmpNewConfig = (typeof tmpBody.Config === 'string')
234
+ ? JSON.parse(tmpBody.Config)
235
+ : tmpBody.Config;
236
+ pExisting.Config = this._mergeConfig(tmpNewConfig, pExisting.Config);
237
+ }
238
+ if (tmpBody.Status !== undefined) pExisting.Status = tmpBody.Status;
239
+
240
+ let tmpUpdateQuery = this.fable.DAL.StoreConnection.query.clone()
241
+ .addRecord(pExisting);
242
+
243
+ this.fable.DAL.StoreConnection.doUpdate(tmpUpdateQuery,
244
+ (pError, pQuery, pRecord) =>
245
+ {
246
+ if (pError)
247
+ {
248
+ pResponse.send({ Error: pError.message || pError });
249
+ return fNext();
250
+ }
251
+
252
+ pRecord.Config = this._maskConfig(pRecord.Config);
253
+ pResponse.send({ Success: true, Connection: pRecord });
254
+ return fNext();
255
+ });
256
+ });
257
+ });
258
+
259
+ // DELETE /facto/connection/:IDStoreConnection -- soft-delete
260
+ pOratorServiceServer.doDel(`${tmpRoutePrefix}/connection/:IDStoreConnection`,
261
+ (pRequest, pResponse, fNext) =>
262
+ {
263
+ if (!this.fable.DAL || !this.fable.DAL.StoreConnection)
264
+ {
265
+ pResponse.send({ Error: 'StoreConnection DAL not initialized' });
266
+ return fNext();
267
+ }
268
+
269
+ let tmpID = parseInt(pRequest.params.IDStoreConnection, 10);
270
+
271
+ let tmpReadQuery = this.fable.DAL.StoreConnection.query.clone()
272
+ .addFilter('IDStoreConnection', tmpID);
273
+
274
+ this.fable.DAL.StoreConnection.doRead(tmpReadQuery,
275
+ (pReadError, pReadQuery, pExisting) =>
276
+ {
277
+ if (pReadError || !pExisting || !pExisting.IDStoreConnection)
278
+ {
279
+ pResponse.send({ Error: 'Connection not found' });
280
+ return fNext();
281
+ }
282
+
283
+ pExisting.Deleted = 1;
284
+ pExisting.DeleteDate = new Date().toISOString();
285
+
286
+ let tmpUpdateQuery = this.fable.DAL.StoreConnection.query.clone()
287
+ .addRecord(pExisting);
288
+
289
+ this.fable.DAL.StoreConnection.doUpdate(tmpUpdateQuery,
290
+ (pError) =>
291
+ {
292
+ if (pError)
293
+ {
294
+ pResponse.send({ Error: pError.message || pError });
295
+ return fNext();
296
+ }
297
+
298
+ pResponse.send({ Success: true });
299
+ return fNext();
300
+ });
301
+ });
302
+ });
303
+
304
+ // POST /facto/connection/:IDStoreConnection/test -- test a saved connection
305
+ pOratorServiceServer.doPost(`${tmpRoutePrefix}/connection/:IDStoreConnection/test`,
306
+ (pRequest, pResponse, fNext) =>
307
+ {
308
+ if (!this.fable.DAL || !this.fable.DAL.StoreConnection)
309
+ {
310
+ pResponse.send({ Success: false, Error: 'StoreConnection DAL not initialized' });
311
+ return fNext();
312
+ }
313
+
314
+ let tmpID = parseInt(pRequest.params.IDStoreConnection, 10);
315
+
316
+ let tmpReadQuery = this.fable.DAL.StoreConnection.query.clone()
317
+ .addFilter('IDStoreConnection', tmpID);
318
+
319
+ this.fable.DAL.StoreConnection.doRead(tmpReadQuery,
320
+ (pReadError, pReadQuery, pExisting) =>
321
+ {
322
+ if (pReadError || !pExisting || !pExisting.IDStoreConnection)
323
+ {
324
+ pResponse.send({ Success: false, Error: 'Connection not found' });
325
+ return fNext();
326
+ }
327
+
328
+ let tmpConfig = {};
329
+ try { tmpConfig = JSON.parse(pExisting.Config || '{}'); }
330
+ catch (e) { /* ignore */ }
331
+
332
+ this._testConnection(pExisting.Type, tmpConfig,
333
+ (pTestError, pResult) =>
334
+ {
335
+ // Update the connection record with test results
336
+ pExisting.LastTestedDate = new Date().toISOString();
337
+ pExisting.Status = pTestError ? 'Failed' : 'OK';
338
+
339
+ let tmpUpdateQuery = this.fable.DAL.StoreConnection.query.clone()
340
+ .addRecord(pExisting);
341
+
342
+ this.fable.DAL.StoreConnection.doUpdate(tmpUpdateQuery,
343
+ () =>
344
+ {
345
+ if (pTestError)
346
+ {
347
+ pResponse.send({ Success: false, Error: pTestError.message || pTestError, Status: 'Failed' });
348
+ }
349
+ else
350
+ {
351
+ pResponse.send({ Success: true, Status: 'OK', Result: pResult || {} });
352
+ }
353
+ return fNext();
354
+ });
355
+ });
356
+ });
357
+ });
358
+
359
+ // POST /facto/connection/test -- test an ad-hoc connection config (no save)
360
+ pOratorServiceServer.doPost(`${tmpRoutePrefix}/connection/test`,
361
+ (pRequest, pResponse, fNext) =>
362
+ {
363
+ let tmpBody = pRequest.body || {};
364
+ let tmpType = tmpBody.Type || '';
365
+ let tmpConfig = tmpBody.Config || {};
366
+
367
+ if (!tmpType)
368
+ {
369
+ pResponse.send({ Success: false, Error: 'Type is required' });
370
+ return fNext();
371
+ }
372
+
373
+ this._testConnection(tmpType, tmpConfig,
374
+ (pTestError, pResult) =>
375
+ {
376
+ if (pTestError)
377
+ {
378
+ pResponse.send({ Success: false, Error: pTestError.message || pTestError });
379
+ }
380
+ else
381
+ {
382
+ pResponse.send({ Success: true, Result: pResult || {} });
383
+ }
384
+ return fNext();
385
+ });
386
+ });
387
+
388
+ // GET /facto/connection/available-types -- list installed connector types
389
+ pOratorServiceServer.doGet(`${tmpRoutePrefix}/connection/available-types`,
390
+ (pRequest, pResponse, fNext) =>
391
+ {
392
+ let tmpAvailable = [];
393
+ let tmpProviders = this.fable.MeadowConnectionManager.getAvailableProviders();
394
+ let tmpTypes = Object.keys(tmpProviders);
395
+
396
+ for (let i = 0; i < tmpTypes.length; i++)
397
+ {
398
+ tmpAvailable.push(
399
+ {
400
+ Type: tmpTypes[i],
401
+ Installed: tmpProviders[tmpTypes[i]]
402
+ });
403
+ }
404
+
405
+ pResponse.send({ Types: tmpAvailable });
406
+ return fNext();
407
+ });
408
+
409
+ this.fable.log.info(`StoreConnectionManager routes connected at ${tmpRoutePrefix}/connection*`);
410
+ }
411
+
412
+ /**
413
+ * Test a database connection by attempting to connect with the given config.
414
+ *
415
+ * @param {string} pType - Connection type (MySQL, PostgreSQL, etc.)
416
+ * @param {object} pConfig - Connection configuration object
417
+ * @param {function} fCallback - Callback(pError, pResult)
418
+ */
419
+ _testConnection(pType, pConfig, fCallback)
420
+ {
421
+ let tmpTestConfig = Object.assign({}, pConfig, { Type: pType });
422
+
423
+ this.fable.MeadowConnectionManager.testConnection(tmpTestConfig,
424
+ (pError, pResult) =>
425
+ {
426
+ if (pError)
427
+ {
428
+ return fCallback(pError);
429
+ }
430
+ if (!pResult.Success)
431
+ {
432
+ return fCallback(new Error(pResult.Error || 'Connection test failed'));
433
+ }
434
+ return fCallback(null, { Connected: true, Type: pType });
435
+ });
436
+ }
437
+ }
438
+
439
+ module.exports = RetoldFactoStoreConnectionManager;
440
+ module.exports.serviceType = 'RetoldFactoStoreConnectionManager';
441
+ module.exports.default_configuration = defaultStoreConnectionManagerOptions;