dbgate-api-premium 7.0.0 → 7.0.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dbgate-api-premium",
3
3
  "main": "src/index.js",
4
- "version": "7.0.0",
4
+ "version": "7.0.2",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -24,16 +24,16 @@
24
24
  "activedirectory2": "^2.1.0",
25
25
  "archiver": "^7.0.1",
26
26
  "async-lock": "^1.2.6",
27
- "axios": "^0.21.1",
27
+ "axios": "^1.13.2",
28
28
  "body-parser": "^1.19.0",
29
29
  "byline": "^5.0.0",
30
30
  "compare-versions": "^3.6.0",
31
31
  "cors": "^2.8.5",
32
32
  "cross-env": "^6.0.3",
33
- "dbgate-datalib": "^7.0.0",
33
+ "dbgate-datalib": "^7.0.2",
34
34
  "dbgate-query-splitter": "^4.11.9",
35
- "dbgate-sqltree": "^7.0.0",
36
- "dbgate-tools": "^7.0.0",
35
+ "dbgate-sqltree": "^7.0.2",
36
+ "dbgate-tools": "^7.0.2",
37
37
  "debug": "^4.3.4",
38
38
  "diff": "^5.0.0",
39
39
  "diff2html": "^3.4.13",
@@ -87,7 +87,7 @@
87
87
  "devDependencies": {
88
88
  "@types/fs-extra": "^9.0.11",
89
89
  "@types/lodash": "^4.14.149",
90
- "dbgate-types": "^7.0.0",
90
+ "dbgate-types": "^7.0.2",
91
91
  "env-cmd": "^10.1.0",
92
92
  "jsdoc-to-markdown": "^9.0.5",
93
93
  "node-loader": "^1.0.2",
@@ -24,10 +24,12 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
24
24
  const { getAuthProviderById } = require('../auth/authProvider');
25
25
  const { startTokenChecking } = require('../utility/authProxy');
26
26
  const { extractConnectionsFromEnv } = require('../utility/envtools');
27
+ const { MissingCredentialsError } = require('../utility/exceptions');
27
28
 
28
29
  const logger = getLogger('connections');
29
30
 
30
31
  let volatileConnections = {};
32
+ let pendingTestSubprocesses = {}; // Map of conid -> subprocess for MS Entra auth flows
31
33
 
32
34
  function getNamedArgs() {
33
35
  const res = {};
@@ -239,14 +241,60 @@ module.exports = {
239
241
  );
240
242
  pipeForkLogs(subprocess);
241
243
  subprocess.send({ ...connection, requestDbList });
242
- return new Promise(resolve => {
244
+ return new Promise((resolve, reject) => {
245
+ let isWaitingForVolatile = false;
246
+
247
+ const cleanup = () => {
248
+ if (connection._id && pendingTestSubprocesses[connection._id]) {
249
+ delete pendingTestSubprocesses[connection._id];
250
+ }
251
+ };
252
+
243
253
  subprocess.on('message', resp => {
244
254
  if (handleProcessCommunication(resp, subprocess)) return;
245
255
  // @ts-ignore
246
- const { msgtype } = resp;
256
+ const { msgtype, missingCredentialsDetail } = resp;
247
257
  if (msgtype == 'connected' || msgtype == 'error') {
258
+ cleanup();
248
259
  resolve(resp);
249
260
  }
261
+ if (msgtype == 'missingCredentials') {
262
+ if (missingCredentialsDetail?.redirectToDbLogin) {
263
+ // Store the subprocess for later when volatile connection is ready
264
+ isWaitingForVolatile = true;
265
+ pendingTestSubprocesses[connection._id] = {
266
+ subprocess,
267
+ requestDbList,
268
+ };
269
+ // Return immediately with redirectToDbLogin status in the old format
270
+ resolve({
271
+ missingCredentials: true,
272
+ detail: {
273
+ ...missingCredentialsDetail,
274
+ keepErrorResponseFromApi: true,
275
+ },
276
+ });
277
+ return;
278
+ }
279
+ reject(new MissingCredentialsError(missingCredentialsDetail));
280
+ }
281
+ });
282
+
283
+ subprocess.on('exit', (code) => {
284
+ // If exit happens while waiting for volatile, that's expected
285
+ if (isWaitingForVolatile && code === 0) {
286
+ cleanup();
287
+ return;
288
+ }
289
+ cleanup();
290
+ if (code !== 0) {
291
+ reject(new Error(`Test subprocess exited with code ${code}`));
292
+ }
293
+ });
294
+
295
+ subprocess.on('error', (err) => {
296
+ cleanup();
297
+ reject(err);
250
298
  });
251
299
  });
252
300
  },
@@ -279,6 +327,38 @@ module.exports = {
279
327
  return testRes;
280
328
  } else {
281
329
  volatileConnections[res._id] = res;
330
+
331
+ // Check if there's a pending test subprocess waiting for this volatile connection
332
+ const pendingTest = pendingTestSubprocesses[conid];
333
+ if (pendingTest) {
334
+ const { subprocess, requestDbList } = pendingTest;
335
+ try {
336
+ // Send the volatile connection to the waiting subprocess
337
+ subprocess.send({ ...res, requestDbList, isVolatileResolved: true });
338
+
339
+ // Wait for the test result and emit it as an event
340
+ subprocess.once('message', resp => {
341
+ if (handleProcessCommunication(resp, subprocess)) return;
342
+ const { msgtype } = resp;
343
+ if (msgtype == 'connected' || msgtype == 'error') {
344
+ // Emit SSE event with test result
345
+ socket.emit(`connection-test-result-${conid}`, {
346
+ ...resp,
347
+ volatileConId: res._id,
348
+ });
349
+ delete pendingTestSubprocesses[conid];
350
+ }
351
+ });
352
+ } catch (err) {
353
+ logger.error(extractErrorLogData(err), 'DBGM-00118 Error sending volatile connection to test subprocess');
354
+ socket.emit(`connection-test-result-${conid}`, {
355
+ msgtype: 'error',
356
+ error: err.message,
357
+ });
358
+ delete pendingTestSubprocesses[conid];
359
+ }
360
+ }
361
+
282
362
  return res;
283
363
  }
284
364
  },
@@ -957,12 +957,20 @@ async function storageUpdateTeamFile({ teamFileId, data, name, metadata }) {
957
957
  return true;
958
958
  }
959
959
 
960
- async function storageUpdateTeamFileAdmin({ teamFileId, name }) {
960
+ async function storageUpdateTeamFileAdmin({ teamFileId, name, teamFolderId, changedContent }) {
961
961
  const [conn, driver] = await getStorageConnection();
962
962
  if (!conn) {
963
963
  return null;
964
964
  }
965
- await storageSqlCommandFmt('update ~team_files set ~file_name = %v where ~id = %v', name, teamFileId);
965
+ await storageSqlCommandFmt(
966
+ 'update ~team_files set ~file_name = %v, ~team_folder_id = %v where ~id = %v',
967
+ name,
968
+ teamFolderId,
969
+ teamFileId
970
+ );
971
+ if (changedContent != null) {
972
+ await storageSqlCommandFmt('update ~team_files set ~file_content = %v where ~id = %v', changedContent, teamFileId);
973
+ }
966
974
  return true;
967
975
  }
968
976
 
@@ -991,7 +999,7 @@ async function storageListAllAdminFolders() {
991
999
 
992
1000
  const resp = await storageSelectFmt(`select ~team_folders.~id, ~team_folders.~folder_name,
993
1001
  (select count(*) from ~team_files where ~team_files.~team_folder_id = ~team_folders.~id) as ~file_count
994
- from ~team_folders`);
1002
+ from ~team_folders order by ~team_folders.~folder_name, ~team_folders.~id`);
995
1003
  return resp;
996
1004
  }
997
1005
 
@@ -1020,6 +1028,7 @@ async function storageListAllAdminFiles() {
1020
1028
  from ~team_files
1021
1029
  inner join ~team_file_types on ~team_files.~file_type_id = ~team_file_types.~id
1022
1030
  inner join ~team_folders on ~team_files.~team_folder_id = ~team_folders.~id
1031
+ order by ~team_files.~file_name, ~team_files.~id
1023
1032
  `);
1024
1033
  return resp;
1025
1034
  }
@@ -375,6 +375,7 @@ module.exports = {
375
375
  ownerEmail: item.owner_email,
376
376
  typeName: item.type_name,
377
377
  folderName: item.folder_name,
378
+ teamFolderId: item.team_folder_id,
378
379
  }));
379
380
  },
380
381
 
@@ -392,14 +393,15 @@ module.exports = {
392
393
  ownerName: existingFile.owner_login,
393
394
  ownerEmail: existingFile.owner_email,
394
395
  typeName: existingFile.type_name,
396
+ teamFolderId: existingFile.team_folder_id?.toString(),
395
397
  };
396
398
  },
397
399
 
398
400
  setAdminFile_meta: true,
399
- async setAdminFile({ id, name }, req) {
401
+ async setAdminFile({ id, name, teamFolderId, changedContent }, req) {
400
402
  const loadedPermissions = await loadPermissionsFromRequest(req);
401
403
  if (!hasPermission(`admin/team-files`, loadedPermissions)) return false;
402
- await storageUpdateTeamFileAdmin({ teamFileId: id, name });
404
+ await storageUpdateTeamFileAdmin({ teamFileId: id, name, teamFolderId, changedContent });
403
405
  socket.emitChanged('team-files-changed');
404
406
  return true;
405
407
  },
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '7.0.0',
4
- buildTime: '2026-01-22T09:09:52.304Z'
3
+ version: '7.0.2',
4
+ buildTime: '2026-02-05T12:05:51.104Z'
5
5
  };
@@ -18,13 +18,36 @@ Platform: ${process.platform}
18
18
 
19
19
  function start() {
20
20
  childProcessChecker();
21
- process.on('message', async connection => {
21
+
22
+ let isWaitingForVolatile = false;
23
+
24
+ const handleConnection = async connection => {
22
25
  // @ts-ignore
23
26
  const { requestDbList } = connection;
24
27
  if (handleProcessCommunication(connection)) return;
28
+
25
29
  try {
26
30
  const driver = requireEngineDriver(connection);
27
- const dbhan = await connectUtility(driver, connection, 'app');
31
+ const connectionChanged = driver?.beforeConnectionSave ? driver.beforeConnectionSave(connection) : connection;
32
+
33
+ if (!connection.isVolatileResolved) {
34
+ if (connectionChanged.useRedirectDbLogin) {
35
+ process.send({
36
+ msgtype: 'missingCredentials',
37
+ missingCredentialsDetail: {
38
+ // @ts-ignore
39
+ conid: connection._id,
40
+ redirectToDbLogin: true,
41
+ keepErrorResponseFromApi: true,
42
+ },
43
+ });
44
+ // Don't exit - wait for volatile connection to be sent
45
+ isWaitingForVolatile = true;
46
+ return;
47
+ }
48
+ }
49
+
50
+ const dbhan = await connectUtility(driver, connectionChanged, 'app');
28
51
  let version = {
29
52
  version: 'Unknown',
30
53
  };
@@ -45,6 +68,16 @@ function start() {
45
68
  }
46
69
 
47
70
  process.exit(0);
71
+ };
72
+
73
+ process.on('message', async connection => {
74
+ // If we're waiting for volatile and receive a new connection, use it
75
+ if (isWaitingForVolatile) {
76
+ isWaitingForVolatile = false;
77
+ await handleConnection(connection);
78
+ } else {
79
+ await handleConnection(connection);
80
+ }
48
81
  });
49
82
  }
50
83