UNPKG

@ledgerhq/domain-service

Version:
124 lines 4.83 kB
import React, { createContext, useContext, useEffect, useMemo, useState } from "react"; import { resolveAddress, resolveDomain } from "../resolvers"; import { getRegistriesForAddress } from "../registries"; import { getRegistriesForDomain } from "../registries"; import { validateDomain } from "../utils"; import { isOutdated } from "./logic"; import { DomainEmpty, InvalidDomain, NoResolution, UnsupportedDomainOrAddress } from "../errors"; const DomainServiceContext = createContext({ cache: {}, loadDomainServiceAPI: () => Promise.resolve(), clearCache: /* istanbul ignore next: don't test default state because it's gonna be overriden */ () => { }, }); export const useDomain = (addressOrDomain, registry) => { const [state, setState] = useState({ status: "queued" }); const addressOrDomainLC = addressOrDomain.toLowerCase(); const { cache, loadDomainServiceAPI } = useContext(DomainServiceContext); const cachedData = addressOrDomain && cache[addressOrDomainLC]; useEffect(() => { (async () => { // serve data from the context API if (cachedData && !isOutdated(cachedData)) return; // no input if (!addressOrDomainLC) { setState({ status: "error", error: new DomainEmpty(), updatedAt: Date.now(), }); return; } // checking if any registry is compatible with the provided string const [forwardRegistries, reverseRegistries] = await Promise.all([ getRegistriesForDomain(addressOrDomainLC), getRegistriesForAddress(addressOrDomainLC), ]); // if no registry is found at all if (!forwardRegistries.length && !reverseRegistries.length) { setState({ status: "error", error: new UnsupportedDomainOrAddress(), updatedAt: Date.now(), }); return; } // if it's a domain but the domain is not respecting our security rules if (forwardRegistries.length && !validateDomain(addressOrDomainLC)) { setState({ status: "error", error: new InvalidDomain(), updatedAt: Date.now(), }); return; } // otherwise let the resolution happen by the backend await loadDomainServiceAPI(addressOrDomainLC, registry); })(); }, [loadDomainServiceAPI, addressOrDomainLC, cachedData]); if (cachedData) { return cachedData; } return state; }; export function DomainServiceProvider({ children, }) { const [state, setState] = useState({ cache: {}, }); const api = useMemo(() => ({ loadDomainServiceAPI: async (addressOrDomain, registry) => { setState(oldState => ({ ...oldState, cache: { ...oldState.cache, [addressOrDomain]: { status: "loading", }, }, })); const resolutions = await Promise.all([ resolveDomain(addressOrDomain, registry), resolveAddress(addressOrDomain, registry), ]) .then(res => res.flat()) .catch((e) => e); const newEntry = (() => { if (Array.isArray(resolutions)) { return resolutions.length ? { status: "loaded", resolutions, updatedAt: Date.now(), } : { status: "error", error: new NoResolution(`No resolution found for ${addressOrDomain}`), updatedAt: Date.now(), }; } return { status: "error", error: resolutions, updatedAt: Date.now(), }; })(); setState(oldState => ({ ...oldState, cache: { ...oldState.cache, [addressOrDomain]: newEntry, }, })); }, clearCache: () => { setState(oldState => ({ ...oldState, cache: {}, })); }, }), []); const value = { ...state, ...api }; return React.createElement(DomainServiceContext.Provider, { value: value }, children); } //# sourceMappingURL=index.js.map