@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,368 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
CREDENTIAL_LABEL_MAX_LENGTH,
|
|
4
|
+
CREDENTIAL_SECRET_MAX_LENGTH,
|
|
5
|
+
credentialSchema
|
|
6
|
+
} from '../domain/credential';
|
|
7
|
+
import {
|
|
8
|
+
GIT_REPO_NAME_MAX_LENGTH,
|
|
9
|
+
GIT_REPO_OWNER_MAX_LENGTH,
|
|
10
|
+
gitBranchSchema,
|
|
11
|
+
gitCommitAuthorSchema,
|
|
12
|
+
gitCommitDetailSchema,
|
|
13
|
+
gitCommitCursorSchema,
|
|
14
|
+
gitCommitPointsSchema,
|
|
15
|
+
gitCommitSchema,
|
|
16
|
+
gitRepoCandidateSchema,
|
|
17
|
+
gitProviderSchema,
|
|
18
|
+
gitPullRequestSchema,
|
|
19
|
+
gitReleaseSchema,
|
|
20
|
+
gitRepoSchema,
|
|
21
|
+
gitRepoSyncStateSchema,
|
|
22
|
+
gitRepoUsageSchema,
|
|
23
|
+
gitSyncStatusSchema
|
|
24
|
+
} from '../domain/git';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Commandes des dépôts git de l'espace.
|
|
28
|
+
*
|
|
29
|
+
* Préfixe unique `git.`, comme `project.` — d'où le camelCase derrière le point.
|
|
30
|
+
*
|
|
31
|
+
* ⚠️ Conséquence à connaître : le filet de démarrage (`MUTATION_VERB` dans
|
|
32
|
+
* `src/features/_topics.ts`) cherche un verbe **juste après le point**. Il ne
|
|
33
|
+
* verra donc **aucune** de ces commandes, et un `mutates` oublié ne produira
|
|
34
|
+
* aucun avertissement. Il se relit à la main.
|
|
35
|
+
*
|
|
36
|
+
* L'espace visé n'apparaît dans aucune entrée : il voyage sur l'enveloppe WS et
|
|
37
|
+
* le dispatcheur le résout, appartenance vérifiée, avant le handler.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
const repoId = z.number().int().positive();
|
|
41
|
+
const credentialId = z.number().int().positive();
|
|
42
|
+
|
|
43
|
+
// ------------------------------------------------------------- identifiants
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Les jetons **GitHub** de l'espace.
|
|
47
|
+
*
|
|
48
|
+
* Ils vivent ici et non dans les projets : un même jeton ouvre en général
|
|
49
|
+
* plusieurs dépôts. Les secrets n'en sortent jamais — la sortie ne porte qu'un
|
|
50
|
+
* `hasSecret`.
|
|
51
|
+
*
|
|
52
|
+
* Les clés **Dokploy** ne sont plus ici : elles ont leur propre feature
|
|
53
|
+
* (`deploy.credential*`). Elles n'avaient atterri dans cet écran que faute d'un
|
|
54
|
+
* module de déploiement pour les accueillir, et poser la clé qui met en
|
|
55
|
+
* production ne relève pas du droit de lire des dépôts. La table est restée
|
|
56
|
+
* commune ; c'est la porte, et le droit, qui se sont séparés.
|
|
57
|
+
*/
|
|
58
|
+
export const gitCredentialList = {
|
|
59
|
+
command: 'git.credentialList' as const,
|
|
60
|
+
input: z.object({}),
|
|
61
|
+
output: z.object({ credentials: z.array(credentialSchema) })
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Aucun `provider` ni `baseUrl` en entrée : GitHub, et son API publique. Le
|
|
66
|
+
* fournisseur se choisissait autrefois dans un sélecteur, parce que le même
|
|
67
|
+
* écran servait les deux — il n'y a plus rien à choisir ici.
|
|
68
|
+
*/
|
|
69
|
+
export const gitCredentialAdd = {
|
|
70
|
+
command: 'git.credentialAdd' as const,
|
|
71
|
+
input: z.object({
|
|
72
|
+
label: z.string().min(1).max(CREDENTIAL_LABEL_MAX_LENGTH),
|
|
73
|
+
secret: z.string().min(1).max(CREDENTIAL_SECRET_MAX_LENGTH)
|
|
74
|
+
}),
|
|
75
|
+
output: z.object({ credential: credentialSchema })
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Modifie un jeton. `secret` absent = on garde celui en place ; une chaîne non
|
|
80
|
+
* vide le remplace. Il n'y a pas de « vider » : un accès sans secret ne sert à
|
|
81
|
+
* rien, on retire le jeton entier.
|
|
82
|
+
*/
|
|
83
|
+
export const gitCredentialUpdate = {
|
|
84
|
+
command: 'git.credentialUpdate' as const,
|
|
85
|
+
input: z.object({
|
|
86
|
+
credentialId,
|
|
87
|
+
label: z.string().min(1).max(CREDENTIAL_LABEL_MAX_LENGTH),
|
|
88
|
+
secret: z.string().min(1).max(CREDENTIAL_SECRET_MAX_LENGTH).optional()
|
|
89
|
+
}),
|
|
90
|
+
output: z.object({ credential: credentialSchema })
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Retire un jeton.
|
|
95
|
+
*
|
|
96
|
+
* Les dépôts qui s'en servaient gardent leur lien mais perdent leur accès
|
|
97
|
+
* (`ON DELETE SET NULL`) : la synchronisation s'arrête proprement et le dit, au
|
|
98
|
+
* lieu de disparaître avec le jeton.
|
|
99
|
+
*/
|
|
100
|
+
export const gitCredentialRemove = {
|
|
101
|
+
command: 'git.credentialRemove' as const,
|
|
102
|
+
input: z.object({ credentialId }),
|
|
103
|
+
output: z.object({ credentialId })
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// -------------------------------------------------------------------- dépôts
|
|
107
|
+
|
|
108
|
+
/** Le nombre de dépôts de l'espace, pour la tuile de l'accueil. */
|
|
109
|
+
export const gitCount = {
|
|
110
|
+
command: 'git.count' as const,
|
|
111
|
+
input: z.object({}),
|
|
112
|
+
output: z.object({ count: z.number().int().nonnegative() })
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const gitRepoList = {
|
|
116
|
+
command: 'git.repoList' as const,
|
|
117
|
+
input: z.object({}),
|
|
118
|
+
output: z.object({ repos: z.array(gitRepoSchema) })
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/** Un dépôt, avec les projets qui s'en servent — tout doit être cliquable. */
|
|
122
|
+
export const gitRepoGet = {
|
|
123
|
+
command: 'git.repoGet' as const,
|
|
124
|
+
input: z.object({ repoId }),
|
|
125
|
+
output: z.object({ repo: gitRepoSchema, usage: z.array(gitRepoUsageSchema) })
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Ajoute un dépôt à l'espace.
|
|
130
|
+
*
|
|
131
|
+
* **Idempotente** : le même `owner/repo` déjà présent rend la ligne existante
|
|
132
|
+
* (avec son jeton mis à jour) au lieu d'un doublon. C'est ce qui permet à un
|
|
133
|
+
* projet de « créer » un dépôt sans savoir s'il existe déjà ailleurs, et
|
|
134
|
+
* garantit qu'un dépôt n'est jamais synchronisé deux fois.
|
|
135
|
+
*/
|
|
136
|
+
export const gitRepoAdd = {
|
|
137
|
+
command: 'git.repoAdd' as const,
|
|
138
|
+
input: z.object({
|
|
139
|
+
provider: gitProviderSchema,
|
|
140
|
+
owner: z.string().min(1).max(GIT_REPO_OWNER_MAX_LENGTH),
|
|
141
|
+
repo: z.string().min(1).max(GIT_REPO_NAME_MAX_LENGTH),
|
|
142
|
+
credentialId: credentialId.nullable()
|
|
143
|
+
}),
|
|
144
|
+
output: z.object({ repo: gitRepoSchema })
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Les dépôts d'un propriétaire ou d'une organisation, chez le fournisseur.
|
|
149
|
+
*
|
|
150
|
+
* Interroge GitHub **au moment de la demande** — c'est, avec le diff d'un
|
|
151
|
+
* commit, la seule commande du module dans ce cas. La liste dépend du jeton
|
|
152
|
+
* choisi (un jeton donne accès aux dépôts privés, l'absence de jeton n'ouvre que
|
|
153
|
+
* le public), d'où le `credentialId` en entrée : changer de jeton change le
|
|
154
|
+
* résultat, et l'interface doit pouvoir le re-demander.
|
|
155
|
+
*/
|
|
156
|
+
export const gitRepoCandidates = {
|
|
157
|
+
command: 'git.repoCandidates' as const,
|
|
158
|
+
input: z.object({
|
|
159
|
+
owner: z.string().min(1).max(GIT_REPO_OWNER_MAX_LENGTH),
|
|
160
|
+
credentialId: credentialId.nullable()
|
|
161
|
+
}),
|
|
162
|
+
output: z.object({ repos: z.array(gitRepoCandidateSchema) })
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Range les dépôts de l'espace : `ids` est la liste **complète** dans son ordre
|
|
167
|
+
* final (rang le plus faible en tête).
|
|
168
|
+
*
|
|
169
|
+
* Rien d'autre ne positionne un dépôt — un nouveau prend le rang suivant, donc
|
|
170
|
+
* la fin de la liste — de sorte que l'ordre appartient entièrement à
|
|
171
|
+
* l'utilisateur, comme celui des services surveillés et des notes. Ne touche ni
|
|
172
|
+
* au cache ni à l'état de synchronisation : ranger n'est pas configurer.
|
|
173
|
+
*/
|
|
174
|
+
export const gitRepoReorder = {
|
|
175
|
+
command: 'git.repoReorder' as const,
|
|
176
|
+
input: z.object({ ids: z.array(repoId).min(1) }),
|
|
177
|
+
output: z.object({ ids: z.array(repoId) })
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/** Change le jeton d'un dépôt, ou suspend sa synchronisation. */
|
|
181
|
+
export const gitRepoUpdate = {
|
|
182
|
+
command: 'git.repoUpdate' as const,
|
|
183
|
+
input: z.object({ repoId, credentialId: credentialId.nullable(), enabled: z.boolean() }),
|
|
184
|
+
output: z.object({ repo: gitRepoSchema })
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Supprime un dépôt de l'espace, avec son cache et toutes ses liaisons.
|
|
189
|
+
*
|
|
190
|
+
* Les projets liés ne sont **pas** touchés : ils perdent leur dépôt, rien
|
|
191
|
+
* d'autre. Le dépôt chez le fournisseur, lui, n'est évidemment jamais atteint.
|
|
192
|
+
*/
|
|
193
|
+
export const gitRepoRemove = {
|
|
194
|
+
command: 'git.repoRemove' as const,
|
|
195
|
+
input: z.object({ repoId }),
|
|
196
|
+
output: z.object({ repoId })
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Force une synchronisation immédiate, sans attendre le tour de
|
|
201
|
+
* l'ordonnanceur. N'écrit rien elle-même : elle réveille le service de fond.
|
|
202
|
+
*/
|
|
203
|
+
export const gitRepoSyncNow = {
|
|
204
|
+
command: 'git.repoSyncNow' as const,
|
|
205
|
+
input: z.object({ repoId }),
|
|
206
|
+
output: z.object({ repo: gitRepoSchema })
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Jette le cache local du dépôt et repart de zéro.
|
|
211
|
+
*
|
|
212
|
+
* À distinguer de `gitRepoSyncNow`, qui reprend là où le service s'était
|
|
213
|
+
* arrêté : ici on efface commits, branches, releases et pull requests, ainsi que
|
|
214
|
+
* les ETags et le drapeau de backfill, de sorte que le tour suivant relise
|
|
215
|
+
* **tout** l'historique depuis le fournisseur.
|
|
216
|
+
*
|
|
217
|
+
* Deux choses survivent, et ce n'est pas un oubli :
|
|
218
|
+
*
|
|
219
|
+
* - le **rattachement des auteurs** à des membres de l'espace, qui est du
|
|
220
|
+
* travail fait à la main et que rien ne permettrait de reconstituer ;
|
|
221
|
+
* - les **liaisons aux projets**, qui ne relèvent pas du cache.
|
|
222
|
+
*
|
|
223
|
+
* N'écrit rien elle-même côté fournisseur : elle vide, puis réveille
|
|
224
|
+
* l'ordonnanceur.
|
|
225
|
+
*/
|
|
226
|
+
export const gitRepoResync = {
|
|
227
|
+
command: 'git.repoResync' as const,
|
|
228
|
+
input: z.object({ repoId }),
|
|
229
|
+
output: z.object({ repo: gitRepoSchema })
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* L'avancement de la synchronisation d'un dépôt.
|
|
234
|
+
*
|
|
235
|
+
* Lecture pure et **très bon marché** : elle n'interroge qu'une table en
|
|
236
|
+
* mémoire du service de fond. C'est ce qui la rend sondable pendant qu'une
|
|
237
|
+
* synchronisation tourne, sans passer par une diffusion `live` qui ferait
|
|
238
|
+
* re-solliciter tout l'écran à chaque étape, chez tous les membres.
|
|
239
|
+
*/
|
|
240
|
+
export const gitRepoSyncStatus = {
|
|
241
|
+
command: 'git.repoSyncStatus' as const,
|
|
242
|
+
input: z.object({ repoId }),
|
|
243
|
+
output: z.object({ status: gitSyncStatusSchema })
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Les synchronisations en cours dans l'espace, toutes d'un coup.
|
|
248
|
+
*
|
|
249
|
+
* **Aucune requête, aucun déchiffrement** : le service tient l'avancement en
|
|
250
|
+
* mémoire le temps d'un tour. C'est ce qui rend la liste des dépôts sondable à
|
|
251
|
+
* la seconde pour y animer une bande de progression, sans que cela coûte quoi
|
|
252
|
+
* que ce soit — même parti pris que la barre d'une synchro mail.
|
|
253
|
+
*
|
|
254
|
+
* Un dépôt absent de la réponse ne synchronise pas : il n'y a pas d'entrée
|
|
255
|
+
* « au repos », seulement celles qui tournent.
|
|
256
|
+
*/
|
|
257
|
+
export const gitSyncStatuses = {
|
|
258
|
+
command: 'git.syncStatuses' as const,
|
|
259
|
+
input: z.object({}),
|
|
260
|
+
output: z.object({ statuses: z.array(gitRepoSyncStateSchema) })
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// ------------------------------------------------------------------- lecture
|
|
264
|
+
|
|
265
|
+
export const gitBranchList = {
|
|
266
|
+
command: 'git.branchList' as const,
|
|
267
|
+
input: z.object({ repoId }),
|
|
268
|
+
output: z.object({ branches: z.array(gitBranchSchema) })
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Les derniers commits, en clair, pour la liste (pas pour le graphe).
|
|
273
|
+
*
|
|
274
|
+
* Pagination par **curseur** `(committedAt, id)` et non par identifiant seul :
|
|
275
|
+
* voir `gitCommitCursorSchema`. La page suivante se demande avec le couple porté
|
|
276
|
+
* par le dernier commit reçu.
|
|
277
|
+
*/
|
|
278
|
+
export const gitCommitList = {
|
|
279
|
+
command: 'git.commitList' as const,
|
|
280
|
+
input: z.object({
|
|
281
|
+
repoId,
|
|
282
|
+
before: gitCommitCursorSchema.optional(),
|
|
283
|
+
limit: z.number().int().positive().max(200).optional()
|
|
284
|
+
}),
|
|
285
|
+
output: z.object({ commits: z.array(gitCommitSchema), hasMore: z.boolean() })
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Le graphe : un point par commit, du premier au dernier, avec la liste des
|
|
290
|
+
* auteurs et leur couleur.
|
|
291
|
+
*
|
|
292
|
+
* Les points ne portent **pas** les messages — un graphe en affiche des
|
|
293
|
+
* milliers, et les déchiffrer tous pour dessiner des ronds serait absurde.
|
|
294
|
+
*/
|
|
295
|
+
export const gitCommitGraph = {
|
|
296
|
+
command: 'git.commitGraph' as const,
|
|
297
|
+
input: z.object({ repoId }),
|
|
298
|
+
output: z.object({
|
|
299
|
+
points: gitCommitPointsSchema,
|
|
300
|
+
authors: z.array(gitCommitAuthorSchema),
|
|
301
|
+
/** Bornes réelles de l'historique, même si les points sont écrêtés. */
|
|
302
|
+
firstCommitAt: z.number().int().nullable(),
|
|
303
|
+
lastCommitAt: z.number().int().nullable(),
|
|
304
|
+
total: z.number().int().nonnegative()
|
|
305
|
+
})
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
/** Rattache un auteur git à un membre de l'espace (ou l'en détache). */
|
|
309
|
+
export const gitAuthorMap = {
|
|
310
|
+
command: 'git.authorMap' as const,
|
|
311
|
+
input: z.object({
|
|
312
|
+
repoId,
|
|
313
|
+
authorRef: z.string().min(1).max(32),
|
|
314
|
+
userId: z.number().int().positive().nullable()
|
|
315
|
+
}),
|
|
316
|
+
output: z.object({ authorRef: z.string(), userId: z.number().int().positive().nullable() })
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
export const gitReleaseList = {
|
|
320
|
+
command: 'git.releaseList' as const,
|
|
321
|
+
input: z.object({ repoId }),
|
|
322
|
+
output: z.object({ releases: z.array(gitReleaseSchema) })
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
export const gitPullRequestList = {
|
|
326
|
+
command: 'git.pullRequestList' as const,
|
|
327
|
+
input: z.object({ repoId }),
|
|
328
|
+
output: z.object({ pullRequests: z.array(gitPullRequestSchema) })
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Le diff d'un commit, lu **chez le fournisseur au moment de la demande**.
|
|
333
|
+
*
|
|
334
|
+
* La seule commande du module qui sorte du cache local : voir
|
|
335
|
+
* `gitCommitDetailSchema` pour la raison. Elle est donc aussi la seule dont la
|
|
336
|
+
* latence dépend d'une API tierce — l'interface doit l'annoncer.
|
|
337
|
+
*/
|
|
338
|
+
export const gitCommitDetail = {
|
|
339
|
+
command: 'git.commitDetail' as const,
|
|
340
|
+
input: z.object({ repoId, sha: z.string().min(7).max(40) }),
|
|
341
|
+
output: z.object({ detail: gitCommitDetailSchema })
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
export const gitCommands = [
|
|
345
|
+
gitCredentialList,
|
|
346
|
+
gitCredentialAdd,
|
|
347
|
+
gitCredentialUpdate,
|
|
348
|
+
gitCredentialRemove,
|
|
349
|
+
gitCount,
|
|
350
|
+
gitRepoList,
|
|
351
|
+
gitRepoGet,
|
|
352
|
+
gitRepoAdd,
|
|
353
|
+
gitRepoCandidates,
|
|
354
|
+
gitRepoReorder,
|
|
355
|
+
gitRepoUpdate,
|
|
356
|
+
gitRepoRemove,
|
|
357
|
+
gitRepoResync,
|
|
358
|
+
gitRepoSyncNow,
|
|
359
|
+
gitRepoSyncStatus,
|
|
360
|
+
gitSyncStatuses,
|
|
361
|
+
gitBranchList,
|
|
362
|
+
gitCommitList,
|
|
363
|
+
gitCommitGraph,
|
|
364
|
+
gitAuthorMap,
|
|
365
|
+
gitReleaseList,
|
|
366
|
+
gitPullRequestList,
|
|
367
|
+
gitCommitDetail
|
|
368
|
+
] as const;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
homeLayoutSchema,
|
|
4
|
+
shortcutPreviewSchema,
|
|
5
|
+
shortcutTemplateSchema,
|
|
6
|
+
SHORTCUT_URL_MAX_LENGTH
|
|
7
|
+
} from '../domain/home';
|
|
8
|
+
|
|
9
|
+
/** Persist the user's home grid layout (tiles + order). */
|
|
10
|
+
export const homeSetLayout = {
|
|
11
|
+
command: 'home.setLayout' as const,
|
|
12
|
+
input: homeLayoutSchema,
|
|
13
|
+
output: z.object({ ok: z.literal(true) })
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Fetch a live preview for a rich shortcut template (e.g. a GitHub profile).
|
|
18
|
+
* Server-side fetch + cache so the client avoids CORS / rate-limit handling and
|
|
19
|
+
* the whole app stays "one typed WS command per action".
|
|
20
|
+
*/
|
|
21
|
+
export const homeShortcutPreview = {
|
|
22
|
+
command: 'home.shortcutPreview' as const,
|
|
23
|
+
input: z.object({
|
|
24
|
+
template: shortcutTemplateSchema,
|
|
25
|
+
url: z.string().url().max(SHORTCUT_URL_MAX_LENGTH),
|
|
26
|
+
/** Bypass the server cache and re-fetch (Ctrl/Cmd-click on the tile). */
|
|
27
|
+
refresh: z.boolean().optional()
|
|
28
|
+
}),
|
|
29
|
+
output: shortcutPreviewSchema
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const homeCommands = [homeSetLayout, homeShortcutPreview] as const;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { liveCursorSchema, livePathSchema, livePeerSchema, liveTopicSchema } from '../domain/live';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Déclare où je suis, et récupère l'état de la salle.
|
|
6
|
+
*
|
|
7
|
+
* L'espace **n'est pas dans l'entrée** : il voyage sur l'enveloppe comme toute
|
|
8
|
+
* commande, donc il est résolu et son appartenance vérifiée par le dispatcheur
|
|
9
|
+
* avant que le handler ne s'exécute. L'entrée en salle est ainsi autorisée
|
|
10
|
+
* gratuitement, par le même chemin que tout le reste.
|
|
11
|
+
*
|
|
12
|
+
* La réponse porte l'instantané de la salle — même motif que
|
|
13
|
+
* `cloudSync.subscribe` : aucun trou entre l'inscription et la première
|
|
14
|
+
* diffusion, et une reconnexion se resynchronise par ce seul appel.
|
|
15
|
+
*/
|
|
16
|
+
export const liveHere = {
|
|
17
|
+
command: 'live.here' as const,
|
|
18
|
+
input: z.object({ path: livePathSchema }),
|
|
19
|
+
output: z.object({ peers: z.array(livePeerSchema) })
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const liveCommands = [liveHere] as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Les positions de curseur, **hors du registre des commandes**.
|
|
26
|
+
*
|
|
27
|
+
* Délibérément absente de `featureCommandRegistry` : `ws.send` y trouverait un
|
|
28
|
+
* descripteur, ouvrirait une promesse en attente et armerait un délai de 15 s —
|
|
29
|
+
* pour une trame émise vingt fois par seconde dont on n'attend aucune réponse.
|
|
30
|
+
* Le client la poste par `ws.post`, le serveur la traite sur une voie rapide
|
|
31
|
+
* avant la recherche de commande.
|
|
32
|
+
*/
|
|
33
|
+
export const LIVE_CURSOR_COMMAND = 'live.cursor' as const;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Ce que porte une trame de curseur : des coordonnées, et rien d'autre.
|
|
37
|
+
*
|
|
38
|
+
* Ni chemin ni espace : la voie rapide court-circuite la résolution
|
|
39
|
+
* d'autorisation, elle ne peut donc rien accepter du client qui déciderait de
|
|
40
|
+
* *qui verra* la trame. Le lieu vient du dernier `live.here`, lui passé par le
|
|
41
|
+
* dispatcheur. `cursor: null` = le pointeur a quitté la surface.
|
|
42
|
+
*/
|
|
43
|
+
export const liveCursorFrameSchema = z.object({ cursor: liveCursorSchema.nullable() });
|
|
44
|
+
export type LiveCursorFrame = z.infer<typeof liveCursorFrameSchema>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* « Untel est en train d'écrire… », sur la même voie rapide que les curseurs.
|
|
48
|
+
*
|
|
49
|
+
* Hors du registre des commandes, pour exactement la même raison : c'est une
|
|
50
|
+
* trame sans réponse, émise par `ws.post`, qu'il serait absurde de faire passer
|
|
51
|
+
* par une promesse en attente, un journal d'audit et une validation d'accès.
|
|
52
|
+
*
|
|
53
|
+
* Volontairement **générique** : la trame ne dit pas *quoi* est en train d'être
|
|
54
|
+
* écrit. Le lieu vient du dernier `live.here`, comme pour les curseurs, donc
|
|
55
|
+
* n'importe quelle feature peut s'en servir sans toucher au moteur — un fil de
|
|
56
|
+
* discussion de projet aujourd'hui, une note à plusieurs demain.
|
|
57
|
+
*
|
|
58
|
+
* Le serveur applique une péremption : sans rafraîchissement, un pair cesse
|
|
59
|
+
* d'être « en train d'écrire » tout seul. C'est ce qui empêche un onglet fermé
|
|
60
|
+
* brutalement de laisser un fantôme à l'écran.
|
|
61
|
+
*/
|
|
62
|
+
export const LIVE_TYPING_COMMAND = 'live.typing' as const;
|
|
63
|
+
export const liveTypingFrameSchema = z.object({ typing: z.boolean() });
|
|
64
|
+
export type LiveTypingFrame = z.infer<typeof liveTypingFrameSchema>;
|
|
65
|
+
|
|
66
|
+
/** Qui écrit, parmi les pairs situés au **même chemin exactement**. */
|
|
67
|
+
export const LIVE_TYPERS_EVENT = 'live.typers' as const;
|
|
68
|
+
export const liveTypersPushSchema = z.object({
|
|
69
|
+
workspaceId: z.number().int().positive(),
|
|
70
|
+
typers: z.array(
|
|
71
|
+
z.object({
|
|
72
|
+
connId: z.string().min(1),
|
|
73
|
+
userId: z.number().int().positive()
|
|
74
|
+
})
|
|
75
|
+
)
|
|
76
|
+
});
|
|
77
|
+
export type LiveTypersPush = z.infer<typeof liveTypersPushSchema>;
|
|
78
|
+
|
|
79
|
+
/** Roster de la salle. Projeté par destinataire : les chemins y sont tronqués. */
|
|
80
|
+
export const LIVE_PEERS_EVENT = 'live.peers' as const;
|
|
81
|
+
export const livePeersPushSchema = z.object({
|
|
82
|
+
workspaceId: z.number().int().positive(),
|
|
83
|
+
peers: z.array(livePeerSchema)
|
|
84
|
+
});
|
|
85
|
+
export type LivePeersPush = z.infer<typeof livePeersPushSchema>;
|
|
86
|
+
|
|
87
|
+
/** Curseurs des pairs situés au **même chemin exactement** que le destinataire. */
|
|
88
|
+
export const LIVE_CURSORS_EVENT = 'live.cursors' as const;
|
|
89
|
+
export const liveCursorsPushSchema = z.object({
|
|
90
|
+
workspaceId: z.number().int().positive(),
|
|
91
|
+
cursors: z.array(
|
|
92
|
+
z.object({
|
|
93
|
+
connId: z.string().min(1),
|
|
94
|
+
userId: z.number().int().positive(),
|
|
95
|
+
cursor: liveCursorSchema
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
});
|
|
99
|
+
export type LiveCursorsPush = z.infer<typeof liveCursorsPushSchema>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Quelque chose a changé dans l'espace : les vues qui en dépendent
|
|
103
|
+
* re-sollicitent. Émis par le dispatcheur après toute commande déclarant
|
|
104
|
+
* `mutates`, et par les tâches de fond qui écrivent sans commande.
|
|
105
|
+
*/
|
|
106
|
+
export const LIVE_CHANGED_EVENT = 'live.changed' as const;
|
|
107
|
+
export const liveChangedPushSchema = z.object({
|
|
108
|
+
workspaceId: z.number().int().positive(),
|
|
109
|
+
topics: z.array(liveTopicSchema).min(1),
|
|
110
|
+
/** L'auteur, ou `null` pour une tâche de fond. Jamais renvoyé à lui-même. */
|
|
111
|
+
by: z.number().int().positive().nullable()
|
|
112
|
+
});
|
|
113
|
+
export type LiveChangedPush = z.infer<typeof liveChangedPushSchema>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { logEntrySchema, logSourceSchema } from '../domain/logs';
|
|
3
|
+
|
|
4
|
+
/** Upper bound on a single page of results (the server clamps to this). */
|
|
5
|
+
export const LOGS_PAGE_MAX = 200;
|
|
6
|
+
export const LOGS_PAGE_DEFAULT = 50;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The shared filter surface for the logs feature. Every field is optional and
|
|
10
|
+
* combines with the others as AND, so the UI can drill down precisely:
|
|
11
|
+
* by user, origin channel, feature, exact action, importance floor, free text,
|
|
12
|
+
* client IP and a date window. All omitted → the unfiltered, newest-first feed.
|
|
13
|
+
*/
|
|
14
|
+
export const logFilterSchema = z.object({
|
|
15
|
+
/** Restrict to one acting user (0 = system events). */
|
|
16
|
+
uid: z.number().int().nonnegative().optional(),
|
|
17
|
+
/** Restrict to one origin channel (web / api / agent / system). */
|
|
18
|
+
source: logSourceSchema.optional(),
|
|
19
|
+
/** Restrict to one emitting feature/subsystem. */
|
|
20
|
+
category: z.string().min(1).max(64).optional(),
|
|
21
|
+
/** Restrict to one exact event key (e.g. `login.failed`). */
|
|
22
|
+
action: z.string().min(1).max(64).optional(),
|
|
23
|
+
/** Importance floor (inclusive): only entries with `level >= levelMin`. */
|
|
24
|
+
levelMin: z.number().int().optional(),
|
|
25
|
+
/** Free-text match against description / action / ip (case-insensitive). */
|
|
26
|
+
search: z.string().max(200).optional(),
|
|
27
|
+
/** Exact client IP. */
|
|
28
|
+
ip: z.string().max(64).optional(),
|
|
29
|
+
/** Window start, unix epoch seconds, inclusive. */
|
|
30
|
+
dateFrom: z.number().int().nonnegative().optional(),
|
|
31
|
+
/** Window end, unix epoch seconds, inclusive. */
|
|
32
|
+
dateTo: z.number().int().nonnegative().optional()
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export type LogFilter = z.infer<typeof logFilterSchema>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Page through log entries newest-first, applying the filter. Admin-only.
|
|
39
|
+
* `total` is the count matching the filter (ignoring paging) so the UI can show
|
|
40
|
+
* "x / total"; `hasMore` says whether another page exists past this one.
|
|
41
|
+
*/
|
|
42
|
+
export const logsList = {
|
|
43
|
+
command: 'logs.list' as const,
|
|
44
|
+
input: logFilterSchema.extend({
|
|
45
|
+
limit: z.number().int().positive().max(LOGS_PAGE_MAX).optional(),
|
|
46
|
+
offset: z.number().int().nonnegative().optional()
|
|
47
|
+
}),
|
|
48
|
+
output: z.object({
|
|
49
|
+
logs: z.array(logEntrySchema),
|
|
50
|
+
total: z.number().int().nonnegative(),
|
|
51
|
+
hasMore: z.boolean()
|
|
52
|
+
})
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** One distinct value present in the logs, with how many entries carry it. */
|
|
56
|
+
export const logsFacetSchema = z.object({
|
|
57
|
+
value: z.string(),
|
|
58
|
+
count: z.number().int().nonnegative()
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** A user that appears in the logs, with a display name and entry count. */
|
|
62
|
+
export const logsFacetUserSchema = z.object({
|
|
63
|
+
uid: z.number().int().nonnegative(),
|
|
64
|
+
username: z.string().nullable(),
|
|
65
|
+
count: z.number().int().nonnegative()
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Distinct filter values actually present in the logs (users, categories,
|
|
70
|
+
* sources, actions) with counts, so the client can offer data-driven filter
|
|
71
|
+
* controls — naming users instead of bare ids — rather than a hard-coded list.
|
|
72
|
+
* Admin-only.
|
|
73
|
+
*/
|
|
74
|
+
export const logsFacets = {
|
|
75
|
+
command: 'logs.facets' as const,
|
|
76
|
+
input: z.object({}),
|
|
77
|
+
output: z.object({
|
|
78
|
+
users: z.array(logsFacetUserSchema),
|
|
79
|
+
categories: z.array(logsFacetSchema),
|
|
80
|
+
sources: z.array(logsFacetSchema),
|
|
81
|
+
actions: z.array(logsFacetSchema),
|
|
82
|
+
total: z.number().int().nonnegative()
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const logsCommands = [logsList, logsFacets] as const;
|