5htp-core 0.2.1 → 0.2.2-1

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 (68) hide show
  1. package/package.json +10 -3
  2. package/src/client/app/index.ts +2 -2
  3. package/src/client/assets/css/components/card.less +0 -3
  4. package/src/client/assets/css/components/other.less +2 -4
  5. package/src/client/assets/css/components/table.less +1 -2
  6. package/src/client/assets/css/components.less +4 -0
  7. package/src/client/assets/css/core.less +0 -1
  8. package/src/client/assets/css/theme.less +2 -2
  9. package/src/client/assets/css/utils/medias.less +21 -0
  10. package/src/client/components/Card/index.tsx +8 -5
  11. package/src/client/components/Dialog/index.less +3 -3
  12. package/src/client/components/Row/index.less +2 -0
  13. package/src/client/components/Row/index.tsx +44 -10
  14. package/src/client/components/Video/index.less +39 -0
  15. package/src/client/components/Video/index.tsx +69 -0
  16. package/src/client/components/containers/Popover/index.tsx +2 -2
  17. package/src/client/components/data/Time.tsx +1 -1
  18. package/src/client/components/data/progressbar/circular/index.tsx +1 -1
  19. package/src/client/components/index.ts +24 -8
  20. package/src/client/components/input/BaseV2/index.tsx +0 -1
  21. package/src/client/components/{input/BaseV2/index.less → inputv3/base.less} +1 -1
  22. package/src/client/components/inputv3/base.tsx +73 -0
  23. package/src/client/components/{input/UploadImage → inputv3/file}/Bouton.tsx +0 -0
  24. package/src/client/components/inputv3/file/FileToUpload.ts +34 -0
  25. package/src/client/components/inputv3/file/index.less +59 -0
  26. package/src/client/components/inputv3/file/index.tsx +157 -0
  27. package/src/client/components/{input → inputv3/string}/index.tsx +41 -27
  28. package/src/client/pages/bug.tsx +3 -4
  29. package/src/client/services/router/index.tsx +0 -1
  30. package/src/client/services/router/request/api.ts +20 -12
  31. package/src/client/services/router/request/multipart.ts +27 -0
  32. package/src/common/data/chaines/greetings.ts +1 -1
  33. package/src/common/data/dates.ts +1 -1
  34. package/src/common/data/input/validate.ts +0 -9
  35. package/src/common/data/markdown.ts +1 -1
  36. package/src/common/errors/index.ts +16 -12
  37. package/src/common/router/request/api.ts +11 -3
  38. package/src/common/validation/schema.ts +21 -20
  39. package/src/common/validation/validators.ts +3 -6
  40. package/src/server/app/commands.ts +149 -0
  41. package/src/server/app/index.ts +25 -5
  42. package/src/server/app/service.ts +4 -0
  43. package/src/server/services/cache/commands.ts +41 -0
  44. package/src/server/services/cache/index.ts +102 -34
  45. package/src/server/services/console/index.ts +1 -1
  46. package/src/server/services/database/connection.ts +38 -22
  47. package/src/server/services/database/datatypes.ts +51 -12
  48. package/src/server/services/database/index.ts +133 -40
  49. package/src/server/services/database/metas.ts +63 -37
  50. package/src/server/services/database/repository.ts +26 -0
  51. package/src/server/services/email/index.ts +102 -42
  52. package/src/server/services/fetch/index.ts +110 -0
  53. package/src/server/services/router/http/multipart.ts +70 -41
  54. package/src/server/services/router/index.ts +35 -4
  55. package/src/server/services/router/request/index.ts +8 -6
  56. package/src/server/services/schema/index.ts +4 -11
  57. package/src/server/services/schema/request.ts +16 -7
  58. package/src/server/services/schema/router.ts +6 -2
  59. package/src/server/{services_old → services/security/encrypt}/aes.ts +33 -14
  60. package/src/server/services/users/index.ts +3 -3
  61. package/src/server/services/users/router/index.ts +0 -2
  62. package/src/types/global/utils.d.ts +11 -1
  63. package/tsconfig.common.json +3 -0
  64. package/src/client/components/input/Textarea.tsx +0 -57
  65. package/src/client/components/input/Upload.tsx +0 -5
  66. package/src/client/components/input/UploadImage/index.less +0 -93
  67. package/src/client/components/input/UploadImage/index.tsx +0 -220
  68. package/src/common/data/file.ts +0 -25
@@ -3,7 +3,7 @@
3
3
  ----------------------------------*/
4
4
 
5
5
  // Core
6
- import { Erreur, TListeErreursSaisie, InputErrorSchema } from '@common/errors';
6
+ import { CoreError, TListeErreursSaisie, InputErrorSchema } from '@common/errors';
7
7
 
8
8
  // Specific
9
9
  import { default as Validator, EXCLUDE_VALUE } from './validator';
@@ -15,10 +15,12 @@ import { default as Validator, EXCLUDE_VALUE } from './validator';
15
15
  export type TSchemaFields = { [fieldName: string]: Schema<{}> | Validator<any> }
16
16
 
17
17
  type TOptsValider = {
18
- critique?: boolean,
19
- validationComplete?: boolean,
20
- avecDependances?: boolean,
21
- corriger?: boolean,
18
+ debug?: boolean,
19
+ throwError?: boolean,
20
+
21
+ validateAll?: boolean,
22
+ validateDeps?: boolean,
23
+ autoCorrect?: boolean,
22
24
  }
23
25
 
24
26
  export type TValidationResult<TFields extends TSchemaFields> = {
@@ -36,8 +38,6 @@ export type TValidatedData<TFields extends TSchemaFields> = {
36
38
  - CONST
37
39
  ----------------------------------*/
38
40
 
39
- const debug = true;
40
-
41
41
  const LogPrefix = '[schema][validator]';
42
42
 
43
43
  /*----------------------------------
@@ -63,14 +63,15 @@ export default class Schema<TFields extends TSchemaFields> {
63
63
  ): TValidationResult<TFields> {
64
64
 
65
65
  opts = {
66
- critique: false,
67
- validationComplete: false,
68
- avecDependances: true,
69
- corriger: false,
66
+ debug: false,
67
+ throwError: false,
68
+ validateAll: false,
69
+ validateDeps: true,
70
+ autoCorrect: false,
70
71
  ...opts,
71
72
  }
72
73
 
73
- const clesAvalider = Object.keys(opts.validationComplete === true ? this.fields : dataToValidate);
74
+ const clesAvalider = Object.keys(opts.validateAll === true ? this.fields : dataToValidate);
74
75
 
75
76
  let outputSchema = output;
76
77
  for (const branche of chemin)
@@ -84,7 +85,7 @@ export default class Schema<TFields extends TSchemaFields> {
84
85
  // La donnée est répertoriée dans le schema
85
86
  const field = this.fields[champ];
86
87
  if (field === undefined) {
87
- debug && console.warn(LogPrefix, '[' + champ + ']', 'Exclusion (pas présent dans le schéma)');
88
+ opts.debug && console.warn(LogPrefix, '[' + champ + ']', 'Exclusion (pas présent dans le schéma)');
88
89
  continue;
89
90
  }
90
91
 
@@ -140,24 +141,24 @@ export default class Schema<TFields extends TSchemaFields> {
140
141
  // Validation
141
142
  try {
142
143
 
143
- const val = field.validate(valOrigine, allData, output, opts.corriger);
144
+ const val = field.validate(valOrigine, allData, output, opts.autoCorrect);
144
145
 
145
146
  // Exclusion seulement si explicitement demandé
146
147
  // IMPORTANT: Conserver les values undefined
147
148
  // La présence d'un valeur undefined peut être utile, par exemple, pour indiquer qu'on souhaite supprimer une donnée
148
149
  // Exemple: undefinec = suppression fichier | Absende donnée = conservation fihcier actuel
149
150
  if (val === EXCLUDE_VALUE)
150
- debug && console.log(LogPrefix, '[' + cheminA + '] Exclusion demandée');
151
+ opts.debug && console.log(LogPrefix, '[' + cheminA + '] Exclusion demandée');
151
152
  else
152
153
  outputSchema[champ] = val;
153
154
 
154
- debug && console.log(LogPrefix, '[' + cheminA + ']', valOrigine, '=>', val);
155
+ opts.debug && console.log(LogPrefix, '[' + cheminA + ']', valOrigine, '=>', val);
155
156
 
156
157
  } catch (error) {
157
158
 
158
- debug && console.warn(LogPrefix, '[' + cheminA + ']', valOrigine, '|| Erreur:', error);
159
+ opts.debug && console.warn(LogPrefix, '[' + cheminA + ']', valOrigine, '|| CoreError:', error);
159
160
 
160
- if (error instanceof Erreur) {
161
+ if (error instanceof CoreError) {
161
162
 
162
163
  // Référencement erreur
163
164
  erreurs[cheminAstr] = [error.message]
@@ -169,11 +170,11 @@ export default class Schema<TFields extends TSchemaFields> {
169
170
  }
170
171
  }
171
172
 
172
- if (nbErreurs !== 0 && opts.critique === true) {
173
+ if (nbErreurs !== 0 && opts.throwError === true) {
173
174
  throw new InputErrorSchema(erreurs);
174
175
  }
175
176
 
176
- debug && console.log(LogPrefix, '', dataToValidate, '=>', output);
177
+ opts.debug && console.log(LogPrefix, '', dataToValidate, '=>', output);
177
178
 
178
179
  return {
179
180
  values: output as TValidatedData<TFields>,
@@ -12,8 +12,7 @@ import {
12
12
 
13
13
  // Core
14
14
  import { InputError } from '@common/errors';
15
- import File from '@common/data/file';
16
- import NormalizedFile from '@common/data/file';
15
+ import FileToUpload from '@client/components/inputv3/file/FileToUpload';
17
16
 
18
17
  // Speciific
19
18
  import Validator, { TValidator } from './validator'
@@ -26,7 +25,7 @@ import Dropdown from '@client/components/dropdown.old';
26
25
  - TYPES
27
26
  ----------------------------------*/
28
27
 
29
- export type TFileValidator = TValidator<NormalizedFile> & {
28
+ export type TFileValidator = TValidator<FileToUpload> & {
30
29
  type?: (keyof typeof raccourcisMime) | string[], // Raccourci, ou liste de mimetype
31
30
  taille?: number
32
31
  }
@@ -274,9 +273,7 @@ export default class SchemaValidator {
274
273
  output: TObjetDonnees
275
274
  ): File | undefined => {
276
275
 
277
- console.log('VALIDER FICHIER', type, val);
278
-
279
- if (!(val instanceof NormalizedFile))
276
+ if (!(val instanceof FileToUpload))
280
277
  throw new InputError(`Must be a File (${typeof val} received)`);
281
278
 
282
279
  // MIME
@@ -0,0 +1,149 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import yargsParser from 'yargs-parser';
7
+
8
+ // Core
9
+ import Application, { Service } from '@server/app';
10
+ import { NotFound } from '@common/errors';
11
+
12
+ /*----------------------------------
13
+ - TYPES
14
+ ----------------------------------*/
15
+
16
+ type CommandCallback<TArgs extends any[]> = (...args: TArgs) => Promise<any>
17
+
18
+ export type CommandsList = {
19
+ [commandName: string]: Command
20
+ }
21
+
22
+ export type Command<TArgs extends any[] = any[]> = {
23
+ name: string,
24
+ description: string,
25
+ run?: CommandCallback<TArgs>
26
+ childrens: CommandsList
27
+ }
28
+
29
+ /*----------------------------------
30
+ - SERVICE TYPES
31
+ ----------------------------------*/
32
+
33
+ const LogPrefix = `[commands]`;
34
+
35
+ export type Config = {
36
+ debug: boolean
37
+ }
38
+
39
+ export type Hooks = {
40
+
41
+ }
42
+
43
+ /*----------------------------------
44
+ - SERVICE
45
+ ----------------------------------*/
46
+ export default class CommandsManager extends Service<Config, Hooks, Application> {
47
+
48
+ public priority = 2 as 2;
49
+
50
+ public commandsIndex: CommandsList = {}
51
+
52
+ public async register() {
53
+
54
+
55
+
56
+ }
57
+
58
+ public async start() {
59
+
60
+ }
61
+
62
+ /*----------------------------------
63
+ - DEFINITIONS
64
+ ----------------------------------*/
65
+ public command<TArgs extends any[]>(
66
+ ...args: (
67
+ [name: string, description: string, childrens: Command[]]
68
+ |
69
+ [name: string, description: string, run: CommandCallback<TArgs>, childrens?: Command[]]
70
+ )
71
+ ): Command {
72
+
73
+ let name: string, description: string;
74
+ let childrens: Command[] | undefined;
75
+ let run: CommandCallback<TArgs> | undefined;
76
+
77
+ if (typeof args[2] === 'object')
78
+ ([name, description, childrens] = args)
79
+ else
80
+ ([name, description, run, childrens] = args)
81
+
82
+ const command: Command = {
83
+ name,
84
+ description,
85
+ run,
86
+ childrens: childrens ? this.indexFromList(childrens) : {}
87
+ }
88
+
89
+ return command;
90
+ }
91
+
92
+ private indexFromList( list: Command[] ): CommandsList {
93
+
94
+ const index: CommandsList = {}
95
+ for (const command of list)
96
+ index[ command.name ] = command;
97
+
98
+ return index;
99
+ }
100
+
101
+ /*----------------------------------
102
+ - REGISTER
103
+ ----------------------------------*/
104
+ public fromList( list: Command[] ) {
105
+ for (const command of list) {
106
+
107
+ if (this.commandsIndex[ command.name ] !== undefined)
108
+ throw new Error(`Tried to register command "${command.name}", but it already has been defined.`);
109
+
110
+ this.commandsIndex[ command.name ] = command;
111
+ }
112
+ }
113
+
114
+ /*----------------------------------
115
+ - RUN
116
+ ----------------------------------*/
117
+ public async run( commandString: string ) {
118
+
119
+ const { _, ...args } = yargsParser(commandString);
120
+
121
+ this.config.debug && console.log(LogPrefix, `Run command: ${commandString} | Parsed:`, { _, ...args });
122
+
123
+ let command: Command | undefined;
124
+ for (const commandName of _) {
125
+
126
+ const commandsList: CommandsList = command === undefined
127
+ ? this.commandsIndex
128
+ : command.childrens;
129
+
130
+ command = commandsList[commandName];
131
+
132
+ if (command === undefined)
133
+ break;
134
+ }
135
+
136
+ if (command === undefined)
137
+ throw new NotFound(`Command not found.`);
138
+
139
+ if (command.run === undefined)
140
+ throw new NotFound(`This command isn't runnable.`);
141
+
142
+ // TODO: order correctly & validate type according to injected typescript typedefs (command.run.params)
143
+ const argsList = Object.values(args);
144
+
145
+ const result = await command.run(argsList);
146
+
147
+ return result;
148
+ }
149
+ }
@@ -10,13 +10,17 @@ import fs from 'fs-extra';
10
10
  // Core
11
11
  import ConfigParser, { TEnvConfig } from './config';
12
12
  import { default as Service, AnyService } from './service';
13
+ import CommandsManager from './commands';
14
+
15
+ // Built-in
13
16
  import type { default as Router, Request as ServerRequest } from '@server/services/router';
14
17
 
15
18
  /*----------------------------------
16
19
  - TYPES
17
20
  ----------------------------------*/
18
21
 
19
- export { default as Service, TPriority } from './service';
22
+ export { default as Service } from './service';
23
+ export type { TPriority } from './service';
20
24
 
21
25
  type Config = {
22
26
 
@@ -61,6 +65,8 @@ export default abstract class Application extends Service<Config, Hooks, /* TODO
61
65
 
62
66
  public path = {
63
67
  root: process.cwd(),
68
+ typings: process.cwd() + '/var/typings',
69
+ cache: process.cwd() + '/var/cache',
64
70
  data: process.cwd() + '/var/data',
65
71
  log: process.cwd() + '/var/log',
66
72
  public: process.cwd() + '/public',
@@ -81,7 +87,7 @@ export default abstract class Application extends Service<Config, Hooks, /* TODO
81
87
  ----------------------------------*/
82
88
 
83
89
  public env: TEnvConfig;
84
- public abstract identity: Config.Identity;
90
+ public identity: Config.Identity;
85
91
 
86
92
  public constructor() {
87
93
 
@@ -90,15 +96,14 @@ export default abstract class Application extends Service<Config, Hooks, /* TODO
90
96
 
91
97
  // Gestion crash
92
98
  process.on('unhandledRejection', (error: any, promise: any) => {
93
-
94
- console.error("Unhandled promise rejection:", error);
99
+ // We don't log the error here because it's the role of the app to decidehiw to log errors
95
100
  this.runHook('error', error);
96
-
97
101
  });
98
102
 
99
103
  // Load config files
100
104
  const configParser = new ConfigParser( this.path.root );
101
105
  this.env = configParser.env();
106
+ this.identity = configParser.identity();
102
107
  }
103
108
 
104
109
  /*----------------------------------
@@ -111,6 +116,16 @@ export default abstract class Application extends Service<Config, Hooks, /* TODO
111
116
  return this[ serviceName ];
112
117
  }
113
118
 
119
+ /*----------------------------------
120
+ - COMMANDS
121
+ ----------------------------------*/
122
+
123
+ private commandsManager = new CommandsManager(this, { debug: true });
124
+
125
+ public command( ...args: Parameters<CommandsManager["command"]> ) {
126
+ return this.commandsManager.command(...args);
127
+ }
128
+
114
129
  /*----------------------------------
115
130
  - LAUNCH
116
131
  ----------------------------------*/
@@ -153,6 +168,11 @@ export default abstract class Application extends Service<Config, Hooks, /* TODO
153
168
  if (service.register)
154
169
  service.register();
155
170
 
171
+ // Register commands
172
+ if (service.commands)
173
+ this.commandsManager.fromList(service.commands);
174
+
175
+ // Start service
156
176
  if (service.start) {
157
177
  service.started = service.start();
158
178
  await service.started;
@@ -2,7 +2,9 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
+ // Specific
5
6
  import Application from ".";
7
+ import type { Command } from "./commands";
6
8
 
7
9
  /*----------------------------------
8
10
  - TYPES: OPTIONS
@@ -40,6 +42,8 @@ export default abstract class Service<
40
42
  public priority: TPriority = 0;
41
43
  public started?: Promise<void>;
42
44
 
45
+ public commands?: Command[];
46
+
43
47
  public constructor(
44
48
  public app: TApplication,
45
49
  public config: TConfig,
@@ -0,0 +1,41 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import sizeOf from 'object-sizeof';
7
+
8
+ // Core
9
+
10
+ // Specific
11
+ import type CacheManager from '.';
12
+
13
+ /*----------------------------------
14
+ - TYPES
15
+ ----------------------------------*/
16
+
17
+ /*----------------------------------
18
+ - SERVICE
19
+ ----------------------------------*/
20
+ export default (cache: CacheManager, app = cache.app) => [
21
+
22
+ app.command('cache', 'Manage the cache service', [
23
+
24
+ app.command('list', 'List cache entries', async () => {
25
+
26
+ return Object.entries(cache.data).map(([ key, entry ]) => ({
27
+ key,
28
+ type: typeof entry?.value,
29
+ size: sizeOf(entry?.value),
30
+ expires: entry?.expiration || 'No expiration'
31
+ }))
32
+ }),
33
+
34
+ app.command('delete', 'List cache entries', async (key?: string) => {
35
+
36
+ await cache.del(key);
37
+
38
+ return true;
39
+ })
40
+ ])
41
+ ]
@@ -12,7 +12,8 @@ import fs from 'fs-extra';
12
12
  // Core
13
13
  import Application, { Service } from '@server/app';
14
14
 
15
- // Libs
15
+ // Specific
16
+ import registerCommands from './commands';
16
17
 
17
18
  /*----------------------------------
18
19
  - CONFIG
@@ -30,13 +31,26 @@ type TPrimitiveValue = string | boolean | number | undefined | TPrimitiveValue[]
30
31
 
31
32
  type TExpirationDelay = 'never' | string | number | Date;
32
33
 
33
- type CacheEntry = {
34
+ type CacheEntry<TValue extends TPrimitiveValue =TPrimitiveValue > = {
34
35
  // Value
35
- value: TPrimitiveValue,
36
+ value: TValue,
36
37
  // Expiration Timestamp
37
- expiration?: number
38
+ expiration?: number,
39
+ changes: number
38
40
  };
39
41
 
42
+ type TCacheGetOrUpdateArgs<TValeur extends TPrimitiveValue> = [
43
+ cle: string,
44
+ func: (() => Promise<TValeur>),
45
+ expiration?: TExpirationDelay,
46
+ avecDetails?: boolean
47
+ ]
48
+
49
+ type TCacheGetOnlyArgs = [
50
+ cle: string,
51
+ avecDetails: true
52
+ ]
53
+
40
54
  /*----------------------------------
41
55
  - TYPES
42
56
  ----------------------------------*/
@@ -53,15 +67,16 @@ export type Hooks = {
53
67
  - SERVICE
54
68
  ----------------------------------*/
55
69
  export default class Cache extends Service<Config, Hooks, Application> {
56
-
57
- private cacheFile = path.join(this.app.path.data, 'cache/mem.json');
58
70
 
59
- private data: {[key: string]: CacheEntry | undefined} = {};
71
+ public commands = registerCommands(this);
72
+
73
+ private cacheDir = this.app.path.cache;
60
74
 
61
- private changes: number = 0;
75
+ public data: {[key: string]: CacheEntry | undefined} = {};
62
76
 
63
77
  public async register() {
64
78
 
79
+
65
80
 
66
81
  }
67
82
 
@@ -70,8 +85,20 @@ export default class Cache extends Service<Config, Hooks, Application> {
70
85
  setInterval(() => this.cleanMem(), 10000);
71
86
 
72
87
  // Restore persisted data
73
- if (fs.existsSync(this.cacheFile))
74
- this.data = fs.readJSONSync(this.cacheFile)
88
+ await this.restore();
89
+ }
90
+
91
+ private restore() {
92
+ const files = fs.readdirSync( this.cacheDir );
93
+ for (const file of files) {
94
+
95
+ if (!file.endsWith('.json'))
96
+ continue;
97
+
98
+ const entryKey = file.substring(0, file.length - 5);
99
+ this.data[ entryKey ] = fs.readJSONSync( path.join(this.cacheDir, file) );
100
+ console.log(LogPrefix, `Restored cache entry ${entryKey}`);
101
+ }
75
102
  }
76
103
 
77
104
  private cleanMem() {
@@ -87,13 +114,29 @@ export default class Cache extends Service<Config, Hooks, Application> {
87
114
  }
88
115
 
89
116
  // Write changes
90
- if (this.changes > 0) {
91
- fs.outputJSONSync(this.cacheFile, this.data);
92
- this.config.debug && console.log(LogPrefix, `Flush ${this.changes} changes`);
93
- this.changes = 0;
117
+ for (const entryKey in this.data) {
118
+
119
+ const entry = this.data[entryKey];
120
+ if (!entry?.changes)
121
+ continue;
122
+
123
+ this.config.debug && console.log(LogPrefix, `Flush ${entry.changes} changes for ${entryKey}`);
124
+
125
+ entry.changes = 0;
126
+ const entryFile = this.getEntryFile(entryKey);
127
+ fs.outputJSONSync(entryFile , this.data[entryKey]);
94
128
  }
95
129
  }
96
130
 
131
+ private getEntryFile( entryKey: string ) {
132
+ return path.join(this.cacheDir, entryKey + '.json');
133
+ }
134
+
135
+ public get<TValeur extends TPrimitiveValue>(
136
+ cle: string,
137
+ avecDetails?: true
138
+ ): Promise<CacheEntry<TValeur> | TValeur | undefined>;
139
+
97
140
  // Expiration = Durée de vie en secondes ou date max
98
141
  // Retourne null quand pas de valeur
99
142
  public get<TValeur extends TPrimitiveValue>(
@@ -101,7 +144,7 @@ export default class Cache extends Service<Config, Hooks, Application> {
101
144
  func: (() => Promise<TValeur>),
102
145
  expiration: TExpirationDelay,
103
146
  avecDetails: true
104
- ): Promise<CacheEntry>;
147
+ ): Promise<CacheEntry<TValeur>>;
105
148
 
106
149
  public get<TValeur extends TPrimitiveValue>(
107
150
  cle: string,
@@ -110,14 +153,25 @@ export default class Cache extends Service<Config, Hooks, Application> {
110
153
  avecDetails?: false
111
154
  ): Promise<TValeur>;
112
155
 
113
- public async get<TValeur extends TPrimitiveValue>(
114
- cle: string,
115
- func: (() => Promise<TValeur>),
116
- expiration: TExpirationDelay = 'never',
117
- avecDetails?: boolean
118
- ): Promise<TValeur | CacheEntry> {
156
+ public async get<TValeur extends TPrimitiveValue, TArgs extends TCacheGetOnlyArgs | TCacheGetOrUpdateArgs<TValeur> = TCacheGetOnlyArgs | TCacheGetOrUpdateArgs<TValeur>>(
157
+ ...args: TArgs
158
+ ): Promise< TValeur | CacheEntry<TValeur> | (TArgs extends TCacheGetOnlyArgs ? undefined : TValeur)> {
159
+
160
+ let cle: string;
161
+ let func: (() => Promise<TValeur>) | undefined;
162
+ let expiration: TExpirationDelay | undefined;
163
+ let avecDetails: boolean | undefined = true;
119
164
 
120
- let entry: CacheEntry | undefined = this.data[cle];
165
+ if (typeof args[1] === 'function') {
166
+ ([ cle, func, expiration, avecDetails ] = args);
167
+ } else {
168
+ ([ cle, avecDetails ] = args);
169
+ }
170
+
171
+ if (expiration === undefined)
172
+ expiration = 'never';
173
+
174
+ let entry: CacheEntry<TValeur> | undefined = this.data[cle];
121
175
 
122
176
  // Expired
123
177
  if (entry?.expiration && entry.expiration < Date.now()){
@@ -126,22 +180,26 @@ export default class Cache extends Service<Config, Hooks, Application> {
126
180
  }
127
181
 
128
182
  // Donnée inexistante
129
- if (entry === undefined) {
183
+ if (entry !== undefined) {
184
+
185
+ this.config.debug && console.log(LogPrefix, `Get "${cle}": restored via cache`);
186
+
187
+ } else if (func !== undefined) {
130
188
 
131
189
  this.config.debug && console.log(LogPrefix, `Get "${cle}": refresh value`);
132
190
 
133
191
  // Rechargement
134
192
  entry = {
135
193
  value: await func(),
136
- expiration: this.delayToTimestamp(expiration)
194
+ expiration: this.delayToTimestamp(expiration),
195
+ changes: 0
137
196
  }
138
197
 
139
- // undefined retourné = pas d'enregistrement
140
- //if (entry.value !== undefined)
198
+ if (expiration !== 'now')
141
199
  await this.set(cle, entry.value, expiration);
142
200
 
143
201
  } else
144
- this.config.debug && console.log(LogPrefix, `Get "${cle}": restored via cache`);
202
+ return undefined;
145
203
 
146
204
  return avecDetails
147
205
  ? entry
@@ -160,19 +218,29 @@ export default class Cache extends Service<Config, Hooks, Application> {
160
218
  * @returns A void promise
161
219
  */
162
220
  public set( cle: string, val: TPrimitiveValue, expiration: TExpirationDelay = 'never' ): void {
163
-
221
+
222
+ // TODO: check is key contains illegal characters
223
+
164
224
  this.config.debug && console.log(LogPrefix, "Updating cache " + cle);
165
225
  this.data[ cle ] = {
166
226
  value: val,
167
- expiration: this.delayToTimestamp(expiration)
227
+ expiration: this.delayToTimestamp(expiration),
228
+ changes: 1
168
229
  }
169
-
170
- this.changes++;
171
230
  };
172
231
 
173
- public del( cle: string ): void {
174
- this.data[ cle ] = undefined;
175
- this.changes++;
232
+ public del( key?: string ): void {
233
+
234
+ if (key === undefined) {
235
+ this.data = {};
236
+ console.log(LogPrefix, "Deleting all keys from cache");
237
+ fs.removeSync( this.cacheDir );
238
+ } else {
239
+ this.data[ key ] = undefined;
240
+ console.log(LogPrefix, `Deleting key "${key}" from cache`);
241
+ const entryFile = this.getEntryFile(key);
242
+ fs.removeSync( entryFile );
243
+ }
176
244
  }
177
245
 
178
246
 
@@ -305,7 +305,7 @@ export default class Console extends Service<Config, Hooks, Application> {
305
305
  }
306
306
 
307
307
  public printSql = (requete: string) => highlight(
308
- formatSql(requete, { indent: ' '.repeat(4) }),
308
+ requete,//formatSql(requete, { indent: ' '.repeat(4) }),
309
309
  { language: 'sql', ignoreIllegals: true }
310
310
  )
311
311