@thurinlabs/identity-kit 0.7.3 → 0.7.5

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 CHANGED
@@ -184,11 +184,14 @@ Hooks-only consumers don't need to import styles.
184
184
 
185
185
  ## Embed (No React Required)
186
186
 
187
- For static sites, Jekyll blogs, WordPress, or any HTML page — use the standalone embed script. No React, no bundler, no config.
187
+ For static sites, Jekyll blogs, WordPress, or any HTML page — use the standalone embed script. Everything runs client-side; there's no Thurin backend in the path.
188
188
 
189
189
  ```html
190
- <div data-scry-card="bendoubleu.eth" data-theme="thurin"></div>
191
- <div data-scry-card="0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" data-theme="dark"></div>
190
+ <div
191
+ data-scry-card="bendoubleu.eth"
192
+ data-theme="thurin"
193
+ data-rpc-url="https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
194
+ ></div>
192
195
 
193
196
  <script src="https://cdn.jsdelivr.net/npm/@thurinlabs/identity-kit/dist/embed.global.js"></script>
194
197
  ```
@@ -197,8 +200,10 @@ For static sites, Jekyll blogs, WordPress, or any HTML page — use the standalo
197
200
  |-----------|-------------|
198
201
  | `data-scry-card` | ENS name or ETH address to look up (required) |
199
202
  | `data-theme` | `thurin`, `dark`, or `light` (default: `thurin`) |
203
+ | `data-rpc-url` | An Ethereum RPC that supports `eth_getLogs` — required to verify on-chain claims. The card reads the chain directly, so use your own node or any provider. (Public fallback RPCs throttle `getLogs`.) |
204
+ | `data-neynar-key` | Optional. A Neynar API key, only to verify Farcaster proofs. Without it, Farcaster shows as unverified. |
200
205
 
201
- The script bundles everything (React, wagmi, viem) internally. Cards render automatically on page load and for dynamically added elements.
206
+ The card talks directly to Ethereum, keys.openpgp.org, and each proof platform — no intermediary. Cards render automatically on page load and for dynamically added elements.
202
207
 
203
208
  ## Supported Proof Providers
204
209
 
@@ -39380,9 +39380,8 @@ ${prettyStateOverride(stateOverride)}`;
39380
39380
  const name = typeof n2.name === "string" ? n2.name : new TextDecoder().decode(n2.name);
39381
39381
  const value = n2.value instanceof Uint8Array ? new TextDecoder().decode(n2.value) : typeof n2.value === "string" ? n2.value : null;
39382
39382
  if (value) {
39383
- const dedupeKey = `${name}:${value}`;
39384
- if (!seen.has(dedupeKey)) {
39385
- seen.add(dedupeKey);
39383
+ if (!seen.has(value)) {
39384
+ seen.add(value);
39386
39385
  notations.push({ name, value });
39387
39386
  }
39388
39387
  }
@@ -39528,7 +39527,8 @@ ${prettyStateOverride(stateOverride)}`;
39528
39527
  enabled: !!attestations && attestations.length > 0,
39529
39528
  staleTime: 3e5
39530
39529
  });
39531
- const isLoading = countLoading || attestationsLoading || verifyLoading;
39530
+ const eventLogsPending = !!address && attestationCount > 0 && eventData === void 0;
39531
+ const isLoading = countLoading || attestationsLoading || verifyLoading || eventLogsPending;
39532
39532
  const activeClaims = (claims || []).filter((c2) => !c2.revoked);
39533
39533
  const verifiedClaims = activeClaims.filter((c2) => c2.verification?.verified);
39534
39534
  const currentFingerprint = verifiedClaims.length > 0 ? verifiedClaims[verifiedClaims.length - 1].fingerprint : null;
@@ -39620,9 +39620,8 @@ ${prettyStateOverride(stateOverride)}`;
39620
39620
  parse: (m2) => ({ instance: m2[1], user: m2[2] })
39621
39621
  }
39622
39622
  ];
39623
- var PROOF_NAMESPACES = /* @__PURE__ */ new Set(["proof@thurin.id", "proof@ariadne.id"]);
39624
39623
  function identifyProof(notation) {
39625
- if (!PROOF_NAMESPACES.has(notation.name)) return null;
39624
+ if (notation.name !== "proof@thurin.id") return null;
39626
39625
  for (const { provider, label, pattern, parse } of PROVIDERS) {
39627
39626
  const m2 = notation.value.match(pattern);
39628
39627
  if (m2) {
@@ -39798,7 +39797,7 @@ ${prettyStateOverride(stateOverride)}`;
39798
39797
  // src/hooks/usePGPProofs.ts
39799
39798
  function usePGPProofs(fingerprint) {
39800
39799
  const config = useIdentityKitConfig();
39801
- const { data, isLoading } = useQuery({
39800
+ const { data } = useQuery({
39802
39801
  queryKey: ["pgp-proofs", fingerprint],
39803
39802
  queryFn: async () => {
39804
39803
  if (!fingerprint) return { keyInfo: null, proofs: [] };
@@ -39806,7 +39805,7 @@ ${prettyStateOverride(stateOverride)}`;
39806
39805
  if (!armoredKey) return { keyInfo: null, proofs: [] };
39807
39806
  const keyInfo = await parsePgpKey(armoredKey);
39808
39807
  if (!keyInfo) return { keyInfo: null, proofs: [] };
39809
- const identified = keyInfo.notations.map((n2) => identifyProof(n2)).filter((p2) => p2 !== null);
39808
+ const identified = keyInfo.notations.map((n2) => identifyProof(n2)).filter((p2) => p2 !== null && p2.provider !== "unknown");
39810
39809
  const proofs = await Promise.all(
39811
39810
  identified.map(async (proof) => {
39812
39811
  const result = await verifyProof(proof, fingerprint, config.neynarApiKey);
@@ -39822,7 +39821,15 @@ ${prettyStateOverride(stateOverride)}`;
39822
39821
  };
39823
39822
  })
39824
39823
  );
39825
- return { keyInfo, proofs };
39824
+ const byAccount = /* @__PURE__ */ new Map();
39825
+ for (const p2 of proofs) {
39826
+ const key = `${p2.provider}:${p2.displayUrl}`;
39827
+ const prev = byAccount.get(key);
39828
+ if (!prev || p2.status === "verified" && prev.status !== "verified") {
39829
+ byAccount.set(key, p2);
39830
+ }
39831
+ }
39832
+ return { keyInfo, proofs: [...byAccount.values()] };
39826
39833
  },
39827
39834
  enabled: !!fingerprint,
39828
39835
  staleTime: 3e5
@@ -39830,7 +39837,11 @@ ${prettyStateOverride(stateOverride)}`;
39830
39837
  return {
39831
39838
  keyInfo: data?.keyInfo ?? null,
39832
39839
  proofs: data?.proofs ?? [],
39833
- isLoading
39840
+ // Report loading whenever a fingerprint is set but its proofs haven't
39841
+ // resolved yet. Using react-query's own isLoading leaves a gap while the
39842
+ // query is enabling (fingerprint just became known), during which the card
39843
+ // would briefly paint without proof badges and then pop them in.
39844
+ isLoading: !!fingerprint && data === void 0
39834
39845
  };
39835
39846
  }
39836
39847
 
@@ -39990,6 +40001,8 @@ ${prettyStateOverride(stateOverride)}`;
39990
40001
  el2.dataset.scryRendered = "true";
39991
40002
  const value = el2.dataset.scryCard;
39992
40003
  const theme = el2.dataset.theme || "thurin";
40004
+ const rpcUrl = el2.dataset.rpcUrl;
40005
+ const neynarApiKey = el2.dataset.neynarKey;
39993
40006
  const props = isAddress3(value) ? { address: value } : { ens: value };
39994
40007
  const shadow = el2.attachShadow({ mode: "open" });
39995
40008
  const style = document.createElement("style");
@@ -39999,7 +40012,7 @@ ${prettyStateOverride(stateOverride)}`;
39999
40012
  shadow.appendChild(container);
40000
40013
  const root = (0, import_client.createRoot)(container);
40001
40014
  root.render(
40002
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IdentityKitProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScryCard, { ...props, theme }) })
40015
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(IdentityKitProvider, { rpcUrl, neynarApiKey, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScryCard, { ...props, theme }) })
40003
40016
  );
40004
40017
  });
40005
40018
  }