lsh-framework 3.6.0 → 3.7.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/README.md +20 -0
- package/dist/constants/config.js +10 -0
- package/dist/lib/ipfs-sync.js +52 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,6 +115,21 @@ lsh sync push --env dev
|
|
|
115
115
|
|
|
116
116
|
If exactly one remote service is configured, `lsh` uses it automatically and `LSH_PIN_SERVICE` is optional.
|
|
117
117
|
|
|
118
|
+
### Quickest: bundled pinner (just a token)
|
|
119
|
+
|
|
120
|
+
Skip the manual `ipfs pin remote service add`. Set **`LSH_PIN_TOKEN`** and `lsh` auto-registers a
|
|
121
|
+
remote pinning service for you on first push — defaulting to **4EVERLAND** (free 5GB, standard
|
|
122
|
+
Pinning Service API):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Get a free accessToken from the 4EVERLAND "4EVER Pin" page (https://4everland.org)
|
|
126
|
+
export LSH_PIN_TOKEN=<your-4everland-accessToken>
|
|
127
|
+
lsh push --env dev # auto-registers "lsh-pin" → https://api.4everland.dev, then pins
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Use a different provider by overriding the endpoint: `export LSH_PIN_ENDPOINT=<psa-endpoint>`.
|
|
131
|
+
(Note: Pinata's pin-by-CID PSA is paid-only; 4EVERLAND and Filebase offer it free.)
|
|
132
|
+
|
|
118
133
|
## Installation
|
|
119
134
|
|
|
120
135
|
### Prerequisites
|
|
@@ -331,6 +346,11 @@ LSH_PIN_SERVICE=<service-name>
|
|
|
331
346
|
# Default 'w3name,ipns': durable w3name (signed IPNS via name.web3.storage, no
|
|
332
347
|
# account, no DHT TTL) with IPNS-over-DHT fallback. Set 'ipns' for DHT-only.
|
|
333
348
|
LSH_DISCOVERY=w3name,ipns
|
|
349
|
+
|
|
350
|
+
# Optional - bundled pinner: with a token set, lsh auto-registers a remote pin
|
|
351
|
+
# service so pushed content is durable. Endpoint defaults to 4EVERLAND (free 5GB).
|
|
352
|
+
LSH_PIN_TOKEN=<psa-access-token>
|
|
353
|
+
LSH_PIN_ENDPOINT=https://api.4everland.dev # override for another PSA provider
|
|
334
354
|
```
|
|
335
355
|
|
|
336
356
|
### Configuration Files
|
package/dist/constants/config.js
CHANGED
|
@@ -36,6 +36,12 @@ export const ENV_VARS = {
|
|
|
36
36
|
// Discovery backend(s) for the key→CID pointer, comma-separated in priority
|
|
37
37
|
// order. Supported: 'w3name' (durable, hosted), 'ipns' (DHT). Default: 'w3name,ipns'.
|
|
38
38
|
LSH_DISCOVERY: 'LSH_DISCOVERY',
|
|
39
|
+
// Access token for a bundled IPFS remote pinning service. When set (and no
|
|
40
|
+
// remote pin service is already configured), lsh auto-registers one so pushed
|
|
41
|
+
// content is durably pinned. Endpoint defaults to 4EVERLAND (free 5GB).
|
|
42
|
+
LSH_PIN_TOKEN: 'LSH_PIN_TOKEN',
|
|
43
|
+
// Override the PSA endpoint used with LSH_PIN_TOKEN (any IPFS Pinning Service).
|
|
44
|
+
LSH_PIN_ENDPOINT: 'LSH_PIN_ENDPOINT',
|
|
39
45
|
// Feature flags
|
|
40
46
|
LSH_LOCAL_STORAGE_QUIET: 'LSH_LOCAL_STORAGE_QUIET',
|
|
41
47
|
LSH_V1_COMPAT: 'LSH_V1_COMPAT',
|
|
@@ -148,4 +154,8 @@ export const DEFAULTS = {
|
|
|
148
154
|
IPNS_KEY_DERIVATION_CONTEXT: 'lsh-ipns-v1',
|
|
149
155
|
// Default discovery backends (priority order): durable w3name, then DHT-IPNS fallback.
|
|
150
156
|
DISCOVERY_BACKENDS: 'w3name,ipns',
|
|
157
|
+
// Bundled remote pinning service (used with LSH_PIN_TOKEN). 4EVERLAND free tier (5GB),
|
|
158
|
+
// standard IPFS Pinning Service API. Override the endpoint via LSH_PIN_ENDPOINT.
|
|
159
|
+
DEFAULT_PIN_ENDPOINT: 'https://api.4everland.dev',
|
|
160
|
+
DEFAULT_PIN_SERVICE_NAME: 'lsh-pin',
|
|
151
161
|
};
|
package/dist/lib/ipfs-sync.js
CHANGED
|
@@ -15,7 +15,23 @@ import * as path from 'path';
|
|
|
15
15
|
import * as os from 'os';
|
|
16
16
|
import { createLogger } from './logger.js';
|
|
17
17
|
import { extractErrorMessage } from './lsh-error.js';
|
|
18
|
-
import { ENV_VARS } from '../constants/config.js';
|
|
18
|
+
import { ENV_VARS, DEFAULTS } from '../constants/config.js';
|
|
19
|
+
/**
|
|
20
|
+
* Pure helper: choose which configured remote pinning service to use.
|
|
21
|
+
* - explicit `LSH_PIN_SERVICE` wins, but only if it's actually configured;
|
|
22
|
+
* - else the bundled default service (`lsh-pin`) if present;
|
|
23
|
+
* - else the sole configured service;
|
|
24
|
+
* - else null (none / ambiguous).
|
|
25
|
+
*/
|
|
26
|
+
export function chooseRemoteService(services, explicit, defaultName) {
|
|
27
|
+
if (explicit) {
|
|
28
|
+
return services.includes(explicit) ? explicit : null;
|
|
29
|
+
}
|
|
30
|
+
if (services.includes(defaultName)) {
|
|
31
|
+
return defaultName;
|
|
32
|
+
}
|
|
33
|
+
return services.length === 1 ? services[0] : null;
|
|
34
|
+
}
|
|
19
35
|
const logger = createLogger('IPFSSync');
|
|
20
36
|
/**
|
|
21
37
|
* Native IPFS Sync
|
|
@@ -369,12 +385,43 @@ export class IPFSSync {
|
|
|
369
385
|
* - Returns null when nothing is configured or the choice is ambiguous.
|
|
370
386
|
*/
|
|
371
387
|
async resolveRemoteService() {
|
|
388
|
+
await this.ensureDefaultPinService();
|
|
372
389
|
const services = await this.listRemoteServices();
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
390
|
+
return chooseRemoteService(services, process.env[ENV_VARS.LSH_PIN_SERVICE], DEFAULTS.DEFAULT_PIN_SERVICE_NAME);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Bundled pinner: when LSH_PIN_TOKEN is set and no remote pin service named
|
|
394
|
+
* `lsh-pin` is registered yet, auto-register one (endpoint defaults to
|
|
395
|
+
* 4EVERLAND, override via LSH_PIN_ENDPOINT). Lets users get durable pinning
|
|
396
|
+
* with just a token — no manual `ipfs pin remote service add`. Best-effort;
|
|
397
|
+
* never throws. Respects an existing service of the same name and the
|
|
398
|
+
* explicit LSH_PIN_SERVICE (handled by chooseRemoteService).
|
|
399
|
+
*/
|
|
400
|
+
async ensureDefaultPinService() {
|
|
401
|
+
const token = process.env[ENV_VARS.LSH_PIN_TOKEN];
|
|
402
|
+
if (!token)
|
|
403
|
+
return;
|
|
404
|
+
const name = DEFAULTS.DEFAULT_PIN_SERVICE_NAME;
|
|
405
|
+
try {
|
|
406
|
+
const existing = await this.listRemoteServices();
|
|
407
|
+
if (existing.includes(name))
|
|
408
|
+
return;
|
|
409
|
+
const endpoint = process.env[ENV_VARS.LSH_PIN_ENDPOINT] || DEFAULTS.DEFAULT_PIN_ENDPOINT;
|
|
410
|
+
const url = `${this.LOCAL_IPFS_API}/pin/remote/service/add` +
|
|
411
|
+
`?arg=${encodeURIComponent(name)}` +
|
|
412
|
+
`&arg=${encodeURIComponent(endpoint)}` +
|
|
413
|
+
`&arg=${encodeURIComponent(token)}`;
|
|
414
|
+
const response = await fetch(url, { method: 'POST', signal: AbortSignal.timeout(10000) });
|
|
415
|
+
if (response.ok) {
|
|
416
|
+
logger.info(`📌 Registered bundled pin service "${name}" → ${endpoint}`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
logger.warn(`Could not register pin service "${name}": ${await response.text()}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch (error) {
|
|
423
|
+
logger.warn(`Pin service registration error: ${extractErrorMessage(error)}`);
|
|
376
424
|
}
|
|
377
|
-
return services.length === 1 ? services[0] : null;
|
|
378
425
|
}
|
|
379
426
|
/**
|
|
380
427
|
* Pin a CID to a configured remote pinning service so the content survives
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsh-framework",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
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/cli.js",
|
|
6
6
|
"bin": {
|