@deveye/types 0.15.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/package.json +68 -0
  4. package/src/domain/audience.ts +549 -0
  5. package/src/domain/backup.ts +355 -0
  6. package/src/domain/credential.ts +55 -0
  7. package/src/domain/database.ts +467 -0
  8. package/src/domain/deploy.ts +231 -0
  9. package/src/domain/device.ts +172 -0
  10. package/src/domain/deviceFiles.ts +84 -0
  11. package/src/domain/deviceLogs.ts +82 -0
  12. package/src/domain/featureRegistry.ts +392 -0
  13. package/src/domain/finance.ts +477 -0
  14. package/src/domain/git.ts +419 -0
  15. package/src/domain/home.ts +314 -0
  16. package/src/domain/live.ts +272 -0
  17. package/src/domain/logs.ts +117 -0
  18. package/src/domain/mail.ts +394 -0
  19. package/src/domain/metrics.ts +127 -0
  20. package/src/domain/note.ts +202 -0
  21. package/src/domain/notifications.ts +268 -0
  22. package/src/domain/packages.ts +35 -0
  23. package/src/domain/password.ts +36 -0
  24. package/src/domain/presence.ts +21 -0
  25. package/src/domain/project.ts +168 -0
  26. package/src/domain/projectBoard.ts +130 -0
  27. package/src/domain/projectChat.ts +46 -0
  28. package/src/domain/projectHistory.ts +82 -0
  29. package/src/domain/projectLink.ts +87 -0
  30. package/src/domain/projectPlan.ts +68 -0
  31. package/src/domain/report.ts +492 -0
  32. package/src/domain/role.ts +8 -0
  33. package/src/domain/secrecy.ts +66 -0
  34. package/src/domain/sentinel.ts +623 -0
  35. package/src/domain/sharing.ts +186 -0
  36. package/src/domain/syncProtocol.ts +116 -0
  37. package/src/domain/twoFactor.ts +40 -0
  38. package/src/domain/uptime.ts +216 -0
  39. package/src/domain/user.ts +141 -0
  40. package/src/domain/workspace.ts +56 -0
  41. package/src/domain/workspaceRole.ts +251 -0
  42. package/src/features/admin.ts +112 -0
  43. package/src/features/audience.ts +275 -0
  44. package/src/features/backup.ts +230 -0
  45. package/src/features/database.ts +461 -0
  46. package/src/features/deploy.ts +245 -0
  47. package/src/features/device.ts +292 -0
  48. package/src/features/deviceFiles.ts +83 -0
  49. package/src/features/deviceLogs.ts +36 -0
  50. package/src/features/deviceTerminal.ts +57 -0
  51. package/src/features/finance.ts +360 -0
  52. package/src/features/git.ts +368 -0
  53. package/src/features/home.ts +32 -0
  54. package/src/features/live.ts +113 -0
  55. package/src/features/logs.ts +86 -0
  56. package/src/features/mail.ts +374 -0
  57. package/src/features/metrics.ts +185 -0
  58. package/src/features/note.ts +189 -0
  59. package/src/features/notify.ts +164 -0
  60. package/src/features/password.ts +67 -0
  61. package/src/features/project.ts +709 -0
  62. package/src/features/registry.ts +103 -0
  63. package/src/features/secrecy.ts +120 -0
  64. package/src/features/sentinel.ts +233 -0
  65. package/src/features/sharing.ts +79 -0
  66. package/src/features/twoFactor.ts +47 -0
  67. package/src/features/uptime.ts +186 -0
  68. package/src/features/user.ts +91 -0
  69. package/src/features/workspace.ts +200 -0
  70. package/src/http/auth.ts +94 -0
  71. package/src/http/device.ts +222 -0
  72. package/src/http/status.ts +45 -0
  73. package/src/index.ts +1700 -0
  74. package/src/protocol/agent.ts +1171 -0
  75. package/src/protocol/envelope.ts +46 -0
  76. package/src/protocol/error.ts +27 -0
  77. package/src/protocol/result.ts +17 -0
  78. package/src/protocol/version.ts +6 -0
  79. package/src/sdk/client-ambient.d.ts +238 -0
  80. package/src/sdk/client.ts +66 -0
  81. package/src/sdk/ids.ts +25 -0
  82. package/src/sdk/index.ts +11 -0
  83. package/src/sdk/manifest.ts +326 -0
  84. package/src/sdk/providers.ts +48 -0
  85. package/src/sdk/server.ts +378 -0
  86. package/src/sdk/testing.ts +179 -0
  87. package/src/utils/version.ts +28 -0
@@ -0,0 +1,461 @@
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;
@@ -0,0 +1,245 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ CREDENTIAL_LABEL_MAX_LENGTH,
4
+ CREDENTIAL_SECRET_MAX_LENGTH,
5
+ credentialSchema
6
+ } from '../domain/credential';
7
+ import {
8
+ DEPLOY_DESCRIPTION_MAX_LENGTH,
9
+ DEPLOY_EXTERNAL_ID_MAX_LENGTH,
10
+ DEPLOY_TARGET_NAME_MAX_LENGTH,
11
+ DEPLOY_TITLE_MAX_LENGTH,
12
+ deployCandidateSchema,
13
+ deployHistoryEntrySchema,
14
+ deployTargetKindSchema,
15
+ deployTargetSchema,
16
+ deploymentSchema
17
+ } from '../domain/deploy';
18
+
19
+ /**
20
+ * Commandes du déploiement.
21
+ *
22
+ * Feature d'espace de premier rang, sur le modèle de Git : une cible appartient
23
+ * à l'espace, un projet n'y **pointe** (voir `project.deployLink`). Tout est à
24
+ * l'étage ouvert, donc aucune de ces commandes ne demande de session
25
+ * déverrouillée.
26
+ *
27
+ * Les clés d'API Dokploy vivent ici et non plus dans la feature Git, où elles
28
+ * n'avaient atterri que faute de module pour les accueillir : poser la clé qui
29
+ * déploie relève de `deploy`, pas de `git`.
30
+ */
31
+
32
+ const targetId = z.number().int().positive();
33
+ const credentialId = z.number().int().positive();
34
+
35
+ /** Les cibles de l'espace, dans l'ordre choisi par l'utilisateur. */
36
+ export const deployList = {
37
+ command: 'deploy.list' as const,
38
+ input: z.object({}),
39
+ output: z.object({ targets: z.array(deployTargetSchema) })
40
+ };
41
+
42
+ /**
43
+ * Compte les cibles. Métadonnée en clair pure : la tuile d'accueil affiche
44
+ * toujours un nombre, même session verrouillée.
45
+ */
46
+ export const deployCount = {
47
+ command: 'deploy.count' as const,
48
+ input: z.object({}),
49
+ output: z.object({ count: z.number().int().nonnegative() })
50
+ };
51
+
52
+ /** Une cible et son historique de déclenchements, du plus récent au plus ancien. */
53
+ export const deployGet = {
54
+ command: 'deploy.get' as const,
55
+ input: z.object({ targetId, limit: z.number().int().positive().max(50).optional() }),
56
+ output: z.object({
57
+ target: deployTargetSchema,
58
+ deployments: z.array(deploymentSchema),
59
+ /** Les projets qui la déploient, pour que la fiche sache où elle sert. */
60
+ projectIds: z.array(z.number().int().positive())
61
+ })
62
+ };
63
+
64
+ /**
65
+ * Déclare une cible. **Idempotente** sur (jeton, identifiant externe) : la même
66
+ * application déclarée deux fois est la même cible, et la seconde déclaration
67
+ * met simplement son intitulé à jour.
68
+ */
69
+ export const deployAdd = {
70
+ command: 'deploy.add' as const,
71
+ input: z.object({
72
+ credentialId,
73
+ kind: deployTargetKindSchema,
74
+ externalId: z.string().min(1).max(DEPLOY_EXTERNAL_ID_MAX_LENGTH),
75
+ name: z.string().min(1).max(DEPLOY_TARGET_NAME_MAX_LENGTH)
76
+ }),
77
+ output: z.object({ target: deployTargetSchema })
78
+ };
79
+
80
+ /** Change le jeton, le type ou l'intitulé d'une cible. */
81
+ export const deployUpdate = {
82
+ command: 'deploy.update' as const,
83
+ input: z.object({
84
+ targetId,
85
+ credentialId: credentialId.nullable(),
86
+ kind: deployTargetKindSchema,
87
+ externalId: z.string().min(1).max(DEPLOY_EXTERNAL_ID_MAX_LENGTH),
88
+ name: z.string().min(1).max(DEPLOY_TARGET_NAME_MAX_LENGTH)
89
+ }),
90
+ output: z.object({ target: deployTargetSchema })
91
+ };
92
+
93
+ /**
94
+ * Supprime une cible, **et son historique avec elle**.
95
+ *
96
+ * L'application chez le fournisseur n'est pas touchée : DevEye ne fait que la
97
+ * pointer. Les projets qui la déployaient perdent leur liaison, rien d'autre.
98
+ */
99
+ export const deployRemove = {
100
+ command: 'deploy.remove' as const,
101
+ input: z.object({ targetId }),
102
+ output: z.object({ targetId })
103
+ };
104
+
105
+ /** Range la liste : `targetIds` en est le contenu complet, dans son ordre final. */
106
+ export const deployReorder = {
107
+ command: 'deploy.reorder' as const,
108
+ input: z.object({ targetIds: z.array(targetId).min(1) }),
109
+ output: z.object({ targetIds: z.array(targetId) })
110
+ };
111
+
112
+ /**
113
+ * Les applications proposées par l'instance, pour en choisir une.
114
+ *
115
+ * Seule commande du module qui appelle un service externe en direct : elle sert
116
+ * à remplir un sélecteur, et attendre le prochain tour d'un ordonnanceur pour
117
+ * voir apparaître la liste n'aurait aucun sens.
118
+ */
119
+ export const deployCandidates = {
120
+ command: 'deploy.candidates' as const,
121
+ input: z.object({ credentialId }),
122
+ output: z.object({ candidates: z.array(deployCandidateSchema) })
123
+ };
124
+
125
+ /**
126
+ * Déclenche un déploiement.
127
+ *
128
+ * Toujours audité en `warn` : c'est la seule action du module qui produise un
129
+ * effet **hors** de DevEye, et savoir qui a poussé quoi en production compte
130
+ * plus que le reste.
131
+ *
132
+ * `projectId` est facultatif et ne sert qu'à la frise du projet : déclenché
133
+ * depuis l'onglet d'un projet, l'événement y est inscrit ; déclenché depuis la
134
+ * feature, il n'appartient à aucun projet en particulier.
135
+ */
136
+ export const deployTrigger = {
137
+ command: 'deploy.trigger' as const,
138
+ input: z.object({
139
+ targetId,
140
+ title: z.string().max(DEPLOY_TITLE_MAX_LENGTH),
141
+ description: z.string().max(DEPLOY_DESCRIPTION_MAX_LENGTH),
142
+ projectId: z.number().int().positive().optional()
143
+ }),
144
+ output: z.object({ deployment: deploymentSchema })
145
+ };
146
+
147
+ /**
148
+ * L'historique complet d'une cible, **tel que Dokploy le rend** — pas
149
+ * seulement ce que DevEye a déclenché : un déploiement lancé depuis
150
+ * l'interface de Dokploy ou une CI y apparaît aussi.
151
+ *
152
+ * Distincte de `deployGet`, qui reste le suivi local (léger, toujours
153
+ * disponible sans réseau vers le fournisseur) : celle-ci interroge Dokploy en
154
+ * direct à chaque appel, coûte une requête externe, et n'a donc de sens que
155
+ * là où on la demande explicitement — la fiche d'une cible dans la feature,
156
+ * pas l'onglet d'un projet qui en reliste plusieurs.
157
+ */
158
+ export const deployHistory = {
159
+ command: 'deploy.history' as const,
160
+ input: z.object({ targetId }),
161
+ output: z.object({ entries: z.array(deployHistoryEntrySchema) })
162
+ };
163
+
164
+ /**
165
+ * Le journal complet d'un déploiement, tel que Dokploy l'a produit.
166
+ *
167
+ * `externalId` vient d'une ligne de `deployHistory` : c'est la seule façon dont
168
+ * le client connaît un déploiement dont DevEye n'a pas forcément la ligne
169
+ * locale. Repose sur un point d'entrée de Dokploy sans procédure tRPC dédiée
170
+ * (voir l'adaptateur `dokploy.ts`) : peut échouer sur une instance qui
171
+ * l'authentifie autrement, ou pas du tout — l'appelant le traite alors comme
172
+ * n'importe quelle autre panne réseau.
173
+ */
174
+ export const deployLog = {
175
+ command: 'deploy.log' as const,
176
+ input: z.object({ targetId, externalId: z.string().min(1) }),
177
+ output: z.object({ log: z.string() })
178
+ };
179
+
180
+ // ------------------------------------------------------------------ jetons
181
+
182
+ /**
183
+ * Les clés d'API Dokploy de l'espace.
184
+ *
185
+ * Quatre commandes jumelles de `git.credential*` : même table, même forme, mais
186
+ * chaque feature n'expose que les jetons de ses fournisseurs et les garde
187
+ * derrière son propre droit. Le secret n'est jamais rendu.
188
+ */
189
+ export const deployCredentialList = {
190
+ command: 'deploy.credentialList' as const,
191
+ input: z.object({}),
192
+ output: z.object({ credentials: z.array(credentialSchema) })
193
+ };
194
+
195
+ /** Une instance Dokploy exige son adresse : sans elle, rien n'est adressable. */
196
+ export const deployCredentialAdd = {
197
+ command: 'deploy.credentialAdd' as const,
198
+ input: z.object({
199
+ label: z.string().min(1).max(CREDENTIAL_LABEL_MAX_LENGTH),
200
+ baseUrl: z.string().min(1).max(255),
201
+ secret: z.string().min(1).max(CREDENTIAL_SECRET_MAX_LENGTH)
202
+ }),
203
+ output: z.object({ credential: credentialSchema })
204
+ };
205
+
206
+ /** `secret` omis = inchangé : le serveur ne l'a jamais rendu, on ne le réécrit pas. */
207
+ export const deployCredentialUpdate = {
208
+ command: 'deploy.credentialUpdate' as const,
209
+ input: z.object({
210
+ credentialId,
211
+ label: z.string().min(1).max(CREDENTIAL_LABEL_MAX_LENGTH),
212
+ baseUrl: z.string().min(1).max(255),
213
+ secret: z.string().min(1).max(CREDENTIAL_SECRET_MAX_LENGTH).optional()
214
+ }),
215
+ output: z.object({ credential: credentialSchema })
216
+ };
217
+
218
+ /**
219
+ * Retire un jeton. Les cibles qui s'en servaient **restent**, sans jeton
220
+ * (`ON DELETE SET NULL`) : elles cessent d'être déployables et le disent, plutôt
221
+ * que de disparaître avec leur clé.
222
+ */
223
+ export const deployCredentialRemove = {
224
+ command: 'deploy.credentialRemove' as const,
225
+ input: z.object({ credentialId }),
226
+ output: z.object({ credentialId })
227
+ };
228
+
229
+ export const deployCommands = [
230
+ deployList,
231
+ deployCount,
232
+ deployGet,
233
+ deployAdd,
234
+ deployUpdate,
235
+ deployRemove,
236
+ deployReorder,
237
+ deployCandidates,
238
+ deployTrigger,
239
+ deployHistory,
240
+ deployLog,
241
+ deployCredentialList,
242
+ deployCredentialAdd,
243
+ deployCredentialUpdate,
244
+ deployCredentialRemove
245
+ ] as const;