pwi-plata-type 0.3.6 → 0.3.7

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.
@@ -1,74 +1,144 @@
1
1
  import { tools } from "./plata-create-tools";
2
2
  import { PlataDirs } from "../../libs/tools"
3
+ import { Command } from 'commander'
3
4
  import path from 'node:path'
4
5
 
5
- export async function h() {
6
- return tools.args.forEachArg(async (command, args) => {
6
+ const program = new Command()
7
+
8
+ program.name('Plata Create cli')
9
+ program.description('CLI usada para criar rotas, libs, models e muito mais na plata')
10
+ program.version(PlataDirs.PlataJson.version)
11
+
12
+ program.command('route <routes...>')
13
+ .description('Cria uma rota utilizando o templete da plata')
14
+ .action(async routes => {
15
+ if (!Array.isArray(routes)) {
16
+ return
17
+ }
18
+
19
+ const promises: any[] = []
20
+ const plataName = PlataDirs.ProjectJson.plata_name
21
+
22
+ for (const route of routes) {
23
+ const r = `${route}/`.replace(/:(.*?)(?:\/|$)/g, (_, parm) => {
24
+ return parm[parm.length - 1] !== '?' ? `{${parm}}/` : `[${parm.slice(0, -1)}]/`
25
+ })
26
+
27
+ const routeArg = r.slice(0, -1).split('/')
28
+
29
+ const routeFileName = routeArg[routeArg.length - 1] === '' ? 'index' : routeArg.pop()
30
+ const routeFilePath = path.join('routes', ...routeArg.filter(v => v !== ''))
31
+
32
+ promises.push(tools.files.deployFileToProject(
33
+ routeFilePath,
34
+ 'route',
35
+ `${routeFileName}.ts`,
36
+ { PlataName: `${plataName}` }
37
+ ).finally(() => console.log(
38
+ `Rota ${routeFilePath}/${routeFileName === 'index' ? '' : routeFileName} criada`
39
+ )))
40
+ }
41
+
42
+ await Promise.all(promises)
43
+ })
44
+ ;
45
+
46
+ program.command('lib <libs...>')
47
+ .description('Cria uma config com e uma lib utilizando o templete da plata')
48
+ .action(async libs => {
49
+ if (!Array.isArray(libs)) {
50
+ return
51
+ }
52
+
53
+ const promises: any[] = []
54
+
55
+ for (const lib of libs) {
56
+ promises.push(tools.files.deployFileToProject(
57
+ 'configs',
58
+ 'config',
59
+ `${lib}.ts`.toLowerCase(),
60
+ { Name: `${lib}`, name: `${lib}`.toLowerCase() }
61
+ ).finally(() => console.log(`Config ${lib} criada`)))
62
+
63
+ promises.push(tools.files.deployFileToProject(
64
+ 'libs',
65
+ 'lib',
66
+ `${lib}.ts`.toLowerCase(),
67
+ { Name: `${lib}`, name: `${lib}`.toLowerCase() }
68
+ ).finally(() => console.log(`Lib ${lib} criada`)))
69
+ }
70
+
71
+ await Promise.all(promises)
72
+ })
73
+ ;
74
+
75
+ program.command('config <configs...>')
76
+ .description('Cria uma config utilizando o templete da plata')
77
+ .action(async configs => {
78
+ if (!Array.isArray(configs)) {
79
+ return
80
+ }
81
+
82
+ const promises: any[] = []
83
+
84
+ for (const config of configs) {
85
+ promises.push(tools.files.deployFileToProject(
86
+ 'configs',
87
+ 'config',
88
+ `${config}.ts`.toLowerCase(),
89
+ { Name: `${config}`, name: `${config}`.toLowerCase() }
90
+ ).finally(() => console.log(`Config ${config} criada`)))
91
+ }
92
+
93
+ await Promise.all(promises)
94
+
95
+ })
96
+ ;
97
+
98
+ program.command('model <models...>')
99
+ .description('Cria um model utilizando o templete da plata')
100
+ .action(async models => {
101
+ if (!Array.isArray(models)) {
102
+ return
103
+ }
104
+
7
105
  const promises: any[] = []
106
+ const plataName = PlataDirs.ProjectJson.plata_name
8
107
 
9
- switch (command) {
10
- case 'lib':
11
- const nameLib = `${args.shift()}`
12
- promises.push(tools.files.deployFileToProject(
13
- 'configs',
14
- 'config',
15
- `${nameLib}.ts`.toLowerCase(),
16
- { Name: `${nameLib}`, name: `${nameLib}`.toLowerCase() }
17
- ).finally(() => console.log(`Config ${nameLib} criada`)))
18
-
19
- promises.push(tools.files.deployFileToProject(
20
- 'libs',
21
- 'lib',
22
- `${nameLib}.ts`.toLowerCase(),
23
- { Name: `${nameLib}`, name: `${nameLib}`.toLowerCase() }
24
- ).finally(() => console.log(`Lib ${nameLib} criada`)))
25
- break;
26
- case 'config':
27
- const nameConfig = `${args.shift()}`
28
- promises.push(tools.files.deployFileToProject(
29
- 'configs',
30
- 'config',
31
- `${nameConfig}.ts`.toLowerCase(),
32
- { Name: `${nameConfig}`, name: `${nameConfig}`.toLowerCase() }
33
- ).finally(() => console.log(`Config ${nameConfig} criada`)))
34
- break;
35
- case 'cluster':
36
- console.log('CLUSTER AINDA NÃO CRIANDO AINDA')
37
- break;
38
- case 'route':
39
- const r = `${args.shift()}/`.replace(/:(.*?)(?:\/|$)/g, (_, parm) => {
40
- return parm[parm.length - 1] !== '?' ? `{${parm}}/` : `[${parm.slice(0, -1)}]/`
41
- })
42
-
43
- const routeArg = r.slice(0, -1).split('/')
44
-
45
- const routeFileName = routeArg[routeArg.length - 1] === '' ? 'index' : routeArg.pop()
46
- const routeFilePath = path.join('routes', ...routeArg.filter(v => v !== ''))
47
-
48
- promises.push(tools.files.deployFileToProject(
49
- routeFilePath,
50
- 'route',
51
- `${routeFileName}.ts`,
52
- { PlataName: `${PlataDirs.ProjectJson.plata_name}` }
53
- ).finally(() => console.log(
54
- `Rota ${routeFilePath}/${routeFileName === 'index' ? '' : routeFileName} criada`
55
- )))
56
-
57
- break;
58
- case 'model':
59
- const modelName = `${args.shift()}`
60
- const plataName = PlataDirs.ProjectJson.plata_name
61
-
62
- promises.push(tools.files.deployFileToProject(
63
- 'models',
64
- 'model',
65
- `${modelName}.ts`.toLowerCase(),
66
- { Name: `${modelName}`, PlataName: `${plataName}` }
67
- ).finally(() => console.log(`Model ${modelName} criada`)))
68
- break;
108
+ for (const model of models) {
109
+ promises.push(tools.files.deployFileToProject(
110
+ 'models',
111
+ 'model',
112
+ `${model}.ts`.toLowerCase(),
113
+ { Name: `${model}`, PlataName: `${plataName}` }
114
+ ).finally(() => console.log(`Model ${model} criada`)))
69
115
  }
70
116
 
71
117
  await Promise.all(promises)
72
- return args
73
118
  })
74
- }
119
+ ;
120
+
121
+ program.command('task <tasks...>')
122
+ .description('Cria uma task utilizando o templete da plata')
123
+ .action(async tasks => {
124
+ if (!Array.isArray(tasks)) {
125
+ return
126
+ }
127
+
128
+ const promises: any[] = []
129
+ const plataName = PlataDirs.ProjectJson.plata_name
130
+
131
+ for (const task of tasks) {
132
+ promises.push(tools.files.deployFileToProject(
133
+ 'tasks',
134
+ 'task',
135
+ `${task}.ts`.toLowerCase(),
136
+ { Name: `${task}`, PlataName: `${plataName}` }
137
+ ).finally(() => console.log(`Task ${tasks} criada`)))
138
+ }
139
+
140
+ await Promise.all(promises)
141
+ })
142
+ ;
143
+
144
+ export const cli = program
@@ -1,41 +1,109 @@
1
1
  import { tools } from "./plata-create-tools";
2
+ import { PlataDirs } from "../../libs/tools"
3
+ import { Command } from 'commander'
4
+
5
+ const program = new Command()
6
+
7
+ program.name('Plata Create cli')
8
+ program.description('CLI usada para criar rotas, libs, models e muito mais na plata')
9
+ program.version(PlataDirs.PlataJson.version)
10
+
11
+ program.command('lib <libs...>')
12
+ .description('Cria uma config com e uma lib utilizando o templete da plata')
13
+ .action(async libs => {
14
+ if (!Array.isArray(libs)) {
15
+ return
16
+ }
17
+
18
+ const promises: any[] = []
19
+
20
+ for (const lib of libs) {
21
+ promises.push(tools.files.deployFileToProject(
22
+ 'configs',
23
+ 'config',
24
+ `${lib}.ts`.toLowerCase(),
25
+ { Name: `${lib}`, name: `${lib}`.toLowerCase() }
26
+ ).finally(() => console.log(`Config ${lib} criada`)))
27
+
28
+ promises.push(tools.files.deployFileToProject(
29
+ 'libs',
30
+ 'lib',
31
+ `${lib}.ts`.toLowerCase(),
32
+ { Name: `${lib}`, name: `${lib}`.toLowerCase() }
33
+ ).finally(() => console.log(`Lib ${lib} criada`)))
34
+ }
35
+
36
+ await Promise.all(promises)
37
+ })
38
+ ;
39
+
40
+ program.command('config <configs...>')
41
+ .description('Cria uma config utilizando o templete da plata')
42
+ .action(async configs => {
43
+ if (!Array.isArray(configs)) {
44
+ return
45
+ }
46
+
47
+ const promises: any[] = []
48
+
49
+ for (const config of configs) {
50
+ promises.push(tools.files.deployFileToProject(
51
+ 'configs',
52
+ 'config',
53
+ `${config}.ts`.toLowerCase(),
54
+ { Name: `${config}`, name: `${config}`.toLowerCase() }
55
+ ).finally(() => console.log(`Config ${config} criada`)))
56
+ }
57
+
58
+ await Promise.all(promises)
59
+
60
+ })
61
+ ;
62
+
63
+ program.command('model <models...>')
64
+ .description('Cria um model utilizando o templete da plata')
65
+ .action(async models => {
66
+ if (!Array.isArray(models)) {
67
+ return
68
+ }
69
+
70
+ const promises: any[] = []
71
+ const plataName = PlataDirs.ProjectJson.plata_name
72
+
73
+ for (const model of models) {
74
+ promises.push(tools.files.deployFileToProject(
75
+ 'models',
76
+ 'model',
77
+ `${model}.ts`.toLowerCase(),
78
+ { Name: `${model}`, PlataName: `${plataName}` }
79
+ ).finally(() => console.log(`Model ${model} criada`)))
80
+ }
81
+
82
+ await Promise.all(promises)
83
+ })
84
+ ;
85
+
86
+ program.command('task <tasks...>')
87
+ .description('Cria uma task utilizando o templete da plata')
88
+ .action(async tasks => {
89
+ if (!Array.isArray(tasks)) {
90
+ return
91
+ }
2
92
 
3
- export async function h() {
4
- return tools.args.forEachArg(async (command, args) => {
5
93
  const promises: any[] = []
94
+ const plataName = PlataDirs.ProjectJson.plata_name
6
95
 
7
- switch (command) {
8
- case 'lib':
9
- const nameLib = args.shift()
10
- promises.push(tools.files.deployFileToProject(
11
- 'configs',
12
- 'config',
13
- `${nameLib}.ts`.toLowerCase(),
14
- { Name: `${nameLib}`, name: `${nameLib}`.toLowerCase() }
15
- ).finally(() => console.log(`Config ${nameLib} criada`)))
16
-
17
- promises.push(tools.files.deployFileToProject(
18
- 'libs',
19
- 'lib',
20
- `${nameLib}.ts`.toLowerCase(),
21
- { Name: `${nameLib}`, name: `${nameLib}`.toLowerCase() }
22
- ).finally(() => console.log(`Lib ${nameLib} criada`)))
23
- break;
24
- case 'config':
25
- const nameConfig = args.shift()
26
- promises.push(tools.files.deployFileToProject(
27
- 'configs',
28
- 'config',
29
- `${nameConfig}.ts`.toLowerCase(),
30
- { Name: `${nameConfig}`, name: `${nameConfig}`.toLowerCase() }
31
- ).finally(() => console.log(`Config ${nameConfig} criada`)))
32
- break;
33
- case 'cluster':
34
- console.log('CLUSTER AINDA NÃO CRIANDO AINDA')
35
- break;
96
+ for (const task of tasks) {
97
+ promises.push(tools.files.deployFileToProject(
98
+ 'tasks',
99
+ 'task',
100
+ `${task}.ts`.toLowerCase(),
101
+ { Name: `${task}`, PlataName: `${plataName}` }
102
+ ).finally(() => console.log(`Task ${tasks} criada`)))
36
103
  }
37
104
 
38
105
  await Promise.all(promises)
39
- return args
40
106
  })
41
- }
107
+ ;
108
+
109
+ export const cli = program
@@ -3,32 +3,26 @@ import { PlataDirs } from "../libs/tools"
3
3
  import * as PlataCreateApi from "./extras/plata-create-api"
4
4
  import * as PlataCreateLib from "./extras/plata-create-lib"
5
5
 
6
- interface Handler {
7
- h: () => Promise<void>
8
- }
9
-
10
6
  const main = async () => {
11
- const projectPackage = await PlataDirs.ProjectJson
7
+ const projectPackage = PlataDirs.ProjectJson
12
8
 
13
9
  if (projectPackage.plata_no_setup !== undefined) {
14
10
  console.log('Existe o parametro plata_no_setup no package.json ou seja a plata não esta configurada')
15
11
  process.exit(0)
16
-
17
12
  }
18
13
 
19
14
  switch(projectPackage.plata_type ?? 'api') {
20
15
  case 'api':
21
- await PlataCreateApi.h()
16
+ await PlataCreateApi.cli.parseAsync(process.argv)
22
17
  break;
23
18
  case 'lib':
24
- await PlataCreateLib.h()
19
+ await PlataCreateLib.cli.parseAsync(process.argv)
25
20
  break;
26
21
  default:
27
22
  console.log(`tipo ${projectPackage.plata_type} não suportado pela plata`)
28
23
  process.exit(0)
29
24
  break;
30
25
  }
31
-
32
26
  }
33
27
 
34
28
  main()
package/bin/plata.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { PlataClusterManager, PlataClusterMsg } from "../libs/cluster"
2
2
  import { loadEnvProjectFile } from "../libs/env"
3
+ import { loadTasks } from "../libs/tasks"
3
4
  import { buildExpressRouter } from "../libs/routes"
4
5
  import express, { Express } from "express"
5
6
  import { createServer } from 'node:https'
@@ -21,6 +22,8 @@ const main = async () => {
21
22
  }
22
23
  }
23
24
 
25
+ await loadTasks()
26
+
24
27
  console.log(process.env.ENV)
25
28
 
26
29
  clusterLib.run({
package/index.ts CHANGED
@@ -3,6 +3,7 @@ import * as PlataEnv from './libs/env'
3
3
  import * as PlataRoutes from './libs/routes'
4
4
  import * as PlataTools from './libs/tools'
5
5
  import * as PlataModels from './libs/model'
6
+ import * as PlataTasks from './libs/tasks'
6
7
  import { PlataSwagger } from './libs/swagger'
7
8
 
8
9
  export {
@@ -11,5 +12,6 @@ export {
11
12
  PlataRoutes,
12
13
  PlataTools,
13
14
  PlataModels,
14
- PlataSwagger
15
+ PlataSwagger,
16
+ PlataTasks
15
17
  }
package/libs/tasks.ts ADDED
@@ -0,0 +1,157 @@
1
+ import * as schedule from 'node-schedule'
2
+ import { PlataResultado, PlataRequire, PlataDirs, PlataError } from './tools'
3
+
4
+ export type TaskRule = schedule.RecurrenceRule | schedule.RecurrenceSpecDateRange | schedule.RecurrenceSpecObjLit | Date | string | number
5
+ export type TaskCallback = (fireDate: Date) => Promise<PlataError | null>
6
+
7
+ export interface PlataTask {
8
+ name: string
9
+ rule: TaskRule | null
10
+ onPlataStart: boolean
11
+ callback: TaskCallback
12
+ }
13
+
14
+ export interface StatusPlataTask extends PlataTask {
15
+ lastRun: Date | null
16
+ lastReturn: PlataError | null
17
+ }
18
+
19
+ export interface PlataTasksProcess {
20
+ tasks: StatusPlataTask[]
21
+ }
22
+
23
+ export interface _PlataTasksProcess extends NodeJS.Process {
24
+ _plata?: PlataTasksProcess
25
+ }
26
+
27
+ export function getTasksNodeProcess(): PlataTasksProcess {
28
+ const p = process as _PlataTasksProcess
29
+
30
+ if (p._plata === undefined) {
31
+ p._plata = {
32
+ tasks: []
33
+ }
34
+ }
35
+
36
+ if (p._plata.tasks === undefined) {
37
+ p._plata.tasks = []
38
+ }
39
+
40
+ return p._plata
41
+ }
42
+
43
+ export function buildTaskCallBack(task: PlataTask): schedule.JobCallback {
44
+ return async (fireDate: Date) => {
45
+ let status: PlataError | null = null
46
+ const data = new Date()
47
+
48
+ const promise = task.callback(fireDate).then(
49
+ s => status = s,
50
+ err => status = {
51
+ errorID: 'PBT0001',
52
+ msg: `Erro ao rodar a task ${task.name}`,
53
+ error: err
54
+ }
55
+ )
56
+
57
+ const i = getTasksNodeProcess().tasks.findIndex(v => v.name === task.name)
58
+
59
+ await promise
60
+
61
+ if (i !== -1) {
62
+ getTasksNodeProcess().tasks[i].lastReturn = status
63
+ getTasksNodeProcess().tasks[i].lastRun = data
64
+ }
65
+ }
66
+ }
67
+
68
+ export async function buildTask(task: PlataTask): Promise<schedule.Job | null> {
69
+ if (task.onPlataStart) {
70
+ let status: PlataError | null = null
71
+
72
+ try{
73
+ status = await task.callback(new Date())
74
+ } catch (e) {
75
+ status = {
76
+ errorID: 'PBT0002',
77
+ msg: `Erro ao rodar a task ${task.name}`,
78
+ error: e
79
+ }
80
+ }
81
+
82
+ getTasksNodeProcess().tasks.push({
83
+ ...task,
84
+ lastRun: new Date(),
85
+ lastReturn: status
86
+ })
87
+ } else {
88
+ getTasksNodeProcess().tasks.push({
89
+ ...task,
90
+ lastRun: null,
91
+ lastReturn: null
92
+ })
93
+ }
94
+
95
+ if (task.rule === null) {
96
+ return null
97
+ }
98
+
99
+ return schedule.scheduleJob(task.rule as any, buildTaskCallBack(task))
100
+ }
101
+
102
+ export async function loadTasks(): Promise<PlataResultado<schedule.Job[]>> {
103
+ const tasks: schedule.Job[] = []
104
+
105
+ const task = await PlataRequire.requireFolderAsync<PlataTask>(
106
+ PlataDirs.getProjectDirTasks()
107
+ )
108
+
109
+ if (task.errorID !== undefined) {
110
+ return task
111
+ }
112
+
113
+ for (const t of task) {
114
+ if (t.errorID !== undefined) {
115
+ return t
116
+ }
117
+ const j = await buildTask(t.exports)
118
+
119
+ if (j !== null) tasks.push(j)
120
+ }
121
+
122
+ return tasks
123
+ }
124
+
125
+ export async function callTask(name: string): Promise<PlataError | null> {
126
+ const i = getTasksNodeProcess().tasks.findIndex(v => v.name === name)
127
+
128
+ if (i === -1) {
129
+ return {
130
+ errorID: 'PBT0003',
131
+ msg: `Task: ${name} não existe`,
132
+ }
133
+ }
134
+
135
+ const data = new Date()
136
+
137
+ return getTasksNodeProcess().tasks[i].callback(data).then(
138
+ status => {
139
+ getTasksNodeProcess().tasks[i].lastReturn = status
140
+ getTasksNodeProcess().tasks[i].lastRun = data
141
+
142
+ return status
143
+ },
144
+ err => {
145
+ const status = {
146
+ errorID: 'PBT0004',
147
+ msg: `Erro ao rodar a task ${name}`,
148
+ error: err
149
+ }
150
+
151
+ getTasksNodeProcess().tasks[i].lastReturn = status
152
+ getTasksNodeProcess().tasks[i].lastRun = data
153
+
154
+ return status
155
+ }
156
+ )
157
+ }
package/libs/tools.ts CHANGED
@@ -18,6 +18,10 @@ export namespace PlataDirs {
18
18
  return path.resolve('.')
19
19
  }
20
20
 
21
+ export function getProjectDirTasks(): string {
22
+ return path.resolve('.', 'tasks')
23
+ }
24
+
21
25
  export function getProjectDirSwagger(): string {
22
26
  return path.resolve('.', 'swagger')
23
27
  }
@@ -59,7 +63,13 @@ export namespace PlataDirs {
59
63
  export function getPlataDir(): string {
60
64
  return path.resolve('.', 'node_modules', ProjectJson.plata_name)
61
65
  }
62
-
66
+
67
+ export const PlataJson: any = JSON.parse(
68
+ fs.readFileSync(
69
+ path.join(PlataDirs.getPlataDir(), 'package.json')
70
+ ).toString()
71
+ )
72
+
63
73
  export function getPlataTempletesDir(): string {
64
74
  return path.join(getPlataDir(), 'templates')
65
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pwi-plata-type",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "main": "index.ts",
5
5
  "bin": {
6
6
  "plata": "bin/plata.ts",
@@ -19,13 +19,16 @@
19
19
  "@types/express": "^4.17.13",
20
20
  "@types/glob": "^7.2.0",
21
21
  "@types/jest": "^28.1.1",
22
+ "@types/node-schedule": "^2.1.0",
22
23
  "@types/swagger-ui-express": "^4.1.3",
24
+ "commander": "^9.4.0",
25
+ "express": "^4.18.1",
23
26
  "glob": "^8.0.3",
24
27
  "jest": "^28.1.1",
28
+ "node-schedule": "^2.1.0",
25
29
  "swagger-ui-express": "^4.4.0",
26
30
  "ts-jest": "^28.0.4",
27
31
  "ts-node": "^10.9.1",
28
- "express": "^4.18.1",
29
32
  "tsconfig-paths": "^4.0.0"
30
33
  },
31
34
  "description": "",
@@ -0,0 +1,13 @@
1
+ //@ts-nocheck
2
+ import { PlataTasks, PlataTools } from "ç__PlataName__ç"
3
+
4
+ async function main(fireDate: Date): Promise<PlataTools.PlataError | null> {
5
+ return null
6
+ }
7
+
8
+ export default {
9
+ name: '',
10
+ rule: null, // https://crontab.guru/
11
+ onPlataStart: false,
12
+ callback: main
13
+ } as PlataTasks.PlataTask
@@ -10,6 +10,7 @@ export async function install({ dirs, projectPackageJson }) {
10
10
  promises.push(t.createFolderProject('routes'))
11
11
  promises.push(t.createFolderProject('libs'))
12
12
  promises.push(t.createFolderProject('models'))
13
+ promises.push(t.createFolderProject('tasks'))
13
14
 
14
15
  promises.push(t.copyFolderToProject('configs'))
15
16
  promises.push(t.copyFolderToProject('envs'))
@@ -9,7 +9,7 @@ export async function install({ dirs, projectPackageJson }) {
9
9
  promises.push(t.createFolderProject('clusters'))
10
10
  promises.push(t.createFolderProject('routes'))
11
11
  promises.push(t.createFolderProject('libs'))
12
-
12
+ promises.push(t.createFolderProject('tasks'))
13
13
  promises.push(t.createFolderProject('configs'))
14
14
  promises.push(t.createFolderProject('bin'))
15
15
 
@@ -22,6 +22,7 @@ const main = async() => {
22
22
  promises.push(t.copyFolderToProject('configs'))
23
23
  promises.push(t.syncFolderProject('clusters'))
24
24
  promises.push(t.syncFolderProject('libs'))
25
+ promises.push(t.syncFolderProject('tasks'))
25
26
 
26
27
  await Promise.all(promises)
27
28
  }