@unicitylabs/nostr-js-sdk 0.3.2 → 0.4.0-dev.1
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 +80 -12
- package/dist/browser/index.js +2218 -1880
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.min.js +6 -6
- package/dist/browser/index.min.js.map +1 -1
- package/dist/browser/index.umd.js +2227 -1879
- package/dist/browser/index.umd.js.map +1 -1
- package/dist/browser/index.umd.min.js +6 -6
- package/dist/browser/index.umd.min.js.map +1 -1
- package/dist/cjs/client/NostrClient.js +106 -19
- package/dist/cjs/client/NostrClient.js.map +1 -1
- package/dist/cjs/nametag/NametagBinding.js +131 -9
- package/dist/cjs/nametag/NametagBinding.js.map +1 -1
- package/dist/cjs/nametag/NametagUtils.js +163 -0
- package/dist/cjs/nametag/NametagUtils.js.map +1 -1
- package/dist/esm/client/NostrClient.js +106 -19
- package/dist/esm/client/NostrClient.js.map +1 -1
- package/dist/esm/nametag/NametagBinding.js +128 -9
- package/dist/esm/nametag/NametagBinding.js.map +1 -1
- package/dist/esm/nametag/NametagUtils.js +125 -1
- package/dist/esm/nametag/NametagUtils.js.map +1 -1
- package/dist/types/client/NostrClient.d.ts +50 -1
- package/dist/types/client/NostrClient.d.ts.map +1 -1
- package/dist/types/nametag/NametagBinding.d.ts +63 -1
- package/dist/types/nametag/NametagBinding.d.ts.map +1 -1
- package/dist/types/nametag/NametagUtils.d.ts +41 -0
- package/dist/types/nametag/NametagUtils.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -272,25 +272,93 @@ PaymentRequestProtocol.parseAmount('1.5', 8); // BigInt(150_000_000) (8 decimals
|
|
|
272
272
|
|
|
273
273
|
### Nametag Bindings
|
|
274
274
|
|
|
275
|
-
|
|
276
|
-
import { NametagBinding, NametagUtils } from '@unicitylabs/nostr-sdk';
|
|
275
|
+
Nametags are human-readable identifiers (`[a-z0-9_-]`, 3–20 chars) or phone numbers (E.164). All input is normalized to lowercase before hashing. Use `isValidNametag(input)` to validate.
|
|
277
276
|
|
|
278
|
-
|
|
279
|
-
const hash = NametagUtils.hashNametag('+14155551234', 'US');
|
|
277
|
+
#### Publishing a Binding
|
|
280
278
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
'
|
|
285
|
-
'
|
|
279
|
+
```typescript
|
|
280
|
+
// Publish nametag binding with identity info
|
|
281
|
+
const success = await client.publishNametagBinding(
|
|
282
|
+
'alice', // nametag
|
|
283
|
+
keyManager.getPublicKeyHex(), // Nostr pubkey (stored in event's address field)
|
|
284
|
+
{ // optional extended identity
|
|
285
|
+
publicKey: '02abc...', // 33-byte compressed secp256k1 chain pubkey
|
|
286
|
+
l1Address: 'alpha1...', // L1 bech32 address
|
|
287
|
+
directAddress: 'DIRECT://...', // L3 direct address
|
|
288
|
+
proxyAddress: 'PROXY://...', // proxy address (derived from nametag)
|
|
289
|
+
},
|
|
286
290
|
);
|
|
291
|
+
// Throws if nametag is already claimed by another pubkey.
|
|
292
|
+
// Returns true on success, false if publish fails.
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### Resolving a Nametag
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// Simple: get the owner pubkey
|
|
299
|
+
const pubkey = await client.queryPubkeyByNametag('alice');
|
|
287
300
|
|
|
288
|
-
|
|
301
|
+
// Extended: get full binding info (addresses, nametag, etc.)
|
|
302
|
+
const info = await client.queryBindingByNametag('alice');
|
|
303
|
+
// info: { transportPubkey, publicKey?, l1Address?, directAddress?, proxyAddress?, nametag?, timestamp }
|
|
289
304
|
|
|
290
|
-
//
|
|
291
|
-
const
|
|
305
|
+
// Reverse lookup: address → binding
|
|
306
|
+
const info = await client.queryBindingByAddress('alpha1abc...');
|
|
292
307
|
```
|
|
293
308
|
|
|
309
|
+
#### Event Format (kind 30078)
|
|
310
|
+
|
|
311
|
+
Nametag bindings use NIP-78 parameterized replaceable events. Only the original author can update their own event (same pubkey + d-tag = replacement).
|
|
312
|
+
|
|
313
|
+
**Nametag binding event** (with identity):
|
|
314
|
+
|
|
315
|
+
```json
|
|
316
|
+
{
|
|
317
|
+
"kind": 30078,
|
|
318
|
+
"pubkey": "<32-byte x-only Nostr pubkey>",
|
|
319
|
+
"tags": [
|
|
320
|
+
["d", "<SHA256('unicity:nametag:' + normalizedNametag)>"],
|
|
321
|
+
["nametag", "<hashed_nametag>"],
|
|
322
|
+
["t", "<hashed_nametag>"],
|
|
323
|
+
["address", "<nostr_pubkey>"],
|
|
324
|
+
["t", "<SHA256('unicity:address:' + chainPubkey)>"],
|
|
325
|
+
["pubkey", "<chainPubkey>"],
|
|
326
|
+
["t", "<SHA256('unicity:address:' + l1Address)>"],
|
|
327
|
+
["l1", "<l1Address>"],
|
|
328
|
+
["t", "<SHA256('unicity:address:' + directAddress)>"],
|
|
329
|
+
["t", "<SHA256('unicity:address:' + proxyAddress)>"]
|
|
330
|
+
],
|
|
331
|
+
"content": "{\"nametag_hash\":\"...\",\"address\":\"...\",\"verified\":...,\"nametag\":\"alice\",\"encrypted_nametag\":\"...\",\"public_key\":\"02...\",\"l1_address\":\"alpha1...\",\"direct_address\":\"DIRECT://...\",\"proxy_address\":\"PROXY://...\"}"
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Key fields in content:
|
|
336
|
+
- `nametag` — plaintext nametag (for display)
|
|
337
|
+
- `encrypted_nametag` — AES-GCM encrypted nametag (for recovery by private key owner)
|
|
338
|
+
- `public_key`, `l1_address`, `direct_address`, `proxy_address` — identity addresses
|
|
339
|
+
- `nametag_hash` — `SHA256('unicity:nametag:' + normalizedNametag)`
|
|
340
|
+
|
|
341
|
+
Tags enable indexed lookups:
|
|
342
|
+
- `d` tag: makes event replaceable per nametag per author
|
|
343
|
+
- `t` tags: hashed nametag + hashed addresses for relay search (privacy-preserving)
|
|
344
|
+
- `pubkey`, `l1` tags: unhashed for backward-compatible lookups
|
|
345
|
+
|
|
346
|
+
#### Anti-Hijacking Resolution Strategy
|
|
347
|
+
|
|
348
|
+
All query methods use **first-seen-wins across authors, latest-wins for same author**:
|
|
349
|
+
|
|
350
|
+
1. **First-seen-wins across authors** — if multiple pubkeys claim the same nametag, the author who published the earliest `created_at` event wins. Ties are broken deterministically by lexicographic pubkey comparison. This prevents hijacking.
|
|
351
|
+
|
|
352
|
+
2. **Latest-wins for same author** — if the rightful owner publishes multiple events (e.g., initial binding without nametag, then updated binding with nametag), the most recent event is returned. This ensures queries return the most complete data.
|
|
353
|
+
|
|
354
|
+
3. **Signature verification** — events with invalid signatures are silently skipped, preventing malicious relays from injecting forged events.
|
|
355
|
+
|
|
356
|
+
This two-level strategy is critical for the wallet workflow where a binding may be published first without a nametag, then updated later when the user registers one. Both events share address `#t` tags, so address-based lookups see both — the strategy ensures the latest (most complete) event from the original author is returned.
|
|
357
|
+
|
|
358
|
+
#### Privacy
|
|
359
|
+
|
|
360
|
+
Nametags are never stored as plaintext in tags. All `t` and `d` tags use `SHA256('unicity:nametag:' + name)` or `SHA256('unicity:address:' + address)` hashes. The plaintext nametag is only in the event content (JSON), and an encrypted copy (`encrypted_nametag`) allows the private key owner to recover it.
|
|
361
|
+
|
|
294
362
|
## Token Transfer Format
|
|
295
363
|
|
|
296
364
|
Token transfers use Nostr event kind 31113 with NIP-04 encryption.
|