@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.
- package/LICENSE +21 -0
- package/README.md +23 -0
- package/package.json +68 -0
- package/src/domain/audience.ts +549 -0
- package/src/domain/backup.ts +355 -0
- package/src/domain/credential.ts +55 -0
- package/src/domain/database.ts +467 -0
- package/src/domain/deploy.ts +231 -0
- package/src/domain/device.ts +172 -0
- package/src/domain/deviceFiles.ts +84 -0
- package/src/domain/deviceLogs.ts +82 -0
- package/src/domain/featureRegistry.ts +392 -0
- package/src/domain/finance.ts +477 -0
- package/src/domain/git.ts +419 -0
- package/src/domain/home.ts +314 -0
- package/src/domain/live.ts +272 -0
- package/src/domain/logs.ts +117 -0
- package/src/domain/mail.ts +394 -0
- package/src/domain/metrics.ts +127 -0
- package/src/domain/note.ts +202 -0
- package/src/domain/notifications.ts +268 -0
- package/src/domain/packages.ts +35 -0
- package/src/domain/password.ts +36 -0
- package/src/domain/presence.ts +21 -0
- package/src/domain/project.ts +168 -0
- package/src/domain/projectBoard.ts +130 -0
- package/src/domain/projectChat.ts +46 -0
- package/src/domain/projectHistory.ts +82 -0
- package/src/domain/projectLink.ts +87 -0
- package/src/domain/projectPlan.ts +68 -0
- package/src/domain/report.ts +492 -0
- package/src/domain/role.ts +8 -0
- package/src/domain/secrecy.ts +66 -0
- package/src/domain/sentinel.ts +623 -0
- package/src/domain/sharing.ts +186 -0
- package/src/domain/syncProtocol.ts +116 -0
- package/src/domain/twoFactor.ts +40 -0
- package/src/domain/uptime.ts +216 -0
- package/src/domain/user.ts +141 -0
- package/src/domain/workspace.ts +56 -0
- package/src/domain/workspaceRole.ts +251 -0
- package/src/features/admin.ts +112 -0
- package/src/features/audience.ts +275 -0
- package/src/features/backup.ts +230 -0
- package/src/features/database.ts +461 -0
- package/src/features/deploy.ts +245 -0
- package/src/features/device.ts +292 -0
- package/src/features/deviceFiles.ts +83 -0
- package/src/features/deviceLogs.ts +36 -0
- package/src/features/deviceTerminal.ts +57 -0
- package/src/features/finance.ts +360 -0
- package/src/features/git.ts +368 -0
- package/src/features/home.ts +32 -0
- package/src/features/live.ts +113 -0
- package/src/features/logs.ts +86 -0
- package/src/features/mail.ts +374 -0
- package/src/features/metrics.ts +185 -0
- package/src/features/note.ts +189 -0
- package/src/features/notify.ts +164 -0
- package/src/features/password.ts +67 -0
- package/src/features/project.ts +709 -0
- package/src/features/registry.ts +103 -0
- package/src/features/secrecy.ts +120 -0
- package/src/features/sentinel.ts +233 -0
- package/src/features/sharing.ts +79 -0
- package/src/features/twoFactor.ts +47 -0
- package/src/features/uptime.ts +186 -0
- package/src/features/user.ts +91 -0
- package/src/features/workspace.ts +200 -0
- package/src/http/auth.ts +94 -0
- package/src/http/device.ts +222 -0
- package/src/http/status.ts +45 -0
- package/src/index.ts +1700 -0
- package/src/protocol/agent.ts +1171 -0
- package/src/protocol/envelope.ts +46 -0
- package/src/protocol/error.ts +27 -0
- package/src/protocol/result.ts +17 -0
- package/src/protocol/version.ts +6 -0
- package/src/sdk/client-ambient.d.ts +238 -0
- package/src/sdk/client.ts +66 -0
- package/src/sdk/ids.ts +25 -0
- package/src/sdk/index.ts +11 -0
- package/src/sdk/manifest.ts +326 -0
- package/src/sdk/providers.ts +48 -0
- package/src/sdk/server.ts +378 -0
- package/src/sdk/testing.ts +179 -0
- 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);
|