@hashtree/nostr 0.2.3 → 0.2.7
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 +106 -154
- package/dist/events.d.ts +2 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +35 -9
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resolver/nostr.d.ts.map +1 -1
- package/dist/resolver/nostr.js +20 -13
- package/dist/resolver/nostr.js.map +1 -1
- package/dist/snapshot.d.ts.map +1 -1
- package/dist/snapshot.js +2 -1
- package/dist/snapshot.js.map +1 -1
- package/dist/treeEventSnapshotPermalinks.js +2 -2
- package/dist/treeEventSnapshotPermalinks.js.map +1 -1
- package/dist/treeEventSnapshots.d.ts.map +1 -1
- package/dist/treeEventSnapshots.js +5 -1
- package/dist/treeEventSnapshots.js.map +1 -1
- package/package.json +4 -4
- package/src/events.ts +38 -9
- package/src/index.ts +2 -0
- package/src/resolver/nostr.ts +15 -13
- package/src/snapshot.ts +2 -1
- package/src/treeEventSnapshotPermalinks.ts +2 -2
- package/src/treeEventSnapshots.ts +4 -1
package/src/resolver/nostr.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
PublishResult,
|
|
17
17
|
RefResolverSubscriptionMetadata,
|
|
18
18
|
} from '@hashtree/core';
|
|
19
|
-
import { fromHex, toHex, cid } from '@hashtree/core';
|
|
19
|
+
import { fromHex, toHex, cid, objectKeyFromHex } from '@hashtree/core';
|
|
20
20
|
import {
|
|
21
21
|
encryptKeyForLink,
|
|
22
22
|
computeKeyId,
|
|
@@ -195,6 +195,9 @@ function parseHashAndVisibility(event: NostrEvent): ParsedTreeVisibility | null
|
|
|
195
195
|
const selfEncryptedLinkKeyTag = event.tags.find(t => t[0] === 'selfEncryptedLinkKey')?.[1];
|
|
196
196
|
|
|
197
197
|
const key = keyTag ?? legacyContent?.key;
|
|
198
|
+
if (key !== undefined) {
|
|
199
|
+
try { objectKeyFromHex(key); } catch { return null; }
|
|
200
|
+
}
|
|
198
201
|
const encryptedKey = encryptedKeyTag ?? legacyContent?.encryptedKey;
|
|
199
202
|
const keyId = keyIdTag ?? legacyContent?.keyId;
|
|
200
203
|
const selfEncryptedKey = selfEncryptedKeyTag ?? legacyContent?.selfEncryptedKey;
|
|
@@ -341,7 +344,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
341
344
|
const doResolve = () => {
|
|
342
345
|
unsubscribe();
|
|
343
346
|
if (latestData) {
|
|
344
|
-
resolve(cid(fromHex(latestData.hash), latestData.key ?
|
|
347
|
+
resolve(cid(fromHex(latestData.hash), latestData.key ? objectKeyFromHex(latestData.key) : undefined));
|
|
345
348
|
} else {
|
|
346
349
|
resolve(null);
|
|
347
350
|
}
|
|
@@ -416,7 +419,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
416
419
|
currentVisibility: sub.currentVisibility ? JSON.stringify(sub.currentVisibility) : 'null'
|
|
417
420
|
});
|
|
418
421
|
if (sub.currentHash) {
|
|
419
|
-
const keyBytes = sub.currentKey ?
|
|
422
|
+
const keyBytes = sub.currentKey ? objectKeyFromHex(sub.currentKey) : undefined;
|
|
420
423
|
callback(
|
|
421
424
|
cid(fromHex(sub.currentHash), keyBytes),
|
|
422
425
|
sub.currentVisibility ?? undefined,
|
|
@@ -430,7 +433,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
430
433
|
// Helper to notify all callbacks
|
|
431
434
|
const notifyCallbacks = (subEntry: SubscriptionEntry) => {
|
|
432
435
|
if (!subEntry.currentHash) return;
|
|
433
|
-
const keyBytes = subEntry.currentKey ?
|
|
436
|
+
const keyBytes = subEntry.currentKey ? objectKeyFromHex(subEntry.currentKey) : undefined;
|
|
434
437
|
const visibilityInfo = subEntry.currentVisibility ?? undefined;
|
|
435
438
|
const metadata = {
|
|
436
439
|
updatedAt: subEntry.latestCreatedAt,
|
|
@@ -558,7 +561,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
558
561
|
|
|
559
562
|
// Fire callback immediately with cached value if available
|
|
560
563
|
if (cachedEntry?.hash) {
|
|
561
|
-
const keyBytes = cachedEntry.key ?
|
|
564
|
+
const keyBytes = cachedEntry.key ? objectKeyFromHex(cachedEntry.key) : undefined;
|
|
562
565
|
callback(
|
|
563
566
|
cid(fromHex(cachedEntry.hash), keyBytes),
|
|
564
567
|
sub.currentVisibility ?? undefined,
|
|
@@ -651,8 +654,8 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
651
654
|
break;
|
|
652
655
|
|
|
653
656
|
case 'link-visible': {
|
|
654
|
-
//
|
|
655
|
-
const linkKey = options?.linkKey ?? generateLinkKey();
|
|
657
|
+
// Mask the object key with the link secret.
|
|
658
|
+
const linkKey = options?.linkKey ?? generateLinkKey(chkKey.length === 32 ? 32 : 33);
|
|
656
659
|
resultLinkKey = linkKey;
|
|
657
660
|
const encryptedKey = encryptKeyForLink(chkKey, linkKey);
|
|
658
661
|
const keyId = await computeKeyId(linkKey);
|
|
@@ -672,7 +675,6 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
672
675
|
}
|
|
673
676
|
|
|
674
677
|
// Encrypt linkKey to self for URL recovery (so owner can share URLs easily)
|
|
675
|
-
// Owner can also derive linkKey from XOR(encryptedKey, contentKey)
|
|
676
678
|
try {
|
|
677
679
|
const selfEncryptedLinkKey = await visibility.encrypt(linkKey, pubkey);
|
|
678
680
|
tags.push(['selfEncryptedLinkKey', selfEncryptedLinkKey]);
|
|
@@ -771,7 +773,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
771
773
|
if (!entry.hash) continue; // Skip deleted trees
|
|
772
774
|
result.push({
|
|
773
775
|
key: `${npubStr}/${dTag}`,
|
|
774
|
-
cid: cid(fromHex(entry.hash), entry.key ?
|
|
776
|
+
cid: cid(fromHex(entry.hash), entry.key ? objectKeyFromHex(entry.key) : undefined),
|
|
775
777
|
labels: entry.labels,
|
|
776
778
|
visibility: entry.visibility,
|
|
777
779
|
encryptedKey: entry.encryptedKey,
|
|
@@ -853,7 +855,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
853
855
|
}
|
|
854
856
|
result.push({
|
|
855
857
|
key: `${npubStr}/${dTag}`,
|
|
856
|
-
cid: cid(fromHex(entry.hash), entry.key ?
|
|
858
|
+
cid: cid(fromHex(entry.hash), entry.key ? objectKeyFromHex(entry.key) : undefined),
|
|
857
859
|
labels: entry.labels,
|
|
858
860
|
visibility: entry.visibility,
|
|
859
861
|
encryptedKey: entry.encryptedKey,
|
|
@@ -895,7 +897,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
895
897
|
if (!entry.hash) continue;
|
|
896
898
|
result.push({
|
|
897
899
|
key: `${npubStr}/${dTag}`,
|
|
898
|
-
cid: cid(fromHex(entry.hash), entry.key ?
|
|
900
|
+
cid: cid(fromHex(entry.hash), entry.key ? objectKeyFromHex(entry.key) : undefined),
|
|
899
901
|
labels: entry.labels,
|
|
900
902
|
visibility: entry.visibility,
|
|
901
903
|
encryptedKey: entry.encryptedKey,
|
|
@@ -1074,7 +1076,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
1074
1076
|
if (!entry.hash) continue;
|
|
1075
1077
|
result.push({
|
|
1076
1078
|
key: `${npubStr}/${dTag}`,
|
|
1077
|
-
cid: cid(fromHex(entry.hash), entry.key ?
|
|
1079
|
+
cid: cid(fromHex(entry.hash), entry.key ? objectKeyFromHex(entry.key) : undefined),
|
|
1078
1080
|
labels: entry.labels,
|
|
1079
1081
|
visibility: entry.visibility,
|
|
1080
1082
|
encryptedKey: entry.encryptedKey,
|
|
@@ -1186,7 +1188,7 @@ export function createNostrRefResolver(config: NostrRefResolverConfig): RefResol
|
|
|
1186
1188
|
if (!e.hash) continue; // Skip deleted trees
|
|
1187
1189
|
result.push({
|
|
1188
1190
|
key: `${npubStr}/${dTag}`,
|
|
1189
|
-
cid: cid(fromHex(e.hash), e.key ?
|
|
1191
|
+
cid: cid(fromHex(e.hash), e.key ? objectKeyFromHex(e.key) : undefined),
|
|
1190
1192
|
labels: e.labels,
|
|
1191
1193
|
visibility: e.visibility,
|
|
1192
1194
|
encryptedKey: e.encryptedKey,
|
package/src/snapshot.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { objectKeyFromHex } from '@hashtree/core';
|
|
1
2
|
import { HashTree, cid, fromHex, type CID, type Store, type TreeVisibility } from '@hashtree/core';
|
|
2
3
|
import type { StoredNostrEvent } from './events.js';
|
|
3
4
|
|
|
@@ -199,7 +200,7 @@ export function parseHashtreeRootEvent(event: StoredNostrEvent): ParsedHashtreeR
|
|
|
199
200
|
return {
|
|
200
201
|
event: normalized,
|
|
201
202
|
treeName,
|
|
202
|
-
rootCid: cid(fromHex(hashHex), visibility === 'public' && keyHex ?
|
|
203
|
+
rootCid: cid(fromHex(hashHex), visibility === 'public' && keyHex !== undefined ? objectKeyFromHex(keyHex) : undefined),
|
|
203
204
|
visibility,
|
|
204
205
|
labels,
|
|
205
206
|
encryptedKey,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { nhashDecode } from '@hashtree/core';
|
|
2
2
|
|
|
3
3
|
const NHASH_PATTERN = /^nhash1[a-z0-9]+$/;
|
|
4
|
-
const LINK_KEY_PATTERN = /^[a-f0-9]{
|
|
4
|
+
const LINK_KEY_PATTERN = /^(?:[a-f0-9]{2}){32,33}$/i;
|
|
5
5
|
|
|
6
6
|
export interface TreeEventSnapshotPermalink {
|
|
7
7
|
snapshotNhash: string;
|
|
@@ -79,7 +79,7 @@ function normalizeTreeEventSnapshotPermalink(
|
|
|
79
79
|
|
|
80
80
|
const linkKey = normalizeTreeEventSnapshotLinkKey(value.linkKey);
|
|
81
81
|
if (value.linkKey?.trim() && !linkKey) {
|
|
82
|
-
throw new Error(
|
|
82
|
+
throw new Error('Invalid tree event snapshot link key');
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type CID,
|
|
7
7
|
} from '@hashtree/core';
|
|
8
8
|
import type { StoredNostrEvent } from './events.js';
|
|
9
|
+
import { normalizeTreeEventSnapshotLinkKey } from './treeEventSnapshotPermalinks.js';
|
|
9
10
|
import { compareReplaceableEvents } from './eventKeys.js';
|
|
10
11
|
import type { Nip19Like, NostrFilter } from './resolver/nostr.js';
|
|
11
12
|
import {
|
|
@@ -68,7 +69,9 @@ function normalizeLinkKey(linkKey?: string | Uint8Array | null): Uint8Array | nu
|
|
|
68
69
|
if (!linkKey) {
|
|
69
70
|
return null;
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
if (typeof linkKey !== 'string') return linkKey;
|
|
73
|
+
const hex = normalizeTreeEventSnapshotLinkKey(linkKey);
|
|
74
|
+
return hex ? fromHex(hex) : null;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
function isValidTreeEventFor(
|