@runeya/runeya 2.0.48 → 2.0.50

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.
@@ -0,0 +1,7 @@
1
+ import {
2
+ agentManager
3
+ } from "./chunk-JBR3MGS7.js";
4
+ export {
5
+ agentManager
6
+ };
7
+ //# sourceMappingURL=agent-manager-ABEKUAWR.js.map
@@ -442,7 +442,7 @@ var agentStore = new AgentStore();
442
442
 
443
443
  // ../server/src/services/service-store.ts
444
444
  import { randomUUID as randomUUID3 } from "crypto";
445
- import { readFile as readFile4, writeFile as writeFile4, rename as rename3, mkdir as mkdir4, chmod as chmod3 } from "fs/promises";
445
+ import { readFile as readFile4, writeFile as writeFile4, rename as rename3, mkdir as mkdir4, chmod as chmod3, rm as rm2 } from "fs/promises";
446
446
  import { join as join3 } from "path";
447
447
 
448
448
  // ../server/src/services/project-key.ts
@@ -555,7 +555,7 @@ function isVaultConflicted(root) {
555
555
 
556
556
  // ../server/src/services/environment-store.ts
557
557
  import { randomUUID as randomUUID2 } from "crypto";
558
- import { readFile as readFile3, writeFile as writeFile3, rename as rename2, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
558
+ import { readFile as readFile3, writeFile as writeFile3, rename as rename2, mkdir as mkdir3, chmod as chmod2, rm } from "fs/promises";
559
559
  import { join as join2 } from "path";
560
560
 
561
561
  // ../server/src/services/crypto-helpers.ts
@@ -635,7 +635,7 @@ function encryptVariableSlots(variables, existingEncrypted) {
635
635
  }
636
636
  return result;
637
637
  }
638
- function decryptVariableSlots(variables, contextLabel) {
638
+ function decryptVariableSlots(variables, contextLabel, onFailure) {
639
639
  const result = {};
640
640
  for (const [key, variable] of Object.entries(variables)) {
641
641
  const slot = variable.value;
@@ -643,7 +643,8 @@ function decryptVariableSlots(variables, contextLabel) {
643
643
  try {
644
644
  result[key] = { ...variable, value: { ...slot, value: decryptValue(slot.value) } };
645
645
  } catch (err) {
646
- console.error(`[crypto-helpers] Failed to decrypt variable "${key}" for ${contextLabel}: ${err.message}`);
646
+ console.error(`[crypto-helpers] Failed to decrypt variable "${key}" for ${contextLabel}: ${err.message} \u2014 la valeur chiffr\xE9e est conserv\xE9e telle quelle sur le disque`);
647
+ onFailure?.(key);
647
648
  result[key] = { ...variable, value: { ...slot, value: "" } };
648
649
  }
649
650
  } else {
@@ -1928,6 +1929,13 @@ var EnvironmentStore = class {
1928
1929
  loaded = false;
1929
1930
  /** Cache of encrypted secret values as last written to disk */
1930
1931
  diskEncryptedSlots = /* @__PURE__ */ new Map();
1932
+ /**
1933
+ * Les secrets qu'aucune clé chargée n'a ouverts, par environnement.
1934
+ *
1935
+ * Vides en mémoire, ils doivent repartir sur le disque sous leur forme
1936
+ * chiffrée : c'est ce que retient cette liste. Voir `keepUnreadableSecrets`.
1937
+ */
1938
+ unreadableSecrets = /* @__PURE__ */ new Map();
1931
1939
  listeners = /* @__PURE__ */ new Set();
1932
1940
  /** Notified after every persisted mutation, for the cloud sync bridge. */
1933
1941
  onChange(fn) {
@@ -2001,15 +2009,48 @@ var EnvironmentStore = class {
2001
2009
  cache?.envSlots
2002
2010
  );
2003
2011
  }
2004
- return { ...environment, variables: encryptedVars };
2012
+ return { ...environment, variables: this.keepUnreadableSecrets(environment.id, encryptedVars) };
2013
+ }
2014
+ /**
2015
+ * Réécrire un secret illisible tel qu'il est sur le disque, jamais à blanc.
2016
+ *
2017
+ * Un secret qui ne s'ouvre pas est vide en mémoire (voir
2018
+ * `decryptVariableSlots`) : le chiffrer donnerait un chiffré de la chaîne
2019
+ * vide, et la sauvegarde effacerait pour de bon une valeur dont il ne
2020
+ * manquait que la clé. Son chiffré d'origine est encore là — c'est celui que
2021
+ * `diskEncryptedSlots` a mis de côté avant le déchiffrement — et c'est lui
2022
+ * qui repart sur le disque.
2023
+ *
2024
+ * La condition tient à la valeur en mémoire : tant qu'elle est vide, la
2025
+ * variable n'a pas été retouchée et son chiffré fait foi. Dès que
2026
+ * l'utilisateur en saisit une nouvelle, elle l'emporte — et vider un secret
2027
+ * volontairement reste possible, puisque cela ne concerne que les variables
2028
+ * dont le déchiffrement a échoué.
2029
+ */
2030
+ keepUnreadableSecrets(environmentId, variables) {
2031
+ const failed = this.unreadableSecrets.get(environmentId);
2032
+ if (!failed?.size || !variables) return variables;
2033
+ const onDisk = this.diskEncryptedSlots.get(environmentId)?.envSlots ?? {};
2034
+ const result = { ...variables };
2035
+ for (const variableId of failed) {
2036
+ const ciphertext = onDisk[variableId];
2037
+ const variable = result[variableId];
2038
+ if (!ciphertext || !variable || variable.value.value) continue;
2039
+ result[variableId] = { ...variable, value: { ...variable.value, value: ciphertext } };
2040
+ }
2041
+ return result;
2005
2042
  }
2006
2043
  decryptEnvironment(environment) {
2007
2044
  let decryptedVars = environment.variables;
2008
2045
  if (environment.variables && Object.keys(environment.variables).length > 0) {
2046
+ const failed = /* @__PURE__ */ new Set();
2009
2047
  decryptedVars = decryptVariableSlots(
2010
2048
  environment.variables,
2011
- `environment ${environment.id}`
2049
+ `environment ${environment.id}`,
2050
+ (variableId) => failed.add(variableId)
2012
2051
  );
2052
+ if (failed.size > 0) this.unreadableSecrets.set(environment.id, failed);
2053
+ else this.unreadableSecrets.delete(environment.id);
2013
2054
  }
2014
2055
  return { ...environment, variables: decryptedVars };
2015
2056
  }
@@ -2050,8 +2091,9 @@ var EnvironmentStore = class {
2050
2091
  /**
2051
2092
  * Write each vault that holds — or held — an environment.
2052
2093
  *
2053
- * Vaults emptied by this save are still written, as an empty list: an
2054
- * environment that moved to another vault must not survive in the old one.
2094
+ * A vault emptied by this save loses its file: an environment that moved to
2095
+ * another vault must not survive in the old one, and a `[]` left behind would
2096
+ * keep (or recreate) a `.runeya` in a directory that holds nothing.
2055
2097
  */
2056
2098
  async save() {
2057
2099
  const byRoot = /* @__PURE__ */ new Map();
@@ -2070,8 +2112,13 @@ var EnvironmentStore = class {
2070
2112
  else byRoot.set(root, [prepared]);
2071
2113
  }
2072
2114
  for (const [root, environments] of byRoot) {
2073
- await mkdir3(root, { recursive: true });
2074
2115
  const filePath = this.getFilePath(root);
2116
+ if (environments.length === 0) {
2117
+ await rm(filePath, { force: true }).catch(() => {
2118
+ });
2119
+ continue;
2120
+ }
2121
+ await mkdir3(root, { recursive: true });
2075
2122
  const tmpPath = filePath + ".tmp";
2076
2123
  await writeFile3(tmpPath, JSON.stringify(environments, null, 2), "utf-8");
2077
2124
  await rename2(tmpPath, filePath);
@@ -2111,6 +2158,7 @@ var EnvironmentStore = class {
2111
2158
  if (environment.projectId !== projectId) continue;
2112
2159
  this.environments.delete(id);
2113
2160
  this.diskEncryptedSlots.delete(id);
2161
+ this.unreadableSecrets.delete(id);
2114
2162
  this.roots.delete(id);
2115
2163
  }
2116
2164
  this.notify();
@@ -2347,6 +2395,7 @@ var EnvironmentStore = class {
2347
2395
  if (!this.environments.has(id)) return false;
2348
2396
  this.environments.delete(id);
2349
2397
  this.diskEncryptedSlots.delete(id);
2398
+ this.unreadableSecrets.delete(id);
2350
2399
  await this.save();
2351
2400
  return true;
2352
2401
  }
@@ -2471,8 +2520,9 @@ var ServiceStore = class {
2471
2520
  /**
2472
2521
  * Write each vault that holds — or held — a service.
2473
2522
  *
2474
- * A vault emptied by this save is still written, as an empty list: a service
2475
- * that moved to another vault must not survive in the one it left.
2523
+ * A vault emptied by this save loses its file: a service that moved to
2524
+ * another vault must not survive in the one it left, and a `[]` left behind
2525
+ * would keep (or recreate) a `.runeya` in a directory that holds nothing.
2476
2526
  */
2477
2527
  async save() {
2478
2528
  const byRoot = /* @__PURE__ */ new Map();
@@ -2491,8 +2541,13 @@ var ServiceStore = class {
2491
2541
  else byRoot.set(root, [prepared]);
2492
2542
  }
2493
2543
  for (const [root, services] of byRoot) {
2494
- await mkdir4(root, { recursive: true });
2495
2544
  const filePath = this.getFilePath(root);
2545
+ if (services.length === 0) {
2546
+ await rm2(filePath, { force: true }).catch(() => {
2547
+ });
2548
+ continue;
2549
+ }
2550
+ await mkdir4(root, { recursive: true });
2496
2551
  const tmpPath = filePath + ".tmp";
2497
2552
  await writeFile4(tmpPath, JSON.stringify(services, null, 2), "utf-8");
2498
2553
  await rename3(tmpPath, filePath);
@@ -3694,4 +3749,4 @@ export {
3694
3749
  traefikManager,
3695
3750
  agentManager
3696
3751
  };
3697
- //# sourceMappingURL=chunk-JUOZ4L4Y.js.map
3752
+ //# sourceMappingURL=chunk-JBR3MGS7.js.map