@envsafes-org/cli 0.0.6

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 ADDED
@@ -0,0 +1,343 @@
1
+ # 🔐 EnvSafe CLI
2
+
3
+ **Gestionnaire sécurisé de variables d'environnement pour vos équipes**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@envsafes-org/cli.svg)](https://www.npmjs.com/package/@envsafes-org/cli)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ EnvSafe CLI vous permet de gérer vos variables d'environnement de maniÚre sécurisée avec chiffrement de bout en bout. Idéal pour les équipes qui veulent centraliser leurs secrets sans compromettre la sécurité.
9
+
10
+ ## 🛑 PrĂ©requis
11
+
12
+ Avant d'utiliser la CLI, vous devez créer un compte et un projet sur **[https://envsafe.vercel.app](https://envsafe.vercel.app)**.
13
+
14
+ ## 📩 Installation
15
+
16
+ ```bash
17
+ # Installation globale (recommandé)
18
+ npm install -g @envsafes-org/cli
19
+
20
+ # Avec yarn
21
+ yarn global add @envsafes-org/cli
22
+
23
+ # Avec pnpm
24
+ pnpm add -g @envsafes-org/cli
25
+
26
+ # Utilisation ponctuelle sans installation
27
+ npx @envsafes-org/cli
28
+ ```
29
+
30
+ ## 🚀 DĂ©marrage rapide
31
+
32
+ ```bash
33
+ # 1. Connectez-vous avec votre token API
34
+ envsafe login
35
+
36
+ # 2. Listez vos projets
37
+ envsafe projects
38
+
39
+ # 3. Récupérez vos variables
40
+ envsafe pull mon-projet
41
+
42
+ # 4. Ou exécutez directement avec injection
43
+ envsafe run mon-projet -- npm start
44
+ ```
45
+
46
+ ## 📖 Commandes
47
+
48
+ ### `envsafe login`
49
+
50
+ Authentifiez-vous avec un token d'accĂšs personnel (PAT).
51
+
52
+ ```bash
53
+ # Mode interactif
54
+ envsafe login
55
+
56
+ # Avec token direct (CI/CD)
57
+ envsafe login --token es_live_xxxxxxxxxxxxx
58
+ ```
59
+
60
+ **💡 GĂ©nĂ©rer un token :** Rendez-vous dans votre Dashboard → Settings → API Tokens
61
+
62
+ ---
63
+
64
+ ### `envsafe projects` (alias: `ls`)
65
+
66
+ Listez tous les projets accessibles.
67
+
68
+ ```bash
69
+ envsafe projects
70
+ # ou
71
+ envsafe ls
72
+ ```
73
+
74
+ ---
75
+
76
+ ### `envsafe pull <project>`
77
+
78
+ Téléchargez les variables d'environnement dans un fichier local.
79
+
80
+ ```bash
81
+ # Environnement de développement (par défaut)
82
+ envsafe pull mon-projet
83
+
84
+ # Environnement spécifique
85
+ envsafe pull mon-projet --env staging
86
+ envsafe pull mon-projet --env production
87
+
88
+ # Fichier de sortie personnalisé
89
+ envsafe pull mon-projet --output .env.local
90
+ envsafe pull mon-projet --env production --output .env.prod
91
+ ```
92
+
93
+ **Options:**
94
+ - `-e, --env <environment>` : Environnement (development, staging, production) - Défaut: `development`
95
+ - `-o, --output <file>` : Fichier de sortie - Défaut: `.env`
96
+
97
+ ---
98
+
99
+ ### `envsafe push <project>`
100
+
101
+ Envoyez vos variables locales vers EnvSafe (chiffrées automatiquement).
102
+
103
+ ```bash
104
+ # Envoyer .env vers development
105
+ envsafe push mon-projet
106
+
107
+ # Environnement et fichier spécifiques
108
+ envsafe push mon-projet --env production --file .env.prod
109
+ ```
110
+
111
+ **Options:**
112
+ - `-e, --env <environment>` : Environnement cible - Défaut: `development`
113
+ - `-f, --file <file>` : Fichier source - Défaut: `.env`
114
+
115
+ ---
116
+
117
+ ### `envsafe run <project> -- <command>`
118
+
119
+ **⭐ Commande recommandĂ©e** : ExĂ©cutez une commande avec les variables injectĂ©es directement, sans crĂ©er de fichier `.env` sur le disque.
120
+
121
+ ```bash
122
+ # Développement
123
+ envsafe run mon-projet -- npm start
124
+ envsafe run mon-projet -- npm run dev
125
+
126
+ # Production
127
+ envsafe run mon-projet --env production -- node server.js
128
+
129
+ # Autres exemples
130
+ envsafe run mon-projet -- pnpm build
131
+ envsafe run mon-projet -- python main.py
132
+ envsafe run mon-projet -- docker-compose up
133
+ ```
134
+
135
+ **Avantages:**
136
+ - ✅ Plus sĂ©curisĂ© (pas de fichier .env sur le disque)
137
+ - ✅ IdĂ©al pour CI/CD
138
+ - ✅ Pas de risque de commit accidentel de secrets
139
+
140
+ ---
141
+
142
+ ### `envsafe whoami`
143
+
144
+ Affichez les informations du compte connecté.
145
+
146
+ ```bash
147
+ envsafe whoami
148
+ ```
149
+
150
+ ---
151
+
152
+ ### `envsafe logout`
153
+
154
+ Déconnectez-vous (supprime le token local).
155
+
156
+ ```bash
157
+ envsafe logout
158
+ ```
159
+
160
+ ---
161
+
162
+ ### `envsafe config`
163
+
164
+ Gérez la configuration de la CLI.
165
+
166
+ ```bash
167
+ # Afficher la configuration actuelle
168
+ envsafe config --show
169
+
170
+ # Changer l'URL de l'API (pour instances self-hosted)
171
+ envsafe config --api-url https://votre-instance.com
172
+ ```
173
+
174
+ ---
175
+
176
+ ## 🔧 Utilisation en CI/CD
177
+
178
+ ### Méthode recommandée : Variable d'environnement
179
+
180
+ Définissez `ENVSAFE_TOKEN` comme secret dans votre CI/CD, puis utilisez directement les commandes sans `login`.
181
+
182
+ #### GitHub Actions
183
+
184
+ ```yaml
185
+ name: Deploy
186
+ on: [push]
187
+
188
+ jobs:
189
+ deploy:
190
+ runs-on: ubuntu-latest
191
+ steps:
192
+ - uses: actions/checkout@v4
193
+
194
+ - name: Install EnvSafe CLI
195
+ run: npm install -g @envsafes-org/cli
196
+
197
+ - name: Run tests with EnvSafe
198
+ env:
199
+ ENVSAFE_TOKEN: ${{ secrets.ENVSAFE_TOKEN }}
200
+ run: |
201
+ envsafe run mon-projet --env staging -- npm test
202
+
203
+ - name: Deploy to production
204
+ env:
205
+ ENVSAFE_TOKEN: ${{ secrets.ENVSAFE_TOKEN }}
206
+ run: |
207
+ envsafe run mon-projet --env production -- npm run build
208
+ envsafe run mon-projet --env production -- npm run deploy
209
+ ```
210
+
211
+ #### GitLab CI
212
+
213
+ ```yaml
214
+ deploy:
215
+ stage: deploy
216
+ script:
217
+ - npm install -g @envsafes-org/cli
218
+ - envsafe run mon-projet --env production -- npm run deploy
219
+ variables:
220
+ ENVSAFE_TOKEN: $ENVSAFE_TOKEN_SECRET
221
+ ```
222
+
223
+ #### Docker
224
+
225
+ ```dockerfile
226
+ FROM node:20-alpine
227
+
228
+ # Installer la CLI
229
+ RUN npm install -g @envsafes-org/cli
230
+
231
+ WORKDIR /app
232
+ COPY . .
233
+
234
+ # Injecter les variables au démarrage
235
+ CMD ["envsafe", "run", "mon-projet", "--env", "production", "--", "npm", "start"]
236
+ ```
237
+
238
+ ---
239
+
240
+ ## 💡 Exemples d'utilisation
241
+
242
+ ### Développement local
243
+
244
+ ```bash
245
+ # Option 1 : Fichier .env (traditionnel)
246
+ envsafe pull mon-projet
247
+ npm run dev
248
+
249
+ # Option 2 : Injection directe (recommandé)
250
+ envsafe run mon-projet -- npm run dev
251
+ ```
252
+
253
+ ### Script de déploiement
254
+
255
+ ```bash
256
+ #!/bin/bash
257
+ # deploy.sh
258
+
259
+ # Charger les variables de production et déployer
260
+ envsafe run mon-projet --env production -- npm run build
261
+ envsafe run mon-projet --env production -- npm run deploy
262
+ ```
263
+
264
+ ### Tests automatisés
265
+
266
+ ```bash
267
+ # Exécuter les tests avec les variables de staging
268
+ envsafe run mon-projet --env staging -- npm test
269
+ ```
270
+
271
+ ### Multi-environnements
272
+
273
+ ```bash
274
+ # Développement
275
+ envsafe run mon-projet --env development -- npm run dev
276
+
277
+ # Staging
278
+ envsafe run mon-projet --env staging -- npm run build
279
+
280
+ # Production
281
+ envsafe run mon-projet --env production -- npm start
282
+ ```
283
+
284
+ ---
285
+
286
+ ## 🔐 SĂ©curitĂ©
287
+
288
+ EnvSafe utilise une architecture de chiffrement de bout en bout :
289
+
290
+ - **Chiffrement des variables** : AES-256-GCM
291
+ - **Gestion des clés** : RSA-2048 avec chiffrement asymétrique
292
+ - **Transport** : TLS 1.3
293
+ - **Zero Knowledge** : Vos clés privées ne quittent jamais votre machine
294
+
295
+ ### Bonnes pratiques
296
+
297
+ ✅ **À faire :**
298
+ - Utilisez `ENVSAFE_TOKEN` en CI/CD
299
+ - Configurez des dates d'expiration pour vos tokens
300
+ - Privilégiez `envsafe run` pour éviter les fichiers .env
301
+ - Révoquez immédiatement les tokens compromis
302
+
303
+ ❌ **À Ă©viter :**
304
+ - Ne commitez jamais vos tokens dans Git
305
+ - N'utilisez pas `--token` en ligne de commande (visible dans l'historique)
306
+ - Ne partagez pas vos tokens par email/Slack
307
+
308
+ ---
309
+
310
+ ## 🌍 Variables d'environnement
311
+
312
+ | Variable | Description | Exemple |
313
+ |----------|-------------|---------|
314
+ | `ENVSAFE_TOKEN` | Token d'authentification (recommandé en CI/CD) | `es_live_xxx...` |
315
+ | `ENVSAFE_API_URL` | URL de l'API (pour instances self-hosted) | `https://api.example.com` |
316
+
317
+ ---
318
+
319
+ ## 📚 Documentation complùte
320
+
321
+ Pour plus d'informations, consultez la [documentation officielle](https://envsafe.vercel.app/docs).
322
+
323
+ ---
324
+
325
+ ## 🐛 Signaler un bug
326
+
327
+ Si vous rencontrez un problĂšme, [ouvrez une issue](https://github.com/Ifiboys/envsafe-cli/issues).
328
+
329
+ ---
330
+
331
+ ## 📄 Licence
332
+
333
+ MIT © EnvSafe Team
334
+
335
+ ---
336
+
337
+ ## đŸ€ Contribuer
338
+
339
+ Les contributions sont les bienvenues ! Consultez notre [guide de contribution](CONTRIBUTING.md).
340
+
341
+ ---
342
+
343
+ Made with ❀ by the EnvSafe Team
@@ -0,0 +1,328 @@
1
+ # EnvSafe Storage Agent (BYOS)
2
+
3
+ Agent simple pour héberger vos secrets chiffrés EnvSafe sur votre propre infrastructure.
4
+
5
+ ## Qu'est-ce que c'est ?
6
+
7
+ Cet agent vous permet de stocker vos secrets chiffrés sur **votre propre serveur** au lieu du cloud EnvSafe, tout en continuant à utiliser l'interface EnvSafe et la CLI.
8
+
9
+ ## ⚠ Rappel Important de SĂ©curitĂ©
10
+
11
+ **MĂȘme avec cet agent sur votre serveur, vos donnĂ©es sont DÉJÀ chiffrĂ©es (AES-256-GCM).**
12
+
13
+ - **Cet agent ne peut PAS lire vos secrets**
14
+ - Il stocke uniquement du texte illisible
15
+ - **Seule votre clé privée locale peut déchiffrer les données**
16
+ - EnvSafe (SaaS) ne peut pas non plus lire vos secrets
17
+
18
+ ## Installation
19
+
20
+ ### Prérequis
21
+
22
+ - Docker et Docker Compose
23
+ - Node.js 18+ (si vous lancez sans Docker)
24
+
25
+ ### Avec Docker (Recommandé)
26
+
27
+ ```bash
28
+ # Cloner ce dépÎt
29
+ git clone https://github.com/Ifiboys/envsafe-storage-agent
30
+ cd envsafe-storage-agent
31
+
32
+ # Configurer les variables d'environnement
33
+ cp .env.example .env
34
+ # Éditez .env et dĂ©finissez AUTH_SECRET avec une valeur trĂšs sĂ©curisĂ©e
35
+
36
+ # Lancer l'agent
37
+ docker-compose up -d
38
+ ```
39
+
40
+ ### Sans Docker
41
+
42
+ ```bash
43
+ npm install
44
+ npm run build
45
+ npm start
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ ### Variables d'environnement
51
+
52
+ ```bash
53
+ # SECRET PARTAGÉ - Utilisez un gĂ©nĂ©rateur de mots de passe sĂ©curisĂ©
54
+ AUTH_SECRET=your-very-long-and-secure-secret-here
55
+
56
+ # Port d'écoute
57
+ PORT=3001
58
+
59
+ # Base de données (SQLite par défaut, PostgreSQL recommandé en production)
60
+ DATABASE_URL=file:./envsafe-storage.db
61
+ # Exemple PostgreSQL:
62
+ # DATABASE_URL=postgresql://user:password@localhost:5432/envsafe_storage
63
+ ```
64
+
65
+ ### Génération du secret
66
+
67
+ ```bash
68
+ # Utilisez cette commande pour générer un secret sécurisé:
69
+ openssl rand -hex 32
70
+ ```
71
+
72
+ ## Configuration dans EnvSafe
73
+
74
+ 1. Allez dans votre projet EnvSafe
75
+ 2. Paramùtres → Stockage
76
+ 3. Activez **"Stockage Externe (BYOS)"**
77
+ 4. Renseignez:
78
+ - **URL**: `https://votre-serveur.com` (l'URL oĂč votre agent est accessible)
79
+ - **Secret**: Le mĂȘme `AUTH_SECRET` que vous avez dĂ©fini dans `.env`
80
+ 5. Cliquez sur **"Tester la connexion"**
81
+ 6. Si le test est réussi, sauvegardez
82
+
83
+ ## API Endpoints
84
+
85
+ L'agent expose ces routes (toutes protégées par authentification):
86
+
87
+ - `GET /health` - Vérification de la santé de l'agent
88
+ - `POST /store-secret` - Stocke un secret chiffré
89
+ - `GET /get-secret` - RécupÚre un secret chiffré
90
+ - `GET /get-all-secrets` - RécupÚre tous les secrets d'un environnement
91
+ - `DELETE /delete-secret` - Supprime un secret
92
+
93
+ ## Exemple de Code de l'Agent
94
+
95
+ Voici un exemple complet d'agent de stockage (Node.js + Express):
96
+
97
+ ```typescript
98
+ import express, { Request, Response } from "express";
99
+ import crypto from "crypto";
100
+ import { PrismaClient } from "@prisma/client";
101
+
102
+ const app = express();
103
+ const prisma = new PrismaClient();
104
+
105
+ app.use(express.json());
106
+
107
+ // ⚠ IMPORTANT: Cet agent stocke UNIQUEMENT des donnĂ©es CHIFFRÉES
108
+ // Il ne peut PAS lire vos secrets
109
+
110
+ // Middleware d'authentification
111
+ const authenticate = (req: Request, res: Response, next: Function) => {
112
+ const authHeader = req.headers.authorization;
113
+ const timestamp = req.headers["x-envsafe-timestamp"] as string;
114
+ const signature = req.headers["x-envsafe-signature"] as string;
115
+
116
+ if (!authHeader || !timestamp || !signature) {
117
+ return res.status(401).json({ error: "Missing authentication headers" });
118
+ }
119
+
120
+ const token = authHeader.replace("Bearer ", "");
121
+ const expectedSecret = process.env.AUTH_SECRET;
122
+
123
+ if (!expectedSecret) {
124
+ console.error("AUTH_SECRET not configured");
125
+ return res.status(500).json({ error: "Server misconfiguration" });
126
+ }
127
+
128
+ // Vérifier le token
129
+ if (token !== expectedSecret) {
130
+ console.warn(`Failed authentication attempt from ${req.ip}`);
131
+ return res.status(401).json({ error: "Invalid token" });
132
+ }
133
+
134
+ // Vérifier la signature HMAC
135
+ const expectedSignature = crypto
136
+ .createHmac("sha256", expectedSecret)
137
+ .update(timestamp)
138
+ .digest("hex");
139
+
140
+ if (signature !== expectedSignature) {
141
+ console.warn(`Invalid HMAC signature from ${req.ip}`);
142
+ return res.status(401).json({ error: "Invalid signature" });
143
+ }
144
+
145
+ // Vérifier que le timestamp n'est pas trop ancien (5 minutes max)
146
+ const now = Date.now();
147
+ const requestTime = parseInt(timestamp);
148
+ if (Math.abs(now - requestTime) > 5 * 60 * 1000) {
149
+ return res.status(401).json({ error: "Request expired" });
150
+ }
151
+
152
+ next();
153
+ };
154
+
155
+ // Health check
156
+ app.get("/health", authenticate, (req: Request, res: Response) => {
157
+ res.json({
158
+ status: "healthy",
159
+ timestamp: new Date().toISOString(),
160
+ version: "1.0.0"
161
+ });
162
+ });
163
+
164
+ // Stocker un secret chiffré
165
+ app.post("/store-secret", authenticate, async (req: Request, res: Response) => {
166
+ const { key, encryptedValue, environmentId } = req.body;
167
+
168
+ if (!key || !encryptedValue || !environmentId) {
169
+ return res.status(400).json({ error: "Missing required fields" });
170
+ }
171
+
172
+ try {
173
+ // Note: encryptedValue est déjà chiffré par le client
174
+ // L'agent ne fait que le stocker, il ne peut pas le lire
175
+ await prisma.encryptedVariable.upsert({
176
+ where: {
177
+ environmentId_key: { environmentId, key }
178
+ },
179
+ create: { key, encryptedValue, environmentId },
180
+ update: { encryptedValue }
181
+ });
182
+
183
+ console.log(`✅ Stored encrypted variable: ${key} for env: ${environmentId}`);
184
+ res.json({ success: true });
185
+ } catch (error) {
186
+ console.error("Error storing variable:", error);
187
+ res.status(500).json({ error: "Failed to store variable" });
188
+ }
189
+ });
190
+
191
+ // Récupérer un secret chiffré
192
+ app.get("/get-secret", authenticate, async (req: Request, res: Response) => {
193
+ const { key, environmentId } = req.query;
194
+
195
+ if (!key || !environmentId) {
196
+ return res.status(400).json({ error: "Missing required parameters" });
197
+ }
198
+
199
+ try {
200
+ const variable = await prisma.encryptedVariable.findUnique({
201
+ where: {
202
+ environmentId_key: {
203
+ environmentId: environmentId as string,
204
+ key: key as string
205
+ }
206
+ }
207
+ });
208
+
209
+ if (!variable) {
210
+ return res.status(404).json({ error: "Variable not found" });
211
+ }
212
+
213
+ // Retourne la valeur chiffrée (toujours illisible)
214
+ res.json({ encryptedValue: variable.encryptedValue });
215
+ } catch (error) {
216
+ console.error("Error getting variable:", error);
217
+ res.status(500).json({ error: "Failed to get variable" });
218
+ }
219
+ });
220
+
221
+ const PORT = process.env.PORT || 3001;
222
+
223
+ app.listen(PORT, () => {
224
+ console.log(`🔐 EnvSafe Storage Agent running on port ${PORT}`);
225
+ console.log(`⚠ Reminder: This agent stores ENCRYPTED data only`);
226
+ console.log(`⚠ Even with database access, secrets remain unreadable`);
227
+ });
228
+ ```
229
+
230
+ ### Schéma Prisma pour l'agent
231
+
232
+ ```prisma
233
+ // prisma/schema.prisma (pour l'agent de stockage)
234
+
235
+ datasource db {
236
+ provider = "postgresql"
237
+ url = env("DATABASE_URL")
238
+ }
239
+
240
+ generator client {
241
+ provider = "prisma-client-js"
242
+ }
243
+
244
+ model EncryptedVariable {
245
+ id String @id @default(cuid())
246
+ key String
247
+ encryptedValue String @map("encrypted_value") // Toujours chiffré (AES-256-GCM)
248
+ environmentId String @map("environment_id")
249
+
250
+ createdAt DateTime @default(now()) @map("created_at")
251
+ updatedAt DateTime @updatedAt @map("updated_at")
252
+
253
+ @@unique([environmentId, key])
254
+ @@map("encrypted_variables")
255
+ }
256
+ ```
257
+
258
+ ## Sécurité
259
+
260
+ ### Authentification
261
+
262
+ Toutes les requĂȘtes doivent inclure:
263
+ - `Authorization: Bearer <AUTH_SECRET>`
264
+ - `X-EnvSafe-Timestamp: <timestamp>`
265
+ - `X-EnvSafe-Signature: <HMAC-SHA256>`
266
+
267
+ ### Ce que l'agent NE FAIT PAS
268
+
269
+ - ❌ Il ne stocke PAS de secrets en clair
270
+ - ❌ Il ne peut PAS dĂ©chiffrer vos donnĂ©es
271
+ - ❌ Il n'a PAS accĂšs Ă  vos clĂ©s de dĂ©chiffrement
272
+
273
+ ### Ce qu'il FAIT
274
+
275
+ - ✅ Il stocke des blobs chiffrĂ©s (texte illisible)
276
+ - ✅ Il vĂ©rifie l'authentification HMAC des requĂȘtes
277
+ - ✅ Il refuse les requĂȘtes non autorisĂ©es
278
+
279
+ ## Production
280
+
281
+ ### Recommandations
282
+
283
+ 1. **HTTPS Obligatoire** : Utilisez un reverse proxy (Nginx, Caddy) avec certificat SSL
284
+ 2. **Base de données externe** : Utilisez PostgreSQL au lieu de SQLite
285
+ 3. **Firewall** : Limitez l'accĂšs Ă  l'IP du serveur EnvSafe
286
+ 4. **Backups** : Configurez des sauvegardes réguliÚres de votre base de données
287
+ 5. **Monitoring** : Surveillez les logs et les tentatives d'accĂšs
288
+
289
+ ### Exemple Nginx
290
+
291
+ ```nginx
292
+ server {
293
+ listen 443 ssl http2;
294
+ server_name envsafe-storage.votre-domaine.com;
295
+
296
+ ssl_certificate /etc/letsencrypt/live/votre-domaine.com/fullchain.pem;
297
+ ssl_certificate_key /etc/letsencrypt/live/votre-domaine.com/privkey.pem;
298
+
299
+ location / {
300
+ proxy_pass http://localhost:3001;
301
+ proxy_set_header Host $host;
302
+ proxy_set_header X-Real-IP $remote_addr;
303
+ }
304
+ }
305
+ ```
306
+
307
+ ## Logs
308
+
309
+ Les logs de l'agent incluent:
310
+ - Tentatives d'authentification (succÚs/échecs)
311
+ - Opérations de stockage/récupération
312
+ - Erreurs systĂšme
313
+
314
+ ```bash
315
+ # Voir les logs en temps réel
316
+ docker-compose logs -f
317
+ ```
318
+
319
+ ## Support
320
+
321
+ Pour toute question ou problĂšme:
322
+ - Documentation: https://envsafe.vercel.app/docs
323
+ - Issues: https://github.com/Ifiboys/envsafe-storage-agent/issues
324
+ - Email: oladokunefi123@gmail.com
325
+
326
+ ## Licence
327
+
328
+ MIT - Voir LICENSE
@@ -0,0 +1,3 @@
1
+ export declare function login(options: {
2
+ token?: string;
3
+ }): Promise<void>;