@unicitylabs/sphere-sdk 0.1.2 → 0.1.4
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 +54 -15
- package/dist/core/index.cjs +310 -88
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +300 -204
- package/dist/core/index.d.ts +300 -204
- package/dist/core/index.js +310 -88
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +1234 -920
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +1234 -926
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs +1112 -0
- package/dist/impl/browser/ipfs.cjs.map +1 -0
- package/dist/impl/browser/ipfs.js +1079 -0
- package/dist/impl/browser/ipfs.js.map +1 -0
- package/dist/impl/nodejs/index.cjs +1081 -222
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +131 -55
- package/dist/impl/nodejs/index.d.ts +131 -55
- package/dist/impl/nodejs/index.js +1088 -225
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +310 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +663 -345
- package/dist/index.d.ts +663 -345
- package/dist/index.js +310 -88
- package/dist/index.js.map +1 -1
- package/package.json +16 -2
|
@@ -75,6 +75,9 @@ var FileStorageProvider = class {
|
|
|
75
75
|
return this._identity;
|
|
76
76
|
}
|
|
77
77
|
async connect() {
|
|
78
|
+
if (this.status === "connected") {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
78
81
|
if (!fs.existsSync(this.dataDir)) {
|
|
79
82
|
fs.mkdirSync(this.dataDir, { recursive: true });
|
|
80
83
|
}
|
|
@@ -183,7 +186,7 @@ var FileTokenStorageProvider = class {
|
|
|
183
186
|
const data = {
|
|
184
187
|
_meta: {
|
|
185
188
|
version: 1,
|
|
186
|
-
address: this.identity?.
|
|
189
|
+
address: this.identity?.l1Address ?? "",
|
|
187
190
|
formatVersion: "2.0",
|
|
188
191
|
updatedAt: Date.now()
|
|
189
192
|
}
|
|
@@ -298,15 +301,556 @@ var import_ws = __toESM(require("ws"), 1);
|
|
|
298
301
|
|
|
299
302
|
// transport/NostrTransportProvider.ts
|
|
300
303
|
var import_buffer = require("buffer");
|
|
304
|
+
|
|
305
|
+
// node_modules/@noble/hashes/utils.js
|
|
306
|
+
function isBytes(a) {
|
|
307
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
308
|
+
}
|
|
309
|
+
function anumber(n, title = "") {
|
|
310
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
311
|
+
const prefix = title && `"${title}" `;
|
|
312
|
+
throw new Error(`${prefix}expected integer >= 0, got ${n}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function abytes(value, length, title = "") {
|
|
316
|
+
const bytes = isBytes(value);
|
|
317
|
+
const len = value?.length;
|
|
318
|
+
const needsLen = length !== void 0;
|
|
319
|
+
if (!bytes || needsLen && len !== length) {
|
|
320
|
+
const prefix = title && `"${title}" `;
|
|
321
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
322
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
323
|
+
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
324
|
+
}
|
|
325
|
+
return value;
|
|
326
|
+
}
|
|
327
|
+
function ahash(h) {
|
|
328
|
+
if (typeof h !== "function" || typeof h.create !== "function")
|
|
329
|
+
throw new Error("Hash must wrapped by utils.createHasher");
|
|
330
|
+
anumber(h.outputLen);
|
|
331
|
+
anumber(h.blockLen);
|
|
332
|
+
}
|
|
333
|
+
function aexists(instance, checkFinished = true) {
|
|
334
|
+
if (instance.destroyed)
|
|
335
|
+
throw new Error("Hash instance has been destroyed");
|
|
336
|
+
if (checkFinished && instance.finished)
|
|
337
|
+
throw new Error("Hash#digest() has already been called");
|
|
338
|
+
}
|
|
339
|
+
function aoutput(out, instance) {
|
|
340
|
+
abytes(out, void 0, "digestInto() output");
|
|
341
|
+
const min = instance.outputLen;
|
|
342
|
+
if (out.length < min) {
|
|
343
|
+
throw new Error('"digestInto() output" expected to be of length >=' + min);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function clean(...arrays) {
|
|
347
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
348
|
+
arrays[i].fill(0);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function createView(arr) {
|
|
352
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
353
|
+
}
|
|
354
|
+
function rotr(word, shift) {
|
|
355
|
+
return word << 32 - shift | word >>> shift;
|
|
356
|
+
}
|
|
357
|
+
function createHasher(hashCons, info = {}) {
|
|
358
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
359
|
+
const tmp = hashCons(void 0);
|
|
360
|
+
hashC.outputLen = tmp.outputLen;
|
|
361
|
+
hashC.blockLen = tmp.blockLen;
|
|
362
|
+
hashC.create = (opts) => hashCons(opts);
|
|
363
|
+
Object.assign(hashC, info);
|
|
364
|
+
return Object.freeze(hashC);
|
|
365
|
+
}
|
|
366
|
+
var oidNist = (suffix) => ({
|
|
367
|
+
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
// node_modules/@noble/hashes/hmac.js
|
|
371
|
+
var _HMAC = class {
|
|
372
|
+
oHash;
|
|
373
|
+
iHash;
|
|
374
|
+
blockLen;
|
|
375
|
+
outputLen;
|
|
376
|
+
finished = false;
|
|
377
|
+
destroyed = false;
|
|
378
|
+
constructor(hash, key) {
|
|
379
|
+
ahash(hash);
|
|
380
|
+
abytes(key, void 0, "key");
|
|
381
|
+
this.iHash = hash.create();
|
|
382
|
+
if (typeof this.iHash.update !== "function")
|
|
383
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
384
|
+
this.blockLen = this.iHash.blockLen;
|
|
385
|
+
this.outputLen = this.iHash.outputLen;
|
|
386
|
+
const blockLen = this.blockLen;
|
|
387
|
+
const pad = new Uint8Array(blockLen);
|
|
388
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
389
|
+
for (let i = 0; i < pad.length; i++)
|
|
390
|
+
pad[i] ^= 54;
|
|
391
|
+
this.iHash.update(pad);
|
|
392
|
+
this.oHash = hash.create();
|
|
393
|
+
for (let i = 0; i < pad.length; i++)
|
|
394
|
+
pad[i] ^= 54 ^ 92;
|
|
395
|
+
this.oHash.update(pad);
|
|
396
|
+
clean(pad);
|
|
397
|
+
}
|
|
398
|
+
update(buf) {
|
|
399
|
+
aexists(this);
|
|
400
|
+
this.iHash.update(buf);
|
|
401
|
+
return this;
|
|
402
|
+
}
|
|
403
|
+
digestInto(out) {
|
|
404
|
+
aexists(this);
|
|
405
|
+
abytes(out, this.outputLen, "output");
|
|
406
|
+
this.finished = true;
|
|
407
|
+
this.iHash.digestInto(out);
|
|
408
|
+
this.oHash.update(out);
|
|
409
|
+
this.oHash.digestInto(out);
|
|
410
|
+
this.destroy();
|
|
411
|
+
}
|
|
412
|
+
digest() {
|
|
413
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
414
|
+
this.digestInto(out);
|
|
415
|
+
return out;
|
|
416
|
+
}
|
|
417
|
+
_cloneInto(to) {
|
|
418
|
+
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
419
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
420
|
+
to = to;
|
|
421
|
+
to.finished = finished;
|
|
422
|
+
to.destroyed = destroyed;
|
|
423
|
+
to.blockLen = blockLen;
|
|
424
|
+
to.outputLen = outputLen;
|
|
425
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
426
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
427
|
+
return to;
|
|
428
|
+
}
|
|
429
|
+
clone() {
|
|
430
|
+
return this._cloneInto();
|
|
431
|
+
}
|
|
432
|
+
destroy() {
|
|
433
|
+
this.destroyed = true;
|
|
434
|
+
this.oHash.destroy();
|
|
435
|
+
this.iHash.destroy();
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
|
|
439
|
+
hmac.create = (hash, key) => new _HMAC(hash, key);
|
|
440
|
+
|
|
441
|
+
// node_modules/@noble/hashes/hkdf.js
|
|
442
|
+
function extract(hash, ikm, salt) {
|
|
443
|
+
ahash(hash);
|
|
444
|
+
if (salt === void 0)
|
|
445
|
+
salt = new Uint8Array(hash.outputLen);
|
|
446
|
+
return hmac(hash, salt, ikm);
|
|
447
|
+
}
|
|
448
|
+
var HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);
|
|
449
|
+
var EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();
|
|
450
|
+
function expand(hash, prk, info, length = 32) {
|
|
451
|
+
ahash(hash);
|
|
452
|
+
anumber(length, "length");
|
|
453
|
+
const olen = hash.outputLen;
|
|
454
|
+
if (length > 255 * olen)
|
|
455
|
+
throw new Error("Length must be <= 255*HashLen");
|
|
456
|
+
const blocks = Math.ceil(length / olen);
|
|
457
|
+
if (info === void 0)
|
|
458
|
+
info = EMPTY_BUFFER;
|
|
459
|
+
else
|
|
460
|
+
abytes(info, void 0, "info");
|
|
461
|
+
const okm = new Uint8Array(blocks * olen);
|
|
462
|
+
const HMAC = hmac.create(hash, prk);
|
|
463
|
+
const HMACTmp = HMAC._cloneInto();
|
|
464
|
+
const T = new Uint8Array(HMAC.outputLen);
|
|
465
|
+
for (let counter = 0; counter < blocks; counter++) {
|
|
466
|
+
HKDF_COUNTER[0] = counter + 1;
|
|
467
|
+
HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T);
|
|
468
|
+
okm.set(T, olen * counter);
|
|
469
|
+
HMAC._cloneInto(HMACTmp);
|
|
470
|
+
}
|
|
471
|
+
HMAC.destroy();
|
|
472
|
+
HMACTmp.destroy();
|
|
473
|
+
clean(T, HKDF_COUNTER);
|
|
474
|
+
return okm.slice(0, length);
|
|
475
|
+
}
|
|
476
|
+
var hkdf = (hash, ikm, salt, info, length) => expand(hash, extract(hash, ikm, salt), info, length);
|
|
477
|
+
|
|
478
|
+
// node_modules/@noble/hashes/_md.js
|
|
479
|
+
function Chi(a, b, c) {
|
|
480
|
+
return a & b ^ ~a & c;
|
|
481
|
+
}
|
|
482
|
+
function Maj(a, b, c) {
|
|
483
|
+
return a & b ^ a & c ^ b & c;
|
|
484
|
+
}
|
|
485
|
+
var HashMD = class {
|
|
486
|
+
blockLen;
|
|
487
|
+
outputLen;
|
|
488
|
+
padOffset;
|
|
489
|
+
isLE;
|
|
490
|
+
// For partial updates less than block size
|
|
491
|
+
buffer;
|
|
492
|
+
view;
|
|
493
|
+
finished = false;
|
|
494
|
+
length = 0;
|
|
495
|
+
pos = 0;
|
|
496
|
+
destroyed = false;
|
|
497
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
498
|
+
this.blockLen = blockLen;
|
|
499
|
+
this.outputLen = outputLen;
|
|
500
|
+
this.padOffset = padOffset;
|
|
501
|
+
this.isLE = isLE;
|
|
502
|
+
this.buffer = new Uint8Array(blockLen);
|
|
503
|
+
this.view = createView(this.buffer);
|
|
504
|
+
}
|
|
505
|
+
update(data) {
|
|
506
|
+
aexists(this);
|
|
507
|
+
abytes(data);
|
|
508
|
+
const { view, buffer, blockLen } = this;
|
|
509
|
+
const len = data.length;
|
|
510
|
+
for (let pos = 0; pos < len; ) {
|
|
511
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
512
|
+
if (take === blockLen) {
|
|
513
|
+
const dataView = createView(data);
|
|
514
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
515
|
+
this.process(dataView, pos);
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
519
|
+
this.pos += take;
|
|
520
|
+
pos += take;
|
|
521
|
+
if (this.pos === blockLen) {
|
|
522
|
+
this.process(view, 0);
|
|
523
|
+
this.pos = 0;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
this.length += data.length;
|
|
527
|
+
this.roundClean();
|
|
528
|
+
return this;
|
|
529
|
+
}
|
|
530
|
+
digestInto(out) {
|
|
531
|
+
aexists(this);
|
|
532
|
+
aoutput(out, this);
|
|
533
|
+
this.finished = true;
|
|
534
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
535
|
+
let { pos } = this;
|
|
536
|
+
buffer[pos++] = 128;
|
|
537
|
+
clean(this.buffer.subarray(pos));
|
|
538
|
+
if (this.padOffset > blockLen - pos) {
|
|
539
|
+
this.process(view, 0);
|
|
540
|
+
pos = 0;
|
|
541
|
+
}
|
|
542
|
+
for (let i = pos; i < blockLen; i++)
|
|
543
|
+
buffer[i] = 0;
|
|
544
|
+
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
|
|
545
|
+
this.process(view, 0);
|
|
546
|
+
const oview = createView(out);
|
|
547
|
+
const len = this.outputLen;
|
|
548
|
+
if (len % 4)
|
|
549
|
+
throw new Error("_sha2: outputLen must be aligned to 32bit");
|
|
550
|
+
const outLen = len / 4;
|
|
551
|
+
const state = this.get();
|
|
552
|
+
if (outLen > state.length)
|
|
553
|
+
throw new Error("_sha2: outputLen bigger than state");
|
|
554
|
+
for (let i = 0; i < outLen; i++)
|
|
555
|
+
oview.setUint32(4 * i, state[i], isLE);
|
|
556
|
+
}
|
|
557
|
+
digest() {
|
|
558
|
+
const { buffer, outputLen } = this;
|
|
559
|
+
this.digestInto(buffer);
|
|
560
|
+
const res = buffer.slice(0, outputLen);
|
|
561
|
+
this.destroy();
|
|
562
|
+
return res;
|
|
563
|
+
}
|
|
564
|
+
_cloneInto(to) {
|
|
565
|
+
to ||= new this.constructor();
|
|
566
|
+
to.set(...this.get());
|
|
567
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
568
|
+
to.destroyed = destroyed;
|
|
569
|
+
to.finished = finished;
|
|
570
|
+
to.length = length;
|
|
571
|
+
to.pos = pos;
|
|
572
|
+
if (length % blockLen)
|
|
573
|
+
to.buffer.set(buffer);
|
|
574
|
+
return to;
|
|
575
|
+
}
|
|
576
|
+
clone() {
|
|
577
|
+
return this._cloneInto();
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
581
|
+
1779033703,
|
|
582
|
+
3144134277,
|
|
583
|
+
1013904242,
|
|
584
|
+
2773480762,
|
|
585
|
+
1359893119,
|
|
586
|
+
2600822924,
|
|
587
|
+
528734635,
|
|
588
|
+
1541459225
|
|
589
|
+
]);
|
|
590
|
+
|
|
591
|
+
// node_modules/@noble/hashes/sha2.js
|
|
592
|
+
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
593
|
+
1116352408,
|
|
594
|
+
1899447441,
|
|
595
|
+
3049323471,
|
|
596
|
+
3921009573,
|
|
597
|
+
961987163,
|
|
598
|
+
1508970993,
|
|
599
|
+
2453635748,
|
|
600
|
+
2870763221,
|
|
601
|
+
3624381080,
|
|
602
|
+
310598401,
|
|
603
|
+
607225278,
|
|
604
|
+
1426881987,
|
|
605
|
+
1925078388,
|
|
606
|
+
2162078206,
|
|
607
|
+
2614888103,
|
|
608
|
+
3248222580,
|
|
609
|
+
3835390401,
|
|
610
|
+
4022224774,
|
|
611
|
+
264347078,
|
|
612
|
+
604807628,
|
|
613
|
+
770255983,
|
|
614
|
+
1249150122,
|
|
615
|
+
1555081692,
|
|
616
|
+
1996064986,
|
|
617
|
+
2554220882,
|
|
618
|
+
2821834349,
|
|
619
|
+
2952996808,
|
|
620
|
+
3210313671,
|
|
621
|
+
3336571891,
|
|
622
|
+
3584528711,
|
|
623
|
+
113926993,
|
|
624
|
+
338241895,
|
|
625
|
+
666307205,
|
|
626
|
+
773529912,
|
|
627
|
+
1294757372,
|
|
628
|
+
1396182291,
|
|
629
|
+
1695183700,
|
|
630
|
+
1986661051,
|
|
631
|
+
2177026350,
|
|
632
|
+
2456956037,
|
|
633
|
+
2730485921,
|
|
634
|
+
2820302411,
|
|
635
|
+
3259730800,
|
|
636
|
+
3345764771,
|
|
637
|
+
3516065817,
|
|
638
|
+
3600352804,
|
|
639
|
+
4094571909,
|
|
640
|
+
275423344,
|
|
641
|
+
430227734,
|
|
642
|
+
506948616,
|
|
643
|
+
659060556,
|
|
644
|
+
883997877,
|
|
645
|
+
958139571,
|
|
646
|
+
1322822218,
|
|
647
|
+
1537002063,
|
|
648
|
+
1747873779,
|
|
649
|
+
1955562222,
|
|
650
|
+
2024104815,
|
|
651
|
+
2227730452,
|
|
652
|
+
2361852424,
|
|
653
|
+
2428436474,
|
|
654
|
+
2756734187,
|
|
655
|
+
3204031479,
|
|
656
|
+
3329325298
|
|
657
|
+
]);
|
|
658
|
+
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
659
|
+
var SHA2_32B = class extends HashMD {
|
|
660
|
+
constructor(outputLen) {
|
|
661
|
+
super(64, outputLen, 8, false);
|
|
662
|
+
}
|
|
663
|
+
get() {
|
|
664
|
+
const { A, B, C, D, E, F, G, H } = this;
|
|
665
|
+
return [A, B, C, D, E, F, G, H];
|
|
666
|
+
}
|
|
667
|
+
// prettier-ignore
|
|
668
|
+
set(A, B, C, D, E, F, G, H) {
|
|
669
|
+
this.A = A | 0;
|
|
670
|
+
this.B = B | 0;
|
|
671
|
+
this.C = C | 0;
|
|
672
|
+
this.D = D | 0;
|
|
673
|
+
this.E = E | 0;
|
|
674
|
+
this.F = F | 0;
|
|
675
|
+
this.G = G | 0;
|
|
676
|
+
this.H = H | 0;
|
|
677
|
+
}
|
|
678
|
+
process(view, offset) {
|
|
679
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
680
|
+
SHA256_W[i] = view.getUint32(offset, false);
|
|
681
|
+
for (let i = 16; i < 64; i++) {
|
|
682
|
+
const W15 = SHA256_W[i - 15];
|
|
683
|
+
const W2 = SHA256_W[i - 2];
|
|
684
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
685
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
686
|
+
SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
|
|
687
|
+
}
|
|
688
|
+
let { A, B, C, D, E, F, G, H } = this;
|
|
689
|
+
for (let i = 0; i < 64; i++) {
|
|
690
|
+
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
691
|
+
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
|
|
692
|
+
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
|
693
|
+
const T2 = sigma0 + Maj(A, B, C) | 0;
|
|
694
|
+
H = G;
|
|
695
|
+
G = F;
|
|
696
|
+
F = E;
|
|
697
|
+
E = D + T1 | 0;
|
|
698
|
+
D = C;
|
|
699
|
+
C = B;
|
|
700
|
+
B = A;
|
|
701
|
+
A = T1 + T2 | 0;
|
|
702
|
+
}
|
|
703
|
+
A = A + this.A | 0;
|
|
704
|
+
B = B + this.B | 0;
|
|
705
|
+
C = C + this.C | 0;
|
|
706
|
+
D = D + this.D | 0;
|
|
707
|
+
E = E + this.E | 0;
|
|
708
|
+
F = F + this.F | 0;
|
|
709
|
+
G = G + this.G | 0;
|
|
710
|
+
H = H + this.H | 0;
|
|
711
|
+
this.set(A, B, C, D, E, F, G, H);
|
|
712
|
+
}
|
|
713
|
+
roundClean() {
|
|
714
|
+
clean(SHA256_W);
|
|
715
|
+
}
|
|
716
|
+
destroy() {
|
|
717
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
718
|
+
clean(this.buffer);
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
var _SHA256 = class extends SHA2_32B {
|
|
722
|
+
// We cannot use array here since array allows indexing by variable
|
|
723
|
+
// which means optimizer/compiler cannot use registers.
|
|
724
|
+
A = SHA256_IV[0] | 0;
|
|
725
|
+
B = SHA256_IV[1] | 0;
|
|
726
|
+
C = SHA256_IV[2] | 0;
|
|
727
|
+
D = SHA256_IV[3] | 0;
|
|
728
|
+
E = SHA256_IV[4] | 0;
|
|
729
|
+
F = SHA256_IV[5] | 0;
|
|
730
|
+
G = SHA256_IV[6] | 0;
|
|
731
|
+
H = SHA256_IV[7] | 0;
|
|
732
|
+
constructor() {
|
|
733
|
+
super(32);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
var sha256 = /* @__PURE__ */ createHasher(
|
|
737
|
+
() => new _SHA256(),
|
|
738
|
+
/* @__PURE__ */ oidNist(1)
|
|
739
|
+
);
|
|
740
|
+
|
|
741
|
+
// transport/NostrTransportProvider.ts
|
|
301
742
|
var import_nostr_js_sdk = require("@unicitylabs/nostr-js-sdk");
|
|
302
743
|
|
|
744
|
+
// core/crypto.ts
|
|
745
|
+
var bip39 = __toESM(require("bip39"), 1);
|
|
746
|
+
var import_crypto_js = __toESM(require("crypto-js"), 1);
|
|
747
|
+
var import_elliptic = __toESM(require("elliptic"), 1);
|
|
748
|
+
|
|
749
|
+
// core/bech32.ts
|
|
750
|
+
var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
751
|
+
var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
752
|
+
function convertBits(data, fromBits, toBits, pad) {
|
|
753
|
+
let acc = 0;
|
|
754
|
+
let bits = 0;
|
|
755
|
+
const ret = [];
|
|
756
|
+
const maxv = (1 << toBits) - 1;
|
|
757
|
+
for (let i = 0; i < data.length; i++) {
|
|
758
|
+
const value = data[i];
|
|
759
|
+
if (value < 0 || value >> fromBits !== 0) return null;
|
|
760
|
+
acc = acc << fromBits | value;
|
|
761
|
+
bits += fromBits;
|
|
762
|
+
while (bits >= toBits) {
|
|
763
|
+
bits -= toBits;
|
|
764
|
+
ret.push(acc >> bits & maxv);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
if (pad) {
|
|
768
|
+
if (bits > 0) {
|
|
769
|
+
ret.push(acc << toBits - bits & maxv);
|
|
770
|
+
}
|
|
771
|
+
} else if (bits >= fromBits || acc << toBits - bits & maxv) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
return ret;
|
|
775
|
+
}
|
|
776
|
+
function hrpExpand(hrp) {
|
|
777
|
+
const ret = [];
|
|
778
|
+
for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);
|
|
779
|
+
ret.push(0);
|
|
780
|
+
for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);
|
|
781
|
+
return ret;
|
|
782
|
+
}
|
|
783
|
+
function bech32Polymod(values) {
|
|
784
|
+
let chk = 1;
|
|
785
|
+
for (let p = 0; p < values.length; p++) {
|
|
786
|
+
const top = chk >> 25;
|
|
787
|
+
chk = (chk & 33554431) << 5 ^ values[p];
|
|
788
|
+
for (let i = 0; i < 5; i++) {
|
|
789
|
+
if (top >> i & 1) chk ^= GENERATOR[i];
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return chk;
|
|
793
|
+
}
|
|
794
|
+
function bech32Checksum(hrp, data) {
|
|
795
|
+
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
|
796
|
+
const mod = bech32Polymod(values) ^ 1;
|
|
797
|
+
const ret = [];
|
|
798
|
+
for (let p = 0; p < 6; p++) {
|
|
799
|
+
ret.push(mod >> 5 * (5 - p) & 31);
|
|
800
|
+
}
|
|
801
|
+
return ret;
|
|
802
|
+
}
|
|
803
|
+
function encodeBech32(hrp, version, program) {
|
|
804
|
+
if (version < 0 || version > 16) {
|
|
805
|
+
throw new Error("Invalid witness version");
|
|
806
|
+
}
|
|
807
|
+
const converted = convertBits(Array.from(program), 8, 5, true);
|
|
808
|
+
if (!converted) {
|
|
809
|
+
throw new Error("Failed to convert bits");
|
|
810
|
+
}
|
|
811
|
+
const data = [version].concat(converted);
|
|
812
|
+
const checksum = bech32Checksum(hrp, data);
|
|
813
|
+
const combined = data.concat(checksum);
|
|
814
|
+
let out = hrp + "1";
|
|
815
|
+
for (let i = 0; i < combined.length; i++) {
|
|
816
|
+
out += CHARSET[combined[i]];
|
|
817
|
+
}
|
|
818
|
+
return out;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// core/crypto.ts
|
|
822
|
+
var ec = new import_elliptic.default.ec("secp256k1");
|
|
823
|
+
var CURVE_ORDER = BigInt(
|
|
824
|
+
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
|
|
825
|
+
);
|
|
826
|
+
function getPublicKey(privateKey, compressed = true) {
|
|
827
|
+
const keyPair = ec.keyFromPrivate(privateKey, "hex");
|
|
828
|
+
return keyPair.getPublic(compressed, "hex");
|
|
829
|
+
}
|
|
830
|
+
function sha2562(data, inputEncoding = "hex") {
|
|
831
|
+
const parsed = inputEncoding === "hex" ? import_crypto_js.default.enc.Hex.parse(data) : import_crypto_js.default.enc.Utf8.parse(data);
|
|
832
|
+
return import_crypto_js.default.SHA256(parsed).toString();
|
|
833
|
+
}
|
|
834
|
+
function ripemd160(data, inputEncoding = "hex") {
|
|
835
|
+
const parsed = inputEncoding === "hex" ? import_crypto_js.default.enc.Hex.parse(data) : import_crypto_js.default.enc.Utf8.parse(data);
|
|
836
|
+
return import_crypto_js.default.RIPEMD160(parsed).toString();
|
|
837
|
+
}
|
|
838
|
+
function hash160(data) {
|
|
839
|
+
const sha = sha2562(data, "hex");
|
|
840
|
+
return ripemd160(sha, "hex");
|
|
841
|
+
}
|
|
842
|
+
function hash160ToBytes(hash160Hex) {
|
|
843
|
+
const matches = hash160Hex.match(/../g);
|
|
844
|
+
if (!matches) return new Uint8Array(0);
|
|
845
|
+
return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
|
|
846
|
+
}
|
|
847
|
+
function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
|
|
848
|
+
const pubKeyHash = hash160(publicKey);
|
|
849
|
+
const programBytes = hash160ToBytes(pubKeyHash);
|
|
850
|
+
return encodeBech32(prefix, witnessVersion, programBytes);
|
|
851
|
+
}
|
|
852
|
+
|
|
303
853
|
// transport/websocket.ts
|
|
304
|
-
var WebSocketReadyState = {
|
|
305
|
-
CONNECTING: 0,
|
|
306
|
-
OPEN: 1,
|
|
307
|
-
CLOSING: 2,
|
|
308
|
-
CLOSED: 3
|
|
309
|
-
};
|
|
310
854
|
function defaultUUIDGenerator() {
|
|
311
855
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
312
856
|
return crypto.randomUUID();
|
|
@@ -436,6 +980,59 @@ var TIMEOUTS = {
|
|
|
436
980
|
|
|
437
981
|
// transport/NostrTransportProvider.ts
|
|
438
982
|
var EVENT_KINDS = NOSTR_EVENT_KINDS;
|
|
983
|
+
function deriveNametagEncryptionKey(privateKeyHex) {
|
|
984
|
+
const privateKeyBytes = import_buffer.Buffer.from(privateKeyHex, "hex");
|
|
985
|
+
const saltInput = new TextEncoder().encode("sphere-nametag-salt");
|
|
986
|
+
const salt = sha256(saltInput);
|
|
987
|
+
const info = new TextEncoder().encode("nametag-encryption");
|
|
988
|
+
return hkdf(sha256, privateKeyBytes, salt, info, 32);
|
|
989
|
+
}
|
|
990
|
+
async function encryptNametag(nametag, privateKeyHex) {
|
|
991
|
+
const key = deriveNametagEncryptionKey(privateKeyHex);
|
|
992
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
993
|
+
const encoder = new TextEncoder();
|
|
994
|
+
const data = encoder.encode(nametag);
|
|
995
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
996
|
+
"raw",
|
|
997
|
+
new Uint8Array(key).buffer,
|
|
998
|
+
{ name: "AES-GCM" },
|
|
999
|
+
false,
|
|
1000
|
+
["encrypt"]
|
|
1001
|
+
);
|
|
1002
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
1003
|
+
{ name: "AES-GCM", iv: new Uint8Array(iv).buffer },
|
|
1004
|
+
cryptoKey,
|
|
1005
|
+
new Uint8Array(data).buffer
|
|
1006
|
+
);
|
|
1007
|
+
const combined = new Uint8Array(iv.length + encrypted.byteLength);
|
|
1008
|
+
combined.set(iv, 0);
|
|
1009
|
+
combined.set(new Uint8Array(encrypted), iv.length);
|
|
1010
|
+
return import_buffer.Buffer.from(combined).toString("base64");
|
|
1011
|
+
}
|
|
1012
|
+
async function decryptNametag(encryptedBase64, privateKeyHex) {
|
|
1013
|
+
try {
|
|
1014
|
+
const key = deriveNametagEncryptionKey(privateKeyHex);
|
|
1015
|
+
const combined = import_buffer.Buffer.from(encryptedBase64, "base64");
|
|
1016
|
+
const iv = combined.slice(0, 12);
|
|
1017
|
+
const ciphertext = combined.slice(12);
|
|
1018
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
1019
|
+
"raw",
|
|
1020
|
+
new Uint8Array(key).buffer,
|
|
1021
|
+
{ name: "AES-GCM" },
|
|
1022
|
+
false,
|
|
1023
|
+
["decrypt"]
|
|
1024
|
+
);
|
|
1025
|
+
const decrypted = await crypto.subtle.decrypt(
|
|
1026
|
+
{ name: "AES-GCM", iv: new Uint8Array(iv).buffer },
|
|
1027
|
+
cryptoKey,
|
|
1028
|
+
new Uint8Array(ciphertext).buffer
|
|
1029
|
+
);
|
|
1030
|
+
const decoder = new TextDecoder();
|
|
1031
|
+
return decoder.decode(decrypted);
|
|
1032
|
+
} catch {
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
439
1036
|
var NostrTransportProvider = class {
|
|
440
1037
|
id = "nostr";
|
|
441
1038
|
name = "Nostr Transport";
|
|
@@ -445,9 +1042,10 @@ var NostrTransportProvider = class {
|
|
|
445
1042
|
identity = null;
|
|
446
1043
|
keyManager = null;
|
|
447
1044
|
status = "disconnected";
|
|
448
|
-
//
|
|
449
|
-
|
|
450
|
-
|
|
1045
|
+
// NostrClient from nostr-js-sdk handles all WebSocket management,
|
|
1046
|
+
// keepalive pings, reconnection, and NIP-42 authentication
|
|
1047
|
+
nostrClient = null;
|
|
1048
|
+
mainSubscriptionId = null;
|
|
451
1049
|
// Event handlers
|
|
452
1050
|
messageHandlers = /* @__PURE__ */ new Set();
|
|
453
1051
|
transferHandlers = /* @__PURE__ */ new Set();
|
|
@@ -455,9 +1053,6 @@ var NostrTransportProvider = class {
|
|
|
455
1053
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
456
1054
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
457
1055
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
458
|
-
// Subscriptions
|
|
459
|
-
subscriptions = /* @__PURE__ */ new Map();
|
|
460
|
-
// subId -> relays
|
|
461
1056
|
constructor(config) {
|
|
462
1057
|
this.config = {
|
|
463
1058
|
relays: config.relays ?? [...DEFAULT_NOSTR_RELAYS],
|
|
@@ -477,16 +1072,43 @@ var NostrTransportProvider = class {
|
|
|
477
1072
|
if (this.status === "connected") return;
|
|
478
1073
|
this.status = "connecting";
|
|
479
1074
|
try {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
1075
|
+
if (!this.keyManager) {
|
|
1076
|
+
const tempKey = import_buffer.Buffer.alloc(32);
|
|
1077
|
+
crypto.getRandomValues(tempKey);
|
|
1078
|
+
this.keyManager = import_nostr_js_sdk.NostrKeyManager.fromPrivateKey(tempKey);
|
|
1079
|
+
}
|
|
1080
|
+
this.nostrClient = new import_nostr_js_sdk.NostrClient(this.keyManager, {
|
|
1081
|
+
autoReconnect: this.config.autoReconnect,
|
|
1082
|
+
reconnectIntervalMs: this.config.reconnectDelay,
|
|
1083
|
+
maxReconnectIntervalMs: this.config.reconnectDelay * 16,
|
|
1084
|
+
// exponential backoff cap
|
|
1085
|
+
pingIntervalMs: 15e3
|
|
1086
|
+
// 15 second keepalive pings (more aggressive to prevent drops)
|
|
1087
|
+
});
|
|
1088
|
+
this.nostrClient.addConnectionListener({
|
|
1089
|
+
onConnect: (url) => {
|
|
1090
|
+
this.log("NostrClient connected to relay:", url);
|
|
1091
|
+
this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
|
|
1092
|
+
},
|
|
1093
|
+
onDisconnect: (url, reason) => {
|
|
1094
|
+
this.log("NostrClient disconnected from relay:", url, "reason:", reason);
|
|
1095
|
+
},
|
|
1096
|
+
onReconnecting: (url, attempt) => {
|
|
1097
|
+
this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
|
|
1098
|
+
this.emitEvent({ type: "transport:reconnecting", timestamp: Date.now() });
|
|
1099
|
+
},
|
|
1100
|
+
onReconnected: (url) => {
|
|
1101
|
+
this.log("NostrClient reconnected to relay:", url);
|
|
1102
|
+
this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
await this.nostrClient.connect(...this.config.relays);
|
|
1106
|
+
if (!this.nostrClient.isConnected()) {
|
|
485
1107
|
throw new Error("Failed to connect to any relay");
|
|
486
1108
|
}
|
|
487
1109
|
this.status = "connected";
|
|
488
1110
|
this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
|
|
489
|
-
this.log("Connected to", this.
|
|
1111
|
+
this.log("Connected to", this.nostrClient.getConnectedRelays().size, "relays");
|
|
490
1112
|
if (this.identity) {
|
|
491
1113
|
this.subscribeToEvents();
|
|
492
1114
|
}
|
|
@@ -496,17 +1118,19 @@ var NostrTransportProvider = class {
|
|
|
496
1118
|
}
|
|
497
1119
|
}
|
|
498
1120
|
async disconnect() {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
this.
|
|
1121
|
+
if (this.nostrClient) {
|
|
1122
|
+
this.nostrClient.disconnect();
|
|
1123
|
+
this.nostrClient = null;
|
|
502
1124
|
}
|
|
503
|
-
this.
|
|
1125
|
+
this.mainSubscriptionId = null;
|
|
1126
|
+
this.walletSubscriptionId = null;
|
|
1127
|
+
this.chatSubscriptionId = null;
|
|
504
1128
|
this.status = "disconnected";
|
|
505
1129
|
this.emitEvent({ type: "transport:disconnected", timestamp: Date.now() });
|
|
506
1130
|
this.log("Disconnected from all relays");
|
|
507
1131
|
}
|
|
508
1132
|
isConnected() {
|
|
509
|
-
return this.status === "connected" && this.
|
|
1133
|
+
return this.status === "connected" && this.nostrClient?.isConnected() === true;
|
|
510
1134
|
}
|
|
511
1135
|
getStatus() {
|
|
512
1136
|
return this.status;
|
|
@@ -524,7 +1148,8 @@ var NostrTransportProvider = class {
|
|
|
524
1148
|
* Get list of currently connected relay URLs
|
|
525
1149
|
*/
|
|
526
1150
|
getConnectedRelays() {
|
|
527
|
-
|
|
1151
|
+
if (!this.nostrClient) return [];
|
|
1152
|
+
return Array.from(this.nostrClient.getConnectedRelays());
|
|
528
1153
|
}
|
|
529
1154
|
/**
|
|
530
1155
|
* Add a new relay dynamically
|
|
@@ -536,9 +1161,9 @@ var NostrTransportProvider = class {
|
|
|
536
1161
|
return false;
|
|
537
1162
|
}
|
|
538
1163
|
this.config.relays.push(relayUrl);
|
|
539
|
-
if (this.status === "connected") {
|
|
1164
|
+
if (this.status === "connected" && this.nostrClient) {
|
|
540
1165
|
try {
|
|
541
|
-
await this.
|
|
1166
|
+
await this.nostrClient.connect(relayUrl);
|
|
542
1167
|
this.log("Added and connected to relay:", relayUrl);
|
|
543
1168
|
this.emitEvent({
|
|
544
1169
|
type: "transport:relay_added",
|
|
@@ -566,6 +1191,8 @@ var NostrTransportProvider = class {
|
|
|
566
1191
|
/**
|
|
567
1192
|
* Remove a relay dynamically
|
|
568
1193
|
* Will disconnect from the relay if connected
|
|
1194
|
+
* NOTE: NostrClient doesn't support removing individual relays at runtime.
|
|
1195
|
+
* We remove from config so it won't be used on next connect().
|
|
569
1196
|
*/
|
|
570
1197
|
async removeRelay(relayUrl) {
|
|
571
1198
|
const index = this.config.relays.indexOf(relayUrl);
|
|
@@ -574,19 +1201,13 @@ var NostrTransportProvider = class {
|
|
|
574
1201
|
return false;
|
|
575
1202
|
}
|
|
576
1203
|
this.config.relays.splice(index, 1);
|
|
577
|
-
|
|
578
|
-
if (ws) {
|
|
579
|
-
ws.close();
|
|
580
|
-
this.connections.delete(relayUrl);
|
|
581
|
-
this.reconnectAttempts.delete(relayUrl);
|
|
582
|
-
this.log("Removed and disconnected from relay:", relayUrl);
|
|
583
|
-
}
|
|
1204
|
+
this.log("Removed relay from config:", relayUrl);
|
|
584
1205
|
this.emitEvent({
|
|
585
1206
|
type: "transport:relay_removed",
|
|
586
1207
|
timestamp: Date.now(),
|
|
587
1208
|
data: { relay: relayUrl }
|
|
588
1209
|
});
|
|
589
|
-
if (this.
|
|
1210
|
+
if (this.nostrClient && !this.nostrClient.isConnected() && this.status === "connected") {
|
|
590
1211
|
this.status = "error";
|
|
591
1212
|
this.emitEvent({
|
|
592
1213
|
type: "transport:error",
|
|
@@ -606,8 +1227,8 @@ var NostrTransportProvider = class {
|
|
|
606
1227
|
* Check if a relay is currently connected
|
|
607
1228
|
*/
|
|
608
1229
|
isRelayConnected(relayUrl) {
|
|
609
|
-
|
|
610
|
-
return
|
|
1230
|
+
if (!this.nostrClient) return false;
|
|
1231
|
+
return this.nostrClient.getConnectedRelays().has(relayUrl);
|
|
611
1232
|
}
|
|
612
1233
|
// ===========================================================================
|
|
613
1234
|
// TransportProvider Implementation
|
|
@@ -618,7 +1239,37 @@ var NostrTransportProvider = class {
|
|
|
618
1239
|
this.keyManager = import_nostr_js_sdk.NostrKeyManager.fromPrivateKey(secretKey);
|
|
619
1240
|
const nostrPubkey = this.keyManager.getPublicKeyHex();
|
|
620
1241
|
this.log("Identity set, Nostr pubkey:", nostrPubkey.slice(0, 16) + "...");
|
|
621
|
-
if (this.
|
|
1242
|
+
if (this.nostrClient && this.status === "connected") {
|
|
1243
|
+
this.log("Identity changed while connected - recreating NostrClient");
|
|
1244
|
+
const oldClient = this.nostrClient;
|
|
1245
|
+
this.nostrClient = new import_nostr_js_sdk.NostrClient(this.keyManager, {
|
|
1246
|
+
autoReconnect: this.config.autoReconnect,
|
|
1247
|
+
reconnectIntervalMs: this.config.reconnectDelay,
|
|
1248
|
+
maxReconnectIntervalMs: this.config.reconnectDelay * 16,
|
|
1249
|
+
pingIntervalMs: 15e3
|
|
1250
|
+
// 15 second keepalive pings
|
|
1251
|
+
});
|
|
1252
|
+
this.nostrClient.addConnectionListener({
|
|
1253
|
+
onConnect: (url) => {
|
|
1254
|
+
this.log("NostrClient connected to relay:", url);
|
|
1255
|
+
},
|
|
1256
|
+
onDisconnect: (url, reason) => {
|
|
1257
|
+
this.log("NostrClient disconnected from relay:", url, "reason:", reason);
|
|
1258
|
+
},
|
|
1259
|
+
onReconnecting: (url, attempt) => {
|
|
1260
|
+
this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
|
|
1261
|
+
},
|
|
1262
|
+
onReconnected: (url) => {
|
|
1263
|
+
this.log("NostrClient reconnected to relay:", url);
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
this.nostrClient.connect(...this.config.relays).then(() => {
|
|
1267
|
+
this.subscribeToEvents();
|
|
1268
|
+
oldClient.disconnect();
|
|
1269
|
+
}).catch((err) => {
|
|
1270
|
+
this.log("Failed to reconnect with new identity:", err);
|
|
1271
|
+
});
|
|
1272
|
+
} else if (this.isConnected()) {
|
|
622
1273
|
this.subscribeToEvents();
|
|
623
1274
|
}
|
|
624
1275
|
}
|
|
@@ -634,18 +1285,17 @@ var NostrTransportProvider = class {
|
|
|
634
1285
|
}
|
|
635
1286
|
async sendMessage(recipientPubkey, content) {
|
|
636
1287
|
this.ensureReady();
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
);
|
|
642
|
-
await this.publishEvent(event);
|
|
1288
|
+
const nostrRecipient = recipientPubkey.length === 66 && (recipientPubkey.startsWith("02") || recipientPubkey.startsWith("03")) ? recipientPubkey.slice(2) : recipientPubkey;
|
|
1289
|
+
const senderNametag = this.identity?.nametag;
|
|
1290
|
+
const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
|
|
1291
|
+
const giftWrap = import_nostr_js_sdk.NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
|
|
1292
|
+
await this.publishEvent(giftWrap);
|
|
643
1293
|
this.emitEvent({
|
|
644
1294
|
type: "message:sent",
|
|
645
1295
|
timestamp: Date.now(),
|
|
646
1296
|
data: { recipient: recipientPubkey }
|
|
647
1297
|
});
|
|
648
|
-
return
|
|
1298
|
+
return giftWrap.id;
|
|
649
1299
|
}
|
|
650
1300
|
onMessage(handler) {
|
|
651
1301
|
this.messageHandlers.add(handler);
|
|
@@ -762,6 +1412,118 @@ var NostrTransportProvider = class {
|
|
|
762
1412
|
if (pubkeyTag?.[1]) return pubkeyTag[1];
|
|
763
1413
|
return null;
|
|
764
1414
|
}
|
|
1415
|
+
async resolveNametagInfo(nametag) {
|
|
1416
|
+
this.ensureReady();
|
|
1417
|
+
const hashedNametag = (0, import_nostr_js_sdk.hashNametag)(nametag);
|
|
1418
|
+
let events = await this.queryEvents({
|
|
1419
|
+
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1420
|
+
"#t": [hashedNametag],
|
|
1421
|
+
limit: 1
|
|
1422
|
+
});
|
|
1423
|
+
if (events.length === 0) {
|
|
1424
|
+
events = await this.queryEvents({
|
|
1425
|
+
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1426
|
+
"#d": [hashedNametag],
|
|
1427
|
+
limit: 1
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
if (events.length === 0) return null;
|
|
1431
|
+
const bindingEvent = events[0];
|
|
1432
|
+
try {
|
|
1433
|
+
const content = JSON.parse(bindingEvent.content);
|
|
1434
|
+
if (content.public_key && content.l1_address) {
|
|
1435
|
+
const l3Address = `PROXY:${hashedNametag}`;
|
|
1436
|
+
return {
|
|
1437
|
+
nametag,
|
|
1438
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1439
|
+
chainPubkey: content.public_key,
|
|
1440
|
+
l1Address: content.l1_address,
|
|
1441
|
+
directAddress: content.direct_address || "",
|
|
1442
|
+
proxyAddress: l3Address,
|
|
1443
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
this.log("Legacy nametag event without extended fields:", nametag);
|
|
1447
|
+
const pubkeyTag = bindingEvent.tags.find((t) => t[0] === "pubkey");
|
|
1448
|
+
const l1Tag = bindingEvent.tags.find((t) => t[0] === "l1");
|
|
1449
|
+
if (pubkeyTag?.[1] && l1Tag?.[1]) {
|
|
1450
|
+
const l3Address = `PROXY:${hashedNametag}`;
|
|
1451
|
+
return {
|
|
1452
|
+
nametag,
|
|
1453
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1454
|
+
chainPubkey: pubkeyTag[1],
|
|
1455
|
+
l1Address: l1Tag[1],
|
|
1456
|
+
directAddress: "",
|
|
1457
|
+
proxyAddress: l3Address,
|
|
1458
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
return {
|
|
1462
|
+
nametag,
|
|
1463
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1464
|
+
chainPubkey: "",
|
|
1465
|
+
// Cannot derive from 32-byte Nostr pubkey
|
|
1466
|
+
l1Address: "",
|
|
1467
|
+
// Cannot derive without 33-byte pubkey
|
|
1468
|
+
directAddress: "",
|
|
1469
|
+
proxyAddress: `PROXY:${hashedNametag}`,
|
|
1470
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1471
|
+
};
|
|
1472
|
+
} catch {
|
|
1473
|
+
return {
|
|
1474
|
+
nametag,
|
|
1475
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1476
|
+
chainPubkey: "",
|
|
1477
|
+
l1Address: "",
|
|
1478
|
+
directAddress: "",
|
|
1479
|
+
proxyAddress: `PROXY:${hashedNametag}`,
|
|
1480
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Recover nametag for the current identity by searching for encrypted nametag events
|
|
1486
|
+
* Used after wallet import to recover associated nametag
|
|
1487
|
+
* @returns Decrypted nametag or null if none found
|
|
1488
|
+
*/
|
|
1489
|
+
async recoverNametag() {
|
|
1490
|
+
this.ensureReady();
|
|
1491
|
+
if (!this.identity || !this.keyManager) {
|
|
1492
|
+
throw new Error("Identity not set");
|
|
1493
|
+
}
|
|
1494
|
+
const nostrPubkey = this.getNostrPubkey();
|
|
1495
|
+
this.log("Searching for nametag events for pubkey:", nostrPubkey.slice(0, 16) + "...");
|
|
1496
|
+
const events = await this.queryEvents({
|
|
1497
|
+
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1498
|
+
authors: [nostrPubkey],
|
|
1499
|
+
limit: 10
|
|
1500
|
+
// Get recent events in case of updates
|
|
1501
|
+
});
|
|
1502
|
+
if (events.length === 0) {
|
|
1503
|
+
this.log("No nametag events found for this pubkey");
|
|
1504
|
+
return null;
|
|
1505
|
+
}
|
|
1506
|
+
events.sort((a, b) => b.created_at - a.created_at);
|
|
1507
|
+
for (const event of events) {
|
|
1508
|
+
try {
|
|
1509
|
+
const content = JSON.parse(event.content);
|
|
1510
|
+
if (content.encrypted_nametag) {
|
|
1511
|
+
const decrypted = await decryptNametag(
|
|
1512
|
+
content.encrypted_nametag,
|
|
1513
|
+
this.identity.privateKey
|
|
1514
|
+
);
|
|
1515
|
+
if (decrypted) {
|
|
1516
|
+
this.log("Recovered nametag:", decrypted);
|
|
1517
|
+
return decrypted;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
} catch {
|
|
1521
|
+
continue;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
this.log("Could not decrypt nametag from any event");
|
|
1525
|
+
return null;
|
|
1526
|
+
}
|
|
765
1527
|
async publishNametag(nametag, address) {
|
|
766
1528
|
this.ensureReady();
|
|
767
1529
|
const hashedNametag = (0, import_nostr_js_sdk.hashNametag)(nametag);
|
|
@@ -772,8 +1534,11 @@ var NostrTransportProvider = class {
|
|
|
772
1534
|
await this.publishEvent(event);
|
|
773
1535
|
this.log("Published nametag binding:", nametag);
|
|
774
1536
|
}
|
|
775
|
-
async registerNametag(nametag, _publicKey) {
|
|
1537
|
+
async registerNametag(nametag, _publicKey, directAddress = "") {
|
|
776
1538
|
this.ensureReady();
|
|
1539
|
+
if (!this.identity) {
|
|
1540
|
+
throw new Error("Identity not set");
|
|
1541
|
+
}
|
|
777
1542
|
const nostrPubkey = this.getNostrPubkey();
|
|
778
1543
|
const existing = await this.resolveNametag(nametag);
|
|
779
1544
|
this.log("registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
|
|
@@ -781,27 +1546,42 @@ var NostrTransportProvider = class {
|
|
|
781
1546
|
this.log("Nametag already taken:", nametag, "- owner:", existing);
|
|
782
1547
|
return false;
|
|
783
1548
|
}
|
|
1549
|
+
const privateKeyHex = this.identity.privateKey;
|
|
1550
|
+
const compressedPubkey = getPublicKey(privateKeyHex, true);
|
|
1551
|
+
const l1Address = publicKeyToAddress(compressedPubkey, "alpha");
|
|
1552
|
+
const encryptedNametag = await encryptNametag(nametag, privateKeyHex);
|
|
784
1553
|
const hashedNametag = (0, import_nostr_js_sdk.hashNametag)(nametag);
|
|
785
1554
|
const content = JSON.stringify({
|
|
786
1555
|
nametag_hash: hashedNametag,
|
|
787
1556
|
address: nostrPubkey,
|
|
788
|
-
verified: Date.now()
|
|
1557
|
+
verified: Date.now(),
|
|
1558
|
+
// Extended fields for nametag recovery and address lookup
|
|
1559
|
+
encrypted_nametag: encryptedNametag,
|
|
1560
|
+
public_key: compressedPubkey,
|
|
1561
|
+
l1_address: l1Address,
|
|
1562
|
+
direct_address: directAddress
|
|
789
1563
|
});
|
|
790
1564
|
const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, [
|
|
791
1565
|
["d", hashedNametag],
|
|
792
1566
|
["nametag", hashedNametag],
|
|
793
1567
|
["t", hashedNametag],
|
|
794
|
-
["address", nostrPubkey]
|
|
1568
|
+
["address", nostrPubkey],
|
|
1569
|
+
// Extended tags for indexing
|
|
1570
|
+
["pubkey", compressedPubkey],
|
|
1571
|
+
["l1", l1Address]
|
|
795
1572
|
]);
|
|
796
1573
|
await this.publishEvent(event);
|
|
797
|
-
this.log("Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
|
|
1574
|
+
this.log("Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
|
|
798
1575
|
return true;
|
|
799
1576
|
}
|
|
1577
|
+
// Track broadcast subscriptions
|
|
1578
|
+
broadcastSubscriptions = /* @__PURE__ */ new Map();
|
|
1579
|
+
// key -> subId
|
|
800
1580
|
subscribeToBroadcast(tags, handler) {
|
|
801
1581
|
const key = tags.sort().join(":");
|
|
802
1582
|
if (!this.broadcastHandlers.has(key)) {
|
|
803
1583
|
this.broadcastHandlers.set(key, /* @__PURE__ */ new Set());
|
|
804
|
-
if (this.isConnected()) {
|
|
1584
|
+
if (this.isConnected() && this.nostrClient) {
|
|
805
1585
|
this.subscribeToTags(tags);
|
|
806
1586
|
}
|
|
807
1587
|
}
|
|
@@ -810,6 +1590,11 @@ var NostrTransportProvider = class {
|
|
|
810
1590
|
this.broadcastHandlers.get(key)?.delete(handler);
|
|
811
1591
|
if (this.broadcastHandlers.get(key)?.size === 0) {
|
|
812
1592
|
this.broadcastHandlers.delete(key);
|
|
1593
|
+
const subId = this.broadcastSubscriptions.get(key);
|
|
1594
|
+
if (subId && this.nostrClient) {
|
|
1595
|
+
this.nostrClient.unsubscribe(subId);
|
|
1596
|
+
this.broadcastSubscriptions.delete(key);
|
|
1597
|
+
}
|
|
813
1598
|
}
|
|
814
1599
|
};
|
|
815
1600
|
}
|
|
@@ -828,81 +1613,19 @@ var NostrTransportProvider = class {
|
|
|
828
1613
|
return () => this.eventCallbacks.delete(callback);
|
|
829
1614
|
}
|
|
830
1615
|
// ===========================================================================
|
|
831
|
-
// Private: Connection Management
|
|
832
|
-
// ===========================================================================
|
|
833
|
-
async connectToRelay(url) {
|
|
834
|
-
return new Promise((resolve, reject) => {
|
|
835
|
-
const ws = this.config.createWebSocket(url);
|
|
836
|
-
const timeout = setTimeout(() => {
|
|
837
|
-
ws.close();
|
|
838
|
-
reject(new Error(`Connection timeout: ${url}`));
|
|
839
|
-
}, this.config.timeout);
|
|
840
|
-
ws.onopen = () => {
|
|
841
|
-
clearTimeout(timeout);
|
|
842
|
-
this.connections.set(url, ws);
|
|
843
|
-
this.reconnectAttempts.set(url, 0);
|
|
844
|
-
this.log("Connected to relay:", url);
|
|
845
|
-
resolve();
|
|
846
|
-
};
|
|
847
|
-
ws.onerror = (error) => {
|
|
848
|
-
clearTimeout(timeout);
|
|
849
|
-
this.log("Relay error:", url, error);
|
|
850
|
-
reject(error);
|
|
851
|
-
};
|
|
852
|
-
ws.onclose = () => {
|
|
853
|
-
this.connections.delete(url);
|
|
854
|
-
if (this.config.autoReconnect && this.status === "connected") {
|
|
855
|
-
this.scheduleReconnect(url);
|
|
856
|
-
}
|
|
857
|
-
};
|
|
858
|
-
ws.onmessage = (event) => {
|
|
859
|
-
this.handleRelayMessage(url, event.data);
|
|
860
|
-
};
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
scheduleReconnect(url) {
|
|
864
|
-
const attempts = this.reconnectAttempts.get(url) ?? 0;
|
|
865
|
-
if (attempts >= this.config.maxReconnectAttempts) {
|
|
866
|
-
this.log("Max reconnect attempts reached for:", url);
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
this.reconnectAttempts.set(url, attempts + 1);
|
|
870
|
-
const delay = this.config.reconnectDelay * Math.pow(2, attempts);
|
|
871
|
-
this.emitEvent({ type: "transport:reconnecting", timestamp: Date.now() });
|
|
872
|
-
setTimeout(() => {
|
|
873
|
-
this.connectToRelay(url).catch(() => {
|
|
874
|
-
});
|
|
875
|
-
}, delay);
|
|
876
|
-
}
|
|
877
|
-
// ===========================================================================
|
|
878
1616
|
// Private: Message Handling
|
|
879
1617
|
// ===========================================================================
|
|
880
|
-
handleRelayMessage(relay, data) {
|
|
881
|
-
try {
|
|
882
|
-
const message = JSON.parse(data);
|
|
883
|
-
const [type, ...args] = message;
|
|
884
|
-
switch (type) {
|
|
885
|
-
case "EVENT":
|
|
886
|
-
this.handleEvent(args[1]);
|
|
887
|
-
break;
|
|
888
|
-
case "EOSE":
|
|
889
|
-
break;
|
|
890
|
-
case "OK":
|
|
891
|
-
break;
|
|
892
|
-
case "NOTICE":
|
|
893
|
-
this.log("Relay notice:", relay, args[0]);
|
|
894
|
-
break;
|
|
895
|
-
}
|
|
896
|
-
} catch (error) {
|
|
897
|
-
this.log("Failed to parse relay message:", error);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
1618
|
async handleEvent(event) {
|
|
1619
|
+
this.log("Processing event kind:", event.kind, "id:", event.id?.slice(0, 12));
|
|
901
1620
|
try {
|
|
902
1621
|
switch (event.kind) {
|
|
903
1622
|
case EVENT_KINDS.DIRECT_MESSAGE:
|
|
904
1623
|
await this.handleDirectMessage(event);
|
|
905
1624
|
break;
|
|
1625
|
+
case import_nostr_js_sdk.EventKinds.GIFT_WRAP:
|
|
1626
|
+
this.log("Handling gift wrap (NIP-17 DM)");
|
|
1627
|
+
await this.handleGiftWrap(event);
|
|
1628
|
+
break;
|
|
906
1629
|
case EVENT_KINDS.TOKEN_TRANSFER:
|
|
907
1630
|
await this.handleTokenTransfer(event);
|
|
908
1631
|
break;
|
|
@@ -921,23 +1644,54 @@ var NostrTransportProvider = class {
|
|
|
921
1644
|
}
|
|
922
1645
|
}
|
|
923
1646
|
async handleDirectMessage(event) {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
1647
|
+
this.log("Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
|
|
1648
|
+
}
|
|
1649
|
+
async handleGiftWrap(event) {
|
|
1650
|
+
if (!this.identity || !this.keyManager) {
|
|
1651
|
+
this.log("handleGiftWrap: no identity/keyManager");
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
try {
|
|
1655
|
+
const pm = import_nostr_js_sdk.NIP17.unwrap(event, this.keyManager);
|
|
1656
|
+
this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
|
|
1657
|
+
if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
|
|
1658
|
+
this.log("Skipping own message");
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
if (pm.kind !== import_nostr_js_sdk.EventKinds.CHAT_MESSAGE) {
|
|
1662
|
+
this.log("Skipping non-chat message, kind:", pm.kind);
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
let content = pm.content;
|
|
1666
|
+
let senderNametag;
|
|
936
1667
|
try {
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1668
|
+
const parsed = JSON.parse(content);
|
|
1669
|
+
if (typeof parsed === "object" && parsed.text !== void 0) {
|
|
1670
|
+
content = parsed.text;
|
|
1671
|
+
senderNametag = parsed.senderNametag || void 0;
|
|
1672
|
+
}
|
|
1673
|
+
} catch {
|
|
1674
|
+
}
|
|
1675
|
+
this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
|
|
1676
|
+
const message = {
|
|
1677
|
+
id: pm.eventId,
|
|
1678
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
1679
|
+
senderNametag,
|
|
1680
|
+
content,
|
|
1681
|
+
timestamp: pm.timestamp * 1e3,
|
|
1682
|
+
encrypted: true
|
|
1683
|
+
};
|
|
1684
|
+
this.emitEvent({ type: "message:received", timestamp: Date.now() });
|
|
1685
|
+
this.log("Dispatching to", this.messageHandlers.size, "handlers");
|
|
1686
|
+
for (const handler of this.messageHandlers) {
|
|
1687
|
+
try {
|
|
1688
|
+
handler(message);
|
|
1689
|
+
} catch (error) {
|
|
1690
|
+
this.log("Message handler error:", error);
|
|
1691
|
+
}
|
|
940
1692
|
}
|
|
1693
|
+
} catch (err) {
|
|
1694
|
+
this.log("Gift wrap decrypt failed (expected if not for us):", err?.message?.slice(0, 50));
|
|
941
1695
|
}
|
|
942
1696
|
}
|
|
943
1697
|
async handleTokenTransfer(event) {
|
|
@@ -946,7 +1700,7 @@ var NostrTransportProvider = class {
|
|
|
946
1700
|
const payload = JSON.parse(content);
|
|
947
1701
|
const transfer = {
|
|
948
1702
|
id: event.id,
|
|
949
|
-
|
|
1703
|
+
senderTransportPubkey: event.pubkey,
|
|
950
1704
|
payload,
|
|
951
1705
|
timestamp: event.created_at * 1e3
|
|
952
1706
|
};
|
|
@@ -966,7 +1720,7 @@ var NostrTransportProvider = class {
|
|
|
966
1720
|
const requestData = JSON.parse(content);
|
|
967
1721
|
const request = {
|
|
968
1722
|
id: event.id,
|
|
969
|
-
|
|
1723
|
+
senderTransportPubkey: event.pubkey,
|
|
970
1724
|
request: {
|
|
971
1725
|
requestId: requestData.requestId,
|
|
972
1726
|
amount: requestData.amount,
|
|
@@ -996,7 +1750,7 @@ var NostrTransportProvider = class {
|
|
|
996
1750
|
const responseData = JSON.parse(content);
|
|
997
1751
|
const response = {
|
|
998
1752
|
id: event.id,
|
|
999
|
-
|
|
1753
|
+
responderTransportPubkey: event.pubkey,
|
|
1000
1754
|
response: {
|
|
1001
1755
|
requestId: responseData.requestId,
|
|
1002
1756
|
responseType: responseData.responseType,
|
|
@@ -1021,7 +1775,7 @@ var NostrTransportProvider = class {
|
|
|
1021
1775
|
const tags = event.tags.filter((t) => t[0] === "t").map((t) => t[1]);
|
|
1022
1776
|
const broadcast = {
|
|
1023
1777
|
id: event.id,
|
|
1024
|
-
|
|
1778
|
+
authorTransportPubkey: event.pubkey,
|
|
1025
1779
|
content: event.content,
|
|
1026
1780
|
tags,
|
|
1027
1781
|
timestamp: event.created_at * 1e3
|
|
@@ -1076,109 +1830,149 @@ var NostrTransportProvider = class {
|
|
|
1076
1830
|
return this.createEvent(kind, encrypted, tags);
|
|
1077
1831
|
}
|
|
1078
1832
|
async publishEvent(event) {
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
ws.send(message);
|
|
1087
|
-
resolve();
|
|
1088
|
-
});
|
|
1089
|
-
});
|
|
1090
|
-
await Promise.any(publishPromises);
|
|
1833
|
+
if (!this.nostrClient) {
|
|
1834
|
+
throw new Error("NostrClient not initialized");
|
|
1835
|
+
}
|
|
1836
|
+
const sdkEvent = import_nostr_js_sdk.Event.fromJSON(event);
|
|
1837
|
+
await this.nostrClient.publishEvent(sdkEvent);
|
|
1091
1838
|
}
|
|
1092
|
-
async queryEvents(
|
|
1093
|
-
if (this.
|
|
1839
|
+
async queryEvents(filterObj) {
|
|
1840
|
+
if (!this.nostrClient || !this.nostrClient.isConnected()) {
|
|
1094
1841
|
throw new Error("No connected relays");
|
|
1095
1842
|
}
|
|
1096
|
-
const queryPromises = Array.from(this.connections.values()).map(
|
|
1097
|
-
(ws) => this.queryEventsFromRelay(ws, filter)
|
|
1098
|
-
);
|
|
1099
|
-
const results = await Promise.allSettled(queryPromises);
|
|
1100
|
-
for (const result of results) {
|
|
1101
|
-
if (result.status === "fulfilled" && result.value.length > 0) {
|
|
1102
|
-
return result.value;
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
return [];
|
|
1106
|
-
}
|
|
1107
|
-
async queryEventsFromRelay(ws, filter) {
|
|
1108
|
-
const subId = this.config.generateUUID().slice(0, 8);
|
|
1109
1843
|
const events = [];
|
|
1844
|
+
const filter = new import_nostr_js_sdk.Filter(filterObj);
|
|
1110
1845
|
return new Promise((resolve) => {
|
|
1111
1846
|
const timeout = setTimeout(() => {
|
|
1112
|
-
|
|
1847
|
+
if (subId) {
|
|
1848
|
+
this.nostrClient?.unsubscribe(subId);
|
|
1849
|
+
}
|
|
1113
1850
|
resolve(events);
|
|
1114
1851
|
}, 5e3);
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1852
|
+
const subId = this.nostrClient.subscribe(filter, {
|
|
1853
|
+
onEvent: (event) => {
|
|
1854
|
+
events.push({
|
|
1855
|
+
id: event.id,
|
|
1856
|
+
kind: event.kind,
|
|
1857
|
+
content: event.content,
|
|
1858
|
+
tags: event.tags,
|
|
1859
|
+
pubkey: event.pubkey,
|
|
1860
|
+
created_at: event.created_at,
|
|
1861
|
+
sig: event.sig
|
|
1862
|
+
});
|
|
1863
|
+
},
|
|
1864
|
+
onEndOfStoredEvents: () => {
|
|
1126
1865
|
clearTimeout(timeout);
|
|
1127
|
-
|
|
1128
|
-
this.unsubscribeFromRelay(ws, subId);
|
|
1866
|
+
this.nostrClient?.unsubscribe(subId);
|
|
1129
1867
|
resolve(events);
|
|
1130
1868
|
}
|
|
1131
|
-
};
|
|
1132
|
-
ws.send(JSON.stringify(["REQ", subId, filter]));
|
|
1869
|
+
});
|
|
1133
1870
|
});
|
|
1134
1871
|
}
|
|
1135
|
-
unsubscribeFromRelay(ws, subId) {
|
|
1136
|
-
if (ws.readyState === WebSocketReadyState.OPEN) {
|
|
1137
|
-
ws.send(JSON.stringify(["CLOSE", subId]));
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
1872
|
// ===========================================================================
|
|
1141
1873
|
// Private: Subscriptions
|
|
1142
1874
|
// ===========================================================================
|
|
1875
|
+
// Track subscription IDs for cleanup
|
|
1876
|
+
walletSubscriptionId = null;
|
|
1877
|
+
chatSubscriptionId = null;
|
|
1143
1878
|
subscribeToEvents() {
|
|
1144
|
-
|
|
1145
|
-
|
|
1879
|
+
this.log("subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
|
|
1880
|
+
if (!this.identity || !this.keyManager || !this.nostrClient) {
|
|
1881
|
+
this.log("subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
if (this.walletSubscriptionId) {
|
|
1885
|
+
this.nostrClient.unsubscribe(this.walletSubscriptionId);
|
|
1886
|
+
this.walletSubscriptionId = null;
|
|
1887
|
+
}
|
|
1888
|
+
if (this.chatSubscriptionId) {
|
|
1889
|
+
this.nostrClient.unsubscribe(this.chatSubscriptionId);
|
|
1890
|
+
this.chatSubscriptionId = null;
|
|
1891
|
+
}
|
|
1892
|
+
if (this.mainSubscriptionId) {
|
|
1893
|
+
this.nostrClient.unsubscribe(this.mainSubscriptionId);
|
|
1894
|
+
this.mainSubscriptionId = null;
|
|
1895
|
+
}
|
|
1146
1896
|
const nostrPubkey = this.keyManager.getPublicKeyHex();
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1897
|
+
this.log("Subscribing with Nostr pubkey:", nostrPubkey);
|
|
1898
|
+
const walletFilter = new import_nostr_js_sdk.Filter();
|
|
1899
|
+
walletFilter.kinds = [
|
|
1900
|
+
EVENT_KINDS.DIRECT_MESSAGE,
|
|
1901
|
+
EVENT_KINDS.TOKEN_TRANSFER,
|
|
1902
|
+
EVENT_KINDS.PAYMENT_REQUEST,
|
|
1903
|
+
EVENT_KINDS.PAYMENT_REQUEST_RESPONSE
|
|
1904
|
+
];
|
|
1905
|
+
walletFilter["#p"] = [nostrPubkey];
|
|
1906
|
+
walletFilter.since = Math.floor(Date.now() / 1e3) - 86400;
|
|
1907
|
+
this.walletSubscriptionId = this.nostrClient.subscribe(walletFilter, {
|
|
1908
|
+
onEvent: (event) => {
|
|
1909
|
+
this.log("Received wallet event kind:", event.kind, "id:", event.id?.slice(0, 12));
|
|
1910
|
+
this.handleEvent({
|
|
1911
|
+
id: event.id,
|
|
1912
|
+
kind: event.kind,
|
|
1913
|
+
content: event.content,
|
|
1914
|
+
tags: event.tags,
|
|
1915
|
+
pubkey: event.pubkey,
|
|
1916
|
+
created_at: event.created_at,
|
|
1917
|
+
sig: event.sig
|
|
1918
|
+
});
|
|
1919
|
+
},
|
|
1920
|
+
onEndOfStoredEvents: () => {
|
|
1921
|
+
this.log("Wallet subscription ready (EOSE)");
|
|
1922
|
+
},
|
|
1923
|
+
onError: (_subId, error) => {
|
|
1924
|
+
this.log("Wallet subscription error:", error);
|
|
1162
1925
|
}
|
|
1163
|
-
}
|
|
1164
|
-
this.
|
|
1165
|
-
|
|
1926
|
+
});
|
|
1927
|
+
this.log("Wallet subscription created, subId:", this.walletSubscriptionId);
|
|
1928
|
+
const chatFilter = new import_nostr_js_sdk.Filter();
|
|
1929
|
+
chatFilter.kinds = [import_nostr_js_sdk.EventKinds.GIFT_WRAP];
|
|
1930
|
+
chatFilter["#p"] = [nostrPubkey];
|
|
1931
|
+
this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
|
|
1932
|
+
onEvent: (event) => {
|
|
1933
|
+
this.log("Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
|
|
1934
|
+
this.handleEvent({
|
|
1935
|
+
id: event.id,
|
|
1936
|
+
kind: event.kind,
|
|
1937
|
+
content: event.content,
|
|
1938
|
+
tags: event.tags,
|
|
1939
|
+
pubkey: event.pubkey,
|
|
1940
|
+
created_at: event.created_at,
|
|
1941
|
+
sig: event.sig
|
|
1942
|
+
});
|
|
1943
|
+
},
|
|
1944
|
+
onEndOfStoredEvents: () => {
|
|
1945
|
+
this.log("Chat subscription ready (EOSE)");
|
|
1946
|
+
},
|
|
1947
|
+
onError: (_subId, error) => {
|
|
1948
|
+
this.log("Chat subscription error:", error);
|
|
1949
|
+
}
|
|
1950
|
+
});
|
|
1951
|
+
this.log("Chat subscription created, subId:", this.chatSubscriptionId);
|
|
1166
1952
|
}
|
|
1167
1953
|
subscribeToTags(tags) {
|
|
1168
|
-
|
|
1169
|
-
const
|
|
1954
|
+
if (!this.nostrClient) return;
|
|
1955
|
+
const key = tags.sort().join(":");
|
|
1956
|
+
const filter = new import_nostr_js_sdk.Filter({
|
|
1170
1957
|
kinds: [EVENT_KINDS.BROADCAST],
|
|
1171
1958
|
"#t": tags,
|
|
1172
1959
|
since: Math.floor(Date.now() / 1e3) - 3600
|
|
1173
1960
|
// Last hour
|
|
1174
|
-
};
|
|
1175
|
-
const
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1961
|
+
});
|
|
1962
|
+
const subId = this.nostrClient.subscribe(filter, {
|
|
1963
|
+
onEvent: (event) => {
|
|
1964
|
+
this.handleBroadcast({
|
|
1965
|
+
id: event.id,
|
|
1966
|
+
kind: event.kind,
|
|
1967
|
+
content: event.content,
|
|
1968
|
+
tags: event.tags,
|
|
1969
|
+
pubkey: event.pubkey,
|
|
1970
|
+
created_at: event.created_at,
|
|
1971
|
+
sig: event.sig
|
|
1972
|
+
});
|
|
1179
1973
|
}
|
|
1180
|
-
}
|
|
1181
|
-
this.
|
|
1974
|
+
});
|
|
1975
|
+
this.broadcastSubscriptions.set(key, subId);
|
|
1182
1976
|
}
|
|
1183
1977
|
// ===========================================================================
|
|
1184
1978
|
// Private: Encryption
|
|
@@ -1639,13 +2433,72 @@ var UnicityAggregatorProvider = class {
|
|
|
1639
2433
|
};
|
|
1640
2434
|
var UnicityOracleProvider = UnicityAggregatorProvider;
|
|
1641
2435
|
|
|
2436
|
+
// assets/trustbase.ts
|
|
2437
|
+
var TRUSTBASE_TESTNET = {
|
|
2438
|
+
version: 1,
|
|
2439
|
+
networkId: 3,
|
|
2440
|
+
epoch: 1,
|
|
2441
|
+
epochStartRound: 1,
|
|
2442
|
+
rootNodes: [
|
|
2443
|
+
{
|
|
2444
|
+
nodeId: "16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU",
|
|
2445
|
+
sigKey: "0x039afb2acb65f5fbc272d8907f763d0a5d189aadc9b97afdcc5897ea4dd112e68b",
|
|
2446
|
+
stake: 1
|
|
2447
|
+
}
|
|
2448
|
+
],
|
|
2449
|
+
quorumThreshold: 1,
|
|
2450
|
+
stateHash: "",
|
|
2451
|
+
changeRecordHash: "",
|
|
2452
|
+
previousEntryHash: "",
|
|
2453
|
+
signatures: {
|
|
2454
|
+
"16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU": "0xf157c9fdd8a378e3ca70d354ccc4475ab2cd8de360127bc46b0aeab4b453a80f07fd9136a5843b60a8babaff23e20acc8879861f7651440a5e2829f7541b31f100"
|
|
2455
|
+
}
|
|
2456
|
+
};
|
|
2457
|
+
var TRUSTBASE_MAINNET = null;
|
|
2458
|
+
var TRUSTBASE_DEV = TRUSTBASE_TESTNET;
|
|
2459
|
+
|
|
2460
|
+
// impl/shared/trustbase-loader.ts
|
|
2461
|
+
function getEmbeddedTrustBase(network) {
|
|
2462
|
+
switch (network) {
|
|
2463
|
+
case "mainnet":
|
|
2464
|
+
return TRUSTBASE_MAINNET;
|
|
2465
|
+
case "testnet":
|
|
2466
|
+
return TRUSTBASE_TESTNET;
|
|
2467
|
+
case "dev":
|
|
2468
|
+
return TRUSTBASE_DEV;
|
|
2469
|
+
default:
|
|
2470
|
+
return TRUSTBASE_TESTNET;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
var BaseTrustBaseLoader = class {
|
|
2474
|
+
network;
|
|
2475
|
+
constructor(network = "testnet") {
|
|
2476
|
+
this.network = network;
|
|
2477
|
+
}
|
|
2478
|
+
async load() {
|
|
2479
|
+
const external = await this.loadFromExternal();
|
|
2480
|
+
if (external) {
|
|
2481
|
+
return external;
|
|
2482
|
+
}
|
|
2483
|
+
return getEmbeddedTrustBase(this.network);
|
|
2484
|
+
}
|
|
2485
|
+
};
|
|
2486
|
+
|
|
1642
2487
|
// impl/nodejs/oracle/index.ts
|
|
1643
|
-
var NodeTrustBaseLoader = class {
|
|
2488
|
+
var NodeTrustBaseLoader = class extends BaseTrustBaseLoader {
|
|
1644
2489
|
filePath;
|
|
1645
|
-
constructor(
|
|
1646
|
-
|
|
2490
|
+
constructor(filePathOrNetwork) {
|
|
2491
|
+
if (!filePathOrNetwork) {
|
|
2492
|
+
super("testnet");
|
|
2493
|
+
} else if (filePathOrNetwork.includes("/") || filePathOrNetwork.includes(".")) {
|
|
2494
|
+
super("testnet");
|
|
2495
|
+
this.filePath = filePathOrNetwork;
|
|
2496
|
+
} else {
|
|
2497
|
+
super(filePathOrNetwork);
|
|
2498
|
+
}
|
|
1647
2499
|
}
|
|
1648
|
-
async
|
|
2500
|
+
async loadFromExternal() {
|
|
2501
|
+
if (!this.filePath) return null;
|
|
1649
2502
|
try {
|
|
1650
2503
|
if (fs3.existsSync(this.filePath)) {
|
|
1651
2504
|
const content = fs3.readFileSync(this.filePath, "utf-8");
|
|
@@ -1656,14 +2509,14 @@ var NodeTrustBaseLoader = class {
|
|
|
1656
2509
|
return null;
|
|
1657
2510
|
}
|
|
1658
2511
|
};
|
|
1659
|
-
function createNodeTrustBaseLoader(
|
|
1660
|
-
return new NodeTrustBaseLoader(
|
|
2512
|
+
function createNodeTrustBaseLoader(filePathOrNetwork) {
|
|
2513
|
+
return new NodeTrustBaseLoader(filePathOrNetwork);
|
|
1661
2514
|
}
|
|
1662
2515
|
function createUnicityAggregatorProvider(config) {
|
|
1663
|
-
const { trustBasePath, ...restConfig } = config;
|
|
2516
|
+
const { trustBasePath, network, ...restConfig } = config;
|
|
1664
2517
|
return new UnicityAggregatorProvider({
|
|
1665
2518
|
...restConfig,
|
|
1666
|
-
trustBaseLoader: createNodeTrustBaseLoader(trustBasePath)
|
|
2519
|
+
trustBaseLoader: createNodeTrustBaseLoader(trustBasePath ?? network ?? "testnet")
|
|
1667
2520
|
});
|
|
1668
2521
|
}
|
|
1669
2522
|
var createUnicityOracleProvider = createUnicityAggregatorProvider;
|
|
@@ -1742,7 +2595,8 @@ function createNodeProviders(config) {
|
|
|
1742
2595
|
timeout: oracleConfig.timeout,
|
|
1743
2596
|
trustBasePath: oracleConfig.trustBasePath,
|
|
1744
2597
|
skipVerification: oracleConfig.skipVerification,
|
|
1745
|
-
debug: oracleConfig.debug
|
|
2598
|
+
debug: oracleConfig.debug,
|
|
2599
|
+
network
|
|
1746
2600
|
}),
|
|
1747
2601
|
l1: l1Config
|
|
1748
2602
|
};
|
|
@@ -1764,4 +2618,9 @@ function createNodeProviders(config) {
|
|
|
1764
2618
|
createUnicityAggregatorProvider,
|
|
1765
2619
|
createUnicityOracleProvider
|
|
1766
2620
|
});
|
|
2621
|
+
/*! Bundled license information:
|
|
2622
|
+
|
|
2623
|
+
@noble/hashes/utils.js:
|
|
2624
|
+
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
2625
|
+
*/
|
|
1767
2626
|
//# sourceMappingURL=index.cjs.map
|