UNPKG

3.87 kBJavaScriptView Raw
1import * as check from "./fs/types/check.js";
2import * as debug from "./common/debug.js";
3import * as did from "./did/index.js";
4import * as dns from "./dns/index.js";
5import * as ucan from "./ucan/index.js";
6import { api } from "./common/index.js";
7import { setup } from "./setup/internal.js";
8/**
9 * CID representing an empty string. We use to to speed up DNS propagation
10 * However, we treat that as a null value in the code
11 */
12const EMPTY_CID = 'Qmc5m94Gu7z62RC8waSKkZUrCCBJPyHbkpmGzEePxy2oXJ';
13/**
14 * Get the CID of a user's data root.
15 * First check Fission server, then check DNS
16 *
17 * @param username The username of the user that we want to get the data root of.
18 */
19export async function lookup(username) {
20 const maybeRoot = await lookupOnFisson(username);
21 if (maybeRoot === EMPTY_CID)
22 return null;
23 if (maybeRoot !== null)
24 return maybeRoot;
25 try {
26 const cid = await dns.lookupDnsLink(username + '.files.' + setup.endpoints.user);
27 return cid === EMPTY_CID ? null : cid;
28 }
29 catch (err) {
30 console.error(err);
31 throw new Error('Could not locate user root in dns');
32 }
33}
34/**
35 * Get the CID of a user's data root from the Fission server.
36 *
37 * @param username The username of the user that we want to get the data root of.
38 */
39export async function lookupOnFisson(username) {
40 try {
41 const resp = await fetch(`${setup.endpoints.api}/user/data/${username}`, { cache: 'reload' } // don't use cache
42 );
43 const cid = await resp.json();
44 if (!check.isCID(cid)) {
45 throw new Error("Did not receive a CID");
46 }
47 return cid;
48 }
49 catch (err) {
50 debug.log('Could not locate user root on Fission server: ', err.toString());
51 return null;
52 }
53}
54/**
55 * Update a user's data root.
56 *
57 * @param cid The CID of the data root.
58 * @param proof The proof to use in the UCAN sent to the API.
59 */
60export async function update(cid, proof) {
61 const apiEndpoint = setup.endpoints.api;
62 // Debug
63 debug.log("🌊 Updating your DNSLink:", cid);
64 // Make API call
65 return await fetchWithRetry(`${apiEndpoint}/user/data/${cid}`, {
66 headers: async () => {
67 const jwt = ucan.encode(await ucan.build({
68 audience: await api.did(),
69 issuer: await did.ucan(),
70 potency: "APPEND",
71 proof,
72 // TODO: Waiting on API change.
73 // Should be `username.fission.name/*`
74 resource: ucan.decode(proof).payload.rsc
75 }));
76 return { 'authorization': `Bearer ${jwt}` };
77 },
78 retries: 100,
79 retryDelay: 5000,
80 retryOn: [502, 503, 504],
81 }, {
82 method: 'PATCH'
83 }).then((response) => {
84 if (response.status < 300)
85 debug.log("🪴 DNSLink updated:", cid);
86 else
87 debug.log("🔥 Failed to update DNSLink for:", cid);
88 return { success: response.status < 300 };
89 }).catch(err => {
90 debug.log("🔥 Failed to update DNSLink for:", cid);
91 console.error(err);
92 return { success: false };
93 });
94}
95async function fetchWithRetry(url, retryOptions, fetchOptions, retry = 0) {
96 const headers = await retryOptions.headers();
97 const response = await fetch(url, {
98 ...fetchOptions,
99 headers: { ...fetchOptions.headers, ...headers }
100 });
101 if (retryOptions.retryOn.includes(response.status)) {
102 if (retry < retryOptions.retries) {
103 return await new Promise((resolve, reject) => setTimeout(() => fetchWithRetry(url, retryOptions, fetchOptions, retry + 1).then(resolve, reject), retryOptions.retryDelay));
104 }
105 else {
106 throw new Error("Too many retries for fetch");
107 }
108 }
109 return response;
110}
111//# sourceMappingURL=data-root.js.map
\No newline at end of file