@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,392 @@
1
+ import {
2
+ isExternalFeatureId,
3
+ type ExternalFeatureId,
4
+ type FeatureId,
5
+ type WorkspaceFeatureId
6
+ } from './workspaceRole';
7
+
8
+ /**
9
+ * Ce qu'est une fonctionnalité, dit **une fois**.
10
+ *
11
+ * Le même renseignement vivait à trois endroits : `HOME_FEATURE_IDS` pour les
12
+ * tuiles, `WORKSPACE_FEATURE_IDS` pour les droits, et les intitulés recopiés à la
13
+ * main dans `RoleDialog` **et** dans `FEATURE_CATALOG`. Trois copies d'un même
14
+ * couple identifiant / libellé, c'est la garantie qu'une fonctionnalité ajoutée
15
+ * n'arrivera que dans deux d'entre elles — et c'est exactement ce qui était
16
+ * arrivé à `monitoring`, présent dans un tableau et absent de l'autre sans que
17
+ * rien ne le dise.
18
+ *
19
+ * Ce registre porte donc le **descriptif** ; les deux enums gardent leur rôle,
20
+ * qui est de dire *où* une fonctionnalité a le droit d'apparaître. Ils ne sont
21
+ * volontairement pas fusionnés : leur écart est documenté et voulu (`devices`
22
+ * s'accorde mais n'a pas de tuile, `monitoring` a une tuile mais ne s'accorde
23
+ * pas — voir `workspaceRole.ts`).
24
+ *
25
+ * Les écrans qui parcourent les fonctionnalités — la coquille de réglages, la
26
+ * matrice de permissions, l'écran des rôles — lisent celui-ci et rien d'autre.
27
+ */
28
+ export interface FeatureDescriptor {
29
+ id: FeatureId;
30
+ /** Intitulé d'interface, en français (anglais pour un module externe). Jamais l'identifiant technique. */
31
+ label: string;
32
+ /**
33
+ * Ce que le droit ouvre, en une phrase — affichée sous la ligne de la
34
+ * fonctionnalité dans l'écran des rôles. Dit ce que `read` et `write`
35
+ * recouvrent quand la différence n'est pas évidente.
36
+ */
37
+ description: string;
38
+ /** Classe d'icône de `Styles/icons.css`, sans le préfixe `icon-`. */
39
+ icon: string;
40
+ /**
41
+ * Cette fonctionnalité sait prévenir. Décide de l'onglet « Notifications »
42
+ * de ses réglages — et, à elle seule, de l'existence du bouton pour les
43
+ * quatre qui n'ont rien d'autre à régler.
44
+ */
45
+ notifies: boolean;
46
+ /**
47
+ * Elle tient une liste d'entités adressables (un service, une base, une
48
+ * cible) sur lesquelles des réglages peuvent porter individuellement.
49
+ *
50
+ * Faux ne veut pas dire « aucune donnée » : Sentinelle a bien des constats,
51
+ * mais on ne règle pas un constat, on règle la surveillance. Le critère est
52
+ * « peut-on ouvrir les réglages de **cet** élément ? ».
53
+ */
54
+ hasItems: boolean;
55
+ /**
56
+ * Comment nommer un de ses éléments au singulier, pour les intitulés
57
+ * d'écran (« Réglages de ce service »). Absent quand `hasItems` est faux.
58
+ */
59
+ itemNoun?: string;
60
+ /**
61
+ * Les **sources** de la fonctionnalité : des réglages d'espace réutilisables
62
+ * (un jeton Dokploy, un jeton GitHub, une destination d'archives) que
63
+ * chaque élément ne fait que **désigner**. Corriger une source corrige d'un
64
+ * coup tout ce qui s'en sert.
65
+ *
66
+ * Présent, il ouvre l'onglet « Sources » des réglages **à l'échelle de la
67
+ * fonctionnalité**, le seul endroit où les sources se créent et se
68
+ * corrigent. Les dialogues d'élément, eux, ne font que choisir dans la
69
+ * liste, avec un bouton qui mène ici. `hint` est la phrase de tête de
70
+ * l'onglet : elle dit ce qu'on y gère et qui s'en sert.
71
+ *
72
+ * Les canaux de notification suivent la même logique sans passer par ce
73
+ * champ : ce sont les sources des émetteurs (chaque feature a les siens,
74
+ * migration 091), gérées dans leur onglet « Notifications », qui porte
75
+ * aussi le routage, indissociable (voir `notifies`).
76
+ */
77
+ sources?: { hint: string };
78
+ /**
79
+ * Un de ses éléments peut-il être rendu visible depuis un autre espace ?
80
+ *
81
+ * La réponse tient entièrement au **chiffrement**, pas au goût : un élément
82
+ * partagé reste chiffré sous la clé de son espace d'origine — c'est le
83
+ * levier L3 de `WORKSPACES.md`, et y renoncer voudrait dire re-chiffrer sous
84
+ * session vivante, ce que ce document range explicitement hors périmètre.
85
+ *
86
+ * Or seule la clé de l'**étage ouvert** est résoluble par le serveur seul.
87
+ * D'où trois cas :
88
+ *
89
+ * - `'open'` — toute la fonctionnalité vit à l'étage ouvert : partageable
90
+ * sans condition (Uptime, Bases, Déploiement, Git, Audience, Sauvegardes) ;
91
+ * - `'perItem'` — l'étage se choisit élément par élément. Une note
92
+ * ordinaire se partage, une note privée non ; un compte mail « open »
93
+ * oui, un compte « guarded » non. Le serveur tranche à la ligne, jamais
94
+ * la fonctionnalité en bloc ;
95
+ * - `'never'` — rien n'y est partageable, pour une raison propre à chaque
96
+ * cas (voir la note sous le registre).
97
+ */
98
+ shareTier: 'open' | 'perItem' | 'never';
99
+ }
100
+
101
+ /**
102
+ * Ordre volontairement identique à celui de `workspaceFeatureIdSchema` : les
103
+ * deux se lisent côte à côte, et une entrée manquante se voit.
104
+ */
105
+ export const FEATURE_REGISTRY: readonly (FeatureDescriptor & { id: WorkspaceFeatureId })[] = [
106
+ {
107
+ id: 'devices',
108
+ label: 'Appareils',
109
+ description:
110
+ 'Lecture : voir les machines et leur supervision. Écriture : les appairer, renommer, retirer.',
111
+ icon: 'server',
112
+ notifies: false,
113
+ hasItems: true,
114
+ itemNoun: 'appareil',
115
+ shareTier: 'never'
116
+ },
117
+ {
118
+ id: 'sentinel',
119
+ label: 'Sentinelle',
120
+ description:
121
+ 'Lecture : constats et posture. Écriture : acquitter, régler, relancer un relevé.',
122
+ icon: 'shield',
123
+ notifies: true,
124
+ hasItems: false,
125
+ shareTier: 'never'
126
+ },
127
+ {
128
+ id: 'weather',
129
+ label: 'Météo',
130
+ description: 'Les lieux suivis et leurs prévisions.',
131
+ icon: 'cloud',
132
+ notifies: false,
133
+ hasItems: false,
134
+ shareTier: 'never',
135
+ sources: {
136
+ hint: 'Les clés d’API des fournisseurs, communes à l’espace. Un lieu peut porter la sienne dans ses propres réglages ; sans elle, il retombe sur celle-ci.'
137
+ }
138
+ },
139
+ {
140
+ id: 'password',
141
+ label: 'Mots de passe',
142
+ description: 'Le coffre de mots de passe de l’espace.',
143
+ icon: 'lock',
144
+ notifies: false,
145
+ hasItems: true,
146
+ itemNoun: 'mot de passe',
147
+ shareTier: 'never'
148
+ },
149
+ {
150
+ id: 'notes',
151
+ label: 'Notes',
152
+ description: 'Notes et dossiers partagés de l’espace.',
153
+ icon: 'notes',
154
+ notifies: false,
155
+ hasItems: true,
156
+ itemNoun: 'note',
157
+ shareTier: 'perItem'
158
+ },
159
+ {
160
+ id: 'cloudsync',
161
+ label: 'CloudSync',
162
+ description: 'Partages de fichiers : dossiers, versions, appareils attachés.',
163
+ icon: 'cloud',
164
+ notifies: false,
165
+ hasItems: true,
166
+ itemNoun: 'partage',
167
+ shareTier: 'never'
168
+ },
169
+ {
170
+ id: 'uptime',
171
+ label: 'Uptime',
172
+ description:
173
+ 'Lecture : disponibilité et incidents. Écriture : déclarer et régler les services.',
174
+ icon: 'uptime',
175
+ notifies: true,
176
+ hasItems: true,
177
+ itemNoun: 'service',
178
+ shareTier: 'open'
179
+ },
180
+ {
181
+ id: 'mail',
182
+ label: 'Mail',
183
+ description: 'Comptes mail de l’espace, boîtes et messages.',
184
+ icon: 'mail',
185
+ notifies: false,
186
+ hasItems: true,
187
+ itemNoun: 'compte',
188
+ shareTier: 'perItem'
189
+ },
190
+ {
191
+ id: 'projects',
192
+ label: 'Projets',
193
+ description: 'Tableaux, jalons, cartes et discussions des projets.',
194
+ icon: 'projects',
195
+ notifies: false,
196
+ hasItems: true,
197
+ itemNoun: 'projet',
198
+ shareTier: 'perItem'
199
+ },
200
+ {
201
+ id: 'git',
202
+ label: 'Git',
203
+ description:
204
+ 'Lecture : dépôts, commits, PR. Écriture : déclarer un dépôt, poser le jeton du fournisseur.',
205
+ icon: 'branch',
206
+ notifies: false,
207
+ hasItems: true,
208
+ itemNoun: 'dépôt',
209
+ sources: {
210
+ hint: 'Les jetons GitHub de l’espace. Chaque dépôt en désigne un ; corriger un jeton corrige d’un coup tous les dépôts qui s’en servent.'
211
+ },
212
+ shareTier: 'open'
213
+ },
214
+ {
215
+ id: 'deploy',
216
+ label: 'Déploiements',
217
+ description:
218
+ 'Lecture : cibles et historique. Écriture : poser la clé d’API et déclencher une mise en production.',
219
+ icon: 'rocket',
220
+ notifies: true,
221
+ hasItems: true,
222
+ itemNoun: 'cible',
223
+ sources: {
224
+ hint: 'Les accès Dokploy de l’espace (adresse de l’instance et clé d’API). Chaque cible en désigne un ; corriger un accès corrige d’un coup toutes les cibles qui s’en servent.'
225
+ },
226
+ shareTier: 'open'
227
+ },
228
+ {
229
+ id: 'database',
230
+ label: 'Bases de données',
231
+ description:
232
+ 'Lecture : état et exploration. Écriture : déclarer une base, ses accès et ses alertes.',
233
+ icon: 'database',
234
+ notifies: true,
235
+ hasItems: true,
236
+ itemNoun: 'base',
237
+ shareTier: 'open'
238
+ },
239
+ {
240
+ id: 'backup',
241
+ label: 'Sauvegardes',
242
+ description:
243
+ 'Lecture : travaux et historique (la liste dit où dorment les copies). Écriture : destinations et déclenchement.',
244
+ icon: 'archive',
245
+ notifies: true,
246
+ hasItems: true,
247
+ itemNoun: 'travail',
248
+ sources: {
249
+ hint: 'Les destinations d’archives de l’espace : un dossier du serveur, une machine ou un bucket S3. Chaque travail écrit vers l’une d’elles ; la corriger corrige d’un coup tous les travaux qui s’en servent.'
250
+ },
251
+ shareTier: 'open'
252
+ },
253
+ {
254
+ id: 'finance',
255
+ label: 'Finances',
256
+ description:
257
+ 'Le grand livre : comptes, opérations, budgets. La lecture seule est déjà lourde.',
258
+ icon: 'finance',
259
+ notifies: false,
260
+ hasItems: true,
261
+ itemNoun: 'compte',
262
+ shareTier: 'never'
263
+ },
264
+ {
265
+ id: 'audience',
266
+ label: 'Audience',
267
+ description:
268
+ 'Lecture : statistiques des sites. Écriture : déclarer un site, ses origines, sa clé.',
269
+ icon: 'eye-open',
270
+ notifies: false,
271
+ hasItems: true,
272
+ itemNoun: 'site',
273
+ shareTier: 'open'
274
+ },
275
+ {
276
+ id: 'osint',
277
+ label: 'OSINT',
278
+ description:
279
+ 'Lecture : recherches et historique. Écriture : purge et clés d’API des fournisseurs.',
280
+ icon: 'search',
281
+ notifies: false,
282
+ hasItems: false,
283
+ shareTier: 'never',
284
+ sources: {
285
+ hint: 'Les clés d’API des fournisseurs, toutes facultatives : chaque sonde libre fonctionne déjà, une clé ne fait qu’enrichir la sienne.'
286
+ }
287
+ }
288
+ ];
289
+
290
+ const BY_ID = new Map<string, FeatureDescriptor>(FEATURE_REGISTRY.map((f) => [f.id, f]));
291
+
292
+ /**
293
+ * Les modules **externes** enregistrés dans ce processus.
294
+ *
295
+ * Le registre natif est une constante ; celui-ci se remplit au chargement, une
296
+ * fois par module installé, depuis la glue générée des deux bundles. Il ne
297
+ * s'agit pas de chargement à chaud : la liste est figée à la compilation, la
298
+ * carte n'existe que parce qu'un fichier ne peut pas être à la fois publié dans
299
+ * ce package et généré par l'application qui l'installe.
300
+ */
301
+ const EXTERNAL_BY_ID = new Map<ExternalFeatureId, FeatureDescriptor>();
302
+
303
+ /** Déclare le descripteur d'un module externe. Appelée par la glue générée. */
304
+ export function registerExternalFeature(desc: FeatureDescriptor & { id: ExternalFeatureId }): void {
305
+ if (!isExternalFeatureId(desc.id)) {
306
+ throw new Error(`registerExternalFeature: id invalide « ${desc.id} » (attendu x-<slug>)`);
307
+ }
308
+ EXTERNAL_BY_ID.set(desc.id, desc);
309
+ }
310
+
311
+ /** Le registre fusionné : les seize natives puis les modules, dans l'ordre d'enregistrement. */
312
+ export function allFeatureDescriptors(): readonly FeatureDescriptor[] {
313
+ return EXTERNAL_BY_ID.size === 0
314
+ ? FEATURE_REGISTRY
315
+ : [...FEATURE_REGISTRY, ...EXTERNAL_BY_ID.values()];
316
+ }
317
+
318
+ /**
319
+ * Le descriptif d'une fonctionnalité, native ou externe.
320
+ *
321
+ * Lève plutôt que de rendre `undefined` : un id natif vient d'un enum fermé,
322
+ * donc une absence est un oubli d'entrée dans ce fichier ; un id externe
323
+ * inconnu signifie que la glue générée n'a pas tourné, pas un cas d'exécution
324
+ * à traiter chez l'appelant. Les écrans qui veulent tolérer un module absent
325
+ * (une tuile orpheline) passent par {@link maybeFeatureDescriptor}.
326
+ */
327
+ export function featureDescriptor(id: FeatureId): FeatureDescriptor {
328
+ const found = maybeFeatureDescriptor(id);
329
+ if (!found) throw new Error(`FEATURE_REGISTRY: aucune entrée pour « ${id} »`);
330
+ return found;
331
+ }
332
+
333
+ /** Variante tolérante, pour les données qui peuvent survivre à un module retiré. */
334
+ export function maybeFeatureDescriptor(id: FeatureId): FeatureDescriptor | undefined {
335
+ return isExternalFeatureId(id) ? EXTERNAL_BY_ID.get(id) : BY_ID.get(id);
336
+ }
337
+
338
+ /** L'intitulé seul — le besoin de très loin le plus courant. */
339
+ export function featureLabel(id: FeatureId): string {
340
+ return featureDescriptor(id).label;
341
+ }
342
+
343
+ /**
344
+ * Trois `never` méritent leur justification, parce qu'on pourrait croire le
345
+ * contraire :
346
+ *
347
+ * - **`devices`** a **déjà** son partage inter-espaces, antérieur et d'une
348
+ * autre nature : `device_workspaces` (migration 072) est une adhésion à part
349
+ * entière, pas une projection. Le mécanisme d'ici ne s'y superpose pas.
350
+ * - **`password`** vit toujours à l'étage gardé — c'est la promesse du coffre.
351
+ * Le serveur sait certes le lire quand le chiffrement par mot de passe est
352
+ * éteint, mais un partage dont la survie dépend d'un réglage de sécurité
353
+ * qu'on encourage n'est pas un partage.
354
+ * - **`cloudsync`** range ses contenus dans un magasin de blobs sur disque,
355
+ * chiffrés par la BMK et non par une clé d'espace : ce serait un autre
356
+ * chantier.
357
+ */
358
+
359
+ /** Les fonctionnalités dont un élément **pourrait** voyager, côté chiffrement. */
360
+ export const SHAREABLE_FEATURES: readonly WorkspaceFeatureId[] = FEATURE_REGISTRY.filter(
361
+ (f) => f.shareTier !== 'never'
362
+ ).map((f) => f.id);
363
+
364
+ /**
365
+ * Celles dont la **lecture élargie est réellement branchée**.
366
+ *
367
+ * `shareTier` dit ce que le chiffrement autorise ; cette liste dit ce que le
368
+ * code fait. L'écart est volontaire et temporaire : projeter suppose que le
369
+ * listage de la fonctionnalité sache aller chercher les lignes projetées et
370
+ * choisir le bon codec ligne par ligne. Tant que ce n'est pas fait, la case
371
+ * cocherait et rien n'apparaîtrait de l'autre côté.
372
+ *
373
+ * Partagée entre client et serveur **exprès** : le serveur refuse, le client
374
+ * n'affiche pas l'onglet. Deux listes séparées auraient donné un onglet qui ne
375
+ * mène nulle part — précisément ce que la coquille de réglages refuse.
376
+ *
377
+ * Brancher une fonctionnalité de plus : `listVisible` / `findVisible` dans son
378
+ * dépôt, le codec par ligne dans son listage, une entrée ici.
379
+ */
380
+ export const SHARE_WIRED_FEATURES: readonly WorkspaceFeatureId[] = [
381
+ 'uptime',
382
+ 'database',
383
+ 'deploy',
384
+ 'git',
385
+ 'audience',
386
+ 'backup'
387
+ ];
388
+
389
+ /** Les fonctionnalités qui savent prévenir, dans l'ordre du registre. */
390
+ export const NOTIFYING_FEATURES: readonly WorkspaceFeatureId[] = FEATURE_REGISTRY.filter(
391
+ (f) => f.notifies
392
+ ).map((f) => f.id);