@unicitylabs/nostr-js-sdk 0.3.3 → 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 +79 -13
- package/dist/browser/index.js +2219 -1905
- 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 +2225 -1904
- 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 +140 -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 +104 -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 +28 -0
- package/dist/types/nametag/NametagUtils.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -272,27 +272,93 @@ PaymentRequestProtocol.parseAmount('1.5', 8); // BigInt(150_000_000) (8 decimals
|
|
|
272
272
|
|
|
273
273
|
### Nametag Bindings
|
|
274
274
|
|
|
275
|
-
Nametags are
|
|
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.
|
|
276
|
+
|
|
277
|
+
#### Publishing a Binding
|
|
276
278
|
|
|
277
279
|
```typescript
|
|
278
|
-
|
|
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
|
+
},
|
|
290
|
+
);
|
|
291
|
+
// Throws if nametag is already claimed by another pubkey.
|
|
292
|
+
// Returns true on success, false if publish fails.
|
|
293
|
+
```
|
|
279
294
|
|
|
280
|
-
|
|
281
|
-
const hash = NametagUtils.hashNametag('+14155551234', 'US');
|
|
295
|
+
#### Resolving a Nametag
|
|
282
296
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
'+14155551234',
|
|
287
|
-
'unicity_address_...'
|
|
288
|
-
);
|
|
297
|
+
```typescript
|
|
298
|
+
// Simple: get the owner pubkey
|
|
299
|
+
const pubkey = await client.queryPubkeyByNametag('alice');
|
|
289
300
|
|
|
290
|
-
|
|
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 }
|
|
291
304
|
|
|
292
|
-
//
|
|
293
|
-
const
|
|
305
|
+
// Reverse lookup: address → binding
|
|
306
|
+
const info = await client.queryBindingByAddress('alpha1abc...');
|
|
307
|
+
```
|
|
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
|
+
}
|
|
294
333
|
```
|
|
295
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
|
+
|
|
296
362
|
## Token Transfer Format
|
|
297
363
|
|
|
298
364
|
Token transfers use Nostr event kind 31113 with NIP-04 encryption.
|