@thurinlabs/identity-kit 0.8.0 → 1.0.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/README.md +87 -13
- package/dist/embed.global.js +5601 -13813
- package/dist/embed.global.js.map +1 -1
- package/dist/index.cjs +1533 -167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1437 -47
- package/dist/index.d.ts +1437 -47
- package/dist/index.js +1518 -152
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,9 +74,11 @@ Wrap your app (or just the part using identity-kit) in `IdentityKitProvider`. If
|
|
|
74
74
|
|
|
75
75
|
| Prop | Type | Default | Description |
|
|
76
76
|
|------|------|---------|-------------|
|
|
77
|
-
| `rpcUrl` | `string` | publicnode | Ethereum RPC endpoint |
|
|
77
|
+
| `rpcUrl` | `string` | publicnode | Ethereum RPC endpoint. Any RPC works — v2 needs only `eth_call` |
|
|
78
78
|
| `neynarApiKey` | `string` | — | Neynar API key for Farcaster proof verification |
|
|
79
79
|
| `baseUrl` | `string` | `https://thurin.id` | Base URL for "View on Thurin" links |
|
|
80
|
+
| `network` | `'mainnet' \| 'sepolia' \| 'local'` | `'mainnet'` | Which chain to read the PGPRegistry on (`local` = a running anvil) |
|
|
81
|
+
| `registryAddress` | `string` | v2 address | Override the registry contract address |
|
|
80
82
|
|
|
81
83
|
## Hooks
|
|
82
84
|
|
|
@@ -96,11 +98,12 @@ Returns: `ThurinIdentity` with `address`, `ensName`, `ensAvatar`, `claims`, `tot
|
|
|
96
98
|
|
|
97
99
|
### useAttestations
|
|
98
100
|
|
|
99
|
-
On-chain attestation data from the PGPRegistry contract.
|
|
101
|
+
On-chain attestation data from the PGPRegistry v2 contract — the owner's history plus the stored signature and key for each claim, read with plain contract calls (no event logs), each verified off-chain.
|
|
100
102
|
|
|
101
103
|
```tsx
|
|
102
104
|
const { claims, totalClaims, activeClaims, currentFingerprint, isLoading } =
|
|
103
105
|
useAttestations('0xd8dA...')
|
|
106
|
+
// claims[].{ index, fingerprint, createdAt, revoked, revokedAt, messageVersion, pgpSignature, pgpPublicKey, verification }
|
|
104
107
|
```
|
|
105
108
|
|
|
106
109
|
### useEFPGraph
|
|
@@ -114,13 +117,15 @@ const { efp, isLoading } = useEFPGraph('0xd8dA...')
|
|
|
114
117
|
|
|
115
118
|
### usePGPProofs
|
|
116
119
|
|
|
117
|
-
PGP key info and verified social proofs from keyserver.
|
|
120
|
+
PGP key info and verified social proofs, read from the key stored in the identity's on-chain attestation. No keyserver is consulted.
|
|
118
121
|
|
|
119
122
|
```tsx
|
|
120
|
-
const { keyInfo, proofs, isLoading } = usePGPProofs(
|
|
123
|
+
const { keyInfo, proofs, isLoading } = usePGPProofs(fingerprint, attestation.pgpPublicKey)
|
|
121
124
|
// proofs[].provider, proofs[].status, proofs[].displayUrl
|
|
122
125
|
```
|
|
123
126
|
|
|
127
|
+
`useThurinIdentity` wires this up for you from the current attestation.
|
|
128
|
+
|
|
124
129
|
## Core utilities (no React)
|
|
125
130
|
|
|
126
131
|
The verification and data logic is exported as plain functions — no React, no provider. This is the layer the thurin.id explorer and the hooks both build on; use it directly when you need the validated data behind your own UI.
|
|
@@ -142,7 +147,7 @@ const result = await verifyProof(proof, fingerprint, neynarApiKey /* only needed
|
|
|
142
147
|
### PGP
|
|
143
148
|
|
|
144
149
|
```ts
|
|
145
|
-
import { parsePgpKey, verifyAttestation,
|
|
150
|
+
import { parsePgpKey, verifyAttestation, stripEmailUserIDs, hasEmailUserID } from '@thurinlabs/identity-kit'
|
|
146
151
|
|
|
147
152
|
const keyInfo = await parsePgpKey(armoredKey)
|
|
148
153
|
// → { fingerprint, userIDs, algorithm, created, expires, notations, subkeys } | null
|
|
@@ -150,9 +155,17 @@ const keyInfo = await parsePgpKey(armoredKey)
|
|
|
150
155
|
const verification = await verifyAttestation({ pgpPublicKey, pgpSignature, fingerprint, ethAddress })
|
|
151
156
|
// → { verified: boolean, reason?: string }
|
|
152
157
|
|
|
153
|
-
|
|
158
|
+
// Prepare a key for publishing: drop every user ID that contains an email address.
|
|
159
|
+
const stripped = await stripEmailUserIDs(armoredKey)
|
|
160
|
+
// → { armored, kept: ['thurin'], removed: ['Alice <alice@example.com>'] } | null (null = nothing would remain)
|
|
161
|
+
|
|
162
|
+
await hasEmailUserID(armoredKey) // → true if any user ID contains an @
|
|
154
163
|
```
|
|
155
164
|
|
|
165
|
+
**Published identity.** An attestation stores the armored key on-chain, permanently and publicly. Since 0.9.0 the intended shape is a key whose only user ID is a non-email one (any name — `thurin` is the suggestion), carrying the `proof@thurin.id` notations. `stripEmailUserIDs` produces that from a normal export; the stripped key still verifies (`verifyAttestation` needs at least one self-certified user ID, so a key with none is rejected) and keeps the notations on the user ID it retains. Proofs are then read from the on-chain key, never from a keyserver.
|
|
166
|
+
|
|
167
|
+
`fetchKeyByFingerprint` / `fetchKeyByKeyId` (keys.openpgp.org) remain exported for key-ID → fingerprint resolution, but note that keyserver serves unverified-email keys as bare packets and drops non-email user IDs, so it cannot supply a published identity.
|
|
168
|
+
|
|
156
169
|
### EFP & claims
|
|
157
170
|
|
|
158
171
|
```ts
|
|
@@ -162,13 +175,46 @@ const graph = await fetchEFPGraph(address)
|
|
|
162
175
|
// → { followers, following, top8: string[], hasEfp } | null
|
|
163
176
|
```
|
|
164
177
|
|
|
165
|
-
### Contract
|
|
178
|
+
### Contract
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { REGISTRY_ADDRESS, REGISTRY_ABI, NETWORKS, getRegistry } from '@thurinlabs/identity-kit'
|
|
182
|
+
|
|
183
|
+
getRegistry('sepolia') // → { chainId: 11155111, address, deployBlock, explorerUrl, defaultRpcUrl }
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`REGISTRY_ABI` is the complete v2 ABI (reads and writes), so apps that publish claims use the same one. The v2 registry is deployed with CREATE2 and has the same address on every network.
|
|
187
|
+
|
|
188
|
+
### Fingerprints and key IDs
|
|
189
|
+
|
|
190
|
+
The v2 registry takes raw fingerprint bytes and indexes by their hash and by long key ID:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { fingerprintToBytes, bytesToFingerprint, fingerprintHash, keyIdOf, keyIdToBytes } from '@thurinlabs/identity-kit'
|
|
194
|
+
|
|
195
|
+
fingerprintToBytes('6E00 5391 … 7FE7') // → '0x6e0053911942a889426c1866e34d9266098f7fe7' (attest / reattest arg)
|
|
196
|
+
bytesToFingerprint('0x6e00…7fe7') // → '6e0053911942a889426c1866e34d9266098f7fe7'
|
|
197
|
+
fingerprintHash(fp) // → keccak256 of the raw bytes (addressesFor arg)
|
|
198
|
+
keyIdOf(fp) // → '0xe34d9266098f7fe7' (fingerprintsForKeyId arg; v4 = last 8 bytes, v6 = first 8, per RFC 9580)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Authorized writes (EIP-712)
|
|
202
|
+
|
|
203
|
+
Every write has a `…For` twin that anyone can submit with the owner's signature — for cold wallets, a CLI, or a sponsor. The helpers build exactly the typed data the contract verifies:
|
|
166
204
|
|
|
167
205
|
```ts
|
|
168
|
-
import {
|
|
206
|
+
import { attestTypedData, authorizationDigest } from '@thurinlabs/identity-kit'
|
|
207
|
+
import { signTypedData } from '@wagmi/core'
|
|
208
|
+
|
|
209
|
+
const nonce = await readContract({ ..., functionName: 'nonces', args: [owner] })
|
|
210
|
+
const typedData = attestTypedData(chainId, registryAddress, {
|
|
211
|
+
owner, fingerprint, pgpSignature, pgpPublicKey, nonce, deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
212
|
+
})
|
|
213
|
+
const signature = await signTypedData(config, typedData)
|
|
214
|
+
// anyone: attestFor(owner, fingerprintBytes, sigBytes, keyBytes, deadline, signature)
|
|
169
215
|
```
|
|
170
216
|
|
|
171
|
-
|
|
217
|
+
Also `reattestTypedData`, `updateKeyTypedData`, `revokeTypedData`, `setRecordTypedData`, and `recordKind(name)` for the `bytes32 kind` of a record.
|
|
172
218
|
|
|
173
219
|
## Themes
|
|
174
220
|
|
|
@@ -193,17 +239,20 @@ For static sites, Jekyll blogs, WordPress, or any HTML page — use the standalo
|
|
|
193
239
|
data-rpc-url="https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
|
|
194
240
|
></div>
|
|
195
241
|
|
|
196
|
-
<script src="https://cdn.jsdelivr.net/npm/@thurinlabs/identity-kit/dist/embed.global.js"></script>
|
|
242
|
+
<script src="https://cdn.jsdelivr.net/npm/@thurinlabs/identity-kit@0/dist/embed.global.js"></script>
|
|
197
243
|
```
|
|
198
244
|
|
|
199
245
|
| Attribute | Description |
|
|
200
246
|
|-----------|-------------|
|
|
201
247
|
| `data-thurin-card` | ENS name or ETH address to look up (required) |
|
|
202
|
-
| `data-theme` | `thurin`, `dark`, or `light` (default: `thurin`) |
|
|
203
|
-
| `data-rpc-url` |
|
|
248
|
+
| `data-theme` | `thurin`, `dark`, or `light` (default: `thurin`). Change it after render and the card follows, so a page with a theme switch can keep the card in step. |
|
|
249
|
+
| `data-rpc-url` | Optional. Any Ethereum RPC; the card reads the v2 registry with plain calls, so the keyless public default works. |
|
|
204
250
|
| `data-neynar-key` | Optional. A Neynar API key, only to verify Farcaster proofs. Without it, Farcaster shows as unverified. |
|
|
251
|
+
| `data-base-url` | Optional. Where the card's "View on Thurin" link points (default `https://thurin.id`). A page served from ENS can pass its own name so the link stays on ENS. |
|
|
252
|
+
| `data-network` | Optional. `sepolia` or `local` instead of mainnet. |
|
|
253
|
+
| `data-registry-address` | Optional. Override the registry contract address. |
|
|
205
254
|
|
|
206
|
-
The card talks directly to Ethereum
|
|
255
|
+
The card talks directly to Ethereum and each proof platform — no intermediary, no keyserver. Cards render automatically on page load and for dynamically added elements.
|
|
207
256
|
|
|
208
257
|
## Supported Proof Providers
|
|
209
258
|
|
|
@@ -215,6 +264,31 @@ The card talks directly to Ethereum, keys.openpgp.org, and each proof platform
|
|
|
215
264
|
| Codeberg | Repository description |
|
|
216
265
|
| Mastodon | Profile metadata |
|
|
217
266
|
|
|
267
|
+
## Migrating from 0.9.x
|
|
268
|
+
|
|
269
|
+
1.0.0 reads the **PGPRegistry v2** contract. The v1 registry is no longer read.
|
|
270
|
+
|
|
271
|
+
| 0.9.x | 1.0.0 |
|
|
272
|
+
|-------|-------|
|
|
273
|
+
| `REGISTRY_ABI` (v1, reads only) | v2 ABI, reads + writes |
|
|
274
|
+
| `CONTRACT_DEPLOY_BLOCK` | removed (no log scans) |
|
|
275
|
+
| `Attestation.txHash` | removed; `revokedAt` and `messageVersion` added |
|
|
276
|
+
| `rpcUrl` needed `eth_getLogs` | any RPC |
|
|
277
|
+
| — | `local` network, `registryAddress` prop / `data-registry-address` |
|
|
278
|
+
| — | fingerprint helpers, EIP-712 authorization helpers |
|
|
279
|
+
|
|
280
|
+
## Migrating from 0.8.x
|
|
281
|
+
|
|
282
|
+
0.9.0 moves proofs to the on-chain key and adds key-preparation helpers.
|
|
283
|
+
|
|
284
|
+
| 0.8.x | 0.9.0 |
|
|
285
|
+
|-------|-------|
|
|
286
|
+
| `usePGPProofs(fingerprint)` — fetched the key from keys.openpgp.org | `usePGPProofs(fingerprint, armoredKey)` — parses the supplied (on-chain) key |
|
|
287
|
+
| — | `stripEmailUserIDs(armoredKey)`, `hasEmailUserID(armoredKey)` |
|
|
288
|
+
| mainnet only | `network` prop / `data-network` attribute; `NETWORKS`, `getRegistry()` |
|
|
289
|
+
|
|
290
|
+
`useThurinIdentity`, `ThurinCard`, and the embed need no changes; they pass the attestation's key through automatically.
|
|
291
|
+
|
|
218
292
|
## Migrating from 0.7.x
|
|
219
293
|
|
|
220
294
|
0.8.0 collapses the Scry / Signet sub-brands into Thurin. Renames only — no behaviour changed, and existing on-chain attestations verify exactly as before.
|