@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/domain/report.ts
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* "Latest known state" report for a device
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* "Latest known state" report for a device, distinct from the metric snapshots:
|
|
5
|
+
* slow-moving signals (OS info, security posture). The agent emits one on
|
|
6
|
+
* connect and then periodically; the server keeps only the most recent per
|
|
7
|
+
* device (`devices.report_json`) and fans it out live.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Every security field is nullable: collectors are best-effort and shell out to
|
|
12
|
-
* OS tools that may be absent or require privileges. `null` means "unknown".
|
|
13
|
-
*
|
|
14
|
-
* Processes are *not* in the report: they ride along with each metric snapshot
|
|
15
|
-
* (`metricSnapshotSchema.processes`) so every graph point has the process list of
|
|
16
|
-
* that exact instant, and are historised under the same `ts`.
|
|
9
|
+
* Every security field is nullable: collectors are best-effort, `null` means
|
|
10
|
+
* "unknown". Processes are not in the report: they ride along with each metric
|
|
11
|
+
* snapshot (`metricSnapshotSchema.processes`).
|
|
17
12
|
*/
|
|
18
13
|
|
|
19
14
|
/**
|
|
@@ -30,25 +25,18 @@ import { z } from 'zod';
|
|
|
30
25
|
export const reportProcessSchema = z.object({
|
|
31
26
|
name: z.string().min(1).max(128),
|
|
32
27
|
/**
|
|
33
|
-
* Chemin de l'exécutable,
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* forment désormais deux entrées, ce qui est l'information utile.
|
|
39
|
-
*
|
|
40
|
-
* `null` = inconnu : agent trop ancien pour le renvoyer, ou chemin illisible
|
|
41
|
-
* faute de droits. Les règles qui en dépendent restent alors muettes plutôt
|
|
42
|
-
* que de conclure dans le vide (invariant 6 de Monitoring).
|
|
28
|
+
* Chemin de l'exécutable, seconde moitié de la clé d'agrégation
|
|
29
|
+
* `(name, execPath)` : deux binaires homonymes de chemins distincts sont
|
|
30
|
+
* deux entrées, ce derrière quoi un imposteur se cache. `null` = inconnu
|
|
31
|
+
* (agent trop ancien, ou chemin illisible faute de droits) ; les règles qui
|
|
32
|
+
* en dépendent restent alors muettes.
|
|
43
33
|
*/
|
|
44
34
|
execPath: z.string().max(512).nullable().default(null),
|
|
45
35
|
/**
|
|
46
36
|
* L'exécutable a été effacé du disque mais le processus tourne toujours
|
|
47
|
-
* (`/proc/<pid>/exe`
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* ne coûte rien : le lien symbolique est déjà lu pour `execPath`. `null` là
|
|
51
|
-
* où la plateforme ne l'expose pas (macOS, Windows).
|
|
37
|
+
* (`/proc/<pid>/exe` suffixé « (deleted) ») : un des indicateurs les plus
|
|
38
|
+
* francs d'un implant résident en mémoire. `null` là où la plateforme ne
|
|
39
|
+
* l'expose pas (macOS, Windows).
|
|
52
40
|
*/
|
|
53
41
|
deleted: z.boolean().nullable().default(null),
|
|
54
42
|
/** Number of PIDs aggregated under this name. */
|
|
@@ -98,9 +86,8 @@ export const processKindSchema = z.enum(['top', 'all']);
|
|
|
98
86
|
export type ProcessKind = z.infer<typeof processKindSchema>;
|
|
99
87
|
|
|
100
88
|
/**
|
|
101
|
-
* A stored process list at one instant.
|
|
102
|
-
*
|
|
103
|
-
* so a graph point and its process list always share one `ts`. This is what
|
|
89
|
+
* A stored process list at one instant. Read model only: processes travel
|
|
90
|
+
* inside `metricSnapshotSchema.processes`, and this is what
|
|
104
91
|
* `metrics.processesAt` returns when reading history back.
|
|
105
92
|
*/
|
|
106
93
|
export const processSampleSchema = z.object({
|
|
@@ -134,12 +121,9 @@ export const deviceSecuritySchema = z.object({
|
|
|
134
121
|
/** Count of pending OS updates (null when not collected, e.g. macOS). */
|
|
135
122
|
pendingUpdates: z.number().int().nonnegative().nullable(),
|
|
136
123
|
/**
|
|
137
|
-
* Correctifs de
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* dont aucune de sécurité n'est qu'un retard d'entretien, tandis qu'une
|
|
141
|
-
* seule faille non corrigée est une porte. Ces champs sont facultatifs et
|
|
142
|
-
* défaillent à `null` — un agent antérieur à Sentinelle n'en dit rien, et
|
|
124
|
+
* Correctifs de sécurité en attente, distingués du total : quarante mises à
|
|
125
|
+
* jour sans sécurité ne sont qu'un retard d'entretien, une seule faille non
|
|
126
|
+
* corrigée est une porte. `null` quand l'agent ne le dit pas, et
|
|
143
127
|
* `posture.updates_stale` reste alors muette.
|
|
144
128
|
*/
|
|
145
129
|
pendingSecurityUpdates: z.number().int().nonnegative().nullable().default(null),
|
|
@@ -226,20 +210,10 @@ export const agentInfoSchema = z.object({
|
|
|
226
210
|
/** True when launched by a service manager (so a self-update just exits to be relaunched). */
|
|
227
211
|
managed: z.boolean().default(false),
|
|
228
212
|
/**
|
|
229
|
-
* Ce que cet agent sait relever, déclaré par lui-même
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* afficherait le même vide pour deux situations qui n'appellent pas la même
|
|
234
|
-
* réaction — mettre l'agent à jour, ou aller regarder la machine.
|
|
235
|
-
*
|
|
236
|
-
* On ne peut pas s'en remettre à la version : elle est injectée à la
|
|
237
|
-
* compilation par la CI et vaut `0.0.0` sur une construction locale. Une
|
|
238
|
-
* capacité déclarée est de toute façon plus honnête qu'un numéro dont on
|
|
239
|
-
* déduirait ce qu'il contient.
|
|
240
|
-
*
|
|
241
|
-
* Vide par défaut : un agent antérieur à Sentinelle ne dit rien, et c'est
|
|
242
|
-
* exactement ce qu'il faut comprendre.
|
|
213
|
+
* Ce que cet agent sait relever, déclaré par lui-même : distingue « la
|
|
214
|
+
* sonde a échoué » d'« un agent trop ancien pour l'avoir », que la version
|
|
215
|
+
* ne dit pas (elle vaut `0.0.0` sur une construction locale). Vide par
|
|
216
|
+
* défaut : un agent qui ne dit rien n'a pas ces sondes.
|
|
243
217
|
*/
|
|
244
218
|
probes: z.array(z.string().max(32)).max(16).default([])
|
|
245
219
|
});
|
|
@@ -320,11 +294,9 @@ export const deviceHardwareSchema = z.object({
|
|
|
320
294
|
.catch([])
|
|
321
295
|
.default([]),
|
|
322
296
|
/**
|
|
323
|
-
* Network interfaces (best-effort
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
* report — one noisy field must never drop the agent's entire posture, which is
|
|
327
|
-
* validated at the agent socket's ingress (`deviceReportSchema`).
|
|
297
|
+
* Network interfaces (best-effort). A container host can expose dozens of
|
|
298
|
+
* virtual `veth*`/`br-*` devices, so an over-long list is truncated (and a
|
|
299
|
+
* residual error degrades to `[]`) rather than rejecting the whole report.
|
|
328
300
|
*/
|
|
329
301
|
network: z
|
|
330
302
|
.preprocess(
|
|
@@ -352,15 +324,9 @@ export const deviceReportSchema = z.object({
|
|
|
352
324
|
security: deviceSecuritySchema,
|
|
353
325
|
/** Per-disk usage (deduped across shared APFS volumes). Empty if unknown. */
|
|
354
326
|
disks: z.array(reportDiskSchema).default([]),
|
|
355
|
-
/**
|
|
356
|
-
* The agent's runtime identity (privilege level + account). `null` on legacy
|
|
357
|
-
* reports stored before this field existed; the agent always sends it now.
|
|
358
|
-
*/
|
|
327
|
+
/** The agent's runtime identity. `null` on reports stored before this field existed. */
|
|
359
328
|
agent: agentInfoSchema.nullable().default(null),
|
|
360
|
-
/**
|
|
361
|
-
* Static hardware inventory (CPU, RAM, GPU, network, bluetooth). `null` on
|
|
362
|
-
* legacy reports stored before this field existed; the agent always sends it.
|
|
363
|
-
*/
|
|
329
|
+
/** Static hardware inventory. `null` on reports stored before this field existed. */
|
|
364
330
|
hardware: deviceHardwareSchema.nullable().default(null),
|
|
365
331
|
/**
|
|
366
332
|
* Listening sockets, one entry per bind address. `null` = not collected
|
|
@@ -378,25 +344,16 @@ export const deviceReportSchema = z.object({
|
|
|
378
344
|
|
|
379
345
|
export type DeviceReport = z.infer<typeof deviceReportSchema>;
|
|
380
346
|
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
385
|
-
// Le rapport est un « dernier état connu » : le serveur n'en garde qu'un par
|
|
386
|
-
// appareil, écrasé à chaque envoi. Cela convient à la posture, pas à ces
|
|
387
|
-
// deux-là. Le manifeste de persistance est trop gros pour être réécrit en
|
|
388
|
-
// entier chaque heure dans `devices.report_json`, et la fenêtre
|
|
389
|
-
// d'authentification est **additive** — l'écraser perdrait des tentatives, ce
|
|
390
|
-
// qui est précisément ce qu'on cherche à compter.
|
|
347
|
+
// Relevés Sentinelle, volontairement hors de `deviceReportSchema` : le rapport
|
|
348
|
+
// est un « dernier état connu » écrasé à chaque envoi, alors que le manifeste
|
|
349
|
+
// de persistance est trop gros pour être réécrit chaque heure et que la
|
|
350
|
+
// fenêtre d'authentification est additive (l'écraser perdrait des tentatives).
|
|
391
351
|
|
|
392
352
|
/**
|
|
393
|
-
* Une entrée d'une surface de persistance : l'endroit où un programme
|
|
394
|
-
* pour survivre au redémarrage.
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
* C'est ce qui rend la sonde acceptable sur une machine partagée : elle prouve
|
|
398
|
-
* qu'un fichier a changé sans jamais révéler ce qu'il contient, et un `sha256`
|
|
399
|
-
* suffit entièrement au diff que le serveur en fait.
|
|
353
|
+
* Une entrée d'une surface de persistance : l'endroit où un programme
|
|
354
|
+
* s'installe pour survivre au redémarrage. Jamais le contenu du fichier,
|
|
355
|
+
* seulement son empreinte et ses métadonnées : la sonde prouve qu'un fichier a
|
|
356
|
+
* changé sans révéler ce qu'il contient.
|
|
400
357
|
*/
|
|
401
358
|
export const persistenceEntrySchema = z.object({
|
|
402
359
|
/** Famille d'origine : `cron`, `systemd`, `launchd`, `authorized_keys`, `sudoers`, `run_key`, `scheduled_task`… */
|
|
@@ -430,11 +387,9 @@ export const integrityReportSchema = z.object({
|
|
|
430
387
|
export type IntegrityReport = z.infer<typeof integrityReportSchema>;
|
|
431
388
|
|
|
432
389
|
/**
|
|
433
|
-
* Une adresse et ce qu'elle a
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
* savoir qu'une adresse chinoise a essayé `root`, `admin` puis `oracle` est ce
|
|
437
|
-
* qui distingue un balayage automatique d'une erreur de frappe.
|
|
390
|
+
* Une adresse et ce qu'elle a tenté sur la fenêtre écoulée. `users` porte les
|
|
391
|
+
* comptes visés : `root`, `admin` puis `oracle` distingue un balayage d'une
|
|
392
|
+
* erreur de frappe.
|
|
438
393
|
*/
|
|
439
394
|
export const authSourceSchema = z.object({
|
|
440
395
|
address: z.string().min(1).max(64),
|
|
@@ -458,13 +413,10 @@ export const AUTH_SOURCE_LIMIT = 50;
|
|
|
458
413
|
export const AUTH_LOGIN_LIMIT = 50;
|
|
459
414
|
|
|
460
415
|
/**
|
|
461
|
-
* Les issues d'authentification sur une fenêtre glissante.
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
* n'est pas une optimisation de taille, c'est la frontière de la feature — un
|
|
466
|
-
* flux brut aurait remonté des lignes de commande sudo et des noms de service,
|
|
467
|
-
* c'est-à-dire l'activité des gens.
|
|
416
|
+
* Les issues d'authentification sur une fenêtre glissante. Des compteurs, pas
|
|
417
|
+
* un flux de journal : c'est la frontière de la feature, un flux brut aurait
|
|
418
|
+
* remonté des lignes de commande sudo et des noms de service, c'est-à-dire
|
|
419
|
+
* l'activité des gens.
|
|
468
420
|
*/
|
|
469
421
|
export const authWindowSchema = z.object({
|
|
470
422
|
/** Bornes de la fenêtre, unix ms. `from` = fin de la fenêtre précédente. */
|
|
@@ -483,9 +435,8 @@ export const authWindowSchema = z.object({
|
|
|
483
435
|
topSources: z.array(authSourceSchema).max(AUTH_SOURCE_LIMIT).default([]),
|
|
484
436
|
logins: z.array(authLoginSchema).max(AUTH_LOGIN_LIMIT).default([]),
|
|
485
437
|
/**
|
|
486
|
-
* La source n'a pas pu être lue (pas de journal, pas les droits)
|
|
487
|
-
*
|
|
488
|
-
* machine aveugle passerait pour une machine tranquille.
|
|
438
|
+
* La source n'a pas pu être lue (pas de journal, pas les droits) : sans ce
|
|
439
|
+
* drapeau, une machine aveugle passerait pour une machine tranquille.
|
|
489
440
|
*/
|
|
490
441
|
unavailable: z.boolean().default(false)
|
|
491
442
|
});
|
package/src/domain/secrecy.ts
CHANGED
|
@@ -26,11 +26,9 @@ export const secrecyStatusSchema = z.object({
|
|
|
26
26
|
*/
|
|
27
27
|
reAuthInterval: z.number().int().min(0).nullable(),
|
|
28
28
|
/**
|
|
29
|
-
* Epoch ms at which the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* action" mode — i.e. whenever there is no countdown to display. Lets the
|
|
33
|
-
* topbar timer widget render a live progress bar without guessing the window.
|
|
29
|
+
* Epoch ms at which the grace window expires (cached DEK flushed unless
|
|
30
|
+
* activity slides it forward). `null` when there is no countdown: session
|
|
31
|
+
* locked, feature off, or "validate on every action" mode.
|
|
34
32
|
*/
|
|
35
33
|
unlockedUntil: z.number().int().nullable()
|
|
36
34
|
});
|
package/src/domain/sharing.ts
CHANGED
|
@@ -1,37 +1,19 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
import { featureAccessSchema,
|
|
3
|
+
import { featureAccessSchema, featureIdSchema } from './workspaceRole';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Rendre un élément visible depuis un autre espace,
|
|
6
|
+
* Rendre un élément visible depuis un autre espace, sans le déplacer.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Invariant : un élément partagé ne change jamais de clé. Il reste chiffré sous
|
|
9
|
+
* celle de son espace d'origine et, servi ailleurs, est déchiffré avec le codec
|
|
10
|
+
* ouvert de cet espace-là (levier L3 de `WORKSPACES.md`). Partager est une
|
|
11
|
+
* projection, pas un transfert. Seule la clé de l'étage ouvert étant résoluble
|
|
12
|
+
* par le serveur seul, un élément de l'étage gardé ne peut pas être partagé
|
|
13
|
+
* (voir `shareTier` dans le registre).
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* de cet espace-là. C'est le prolongement direct du levier L3 de
|
|
13
|
-
* `WORKSPACES.md`, « chaque espace a sa clé, et un blob n'en change jamais »,
|
|
14
|
-
* et la raison pour laquelle ce chantier ne re-chiffre rien.
|
|
15
|
-
*
|
|
16
|
-
* `WORKSPACES.md` §10 range **déplacer** un élément hors périmètre, précisément
|
|
17
|
-
* parce que ce serait la seule opération à exiger un déchiffrement clé A puis un
|
|
18
|
-
* re-chiffrement clé B sous session vivante. Partager ne l'exige pas : c'est une
|
|
19
|
-
* **projection**, pas un transfert. L'élément a un seul domicile, et des
|
|
20
|
-
* fenêtres ailleurs.
|
|
21
|
-
*
|
|
22
|
-
* ## Ce qui en découle, et qu'il faut assumer
|
|
23
|
-
*
|
|
24
|
-
* Seule la clé de l'étage ouvert est résoluble par le serveur seul. Un élément
|
|
25
|
-
* de l'étage gardé ne peut donc pas être partagé — pas par prudence, par
|
|
26
|
-
* impossibilité mécanique. Voir `shareTier` dans le registre.
|
|
27
|
-
*
|
|
28
|
-
* ## On ne partage qu'avec soi-même
|
|
29
|
-
*
|
|
30
|
-
* La liste proposée est celle des espaces **dont l'appelant est membre**. Ce
|
|
31
|
-
* n'est pas une restriction d'interface mais la règle : partager vers un espace
|
|
32
|
-
* où l'on n'entre pas reviendrait à y déposer une donnée sans pouvoir en
|
|
33
|
-
* répondre, et à contourner l'appartenance — qui est la frontière absolue du
|
|
34
|
-
* modèle (`WORKSPACES.md` §3).
|
|
15
|
+
* On ne partage qu'avec les espaces dont l'appelant est membre : l'appartenance
|
|
16
|
+
* est la frontière absolue du modèle (`WORKSPACES.md` §3).
|
|
35
17
|
*/
|
|
36
18
|
|
|
37
19
|
export const itemShareSchema = z.object({
|
|
@@ -42,25 +24,19 @@ export const itemShareSchema = z.object({
|
|
|
42
24
|
isHome: z.boolean(),
|
|
43
25
|
shared: z.boolean(),
|
|
44
26
|
/**
|
|
45
|
-
* L'appelant peut régler
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Vrai quand l'élément y est visible, que l'espace est partagé (un espace
|
|
50
|
-
* personnel n'a pas de rôles) et que l'appelant y tient `workspace.roles`.
|
|
51
|
-
* C'est ce qui permet de gérer les permissions de toutes les fenêtres
|
|
52
|
-
* depuis l'onglet Partage, sans changer d'espace.
|
|
27
|
+
* L'appelant peut régler d'ici ce que chaque rôle de cet espace voit de
|
|
28
|
+
* l'élément (`share.grantList` / `share.grantSet` avec ce `workspaceId`) :
|
|
29
|
+
* l'élément y est visible, l'espace est partagé et l'appelant y tient
|
|
30
|
+
* `workspace.roles`.
|
|
53
31
|
*/
|
|
54
32
|
grantsManageable: z.boolean()
|
|
55
33
|
});
|
|
56
34
|
export type ItemShare = z.infer<typeof itemShareSchema>;
|
|
57
35
|
|
|
58
36
|
/**
|
|
59
|
-
* Pourquoi un élément ne peut pas être partag
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* un réglage qui n'existe pas. Ici la cause est toujours structurelle, et la
|
|
63
|
-
* dire évite qu'on la prenne pour une panne.
|
|
37
|
+
* Pourquoi un élément ne peut pas être partagé. Une raison plutôt qu'un
|
|
38
|
+
* booléen : la cause est toujours structurelle, et la dire évite qu'on la
|
|
39
|
+
* prenne pour une panne.
|
|
64
40
|
*/
|
|
65
41
|
export const shareBlockerSchema = z.enum([
|
|
66
42
|
/** La fonctionnalité entière vit à l'étage gardé, ou n'a pas de sens ici. */
|
|
@@ -86,16 +62,10 @@ export const itemShareStateSchema = z.object({
|
|
|
86
62
|
export type ItemShareState = z.infer<typeof itemShareStateSchema>;
|
|
87
63
|
|
|
88
64
|
/**
|
|
89
|
-
* Ce qu'un rôle peut faire sur
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* plafond, ici comme pour les droits fins.
|
|
94
|
-
*
|
|
95
|
-
* L'alternative — permettre d'élever — a été écartée : l'accès effectif à une
|
|
96
|
-
* fonctionnalité deviendrait « le maximum entre le rôle et le meilleur droit
|
|
97
|
-
* d'élément », donc une requête de plus dans la résolution d'accès, et surtout
|
|
98
|
-
* un écran des rôles qui ne dirait plus à lui seul qui voit quoi.
|
|
65
|
+
* Ce qu'un rôle peut faire sur un élément. Restrictif seulement : `none` ou
|
|
66
|
+
* `read` abaissent ce que le rôle a sur la fonctionnalité, jamais l'inverse ;
|
|
67
|
+
* le droit de feature reste le plafond, et l'écran des rôles dit à lui seul
|
|
68
|
+
* qui voit quoi.
|
|
99
69
|
*/
|
|
100
70
|
export const itemAccessSchema = z.enum(['none', 'read']);
|
|
101
71
|
export type ItemAccess = z.infer<typeof itemAccessSchema>;
|
|
@@ -108,13 +78,9 @@ export const itemRoleGrantSchema = z.object({
|
|
|
108
78
|
export type ItemRoleGrant = z.infer<typeof itemRoleGrantSchema>;
|
|
109
79
|
|
|
110
80
|
/**
|
|
111
|
-
* Un rôle d'un espace, vu depuis l'écran des restrictions d'un élément
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* faire : l'identité du rôle, ce que la fonctionnalité lui donne (le droit
|
|
115
|
-
* *hérité*, affiché même quand aucune exception n'est posée — une vue
|
|
116
|
-
* d'ensemble qui ne montre que les exceptions oblige à deviner le reste), et
|
|
117
|
-
* l'exception posée s'il y en a une.
|
|
81
|
+
* Un rôle d'un espace, vu depuis l'écran des restrictions d'un élément : son
|
|
82
|
+
* identité, le droit hérité de la fonctionnalité (affiché même sans exception)
|
|
83
|
+
* et l'exception posée s'il y en a une.
|
|
118
84
|
*/
|
|
119
85
|
export const itemRoleGrantViewSchema = z.object({
|
|
120
86
|
roleId: z.number().int().positive(),
|
|
@@ -138,24 +104,21 @@ export const itemGrantStateSchema = z.object({
|
|
|
138
104
|
});
|
|
139
105
|
export type ItemGrantState = z.infer<typeof itemGrantStateSchema>;
|
|
140
106
|
|
|
141
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* La cible d'un partage ou d'une restriction. `featureIdSchema` et non l'enum
|
|
109
|
+
* natif : les éléments d'un module se projettent comme ceux d'une native.
|
|
110
|
+
*/
|
|
142
111
|
export const itemRefSchema = z.object({
|
|
143
|
-
feature:
|
|
112
|
+
feature: featureIdSchema,
|
|
144
113
|
itemId: z.number().int().positive()
|
|
145
114
|
});
|
|
146
115
|
export type ItemRef = z.infer<typeof itemRefSchema>;
|
|
147
116
|
|
|
148
117
|
/**
|
|
149
|
-
* Une référence qu'on voit sans pouvoir la lire
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* **savoir que le lien existe** sans en connaître le contenu. Le masquer
|
|
154
|
-
* entièrement ferait croire à un élément mal réglé ; le montrer ferait fuiter
|
|
155
|
-
* l'espace d'origine.
|
|
156
|
-
*
|
|
157
|
-
* Il peut la **retirer** si ses droits le permettent — retirer un lien ne
|
|
158
|
-
* demande pas de le lire. Il ne peut ni le voir ni le modifier.
|
|
118
|
+
* Une référence qu'on voit sans pouvoir la lire : un élément partagé vers B
|
|
119
|
+
* pointe une donnée de A (compte mail, appareil, canal). Un membre de B non
|
|
120
|
+
* membre de A doit savoir que le lien existe sans en connaître le contenu ; il
|
|
121
|
+
* peut le retirer si ses droits le permettent, ni le voir ni le modifier.
|
|
159
122
|
*/
|
|
160
123
|
export const foreignRefSchema = z.object({
|
|
161
124
|
kind: z.literal('inaccessible'),
|
|
@@ -32,13 +32,10 @@ export const SYNC_FINGERPRINT_SEP = '\u0001';
|
|
|
32
32
|
export const syncScanModeSchema = z.enum(['auto', 'full']);
|
|
33
33
|
export type SyncScanMode = z.infer<typeof syncScanModeSchema>;
|
|
34
34
|
/**
|
|
35
|
-
* Empreinte d'un index : `{nombre}.{octets}.{sha256hex}`.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* (ordre unité UTF-16) à s'accorder sur les caractères hors BMP, ce qu'ils ne
|
|
40
|
-
* font pas. Un seul emoji dans un nom de fichier aurait alors désactivé le
|
|
41
|
-
* chemin rapide pour toujours, sans que rien ne le signale.
|
|
35
|
+
* Empreinte d'un index : `{nombre}.{octets}.{sha256hex}`. Le pli est un XOR des
|
|
36
|
+
* hachages par ligne, donc INDÉPENDANT DE L'ORDRE, à dessein : un tri obligerait
|
|
37
|
+
* Rust (ordre octet UTF-8) et TypeScript (ordre unité UTF-16) à s'accorder sur
|
|
38
|
+
* les caractères hors BMP, ce qu'ils ne font pas.
|
|
42
39
|
*/
|
|
43
40
|
export const syncIndexFingerprintSchema = z.string().regex(/^\d+\.\d+\.[0-9a-f]{64}$/);
|
|
44
41
|
/** SHA-256 hexadécimal (du clair d'un fichier, ou d'un chemin normalisé). */
|
|
@@ -93,11 +90,7 @@ export const cloudSyncProgressSchema = z.object({
|
|
|
93
90
|
bytesDone: z.number().int().nonnegative(),
|
|
94
91
|
/** Fichier en cours de transfert, pour la ligne discrète de l'UI. */
|
|
95
92
|
currentPath: z.string().max(SYNC_REL_PATH_MAX).nullable(),
|
|
96
|
-
/**
|
|
97
|
-
* Avancement DANS le fichier en cours. Sans ça, un fichier de plusieurs Go
|
|
98
|
-
* laissait la barre parfaitement figée du début à la fin de son transfert :
|
|
99
|
-
* les octets n'étaient comptés qu'une fois le fichier terminé.
|
|
100
|
-
*/
|
|
93
|
+
/** Avancement dans le fichier en cours, pour qu'un gros fichier ne fige pas la barre. */
|
|
101
94
|
currentBytes: z.number().int().nonnegative(),
|
|
102
95
|
currentTotal: z.number().int().nonnegative(),
|
|
103
96
|
direction: syncDirectionSchema.nullable(),
|
package/src/domain/user.ts
CHANGED
|
@@ -30,14 +30,12 @@ export const userColorSchema = z.enum([
|
|
|
30
30
|
]);
|
|
31
31
|
export type UserColor = z.infer<typeof userColorSchema>;
|
|
32
32
|
|
|
33
|
-
/** L'ordre fait foi : `defaultUserColor` et
|
|
33
|
+
/** L'ordre fait foi : il est indexé par `defaultUserColor` et en base. */
|
|
34
34
|
export const USER_COLORS = userColorSchema.options;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Teinte attribuée d'office à un compte
|
|
38
|
-
* créés à la suite n'ont pas la même
|
|
39
|
-
* la migration 059 colorie l'existant, `usersRepo.create` fait de même à
|
|
40
|
-
* l'inscription.
|
|
37
|
+
* Teinte attribuée d'office à un compte depuis son identifiant : deux comptes
|
|
38
|
+
* créés à la suite n'ont pas la même.
|
|
41
39
|
*/
|
|
42
40
|
export function defaultUserColor(userId: number): UserColor {
|
|
43
41
|
return USER_COLORS[Math.abs(userId) % USER_COLORS.length];
|
|
@@ -76,17 +74,13 @@ export const userSecuritySchema = z.object({
|
|
|
76
74
|
export type UserSecurity = z.infer<typeof userSecuritySchema>;
|
|
77
75
|
|
|
78
76
|
/**
|
|
79
|
-
* Drapeaux de compte, rangés dans `users.settings`
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* qu'un drapeau existe se comporte donc comme le reste, sans migration ni
|
|
83
|
-
* rattrapage. C'est ce qui fait de cette colonne le bon endroit pour un réglage
|
|
84
|
-
* booléen privé, là où une colonne dédiée (le modèle de `color`) se justifie
|
|
85
|
-
* quand la valeur n'est pas binaire ou qu'elle intéresse d'autres comptes.
|
|
77
|
+
* Drapeaux de compte, rangés dans `users.settings` (un sac de chaînes).
|
|
78
|
+
* L'absence d'un drapeau est sa valeur par défaut : aucune migration quand un
|
|
79
|
+
* drapeau apparaît.
|
|
86
80
|
*
|
|
87
81
|
* - `hideLiveCursors` : ne pas afficher les curseurs des autres membres. La
|
|
88
|
-
* coupure est
|
|
89
|
-
*
|
|
82
|
+
* coupure est réciproque : le client cesse aussi d'émettre le sien, on ne
|
|
83
|
+
* peut pas regarder sans être vu.
|
|
90
84
|
*/
|
|
91
85
|
export const userSettingFlagSchema = z.enum(['hideLiveCursors']);
|
|
92
86
|
export type UserSettingFlag = z.infer<typeof userSettingFlagSchema>;
|
package/src/domain/workspace.ts
CHANGED
|
@@ -8,9 +8,6 @@ import { minimalUserSchema } from './user';
|
|
|
8
8
|
* quittable ni supprimable, jamais partageable. C'est le repli implicite quand
|
|
9
9
|
* une commande ne vise aucun espace en particulier.
|
|
10
10
|
* - `shared` : créé à la demande, plusieurs membres, rôles et invitations.
|
|
11
|
-
*
|
|
12
|
-
* Les deux sont de vraies lignes de `workspaces` : il n'existe plus d'espace
|
|
13
|
-
* virtuel d'id 0.
|
|
14
11
|
*/
|
|
15
12
|
export const workspaceKindSchema = z.enum(['personal', 'shared']);
|
|
16
13
|
export type WorkspaceKind = z.infer<typeof workspaceKindSchema>;
|