@bsv/sdk 1.4.0 → 1.4.2

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.
Files changed (80) hide show
  1. package/dist/cjs/mod.js +2 -0
  2. package/dist/cjs/mod.js.map +1 -1
  3. package/dist/cjs/package.json +1 -1
  4. package/dist/cjs/src/identity/IdentityClient.js +258 -0
  5. package/dist/cjs/src/identity/IdentityClient.js.map +1 -0
  6. package/dist/cjs/src/identity/index.js +19 -0
  7. package/dist/cjs/src/identity/index.js.map +1 -0
  8. package/dist/cjs/src/identity/types/index.js +30 -0
  9. package/dist/cjs/src/identity/types/index.js.map +1 -0
  10. package/dist/cjs/src/registry/RegistryClient.js +392 -0
  11. package/dist/cjs/src/registry/RegistryClient.js.map +1 -0
  12. package/dist/cjs/src/registry/index.js +19 -0
  13. package/dist/cjs/src/registry/index.js.map +1 -0
  14. package/dist/cjs/src/registry/types/index.js +3 -0
  15. package/dist/cjs/src/registry/types/index.js.map +1 -0
  16. package/dist/cjs/src/storage/StorageDownloader.js +82 -0
  17. package/dist/cjs/src/storage/StorageDownloader.js.map +1 -0
  18. package/dist/cjs/src/storage/__test/StorageDownloader.test.js +144 -0
  19. package/dist/cjs/src/storage/__test/StorageDownloader.test.js.map +1 -0
  20. package/dist/cjs/src/storage/index.js +3 -1
  21. package/dist/cjs/src/storage/index.js.map +1 -1
  22. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  23. package/dist/esm/mod.js +2 -0
  24. package/dist/esm/mod.js.map +1 -1
  25. package/dist/esm/src/identity/IdentityClient.js +255 -0
  26. package/dist/esm/src/identity/IdentityClient.js.map +1 -0
  27. package/dist/esm/src/identity/index.js +3 -0
  28. package/dist/esm/src/identity/index.js.map +1 -0
  29. package/dist/esm/src/identity/types/index.js +27 -0
  30. package/dist/esm/src/identity/types/index.js.map +1 -0
  31. package/dist/esm/src/registry/RegistryClient.js +388 -0
  32. package/dist/esm/src/registry/RegistryClient.js.map +1 -0
  33. package/dist/esm/src/registry/index.js +3 -0
  34. package/dist/esm/src/registry/index.js.map +1 -0
  35. package/dist/esm/src/registry/types/index.js +2 -0
  36. package/dist/esm/src/registry/types/index.js.map +1 -0
  37. package/dist/esm/src/storage/StorageDownloader.js +75 -0
  38. package/dist/esm/src/storage/StorageDownloader.js.map +1 -0
  39. package/dist/esm/src/storage/__test/StorageDownloader.test.js +139 -0
  40. package/dist/esm/src/storage/__test/StorageDownloader.test.js.map +1 -0
  41. package/dist/esm/src/storage/index.js +1 -0
  42. package/dist/esm/src/storage/index.js.map +1 -1
  43. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  44. package/dist/types/mod.d.ts +2 -0
  45. package/dist/types/mod.d.ts.map +1 -1
  46. package/dist/types/src/identity/IdentityClient.d.ts +50 -0
  47. package/dist/types/src/identity/IdentityClient.d.ts.map +1 -0
  48. package/dist/types/src/identity/index.d.ts +3 -0
  49. package/dist/types/src/identity/index.d.ts.map +1 -0
  50. package/dist/types/src/identity/types/index.d.ts +30 -0
  51. package/dist/types/src/identity/types/index.d.ts.map +1 -0
  52. package/dist/types/src/registry/RegistryClient.d.ts +94 -0
  53. package/dist/types/src/registry/RegistryClient.d.ts.map +1 -0
  54. package/dist/types/src/registry/index.d.ts +3 -0
  55. package/dist/types/src/registry/index.d.ts.map +1 -0
  56. package/dist/types/src/registry/types/index.d.ts +86 -0
  57. package/dist/types/src/registry/types/index.d.ts.map +1 -0
  58. package/dist/types/src/storage/StorageDownloader.d.ts +25 -0
  59. package/dist/types/src/storage/StorageDownloader.d.ts.map +1 -0
  60. package/dist/types/src/storage/__test/StorageDownloader.test.d.ts +2 -0
  61. package/dist/types/src/storage/__test/StorageDownloader.test.d.ts.map +1 -0
  62. package/dist/types/src/storage/index.d.ts +1 -0
  63. package/dist/types/src/storage/index.d.ts.map +1 -1
  64. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  65. package/dist/umd/bundle.js +1 -1
  66. package/docs/storage.md +51 -0
  67. package/mod.ts +3 -1
  68. package/package.json +2 -2
  69. package/src/identity/IdentityClient.ts +305 -0
  70. package/src/identity/README.md +93 -0
  71. package/src/identity/__tests/IdentityClient.test.ts +278 -0
  72. package/src/identity/index.ts +2 -0
  73. package/src/identity/types/index.ts +46 -0
  74. package/src/registry/RegistryClient.ts +493 -0
  75. package/src/registry/__tests/RegistryClient.test.ts +444 -0
  76. package/src/registry/index.ts +2 -0
  77. package/src/registry/types/index.ts +101 -0
  78. package/src/storage/StorageDownloader.ts +91 -0
  79. package/src/storage/__test/StorageDownloader.test.ts +170 -0
  80. package/src/storage/index.ts +3 -0
package/docs/storage.md CHANGED
@@ -6,6 +6,8 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
6
6
 
7
7
  | |
8
8
  | --- |
9
+ | [DownloadResult](#interface-downloadresult) |
10
+ | [DownloaderConfig](#interface-downloaderconfig) |
9
11
  | [UploadFileResult](#interface-uploadfileresult) |
10
12
  | [UploadableFile](#interface-uploadablefile) |
11
13
  | [UploaderConfig](#interface-uploaderconfig) |
@@ -14,6 +16,29 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
14
16
 
15
17
  ---
16
18
 
19
+ ### Interface: DownloadResult
20
+
21
+ ```ts
22
+ export interface DownloadResult {
23
+ data: Buffer;
24
+ mimeType: string | null;
25
+ }
26
+ ```
27
+
28
+ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
29
+
30
+ ---
31
+ ### Interface: DownloaderConfig
32
+
33
+ ```ts
34
+ export interface DownloaderConfig {
35
+ networkPreset: string;
36
+ }
37
+ ```
38
+
39
+ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
40
+
41
+ ---
17
42
  ### Interface: UploadFileResult
18
43
 
19
44
  ```ts
@@ -54,6 +79,32 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
54
79
  ---
55
80
  ## Classes
56
81
 
82
+ | |
83
+ | --- |
84
+ | [StorageDownloader](#class-storagedownloader) |
85
+ | [StorageUploader](#class-storageuploader) |
86
+
87
+ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
88
+
89
+ ---
90
+
91
+ ### Class: StorageDownloader
92
+
93
+ Locates HTTP URLs where content can be downloaded. It uses the passed or the default one.
94
+
95
+ ```ts
96
+ export class StorageDownloader {
97
+ constructor(config?: DownloaderConfig)
98
+ public async resolve(uhrpUrl: string): Promise<string[]>
99
+ public async download(uhrpUrl: string)
100
+ }
101
+ ```
102
+
103
+ See also: [DownloaderConfig](./storage.md#interface-downloaderconfig)
104
+
105
+ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Enums](#enums), [Variables](#variables)
106
+
107
+ ---
57
108
  ### Class: StorageUploader
58
109
 
59
110
  ```ts
package/mod.ts CHANGED
@@ -13,4 +13,6 @@ export * from './src/wallet/index.js'
13
13
  export * from './src/wallet/substrates/index.js'
14
14
  export * from './src/auth/index.js'
15
15
  export * from './src/overlay-tools/index.js'
16
- export * from './src/storage/index.js'
16
+ export * from './src/storage/index.js'
17
+ export * from './src/identity/index.js'
18
+ export * from './src/registry/index.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -254,4 +254,4 @@
254
254
  "src/auth/transports/SimplifiedFetchTransport.ts"
255
255
  ]
256
256
  }
257
- }
257
+ }
@@ -0,0 +1,305 @@
1
+ import { AuthFetch } from '../auth/clients/index.js'
2
+ import { DEFAULT_IDENTITY_CLIENT_OPTIONS, defaultIdentity, DisplayableIdentity, KNOWN_IDENTITY_TYPES } from './types/index.js'
3
+ import {
4
+ CertificateFieldNameUnder50Bytes,
5
+ DiscoverByAttributesArgs,
6
+ DiscoverByIdentityKeyArgs,
7
+ IdentityCertificate,
8
+ OriginatorDomainNameStringUnder250Bytes,
9
+ WalletCertificate,
10
+ WalletClient,
11
+ WalletInterface
12
+ } from '../wallet/index.js'
13
+ import { BroadcastFailure, BroadcastResponse, Transaction } from '../transaction/index.js'
14
+ import Certificate from '../auth/certificates/Certificate.js'
15
+ import { PushDrop } from '../script/index.js'
16
+ import { PrivateKey, Utils } from '../primitives/index.js'
17
+ import { TopicBroadcaster } from '../overlay-tools/index.js'
18
+
19
+ /**
20
+ * IdentityClient lets you discover who others are, and let the world know who you are.
21
+ */
22
+ export class IdentityClient {
23
+ private readonly authClient: AuthFetch
24
+ private readonly wallet: WalletInterface
25
+ constructor (
26
+ wallet?: WalletInterface,
27
+ private readonly options = DEFAULT_IDENTITY_CLIENT_OPTIONS,
28
+ private readonly originator?: OriginatorDomainNameStringUnder250Bytes
29
+ ) {
30
+ this.wallet = wallet ?? new WalletClient()
31
+ this.authClient = new AuthFetch(this.wallet)
32
+ }
33
+
34
+ /**
35
+ * Publicly reveals selected fields from a given certificate by creating a publicly verifiable certificate.
36
+ * The publicly revealed certificate is included in a blockchain transaction and broadcast to a federated overlay node.
37
+ *
38
+ * @param {Certificate} certificate - The master certificate to selectively reveal.
39
+ * @param {CertificateFieldNameUnder50Bytes[]} fieldsToReveal - An array of certificate field names to reveal. Only these fields will be included in the public certificate.
40
+ *
41
+ * @returns {Promise<object>} A promise that resolves with the broadcast result from the overlay network.
42
+ * @throws {Error} Throws an error if the certificate is invalid, the fields cannot be revealed, or if the broadcast fails.
43
+ */
44
+ async publiclyRevealAttributes (
45
+ certificate: WalletCertificate,
46
+ fieldsToReveal: CertificateFieldNameUnder50Bytes[]
47
+ ): Promise<BroadcastResponse | BroadcastFailure> {
48
+ if (Object.keys(certificate.fields).length === 0) {
49
+ throw new Error('Public reveal failed: Certificate has no fields to reveal!')
50
+ }
51
+ if (fieldsToReveal.length === 0) {
52
+ throw new Error('Public reveal failed: You must reveal at least one field!')
53
+ }
54
+ try {
55
+ const masterCert = new Certificate(
56
+ certificate.type,
57
+ certificate.serialNumber,
58
+ certificate.subject,
59
+ certificate.certifier,
60
+ certificate.revocationOutpoint,
61
+ certificate.fields,
62
+ certificate.signature
63
+ )
64
+ await masterCert.verify()
65
+ } catch (error) {
66
+ throw new Error('Public reveal failed: Certificate verification failed!')
67
+ }
68
+
69
+ // Given we already have a master certificate from a certifier,
70
+ // create an anyone verifiable certificate with selectively revealed fields
71
+ const { keyringForVerifier } = await this.wallet.proveCertificate({
72
+ certificate,
73
+ fieldsToReveal,
74
+ verifier: new PrivateKey(1).toPublicKey().toString()
75
+ })
76
+
77
+ // Build the lockingScript with pushdrop.create() and the transaction with createAction()
78
+ const lockingScript = await new PushDrop(this.wallet).lock(
79
+ [Utils.toArray(JSON.stringify({ ...certificate, keyring: keyringForVerifier }))],
80
+ this.options.protocolID,
81
+ this.options.keyID,
82
+ 'anyone',
83
+ true,
84
+ true
85
+ )
86
+ // TODO: Consider verification and if this is necessary
87
+ // counterpartyCanVerifyMyOwnership: true
88
+
89
+ const { tx } = await this.wallet.createAction({
90
+ description: 'Create a new Identity Token',
91
+ outputs: [{
92
+ satoshis: this.options.tokenAmount,
93
+ lockingScript: lockingScript.toHex(),
94
+ outputDescription: 'Identity Token'
95
+ }],
96
+ options: {
97
+ randomizeOutputs: false
98
+ }
99
+ })
100
+
101
+ if (tx !== undefined) {
102
+ // Submit the transaction to an overlay
103
+ const broadcaster = new TopicBroadcaster(['tm_identity'], {
104
+ networkPreset: (await (this.wallet.getNetwork({}))).network
105
+ })
106
+ return await broadcaster.broadcast(Transaction.fromAtomicBEEF(tx))
107
+ }
108
+ throw new Error('Public reveal failed: failed to create action!')
109
+ }
110
+
111
+ /**
112
+ * Resolves displayable identity certificates, issued to a given identity key by a trusted certifier.
113
+ *
114
+ * @param {DiscoverByIdentityKeyArgs} args - Arguments for requesting the discovery based on the identity key.
115
+ * @returns {Promise<DisplayableIdentity[]>} The promise resolves to displayable identities.
116
+ */
117
+ async resolveByIdentityKey (
118
+ args: DiscoverByIdentityKeyArgs
119
+ ): Promise<DisplayableIdentity[]> {
120
+ const { certificates } = await this.wallet.discoverByIdentityKey(args, this.originator)
121
+ return certificates.map(cert => {
122
+ return IdentityClient.parseIdentity(cert)
123
+ })
124
+ }
125
+
126
+ /**
127
+ * Resolves displayable identity certificates by specific identity attributes, issued by a trusted entity.
128
+ *
129
+ * @param {DiscoverByAttributesArgs} args - Attributes and optional parameters used to discover certificates.
130
+ * @returns {Promise<DisplayableIdentity[]>} The promise resolves to displayable identities.
131
+ */
132
+ async resolveByAttributes (
133
+ args: DiscoverByAttributesArgs
134
+ ): Promise<DisplayableIdentity[]> {
135
+ const { certificates } = await this.wallet.discoverByAttributes(args, this.originator)
136
+ return certificates.map(cert => {
137
+ return IdentityClient.parseIdentity(cert)
138
+ })
139
+ }
140
+
141
+ /**
142
+ * TODO: Implement once revocation overlay is created
143
+ * Remove public certificate revelation from overlay services by spending the identity token
144
+ * @param serialNumber - Unique serial number of the certificate to revoke revelation
145
+ */
146
+ // async revokeCertificateRevelation(
147
+ // serialNumber: Base64String
148
+ // ): Promise<BroadcastResponse | BroadcastFailure> {
149
+ // // 1. Find existing UTXO
150
+ // const lookupResolver = new LookupResolver()
151
+ // const result = await lookupResolver.query({
152
+ // service: 'ls_identity',
153
+ // query: {
154
+ // serialNumber
155
+ // }
156
+ // })
157
+
158
+ // let outpoint: string
159
+ // let lockingScript: LockingScript | undefined
160
+ // if (result.type === 'output-list') {
161
+ // const tx = Transaction.fromAtomicBEEF(result.outputs[this.options.outputIndex].beef)
162
+ // outpoint = `${tx.id('hex')}.${this.options.outputIndex}` // Consider better way
163
+ // lockingScript = tx.outputs[this.options.outputIndex].lockingScript
164
+ // }
165
+
166
+ // if (lockingScript === undefined) {
167
+ // throw new Error('Failed to get locking script for revelation output!')
168
+ // }
169
+
170
+ // // 2. Parse results
171
+ // const { signableTransaction } = await this.wallet.createAction({
172
+ // description: '',
173
+ // inputs: [{
174
+ // inputDescription: 'Spend certificate revelation token',
175
+ // outpoint,
176
+ // unlockingScriptLength: 73
177
+ // }],
178
+ // options: {
179
+ // randomizeOutputs: false
180
+ // }
181
+ // })
182
+
183
+ // if (signableTransaction === undefined) {
184
+ // throw new Error('Failed to create signable transaction')
185
+ // }
186
+
187
+ // const partialTx = Transaction.fromBEEF(signableTransaction.tx)
188
+
189
+ // const unlocker = new PushDrop(this.wallet).unlock(
190
+ // this.options.protocolID,
191
+ // this.options.keyID,
192
+ // 'self',
193
+ // 'all',
194
+ // false,
195
+ // 1,
196
+ // lockingScript
197
+ // )
198
+
199
+ // const unlockingScript = await unlocker.sign(partialTx, this.options.outputIndex)
200
+
201
+ // const { tx: signedTx } = await this.wallet.signAction({
202
+ // reference: signableTransaction.reference,
203
+ // spends: {
204
+ // [this.options.outputIndex]: {
205
+ // unlockingScript: unlockingScript.toHex()
206
+ // }
207
+ // }
208
+ // })
209
+
210
+ // // 4. Return broadcast status
211
+ // // Submit the transaction to an overlay
212
+ // const broadcaster = new SHIPBroadcaster(['tm_identity'])
213
+ // return await broadcaster.broadcast(Transaction.fromAtomicBEEF(signedTx as number[]))
214
+ // }
215
+
216
+ /**
217
+ * Parse out identity and certifier attributes to display from an IdentityCertificate
218
+ * @param identityToParse - The Identity Certificate to parse
219
+ * @returns - IdentityToDisplay
220
+ */
221
+ static parseIdentity (identityToParse: IdentityCertificate): DisplayableIdentity {
222
+ const { type, decryptedFields, certifierInfo } = identityToParse
223
+ let name, avatarURL, badgeLabel, badgeIconURL, badgeClickURL
224
+
225
+ // Parse out the name to display based on the specific certificate type which has clearly defined fields.
226
+ switch (type) {
227
+ case KNOWN_IDENTITY_TYPES.xCert:
228
+ name = decryptedFields.userName
229
+ avatarURL = decryptedFields.profilePhoto
230
+ badgeLabel = `X account certified by ${certifierInfo.name}`
231
+ badgeIconURL = certifierInfo.iconUrl
232
+ badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
233
+ break
234
+ case KNOWN_IDENTITY_TYPES.discordCert:
235
+ name = decryptedFields.userName
236
+ avatarURL = decryptedFields.profilePhoto
237
+ badgeLabel = `Discord account certified by ${certifierInfo.name}`
238
+ badgeIconURL = certifierInfo.iconUrl
239
+ badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
240
+ break
241
+ case KNOWN_IDENTITY_TYPES.emailCert:
242
+ name = decryptedFields.email
243
+ avatarURL = 'XUTZxep7BBghAJbSBwTjNfmcsDdRFs5EaGEgkESGSgjJVYgMEizu'
244
+ badgeLabel = `Email certified by ${certifierInfo.name}`
245
+ badgeIconURL = certifierInfo.iconUrl
246
+ badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
247
+ break
248
+ case KNOWN_IDENTITY_TYPES.phoneCert:
249
+ name = decryptedFields.phoneNumber
250
+ avatarURL = 'XUTLxtX3ELNUwRhLwL7kWNGbdnFM8WG2eSLv84J7654oH8HaJWrU'
251
+ badgeLabel = `Phone certified by ${certifierInfo.name}`
252
+ badgeIconURL = certifierInfo.iconUrl
253
+ badgeClickURL = 'https://socialcert.net' // TODO Make a specific page for this.
254
+ break
255
+ case KNOWN_IDENTITY_TYPES.identiCert:
256
+ name = `${decryptedFields.firstName} ${decryptedFields.lastName}`
257
+ avatarURL = decryptedFields.profilePhoto
258
+ badgeLabel = `Government ID certified by ${certifierInfo.name}`
259
+ badgeIconURL = certifierInfo.iconUrl
260
+ badgeClickURL = 'https://identicert.me' // TODO Make a specific page for this.
261
+ break
262
+ case KNOWN_IDENTITY_TYPES.registrant:
263
+ name = decryptedFields.name
264
+ avatarURL = decryptedFields.icon
265
+ badgeLabel = `Entity certified by ${certifierInfo.name}`
266
+ badgeIconURL = certifierInfo.iconUrl
267
+ badgeClickURL = 'https://projectbabbage.com/docs/registrant' // TODO: Make this doc page exist
268
+ break
269
+ case KNOWN_IDENTITY_TYPES.coolCert:
270
+ name = decryptedFields.cool === 'true' ? 'Cool Person!' : 'Not cool!'
271
+ break
272
+ case KNOWN_IDENTITY_TYPES.anyone:
273
+ name = 'Anyone'
274
+ avatarURL = 'XUT4bpQ6cpBaXi1oMzZsXfpkWGbtp2JTUYAoN7PzhStFJ6wLfoeR'
275
+ badgeLabel = 'Represents the ability for anyone to access this information.'
276
+ badgeIconURL = 'XUUV39HVPkpmMzYNTx7rpKzJvXfeiVyQWg2vfSpjBAuhunTCA9uG'
277
+ badgeClickURL = 'https://projectbabbage.com/docs/anyone-identity' // TODO: Make this doc page exist
278
+ break
279
+ case KNOWN_IDENTITY_TYPES.self:
280
+ name = 'You'
281
+ avatarURL = 'XUT9jHGk2qace148jeCX5rDsMftkSGYKmigLwU2PLLBc7Hm63VYR'
282
+ badgeLabel = 'Represents your ability to access this information.'
283
+ badgeIconURL = 'XUUV39HVPkpmMzYNTx7rpKzJvXfeiVyQWg2vfSpjBAuhunTCA9uG'
284
+ badgeClickURL = 'https://projectbabbage.com/docs/self-identity' // TODO: Make this doc page exist
285
+ break
286
+ default:
287
+ name = defaultIdentity.name
288
+ avatarURL = decryptedFields.profilePhoto
289
+ badgeLabel = defaultIdentity.badgeLabel
290
+ badgeIconURL = defaultIdentity.badgeIconURL
291
+ badgeClickURL = defaultIdentity.badgeClickURL // TODO: Make this doc page exist
292
+ break
293
+ }
294
+
295
+ return {
296
+ name,
297
+ avatarURL,
298
+ abbreviatedKey: identityToParse.subject.length > 0 ? `${identityToParse.subject.substring(0, 10)}...` : '',
299
+ identityKey: identityToParse.subject,
300
+ badgeIconURL,
301
+ badgeLabel,
302
+ badgeClickURL
303
+ }
304
+ }
305
+ }
@@ -0,0 +1,93 @@
1
+ # IdentityClient
2
+
3
+ **Resolve who others are and let the world know who you are.**
4
+
5
+ ## Overview
6
+
7
+ `IdentityClient` provides a straightforward interface for resolving and revealing identity certificates. It allows applications to verify user identities through certificates issued by trusted certifiers, reveal identity attributes publicly on the blockchain, and resolving identities associated with given attributes or identity keys.
8
+
9
+ ## Features
10
+
11
+ - **Selective Attribute Revelation**: Create identity tokens which publicly reveal selective identity attributes and are tracked by overlay services.
12
+ - **Identity Resolution**: Easily resolve identity certificates based on identity keys or specific attributes.
13
+ - **Displayable Identities**: Parse identity certificates into user-friendly, displayable identities.
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @bsv/sdk
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Initialization
24
+
25
+ ```typescript
26
+ import { IdentityClient } from '@bsv/sdk'
27
+
28
+ const identityClient = new IdentityClient()
29
+ ```
30
+
31
+ ### Publicly Reveal Attributes
32
+
33
+ ```typescript
34
+ const broadcastResult = await identityClient.publiclyRevealAttributes(certificate, ['name', 'email'])
35
+ ```
36
+
37
+ ### Resolve Identity by Key
38
+
39
+ ```typescript
40
+ const identities = await identityClient.resolveByIdentityKey({
41
+ identityKey: '<identity-key-here>'
42
+ })
43
+ ```
44
+
45
+ ### Resolve Identity by Attributes
46
+
47
+ ```typescript
48
+ const identities = await identityClient.resolveByAttributes({
49
+ attributes: { email: 'user@example.com' }
50
+ })
51
+ ```
52
+
53
+ ## React Example
54
+
55
+ ```ts
56
+ import React, { useEffect, useState } from 'react'
57
+ import { IdentityClient } from '@bsv/sdk'
58
+
59
+ const identityClient = new IdentityClient()
60
+
61
+ function IdentityDisplay({ identityKey }) {
62
+ const [identities, setIdentities] = useState([])
63
+
64
+ useEffect(() => {
65
+ async function fetchIdentities() {
66
+ const results = await identityClient.resolveByIdentityKey({ identityKey })
67
+ setIdentities(results)
68
+ }
69
+
70
+ fetchIdentities()
71
+ }, [identityKey])
72
+
73
+ return (
74
+ <div>
75
+ {identities.map((identity, index) => (
76
+ <div key={index} style={{ border: '1px solid #ccc', padding: '10px', marginBottom: '10px', borderRadius: '5px' }}>
77
+ <img src={identity.avatarURL} alt="Avatar" style={{ width: '50px', height: '50px', borderRadius: '25px' }} />
78
+ <h3>{identity.name}</h3>
79
+ <p>{identity.badgeLabel}</p>
80
+ <a href={identity.badgeClickURL}>Learn More</a>
81
+ </div>
82
+ ))}
83
+ </div>
84
+ )
85
+ }
86
+
87
+ export default IdentityDisplay
88
+ ```
89
+
90
+ ## License
91
+
92
+ Open BSV License
93
+