keychat-save 1.2.0 → 1.3.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 +9 -3
- package/index.mjs +55 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,14 +19,17 @@ This creates your identity at `~/.keychat/identity.wif` and shows your BSV addre
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
# Save content
|
|
22
|
+
# Save content (positional: label first, then body)
|
|
23
23
|
keychat-save save "my notes" "content to save permanently"
|
|
24
24
|
|
|
25
|
+
# Or use --label flag explicitly
|
|
26
|
+
keychat-save save --label "my notes" "content to save permanently"
|
|
27
|
+
|
|
25
28
|
# Save a file
|
|
26
|
-
keychat-save save "backup" --file ./myfile.txt
|
|
29
|
+
keychat-save save --label "backup" --file ./myfile.txt
|
|
27
30
|
|
|
28
31
|
# Pipe content in
|
|
29
|
-
cat session.log | keychat-save save "session log" --stdin
|
|
32
|
+
cat session.log | keychat-save save --label "session log" --stdin
|
|
30
33
|
|
|
31
34
|
# Load all saves
|
|
32
35
|
keychat-save load
|
|
@@ -34,6 +37,9 @@ keychat-save load
|
|
|
34
37
|
# Load most recent
|
|
35
38
|
keychat-save load --last
|
|
36
39
|
|
|
40
|
+
# Load a specific save by txid
|
|
41
|
+
keychat-save load --txid <txid>
|
|
42
|
+
|
|
37
43
|
# Search
|
|
38
44
|
keychat-save load --search "keyword"
|
|
39
45
|
```
|
package/index.mjs
CHANGED
|
@@ -44,6 +44,20 @@ function decrypt (encrypted, privKey) {
|
|
|
44
44
|
return Utils.toUTF8(EncryptedMessage.decrypt(encrypted, privKey))
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// ── local index ──────────────────────────────────────────────────
|
|
48
|
+
// Newest-first markdown table: `| date | label | txid | cost |`.
|
|
49
|
+
// Returns the first txid-shaped cell; null if none.
|
|
50
|
+
function readNewestTxidFromIndex (path) {
|
|
51
|
+
const text = readFileSync(path, 'utf8')
|
|
52
|
+
for (const line of text.split('\n')) {
|
|
53
|
+
if (!line.startsWith('|')) continue
|
|
54
|
+
const cells = line.split('|').map(c => c.trim())
|
|
55
|
+
const txid = cells.find(c => /^[0-9a-f]{64}$/i.test(c))
|
|
56
|
+
if (txid) return txid.toLowerCase()
|
|
57
|
+
}
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
|
|
47
61
|
// ── bridge API ───────────────────────────────────────────────────
|
|
48
62
|
async function getUnspent (address) {
|
|
49
63
|
const res = await fetch(`${BRIDGE}/api/address/${address}/unspent`)
|
|
@@ -327,21 +341,56 @@ const [,, cmd, ...args] = process.argv
|
|
|
327
341
|
if (cmd === 'init') {
|
|
328
342
|
await cmdInit()
|
|
329
343
|
} else if (cmd === 'save') {
|
|
330
|
-
|
|
344
|
+
// Accept both invocation styles:
|
|
345
|
+
// keychat-save save "Title" "Body" (positional)
|
|
346
|
+
// keychat-save save --label "Title" "Body" (named)
|
|
347
|
+
// keychat-save save --label "Title" --file p.txt
|
|
348
|
+
// keychat-save save --label "Title" --stdin
|
|
349
|
+
// Earlier versions only handled the positional form, so users who
|
|
350
|
+
// typed --label got the literal "--label" as their label string.
|
|
351
|
+
let label = 'Untitled'
|
|
352
|
+
let positional = [...args]
|
|
353
|
+
|
|
354
|
+
const labelIdx = positional.indexOf('--label')
|
|
355
|
+
if (labelIdx >= 0 && positional[labelIdx + 1] != null) {
|
|
356
|
+
label = positional[labelIdx + 1]
|
|
357
|
+
positional.splice(labelIdx, 2)
|
|
358
|
+
} else if (positional[0] && !positional[0].startsWith('--')) {
|
|
359
|
+
label = positional[0]
|
|
360
|
+
positional = positional.slice(1)
|
|
361
|
+
}
|
|
362
|
+
|
|
331
363
|
let body
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
else
|
|
335
|
-
|
|
364
|
+
if (positional[0] === '--file' && positional[1]) {
|
|
365
|
+
body = readFileSync(positional[1], 'utf8')
|
|
366
|
+
} else if (positional[0] === '--stdin') {
|
|
367
|
+
body = readFileSync(0, 'utf8')
|
|
368
|
+
} else {
|
|
369
|
+
body = positional.join(' ')
|
|
370
|
+
}
|
|
371
|
+
if (!body) {
|
|
372
|
+
console.error('Usage:\n keychat-save save "label" "content"\n keychat-save save --label "title" "content"\n keychat-save save --label "title" --file <path>\n keychat-save save --label "title" --stdin')
|
|
373
|
+
process.exit(1)
|
|
374
|
+
}
|
|
336
375
|
await cmdSave(label, body)
|
|
337
376
|
} else if (cmd === 'load') {
|
|
338
377
|
// Direct txid lookup — instant, no history scan
|
|
339
378
|
const txidIdx = args.indexOf('--txid')
|
|
340
379
|
if (txidIdx >= 0 && args[txidIdx + 1]) {
|
|
341
380
|
await cmdLoadByTxid(args[txidIdx + 1])
|
|
381
|
+
} else if (args.includes('--last')) {
|
|
382
|
+
// Fast path: read newest txid from local saves-index.md.
|
|
383
|
+
// The slow UTXO-scan path stalls when the address holds many UTXOs
|
|
384
|
+
// (e.g. packaged Compute pieces from the splitter).
|
|
385
|
+
const lastTxid = existsSync(INDEX_PATH) ? readNewestTxidFromIndex(INDEX_PATH) : null
|
|
386
|
+
if (lastTxid) {
|
|
387
|
+
await cmdLoadByTxid(lastTxid)
|
|
388
|
+
} else {
|
|
389
|
+
console.error('No local saves index found — falling back to UTXO scan.')
|
|
390
|
+
await cmdLoad({ last: true })
|
|
391
|
+
}
|
|
342
392
|
} else {
|
|
343
393
|
const opts = {}
|
|
344
|
-
if (args.includes('--last')) opts.last = true
|
|
345
394
|
if (args.includes('--search')) opts.search = args[args.indexOf('--search') + 1]
|
|
346
395
|
await cmdLoad(opts)
|
|
347
396
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keychat-save",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Save and load files to BSV blockchain via KeyChat",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"keychat-save": "
|
|
7
|
+
"keychat-save": "index.mjs"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
10
|
"node": ">=18"
|