refactor: add api client to upend.js
parent
3fd29a962e
commit
3956856c6f
|
@ -0,0 +1,177 @@
|
|||
import LRU from "lru-cache";
|
||||
import { UpListing, UpObject } from ".";
|
||||
import type {
|
||||
Address,
|
||||
AttributeListingResult,
|
||||
EntityListing,
|
||||
IJob,
|
||||
IValue,
|
||||
ListingResult,
|
||||
PutInput,
|
||||
PutResult,
|
||||
StoreInfo,
|
||||
VaultInfo,
|
||||
} from "./types";
|
||||
|
||||
export class UpEndApi {
|
||||
private instanceUrl = "";
|
||||
|
||||
private queryOnceLRU = new LRU<string, UpListing>({ max: 128 });
|
||||
private inFlightRequests: { [key: string]: Promise<UpListing> | null } = {};
|
||||
|
||||
constructor(instanceUrl = "") {
|
||||
this.setInstanceUrl(instanceUrl);
|
||||
}
|
||||
|
||||
public setInstanceUrl(apiUrl: string) {
|
||||
this.instanceUrl = apiUrl.replace(/\/+$/g, "");
|
||||
}
|
||||
|
||||
private get apiUrl() {
|
||||
return this.instanceUrl + "/api";
|
||||
}
|
||||
|
||||
public async fetchEntity(address: string): Promise<UpObject> {
|
||||
const entityFetch = await fetch(`${this.apiUrl}/obj/${address}`);
|
||||
const entityResult = (await entityFetch.json()) as EntityListing;
|
||||
const entityListing = new UpListing(entityResult.entries);
|
||||
return entityListing.getObject(address);
|
||||
}
|
||||
|
||||
public async fetchEntry(address: string) {
|
||||
const response = await fetch(`${this.apiUrl}/raw/${address}`);
|
||||
const data = await response.json();
|
||||
const listing = new UpListing({ address: data });
|
||||
return listing.entries[0];
|
||||
}
|
||||
|
||||
public async query(query: string): Promise<UpListing> {
|
||||
const cacheResult = this.queryOnceLRU.get(query);
|
||||
if (!cacheResult) {
|
||||
if (!this.inFlightRequests[query]) {
|
||||
console.debug(`Querying: ${query}`);
|
||||
this.inFlightRequests[query] = new Promise((resolve, reject) => {
|
||||
fetch(`${this.apiUrl}/query`, {
|
||||
method: "POST",
|
||||
body: query,
|
||||
keepalive: true,
|
||||
})
|
||||
.then(async (response) => {
|
||||
resolve(new UpListing(await response.json()));
|
||||
this.inFlightRequests[query] = null;
|
||||
})
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
} else {
|
||||
console.debug(`Chaining request for ${query}...`);
|
||||
}
|
||||
return await (this.inFlightRequests[query] as Promise<UpListing>); // TODO?
|
||||
} else {
|
||||
console.debug(`Returning cached: ${query}`);
|
||||
return cacheResult;
|
||||
}
|
||||
}
|
||||
|
||||
public async putEntry(input: PutInput): Promise<PutResult> {
|
||||
const response = await fetch(`${this.apiUrl}/obj`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async putEntityAttribute(
|
||||
entity: Address,
|
||||
attribute: string,
|
||||
value: IValue
|
||||
): Promise<Address> {
|
||||
const response = await fetch(`${this.apiUrl}/obj/${entity}/${attribute}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(value),
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async uploadFile(file: File): Promise<PutResult> {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/blob`, {
|
||||
method: "PUT",
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw Error(await response.text());
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async deleteEntry(address: Address): Promise<void> {
|
||||
await fetch(`${this.apiUrl}/obj/${address}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
public async getRaw(address: Address, preview = false) {
|
||||
return await fetch(
|
||||
`${this.apiUrl}/${preview ? "thumb" : "raw"}/${address}`
|
||||
);
|
||||
}
|
||||
|
||||
public async refreshVault() {
|
||||
return await fetch(`${this.apiUrl}/refresh`, { method: "POST" });
|
||||
}
|
||||
|
||||
public async nativeOpen(address: Address) {
|
||||
return fetch(`${this.apiUrl}/raw/${address}?native=1`);
|
||||
}
|
||||
|
||||
public async fetchRoots(): Promise<ListingResult> {
|
||||
const response = await fetch(`${this.apiUrl}/hier_roots`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async fetchJobs(): Promise<IJob[]> {
|
||||
const response = await fetch(`${this.apiUrl}/jobs`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async fetchAllAttributes(): Promise<AttributeListingResult> {
|
||||
const response = await fetch(`${this.apiUrl}/all/attributes`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async fetchInfo(): Promise<VaultInfo> {
|
||||
const response = await fetch(`${this.apiUrl}/info`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async fetchStoreInfo(): Promise<{ [key: string]: StoreInfo }> {
|
||||
const response = await fetch(`${this.apiUrl}/store`);
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
public async getAddress(
|
||||
input: { attribute: string } | { url: string } | { urlContent: string }
|
||||
): Promise<string> {
|
||||
let response;
|
||||
if ("attribute" in input) {
|
||||
response = await fetch(
|
||||
`${this.apiUrl}/address?attribute=${input.attribute}`
|
||||
);
|
||||
} else if ("url" in input) {
|
||||
response = await fetch(`${this.apiUrl}/address?url=${input.url}`);
|
||||
} else if ("urlContent" in input) {
|
||||
response = await fetch(
|
||||
`${this.apiUrl}/address?url_content=${input.urlContent}`
|
||||
);
|
||||
} else {
|
||||
throw new Error("Input cannot be empty.");
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
}
|
|
@ -16,5 +16,8 @@
|
|||
"eslint": "^8.7.0",
|
||||
"typescript": "^4.4.4"
|
||||
},
|
||||
"packageManager": "yarn@3.1.1"
|
||||
"packageManager": "yarn@3.1.1",
|
||||
"dependencies": {
|
||||
"lru-cache": "^7.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
/* Language and Environment */
|
||||
"target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
"lib": ["es2019"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
"lib": ["es2019", "DOM"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
|
|
|
@ -2281,6 +2281,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^7.0.0":
|
||||
version: 7.18.3
|
||||
resolution: "lru-cache@npm:7.18.3"
|
||||
checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"make-dir@npm:^3.0.0":
|
||||
version: 3.1.0
|
||||
resolution: "make-dir@npm:3.1.0"
|
||||
|
@ -3593,6 +3600,7 @@ __metadata:
|
|||
"@typescript-eslint/parser": latest
|
||||
ava: ^3.15.0
|
||||
eslint: ^8.7.0
|
||||
lru-cache: ^7.0.0
|
||||
typescript: ^4.4.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"svelte": "^3.55.0",
|
||||
"svelte-preprocess": "^5.0.3",
|
||||
"typescript": "^4.9.4",
|
||||
"upend": "../tools/upend_js/",
|
||||
"upend": "../tools/upend_js",
|
||||
"vite": "^4.0.3",
|
||||
"vite-plugin-static-copy": "^0.15.0",
|
||||
"web-ext": "^7.6.2"
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<script lang="ts">
|
||||
import browser from "webextension-polyfill";
|
||||
import type { EntityListing, VaultInfo } from "upend/types";
|
||||
import { UpEndApi } from "upend/api";
|
||||
import { cleanInstanceUrl, instanceUrlStore } from "./common";
|
||||
import { onMount } from "svelte";
|
||||
import "./main.scss";
|
||||
|
||||
const api = new UpEndApi("http://localhost:8093");
|
||||
|
||||
let opening = false;
|
||||
let openError: string | undefined;
|
||||
|
||||
|
@ -22,10 +24,7 @@
|
|||
instanceVersionError = undefined;
|
||||
|
||||
try {
|
||||
const vaultInfo = (await (
|
||||
await fetch(`${$cleanInstanceUrl}/api/info`)
|
||||
).json()) as VaultInfo;
|
||||
|
||||
const vaultInfo = await api.fetchInfo();
|
||||
instanceVersion = vaultInfo.version;
|
||||
} catch (err: unknown) {
|
||||
instanceVersionError = processError(err);
|
||||
|
@ -55,19 +54,17 @@
|
|||
}
|
||||
|
||||
async function openAsUrl() {
|
||||
open("url");
|
||||
open({ url: currentUrl });
|
||||
}
|
||||
|
||||
async function openContent() {
|
||||
open("url_content");
|
||||
open({ urlContent: currentUrl });
|
||||
}
|
||||
|
||||
async function open(key: string) {
|
||||
async function open(input: { url?: string; urlContent?: string }) {
|
||||
opening = true;
|
||||
try {
|
||||
const address = (await (
|
||||
await fetch(`${$cleanInstanceUrl}/api/address?${key}=${currentUrl}`)
|
||||
).json()) as string;
|
||||
const address = await api.getAddress(input);
|
||||
|
||||
// const obj = (await (
|
||||
// await fetch(`${$cleanInstanceUrl}/api/obj/${address}`)
|
||||
|
|
|
@ -2533,6 +2533,11 @@ lru-cache@^6.0.0:
|
|||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
lru-cache@^7.0.0:
|
||||
version "7.18.3"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
|
||||
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
|
||||
|
||||
lru-cache@^9.1.1:
|
||||
version "9.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.1.tgz#c58a93de58630b688de39ad04ef02ef26f1902f1"
|
||||
|
@ -4111,8 +4116,15 @@ update-notifier@6.0.2:
|
|||
semver-diff "^4.0.0"
|
||||
xdg-basedir "^5.1.0"
|
||||
|
||||
upend@../tools/upend_js:
|
||||
version "0.0.1"
|
||||
dependencies:
|
||||
lru-cache "^7.0.0"
|
||||
|
||||
upend@../tools/upend_js/:
|
||||
version "0.0.1"
|
||||
dependencies:
|
||||
lru-cache "^7.0.0"
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
|
|
|
@ -10,8 +10,8 @@ import type {
|
|||
VaultInfo,
|
||||
StoreInfo,
|
||||
AttributeListingResult,
|
||||
EntityListing,
|
||||
} from "upend/types";
|
||||
import type { EntityListing } from "./entity";
|
||||
|
||||
export const API_URL = "api";
|
||||
|
||||
|
|
|
@ -8884,6 +8884,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^7.0.0":
|
||||
version: 7.18.3
|
||||
resolution: "lru-cache@npm:7.18.3"
|
||||
checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lz-string@npm:^1.4.4":
|
||||
version: 1.4.4
|
||||
resolution: "lz-string@npm:1.4.4"
|
||||
|
@ -12560,8 +12567,10 @@ __metadata:
|
|||
|
||||
"upend@file:../tools/upend_js::locator=upend-kestrel%40workspace%3A.":
|
||||
version: 0.0.1
|
||||
resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=9eb5fd&locator=upend-kestrel%40workspace%3A."
|
||||
checksum: 03e1fe88abd8f6963e450e820c3d8a0b231aebdbe8e18c04d212adb6f3c3b820bf805705a9cc5d9643667257b94cd2c0a7a723fe547965f50496eaccb0b6e9e9
|
||||
resolution: "upend@file:../tools/upend_js#../tools/upend_js::hash=20d186&locator=upend-kestrel%40workspace%3A."
|
||||
dependencies:
|
||||
lru-cache: ^7.0.0
|
||||
checksum: 0ea49df94876cfe7ffacf3c3c7342d71fdbdcc0326d6aa4c4ce7d1b8a6a14648357e3cf15adeb1c6ad8b5e65c7dce76c312296e16763dd79fc50c2a11907eae6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Reference in New Issue