lsh-framework 3.2.0 → 3.2.2

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.
@@ -87,6 +87,7 @@ async function runSetupWizard(options) {
87
87
  // Check if secrets already exist locally
88
88
  const cloudCheck = await checkCloudSecretsExist();
89
89
  let encryptionKey;
90
+ let importedKey = false;
90
91
  if (cloudCheck.exists && cloudCheck.repoName) {
91
92
  // Secrets found! This is an existing project
92
93
  console.log(chalk.cyan(`\n✨ Found existing secrets for "${cloudCheck.repoName}" in cloud!`));
@@ -120,6 +121,7 @@ async function runSetupWizard(options) {
120
121
  },
121
122
  ]);
122
123
  encryptionKey = existingKey.trim();
124
+ importedKey = true;
123
125
  }
124
126
  else {
125
127
  // Generate new key (will overwrite existing)
@@ -128,28 +130,61 @@ async function runSetupWizard(options) {
128
130
  }
129
131
  }
130
132
  else {
131
- // No existing secrets - generate new key
132
- encryptionKey = generateEncryptionKey();
133
+ // No existing secrets found locally ask if joining an existing project
134
+ const { keyChoice } = await inquirer.prompt([
135
+ {
136
+ type: 'list',
137
+ name: 'keyChoice',
138
+ message: 'How would you like to set up this project?',
139
+ choices: [
140
+ { name: '🔑 Generate a new encryption key (new project)', value: 'generate' },
141
+ { name: '🤝 Import an existing key from a teammate', value: 'import' },
142
+ ],
143
+ },
144
+ ]);
145
+ if (keyChoice === 'import') {
146
+ const { existingKey } = await inquirer.prompt([
147
+ {
148
+ type: 'password',
149
+ name: 'existingKey',
150
+ message: 'Enter the LSH_SECRETS_KEY from your teammate:',
151
+ mask: '*',
152
+ validate: (input) => {
153
+ if (!input.trim())
154
+ return 'Encryption key is required';
155
+ if (input.length < 16)
156
+ return 'Key is too short (minimum 16 characters)';
157
+ return true;
158
+ },
159
+ },
160
+ ]);
161
+ encryptionKey = existingKey.trim();
162
+ importedKey = true;
163
+ }
164
+ else {
165
+ encryptionKey = generateEncryptionKey();
166
+ }
133
167
  }
134
168
  const config = {
135
169
  encryptionKey,
136
170
  };
137
- // If using existing key and secrets exist, offer to pull them now
138
- if (cloudCheck.exists && config.encryptionKey && cloudCheck.repoName) {
171
+ // Save configuration first so LSH_SECRETS_KEY is available for pull
172
+ await saveConfiguration(config, baseDir, globalMode);
173
+ // If user imported a key, offer to pull secrets via IPNS
174
+ if (importedKey && daemonRunning) {
139
175
  const { pullNow } = await inquirer.prompt([
140
176
  {
141
177
  type: 'confirm',
142
178
  name: 'pullNow',
143
- message: 'Pull secrets now?',
179
+ message: 'Pull secrets now via IPNS?',
144
180
  default: true,
145
181
  },
146
182
  ]);
147
183
  if (pullNow) {
148
- await pullSecretsAfterInit(config.encryptionKey, cloudCheck.repoName);
184
+ const gitInfo = getGitRepoInfo();
185
+ await pullSecretsAfterInit(config.encryptionKey, cloudCheck.repoName || gitInfo?.repoName || '');
149
186
  }
150
187
  }
151
- // Save configuration
152
- await saveConfiguration(config, baseDir, globalMode);
153
188
  // Show success message
154
189
  showSuccessMessage(config);
155
190
  }
@@ -333,18 +368,12 @@ function showSuccessMessage(config) {
333
368
  console.log(chalk.gray(' 1. (Optional) Start IPFS daemon for network sync:'));
334
369
  console.log(chalk.cyan(' lsh ipfs install && lsh ipfs init && lsh ipfs start'));
335
370
  console.log('');
336
- console.log(chalk.gray(' 2. Push your secrets to IPFS:'));
337
- console.log(chalk.cyan(' lsh sync push'));
338
- console.log(chalk.gray(' (Returns a CID - share this with teammates)'));
339
- console.log('');
340
- console.log(chalk.gray(' 3. On another machine:'));
341
- console.log(chalk.cyan(' lsh init'));
342
- console.log(chalk.cyan(' export LSH_SECRETS_KEY=<key-from-teammate>'));
343
- console.log(chalk.cyan(' lsh sync pull <cid>'));
371
+ console.log(chalk.gray(' 2. Push your secrets:'));
372
+ console.log(chalk.cyan(' lsh push'));
344
373
  console.log('');
345
- console.log(chalk.gray(' Alternatively, use the classic push/pull commands:'));
346
- console.log(chalk.cyan(' lsh push --env dev'));
347
- console.log(chalk.cyan(' lsh pull --env dev'));
374
+ console.log(chalk.gray(' 3. Teammates (share only the key, nothing else):'));
375
+ console.log(chalk.cyan(' lsh init # Choose "Import existing key"'));
376
+ console.log(chalk.cyan(' lsh pull # Auto-resolves latest via IPNS'));
348
377
  console.log('');
349
378
  console.log(chalk.gray('📖 Documentation: https://github.com/gwicho38/lsh'));
350
379
  console.log('');
@@ -350,9 +350,12 @@ export class IPFSSync {
350
350
  */
351
351
  async publishToIPNS(cid, keyName) {
352
352
  try {
353
- const response = await fetch(`${this.LOCAL_IPFS_API}/name/publish?arg=${cid}&key=${encodeURIComponent(keyName)}&lifetime=87600h&resolve=false`, {
353
+ // allow-offline=true stores the record locally and returns immediately;
354
+ // the daemon propagates it to the DHT in the background.
355
+ // Without this, first publishes can take 60-90s for DHT propagation.
356
+ const response = await fetch(`${this.LOCAL_IPFS_API}/name/publish?arg=${cid}&key=${encodeURIComponent(keyName)}&lifetime=87600h&resolve=false&offline=true`, {
354
357
  method: 'POST',
355
- signal: AbortSignal.timeout(30000),
358
+ signal: AbortSignal.timeout(15000),
356
359
  });
357
360
  if (!response.ok) {
358
361
  const errorText = await response.text();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lsh-framework",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "Simple, cross-platform encrypted secrets manager with automatic sync, IPFS audit logs, and multi-environment support. Just run lsh sync and start managing your secrets.",
5
5
  "main": "dist/app.js",
6
6
  "bin": {