diff --git a/package-lock.json b/package-lock.json index 3e17c5b..8ce70c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@lumeweb/kernel-ipfs-client": "^0.1.0-develop.25", "@lumeweb/kernel-network-registry-client": "^0.1.0-develop.10", "@lumeweb/kernel-peer-discovery-client": "^0.0.2-develop.18", + "@lumeweb/kernel-s5-client": "^0.1.0-develop.5", "@lumeweb/kernel-swarm-client": "^0.1.0-develop.12", "@lumeweb/libresolver": "^0.1.0-develop.1", "@lumeweb/sdk": "^0.1.0-develop.44", @@ -2504,6 +2505,14 @@ "hyperswarm": "^4.3.7" } }, + "node_modules/@lumeweb/kernel-s5-client": { + "version": "0.1.0-develop.5", + "resolved": "https://registry.npmjs.org/@lumeweb/kernel-s5-client/-/kernel-s5-client-0.1.0-develop.5.tgz", + "integrity": "sha512-3yjq8F6JiLaY8ymtaVm/9uR0AtO9IHl/fOUmJyT2XCT+kbz0LJYZgMv0UMddnz/RHXiRMKRbIXxHhz2aEOw8kg==", + "dependencies": { + "@lumeweb/libkernel": "0.1.0-develop.68" + } + }, "node_modules/@lumeweb/kernel-swarm-client": { "version": "0.1.0-develop.12", "resolved": "https://registry.npmjs.org/@lumeweb/kernel-swarm-client/-/kernel-swarm-client-0.1.0-develop.12.tgz", diff --git a/package.json b/package.json index 6a64fda..e4e88a6 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@lumeweb/kernel-ipfs-client": "^0.1.0-develop.25", "@lumeweb/kernel-network-registry-client": "^0.1.0-develop.10", "@lumeweb/kernel-peer-discovery-client": "^0.0.2-develop.18", + "@lumeweb/kernel-s5-client": "^0.1.0-develop.5", "@lumeweb/kernel-swarm-client": "^0.1.0-develop.12", "@lumeweb/libresolver": "^0.1.0-develop.1", "@lumeweb/sdk": "^0.1.0-develop.44", diff --git a/src/backend/providers/s5.ts b/src/backend/providers/s5.ts new file mode 100644 index 0000000..bbcb76b --- /dev/null +++ b/src/backend/providers/s5.ts @@ -0,0 +1,79 @@ +import type { ContentProvider } from "../types.js"; +import * as nodePath from "path"; +import { s5Client } from "@/clients.ts"; + +export default class IPFSProvider implements ContentProvider { + private _client = s5Client; + + async fetchContent( + uri: string, + path: string, + query?: string, + ): Promise { + let cid = translatePath(uri); + let err; + let urlPath = path; + const parsedPath = nodePath.parse(urlPath); + + if (!cid.startsWith("/s5/") && cid.startsWith("/sia/")) { + err = "404"; + } + + if (err) { + throw new Error(err); + } + + cid = cid.replace("/s5/", "").replace("/sia/", ""); + + let file; + + try { + const meta = await this._client.stat(cid); + if (meta.type !== "web_app") { + throw new Error("404"); + } + + if (!parsedPath.base.length || !parsedPath.ext.length) { + let found = false; + for (const indexFile of meta.tryFiles) { + urlPath = nodePath.join(urlPath, indexFile); + if (urlPath in meta.paths) { + found = true; + break; + } + } + + if (!found) { + throw new Error("404"); + } + file = meta.paths[urlPath]; + } else { + if (!(urlPath in meta.paths)) { + throw new Error("404"); + } + } + } catch (e) { + throw new Error(err); + } + + const headers: HeadersInit = {}; + + headers["Content-Type"] = file.contentType as string; + + return new Response( + new Blob([(await this._client.cat(cid)) as Uint8Array]), + { + headers, + }, + ); + } + + supports(uri: string): boolean { + uri = translatePath(uri); + return uri.startsWith("/s5/") || uri.startsWith("/sia/"); + } +} + +function translatePath(uri: string) { + return uri.replace(/:\/\//, "/").replace(/^/, "/"); +} diff --git a/src/clients.ts b/src/clients.ts index aff54f5..3f3e183 100644 --- a/src/clients.ts +++ b/src/clients.ts @@ -5,6 +5,7 @@ import { createClient as createPeerDiscoveryClient } from "@lumeweb/kernel-peer- import { createClient as createNetworkRegistryClient } from "@lumeweb/kernel-network-registry-client"; import { createClient as createHandshakeClient } from "@lumeweb/kernel-handshake-client"; import { createClient as createEthClient } from "@lumeweb/kernel-eth-client"; +import { createClient as createS5Client } from "@lumeweb/kernel-s5-client"; const dnsClient = createDnsClient(); const ipfsClient = createIpfsClient(); @@ -13,6 +14,7 @@ const peerDiscoveryClient = createPeerDiscoveryClient(); const networkRegistryClient = createNetworkRegistryClient(); const handshakeClient = createHandshakeClient(); const ethClient = createEthClient(); +const s5Client = createS5Client(); export { dnsClient, @@ -22,4 +24,5 @@ export { networkRegistryClient, handshakeClient, ethClient, + s5Client, };