@unicitylabs/nostr-js-sdk 0.5.0 → 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
package/dist/browser/index.js
CHANGED
|
@@ -9244,6 +9244,16 @@ var NametagUtils = /*#__PURE__*/Object.freeze({
|
|
|
9244
9244
|
*/
|
|
9245
9245
|
/** Default country code for phone number normalization (shared with NametagUtils) */
|
|
9246
9246
|
const DEFAULT_COUNTRY = 'US';
|
|
9247
|
+
/**
|
|
9248
|
+
* UNIP-01 namespace label for nametag ownership bindings.
|
|
9249
|
+
*
|
|
9250
|
+
* A binding event carrying a NIP-32 ["L", UNICITY_NAMETAG_NAMESPACE] label opts
|
|
9251
|
+
* into relay-enforced single-owner semantics: the first author a UNIP-01 relay
|
|
9252
|
+
* accepts for a given identifier (d-tag) owns it, by relay receive order. The
|
|
9253
|
+
* marker is what makes ownership independent of the self-asserted `created_at`.
|
|
9254
|
+
* See the UNIP-01 spec (unicity-tokens-relay/docs/UNIP-01.md).
|
|
9255
|
+
*/
|
|
9256
|
+
const UNICITY_NAMETAG_NAMESPACE = 'unicity:nametag';
|
|
9247
9257
|
/**
|
|
9248
9258
|
* Create a nametag binding event.
|
|
9249
9259
|
*
|
|
@@ -9275,6 +9285,8 @@ async function createBindingEvent(keyManager, nametagId, unicityAddress, default
|
|
|
9275
9285
|
};
|
|
9276
9286
|
const tags = [
|
|
9277
9287
|
['d', hashedNametag],
|
|
9288
|
+
// UNIP-01: opt this binding into relay-enforced single-owner semantics.
|
|
9289
|
+
['L', UNICITY_NAMETAG_NAMESPACE],
|
|
9278
9290
|
['nametag', hashedNametag],
|
|
9279
9291
|
['t', hashedNametag],
|
|
9280
9292
|
['address', unicityAddress],
|
|
@@ -9478,6 +9490,18 @@ function parseAddressFromEvent(event) {
|
|
|
9478
9490
|
return undefined;
|
|
9479
9491
|
}
|
|
9480
9492
|
}
|
|
9493
|
+
/**
|
|
9494
|
+
* UNIP-01: true if this binding event carries the single-owner namespace marker
|
|
9495
|
+
* (a NIP-32 ["L", UNICITY_NAMETAG_NAMESPACE] label). Such bindings are vetted by
|
|
9496
|
+
* UNIP-01 relays for single ownership and are preferred at resolution over
|
|
9497
|
+
* unmarked (legacy) bindings, independent of the self-asserted `created_at`.
|
|
9498
|
+
*
|
|
9499
|
+
* @param event Binding event
|
|
9500
|
+
* @returns true if the UNIP-01 nametag marker is present
|
|
9501
|
+
*/
|
|
9502
|
+
function hasNametagOwnershipMarker(event) {
|
|
9503
|
+
return event.getTagValues('L').includes(UNICITY_NAMETAG_NAMESPACE);
|
|
9504
|
+
}
|
|
9481
9505
|
/**
|
|
9482
9506
|
* Verify that a binding event is valid.
|
|
9483
9507
|
* Checks signature and structure.
|
|
@@ -9510,11 +9534,13 @@ function isValidBindingEvent(event) {
|
|
|
9510
9534
|
|
|
9511
9535
|
var NametagBinding = /*#__PURE__*/Object.freeze({
|
|
9512
9536
|
__proto__: null,
|
|
9537
|
+
UNICITY_NAMETAG_NAMESPACE: UNICITY_NAMETAG_NAMESPACE,
|
|
9513
9538
|
createAddressToBindingFilter: createAddressToBindingFilter,
|
|
9514
9539
|
createBindingEvent: createBindingEvent,
|
|
9515
9540
|
createIdentityBindingEvent: createIdentityBindingEvent,
|
|
9516
9541
|
createNametagToPubkeyFilter: createNametagToPubkeyFilter,
|
|
9517
9542
|
createPubkeyToNametagFilter: createPubkeyToNametagFilter,
|
|
9543
|
+
hasNametagOwnershipMarker: hasNametagOwnershipMarker,
|
|
9518
9544
|
isValidBindingEvent: isValidBindingEvent,
|
|
9519
9545
|
parseAddressFromEvent: parseAddressFromEvent,
|
|
9520
9546
|
parseBindingInfo: parseBindingInfo,
|
|
@@ -10448,7 +10474,18 @@ class NostrClient {
|
|
|
10448
10474
|
await this.publishEvent(event);
|
|
10449
10475
|
return true;
|
|
10450
10476
|
}
|
|
10451
|
-
catch {
|
|
10477
|
+
catch (err) {
|
|
10478
|
+
// UNIP-01: a relay-enforced single-owner rejection (NIP-20 `blocked:`)
|
|
10479
|
+
// means the nametag is owned by another key — surface it as a hard
|
|
10480
|
+
// failure rather than a silent `false`, which a caller could mistake for
|
|
10481
|
+
// a transient publish error. Other (transient) errors keep returning
|
|
10482
|
+
// false, preserving the prior best-effort behavior.
|
|
10483
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10484
|
+
// Match only the ownership-conflict message, not the generic NIP-20
|
|
10485
|
+
// `blocked:` prefix (which also covers spam/rate-limit/policy rejections).
|
|
10486
|
+
if (/owned by another key|already claimed/i.test(msg)) {
|
|
10487
|
+
throw new Error(`Nametag "${nametagId}" is already claimed by another key`);
|
|
10488
|
+
}
|
|
10452
10489
|
return false;
|
|
10453
10490
|
}
|
|
10454
10491
|
}
|
|
@@ -10532,20 +10569,26 @@ class NostrClient {
|
|
|
10532
10569
|
}
|
|
10533
10570
|
}
|
|
10534
10571
|
/**
|
|
10535
|
-
* Query binding events
|
|
10572
|
+
* Query binding events and select the owner.
|
|
10536
10573
|
*
|
|
10537
|
-
*
|
|
10538
|
-
* -
|
|
10539
|
-
*
|
|
10540
|
-
*
|
|
10574
|
+
* UNIP-01 (preferred): if any returned binding carries the single-owner
|
|
10575
|
+
* namespace marker (NIP-32 ["L", "unicity:nametag"]), ownership is taken from
|
|
10576
|
+
* the marked binding. These are vetted by UNIP-01 relays for single ownership
|
|
10577
|
+
* (first author by relay receive order owns the identifier), so the
|
|
10578
|
+
* self-asserted `created_at` is ignored entirely. With a UNIP-01 relay set
|
|
10579
|
+
* there is exactly one marked owner; observing more than one distinct marked
|
|
10580
|
+
* author (e.g. across relays in differing states) is treated as ambiguous and
|
|
10581
|
+
* resolves to null rather than guessing.
|
|
10541
10582
|
*
|
|
10542
|
-
*
|
|
10583
|
+
* Legacy fallback (no marked binding present — e.g. an identifier not yet
|
|
10584
|
+
* migrated): first-seen-wins across authors by `created_at`, latest-wins for
|
|
10585
|
+
* the same author, lexicographic pubkey tie-break. Retained for backward
|
|
10586
|
+
* compatibility during migration; superseded as soon as the owner republishes
|
|
10587
|
+
* a marked binding. (Self-asserted timestamps are not authoritative — this
|
|
10588
|
+
* path exists only so un-migrated identifiers keep resolving.)
|
|
10543
10589
|
*
|
|
10544
|
-
*
|
|
10545
|
-
*
|
|
10546
|
-
* Chain-anchored proof of registration time is the only reliable defense.
|
|
10547
|
-
* - TOCTOU: between conflict check and publish, another user can claim the same nametag.
|
|
10548
|
-
* This is inherent to Nostr's eventually-consistent relay model.
|
|
10590
|
+
* Events with invalid signatures are silently skipped to prevent relay
|
|
10591
|
+
* injection of forged events.
|
|
10549
10592
|
*
|
|
10550
10593
|
* @param filter Subscription filter
|
|
10551
10594
|
* @param extractResult Callback to extract the desired result from the winning event
|
|
@@ -10581,6 +10624,19 @@ class NostrClient {
|
|
|
10581
10624
|
const authors = new Map();
|
|
10582
10625
|
const allRelaysDone = (id) => this.allRelaysDoneFor(id);
|
|
10583
10626
|
const pickWinner = () => {
|
|
10627
|
+
// UNIP-01: prefer marker-carrying (relay-vetted single-owner) bindings,
|
|
10628
|
+
// ignoring the self-asserted created_at. The marker is read from each
|
|
10629
|
+
// author's CURRENT (latest, per NIP-33 replaceable) event, so a newer
|
|
10630
|
+
// unmarked update correctly drops the author from the marked set, and a
|
|
10631
|
+
// marked owner resolves to their freshest binding.
|
|
10632
|
+
const marked = [...authors.values()].filter((e) => hasNametagOwnershipMarker(e.latestEvent));
|
|
10633
|
+
if (marked.length > 0) {
|
|
10634
|
+
// Exactly one marked owner is the relay-enforced norm. More than one
|
|
10635
|
+
// distinct marked author means cross-relay disagreement — do not guess.
|
|
10636
|
+
const owner = marked.length === 1 ? marked[0] : undefined;
|
|
10637
|
+
return owner ? extractResult(owner.latestEvent) : null;
|
|
10638
|
+
}
|
|
10639
|
+
// Legacy fallback: first-seen-wins by self-asserted created_at.
|
|
10584
10640
|
let winnerEntry = null;
|
|
10585
10641
|
let winnerPubkey = '';
|
|
10586
10642
|
for (const [pubkey, entry] of authors) {
|
|
@@ -11387,5 +11443,5 @@ function isReadReceipt(message) {
|
|
|
11387
11443
|
return message.kind === 15;
|
|
11388
11444
|
}
|
|
11389
11445
|
|
|
11390
|
-
export { AGENT_LOCATION, AGENT_PROFILE, APP_DATA, AUTH, bech32 as Bech32, CHAT_MESSAGE, CLOSED, CLOSING, CONNECTING, CONTACTS, CallbackEventListener, DELETION, ENCRYPTED_DM, Event, EventKinds, FILE_METADATA, Filter, FilterBuilder, GIFT_WRAP, NAMETAG_MAX_LENGTH, NAMETAG_MIN_LENGTH, nip04 as NIP04, nip17 as NIP17, nip44 as NIP44, NametagBinding, NametagUtils, NostrClient, NostrKeyManager, OPEN, PAYMENT_REQUEST, PAYMENT_REQUEST_RESPONSE, PROFILE, PaymentRequestProtocol, REACTION, READ_RECEIPT, RECOMMEND_RELAY, RELAY_LIST, SEAL, schnorr as SchnorrSigner, TEXT_NOTE, TOKEN_TRANSFER, TokenTransferProtocol, areSameNametag, createAddressToBindingFilter, createBindingEvent, createGiftWrap, createIdentityBindingEvent, createNametagToPubkeyFilter, createPubkeyToNametagFilter, createReadReceipt, createWebSocket, decode, decodeNpub, decodeNsec, decryptNametag, encode, encodeNpub, encodeNsec, encryptNametag, extractMessageData, formatForDisplay, getName, getPublicKey, getPublicKeyHex, hashAddressForTag, hashNametag, isChatMessage, isEphemeral, isParameterizedReplaceable, isPhoneNumber, isReadReceipt, isReplaceable, isValidBindingEvent, isValidNametag, normalizeNametag, parseAddressFromEvent, parseBindingInfo, parseNametagHashFromEvent, sha256Hex, sign, signHex, unwrap, verify, verifyHex };
|
|
11446
|
+
export { AGENT_LOCATION, AGENT_PROFILE, APP_DATA, AUTH, bech32 as Bech32, CHAT_MESSAGE, CLOSED, CLOSING, CONNECTING, CONTACTS, CallbackEventListener, DELETION, ENCRYPTED_DM, Event, EventKinds, FILE_METADATA, Filter, FilterBuilder, GIFT_WRAP, NAMETAG_MAX_LENGTH, NAMETAG_MIN_LENGTH, nip04 as NIP04, nip17 as NIP17, nip44 as NIP44, NametagBinding, NametagUtils, NostrClient, NostrKeyManager, OPEN, PAYMENT_REQUEST, PAYMENT_REQUEST_RESPONSE, PROFILE, PaymentRequestProtocol, REACTION, READ_RECEIPT, RECOMMEND_RELAY, RELAY_LIST, SEAL, schnorr as SchnorrSigner, TEXT_NOTE, TOKEN_TRANSFER, TokenTransferProtocol, UNICITY_NAMETAG_NAMESPACE, areSameNametag, createAddressToBindingFilter, createBindingEvent, createGiftWrap, createIdentityBindingEvent, createNametagToPubkeyFilter, createPubkeyToNametagFilter, createReadReceipt, createWebSocket, decode, decodeNpub, decodeNsec, decryptNametag, encode, encodeNpub, encodeNsec, encryptNametag, extractMessageData, formatForDisplay, getName, getPublicKey, getPublicKeyHex, hasNametagOwnershipMarker, hashAddressForTag, hashNametag, isChatMessage, isEphemeral, isParameterizedReplaceable, isPhoneNumber, isReadReceipt, isReplaceable, isValidBindingEvent, isValidNametag, normalizeNametag, parseAddressFromEvent, parseBindingInfo, parseNametagHashFromEvent, sha256Hex, sign, signHex, unwrap, verify, verifyHex };
|
|
11391
11447
|
//# sourceMappingURL=index.js.map
|