@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/protocol/agent.ts
CHANGED
|
@@ -39,9 +39,8 @@ import { ProtocolErrorSchema } from './error';
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Agent <-> Server wire protocol (distinct from the user feature protocol).
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* The server acknowledges and may push commands (reserved for later).
|
|
42
|
+
* The agent authenticates with its device token, then streams metric batches,
|
|
43
|
+
* reports and replies; the server acknowledges and pushes orders.
|
|
45
44
|
*/
|
|
46
45
|
|
|
47
46
|
/** Command names the agent may send to the server. */
|
|
@@ -301,17 +300,12 @@ export const agentSyncIndexPayloadSchema = z.object({
|
|
|
301
300
|
entries: z.array(syncIndexEntrySchema).max(SYNC_INDEX_BATCH_MAX),
|
|
302
301
|
done: z.boolean(),
|
|
303
302
|
/**
|
|
304
|
-
* L'agent a-t-il
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
* l'appareil est à jour, il le VÉRIFIE — une vérification fausse coûte un
|
|
311
|
-
* scan complet, jamais une divergence.
|
|
312
|
-
*
|
|
313
|
-
* Le défaut `true` est ce qui rend un vieil agent inoffensif : sans le champ,
|
|
314
|
-
* le serveur retombe sur le chemin d'aujourd'hui.
|
|
303
|
+
* L'agent a-t-il réellement parcouru le disque ? `false` répond à un
|
|
304
|
+
* `sync.scan` en mode `auto` sur un partage que le watcher sait intact :
|
|
305
|
+
* aucune entrée, seule `fingerprint` est renseignée, et le serveur VÉRIFIE
|
|
306
|
+
* qu'elle correspond à sa baseline (une vérification fausse coûte un scan
|
|
307
|
+
* complet, jamais une divergence). Le défaut `true` rend un vieil agent
|
|
308
|
+
* inoffensif.
|
|
315
309
|
*/
|
|
316
310
|
scanned: z.boolean().default(true),
|
|
317
311
|
/** Empreinte de l'index détenu par l'agent, quand il sait la calculer. */
|
|
@@ -520,11 +514,8 @@ export const AGENT_ERROR = 'agent.error' as const;
|
|
|
520
514
|
export const AGENT_COLLECT = 'agent.collect' as const;
|
|
521
515
|
/**
|
|
522
516
|
* Demande un relevé Sentinelle immédiat (persistance + authentification).
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
* peut être déclenché à volonté, tandis qu'un relevé de persistance empreinte
|
|
526
|
-
* des centaines de fichiers. Les confondre reviendrait à faire payer ce prix à
|
|
527
|
-
* chaque bouton « rafraîchir » de la page Monitoring.
|
|
517
|
+
* Distinct d'`agent.collect` : celui-ci coûte quelques millisecondes, un relevé
|
|
518
|
+
* de persistance empreinte des centaines de fichiers.
|
|
528
519
|
*/
|
|
529
520
|
export const AGENT_SCAN = 'agent.scan' as const;
|
|
530
521
|
/** Push the per-device collection config (cadences + capture mode) to the agent. */
|
|
@@ -731,11 +722,9 @@ export const agentSyncScanPayloadSchema = z.object({
|
|
|
731
722
|
sessionId: syncOpId,
|
|
732
723
|
shareId: z.number().int().positive(),
|
|
733
724
|
/**
|
|
734
|
-
* Le défaut `full`
|
|
735
|
-
*
|
|
736
|
-
*
|
|
737
|
-
* complet », jamais vers « saut » — sauter exige une empreinte que seul un
|
|
738
|
-
* agent récent produit et que seul un serveur récent exploite.
|
|
725
|
+
* Le défaut `full` rend un vieux serveur inoffensif : les deux sens de la
|
|
726
|
+
* dissymétrie de version dégradent vers « scan complet », jamais vers
|
|
727
|
+
* « saut ».
|
|
739
728
|
*/
|
|
740
729
|
mode: syncScanModeSchema.default('full')
|
|
741
730
|
});
|
|
@@ -780,23 +769,20 @@ export const agentSyncApplyChunkPayloadSchema = z.object({
|
|
|
780
769
|
mode: z.number().int().min(0).max(0o777).nullable().default(null),
|
|
781
770
|
/**
|
|
782
771
|
* Offset de clair à partir duquel CE transfert reprend. Décidé par le
|
|
783
|
-
* serveur (
|
|
784
|
-
*
|
|
785
|
-
*
|
|
786
|
-
* doit jamais présumer de son propre point de reprise.
|
|
772
|
+
* serveur (d'après le `resumeFrom` de l'agent) et répété sur chaque frame :
|
|
773
|
+
* l'agent tronque son temporaire à cette valeur avant d'écrire, et ne
|
|
774
|
+
* présume jamais de son propre point de reprise.
|
|
787
775
|
*/
|
|
788
776
|
resumeFrom: z.number().int().nonnegative().default(0)
|
|
789
777
|
});
|
|
790
778
|
export type AgentSyncApplyChunkPayload = z.infer<typeof agentSyncApplyChunkPayloadSchema>;
|
|
791
779
|
|
|
792
780
|
/**
|
|
793
|
-
* Amorce un download. L'agent répond `sync.opResult` avec `op: 'applyReady'`
|
|
794
|
-
* un `resumeFrom` :
|
|
795
|
-
* temporaire pour ce hash exact. Le
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
* auto-corrective : un fichier modifié entre-temps a un autre hash, donc un
|
|
799
|
-
* autre temporaire, donc aucune reprise possible sur des octets périmés.
|
|
781
|
+
* Amorce un download. L'agent répond `sync.opResult` avec `op: 'applyReady'`
|
|
782
|
+
* et un `resumeFrom` : les octets de clair qu'il détient DÉJÀ dans son
|
|
783
|
+
* temporaire pour ce hash exact. Le temporaire est nommé par hash et non par
|
|
784
|
+
* `opId` : un fichier modifié entre-temps a un autre hash, donc aucune reprise
|
|
785
|
+
* sur des octets périmés.
|
|
800
786
|
*/
|
|
801
787
|
export const AGENT_SYNC_APPLY_START = 'sync.applyStart' as const;
|
|
802
788
|
export const agentSyncApplyStartPayloadSchema = z.object({
|
|
@@ -822,10 +808,9 @@ export const agentSyncApplyDirPayloadSchema = z.object({
|
|
|
822
808
|
shareId: z.number().int().positive(),
|
|
823
809
|
relPath: syncRelPath,
|
|
824
810
|
/**
|
|
825
|
-
* `dir` autorise la CRÉATION du chemin ; `file`
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
* que le planner écarterait ensuite pour toujours en « conflit de nature ».
|
|
811
|
+
* `dir` autorise la CRÉATION du chemin ; `file` ne fait qu'ajuster le mode
|
|
812
|
+
* s'il existe. Sans cette distinction, un `chmod` sur un fichier
|
|
813
|
+
* momentanément absent ferait naître un DOSSIER à sa place.
|
|
829
814
|
*/
|
|
830
815
|
kind: syncEntryKindSchema.default('dir'),
|
|
831
816
|
mode: z.number().int().min(0).max(0o777).nullable().default(null)
|
|
@@ -854,13 +839,9 @@ export type AgentSyncApplyLocalPayload = z.infer<typeof agentSyncApplyLocalPaylo
|
|
|
854
839
|
|
|
855
840
|
/**
|
|
856
841
|
* Propage un DÉPLACEMENT : l'agent renomme sur place, sans transfert ni
|
|
857
|
-
* corbeille
|
|
858
|
-
*
|
|
859
|
-
*
|
|
860
|
-
*
|
|
861
|
-
* L'agent vérifie que la source porte bien le contenu attendu avant de bouger.
|
|
862
|
-
* En cas d'échec il répond `opResult !ok`, et le serveur retombe sur le chemin
|
|
863
|
-
* ordinaire (téléchargement puis suppression), qui reste sûr.
|
|
842
|
+
* corbeille, après avoir vérifié que la source porte le contenu attendu. En
|
|
843
|
+
* cas d'échec il répond `opResult !ok` et le serveur retombe sur le chemin
|
|
844
|
+
* ordinaire (téléchargement puis suppression).
|
|
864
845
|
*/
|
|
865
846
|
export const AGENT_SYNC_MOVE = 'sync.move' as const;
|
|
866
847
|
export const agentSyncMovePayloadSchema = z.object({
|
|
@@ -900,13 +881,10 @@ export const agentConfigPayloadSchema = z.object({
|
|
|
900
881
|
/** How much of the process list to carry on each tick (`off`/`top`/`all`). */
|
|
901
882
|
processCapture: processCaptureSchema,
|
|
902
883
|
/**
|
|
903
|
-
* Sentinelle est-elle active sur cet appareil ? Éteinte, l'agent ne relève
|
|
904
|
-
* persistance ni authentification
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
* Facultatif : un serveur antérieur à Sentinelle n'envoie pas le champ, et
|
|
909
|
-
* l'agent se comporte alors comme avant.
|
|
884
|
+
* Sentinelle est-elle active sur cet appareil ? Éteinte, l'agent ne relève
|
|
885
|
+
* ni persistance ni authentification : une machine non surveillée ne doit
|
|
886
|
+
* pas voir ses journaux lus « au cas où ». Facultatif : absent, l'agent ne
|
|
887
|
+
* relève rien.
|
|
910
888
|
*/
|
|
911
889
|
sentinelEnabled: z.boolean().optional(),
|
|
912
890
|
/** Cadence du manifeste de persistance, en ms. */
|
|
@@ -1048,12 +1026,9 @@ export const DEVICE_REPORT_EVENT = 'device.report' as const;
|
|
|
1048
1026
|
/** Package-manager inventory, live upgrade progress, and completion (Appareils panel). */
|
|
1049
1027
|
export const PACKAGE_LIST_EVENT = 'package.list' as const;
|
|
1050
1028
|
/**
|
|
1051
|
-
* Une mise à jour vient d'être
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
* la première ligne de sortie de l'outil, qui peut se faire attendre. C'est ce
|
|
1055
|
-
* qui permet à tous les écrans ouverts, y compris ceux d'autres personnes, de
|
|
1056
|
-
* griser le bouton au même instant.
|
|
1029
|
+
* Une mise à jour vient d'être acceptée pour ce gestionnaire. Émis par le
|
|
1030
|
+
* serveur avant la première ligne de sortie de l'outil, pour que tous les
|
|
1031
|
+
* écrans ouverts grisent le bouton au même instant.
|
|
1057
1032
|
*/
|
|
1058
1033
|
export const PACKAGE_STARTED_EVENT = 'package.started' as const;
|
|
1059
1034
|
export const PACKAGE_PROGRESS_EVENT = 'package.progress' as const;
|
|
@@ -1063,10 +1038,6 @@ export const DEVICE_POWER_EVENT = 'device.powerResult' as const;
|
|
|
1063
1038
|
/**
|
|
1064
1039
|
* Outcome of a persistence/privilege change (autostart, elevate, drop), fanned to
|
|
1065
1040
|
* subscribers exactly like the power result.
|
|
1066
|
-
*
|
|
1067
|
-
* Sans lui, la seule trace de l'échec d'une installation de service était une
|
|
1068
|
-
* ligne de journal d'audit : l'interface attendait quelques secondes, relisait
|
|
1069
|
-
* l'appareil, et n'affichait rien — ni la réussite, ni la raison de l'échec.
|
|
1070
1041
|
*/
|
|
1071
1042
|
export const DEVICE_SERVICE_EVENT = 'device.serviceResult' as const;
|
|
1072
1043
|
/** Device log sources inventory + queried log lines, fanned to subscribers. */
|
|
@@ -1086,14 +1057,13 @@ export const CLOUD_SYNC_PROGRESS_EVENT = 'cloudSync.progress' as const;
|
|
|
1086
1057
|
export const CLOUD_SYNC_STATE_EVENT = 'cloudSync.state' as const;
|
|
1087
1058
|
export const CLOUD_SYNC_CHUNK_EVENT = 'cloudSync.chunk' as const;
|
|
1088
1059
|
|
|
1089
|
-
|
|
1060
|
+
// Push payloads reuse the agent reply shapes (they already carry `deviceId`).
|
|
1061
|
+
|
|
1090
1062
|
/**
|
|
1091
|
-
* L'inventaire des gestionnaires,
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
* après avoir refermé la fenêtre, ou chez quelqu'un d'autre — repartait d'un
|
|
1096
|
-
* bouton actif et permettait de relancer la même commande.
|
|
1063
|
+
* L'inventaire des gestionnaires, enrichi par le serveur de ce que l'agent ne
|
|
1064
|
+
* peut pas savoir : quelles mises à jour tournent déjà. Sans ce champ, un
|
|
1065
|
+
* écran ouvert pendant une mise à jour permettrait de relancer la même
|
|
1066
|
+
* commande.
|
|
1097
1067
|
*/
|
|
1098
1068
|
export const packageListPushSchema = agentPkgListResultPayloadSchema.extend({
|
|
1099
1069
|
running: z.array(packageManagerIdSchema).default([])
|
package/src/protocol/envelope.ts
CHANGED
|
@@ -15,16 +15,9 @@ export const clientMessageSchema = z.object({
|
|
|
15
15
|
command: z.string().min(1),
|
|
16
16
|
/**
|
|
17
17
|
* Espace de travail visé par la commande. Absent → l'espace personnel de
|
|
18
|
-
* l'appelant.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* trois raisons : aucun schéma d'entrée ne porte de `workspaceId`, aucun site
|
|
22
|
-
* d'appel client ne le passe à la main (`ws.send` l'estampille), et le
|
|
23
|
-
* serveur n'a qu'un seul point de résolution et d'autorisation. Le tenir dans
|
|
24
|
-
* un état de session côté serveur serait plus fragile : la socket se
|
|
25
|
-
* reconnecte seule (backoff, retour de focus) et une commande émise avant la
|
|
26
|
-
* ré-activation viserait le mauvais espace — ici chaque message se décrit
|
|
27
|
-
* lui-même.
|
|
18
|
+
* l'appelant. Porté par l'enveloppe et non par chaque `payload` : `ws.send`
|
|
19
|
+
* l'estampille, le serveur n'a qu'un seul point de résolution et
|
|
20
|
+
* d'autorisation, et chaque message se décrit lui-même, reconnexions comprises.
|
|
28
21
|
*/
|
|
29
22
|
workspaceId: z.number().int().positive().optional(),
|
|
30
23
|
payload: z.unknown()
|
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ambient declaration of `deveye-sdk-client
|
|
2
|
+
* Ambient declaration of `deveye-sdk-client`, the runtime barrel the APP
|
|
3
3
|
* provides when a feature module is compiled in (resolved by alias inside
|
|
4
|
-
* DevEye). The module itself is app code
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* one tsconfig `include` entry pointing at this file in node_modules;
|
|
10
|
-
* - DevEye itself verifies MECHANICALLY that the real barrel honours this
|
|
11
|
-
* declaration (`client/npm run check:sdk`): a drift breaks the app's CI,
|
|
12
|
-
* never a third-party build.
|
|
13
|
-
*
|
|
14
|
-
* Extend it when the app's stable surface grows — same gesture as before,
|
|
15
|
-
* one file instead of one per module repo.
|
|
4
|
+
* DevEye). The module itself is app code, published nowhere; this file is its
|
|
5
|
+
* typed portrait, so a module repo can `tsc --noEmit` standalone (one tsconfig
|
|
6
|
+
* `include` entry pointing here). DevEye verifies mechanically that the real
|
|
7
|
+
* barrel honours it (`client/npm run check:sdk`): a drift breaks the app's CI,
|
|
8
|
+
* never a third-party build.
|
|
16
9
|
*/
|
|
17
10
|
declare module 'deveye-sdk-client' {
|
|
18
11
|
import type {
|
|
19
12
|
ButtonHTMLAttributes,
|
|
13
|
+
CSSProperties,
|
|
20
14
|
ChangeEvent,
|
|
21
15
|
ComponentType,
|
|
22
|
-
CSSProperties,
|
|
23
16
|
InputHTMLAttributes,
|
|
24
17
|
ReactNode,
|
|
18
|
+
RefObject,
|
|
25
19
|
SelectHTMLAttributes
|
|
26
20
|
} from 'react';
|
|
27
21
|
import type { z, ZodType } from 'zod';
|
|
28
|
-
import type {
|
|
29
|
-
|
|
22
|
+
import type {
|
|
23
|
+
ButtonHTMLAttributes as DialogButtonAttributes,
|
|
24
|
+
PointerEvent as ReactPointerEvent
|
|
25
|
+
} from 'react';
|
|
26
|
+
import type {
|
|
27
|
+
FeatureAccess,
|
|
28
|
+
FeatureId,
|
|
29
|
+
MinimalUser,
|
|
30
|
+
User,
|
|
31
|
+
WorkspaceCapability
|
|
32
|
+
} from '@deveye/types';
|
|
33
|
+
import type { FeatureManifest, ManifestCommand } from '@deveye/types/sdk';
|
|
34
|
+
import type { SdkDeviceSummary } from '@deveye/types/sdk/client';
|
|
30
35
|
|
|
31
36
|
// ── UI kit ─────────────────────────────────────────────────────────────
|
|
32
37
|
export const Button: ComponentType<
|
|
@@ -36,7 +41,7 @@ declare module 'deveye-sdk-client' {
|
|
|
36
41
|
}
|
|
37
42
|
>;
|
|
38
43
|
export const TextInput: ComponentType<
|
|
39
|
-
InputHTMLAttributes<HTMLInputElement> & { enableShowHideButton?: boolean }
|
|
44
|
+
InputHTMLAttributes<HTMLInputElement> & { enableShowHideButton?: boolean; error?: string }
|
|
40
45
|
>;
|
|
41
46
|
export const SelectInput: ComponentType<SelectHTMLAttributes<HTMLSelectElement>>;
|
|
42
47
|
export const Checkbox: ComponentType<{
|
|
@@ -45,6 +50,7 @@ declare module 'deveye-sdk-client' {
|
|
|
45
50
|
onChange: (checked: boolean) => void;
|
|
46
51
|
children?: ReactNode;
|
|
47
52
|
disabled?: boolean;
|
|
53
|
+
className?: string;
|
|
48
54
|
/** Required when there is no visible label. */
|
|
49
55
|
'aria-label'?: string;
|
|
50
56
|
}>;
|
|
@@ -78,6 +84,41 @@ declare module 'deveye-sdk-client' {
|
|
|
78
84
|
fill?: boolean;
|
|
79
85
|
holdSecrecy?: boolean;
|
|
80
86
|
}>;
|
|
87
|
+
/** The "Annuler" button of a Dialog footer: closes through the guarded close. */
|
|
88
|
+
export const DialogCancelButton: ComponentType<
|
|
89
|
+
DialogButtonAttributes<HTMLButtonElement> & {
|
|
90
|
+
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
|
|
91
|
+
icon?: string;
|
|
92
|
+
}
|
|
93
|
+
>;
|
|
94
|
+
/**
|
|
95
|
+
* The imperative dialog layer over Dialog: mount `<Popup id=...>` once
|
|
96
|
+
* around a form, then drive it with `OpenPopup(id, input)` (resolves with
|
|
97
|
+
* whatever `ClosePopup(id, result)` passes, `null` on dismiss).
|
|
98
|
+
*/
|
|
99
|
+
export function Popup<TInput = unknown>(props: {
|
|
100
|
+
children: ReactNode;
|
|
101
|
+
id: string;
|
|
102
|
+
title?: string;
|
|
103
|
+
width?: number;
|
|
104
|
+
headerAction?: ReactNode;
|
|
105
|
+
onInputChange?: ((input: TInput) => void) | null;
|
|
106
|
+
onClosePopup?: ((id: string) => void) | null;
|
|
107
|
+
onSubmit?: () => void;
|
|
108
|
+
autoFocus?: boolean;
|
|
109
|
+
dirty?: boolean;
|
|
110
|
+
onSave?: () => void;
|
|
111
|
+
tall?: boolean;
|
|
112
|
+
holdSecrecy?: boolean;
|
|
113
|
+
}): ReactNode;
|
|
114
|
+
export function OpenPopup<T = object>(id: string, inputData?: unknown): Promise<T | null>;
|
|
115
|
+
export function ClosePopup(id: string, data?: unknown): void;
|
|
116
|
+
/** The app-wide "i" explainer dialog: a heading and a body, one behaviour everywhere. */
|
|
117
|
+
export function openInfo(input: {
|
|
118
|
+
title: string;
|
|
119
|
+
body: ReactNode;
|
|
120
|
+
width?: number;
|
|
121
|
+
}): Promise<unknown>;
|
|
81
122
|
/** Request the enclosing Dialog's guarded close (the unsaved-changes prompt included). */
|
|
82
123
|
export function useDialogClose(): () => void;
|
|
83
124
|
/** Register `fn` as the enclosing Dialog's primary action (Enter triggers it); `null` clears it. */
|
|
@@ -112,12 +153,69 @@ declare module 'deveye-sdk-client' {
|
|
|
112
153
|
export const FeatureSettingsButton: ComponentType<{
|
|
113
154
|
scope:
|
|
114
155
|
| { kind: 'feature'; feature: FeatureId }
|
|
115
|
-
| {
|
|
156
|
+
| {
|
|
157
|
+
kind: 'item';
|
|
158
|
+
feature: FeatureId;
|
|
159
|
+
itemId: number | string;
|
|
160
|
+
itemLabel: string;
|
|
161
|
+
shareable?: boolean;
|
|
162
|
+
};
|
|
116
163
|
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
|
|
117
164
|
label?: string;
|
|
165
|
+
/** The tab a click opens (one of the manifest's tab ids); the first by default. */
|
|
166
|
+
initialSection?: string;
|
|
167
|
+
/**
|
|
168
|
+
* The shell opened or closed (unmount counts as closed): for the one
|
|
169
|
+
* component that owns the item's presence (`useLiveSegment`) when
|
|
170
|
+
* nothing else announces the item. The shell never declares the level.
|
|
171
|
+
*/
|
|
172
|
+
onOpenChange?: (open: boolean) => void;
|
|
118
173
|
}>;
|
|
119
174
|
/** The canonical settings row classes (channelRow, field, sectionHint...). */
|
|
120
175
|
export const settingsStyles: Readonly<Record<string, string>>;
|
|
176
|
+
/** A plain count on a home card: a big number, a noun, a secondary line. */
|
|
177
|
+
export type CountState = { kind: 'loading' } | { kind: 'ready'; count: number };
|
|
178
|
+
export const CountWidget: ComponentType<{
|
|
179
|
+
state: CountState;
|
|
180
|
+
/** Singular noun, pluralized with a trailing "s" unless `plural` says otherwise. */
|
|
181
|
+
noun: string;
|
|
182
|
+
plural?: string;
|
|
183
|
+
/** Secondary line when there is at least one item. */
|
|
184
|
+
hint: string;
|
|
185
|
+
/** Secondary line when the count is zero. */
|
|
186
|
+
empty: string;
|
|
187
|
+
tone?: 'neutral' | 'danger';
|
|
188
|
+
}>;
|
|
189
|
+
/**
|
|
190
|
+
* A workspace count over one of YOUR `.count` commands (or any `...Count`
|
|
191
|
+
* command answering `{ count }`), re-fetched on reconnect and on
|
|
192
|
+
* invalidation of that key. Never gated by the password-encryption unlock:
|
|
193
|
+
* the command must answer while locked.
|
|
194
|
+
*/
|
|
195
|
+
export function useWorkspaceCount(
|
|
196
|
+
command: `x-${string}.count` | `${string}.${string}Count`
|
|
197
|
+
): CountState;
|
|
198
|
+
/**
|
|
199
|
+
* Reorder a list by drag-and-drop, the app's one gesture for it (Pointer
|
|
200
|
+
* Events, a handle per row, an insertion bar the hook positions itself).
|
|
201
|
+
* The list container must be `position: relative`; rows carry
|
|
202
|
+
* `rowSelector`; the handle wires `onGripPointerDown`.
|
|
203
|
+
*/
|
|
204
|
+
export function useDragReorder<
|
|
205
|
+
L extends HTMLElement = HTMLElement,
|
|
206
|
+
B extends HTMLElement = HTMLElement
|
|
207
|
+
>(options: {
|
|
208
|
+
ids: (string | number)[];
|
|
209
|
+
rowSelector: string;
|
|
210
|
+
onReorder: (ids: (string | number)[]) => void;
|
|
211
|
+
onDragStateChange?: (dragging: boolean) => void;
|
|
212
|
+
layout?: 'rows' | 'grid';
|
|
213
|
+
}): {
|
|
214
|
+
listRef: RefObject<L | null>;
|
|
215
|
+
barRef: RefObject<B | null>;
|
|
216
|
+
onGripPointerDown: (e: ReactPointerEvent, id: string | number) => void;
|
|
217
|
+
draggingId: string | number | null;
|
|
218
|
+
};
|
|
121
219
|
|
|
122
220
|
// ── Server push events ─────────────────────────────────────────────────
|
|
123
221
|
/** Typed push subscription: filters `event`, safeParses, drops mismatches. */
|
|
@@ -150,6 +248,29 @@ declare module 'deveye-sdk-client' {
|
|
|
150
248
|
/** Imperative subscription to one resource key's invalidations. Returns the unsubscribe. */
|
|
151
249
|
export function onResourceChange(key: ExternalResourceKey, cb: () => void): () => void;
|
|
152
250
|
export function humanizeError(error: unknown, fallback: string): string;
|
|
251
|
+
/** The error a command rejects with: the server's code (or the socket's), its message, and the validation details when any. */
|
|
252
|
+
export class WsError extends Error {
|
|
253
|
+
constructor(code: string, message: string, details?: unknown);
|
|
254
|
+
readonly code: string;
|
|
255
|
+
readonly details?: unknown;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* The typed sender of any list of contracts (`featureApi` is it on a
|
|
259
|
+
* manifest's commands). `commandsApi(agentCommands)` is how a module talks
|
|
260
|
+
* to a device: the native agent transport (`agent.*`: files, terminal,
|
|
261
|
+
* logs, packages, power, live metrics subscription), under the active
|
|
262
|
+
* workspace's `devices` right; deferred answers arrive through
|
|
263
|
+
* `onServerEvent`.
|
|
264
|
+
*/
|
|
265
|
+
export function commandsApi<const C extends readonly ManifestCommand[]>(
|
|
266
|
+
commands: C
|
|
267
|
+
): {
|
|
268
|
+
send<N extends C[number]['command']>(
|
|
269
|
+
name: N,
|
|
270
|
+
input: z.input<Extract<C[number], { command: N }>['input'] & ZodType>,
|
|
271
|
+
opts?: { timeoutMs?: number }
|
|
272
|
+
): Promise<z.output<Extract<C[number], { command: N }>['output'] & ZodType>>;
|
|
273
|
+
};
|
|
153
274
|
export function featureApi<const M extends FeatureManifest>(
|
|
154
275
|
manifest: M
|
|
155
276
|
): {
|
|
@@ -182,6 +303,14 @@ declare module 'deveye-sdk-client' {
|
|
|
182
303
|
export function ensureSecrecyUnlocked(): Promise<void>;
|
|
183
304
|
/** Runs `run`; on a `locked` error, opens the unlock prompt and retries once. */
|
|
184
305
|
export function withSecrecy<T>(run: () => Promise<T>): Promise<T>;
|
|
306
|
+
/** Keep the unlocked session alive during a long operation (a mailbox sync the user is watching). */
|
|
307
|
+
export function touchSecrecy(): void;
|
|
308
|
+
/**
|
|
309
|
+
* The rejection of `ensureSecrecyUnlocked` / `withSecrecy` when the user
|
|
310
|
+
* dismisses the unlock prompt: a deliberate cancel, not a failure (close a
|
|
311
|
+
* view that has nothing to show, rather than reporting an error).
|
|
312
|
+
*/
|
|
313
|
+
export class UnlockCancelledError extends Error {}
|
|
185
314
|
|
|
186
315
|
// ── Live ───────────────────────────────────────────────────────────────
|
|
187
316
|
export type LiveSegmentKind = 'view' | 'l1' | 'l2' | 'l3' | 'l4';
|
|
@@ -216,13 +345,37 @@ declare module 'deveye-sdk-client' {
|
|
|
216
345
|
/** What the folder is for, said by the caller. */
|
|
217
346
|
description?: string;
|
|
218
347
|
}>;
|
|
219
|
-
/**
|
|
348
|
+
/**
|
|
349
|
+
* The workspace's enrolled devices, live: what the Devices module offers
|
|
350
|
+
* the app (`DEVICES_CLIENT_PROVIDER`), refreshed by the `devices` topic.
|
|
351
|
+
* Empty, loaded and without error when that module is not installed.
|
|
352
|
+
*/
|
|
220
353
|
export function useDevices(): {
|
|
221
|
-
devices:
|
|
354
|
+
devices: readonly SdkDeviceSummary[];
|
|
222
355
|
loading: boolean;
|
|
223
356
|
error: string | null;
|
|
224
|
-
refresh: () => Promise<void>;
|
|
225
357
|
};
|
|
358
|
+
/**
|
|
359
|
+
* Acquires a live metrics subscription to a device and returns its release;
|
|
360
|
+
* consumers of one socket are counted so that none unsubscribes another.
|
|
361
|
+
*/
|
|
362
|
+
export function acquireMetrics(deviceId: string): () => void;
|
|
363
|
+
/** Device paths as the agent reports them: Windows or POSIX, joined accordingly. */
|
|
364
|
+
export function isWinPath(p: string): boolean;
|
|
365
|
+
export function joinPath(base: string, name: string): string;
|
|
366
|
+
/**
|
|
367
|
+
* The DevEye version this interface was built from: what an agent's
|
|
368
|
+
* reported version is compared against to offer a self-update.
|
|
369
|
+
*/
|
|
370
|
+
export const APP_VERSION: string;
|
|
371
|
+
/**
|
|
372
|
+
* A validated GET on one of the app's HTTP routes (the session cookie
|
|
373
|
+
* rides along; an expired access token is renewed and the call replayed
|
|
374
|
+
* once). For the routes that stay HTTP because they serve binaries.
|
|
375
|
+
*/
|
|
376
|
+
export function httpGet<T>(path: string, outputSchema?: ZodType<T>): Promise<T>;
|
|
377
|
+
/** Renews the access cookie before a raw `fetch` that bypasses the client (a download). */
|
|
378
|
+
export function ensureFreshAccess(): Promise<void>;
|
|
226
379
|
export interface LiveOutlineProps {
|
|
227
380
|
'data-live-peer'?: true;
|
|
228
381
|
style?: CSSProperties;
|
|
@@ -247,6 +400,60 @@ declare module 'deveye-sdk-client' {
|
|
|
247
400
|
name: string;
|
|
248
401
|
} | null;
|
|
249
402
|
export function useFeatureLifecycle(hooks: { onUnmount?: () => void }): void;
|
|
403
|
+
/** The members of the active workspace, as the session lists them (empty before it answers). */
|
|
404
|
+
export function useWorkspaceMembers(): readonly MinimalUser[];
|
|
405
|
+
/**
|
|
406
|
+
* A member's identity dot: their avatar, or their initial on their account
|
|
407
|
+
* colour (the same one as the live presence). `user` may be undefined: a
|
|
408
|
+
* deleted account must not break a row.
|
|
409
|
+
*/
|
|
410
|
+
export const Avatar: ComponentType<{
|
|
411
|
+
user: MinimalUser | undefined;
|
|
412
|
+
size?: number;
|
|
413
|
+
title?: string;
|
|
414
|
+
}>;
|
|
415
|
+
/** The CSS variable of an account colour, the one the live presence paints with. */
|
|
416
|
+
export function userColorVar(color: MinimalUser['color']): string;
|
|
417
|
+
/**
|
|
418
|
+
* Two sticky bands, one under the other: measure the top one and hand the
|
|
419
|
+
* ancestor a `--sticky-head` variable the lower band offsets itself by.
|
|
420
|
+
*/
|
|
421
|
+
export interface StickyOffset<T extends HTMLElement> {
|
|
422
|
+
ref: RefObject<T | null>;
|
|
423
|
+
style: CSSProperties;
|
|
424
|
+
}
|
|
425
|
+
export function useStickyOffset<T extends HTMLElement>(): StickyOffset<T>;
|
|
426
|
+
/**
|
|
427
|
+
* The client contract another module offers (`FeatureClient.providers`,
|
|
428
|
+
* keys in `@deveye/types/sdk`): how a module composes another's screens
|
|
429
|
+
* (Projects renders the linked items of Git, Uptime...). `undefined` when
|
|
430
|
+
* that module is not installed: degrade, never assume.
|
|
431
|
+
*/
|
|
432
|
+
export function moduleClientProvider<T>(key: string): T | undefined;
|
|
433
|
+
/** The signed-in user, `null` before the session answers. */
|
|
434
|
+
export function useCurrentUser(): User | null;
|
|
435
|
+
/** Image inputs accepted by `fileToSquareDataUrl`. */
|
|
436
|
+
export const ACCEPTED_TYPES: readonly string[];
|
|
437
|
+
export const MAX_INPUT_BYTES: number;
|
|
438
|
+
/** A picked image, resized to a square data URL under `maxLength` characters; throws a readable message. */
|
|
439
|
+
export function fileToSquareDataUrl(
|
|
440
|
+
file: File,
|
|
441
|
+
opts: { size: number; maxLength: number }
|
|
442
|
+
): Promise<string>;
|
|
443
|
+
/**
|
|
444
|
+
* Open another feature of the active workspace, on one of its items when
|
|
445
|
+
* `itemId` is given (the item's presence segment is its bare id): the
|
|
446
|
+
* host's teleport, the same mechanism as "join someone". The access guard
|
|
447
|
+
* is the host's; a missing item is ignored after a short grace.
|
|
448
|
+
*/
|
|
449
|
+
export function openFeature(feature: string, itemId?: number): void;
|
|
450
|
+
/**
|
|
451
|
+
* Ask the feature popup for a wider frame (px) while the calling
|
|
452
|
+
* component is mounted, `null` to ask for nothing. Several requests
|
|
453
|
+
* coexist; the widest wins. For a view that outgrows the default width
|
|
454
|
+
* (a table explorer in expanded mode).
|
|
455
|
+
*/
|
|
456
|
+
export function useRequestPopupWidth(px: number | null): void;
|
|
250
457
|
|
|
251
458
|
// Change events re-exported for convenience in handlers.
|
|
252
459
|
export type InputChange = ChangeEvent<HTMLInputElement>;
|