docker-client-mx 1.35.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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -0
  3. package/bin/docker-client-mx.js +42 -0
  4. package/build/icons/icon-1024.png +0 -0
  5. package/build/icons/icon-128.png +0 -0
  6. package/build/icons/icon-16.png +0 -0
  7. package/build/icons/icon-256.png +0 -0
  8. package/build/icons/icon-32.png +0 -0
  9. package/build/icons/icon-48.png +0 -0
  10. package/build/icons/icon-512.png +0 -0
  11. package/build/icons/icon-64.png +0 -0
  12. package/build/icons/icon.ico +0 -0
  13. package/build/icons/icon.iconset/icon_128x128.png +0 -0
  14. package/build/icons/icon.iconset/icon_128x128@2x.png +0 -0
  15. package/build/icons/icon.iconset/icon_16x16.png +0 -0
  16. package/build/icons/icon.iconset/icon_16x16@2x.png +0 -0
  17. package/build/icons/icon.iconset/icon_256x256.png +0 -0
  18. package/build/icons/icon.iconset/icon_256x256@2x.png +0 -0
  19. package/build/icons/icon.iconset/icon_32x32.png +0 -0
  20. package/build/icons/icon.iconset/icon_32x32@2x.png +0 -0
  21. package/build/icons/icon.iconset/icon_512x512.png +0 -0
  22. package/build/icons/icon.iconset/icon_512x512@2x.png +0 -0
  23. package/build/icons/icon.png +0 -0
  24. package/dist/docker-desktop-mx/browser/chunk-64WWLMUP.js +39 -0
  25. package/dist/docker-desktop-mx/browser/chunk-N4VBBC4W.js +1 -0
  26. package/dist/docker-desktop-mx/browser/favicon.ico +0 -0
  27. package/dist/docker-desktop-mx/browser/index.html +14 -0
  28. package/dist/docker-desktop-mx/browser/main-CTIRTSOI.js +5 -0
  29. package/dist/docker-desktop-mx/browser/styles-JS3HDDI4.css +1 -0
  30. package/dist-electron/api.js +10 -0
  31. package/dist-electron/api.js.map +1 -0
  32. package/dist-electron/assistant-key.js +70 -0
  33. package/dist-electron/assistant-key.js.map +1 -0
  34. package/dist-electron/assistant-models.js +19 -0
  35. package/dist-electron/assistant-models.js.map +1 -0
  36. package/dist-electron/assistant-tools.js +335 -0
  37. package/dist-electron/assistant-tools.js.map +1 -0
  38. package/dist-electron/assistant.js +302 -0
  39. package/dist-electron/assistant.js.map +1 -0
  40. package/dist-electron/attention.js +75 -0
  41. package/dist-electron/attention.js.map +1 -0
  42. package/dist-electron/channels.js +113 -0
  43. package/dist-electron/channels.js.map +1 -0
  44. package/dist-electron/compose-files.js +104 -0
  45. package/dist-electron/compose-files.js.map +1 -0
  46. package/dist-electron/compose.js +271 -0
  47. package/dist-electron/compose.js.map +1 -0
  48. package/dist-electron/container-events.js +188 -0
  49. package/dist-electron/container-events.js.map +1 -0
  50. package/dist-electron/containers.js +165 -0
  51. package/dist-electron/containers.js.map +1 -0
  52. package/dist-electron/context-menu.js +56 -0
  53. package/dist-electron/context-menu.js.map +1 -0
  54. package/dist-electron/contexts.js +346 -0
  55. package/dist-electron/contexts.js.map +1 -0
  56. package/dist-electron/crash.js +129 -0
  57. package/dist-electron/crash.js.map +1 -0
  58. package/dist-electron/diagnosis.js +338 -0
  59. package/dist-electron/diagnosis.js.map +1 -0
  60. package/dist-electron/docker-client.js +284 -0
  61. package/dist-electron/docker-client.js.map +1 -0
  62. package/dist-electron/engine.js +145 -0
  63. package/dist-electron/engine.js.map +1 -0
  64. package/dist-electron/event-store.js +146 -0
  65. package/dist-electron/event-store.js.map +1 -0
  66. package/dist-electron/events.js +132 -0
  67. package/dist-electron/events.js.map +1 -0
  68. package/dist-electron/exec.js +138 -0
  69. package/dist-electron/exec.js.map +1 -0
  70. package/dist-electron/files.js +407 -0
  71. package/dist-electron/files.js.map +1 -0
  72. package/dist-electron/health.js +92 -0
  73. package/dist-electron/health.js.map +1 -0
  74. package/dist-electron/host-overview.js +50 -0
  75. package/dist-electron/host-overview.js.map +1 -0
  76. package/dist-electron/host-shell.js +196 -0
  77. package/dist-electron/host-shell.js.map +1 -0
  78. package/dist-electron/i18n.js +58 -0
  79. package/dist-electron/i18n.js.map +1 -0
  80. package/dist-electron/image-history.js +87 -0
  81. package/dist-electron/image-history.js.map +1 -0
  82. package/dist-electron/images.js +141 -0
  83. package/dist-electron/images.js.map +1 -0
  84. package/dist-electron/ipc.js +783 -0
  85. package/dist-electron/ipc.js.map +1 -0
  86. package/dist-electron/links.js +46 -0
  87. package/dist-electron/links.js.map +1 -0
  88. package/dist-electron/logs.js +153 -0
  89. package/dist-electron/logs.js.map +1 -0
  90. package/dist-electron/main.js +494 -0
  91. package/dist-electron/main.js.map +1 -0
  92. package/dist-electron/merged-logs.js +127 -0
  93. package/dist-electron/merged-logs.js.map +1 -0
  94. package/dist-electron/navigation.js +37 -0
  95. package/dist-electron/navigation.js.map +1 -0
  96. package/dist-electron/ndjson.js +30 -0
  97. package/dist-electron/ndjson.js.map +1 -0
  98. package/dist-electron/networks.js +507 -0
  99. package/dist-electron/networks.js.map +1 -0
  100. package/dist-electron/port-conflicts.js +106 -0
  101. package/dist-electron/port-conflicts.js.map +1 -0
  102. package/dist-electron/preload.js +257 -0
  103. package/dist-electron/preload.js.map +1 -0
  104. package/dist-electron/pull.js +220 -0
  105. package/dist-electron/pull.js.map +1 -0
  106. package/dist-electron/redact.js +129 -0
  107. package/dist-electron/redact.js.map +1 -0
  108. package/dist-electron/registry-auth.js +150 -0
  109. package/dist-electron/registry-auth.js.map +1 -0
  110. package/dist-electron/renew.js +162 -0
  111. package/dist-electron/renew.js.map +1 -0
  112. package/dist-electron/restart-policy.js +58 -0
  113. package/dist-electron/restart-policy.js.map +1 -0
  114. package/dist-electron/run-command.js +146 -0
  115. package/dist-electron/run-command.js.map +1 -0
  116. package/dist-electron/run.js +151 -0
  117. package/dist-electron/run.js.map +1 -0
  118. package/dist-electron/self-update.js +163 -0
  119. package/dist-electron/self-update.js.map +1 -0
  120. package/dist-electron/servers.js +108 -0
  121. package/dist-electron/servers.js.map +1 -0
  122. package/dist-electron/settings.js +146 -0
  123. package/dist-electron/settings.js.map +1 -0
  124. package/dist-electron/ssh.js +574 -0
  125. package/dist-electron/ssh.js.map +1 -0
  126. package/dist-electron/stats.js +209 -0
  127. package/dist-electron/stats.js.map +1 -0
  128. package/dist-electron/streams.js +63 -0
  129. package/dist-electron/streams.js.map +1 -0
  130. package/dist-electron/system.js +123 -0
  131. package/dist-electron/system.js.map +1 -0
  132. package/dist-electron/terminal-transcript.js +55 -0
  133. package/dist-electron/terminal-transcript.js.map +1 -0
  134. package/dist-electron/updates.js +136 -0
  135. package/dist-electron/updates.js.map +1 -0
  136. package/dist-electron/volume-backup.js +203 -0
  137. package/dist-electron/volume-backup.js.map +1 -0
  138. package/dist-electron/volume-files.js +124 -0
  139. package/dist-electron/volume-files.js.map +1 -0
  140. package/dist-electron/volumes.js +253 -0
  141. package/dist-electron/volumes.js.map +1 -0
  142. package/dist-electron/wiring-watch.js +93 -0
  143. package/dist-electron/wiring-watch.js.map +1 -0
  144. package/dist-electron/wiring.js +71 -0
  145. package/dist-electron/wiring.js.map +1 -0
  146. package/dist-electron/wsl.js +167 -0
  147. package/dist-electron/wsl.js.map +1 -0
  148. package/package.json +125 -0
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.splitConfigFiles = splitConfigFiles;
4
+ exports.resolveProjectLocation = resolveProjectLocation;
5
+ exports.readComposeStatus = readComposeStatus;
6
+ exports.resetComposeStatus = resetComposeStatus;
7
+ exports.stripWslNoise = stripWslNoise;
8
+ exports.projectArgs = projectArgs;
9
+ exports.buildComposeArgs = buildComposeArgs;
10
+ exports.buildRecreateArgs = buildRecreateArgs;
11
+ exports.buildRenewArgs = buildRenewArgs;
12
+ exports.composeInvocation = composeInvocation;
13
+ exports.windowsPathOf = windowsPathOf;
14
+ exports.runComposeCapture = runComposeCapture;
15
+ exports.runCompose = runCompose;
16
+ exports.runComposeCommand = runComposeCommand;
17
+ exports.recreateService = recreateService;
18
+ const node_child_process_1 = require("node:child_process");
19
+ const node_fs_1 = require("node:fs");
20
+ const node_util_1 = require("node:util");
21
+ const docker_client_1 = require("./docker-client");
22
+ const wsl_1 = require("./wsl");
23
+ const i18n_1 = require("./i18n");
24
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
25
+ const COMPOSE_PROJECT = 'com.docker.compose.project';
26
+ const COMPOSE_WORKING_DIR = 'com.docker.compose.project.working_dir';
27
+ const COMPOSE_CONFIG_FILES = 'com.docker.compose.project.config_files';
28
+ /** Een `up` mag images ophalen of bouwen, en dat duurt soms minuten. */
29
+ const UP_TIMEOUT_MS = 10 * 60 * 1000;
30
+ const VERSION_TIMEOUT_MS = 10 * 1000;
31
+ /** Meerdere compose-bestanden staan in één label, gescheiden door komma's. */
32
+ function splitConfigFiles(label) {
33
+ return (label ?? '')
34
+ .split(',')
35
+ .map((file) => file.trim())
36
+ .filter((file) => file !== '');
37
+ }
38
+ /**
39
+ * Zoekt op waar een project staat, op basis van de labels op zijn containers.
40
+ *
41
+ * Dit gebeurt hier en niet in de renderer: die stuurt alleen een projectnaam mee. Zou het pad
42
+ * van de overkant komen, dan bepaalt de renderer in welke map we een subproces starten, en dat
43
+ * is precies de soort grens die je niet wilt oversteken.
44
+ */
45
+ async function resolveProjectLocation(projectName) {
46
+ const { docker } = (0, docker_client_1.getConnection)();
47
+ const containers = await docker.listContainers({ all: true });
48
+ for (const container of containers) {
49
+ const labels = container.Labels;
50
+ if (labels[COMPOSE_PROJECT] !== projectName) {
51
+ continue;
52
+ }
53
+ const workingDir = labels[COMPOSE_WORKING_DIR];
54
+ const configFiles = splitConfigFiles(labels[COMPOSE_CONFIG_FILES]);
55
+ if (workingDir !== undefined && workingDir !== '') {
56
+ return { workingDir, configFiles };
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+ let cachedStatus = null;
62
+ /**
63
+ * Of de docker CLI er is. Zonder CLI blijven groeperen en start/stop gewoon werken — die gaan
64
+ * via de Engine API — en vallen alleen `up` en `down` weg, want die kent de Engine API niet.
65
+ */
66
+ async function readComposeStatus(refresh = false) {
67
+ if (cachedStatus !== null && !refresh) {
68
+ return cachedStatus;
69
+ }
70
+ try {
71
+ const { stdout } = await execFileAsync('docker', ['compose', 'version'], { timeout: VERSION_TIMEOUT_MS });
72
+ cachedStatus = { cliAvailable: true, version: stdout.trim(), problem: null };
73
+ }
74
+ catch (err) {
75
+ cachedStatus = {
76
+ cliAvailable: false,
77
+ version: null,
78
+ problem: (0, i18n_1.t)({
79
+ en: `The docker CLI cannot be reached, so up and down are unavailable. ${describeError(err)}`,
80
+ nl: `De docker CLI is niet bereikbaar, dus up en down kunnen niet. ${describeError(err)}`,
81
+ de: `Die docker-CLI ist nicht erreichbar, up und down sind daher nicht verfügbar. ${describeError(err)}`,
82
+ fr: `La CLI docker est injoignable, up et down ne sont donc pas disponibles. ${describeError(err)}`,
83
+ es: `No se puede contactar con la CLI de docker, así que up y down no están disponibles. ${describeError(err)}`,
84
+ }),
85
+ };
86
+ }
87
+ return cachedStatus;
88
+ }
89
+ /** Wist wat we over de CLI wisten. Bedoeld voor tests. */
90
+ function resetComposeStatus() {
91
+ cachedStatus = null;
92
+ }
93
+ /**
94
+ * Haalt de regels weg die `wsl.exe` zelf tussen de uitvoer zet, zoals
95
+ * `<3>WSL (46512 - Relay) ERROR: CreateProcessCommon:792: chdir(/tmp/x) failed 2`. Wat compose
96
+ * erna zegt, is dezelfde fout in leesbare vorm.
97
+ */
98
+ function stripWslNoise(text) {
99
+ return text
100
+ .split(/\r?\n/)
101
+ .filter((line) => !/^<\d>WSL \(/.test(line))
102
+ .join('\n');
103
+ }
104
+ function describeError(err) {
105
+ const detail = err;
106
+ const text = [detail.stderr, detail.stdout, detail.message]
107
+ .map((part) => stripWslNoise(Buffer.isBuffer(part) ? (0, wsl_1.decodeWslOutput)(part) : (part ?? '')).trim())
108
+ .find((part) => part !== '');
109
+ return text ?? String(err);
110
+ }
111
+ /** Het begin van elk compose-commando voor een project, tot en met de bestanden. */
112
+ function projectArgs(projectName, location) {
113
+ // -p met de projectnaam erbij: de naam van een compose-project hoeft niet gelijk te zijn aan
114
+ // de mapnaam, en zonder dit zou compose op een ander project uitkomen.
115
+ return ['compose', '-p', projectName, ...location.configFiles.flatMap((file) => ['-f', file])];
116
+ }
117
+ /** De argumenten voor `docker`. Apart en geëxporteerd omdat de `-p` hieronder ertoe doet. */
118
+ function buildComposeArgs(command, projectName, location) {
119
+ const base = projectArgs(projectName, location);
120
+ return command === 'up' ? [...base, 'up', '-d'] : [...base, 'down'];
121
+ }
122
+ /**
123
+ * Eén service opnieuw aanmaken, ook als er niets aan zijn image veranderd is.
124
+ *
125
+ * `--force-recreate` is het verschil met `buildRenewArgs`: die draait na een pull, en dan ziet
126
+ * compose vanzelf dat de container op een oude image staat. Hier is de aanleiding een wijziging
127
+ * in het bestand, en zonder die vlag besluit compose dat alles al klopt en doet hij niets.
128
+ *
129
+ * `--no-deps` blijft: je wilt deze service, niet zijn database erbij.
130
+ */
131
+ function buildRecreateArgs(projectName, location, service) {
132
+ return [...projectArgs(projectName, location), 'up', '-d', '--no-deps', '--force-recreate', '--', service];
133
+ }
134
+ /**
135
+ * Alleen deze services opnieuw aanmaken, met de image waar hun tag nu naar wijst.
136
+ *
137
+ * `--no-deps`: een service waar ze van afhangen blijft zoals hij is, ook als die stilstaat.
138
+ * Compose maakt alleen opnieuw aan wat veranderd is, en een andere image is een verandering.
139
+ * De `--` ervoor, zodat een servicenaam nooit als optie gelezen wordt.
140
+ */
141
+ function buildRenewArgs(projectName, location, services) {
142
+ return [...projectArgs(projectName, location), 'up', '-d', '--no-deps', '--', ...services];
143
+ }
144
+ /**
145
+ * Waar compose moet draaien: waar het project ooit gestart is.
146
+ *
147
+ * Op Windows met een Linux-pad als werkmap (`/mnt/c/projects/infra`) is het project vanuit
148
+ * WSL gestart. Dan draait compose ook daar, in de standaard-distro, dezelfde aanname als in
149
+ * `wsl.ts`. Vanuit Windows zou compose de map niet vinden, en als je hem vertaalt naar
150
+ * `C:\projects\infra` krijgen relatieve bind mounts een Windows-pad dat de daemon in WSL
151
+ * niet kent: dan maakt `up` stil lege mappen aan in plaats van je configuratie te mounten.
152
+ */
153
+ function composeInvocation(location, dockerArgs, platform = process.platform) {
154
+ if (platform === 'win32' && location.workingDir.startsWith('/')) {
155
+ return { file: 'wsl.exe', args: ['--cd', location.workingDir, '--exec', 'docker', ...dockerArgs], cwd: undefined, viaWsl: true };
156
+ }
157
+ return { file: 'docker', args: dockerArgs, cwd: location.workingDir, viaWsl: false };
158
+ }
159
+ /**
160
+ * Het Windows-pad bij een WSL-pad onder `/mnt/<schijf>`, om te kunnen zien of de map er nog is.
161
+ * `null` voor een pad binnen de distro zelf; dat kunnen we vanaf hier niet nakijken.
162
+ */
163
+ function windowsPathOf(wslPath) {
164
+ const match = /^\/mnt\/([a-z])(\/.*)?$/i.exec(wslPath);
165
+ return match === null ? null : `${match[1].toUpperCase()}:${(match[2] ?? '/').replaceAll('/', '\\')}`;
166
+ }
167
+ /** Of de werkmap er nog is, voor zover we dat kunnen zien. */
168
+ function workingDirExists(invocation, workingDir) {
169
+ if (!invocation.viaWsl) {
170
+ return (0, node_fs_1.existsSync)(workingDir);
171
+ }
172
+ const windowsPath = windowsPathOf(workingDir);
173
+ return windowsPath === null || (0, node_fs_1.existsSync)(windowsPath);
174
+ }
175
+ /**
176
+ * Draait één compose-commando voor een project op de plek waar het hoort.
177
+ *
178
+ * Via execFile en nooit via een shell, zodat een projectnaam of pad nooit als shell-tekst
179
+ * geïnterpreteerd wordt — hetzelfde uitgangspunt als in docker-mcp-mx' compose-client. De
180
+ * omgeving gaat ongewijzigd mee: dit is de omgeving van de gebruiker zelf, net als wanneer ze
181
+ * het commando in een terminal zouden typen, en er komt niets van buitenaf bij.
182
+ */
183
+ async function runComposeCapture(location, dockerArgs, label) {
184
+ const invocation = composeInvocation(location, dockerArgs);
185
+ // De CLI op Windows doet er alleen toe als compose ook op Windows draait.
186
+ if (!invocation.viaWsl) {
187
+ const status = await readComposeStatus();
188
+ if (!status.cliAvailable) {
189
+ return { ok: false, problem: status.problem ?? (0, i18n_1.t)({
190
+ en: 'The docker CLI is not available.',
191
+ nl: 'De docker CLI is niet beschikbaar.',
192
+ de: 'Die docker-CLI ist nicht verfügbar.',
193
+ fr: 'La CLI docker n’est pas disponible.',
194
+ es: 'La CLI de docker no está disponible.',
195
+ }) };
196
+ }
197
+ }
198
+ if (!workingDirExists(invocation, location.workingDir)) {
199
+ return { ok: false, problem: (0, i18n_1.t)({
200
+ en: `The folder '${location.workingDir}' no longer exists.`,
201
+ nl: `De map '${location.workingDir}' bestaat niet meer.`,
202
+ de: `Den Ordner '${location.workingDir}' gibt es nicht mehr.`,
203
+ fr: `Le dossier '${location.workingDir}' n’existe plus.`,
204
+ es: `La carpeta '${location.workingDir}' ya no existe.`,
205
+ }) };
206
+ }
207
+ try {
208
+ const { stdout } = await execFileAsync(invocation.file, [...invocation.args], {
209
+ cwd: invocation.cwd,
210
+ encoding: 'buffer',
211
+ // Voor de meldingen van wsl.exe zelf; wat docker in de distro schrijft is al UTF-8.
212
+ env: invocation.viaWsl ? { ...process.env, WSL_UTF8: '1' } : process.env,
213
+ timeout: UP_TIMEOUT_MS,
214
+ maxBuffer: 20 * 1024 * 1024,
215
+ windowsHide: true,
216
+ });
217
+ return { ok: true, stdout: stripWslNoise(stdout.toString('utf8')) };
218
+ }
219
+ catch (err) {
220
+ return { ok: false, problem: (0, i18n_1.t)({
221
+ en: `'docker compose ${label}' failed: ${describeError(err)}`,
222
+ nl: `'docker compose ${label}' mislukte: ${describeError(err)}`,
223
+ de: `'docker compose ${label}' ist fehlgeschlagen: ${describeError(err)}`,
224
+ fr: `'docker compose ${label}' a échoué : ${describeError(err)}`,
225
+ es: `'docker compose ${label}' ha fallado: ${describeError(err)}`,
226
+ }) };
227
+ }
228
+ }
229
+ /** Zoals `runComposeCapture`, maar alleen of het lukte; de meeste aanroepers willen niets weten. */
230
+ async function runCompose(location, dockerArgs, label) {
231
+ const result = await runComposeCapture(location, dockerArgs, label);
232
+ return result.ok ? { ok: true } : result;
233
+ }
234
+ /** Voert `docker compose up -d` of `down` uit voor een project. */
235
+ async function runComposeCommand(projectName, command) {
236
+ const location = await resolveProjectLocation(projectName);
237
+ if (location === null) {
238
+ return {
239
+ ok: false,
240
+ problem: (0, i18n_1.t)({
241
+ en: `It is not known where '${projectName}' is located. That label is on the containers, so this only works while containers of this project still exist.`,
242
+ nl: `Van '${projectName}' is niet bekend waar het staat. Dat label zit op de containers, dus het lukt alleen zolang er nog containers van dit project bestaan.`,
243
+ de: `Es ist nicht bekannt, wo '${projectName}' liegt. Dieses Label steht auf den Containern, das geht also nur, solange es noch Container dieses Projekts gibt.`,
244
+ fr: `L’emplacement de '${projectName}' est inconnu. Ce label est porté par les conteneurs, cela ne marche donc que tant qu’il existe encore des conteneurs de ce projet.`,
245
+ es: `No se sabe dónde está '${projectName}'. Esa label está en los contenedores, así que esto solo funciona mientras sigan existiendo contenedores de este proyecto.`,
246
+ }),
247
+ };
248
+ }
249
+ return runCompose(location, buildComposeArgs(command, projectName, location), command);
250
+ }
251
+ /**
252
+ * Bouwt één service van een project opnieuw op.
253
+ *
254
+ * Apart van `runComposeCommand`, want dat gaat over het hele project. Hier is de aanleiding dat
255
+ * je het bestand hebt aangepast en dat ene ding wil vernieuwen zonder de rest om te gooien —
256
+ * een `down` en `up` zou je database ook meenemen.
257
+ */
258
+ async function recreateService(projectName, service) {
259
+ const location = await resolveProjectLocation(projectName);
260
+ if (location === null) {
261
+ return { ok: false, problem: (0, i18n_1.t)({
262
+ en: `It is not known where '${projectName}' is located. That label is on the containers, so this only works while containers of this project still exist.`,
263
+ nl: `Van '${projectName}' is niet bekend waar het staat. Dat label zit op de containers, dus het lukt alleen zolang er nog containers van dit project bestaan.`,
264
+ de: `Es ist nicht bekannt, wo '${projectName}' liegt. Dieses Label steht auf den Containern, das geht also nur, solange es noch Container dieses Projekts gibt.`,
265
+ fr: `L’emplacement de '${projectName}' est inconnu. Ce label est porté par les conteneurs, cela ne marche donc que tant qu’il existe encore des conteneurs de ce projet.`,
266
+ es: `No se sabe dónde está '${projectName}'. Esa label está en los contenedores, así que esto solo funciona mientras sigan existiendo contenedores de este proyecto.`,
267
+ }) };
268
+ }
269
+ return runCompose(location, buildRecreateArgs(projectName, location, service), 'up');
270
+ }
271
+ //# sourceMappingURL=compose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.js","sourceRoot":"","sources":["../electron/compose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContainerHistory = exports.FORGET_AFTER_MS = exports.EVENTS_PER_NAME = void 0;
4
+ exports.toNamedEvent = toNamedEvent;
5
+ exports.readDaemonEvents = readDaemonEvents;
6
+ const docker_client_1 = require("./docker-client");
7
+ const ndjson_1 = require("./ndjson");
8
+ /**
9
+ * Wat er met een container gebeurd is, per naam.
10
+ *
11
+ * De daemon bewaart zelf maar 256 events, voor alle resources samen, en een healthcheck kost er
12
+ * elke keer drie (`exec_create`, `exec_start`, `exec_die`). Met een paar containers met een
13
+ * healthcheck reikt `GET /events?since=…` daardoor maar minuten terug. Daarom houdt main het zelf
14
+ * bij, uit dezelfde stream die de crashmelding al volgt, en vult het bij het starten aan met wat
15
+ * de daemon nog heeft.
16
+ *
17
+ * Per naam en niet per id: na "opnieuw opbouwen" of een `compose up` met een nieuwe image krijgt
18
+ * de container een nieuw id. Per naam zie je dan destroy, create en start, en loopt de
19
+ * geschiedenis door.
20
+ */
21
+ /** Zoveel per naam. Een container in een herstartlus maakt er drie per ronde; dit is ruim een uur. */
22
+ exports.EVENTS_PER_NAME = 100;
23
+ /** Zover terug vragen we de daemon bij het starten. Wat hij heeft, is meestal veel korter. */
24
+ const BACKFILL_SINCE_S = 24 * 60 * 60;
25
+ /** Wat iets zegt. `exec_*`, `attach`, `resize`, `top` en `archive-path` (de tab Bestanden zelf) niet. */
26
+ const ACTIONS = new Set([
27
+ 'create',
28
+ 'start',
29
+ 'die',
30
+ 'kill',
31
+ 'oom',
32
+ 'stop',
33
+ 'restart',
34
+ 'pause',
35
+ 'unpause',
36
+ 'destroy',
37
+ 'rename',
38
+ ]);
39
+ const HEALTH_PREFIX = 'health_status: ';
40
+ const HEALTH_STATUSES = new Set(['starting', 'healthy', 'unhealthy']);
41
+ function text(value) {
42
+ return typeof value === 'string' && value !== '' ? value : null;
43
+ }
44
+ /** Docker zet soms een `/` voor een naam, zoals in de containerlijst; de rest van de app niet. */
45
+ function bareName(value) {
46
+ const name = text(value);
47
+ return name === null ? null : name.replace(/^\//, '');
48
+ }
49
+ function toAction(raw) {
50
+ if (raw.startsWith(HEALTH_PREFIX)) {
51
+ const status = raw.slice(HEALTH_PREFIX.length).trim();
52
+ return HEALTH_STATUSES.has(status) ? { action: 'health', health: status } : null;
53
+ }
54
+ return ACTIONS.has(raw) ? { action: raw, health: null } : null;
55
+ }
56
+ /** De tijd in nanoseconden, als tekst: getallen van die grootte passen niet precies in een double. */
57
+ function nanosOf(event) {
58
+ if (typeof event.timeNano === 'number' || typeof event.timeNano === 'bigint') {
59
+ return String(event.timeNano);
60
+ }
61
+ if (typeof event.time === 'number') {
62
+ return `${String(event.time)}000000000`;
63
+ }
64
+ return null;
65
+ }
66
+ /** Zet één ruw event om, of geeft `null` voor alles wat hier niet over gaat. */
67
+ function toNamedEvent(raw) {
68
+ const event = raw;
69
+ if (event?.Type !== 'container' || typeof event.Action !== 'string') {
70
+ return null;
71
+ }
72
+ const parsed = toAction(event.Action);
73
+ const attributes = event.Actor?.Attributes ?? {};
74
+ const name = bareName(attributes['name']);
75
+ const nanos = nanosOf(event);
76
+ if (parsed === null || name === null || nanos === null) {
77
+ return null;
78
+ }
79
+ const exitCode = parsed.action === 'die' ? Number(attributes['exitCode']) : NaN;
80
+ return {
81
+ name,
82
+ key: `${nanos}:${event.Action}`,
83
+ event: {
84
+ time: Math.floor(Number(nanos.slice(0, -6))),
85
+ action: parsed.action,
86
+ exitCode: Number.isFinite(exitCode) ? exitCode : null,
87
+ signal: parsed.action === 'kill' ? text(attributes['signal']) : null,
88
+ health: parsed.health,
89
+ oldName: parsed.action === 'rename' ? bareName(attributes['oldName']) : null,
90
+ },
91
+ };
92
+ }
93
+ /** Zo lang blijft een naam bewaard zonder dat er iets mee gebeurt; daarna is de container meestal weg. */
94
+ exports.FORGET_AFTER_MS = 7 * 24 * 60 * 60 * 1000;
95
+ /** De geschiedenis zelf. Zonder Docker, zodat hij met gewone objecten te testen is. */
96
+ class ContainerHistory {
97
+ limit;
98
+ /** Per naam de events, oudste eerst, met de sleutel erbij om dubbelen te herkennen. */
99
+ byName = new Map();
100
+ constructor(limit = exports.EVENTS_PER_NAME) {
101
+ this.limit = limit;
102
+ }
103
+ /**
104
+ * Een geschiedenis uit wat eerder bewaard is. Namen waar sinds `FORGET_AFTER_MS` niets meer mee
105
+ * gebeurde, komen niet terug; per naam geldt de grens weer, voor als die intussen lager is.
106
+ */
107
+ static restore(saved, now, limit = exports.EVENTS_PER_NAME) {
108
+ const history = new ContainerHistory(limit);
109
+ for (const [name, entries] of Object.entries(saved)) {
110
+ const latest = Math.max(...entries.map((entry) => entry.event.time));
111
+ if (entries.length > 0 && now - latest <= exports.FORGET_AFTER_MS) {
112
+ const copy = [...entries];
113
+ history.settle(copy);
114
+ history.byName.set(name, copy);
115
+ }
116
+ }
117
+ return history;
118
+ }
119
+ /** Alles, per naam, om weg te schrijven. */
120
+ save() {
121
+ return Object.fromEntries(this.byName);
122
+ }
123
+ /** Neemt één ruw event op. Dubbelen (uit de aanvulling én de stream) tellen één keer. Geeft terug of er iets bij kwam. */
124
+ record(raw) {
125
+ const named = toNamedEvent(raw);
126
+ if (named === null) {
127
+ return false;
128
+ }
129
+ // Een hernoemde container neemt zijn geschiedenis mee naar de nieuwe naam.
130
+ if (named.event.action === 'rename' && named.event.oldName !== null && named.event.oldName !== named.name) {
131
+ this.move(named.event.oldName, named.name);
132
+ }
133
+ const entries = this.entriesOf(named.name);
134
+ if (entries.some((entry) => entry.key === named.key)) {
135
+ return false;
136
+ }
137
+ entries.push({ key: named.key, event: named.event });
138
+ this.settle(entries);
139
+ return true;
140
+ }
141
+ /** Nieuwste eerst. */
142
+ eventsOf(name) {
143
+ return (this.byName.get(bareName(name) ?? '') ?? []).map((entry) => entry.event).reverse();
144
+ }
145
+ entriesOf(name) {
146
+ let entries = this.byName.get(name);
147
+ if (entries === undefined) {
148
+ entries = [];
149
+ this.byName.set(name, entries);
150
+ }
151
+ return entries;
152
+ }
153
+ /** Op tijd houden, want aanvulling en stream komen door elkaar binnen, en de oudste laten gaan. */
154
+ settle(entries) {
155
+ entries.sort((a, b) => a.event.time - b.event.time);
156
+ entries.splice(0, Math.max(0, entries.length - this.limit));
157
+ }
158
+ move(from, to) {
159
+ const old = this.byName.get(from);
160
+ if (old === undefined) {
161
+ return;
162
+ }
163
+ this.byName.delete(from);
164
+ const target = this.entriesOf(to);
165
+ target.push(...old);
166
+ this.settle(target);
167
+ }
168
+ }
169
+ exports.ContainerHistory = ContainerHistory;
170
+ /**
171
+ * Wat de daemon nog aan container-events heeft. Met `until` sluit Docker de stream zelf zodra hij
172
+ * bij nu is; zonder zou hij blijven wachten op nieuwe.
173
+ */
174
+ async function readDaemonEvents(nowMs = Date.now()) {
175
+ const now = Math.floor(nowMs / 1000);
176
+ const stream = await (0, docker_client_1.getConnection)().docker.getEvents({
177
+ since: now - BACKFILL_SINCE_S,
178
+ until: now,
179
+ filters: { type: ['container'] },
180
+ });
181
+ return new Promise((resolve, reject) => {
182
+ const events = [];
183
+ stream.on('data', (0, ndjson_1.ndjson)((value) => events.push(value)));
184
+ stream.on('error', reject);
185
+ stream.on('end', () => resolve(events));
186
+ });
187
+ }
188
+ //# sourceMappingURL=container-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-events.js","sourceRoot":"","sources":["../electron/container-events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseExitCode = parseExitCode;
4
+ exports.toContainerSummary = toContainerSummary;
5
+ exports.listContainers = listContainers;
6
+ exports.inspectContainer = inspectContainer;
7
+ exports.runContainerAction = runContainerAction;
8
+ exports.pruneContainers = pruneContainers;
9
+ const compose_1 = require("./compose");
10
+ const docker_client_1 = require("./docker-client");
11
+ const i18n_1 = require("./i18n");
12
+ const port_conflicts_1 = require("./port-conflicts");
13
+ const wiring_1 = require("./wiring");
14
+ const COMPOSE_PROJECT = 'com.docker.compose.project';
15
+ const COMPOSE_SERVICE = 'com.docker.compose.service';
16
+ const COMPOSE_WORKING_DIR = 'com.docker.compose.project.working_dir';
17
+ const COMPOSE_CONFIG_FILES = 'com.docker.compose.project.config_files';
18
+ const STATES = ['created', 'running', 'paused', 'restarting', 'removing', 'exited', 'dead'];
19
+ function toState(raw) {
20
+ return STATES.includes(raw) ? raw : 'dead';
21
+ }
22
+ /**
23
+ * Docker geeft een gepubliceerde poort twee keer terug, één keer voor IPv4 en één keer voor
24
+ * IPv6. In de tabel is dat twee identieke regels, dus we houden er één over per combinatie
25
+ * van host- en containerpoort.
26
+ */
27
+ function toPorts(raw) {
28
+ const seen = new Map();
29
+ for (const port of raw ?? []) {
30
+ const binding = {
31
+ hostPort: port.PublicPort ?? null,
32
+ containerPort: port.PrivatePort,
33
+ protocol: port.Type,
34
+ };
35
+ seen.set(`${String(binding.hostPort)}:${String(binding.containerPort)}/${binding.protocol}`, binding);
36
+ }
37
+ return [...seen.values()].sort((a, b) => a.containerPort - b.containerPort);
38
+ }
39
+ /**
40
+ * Leest de afsluitcode uit de statuszin.
41
+ *
42
+ * `docker ps` geeft die alleen in de tekst mee: "Exited (137) 2 minutes ago". Per container
43
+ * een inspect doen om hem netjes op te halen zou net zoveel aanroepen kosten als er containers
44
+ * zijn. De Engine API is niet vertaald, dus dit woord staat er altijd in het Engels.
45
+ */
46
+ function parseExitCode(status) {
47
+ const match = /^Exited \((\d+)\)/.exec(status);
48
+ return match === null ? null : Number(match[1]);
49
+ }
50
+ /** Vertaalt één regel uit `docker ps` naar het contract van de renderer. */
51
+ function toContainerSummary(raw) {
52
+ const labels = raw.Labels;
53
+ return {
54
+ id: raw.Id,
55
+ shortId: raw.Id.slice(0, 12),
56
+ // Een container kan meerdere namen hebben (aliassen); de eerste is de echte, met een
57
+ // leidende slash die nergens in de UI thuishoort.
58
+ name: (raw.Names[0] ?? raw.Id).replace(/^\//, ''),
59
+ image: raw.Image,
60
+ state: toState(raw.State),
61
+ status: raw.Status,
62
+ exitCode: parseExitCode(raw.Status),
63
+ createdAt: raw.Created,
64
+ ports: toPorts(raw.Ports),
65
+ missingNetwork: (0, wiring_1.missingNetworkOf)(raw.HostConfig.NetworkMode, Object.keys(raw.NetworkSettings.Networks), raw.State === 'running'),
66
+ composeProject: labels[COMPOSE_PROJECT] ?? null,
67
+ composeService: labels[COMPOSE_SERVICE] ?? null,
68
+ // Waar het project staat; de Compose-pagina groepeert hierop en toont het pad. Het
69
+ // uitvoeren van up/down gebruikt dit pad niet — dat zoekt main zelf opnieuw op.
70
+ composeWorkingDir: labels[COMPOSE_WORKING_DIR] ?? null,
71
+ composeConfigFiles: (0, compose_1.splitConfigFiles)(labels[COMPOSE_CONFIG_FILES]),
72
+ };
73
+ }
74
+ /** Alle containers, ook de gestopte: de lijst filtert zelf op status. */
75
+ async function listContainers() {
76
+ const { docker } = (0, docker_client_1.getConnection)();
77
+ const raw = await docker.listContainers({ all: true });
78
+ return raw.map(toContainerSummary).sort((a, b) => a.name.localeCompare(b.name));
79
+ }
80
+ /**
81
+ * De rauwe inspect-uitvoer, ongewijzigd. Dit is de ene plek waar de Engine API wél tot in de
82
+ * renderer doorloopt, en dat is precies de bedoeling: de Inspect-tab laat zien wat Docker
83
+ * zegt, niet onze samenvatting daarvan.
84
+ */
85
+ async function inspectContainer(id) {
86
+ const { docker } = (0, docker_client_1.getConnection)();
87
+ // Via unknown: dockerode typeert inspect() als ContainerInspectInfo, en dat is een gesloten
88
+ // interface zonder indexsignatuur. Dat het geen JsonValue ís volgens TypeScript zegt niets
89
+ // over de waarde — het is letterlijk JSON van de daemon.
90
+ return (await docker.getContainer(id).inspect());
91
+ }
92
+ function run(container, action) {
93
+ switch (action) {
94
+ case 'start':
95
+ return container.start();
96
+ case 'stop':
97
+ return container.stop();
98
+ case 'restart':
99
+ return container.restart();
100
+ case 'pause':
101
+ return container.pause();
102
+ case 'unpause':
103
+ return container.unpause();
104
+ case 'remove':
105
+ // force: ook een draaiende container. De bevestiging in de UI zegt dat er gestopt wordt.
106
+ return container.remove({ force: true });
107
+ }
108
+ }
109
+ /** De eerste helft van de melding bij een bezette poort; de tweede zegt wie hem heeft. */
110
+ function describePortBlocked(action, name) {
111
+ return action === 'restart'
112
+ ? (0, i18n_1.t)({
113
+ en: `'${name}' could not restart: one of its ports is taken.`,
114
+ nl: `'${name}' kon niet herstarten: een van zijn poorten is bezet.`,
115
+ de: `'${name}' konnte nicht neu starten: einer seiner Ports ist belegt.`,
116
+ fr: `'${name}' n’a pas pu redémarrer : l’un de ses ports est pris.`,
117
+ es: `'${name}' no pudo reiniciarse: uno de sus puertos está ocupado.`,
118
+ })
119
+ : (0, i18n_1.t)({
120
+ en: `'${name}' could not start: one of its ports is taken.`,
121
+ nl: `'${name}' kon niet starten: een van zijn poorten is bezet.`,
122
+ de: `'${name}' konnte nicht starten: einer seiner Ports ist belegt.`,
123
+ fr: `'${name}' n’a pas pu démarrer : l’un de ses ports est pris.`,
124
+ es: `'${name}' no pudo iniciarse: uno de sus puertos está ocupado.`,
125
+ });
126
+ }
127
+ /**
128
+ * Voert een actie uit en geeft het resultaat terug in plaats van te gooien. Een fout die
129
+ * door ipcMain heen gaat komt bij de renderer aan met "Error invoking remote method …"
130
+ * ervoor geplakt; dan is de melding die we net netjes hebben opgesteld onbruikbaar.
131
+ */
132
+ async function runContainerAction(action, id) {
133
+ const { docker } = (0, docker_client_1.getConnection)();
134
+ try {
135
+ await run(docker.getContainer(id), action);
136
+ return { ok: true };
137
+ }
138
+ catch (err) {
139
+ // Bij een bezette poort zeggen wie hem heeft; deze container zelf telt dan niet mee.
140
+ const problem = await (0, port_conflicts_1.explainPortConflict)((0, docker_client_1.describeActionProblem)(err, action, id), listContainers, {
141
+ except: id,
142
+ lead: (containers) => describePortBlocked(action, containers.find((container) => container.id === id)?.name ?? id),
143
+ });
144
+ return { ok: false, problem };
145
+ }
146
+ }
147
+ /** Verwijdert alle gestopte containers, zoals `docker container prune`. Een gepauzeerde telt als draaiend. */
148
+ async function pruneContainers() {
149
+ const { docker } = (0, docker_client_1.getConnection)();
150
+ try {
151
+ const raw = (await docker.pruneContainers());
152
+ return { ok: true, removed: raw.ContainersDeleted?.length ?? 0, reclaimedBytes: raw.SpaceReclaimed ?? 0 };
153
+ }
154
+ catch (err) {
155
+ const reason = err instanceof Error ? err.message : String(err);
156
+ return { ok: false, problem: (0, i18n_1.t)({
157
+ en: `Prune failed: ${reason}`,
158
+ nl: `Opruimen mislukte: ${reason}`,
159
+ de: `Aufräumen fehlgeschlagen: ${reason}`,
160
+ fr: `Le nettoyage a échoué : ${reason}`,
161
+ es: `La limpieza ha fallado: ${reason}`,
162
+ }) };
163
+ }
164
+ }
165
+ //# sourceMappingURL=containers.js.map