lsh-framework 3.2.4 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +72 -34
- package/dist/commands/ipfs.js +7 -12
- package/dist/commands/sync.js +51 -39
- package/dist/constants/config.js +3 -0
- package/dist/lib/floating-point-arithmetic.js +2 -2
- package/dist/lib/ipfs-client-manager.js +51 -13
- package/dist/lib/ipfs-secrets-storage.js +21 -16
- package/dist/lib/ipfs-sync.js +88 -14
- package/dist/lib/secrets-manager.js +117 -47
- package/dist/lib/sync-key-store.js +87 -0
- package/dist/services/secrets/secrets.js +77 -39
- package/package.json +16 -16
- package/dist/__tests__/fixtures/job-fixtures.js +0 -204
- package/dist/__tests__/fixtures/supabase-mocks.js +0 -252
- package/dist/daemon/job-registry.js +0 -556
- package/dist/daemon/lshd.js +0 -968
- package/dist/daemon/saas-api-routes.js +0 -599
- package/dist/daemon/saas-api-server.js +0 -231
- package/dist/examples/supabase-integration.js +0 -106
- package/dist/lib/api-response.js +0 -226
- package/dist/lib/base-command-registrar.js +0 -287
- package/dist/lib/base-job-manager.js +0 -295
- package/dist/lib/cloud-config-manager.js +0 -348
- package/dist/lib/cron-job-manager.js +0 -368
- package/dist/lib/daemon-client-helper.js +0 -145
- package/dist/lib/daemon-client.js +0 -513
- package/dist/lib/database-persistence.js +0 -727
- package/dist/lib/database-schema.js +0 -259
- package/dist/lib/database-types.js +0 -90
- package/dist/lib/enhanced-history-system.js +0 -247
- package/dist/lib/history-system.js +0 -246
- package/dist/lib/job-manager.js +0 -436
- package/dist/lib/job-storage-database.js +0 -164
- package/dist/lib/job-storage-memory.js +0 -73
- package/dist/lib/local-storage-adapter.js +0 -507
- package/dist/lib/optimized-job-scheduler.js +0 -356
- package/dist/lib/saas-audit.js +0 -215
- package/dist/lib/saas-auth.js +0 -465
- package/dist/lib/saas-billing.js +0 -503
- package/dist/lib/saas-email.js +0 -403
- package/dist/lib/saas-encryption.js +0 -221
- package/dist/lib/saas-organizations.js +0 -662
- package/dist/lib/saas-secrets.js +0 -408
- package/dist/lib/saas-types.js +0 -165
- package/dist/lib/supabase-client.js +0 -125
- package/dist/lib/supabase-utils.js +0 -396
- package/dist/services/cron/cron-registrar.js +0 -240
- package/dist/services/cron/cron.js +0 -9
- package/dist/services/daemon/daemon-registrar.js +0 -585
- package/dist/services/daemon/daemon.js +0 -9
- package/dist/services/supabase/supabase-registrar.js +0 -375
- package/dist/services/supabase/supabase.js +0 -9
|
@@ -1,507 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local File-Based Storage Adapter
|
|
3
|
-
* Provides persistence when Supabase/PostgreSQL is not available
|
|
4
|
-
* Uses JSON files for storage - suitable for development and single-user deployments
|
|
5
|
-
*/
|
|
6
|
-
import * as fs from 'fs/promises';
|
|
7
|
-
import * as path from 'path';
|
|
8
|
-
import * as os from 'os';
|
|
9
|
-
/**
|
|
10
|
-
* Local file-based storage adapter
|
|
11
|
-
* Implements same interface as DatabasePersistence but uses local JSON files
|
|
12
|
-
*/
|
|
13
|
-
export class LocalStorageAdapter {
|
|
14
|
-
dataDir;
|
|
15
|
-
dataFile;
|
|
16
|
-
data;
|
|
17
|
-
userId;
|
|
18
|
-
sessionId;
|
|
19
|
-
autoFlush;
|
|
20
|
-
flushInterval;
|
|
21
|
-
isDirty = false;
|
|
22
|
-
constructor(userId, config = {}) {
|
|
23
|
-
this.userId = userId;
|
|
24
|
-
this.sessionId = this.generateSessionId();
|
|
25
|
-
this.dataDir = config.dataDir || path.join(os.homedir(), '.lsh', 'data');
|
|
26
|
-
this.dataFile = path.join(this.dataDir, 'storage.json');
|
|
27
|
-
this.autoFlush = config.autoFlush !== false; // default true
|
|
28
|
-
// Initialize empty data structure
|
|
29
|
-
this.data = {
|
|
30
|
-
shell_history: [],
|
|
31
|
-
shell_jobs: [],
|
|
32
|
-
shell_configuration: [],
|
|
33
|
-
shell_sessions: [],
|
|
34
|
-
shell_aliases: [],
|
|
35
|
-
shell_functions: [],
|
|
36
|
-
shell_completions: [],
|
|
37
|
-
};
|
|
38
|
-
// Start auto-flush if enabled
|
|
39
|
-
if (this.autoFlush) {
|
|
40
|
-
const interval = config.flushInterval || 5000; // default 5s
|
|
41
|
-
this.flushInterval = setInterval(() => this.flush(), interval);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Initialize storage directory and load existing data
|
|
46
|
-
*/
|
|
47
|
-
async initialize() {
|
|
48
|
-
try {
|
|
49
|
-
// Create data directory if it doesn't exist
|
|
50
|
-
await fs.mkdir(this.dataDir, { recursive: true });
|
|
51
|
-
// Load existing data if file exists
|
|
52
|
-
try {
|
|
53
|
-
const content = await fs.readFile(this.dataFile, 'utf-8');
|
|
54
|
-
this.data = JSON.parse(content);
|
|
55
|
-
}
|
|
56
|
-
catch (_error) {
|
|
57
|
-
// File doesn't exist yet, use empty data
|
|
58
|
-
await this.flush();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
console.error('Failed to initialize local storage:', error);
|
|
63
|
-
throw error;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Flush in-memory data to disk
|
|
68
|
-
*/
|
|
69
|
-
async flush() {
|
|
70
|
-
if (!this.isDirty) {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
try {
|
|
74
|
-
await fs.writeFile(this.dataFile, JSON.stringify(this.data, null, 2), 'utf-8');
|
|
75
|
-
this.isDirty = false;
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
console.error('Failed to flush data to disk:', error);
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Mark data as dirty (needs flush)
|
|
84
|
-
*/
|
|
85
|
-
markDirty() {
|
|
86
|
-
this.isDirty = true;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Reload data from disk (useful to get latest data from other processes)
|
|
90
|
-
*/
|
|
91
|
-
async reload() {
|
|
92
|
-
try {
|
|
93
|
-
const content = await fs.readFile(this.dataFile, 'utf-8');
|
|
94
|
-
this.data = JSON.parse(content);
|
|
95
|
-
this.isDirty = false;
|
|
96
|
-
}
|
|
97
|
-
catch (_error) {
|
|
98
|
-
// File doesn't exist or can't be read - use current in-memory data
|
|
99
|
-
// Don't throw here, as this is expected on first run
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Cleanup and flush on exit
|
|
104
|
-
*/
|
|
105
|
-
async cleanup() {
|
|
106
|
-
if (this.flushInterval) {
|
|
107
|
-
clearInterval(this.flushInterval);
|
|
108
|
-
}
|
|
109
|
-
await this.flush();
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Generate a unique session ID
|
|
113
|
-
*/
|
|
114
|
-
generateSessionId() {
|
|
115
|
-
return `lsh_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Generate a unique ID
|
|
119
|
-
*/
|
|
120
|
-
generateId() {
|
|
121
|
-
return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Save shell history entry
|
|
125
|
-
*/
|
|
126
|
-
async saveHistoryEntry(entry) {
|
|
127
|
-
try {
|
|
128
|
-
const newEntry = {
|
|
129
|
-
...entry,
|
|
130
|
-
id: this.generateId(),
|
|
131
|
-
user_id: this.userId,
|
|
132
|
-
session_id: this.sessionId,
|
|
133
|
-
created_at: new Date().toISOString(),
|
|
134
|
-
updated_at: new Date().toISOString(),
|
|
135
|
-
};
|
|
136
|
-
this.data.shell_history.push(newEntry);
|
|
137
|
-
this.markDirty();
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
console.error('Error saving history entry:', error);
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Get shell history entries
|
|
147
|
-
*/
|
|
148
|
-
async getHistoryEntries(limit = 100, offset = 0) {
|
|
149
|
-
try {
|
|
150
|
-
const filtered = this.data.shell_history.filter(entry => this.userId ? entry.user_id === this.userId : entry.user_id === undefined || entry.user_id === null);
|
|
151
|
-
// Sort by timestamp descending
|
|
152
|
-
filtered.sort((a, b) => {
|
|
153
|
-
const timeA = new Date(a.timestamp).getTime();
|
|
154
|
-
const timeB = new Date(b.timestamp).getTime();
|
|
155
|
-
return timeB - timeA;
|
|
156
|
-
});
|
|
157
|
-
return filtered.slice(offset, offset + limit);
|
|
158
|
-
}
|
|
159
|
-
catch (error) {
|
|
160
|
-
console.error('Error getting history entries:', error);
|
|
161
|
-
return [];
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Save shell job
|
|
166
|
-
*/
|
|
167
|
-
async saveJob(job) {
|
|
168
|
-
try {
|
|
169
|
-
const newJob = {
|
|
170
|
-
...job,
|
|
171
|
-
id: this.generateId(),
|
|
172
|
-
user_id: this.userId,
|
|
173
|
-
session_id: this.sessionId,
|
|
174
|
-
created_at: new Date().toISOString(),
|
|
175
|
-
updated_at: new Date().toISOString(),
|
|
176
|
-
};
|
|
177
|
-
this.data.shell_jobs.push(newJob);
|
|
178
|
-
this.markDirty();
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
console.error('Error saving job:', error);
|
|
183
|
-
return false;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Update shell job status
|
|
188
|
-
*/
|
|
189
|
-
async updateJobStatus(jobId, status, exitCode) {
|
|
190
|
-
try {
|
|
191
|
-
const job = this.data.shell_jobs.find(j => j.job_id === jobId &&
|
|
192
|
-
(this.userId ? j.user_id === this.userId : j.user_id === undefined || j.user_id === null));
|
|
193
|
-
if (!job) {
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
job.status = status;
|
|
197
|
-
job.updated_at = new Date().toISOString();
|
|
198
|
-
if (status === 'completed' || status === 'failed') {
|
|
199
|
-
job.completed_at = new Date().toISOString();
|
|
200
|
-
if (exitCode !== undefined) {
|
|
201
|
-
job.exit_code = exitCode;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
this.markDirty();
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
catch (error) {
|
|
208
|
-
console.error('Error updating job status:', error);
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Get active jobs
|
|
214
|
-
*/
|
|
215
|
-
async getActiveJobs() {
|
|
216
|
-
try {
|
|
217
|
-
return this.data.shell_jobs
|
|
218
|
-
.filter(job => ['running', 'stopped', 'completed', 'failed'].includes(job.status) &&
|
|
219
|
-
(this.userId ? job.user_id === this.userId : job.user_id === undefined || job.user_id === null))
|
|
220
|
-
.sort((a, b) => {
|
|
221
|
-
const timeA = new Date(a.created_at || 0).getTime();
|
|
222
|
-
const timeB = new Date(b.created_at || 0).getTime();
|
|
223
|
-
return timeB - timeA;
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
catch (error) {
|
|
227
|
-
console.error('Error getting active jobs:', error);
|
|
228
|
-
return [];
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Save shell configuration
|
|
233
|
-
*/
|
|
234
|
-
async saveConfiguration(config) {
|
|
235
|
-
try {
|
|
236
|
-
// Find existing config
|
|
237
|
-
const existingIndex = this.data.shell_configuration.findIndex(c => c.user_id === (this.userId || null) &&
|
|
238
|
-
c.config_key === config.config_key);
|
|
239
|
-
const newConfig = {
|
|
240
|
-
...config,
|
|
241
|
-
id: existingIndex >= 0 ? this.data.shell_configuration[existingIndex].id : this.generateId(),
|
|
242
|
-
user_id: this.userId,
|
|
243
|
-
created_at: existingIndex >= 0 ? this.data.shell_configuration[existingIndex].created_at : new Date().toISOString(),
|
|
244
|
-
updated_at: new Date().toISOString(),
|
|
245
|
-
};
|
|
246
|
-
if (existingIndex >= 0) {
|
|
247
|
-
this.data.shell_configuration[existingIndex] = newConfig;
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
this.data.shell_configuration.push(newConfig);
|
|
251
|
-
}
|
|
252
|
-
this.markDirty();
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
catch (error) {
|
|
256
|
-
console.error('Error saving configuration:', error);
|
|
257
|
-
return false;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Get shell configuration
|
|
262
|
-
*/
|
|
263
|
-
async getConfiguration(key) {
|
|
264
|
-
try {
|
|
265
|
-
let filtered = this.data.shell_configuration.filter(config => this.userId ? config.user_id === this.userId : config.user_id === undefined || config.user_id === null);
|
|
266
|
-
if (key) {
|
|
267
|
-
filtered = filtered.filter(config => config.config_key === key);
|
|
268
|
-
}
|
|
269
|
-
return filtered;
|
|
270
|
-
}
|
|
271
|
-
catch (error) {
|
|
272
|
-
console.error('Error getting configuration:', error);
|
|
273
|
-
return [];
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Save shell alias
|
|
278
|
-
*/
|
|
279
|
-
async saveAlias(alias) {
|
|
280
|
-
try {
|
|
281
|
-
const existingIndex = this.data.shell_aliases.findIndex(a => a.user_id === (this.userId || null) &&
|
|
282
|
-
a.alias_name === alias.alias_name);
|
|
283
|
-
const newAlias = {
|
|
284
|
-
...alias,
|
|
285
|
-
id: existingIndex >= 0 ? this.data.shell_aliases[existingIndex].id : this.generateId(),
|
|
286
|
-
user_id: this.userId,
|
|
287
|
-
created_at: existingIndex >= 0 ? this.data.shell_aliases[existingIndex].created_at : new Date().toISOString(),
|
|
288
|
-
updated_at: new Date().toISOString(),
|
|
289
|
-
};
|
|
290
|
-
if (existingIndex >= 0) {
|
|
291
|
-
this.data.shell_aliases[existingIndex] = newAlias;
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
this.data.shell_aliases.push(newAlias);
|
|
295
|
-
}
|
|
296
|
-
this.markDirty();
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
console.error('Error saving alias:', error);
|
|
301
|
-
return false;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Get shell aliases
|
|
306
|
-
*/
|
|
307
|
-
async getAliases() {
|
|
308
|
-
try {
|
|
309
|
-
return this.data.shell_aliases.filter(alias => alias.is_active &&
|
|
310
|
-
(this.userId ? alias.user_id === this.userId : alias.user_id === undefined || alias.user_id === null));
|
|
311
|
-
}
|
|
312
|
-
catch (error) {
|
|
313
|
-
console.error('Error getting aliases:', error);
|
|
314
|
-
return [];
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Save shell function
|
|
319
|
-
*/
|
|
320
|
-
async saveFunction(func) {
|
|
321
|
-
try {
|
|
322
|
-
const existingIndex = this.data.shell_functions.findIndex(f => f.user_id === (this.userId || null) &&
|
|
323
|
-
f.function_name === func.function_name);
|
|
324
|
-
const newFunc = {
|
|
325
|
-
...func,
|
|
326
|
-
id: existingIndex >= 0 ? this.data.shell_functions[existingIndex].id : this.generateId(),
|
|
327
|
-
user_id: this.userId,
|
|
328
|
-
created_at: existingIndex >= 0 ? this.data.shell_functions[existingIndex].created_at : new Date().toISOString(),
|
|
329
|
-
updated_at: new Date().toISOString(),
|
|
330
|
-
};
|
|
331
|
-
if (existingIndex >= 0) {
|
|
332
|
-
this.data.shell_functions[existingIndex] = newFunc;
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
this.data.shell_functions.push(newFunc);
|
|
336
|
-
}
|
|
337
|
-
this.markDirty();
|
|
338
|
-
return true;
|
|
339
|
-
}
|
|
340
|
-
catch (error) {
|
|
341
|
-
console.error('Error saving function:', error);
|
|
342
|
-
return false;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Get shell functions
|
|
347
|
-
*/
|
|
348
|
-
async getFunctions() {
|
|
349
|
-
try {
|
|
350
|
-
return this.data.shell_functions.filter(func => func.is_active &&
|
|
351
|
-
(this.userId ? func.user_id === this.userId : func.user_id === undefined || func.user_id === null));
|
|
352
|
-
}
|
|
353
|
-
catch (error) {
|
|
354
|
-
console.error('Error getting functions:', error);
|
|
355
|
-
return [];
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Start a new shell session
|
|
360
|
-
*/
|
|
361
|
-
async startSession(workingDirectory, environmentVariables) {
|
|
362
|
-
try {
|
|
363
|
-
const newSession = {
|
|
364
|
-
id: this.generateId(),
|
|
365
|
-
user_id: this.userId,
|
|
366
|
-
session_id: this.sessionId,
|
|
367
|
-
hostname: os.hostname(),
|
|
368
|
-
working_directory: workingDirectory,
|
|
369
|
-
environment_variables: environmentVariables,
|
|
370
|
-
started_at: new Date().toISOString(),
|
|
371
|
-
is_active: true,
|
|
372
|
-
created_at: new Date().toISOString(),
|
|
373
|
-
updated_at: new Date().toISOString(),
|
|
374
|
-
};
|
|
375
|
-
this.data.shell_sessions.push(newSession);
|
|
376
|
-
this.markDirty();
|
|
377
|
-
return true;
|
|
378
|
-
}
|
|
379
|
-
catch (error) {
|
|
380
|
-
console.error('Error starting session:', error);
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* End the current shell session
|
|
386
|
-
*/
|
|
387
|
-
async endSession() {
|
|
388
|
-
try {
|
|
389
|
-
const session = this.data.shell_sessions.find(s => s.session_id === this.sessionId &&
|
|
390
|
-
(this.userId ? s.user_id === this.userId : s.user_id === undefined || s.user_id === null));
|
|
391
|
-
if (!session) {
|
|
392
|
-
return false;
|
|
393
|
-
}
|
|
394
|
-
session.ended_at = new Date().toISOString();
|
|
395
|
-
session.is_active = false;
|
|
396
|
-
session.updated_at = new Date().toISOString();
|
|
397
|
-
this.markDirty();
|
|
398
|
-
return true;
|
|
399
|
-
}
|
|
400
|
-
catch (error) {
|
|
401
|
-
console.error('Error ending session:', error);
|
|
402
|
-
return false;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
/**
|
|
406
|
-
* Test storage connectivity (always succeeds for local storage)
|
|
407
|
-
*/
|
|
408
|
-
async testConnection() {
|
|
409
|
-
try {
|
|
410
|
-
await fs.access(this.dataDir);
|
|
411
|
-
return true;
|
|
412
|
-
}
|
|
413
|
-
catch (_error) {
|
|
414
|
-
return false;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Get session ID
|
|
419
|
-
*/
|
|
420
|
-
getSessionId() {
|
|
421
|
-
return this.sessionId;
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Get latest rows from all tables
|
|
425
|
-
*/
|
|
426
|
-
async getLatestRows(limit = 5) {
|
|
427
|
-
const result = {};
|
|
428
|
-
try {
|
|
429
|
-
// Get latest shell history entries
|
|
430
|
-
const history = this.data.shell_history
|
|
431
|
-
.filter(entry => this.userId ? entry.user_id === this.userId : entry.user_id === undefined || entry.user_id === null)
|
|
432
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
433
|
-
.slice(0, limit);
|
|
434
|
-
result.shell_history = history;
|
|
435
|
-
// Get latest shell jobs
|
|
436
|
-
const jobs = this.data.shell_jobs
|
|
437
|
-
.filter(job => this.userId ? job.user_id === this.userId : job.user_id === undefined || job.user_id === null)
|
|
438
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
439
|
-
.slice(0, limit);
|
|
440
|
-
result.shell_jobs = jobs;
|
|
441
|
-
// Get latest shell configuration
|
|
442
|
-
const config = this.data.shell_configuration
|
|
443
|
-
.filter(cfg => this.userId ? cfg.user_id === this.userId : cfg.user_id === undefined || cfg.user_id === null)
|
|
444
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
445
|
-
.slice(0, limit);
|
|
446
|
-
result.shell_configuration = config;
|
|
447
|
-
// Get latest shell sessions
|
|
448
|
-
const sessions = this.data.shell_sessions
|
|
449
|
-
.filter(session => this.userId ? session.user_id === this.userId : session.user_id === undefined || session.user_id === null)
|
|
450
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
451
|
-
.slice(0, limit);
|
|
452
|
-
result.shell_sessions = sessions;
|
|
453
|
-
// Get latest shell aliases
|
|
454
|
-
const aliases = this.data.shell_aliases
|
|
455
|
-
.filter(alias => this.userId ? alias.user_id === this.userId : alias.user_id === undefined || alias.user_id === null)
|
|
456
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
457
|
-
.slice(0, limit);
|
|
458
|
-
result.shell_aliases = aliases;
|
|
459
|
-
// Get latest shell functions
|
|
460
|
-
const functions = this.data.shell_functions
|
|
461
|
-
.filter(func => this.userId ? func.user_id === this.userId : func.user_id === undefined || func.user_id === null)
|
|
462
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
463
|
-
.slice(0, limit);
|
|
464
|
-
result.shell_functions = functions;
|
|
465
|
-
// Get latest shell completions
|
|
466
|
-
const completions = this.data.shell_completions
|
|
467
|
-
.filter(comp => this.userId ? comp.user_id === this.userId : comp.user_id === undefined || comp.user_id === null)
|
|
468
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
469
|
-
.slice(0, limit);
|
|
470
|
-
result.shell_completions = completions;
|
|
471
|
-
return result;
|
|
472
|
-
}
|
|
473
|
-
catch (error) {
|
|
474
|
-
console.error('Error getting latest rows:', error);
|
|
475
|
-
return {};
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Get latest rows from a specific table
|
|
480
|
-
*/
|
|
481
|
-
async getLatestRowsFromTable(tableName, limit = 5) {
|
|
482
|
-
try {
|
|
483
|
-
const validTables = [
|
|
484
|
-
'shell_history',
|
|
485
|
-
'shell_jobs',
|
|
486
|
-
'shell_configuration',
|
|
487
|
-
'shell_sessions',
|
|
488
|
-
'shell_aliases',
|
|
489
|
-
'shell_functions',
|
|
490
|
-
'shell_completions',
|
|
491
|
-
];
|
|
492
|
-
if (!validTables.includes(tableName)) {
|
|
493
|
-
throw new Error(`Invalid table name: ${tableName}`);
|
|
494
|
-
}
|
|
495
|
-
const table = this.data[tableName];
|
|
496
|
-
return table
|
|
497
|
-
.filter(row => this.userId ? row.user_id === this.userId : row.user_id === undefined || row.user_id === null)
|
|
498
|
-
.sort((a, b) => new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())
|
|
499
|
-
.slice(0, limit);
|
|
500
|
-
}
|
|
501
|
-
catch (error) {
|
|
502
|
-
console.error(`Error getting latest rows from ${tableName}:`, error);
|
|
503
|
-
return [];
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
export default LocalStorageAdapter;
|