backend-plus 2.0.0-beta.10 → 2.0.0-beta.12
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/for-client/my-tables.js +34 -11
- package/lib/backend-plus.d.ts +3 -1
- package/lib/backend-plus.js +24 -1
- package/lib/procedures-table.js +65 -1
- package/package.json +20 -20
package/for-client/my-tables.js
CHANGED
|
@@ -294,9 +294,13 @@ myOwn.TableConnector = function(context, opts){
|
|
|
294
294
|
connector.opts = opts||{};
|
|
295
295
|
connector.fixedFields = connector.opts.fixedFields || [];
|
|
296
296
|
connector.fixedField = {};
|
|
297
|
+
connector.hideBecauseRelated = {};
|
|
297
298
|
connector.fixedFields.forEach(function(pair){
|
|
298
299
|
if(!pair.range && pair.value != myOwn.skipInFixedFields){
|
|
299
300
|
connector.fixedField[pair.fieldName] = pair.value;
|
|
301
|
+
if (!pair.show) {
|
|
302
|
+
connector.hideBecauseRelated[pair.fieldName] = true;
|
|
303
|
+
}
|
|
300
304
|
}
|
|
301
305
|
});
|
|
302
306
|
connector.parameterFunctions=connector.opts.parameterFunctions||{};
|
|
@@ -443,9 +447,13 @@ myOwn.TableConnectorLocal = function(context, opts){
|
|
|
443
447
|
connector.opts = opts||{};
|
|
444
448
|
connector.fixedFields = connector.opts.fixedFields || [];
|
|
445
449
|
connector.fixedField = {};
|
|
450
|
+
connector.hideBecauseRelated = {};
|
|
446
451
|
connector.fixedFields.forEach(function(pair){
|
|
447
452
|
if(!pair.range && pair.value != myOwn.skipInFixedFields){
|
|
448
453
|
connector.fixedField[pair.fieldName] = pair.value;
|
|
454
|
+
if (!pair.show) {
|
|
455
|
+
connector.hideBecauseRelated[pair.fieldName] = true;
|
|
456
|
+
}
|
|
449
457
|
}
|
|
450
458
|
});
|
|
451
459
|
connector.parameterFunctions=connector.opts.parameterFunctions||{};
|
|
@@ -624,19 +632,27 @@ myOwn.tableGrid = function tableGrid(tableName, mainElement, opts){
|
|
|
624
632
|
var primaryKeyValuesForDepotRow = getPrimaryKeyValues(primaryKey, depot.row);
|
|
625
633
|
return sameValue(JSON.stringify(primaryKeyValuesForRow),JSON.stringify(primaryKeyValuesForDepotRow))
|
|
626
634
|
});
|
|
635
|
+
if (!depot) {
|
|
636
|
+
var depot = grid.createDepotFromRow(row);
|
|
637
|
+
var needToAddInGrid = true;
|
|
638
|
+
}
|
|
639
|
+
var needToDisplayDepot = !!grid.filterDepots([depot])[0];
|
|
640
|
+
if (!needToDisplayDepot) return;
|
|
627
641
|
//chequeo que exista depot por las dudas
|
|
628
642
|
if ((!depot || !depot.tr || !depot.tr.parentNode) && !thereIsANewRecord && !grid.vertical) {
|
|
629
|
-
|
|
643
|
+
var depotsToDisplay = grid.filterDepots(grid.depots);
|
|
644
|
+
if (needToAddInGrid) {
|
|
630
645
|
var depot = grid.createDepotFromRow(row);
|
|
631
646
|
grid.depots.push(depot);
|
|
632
|
-
grid.
|
|
647
|
+
var depotsToDisplay = grid.filterDepots(grid.depots);
|
|
648
|
+
grid.sortDepotsToDisplay(depotsToDisplay);
|
|
633
649
|
} else if (depot.tr && !depot.tr.parentNode) {
|
|
634
650
|
depot.tr = null
|
|
635
651
|
}
|
|
636
652
|
var iRow = -1;
|
|
637
653
|
var i = 0;
|
|
638
|
-
while (i <
|
|
639
|
-
var aDepot =
|
|
654
|
+
while (i < depotsToDisplay.length){
|
|
655
|
+
var aDepot = depotsToDisplay[i];
|
|
640
656
|
if (depot == aDepot) break;
|
|
641
657
|
if (aDepot && aDepot.tr && aDepot.tr.parentNode && aDepot.tr.rowIndex != null) {
|
|
642
658
|
iRow = aDepot.tr.sectionRowIndex
|
|
@@ -664,7 +680,8 @@ myOwn.tableGrid = function tableGrid(tableName, mainElement, opts){
|
|
|
664
680
|
})
|
|
665
681
|
if(!thereIsANewRecord){
|
|
666
682
|
var i = 0;
|
|
667
|
-
var
|
|
683
|
+
var depotsToDisplay = grid.filterDepots(grid.depots);
|
|
684
|
+
var depotsToDelete = depotsToDisplay.filter(depot => depot.tick != tick);
|
|
668
685
|
var depot;
|
|
669
686
|
if (myOwn.config.config['grid-row-retain-moved-or-deleted'] && !force) {
|
|
670
687
|
var depotsToRetain = grid.depots.filter(depot => depot.tick == tick);
|
|
@@ -921,11 +938,11 @@ myOwn.DataColumnGrid.prototype.cellAttributes = function cellAttributes(specific
|
|
|
921
938
|
attr["my-mandatory"]="normal";
|
|
922
939
|
}
|
|
923
940
|
}
|
|
924
|
-
if(grid.connector.
|
|
941
|
+
if(grid.connector.hideBecauseRelated[fieldDef.name] && !fieldDef.alwaysShow){
|
|
925
942
|
attr["inherited-pk-column"]="yes";
|
|
926
943
|
}
|
|
927
944
|
if(fieldDef.referencesField){
|
|
928
|
-
if(grid.connector.
|
|
945
|
+
if(grid.connector.hideBecauseRelated[fieldDef.referencesField] && !fieldDef.alwaysShow){
|
|
929
946
|
attr["inherited-pk-column"]="yes";
|
|
930
947
|
}
|
|
931
948
|
if(grid.def.field[fieldDef.referencesField].isPk){
|
|
@@ -2605,18 +2622,19 @@ myOwn.TableGrid.prototype.displayGrid = function displayGrid(){
|
|
|
2605
2622
|
}
|
|
2606
2623
|
return depot;
|
|
2607
2624
|
};
|
|
2608
|
-
grid.
|
|
2625
|
+
grid.filterDepots = function filterDepots(depotsToFilter){
|
|
2609
2626
|
var grid = this;
|
|
2610
|
-
var depotsToDisplay;
|
|
2611
2627
|
var filterRows = grid.view.filter;
|
|
2628
|
+
var depotsToDisplay;
|
|
2612
2629
|
if(filterRows && filterRows.length){
|
|
2613
|
-
depotsToDisplay =
|
|
2630
|
+
depotsToDisplay = depotsToFilter.filter(function(depot,i){
|
|
2614
2631
|
var iFilter=0;
|
|
2615
2632
|
while(iFilter<filterRows.length){
|
|
2616
2633
|
var filterData=filterRows[iFilter];
|
|
2617
2634
|
var partialOk=true;
|
|
2618
2635
|
var columnsCompared = 0;
|
|
2619
2636
|
for(var column in depot.row){
|
|
2637
|
+
// var compSymb = filterData.rowSymbols && filterData.rowSymbols[column] || filterData[column].operator;
|
|
2620
2638
|
var compSymb = filterData.rowSymbols[column];
|
|
2621
2639
|
if(compSymb && my.comparator[compSymb] && (my.comparatorParameterNull[compSymb] || filterData.row[column] != null)){
|
|
2622
2640
|
var isSatisfied=my.comparator[compSymb](depot.row[column],filterData.row[column]);
|
|
@@ -2634,8 +2652,13 @@ myOwn.TableGrid.prototype.displayGrid = function displayGrid(){
|
|
|
2634
2652
|
return false;
|
|
2635
2653
|
});
|
|
2636
2654
|
}else{
|
|
2637
|
-
depotsToDisplay =
|
|
2655
|
+
depotsToDisplay = depotsToFilter;
|
|
2638
2656
|
}
|
|
2657
|
+
return depotsToDisplay;
|
|
2658
|
+
}
|
|
2659
|
+
grid.displayBody=function displayBody(){
|
|
2660
|
+
var grid = this;
|
|
2661
|
+
var depotsToDisplay = grid.filterDepots(grid.depots);
|
|
2639
2662
|
grid.sortDepotsToDisplay = function sortDepotsToDisplay(depotsToDisplay){
|
|
2640
2663
|
if(grid.view.sortColumns.length>0){
|
|
2641
2664
|
return depotsToDisplay.sort(function(depot1, depot2){
|
package/lib/backend-plus.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ export type MenuInfoMenu = {
|
|
|
120
120
|
export type MenuInfoTable = {
|
|
121
121
|
menuType:'table'
|
|
122
122
|
table?:string
|
|
123
|
-
ff?:{fieldName:string, value:any}[]
|
|
123
|
+
ff?:{fieldName:string, value:any, show?:boolean}[]
|
|
124
124
|
fc?:{fieldName:string, operator:string, value:any}[]
|
|
125
125
|
pf?:any
|
|
126
126
|
td?:TableDefinition
|
|
@@ -211,6 +211,7 @@ export type FieldDefinition = EditableDbDefinition & {
|
|
|
211
211
|
table?:string
|
|
212
212
|
inherited?:boolean
|
|
213
213
|
nameForUpsert?:string
|
|
214
|
+
alwaysShow?:boolean /* show when appears in fixed fields */
|
|
214
215
|
} & ({} | {
|
|
215
216
|
sequence:SequenceDefinition
|
|
216
217
|
nullable:true
|
|
@@ -419,6 +420,7 @@ export class AppBackend{
|
|
|
419
420
|
messages:Record<LangId,Record<string, string>>
|
|
420
421
|
}
|
|
421
422
|
shootDownBackend():Promise<void>
|
|
423
|
+
setLog(opts:{until:string, results?:boolean})
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
}
|
package/lib/backend-plus.js
CHANGED
|
@@ -163,6 +163,7 @@ AppBackend.prototype.configStaticConfig = function configStaticConfig(){
|
|
|
163
163
|
skins:
|
|
164
164
|
"":
|
|
165
165
|
local-path: for-client
|
|
166
|
+
bin: {}
|
|
166
167
|
client-setup:
|
|
167
168
|
skin: ""
|
|
168
169
|
lang: en
|
|
@@ -235,7 +236,11 @@ AppBackend.prototype.i18n.messages.en={
|
|
|
235
236
|
fileUploaded:'file uploaded',
|
|
236
237
|
unkownExt:'unkown file extension'
|
|
237
238
|
},
|
|
238
|
-
server:{
|
|
239
|
+
server:{
|
|
240
|
+
backupNotAvailable: 'Backup not available',
|
|
241
|
+
backupReady: 'Backup ready to download',
|
|
242
|
+
backupZipping: 'Zipping backup file',
|
|
243
|
+
badBackupEncryptKey: 'encrypt key not present or less than 10 characters',
|
|
239
244
|
cantDelete_TLDR:'Can\'t delete. May be rights problems, locked records or internal problems',
|
|
240
245
|
cantInsert_TLDR:'Can\'t insert. May be rights problems, locked records or internal problems',
|
|
241
246
|
cantUpdate_TLDR:'Can\'t update. May be rights problems, locked records or internal problems',
|
|
@@ -314,6 +319,10 @@ AppBackend.prototype.i18n.messages.es={
|
|
|
314
319
|
unkownExt:'extensión de archivo desconocida'
|
|
315
320
|
},
|
|
316
321
|
server:{
|
|
322
|
+
backupNotAvailable: 'Backup no disponible',
|
|
323
|
+
backupReady: 'Archivo listo para bajar',
|
|
324
|
+
backupZipping: 'Compactando el backup',
|
|
325
|
+
badBackupEncryptKey: 'Debe proveer una clave de encriptacion de 10 caracteres o mas para encriptar el archivo de destino',
|
|
317
326
|
cantDelete_TLDR:'no se pudo eliminar el registro. Podrían haber problemas de persmisos, bloqueo de registros o problemas internos en la definición de la PK',
|
|
318
327
|
cantInsert_TLDR:'no se pudo insertar el registro. Podrían haber problemas de persmisos, bloqueo de registros o problemas internos en la definición de la PK',
|
|
319
328
|
cantUpdate_TLDR:'no se pudo modificar el registro. Podrían haber problemas de persmisos, bloqueo de registros o problemas internos en la definición de la PK',
|
|
@@ -483,6 +492,12 @@ AppBackend.prototype.isAdmin = function isAdmin(reqOrContext){
|
|
|
483
492
|
return reqOrContext && (reqOrContext.forDump || reqOrContext.user && reqOrContext.user[be.config.login.rolFieldName] == 'admin');
|
|
484
493
|
}
|
|
485
494
|
|
|
495
|
+
AppBackend.prototype.can = function can(reqOrContext, what){
|
|
496
|
+
var be = this;
|
|
497
|
+
if (be.isAdmin(reqOrContext)) return true;
|
|
498
|
+
return reqOrContext?.user?.['can' + what];
|
|
499
|
+
}
|
|
500
|
+
|
|
486
501
|
AppBackend.prototype.canChangePass = async function canChangePass(reqOrContext, _userToChangePass){
|
|
487
502
|
var be = this;
|
|
488
503
|
return be.isAdmin(reqOrContext);
|
|
@@ -1286,6 +1301,7 @@ AppBackend.prototype.generateInsertSQL = function generateInsertSQL(schemaName,
|
|
|
1286
1301
|
}
|
|
1287
1302
|
|
|
1288
1303
|
AppBackend.prototype.updateUpdateSQL = function updateUpdateSQL(schemaName, tableName, updateElement, updateConditions){
|
|
1304
|
+
var be = this;
|
|
1289
1305
|
var {db} = this;
|
|
1290
1306
|
var setPairs = [];
|
|
1291
1307
|
for (var key in updateElement) {
|
|
@@ -2381,6 +2397,13 @@ AppBackend.prototype.addLoggedServices = function addLoggedServices(){
|
|
|
2381
2397
|
}).catch(MiniTools.serveErr(req,res,next));
|
|
2382
2398
|
});
|
|
2383
2399
|
}
|
|
2400
|
+
if(be.config.db['downloadable-backup-path']){
|
|
2401
|
+
be.app.get('/backup-db.zip', function(req,res,next){
|
|
2402
|
+
if (be.can(req, 'DownloadBackup')) {
|
|
2403
|
+
MiniTools.serveFile('./local-private/backup-db.zip')(req,res,next);
|
|
2404
|
+
}
|
|
2405
|
+
})
|
|
2406
|
+
}
|
|
2384
2407
|
be.app.use(function(req,res,next){
|
|
2385
2408
|
// req != '/keep-alive.json'
|
|
2386
2409
|
req.session.lastNonKeepAlive = new Date().getTime();
|
package/lib/procedures-table.js
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
var {datetime, changing, coalesce} = require('best-globals');
|
|
5
5
|
var XLSX = require('xlsx');
|
|
6
6
|
var fs = require('fs/promises')
|
|
7
|
+
var fsSync = require('fs');
|
|
7
8
|
var typeStore=require('type-store');
|
|
8
9
|
var likeAr=require('like-ar');
|
|
9
10
|
const f = require('session-file-store');
|
|
11
|
+
const { expected } = require('cast-error');
|
|
10
12
|
|
|
11
13
|
const PANIC_IMPORT = true;
|
|
12
14
|
|
|
@@ -1190,7 +1192,7 @@ ProcedureTables = [
|
|
|
1190
1192
|
resultOk:'showGrid',
|
|
1191
1193
|
coreFunction:async function(context,parameters){
|
|
1192
1194
|
var {be,client} = context;
|
|
1193
|
-
if(
|
|
1195
|
+
if(!be.can(context,'SeeHistoryChanges')){
|
|
1194
1196
|
throw new Error('Forbiden history')
|
|
1195
1197
|
}
|
|
1196
1198
|
var tableDef = be.tableStructures[parameters.tableName](context);
|
|
@@ -1207,6 +1209,68 @@ ProcedureTables = [
|
|
|
1207
1209
|
`,[parameters.tableName, parameters.fieldName]).fetchAll();
|
|
1208
1210
|
return result.rows;
|
|
1209
1211
|
}
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
action:'download_dump',
|
|
1215
|
+
parameters:[
|
|
1216
|
+
{name:'encrypt', typeName:'text'}
|
|
1217
|
+
],
|
|
1218
|
+
bitacora:{always: true, error: true},
|
|
1219
|
+
progress:true,
|
|
1220
|
+
resultOk:'showDownloadUrl',
|
|
1221
|
+
coreFunction:async function(context, parameters){
|
|
1222
|
+
context.informProgress({message:"tart"});
|
|
1223
|
+
var {be,client} = context;
|
|
1224
|
+
if (!be.can(context,'DownloadBackup')) {
|
|
1225
|
+
throw new Error('Forbiden backup')
|
|
1226
|
+
}
|
|
1227
|
+
if (parameters.encript?.length < 10) {
|
|
1228
|
+
throw new Error(be.messages.server.badBackupEncryptKey)
|
|
1229
|
+
}
|
|
1230
|
+
var path = be.config.db['downloadable-backup-path']
|
|
1231
|
+
if (!path) {
|
|
1232
|
+
throw new Error(be.messages.server.backupNotAvailable)
|
|
1233
|
+
}
|
|
1234
|
+
context.informProgress({message:be.messages.server.backupZipping});
|
|
1235
|
+
var spawn = require('child_process').spawn;
|
|
1236
|
+
try {
|
|
1237
|
+
await fs.mkdir('./local-private');
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
if (expected(error).code !== 'EEXIST') throw error;
|
|
1240
|
+
try {
|
|
1241
|
+
await fs.unlink('./local-private/backup-db.zip');
|
|
1242
|
+
} catch (error) {
|
|
1243
|
+
if (expected(error).code !== 'ENOENT') throw error;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
var out = fsSync.createWriteStream('./local-private/backup-db.log');
|
|
1247
|
+
await new Promise((resolve, reject) => {
|
|
1248
|
+
out.on('error', reject);
|
|
1249
|
+
out.on('open', resolve);
|
|
1250
|
+
})
|
|
1251
|
+
var zip = spawn(be.config.server.bin.zip ?? 'zip',[
|
|
1252
|
+
...(be.config.server.bin["zip-fixed-parameters"] ?? []),
|
|
1253
|
+
...(be.config.server.bin["zip-password-parameter-flag"] === false ? [] : [be.config.server.bin["zip-password-parameter-flag"] ?? '--password']),
|
|
1254
|
+
`${be.config.server.bin["zip-password-prefix"] ?? ''}${parameters.encrypt}` ,
|
|
1255
|
+
'./local-private/backup-db.zip',
|
|
1256
|
+
path
|
|
1257
|
+
], {stdio: [out, out, out]});
|
|
1258
|
+
var code = await new Promise((resolve, reject) => {
|
|
1259
|
+
zip.on('data', chunk => out.write(chunk));
|
|
1260
|
+
zip.on('error', err => {
|
|
1261
|
+
context.informProgress(err);
|
|
1262
|
+
out.end();
|
|
1263
|
+
reject(err);
|
|
1264
|
+
});
|
|
1265
|
+
zip.on('exit', any => {
|
|
1266
|
+
out.end();
|
|
1267
|
+
if (any) reject(new Error("ZIP Error: " + any));
|
|
1268
|
+
resolve(any);
|
|
1269
|
+
});
|
|
1270
|
+
})
|
|
1271
|
+
context.informProgress({message:be.messages.server.backupReady});
|
|
1272
|
+
return [{url: './backup-db.zip', label:'backup-db.zip'}];
|
|
1273
|
+
}
|
|
1210
1274
|
}
|
|
1211
1275
|
];
|
|
1212
1276
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-plus",
|
|
3
3
|
"description": "Backend for the anti Pareto rule",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.12",
|
|
5
5
|
"author": "Codenautas <codenautas@googlegroups.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "codenautas/backend-plus",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"mini-tools": "^1.12.1",
|
|
55
55
|
"moment": "^2.29.4",
|
|
56
56
|
"multiparty": "^4.2.3",
|
|
57
|
-
"nodemailer": "^6.9.
|
|
57
|
+
"nodemailer": "^6.9.6",
|
|
58
58
|
"numeral": "^2.0.6",
|
|
59
59
|
"pg-promise-strict": "^1.3.3",
|
|
60
60
|
"pikaday": "^1.8.2",
|
|
@@ -67,26 +67,26 @@
|
|
|
67
67
|
"session-file-store": "^1.5.0",
|
|
68
68
|
"sql-tools": "^0.1.2",
|
|
69
69
|
"stack-trace": "^0.0.10",
|
|
70
|
-
"stylus": "0.
|
|
70
|
+
"stylus": "0.60.0",
|
|
71
71
|
"type-store": "^0.4.0",
|
|
72
72
|
"typed-controls": "^0.12.0",
|
|
73
73
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@types/big.js": "^6.2.
|
|
77
|
-
"@types/expect.js": "~0.3.
|
|
78
|
-
"@types/express": "^4.17.
|
|
79
|
-
"@types/express-useragent": "^1.0.
|
|
80
|
-
"@types/fs-extra": "^11.0.
|
|
81
|
-
"@types/js-yaml": "^4.0.
|
|
82
|
-
"@types/mocha": "^10.0.
|
|
83
|
-
"@types/multiparty": "~0.0.
|
|
84
|
-
"@types/node": "^20.
|
|
85
|
-
"@types/nodemailer": "^6.4.
|
|
86
|
-
"@types/numeral": "~2.0.
|
|
87
|
-
"@types/session-file-store": "^1.2.
|
|
88
|
-
"@types/stack-trace": "~0.0.
|
|
89
|
-
"@types/websql": "~0.0.
|
|
76
|
+
"@types/big.js": "^6.2.1",
|
|
77
|
+
"@types/expect.js": "~0.3.31",
|
|
78
|
+
"@types/express": "^4.17.20",
|
|
79
|
+
"@types/express-useragent": "^1.0.4",
|
|
80
|
+
"@types/fs-extra": "^11.0.3",
|
|
81
|
+
"@types/js-yaml": "^4.0.8",
|
|
82
|
+
"@types/mocha": "^10.0.3",
|
|
83
|
+
"@types/multiparty": "~0.0.35",
|
|
84
|
+
"@types/node": "^20.8.7",
|
|
85
|
+
"@types/nodemailer": "^6.4.13",
|
|
86
|
+
"@types/numeral": "~2.0.4",
|
|
87
|
+
"@types/session-file-store": "^1.2.4",
|
|
88
|
+
"@types/stack-trace": "~0.0.32",
|
|
89
|
+
"@types/websql": "~0.0.29",
|
|
90
90
|
"esprima": "^4.0.1",
|
|
91
91
|
"expect.js": "~0.3.1",
|
|
92
92
|
"karma": "6.4.2",
|
|
@@ -98,11 +98,11 @@
|
|
|
98
98
|
"kill-9": "~0.4.3",
|
|
99
99
|
"mocha": "^10.2.0",
|
|
100
100
|
"nyc": "^15.1.0",
|
|
101
|
-
"puppeteer": "^21.
|
|
102
|
-
"sinon": "^
|
|
101
|
+
"puppeteer": "^21.4.0",
|
|
102
|
+
"sinon": "^17.0.0",
|
|
103
103
|
"supertest": "^6.3.3",
|
|
104
104
|
"types.d.ts": "~0.6.18",
|
|
105
|
-
"typescript": "^5.
|
|
105
|
+
"typescript": "^5.2.2",
|
|
106
106
|
"why-is-node-running": "^2.2.2"
|
|
107
107
|
},
|
|
108
108
|
"engines": {
|