@runeya/runeya 1.33.20 → 1.33.23

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 (107) hide show
  1. package/node-red-contrib-runeya.tar +0 -0
  2. package/package.json +1 -1
  3. package/public/assets/{App-BVTb2f1U.css → App-BGPtogo-.css} +1 -1
  4. package/public/assets/App-Bj3c8ECd.js +101 -0
  5. package/public/assets/Bugs-B6LM8YSZ.js +1 -0
  6. package/public/assets/Bugs-DZVuTDKA.css +1 -0
  7. package/public/assets/Configs-CRGDsvnb.js +464 -0
  8. package/public/assets/Configs-DdBteQMK.css +1 -0
  9. package/public/assets/CurrentEditor-DI0XEvLu.js +1 -0
  10. package/public/assets/DynamicComponent-CmXZUvVU.js +1 -0
  11. package/public/assets/DynamicComponent-DgxRO4Pl.css +1 -0
  12. package/public/assets/{Editor-Ck3cFVn3.js → Editor-CBZeVePs.js} +7 -7
  13. package/public/assets/{Editor-BC23IeB6.css → Editor-CPPFMOjb.css} +1 -1
  14. package/public/assets/Git-Cf-zgTWr.js +11 -0
  15. package/public/assets/Git-UQIt5ANe.css +1 -0
  16. package/public/assets/ImportCreate-DZSPN5cY.js +1 -0
  17. package/public/assets/Index-BJieQWaU.js +1 -0
  18. package/public/assets/Index-BcFahN3S.css +1 -0
  19. package/public/assets/Index-BrbegLuT.js +1 -0
  20. package/public/assets/Index-C3gFkhHj.js +1 -0
  21. package/public/assets/Index-C66tLKvy.css +1 -0
  22. package/public/assets/Index-Cd-qd5VG.css +1 -0
  23. package/public/assets/Index-Cg-pTjT5.js +1 -0
  24. package/public/assets/Index-CvhWs0kp.css +1 -0
  25. package/public/assets/Index-D67OAIVa.js +314 -0
  26. package/public/assets/Index-DZ8CXixy.js +1 -0
  27. package/public/assets/{Init-Lt-2DFbi.js → Init-BILP6lrr.js} +1 -1
  28. package/public/assets/{LeftLogo-fTp83qX1.js → LeftLogo-BCYb654E.js} +1 -1
  29. package/public/assets/Logs-BfqPcp-L.js +74 -0
  30. package/public/assets/Logs-BhdfGaw5.css +32 -0
  31. package/public/assets/{Markdown-CNWZoHio.js → Markdown-CuewGlVj.js} +19 -103
  32. package/public/assets/Modal-CGUZawhK.css +1 -0
  33. package/public/assets/Modal-DmKdmCtc.js +1 -0
  34. package/public/assets/Modals-BHTrmB19.js +1 -0
  35. package/public/assets/NotUpToDate-CnmuPdX-.js +1 -0
  36. package/public/assets/NotUpToDate-Dh9RbAwK.css +1 -0
  37. package/public/assets/Npm-HBPCi13F.js +1 -0
  38. package/public/assets/Npm-KBzO1DYv.css +1 -0
  39. package/public/assets/Overview-CRtTdDEz.js +1 -0
  40. package/public/assets/Overview-DZIOmzKx.css +1 -0
  41. package/public/assets/{Section-BC6pA1HZ.js → Section-OccJuk7A.js} +1 -1
  42. package/public/assets/{Settings-Dp_ktsgs.js → Settings-CgEyOTsE.js} +6 -6
  43. package/public/assets/{Settings-BBbk67zT.css → Settings-DUCkJDco.css} +1 -1
  44. package/public/assets/Spinner-BMGbc3X9.js +1 -0
  45. package/public/assets/Spinner-BZXOybIg.css +1 -0
  46. package/public/assets/StackChooser-DBof37zx.js +1 -0
  47. package/public/assets/{StackChooser-CsNxPvyi.js → StackChooser-PJ4_aCX-.js} +1 -1
  48. package/public/assets/StackMultiple-CiXqkibR.css +1 -0
  49. package/public/assets/{StackMultiple-BeZmv6DX.js → StackMultiple-D0bM6dXR.js} +17 -17
  50. package/public/assets/{StackSingle-DBZX9nN_.css → StackSingle-BVHxvisP.css} +1 -1
  51. package/public/assets/StackSingle-D1Yk8PXD.js +1 -0
  52. package/public/assets/{Tabs-fu2myJd9.css → Tabs-BGPqRkjE.css} +1 -1
  53. package/public/assets/Tabs-DQDvjS5y.js +1 -0
  54. package/public/assets/Theme-CzHFcMoz.js +1 -0
  55. package/public/assets/Toolbox-B5KXz4eX.css +1 -0
  56. package/public/assets/Toolbox-C5XEPDmg.js +1 -0
  57. package/public/assets/_baseFor-DiPelG4M.js +1 -0
  58. package/public/assets/_commonjsHelpers-D6-XlEtG.js +1 -0
  59. package/public/assets/{cssMode-DptFVzSA.js → cssMode-CccHpseG.js} +1 -1
  60. package/public/assets/currentEditor-DKB6Zox9.js +1 -0
  61. package/public/assets/dayjs.min-CfWDS3UC.js +1 -0
  62. package/public/assets/{freemarker2-Nj-3NhAz.js → freemarker2-DSPhVVzD.js} +1 -1
  63. package/public/assets/fs-CwxHstJI.js +1 -0
  64. package/public/assets/{handlebars-DccXq6O-.js → handlebars-1zANa-F3.js} +1 -1
  65. package/public/assets/{html-BFezHwqy.js → html-fsS26eC3.js} +1 -1
  66. package/public/assets/{htmlMode-8pIWMfce.js → htmlMode-DvnqyT9t.js} +1 -1
  67. package/public/assets/index-0X67tmWL.js +82 -0
  68. package/public/assets/index-B3Vh_zdc.js +1454 -0
  69. package/public/assets/index-B614CRIK.js +201 -0
  70. package/public/assets/index-BO82C_5u.js +720 -0
  71. package/public/assets/index-Brqxsm84.js +308 -0
  72. package/public/assets/index-CILDVkDy.js +310 -0
  73. package/public/assets/{index--FPUu8lq.css → index-D9v3u7Fv.css} +1 -1
  74. package/public/assets/index-DcbuCmxJ.js +84 -0
  75. package/public/assets/{index-DVXSyllr.js → index-G_rNbFve.js} +2 -2
  76. package/public/assets/index-d75RPzOA.js +176 -0
  77. package/public/assets/index-uWoKtv9r.js +2 -0
  78. package/public/assets/{javascript-B0mQdjwH.js → javascript-DRHvp6-v.js} +1 -1
  79. package/public/assets/json-tree-view-vue3.es-DVJTi2Rq.js +1 -0
  80. package/public/assets/{jsonMode-BuKXiIei.js → jsonMode-CJHmEzcn.js} +1 -1
  81. package/public/assets/{liquid-9G58QM1k.js → liquid-V1Od9uns.js} +1 -1
  82. package/public/assets/lodash-D2RHCRSL.js +27 -0
  83. package/public/assets/{mdx-DWeREtqy.js → mdx-DlWa4FFs.js} +1 -1
  84. package/public/assets/{python-BZtttaDe.js → python-DawPqpxL.js} +1 -1
  85. package/public/assets/{razor-CIhED9yj.js → razor-CrbHGO04.js} +1 -1
  86. package/public/assets/router-DPuc_QdV.css +1 -0
  87. package/public/assets/router-Dzu6a_zz.js +103 -0
  88. package/public/assets/sort-BibmqbFD.js +1 -0
  89. package/public/assets/{system-IAlLmFx7.js → system-BqvwX5_3.js} +1 -1
  90. package/public/assets/{tsMode-BMdhWjVC.js → tsMode-Cb1yqXWI.js} +1 -1
  91. package/public/assets/{typescript-DurNSXGF.js → typescript-CnZCKV3a.js} +1 -1
  92. package/public/assets/{xml-Ckok0faQ.js → xml-B90p6BQJ.js} +1 -1
  93. package/public/assets/{yaml-C2OtFevY.js → yaml-Bkk9HYtt.js} +1 -1
  94. package/public/index.html +1 -1
  95. package/www.js +744 -692
  96. package/www.js.map +1 -1
  97. package/public/assets/App-CxWYnNM-.js +0 -101
  98. package/public/assets/CurrentEditor-C38cqf-Z.js +0 -1
  99. package/public/assets/ImportCreate-DFEf3KiI.js +0 -1
  100. package/public/assets/Overview-BaSpvlXu.css +0 -1
  101. package/public/assets/Overview-DR4QmO04.js +0 -1
  102. package/public/assets/StackChooser-vHgodEvA.js +0 -1
  103. package/public/assets/StackMultiple-Dw-7UAYX.css +0 -1
  104. package/public/assets/StackSingle-Bza6Vusw.js +0 -1
  105. package/public/assets/Tabs-DMteuptw.js +0 -1
  106. package/public/assets/router-BIesWMTV.css +0 -32
  107. package/public/assets/router-BaBuIyxA.js +0 -4232
package/www.js CHANGED
@@ -104,9 +104,12 @@ var require_args = __commonJS({
104
104
  var { hideBin } = require("yargs/helpers");
105
105
  var { existsSync } = require("fs");
106
106
  var yarg = yargs(hideBin(process.argv)).usage("Usage: <path-to-your-stack> [options]").alias("pe", "pull-env").describe("pe", "Pull env from a service (need --environment and --service)").default("pe", false).alias("e", "environment").describe("e", "Choose your environment").default("e", void 0).alias("s", "service").describe("s", "Service").default("s", void 0).alias("ss", "services").describe("ss", "Services").default("ss", []).boolean(["pe"]).string(["e", "s"]).array(["ss"]).help("h").alias("h", "help").parse();
107
+ var rootPath = path.resolve(yarg["_"]?.[0] || ".");
107
108
  var args2 = Object.assign({
108
- rootPath: path.resolve(yarg["_"]?.[0] || "."),
109
- initialCwd: ""
109
+ rootPath,
110
+ initialCwd: "",
111
+ runeyaConfigPath: path.resolve(rootPath, ".runeya"),
112
+ runeyaGlobalConfigPath: path.resolve(require("os").homedir(), ".runeya-global")
110
113
  }, yarg);
111
114
  if (!existsSync(args2.rootPath)) {
112
115
  console.error("Error: Runeya was launched with an invalid root path that does not exist. Please check your launch command. \nPath: ", args2.rootPath);
@@ -128,6 +131,99 @@ var require_args = __commonJS({
128
131
  }
129
132
  });
130
133
 
134
+ // helpers/migrateStackMonitor.js
135
+ var require_migrateStackMonitor = __commonJS({
136
+ "helpers/migrateStackMonitor.js"(exports2, module2) {
137
+ "use strict";
138
+ var pathfs = require("path");
139
+ var { existsSync } = require("fs");
140
+ var { cp } = require("fs/promises");
141
+ var args2 = require_args();
142
+ module2.exports = async function migrateStackMonitor2() {
143
+ const localLegacyPath = pathfs.resolve(args2.runeyaConfigPath, "../.stackmonitor");
144
+ const localNewPath = args2.runeyaConfigPath;
145
+ if (existsSync(localLegacyPath) && !existsSync(localNewPath)) {
146
+ console.log("Legacy path found, copy to new path");
147
+ await cp(localLegacyPath, localNewPath, { recursive: true, force: true });
148
+ }
149
+ const globalLegacyPath = pathfs.resolve(args2.runeyaGlobalConfigPath, "../.stackmonitor");
150
+ const globalNewPath = args2.runeyaGlobalConfigPath;
151
+ if (existsSync(globalLegacyPath) && !existsSync(globalNewPath)) {
152
+ console.log("Legacy path found, copy to new path");
153
+ await cp(globalLegacyPath, globalNewPath, { recursive: true, force: true });
154
+ }
155
+ if (existsSync(localLegacyPath) && !existsSync(pathfs.resolve(args2.runeyaConfigPath, "dbs/overrides"))) {
156
+ console.log("Legacy path found, copy to new path");
157
+ await cp(pathfs.resolve(localLegacyPath, "dbs/overrides"), pathfs.resolve(args2.runeyaConfigPath, "dbs/overrides"), { recursive: true, force: true });
158
+ }
159
+ if (existsSync(localLegacyPath) && !existsSync(pathfs.resolve(args2.runeyaConfigPath, "dbs/encryption-key.json"))) {
160
+ console.log("Legacy path found, copy to new path");
161
+ await cp(pathfs.resolve(localLegacyPath, "dbs/encryption-key.json"), pathfs.resolve(args2.runeyaConfigPath, "dbs/encryption-key.json"), { recursive: true, force: true });
162
+ }
163
+ };
164
+ }
165
+ });
166
+
167
+ // helpers/conflictStorage.js
168
+ var require_conflictStorage = __commonJS({
169
+ "helpers/conflictStorage.js"(exports2, module2) {
170
+ "use strict";
171
+ var pendingConflicts = [];
172
+ function storeConflict(conflict) {
173
+ const conflictId = Date.now().toString();
174
+ pendingConflicts.push({
175
+ id: conflictId,
176
+ timestamp: Date.now(),
177
+ ...conflict
178
+ });
179
+ if (pendingConflicts.length > 20) {
180
+ pendingConflicts.shift();
181
+ }
182
+ return conflictId;
183
+ }
184
+ function getPendingConflicts() {
185
+ return pendingConflicts;
186
+ }
187
+ function removeConflict(conflictId) {
188
+ const index = pendingConflicts.findIndex((c) => c.id === conflictId);
189
+ if (index !== -1) {
190
+ pendingConflicts.splice(index, 1);
191
+ }
192
+ }
193
+ module2.exports = {
194
+ storeConflict,
195
+ getPendingConflicts,
196
+ removeConflict
197
+ };
198
+ }
199
+ });
200
+
201
+ // helpers/reencrypt-nodered.js
202
+ var require_reencrypt_nodered = __commonJS({
203
+ "helpers/reencrypt-nodered.js"(exports2, module2) {
204
+ "use strict";
205
+ var crypto = require("crypto");
206
+ var { readFile, writeFile } = require("fs/promises");
207
+ var encryptionAlgorithm = "aes-256-ctr";
208
+ module2.exports = async function decryptCreds(oldSecret, newScret, path) {
209
+ const oldKey = crypto.createHash("sha256").update(oldSecret).digest();
210
+ const newKey = crypto.createHash("sha256").update(newScret).digest();
211
+ const cipher = JSON.parse(await readFile(path, "utf-8"));
212
+ let flows = cipher["$"];
213
+ const vector = Buffer.from(flows.substring(0, 32), "hex");
214
+ flows = flows.substring(32);
215
+ const decipher = crypto.createDecipheriv(encryptionAlgorithm, oldKey, vector);
216
+ const decrypted = decipher.update(flows, "base64", "utf8") + decipher.final("utf8");
217
+ const newVector = crypto.randomBytes(16);
218
+ const newCipher = crypto.createCipheriv(encryptionAlgorithm, newKey, newVector);
219
+ const encrypted = newCipher.update(decrypted, "utf8", "base64") + newCipher.final("base64");
220
+ await writeFile(path, JSON.stringify({
221
+ "$": newVector.toString("hex") + encrypted
222
+ }, null, 2), "utf-8");
223
+ };
224
+ }
225
+ });
226
+
131
227
  // ../../modules/bugs/backend/routes.js
132
228
  var require_routes = __commonJS({
133
229
  "../../modules/bugs/backend/routes.js"(exports2, module2) {
@@ -198,724 +294,281 @@ var require_backend2 = __commonJS({
198
294
  }
199
295
  });
200
296
 
201
- // helpers/conflictStorage.js
202
- var require_conflictStorage = __commonJS({
203
- "helpers/conflictStorage.js"(exports2, module2) {
297
+ // ../../modules/documentation/backend/Documentation.js
298
+ var require_Documentation = __commonJS({
299
+ "../../modules/documentation/backend/Documentation.js"(exports2, module2) {
204
300
  "use strict";
205
- var pendingConflicts = [];
206
- function storeConflict(conflict) {
207
- const conflictId = Date.now().toString();
208
- pendingConflicts.push({
209
- id: conflictId,
210
- timestamp: Date.now(),
211
- ...conflict
212
- });
213
- if (pendingConflicts.length > 20) {
214
- pendingConflicts.shift();
301
+ var PromiseB2 = require("bluebird");
302
+ var { randomUUID: randomUUID2 } = require("crypto");
303
+ var dbs2 = require_dbs();
304
+ var db = dbs2.getDb(`documentations`);
305
+ var dbDocumentationTree = dbs2.getDb(`documentations-tree`, { encrypted: true, defaultData: [] }).alasql;
306
+ var Documentation = class {
307
+ /**
308
+ * @param {import('@runeya/common-typings').NonFunctionProperties<Documentation>} documentation
309
+ */
310
+ constructor(documentation) {
311
+ this.id = documentation.id || "";
312
+ this.text = documentation.text || "";
215
313
  }
216
- return conflictId;
217
- }
218
- function getPendingConflicts() {
219
- return pendingConflicts;
220
- }
221
- function removeConflict(conflictId) {
222
- const index = pendingConflicts.findIndex((c) => c.id === conflictId);
223
- if (index !== -1) {
224
- pendingConflicts.splice(index, 1);
314
+ static async load(id) {
315
+ }
316
+ static async all() {
317
+ return db.alasql.select("Select * from ?");
318
+ }
319
+ static async find(envId) {
320
+ const documentations = await this.all();
321
+ return documentations.find((env) => env.id === envId);
322
+ }
323
+ async save() {
324
+ const obj = this.toStorage();
325
+ await dbs2.getDb(`documentations/${this.id}`).write(obj);
326
+ return this;
327
+ }
328
+ async update(env) {
329
+ this.transform = env.transform;
330
+ this.label = env.label;
331
+ await dbs2.getDb(`documentations/${this.id}`).write(this.toStorage());
332
+ }
333
+ async delete() {
334
+ await dbs2.getDb(`documentations/${this.id}`).delete();
335
+ }
336
+ toStorage() {
337
+ return {
338
+ id: this.id,
339
+ label: this.label,
340
+ transform: this.transform
341
+ };
225
342
  }
226
- }
227
- module2.exports = {
228
- storeConflict,
229
- getPendingConflicts,
230
- removeConflict
231
- };
232
- }
233
- });
234
-
235
- // helpers/reencrypt-nodered.js
236
- var require_reencrypt_nodered = __commonJS({
237
- "helpers/reencrypt-nodered.js"(exports2, module2) {
238
- "use strict";
239
- var crypto = require("crypto");
240
- var { readFile, writeFile } = require("fs/promises");
241
- var encryptionAlgorithm = "aes-256-ctr";
242
- module2.exports = async function decryptCreds(oldSecret, newScret, path) {
243
- const oldKey = crypto.createHash("sha256").update(oldSecret).digest();
244
- const newKey = crypto.createHash("sha256").update(newScret).digest();
245
- const cipher = JSON.parse(await readFile(path, "utf-8"));
246
- let flows = cipher["$"];
247
- const vector = Buffer.from(flows.substring(0, 32), "hex");
248
- flows = flows.substring(32);
249
- const decipher = crypto.createDecipheriv(encryptionAlgorithm, oldKey, vector);
250
- const decrypted = decipher.update(flows, "base64", "utf8") + decipher.final("utf8");
251
- const newVector = crypto.randomBytes(16);
252
- const newCipher = crypto.createCipheriv(encryptionAlgorithm, newKey, newVector);
253
- const encrypted = newCipher.update(decrypted, "utf8", "base64") + newCipher.final("base64");
254
- await writeFile(path, JSON.stringify({
255
- "$": newVector.toString("hex") + encrypted
256
- }, null, 2), "utf-8");
257
343
  };
344
+ module2.exports = Documentation;
258
345
  }
259
346
  });
260
347
 
261
- // models/EncryptionKey.js
262
- var require_EncryptionKey = __commonJS({
263
- "models/EncryptionKey.js"(exports2, module2) {
348
+ // ../../modules/documentation/backend/Leaf.js
349
+ var require_Leaf = __commonJS({
350
+ "../../modules/documentation/backend/Leaf.js"(exports2, module2) {
264
351
  "use strict";
265
- var { existsSync } = require("fs");
266
- var path = require("path");
267
- var { writeFile, readFile, appendFile } = require("fs/promises");
352
+ var PromiseB2 = require("bluebird");
268
353
  var { randomUUID: randomUUID2 } = require("crypto");
269
354
  var dbs2 = require_dbs();
270
- var { generateKey, encrypt, decrypt } = require_crypto();
271
- var reencryptNodered = require_reencrypt_nodered();
272
- var pathfs = require("path");
273
- var args2 = require_args();
274
- var _EncryptionKey_instances, getDb_fn;
275
- var EncryptionKey = class {
276
- constructor() {
277
- __privateAdd(this, _EncryptionKey_instances);
278
- this.encryptionKey = "";
279
- }
280
- async init() {
281
- this.encryptionKey = (await __privateMethod(this, _EncryptionKey_instances, getDb_fn).call(this).read()).encryptionKey;
282
- const dirname = path.dirname(await dbs2.getDb("encryption-key", { encrypted: false }).getPath());
283
- const gitignorePath = path.resolve(dirname, ".gitignore");
284
- if (!existsSync(gitignorePath)) {
285
- writeFile(gitignorePath, "encryption-key.json");
286
- } else {
287
- const gitignoreFile = (await readFile(gitignorePath, "utf-8")).split("\n");
288
- const gitignoreHasKey = (key) => gitignoreFile.some((line) => line.trim() === key);
289
- if (!gitignoreHasKey("encryption-key.json")) await appendFile(gitignorePath, "\nencryption-key.json");
290
- if (!gitignoreHasKey("overrides")) await appendFile(gitignorePath, "\noverrides");
291
- }
355
+ var { v4 } = require("uuid");
356
+ var dbLeafTree = dbs2.getDb(`leafs-leafs`, { encrypted: true, defaultData: [] }).alasql;
357
+ var Leaf = class _Leaf {
358
+ /**
359
+ * @param {import('@runeya/common-typings').NonFunctionProperties<Leaf>} leaf
360
+ */
361
+ constructor(leaf) {
362
+ this.id = leaf.id || v4();
363
+ this.docId = leaf.docId || "";
364
+ this.serviceId = leaf.serviceId || "";
365
+ this.label = leaf.label || "";
366
+ this.position = leaf.position || -1;
367
+ this.text = leaf.text || "";
368
+ this.parentId = leaf.parentId || "";
292
369
  }
293
- async update() {
294
- return __privateMethod(this, _EncryptionKey_instances, getDb_fn).call(this).write(this.toStorage());
370
+ static async getTree(serviceLabel) {
371
+ const leafs = await dbLeafTree.read(`Select * from ${dbLeafTree.table} ${serviceLabel ? `where serviceId = '${serviceLabel}'` : `where serviceId=''`}`);
372
+ return leafs;
295
373
  }
296
374
  toStorage() {
297
375
  return {
298
- encryptionKey: this.encryptionKey
376
+ docId: this.docId,
377
+ position: this.position,
378
+ serviceId: this.serviceId,
379
+ label: this.label,
380
+ text: this.text,
381
+ parentId: this.parentId
299
382
  };
300
383
  }
301
- async generateKey() {
302
- return generateKey();
384
+ async remove() {
385
+ return dbLeafTree.write(`DELETE from ${dbLeafTree.table} where id = '${this.id}'`);
303
386
  }
304
- async testKey(encryptionKey) {
305
- try {
306
- const variable = randomUUID2();
307
- const result = await encrypt(variable, { encryptionKey });
308
- const decrypted = await decrypt(result, { encryptionKey });
309
- if (decrypted === variable) return true;
310
- return false;
311
- } catch (error) {
312
- console.error(error);
313
- return false;
314
- }
387
+ static async find({ id }) {
388
+ const [leaf] = await dbLeafTree.read(`Select * from ${dbLeafTree.table} where id='${id}'`);
389
+ return leaf ? new _Leaf(leaf) : null;
315
390
  }
316
- async saveKey(key, { noReload } = { noReload: false }) {
317
- if (!await this.testKey(key)) throw new Error("Key not valid");
318
- try {
319
- const envSample = (await dbs2.getDbs("envs"))[0];
320
- if (envSample) await dbs2.getDb(`envs/${envSample}`).read();
321
- if (this.encryptionKey) {
322
- await reencryptNodered(this.encryptionKey, key, pathfs.resolve(require_stack().getRootPath(), "nodered/flow_cred.json"));
323
- await dbs2.reencrypt(this.encryptionKey, key);
324
- }
325
- ;
326
- } catch (error) {
327
- console.error(error);
328
- }
329
- const shouldRestart = this.encryptionKey !== key;
330
- this.encryptionKey = key;
331
- await this.update();
332
- if (!noReload) {
333
- await require_stack().selectConf();
334
- }
335
- if (shouldRestart) {
336
- console.log("Restart...");
337
- require("child_process").spawn(process.argv[0], process.argv.slice(1), {
338
- cwd: args2.initialCwd,
339
- detached: true,
340
- stdio: "inherit"
341
- }).unref();
342
- process.exit(0);
343
- }
344
- return key;
391
+ async save() {
392
+ const leafExists = await _Leaf.find({ id: this.id });
393
+ const storage = this.toStorage();
394
+ const set = dbLeafTree.buildUpdateQuery(storage);
395
+ await leafExists ? dbLeafTree.write(`update ${dbLeafTree.table} set ${set} where id='${this.id}'`) : dbLeafTree.write(`insert into ${dbLeafTree.table} (id, docId, position, serviceId, label, text, parentId) values ('${this.id}', '${this.docId}', ${this.position}, '${this.serviceId}', '${this.label.replace(/'/g, "''")}', '${this.text.replace(/'/g, "''")}', '${this.parentId}')`);
396
+ return this;
345
397
  }
346
398
  };
347
- _EncryptionKey_instances = new WeakSet();
348
- getDb_fn = function() {
349
- return dbs2.getDb("encryption-key", { encrypted: false });
350
- };
351
- module2.exports = new EncryptionKey();
399
+ module2.exports = Leaf;
352
400
  }
353
401
  });
354
402
 
355
- // helpers/crypto.js
356
- var require_crypto = __commonJS({
357
- "helpers/crypto.js"(exports2, module2) {
403
+ // ../../modules/documentation/backend/routes.js
404
+ var require_routes2 = __commonJS({
405
+ "../../modules/documentation/backend/routes.js"(exports2, module2) {
358
406
  "use strict";
359
- var _sodium = require("libsodium-wrappers");
360
- var crypto = require("crypto");
361
- var { sockets: sockets2 } = require_src();
362
- var conflictStorage = require_conflictStorage();
363
- var path = require("path");
364
- module2.exports.generateKey = async () => {
365
- await _sodium.ready;
366
- const sodium = _sodium;
367
- const key = sodium.crypto_aead_aegis256_keygen();
368
- return sodium.to_base64(key);
369
- };
370
- module2.exports.encrypt = async (data, { additionnalNonce = "", encryptionKey = "" } = {}) => {
371
- await _sodium.ready;
372
- const sodium = _sodium;
373
- if (!encryptionKey) encryptionKey = require_EncryptionKey().encryptionKey;
374
- const key = sodium.from_base64(encryptionKey);
375
- if (!key || key.length !== sodium.crypto_secretbox_KEYBYTES) {
376
- throw new Error("Invalid encryption key length");
377
- }
378
- let nonce;
379
- if (additionnalNonce) {
380
- const combinedHash = crypto.createHash("blake2b512").update(data + additionnalNonce).digest();
381
- nonce = combinedHash.slice(0, sodium.crypto_secretbox_NONCEBYTES);
382
- } else {
383
- nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
384
- }
385
- const dataStr = typeof data === "string" ? data : String(data);
386
- const dataArray = new TextEncoder().encode(dataStr);
387
- const ciphertext = sodium.crypto_secretbox_easy(dataArray, nonce, key);
388
- return Buffer.concat([
389
- Buffer.from(nonce.buffer, nonce.byteOffset, nonce.byteLength),
390
- Buffer.from(ciphertext.buffer, ciphertext.byteOffset, ciphertext.byteLength)
391
- ]).toString("base64");
392
- };
393
- module2.exports.decryptFile = async (encryptedData, options = {}, filePath) => {
394
- if (typeof encryptedData === "string" && (encryptedData.includes("<<<<<<< HEAD") || encryptedData.includes("=======") || encryptedData.includes(">>>>>>>"))) {
395
- return await handleGitConflict(encryptedData, options, filePath);
396
- }
397
- return await module2.exports.decrypt(encryptedData, options);
407
+ var express = require("express");
408
+ var Leaf = require_Leaf();
409
+ var PromiseB2 = require("bluebird");
410
+ var router = express.Router();
411
+ module2.exports = (runeya) => {
412
+ const { findService } = runeya;
413
+ router.get("/documentation/tree", async (req, res) => {
414
+ const service = findService(req.query.serviceId?.toString() || "");
415
+ const result = await Leaf.getTree(service?.label);
416
+ return res.send(result);
417
+ });
418
+ router.post("/documentation/tree/sort", async (req, res) => {
419
+ const leafs = await PromiseB2.mapSeries(req.body, async (_leaf, index) => {
420
+ const leaf = await Leaf.find({ id: _leaf.id });
421
+ if (!leaf) return;
422
+ leaf.position = index;
423
+ await leaf.save();
424
+ return leaf;
425
+ });
426
+ return res.send(leafs);
427
+ });
428
+ router.post("/documentation/tree", async (req, res) => {
429
+ const result = await new Leaf({
430
+ ...req.body
431
+ }).save();
432
+ return res.send(result);
433
+ });
434
+ router.post("/documentation/tree/:key", async (req, res) => {
435
+ const result = await new Leaf({
436
+ ...req.body,
437
+ id: req.params.key
438
+ }).save();
439
+ return res.send(result);
440
+ });
441
+ router.delete("/documentation/tree/:key", async (req, res) => {
442
+ const result = await Leaf.find({
443
+ id: req.params.key
444
+ });
445
+ if (result) return res.send(await result.remove());
446
+ return res.send();
447
+ });
448
+ return router;
398
449
  };
399
- module2.exports.decrypt = async (encryptedData, { additionnalNonce = "", encryptionKey = "" } = {}) => {
400
- if (typeof encryptedData === "string" && (encryptedData.includes("<<<<<<< HEAD") || encryptedData.includes("=======") || encryptedData.includes(">>>>>>>"))) {
401
- return await handleGitConflict(encryptedData, { additionnalNonce, encryptionKey });
402
- }
403
- await _sodium.ready;
404
- const sodium = _sodium;
405
- if (!encryptionKey) encryptionKey = require_EncryptionKey().encryptionKey;
406
- const key = sodium.from_base64(encryptionKey);
407
- if (!key || key.length !== sodium.crypto_secretbox_KEYBYTES) {
408
- throw new Error("Invalid decryption key length");
409
- }
410
- const encryptedBuffer = Buffer.from(encryptedData, "base64");
411
- const nonce = encryptedBuffer.slice(0, sodium.crypto_secretbox_NONCEBYTES);
412
- const ciphertext = encryptedBuffer.slice(sodium.crypto_secretbox_NONCEBYTES);
413
- let decrypted;
414
- try {
415
- const ciphertextArray = new Uint8Array(ciphertext);
416
- const nonceArray = new Uint8Array(nonce);
417
- decrypted = sodium.crypto_secretbox_open_easy(ciphertextArray, nonceArray, key);
418
- } catch (error) {
419
- throw new Error("Decryption failed");
420
- }
421
- if (!decrypted) {
422
- throw new Error("Decryption failed");
450
+ }
451
+ });
452
+
453
+ // ../../modules/documentation/backend/index.js
454
+ var require_backend3 = __commonJS({
455
+ "../../modules/documentation/backend/index.js"(exports2, module2) {
456
+ "use strict";
457
+ var { readFile } = require("fs/promises");
458
+ var PromiseB2 = require("bluebird");
459
+ var pathfs = require("path");
460
+ var Documentation = require_Documentation();
461
+ var plugin = {
462
+ enabled: true,
463
+ name: "Documentation",
464
+ displayName: "Documentation",
465
+ description: "Read documentation for a given service",
466
+ icon: "fas fa-book",
467
+ // export: Documentation,
468
+ placements: ["service"],
469
+ order: 6,
470
+ routes: require_routes2(),
471
+ finder: async (search, runeya) => {
423
472
  }
424
- return Buffer.from(decrypted).toString("utf-8");
425
473
  };
426
- async function handleGitConflict(conflictedData, options, filePath) {
427
- const headMatch = conflictedData.match(/<<<<<<< HEAD\r?\n([\s\S]*?)\r?\n=======\r?\n([\s\S]*?)\r?\n>>>>>>>.*/);
428
- if (!headMatch) {
429
- throw new Error("Git conflict detected but could not be properly parsed");
430
- }
431
- try {
432
- const ourVersion = headMatch[1];
433
- const theirVersion = headMatch[2];
434
- let ourDecrypted = "";
435
- let theirDecrypted = "";
436
- try {
437
- ourDecrypted = await module2.exports.decrypt(ourVersion, options);
438
- } catch (err) {
439
- const errorMessage = err instanceof Error ? err.message : String(err);
440
- ourDecrypted = `[ERROR DECRYPTING OUR VERSION: ${errorMessage}]`;
441
- }
442
- try {
443
- theirDecrypted = await module2.exports.decrypt(theirVersion, options);
444
- } catch (err) {
445
- const errorMessage = err instanceof Error ? err.message : String(err);
446
- theirDecrypted = `[ERROR DECRYPTING THEIR VERSION: ${errorMessage}]`;
447
- }
448
- const conflictData = {
449
- original: conflictedData,
450
- ourVersion: ourDecrypted,
451
- theirVersion: theirDecrypted,
452
- filePath: filePath || null,
453
- filename: filePath ? path.basename(filePath) : null
454
- };
455
- const conflictId = conflictStorage.storeConflict(conflictData);
456
- conflictData.id = conflictId;
457
- sockets2.emit("crypto:conflict", conflictData);
458
- return `${JSON.stringify({
459
- ourVersion: ourDecrypted,
460
- theirVersion: theirDecrypted
461
- })}`;
462
- } catch (error) {
463
- const errorMessage = error instanceof Error ? error.message : String(error);
464
- console.error("Error handling git conflict:", errorMessage);
465
- throw new Error(`Git conflict detected, but failed to process: ${errorMessage}`);
466
- }
467
- }
474
+ module2.exports = plugin;
468
475
  }
469
476
  });
470
477
 
471
- // helpers/dbs.js
472
- var require_dbs = __commonJS({
473
- "helpers/dbs.js"(exports2, module2) {
478
+ // ../../modules/finder/backend/routes.js
479
+ var require_routes3 = __commonJS({
480
+ "../../modules/finder/backend/routes.js"(exports2, module2) {
474
481
  "use strict";
475
- var {
476
- existsSync,
477
- mkdirSync,
478
- writeFileSync,
479
- readFileSync,
480
- unlinkSync
481
- } = require("fs");
482
- var pathfs = require("path");
483
- var {
484
- readdir,
485
- mkdir,
486
- writeFile,
487
- readFile,
488
- unlink
489
- } = require("fs/promises");
490
- var { fdir } = require("fdir");
482
+ var express = require("express");
483
+ var router = express.Router();
491
484
  var PromiseB2 = require("bluebird");
492
- var { sockets: sockets2 } = require_src();
493
- var args2 = require_args();
494
- var { encrypt, decrypt, decryptFile } = require_crypto();
495
- var alasql = require("alasql");
496
- module2.exports = new class {
497
- constructor() {
498
- __publicField(this, "cache", {});
499
- }
500
- getRootPath() {
501
- const rootPath = pathfs.resolve(args2.rootPath, ".runeya/dbs");
502
- if (!existsSync(rootPath)) mkdirSync(rootPath, { recursive: true });
503
- return rootPath;
504
- }
505
- async getDbs(namespace = "") {
506
- const pathToDbs = pathfs.resolve(this.getRootPath(), namespace);
507
- if (!existsSync(pathToDbs)) await mkdir(pathToDbs, { recursive: true });
508
- return (await readdir(pathToDbs)).map((id) => id.replace(pathfs.extname(id), "").replace(".encrypted", ""));
485
+ function pluginToUrl(plugin) {
486
+ for (let i = 0; i < plugin.placements.length; i += 1) {
487
+ const placement = plugin.placements[i];
488
+ if (typeof placement !== "string") {
489
+ if (placement.position === "toolbox") {
490
+ return `/toolbox${placement.goTo?.path || placement.goTo}`;
491
+ }
492
+ if (placement.position === "sidebar") {
493
+ return `${placement.goTo?.path || placement.goTo}`;
494
+ }
495
+ }
509
496
  }
510
- async reencrypt(oldKey, newKey) {
511
- const api = new fdir().withFullPaths().filter((path) => path.endsWith("encrypted.json")).crawl(this.getRootPath());
512
- await PromiseB2.map(api.withPromise(), async (file) => {
513
- const fileEncrypted = await readFile(file, "utf-8");
514
- const additionnalNonce = file.split(".runeya").pop();
515
- const fileDecrypted = await decrypt(fileEncrypted, { additionnalNonce, encryptionKey: oldKey });
516
- const fileReEncrypted = await encrypt(fileDecrypted, { additionnalNonce, encryptionKey: newKey });
517
- await writeFile(file, fileReEncrypted, "utf-8");
518
- });
519
- }
520
- getDb(id, { encrypted, defaultData } = { encrypted: true, defaultData: {} }) {
521
- const getPath = async () => {
522
- const persistencePath = pathfs.resolve(`${this.getRootPath()}/${id}${encrypted ? ".encrypted" : ""}.json`);
523
- if (!existsSync(pathfs.dirname(persistencePath))) await mkdirSync(pathfs.dirname(persistencePath), { recursive: true });
524
- if (!existsSync(persistencePath)) {
525
- let defaultDB = JSON.stringify(defaultData || [], null, 2);
526
- if (encrypted) defaultDB = await encrypt(defaultDB, { additionnalNonce: persistencePath.split(".runeya").pop() });
527
- await writeFile(persistencePath, defaultDB, "utf-8");
528
- this.cache[id] = defaultDB;
529
- }
530
- return persistencePath;
531
- };
532
- const table = id.replace(/[^a-z0-9]|\s+|\r?\n|\r/gmi, "_");
533
- const read = async () => {
534
- if (this.cache[id]) return this.cache[id];
535
- const path = await getPath();
536
- const additionnalNonce = path.split(".runeya").pop();
537
- let db = readFileSync(path, "utf-8");
538
- if (encrypted) {
539
- try {
540
- if (typeof db === "string" && (db.includes("<<<<<<< HEAD") || db.includes("=======") || db.includes(">>>>>>>"))) {
541
- db = await decryptFile(db, { additionnalNonce }, path);
542
- } else {
543
- db = await decrypt(db, { additionnalNonce }).catch((err) => {
544
- console.error(path, err);
545
- sockets2.emit("system:wrongKey");
546
- throw err;
547
- });
548
- }
549
- } catch (err) {
550
- console.error(path, err);
551
- sockets2.emit("system:wrongKey");
552
- throw err;
553
- }
554
- }
555
- this.cache[id] = JSON.parse(db);
556
- if (!alasql.tables[table]) {
557
- await alasql(`CREATE TABLE ${table}`);
558
- }
559
- alasql.tables[table].data = this.cache[id];
560
- return this.cache[id];
561
- };
562
- const write = async (data) => {
563
- let db = JSON.stringify(data, null, 2);
564
- const path = await getPath();
565
- const additionnalNonce = path.split(".runeya").pop();
566
- if (encrypted) db = await encrypt(db, { additionnalNonce });
567
- writeFileSync(path, db, "utf-8");
568
- this.cache[id] = data;
569
- if (alasql.tables[table]) {
570
- alasql.tables[table].data = data;
571
- }
572
- };
573
- const escapeQuote = (data) => {
574
- if (typeof data === "string") {
575
- return data.replace(/'/g, "''");
576
- }
577
- return data;
578
- };
579
- const setValue = (item) => {
580
- if (item == null) {
581
- return "NULL";
582
- }
583
- if (item instanceof Date && item.toISOString) {
584
- return `'${item.toISOString()}'`;
585
- }
586
- if (typeof item === "string") {
587
- return `'${escapeQuote(item)}'`;
588
- }
589
- return `${item}`;
590
- };
591
- return {
592
- getPath,
593
- alasql: {
594
- table,
595
- buildUpdateQuery(data) {
596
- const set = [];
597
- Object.keys(data).forEach((key) => {
598
- set.push(`${key} = ${setValue(data[key])}`);
599
- });
600
- return set.join(", ");
601
- },
602
- read: async (sql) => {
603
- await read();
604
- return alasql.promise(sql);
605
- },
606
- /**
607
- *
608
- * @param {{where?: string, orderBy?: string, limit?: number, offset?: number}} param0
609
- * @returns {Promise<any[]>}
610
- */
611
- simpleSelect: async ({ where, orderBy, limit, offset }) => {
612
- await read();
613
- return alasql.promise(`SELECT * FROM ${table} ${where ? `WHERE ${where}` : ""} ${orderBy ? `ORDER BY ${orderBy}` : ""} ${limit ? `LIMIT ${limit}` : ""} ${offset ? `OFFSET ${offset}` : ""}`);
614
- },
615
- /** @param {string} where */
616
- delete: async (where) => {
617
- await read();
618
- await alasql.promise(`DELETE FROM ${table} WHERE ${where}`);
619
- await write(await alasql(`select * from ${table}`));
620
- },
621
- insertOne: async (data) => {
622
- await read();
623
- await alasql.promise(`INSERT INTO ${table} VALUES ${JSON.stringify(data)}`);
624
- await write(await alasql(`select * from ${table}`));
625
- },
626
- write: async (sql, value) => {
627
- await read();
628
- await alasql.promise(sql, value);
629
- await write(await alasql(`select * from ${table}`));
630
- }
631
- },
632
- write,
633
- read,
634
- delete: async () => {
635
- delete this.cache[id];
636
- return unlink(await getPath());
637
- }
638
- };
639
- }
640
- }();
497
+ return "";
498
+ }
499
+ var routes = (runeya) => {
500
+ const {
501
+ getServices,
502
+ helpers: { searchString }
503
+ } = runeya;
504
+ router.get("/finder/search", async (req, res) => {
505
+ const search = req.query.q?.toString()?.toUpperCase() || "";
506
+ const services = getServices().filter((service) => searchString(service?.label, search)).map((service) => ({
507
+ title: service.label,
508
+ description: service.description,
509
+ group: "Service",
510
+ url: `/stack-single/${service.label}`
511
+ }));
512
+ const { plugins } = runeya;
513
+ const _plugins = (await PromiseB2.map(Object.keys(plugins), (key) => plugins[key]).map(async (plugin) => [
514
+ ...await plugin?.finder?.(search, runeya)?.catch?.(() => []) || [],
515
+ ...searchString(plugin.name, search) ? [{
516
+ title: plugin.displayName || plugin.name,
517
+ description: plugin.description,
518
+ group: "Plugin",
519
+ icon: plugin.icon,
520
+ url: pluginToUrl(plugin) || ""
521
+ }] : []
522
+ ])).flat().filter((a) => a?.url);
523
+ const result = [
524
+ ...services,
525
+ ..._plugins
526
+ ].filter((a) => a);
527
+ res.send(result);
528
+ });
529
+ return router;
530
+ };
531
+ module2.exports = routes;
641
532
  }
642
533
  });
643
534
 
644
- // ../../modules/documentation/backend/Documentation.js
645
- var require_Documentation = __commonJS({
646
- "../../modules/documentation/backend/Documentation.js"(exports2, module2) {
535
+ // ../../modules/finder/backend/index.js
536
+ var require_backend4 = __commonJS({
537
+ "../../modules/finder/backend/index.js"(exports2, module2) {
647
538
  "use strict";
648
- var PromiseB2 = require("bluebird");
649
- var { randomUUID: randomUUID2 } = require("crypto");
650
- var dbs2 = require_dbs();
651
- var db = dbs2.getDb(`documentations`);
652
- var dbDocumentationTree = dbs2.getDb(`documentations-tree`, { encrypted: true, defaultData: [] }).alasql;
653
- var Documentation = class {
654
- /**
655
- * @param {import('@runeya/common-typings').NonFunctionProperties<Documentation>} documentation
656
- */
657
- constructor(documentation) {
658
- this.id = documentation.id || "";
659
- this.text = documentation.text || "";
660
- }
661
- static async load(id) {
662
- }
663
- static async all() {
664
- return db.alasql.select("Select * from ?");
665
- }
666
- static async find(envId) {
667
- const documentations = await this.all();
668
- return documentations.find((env) => env.id === envId);
669
- }
670
- async save() {
671
- const obj = this.toStorage();
672
- await dbs2.getDb(`documentations/${this.id}`).write(obj);
673
- return this;
674
- }
675
- async update(env) {
676
- this.transform = env.transform;
677
- this.label = env.label;
678
- await dbs2.getDb(`documentations/${this.id}`).write(this.toStorage());
679
- }
680
- async delete() {
681
- await dbs2.getDb(`documentations/${this.id}`).delete();
682
- }
683
- toStorage() {
684
- return {
685
- id: this.id,
686
- label: this.label,
687
- transform: this.transform
688
- };
689
- }
539
+ var commandExists = require("command-exists");
540
+ var plugin = {
541
+ enabled: true,
542
+ name: "Finder",
543
+ displayName: "Finder",
544
+ description: "Find all you want inside this app",
545
+ icon: "fab fa-git-alt",
546
+ export: null,
547
+ order: -1,
548
+ placements: ["global", {
549
+ position: "sidebar",
550
+ label: "Finder",
551
+ icon: "fas fa-search",
552
+ goTo: { path: "/Finder" },
553
+ active: "Finder"
554
+ }],
555
+ hidden: () => commandExists("git").then(() => false).catch(() => true),
556
+ routes: require_routes3()
690
557
  };
691
- module2.exports = Documentation;
558
+ module2.exports = plugin;
692
559
  }
693
560
  });
694
561
 
695
- // ../../modules/documentation/backend/Leaf.js
696
- var require_Leaf = __commonJS({
697
- "../../modules/documentation/backend/Leaf.js"(exports2, module2) {
562
+ // helpers/exec.js
563
+ var require_exec = __commonJS({
564
+ "helpers/exec.js"(exports2, module2) {
698
565
  "use strict";
699
- var PromiseB2 = require("bluebird");
700
- var { randomUUID: randomUUID2 } = require("crypto");
701
- var dbs2 = require_dbs();
702
- var { v4 } = require("uuid");
703
- var dbLeafTree = dbs2.getDb(`leafs-leafs`, { encrypted: true, defaultData: [] }).alasql;
704
- var Leaf = class _Leaf {
566
+ var { exec } = require("child_process");
567
+ module2.exports = {
705
568
  /**
706
- * @param {import('@runeya/common-typings').NonFunctionProperties<Leaf>} leaf
707
- */
708
- constructor(leaf) {
709
- this.id = leaf.id || v4();
710
- this.docId = leaf.docId || "";
711
- this.serviceId = leaf.serviceId || "";
712
- this.label = leaf.label || "";
713
- this.position = leaf.position || -1;
714
- this.text = leaf.text || "";
715
- this.parentId = leaf.parentId || "";
716
- }
717
- static async getTree(serviceLabel) {
718
- const leafs = await dbLeafTree.read(`Select * from ${dbLeafTree.table} ${serviceLabel ? `where serviceId = '${serviceLabel}'` : `where serviceId=''`}`);
719
- return leafs;
720
- }
721
- toStorage() {
722
- return {
723
- docId: this.docId,
724
- position: this.position,
725
- serviceId: this.serviceId,
726
- label: this.label,
727
- text: this.text,
728
- parentId: this.parentId
729
- };
730
- }
731
- async remove() {
732
- return dbLeafTree.write(`DELETE from ${dbLeafTree.table} where id = '${this.id}'`);
733
- }
734
- static async find({ id }) {
735
- const [leaf] = await dbLeafTree.read(`Select * from ${dbLeafTree.table} where id='${id}'`);
736
- return leaf ? new _Leaf(leaf) : null;
737
- }
738
- async save() {
739
- const leafExists = await _Leaf.find({ id: this.id });
740
- const storage = this.toStorage();
741
- const set = dbLeafTree.buildUpdateQuery(storage);
742
- await leafExists ? dbLeafTree.write(`update ${dbLeafTree.table} set ${set} where id='${this.id}'`) : dbLeafTree.write(`insert into ${dbLeafTree.table} (id, docId, position, serviceId, label, text, parentId) values ('${this.id}', '${this.docId}', ${this.position}, '${this.serviceId}', '${this.label.replace(/'/g, "''")}', '${this.text.replace(/'/g, "''")}', '${this.parentId}')`);
743
- return this;
744
- }
745
- };
746
- module2.exports = Leaf;
747
- }
748
- });
749
-
750
- // ../../modules/documentation/backend/routes.js
751
- var require_routes2 = __commonJS({
752
- "../../modules/documentation/backend/routes.js"(exports2, module2) {
753
- "use strict";
754
- var express = require("express");
755
- var Leaf = require_Leaf();
756
- var PromiseB2 = require("bluebird");
757
- var router = express.Router();
758
- module2.exports = (runeya) => {
759
- const { findService } = runeya;
760
- router.get("/documentation/tree", async (req, res) => {
761
- const service = findService(req.query.serviceId?.toString() || "");
762
- const result = await Leaf.getTree(service?.label);
763
- return res.send(result);
764
- });
765
- router.post("/documentation/tree/sort", async (req, res) => {
766
- const leafs = await PromiseB2.mapSeries(req.body, async (_leaf, index) => {
767
- const leaf = await Leaf.find({ id: _leaf.id });
768
- if (!leaf) return;
769
- leaf.position = index;
770
- await leaf.save();
771
- return leaf;
772
- });
773
- return res.send(leafs);
774
- });
775
- router.post("/documentation/tree", async (req, res) => {
776
- const result = await new Leaf({
777
- ...req.body
778
- }).save();
779
- return res.send(result);
780
- });
781
- router.post("/documentation/tree/:key", async (req, res) => {
782
- const result = await new Leaf({
783
- ...req.body,
784
- id: req.params.key
785
- }).save();
786
- return res.send(result);
787
- });
788
- router.delete("/documentation/tree/:key", async (req, res) => {
789
- const result = await Leaf.find({
790
- id: req.params.key
791
- });
792
- if (result) return res.send(await result.remove());
793
- return res.send();
794
- });
795
- return router;
796
- };
797
- }
798
- });
799
-
800
- // ../../modules/documentation/backend/index.js
801
- var require_backend3 = __commonJS({
802
- "../../modules/documentation/backend/index.js"(exports2, module2) {
803
- "use strict";
804
- var { readFile } = require("fs/promises");
805
- var PromiseB2 = require("bluebird");
806
- var pathfs = require("path");
807
- var Documentation = require_Documentation();
808
- var plugin = {
809
- enabled: true,
810
- name: "Documentation",
811
- displayName: "Documentation",
812
- description: "Read documentation for a given service",
813
- icon: "fas fa-book",
814
- // export: Documentation,
815
- placements: ["service"],
816
- order: 6,
817
- routes: require_routes2(),
818
- finder: async (search, runeya) => {
819
- }
820
- };
821
- module2.exports = plugin;
822
- }
823
- });
824
-
825
- // ../../modules/finder/backend/routes.js
826
- var require_routes3 = __commonJS({
827
- "../../modules/finder/backend/routes.js"(exports2, module2) {
828
- "use strict";
829
- var express = require("express");
830
- var router = express.Router();
831
- var PromiseB2 = require("bluebird");
832
- function pluginToUrl(plugin) {
833
- for (let i = 0; i < plugin.placements.length; i += 1) {
834
- const placement = plugin.placements[i];
835
- if (typeof placement !== "string") {
836
- if (placement.position === "toolbox") {
837
- return `/toolbox${placement.goTo?.path || placement.goTo}`;
838
- }
839
- if (placement.position === "sidebar") {
840
- return `${placement.goTo?.path || placement.goTo}`;
841
- }
842
- }
843
- }
844
- return "";
845
- }
846
- var routes = (runeya) => {
847
- const {
848
- getServices,
849
- helpers: { searchString }
850
- } = runeya;
851
- router.get("/finder/search", async (req, res) => {
852
- const search = req.query.q?.toString()?.toUpperCase() || "";
853
- const services = getServices().filter((service) => searchString(service?.label, search)).map((service) => ({
854
- title: service.label,
855
- description: service.description,
856
- group: "Service",
857
- url: `/stack-single/${service.label}`
858
- }));
859
- const { plugins } = runeya;
860
- const _plugins = (await PromiseB2.map(Object.keys(plugins), (key) => plugins[key]).map(async (plugin) => [
861
- ...await plugin?.finder?.(search, runeya)?.catch?.(() => []) || [],
862
- ...searchString(plugin.name, search) ? [{
863
- title: plugin.displayName || plugin.name,
864
- description: plugin.description,
865
- group: "Plugin",
866
- icon: plugin.icon,
867
- url: pluginToUrl(plugin) || ""
868
- }] : []
869
- ])).flat().filter((a) => a?.url);
870
- const result = [
871
- ...services,
872
- ..._plugins
873
- ].filter((a) => a);
874
- res.send(result);
875
- });
876
- return router;
877
- };
878
- module2.exports = routes;
879
- }
880
- });
881
-
882
- // ../../modules/finder/backend/index.js
883
- var require_backend4 = __commonJS({
884
- "../../modules/finder/backend/index.js"(exports2, module2) {
885
- "use strict";
886
- var commandExists = require("command-exists");
887
- var plugin = {
888
- enabled: true,
889
- name: "Finder",
890
- displayName: "Finder",
891
- description: "Find all you want inside this app",
892
- icon: "fab fa-git-alt",
893
- export: null,
894
- order: -1,
895
- placements: ["global", {
896
- position: "sidebar",
897
- label: "Finder",
898
- icon: "fas fa-search",
899
- goTo: { path: "/Finder" },
900
- active: "Finder"
901
- }],
902
- hidden: () => commandExists("git").then(() => false).catch(() => true),
903
- routes: require_routes3()
904
- };
905
- module2.exports = plugin;
906
- }
907
- });
908
-
909
- // helpers/exec.js
910
- var require_exec = __commonJS({
911
- "helpers/exec.js"(exports2, module2) {
912
- "use strict";
913
- var { exec } = require("child_process");
914
- module2.exports = {
915
- /**
916
- * @param {string} cmd
917
- * @param {import('child_process').ExecOptions} options
918
- * @returns {Promise<string>}
569
+ * @param {string} cmd
570
+ * @param {import('child_process').ExecOptions} options
571
+ * @returns {Promise<string>}
919
572
  */
920
573
  execAsync(cmd, options) {
921
574
  return new Promise((res, rej) => {
@@ -3601,7 +3254,7 @@ var require_stack = __commonJS({
3601
3254
  var CustomObservable = require_CustomObservable();
3602
3255
  var args2 = require_args();
3603
3256
  var { existsSync, mkdirSync } = require("fs");
3604
- var { rename } = require("fs/promises");
3257
+ var { rename, cp, rmdir, rm } = require("fs/promises");
3605
3258
  var pathfs = require("path");
3606
3259
  var { default: axios } = require("axios");
3607
3260
  function Stack(stack) {
@@ -3672,7 +3325,6 @@ var require_stack = __commonJS({
3672
3325
  };
3673
3326
  Stack.getRootPath = () => {
3674
3327
  const rootPath = pathfs.resolve(args2.rootPath, ".runeya");
3675
- if (!existsSync(rootPath)) mkdirSync(rootPath, { recursive: true });
3676
3328
  return rootPath;
3677
3329
  };
3678
3330
  Stack.parse = async function() {
@@ -3735,18 +3387,6 @@ var require_stack = __commonJS({
3735
3387
  return Stack.findService(serviceLabel);
3736
3388
  };
3737
3389
  Stack.selectConf = async function() {
3738
- const localLegacyPath = pathfs.resolve(require_stack().getRootPath(), "../.stackmonitor");
3739
- const localNewPath = pathfs.resolve(require_stack().getRootPath(), ".runeya");
3740
- if (existsSync(localLegacyPath) && !existsSync(localNewPath)) {
3741
- console.log("Legacy path found, move to new path");
3742
- await rename(localLegacyPath, localNewPath);
3743
- }
3744
- const globalLegacyPath = pathfs.resolve(require("os").homedir(), ".stackmonitor");
3745
- const globalNewPath = pathfs.resolve(require("os").homedir(), ".runeya-global");
3746
- if (existsSync(globalLegacyPath) && !existsSync(globalNewPath)) {
3747
- console.log("Legacy path found, move to new path");
3748
- await rename(globalLegacyPath, globalNewPath);
3749
- }
3750
3390
  await EncryptionKey.init();
3751
3391
  if (!EncryptionKey.encryptionKey) {
3752
3392
  await EncryptionKey.saveKey(await EncryptionKey.generateKey());
@@ -3806,6 +3446,414 @@ var require_stack = __commonJS({
3806
3446
  }
3807
3447
  });
3808
3448
 
3449
+ // models/EncryptionKey.js
3450
+ var require_EncryptionKey = __commonJS({
3451
+ "models/EncryptionKey.js"(exports2, module2) {
3452
+ "use strict";
3453
+ var { existsSync } = require("fs");
3454
+ var path = require("path");
3455
+ var { writeFile, readFile, appendFile } = require("fs/promises");
3456
+ var { randomUUID: randomUUID2 } = require("crypto");
3457
+ var dbs2 = require_dbs();
3458
+ var { generateKey, encrypt, decrypt } = require_crypto();
3459
+ var reencryptNodered = require_reencrypt_nodered();
3460
+ var pathfs = require("path");
3461
+ var args2 = require_args();
3462
+ var _EncryptionKey_instances, getDb_fn;
3463
+ var EncryptionKey = class {
3464
+ constructor() {
3465
+ __privateAdd(this, _EncryptionKey_instances);
3466
+ this.encryptionKey = "";
3467
+ }
3468
+ async init() {
3469
+ this.encryptionKey = (await __privateMethod(this, _EncryptionKey_instances, getDb_fn).call(this).read()).encryptionKey;
3470
+ }
3471
+ async update() {
3472
+ return __privateMethod(this, _EncryptionKey_instances, getDb_fn).call(this).write(this.toStorage());
3473
+ }
3474
+ toStorage() {
3475
+ return {
3476
+ encryptionKey: this.encryptionKey
3477
+ };
3478
+ }
3479
+ async generateKey() {
3480
+ return generateKey();
3481
+ }
3482
+ async testKey(encryptionKey) {
3483
+ try {
3484
+ const variable = randomUUID2();
3485
+ const result = await encrypt(variable, { encryptionKey });
3486
+ const decrypted = await decrypt(result, { encryptionKey });
3487
+ if (decrypted === variable) return true;
3488
+ return false;
3489
+ } catch (error) {
3490
+ console.error(error);
3491
+ return false;
3492
+ }
3493
+ }
3494
+ async saveKey(key, { noReload } = { noReload: false }) {
3495
+ if (!await this.testKey(key)) throw new Error("Key not valid");
3496
+ try {
3497
+ const envSample = (await dbs2.getDbs("envs"))[0];
3498
+ if (envSample) await dbs2.getDb(`envs/${envSample}`).read();
3499
+ if (this.encryptionKey) {
3500
+ await reencryptNodered(this.encryptionKey, key, pathfs.resolve(require_stack().getRootPath(), "nodered/flow_cred.json"));
3501
+ await dbs2.reencrypt(this.encryptionKey, key);
3502
+ }
3503
+ ;
3504
+ } catch (error) {
3505
+ console.error(error);
3506
+ }
3507
+ const shouldRestart = this.encryptionKey !== key;
3508
+ this.encryptionKey = key;
3509
+ await this.update();
3510
+ if (!noReload) {
3511
+ await require_stack().selectConf();
3512
+ }
3513
+ if (shouldRestart) {
3514
+ console.log("Restart...");
3515
+ require("child_process").spawn(process.argv[0], process.argv.slice(1), {
3516
+ cwd: args2.initialCwd,
3517
+ detached: true,
3518
+ stdio: "inherit"
3519
+ }).unref();
3520
+ process.exit(0);
3521
+ }
3522
+ return key;
3523
+ }
3524
+ };
3525
+ _EncryptionKey_instances = new WeakSet();
3526
+ getDb_fn = function() {
3527
+ return dbs2.getDb("encryption-key", { encrypted: false });
3528
+ };
3529
+ module2.exports = new EncryptionKey();
3530
+ }
3531
+ });
3532
+
3533
+ // helpers/crypto.js
3534
+ var require_crypto = __commonJS({
3535
+ "helpers/crypto.js"(exports2, module2) {
3536
+ "use strict";
3537
+ var _sodium = require("libsodium-wrappers");
3538
+ var crypto = require("crypto");
3539
+ var { sockets: sockets2 } = require_src();
3540
+ var conflictStorage = require_conflictStorage();
3541
+ var path = require("path");
3542
+ module2.exports.generateKey = async () => {
3543
+ await _sodium.ready;
3544
+ const sodium = _sodium;
3545
+ const key = sodium.crypto_aead_aegis256_keygen();
3546
+ return sodium.to_base64(key);
3547
+ };
3548
+ module2.exports.encrypt = async (data, { additionnalNonce = "", encryptionKey = "" } = {}) => {
3549
+ await _sodium.ready;
3550
+ const sodium = _sodium;
3551
+ if (!encryptionKey) encryptionKey = require_EncryptionKey().encryptionKey;
3552
+ const key = sodium.from_base64(encryptionKey);
3553
+ if (!key || key.length !== sodium.crypto_secretbox_KEYBYTES) {
3554
+ throw new Error("Invalid encryption key length");
3555
+ }
3556
+ let nonce;
3557
+ if (additionnalNonce) {
3558
+ const combinedHash = crypto.createHash("blake2b512").update(data + additionnalNonce).digest();
3559
+ nonce = combinedHash.slice(0, sodium.crypto_secretbox_NONCEBYTES);
3560
+ } else {
3561
+ nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
3562
+ }
3563
+ const dataStr = typeof data === "string" ? data : String(data);
3564
+ const dataArray = new TextEncoder().encode(dataStr);
3565
+ const ciphertext = sodium.crypto_secretbox_easy(dataArray, nonce, key);
3566
+ return Buffer.concat([
3567
+ Buffer.from(nonce.buffer, nonce.byteOffset, nonce.byteLength),
3568
+ Buffer.from(ciphertext.buffer, ciphertext.byteOffset, ciphertext.byteLength)
3569
+ ]).toString("base64");
3570
+ };
3571
+ module2.exports.decryptFile = async (encryptedData, options = {}, filePath) => {
3572
+ if (typeof encryptedData === "string" && (encryptedData.includes("<<<<<<< HEAD") || encryptedData.includes("=======") || encryptedData.includes(">>>>>>>"))) {
3573
+ return await handleGitConflict(encryptedData, options, filePath);
3574
+ }
3575
+ return await module2.exports.decrypt(encryptedData, options);
3576
+ };
3577
+ module2.exports.decrypt = async (encryptedData, { additionnalNonce = "", encryptionKey = "" } = {}) => {
3578
+ if (typeof encryptedData === "string" && (encryptedData.includes("<<<<<<< HEAD") || encryptedData.includes("=======") || encryptedData.includes(">>>>>>>"))) {
3579
+ return await handleGitConflict(encryptedData, { additionnalNonce, encryptionKey });
3580
+ }
3581
+ await _sodium.ready;
3582
+ const sodium = _sodium;
3583
+ if (!encryptionKey) encryptionKey = require_EncryptionKey().encryptionKey;
3584
+ const key = sodium.from_base64(encryptionKey);
3585
+ if (!key || key.length !== sodium.crypto_secretbox_KEYBYTES) {
3586
+ throw new Error("Invalid decryption key length");
3587
+ }
3588
+ const encryptedBuffer = Buffer.from(encryptedData, "base64");
3589
+ const nonce = encryptedBuffer.slice(0, sodium.crypto_secretbox_NONCEBYTES);
3590
+ const ciphertext = encryptedBuffer.slice(sodium.crypto_secretbox_NONCEBYTES);
3591
+ let decrypted;
3592
+ try {
3593
+ const ciphertextArray = new Uint8Array(ciphertext);
3594
+ const nonceArray = new Uint8Array(nonce);
3595
+ decrypted = sodium.crypto_secretbox_open_easy(ciphertextArray, nonceArray, key);
3596
+ } catch (error) {
3597
+ throw new Error("Decryption failed");
3598
+ }
3599
+ if (!decrypted) {
3600
+ throw new Error("Decryption failed");
3601
+ }
3602
+ return Buffer.from(decrypted).toString("utf-8");
3603
+ };
3604
+ async function handleGitConflict(conflictedData, options, filePath) {
3605
+ const headMatch = conflictedData.match(/<<<<<<< HEAD\r?\n([\s\S]*?)\r?\n=======\r?\n([\s\S]*?)\r?\n>>>>>>>.*/);
3606
+ if (!headMatch) {
3607
+ throw new Error("Git conflict detected but could not be properly parsed");
3608
+ }
3609
+ try {
3610
+ const ourVersion = headMatch[1];
3611
+ const theirVersion = headMatch[2];
3612
+ let ourDecrypted = "";
3613
+ let theirDecrypted = "";
3614
+ try {
3615
+ ourDecrypted = await module2.exports.decrypt(ourVersion, options);
3616
+ } catch (err) {
3617
+ const errorMessage = err instanceof Error ? err.message : String(err);
3618
+ ourDecrypted = `[ERROR DECRYPTING OUR VERSION: ${errorMessage}]`;
3619
+ }
3620
+ try {
3621
+ theirDecrypted = await module2.exports.decrypt(theirVersion, options);
3622
+ } catch (err) {
3623
+ const errorMessage = err instanceof Error ? err.message : String(err);
3624
+ theirDecrypted = `[ERROR DECRYPTING THEIR VERSION: ${errorMessage}]`;
3625
+ }
3626
+ const conflictData = {
3627
+ original: conflictedData,
3628
+ ourVersion: ourDecrypted,
3629
+ theirVersion: theirDecrypted,
3630
+ filePath: filePath || null,
3631
+ filename: filePath ? path.basename(filePath) : null
3632
+ };
3633
+ const conflictId = conflictStorage.storeConflict(conflictData);
3634
+ conflictData.id = conflictId;
3635
+ sockets2.emit("crypto:conflict", conflictData);
3636
+ return `${JSON.stringify({
3637
+ ourVersion: ourDecrypted,
3638
+ theirVersion: theirDecrypted
3639
+ })}`;
3640
+ } catch (error) {
3641
+ const errorMessage = error instanceof Error ? error.message : String(error);
3642
+ console.error("Error handling git conflict:", errorMessage);
3643
+ throw new Error(`Git conflict detected, but failed to process: ${errorMessage}`);
3644
+ }
3645
+ }
3646
+ }
3647
+ });
3648
+
3649
+ // helpers/dbs.js
3650
+ var require_dbs = __commonJS({
3651
+ "helpers/dbs.js"(exports2, module2) {
3652
+ "use strict";
3653
+ var {
3654
+ existsSync,
3655
+ mkdirSync,
3656
+ writeFileSync,
3657
+ readFileSync,
3658
+ unlinkSync
3659
+ } = require("fs");
3660
+ var pathfs = require("path");
3661
+ var {
3662
+ readdir,
3663
+ mkdir,
3664
+ writeFile,
3665
+ readFile,
3666
+ unlink
3667
+ } = require("fs/promises");
3668
+ var { fdir } = require("fdir");
3669
+ var PromiseB2 = require("bluebird");
3670
+ var { sockets: sockets2 } = require_src();
3671
+ var args2 = require_args();
3672
+ var { encrypt, decrypt, decryptFile } = require_crypto();
3673
+ var alasql = require("alasql");
3674
+ module2.exports = new class {
3675
+ constructor() {
3676
+ __publicField(this, "cache", {});
3677
+ }
3678
+ getRootPath() {
3679
+ const rootPath = pathfs.resolve(args2.rootPath, ".runeya/dbs");
3680
+ if (!existsSync(rootPath)) mkdirSync(rootPath, { recursive: true });
3681
+ return rootPath;
3682
+ }
3683
+ async getDbs(namespace = "") {
3684
+ const pathToDbs = pathfs.resolve(this.getRootPath(), namespace);
3685
+ if (!existsSync(pathToDbs)) await mkdir(pathToDbs, { recursive: true });
3686
+ return (await readdir(pathToDbs)).map((id) => id.replace(pathfs.extname(id), "").replace(".encrypted", ""));
3687
+ }
3688
+ async reencrypt(oldKey, newKey) {
3689
+ const api = new fdir().withFullPaths().filter((path) => path.endsWith("encrypted.json")).crawl(this.getRootPath());
3690
+ await PromiseB2.map(api.withPromise(), async (file) => {
3691
+ const fileEncrypted = await readFile(file, "utf-8");
3692
+ const additionnalNonce = file.split(".runeya").pop();
3693
+ const fileDecrypted = await decrypt(fileEncrypted, { additionnalNonce, encryptionKey: oldKey });
3694
+ const fileReEncrypted = await encrypt(fileDecrypted, { additionnalNonce, encryptionKey: newKey });
3695
+ await writeFile(file, fileReEncrypted, "utf-8");
3696
+ });
3697
+ }
3698
+ getDb(id, { encrypted, defaultData } = { encrypted: true, defaultData: {} }) {
3699
+ const getPath = async () => {
3700
+ const persistencePath = pathfs.resolve(`${this.getRootPath()}/${id}${encrypted ? ".encrypted" : ""}.json`);
3701
+ if (!existsSync(pathfs.dirname(persistencePath))) await mkdirSync(pathfs.dirname(persistencePath), { recursive: true });
3702
+ if (!existsSync(persistencePath)) {
3703
+ let defaultDB = JSON.stringify(defaultData || [], null, 2);
3704
+ if (encrypted) defaultDB = await encrypt(defaultDB, { additionnalNonce: persistencePath.split(".runeya").pop() });
3705
+ await writeFile(persistencePath, defaultDB, "utf-8");
3706
+ this.cache[id] = defaultDB;
3707
+ }
3708
+ return persistencePath;
3709
+ };
3710
+ const table = id.replace(/[^a-z0-9]|\s+|\r?\n|\r/gmi, "_");
3711
+ const read = async () => {
3712
+ if (this.cache[id]) return this.cache[id];
3713
+ const path = await getPath();
3714
+ const additionnalNonce = path.split(".runeya").pop();
3715
+ let db = readFileSync(path, "utf-8");
3716
+ if (encrypted) {
3717
+ try {
3718
+ if (typeof db === "string" && (db.includes("<<<<<<< HEAD") || db.includes("=======") || db.includes(">>>>>>>"))) {
3719
+ db = await decryptFile(db, { additionnalNonce }, path);
3720
+ } else {
3721
+ db = await decrypt(db, { additionnalNonce }).catch((err) => {
3722
+ console.error(path, err);
3723
+ sockets2.emit("system:wrongKey");
3724
+ throw err;
3725
+ });
3726
+ }
3727
+ } catch (err) {
3728
+ console.error(path, err);
3729
+ sockets2.emit("system:wrongKey");
3730
+ throw err;
3731
+ }
3732
+ }
3733
+ this.cache[id] = JSON.parse(db);
3734
+ if (!alasql.tables[table]) {
3735
+ await alasql(`CREATE TABLE ${table}`);
3736
+ }
3737
+ alasql.tables[table].data = this.cache[id];
3738
+ return this.cache[id];
3739
+ };
3740
+ const write = async (data) => {
3741
+ let db = JSON.stringify(data, null, 2);
3742
+ const path = await getPath();
3743
+ const additionnalNonce = path.split(".runeya").pop();
3744
+ if (encrypted) db = await encrypt(db, { additionnalNonce });
3745
+ writeFileSync(path, db, "utf-8");
3746
+ this.cache[id] = data;
3747
+ if (alasql.tables[table]) {
3748
+ alasql.tables[table].data = data;
3749
+ }
3750
+ };
3751
+ const escapeQuote = (data) => {
3752
+ if (typeof data === "string") {
3753
+ return data.replace(/'/g, "''");
3754
+ }
3755
+ return data;
3756
+ };
3757
+ const setValue = (item) => {
3758
+ if (item == null) {
3759
+ return "NULL";
3760
+ }
3761
+ if (item instanceof Date && item.toISOString) {
3762
+ return `'${item.toISOString()}'`;
3763
+ }
3764
+ if (typeof item === "string") {
3765
+ return `'${escapeQuote(item)}'`;
3766
+ }
3767
+ return `${item}`;
3768
+ };
3769
+ return {
3770
+ getPath,
3771
+ alasql: {
3772
+ table,
3773
+ buildUpdateQuery(data) {
3774
+ const set = [];
3775
+ Object.keys(data).forEach((key) => {
3776
+ set.push(`${key} = ${setValue(data[key])}`);
3777
+ });
3778
+ return set.join(", ");
3779
+ },
3780
+ read: async (sql) => {
3781
+ await read();
3782
+ return alasql.promise(sql);
3783
+ },
3784
+ /**
3785
+ *
3786
+ * @param {{where?: string, orderBy?: string, limit?: number, offset?: number}} param0
3787
+ * @returns {Promise<any[]>}
3788
+ */
3789
+ simpleSelect: async ({ where, orderBy, limit, offset }) => {
3790
+ await read();
3791
+ return alasql.promise(`SELECT * FROM ${table} ${where ? `WHERE ${where}` : ""} ${orderBy ? `ORDER BY ${orderBy}` : ""} ${limit ? `LIMIT ${limit}` : ""} ${offset ? `OFFSET ${offset}` : ""}`);
3792
+ },
3793
+ /** @param {string} where */
3794
+ delete: async (where) => {
3795
+ await read();
3796
+ await alasql.promise(`DELETE FROM ${table} WHERE ${where}`);
3797
+ await write(await alasql(`select * from ${table}`));
3798
+ },
3799
+ insertOne: async (data) => {
3800
+ await read();
3801
+ await alasql.promise(`INSERT INTO ${table} VALUES ${JSON.stringify(data)}`);
3802
+ await write(await alasql(`select * from ${table}`));
3803
+ },
3804
+ write: async (sql, value) => {
3805
+ await read();
3806
+ await alasql.promise(sql, value);
3807
+ await write(await alasql(`select * from ${table}`));
3808
+ }
3809
+ },
3810
+ write,
3811
+ read,
3812
+ delete: async () => {
3813
+ delete this.cache[id];
3814
+ return unlink(await getPath());
3815
+ }
3816
+ };
3817
+ }
3818
+ }();
3819
+ }
3820
+ });
3821
+
3822
+ // helpers/createDefaultFiles.js
3823
+ var require_createDefaultFiles = __commonJS({
3824
+ "helpers/createDefaultFiles.js"(exports2, module2) {
3825
+ "use strict";
3826
+ var pathfs = require("path");
3827
+ var { existsSync } = require("fs");
3828
+ var { writeFile, readFile, appendFile } = require("fs/promises");
3829
+ var args2 = require_args();
3830
+ var dbs2 = require_dbs();
3831
+ module2.exports = async function createDefaultFiles2() {
3832
+ await createGitignore();
3833
+ await createPluginsGitignore();
3834
+ };
3835
+ async function createPluginsGitignore() {
3836
+ const gitignorePath = pathfs.resolve(args2.runeyaConfigPath, ".gitignore");
3837
+ if (!existsSync(gitignorePath)) await writeFile(gitignorePath, "");
3838
+ const gitignoreFile = (await readFile(gitignorePath, "utf-8")).split("\n");
3839
+ const gitignoreHasKey = (key) => gitignoreFile.some((line) => line.trim() === key);
3840
+ if (!gitignoreHasKey("plugins.json")) await appendFile(gitignorePath, "\nplugins.json");
3841
+ if (!gitignoreHasKey("plugins")) await appendFile(gitignorePath, "\nplugins");
3842
+ }
3843
+ async function createGitignore() {
3844
+ const dirname = pathfs.dirname(await dbs2.getDb("encryption-key", { encrypted: false, defaultData: {} }).getPath());
3845
+ const gitignorePath = pathfs.resolve(dirname, ".gitignore");
3846
+ if (!existsSync(gitignorePath)) {
3847
+ await writeFile(gitignorePath, "encryption-key.json");
3848
+ }
3849
+ const gitignoreFile = (await readFile(gitignorePath, "utf-8")).split("\n");
3850
+ const gitignoreHasKey = (key) => gitignoreFile.some((line) => line.trim() === key);
3851
+ if (!gitignoreHasKey("encryption-key.json")) await appendFile(gitignorePath, "\nencryption-key.json");
3852
+ if (!gitignoreHasKey("overrides")) await appendFile(gitignorePath, "\noverrides");
3853
+ }
3854
+ }
3855
+ });
3856
+
3809
3857
  // helpers/console.table.js
3810
3858
  var require_console_table = __commonJS({
3811
3859
  "helpers/console.table.js"(exports2, module2) {
@@ -3845,7 +3893,7 @@ var require_plugins2 = __commonJS({
3845
3893
  var { tmpdir } = require("os");
3846
3894
  var path = require("path");
3847
3895
  var { existsSync } = require("fs");
3848
- var { writeFile, mkdir, readFile, cp, rm, readdir } = require("fs/promises");
3896
+ var { writeFile, mkdir, readFile, cp, rm, readdir, appendFile } = require("fs/promises");
3849
3897
  var { spawn } = require("child_process");
3850
3898
  var dbs2 = require_dbs();
3851
3899
  var HTTPError = require_src2();
@@ -5028,10 +5076,14 @@ var require_server = __commonJS({
5028
5076
 
5029
5077
  // bin/www
5030
5078
  var { sockets } = require_src();
5079
+ var migrateStackMonitor = require_migrateStackMonitor();
5080
+ var createDefaultFiles = require_createDefaultFiles();
5031
5081
  process.title = "runeya";
5032
5082
  var args = require_args();
5033
5083
  require("dotenv").config();
5034
5084
  (async () => {
5085
+ await migrateStackMonitor();
5086
+ await createDefaultFiles();
5035
5087
  if (args["pull-env"]) {
5036
5088
  await require_stack().selectConf();
5037
5089
  const service = require_stack().findService(args.s);