@unicitylabs/nostr-js-sdk 0.5.0-dev.3 → 0.6.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/dist/browser/index.js +69 -13
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.min.js +5 -5
- package/dist/browser/index.min.js.map +1 -1
- package/dist/browser/index.umd.js +70 -12
- package/dist/browser/index.umd.js.map +1 -1
- package/dist/browser/index.umd.min.js +1 -1
- package/dist/browser/index.umd.min.js.map +1 -1
- package/dist/cjs/client/NostrClient.js +42 -12
- package/dist/cjs/client/NostrClient.js.map +1 -1
- package/dist/cjs/nametag/NametagBinding.js +26 -0
- package/dist/cjs/nametag/NametagBinding.js.map +1 -1
- package/dist/esm/client/NostrClient.js +43 -13
- package/dist/esm/client/NostrClient.js.map +1 -1
- package/dist/esm/nametag/NametagBinding.js +24 -0
- package/dist/esm/nametag/NametagBinding.js.map +1 -1
- package/dist/types/client/NostrClient.d.ts +17 -11
- package/dist/types/client/NostrClient.d.ts.map +1 -1
- package/dist/types/nametag/NametagBinding.d.ts +20 -0
- package/dist/types/nametag/NametagBinding.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -9250,6 +9250,16 @@
|
|
|
9250
9250
|
*/
|
|
9251
9251
|
/** Default country code for phone number normalization (shared with NametagUtils) */
|
|
9252
9252
|
const DEFAULT_COUNTRY = 'US';
|
|
9253
|
+
/**
|
|
9254
|
+
* UNIP-01 namespace label for nametag ownership bindings.
|
|
9255
|
+
*
|
|
9256
|
+
* A binding event carrying a NIP-32 ["L", UNICITY_NAMETAG_NAMESPACE] label opts
|
|
9257
|
+
* into relay-enforced single-owner semantics: the first author a UNIP-01 relay
|
|
9258
|
+
* accepts for a given identifier (d-tag) owns it, by relay receive order. The
|
|
9259
|
+
* marker is what makes ownership independent of the self-asserted `created_at`.
|
|
9260
|
+
* See the UNIP-01 spec (unicity-tokens-relay/docs/UNIP-01.md).
|
|
9261
|
+
*/
|
|
9262
|
+
const UNICITY_NAMETAG_NAMESPACE = 'unicity:nametag';
|
|
9253
9263
|
/**
|
|
9254
9264
|
* Create a nametag binding event.
|
|
9255
9265
|
*
|
|
@@ -9281,6 +9291,8 @@
|
|
|
9281
9291
|
};
|
|
9282
9292
|
const tags = [
|
|
9283
9293
|
['d', hashedNametag],
|
|
9294
|
+
// UNIP-01: opt this binding into relay-enforced single-owner semantics.
|
|
9295
|
+
['L', UNICITY_NAMETAG_NAMESPACE],
|
|
9284
9296
|
['nametag', hashedNametag],
|
|
9285
9297
|
['t', hashedNametag],
|
|
9286
9298
|
['address', unicityAddress],
|
|
@@ -9484,6 +9496,18 @@
|
|
|
9484
9496
|
return undefined;
|
|
9485
9497
|
}
|
|
9486
9498
|
}
|
|
9499
|
+
/**
|
|
9500
|
+
* UNIP-01: true if this binding event carries the single-owner namespace marker
|
|
9501
|
+
* (a NIP-32 ["L", UNICITY_NAMETAG_NAMESPACE] label). Such bindings are vetted by
|
|
9502
|
+
* UNIP-01 relays for single ownership and are preferred at resolution over
|
|
9503
|
+
* unmarked (legacy) bindings, independent of the self-asserted `created_at`.
|
|
9504
|
+
*
|
|
9505
|
+
* @param event Binding event
|
|
9506
|
+
* @returns true if the UNIP-01 nametag marker is present
|
|
9507
|
+
*/
|
|
9508
|
+
function hasNametagOwnershipMarker(event) {
|
|
9509
|
+
return event.getTagValues('L').includes(UNICITY_NAMETAG_NAMESPACE);
|
|
9510
|
+
}
|
|
9487
9511
|
/**
|
|
9488
9512
|
* Verify that a binding event is valid.
|
|
9489
9513
|
* Checks signature and structure.
|
|
@@ -9516,11 +9540,13 @@
|
|
|
9516
9540
|
|
|
9517
9541
|
var NametagBinding = /*#__PURE__*/Object.freeze({
|
|
9518
9542
|
__proto__: null,
|
|
9543
|
+
UNICITY_NAMETAG_NAMESPACE: UNICITY_NAMETAG_NAMESPACE,
|
|
9519
9544
|
createAddressToBindingFilter: createAddressToBindingFilter,
|
|
9520
9545
|
createBindingEvent: createBindingEvent,
|
|
9521
9546
|
createIdentityBindingEvent: createIdentityBindingEvent,
|
|
9522
9547
|
createNametagToPubkeyFilter: createNametagToPubkeyFilter,
|
|
9523
9548
|
createPubkeyToNametagFilter: createPubkeyToNametagFilter,
|
|
9549
|
+
hasNametagOwnershipMarker: hasNametagOwnershipMarker,
|
|
9524
9550
|
isValidBindingEvent: isValidBindingEvent,
|
|
9525
9551
|
parseAddressFromEvent: parseAddressFromEvent,
|
|
9526
9552
|
parseBindingInfo: parseBindingInfo,
|
|
@@ -10454,7 +10480,18 @@
|
|
|
10454
10480
|
await this.publishEvent(event);
|
|
10455
10481
|
return true;
|
|
10456
10482
|
}
|
|
10457
|
-
catch {
|
|
10483
|
+
catch (err) {
|
|
10484
|
+
// UNIP-01: a relay-enforced single-owner rejection (NIP-20 `blocked:`)
|
|
10485
|
+
// means the nametag is owned by another key — surface it as a hard
|
|
10486
|
+
// failure rather than a silent `false`, which a caller could mistake for
|
|
10487
|
+
// a transient publish error. Other (transient) errors keep returning
|
|
10488
|
+
// false, preserving the prior best-effort behavior.
|
|
10489
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10490
|
+
// Match only the ownership-conflict message, not the generic NIP-20
|
|
10491
|
+
// `blocked:` prefix (which also covers spam/rate-limit/policy rejections).
|
|
10492
|
+
if (/owned by another key|already claimed/i.test(msg)) {
|
|
10493
|
+
throw new Error(`Nametag "${nametagId}" is already claimed by another key`);
|
|
10494
|
+
}
|
|
10458
10495
|
return false;
|
|
10459
10496
|
}
|
|
10460
10497
|
}
|
|
@@ -10538,20 +10575,26 @@
|
|
|
10538
10575
|
}
|
|
10539
10576
|
}
|
|
10540
10577
|
/**
|
|
10541
|
-
* Query binding events
|
|
10578
|
+
* Query binding events and select the owner.
|
|
10542
10579
|
*
|
|
10543
|
-
*
|
|
10544
|
-
* -
|
|
10545
|
-
*
|
|
10546
|
-
*
|
|
10580
|
+
* UNIP-01 (preferred): if any returned binding carries the single-owner
|
|
10581
|
+
* namespace marker (NIP-32 ["L", "unicity:nametag"]), ownership is taken from
|
|
10582
|
+
* the marked binding. These are vetted by UNIP-01 relays for single ownership
|
|
10583
|
+
* (first author by relay receive order owns the identifier), so the
|
|
10584
|
+
* self-asserted `created_at` is ignored entirely. With a UNIP-01 relay set
|
|
10585
|
+
* there is exactly one marked owner; observing more than one distinct marked
|
|
10586
|
+
* author (e.g. across relays in differing states) is treated as ambiguous and
|
|
10587
|
+
* resolves to null rather than guessing.
|
|
10547
10588
|
*
|
|
10548
|
-
*
|
|
10589
|
+
* Legacy fallback (no marked binding present — e.g. an identifier not yet
|
|
10590
|
+
* migrated): first-seen-wins across authors by `created_at`, latest-wins for
|
|
10591
|
+
* the same author, lexicographic pubkey tie-break. Retained for backward
|
|
10592
|
+
* compatibility during migration; superseded as soon as the owner republishes
|
|
10593
|
+
* a marked binding. (Self-asserted timestamps are not authoritative — this
|
|
10594
|
+
* path exists only so un-migrated identifiers keep resolving.)
|
|
10549
10595
|
*
|
|
10550
|
-
*
|
|
10551
|
-
*
|
|
10552
|
-
* Chain-anchored proof of registration time is the only reliable defense.
|
|
10553
|
-
* - TOCTOU: between conflict check and publish, another user can claim the same nametag.
|
|
10554
|
-
* This is inherent to Nostr's eventually-consistent relay model.
|
|
10596
|
+
* Events with invalid signatures are silently skipped to prevent relay
|
|
10597
|
+
* injection of forged events.
|
|
10555
10598
|
*
|
|
10556
10599
|
* @param filter Subscription filter
|
|
10557
10600
|
* @param extractResult Callback to extract the desired result from the winning event
|
|
@@ -10587,6 +10630,19 @@
|
|
|
10587
10630
|
const authors = new Map();
|
|
10588
10631
|
const allRelaysDone = (id) => this.allRelaysDoneFor(id);
|
|
10589
10632
|
const pickWinner = () => {
|
|
10633
|
+
// UNIP-01: prefer marker-carrying (relay-vetted single-owner) bindings,
|
|
10634
|
+
// ignoring the self-asserted created_at. The marker is read from each
|
|
10635
|
+
// author's CURRENT (latest, per NIP-33 replaceable) event, so a newer
|
|
10636
|
+
// unmarked update correctly drops the author from the marked set, and a
|
|
10637
|
+
// marked owner resolves to their freshest binding.
|
|
10638
|
+
const marked = [...authors.values()].filter((e) => hasNametagOwnershipMarker(e.latestEvent));
|
|
10639
|
+
if (marked.length > 0) {
|
|
10640
|
+
// Exactly one marked owner is the relay-enforced norm. More than one
|
|
10641
|
+
// distinct marked author means cross-relay disagreement — do not guess.
|
|
10642
|
+
const owner = marked.length === 1 ? marked[0] : undefined;
|
|
10643
|
+
return owner ? extractResult(owner.latestEvent) : null;
|
|
10644
|
+
}
|
|
10645
|
+
// Legacy fallback: first-seen-wins by self-asserted created_at.
|
|
10590
10646
|
let winnerEntry = null;
|
|
10591
10647
|
let winnerPubkey = '';
|
|
10592
10648
|
for (const [pubkey, entry] of authors) {
|
|
@@ -11435,6 +11491,7 @@
|
|
|
11435
11491
|
exports.TEXT_NOTE = TEXT_NOTE;
|
|
11436
11492
|
exports.TOKEN_TRANSFER = TOKEN_TRANSFER;
|
|
11437
11493
|
exports.TokenTransferProtocol = TokenTransferProtocol;
|
|
11494
|
+
exports.UNICITY_NAMETAG_NAMESPACE = UNICITY_NAMETAG_NAMESPACE;
|
|
11438
11495
|
exports.areSameNametag = areSameNametag;
|
|
11439
11496
|
exports.createAddressToBindingFilter = createAddressToBindingFilter;
|
|
11440
11497
|
exports.createBindingEvent = createBindingEvent;
|
|
@@ -11457,6 +11514,7 @@
|
|
|
11457
11514
|
exports.getName = getName;
|
|
11458
11515
|
exports.getPublicKey = getPublicKey;
|
|
11459
11516
|
exports.getPublicKeyHex = getPublicKeyHex;
|
|
11517
|
+
exports.hasNametagOwnershipMarker = hasNametagOwnershipMarker;
|
|
11460
11518
|
exports.hashAddressForTag = hashAddressForTag;
|
|
11461
11519
|
exports.hashNametag = hashNametag;
|
|
11462
11520
|
exports.isChatMessage = isChatMessage;
|