@le-space/aleph-bootstrap 0.6.23 → 0.6.25
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 +6 -5
- package/index.d.ts +3 -11
- package/index.js +51 -56
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,20 +27,21 @@ The package defaults to the shared relay-bootstrap namespace:
|
|
|
27
27
|
|
|
28
28
|
- channel: `simple-todo`
|
|
29
29
|
- ref: `simple-todo-bootstrap`
|
|
30
|
-
- post type: `relay-bootstrap`
|
|
30
|
+
- post type: `relay-bootstrap-v2`
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The channel and ref are overrideable per app or environment. The post type is
|
|
33
|
+
fixed to `relay-bootstrap-v2`.
|
|
33
34
|
|
|
34
35
|
## Discovery Trust Modes
|
|
35
36
|
|
|
36
|
-
The package accepts
|
|
37
|
+
The package accepts two signing modes for v2 records:
|
|
37
38
|
|
|
38
|
-
-
|
|
39
|
+
- wallet-signed bootstrap posts
|
|
39
40
|
- dual-key-attested bootstrap posts
|
|
40
41
|
|
|
41
42
|
By default, discovery will:
|
|
42
43
|
|
|
43
|
-
- accept
|
|
44
|
+
- accept wallet-signed v2 posts
|
|
44
45
|
- verify dual-key records when they are present
|
|
45
46
|
- ignore malformed or invalid dual-key records
|
|
46
47
|
|
package/index.d.ts
CHANGED
|
@@ -3,8 +3,7 @@ import { bootstrap } from '@libp2p/bootstrap';
|
|
|
3
3
|
declare const DEFAULT_ALEPH_API_HOST = "https://api.aleph.im";
|
|
4
4
|
declare const DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
|
|
5
5
|
declare const DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
|
|
6
|
-
declare const DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
|
|
7
|
-
declare const DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE = "relay-bootstrap-v2";
|
|
6
|
+
declare const DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap-v2";
|
|
8
7
|
declare const DEFAULT_BOOTSTRAP_MAX_AGE_MS: number;
|
|
9
8
|
declare const DEFAULT_BOOTSTRAP_PAGINATION = 50;
|
|
10
9
|
declare const DEFAULT_BOOTSTRAP_MAX_PAGES = 5;
|
|
@@ -80,8 +79,6 @@ interface DiscoverAlephBootstrapOptions {
|
|
|
80
79
|
apiHost?: string;
|
|
81
80
|
channel?: string;
|
|
82
81
|
ref?: string;
|
|
83
|
-
postType?: string;
|
|
84
|
-
postTypes?: string[];
|
|
85
82
|
page?: number;
|
|
86
83
|
pagination?: number;
|
|
87
84
|
maxPages?: number;
|
|
@@ -104,19 +101,17 @@ interface CreateRelayBootstrapPostOptions {
|
|
|
104
101
|
registrationId?: string;
|
|
105
102
|
ref?: string;
|
|
106
103
|
channel?: string;
|
|
107
|
-
postType?: string;
|
|
108
104
|
profile?: string;
|
|
109
105
|
version?: string;
|
|
110
106
|
ownerAddress?: string;
|
|
111
107
|
publisherAddress?: string;
|
|
112
108
|
authorization?: RelayBootstrapAuthorizationRecord;
|
|
113
109
|
relayProof?: RelayBootstrapProofRecord;
|
|
114
|
-
compact?: boolean;
|
|
115
110
|
compactMultiaddrLimit?: number;
|
|
116
111
|
now?: number;
|
|
117
112
|
hasher: (payload: string) => Promise<string> | string;
|
|
118
113
|
}
|
|
119
|
-
type RelayBootstrapTrustMode = "
|
|
114
|
+
type RelayBootstrapTrustMode = "wallet-signed" | "dual-key-attested";
|
|
120
115
|
declare function relayBootstrapMultiaddrsHash(addrs: readonly string[]): string;
|
|
121
116
|
declare function selectCompactRelayBootstrapMultiaddrs(addrs: readonly string[], limit?: number): string[];
|
|
122
117
|
declare function dedupeMultiaddrs(addrs: readonly string[]): string[];
|
|
@@ -129,14 +124,12 @@ declare function buildRelayBootstrapPostContent(args: {
|
|
|
129
124
|
browserMultiaddrs?: string[];
|
|
130
125
|
registrationId?: string;
|
|
131
126
|
ref?: string;
|
|
132
|
-
postType?: string;
|
|
133
127
|
profile?: string;
|
|
134
128
|
version?: string;
|
|
135
129
|
ownerAddress?: string;
|
|
136
130
|
publisherAddress?: string;
|
|
137
131
|
authorization?: RelayBootstrapAuthorizationRecord;
|
|
138
132
|
relayProof?: RelayBootstrapProofRecord;
|
|
139
|
-
compact?: boolean;
|
|
140
133
|
compactMultiaddrLimit?: number;
|
|
141
134
|
now?: number;
|
|
142
135
|
}): RelayBootstrapPostContent;
|
|
@@ -172,7 +165,6 @@ declare function signRelayBootstrapProof(args: {
|
|
|
172
165
|
profile?: string;
|
|
173
166
|
version?: string;
|
|
174
167
|
updatedAt?: number;
|
|
175
|
-
compact?: boolean;
|
|
176
168
|
compactMultiaddrLimit?: number;
|
|
177
169
|
signer: RelayBootstrapProofSigner;
|
|
178
170
|
}): Promise<RelayBootstrapProofRecord>;
|
|
@@ -196,4 +188,4 @@ declare function createLibp2pAlephBootstrap(options?: DiscoverAlephBootstrapOpti
|
|
|
196
188
|
tagName?: string;
|
|
197
189
|
}): Promise<ReturnType<typeof bootstrap>>;
|
|
198
190
|
|
|
199
|
-
export { type CreateRelayBootstrapPostOptions, DEFAULT_ALEPH_API_HOST, DEFAULT_ALEPH_BOOTSTRAP_CHANNEL,
|
|
191
|
+
export { type CreateRelayBootstrapPostOptions, DEFAULT_ALEPH_API_HOST, DEFAULT_ALEPH_BOOTSTRAP_CHANNEL, DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE, DEFAULT_ALEPH_BOOTSTRAP_REF, DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT, DEFAULT_BOOTSTRAP_MAX_AGE_MS, DEFAULT_BOOTSTRAP_MAX_PAGES, DEFAULT_BOOTSTRAP_PAGINATION, type DiscoverAlephBootstrapOptions, type FilterPublicMultiaddrsOptions, RELAY_BOOTSTRAP_SIGNATURE_SCHEME, type RelayBootstrapAuthorizationPayload, type RelayBootstrapAuthorizationRecord, type RelayBootstrapContent, type RelayBootstrapPostContent, type RelayBootstrapPostRecord, type RelayBootstrapProofPayload, type RelayBootstrapProofRecord, type RelayBootstrapProofSigner, type RelayBootstrapTrustMode, type RelayBootstrapVerificationResult, buildRelayBootstrapPostContent, createLibp2pAlephBootstrap, createRelayBootstrapPost, dedupeMultiaddrs, discoverAlephBootstrapMultiaddrs, fetchAlephBootstrapPosts, filterPublicMultiaddrs, isPublicMultiaddr, relayBootstrapMultiaddrsHash, relayBootstrapTrustMode, selectCompactRelayBootstrapMultiaddrs, selectCurrentRelayBootstrapPosts, signRelayBootstrapAuthorization, signRelayBootstrapProof, verifyRelayBootstrapAuthorization, verifyRelayBootstrapDualKeyContent, verifyRelayBootstrapProof };
|
package/index.js
CHANGED
|
@@ -4,8 +4,7 @@ import { keccak256, recoverMessageAddress, stringToHex } from "viem";
|
|
|
4
4
|
var DEFAULT_ALEPH_API_HOST = "https://api.aleph.im";
|
|
5
5
|
var DEFAULT_ALEPH_BOOTSTRAP_CHANNEL = "simple-todo";
|
|
6
6
|
var DEFAULT_ALEPH_BOOTSTRAP_REF = "simple-todo-bootstrap";
|
|
7
|
-
var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap";
|
|
8
|
-
var DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE = "relay-bootstrap-v2";
|
|
7
|
+
var DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE = "relay-bootstrap-v2";
|
|
9
8
|
var DEFAULT_BOOTSTRAP_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
10
9
|
var DEFAULT_BOOTSTRAP_PAGINATION = 50;
|
|
11
10
|
var DEFAULT_BOOTSTRAP_MAX_PAGES = 5;
|
|
@@ -40,9 +39,6 @@ function serializeRelayProofPayload(payload) {
|
|
|
40
39
|
function relayBootstrapMultiaddrsHash(addrs) {
|
|
41
40
|
return keccak256(stringToHex(JSON.stringify(dedupeMultiaddrs(addrs))));
|
|
42
41
|
}
|
|
43
|
-
function compactPostType(postType) {
|
|
44
|
-
return (postType ?? DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE) === DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE;
|
|
45
|
-
}
|
|
46
42
|
function browserMultiaddrPreference(addr) {
|
|
47
43
|
const normalized = addr.toLowerCase();
|
|
48
44
|
if (normalized.includes("/tcp/443/tls/ws/")) return 0;
|
|
@@ -278,8 +274,6 @@ function normalizeRelayBootstrapPostRecord(value) {
|
|
|
278
274
|
function buildRelayBootstrapPostContent(args) {
|
|
279
275
|
const now = args.now ?? Date.now() / 1e3;
|
|
280
276
|
const updatedAt = args.now ?? Date.now();
|
|
281
|
-
const postType = args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE;
|
|
282
|
-
const compact = args.compact ?? compactPostType(postType);
|
|
283
277
|
const fullMultiaddrs = filterPublicMultiaddrs(args.multiaddrs);
|
|
284
278
|
const fullBrowserMultiaddrs = args.browserMultiaddrs ? filterPublicMultiaddrs(args.browserMultiaddrs, {
|
|
285
279
|
browserDialableOnly: true
|
|
@@ -289,13 +283,13 @@ function buildRelayBootstrapPostContent(args) {
|
|
|
289
283
|
args.compactMultiaddrLimit
|
|
290
284
|
);
|
|
291
285
|
return {
|
|
292
|
-
type:
|
|
286
|
+
type: DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
|
|
293
287
|
address: args.sender,
|
|
294
288
|
...args.ref ? { ref: args.ref } : {},
|
|
295
289
|
content: {
|
|
296
290
|
peerId: args.peerId,
|
|
297
|
-
multiaddrs:
|
|
298
|
-
browserMultiaddrs:
|
|
291
|
+
multiaddrs: compactMultiaddrs,
|
|
292
|
+
browserMultiaddrs: void 0,
|
|
299
293
|
registrationId: args.registrationId,
|
|
300
294
|
profile: args.profile,
|
|
301
295
|
version: args.version,
|
|
@@ -318,14 +312,12 @@ async function createRelayBootstrapPost(args) {
|
|
|
318
312
|
browserMultiaddrs: args.browserMultiaddrs,
|
|
319
313
|
registrationId: args.registrationId,
|
|
320
314
|
ref: args.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF,
|
|
321
|
-
postType: args.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
|
|
322
315
|
profile: args.profile,
|
|
323
316
|
version: args.version,
|
|
324
317
|
ownerAddress: args.ownerAddress,
|
|
325
318
|
publisherAddress: args.publisherAddress,
|
|
326
319
|
authorization: args.authorization,
|
|
327
320
|
relayProof: args.relayProof,
|
|
328
|
-
compact: args.compact,
|
|
329
321
|
compactMultiaddrLimit: args.compactMultiaddrLimit,
|
|
330
322
|
now: nowMillis
|
|
331
323
|
});
|
|
@@ -347,7 +339,7 @@ function relayBootstrapTrustMode(content) {
|
|
|
347
339
|
if (content?.authorization && content?.relayProof && content.authorization.payload.publisherAddress && content.relayProof.payload.peerId) {
|
|
348
340
|
return "dual-key-attested";
|
|
349
341
|
}
|
|
350
|
-
return "
|
|
342
|
+
return "wallet-signed";
|
|
351
343
|
}
|
|
352
344
|
async function signRelayBootstrapAuthorization(args) {
|
|
353
345
|
const payload = {
|
|
@@ -378,12 +370,11 @@ async function signRelayBootstrapProof(args) {
|
|
|
378
370
|
fullBrowserMultiaddrs && fullBrowserMultiaddrs.length > 0 ? fullBrowserMultiaddrs : fullMultiaddrs,
|
|
379
371
|
args.compactMultiaddrLimit
|
|
380
372
|
);
|
|
381
|
-
const compact = args.compact ?? false;
|
|
382
373
|
const payload = {
|
|
383
374
|
peerId: args.peerId,
|
|
384
|
-
multiaddrs:
|
|
385
|
-
browserMultiaddrs:
|
|
386
|
-
multiaddrsHash:
|
|
375
|
+
multiaddrs: void 0,
|
|
376
|
+
browserMultiaddrs: void 0,
|
|
377
|
+
multiaddrsHash: relayBootstrapMultiaddrsHash(compactMultiaddrs),
|
|
387
378
|
registrationId: args.registrationId,
|
|
388
379
|
profile: args.profile,
|
|
389
380
|
version: args.version,
|
|
@@ -538,10 +529,7 @@ async function fetchAlephBootstrapPosts(options = {}) {
|
|
|
538
529
|
options.channel ?? DEFAULT_ALEPH_BOOTSTRAP_CHANNEL
|
|
539
530
|
);
|
|
540
531
|
url.searchParams.set("refs", options.ref ?? DEFAULT_ALEPH_BOOTSTRAP_REF);
|
|
541
|
-
url.searchParams.set(
|
|
542
|
-
"types",
|
|
543
|
-
options.postType ?? DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE
|
|
544
|
-
);
|
|
532
|
+
url.searchParams.set("types", DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE);
|
|
545
533
|
url.searchParams.set(
|
|
546
534
|
"pagination",
|
|
547
535
|
String(options.pagination ?? DEFAULT_BOOTSTRAP_PAGINATION)
|
|
@@ -555,7 +543,21 @@ async function fetchAlephBootstrapPosts(options = {}) {
|
|
|
555
543
|
throw new Error(`Aleph bootstrap post lookup failed: ${response.status}`);
|
|
556
544
|
}
|
|
557
545
|
const payload = await response.json();
|
|
558
|
-
|
|
546
|
+
const posts = (payload.posts ?? []).map((entry) => normalizeRelayBootstrapPostRecord(entry)).filter((entry) => entry != null).sort((left, right) => compareRelayBootstrapPostRecency(right, left));
|
|
547
|
+
posts.forEach(assertSupportedRelayBootstrapPost);
|
|
548
|
+
return posts;
|
|
549
|
+
}
|
|
550
|
+
function assertSupportedRelayBootstrapPost(post) {
|
|
551
|
+
if (post.type === "relay-bootstrap") {
|
|
552
|
+
throw new Error(
|
|
553
|
+
"Legacy relay-bootstrap record encountered. Only relay-bootstrap-v2 is supported."
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
if (post.type && post.type !== DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE) {
|
|
557
|
+
throw new Error(
|
|
558
|
+
`Unsupported relay bootstrap post type: ${post.type}. Expected ${DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE}.`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
559
561
|
}
|
|
560
562
|
function compareRelayBootstrapPostRecency(left, right) {
|
|
561
563
|
const leftUpdatedAt = left.content?.updatedAt ?? 0;
|
|
@@ -577,6 +579,7 @@ function selectCurrentRelayBootstrapPosts(posts, options = {}) {
|
|
|
577
579
|
const now = options.now ?? Date.now();
|
|
578
580
|
const selected = /* @__PURE__ */ new Map();
|
|
579
581
|
for (const post of posts) {
|
|
582
|
+
assertSupportedRelayBootstrapPost(post);
|
|
580
583
|
const content = post.content;
|
|
581
584
|
if (!content) continue;
|
|
582
585
|
if (now - content.updatedAt > maxAgeMs) continue;
|
|
@@ -599,7 +602,7 @@ async function filterTrustedRelayBootstrapPosts(posts, options = {}) {
|
|
|
599
602
|
const content = post.content;
|
|
600
603
|
if (!content) continue;
|
|
601
604
|
const trustMode = relayBootstrapTrustMode(content);
|
|
602
|
-
if (trustMode === "
|
|
605
|
+
if (trustMode === "wallet-signed") {
|
|
603
606
|
if (!requireDualKeyAttestation) {
|
|
604
607
|
trusted.push(post);
|
|
605
608
|
}
|
|
@@ -621,38 +624,31 @@ async function discoverAlephBootstrapMultiaddrs(options = {}) {
|
|
|
621
624
|
const pagination = options.pagination ?? DEFAULT_BOOTSTRAP_PAGINATION;
|
|
622
625
|
const startPage = options.page ?? 1;
|
|
623
626
|
const maxPages = Math.max(1, options.maxPages ?? DEFAULT_BOOTSTRAP_MAX_PAGES);
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
);
|
|
650
|
-
if (addrs.length > 0) {
|
|
651
|
-
return addrs;
|
|
652
|
-
}
|
|
653
|
-
if (pagePosts.length < pagination) {
|
|
654
|
-
break;
|
|
655
|
-
}
|
|
627
|
+
const collectedPosts = [];
|
|
628
|
+
for (let offset = 0; offset < maxPages; offset += 1) {
|
|
629
|
+
const page = startPage + offset;
|
|
630
|
+
const pagePosts = await fetchAlephBootstrapPosts({
|
|
631
|
+
...options,
|
|
632
|
+
page,
|
|
633
|
+
pagination
|
|
634
|
+
});
|
|
635
|
+
collectedPosts.push(...pagePosts);
|
|
636
|
+
const selectedPosts = selectCurrentRelayBootstrapPosts(collectedPosts, {
|
|
637
|
+
maxAgeMs: options.maxAgeMs
|
|
638
|
+
});
|
|
639
|
+
const trustedPosts = await filterTrustedRelayBootstrapPosts(selectedPosts, {
|
|
640
|
+
requireDualKeyAttestation: options.requireDualKeyAttestation,
|
|
641
|
+
verifyDualKeyAttestation: options.verifyDualKeyAttestation
|
|
642
|
+
});
|
|
643
|
+
const addrs = relayBootstrapPostsToMultiaddrs(
|
|
644
|
+
trustedPosts,
|
|
645
|
+
browserDialableOnly
|
|
646
|
+
);
|
|
647
|
+
if (addrs.length > 0) {
|
|
648
|
+
return addrs;
|
|
649
|
+
}
|
|
650
|
+
if (pagePosts.length < pagination) {
|
|
651
|
+
break;
|
|
656
652
|
}
|
|
657
653
|
}
|
|
658
654
|
return [];
|
|
@@ -682,7 +678,6 @@ async function createLibp2pAlephBootstrap(options = {}) {
|
|
|
682
678
|
export {
|
|
683
679
|
DEFAULT_ALEPH_API_HOST,
|
|
684
680
|
DEFAULT_ALEPH_BOOTSTRAP_CHANNEL,
|
|
685
|
-
DEFAULT_ALEPH_BOOTSTRAP_COMPACT_POST_TYPE,
|
|
686
681
|
DEFAULT_ALEPH_BOOTSTRAP_POST_TYPE,
|
|
687
682
|
DEFAULT_ALEPH_BOOTSTRAP_REF,
|
|
688
683
|
DEFAULT_BOOTSTRAP_COMPACT_MULTIADDR_LIMIT,
|