@thurinlabs/identity-kit 1.4.0 → 2.1.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 +44 -384
- package/dist/{chunk-ZAQ2EPF5.js → chunk-SGAMXZDL.js} +2484 -1343
- package/dist/{chunk-M2OJDB7I.cjs → chunk-T4VPFPFP.cjs} +2489 -1348
- package/dist/core.cjs +46 -3
- package/dist/core.d.cts +1593 -902
- package/dist/core.d.ts +1593 -902
- package/dist/core.js +67 -24
- package/dist/index.cjs +27 -459
- package/dist/index.d.cts +1 -83
- package/dist/index.d.ts +1 -83
- package/dist/index.js +67 -499
- package/package.json +6 -22
- package/dist/chunk-M2OJDB7I.cjs.map +0 -1
- package/dist/chunk-ZAQ2EPF5.js.map +0 -1
- package/dist/core.cjs.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/embed.global.js +0 -32213
- package/dist/embed.global.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.css +0 -185
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,619 +2,187 @@ import {
|
|
|
2
2
|
ARWEAVE_GATEWAY,
|
|
3
3
|
AUTHORIZATION_TYPES,
|
|
4
4
|
CLAIM_CHECK_LABEL,
|
|
5
|
+
CLAIM_LIMIT,
|
|
6
|
+
CONTRACT_ERROR_TEXT,
|
|
5
7
|
EIP712_NAME,
|
|
6
8
|
EIP712_VERSION,
|
|
7
9
|
ENS_HINT_KEY,
|
|
8
10
|
ENS_TEXT_RESOLVER_ABI,
|
|
9
11
|
FARCASTER_HUB,
|
|
10
|
-
IDENTITY_ERROR_TEXT,
|
|
11
|
-
IDENTITY_KINDS,
|
|
12
12
|
IPFS_GATEWAY,
|
|
13
13
|
IPFS_GATEWAYS,
|
|
14
14
|
KNOWN_KINDS,
|
|
15
|
+
MAX_KIND_BYTES,
|
|
15
16
|
MAX_RECORD_BYTES,
|
|
16
17
|
NETWORKS,
|
|
17
18
|
NFT_AVATAR_ABI,
|
|
19
|
+
OWNER_REVOKE_REASONS,
|
|
18
20
|
REGISTRY_ABI,
|
|
19
21
|
REGISTRY_ADDRESS,
|
|
20
|
-
|
|
22
|
+
REVOKE_REASONS,
|
|
23
|
+
addRelease,
|
|
21
24
|
attestTypedData,
|
|
22
25
|
authorizationDigest,
|
|
23
26
|
avatarFallbacks,
|
|
24
27
|
avatarUrl,
|
|
25
28
|
bytesToFingerprint,
|
|
26
29
|
chainFor,
|
|
30
|
+
checkKindName,
|
|
31
|
+
checkRecordValue,
|
|
27
32
|
claimCheckText,
|
|
28
33
|
claimFateText,
|
|
29
34
|
claimFates,
|
|
30
|
-
|
|
35
|
+
claimSignature,
|
|
36
|
+
contractErrorName,
|
|
37
|
+
contractErrorText,
|
|
31
38
|
displayUrl,
|
|
32
|
-
|
|
39
|
+
encryptRefusalText,
|
|
40
|
+
encryptTo,
|
|
41
|
+
encryptionKeyFor,
|
|
33
42
|
ensHintFor,
|
|
34
43
|
ensHintValue,
|
|
35
44
|
ensHintWrite,
|
|
36
45
|
expiresSoon,
|
|
37
46
|
expiresSoonText,
|
|
38
|
-
fetchEFPGraph,
|
|
39
47
|
fetchEnsHint,
|
|
40
48
|
fetchRecords,
|
|
49
|
+
findOwners,
|
|
41
50
|
fingerprintHash,
|
|
42
51
|
fingerprintToBytes,
|
|
43
52
|
formatClaimDate,
|
|
44
53
|
getRegistry,
|
|
45
54
|
hasEmailUserID,
|
|
46
55
|
identifyProof,
|
|
47
|
-
identityErrorKind,
|
|
48
56
|
isNetworkName,
|
|
57
|
+
keyChangedText,
|
|
49
58
|
keyIdOf,
|
|
50
59
|
keyIdToBytes,
|
|
60
|
+
keyProblemText,
|
|
61
|
+
keyStanding,
|
|
51
62
|
kindName,
|
|
52
|
-
|
|
63
|
+
leanKey,
|
|
64
|
+
markCompromisedTypedData,
|
|
53
65
|
nftAvatarImage,
|
|
54
66
|
normalizeFingerprint,
|
|
67
|
+
pageRecords,
|
|
55
68
|
parseNftAvatar,
|
|
56
69
|
parsePgpKey,
|
|
57
|
-
parsePointer,
|
|
58
70
|
parseRecord,
|
|
71
|
+
parseReleases,
|
|
72
|
+
payloadText,
|
|
73
|
+
permissionSigned,
|
|
74
|
+
pickRecords,
|
|
59
75
|
proofHref,
|
|
60
76
|
proofSecondaryHref,
|
|
77
|
+
readClaims,
|
|
61
78
|
reattestTypedData,
|
|
62
79
|
recordKind,
|
|
63
80
|
registryDomain,
|
|
64
|
-
|
|
81
|
+
renderReleases,
|
|
65
82
|
revokeTypedData,
|
|
83
|
+
sameFingerprint,
|
|
66
84
|
setRecordTypedData,
|
|
85
|
+
signatureEmail,
|
|
86
|
+
sshKeys,
|
|
87
|
+
statementText,
|
|
67
88
|
stripEmailUserIDs,
|
|
68
89
|
updateKeyTypedData,
|
|
69
90
|
verifyAttestation,
|
|
70
91
|
verifyClearsigned,
|
|
71
|
-
verifyProof
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// src/provider.tsx
|
|
75
|
-
import { useMemo } from "react";
|
|
76
|
-
import { WagmiProvider, createConfig, http, useConfig } from "wagmi";
|
|
77
|
-
import { mainnet, sepolia, foundry } from "wagmi/chains";
|
|
78
|
-
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
79
|
-
|
|
80
|
-
// src/context.ts
|
|
81
|
-
import { createContext, useContext } from "react";
|
|
82
|
-
var defaultConfig = {
|
|
83
|
-
baseUrl: "https://thurin.id",
|
|
84
|
-
network: "mainnet"
|
|
85
|
-
};
|
|
86
|
-
var IdentityKitContext = createContext(defaultConfig);
|
|
87
|
-
function useIdentityKitConfig() {
|
|
88
|
-
return useContext(IdentityKitContext);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// src/provider.tsx
|
|
92
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
93
|
-
var defaultQueryClient = new QueryClient({
|
|
94
|
-
defaultOptions: {
|
|
95
|
-
queries: {
|
|
96
|
-
staleTime: 6e4,
|
|
97
|
-
retry: 1
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
function createDefaultWagmiConfig(rpcUrl, network) {
|
|
102
|
-
const url = rpcUrl || getRegistry(network).defaultRpcUrl;
|
|
103
|
-
if (network === "sepolia") return createConfig({ chains: [sepolia], transports: { [sepolia.id]: http(url) } });
|
|
104
|
-
if (network === "local") return createConfig({ chains: [foundry], transports: { [foundry.id]: http(url) } });
|
|
105
|
-
return createConfig({ chains: [mainnet], transports: { [mainnet.id]: http(url) } });
|
|
106
|
-
}
|
|
107
|
-
function WagmiDetector({ children, rpcUrl, network }) {
|
|
108
|
-
let hasWagmi = false;
|
|
109
|
-
try {
|
|
110
|
-
useConfig();
|
|
111
|
-
hasWagmi = true;
|
|
112
|
-
} catch {
|
|
113
|
-
}
|
|
114
|
-
const wagmiConfig = useMemo(() => createDefaultWagmiConfig(rpcUrl, network), [rpcUrl, network]);
|
|
115
|
-
if (hasWagmi) {
|
|
116
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
117
|
-
}
|
|
118
|
-
return /* @__PURE__ */ jsx(WagmiProvider, { config: wagmiConfig, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: defaultQueryClient, children }) });
|
|
119
|
-
}
|
|
120
|
-
function IdentityKitProvider({
|
|
121
|
-
children,
|
|
122
|
-
rpcUrl,
|
|
123
|
-
neynarApiKey,
|
|
124
|
-
farcasterHub,
|
|
125
|
-
baseUrl = "https://thurin.id",
|
|
126
|
-
network = "mainnet",
|
|
127
|
-
registryAddress
|
|
128
|
-
}) {
|
|
129
|
-
const config = useMemo(
|
|
130
|
-
() => ({ rpcUrl, neynarApiKey, farcasterHub, baseUrl, network, registryAddress }),
|
|
131
|
-
[rpcUrl, neynarApiKey, farcasterHub, baseUrl, network, registryAddress]
|
|
132
|
-
);
|
|
133
|
-
return /* @__PURE__ */ jsx(IdentityKitContext.Provider, { value: config, children: /* @__PURE__ */ jsx(WagmiDetector, { rpcUrl, network, children }) });
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// src/components/ThurinCard/ThurinCard.tsx
|
|
137
|
-
import { useEffect, useState } from "react";
|
|
138
|
-
|
|
139
|
-
// src/hooks/useThurinIdentity.ts
|
|
140
|
-
import { useBlockNumber, useEnsAddress, useEnsName } from "wagmi";
|
|
141
|
-
import { normalize } from "viem/ens";
|
|
142
|
-
|
|
143
|
-
// src/hooks/useAttestations.ts
|
|
144
|
-
import { useReadContract, useReadContracts } from "wagmi";
|
|
145
|
-
import { useQuery } from "@tanstack/react-query";
|
|
146
|
-
import { hexToString } from "viem";
|
|
147
|
-
function useAttestations(address) {
|
|
148
|
-
const config = useIdentityKitConfig();
|
|
149
|
-
const registry = getRegistry(config.network, config.registryAddress);
|
|
150
|
-
const chain = chainFor(config.network);
|
|
151
|
-
const owner = address;
|
|
152
|
-
const { data: rows, isLoading: rowsLoading, isFetched: rowsFetched, error: rowsError, refetch: refetchRows } = useReadContract({
|
|
153
|
-
address: registry.address,
|
|
154
|
-
abi: REGISTRY_ABI,
|
|
155
|
-
functionName: "attestationsOf",
|
|
156
|
-
args: owner ? [owner] : void 0,
|
|
157
|
-
chainId: chain.id,
|
|
158
|
-
query: { enabled: !!owner }
|
|
159
|
-
});
|
|
160
|
-
const count = rows?.length ?? 0;
|
|
161
|
-
const contracts = owner && rows ? rows.map((_, i) => ({
|
|
162
|
-
address: registry.address,
|
|
163
|
-
abi: REGISTRY_ABI,
|
|
164
|
-
functionName: "getPayload",
|
|
165
|
-
args: [owner, BigInt(i)],
|
|
166
|
-
chainId: chain.id
|
|
167
|
-
})) : [];
|
|
168
|
-
const { data: payloads, isLoading: payloadsLoading, error: payloadsError, refetch: refetchPayloads } = useReadContracts({
|
|
169
|
-
contracts,
|
|
170
|
-
query: { enabled: contracts.length > 0 }
|
|
171
|
-
});
|
|
172
|
-
const payloadsReady = count === 0 || payloads !== void 0 && payloads.length === count;
|
|
173
|
-
const { data: claims, isLoading: verifyLoading } = useQuery({
|
|
174
|
-
queryKey: ["attestations", config.network, registry.address, address, count, payloadsReady],
|
|
175
|
-
queryFn: async () => {
|
|
176
|
-
if (!rows || !address) return [];
|
|
177
|
-
const results = [];
|
|
178
|
-
for (let i = 0; i < rows.length; i++) {
|
|
179
|
-
const row = rows[i];
|
|
180
|
-
const payload = payloads?.[i];
|
|
181
|
-
let pgpSignature = null;
|
|
182
|
-
let pgpPublicKey = null;
|
|
183
|
-
if (payload && payload.status === "success") {
|
|
184
|
-
const [sigHex, keyHex] = payload.result;
|
|
185
|
-
pgpSignature = hexToString(sigHex);
|
|
186
|
-
pgpPublicKey = hexToString(keyHex);
|
|
187
|
-
}
|
|
188
|
-
const fingerprint = bytesToFingerprint(row.fingerprint);
|
|
189
|
-
const verification = pgpPublicKey && pgpSignature ? await verifyAttestation({ pgpPublicKey, pgpSignature, fingerprint, ethAddress: address }) : null;
|
|
190
|
-
const revokedAt = Number(row.revokedAt);
|
|
191
|
-
results.push({
|
|
192
|
-
index: i,
|
|
193
|
-
fingerprint,
|
|
194
|
-
createdAt: Number(row.createdAt),
|
|
195
|
-
revoked: revokedAt !== 0,
|
|
196
|
-
revokedAt: revokedAt === 0 ? null : revokedAt,
|
|
197
|
-
messageVersion: Number(row.messageVersion),
|
|
198
|
-
pgpSignature,
|
|
199
|
-
pgpPublicKey,
|
|
200
|
-
verification
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
return results;
|
|
204
|
-
},
|
|
205
|
-
enabled: !!rows && payloadsReady,
|
|
206
|
-
staleTime: 3e5
|
|
207
|
-
});
|
|
208
|
-
const isLoading = rowsLoading || !!owner && !rowsFetched || payloadsLoading || verifyLoading || !!owner && rows !== void 0 && !payloadsReady;
|
|
209
|
-
const activeClaims = (claims || []).filter((c) => !c.revoked);
|
|
210
|
-
const verifiedClaims = activeClaims.filter((c) => c.verification?.verified);
|
|
211
|
-
const currentFingerprint = verifiedClaims.length > 0 ? verifiedClaims[verifiedClaims.length - 1].fingerprint : null;
|
|
212
|
-
return {
|
|
213
|
-
claims: claims || [],
|
|
214
|
-
totalClaims: count,
|
|
215
|
-
activeClaims: activeClaims.length,
|
|
216
|
-
currentFingerprint,
|
|
217
|
-
isLoading,
|
|
218
|
-
/** A registry read failed (the RPC may be down; useThurinIdentity finds out which). */
|
|
219
|
-
error: rowsError ?? payloadsError ?? null,
|
|
220
|
-
refetch: () => {
|
|
221
|
-
if (owner) {
|
|
222
|
-
refetchRows();
|
|
223
|
-
if (contracts.length > 0) refetchPayloads();
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// src/hooks/useEFPGraph.ts
|
|
230
|
-
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
231
|
-
function useEFPGraph(address) {
|
|
232
|
-
const { data, isLoading } = useQuery2({
|
|
233
|
-
queryKey: ["efp-graph", address],
|
|
234
|
-
queryFn: () => fetchEFPGraph(address),
|
|
235
|
-
enabled: !!address,
|
|
236
|
-
staleTime: 3e5
|
|
237
|
-
});
|
|
238
|
-
return {
|
|
239
|
-
efp: data ?? null,
|
|
240
|
-
isLoading
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// src/hooks/usePGPProofs.ts
|
|
245
|
-
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
246
|
-
function usePGPProofs(fingerprint, armoredKey) {
|
|
247
|
-
const config = useIdentityKitConfig();
|
|
248
|
-
const { data } = useQuery3({
|
|
249
|
-
// The key is large; key the query on its length + fingerprint, which
|
|
250
|
-
// changes whenever a different attestation's key is supplied.
|
|
251
|
-
queryKey: ["pgp-proofs", fingerprint, armoredKey?.length ?? 0],
|
|
252
|
-
queryFn: async () => {
|
|
253
|
-
if (!fingerprint || !armoredKey) return { keyInfo: null, proofs: [] };
|
|
254
|
-
const keyInfo = await parsePgpKey(armoredKey);
|
|
255
|
-
if (!keyInfo) return { keyInfo: null, proofs: [] };
|
|
256
|
-
const identified = keyInfo.notations.map((n) => identifyProof(n)).filter((p) => p !== null && p.provider !== "unknown");
|
|
257
|
-
const proofs = await Promise.all(
|
|
258
|
-
identified.map(async (proof) => {
|
|
259
|
-
const result = await verifyProof(proof, fingerprint, { neynarApiKey: config.neynarApiKey, farcasterHub: config.farcasterHub });
|
|
260
|
-
return {
|
|
261
|
-
provider: proof.provider,
|
|
262
|
-
label: proof.label,
|
|
263
|
-
url: proof.url,
|
|
264
|
-
displayUrl: displayUrl(proof),
|
|
265
|
-
href: proofHref(proof),
|
|
266
|
-
secondaryHref: proofSecondaryHref(proof),
|
|
267
|
-
status: result.verified ? "verified" : "unverified",
|
|
268
|
-
reason: result.reason
|
|
269
|
-
};
|
|
270
|
-
})
|
|
271
|
-
);
|
|
272
|
-
const byAccount = /* @__PURE__ */ new Map();
|
|
273
|
-
for (const p of proofs) {
|
|
274
|
-
const key = `${p.provider}:${p.displayUrl}`;
|
|
275
|
-
const prev = byAccount.get(key);
|
|
276
|
-
if (!prev || p.status === "verified" && prev.status !== "verified") {
|
|
277
|
-
byAccount.set(key, p);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
return { keyInfo, proofs: [...byAccount.values()] };
|
|
281
|
-
},
|
|
282
|
-
enabled: !!fingerprint && !!armoredKey,
|
|
283
|
-
staleTime: 3e5
|
|
284
|
-
});
|
|
285
|
-
return {
|
|
286
|
-
keyInfo: data?.keyInfo ?? null,
|
|
287
|
-
proofs: data?.proofs ?? [],
|
|
288
|
-
// Report loading whenever a fingerprint is set but its proofs haven't
|
|
289
|
-
// resolved yet. Using react-query's own isLoading leaves a gap while the
|
|
290
|
-
// query is enabling (fingerprint just became known), during which the card
|
|
291
|
-
// would briefly paint without proof badges and then pop them in.
|
|
292
|
-
isLoading: !!fingerprint && !!armoredKey && data === void 0
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// src/hooks/useSafeAvatar.ts
|
|
297
|
-
import { useEnsText, useReadContract as useReadContract2 } from "wagmi";
|
|
298
|
-
import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
299
|
-
function useSafeAvatar(name, chainId) {
|
|
300
|
-
const { data: raw } = useEnsText({ name, key: "avatar", chainId, query: { enabled: !!name } });
|
|
301
|
-
const direct = avatarUrl(raw);
|
|
302
|
-
const nft = direct ? null : parseNftAvatar(raw);
|
|
303
|
-
const { data: tokenUri } = useReadContract2({
|
|
304
|
-
address: nft?.contract,
|
|
305
|
-
abi: NFT_AVATAR_ABI,
|
|
306
|
-
functionName: nft?.standard === "erc1155" ? "uri" : "tokenURI",
|
|
307
|
-
args: nft ? [nft.tokenId] : void 0,
|
|
308
|
-
chainId,
|
|
309
|
-
query: { enabled: !!nft && nft.chainId === chainId }
|
|
310
|
-
});
|
|
311
|
-
const { data: image } = useQuery4({
|
|
312
|
-
queryKey: ["thurin-nft-avatar", tokenUri, nft?.tokenId.toString()],
|
|
313
|
-
queryFn: () => nftAvatarImage(tokenUri, nft.tokenId).catch(() => null),
|
|
314
|
-
enabled: typeof tokenUri === "string" && !!nft
|
|
315
|
-
});
|
|
316
|
-
return direct ?? image ?? null;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// src/hooks/useThurinIdentity.ts
|
|
320
|
-
function isAddress(value) {
|
|
321
|
-
return /^0x[0-9a-fA-F]{40}$/.test(value);
|
|
322
|
-
}
|
|
323
|
-
function safeNormalize(name) {
|
|
324
|
-
try {
|
|
325
|
-
return normalize(name);
|
|
326
|
-
} catch {
|
|
327
|
-
return void 0;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
function useThurinIdentity(ensOrAddress) {
|
|
331
|
-
const chain = chainFor(useIdentityKitConfig().network);
|
|
332
|
-
const isAddr = ensOrAddress ? isAddress(ensOrAddress) : false;
|
|
333
|
-
const ensInput = ensOrAddress && !isAddr ? safeNormalize(ensOrAddress) : void 0;
|
|
334
|
-
const { data: resolvedAddress, error: ensError, isFetched: ensFetched, refetch: refetchEns } = useEnsAddress({
|
|
335
|
-
name: ensInput,
|
|
336
|
-
chainId: chain.id,
|
|
337
|
-
query: { enabled: !!ensInput }
|
|
338
|
-
});
|
|
339
|
-
const address = isAddr ? ensOrAddress : resolvedAddress ?? null;
|
|
340
|
-
const { data: ensName } = useEnsName({
|
|
341
|
-
address,
|
|
342
|
-
chainId: chain.id,
|
|
343
|
-
query: { enabled: !!address }
|
|
344
|
-
});
|
|
345
|
-
const displayName = ensInput || ensName || null;
|
|
346
|
-
const ensAvatar = useSafeAvatar(displayName ? safeNormalize(displayName) : void 0, chain.id);
|
|
347
|
-
const {
|
|
348
|
-
claims,
|
|
349
|
-
totalClaims,
|
|
350
|
-
activeClaims,
|
|
351
|
-
currentFingerprint,
|
|
352
|
-
isLoading: claimsLoading,
|
|
353
|
-
error: claimsError,
|
|
354
|
-
refetch: refetchClaims
|
|
355
|
-
} = useAttestations(address);
|
|
356
|
-
const currentClaim = [...claims].reverse().find(
|
|
357
|
-
(c) => !c.revoked && c.verification?.verified && c.fingerprint === currentFingerprint
|
|
358
|
-
);
|
|
359
|
-
const {
|
|
360
|
-
keyInfo: pgpKeyInfo,
|
|
361
|
-
proofs,
|
|
362
|
-
isLoading: proofsLoading
|
|
363
|
-
} = usePGPProofs(currentFingerprint, currentClaim?.pgpPublicKey ?? null);
|
|
364
|
-
const { efp, isLoading: efpLoading } = useEFPGraph(address);
|
|
365
|
-
const lookup = { ensEmpty: !!ensInput && ensFetched && !resolvedAddress, ensFailed: !!ensError, claimsFailed: !!claimsError };
|
|
366
|
-
const probeNeeded = needsRpcProbe(lookup);
|
|
367
|
-
const probe = useBlockNumber({
|
|
368
|
-
chainId: chain.id,
|
|
369
|
-
scopeKey: `thurin-rpc-probe:${ensOrAddress ?? ""}`,
|
|
370
|
-
query: { enabled: probeNeeded, retry: 0, staleTime: 0, gcTime: 0 }
|
|
371
|
-
});
|
|
372
|
-
const rpcAnswered = !probeNeeded || probe.isFetching ? void 0 : probe.isSuccess ? true : probe.isError ? false : void 0;
|
|
373
|
-
const errorKind = identityErrorKind({ ...lookup, rpcAnswered });
|
|
374
|
-
const probing = probeNeeded && rpcAnswered === void 0;
|
|
375
|
-
const retry = () => {
|
|
376
|
-
if (ensInput) refetchEns();
|
|
377
|
-
refetchClaims();
|
|
378
|
-
if (probeNeeded) probe.refetch();
|
|
379
|
-
};
|
|
380
|
-
return {
|
|
381
|
-
address,
|
|
382
|
-
ensName: displayName,
|
|
383
|
-
ensAvatar,
|
|
384
|
-
claims,
|
|
385
|
-
totalClaims,
|
|
386
|
-
activeClaims,
|
|
387
|
-
currentFingerprint,
|
|
388
|
-
pgpKeyInfo,
|
|
389
|
-
proofs,
|
|
390
|
-
efp,
|
|
391
|
-
// "Not finished" counts as loading, including queries paused in a background tab: the card
|
|
392
|
-
// must not render defaults (zeros) for an identity it hasn't looked up yet.
|
|
393
|
-
isLoading: !!ensInput && !ensFetched || claimsLoading || proofsLoading || efpLoading || probing,
|
|
394
|
-
error: errorKind ? new Error(IDENTITY_ERROR_TEXT[errorKind]) : null,
|
|
395
|
-
errorKind,
|
|
396
|
-
retry
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// src/components/ThurinCard/ThurinCard.tsx
|
|
401
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
402
|
-
function ThurinLogo() {
|
|
403
|
-
return /* @__PURE__ */ jsxs("svg", { className: "thurin-card-avatar-placeholder", viewBox: "0 0 100 100", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
404
|
-
/* @__PURE__ */ jsx2("circle", { cx: "50", cy: "50", r: "50", fill: "var(--thurin-surface-deep)" }),
|
|
405
|
-
/* @__PURE__ */ jsx2("path", { d: "M25 80 Q25 25 50 25 Q75 25 75 50", fill: "none", stroke: "#7c9a3e", strokeWidth: "4", strokeLinecap: "round" }),
|
|
406
|
-
/* @__PURE__ */ jsx2("path", { d: "M33 75 Q33 35 50 35 Q67 35 67 52", fill: "none", stroke: "#7c9a3e", strokeWidth: "4", strokeLinecap: "round" }),
|
|
407
|
-
/* @__PURE__ */ jsx2("path", { d: "M41 70 Q41 45 50 45 Q59 45 59 55", fill: "none", stroke: "#c9a227", strokeWidth: "4", strokeLinecap: "round" }),
|
|
408
|
-
/* @__PURE__ */ jsx2("path", { d: "M50 65 L50 53", fill: "none", stroke: "#c9a227", strokeWidth: "4", strokeLinecap: "round" })
|
|
409
|
-
] });
|
|
410
|
-
}
|
|
411
|
-
function Avatar({ src, alt }) {
|
|
412
|
-
const [tries, setTries] = useState([]);
|
|
413
|
-
useEffect(() => {
|
|
414
|
-
setTries(src ? [src, ...avatarFallbacks(src)] : []);
|
|
415
|
-
}, [src]);
|
|
416
|
-
if (!tries.length) return /* @__PURE__ */ jsx2(ThurinLogo, {});
|
|
417
|
-
return /* @__PURE__ */ jsx2("img", { className: "thurin-card-avatar", src: tries[0], alt, onError: () => setTries((t) => t.slice(1)) });
|
|
418
|
-
}
|
|
419
|
-
function ThurinCard({ ens, address, theme = "thurin" }) {
|
|
420
|
-
const input = ens || address;
|
|
421
|
-
const identity = useThurinIdentity(input);
|
|
422
|
-
const config = useIdentityKitConfig();
|
|
423
|
-
const profileUrl = identity.address ? `${config.baseUrl}/eth/${identity.address}` : ens ? `${config.baseUrl}/ens/${ens}` : null;
|
|
424
|
-
if (identity.isLoading) {
|
|
425
|
-
return /* @__PURE__ */ jsx2("div", { className: "thurin-card", "data-thurin-theme": theme, children: /* @__PURE__ */ jsx2("div", { className: "thurin-card-loading", children: "Loading identity..." }) });
|
|
426
|
-
}
|
|
427
|
-
const displayAddress = identity.address || null;
|
|
428
|
-
if (identity.errorKind) {
|
|
429
|
-
return /* @__PURE__ */ jsxs("div", { className: "thurin-card", "data-thurin-theme": theme, children: [
|
|
430
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-header", children: [
|
|
431
|
-
/* @__PURE__ */ jsx2(ThurinLogo, {}),
|
|
432
|
-
/* @__PURE__ */ jsx2("div", { children: /* @__PURE__ */ jsx2("div", { className: "thurin-card-name", children: identity.ensName || ens || address }) })
|
|
433
|
-
] }),
|
|
434
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-error", role: "status", children: [
|
|
435
|
-
identity.error?.message,
|
|
436
|
-
identity.errorKind !== "not-found" && /* @__PURE__ */ jsx2("button", { type: "button", className: "thurin-card-retry", onClick: identity.retry, children: "Try again" })
|
|
437
|
-
] }),
|
|
438
|
-
profileUrl && identity.errorKind !== "not-found" && /* @__PURE__ */ jsx2("a", { className: "thurin-card-link", href: profileUrl, target: "_blank", rel: "noopener noreferrer", children: "View on Thurin" })
|
|
439
|
-
] });
|
|
440
|
-
}
|
|
441
|
-
const verifiedProofs = identity.proofs.filter((p) => p.status === "verified").length;
|
|
442
|
-
const hasVerifiedPgp = identity.claims.some((c) => c.verification?.verified && !c.revoked);
|
|
443
|
-
return /* @__PURE__ */ jsxs("div", { className: "thurin-card", "data-thurin-theme": theme, children: [
|
|
444
|
-
/* @__PURE__ */ jsxs("a", { className: "thurin-card-header", href: profileUrl || void 0, target: "_blank", rel: "noopener noreferrer", children: [
|
|
445
|
-
/* @__PURE__ */ jsx2(Avatar, { src: identity.ensAvatar, alt: identity.ensName || "" }),
|
|
446
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
447
|
-
identity.ensName && /* @__PURE__ */ jsx2("div", { className: "thurin-card-name", children: identity.ensName }),
|
|
448
|
-
displayAddress && /* @__PURE__ */ jsx2("div", { className: "thurin-card-address", children: displayAddress })
|
|
449
|
-
] })
|
|
450
|
-
] }),
|
|
451
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-stats", children: [
|
|
452
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-stat", children: [
|
|
453
|
-
/* @__PURE__ */ jsx2("span", { className: "thurin-card-stat-value", children: identity.activeClaims }),
|
|
454
|
-
/* @__PURE__ */ jsx2("span", { className: "thurin-card-stat-label", children: "Attestations" })
|
|
455
|
-
] }),
|
|
456
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-stat", children: [
|
|
457
|
-
/* @__PURE__ */ jsx2("span", { className: "thurin-card-stat-value", children: verifiedProofs }),
|
|
458
|
-
/* @__PURE__ */ jsx2("span", { className: "thurin-card-stat-label", children: "Proofs" })
|
|
459
|
-
] }),
|
|
460
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-stat", children: [
|
|
461
|
-
/* @__PURE__ */ jsx2("span", { className: "thurin-card-stat-value", children: identity.efp ? identity.efp.followers : "\u2013" }),
|
|
462
|
-
/* @__PURE__ */ jsx2("span", { className: "thurin-card-stat-label", children: "Followers" })
|
|
463
|
-
] })
|
|
464
|
-
] }),
|
|
465
|
-
/* @__PURE__ */ jsxs("div", { className: "thurin-card-badges", children: [
|
|
466
|
-
hasVerifiedPgp && /* @__PURE__ */ jsx2("span", { className: "thurin-card-badge thurin-card-badge--verified", children: "PGP Verified" }),
|
|
467
|
-
identity.efp?.hasEfp && /* @__PURE__ */ jsx2("span", { className: "thurin-card-badge thurin-card-badge--verified", children: "EFP" }),
|
|
468
|
-
identity.proofs.map((p, i) => /* @__PURE__ */ jsx2(
|
|
469
|
-
"span",
|
|
470
|
-
{
|
|
471
|
-
className: `thurin-card-badge thurin-card-badge--${p.status === "verified" ? "verified" : "unverified"}`,
|
|
472
|
-
children: p.label
|
|
473
|
-
},
|
|
474
|
-
i
|
|
475
|
-
))
|
|
476
|
-
] }),
|
|
477
|
-
profileUrl && /* @__PURE__ */ jsx2(
|
|
478
|
-
"a",
|
|
479
|
-
{
|
|
480
|
-
className: "thurin-card-link",
|
|
481
|
-
href: profileUrl,
|
|
482
|
-
target: "_blank",
|
|
483
|
-
rel: "noopener noreferrer",
|
|
484
|
-
children: "View on Thurin"
|
|
485
|
-
}
|
|
486
|
-
)
|
|
487
|
-
] });
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// src/hooks/useEnsHint.ts
|
|
491
|
-
import { useEnsText as useEnsText2 } from "wagmi";
|
|
492
|
-
import { normalize as normalize2 } from "viem/ens";
|
|
493
|
-
function safeNormalize2(name) {
|
|
494
|
-
try {
|
|
495
|
-
return normalize2(name);
|
|
496
|
-
} catch {
|
|
497
|
-
return void 0;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
function useEnsHint(name, verifiedFingerprint) {
|
|
501
|
-
const chain = chainFor(useIdentityKitConfig().network);
|
|
502
|
-
const ensName = name ? safeNormalize2(name) : void 0;
|
|
503
|
-
const { data, isLoading, refetch } = useEnsText2({
|
|
504
|
-
name: ensName,
|
|
505
|
-
key: ENS_HINT_KEY,
|
|
506
|
-
chainId: chain.id,
|
|
507
|
-
query: { enabled: !!ensName }
|
|
508
|
-
});
|
|
509
|
-
return { ...ensHintFor(data ?? null, verifiedFingerprint), isLoading: !!ensName && isLoading, refetch: () => {
|
|
510
|
-
void refetch();
|
|
511
|
-
} };
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// src/hooks/useRecords.ts
|
|
515
|
-
import { useReadContracts as useReadContracts2 } from "wagmi";
|
|
516
|
-
import { useQuery as useQuery5 } from "@tanstack/react-query";
|
|
517
|
-
function useRecords(address, index, kinds = IDENTITY_KINDS, armoredKey) {
|
|
518
|
-
const config = useIdentityKitConfig();
|
|
519
|
-
const registry = getRegistry(config.network, config.registryAddress);
|
|
520
|
-
const chain = chainFor(config.network);
|
|
521
|
-
const owner = address;
|
|
522
|
-
const enabled = !!owner && index !== void 0 && index !== null;
|
|
523
|
-
const contracts = enabled ? kinds.map((kind) => ({ address: registry.address, abi: REGISTRY_ABI, functionName: "record", args: [owner, BigInt(index), recordKind(kind)], chainId: chain.id })) : [];
|
|
524
|
-
const { data: raw, isLoading: readLoading, refetch } = useReadContracts2({ contracts, query: { enabled: contracts.length > 0 } });
|
|
525
|
-
const texts = (raw ?? []).map((r) => r.status === "success" ? decodeRecord(r.result) : "");
|
|
526
|
-
const { data: records, isLoading: parseLoading } = useQuery5({
|
|
527
|
-
queryKey: ["records", config.network, registry.address, address, index, kinds.join(","), texts.join(" "), armoredKey ?? ""],
|
|
528
|
-
queryFn: async () => {
|
|
529
|
-
const out = [];
|
|
530
|
-
for (let i = 0; i < kinds.length; i++) if (texts[i]) out.push(await parseRecord(kinds[i], texts[i], { armoredKey: armoredKey ?? void 0 }));
|
|
531
|
-
return out;
|
|
532
|
-
},
|
|
533
|
-
enabled: enabled && raw !== void 0
|
|
534
|
-
});
|
|
535
|
-
return { records: records ?? [], isLoading: enabled && (readLoading || parseLoading), refetch: () => {
|
|
536
|
-
void refetch();
|
|
537
|
-
} };
|
|
538
|
-
}
|
|
92
|
+
verifyProof,
|
|
93
|
+
verifyStatementSignature
|
|
94
|
+
} from "./chunk-SGAMXZDL.js";
|
|
539
95
|
export {
|
|
540
96
|
ARWEAVE_GATEWAY,
|
|
541
97
|
AUTHORIZATION_TYPES,
|
|
542
98
|
CLAIM_CHECK_LABEL,
|
|
99
|
+
CLAIM_LIMIT,
|
|
100
|
+
CONTRACT_ERROR_TEXT,
|
|
543
101
|
EIP712_NAME,
|
|
544
102
|
EIP712_VERSION,
|
|
545
103
|
ENS_HINT_KEY,
|
|
546
104
|
ENS_TEXT_RESOLVER_ABI,
|
|
547
105
|
FARCASTER_HUB,
|
|
548
|
-
IDENTITY_ERROR_TEXT,
|
|
549
|
-
IDENTITY_KINDS,
|
|
550
106
|
IPFS_GATEWAY,
|
|
551
107
|
IPFS_GATEWAYS,
|
|
552
|
-
IdentityKitProvider,
|
|
553
108
|
KNOWN_KINDS,
|
|
109
|
+
MAX_KIND_BYTES,
|
|
554
110
|
MAX_RECORD_BYTES,
|
|
555
111
|
NETWORKS,
|
|
556
112
|
NFT_AVATAR_ABI,
|
|
113
|
+
OWNER_REVOKE_REASONS,
|
|
557
114
|
REGISTRY_ABI,
|
|
558
115
|
REGISTRY_ADDRESS,
|
|
559
|
-
|
|
560
|
-
|
|
116
|
+
REVOKE_REASONS,
|
|
117
|
+
addRelease,
|
|
561
118
|
attestTypedData,
|
|
562
119
|
authorizationDigest,
|
|
563
120
|
avatarFallbacks,
|
|
564
121
|
avatarUrl,
|
|
565
122
|
bytesToFingerprint,
|
|
566
123
|
chainFor,
|
|
124
|
+
checkKindName,
|
|
125
|
+
checkRecordValue,
|
|
567
126
|
claimCheckText,
|
|
568
127
|
claimFateText,
|
|
569
128
|
claimFates,
|
|
570
|
-
|
|
129
|
+
claimSignature,
|
|
130
|
+
contractErrorName,
|
|
131
|
+
contractErrorText,
|
|
571
132
|
displayUrl,
|
|
572
|
-
|
|
133
|
+
encryptRefusalText,
|
|
134
|
+
encryptTo,
|
|
135
|
+
encryptionKeyFor,
|
|
573
136
|
ensHintFor,
|
|
574
137
|
ensHintValue,
|
|
575
138
|
ensHintWrite,
|
|
576
139
|
expiresSoon,
|
|
577
140
|
expiresSoonText,
|
|
578
|
-
fetchEFPGraph,
|
|
579
141
|
fetchEnsHint,
|
|
580
142
|
fetchRecords,
|
|
143
|
+
findOwners,
|
|
581
144
|
fingerprintHash,
|
|
582
145
|
fingerprintToBytes,
|
|
583
146
|
formatClaimDate,
|
|
584
147
|
getRegistry,
|
|
585
148
|
hasEmailUserID,
|
|
586
149
|
identifyProof,
|
|
587
|
-
identityErrorKind,
|
|
588
150
|
isNetworkName,
|
|
151
|
+
keyChangedText,
|
|
589
152
|
keyIdOf,
|
|
590
153
|
keyIdToBytes,
|
|
154
|
+
keyProblemText,
|
|
155
|
+
keyStanding,
|
|
591
156
|
kindName,
|
|
592
|
-
|
|
157
|
+
leanKey,
|
|
158
|
+
markCompromisedTypedData,
|
|
593
159
|
nftAvatarImage,
|
|
594
160
|
normalizeFingerprint,
|
|
161
|
+
pageRecords,
|
|
595
162
|
parseNftAvatar,
|
|
596
163
|
parsePgpKey,
|
|
597
|
-
parsePointer,
|
|
598
164
|
parseRecord,
|
|
165
|
+
parseReleases,
|
|
166
|
+
payloadText,
|
|
167
|
+
permissionSigned,
|
|
168
|
+
pickRecords,
|
|
599
169
|
proofHref,
|
|
600
170
|
proofSecondaryHref,
|
|
171
|
+
readClaims,
|
|
601
172
|
reattestTypedData,
|
|
602
173
|
recordKind,
|
|
603
174
|
registryDomain,
|
|
604
|
-
|
|
175
|
+
renderReleases,
|
|
605
176
|
revokeTypedData,
|
|
177
|
+
sameFingerprint,
|
|
606
178
|
setRecordTypedData,
|
|
179
|
+
signatureEmail,
|
|
180
|
+
sshKeys,
|
|
181
|
+
statementText,
|
|
607
182
|
stripEmailUserIDs,
|
|
608
183
|
updateKeyTypedData,
|
|
609
|
-
useAttestations,
|
|
610
|
-
useEFPGraph,
|
|
611
|
-
useEnsHint,
|
|
612
|
-
usePGPProofs,
|
|
613
|
-
useRecords,
|
|
614
|
-
useSafeAvatar,
|
|
615
|
-
useThurinIdentity,
|
|
616
184
|
verifyAttestation,
|
|
617
185
|
verifyClearsigned,
|
|
618
|
-
verifyProof
|
|
186
|
+
verifyProof,
|
|
187
|
+
verifyStatementSignature
|
|
619
188
|
};
|
|
620
|
-
//# sourceMappingURL=index.js.map
|