Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPFS: Attach files and images in the chat #628

Merged
merged 130 commits into from
Jan 9, 2025
Merged
Changes from 1 commit
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
0b4628f
feat: preview image
juliahermak Mar 28, 2024
a255a60
fix: delete img and scroll element
juliahermak Mar 30, 2024
67bbc12
feat: image modal
juliahermak Apr 6, 2024
151c74f
fix: images in chat grid css
juliahermak Apr 9, 2024
d2c6031
fix: icon file in chat preview
juliahermak Apr 10, 2024
cb40c0d
fix: classes names
juliahermak Apr 10, 2024
cc1fcc3
fix: styles, max files, new component upload file
juliahermak Apr 17, 2024
3e0b5a0
fix: upload a file and photo with a limited selection
juliahermak Apr 17, 2024
be7f839
feat(AChatAttachment): basic logic for interaction with Helia nodes. …
RealGoodProgrammer Apr 19, 2024
fb81a5c
feat(normalizeMessage): reply with image. Work in progress
RealGoodProgrammer Apr 19, 2024
042b201
feat(QuotedMessage): rewritten to TS. Ready to interact with attachme…
RealGoodProgrammer Apr 20, 2024
172141d
fix(services): build fix. Work in progress
RealGoodProgrammer Apr 20, 2024
660352a
chore(services): cleanup
RealGoodProgrammer Apr 20, 2024
b4bc311
Merge pull request #617 from Adamant-im/feat/user-interface-upload-file
juliahermak Apr 20, 2024
5ec4a53
fix(chat): fix file transaction normalization
bludnic Apr 21, 2024
5fa189a
refactor(QuotedMessage): simplify code
bludnic Apr 21, 2024
15e00f3
refactor(AChatAttachment): use AChatMessage as a template
bludnic Apr 21, 2024
6492414
chore(nodes): preparation for IPFS infoService health check
RealGoodProgrammer Apr 23, 2024
d801998
fix: number of files in chat preview and quoted message
juliahermak Apr 25, 2024
1eb3e78
feat(IpfsNodesTable): table on a new tab (work in progress)
RealGoodProgrammer Apr 28, 2024
03f6816
Merge remote-tracking branch 'refs/remotes/origin/feat/user-interface…
RealGoodProgrammer Apr 28, 2024
e220b4f
Merge remote-tracking branch 'refs/remotes/origin/dev' into feat/info…
RealGoodProgrammer May 2, 2024
321298e
feat(AChatAttachment): download and upload files (work in progress)
RealGoodProgrammer May 2, 2024
e4ce4b6
Merge branch 'refs/heads/dev' into Feat/user-interface-file-in-chat
bludnic May 2, 2024
6c7f7d2
Merge branch 'refs/heads/feat/user-interface-file-in-chat' into feat/…
RealGoodProgrammer May 3, 2024
b29ebd2
Merge pull request #625 from Adamant-im/feat/download_and_upload_files
bludnic May 6, 2024
47c550a
Merge branch 'refs/heads/dev' into feat/ipfs
bludnic May 7, 2024
97d13b3
chore: regenerate `adamant-wallets`
bludnic May 7, 2024
584f97e
fix(healtcheck): fix IPFS service path
bludnic May 7, 2024
a2f5bac
fix(nodes, storage): fix undefined error
bludnic May 7, 2024
4b4d8a4
feat(IpfsNodesTableItem): rewritten healthcheck (work in progress)
RealGoodProgrammer May 14, 2024
abfea27
Merge remote-tracking branch 'refs/remotes/origin/dev' into feat/ipfs
RealGoodProgrammer May 14, 2024
05f2f57
fix(AChatAttachment): the AIP changed
bludnic May 20, 2024
bcd7578
fix: photo display in chat and image modal
juliahermak May 27, 2024
95a6cc9
refactor: remove legacy README.md
bludnic Jun 3, 2024
3af78a5
Update src/components/nodes/ipfs/IpfsNodesTable.vue
RealGoodProgrammer Jul 13, 2024
84eafb5
Merge branch 'refs/heads/dev' into feat/ipfs
RealGoodProgrammer Jul 19, 2024
2c5da6a
Merge remote-tracking branch 'origin/feat/ipfs' into feat/ipfs
bludnic Sep 11, 2024
fe8bf86
chore: fix merge conflicts
bludnic Sep 11, 2024
0420727
fix(AChatAttachment): fix status icon
bludnic Sep 11, 2024
c4e202a
fix(vuex): commit is not defined in attachment module
bludnic Sep 11, 2024
12d06d8
fix(UploadFile.vue): convert File to Uint8Array and refactor to TS
bludnic Sep 13, 2024
65cdac4
refactor(Chat.vue): refactor to Composition API
bludnic Sep 14, 2024
603e479
fix(UploadFile): remove extra symbols
bludnic Sep 14, 2024
4de5a55
feat(asset): describe `FileAsset` according to AIP-18
bludnic Sep 14, 2024
dc66f53
feat(adamant-api): add `encodeFile` helper
bludnic Sep 14, 2024
0514253
feat(IpfsClient): add `upload` method
bludnic Sep 14, 2024
863b6dc
feat(AChatFile): fix file type
bludnic Sep 14, 2024
a24c05e
refactor(UploadFile): type it properly
bludnic Sep 15, 2024
6da8c2d
feat(adamant-api): add `createAttachment` util
bludnic Sep 15, 2024
d5b331d
feat(store, chat): add `sendAttachment` action
bludnic Sep 15, 2024
c312db7
chore(Vue): add JSX support
bludnic Sep 16, 2024
3e2b236
fix(i18n): use tFunction
bludnic Sep 16, 2024
885d662
fix(lib/adamant): senderPublicKey can be either HEX string or Uint8Array
bludnic Sep 17, 2024
a257cdd
feat(IpfsClient): add `downloadFile` method
bludnic Sep 17, 2024
37ba567
feat(IPFS): add file loader component
bludnic Sep 17, 2024
e76475a
feat(AChatFileLoader): handle local files
bludnic Sep 17, 2024
ad14420
fix(adamant-api, encodeFile): fix `file` param type
bludnic Sep 17, 2024
74b0689
refactor(UploadFile.vue): move `readFileAsDataURL` to util
bludnic Sep 17, 2024
0eea02a
fix(Vuex, chat, sendAttachment): fix `files` param type
bludnic Sep 17, 2024
32a0bc3
feat(IPFS): upload file functionality
bludnic Sep 17, 2024
1376527
chore(config): use prod IPFS nodes
bludnic Sep 17, 2024
43df190
fix(Vuex): attachment not cached
bludnic Sep 17, 2024
77cd1a6
feat(lib/file, IPFS): add `computeCID` helper
bludnic Sep 17, 2024
84660ac
feat(sendAttachment): compute CIDs on the client side
bludnic Sep 17, 2024
d16e134
feat(UploadFile): save to File API right after file is selected
bludnic Sep 17, 2024
1eb6d3c
fix(`lib/asset`): use CID from file data
bludnic Sep 17, 2024
56d1cbd
refactor(AChatTransaction): remove `crypto` prop & fix TS error
bludnic Sep 18, 2024
23f1afc
fix(i18n): use `t()` instead of legacy `$t()`
bludnic Sep 18, 2024
ad5dcd1
fix(TS): fix build errors
bludnic Sep 18, 2024
b1333ba
fix(IPFS): update production config
bludnic Sep 18, 2024
8bcf319
fix(IPFS): increase threshold up to 50 seconds due to Sync state
bludnic Sep 18, 2024
02f4dc3
fix(UploadFile): CID of the file is different from the one returned b…
bludnic Sep 18, 2024
5380e0c
chore: regenerate wallets
bludnic Sep 26, 2024
f5c7b7c
chore: migrate to new adamant-wallets structure
bludnic Sep 26, 2024
89b60ee
feat(AChatAttachment): restyle image grid layout to show 2/3 images p…
bludnic Sep 27, 2024
fb69d48
feat(AChatAttachment): add inline layout
bludnic Sep 27, 2024
6f3b964
fix(Chat): attachment does not require a message
bludnic Sep 27, 2024
a72366a
fix(Chat): reset preview attachments after message was send
bludnic Sep 27, 2024
e2665c5
feat(AChatAttachment): hide avatar
bludnic Sep 28, 2024
ca4bdcd
Merge branch 'refs/heads/dev' into feat/ipfs
bludnic Sep 30, 2024
da180d2
feat(AChatAttachment): align inline attachments to right
bludnic Sep 30, 2024
5eff429
fix(AChatAttachment): open images gallery when inline layout
bludnic Sep 30, 2024
3cec833
feat(attachment): handle error state
bludnic Oct 4, 2024
b7d292d
chore: add VueUse
bludnic Oct 10, 2024
688889f
feat(AChatImageModal): restyle dialog
bludnic Oct 10, 2024
0e2b6f8
feat(AChatImageModal): slider navigation using arrows
bludnic Oct 10, 2024
d573973
feat(AChatImageModal): slider navigation using arrows
bludnic Oct 10, 2024
fa68c6c
fix(AChatModalItem): refactor component
bludnic Oct 10, 2024
cd770dd
feat(AChatImageModal): close slider when click outside
bludnic Oct 10, 2024
cc5537c
refactor(AChatImageModalItem): fix types
bludnic Oct 10, 2024
373510f
fix(AChatImageModal): fix `files` prop type
bludnic Oct 10, 2024
1fd6b26
fix(AChatImageModal): download file by URL
bludnic Oct 10, 2024
2add32b
feat(ImageLayout): improve image grid layout
bludnic Oct 10, 2024
46b0d8d
feat(AChatImage): show error icon when failed to load the image
bludnic Oct 10, 2024
a353538
fix(AChatImage): don't open image slider while the image is loading
bludnic Oct 11, 2024
e37f425
fix(AChatImageModal): hide arrow on mobile or when only one image att…
bludnic Oct 11, 2024
68c615d
feat(ImageModal): layout for files
bludnic Oct 11, 2024
8062fa9
feat(attachments): restyle inline layout
bludnic Oct 12, 2024
0c88442
feat(attachment): add box-shadow to ImageLayout
bludnic Oct 12, 2024
86eb3af
fix(attachments): reset the input value to allow selecting the same f…
bludnic Oct 12, 2024
314ec03
refactor(UploadFile): to Composition API
bludnic Oct 12, 2024
b5a8f6a
feat(AChatFile): show error icon when failed to load the image
bludnic Oct 12, 2024
b77ca53
fix(AChatFile, AChatImage): don't open file slider until image previe…
bludnic Oct 12, 2024
eac60d9
fix(AChatFileLoader): don't retry or refetch
bludnic Oct 12, 2024
f4f7c06
fix(lib/nodes): export `ipfs` client
bludnic Oct 18, 2024
acaa64f
fix(attachments): revoke objects URLs when logout
bludnic Oct 18, 2024
35640d1
Merge branch 'refs/heads/dev' into feat/ipfs
bludnic Oct 28, 2024
b0bfc55
refactor(constants): merge JS and DTS files
bludnic Oct 28, 2024
5856bae
feat(attachments): set max 10 files
bludnic Oct 28, 2024
f11d83f
feat(IconFile): improve file icon
bludnic Nov 5, 2024
7f24a40
fix(AChatFile): uppercase file extension
bludnic Nov 5, 2024
d5d73cc
refactor(IconFile): wrap in `defineComponent`
bludnic Nov 5, 2024
a6cf06e
fix(AChatModalFile): display file extension
bludnic Nov 5, 2024
58b5642
refactor: decompose files preview components
bludnic Nov 5, 2024
0f46571
fix(AChatModalFile): width/height props should be type number
bludnic Nov 5, 2024
122a882
fix(AChatImageModal): disable carousel continuous
bludnic Nov 5, 2024
14ce69b
feat(attachments): show upload progress
bludnic Nov 10, 2024
6f5e535
feat(adamant-api): update attachmentAsset params
bludnic Nov 10, 2024
50b1d6e
feat: add `cropImage` helper
bludnic Nov 10, 2024
d28fad8
feat(attachments): upload previews
bludnic Nov 10, 2024
ba69d63
fix(attachments): upload previews
bludnic Nov 10, 2024
e289e8b
chore(adamant-api, asset): DTS to TS
bludnic Nov 10, 2024
4b03ca6
feat(attachments): show prompt if files are uploading
bludnic Nov 26, 2024
53d3458
feat(ipfs): max file size allowed
bludnic Jan 8, 2025
242191a
Merge branch 'dev' into feat/ipfs
bludnic Jan 8, 2025
4bc956c
refactor(ipfs): reuse file utils
bludnic Jan 9, 2025
b7fd30a
feat(ipfs): improve attachment text preview
bludnic Jan 9, 2025
3991e33
refactor(ipfs): improve logging
bludnic Jan 9, 2025
4ac40d8
feat(ipfs): localize image/file loading errors
bludnic Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
chore(nodes): preparation for IPFS infoService health check
RealGoodProgrammer committed Apr 23, 2024
commit 64924143b04060747260179a93ff107d241e7009
48 changes: 48 additions & 0 deletions src/components/nodes/ipfs/IpfsNodesTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<NodesTableContainer>
<NodesTableHead hide-label />

<tbody>
<IpfsNodesTableItem v-for="node in ipfsNodes" :key="node.url" blockchain="adm" :node="node" />
</tbody>
</NodesTableContainer>
</template>

<script lang="ts">
import { computed, defineComponent } from 'vue'
import { useStore } from 'vuex'
import NodesTableContainer from '@/components/nodes/components/NodesTableContainer.vue'
import NodesTableHead from '@/components/nodes/components/NodesTableHead.vue'
import IpfsNodesTableItem from './IpfsNodesTableItem.vue'
import { sortNodesFn } from '@/components/nodes/utils/sortNodesFn'

const className = 'adm-nodes-table'
const classes = {
root: className
}

export default defineComponent({
components: {
NodesTableContainer,
NodesTableHead,
IpfsNodesTableItem
},
setup() {
const store = useStore()
const ipfsNodes = computed(() => {
const arr = store.getters['nodes/ipfs']

return [...arr].sort(sortNodesFn)
})

return {
ipfsNodes,
classes
}
}
})
</script>

<style lang="scss">
@import 'vuetify/settings';
</style>
122 changes: 122 additions & 0 deletions src/components/nodes/ipfs/IpfsNodesTableItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<template>
<tr :class="classes.root">
<NodeColumn checkbox>
<NodeStatusCheckbox :value="active" @change="toggleActiveStatus" />
</NodeColumn>

<NodeColumn>
<NodeUrl :node="node" />
<NodeVersion v-if="node.version && active" :node="node" />
</NodeColumn>

<NodeColumn :colspan="!showSocketColumn ? 2 : 1">
<NodeStatus :node="node" />
</NodeColumn>

<NodeColumn v-if="showSocketColumn">
<SocketSupport :node="node" />
</NodeColumn>
</tr>
</template>

<script lang="ts">
import { computed, PropType } from 'vue'
import { useStore } from 'vuex'
import type { NodeStatusResult } from '@/lib/nodes/abstract.node'
import NodeUrl from '@/components/nodes/components/NodeUrl.vue'
import NodeColumn from '@/components/nodes/components/NodeColumn.vue'
import NodeStatus from '@/components/nodes/components/NodeStatus.vue'
import NodeVersion from '@/components/nodes/components/NodeVersion.vue'
import SocketSupport from '@/components/nodes/components/SocketSupport.vue'
import NodeStatusCheckbox from '@/components/nodes/components/NodeStatusCheckbox.vue'

const className = 'adm-nodes-table-item'
const classes = {
root: className,
column: `${className}__column`,
columnCheckbox: `${className}__column--checkbox`,
checkbox: `${className}__checkbox`
}

export default {
components: {
NodeStatusCheckbox,
NodeColumn,
NodeStatus,
NodeVersion,
SocketSupport,
NodeUrl
},
props: {
node: {
type: Object as PropType<NodeStatusResult>,
required: true
}
},
setup(props) {
const store = useStore()

const url = computed(() => props.node.url)
const active = computed(() => props.node.active)
const socketSupport = computed(() => props.node.socketSupport)
const isUnsupported = computed(() => props.node.status === 'unsupported_version')
const type = computed(() => props.node.type)
const showSocketColumn = computed(() => active.value && !isUnsupported.value)

const toggleActiveStatus = () => {
store.dispatch('nodes/toggle', {
type: type.value,
url: url.value,
active: !active.value
})
store.dispatch('nodes/updateStatus')
}

const computedResult = computed(() => {
const baseUrl = new URL(url.value)
const protocol = baseUrl.protocol
const hostname = baseUrl.hostname
const port = baseUrl.port
const result = /^[\d.]+$/.test(hostname)

let nodeName = null
let domain = null

if (!result) {
const regex = /([^.]*)\.(.*)/
const parts = hostname.match(regex)
if (parts !== null) {
nodeName = parts[1]
domain = parts[2]
}
}

return {
protocol,
hostname,
nodeName,
domain,
result,
port
}
})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you convert this part into a hook and reuse it in both components: IpfsNodesTableItem.vue and AdmNodesTableItem.vue?

Example of usage:

const { protocol, hostname, nodeName, domain, result, port } = useNodeUrl(url);

Put the hook in src/components/nodes/hooks

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's important not to lose the reactivity of protocol, hostname, etc., after destructuring. You probably need to use toRefs inside the hook.


return {
classes,
url,
active,
socketSupport,
isUnsupported,
showSocketColumn,
toggleActiveStatus,
computedResult
}
}
}
</script>

<style lang="scss">
.ipfs-nodes-table-item {
line-height: 14px;
}
</style>
1 change: 1 addition & 0 deletions src/components/nodes/ipfs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as IpfsNodesTable } from './IpfsNodesTable.vue'
2 changes: 2 additions & 0 deletions src/lib/nodes/constants.ts
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ export type TNodeLabel =
| 'doge-node'
| 'doge-indexer'
| 'dash-node'
| 'ipfs-node'
| 'lsk-node'
| 'lsk-indexer'
| 'rates-info'
@@ -36,6 +37,7 @@ export const NODE_LABELS: NodeLabels = {
DogeNode: 'doge-node',
DogeIndexer: 'doge-indexer',
DashNode: 'dash-node',
IpfsNode: 'ipfs-node',
LskNode: 'lsk-node',
LskIndexer: 'lsk-indexer',
RatesInfo: 'rates-info'
62 changes: 62 additions & 0 deletions src/lib/nodes/ipfs/IpfsClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { isNodeOfflineError } from '@/lib/nodes/utils/errors'
import { IpfsNode, Payload, RequestConfig } from './IpfsNode.ts'
import { Client } from '../abstract.client'

/**
* Provides methods for calling the ADAMANT API.
*
* The `ApiClient` instance automatically selects an ADAMANT node to
* send the API-requests to and switches to another node if the current one
* is not available at the moment.
*/
Comment on lines +7 to +13
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update JSDoc: ADAMANT API -> IPFS NODE API

export class IpfsClient extends Client<IpfsNode> {
constructor(endpoints: string[] = [], minNodeVersion = '0.0.0') {
super('ipfs')
this.nodes = endpoints.map((endpoint) => new IpfsNode(endpoint, minNodeVersion))
this.minNodeVersion = minNodeVersion

void this.watchNodeStatusChange()
}

/**
* Performs a GET API request.
* @param {String} url relative API url
* @param {any} params request params (an object) or a function that accepts `ApiNode` and returns the request params
*/
get<P extends Payload = Payload>(url: string, params: P) {
return this.request({ method: 'get', url, payload: params })
}

/**
* Performs a POST API request.
* @param {String} url relative API url
* @param {any} payload request payload (an object) or a function that accepts `ApiNode` and returns the request payload
*/
post<P extends Payload = Payload>(url: string, payload: P) {
return this.request({ method: 'post', url, payload })
}

/**
* Performs an API request.
* @param {RequestConfig} config request config
*/
async request<P extends Payload = Payload, R = any>(config: RequestConfig<P>): Promise<R> {
const node = this.useFastest ? this.getFastestNode() : this.getRandomNode()
if (!node) {
// All nodes seem to be offline: let's refresh the statuses
this.checkHealth()
// But there's nothing we can do right now
return Promise.reject(new Error('No online nodes at the moment'))
}

return node.request(config).catch((error) => {
if (isNodeOfflineError(error)) {
// Initiate nodes status check
this.checkHealth()
// If the selected node is not available, repeat the request with another one.
return this.request(config)
}
throw error
})
}
}
124 changes: 124 additions & 0 deletions src/lib/nodes/ipfs/IpfsNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import utils from '@/lib/adamant'
import { NodeOfflineError } from '@/lib/nodes/utils/errors'
import { GetNodeStatusResponseDto } from '@/lib/schema/client'
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { Node } from '@/lib/nodes/abstract.node'
import { NODE_LABELS } from '@/lib/nodes/constants'

type FetchNodeInfoResult = {
socketSupport: boolean
version: string
height: number
wsPort?: string
}

export type Payload =
| Record<string, any>
| {
(ctx: IpfsNode): Record<string, any>
}
export type RequestConfig<P extends Payload> = {
url: string
method?: string
payload?: P
}

/**
* Encapsulates a node. Provides methods to send API-requests
* to the node and verify is status (online/offline, version, ping, etc.)
*/
export class IpfsNode extends Node<AxiosInstance> {
constructor(url: string, minNodeVersion = '0.0.0') {
super(url, 'ipfs', 'node', NODE_LABELS.IpfsNode, '', minNodeVersion)

this.wsPort = '36668' // default wsPort
this.wsProtocol = this.protocol === 'https:' ? 'wss:' : 'ws:'
this.wsPortNeeded = this.wsProtocol === 'ws:' && !this.hostname.includes('.onion')
}

protected buildClient(): AxiosInstance {
return axios.create({
baseURL: this.url
})
}

/**
* Performs an API request.
*
* The `payload` of the `cfg` can be either an object or a function that
* accepts `ApiNode` as a first argument and returns an object.
*/
request<P extends Payload = Payload, R = any>(cfg: RequestConfig<P>): Promise<R> {
const { url, method = 'get', payload } = cfg

const config: AxiosRequestConfig = {
url,
method: method.toLowerCase(),
[method === 'get' ? 'params' : 'data']:
typeof payload === 'function' ? payload(this) : payload
}

return this.client.request(config).then(
(response) => {
const body = response.data
// Refresh time delta on each request
if (body && isFinite(body.nodeTimestamp)) {
this.timeDelta = utils.epochTime() - body.nodeTimestamp
}

return body
},
(error) => {
// According to https://github.com/axios/axios#handling-errors this means, that request was sent,
// but server could not respond.
if (!error.response && error.request) {
this.online = false
throw new NodeOfflineError()
}
throw error
}
)
}

/**
* Fetch node version, block height and ping.
* @returns {Promise<{version: string, height: number, ping: number}>}
*/
private async fetchNodeInfo(): Promise<FetchNodeInfoResult> {
const { success, version, network, wsClient } = await this.request<
Payload,
GetNodeStatusResponseDto
>({ url: '/api/node/status' })

if (success) {
const readableVersion = version.version
const height = Number(network.height)
const socketSupport = wsClient ? wsClient.enabled : false
const wsPort = wsClient ? String(wsClient.port) : ''

this.version = readableVersion
this.height = height
this.socketSupport = socketSupport
this.wsPort = wsPort

return {
version: readableVersion,
height,
socketSupport,
wsPort
}
}

throw new Error('Request to /api/node/status was unsuccessful')
}

protected async checkHealth() {
const time = Date.now()
const { height } = await this.fetchNodeInfo()

return {
height,
ping: Date.now() - time
}
}
}
8 changes: 8 additions & 0 deletions src/lib/nodes/ipfs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import config from '@/config'
import { NodeInfo } from '@/types/wallets'
import { IpfsClient } from './IpfsClient.ts'

const endpoints = (config.ipfs.nodes.list as NodeInfo[]).map((endpoint) => endpoint.url)
export const ipfs = new IpfsClient(endpoints, config.ipfs.nodes.minVersion)

export default ipfs
Loading

Unchanged files with check annotations Beta

const stateStorage = new TypedStorage(NODES_STATE_STORAGE_KEY, {} as State, window.localStorage)
const defaultOptions: Options = {

Check failure on line 20 in src/lib/nodes/storage.ts

GitHub Actions / Build and Deploy to surge

Property 'ipfs' is missing in type '{ adm: { useFastest: false; }; btc: { useFastest: true; }; doge: { useFastest: true; }; dash: { useFastest: true; }; eth: { useFastest: true; }; lsk: { useFastest: true; }; }' but required in type 'Options'.
adm: { useFastest: false },
btc: { useFastest: true },
doge: { useFastest: true },