@deveye/types 0.15.2 → 0.16.0
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/package.json +6 -6
- package/src/domain/device.ts +4 -29
- package/src/domain/featureRegistry.ts +40 -108
- package/src/domain/home.ts +40 -101
- package/src/domain/live.ts +36 -87
- package/src/domain/metrics.ts +10 -14
- package/src/domain/notifications.ts +39 -110
- package/src/domain/project.ts +3 -162
- package/src/domain/report.ts +46 -95
- package/src/domain/secrecy.ts +3 -5
- package/src/domain/sharing.ts +33 -70
- package/src/domain/syncProtocol.ts +5 -12
- package/src/domain/user.ts +8 -14
- package/src/domain/workspace.ts +0 -3
- package/src/domain/workspaceRole.ts +34 -82
- package/src/features/agent.ts +306 -0
- package/src/features/live.ts +17 -37
- package/src/features/notify.ts +19 -57
- package/src/features/registry.ts +7 -44
- package/src/features/secrecy.ts +4 -9
- package/src/features/sharing.ts +12 -26
- package/src/features/user.ts +6 -11
- package/src/features/workspace.ts +6 -11
- package/src/http/auth.ts +6 -13
- package/src/http/device.ts +13 -17
- package/src/http/status.ts +6 -10
- package/src/index.ts +29 -932
- package/src/protocol/agent.ts +40 -70
- package/src/protocol/envelope.ts +3 -10
- package/src/sdk/client-ambient.d.ts +228 -21
- package/src/sdk/client.ts +277 -17
- package/src/sdk/devb.ts +120 -0
- package/src/sdk/manifest.test.ts +0 -1
- package/src/sdk/manifest.ts +94 -25
- package/src/sdk/providers.ts +310 -5
- package/src/sdk/server.ts +483 -19
- package/src/sdk/testing.test.ts +2 -2
- package/src/sdk/testing.ts +302 -26
- package/src/utils/version.ts +5 -8
- package/src/domain/audience.ts +0 -549
- package/src/domain/backup.ts +0 -355
- package/src/domain/credential.ts +0 -55
- package/src/domain/database.ts +0 -467
- package/src/domain/deploy.ts +0 -231
- package/src/domain/finance.ts +0 -477
- package/src/domain/git.ts +0 -419
- package/src/domain/mail.ts +0 -394
- package/src/domain/note.ts +0 -202
- package/src/domain/password.ts +0 -36
- package/src/domain/projectBoard.ts +0 -130
- package/src/domain/projectChat.ts +0 -46
- package/src/domain/projectHistory.ts +0 -82
- package/src/domain/projectLink.ts +0 -87
- package/src/domain/projectPlan.ts +0 -68
- package/src/domain/sentinel.ts +0 -623
- package/src/domain/uptime.ts +0 -216
- package/src/features/audience.ts +0 -275
- package/src/features/backup.ts +0 -230
- package/src/features/database.ts +0 -461
- package/src/features/deploy.ts +0 -245
- package/src/features/device.ts +0 -292
- package/src/features/deviceFiles.ts +0 -83
- package/src/features/deviceLogs.ts +0 -36
- package/src/features/deviceTerminal.ts +0 -57
- package/src/features/finance.ts +0 -360
- package/src/features/git.ts +0 -368
- package/src/features/mail.ts +0 -374
- package/src/features/metrics.ts +0 -185
- package/src/features/note.ts +0 -189
- package/src/features/password.ts +0 -67
- package/src/features/project.ts +0 -709
- package/src/features/sentinel.ts +0 -233
- package/src/features/uptime.ts +0 -186
package/src/features/backup.ts
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
BACKUP_ACCESS_KEY_MAX,
|
|
4
|
-
BACKUP_BUCKET_MAX,
|
|
5
|
-
BACKUP_DESTINATION_NAME_MAX,
|
|
6
|
-
BACKUP_ENDPOINT_MAX,
|
|
7
|
-
BACKUP_JOB_NAME_MAX,
|
|
8
|
-
BACKUP_PATH_MAX,
|
|
9
|
-
BACKUP_SECRET_MAX,
|
|
10
|
-
backupDestinationKindSchema,
|
|
11
|
-
backupDestinationProbeSchema,
|
|
12
|
-
backupDestinationSchema,
|
|
13
|
-
backupEncryptionSchema,
|
|
14
|
-
backupJobSchema,
|
|
15
|
-
backupRunSchema,
|
|
16
|
-
backupScheduleKindSchema,
|
|
17
|
-
backupSourceCandidateSchema,
|
|
18
|
-
backupSourceKindSchema
|
|
19
|
-
} from '../domain/backup';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Commandes des sauvegardes.
|
|
23
|
-
*
|
|
24
|
-
* Deux moitiés qui ne se recouvrent pas: les **destinations** (où) et les
|
|
25
|
-
* **travaux** (quoi, quand, combien de copies). Tout est à l'étage ouvert, donc
|
|
26
|
-
* aucune de ces commandes ne demande de session déverrouillée — c'est la
|
|
27
|
-
* condition pour qu'une sauvegarde parte à 3 h du matin.
|
|
28
|
-
*
|
|
29
|
-
* `backup.deveyeDump` n'existe pas comme commande: la base de DevEye se
|
|
30
|
-
* sauvegarde par un travail de source `deveye` comme les autres, et il n'y a
|
|
31
|
-
* aucune raison de lui inventer un chemin à part.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
const destinationId = z.number().int().positive();
|
|
35
|
-
const jobId = z.number().int().positive();
|
|
36
|
-
|
|
37
|
-
// ---------------------------------------------------------- destinations
|
|
38
|
-
|
|
39
|
-
/** Les destinations de l'espace, dans l'ordre où elles ont été déclarées. */
|
|
40
|
-
export const backupDestinationList = {
|
|
41
|
-
command: 'backup.destinationList' as const,
|
|
42
|
-
input: z.object({}),
|
|
43
|
-
output: z.object({ destinations: z.array(backupDestinationSchema) })
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Déclare une destination.
|
|
48
|
-
*
|
|
49
|
-
* Un seul schéma pour les trois genres, avec les champs des deux autres à
|
|
50
|
-
* `null`: la forme alternative (trois commandes, ou une union discriminée)
|
|
51
|
-
* obligerait l'écran à trois formulaires là où il n'en a qu'un, dont les champs
|
|
52
|
-
* apparaissent selon le genre choisi.
|
|
53
|
-
*/
|
|
54
|
-
export const backupDestinationAdd = {
|
|
55
|
-
command: 'backup.destinationAdd' as const,
|
|
56
|
-
input: z.object({
|
|
57
|
-
kind: backupDestinationKindSchema,
|
|
58
|
-
name: z.string().min(1).max(BACKUP_DESTINATION_NAME_MAX),
|
|
59
|
-
deviceId: z.uuid().nullable(),
|
|
60
|
-
path: z.string().max(BACKUP_PATH_MAX),
|
|
61
|
-
endpoint: z.string().max(BACKUP_ENDPOINT_MAX).nullable(),
|
|
62
|
-
region: z.string().max(64).nullable(),
|
|
63
|
-
bucket: z.string().max(BACKUP_BUCKET_MAX).nullable(),
|
|
64
|
-
accessKeyId: z.string().max(BACKUP_ACCESS_KEY_MAX).nullable(),
|
|
65
|
-
secret: z.string().max(BACKUP_SECRET_MAX).nullable(),
|
|
66
|
-
pathStyle: z.boolean()
|
|
67
|
-
}),
|
|
68
|
-
output: z.object({ destination: backupDestinationSchema })
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/** `secret` omis = inchangé: le serveur ne l'a jamais rendu, on ne le réécrit pas. */
|
|
72
|
-
export const backupDestinationUpdate = {
|
|
73
|
-
command: 'backup.destinationUpdate' as const,
|
|
74
|
-
input: z.object({
|
|
75
|
-
destinationId,
|
|
76
|
-
name: z.string().min(1).max(BACKUP_DESTINATION_NAME_MAX),
|
|
77
|
-
deviceId: z.uuid().nullable(),
|
|
78
|
-
path: z.string().max(BACKUP_PATH_MAX),
|
|
79
|
-
endpoint: z.string().max(BACKUP_ENDPOINT_MAX).nullable(),
|
|
80
|
-
region: z.string().max(64).nullable(),
|
|
81
|
-
bucket: z.string().max(BACKUP_BUCKET_MAX).nullable(),
|
|
82
|
-
accessKeyId: z.string().max(BACKUP_ACCESS_KEY_MAX).nullable(),
|
|
83
|
-
secret: z.string().max(BACKUP_SECRET_MAX).optional(),
|
|
84
|
-
pathStyle: z.boolean()
|
|
85
|
-
}),
|
|
86
|
-
output: z.object({ destination: backupDestinationSchema })
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Retire une destination. **Refusée** tant qu'un travail la vise.
|
|
91
|
-
*
|
|
92
|
-
* Contrairement aux jetons de déploiement, qui laissent la cible orpheline mais
|
|
93
|
-
* vivante: un travail sans destination n'a aucun comportement raisonnable — il
|
|
94
|
-
* ne peut ni s'exécuter ni le dire à l'avance. Mieux vaut obliger à trancher.
|
|
95
|
-
*/
|
|
96
|
-
export const backupDestinationRemove = {
|
|
97
|
-
command: 'backup.destinationRemove' as const,
|
|
98
|
-
input: z.object({ destinationId }),
|
|
99
|
-
output: z.object({ destinationId })
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Contrôle qu'une destination est joignable et inscriptible, **maintenant**.
|
|
104
|
-
*
|
|
105
|
-
* Écrit puis relit puis efface un petit objet témoin: lister un bucket ne prouve
|
|
106
|
-
* pas qu'on peut y écrire, et découvrir le contraire à 3 h du matin est
|
|
107
|
-
* exactement ce que cette commande existe pour éviter.
|
|
108
|
-
*/
|
|
109
|
-
export const backupDestinationTest = {
|
|
110
|
-
command: 'backup.destinationTest' as const,
|
|
111
|
-
input: z.object({ destinationId }),
|
|
112
|
-
output: backupDestinationProbeSchema
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// ---------------------------------------------------------------- travaux
|
|
116
|
-
|
|
117
|
-
/** Les travaux de l'espace, avec l'état de leur dernier passage. */
|
|
118
|
-
export const backupJobList = {
|
|
119
|
-
command: 'backup.jobList' as const,
|
|
120
|
-
input: z.object({}),
|
|
121
|
-
output: z.object({ jobs: z.array(backupJobSchema) })
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/** Compte les travaux actifs. Métadonnée en clair pure, pour la tuile d'accueil. */
|
|
125
|
-
export const backupCount = {
|
|
126
|
-
command: 'backup.count' as const,
|
|
127
|
-
input: z.object({}),
|
|
128
|
-
output: z.object({
|
|
129
|
-
count: z.number().int().nonnegative(),
|
|
130
|
-
/** Combien ont échoué à leur dernier passage — ce que la tuile signale. */
|
|
131
|
-
failing: z.number().int().nonnegative()
|
|
132
|
-
})
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
/** Un travail et son historique, du plus récent au plus ancien. */
|
|
136
|
-
export const backupJobGet = {
|
|
137
|
-
command: 'backup.jobGet' as const,
|
|
138
|
-
input: z.object({ jobId, limit: z.number().int().positive().max(100).optional() }),
|
|
139
|
-
output: z.object({ job: backupJobSchema, runs: z.array(backupRunSchema) })
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const jobBody = {
|
|
143
|
-
name: z.string().min(1).max(BACKUP_JOB_NAME_MAX),
|
|
144
|
-
destinationId,
|
|
145
|
-
encryption: backupEncryptionSchema,
|
|
146
|
-
source: backupSourceKindSchema,
|
|
147
|
-
sourceId: z.number().int().positive().nullable(),
|
|
148
|
-
enabled: z.boolean(),
|
|
149
|
-
schedule: backupScheduleKindSchema,
|
|
150
|
-
scheduleHour: z.number().int().min(0).max(23),
|
|
151
|
-
scheduleWeekday: z.number().int().min(0).max(6),
|
|
152
|
-
scheduleDay: z.number().int().min(1).max(28),
|
|
153
|
-
keepLast: z.number().int().min(1).max(365)
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
export const backupJobAdd = {
|
|
157
|
-
command: 'backup.jobAdd' as const,
|
|
158
|
-
input: z.object(jobBody),
|
|
159
|
-
output: z.object({ job: backupJobSchema })
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
export const backupJobUpdate = {
|
|
163
|
-
command: 'backup.jobUpdate' as const,
|
|
164
|
-
input: z.object({ jobId, ...jobBody }),
|
|
165
|
-
output: z.object({ job: backupJobSchema })
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Supprime un travail et son historique.
|
|
170
|
-
*
|
|
171
|
-
* Les archives déjà écrites ne sont **pas** touchées: DevEye a produit des
|
|
172
|
-
* fichiers chez quelqu'un d'autre, et les effacer parce qu'on range sa
|
|
173
|
-
* configuration serait le contraire d'une sauvegarde. L'écran le dit.
|
|
174
|
-
*/
|
|
175
|
-
export const backupJobRemove = {
|
|
176
|
-
command: 'backup.jobRemove' as const,
|
|
177
|
-
input: z.object({ jobId }),
|
|
178
|
-
output: z.object({ jobId })
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Lance un travail tout de suite.
|
|
183
|
-
*
|
|
184
|
-
* Ne rend pas l'archive: une sauvegarde dure des minutes, et attendre la réponse
|
|
185
|
-
* d'une commande WS pendant ce temps-là ne marcherait pas. Elle inscrit
|
|
186
|
-
* l'exécution en `running` et rend sa ligne; l'avancement se lit en
|
|
187
|
-
* re-sollicitant, comme partout ailleurs (le sujet `backup` est diffusé à
|
|
188
|
-
* chaque transition).
|
|
189
|
-
*/
|
|
190
|
-
export const backupJobRun = {
|
|
191
|
-
command: 'backup.jobRun' as const,
|
|
192
|
-
input: z.object({ jobId }),
|
|
193
|
-
output: z.object({ run: backupRunSchema })
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
/** Les sources sauvegardables de l'espace, pour remplir le sélecteur. */
|
|
197
|
-
export const backupSources = {
|
|
198
|
-
command: 'backup.sources' as const,
|
|
199
|
-
input: z.object({}),
|
|
200
|
-
output: z.object({ candidates: z.array(backupSourceCandidateSchema) })
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Les dernières exécutions de l'espace, tous travaux confondus.
|
|
205
|
-
*
|
|
206
|
-
* Ce que la vue d'ensemble montre: on veut savoir « est-ce que mes sauvegardes
|
|
207
|
-
* tournent », pas ouvrir sept fiches pour le découvrir.
|
|
208
|
-
*/
|
|
209
|
-
export const backupRuns = {
|
|
210
|
-
command: 'backup.runs' as const,
|
|
211
|
-
input: z.object({ limit: z.number().int().positive().max(200).optional() }),
|
|
212
|
-
output: z.object({ runs: z.array(backupRunSchema) })
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
export const backupCommands = [
|
|
216
|
-
backupDestinationList,
|
|
217
|
-
backupDestinationAdd,
|
|
218
|
-
backupDestinationUpdate,
|
|
219
|
-
backupDestinationRemove,
|
|
220
|
-
backupDestinationTest,
|
|
221
|
-
backupJobList,
|
|
222
|
-
backupCount,
|
|
223
|
-
backupJobGet,
|
|
224
|
-
backupJobAdd,
|
|
225
|
-
backupJobUpdate,
|
|
226
|
-
backupJobRemove,
|
|
227
|
-
backupJobRun,
|
|
228
|
-
backupSources,
|
|
229
|
-
backupRuns
|
|
230
|
-
] as const;
|
package/src/features/database.ts
DELETED
|
@@ -1,461 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
DATABASE_ALERT_MESSAGE_MAX_LENGTH,
|
|
4
|
-
DATABASE_ALERT_NAME_MAX_LENGTH,
|
|
5
|
-
DATABASE_HOST_MAX_LENGTH,
|
|
6
|
-
DATABASE_NAME_MAX_LENGTH,
|
|
7
|
-
DATABASE_SECRET_MAX_LENGTH,
|
|
8
|
-
DATABASE_SQL_MAX_LENGTH,
|
|
9
|
-
DATABASE_USER_MAX_LENGTH,
|
|
10
|
-
databaseAccessKindSchema,
|
|
11
|
-
databaseAlertSchema,
|
|
12
|
-
databaseCellSchema,
|
|
13
|
-
databaseCombinatorSchema,
|
|
14
|
-
databaseConditionSchema,
|
|
15
|
-
databaseEngineSchema,
|
|
16
|
-
databaseExecutionSchema,
|
|
17
|
-
databaseExportFormatSchema,
|
|
18
|
-
databaseFilterSchema,
|
|
19
|
-
databaseIdRangeSchema,
|
|
20
|
-
databaseProbeSchema,
|
|
21
|
-
databaseRowsSchema,
|
|
22
|
-
databaseSchema,
|
|
23
|
-
databaseSortSchema,
|
|
24
|
-
databaseSshAuthSchema,
|
|
25
|
-
databaseStructureSchema,
|
|
26
|
-
databaseTableSchema,
|
|
27
|
-
databaseUsageSchema
|
|
28
|
-
} from '../domain/database';
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Commandes des bases de données de l'espace.
|
|
32
|
-
*
|
|
33
|
-
* Préfixe unique `database.`, comme `git.` et `project.` — d'où le camelCase
|
|
34
|
-
* derrière le point.
|
|
35
|
-
*
|
|
36
|
-
* ⚠️ Conséquence à connaître : le filet de démarrage (`MUTATION_VERB` dans
|
|
37
|
-
* `src/features/_topics.ts`) cherche un verbe **juste après le point**. Il ne
|
|
38
|
-
* verra donc **aucune** de ces commandes, et un `mutates` oublié ne produira
|
|
39
|
-
* aucun avertissement. Il se relit à la main.
|
|
40
|
-
*
|
|
41
|
-
* ## Rien ne se connecte tout seul
|
|
42
|
-
*
|
|
43
|
-
* Seules `test`, `inspect`, `tableList`, `tableRows` et `alertTest` joignent la
|
|
44
|
-
* base, et toutes sont déclenchées par un geste explicite. `list` et `get`
|
|
45
|
-
* lisent le cache local — ouvrir la feature ne réveille aucun serveur.
|
|
46
|
-
*
|
|
47
|
-
* L'espace visé n'apparaît dans aucune entrée : il voyage sur l'enveloppe WS et
|
|
48
|
-
* le dispatcheur le résout, appartenance vérifiée, avant le handler.
|
|
49
|
-
*/
|
|
50
|
-
|
|
51
|
-
const databaseId = z.number().int().positive();
|
|
52
|
-
const alertId = z.number().int().positive();
|
|
53
|
-
|
|
54
|
-
/** La partie réglable d'un accès, secret compris (jamais rendu en retour). */
|
|
55
|
-
const accessInput = z.object({
|
|
56
|
-
kind: databaseAccessKindSchema,
|
|
57
|
-
host: z.string().max(DATABASE_HOST_MAX_LENGTH),
|
|
58
|
-
port: z.number().int().min(1).max(65535).nullable(),
|
|
59
|
-
username: z.string().max(DATABASE_USER_MAX_LENGTH),
|
|
60
|
-
auth: databaseSshAuthSchema,
|
|
61
|
-
/**
|
|
62
|
-
* Mot de passe SSH ou clé privée. Absent = on garde celui en place ; une
|
|
63
|
-
* chaîne vide l'efface. Le client ne le reçoit jamais, il ne peut donc pas
|
|
64
|
-
* le renvoyer inchangé — d'où cette convention plutôt qu'un champ obligatoire.
|
|
65
|
-
*/
|
|
66
|
-
secret: z.string().max(DATABASE_SECRET_MAX_LENGTH).optional()
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// ------------------------------------------------------------------- bases
|
|
70
|
-
|
|
71
|
-
/** Le nombre de bases de l'espace, pour la tuile de l'accueil. */
|
|
72
|
-
export const databaseCount = {
|
|
73
|
-
command: 'database.count' as const,
|
|
74
|
-
input: z.object({}),
|
|
75
|
-
output: z.object({ count: z.number().int().nonnegative() })
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
/** Les bases de l'espace, dans l'ordre de l'utilisateur. Lit le cache local. */
|
|
79
|
-
export const databaseList = {
|
|
80
|
-
command: 'database.list' as const,
|
|
81
|
-
input: z.object({}),
|
|
82
|
-
output: z.object({ databases: z.array(databaseSchema) })
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/** Une base, avec les projets qui s'en servent et ses alertes. */
|
|
86
|
-
export const databaseGet = {
|
|
87
|
-
command: 'database.get' as const,
|
|
88
|
-
input: z.object({ databaseId }),
|
|
89
|
-
output: z.object({
|
|
90
|
-
database: databaseSchema,
|
|
91
|
-
usage: z.array(databaseUsageSchema),
|
|
92
|
-
alerts: z.array(databaseAlertSchema)
|
|
93
|
-
})
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
export const databaseAdd = {
|
|
97
|
-
command: 'database.add' as const,
|
|
98
|
-
input: z.object({
|
|
99
|
-
engine: databaseEngineSchema,
|
|
100
|
-
name: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
101
|
-
host: z.string().min(1).max(DATABASE_HOST_MAX_LENGTH),
|
|
102
|
-
port: z.number().int().min(1).max(65535),
|
|
103
|
-
database: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
104
|
-
username: z.string().max(DATABASE_USER_MAX_LENGTH),
|
|
105
|
-
password: z.string().max(DATABASE_SECRET_MAX_LENGTH),
|
|
106
|
-
access: accessInput,
|
|
107
|
-
monitorEnabled: z.boolean(),
|
|
108
|
-
intervalSeconds: z.number().int().min(60).max(86400),
|
|
109
|
-
autoLoadTables: z.boolean()
|
|
110
|
-
}),
|
|
111
|
-
output: z.object({ database: databaseSchema })
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Modifie une base. `password` absent = on garde celui en place ; une chaîne
|
|
116
|
-
* vide l'efface. Même convention que le secret du tunnel, et pour la même
|
|
117
|
-
* raison : un secret rendu au client est un secret qu'on ne peut plus reprendre.
|
|
118
|
-
*/
|
|
119
|
-
export const databaseUpdate = {
|
|
120
|
-
command: 'database.update' as const,
|
|
121
|
-
input: z.object({
|
|
122
|
-
databaseId,
|
|
123
|
-
name: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
124
|
-
host: z.string().min(1).max(DATABASE_HOST_MAX_LENGTH),
|
|
125
|
-
port: z.number().int().min(1).max(65535),
|
|
126
|
-
database: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
127
|
-
username: z.string().max(DATABASE_USER_MAX_LENGTH),
|
|
128
|
-
password: z.string().max(DATABASE_SECRET_MAX_LENGTH).optional(),
|
|
129
|
-
access: accessInput,
|
|
130
|
-
monitorEnabled: z.boolean(),
|
|
131
|
-
intervalSeconds: z.number().int().min(60).max(86400),
|
|
132
|
-
autoLoadTables: z.boolean()
|
|
133
|
-
}),
|
|
134
|
-
output: z.object({ database: databaseSchema })
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Retire une base de l'espace, avec ses alertes et toutes ses liaisons.
|
|
139
|
-
*
|
|
140
|
-
* Les projets liés ne sont **pas** touchés : ils perdent leur base, rien
|
|
141
|
-
* d'autre. Le serveur distant, lui, n'est évidemment jamais atteint.
|
|
142
|
-
*/
|
|
143
|
-
export const databaseRemove = {
|
|
144
|
-
command: 'database.remove' as const,
|
|
145
|
-
input: z.object({ databaseId }),
|
|
146
|
-
output: z.object({ databaseId })
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Range les bases de l'espace : `ids` est la liste **complète** dans son ordre
|
|
151
|
-
* final. Une nouvelle base prend le rang suivant, donc la fin de la liste.
|
|
152
|
-
*/
|
|
153
|
-
export const databaseReorder = {
|
|
154
|
-
command: 'database.reorder' as const,
|
|
155
|
-
input: z.object({ ids: z.array(databaseId).min(1) }),
|
|
156
|
-
output: z.object({ ids: z.array(databaseId) })
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// ------------------------------------------------------- à la demande
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Essaie de joindre la base, maintenant.
|
|
163
|
-
*
|
|
164
|
-
* Ne lève **jamais** sur un échec de connexion : un serveur injoignable est une
|
|
165
|
-
* réponse, pas une erreur de commande. Le message revient dans `error`, déjà
|
|
166
|
-
* traduit, et l'interface le montre sans rien bloquer.
|
|
167
|
-
*/
|
|
168
|
-
export const databaseTest = {
|
|
169
|
-
command: 'database.test' as const,
|
|
170
|
-
input: z.object({ databaseId }),
|
|
171
|
-
output: z.object({ probe: databaseProbeSchema })
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Essaie une connexion **avant** de l'enregistrer.
|
|
176
|
-
*
|
|
177
|
-
* Le formulaire d'ajout décrit une base qui n'existe pas encore : `test` ne peut
|
|
178
|
-
* rien pour lui, il part d'un identifiant. Celui-ci prend les réglages tels
|
|
179
|
-
* qu'ils sont saisis, et n'écrit rien — ni ligne, ni état.
|
|
180
|
-
*
|
|
181
|
-
* `databaseId` sert à la modification : les secrets ne redescendant jamais au
|
|
182
|
-
* client, un champ laissé intact n'a rien à renvoyer, et le serveur reprend
|
|
183
|
-
* alors celui qu'il détient déjà. Sans cela, « Tester » échouerait sur une base
|
|
184
|
-
* qui fonctionne, faute de mot de passe.
|
|
185
|
-
*/
|
|
186
|
-
export const databaseTestDraft = {
|
|
187
|
-
command: 'database.testDraft' as const,
|
|
188
|
-
input: z.object({
|
|
189
|
-
databaseId: databaseId.optional(),
|
|
190
|
-
engine: databaseEngineSchema,
|
|
191
|
-
host: z.string().min(1).max(DATABASE_HOST_MAX_LENGTH),
|
|
192
|
-
port: z.number().int().min(1).max(65535),
|
|
193
|
-
database: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
194
|
-
username: z.string().max(DATABASE_USER_MAX_LENGTH),
|
|
195
|
-
password: z.string().max(DATABASE_SECRET_MAX_LENGTH).optional(),
|
|
196
|
-
access: accessInput
|
|
197
|
-
}),
|
|
198
|
-
output: z.object({ probe: databaseProbeSchema })
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Relève l'inventaire maintenant : version du serveur, taille, nombre de
|
|
203
|
-
* tables, et l'état des alertes. C'est ce que fait le relevé périodique, sur
|
|
204
|
-
* demande explicite — ce qui le rend utile même sur une base au repos.
|
|
205
|
-
*/
|
|
206
|
-
export const databaseInspect = {
|
|
207
|
-
command: 'database.inspect' as const,
|
|
208
|
-
input: z.object({ databaseId }),
|
|
209
|
-
output: z.object({ database: databaseSchema, probe: databaseProbeSchema })
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
/** Les tables de la base, lues chez le serveur au moment de la demande. */
|
|
213
|
-
export const databaseTableList = {
|
|
214
|
-
command: 'database.tableList' as const,
|
|
215
|
-
input: z.object({ databaseId }),
|
|
216
|
-
output: z.object({ tables: z.array(databaseTableSchema) })
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Le contenu d'une table, page par page.
|
|
221
|
-
*
|
|
222
|
-
* ## Rien de ce qui vient du client n'entre tel quel dans une requête
|
|
223
|
-
*
|
|
224
|
-
* Un identifiant ne peut pas être un paramètre lié : nom de table, nom de
|
|
225
|
-
* colonne, sens du tri sont donc **confrontés au catalogue réel** avant d'être
|
|
226
|
-
* cités, et un nom qui n'y figure pas n'atteint jamais le moteur. Les valeurs,
|
|
227
|
-
* elles, sont toujours liées ; l'opérateur d'un filtre est choisi dans une
|
|
228
|
-
* énumération fermée. Aucun fragment de SQL ne traverse le contrat.
|
|
229
|
-
*
|
|
230
|
-
* `withStructure` évite un second aller-retour à la sélection d'une table : la
|
|
231
|
-
* structure et la première page arrivent alors dans la **même session**, ce qui
|
|
232
|
-
* compte quand chaque connexion rouvre un tunnel SSH.
|
|
233
|
-
*/
|
|
234
|
-
export const databaseTableRows = {
|
|
235
|
-
command: 'database.tableRows' as const,
|
|
236
|
-
input: z.object({
|
|
237
|
-
databaseId,
|
|
238
|
-
schema: z.string().max(DATABASE_NAME_MAX_LENGTH),
|
|
239
|
-
table: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
240
|
-
offset: z.number().int().nonnegative().max(1_000_000).optional(),
|
|
241
|
-
limit: z.number().int().positive().max(200).optional(),
|
|
242
|
-
filters: z.array(databaseFilterSchema).max(8).optional(),
|
|
243
|
-
combinator: databaseCombinatorSchema.optional(),
|
|
244
|
-
sort: databaseSortSchema.optional(),
|
|
245
|
-
withStructure: z.boolean().optional()
|
|
246
|
-
}),
|
|
247
|
-
output: z.object({ rows: databaseRowsSchema, structure: databaseStructureSchema.optional() })
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
/** La structure seule : colonnes, clé primaire, clés étrangères, index. */
|
|
251
|
-
export const databaseTableStructure = {
|
|
252
|
-
command: 'database.tableStructure' as const,
|
|
253
|
-
input: z.object({
|
|
254
|
-
databaseId,
|
|
255
|
-
schema: z.string().max(DATABASE_NAME_MAX_LENGTH),
|
|
256
|
-
table: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH)
|
|
257
|
-
}),
|
|
258
|
-
output: z.object({ structure: databaseStructureSchema })
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// ------------------------------------------------------- écrire des lignes
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Les trois écritures de l'explorateur.
|
|
265
|
-
*
|
|
266
|
-
* ## Ce que le serveur refuse, et pourquoi
|
|
267
|
-
*
|
|
268
|
-
* Modifier ou supprimer exige une **clé primaire**. Sans elle, aucune condition
|
|
269
|
-
* ne désigne *une* ligne : un `UPDATE` en toucherait plusieurs, un `DELETE` en
|
|
270
|
-
* emporterait autant, et rien ne permettrait de revenir en arrière. Le serveur
|
|
271
|
-
* refuse alors, avec la raison ; l'interface ne propose même pas le geste.
|
|
272
|
-
*
|
|
273
|
-
* ## Ce qui décide en dernier ressort
|
|
274
|
-
*
|
|
275
|
-
* Le compte saisi dans les réglages de la base. DevEye peut demander une
|
|
276
|
-
* écriture ; c'est le serveur distant qui l'accorde ou la refuse. Un compte en
|
|
277
|
-
* lecture seule rend donc tout ceci inoffensif, ce que dit le formulaire.
|
|
278
|
-
*/
|
|
279
|
-
export const databaseRowInsert = {
|
|
280
|
-
command: 'database.rowInsert' as const,
|
|
281
|
-
input: z.object({
|
|
282
|
-
databaseId,
|
|
283
|
-
schema: z.string().max(DATABASE_NAME_MAX_LENGTH),
|
|
284
|
-
table: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
285
|
-
values: z.array(databaseCellSchema).min(1).max(200)
|
|
286
|
-
}),
|
|
287
|
-
output: z.object({ inserted: z.number().int().nonnegative() })
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
export const databaseRowUpdate = {
|
|
291
|
-
command: 'database.rowUpdate' as const,
|
|
292
|
-
input: z.object({
|
|
293
|
-
databaseId,
|
|
294
|
-
schema: z.string().max(DATABASE_NAME_MAX_LENGTH),
|
|
295
|
-
table: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
296
|
-
/** La ligne visée, par ses colonnes de clé primaire. */
|
|
297
|
-
key: z.array(databaseCellSchema).min(1).max(16),
|
|
298
|
-
values: z.array(databaseCellSchema).min(1).max(200)
|
|
299
|
-
}),
|
|
300
|
-
output: z.object({ updated: z.number().int().nonnegative() })
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
export const databaseRowDelete = {
|
|
304
|
-
command: 'database.rowDelete' as const,
|
|
305
|
-
input: z.object({
|
|
306
|
-
databaseId,
|
|
307
|
-
schema: z.string().max(DATABASE_NAME_MAX_LENGTH),
|
|
308
|
-
table: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH),
|
|
309
|
-
/** Une entrée par ligne, chacune par ses colonnes de clé primaire. */
|
|
310
|
-
keys: z.array(z.array(databaseCellSchema).min(1).max(16)).min(1).max(200)
|
|
311
|
-
}),
|
|
312
|
-
output: z.object({ deleted: z.number().int().nonnegative() })
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Une instruction libre, écriture comprise — le terminal.
|
|
317
|
-
*
|
|
318
|
-
* Distincte de `query`, qui refuse tout ce qui n'est pas une lecture parce
|
|
319
|
-
* qu'elle sert à mettre au point une condition d'alerte. Ici l'intention est
|
|
320
|
-
* l'inverse : administrer. Une seule instruction à la fois malgré tout, le
|
|
321
|
-
* point-virgule interne restant refusé — c'est ce qui empêche qu'un copier-coller
|
|
322
|
-
* en exécute trois quand on en visait une.
|
|
323
|
-
*/
|
|
324
|
-
export const databaseExecute = {
|
|
325
|
-
command: 'database.execute' as const,
|
|
326
|
-
input: z.object({ databaseId, sql: z.string().min(1).max(DATABASE_SQL_MAX_LENGTH) }),
|
|
327
|
-
output: z.object({ result: databaseExecutionSchema })
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Exporte une table, ou toute la base.
|
|
332
|
-
*
|
|
333
|
-
* L'export est **complet** : il lit tout ce que la portée désigne, page par
|
|
334
|
-
* page. Le seul plafond qui subsiste est un garde-fou mémoire du serveur, très
|
|
335
|
-
* au-dessus de ce qu'un export normal atteint ; s'il est touché, `truncated` le
|
|
336
|
-
* dit et l'interface le répète. Pour une copie fidèle d'un serveur entier,
|
|
337
|
-
* `mysqldump` et `pg_dump` restent malgré tout les bons outils — eux savent
|
|
338
|
-
* rejouer schéma, index et contraintes.
|
|
339
|
-
*
|
|
340
|
-
* `idRanges` restreint l'export aux lignes dont la **clé primaire** tombe dans
|
|
341
|
-
* l'une des plages. Réservé à une portée d'une seule table : sur toute la base,
|
|
342
|
-
* les clés n'ont ni le même nom ni le même sens d'une table à l'autre.
|
|
343
|
-
*/
|
|
344
|
-
export const databaseExport = {
|
|
345
|
-
command: 'database.export' as const,
|
|
346
|
-
input: z.object({
|
|
347
|
-
databaseId,
|
|
348
|
-
format: databaseExportFormatSchema,
|
|
349
|
-
/** Absents : toute la base. Présents : cette table seule. */
|
|
350
|
-
schema: z.string().max(DATABASE_NAME_MAX_LENGTH).optional(),
|
|
351
|
-
table: z.string().min(1).max(DATABASE_NAME_MAX_LENGTH).optional(),
|
|
352
|
-
/** Plages d'identifiants, bornes comprises. Sans effet sans `table`. */
|
|
353
|
-
idRanges: z.array(databaseIdRangeSchema).max(64).optional()
|
|
354
|
-
}),
|
|
355
|
-
output: z.object({
|
|
356
|
-
filename: z.string(),
|
|
357
|
-
content: z.string(),
|
|
358
|
-
rowCount: z.number().int().nonnegative(),
|
|
359
|
-
tableCount: z.number().int().nonnegative(),
|
|
360
|
-
/** Le plafond a été atteint : ce qui suit manque. */
|
|
361
|
-
truncated: z.boolean()
|
|
362
|
-
})
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
// ----------------------------------------------------------------- alertes
|
|
366
|
-
|
|
367
|
-
export const databaseAlertList = {
|
|
368
|
-
command: 'database.alertList' as const,
|
|
369
|
-
input: z.object({ databaseId }),
|
|
370
|
-
output: z.object({ alerts: z.array(databaseAlertSchema) })
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
export const databaseAlertAdd = {
|
|
374
|
-
command: 'database.alertAdd' as const,
|
|
375
|
-
input: z.object({
|
|
376
|
-
databaseId,
|
|
377
|
-
name: z.string().min(1).max(DATABASE_ALERT_NAME_MAX_LENGTH),
|
|
378
|
-
enabled: z.boolean(),
|
|
379
|
-
combinator: databaseCombinatorSchema,
|
|
380
|
-
conditions: z.array(databaseConditionSchema).min(1).max(8),
|
|
381
|
-
message: z.string().min(1).max(DATABASE_ALERT_MESSAGE_MAX_LENGTH)
|
|
382
|
-
}),
|
|
383
|
-
output: z.object({ alert: databaseAlertSchema })
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
export const databaseAlertUpdate = {
|
|
387
|
-
command: 'database.alertUpdate' as const,
|
|
388
|
-
input: z.object({
|
|
389
|
-
alertId,
|
|
390
|
-
name: z.string().min(1).max(DATABASE_ALERT_NAME_MAX_LENGTH),
|
|
391
|
-
enabled: z.boolean(),
|
|
392
|
-
combinator: databaseCombinatorSchema,
|
|
393
|
-
conditions: z.array(databaseConditionSchema).min(1).max(8),
|
|
394
|
-
message: z.string().min(1).max(DATABASE_ALERT_MESSAGE_MAX_LENGTH)
|
|
395
|
-
}),
|
|
396
|
-
output: z.object({ alert: databaseAlertSchema })
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
export const databaseAlertRemove = {
|
|
400
|
-
command: 'database.alertRemove' as const,
|
|
401
|
-
input: z.object({ alertId }),
|
|
402
|
-
output: z.object({ alertId })
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Évalue une alerte tout de suite et rend ce que chaque condition a mesuré,
|
|
407
|
-
* **sans notifier personne**.
|
|
408
|
-
*
|
|
409
|
-
* C'est ce qui rend une condition écrivable : on voit le nombre que rend sa
|
|
410
|
-
* requête avant de choisir un seuil, au lieu d'attendre une notification pour
|
|
411
|
-
* découvrir qu'on s'est trompé de colonne.
|
|
412
|
-
*/
|
|
413
|
-
export const databaseAlertTest = {
|
|
414
|
-
command: 'database.alertTest' as const,
|
|
415
|
-
input: z.object({
|
|
416
|
-
databaseId,
|
|
417
|
-
combinator: databaseCombinatorSchema,
|
|
418
|
-
conditions: z.array(databaseConditionSchema).min(1).max(8)
|
|
419
|
-
}),
|
|
420
|
-
output: z.object({
|
|
421
|
-
firing: z.boolean(),
|
|
422
|
-
values: z.array(z.number().nullable()),
|
|
423
|
-
/** L'erreur de chaque condition, à sa place — `null` si elle a abouti. */
|
|
424
|
-
errors: z.array(z.string().nullable()),
|
|
425
|
-
elapsedMs: z.number().int().nonnegative()
|
|
426
|
-
})
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
/** Une requête libre en lecture seule, pour mettre au point une condition. */
|
|
430
|
-
export const databaseQuery = {
|
|
431
|
-
command: 'database.query' as const,
|
|
432
|
-
input: z.object({ databaseId, sql: z.string().min(1).max(DATABASE_SQL_MAX_LENGTH) }),
|
|
433
|
-
output: z.object({ rows: databaseRowsSchema })
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
export const databaseCommands = [
|
|
437
|
-
databaseCount,
|
|
438
|
-
databaseList,
|
|
439
|
-
databaseGet,
|
|
440
|
-
databaseAdd,
|
|
441
|
-
databaseUpdate,
|
|
442
|
-
databaseRemove,
|
|
443
|
-
databaseReorder,
|
|
444
|
-
databaseTest,
|
|
445
|
-
databaseTestDraft,
|
|
446
|
-
databaseInspect,
|
|
447
|
-
databaseTableList,
|
|
448
|
-
databaseTableRows,
|
|
449
|
-
databaseTableStructure,
|
|
450
|
-
databaseRowInsert,
|
|
451
|
-
databaseRowUpdate,
|
|
452
|
-
databaseRowDelete,
|
|
453
|
-
databaseExecute,
|
|
454
|
-
databaseExport,
|
|
455
|
-
databaseAlertList,
|
|
456
|
-
databaseAlertAdd,
|
|
457
|
-
databaseAlertUpdate,
|
|
458
|
-
databaseAlertRemove,
|
|
459
|
-
databaseAlertTest,
|
|
460
|
-
databaseQuery
|
|
461
|
-
] as const;
|