waengine 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/storage.js ADDED
@@ -0,0 +1,422 @@
1
+ // WAEngine Storage System - Einfaches Daten-Management
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ export class WAStorage {
6
+ constructor(baseDir = './waengine-data') {
7
+ this.baseDir = baseDir;
8
+ this.cache = new Map();
9
+ this.ensureBaseDir();
10
+
11
+ console.log(`💾 WAStorage initialisiert: ${baseDir}`);
12
+ }
13
+
14
+ // ===== SETUP =====
15
+
16
+ ensureBaseDir() {
17
+ if (!fs.existsSync(this.baseDir)) {
18
+ fs.mkdirSync(this.baseDir, { recursive: true });
19
+ // Stille Directory-Erstellung
20
+ }
21
+ }
22
+
23
+ getFilePath(fileName) {
24
+ // Automatisch .json hinzufügen falls nicht vorhanden
25
+ if (!fileName.endsWith('.json')) {
26
+ fileName += '.json';
27
+ }
28
+ return path.join(this.baseDir, fileName);
29
+ }
30
+
31
+ // ===== WRITE SYSTEM =====
32
+
33
+ write = {
34
+ // write.in("datei") - Schreibt Daten in Datei
35
+ in: (fileName) => {
36
+ return {
37
+ // write.in("datei").data(object)
38
+ data: (data) => {
39
+ return this.writeData(fileName, data);
40
+ },
41
+
42
+ // write.in("datei").append(object)
43
+ append: (data) => {
44
+ return this.appendData(fileName, data);
45
+ },
46
+
47
+ // write.in("datei").set(key, value)
48
+ set: (key, value) => {
49
+ return this.setKey(fileName, key, value);
50
+ },
51
+
52
+ // write.in("datei").push(value) - Für Arrays
53
+ push: (value) => {
54
+ return this.pushToArray(fileName, value);
55
+ },
56
+
57
+ // write.in("datei").increment(key, amount)
58
+ increment: (key, amount = 1) => {
59
+ return this.incrementKey(fileName, key, amount);
60
+ }
61
+ };
62
+ }
63
+ };
64
+
65
+ // ===== READ SYSTEM =====
66
+
67
+ read = {
68
+ // read.from("datei")
69
+ from: (fileName) => {
70
+ return {
71
+ // read.from("datei").all()
72
+ all: () => {
73
+ return this.readData(fileName);
74
+ },
75
+
76
+ // read.from("datei").get(key)
77
+ get: (key) => {
78
+ return this.getKey(fileName, key);
79
+ },
80
+
81
+ // read.from("datei").keys()
82
+ keys: () => {
83
+ const data = this.readData(fileName);
84
+ return data ? Object.keys(data) : [];
85
+ },
86
+
87
+ // read.from("datei").values()
88
+ values: () => {
89
+ const data = this.readData(fileName);
90
+ return data ? Object.values(data) : [];
91
+ },
92
+
93
+ // read.from("datei").length() - Für Arrays
94
+ length: () => {
95
+ const data = this.readData(fileName);
96
+ return Array.isArray(data) ? data.length : 0;
97
+ },
98
+
99
+ // read.from("datei").exists()
100
+ exists: () => {
101
+ return this.fileExists(fileName);
102
+ }
103
+ };
104
+ }
105
+ };
106
+
107
+ // ===== DELETE SYSTEM =====
108
+
109
+ delete = {
110
+ // delete.from("datei")
111
+ from: (fileName) => {
112
+ return {
113
+ // delete.from("datei").all()
114
+ all: () => {
115
+ return this.deleteFile(fileName);
116
+ },
117
+
118
+ // delete.from("datei").key(key)
119
+ key: (key) => {
120
+ return this.deleteKey(fileName, key);
121
+ },
122
+
123
+ // delete.from("datei").where(condition)
124
+ where: (condition) => {
125
+ return this.deleteWhere(fileName, condition);
126
+ }
127
+ };
128
+ }
129
+ };
130
+
131
+ // ===== CORE METHODS =====
132
+
133
+ writeData(fileName, data) {
134
+ try {
135
+ const filePath = this.getFilePath(fileName);
136
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
137
+ this.cache.set(fileName, data);
138
+ // Stille Speicherung - keine Console-Ausgabe
139
+ return true;
140
+ } catch (error) {
141
+ console.error(`❌ Fehler beim Schreiben in ${fileName}:`, error);
142
+ return false;
143
+ }
144
+ }
145
+
146
+ readData(fileName) {
147
+ try {
148
+ // Cache prüfen
149
+ if (this.cache.has(fileName)) {
150
+ return this.cache.get(fileName);
151
+ }
152
+
153
+ const filePath = this.getFilePath(fileName);
154
+
155
+ if (!fs.existsSync(filePath)) {
156
+ return null;
157
+ }
158
+
159
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
160
+ this.cache.set(fileName, data);
161
+ return data;
162
+ } catch (error) {
163
+ console.error(`❌ Fehler beim Lesen von ${fileName}:`, error);
164
+ return null;
165
+ }
166
+ }
167
+
168
+ appendData(fileName, newData) {
169
+ const existingData = this.readData(fileName) || [];
170
+
171
+ if (Array.isArray(existingData)) {
172
+ existingData.push(newData);
173
+ } else {
174
+ // Wenn Object, merge
175
+ Object.assign(existingData, newData);
176
+ }
177
+
178
+ return this.writeData(fileName, existingData);
179
+ }
180
+
181
+ setKey(fileName, key, value) {
182
+ let data = this.readData(fileName) || {};
183
+
184
+ // Nested keys unterstützen (z.B. "user.settings.theme")
185
+ if (key.includes('.')) {
186
+ const keys = key.split('.');
187
+ let current = data;
188
+
189
+ for (let i = 0; i < keys.length - 1; i++) {
190
+ if (!current[keys[i]]) {
191
+ current[keys[i]] = {};
192
+ }
193
+ current = current[keys[i]];
194
+ }
195
+
196
+ current[keys[keys.length - 1]] = value;
197
+ } else {
198
+ data[key] = value;
199
+ }
200
+
201
+ return this.writeData(fileName, data);
202
+ }
203
+
204
+ getKey(fileName, key) {
205
+ const data = this.readData(fileName);
206
+ if (!data) return null;
207
+
208
+ // Nested keys unterstützen
209
+ if (key.includes('.')) {
210
+ const keys = key.split('.');
211
+ let current = data;
212
+
213
+ for (const k of keys) {
214
+ if (current[k] === undefined) {
215
+ return null;
216
+ }
217
+ current = current[k];
218
+ }
219
+
220
+ return current;
221
+ }
222
+
223
+ return data[key];
224
+ }
225
+
226
+ pushToArray(fileName, value) {
227
+ let data = this.readData(fileName);
228
+
229
+ if (!data) {
230
+ data = [];
231
+ } else if (!Array.isArray(data)) {
232
+ console.error(`❌ ${fileName} ist kein Array!`);
233
+ return false;
234
+ }
235
+
236
+ data.push(value);
237
+ return this.writeData(fileName, data);
238
+ }
239
+
240
+ incrementKey(fileName, key, amount = 1) {
241
+ const currentValue = this.getKey(fileName, key) || 0;
242
+ const newValue = currentValue + amount;
243
+ return this.setKey(fileName, key, newValue);
244
+ }
245
+
246
+ deleteFile(fileName) {
247
+ try {
248
+ const filePath = this.getFilePath(fileName);
249
+
250
+ if (fs.existsSync(filePath)) {
251
+ fs.unlinkSync(filePath);
252
+ this.cache.delete(fileName);
253
+ // Stille Löschung
254
+ return true;
255
+ }
256
+
257
+ return false;
258
+ } catch (error) {
259
+ console.error(`❌ Fehler beim Löschen von ${fileName}:`, error);
260
+ return false;
261
+ }
262
+ }
263
+
264
+ deleteKey(fileName, key) {
265
+ let data = this.readData(fileName);
266
+ if (!data) return false;
267
+
268
+ if (key.includes('.')) {
269
+ // Nested key löschen
270
+ const keys = key.split('.');
271
+ let current = data;
272
+
273
+ for (let i = 0; i < keys.length - 1; i++) {
274
+ if (!current[keys[i]]) {
275
+ return false;
276
+ }
277
+ current = current[keys[i]];
278
+ }
279
+
280
+ delete current[keys[keys.length - 1]];
281
+ } else {
282
+ delete data[key];
283
+ }
284
+
285
+ return this.writeData(fileName, data);
286
+ }
287
+
288
+ deleteWhere(fileName, condition) {
289
+ let data = this.readData(fileName);
290
+ if (!data) return false;
291
+
292
+ if (Array.isArray(data)) {
293
+ // Array filtern
294
+ const originalLength = data.length;
295
+ data = data.filter(item => !condition(item));
296
+
297
+ if (data.length !== originalLength) {
298
+ return this.writeData(fileName, data);
299
+ }
300
+ } else {
301
+ // Object filtern
302
+ let changed = false;
303
+
304
+ for (const [key, value] of Object.entries(data)) {
305
+ if (condition(value, key)) {
306
+ delete data[key];
307
+ changed = true;
308
+ }
309
+ }
310
+
311
+ if (changed) {
312
+ return this.writeData(fileName, data);
313
+ }
314
+ }
315
+
316
+ return false;
317
+ }
318
+
319
+ fileExists(fileName) {
320
+ const filePath = this.getFilePath(fileName);
321
+ return fs.existsSync(filePath);
322
+ }
323
+
324
+ // ===== UTILITY METHODS =====
325
+
326
+ // Alle Dateien auflisten
327
+ listFiles() {
328
+ try {
329
+ const files = fs.readdirSync(this.baseDir);
330
+ return files.filter(file => file.endsWith('.json')).map(file => file.replace('.json', ''));
331
+ } catch (error) {
332
+ console.error('❌ Fehler beim Auflisten der Dateien:', error);
333
+ return [];
334
+ }
335
+ }
336
+
337
+ // Cache leeren
338
+ clearCache() {
339
+ this.cache.clear();
340
+ // Stille Cache-Bereinigung
341
+ }
342
+
343
+ // Backup erstellen
344
+ backup(backupDir = './waengine-backup') {
345
+ try {
346
+ if (!fs.existsSync(backupDir)) {
347
+ fs.mkdirSync(backupDir, { recursive: true });
348
+ }
349
+
350
+ const files = fs.readdirSync(this.baseDir);
351
+ let backedUp = 0;
352
+
353
+ for (const file of files) {
354
+ const srcPath = path.join(this.baseDir, file);
355
+ const destPath = path.join(backupDir, file);
356
+ fs.copyFileSync(srcPath, destPath);
357
+ backedUp++;
358
+ }
359
+
360
+ // Nur bei explizitem Backup eine Meldung
361
+ console.log(`💾 Backup erstellt: ${backedUp} Dateien in ${backupDir}`);
362
+ return backupDir;
363
+ } catch (error) {
364
+ console.error('❌ Backup Fehler:', error);
365
+ return false;
366
+ }
367
+ }
368
+
369
+ // Storage Statistics
370
+ getStats() {
371
+ const files = this.listFiles();
372
+ let totalSize = 0;
373
+
374
+ for (const file of files) {
375
+ try {
376
+ const filePath = this.getFilePath(file);
377
+ const stats = fs.statSync(filePath);
378
+ totalSize += stats.size;
379
+ } catch (error) {
380
+ // Ignore
381
+ }
382
+ }
383
+
384
+ return {
385
+ totalFiles: files.length,
386
+ totalSize: totalSize,
387
+ totalSizeFormatted: this.formatBytes(totalSize),
388
+ cacheSize: this.cache.size,
389
+ baseDir: this.baseDir,
390
+ files: files
391
+ };
392
+ }
393
+
394
+ formatBytes(bytes) {
395
+ if (bytes === 0) return '0 Bytes';
396
+ const k = 1024;
397
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
398
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
399
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
400
+ }
401
+ }
402
+
403
+ // ===== GLOBAL STORAGE INSTANCE =====
404
+
405
+ let globalStorage = null;
406
+
407
+ export function createStorage(baseDir) {
408
+ return new WAStorage(baseDir);
409
+ }
410
+
411
+ export function getStorage() {
412
+ if (!globalStorage) {
413
+ globalStorage = new WAStorage();
414
+ }
415
+ return globalStorage;
416
+ }
417
+
418
+ // ===== SHORTHAND FUNCTIONS =====
419
+
420
+ export const write = getStorage().write;
421
+ export const read = getStorage().read;
422
+ export const del = getStorage().delete;