5htp-core 0.2.1 → 0.2.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.
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 +23 -4
  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
@@ -8,6 +8,7 @@ import type mysql from 'mysql2/promise';
8
8
 
9
9
  // Core
10
10
  import Application from '@server/app';
11
+ import { ucfirst } from '@common/data/chaines';
11
12
 
12
13
  // Database
13
14
  import type DatabaseConnection from './connection';
@@ -66,12 +67,14 @@ export type TMetasColonne = {
66
67
  // Column
67
68
  table: TMetasTable,
68
69
  nom: string,
70
+ pathname: string,
69
71
  attached: boolean, // Si les métadonnées ont bien été enrichies avec celles provenant de MySQL
70
72
  primary: boolean,
71
73
 
72
74
  // Type
73
75
  type: TColumnTypes,
74
76
  nullable: boolean,
77
+ optional: boolean,
75
78
 
76
79
  // Value
77
80
  defaut?: any, // ATTENTION: Valeur déjà sérialisée
@@ -88,12 +91,14 @@ export type TColumnTypes = {
88
91
 
89
92
  export type TMySQLType = {
90
93
  name: TMySQLTypeName,
91
- params: string[]
94
+ params?: string[],
95
+ raw: string
92
96
  }
93
97
 
94
98
  export type TJsType = {
95
99
  name: TJsTypeName,
96
- params: string[],
100
+ params?: string[],
101
+ raw: string
97
102
  }
98
103
 
99
104
  /*----------------------------------
@@ -103,7 +108,7 @@ export type TJsType = {
103
108
  const LogPrefix = '[database][meta]';
104
109
 
105
110
  const sqlTypeParamsReg = /\'([^\']+)\'\,?/gi;
106
- const typeViaCommentReg = /^\[type=([a-z]+)\]/g;
111
+ const typeViaCommentReg = /\[type=([a-z]+)\]/g;
107
112
 
108
113
  const modelsTypesPath = process.cwd() + '/src/server/models.ts';
109
114
 
@@ -196,7 +201,10 @@ export default class MySQLMetasParser {
196
201
 
197
202
  // Extrct tablesIndex
198
203
  const table = tablesIndex[database][nomTable];
199
- const parsedTypes = this.parseColType(type, comment);
204
+ const isNullable = nullable === 'YES';
205
+ const defaultValue = defaut === null ? undefined : defaut;
206
+ const isOptional = isNullable || defaultValue !== undefined;
207
+ const parsedTypes = this.parseColType(nomColonne, type, comment, isOptional);
200
208
 
201
209
  // Reference primary keys
202
210
  const isPrimary = cle === 'PRI';
@@ -209,15 +217,17 @@ export default class MySQLMetasParser {
209
217
  // Column
210
218
  table: tablesIndex[database][nomTable],
211
219
  nom: nomColonne,
220
+ pathname: database + '.' + nomTable + '.' + nomColonne,
212
221
  attached: true,
213
222
  primary: isPrimary,
214
223
 
215
224
  // Type
216
225
  type: parsedTypes,
217
- nullable: nullable === 'YES',
226
+ nullable: isNullable,
227
+ optional: isOptional,
218
228
 
219
229
  // Value
220
- defaut: defaut === null ? undefined : defaut,
230
+ defaut: defaultValue,
221
231
  autoIncrement: extra.includes('auto_increment'),
222
232
 
223
233
  // Extra
@@ -241,76 +251,92 @@ export default class MySQLMetasParser {
241
251
 
242
252
  }
243
253
 
244
- private parseColType( rawType: string, comment: string | null ): TColumnTypes {
254
+ private parseColType( name: string, rawType: string, comment: string | null, isOptional?: boolean ): TColumnTypes {
245
255
 
246
256
  const mysqlType = this.parseMySQLType(rawType);
247
257
 
248
- const jsType = this.parseJsType(mysqlType, comment);
258
+ const jsType = this.parseJsType(name, mysqlType, comment, isOptional);
249
259
 
250
260
  return {
251
261
  sql: mysqlType,
252
262
  js: jsType
253
263
  }
254
-
255
264
  }
256
265
 
257
266
  private parseMySQLType( rawType: string ): TMySQLType {
258
267
 
259
268
  let name: TMySQLType["name"];
260
- let params: TMySQLType["params"] = [];
269
+ let params: TMySQLType["params"];
261
270
 
262
271
  // Via native MySQL type: parse type expression + params
263
272
  const posParenthese = rawType.indexOf('(');
264
- if (posParenthese === -1)
273
+ if (posParenthese === -1) {
274
+
265
275
  name = rawType.toUpperCase() as TMySQLType["name"];
266
- else {
276
+
277
+ } else {
278
+
267
279
  name = rawType.substring(0, posParenthese).toUpperCase() as TMySQLType["name"];
280
+ params = []
268
281
 
269
282
  // Extraction paramètres du type entre les parentheses
270
283
  const paramsStr = rawType.substring(posParenthese + 1, rawType.length - 1)
271
284
  let m;
272
285
  do {
286
+
273
287
  m = sqlTypeParamsReg.exec(paramsStr);
274
288
  if (m)
275
289
  params.push(m[1]);
290
+
276
291
  } while (m);
292
+
293
+ if (params.length === 0)
294
+ params = undefined;
277
295
  }
278
296
 
279
- return { name, params }
297
+ return { name, params, raw: rawType }
280
298
 
281
299
  }
282
300
 
283
- private parseJsType( mysqlType: TMySQLType, comment: string | null ): TJsType {
301
+ private parseJsType( name: string, mysqlType: TMySQLType, comment: string | null, isOptional?: boolean ): TJsType {
302
+
303
+ let typeName: TJsType["name"] | undefined;
304
+ let params: TJsType["params"];
284
305
 
285
- // Via comment
306
+ // Find type info via comment
286
307
  if (comment) {
287
308
  // Exract via comments: [type=array]
288
- const foundTypeExpression = typeViaCommentReg.exec( comment );
289
- if (foundTypeExpression !== null) {
309
+ const foundTypeExpression = [...comment.matchAll( typeViaCommentReg )][0];
310
+ if (foundTypeExpression !== undefined) {
290
311
 
291
312
  const typeNameViaComment = foundTypeExpression[1];
292
313
  if (!(typeNameViaComment in jsTypes))
293
314
  console.warn(`Invalid type "${typeNameViaComment}" found in column comments.`);
294
315
  else
295
- return {
296
- name: typeNameViaComment as TJsTypeName,
297
- params: []
298
- }
316
+ typeName = typeNameViaComment as TJsTypeName;
299
317
  }
300
318
  }
301
319
 
302
- // Via mysql Type
303
- let jsTypeName = mysqlToJs[ mysqlType.name ];
304
- if (jsTypeName === undefined) {
305
- console.warn(`The mySQL data type « ${mysqlType.name} » has not been associated with a JS equivalent in mysqlToJs. Using any instead.`);
306
- jsTypeName = mysqlToJs['UNKNOWN'];
307
- }
320
+ // Find type info via mysql Type
321
+ if (typeName === undefined) {
322
+
323
+ typeName = mysqlToJs[ mysqlType.name ];
308
324
 
309
- return {
310
- name: jsTypeName,
311
- params: [],
325
+ // Equivalent not found
326
+ if (typeName === undefined) {
327
+ console.warn(`The mySQL data type « ${mysqlType.name} » has not been associated with a JS equivalent in mysqlToJs. Using any instead.`);
328
+ typeName = mysqlToJs['UNKNOWN'];
329
+ }
312
330
  }
313
331
 
332
+ // Get utils from name
333
+ const jsTypeUtils = jsTypes[ typeName ];
334
+ if (!jsTypeUtils)
335
+ throw new Error(`Unable to find the typescript print funvction for js type "${typeName}"`);
336
+
337
+ const raw = name + (isOptional ? '?' : '') + ': ' + jsTypeUtils.print( mysqlType.params );
338
+
339
+ return { name: typeName, params, raw }
314
340
  }
315
341
 
316
342
  private genTypesDef( databases: TDatabasesList ) {
@@ -325,18 +351,18 @@ export default class MySQLMetasParser {
325
351
  const colsDecl: string[] = [];
326
352
  for (const colName in table.colonnes) {
327
353
 
354
+ // Get column metdata
328
355
  const col = table.colonnes[colName];
329
- const jsTypeUtils = jsTypes[ col.type.js.name ];
330
- if (!jsTypeUtils) {
331
- console.warn(`Unable to find the typescript print funvction for js type "${col.type.js.name}"`);
332
- continue;
333
- }
334
356
 
335
- colsDecl.push('\t' + col.nom + (col.nullable ? '?' : '') + ': ' + jsTypeUtils.print( col ));
357
+ // Generate typescript typedef
358
+ colsDecl.push('\t' + col.type.js.raw);
359
+
360
+ // Generate enum
361
+ if (['ENUM', 'SET'].includes( col.type.sql.name ) && col.type.sql.params !== undefined)
362
+ types.push('export const ' + table.nom + ucfirst( colName ) + ' = [' + col.type.sql.params.map( p => "'" + p + "'") + '] as const;');
336
363
  }
337
364
 
338
365
  types.push('export type ' + table.nom + ' = {\n' + colsDecl.join(',\n') + '\n}');
339
-
340
366
  }
341
367
  }
342
368
 
@@ -0,0 +1,26 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Specific
6
+ import type Database from '.';
7
+
8
+ /*----------------------------------
9
+ - TYPES
10
+ ----------------------------------*/
11
+
12
+ /*----------------------------------
13
+ - CLASS
14
+ ----------------------------------*/
15
+ export default class QueriesRepository {
16
+
17
+ public constructor(
18
+ protected database: Database
19
+ ) {
20
+
21
+ }
22
+
23
+ protected sql( strings: TemplateStringsArray, ...data: any[] ) {
24
+ return this.database.sql(strings, ...data);
25
+ }
26
+ }
@@ -8,6 +8,7 @@
8
8
 
9
9
  // Core
10
10
  import Application, { Service } from '@server/app';
11
+ import markdown from '@common/data/markdown';
11
12
 
12
13
  // Speciic
13
14
  import { jsonToHtml } from './utils';
@@ -17,18 +18,21 @@ import type { Transporter } from './transporter';
17
18
  - SERVICE CONFIG
18
19
  ----------------------------------*/
19
20
 
21
+ const LogPrefix = `[services][email]`
22
+
20
23
  export type Config = {
21
24
  debug: boolean,
25
+ simulateWhenLocal: boolean,
22
26
  default: {
23
27
  transporter: string,
24
- from: string
28
+ from: TPerson
25
29
  },
26
30
  transporters: {
27
31
  [transporterName: string]: Transporter
28
32
  },
29
33
  bugReport: {
30
- from: string,
31
- to: string
34
+ from: TPerson,
35
+ to: TPerson
32
36
  }
33
37
  }
34
38
 
@@ -42,11 +46,17 @@ export type Hooks = {
42
46
 
43
47
  export { Transporter } from './transporter';
44
48
 
45
- export type TEmail = THtmlEmail | TTemplateEmail;
49
+ export type TEmail = THtmlEmail | TMarkdownEmail// | TTemplateEmail;
50
+
51
+ type TPerson = {
52
+ name?: string,
53
+ email: string
54
+ }
46
55
 
47
56
  type TBaseEmail = {
48
- to: string | string[],
49
- from?: string
57
+ to: TPerson | TPerson[],
58
+ cc?: TPerson | TPerson[]
59
+ from?: TPerson,
50
60
  };
51
61
 
52
62
  export type THtmlEmail = TBaseEmail & {
@@ -54,22 +64,41 @@ export type THtmlEmail = TBaseEmail & {
54
64
  html: string | { [label: string]: any },
55
65
  }
56
66
 
57
- export type TTemplateEmail = TBaseEmail & {
67
+ export type TMarkdownEmail = TBaseEmail & {
68
+ subject: string,
69
+ markdown: string,
70
+ }
71
+
72
+ /*export type TTemplateEmail = TBaseEmail & {
58
73
  template: keyof typeof templates,
59
74
  data?: TObjetDonnees
60
- }
75
+ }*/
61
76
 
62
77
  export type TCompleteEmail = With<THtmlEmail, {
63
- to: string[],
64
- from: string,
78
+ to: TPerson[],
79
+ from: TPerson,
80
+ cc: TPerson[]
65
81
  }>;
66
82
 
83
+ type TShortEmailSendArgs = [
84
+ to: string,
85
+ subject: string,
86
+ markdown: string,
87
+ options?: TOptions
88
+ ]
89
+
90
+ type TCompleteEmailSendArgs = [
91
+ emails: TEmail | TEmail[],
92
+ options?: TOptions
93
+ ]
94
+
95
+ type TEmailSendArgs = TShortEmailSendArgs | TCompleteEmailSendArgs;
96
+
67
97
  /*----------------------------------
68
98
  - TYPES: OPTIONS
69
99
  ----------------------------------*/
70
100
  type TOptions = {
71
- transporter?: string,
72
- testing?: boolean
101
+ transporter?: string
73
102
  }
74
103
 
75
104
  /*----------------------------------
@@ -88,30 +117,52 @@ export default class Email extends Service<Config, Hooks, Application> {
88
117
  }
89
118
 
90
119
 
91
- public async send(
92
- emails: TEmail | TEmail[],
93
- options: TOptions = {}
94
- ): Promise<void> {
120
+ public async send( to: string, subject: string, markdown: string, options?: TOptions );
121
+ public async send( emails: TEmail | TEmail[], options?: TOptions ): Promise<void>;
122
+ public async send( ...args: TEmailSendArgs ): Promise<void> {
123
+
124
+ let emails: TEmail[] | TEmail;
125
+ let options: TOptions | undefined;
126
+ if (typeof args[0] === 'string') {
127
+ const [to, subject, markdown, opts] = args as TShortEmailSendArgs;
128
+ emails = [{
129
+ to: { email: to },
130
+ subject,
131
+ markdown
132
+ }]
133
+ options = opts;
134
+ } else {
135
+
136
+ ([ emails, options ] = args as TCompleteEmailSendArgs);
137
+ if (!Array.isArray( emails ))
138
+ emails = [emails];
139
+ }
95
140
 
96
- // Normalisation en tableau
97
- if (!Array.isArray( emails ))
98
- emails = [emails];
141
+ options = options || {}
99
142
 
100
143
  this.config.debug && console.log(`Preparing to send ${emails.length} emails ...`);
101
144
 
145
+ const htmlWarning = this.app.env.profile === 'dev'
146
+ ? `⚠️ This email has been sent for testing purposes. Please ignore it if you're not a developer.<br /><br />`
147
+ : '';
148
+
102
149
  const emailsToSend: TCompleteEmail[] = emails.map(email => {
103
150
 
104
- const from = email.from === undefined
151
+ const from: TPerson = email.from === undefined
105
152
  ? this.config.default.from
106
153
  : email.from;
107
154
 
108
- const to = typeof email.to === 'string'
109
- ? [email.to]
110
- : email.to;
155
+ const cc: TPerson[] = email.cc === undefined ? [] : Array.isArray(email.cc)
156
+ ? email.cc
157
+ : [email.cc];
158
+
159
+ const to: TPerson[] = Array.isArray(email.to)
160
+ ? email.to
161
+ : [email.to];
111
162
 
112
163
  // Via template
113
164
  // TODO: Restore templates feature
114
- if ('template' in email) {
165
+ /*if ('template' in email) {
115
166
 
116
167
  const template = templates[email.template];
117
168
 
@@ -126,20 +177,32 @@ export default class Email extends Service<Config, Hooks, Application> {
126
177
  ...email,
127
178
  // Vire le "> " au début
128
179
  subject: txt.substring(2, delimTitre),
129
- html: txt.substring(delimTitre + 2),
180
+ html: htmlWarning + txt.substring(delimTitre + 2),
130
181
  from,
131
- to
182
+ to,
183
+ cc
132
184
  }
133
185
 
134
- }
186
+ } else */if ('markdown' in email) {
135
187
 
136
- return {
137
- ...email,
138
- html: typeof email.html === "string"
139
- ? email.html
140
- : jsonToHtml(email.html),
141
- from,
142
- to
188
+ return {
189
+ ...email,
190
+ html: htmlWarning + markdown.render(email.markdown),
191
+ from,
192
+ to,
193
+ cc
194
+ }
195
+
196
+ } else {
197
+ return {
198
+ ...email,
199
+ html: htmlWarning + (typeof email.html === "string"
200
+ ? email.html
201
+ : jsonToHtml(email.html)),
202
+ from,
203
+ to,
204
+ cc
205
+ }
143
206
  }
144
207
 
145
208
  });
@@ -148,17 +211,14 @@ export default class Email extends Service<Config, Hooks, Application> {
148
211
  if (transporterName === undefined)
149
212
  throw new Error(`Please define at least one mail transporter.`);
150
213
 
151
- console.info(`Sending ${emailsToSend.length} emails via transporter "${transporterName}"`, emailsToSend[0].subject);
214
+ console.info(LogPrefix, `Sending ${emailsToSend.length} emails via transporter "${transporterName}"`, emailsToSend[0].subject);
152
215
 
153
216
  // Pas d'envoi d'email quand local
154
- /*if (app.env.name === 'local' && options.testing !== false) {
155
- console.log(`Email send canceled: Test mode enabled, or you're in local`, {
156
- 'options.testing': options.testing,
157
- 'app.env.name': app.env.name,
158
- });
217
+ if (this.app.env.name === 'local' && this.config.simulateWhenLocal === true) {
218
+ console.log(LogPrefix, `Simulate email sending:\n`, emailsToSend[0].html);
159
219
  return;
160
- } else */if (emailsToSend.length === 0) {
161
- console.log(`No email to send.`);
220
+ } else if (emailsToSend.length === 0) {
221
+ console.warn(LogPrefix, `No email to send.`);
162
222
  return;
163
223
  }
164
224
 
@@ -0,0 +1,110 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import sharp from 'sharp';
7
+ import fs from 'fs-extra';
8
+
9
+ // Node
10
+ import request from 'request';
11
+
12
+ // Core: general
13
+ import type Application from '@server/app';
14
+ import Service from '@server/app/service';
15
+
16
+ /*----------------------------------
17
+ - SERVICE TYPES
18
+ ----------------------------------*/
19
+
20
+ export type Config = {
21
+
22
+ }
23
+
24
+ export type Hooks = {
25
+
26
+ }
27
+
28
+ /*----------------------------------
29
+ - TYPES
30
+ ----------------------------------*/
31
+
32
+ export type TImageConfig = {
33
+ width: number,
34
+ height: number,
35
+ fit: keyof sharp.FitEnum,
36
+ quality: number
37
+ }
38
+
39
+ /*----------------------------------
40
+ - CONST
41
+ ----------------------------------*/
42
+
43
+ const LogPrefix = `[services][fetch]`
44
+
45
+ /*----------------------------------
46
+ - SERVICE
47
+ - Tools that helps to consume external resources (including apis, ..)
48
+ -----------------------------------*/
49
+ export default class FetchService extends Service<Config, Hooks, Application> {
50
+
51
+ public async register() {
52
+
53
+ }
54
+
55
+ public async start() {
56
+
57
+ }
58
+
59
+ public toBuffer( uri: string ): Promise<Buffer> {
60
+ return new Promise<Buffer>((resolve, reject) => {
61
+ request(uri, { encoding: null }, (err, res, body) => {
62
+
63
+ if (err)
64
+ return reject(err);
65
+
66
+ if (!body)
67
+ return reject(`Body is empty for ${uri}.`);
68
+
69
+ resolve(body);
70
+ })
71
+ })
72
+ }
73
+
74
+ public async image(
75
+ imageFileUrl: string,
76
+ { width, height, fit, quality }: TImageConfig,
77
+ saveToPath?: string
78
+ ): Promise<Buffer | null> {
79
+
80
+ // Download
81
+ let imageBuffer: Buffer;
82
+ try {
83
+ imageBuffer = await this.toBuffer( imageFileUrl );
84
+ } catch (error) {
85
+ console.error(LogPrefix, `Error while fetching image at ${imageFileUrl}:`, error);
86
+ return null;
87
+ }
88
+
89
+ // Resize
90
+ const processing = sharp( imageBuffer )
91
+ // Max dimensions (save space)
92
+ .resize(width, height, { fit })
93
+
94
+ // Convert to webp and finalize
95
+ const processedBuffer = await processing.webp({ quality }).toBuffer().catch(e => {
96
+ console.error(LogPrefix, `Error while processing image at ${imageBuffer}:`, e);
97
+ return null;
98
+ })
99
+
100
+ // Save file
101
+ if (saveToPath !== undefined && processedBuffer !== null) {
102
+ console.log(LogPrefix, `Saving ${imageFileUrl} logo to ${saveToPath}`);
103
+ fs.outputFileSync(saveToPath, processedBuffer);
104
+ }
105
+
106
+ // We return the original, because Vibrant.js doesn't support webp
107
+ return imageBuffer;
108
+ }
109
+
110
+ }