@bsv/sdk 1.4.0 → 1.4.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/dist/cjs/mod.js +2 -0
- package/dist/cjs/mod.js.map +1 -1
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/identity/IdentityClient.js +258 -0
- package/dist/cjs/src/identity/IdentityClient.js.map +1 -0
- package/dist/cjs/src/identity/index.js +19 -0
- package/dist/cjs/src/identity/index.js.map +1 -0
- package/dist/cjs/src/identity/types/index.js +30 -0
- package/dist/cjs/src/identity/types/index.js.map +1 -0
- package/dist/cjs/src/registry/RegistryClient.js +392 -0
- package/dist/cjs/src/registry/RegistryClient.js.map +1 -0
- package/dist/cjs/src/registry/index.js +19 -0
- package/dist/cjs/src/registry/index.js.map +1 -0
- package/dist/cjs/src/registry/types/index.js +3 -0
- package/dist/cjs/src/registry/types/index.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/mod.js +2 -0
- package/dist/esm/mod.js.map +1 -1
- package/dist/esm/src/identity/IdentityClient.js +255 -0
- package/dist/esm/src/identity/IdentityClient.js.map +1 -0
- package/dist/esm/src/identity/index.js +3 -0
- package/dist/esm/src/identity/index.js.map +1 -0
- package/dist/esm/src/identity/types/index.js +27 -0
- package/dist/esm/src/identity/types/index.js.map +1 -0
- package/dist/esm/src/registry/RegistryClient.js +388 -0
- package/dist/esm/src/registry/RegistryClient.js.map +1 -0
- package/dist/esm/src/registry/index.js +3 -0
- package/dist/esm/src/registry/index.js.map +1 -0
- package/dist/esm/src/registry/types/index.js +2 -0
- package/dist/esm/src/registry/types/index.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/mod.d.ts +2 -0
- package/dist/types/mod.d.ts.map +1 -1
- package/dist/types/src/identity/IdentityClient.d.ts +50 -0
- package/dist/types/src/identity/IdentityClient.d.ts.map +1 -0
- package/dist/types/src/identity/index.d.ts +3 -0
- package/dist/types/src/identity/index.d.ts.map +1 -0
- package/dist/types/src/identity/types/index.d.ts +30 -0
- package/dist/types/src/identity/types/index.d.ts.map +1 -0
- package/dist/types/src/registry/RegistryClient.d.ts +94 -0
- package/dist/types/src/registry/RegistryClient.d.ts.map +1 -0
- package/dist/types/src/registry/index.d.ts +3 -0
- package/dist/types/src/registry/index.d.ts.map +1 -0
- package/dist/types/src/registry/types/index.d.ts +86 -0
- package/dist/types/src/registry/types/index.d.ts.map +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/mod.ts +3 -1
- package/package.json +2 -2
- package/src/identity/IdentityClient.ts +305 -0
- package/src/identity/README.md +93 -0
- package/src/identity/__tests/IdentityClient.test.ts +278 -0
- package/src/identity/index.ts +2 -0
- package/src/identity/types/index.ts +46 -0
- package/src/registry/RegistryClient.ts +493 -0
- package/src/registry/__tests/RegistryClient.test.ts +444 -0
- package/src/registry/index.ts +2 -0
- package/src/registry/types/index.ts +101 -0
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.
|
|
3
|
+
"version": "1.4.1",
|
|
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
|
+
|