@ledgerhq/domain-service
Version:
Ledger service responsible for domain handling
124 lines • 4.83 kB
JavaScript
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