backend-plus 2.0.0-rc.2 → 2.0.0-rc.21

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 CHANGED
@@ -6,11 +6,11 @@ Backend for the anti Pareto rule.
6
6
 
7
7
 
8
8
  ![stable](https://img.shields.io/badge/stability-stable-blue.svg)
9
- [![npm-version](https://img.shields.io/npm/v/backend-star.svg)](https://npmjs.org/package/backend-star)
10
- [![downloads](https://img.shields.io/npm/dm/backend-star.svg)](https://npmjs.org/package/backend-star)
11
- [![build](https://img.shields.io/travis/codenautas/backend-star/master.svg)](https://travis-ci.org/codenautas/backend-star)
12
- [![coverage](https://img.shields.io/coveralls/codenautas/backend-star/master.svg)](https://coveralls.io/r/codenautas/backend-star)
13
- [![dependencies](https://img.shields.io/david/codenautas/backend-star.svg)](https://david-dm.org/codenautas/backend-star)
9
+ [![npm-version](https://img.shields.io/npm/v/backend-plus.svg)](https://npmjs.org/package/backend-plus)
10
+ [![downloads](https://img.shields.io/npm/dm/backend-plus.svg)](https://npmjs.org/package/backend-plus)
11
+ [![build](https://img.shields.io/travis/codenautas/backend-plus/master.svg)](https://travis-ci.org/codenautas/backend-plus)
12
+ [![coverage](https://img.shields.io/coveralls/codenautas/backend-plus/master.svg)](https://coveralls.io/r/codenautas/backend-plus)
13
+ [![dependencies](https://img.shields.io/david/codenautas/backend-plus.svg)](https://david-dm.org/codenautas/backend-plus)
14
14
 
15
15
 
16
16
  language: ![English](https://raw.githubusercontent.com/codenautas/multilang/master/img/lang-en.png)
@@ -205,7 +205,7 @@ entry | usage
205
205
  -----------------------------|---------------
206
206
  server |
207
207
  .port | port where is listening
208
- .base-rul | base url added to domain name
208
+ .base-url | base url added to domain name
209
209
  .module-store |
210
210
  install | (see Spanish)
211
211
  .dump | (see Spanish)
@@ -161,5 +161,9 @@ a.disabled
161
161
  font-size 80%
162
162
  text-align right
163
163
  color #777
164
+ > .json-container
165
+ position sticky
166
+ top 5%
167
+ bottom 5%
164
168
 
165
169
 
@@ -152,7 +152,7 @@ myOwn.wScreens.procAux = {
152
152
  button.disabled=false;
153
153
  divProgressOutside.style.opacity=0.33;
154
154
  toggleProgress.disabled=false;
155
- labelProgress.textContent=resultOk?my.messages.completed:'error';
155
+ labelProgress.textContent=typeof resultOk == "string" ? resultOk : resultOk !== false ? my.messages.completed : 'error';
156
156
  }).catch(function(err){
157
157
  my.log(err);
158
158
  divProgress.textContent=err.message;
@@ -291,9 +291,11 @@ myOwn.showPage = function showPage(pageDef){
291
291
  rightMenu.style.zIndex=300;
292
292
  totalLayout.appendChild(rightMenu);
293
293
  }
294
- rightMenu.onclick=function(){
295
- if(!my.offline.mode){
296
- my.rightMenu();
294
+ if (rightMenu != null) {
295
+ rightMenu.onclick=function(){
296
+ if(!my.offline.mode){
297
+ my.rightMenu();
298
+ }
297
299
  }
298
300
  }
299
301
  };
@@ -539,9 +541,9 @@ myOwn.informDetectedStatus = function informDetectedStatus(statusCode, logged) {
539
541
  }
540
542
  if(statusCode==='notLogged'){
541
543
  var notLogged = document.getElementById('not-logged');
542
- notLogged.style.display='inherit';
544
+ if (notLogged) notLogged.style.display='inherit';
543
545
  var activeUser = document.getElementById('active-user');
544
- activeUser.style.display='none';
546
+ if (activeUser) activeUser.style.display='none';
545
547
  }
546
548
  }
547
549
 
@@ -558,11 +560,13 @@ myOwn.offlineModeRefresh = function offlineModeRefresh(){
558
560
  /** @type {HTMLImageElement} */
559
561
  // @ts-ignore
560
562
  var imgLight = document.getElementById('light-airplane');
561
- var skin=((my.config||{}).config||{}).skin;
562
- if(my.offline.mode){
563
- imgLight.src=my.path.img+'airplane-on.png';
564
- }else{
565
- imgLight.src=my.path.img+'airplane-off.png';
563
+ if (imgLight != null) {
564
+ var skin=((my.config||{}).config||{}).skin;
565
+ if(my.offline.mode){
566
+ imgLight.src=my.path.img+'airplane-on.png';
567
+ }else{
568
+ imgLight.src=my.path.img+'airplane-off.png';
569
+ }
566
570
  }
567
571
  }
568
572
 
@@ -183,20 +183,15 @@ myOwn.i18n.messages.es=changing(myOwn.i18n.messages.es, {
183
183
  /** @param {string} text */
184
184
  function regex4search(text){
185
185
  return new RegExp(
186
- text.trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
186
+ text.toString().trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
187
187
  // .replace(/"/g,"\\b")
188
188
  .replace(/[ñÑ]/g,'(?:gn|nn?i?|[ñÑ])')
189
- .replace(/[cCçÇ]/g,'[cçÇ]')
190
- .replace(/[áÁàÀäÄãÃ]/gi,'[AáÁàÀäÄãÃ]')
191
- .replace(/[éÉèÈëË]/gi,'[EéÉèÈëË]')
192
- .replace(/[íÍìÌïÏ]/gi,'[IíÍìÌïÏ]')
193
- .replace(/[óÓòÒöÖõÕ]/gi,'[OóÓòÒöÖõÕ]')
194
- .replace(/[úÚùÙüÜ]/gi,'[UúÚùÙüÜ]')
195
- .replace(/a/gi,'[AáÁàÀäÄãÃ]')
196
- .replace(/e/gi,'[EéÉèÈëË]')
197
- .replace(/i/gi,'[IíÍìÌïÏ]')
198
- .replace(/o/gi,'[OóÓòÒöÖõÕ]')
199
- .replace(/u/gi,'[UúÚùÙüÜ]')
189
+ .replace(/[cCçÇ]/g,'[cCçÇ]')
190
+ .replace(/[AáÁàÀäÄãÃ]/gi,'[AáÁàÀäÄãÃ]')
191
+ .replace(/[EéÉèÈëË]/gi,'[EéÉèÈëË]')
192
+ .replace(/[IíÍìÌïÏ]/gi,'[IíÍìÌïÏ]')
193
+ .replace(/[OóÓòÒöÖõÕ]/gi,'[OóÓòÒöÖõÕ]')
194
+ .replace(/[UúÚùÙüÜ]/gi,'[UúÚùÙüÜ]')
200
195
  // .replace(/\s+/g,'.*\\s+.*') mas estricto, exige el espacio
201
196
  .replace(/\s+/g,'.*')
202
197
  , 'i');
@@ -212,9 +207,9 @@ myOwn.comparatorParameterNull={
212
207
  '!=\u2205':true,
213
208
  }
214
209
  myOwn.comparator={
215
- '=':function(valueToCheck,condition){return valueToCheck == condition;},
216
- '~':function(valueToCheck,condition){return condition==null || regex4search(condition.toString()).test(valueToCheck);},
217
- '!~':function(valueToCheck,condition){return condition==null || !regex4search(condition.toString()).test(valueToCheck);},
210
+ '=':function(valueToCheck,condition){return sameValue(valueToCheck,condition);},
211
+ '~': function(valueToCheck,condition){return condition==null || condition instanceof Date ? Math.abs(condition-valueToCheck) <= 1000*60*60*24 : regex4search(condition).test(valueToCheck);},
212
+ '!~':function(valueToCheck,condition){return condition==null || condition instanceof Date ? Math.abs(condition-valueToCheck) > 1000*60*60*24 :!regex4search(condition).test(valueToCheck);},
218
213
  '/R/i':function(valueToCheck,condition){return condition==null || RegExp(condition,'i').test(valueToCheck);},
219
214
  '\u2205':function(valueToCheck,condition){return valueToCheck == null;},//\u2205 = conjunto vacío
220
215
  '!=\u2205':function(valueToCheck,condition){return valueToCheck != null;},//\u2205 = conjunto vacío
@@ -690,11 +685,18 @@ myOwn.tableGrid = function tableGrid(tableName, mainElement, opts){
690
685
  if (myOwn.config.config['grid-row-retain-moved-or-deleted'] && !force) {
691
686
  var depotsToRetain = grid.depots.filter(depot => depot.tick == tick);
692
687
  for (depot of depotsToRetain) {
688
+ depot['$refreshed'] = false
693
689
  if (depot.tr && depot.tr.getAttribute('not-here')) depot.tr.removeAttribute('not-here')
694
690
  }
695
691
  }
696
692
  while (depot = depotsToDelete.pop()) {
697
693
  depot.manager.displayAsDeleted(depot, force ? 'change-ff' : 'unknown');
694
+ if (myOwn.config.config['grid-row-retain-moved-or-deleted']) {
695
+ if(!depot['$refreshed']){
696
+ grid.retrieveRowAndRefresh(depot,{retrieveIgnoringWhere:true})
697
+ depot['$refreshed'] = true
698
+ }
699
+ }
698
700
  }
699
701
  }
700
702
  })
@@ -998,7 +1000,7 @@ myOwn.DataColumnGrid.prototype.thFilter = function thFilter(depot, iColumn){
998
1000
  var grid = this.grid;
999
1001
  var fieldDef = this.fieldDef;
1000
1002
  var fieldName=fieldDef.name;
1001
- depot.rowSymbols[fieldDef.name]=depot.rowSymbols[fieldDef.name]||'~';
1003
+ depot.rowSymbols[fieldDef.name]=depot.rowSymbols[fieldDef.name]||(fieldDef.typeName == 'text' ? '~' : '=');
1002
1004
  var filterImage=my.path.img+my.comparator.traductor[depot.rowSymbols[fieldDef.name]]+'.png';
1003
1005
  var th=html.td(this.cellAttributes({class:"autoFilter", "typed-controls-direct-input":true},{skipMandatory:true})).create();
1004
1006
  var symbolFilter=th;
@@ -1615,7 +1617,7 @@ myOwn.dialogDownload = function dialogDownload(grid){
1615
1617
  }else{
1616
1618
  separator='|';
1617
1619
  var trans={
1618
- '|':'\\|',
1620
+ '|':'\\x7C',
1619
1621
  '\\':'\\\\',
1620
1622
  '\r':'\\r',
1621
1623
  '\n':'\\n',
@@ -2246,7 +2248,8 @@ myOwn.TableGrid.prototype.createRowInsertElements = function createRowInsertElem
2246
2248
  }
2247
2249
  var depotForInsert = grid.createDepotFromRow({$allow:{delete:true, update:true}}, 'new');
2248
2250
  grid.connector.fixedFields.forEach(function(pair){
2249
- if(!pair.range && grid.def.field[pair.fieldName].inTable !== false){
2251
+ var fieldDef = grid.def.field[pair.fieldName];
2252
+ if(!pair.range && (fieldDef.inTable !== false || fieldDef.isPk && pair.value !=null)){
2250
2253
  depotForInsert.row[pair.fieldName] = pair.value;
2251
2254
  depotForInsert.rowPendingForUpdate[pair.fieldName] = pair.value;
2252
2255
  }
@@ -2385,7 +2388,8 @@ myOwn.TableGrid.prototype.displayGrid = function displayGrid(){
2385
2388
  fixedFields:grid.def.primaryKey.map(function(fieldName, i){
2386
2389
  return {fieldName:fieldName, value:depot.primaryKeyValues[i]};
2387
2390
  }),
2388
- pick:grid.def.pick
2391
+ pick:grid.def.pick,
2392
+ retrieveIgnoringWhere: opts?opts.retrieveIgnoringWhere:false
2389
2393
  }).then(function(result){
2390
2394
  grid.depotRefresh(depot,{updatedRow:result[0], sendedForUpdate:{}}, opts);
2391
2395
  })
@@ -1,4 +1,3 @@
1
- /// <reference types="websql" />
2
1
  import { TableDefinition } from "backend-plus";
3
2
  export type Key = string[];
4
3
  type DetectFeatures = {
@@ -0,0 +1,6 @@
1
+ create or replace function get_app_user() returns text
2
+ stable language sql
3
+ as
4
+ $sql$
5
+ select split_part(current_setting('application_name'),' ',1);
6
+ $sql$;
@@ -12,9 +12,7 @@ export type LangId = 'en'|'es'|'etc...';
12
12
 
13
13
  export type Server=net.Server;
14
14
 
15
- export interface CoreFunctionParameters{
16
- [key:string]: any
17
- }
15
+ export type CoreFunctionParameters<T extends Record<string, any>> = T;
18
16
 
19
17
  export type MarkdownDoc = 'markdown documentation with `` can content newlines. The identation of the first line is deleted in all others'|'etc...';
20
18
 
@@ -35,7 +33,7 @@ export type UploadedFileInfo={
35
33
 
36
34
  }
37
35
  export type CoreFunction = ((context: ProcedureContext, parameters: CoreFunctionParameters) => Promise<any>)
38
- | ((context: ProcedureContext, parameters: CoreFunctionParameters, files?:UploadedFileInfo[]) => Promise<any>);
36
+ | ((context: ProcedureContext, parameters: CoreFunctionParameters, files?:UploadedFileInfo[]) => Promise<any>);
39
37
 
40
38
  export interface ProcedureDef {
41
39
  action: string
@@ -78,7 +76,7 @@ export interface ContextForDump extends Context {
78
76
  forDump?:boolean
79
77
  }
80
78
 
81
- export type InformProgressFunction=(opts:Error|{data:any}|{start:any}|{message:string}|{message?:string, lengthComputable:boolean, loaded:number, total:number, force?:boolean})=>void
79
+ export type InformProgressFunction=(opts:Error|{data:any}|{start:any}|{message:string}|{idGroup?:string, message?:string, lengthComputable:boolean, loaded:number, total:number, force?:boolean})=>void
82
80
 
83
81
  export interface ProcedureContext extends Context{
84
82
  client:Client
@@ -136,7 +134,7 @@ export type MenuInfoPath={
136
134
  path:string
137
135
  } & MenuInfoMinimo;
138
136
  export interface ClientModuleDefinition{
139
- type:'js'|'css'|'ttf'
137
+ type:'js'|'css'|'ttf'|'mjs'
140
138
  module?:string // module where to search in node_modules (node_modules/module/modPath/file) to serve
141
139
  modPath?:string // path inside module where to find file to serve
142
140
  src?:string // full path where browser search file (path/file)
@@ -186,7 +184,7 @@ export type FieldDefinition = EditableDbDefinition & {
186
184
  serverSide?:boolean /* default:!clientSide if the value is retrived from the database */
187
185
  inTable?:boolean /* default:!clientSide && !sql.fields[...].expr. Is a real fisical field in the table */
188
186
  /* sizeByte?:number deprecated size in bytes for numbers */
189
- allowEmtpyText?:boolean /* if a text field accepts '' as a valid value */
187
+ allowEmptyText?:boolean /* if a text field accepts '' as a valid value */
190
188
  mobileInputType?:string
191
189
  extraRow?:number
192
190
  inexactNumber?:number /* default:depends on typeName if = means abs(x-v)<espilon
@@ -212,6 +210,7 @@ export type FieldDefinition = EditableDbDefinition & {
212
210
  inherited?:boolean
213
211
  nameForUpsert?:string
214
212
  alwaysShow?:boolean /* show when appears in fixed fields */
213
+ suggestingKeys?:string[]
215
214
  } & ({} | {
216
215
  sequence:SequenceDefinition
217
216
  nullable:true
@@ -252,22 +251,24 @@ export type Constraint = {constraintType:string, consName?:string} & (
252
251
  {constraintType:'unique', fields:string[], where?:string} |
253
252
  {constraintType:'check', expr?:string}
254
253
  )
254
+ export type OtherTableDefs = Record<string,Partial<TableDefinition & {prefilledField:Record<string,any>}>>
255
255
  export type TableDefinition = EditableDbDefinition & {
256
256
  name:string
257
257
  elementName?:string
258
258
  tableName?:string
259
259
  schema?:string
260
260
  title?:string
261
- fields:FieldDefinition[],
262
- primaryKey:string[],
263
- refrescable?: boolean;
261
+ fields:FieldDefinition[]
262
+ primaryKey:string[]
263
+ refrescable?: boolean
264
264
  sql?:{
265
+ primaryKey4Delete?:string[]
265
266
  isTable?:boolean
266
267
  from?:string
267
268
  where?:string
268
269
  postCreateSqls?:string
269
- skipEnance?: boolean,
270
- isReferable?: boolean,
270
+ skipEnance?: boolean
271
+ isReferable?: boolean
271
272
  logicalDeletes?:{
272
273
  fieldName:string
273
274
  valueToDelete:string
@@ -276,24 +277,26 @@ export type TableDefinition = EditableDbDefinition & {
276
277
  fieldName:string
277
278
  }
278
279
  tableName?:string
280
+ tableName4Delete?:string
279
281
  fields?:{
280
282
  [k:string]:{
281
283
  expr:string
282
284
  }
283
- },
285
+ }
284
286
  orderBy?:string[]
285
287
  viewBody?:string
286
288
  insertIfNotUpdate?:boolean
287
289
  policies?:{
288
- all ?:{using?:string, check?:string}
289
- select?:{using?:string}
290
- insert?:{ check?:string}
291
- update?:{using?:string, check?:string}
292
- delete?:{using?:string}
290
+ all ?:{name?:string, using?:string, check?:string}
291
+ select?:{name?:string, using?:string}
292
+ insert?:{name?:string, check?:string}
293
+ update?:{name?:string, using?:string, check?:string}
294
+ delete?:{name?:string, using?:string}
293
295
  }
294
296
  join?:string
295
297
  constraintsDeferred?:boolean
296
- otherTableDefs?:Record<string,Partial<TableDefinition & {prefilledField:Record<string,any>}>>
298
+ otherTableDefs?:OtherTableDefs
299
+ setExpectedPkValues?:boolean
297
300
  }
298
301
  foreignKeys?:ForeignKey[]
299
302
  softForeignKeys?:ForeignKey[]
@@ -319,10 +322,9 @@ export type TableDefinition = EditableDbDefinition & {
319
322
  specialValidator?:string
320
323
  saveAfter?:boolean
321
324
  selfRefresh?:boolean
322
- filterColumns?:{column:string, operator:string, value:any}[],
325
+ filterColumns?:{column:string, operator:string, value:any}[]
323
326
  gridAlias?:string /* front-end css my-table = gridAlias */
324
327
  }
325
- export type OtherTableDefs = TableDefinition['sql']['otherTableDefs']
326
328
  export interface DetailTable { table?: string, fields: FieldsForConnectDetailTable, abr: string, label?: string, refreshParent?:boolean, refreshFromParent?:boolean, wScreen?:string, condition?:string }
327
329
  export type TableDefinitionFunction = (context: ContextForDump, opts?:any) => TableDefinition;
328
330
  export type TableItemDef=string|{name:string, path?:string, tableGenerator?:(context:TableContext)=>TableDefinition}
@@ -365,6 +367,129 @@ export interface Caches {
365
367
  procedures:Record<string, {timestamp:number, result:any}>
366
368
  }
367
369
 
370
+ export interface AppConfigBin { // executables in SO
371
+ "zip-password-parameter-flag": string // parameter to pass the password to the zipper
372
+ "zip-password-prefix": string // password prefix
373
+ "zip-fixed-parameters":string // fixed parameters to pass to zipper
374
+ }
375
+
376
+ export interface AppConfig {
377
+ package: {
378
+ version: string
379
+ }
380
+ server: {
381
+ "base-url": string // rool path in the url
382
+ port: number // port of the API services
383
+ "session-store": string // strategies to store session info
384
+ "ip-replacer": string // ip that can be not showed or deduced in logs
385
+ "silent-startup": boolean // less logs when startup
386
+ "kill-9": string // a way to kill from URL with a token
387
+ bitacoraSchema: string
388
+ bitacoraTableName: string
389
+ }
390
+ db: {
391
+ motor: 'postgresql'
392
+ database: string
393
+ user: string
394
+ password: string
395
+ schema: string
396
+ search_path: string
397
+ tablespace: string // for creation scripts
398
+ "min-version": string // min version of the motor needed
399
+ nodb: boolean // if there is no database needed in the app
400
+ no_login: boolean // if no login is needed. Used only for all public sites
401
+ "downloadable-backup-path": string // OS path of the encrypted downloadable backup
402
+ }
403
+ login: {
404
+ schema: string // schema of the user table
405
+ table: string // user table
406
+ userFieldname: string // fieldname in user table that stores the user name
407
+ passFieldname: string // fieldname in user table that stores the password hash
408
+ rolFieldname: string // fieldname in user table that stores the rol
409
+ unloggedLandPage: string // land page when there is no user logged when the backend has public services
410
+ noLoggedUrlPath: string // path of non logged users when the backend has no public services
411
+ "preserve-case": boolean // preserve the case of the user name
412
+ activeClausule: string // SQL expression over the user table to check if a user is active
413
+ lockedClausule: string // SQL expression over the user table to check if a user is locked
414
+ disableChangePassword: boolean // disallow password change
415
+ skipBitacora: boolean // don't register logins
416
+ keepAlive: number // secs to keep alive a session if only keep alive request where received
417
+ plus: {
418
+ userFieldName:string
419
+ store:{
420
+ module: string
421
+ }
422
+ }
423
+ forget: { // forget password configurations:
424
+ urlPath: string // url sent by mail. default: `/new-pass`
425
+ urlPathOk: string // confirmation page
426
+ mailFields: string[] // fields for the forget pass mail
427
+
428
+ }
429
+ "double-dragon": boolean // app user must match db user
430
+ }
431
+ install: {
432
+ "table-data-dir": string // SO path to the .tab files in the db creation script
433
+ dump: { // configuration of --dump-db, the db creation script
434
+ "drop-his": boolean // include drop schema his in the db creation script
435
+ db: {
436
+ owner: string
437
+ extensions: string[] // extensions to be installed (gist, pg_trgm, pgcrypto)
438
+ enances: 'file' // if the enances must be dumped in a separate file
439
+ // from here info to set the owner and replace owner and user used in devel when script creation
440
+ "owner4special-scripts": string
441
+ "user4special-scripts": string
442
+ "apply-generic-user-replaces": string
443
+ }
444
+ "admin-can-create-tables": boolean // for apps that allows the user to create tables
445
+ "skip-content": boolean // don't create data from "table-data-dir"
446
+ folders: string //
447
+ scripts: {
448
+ prepare: string // SO path to the prepare scripts that will be run before the functions creations and inserts
449
+ "post-adapt": string // SO path to the post-adapt scripts that will be run after data inserts (of .tab tables)
450
+ }
451
+ }
452
+ }
453
+ "client-setup": { // front-end config
454
+ title:string // title of the app (common sufix of the title bar)
455
+ }
456
+ log: {
457
+ "serve-content": never
458
+ req: {
459
+ "keep-alive": boolean
460
+ }
461
+ db: {
462
+ "last-error": boolean // store last db error in a log file
463
+ devel: boolean //
464
+ "on-demand": string // if log db level can be changed on the fly
465
+ until: string | Date // full log until...
466
+ results: boolean // if query results must be included in full db logs
467
+ }
468
+ session: boolean // if all session activity must be logged
469
+ }
470
+ devel: {
471
+ delay: number // msec avg random delay in API responses (to emulate slow nets)
472
+ "cache-content": boolean // if the cache header must be sent to the client (when no devel config the default is true)
473
+ forceShowAsEditable: boolean // force "editable" behavior in grids
474
+ }
475
+ mailer: { // config to send mails
476
+ conn: string // connection string
477
+ "mail-info": {} // static mail config
478
+ supervise: {
479
+ to: string // email addres of the supervisor
480
+ event: {
481
+ }
482
+ }
483
+ }
484
+ bin: AppConfigBin
485
+ data: {
486
+ transformers: {
487
+ text: string // define the inputTransformers for text comming from the fron-end via the API
488
+ }
489
+ }
490
+ skipUnknownFieldsAtImport: boolean // if unknown fields must be skipped by default in import
491
+ }
492
+
368
493
  export class AppBackend{
369
494
  procedures:ProcedureDef[]
370
495
  procedure:{ [key:string]:ProcedureDef }
@@ -372,7 +497,7 @@ export class AppBackend{
372
497
  getTableDefinition: TableDefinitionsGetters
373
498
  tableStructures: TableDefinitions
374
499
  db: MotorDb
375
- config: any
500
+ config: AppConfig
376
501
  rootPath: string
377
502
  caches:Caches
378
503
  fieldDomain:{[k:string]:Partial<FieldDefinition>}
@@ -420,7 +545,8 @@ export class AppBackend{
420
545
  i18n:{
421
546
  messages:Record<LangId,Record<string, string>>
422
547
  }
423
- shootDownBackend():Promise<void>
548
+ shutdownCallbackListAdd(param:{message:string, fun:()=>Promise<void>}):void
549
+ shutdownBackend():Promise<void>
424
550
  setLog(opts:{until:string, results?:boolean}):void
425
551
  getDataDumpTransformations(rawData:string):Promise<{rawData:string, prepareTransformationSql:string[], endTransformationSql:string[]}>
426
552
  }