lsh-framework 0.7.0 → 0.8.1
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/README.md +4 -4
- package/dist/cli.js +27 -19
- package/dist/lib/secrets-manager.js +69 -8
- package/dist/services/secrets/secrets.js +105 -1
- package/package.json +8 -8
- package/dist/services/api/api.js +0 -58
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ lsh lib secrets pull --env prod # for production debugging
|
|
|
126
126
|
| `lsh lib secrets create` | Create new .env file |
|
|
127
127
|
| `lsh lib secrets delete` | Delete .env file (with confirmation) |
|
|
128
128
|
|
|
129
|
-
See the complete guide: [SECRETS_GUIDE.md](SECRETS_GUIDE.md)
|
|
129
|
+
See the complete guide: [SECRETS_GUIDE.md](docs/features/secrets/SECRETS_GUIDE.md)
|
|
130
130
|
|
|
131
131
|
## Installation
|
|
132
132
|
|
|
@@ -536,10 +536,10 @@ lsh lib daemon start
|
|
|
536
536
|
|
|
537
537
|
## Documentation
|
|
538
538
|
|
|
539
|
-
- **[SECRETS_GUIDE.md](SECRETS_GUIDE.md)** - Complete secrets management guide
|
|
540
|
-
- **[SECRETS_QUICK_REFERENCE.md](SECRETS_QUICK_REFERENCE.md)** - Quick reference for daily use
|
|
539
|
+
- **[SECRETS_GUIDE.md](docs/features/secrets/SECRETS_GUIDE.md)** - Complete secrets management guide
|
|
540
|
+
- **[SECRETS_QUICK_REFERENCE.md](docs/features/secrets/SECRETS_QUICK_REFERENCE.md)** - Quick reference for daily use
|
|
541
541
|
- **[SECRETS_CHEATSHEET.txt](SECRETS_CHEATSHEET.txt)** - Command cheatsheet
|
|
542
|
-
- **[INSTALL.md](INSTALL.md)** - Detailed installation instructions
|
|
542
|
+
- **[INSTALL.md](docs/deployment/INSTALL.md)** - Detailed installation instructions
|
|
543
543
|
- **[CLAUDE.md](CLAUDE.md)** - Developer guide for contributors
|
|
544
544
|
|
|
545
545
|
## Architecture
|
package/dist/cli.js
CHANGED
|
@@ -72,13 +72,13 @@ program
|
|
|
72
72
|
console.log('LSH - Encrypted Secrets Manager with Automatic Rotation');
|
|
73
73
|
console.log('');
|
|
74
74
|
console.log('🔐 Secrets Management (Primary Features):');
|
|
75
|
-
console.log('
|
|
76
|
-
console.log('
|
|
77
|
-
console.log('
|
|
78
|
-
console.log('
|
|
79
|
-
console.log('
|
|
80
|
-
console.log('
|
|
81
|
-
console.log('
|
|
75
|
+
console.log(' secrets sync Check sync status & get recommendations');
|
|
76
|
+
console.log(' secrets push Upload .env to encrypted cloud storage');
|
|
77
|
+
console.log(' secrets pull Download .env from cloud storage');
|
|
78
|
+
console.log(' secrets list List all stored environments');
|
|
79
|
+
console.log(' secrets show View secrets (masked)');
|
|
80
|
+
console.log(' secrets key Generate encryption key');
|
|
81
|
+
console.log(' secrets create Create new .env file');
|
|
82
82
|
console.log('');
|
|
83
83
|
console.log('🔄 Automation (Schedule secret rotation):');
|
|
84
84
|
console.log(' lib cron add Schedule automatic tasks');
|
|
@@ -86,14 +86,17 @@ program
|
|
|
86
86
|
console.log(' lib daemon start Start persistent daemon');
|
|
87
87
|
console.log('');
|
|
88
88
|
console.log('🚀 Quick Start:');
|
|
89
|
-
console.log(' lsh
|
|
90
|
-
console.log(' lsh
|
|
91
|
-
console.log(' lsh
|
|
89
|
+
console.log(' lsh secrets key # Generate encryption key');
|
|
90
|
+
console.log(' lsh secrets push --env dev # Push your secrets');
|
|
91
|
+
console.log(' lsh secrets pull --env dev # Pull on another machine');
|
|
92
92
|
console.log('');
|
|
93
93
|
console.log('📚 More Commands:');
|
|
94
94
|
console.log(' lib api API server management');
|
|
95
95
|
console.log(' lib supabase Supabase database management');
|
|
96
|
+
console.log(' lib daemon Daemon management');
|
|
97
|
+
console.log(' lib cron Cron job management');
|
|
96
98
|
console.log(' self Self-management commands');
|
|
99
|
+
console.log(' self zsh ZSH compatibility commands');
|
|
97
100
|
console.log(' -i, --interactive Start interactive shell');
|
|
98
101
|
console.log(' --help Show all options');
|
|
99
102
|
console.log('');
|
|
@@ -137,8 +140,10 @@ program
|
|
|
137
140
|
process.exit(1);
|
|
138
141
|
}
|
|
139
142
|
});
|
|
140
|
-
//
|
|
141
|
-
program
|
|
143
|
+
// Self-management commands
|
|
144
|
+
program.addCommand(selfCommand);
|
|
145
|
+
// ZSH compatibility commands (under self)
|
|
146
|
+
selfCommand
|
|
142
147
|
.command('zsh')
|
|
143
148
|
.description('ZSH compatibility commands')
|
|
144
149
|
.option('--migrate', 'Migrate ZSH configuration to LSH')
|
|
@@ -153,8 +158,6 @@ program
|
|
|
153
158
|
process.exit(1);
|
|
154
159
|
}
|
|
155
160
|
});
|
|
156
|
-
// Self-management commands
|
|
157
|
-
program.addCommand(selfCommand);
|
|
158
161
|
// Help subcommand
|
|
159
162
|
program
|
|
160
163
|
.command('help')
|
|
@@ -216,8 +219,9 @@ function findSimilarCommands(input, validCommands) {
|
|
|
216
219
|
await init_supabase(libCommand);
|
|
217
220
|
await init_daemon(libCommand);
|
|
218
221
|
await init_cron(libCommand);
|
|
219
|
-
await init_secrets(libCommand);
|
|
220
222
|
registerApiCommands(libCommand);
|
|
223
|
+
// Secrets as top-level command
|
|
224
|
+
await init_secrets(program);
|
|
221
225
|
// Self-management commands with nested utilities
|
|
222
226
|
registerZshImportCommands(selfCommand);
|
|
223
227
|
registerThemeCommands(selfCommand);
|
|
@@ -573,10 +577,10 @@ function showDetailedHelp() {
|
|
|
573
577
|
console.log(' -V, --version Show version');
|
|
574
578
|
console.log('');
|
|
575
579
|
console.log('Subcommands:');
|
|
580
|
+
console.log(' secrets Secrets management (primary feature)');
|
|
576
581
|
console.log(' repl JavaScript REPL interactive shell');
|
|
577
582
|
console.log(' script <file> Execute shell script');
|
|
578
583
|
console.log(' config Manage configuration');
|
|
579
|
-
console.log(' zsh ZSH compatibility commands');
|
|
580
584
|
console.log(' help Show detailed help');
|
|
581
585
|
console.log('');
|
|
582
586
|
console.log('Self-Management (lsh self <command>):');
|
|
@@ -584,6 +588,7 @@ function showDetailedHelp() {
|
|
|
584
588
|
console.log(' self version Show version information');
|
|
585
589
|
console.log(' self uninstall Uninstall LSH from system');
|
|
586
590
|
console.log(' self theme Manage themes (import Oh-My-Zsh themes)');
|
|
591
|
+
console.log(' self zsh ZSH compatibility commands');
|
|
587
592
|
console.log(' self zsh-import Import ZSH configs (aliases, functions, exports)');
|
|
588
593
|
console.log('');
|
|
589
594
|
console.log('Library Commands (lsh lib <command>):');
|
|
@@ -593,7 +598,6 @@ function showDetailedHelp() {
|
|
|
593
598
|
console.log(' lib daemon job Job management');
|
|
594
599
|
console.log(' lib daemon db Database integration');
|
|
595
600
|
console.log(' lib cron Cron job management');
|
|
596
|
-
console.log(' lib secrets Secrets management');
|
|
597
601
|
console.log('');
|
|
598
602
|
console.log('Examples:');
|
|
599
603
|
console.log('');
|
|
@@ -617,13 +621,17 @@ function showDetailedHelp() {
|
|
|
617
621
|
console.log(' lsh self theme import robbyrussell # Import Oh-My-Zsh theme');
|
|
618
622
|
console.log(' lsh self zsh-import aliases # Import ZSH aliases');
|
|
619
623
|
console.log('');
|
|
624
|
+
console.log(' Secrets Management:');
|
|
625
|
+
console.log(' lsh secrets sync # Check sync status');
|
|
626
|
+
console.log(' lsh secrets push # Push secrets to cloud');
|
|
627
|
+
console.log(' lsh secrets pull # Pull secrets from cloud');
|
|
628
|
+
console.log(' lsh secrets list # List environments');
|
|
629
|
+
console.log('');
|
|
620
630
|
console.log(' Library Services:');
|
|
621
631
|
console.log(' lsh lib daemon start # Start daemon');
|
|
622
632
|
console.log(' lsh lib daemon status # Check daemon status');
|
|
623
633
|
console.log(' lsh lib daemon job list # List all jobs');
|
|
624
634
|
console.log(' lsh lib cron list # List cron jobs');
|
|
625
|
-
console.log(' lsh lib secrets push # Push secrets to cloud');
|
|
626
|
-
console.log(' lsh lib secrets list # List environments');
|
|
627
635
|
console.log(' lsh lib api start # Start API server');
|
|
628
636
|
console.log(' lsh lib api key # Generate API key');
|
|
629
637
|
console.log('');
|
|
@@ -117,6 +117,11 @@ export class SecretsManager {
|
|
|
117
117
|
if (!fs.existsSync(envFilePath)) {
|
|
118
118
|
throw new Error(`File not found: ${envFilePath}`);
|
|
119
119
|
}
|
|
120
|
+
// Validate filename pattern for custom files
|
|
121
|
+
const filename = path.basename(envFilePath);
|
|
122
|
+
if (filename !== '.env' && !filename.startsWith('.env.')) {
|
|
123
|
+
throw new Error(`Invalid filename: ${filename}. Must be '.env' or start with '.env.'`);
|
|
124
|
+
}
|
|
120
125
|
// Warn if using default key
|
|
121
126
|
if (!process.env.LSH_SECRETS_KEY) {
|
|
122
127
|
logger.warn('⚠️ Warning: No LSH_SECRETS_KEY set. Using machine-specific key.');
|
|
@@ -129,9 +134,10 @@ export class SecretsManager {
|
|
|
129
134
|
const env = this.parseEnvFile(content);
|
|
130
135
|
// Encrypt entire .env content
|
|
131
136
|
const encrypted = this.encrypt(content);
|
|
132
|
-
//
|
|
137
|
+
// Include filename in job_id for tracking multiple .env files
|
|
138
|
+
const safeFilename = filename.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
133
139
|
const secretData = {
|
|
134
|
-
job_id: `secrets_${environment}_${Date.now()}`,
|
|
140
|
+
job_id: `secrets_${environment}_${safeFilename}_${Date.now()}`,
|
|
135
141
|
command: 'secrets_sync',
|
|
136
142
|
status: 'completed',
|
|
137
143
|
output: encrypted,
|
|
@@ -140,20 +146,31 @@ export class SecretsManager {
|
|
|
140
146
|
working_directory: process.cwd(),
|
|
141
147
|
};
|
|
142
148
|
await this.persistence.saveJob(secretData);
|
|
143
|
-
logger.info(`✅ Pushed ${Object.keys(env).length} secrets to Supabase`);
|
|
149
|
+
logger.info(`✅ Pushed ${Object.keys(env).length} secrets from ${filename} to Supabase`);
|
|
144
150
|
}
|
|
145
151
|
/**
|
|
146
152
|
* Pull .env from Supabase
|
|
147
153
|
*/
|
|
148
154
|
async pull(envFilePath = '.env', environment = 'dev', force = false) {
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
// Validate filename pattern for custom files
|
|
156
|
+
const filename = path.basename(envFilePath);
|
|
157
|
+
if (filename !== '.env' && !filename.startsWith('.env.')) {
|
|
158
|
+
throw new Error(`Invalid filename: ${filename}. Must be '.env' or start with '.env.'`);
|
|
159
|
+
}
|
|
160
|
+
logger.info(`Pulling ${filename} (${environment}) from Supabase...`);
|
|
161
|
+
// Get latest secrets for this specific file
|
|
151
162
|
const jobs = await this.persistence.getActiveJobs();
|
|
163
|
+
const safeFilename = filename.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
152
164
|
const secretsJobs = jobs
|
|
153
|
-
.filter(j =>
|
|
165
|
+
.filter(j => {
|
|
166
|
+
// Match secrets for this environment and filename
|
|
167
|
+
return j.command === 'secrets_sync' &&
|
|
168
|
+
j.job_id.includes(environment) &&
|
|
169
|
+
j.job_id.includes(safeFilename);
|
|
170
|
+
})
|
|
154
171
|
.sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime());
|
|
155
172
|
if (secretsJobs.length === 0) {
|
|
156
|
-
throw new Error(`No secrets found for environment: ${environment}`);
|
|
173
|
+
throw new Error(`No secrets found for file '${filename}' in environment: ${environment}`);
|
|
157
174
|
}
|
|
158
175
|
const latestSecret = secretsJobs[0];
|
|
159
176
|
if (!latestSecret.output) {
|
|
@@ -179,13 +196,57 @@ export class SecretsManager {
|
|
|
179
196
|
const secretsJobs = jobs.filter(j => j.command === 'secrets_sync');
|
|
180
197
|
const envs = new Set();
|
|
181
198
|
for (const job of secretsJobs) {
|
|
182
|
-
|
|
199
|
+
// Updated regex to handle new format with filename
|
|
200
|
+
const match = job.job_id.match(/secrets_([^_]+)_/);
|
|
183
201
|
if (match) {
|
|
184
202
|
envs.add(match[1]);
|
|
185
203
|
}
|
|
186
204
|
}
|
|
187
205
|
return Array.from(envs).sort();
|
|
188
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* List all tracked .env files
|
|
209
|
+
*/
|
|
210
|
+
async listAllFiles() {
|
|
211
|
+
const jobs = await this.persistence.getActiveJobs();
|
|
212
|
+
const secretsJobs = jobs.filter(j => j.command === 'secrets_sync');
|
|
213
|
+
// Group by environment and filename to get latest of each
|
|
214
|
+
const fileMap = new Map();
|
|
215
|
+
for (const job of secretsJobs) {
|
|
216
|
+
// Parse job_id: secrets_${environment}_${safeFilename}_${timestamp}
|
|
217
|
+
const parts = job.job_id.split('_');
|
|
218
|
+
if (parts.length >= 3 && parts[0] === 'secrets') {
|
|
219
|
+
const environment = parts[1];
|
|
220
|
+
// Handle both old and new format
|
|
221
|
+
let filename = '.env';
|
|
222
|
+
if (parts.length >= 4) {
|
|
223
|
+
// New format with filename
|
|
224
|
+
const timestamp = parts[parts.length - 1];
|
|
225
|
+
// Reconstruct filename from middle parts
|
|
226
|
+
const filenameParts = parts.slice(2, -1);
|
|
227
|
+
if (filenameParts.length > 0) {
|
|
228
|
+
// Convert underscores back to dots for the extension
|
|
229
|
+
filename = filenameParts.join('_');
|
|
230
|
+
// Fix the extension dots that were replaced
|
|
231
|
+
filename = filename.replace(/^env_/, '.env.');
|
|
232
|
+
if (filename === 'env') {
|
|
233
|
+
filename = '.env';
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const key = `${environment}_${filename}`;
|
|
238
|
+
const existing = fileMap.get(key);
|
|
239
|
+
if (!existing || new Date(job.completed_at || job.started_at) > new Date(existing.updated)) {
|
|
240
|
+
fileMap.set(key, {
|
|
241
|
+
filename,
|
|
242
|
+
environment,
|
|
243
|
+
updated: new Date(job.completed_at || job.started_at).toLocaleString()
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return Array.from(fileMap.values()).sort((a, b) => a.filename.localeCompare(b.filename) || a.environment.localeCompare(b.environment));
|
|
249
|
+
}
|
|
189
250
|
/**
|
|
190
251
|
* Show secrets (masked)
|
|
191
252
|
*/
|
|
@@ -48,9 +48,24 @@ export async function init_secrets(program) {
|
|
|
48
48
|
.command('list [environment]')
|
|
49
49
|
.alias('ls')
|
|
50
50
|
.description('List all stored environments or show secrets for specific environment')
|
|
51
|
-
.
|
|
51
|
+
.option('--all-files', 'List all tracked .env files across environments')
|
|
52
|
+
.action(async (environment, options) => {
|
|
52
53
|
try {
|
|
53
54
|
const manager = new SecretsManager();
|
|
55
|
+
// If --all-files flag is set, list all tracked files
|
|
56
|
+
if (options.allFiles) {
|
|
57
|
+
const files = await manager.listAllFiles();
|
|
58
|
+
if (files.length === 0) {
|
|
59
|
+
console.log('No .env files found. Push your first file with: lsh secrets push --file <filename>');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log('\n📦 Tracked .env files:\n');
|
|
63
|
+
for (const file of files) {
|
|
64
|
+
console.log(` • ${file.filename} (${file.environment}) - Last updated: ${file.updated}`);
|
|
65
|
+
}
|
|
66
|
+
console.log();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
54
69
|
// If environment specified, show secrets for that environment
|
|
55
70
|
if (environment) {
|
|
56
71
|
await manager.show(environment);
|
|
@@ -187,6 +202,95 @@ API_KEY=
|
|
|
187
202
|
process.exit(1);
|
|
188
203
|
}
|
|
189
204
|
});
|
|
205
|
+
// Get a specific secret value
|
|
206
|
+
secretsCmd
|
|
207
|
+
.command('get <key>')
|
|
208
|
+
.description('Get a specific secret value from .env file')
|
|
209
|
+
.option('-f, --file <path>', 'Path to .env file', '.env')
|
|
210
|
+
.action(async (key, options) => {
|
|
211
|
+
try {
|
|
212
|
+
const envPath = path.resolve(options.file);
|
|
213
|
+
if (!fs.existsSync(envPath)) {
|
|
214
|
+
console.error(`❌ File not found: ${envPath}`);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
218
|
+
const lines = content.split('\n');
|
|
219
|
+
for (const line of lines) {
|
|
220
|
+
if (line.trim().startsWith('#') || !line.trim())
|
|
221
|
+
continue;
|
|
222
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
223
|
+
if (match && match[1].trim() === key) {
|
|
224
|
+
let value = match[2].trim();
|
|
225
|
+
// Remove quotes if present
|
|
226
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
227
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
228
|
+
value = value.slice(1, -1);
|
|
229
|
+
}
|
|
230
|
+
console.log(value);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
console.error(`❌ Key '${key}' not found in ${options.file}`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
console.error('❌ Failed to get secret:', error.message);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
// Set a specific secret value
|
|
243
|
+
secretsCmd
|
|
244
|
+
.command('set <key> <value>')
|
|
245
|
+
.description('Set a specific secret value in .env file')
|
|
246
|
+
.option('-f, --file <path>', 'Path to .env file', '.env')
|
|
247
|
+
.action(async (key, value, options) => {
|
|
248
|
+
try {
|
|
249
|
+
const envPath = path.resolve(options.file);
|
|
250
|
+
// Validate key format
|
|
251
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
252
|
+
console.error(`❌ Invalid key format: ${key}. Must be a valid environment variable name.`);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
let content = '';
|
|
256
|
+
let found = false;
|
|
257
|
+
if (fs.existsSync(envPath)) {
|
|
258
|
+
content = fs.readFileSync(envPath, 'utf8');
|
|
259
|
+
const lines = content.split('\n');
|
|
260
|
+
const newLines = [];
|
|
261
|
+
for (const line of lines) {
|
|
262
|
+
if (line.trim().startsWith('#') || !line.trim()) {
|
|
263
|
+
newLines.push(line);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
267
|
+
if (match && match[1].trim() === key) {
|
|
268
|
+
// Quote values with spaces or special characters
|
|
269
|
+
const needsQuotes = /[\s#]/.test(value);
|
|
270
|
+
const quotedValue = needsQuotes ? `"${value}"` : value;
|
|
271
|
+
newLines.push(`${key}=${quotedValue}`);
|
|
272
|
+
found = true;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
newLines.push(line);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
content = newLines.join('\n');
|
|
279
|
+
}
|
|
280
|
+
// If key wasn't found, append it
|
|
281
|
+
if (!found) {
|
|
282
|
+
const needsQuotes = /[\s#]/.test(value);
|
|
283
|
+
const quotedValue = needsQuotes ? `"${value}"` : value;
|
|
284
|
+
content = content.trimRight() + `\n${key}=${quotedValue}\n`;
|
|
285
|
+
}
|
|
286
|
+
fs.writeFileSync(envPath, content, 'utf8');
|
|
287
|
+
console.log(`✅ Set ${key} in ${options.file}`);
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
console.error('❌ Failed to set secret:', error.message);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
190
294
|
// Delete .env file with confirmation
|
|
191
295
|
secretsCmd
|
|
192
296
|
.command('delete')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Encrypted secrets manager with automatic rotation, team sync, and multi-environment support. Built on a powerful shell with daemon scheduling and CI/CD integration.",
|
|
5
5
|
"main": "dist/app.js",
|
|
6
6
|
"bin": {
|
|
@@ -104,15 +104,10 @@
|
|
|
104
104
|
"ink-text-input": "^5.0.1",
|
|
105
105
|
"inquirer": "^9.2.12",
|
|
106
106
|
"ioredis": "^5.8.0",
|
|
107
|
-
"jest": "^29.7.0",
|
|
108
107
|
"jsonwebtoken": "^9.0.2",
|
|
109
108
|
"lodash": "^4.17.21",
|
|
110
|
-
"mocha": "^10.3.0",
|
|
111
|
-
"ncc": "^0.3.6",
|
|
112
|
-
"nexe": "^4.0.0-rc.2",
|
|
113
109
|
"node-cron": "^3.0.3",
|
|
114
110
|
"node-fetch": "^3.3.2",
|
|
115
|
-
"nodemon": "^3.0.1",
|
|
116
111
|
"ora": "^8.0.1",
|
|
117
112
|
"path": "^0.12.7",
|
|
118
113
|
"pg": "^8.16.3",
|
|
@@ -122,7 +117,6 @@
|
|
|
122
117
|
"socket.io": "^4.8.1",
|
|
123
118
|
"uuid": "^10.0.0",
|
|
124
119
|
"xstate": "^5.9.1",
|
|
125
|
-
"zapier-platform-core": "15.4.1",
|
|
126
120
|
"zx": "^7.2.3"
|
|
127
121
|
},
|
|
128
122
|
"devDependencies": {
|
|
@@ -141,8 +135,14 @@
|
|
|
141
135
|
"eslint": "^9.36.0",
|
|
142
136
|
"eslint-plugin-react": "^7.37.5",
|
|
143
137
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
138
|
+
"jest": "^29.7.0",
|
|
139
|
+
"mocha": "^10.3.0",
|
|
140
|
+
"ncc": "^0.3.6",
|
|
141
|
+
"nexe": "^4.0.0-rc.2",
|
|
142
|
+
"nodemon": "^3.0.1",
|
|
144
143
|
"supertest": "^7.1.4",
|
|
145
144
|
"ts-jest": "^29.2.5",
|
|
146
|
-
"typescript": "^5.4.5"
|
|
145
|
+
"typescript": "^5.4.5",
|
|
146
|
+
"zapier-platform-core": "15.4.1"
|
|
147
147
|
}
|
|
148
148
|
}
|
package/dist/services/api/api.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import AsyncLock from 'async-lock';
|
|
2
|
-
import request from 'request';
|
|
3
|
-
import { CONFIG } from './config.js';
|
|
4
|
-
import { FILE } from './file.js';
|
|
5
|
-
const semaphore = new AsyncLock();
|
|
6
|
-
let pkgId;
|
|
7
|
-
export const makePOSTRequest = async (typeName, method, data, onSuccess) => {
|
|
8
|
-
console.log("makePostRequest");
|
|
9
|
-
const url = CONFIG.URL + '/api/8' + '/' + typeName + '/' + method;
|
|
10
|
-
console.log(url);
|
|
11
|
-
// Prevent parallel writes/deletions
|
|
12
|
-
return semaphore.acquire('request', (done) => {
|
|
13
|
-
return request.post(url, {
|
|
14
|
-
method: 'POST',
|
|
15
|
-
body: data,
|
|
16
|
-
json: true,
|
|
17
|
-
headers: {
|
|
18
|
-
Authorization: CONFIG.AUTH_TOKEN,
|
|
19
|
-
},
|
|
20
|
-
}, (err, response, body) => {
|
|
21
|
-
console.log(body);
|
|
22
|
-
onSuccess?.(response);
|
|
23
|
-
done();
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
const getMetadataPath = (path) => {
|
|
28
|
-
console.log("getMetadataPath");
|
|
29
|
-
return path.substring(path.indexOf(CONFIG.PATH_TO_PACKAGE_REPO) + CONFIG.PATH_TO_PACKAGE_REPO.length);
|
|
30
|
-
};
|
|
31
|
-
const getPkgId = async () => {
|
|
32
|
-
console.log("getPkgId");
|
|
33
|
-
if (pkgId) {
|
|
34
|
-
return pkgId;
|
|
35
|
-
}
|
|
36
|
-
await makePOSTRequest('Pkg', 'inst', ['Pkg'], (body) => {
|
|
37
|
-
pkgId = body;
|
|
38
|
-
});
|
|
39
|
-
return pkgId;
|
|
40
|
-
};
|
|
41
|
-
const _writeContent = async (path) => {
|
|
42
|
-
console.log("writeContent");
|
|
43
|
-
const pkgId = await getPkgId();
|
|
44
|
-
const metadataPath = getMetadataPath(path);
|
|
45
|
-
const content = FILE.encodeContent(path);
|
|
46
|
-
if (await content === FILE.NO_CHANGE_TO_FILE) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
return makePOSTRequest('Pkg', 'writeContent', [pkgId, metadataPath, {
|
|
50
|
-
type: 'ContentValue',
|
|
51
|
-
content,
|
|
52
|
-
}], () => console.log("Success"));
|
|
53
|
-
};
|
|
54
|
-
const _deleteContent = async (path) => {
|
|
55
|
-
const pkgId = await getPkgId();
|
|
56
|
-
const metadataPath = getMetadataPath(path);
|
|
57
|
-
return makePOSTRequest('Pkg', 'deleteContent', [pkgId, metadataPath, true], () => console.log("deleted!"));
|
|
58
|
-
};
|