@deveye/types 0.15.2 → 0.16.1
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 +54 -95
- package/src/domain/secrecy.ts +3 -5
- package/src/domain/sharing.ts +33 -70
- package/src/domain/syncProtocol.ts +5 -12
- package/src/domain/user.ts +8 -14
- package/src/domain/workspace.ts +0 -3
- package/src/domain/workspaceRole.ts +34 -82
- package/src/features/agent.ts +306 -0
- package/src/features/live.ts +17 -37
- package/src/features/notify.ts +19 -57
- package/src/features/registry.ts +7 -44
- package/src/features/secrecy.ts +4 -9
- package/src/features/sharing.ts +12 -26
- package/src/features/user.ts +6 -11
- package/src/features/workspace.ts +6 -11
- package/src/http/auth.ts +6 -13
- package/src/http/device.ts +13 -17
- package/src/http/status.ts +6 -10
- package/src/index.ts +29 -932
- package/src/protocol/agent.ts +40 -70
- package/src/protocol/envelope.ts +3 -10
- package/src/sdk/client-ambient.d.ts +228 -21
- package/src/sdk/client.ts +277 -17
- package/src/sdk/devb.ts +120 -0
- package/src/sdk/manifest.test.ts +0 -1
- package/src/sdk/manifest.ts +94 -25
- package/src/sdk/providers.ts +310 -5
- package/src/sdk/server.ts +483 -19
- package/src/sdk/testing.test.ts +2 -2
- package/src/sdk/testing.ts +302 -26
- package/src/utils/version.ts +5 -8
- package/src/domain/audience.ts +0 -549
- package/src/domain/backup.ts +0 -355
- package/src/domain/credential.ts +0 -55
- package/src/domain/database.ts +0 -467
- package/src/domain/deploy.ts +0 -231
- package/src/domain/finance.ts +0 -477
- package/src/domain/git.ts +0 -419
- package/src/domain/mail.ts +0 -394
- package/src/domain/note.ts +0 -202
- package/src/domain/password.ts +0 -36
- package/src/domain/projectBoard.ts +0 -130
- package/src/domain/projectChat.ts +0 -46
- package/src/domain/projectHistory.ts +0 -82
- package/src/domain/projectLink.ts +0 -87
- package/src/domain/projectPlan.ts +0 -68
- package/src/domain/sentinel.ts +0 -623
- package/src/domain/uptime.ts +0 -216
- package/src/features/audience.ts +0 -275
- package/src/features/backup.ts +0 -230
- package/src/features/database.ts +0 -461
- package/src/features/deploy.ts +0 -245
- package/src/features/device.ts +0 -292
- package/src/features/deviceFiles.ts +0 -83
- package/src/features/deviceLogs.ts +0 -36
- package/src/features/deviceTerminal.ts +0 -57
- package/src/features/finance.ts +0 -360
- package/src/features/git.ts +0 -368
- package/src/features/mail.ts +0 -374
- package/src/features/metrics.ts +0 -185
- package/src/features/note.ts +0 -189
- package/src/features/password.ts +0 -67
- package/src/features/project.ts +0 -709
- package/src/features/sentinel.ts +0 -233
- package/src/features/uptime.ts +0 -186
package/src/features/registry.ts
CHANGED
|
@@ -1,28 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import { backupCommands } from './backup';
|
|
4
|
-
import { deviceCommands } from './device';
|
|
5
|
-
import { deviceFilesCommands } from './deviceFiles';
|
|
6
|
-
import { deviceLogCommands } from './deviceLogs';
|
|
7
|
-
import { deviceTerminalCommands } from './deviceTerminal';
|
|
8
|
-
import { databaseCommands } from './database';
|
|
9
|
-
import { deployCommands } from './deploy';
|
|
10
|
-
import { financeCommands } from './finance';
|
|
11
|
-
import { gitCommands } from './git';
|
|
2
|
+
import { agentCommands } from './agent';
|
|
12
3
|
import { homeCommands } from './home';
|
|
13
4
|
import { liveCommands } from './live';
|
|
14
5
|
import { logsCommands } from './logs';
|
|
15
|
-
import { mailCommands } from './mail';
|
|
16
|
-
import { metricsCommands } from './metrics';
|
|
17
|
-
import { noteCommands } from './note';
|
|
18
6
|
import { notifyCommands } from './notify';
|
|
19
7
|
import { sharingCommands } from './sharing';
|
|
20
|
-
import { passwordCommands } from './password';
|
|
21
|
-
import { projectCommands } from './project';
|
|
22
8
|
import { secrecyCommands } from './secrecy';
|
|
23
|
-
import { sentinelCommands } from './sentinel';
|
|
24
9
|
import { twoFactorCommands } from './twoFactor';
|
|
25
|
-
import { uptimeCommands } from './uptime';
|
|
26
10
|
import { userCommands } from './user';
|
|
27
11
|
import { adminCommands } from './admin';
|
|
28
12
|
import { workspaceCommands } from './workspace';
|
|
@@ -37,27 +21,11 @@ export const featureCommands = [
|
|
|
37
21
|
...workspaceCommands,
|
|
38
22
|
...adminCommands,
|
|
39
23
|
...userCommands,
|
|
40
|
-
...
|
|
41
|
-
...noteCommands,
|
|
42
|
-
...projectCommands,
|
|
43
|
-
...gitCommands,
|
|
44
|
-
...deployCommands,
|
|
45
|
-
...backupCommands,
|
|
46
|
-
...databaseCommands,
|
|
47
|
-
...financeCommands,
|
|
48
|
-
...audienceCommands,
|
|
49
|
-
...deviceCommands,
|
|
50
|
-
...deviceLogCommands,
|
|
51
|
-
...deviceTerminalCommands,
|
|
52
|
-
...deviceFilesCommands,
|
|
53
|
-
...metricsCommands,
|
|
54
|
-
...sentinelCommands,
|
|
55
|
-
...uptimeCommands,
|
|
24
|
+
...agentCommands,
|
|
56
25
|
...twoFactorCommands,
|
|
57
26
|
...secrecyCommands,
|
|
58
27
|
...logsCommands,
|
|
59
28
|
...homeCommands,
|
|
60
|
-
...mailCommands,
|
|
61
29
|
...notifyCommands,
|
|
62
30
|
...sharingCommands,
|
|
63
31
|
...liveCommands
|
|
@@ -68,16 +36,11 @@ export const featureCommandRegistry: Record<string, FeatureCommandDescriptor> =
|
|
|
68
36
|
);
|
|
69
37
|
|
|
70
38
|
/**
|
|
71
|
-
* Verse les contrats d'un module installé dans le registre des commandes,
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* Une native rapatriée déclare les MÊMES objets que le registre publié : la
|
|
78
|
-
* réinscription à l'identique est un no-op. Deux contrats différents sous le
|
|
79
|
-
* même nom, en revanche, sont une collision de config, et le chargement doit
|
|
80
|
-
* le dire plutôt que d'en servir un des deux au hasard.
|
|
39
|
+
* Verse les contrats d'un module installé dans le registre des commandes, que
|
|
40
|
+
* le `ws.send` du client consulte avant tout envoi ; sans cela, chaque commande
|
|
41
|
+
* du module serait refusée côté client (« Unknown command »). Réinscrire les
|
|
42
|
+
* mêmes objets est un no-op ; deux contrats différents sous le même nom sont
|
|
43
|
+
* une collision de config, et le chargement doit le dire.
|
|
81
44
|
*/
|
|
82
45
|
export function registerFeatureCommands(commands: readonly FeatureCommandDescriptor[]): void {
|
|
83
46
|
for (const c of commands) {
|
package/src/features/secrecy.ts
CHANGED
|
@@ -55,15 +55,10 @@ export const secrecySetReauth = {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* Hold (or release) the cached DEK
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* periodically — the server only honours the hold for a short lease, so if the
|
|
63
|
-
* popup vanishes for *any* reason (close, navigation, crash, disconnect) the
|
|
64
|
-
* heartbeats stop and the DEK reverts to a normal countdown. `active: false`
|
|
65
|
-
* releases the hold and restarts a fresh grace window. The DEK can therefore
|
|
66
|
-
* never linger indefinitely: only a genuinely-still-open popup keeps it alive.
|
|
58
|
+
* Hold (or release) the cached DEK while an action popup is open. `active:
|
|
59
|
+
* true` is a heartbeat: the server honours the hold for a short lease only, so
|
|
60
|
+
* if the popup vanishes for any reason the DEK reverts to a normal countdown.
|
|
61
|
+
* `active: false` releases the hold and restarts a fresh grace window.
|
|
67
62
|
*/
|
|
68
63
|
export const secrecyHold = {
|
|
69
64
|
command: 'secrecy.hold' as const,
|
package/src/features/sharing.ts
CHANGED
|
@@ -8,16 +8,10 @@ import {
|
|
|
8
8
|
} from '../domain/sharing';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Le partage d'un élément et ses restrictions par rôle.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* les recopier par émetteur aurait reproduit exactement ce que l'unification des
|
|
16
|
-
* notifications vient de défaire.
|
|
17
|
-
*
|
|
18
|
-
* L'autorisation ne peut pas être déclarative — la fonctionnalité visée est une
|
|
19
|
-
* **donnée d'entrée**. Elle est vérifiée en tête de handler, comme pour
|
|
20
|
-
* `notify.route*` et `device.setConfig`.
|
|
11
|
+
* Le partage d'un élément et ses restrictions par rôle. Un module transversal :
|
|
12
|
+
* ces commandes prennent toujours le même couple `(feature, itemId)`.
|
|
13
|
+
* L'autorisation ne peut pas être déclarative, la fonctionnalité visée étant
|
|
14
|
+
* une donnée d'entrée : elle est vérifiée en tête de handler.
|
|
21
15
|
*/
|
|
22
16
|
|
|
23
17
|
/** Où cet élément est visible, et pourquoi il ne pourrait pas l'être. */
|
|
@@ -28,10 +22,8 @@ export const shareGet = {
|
|
|
28
22
|
};
|
|
29
23
|
|
|
30
24
|
/**
|
|
31
|
-
* Projette (ou retire) l'élément dans un espace.
|
|
32
|
-
*
|
|
33
|
-
* Un seul espace par appel : la case de l'écran est la commande, ce qui rend
|
|
34
|
-
* l'échec lisible — cocher une case qui échoue ne laisse pas les autres dans un
|
|
25
|
+
* Projette (ou retire) l'élément dans un espace. Un seul espace par appel : la
|
|
26
|
+
* case de l'écran est la commande, et un échec ne laisse pas les autres dans un
|
|
35
27
|
* état incertain.
|
|
36
28
|
*/
|
|
37
29
|
export const shareSet = {
|
|
@@ -44,13 +36,10 @@ export const shareSet = {
|
|
|
44
36
|
};
|
|
45
37
|
|
|
46
38
|
/**
|
|
47
|
-
* Ce que chaque rôle d'un espace voit de cet élément
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* l'onglet Partage du domicile, ce que chaque fenêtre montre — sans changer
|
|
52
|
-
* d'espace. L'appelant doit être membre de l'espace visé ; y **écrire** exige
|
|
53
|
-
* d'y tenir `workspace.roles`.
|
|
39
|
+
* Ce que chaque rôle d'un espace voit de cet élément (l'hérité et l'exception).
|
|
40
|
+
* `workspaceId` absent = l'espace actif ; renseigné, n'importe quel espace où
|
|
41
|
+
* l'élément est visible. L'appelant doit en être membre ; y écrire exige
|
|
42
|
+
* `workspace.roles`.
|
|
54
43
|
*/
|
|
55
44
|
export const itemGrantList = {
|
|
56
45
|
command: 'share.grantList' as const,
|
|
@@ -60,11 +49,8 @@ export const itemGrantList = {
|
|
|
60
49
|
|
|
61
50
|
/**
|
|
62
51
|
* Abaisse (ou rétablit) ce qu'un rôle peut faire sur cet élément, dans l'espace
|
|
63
|
-
* visé (`workspaceId` absent = l'actif).
|
|
64
|
-
*
|
|
65
|
-
* `access: null` **retire** la restriction : le rôle reprend ce que la
|
|
66
|
-
* fonctionnalité lui donne. C'est l'absence de ligne qui exprime « rien de
|
|
67
|
-
* particulier », pas une valeur.
|
|
52
|
+
* visé (`workspaceId` absent = l'actif). `access: null` retire la restriction :
|
|
53
|
+
* le rôle reprend ce que la fonctionnalité lui donne.
|
|
68
54
|
*/
|
|
69
55
|
export const itemGrantSet = {
|
|
70
56
|
command: 'share.grantSet' as const,
|
package/src/features/user.ts
CHANGED
|
@@ -31,10 +31,9 @@ export const THEME_IMAGE_MAX_LENGTH = 4_200_000;
|
|
|
31
31
|
export const THEME_SLOT_COUNT = 5;
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* Upper bound on one saved slot value
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* within the browser's localStorage budget and the `users.theme` column.
|
|
34
|
+
* Upper bound on one saved slot value (a compressed data URL or a short raw
|
|
35
|
+
* URL): a safety cap keeping the whole theme JSON (5 slots + active image)
|
|
36
|
+
* within the browser's localStorage budget and the theme column.
|
|
38
37
|
*/
|
|
39
38
|
export const THEME_SLOT_IMAGE_MAX_LENGTH = 1_500_000;
|
|
40
39
|
|
|
@@ -74,13 +73,9 @@ export const userSetColor = {
|
|
|
74
73
|
};
|
|
75
74
|
|
|
76
75
|
/**
|
|
77
|
-
* Pose ou retire un drapeau de compte. Une commande
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* coûte qu'une entrée dans `userSettingFlagSchema`.
|
|
81
|
-
*
|
|
82
|
-
* La sortie renvoie le sac **complet** tel qu'il vient d'être écrit : le client
|
|
83
|
-
* peut s'aligner dessus au lieu de rejouer sa propre arithmétique.
|
|
76
|
+
* Pose ou retire un drapeau de compte. Une commande pour tous les drapeaux :
|
|
77
|
+
* un seul chemin lecture-modification-écriture sur `users.settings`. La sortie
|
|
78
|
+
* renvoie le sac complet tel qu'il vient d'être écrit.
|
|
84
79
|
*/
|
|
85
80
|
export const userSetSetting = {
|
|
86
81
|
command: 'user.setSetting' as const,
|
|
@@ -24,12 +24,9 @@ export const workspaceDelete = {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Bascule vers un espace : renvoie son apparence et sa disposition d'accueil.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* par `/api/auth/me` ne conviendrait pas : cette route recalcule l'espace actif à
|
|
31
|
-
* partir du favori et renverrait l'apparence de l'espace qu'*elle* choisit, pas
|
|
32
|
-
* de celui vers lequel on bascule.
|
|
27
|
+
* L'espace visé voyage sur l'enveloppe, appartenance vérifiée par le
|
|
28
|
+
* dispatcheur. `/api/auth/me` ne conviendrait pas : il recalcule l'espace actif
|
|
29
|
+
* à partir du favori.
|
|
33
30
|
*/
|
|
34
31
|
export const workspaceActivate = {
|
|
35
32
|
command: 'workspace.activate' as const,
|
|
@@ -77,11 +74,9 @@ export const workspaceRemoveMember = {
|
|
|
77
74
|
};
|
|
78
75
|
|
|
79
76
|
/**
|
|
80
|
-
* Ajoute un membre à l'espace actif, désigné par son adresse.
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* invitation d'un administrateur), donc le désigner suffit. Un lien serait un
|
|
84
|
-
* détour — et un secret transmissible de plus à surveiller.
|
|
77
|
+
* Ajoute un membre à l'espace actif, désigné par son adresse. Pas de lien ni
|
|
78
|
+
* d'acceptation : le compte existe déjà (inscription sur invitation), et un
|
|
79
|
+
* lien serait un secret transmissible de plus.
|
|
85
80
|
*/
|
|
86
81
|
export const workspaceAddMember = {
|
|
87
82
|
command: 'workspace.addMember' as const,
|
package/src/http/auth.ts
CHANGED
|
@@ -6,13 +6,11 @@ import { workspacePermissionsSchema } from '../domain/workspaceRole';
|
|
|
6
6
|
import { themeStateSchema } from '../features/user';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Contenu commun à `/login`, `/refresh` et `/me` : le compte,
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* contenir plusieurs data URLs, et les livrer tous multiplierait la charge utile
|
|
15
|
-
* par le nombre d'espaces. Basculer d'espace va chercher les siens.
|
|
9
|
+
* Contenu commun à `/login`, `/refresh` et `/me` : le compte, ses espaces, et
|
|
10
|
+
* le thème et la disposition d'accueil de l'espace actif seul. Les thèmes des
|
|
11
|
+
* autres espaces ne sont pas embarqués : `bgImages` peut porter plusieurs data
|
|
12
|
+
* URLs, et les livrer tous multiplierait la charge utile par le nombre
|
|
13
|
+
* d'espaces.
|
|
16
14
|
*/
|
|
17
15
|
export const sessionBundleSchema = z.object({
|
|
18
16
|
user: userSchema,
|
|
@@ -34,12 +32,7 @@ export const loginRequestSchema = z.object({
|
|
|
34
32
|
|
|
35
33
|
export type LoginRequest = z.infer<typeof loginRequestSchema>;
|
|
36
34
|
|
|
37
|
-
/**
|
|
38
|
-
* L'inscription n'est plus libre : elle exige un jeton d'invitation émis par un
|
|
39
|
-
* administrateur. La route existait déjà, ouverte à tous et connectant
|
|
40
|
-
* automatiquement — simplement inatteignable depuis l'interface, ce qui n'est
|
|
41
|
-
* pas une protection.
|
|
42
|
-
*/
|
|
35
|
+
/** L'inscription exige un jeton d'invitation émis par un administrateur. */
|
|
43
36
|
export const registerRequestSchema = z.object({
|
|
44
37
|
inviteToken: z.string().min(1),
|
|
45
38
|
username: z
|
package/src/http/device.ts
CHANGED
|
@@ -23,15 +23,14 @@ export const LINK_CODE_TTL_MAX_SECONDS = 30 * 24 * 60 * 60;
|
|
|
23
23
|
export const linkCodeRequestSchema = z.object({
|
|
24
24
|
ttlSeconds: z.number().int().positive().max(LINK_CODE_TTL_MAX_SECONDS).nullable().optional(),
|
|
25
25
|
/**
|
|
26
|
-
* Approve the device
|
|
27
|
-
*
|
|
28
|
-
* (manual approval stays the safe default).
|
|
26
|
+
* Approve the device the moment it enrols with this code, instead of
|
|
27
|
+
* leaving it `pending` for manual approval. Defaults to `false`.
|
|
29
28
|
*/
|
|
30
29
|
autoApprove: z.boolean().default(false),
|
|
31
30
|
/**
|
|
32
31
|
* Espace dans lequel la machine sera rangée à l'enrôlement. Omis → l'espace
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* actif de l'émetteur. Explicite (n'importe quel espace existant) : réservé
|
|
33
|
+
* à l'administrateur global.
|
|
35
34
|
*/
|
|
36
35
|
workspaceId: z.number().int().positive().optional()
|
|
37
36
|
});
|
|
@@ -84,13 +83,11 @@ export const enrollDeviceResponseSchema = z.object({
|
|
|
84
83
|
export type EnrollDeviceResponse = z.infer<typeof enrollDeviceResponseSchema>;
|
|
85
84
|
|
|
86
85
|
/**
|
|
87
|
-
* Agent download matrix
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* The CI release workflow and `agent/build-all.sh` mirror the same labels (they
|
|
93
|
-
* can't import TS) — keep all three in sync when adding/removing a target.
|
|
86
|
+
* Agent download matrix: the single source of truth for the platform binaries
|
|
87
|
+
* shipped with a release, consumed by the web UI picker and the server
|
|
88
|
+
* (`:target` validation, file lookup). The CI release workflow and
|
|
89
|
+
* `agent/build-all.sh` mirror the same labels: keep all three in sync when
|
|
90
|
+
* adding or removing a target.
|
|
94
91
|
*/
|
|
95
92
|
export const agentTargetSchema = z.enum([
|
|
96
93
|
'linux-x86_64',
|
|
@@ -203,11 +200,10 @@ export const agentManifestTargetSchema = z.object({
|
|
|
203
200
|
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
|
204
201
|
size: z.number().int().nonnegative(),
|
|
205
202
|
/**
|
|
206
|
-
* Base64 ed25519 signature over the 32 raw bytes of `sha256`,
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* pre-signing build degrades cleanly instead of being rejected outright.
|
|
203
|
+
* Base64 ed25519 signature over the 32 raw bytes of `sha256`, made by the CI
|
|
204
|
+
* release with the update-signing key; the agent verifies it with its
|
|
205
|
+
* embedded public key before self-replacing. Optional: an unsigned target
|
|
206
|
+
* stays downloadable but can never drive a self-update.
|
|
211
207
|
*/
|
|
212
208
|
signature: z.string().min(1).optional()
|
|
213
209
|
});
|
package/src/http/status.ts
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Server readiness / boot status (HTTP, `GET /api/status`)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* ready" — today just the agent-binary reconcile, but the shape is a generic
|
|
8
|
-
* task list so more steps can be added later. The web client shows a discreet
|
|
9
|
-
* topbar zone while `ready` is false, then hides it for good.
|
|
4
|
+
* Server readiness / boot status (HTTP, `GET /api/status`): the startup tasks
|
|
5
|
+
* the server runs before it is fully ready, as a generic task list. The web
|
|
6
|
+
* client shows a topbar zone while `ready` is false.
|
|
10
7
|
*/
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
|
-
* `warning` is
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `error` — but reads as a non-blocking caution rather than a hard failure.
|
|
10
|
+
* `warning` is terminal but visible: the step finished without fully succeeding
|
|
11
|
+
* (e.g. the agent reconcile served an older set), the app is usable, and the
|
|
12
|
+
* topbar zone stays shown as a non-blocking caution.
|
|
17
13
|
*/
|
|
18
14
|
export const bootTaskStateSchema = z.enum(['pending', 'running', 'done', 'warning', 'error']);
|
|
19
15
|
export type BootTaskState = z.infer<typeof bootTaskStateSchema>;
|