From 29ccab65d9a36da068857829ca04c06c738c22b4 Mon Sep 17 00:00:00 2001 From: Neha Kumari Date: Tue, 4 Feb 2025 02:15:41 +0530 Subject: [PATCH 1/9] modified-contentType&-added-testcases --- packages/client/.aegir.js | 215 ++++-- packages/client/package.json | 1 + packages/client/src/client.ts | 2 +- packages/client/test/index.spec.ts | 966 +++++++++++++++++--------- packages/client/test/routings.spec.ts | 398 ++++++----- 5 files changed, 991 insertions(+), 591 deletions(-) diff --git a/packages/client/.aegir.js b/packages/client/.aegir.js index 14e7890..b5b4be1 100644 --- a/packages/client/.aegir.js +++ b/packages/client/.aegir.js @@ -1,96 +1,157 @@ -import EchoServer from 'aegir/echo-server' -import body from 'body-parser' +import EchoServer from "aegir/echo-server"; +import body from "body-parser"; /** @type {import('aegir').PartialOptions} */ const options = { test: { before: async () => { - let callCount = 0 - let lastCalledUrl = '' - const providers = new Map() - const peers = new Map() - const ipnsGet = new Map() - const ipnsPut = new Map() - const echo = new EchoServer() - echo.polka.use(body.raw({ type: 'application/vnd.ipfs.ipns-record'})) - echo.polka.use(body.text()) + let callCount = 0; + let lastCalledUrl = ""; + const providers = new Map(); + const peers = new Map(); + const ipnsGet = new Map(); + const ipnsPut = new Map(); + const echo = new EchoServer(); + echo.polka.use(body.raw({ type: "application/vnd.ipfs.ipns-record" })); + echo.polka.use(body.text()); + echo.polka.use(body.json()); echo.polka.use((req, res, next) => { - next() - lastCalledUrl = req.url - }) - echo.polka.post('/add-providers/:cid', (req, res) => { - callCount++ - providers.set(req.params.cid, req.body) - res.end() - }) - echo.polka.get('/routing/v1/providers/:cid', (req, res) => { - callCount++ - const records = providers.get(req.params.cid) ?? '[]' - providers.delete(req.params.cid) - res.end(records) - }) - echo.polka.post('/add-peers/:peerId', (req, res) => { - callCount++ - peers.set(req.params.peerId, req.body) - res.end() - }) - echo.polka.get('/routing/v1/peers/:peerId', (req, res) => { - callCount++ - const records = peers.get(req.params.peerId) ?? '[]' - peers.delete(req.params.peerId) + next(); + lastCalledUrl = req.url; + }); - res.end(records) - }) - echo.polka.post('/add-ipns/:peerId', (req, res) => { - callCount++ - ipnsGet.set(req.params.peerId, req.body) - res.end() - }) - echo.polka.get('/routing/v1/ipns/:peerId', (req, res) => { - callCount++ - const record = ipnsGet.get(req.params.peerId) ?? '' - ipnsGet.delete(req.params.peerId) + echo.polka.post("/add-providers/:cid", (req, res) => { + callCount++; + try { + console.log("Received POST request body:", req.body); + console.log("Content-Type:", req.headers["content-type"]); - res.end(record) - }) - echo.polka.put('/routing/v1/ipns/:peerId', (req, res) => { - callCount++ - ipnsPut.set(req.params.peerId, req.body) - res.end() - }) - echo.polka.get('/get-ipns/:peerId', (req, res) => { - callCount++ - const record = ipnsPut.get(req.params.peerId) ?? '' - ipnsPut.delete(req.params.peerId) + // Only process if content-type is application/json + if (req.headers["content-type"]?.includes("application/json")) { + const data = + typeof req.body === "string" + ? { + Providers: req.body + .split("\n") + .map((line) => JSON.parse(line)), + } + : req.body; + providers.set(req.params.cid, data); + res.end(JSON.stringify({ success: true })); + } else { + res.statusCode = 400; + res.end( + JSON.stringify({ + error: "Invalid content type. Expected application/json", + code: "ERR_INVALID_INPUT", + }) + ); + // Clear any existing providers for this CID + providers.delete(req.params.cid); + } + } catch (err) { + console.error("Error in add-providers:", err); + res.statusCode = 400; + res.end( + JSON.stringify({ + error: err.message, + code: "ERR_INVALID_INPUT", + }) + ); + providers.delete(req.params.cid); + } + }); - res.end(record) - }) - echo.polka.get('/get-call-count', (req, res) => { - res.end(callCount.toString()) - }) - echo.polka.get('/reset-call-count', (req, res) => { - callCount = 0 - res.end() - }) - echo.polka.get('/last-called-url', (req, res) => { - res.end(lastCalledUrl) - }) + echo.polka.get("/routing/v1/providers/:cid", (req, res) => { + callCount++; + try { + console.log("GET request for CID:", req.params.cid); + console.log("Accept header:", req.headers.accept); - await echo.start() + const providerData = providers.get(req.params.cid) || { + Providers: [], + }; + + const acceptHeader = req.headers.accept; + if (acceptHeader?.includes("application/x-ndjson")) { + res.setHeader("Content-Type", "application/x-ndjson"); + const providers = Array.isArray(providerData.Providers) + ? providerData.Providers + : []; + res.end(providers.map((p) => JSON.stringify(p)).join("\n")); + } else { + res.setHeader("Content-Type", "application/json"); + res.end(JSON.stringify(providerData)); + } + } catch (err) { + console.error("Error in get providers:", err); + res.statusCode = 500; + res.end(JSON.stringify({ error: err.message })); + } + }); + + echo.polka.post("/add-peers/:peerId", (req, res) => { + callCount++; + peers.set(req.params.peerId, req.body); + res.end(); + }); + echo.polka.get("/routing/v1/peers/:peerId", (req, res) => { + callCount++; + const records = peers.get(req.params.peerId) ?? "[]"; + peers.delete(req.params.peerId); + + res.end(records); + }); + echo.polka.post("/add-ipns/:peerId", (req, res) => { + callCount++; + ipnsGet.set(req.params.peerId, req.body); + res.end(); + }); + echo.polka.get("/routing/v1/ipns/:peerId", (req, res) => { + callCount++; + const record = ipnsGet.get(req.params.peerId) ?? ""; + ipnsGet.delete(req.params.peerId); + + res.end(record); + }); + echo.polka.put("/routing/v1/ipns/:peerId", (req, res) => { + callCount++; + ipnsPut.set(req.params.peerId, req.body); + res.end(); + }); + echo.polka.get("/get-ipns/:peerId", (req, res) => { + callCount++; + const record = ipnsPut.get(req.params.peerId) ?? ""; + ipnsPut.delete(req.params.peerId); + + res.end(record); + }); + echo.polka.get("/get-call-count", (req, res) => { + res.end(callCount.toString()); + }); + echo.polka.get("/reset-call-count", (req, res) => { + callCount = 0; + res.end(); + }); + echo.polka.get("/last-called-url", (req, res) => { + res.end(lastCalledUrl); + }); + + await echo.start(); return { env: { - ECHO_SERVER: `http://${echo.host}:${echo.port}` + ECHO_SERVER: `http://${echo.host}:${echo.port}`, }, - echo - } + echo, + }; }, after: async (_, beforeResult) => { if (beforeResult.echo != null) { - await beforeResult.echo.stop() + await beforeResult.echo.stop(); } - } - } -} + }, + }, +}; -export default options +export default options; diff --git a/packages/client/package.json b/packages/client/package.json index 9198c2b..5c1b5b2 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -142,6 +142,7 @@ "@libp2p/logger": "^5.0.1", "@libp2p/peer-id": "^5.0.1", "@multiformats/multiaddr": "^12.3.1", + "@playwright/test": "^1.50.1", "any-signal": "^4.1.1", "browser-readablestream-to-it": "^2.0.7", "ipns": "^10.0.0", diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index bc44672..264e6e2 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -139,7 +139,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV } const contentType = res.headers.get('Content-Type') - if (contentType === 'application/json') { + if (contentType?.startsWith('application/json')) { const body = await res.json() for (const provider of body.Providers) { diff --git a/packages/client/test/index.spec.ts b/packages/client/test/index.spec.ts index 1ffff14..142a1a2 100644 --- a/packages/client/test/index.spec.ts +++ b/packages/client/test/index.spec.ts @@ -1,400 +1,696 @@ /* eslint-env mocha */ -import { generateKeyPair } from '@libp2p/crypto/keys' -import { start, stop } from '@libp2p/interface' -import { peerIdFromPrivateKey, peerIdFromString } from '@libp2p/peer-id' -import { multiaddr } from '@multiformats/multiaddr' -import { expect } from 'aegir/chai' -import { createIPNSRecord, marshalIPNSRecord } from 'ipns' -import all from 'it-all' -import { CID } from 'multiformats/cid' -import { createDelegatedRoutingV1HttpApiClient, type DelegatedRoutingV1HttpApiClient } from '../src/index.js' -import { itBrowser } from './fixtures/it.js' +import { generateKeyPair } from "@libp2p/crypto/keys"; +import { start, stop } from "@libp2p/interface"; +import { peerIdFromPrivateKey, peerIdFromString } from "@libp2p/peer-id"; +import { multiaddr } from "@multiformats/multiaddr"; +import { expect } from "aegir/chai"; +import { createIPNSRecord, marshalIPNSRecord } from "ipns"; +import all from "it-all"; +import { CID } from "multiformats/cid"; +import { + createDelegatedRoutingV1HttpApiClient, + type DelegatedRoutingV1HttpApiClient, +} from "../src/index.js"; +import { itBrowser } from "./fixtures/it.js"; if (process.env.ECHO_SERVER == null) { - throw new Error('Echo server not configured correctly') + throw new Error("Echo server not configured correctly"); } -const serverUrl = process.env.ECHO_SERVER +const serverUrl = process.env.ECHO_SERVER; -describe('delegated-routing-v1-http-api-client', () => { - let client: DelegatedRoutingV1HttpApiClient +describe("delegated-routing-v1-http-api-client", () => { + let client: DelegatedRoutingV1HttpApiClient; beforeEach(async () => { - client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { cacheTTL: 0 }) - await start(client) - }) + client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { + cacheTTL: 0, + }); + await start(client); + }); afterEach(async () => { - await stop(client) - }) - - it('should find providers', async () => { - const providers = [{ - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, { - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/43.43.43.43/tcp/1234'] - }] - - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + await stop(client); + }); + + // it("should find providers", async () => { + // const providers = [ + // { + // Protocol: "transport-bitswap", + // Schema: "bitswap", + // Metadata: "gBI=", + // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + // Addrs: ["/ip4/41.41.41.41/tcp/1234"], + // }, + // { + // Protocol: "transport-bitswap", + // Schema: "peer", + // Metadata: "gBI=", + // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + // Addrs: ["/ip4/42.42.42.42/tcp/1234"], + // }, + // { + // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + // Addrs: ["/ip4/43.43.43.43/tcp/1234"], + // }, + // ]; + + // const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + + // // load providers for the router to fetch + // await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { + // method: "POST", + // headers: { + // 'Content-Type': 'application/json' + // }, + // body: JSON.stringify({ Providers: providers }), + // }); + + // await new Promise(resolve => setTimeout(resolve, 100)) + + // const provs = await all(client.getProviders(cid)); + // console.log("Retrieved providers:", provs); + + // expect( + // provs.map((prov) => ({ + // id: prov.ID.toString(), + // addrs: prov.Addrs?.map((ma) => ma.toString()), + // })) + // ).to.deep.equal( + // providers.map((prov) => ({ + // id: prov.ID, + // addrs: prov.Addrs, + // })) + // ); + // }); + it("should find providers", async () => { + const providers = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + { + Protocol: "transport-bitswap", + Schema: "peer", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/42.42.42.42/tcp/1234"], + }, + { + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/43.43.43.43/tcp/1234"], + }, + ]; - // load providers for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: providers.map(prov => JSON.stringify(prov)).join('\n') - }) - - const provs = await all(client.getProviders(cid)) - expect(provs.map(prov => ({ - id: prov.ID.toString(), - addrs: prov.Addrs?.map(ma => ma.toString()) - }))).to.deep.equal(providers.map(prov => ({ - id: prov.ID, - addrs: prov.Addrs - }))) - }) - - it('should add filter parameters the query of the request url', async () => { - const providers = [{ - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: [] - }, { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, { - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: [] - }] - - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + + console.log("Sending providers:", JSON.stringify(providers, null, 2)); // load providers for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: providers.map(prov => JSON.stringify(prov)).join('\n') - }) + const response = await fetch( + `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ Providers: providers }), + } + ); - await all(client.getProviders(cid, { filterProtocols: ['transport-bitswap', 'unknown'], filterAddrs: ['webtransport', '!p2p-circuit'] })) + console.log("Add providers response:", { + status: response.status, + statusText: response.statusText, + body: await response.text(), + }); - // Check if the correct URL was called with filter parameters - const lastCalledUrl = await fetch(`${process.env.ECHO_SERVER}/last-called-url`) - const lastCalledUrlText = await lastCalledUrl.text() + // Add delay to ensure server processes the request + await new Promise((resolve) => setTimeout(resolve, 100)); - const searchParams = new URLSearchParams(lastCalledUrlText.split('?')[1]) + const provs = await all(client.getProviders(cid)); + console.log("Retrieved providers:", JSON.stringify(provs, null, 2)); - expect(searchParams.get('filter-protocols')).to.equal('transport-bitswap,unknown') - expect(searchParams.get('filter-addrs')).to.equal('webtransport,!p2p-circuit') - }) + expect( + provs.map((prov) => ({ + id: prov.ID.toString(), + addrs: prov.Addrs?.map((ma) => ma.toString()), + })) + ).to.deep.equal( + providers.map((prov) => ({ + id: prov.ID, + addrs: prov.Addrs, + })) + ); + }); + + /*content type test cases */ + it("should handle different Content-Type headers for JSON responses", async () => { + const providers = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + ]; + + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + + const contentTypes = [ + "application/json", + "application/json; charset=utf-8", + "application/json;charset=UTF-8", + ]; + + for (const contentType of contentTypes) { + // Add providers with proper payload structure + await fetch( + `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, + { + method: "POST", + headers: { + "Content-Type": contentType, + }, + body: JSON.stringify({ Providers: providers }), + } + ); + + await new Promise((resolve) => setTimeout(resolve, 100)); + + const provs = await all(client.getProviders(cid)); + console.log( + `Retrieved providers for ${contentType}:`, + JSON.stringify(provs, null, 2) + ); + + expect(provs).to.have.lengthOf( + 1, + `Failed for Content-Type: ${contentType}` + ); + + // Updated assertions to match the transformed structure + expect(provs[0]).to.deep.include({ + Schema: "peer", + Metadata: "gBI=", + Protocols: ["transport-bitswap"], // Protocol is moved to Protocols array + }); + expect(provs[0].ID.toString()).to.equal(providers[0].ID); + expect(provs[0].Addrs[0].toString()).to.equal(providers[0].Addrs[0]); + } + }); + + it("should handle non-json input", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + + // Try to add invalid data + const response = await fetch( + `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, + { + method: "POST", + headers: { + "Content-Type": "text/plain", + }, + body: "not json", + } + ); + + // Verify error response + expect(response.status).to.equal(400); + const errorData = await response.json(); + expect(errorData).to.have.property("error"); + expect(errorData).to.have.property("code", "ERR_INVALID_INPUT"); + + // Verify no providers were added + const provs = await all(client.getProviders(cid)); + expect(provs).to.be.empty; + }); + + it("should add filter parameters the query of the request url", async () => { + const providers = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: [], + }, + { + Protocol: "transport-bitswap", + Schema: "peer", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/42.42.42.42/tcp/1234"], + }, + { + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: [], + }, + ]; + + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - it('should add filter parameters the query of the request url based on global filter', async () => { + // load providers for the router to fetch + await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { + method: "POST", + body: providers.map((prov) => JSON.stringify(prov)).join("\n"), + }); + + await all( + client.getProviders(cid, { + filterProtocols: ["transport-bitswap", "unknown"], + filterAddrs: ["webtransport", "!p2p-circuit"], + }) + ); + + // Check if the correct URL was called with filter parameters + const lastCalledUrl = await fetch( + `${process.env.ECHO_SERVER}/last-called-url` + ); + const lastCalledUrlText = await lastCalledUrl.text(); + + const searchParams = new URLSearchParams(lastCalledUrlText.split("?")[1]); + + expect(searchParams.get("filter-protocols")).to.equal( + "transport-bitswap,unknown" + ); + expect(searchParams.get("filter-addrs")).to.equal( + "webtransport,!p2p-circuit" + ); + }); + + it("should add filter parameters the query of the request url based on global filter", async () => { const client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - filterProtocols: ['transport-bitswap', 'unknown'], - filterAddrs: ['tcp', '!p2p-circuit'] - }) - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + filterProtocols: ["transport-bitswap", "unknown"], + filterAddrs: ["tcp", "!p2p-circuit"], + }); + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - await all(client.getProviders(cid)) + await all(client.getProviders(cid)); // Check if the correct URL was called with filter parameters - const lastCalledUrl = await fetch(`${process.env.ECHO_SERVER}/last-called-url`) - const lastCalledUrlText = await lastCalledUrl.text() + const lastCalledUrl = await fetch( + `${process.env.ECHO_SERVER}/last-called-url` + ); + const lastCalledUrlText = await lastCalledUrl.text(); - const searchParams = new URLSearchParams(lastCalledUrlText.split('?')[1]) + const searchParams = new URLSearchParams(lastCalledUrlText.split("?")[1]); - expect(searchParams.get('filter-protocols')).to.equal('transport-bitswap,unknown') - expect(searchParams.get('filter-addrs')).to.equal('tcp,!p2p-circuit') - }) + expect(searchParams.get("filter-protocols")).to.equal( + "transport-bitswap,unknown" + ); + expect(searchParams.get("filter-addrs")).to.equal("tcp,!p2p-circuit"); + }); - it('should handle non-json input', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + it("should handle non-json input", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: 'not json' - }) - - const provs = await all(client.getProviders(cid)) - expect(provs).to.be.empty() - }) - - it('should handle bad input providers', async () => { - const providers = [{ - Metadata: 'gBI=', - Provider: { - Bad: 'field' - } - }, { - Metadata: 'gBI=', - ContextID: '', - Another: { - Bad: 'field' - } - }] + method: "POST", + body: "not json", + }); + + const provs = await all(client.getProviders(cid)); + expect(provs).to.be.empty(); + }); + + it("should handle bad input providers", async () => { + const providers = [ + { + Metadata: "gBI=", + Provider: { + Bad: "field", + }, + }, + { + Metadata: "gBI=", + ContextID: "", + Another: { + Bad: "field", + }, + }, + ]; - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: providers.map(prov => JSON.stringify(prov)).join('\n') - }) - - const provs = await all(client.getProviders(cid)) - expect(provs).to.be.empty() - }) - - it('should handle empty input', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - - const provs = await all(client.getProviders(cid)) - expect(provs).to.be.empty() - }) - - it('should conform records to peer schema', async () => { - const privateKey = await generateKeyPair('Ed25519') - - const records = [{ - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: privateKey.publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, { - Protocol: 'transport-saddle', - Schema: 'horse-ride', - Metadata: 'gBI=', - ID: privateKey.publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: privateKey.publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, { - Schema: 'peer', - ID: (await generateKeyPair('Ed25519')).publicKey.toString() - }] - - const peers = [{ - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[0].ID), - Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] - }, { - Protocols: ['transport-saddle'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[1].ID), - Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] - }, { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[2].ID), - Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] - }, { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[3].ID), - Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] - }, { - Protocols: [], - Schema: 'peer', - ID: peerIdFromString(records[4].ID), - Addrs: [] - }] + method: "POST", + body: providers.map((prov) => JSON.stringify(prov)).join("\n"), + }); + + const provs = await all(client.getProviders(cid)); + expect(provs).to.be.empty(); + }); + + it("should handle empty input", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + + const provs = await all(client.getProviders(cid)); + expect(provs).to.be.empty(); + }); + + it("should conform records to peer schema", async () => { + const privateKey = await generateKeyPair("Ed25519"); + + const records = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: privateKey.publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + { + Protocol: "transport-saddle", + Schema: "horse-ride", + Metadata: "gBI=", + ID: privateKey.publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + { + Protocols: ["transport-bitswap"], + Schema: "peer", + Metadata: "gBI=", + ID: privateKey.publicKey.toString(), + Addrs: ["/ip4/42.42.42.42/tcp/1234"], + }, + { + Protocol: "transport-bitswap", + Schema: "peer", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/42.42.42.42/tcp/1234"], + }, + { + Schema: "peer", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + }, + ]; + + const peers = [ + { + Protocols: ["transport-bitswap"], + Schema: "peer", + Metadata: "gBI=", + ID: peerIdFromString(records[0].ID), + Addrs: [multiaddr("/ip4/41.41.41.41/tcp/1234")], + }, + { + Protocols: ["transport-saddle"], + Schema: "peer", + Metadata: "gBI=", + ID: peerIdFromString(records[1].ID), + Addrs: [multiaddr("/ip4/41.41.41.41/tcp/1234")], + }, + { + Protocols: ["transport-bitswap"], + Schema: "peer", + Metadata: "gBI=", + ID: peerIdFromString(records[2].ID), + Addrs: [multiaddr("/ip4/42.42.42.42/tcp/1234")], + }, + { + Protocols: ["transport-bitswap"], + Schema: "peer", + Metadata: "gBI=", + ID: peerIdFromString(records[3].ID), + Addrs: [multiaddr("/ip4/42.42.42.42/tcp/1234")], + }, + { + Protocols: [], + Schema: "peer", + ID: peerIdFromString(records[4].ID), + Addrs: [], + }, + ]; // load peer for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-peers/${privateKey.publicKey.toCID()}`, { - method: 'POST', - body: records.map(prov => JSON.stringify(prov)).join('\n') - }) - - const peerRecords = await all(client.getPeers(peerIdFromPrivateKey(privateKey))) - expect(peerRecords.map(peerRecord => ({ - ...peerRecord, - ID: peerRecord.ID.toString(), - Addrs: peerRecord.Addrs?.map(ma => ma.toString()) ?? [] - }))).to.deep.equal(peers.map(peerRecord => ({ - ...peerRecord, - ID: peerRecord.ID.toString(), - Addrs: peerRecord.Addrs?.map(ma => ma.toString()) - }))) - }) - - it('should get ipns record', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const privateKey = await generateKeyPair('Ed25519') - const record = await createIPNSRecord(privateKey, cid, 0, 1000) + await fetch( + `${process.env.ECHO_SERVER}/add-peers/${privateKey.publicKey.toCID()}`, + { + method: "POST", + body: records.map((prov) => JSON.stringify(prov)).join("\n"), + } + ); + + const peerRecords = await all( + client.getPeers(peerIdFromPrivateKey(privateKey)) + ); + expect( + peerRecords.map((peerRecord) => ({ + ...peerRecord, + ID: peerRecord.ID.toString(), + Addrs: peerRecord.Addrs?.map((ma) => ma.toString()) ?? [], + })) + ).to.deep.equal( + peers.map((peerRecord) => ({ + ...peerRecord, + ID: peerRecord.ID.toString(), + Addrs: peerRecord.Addrs?.map((ma) => ma.toString()), + })) + ); + }); + + it("should get ipns record", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const privateKey = await generateKeyPair("Ed25519"); + const record = await createIPNSRecord(privateKey, cid, 0, 1000); // load record for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/vnd.ipfs.ipns-record' - }, - body: marshalIPNSRecord(record) - }) + await fetch( + `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, + { + method: "POST", + headers: { + "Content-Type": "application/vnd.ipfs.ipns-record", + }, + body: marshalIPNSRecord(record), + } + ); - const ipnsRecord = await client.getIPNS(privateKey.publicKey.toCID()) - expect(marshalIPNSRecord(ipnsRecord)).to.equalBytes(marshalIPNSRecord(record)) - }) + const ipnsRecord = await client.getIPNS(privateKey.publicKey.toCID()); + expect(marshalIPNSRecord(ipnsRecord)).to.equalBytes( + marshalIPNSRecord(record) + ); + }); - it('get ipns record fails with bad record', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const privateKey = await generateKeyPair('Ed25519') - const otherPrivateKey = await generateKeyPair('Ed25519') - const record = await createIPNSRecord(otherPrivateKey, cid, 0, 1000) + it("get ipns record fails with bad record", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const privateKey = await generateKeyPair("Ed25519"); + const otherPrivateKey = await generateKeyPair("Ed25519"); + const record = await createIPNSRecord(otherPrivateKey, cid, 0, 1000); // load record for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/vnd.ipfs.ipns-record' - }, - body: marshalIPNSRecord(record) - }) + await fetch( + `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, + { + method: "POST", + headers: { + "Content-Type": "application/vnd.ipfs.ipns-record", + }, + body: marshalIPNSRecord(record), + } + ); - await expect(client.getIPNS(privateKey.publicKey.toCID())).to.be.rejected() - }) + await expect(client.getIPNS(privateKey.publicKey.toCID())).to.be.rejected(); + }); - it('should put ipns', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const privateKey = await generateKeyPair('Ed25519') - const record = await createIPNSRecord(privateKey, cid, 0, 1000) + it("should put ipns", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const privateKey = await generateKeyPair("Ed25519"); + const record = await createIPNSRecord(privateKey, cid, 0, 1000); - await client.putIPNS(privateKey.publicKey.toCID(), record) + await client.putIPNS(privateKey.publicKey.toCID(), record); // load record that our client just PUT to remote server - const res = await fetch(`${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, { - method: 'GET', - headers: { - Accept: 'application/vnd.ipfs.ipns-record' + const res = await fetch( + `${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, + { + method: "GET", + headers: { + Accept: "application/vnd.ipfs.ipns-record", + }, } - }) - - const receivedRecord = new Uint8Array(await res.arrayBuffer()) - expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord) - }) - - it('should deduplicate concurrent requests to the same URL', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const providers = [{ - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }] - - // load providers for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: providers.map(prov => JSON.stringify(prov)).join('\n') - }) - - // Reset call count before our test - await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) - - // Make multiple concurrent requests - const results = await Promise.all([ - all(client.getProviders(cid)), - all(client.getProviders(cid)), - all(client.getProviders(cid)), - all(client.getProviders(cid)) - ]) - - // Get the number of times the server was called - const callCountRes = await fetch(`${process.env.ECHO_SERVER}/get-call-count`) - const callCount = parseInt(await callCountRes.text(), 10) - - // Verify server was only called once - expect(callCount).to.equal(1) - - // Verify all results are the same - results.forEach(resultProviders => { - expect(resultProviders.map(prov => ({ + ); + + const receivedRecord = new Uint8Array(await res.arrayBuffer()); + expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord); + }); + + // it("should deduplicate concurrent requests to the same URL", async () => { + // const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + // const providers = [ + // { + // Protocol: "transport-bitswap", + // Schema: "bitswap", + // Metadata: "gBI=", + // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + // Addrs: ["/ip4/41.41.41.41/tcp/1234"], + // }, + // ]; + + // // load providers for the router to fetch + // await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { + // method: "POST", + // body: providers.map((prov) => JSON.stringify(prov)).join("\n"), + // }); + + // // Reset call count before our test + // await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); + + // // Make multiple concurrent requests + // const results = await Promise.all([ + // all(client.getProviders(cid)), + // all(client.getProviders(cid)), + // all(client.getProviders(cid)), + // all(client.getProviders(cid)), + // ]); + + // // Get the number of times the server was called + // const callCountRes = await fetch( + // `${process.env.ECHO_SERVER}/get-call-count` + // ); + // const callCount = parseInt(await callCountRes.text(), 10); + + // // Verify server was only called once + // expect(callCount).to.equal(1); + + // // Verify all results are the same + // results.forEach((resultProviders) => { + // expect( + // resultProviders.map((prov) => ({ + // id: prov.ID.toString(), + // // eslint-disable-next-line max-nested-callbacks + // addrs: prov.Addrs?.map((ma) => ma.toString()), + // })) + // ).to.deep.equal( + // providers.map((prov) => ({ + // id: prov.ID, + // addrs: prov.Addrs, + // })) + // ); + // }); + // }); +// ... existing code ... + +it("should deduplicate concurrent requests to the same URL", async () => { + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const providers = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + ]; + + // load providers for the router to fetch + await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { + method: "POST", + headers: { + "Content-Type": "application/json" // Add this header + }, + body: JSON.stringify({ Providers: providers }), + }); + + // Reset call count before our test + await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); + + // Make multiple concurrent requests + const results = await Promise.all([ + all(client.getProviders(cid)), + all(client.getProviders(cid)), + all(client.getProviders(cid)), + all(client.getProviders(cid)), + ]); + + // Get the number of times the server was called + const callCountRes = await fetch( + `${process.env.ECHO_SERVER}/get-call-count` + ); + const callCount = parseInt(await callCountRes.text(), 10); + + // Verify server was only called once + expect(callCount).to.equal(1); + + // Verify all results are the same + results.forEach((resultProviders) => { + expect( + resultProviders.map((prov) => ({ id: prov.ID.toString(), - // eslint-disable-next-line max-nested-callbacks - addrs: prov.Addrs?.map(ma => ma.toString()) - }))).to.deep.equal(providers.map(prov => ({ + addrs: prov.Addrs?.map((ma) => ma.toString()), + })) + ).to.deep.equal( + providers.map((prov) => ({ id: prov.ID, - addrs: prov.Addrs - }))) - }) - }) - - itBrowser('should respect cache TTL', async () => { - const shortTTL = 100 // 100ms TTL for testing - const clientWithShortTTL = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - cacheTTL: shortTTL - }) - await start(clientWithShortTTL) - - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const providers = [{ - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }] + addrs: prov.Addrs, + })) + ); + }); +}); + + itBrowser("should respect cache TTL", async () => { + const shortTTL = 100; // 100ms TTL for testing + const clientWithShortTTL = createDelegatedRoutingV1HttpApiClient( + new URL(serverUrl), + { + cacheTTL: shortTTL, + } + ); + await start(clientWithShortTTL); + + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const providers = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + ]; // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: providers.map(prov => JSON.stringify(prov)).join('\n') - }) + method: "POST", + body: providers.map((prov) => JSON.stringify(prov)).join("\n"), + }); // Reset call count - await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) + await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); // First request should hit the server - await all(clientWithShortTTL.getProviders(cid)) + await all(clientWithShortTTL.getProviders(cid)); // Second and third request should use cache - await all(clientWithShortTTL.getProviders(cid)) - await all(clientWithShortTTL.getProviders(cid)) + await all(clientWithShortTTL.getProviders(cid)); + await all(clientWithShortTTL.getProviders(cid)); - let callCount = parseInt(await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), 10) - expect(callCount).to.equal(1) // Only one server call so far + let callCount = parseInt( + await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), + 10 + ); + expect(callCount).to.equal(1); // Only one server call so far // Wait for cache to expire - await new Promise(resolve => setTimeout(resolve, shortTTL + 50)) + await new Promise((resolve) => setTimeout(resolve, shortTTL + 50)); // This request should hit the server again because cache expired - await all(clientWithShortTTL.getProviders(cid)) + await all(clientWithShortTTL.getProviders(cid)); - callCount = parseInt(await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), 10) - expect(callCount).to.equal(2) // Second server call after cache expired + callCount = parseInt( + await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), + 10 + ); + expect(callCount).to.equal(2); // Second server call after cache expired - await stop(clientWithShortTTL) - }) -}) + await stop(clientWithShortTTL); + }); +}); diff --git a/packages/client/test/routings.spec.ts b/packages/client/test/routings.spec.ts index 9dac3b6..6c1018e 100644 --- a/packages/client/test/routings.spec.ts +++ b/packages/client/test/routings.spec.ts @@ -1,277 +1,319 @@ /* eslint-disable max-nested-callbacks */ /* eslint-env mocha */ -import { generateKeyPair } from '@libp2p/crypto/keys' -import { contentRoutingSymbol, peerRoutingSymbol, start, stop } from '@libp2p/interface' -import { peerIdFromPrivateKey } from '@libp2p/peer-id' -import { expect } from 'aegir/chai' -import { createIPNSRecord, marshalIPNSRecord, multihashToIPNSRoutingKey } from 'ipns' -import all from 'it-all' -import { CID } from 'multiformats/cid' -import { concat as uint8ArrayConcat } from 'uint8arrays/concat' -import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' -import { createDelegatedRoutingV1HttpApiClient, type DelegatedRoutingV1HttpApiClient } from '../src/index.js' -import type { PeerRouting, ContentRouting } from '@libp2p/interface' - -const serverUrl = process.env.ECHO_SERVER +import { generateKeyPair } from "@libp2p/crypto/keys"; +import { + contentRoutingSymbol, + peerRoutingSymbol, + start, + stop, +} from "@libp2p/interface"; +import { peerIdFromPrivateKey } from "@libp2p/peer-id"; +import { expect } from "aegir/chai"; +import { + createIPNSRecord, + marshalIPNSRecord, + multihashToIPNSRoutingKey, +} from "ipns"; +import all from "it-all"; +import { CID } from "multiformats/cid"; +import { concat as uint8ArrayConcat } from "uint8arrays/concat"; +import { fromString as uint8ArrayFromString } from "uint8arrays/from-string"; +import { + createDelegatedRoutingV1HttpApiClient, + type DelegatedRoutingV1HttpApiClient, +} from "../src/index.js"; +import type { PeerRouting, ContentRouting } from "@libp2p/interface"; + +const serverUrl = process.env.ECHO_SERVER; if (serverUrl == null) { - throw new Error('Echo server not configured correctly') + throw new Error("Echo server not configured correctly"); } -describe('libp2p content-routing', () => { - let client: DelegatedRoutingV1HttpApiClient +describe("libp2p content-routing", () => { + let client: DelegatedRoutingV1HttpApiClient; beforeEach(async () => { - client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { cacheTTL: 0 }) - await start(client) - }) + client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { + cacheTTL: 0, + }); + await start(client); + }); afterEach(async () => { - await stop(client) + await stop(client); - const res = await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) - await res.text() - }) + const res = await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); + await res.text(); + }); - it('should provide a content routing implementation', () => { - const routing = getContentRouting(client) + it("should provide a content routing implementation", () => { + const routing = getContentRouting(client); - expect(routing).to.be.ok() - }) + expect(routing).to.be.ok(); + }); - it('should find providers', async () => { - const routing = getContentRouting(client) + it("should find providers", async () => { + const routing = getContentRouting(client); if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - const providers = [{ - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, { - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/43.43.43.43/tcp/1234'] - }] - - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - - // load providers for the router to fetch + const providers = [ + { + Protocol: "transport-bitswap", + Schema: "bitswap", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + { + Protocol: "transport-bitswap", + Schema: "peer", + Metadata: "gBI=", + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/42.42.42.42/tcp/1234"], + }, + { + ID: (await generateKeyPair("Ed25519")).publicKey.toString(), + Addrs: ["/ip4/43.43.43.43/tcp/1234"], + }, + ]; + + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + + // load providers for the router to fetch with proper JSON formatting await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - body: providers.map(prov => JSON.stringify(prov)).join('\n') - }) - - const provs = await all(routing.findProviders(cid)) - expect(provs.map(prov => ({ - id: prov.id.toString(), - multiaddrs: prov.multiaddrs.map(ma => ma.toString()) - }))).to.deep.equal(providers.map(prov => ({ - id: prov.ID, - multiaddrs: prov.Addrs - }))) - }) - - it('should provide without error', async () => { - const routing = getContentRouting(client) + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ Providers: providers }), + }); + + const foundProviders = await all(routing.findProviders(cid)); + expect( + foundProviders.map((p) => ({ + id: p.id.toString(), + multiaddrs: p.multiaddrs.map((ma) => ma.toString()), + })) + ).to.deep.equal( + providers.map((prov) => ({ + id: prov.ID, + multiaddrs: prov.Addrs, + })) + ); + }); + + it("should provide without error", async () => { + const routing = getContentRouting(client); if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - await expect(routing.provide(cid)).to.eventually.be.undefined() - }) + await expect(routing.provide(cid)).to.eventually.be.undefined(); + }); - it('should put ipns records', async () => { - const routing = getContentRouting(client) + it("should put ipns records", async () => { + const routing = getContentRouting(client); if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const privateKey = await generateKeyPair('Ed25519') - const record = await createIPNSRecord(privateKey, cid, 0, 1000) - const key = multihashToIPNSRoutingKey(privateKey.publicKey.toMultihash()) + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const privateKey = await generateKeyPair("Ed25519"); + const record = await createIPNSRecord(privateKey, cid, 0, 1000); + const key = multihashToIPNSRoutingKey(privateKey.publicKey.toMultihash()); - await routing.put(key, marshalIPNSRecord(record)) + await routing.put(key, marshalIPNSRecord(record)); // load record that our client just PUT to remote server - const res = await fetch(`${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, { - method: 'GET', - headers: { - Accept: 'application/vnd.ipfs.ipns-record' + const res = await fetch( + `${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, + { + method: "GET", + headers: { + Accept: "application/vnd.ipfs.ipns-record", + }, } - }) + ); - const receivedRecord = new Uint8Array(await res.arrayBuffer()) - expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord) - }) + const receivedRecord = new Uint8Array(await res.arrayBuffer()); + expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord); + }); - it('should not put other records', async () => { - const routing = getContentRouting(client) + it("should not put other records", async () => { + const routing = getContentRouting(client); if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - const privateKey = await generateKeyPair('Ed25519') + const privateKey = await generateKeyPair("Ed25519"); const key = uint8ArrayConcat([ - uint8ArrayFromString('/an-unknown-key/'), - privateKey.publicKey.toMultihash().bytes - ]) + uint8ArrayFromString("/an-unknown-key/"), + privateKey.publicKey.toMultihash().bytes, + ]); - await routing.put(key, Uint8Array.from([0, 1, 2, 3, 4])) + await routing.put(key, Uint8Array.from([0, 1, 2, 3, 4])); - await expect(getServerCallCount()).to.eventually.equal(0) - }) + await expect(getServerCallCount()).to.eventually.equal(0); + }); - it('should get ipns records', async () => { - const routing = getContentRouting(client) + it("should get ipns records", async () => { + const routing = getContentRouting(client); if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const privateKey = await generateKeyPair('Ed25519') - const record = await createIPNSRecord(privateKey, cid, 0, 1000) + const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const privateKey = await generateKeyPair("Ed25519"); + const record = await createIPNSRecord(privateKey, cid, 0, 1000); // load record for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/vnd.ipfs.ipns-record' - }, - body: marshalIPNSRecord(record) - }) + await fetch( + `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, + { + method: "POST", + headers: { + "Content-Type": "application/vnd.ipfs.ipns-record", + }, + body: marshalIPNSRecord(record), + } + ); const key = uint8ArrayConcat([ - uint8ArrayFromString('/ipns/'), - privateKey.publicKey.toMultihash().bytes - ]) + uint8ArrayFromString("/ipns/"), + privateKey.publicKey.toMultihash().bytes, + ]); - const value = await routing.get(key) - expect(value).to.equalBytes(marshalIPNSRecord(record)) - }) + const value = await routing.get(key); + expect(value).to.equalBytes(marshalIPNSRecord(record)); + }); - it('should not get unknown records', async () => { - const routing = getContentRouting(client) + it("should not get unknown records", async () => { + const routing = getContentRouting(client); if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - const privateKey = await generateKeyPair('Ed25519') + const privateKey = await generateKeyPair("Ed25519"); const key = uint8ArrayConcat([ - uint8ArrayFromString('/am-unknown-key/'), - privateKey.publicKey.toMultihash().bytes - ]) + uint8ArrayFromString("/am-unknown-key/"), + privateKey.publicKey.toMultihash().bytes, + ]); - await expect(routing.get(key)).to.eventually.be.rejected - .with.property('name', 'NotFoundError') + await expect(routing.get(key)).to.eventually.be.rejected.with.property( + "name", + "NotFoundError" + ); - await expect(getServerCallCount()).to.eventually.equal(0) - }) -}) + await expect(getServerCallCount()).to.eventually.equal(0); + }); +}); -describe('libp2p peer-routing', () => { - let client: DelegatedRoutingV1HttpApiClient +describe("libp2p peer-routing", () => { + let client: DelegatedRoutingV1HttpApiClient; beforeEach(async () => { - client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl)) - await start(client) - }) + client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl)); + await start(client); + }); afterEach(async () => { - await stop(client) - }) + await stop(client); + }); - describe('peer routing', () => { - it('should provide a peer routing implementation', () => { - const routing = getPeerRouting(client) + describe("peer routing", () => { + it("should provide a peer routing implementation", () => { + const routing = getPeerRouting(client); - expect(routing).to.be.ok() - }) + expect(routing).to.be.ok(); + }); - it('should find peer info', async () => { - const routing = getPeerRouting(client) + it("should find peer info", async () => { + const routing = getPeerRouting(client); if (routing == null) { - throw new Error('PeerRouting not found') + throw new Error("PeerRouting not found"); } - const privateKey = await generateKeyPair('Ed25519') - const peerId = peerIdFromPrivateKey(privateKey) + const privateKey = await generateKeyPair("Ed25519"); + const peerId = peerIdFromPrivateKey(privateKey); - const records = [{ - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: peerId.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }] + const records = [ + { + Protocol: "transport-bitswap", + Schema: "peer", + Metadata: "gBI=", + ID: peerId.toString(), + Addrs: ["/ip4/41.41.41.41/tcp/1234"], + }, + ]; // load peer for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-peers/${peerId.toCID().toString()}`, { - method: 'POST', - body: records.map(prov => JSON.stringify(prov)).join('\n') - }) + await fetch( + `${process.env.ECHO_SERVER}/add-peers/${peerId.toCID().toString()}`, + { + method: "POST", + body: records.map((prov) => JSON.stringify(prov)).join("\n"), + } + ); - const peerInfo = await routing.findPeer(peerId) + const peerInfo = await routing.findPeer(peerId); - expect(peerInfo.id.toString()).to.equal(records[0].ID) - expect(peerInfo.multiaddrs.map(ma => ma.toString())).to.deep.equal(records[0].Addrs) - }) + expect(peerInfo.id.toString()).to.equal(records[0].ID); + expect(peerInfo.multiaddrs.map((ma) => ma.toString())).to.deep.equal( + records[0].Addrs + ); + }); - it('should not get closest peers', async () => { - const routing = getPeerRouting(client) + it("should not get closest peers", async () => { + const routing = getPeerRouting(client); if (routing == null) { - throw new Error('PeerRouting not found') + throw new Error("PeerRouting not found"); } - await expect(all(routing.getClosestPeers(Uint8Array.from([0, 1, 2, 3, 4])))).to.eventually.be.empty() - }) - }) -}) + await expect( + all(routing.getClosestPeers(Uint8Array.from([0, 1, 2, 3, 4]))) + ).to.eventually.be.empty(); + }); + }); +}); -function getContentRouting (obj: any): ContentRouting { - const routing = obj?.[contentRoutingSymbol] +function getContentRouting(obj: any): ContentRouting { + const routing = obj?.[contentRoutingSymbol]; if (routing == null) { - throw new Error('ContentRouting not found') + throw new Error("ContentRouting not found"); } - return routing + return routing; } -function getPeerRouting (obj: any): PeerRouting { - const routing = obj?.[peerRoutingSymbol] +function getPeerRouting(obj: any): PeerRouting { + const routing = obj?.[peerRoutingSymbol]; if (routing == null) { - throw new Error('PeerRouting not found') + throw new Error("PeerRouting not found"); } - return routing + return routing; } -async function getServerCallCount (): Promise { - const res = await fetch(`${process.env.ECHO_SERVER}/get-call-count`) - const body = await res.text() +async function getServerCallCount(): Promise { + const res = await fetch(`${process.env.ECHO_SERVER}/get-call-count`); + const body = await res.text(); - return Number(body) + return Number(body); } From 5d10d98ab12fc7440acbb6eeae792ddd24d8e81c Mon Sep 17 00:00:00 2001 From: Neha Kumari Date: Tue, 4 Feb 2025 18:49:43 +0530 Subject: [PATCH 2/9] fix: explicit Content-Type null check --- packages/client/src/client.ts | 24 +- packages/client/test/index.spec.ts | 795 +++++++++++--------------- packages/client/test/routings.spec.ts | 332 +++++------ 3 files changed, 518 insertions(+), 633 deletions(-) diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 264e6e2..82a9f60 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -122,16 +122,23 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV const getOptions = { headers: { Accept: 'application/x-ndjson' }, signal } const res = await this.#makeRequest(url.toString(), getOptions) - if (res.status === 404) { + if (res == null) { + throw new BadResponseError('No response received') + } + + if (!res.ok) { + if (res.status === 404) { // https://specs.ipfs.tech/routing/http-routing-v1/#response-status-codes // 404 (Not Found): must be returned if no matching records are found - throw new NotFoundError('No matching records found') - } + throw new NotFoundError('No matching records found') + } - if (res.status === 422) { + if (res.status === 422) { // https://specs.ipfs.tech/routing/http-routing-v1/#response-status-codes // 422 (Unprocessable Entity): request does not conform to schema or semantic constraints - throw new InvalidRequestError('Request does not conform to schema or semantic constraints') + throw new InvalidRequestError('Request does not conform to schema or semantic constraints') + } + throw new BadResponseError(`Unexpected status code: ${res.status}`) } if (res.body == null) { @@ -139,6 +146,10 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV } const contentType = res.headers.get('Content-Type') + if (contentType == null) { + throw new BadResponseError('No Content-Type header received') + } + if (contentType?.startsWith('application/json')) { const body = await res.json() @@ -384,10 +395,9 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV const requestMethod = options.method ?? 'GET' const key = `${requestMethod}-${url}` - // Only try to use cache for GET requests if (requestMethod === 'GET') { const cachedResponse = await this.cache?.match(url) - if (cachedResponse != null) { + if (cachedResponse?.ok === true) { // Check if the cached response has expired const expires = parseInt(cachedResponse.headers.get('x-cache-expires') ?? '0', 10) if (expires > Date.now()) { diff --git a/packages/client/test/index.spec.ts b/packages/client/test/index.spec.ts index 142a1a2..8be08c9 100644 --- a/packages/client/test/index.spec.ts +++ b/packages/client/test/index.spec.ts @@ -1,696 +1,571 @@ /* eslint-env mocha */ -import { generateKeyPair } from "@libp2p/crypto/keys"; -import { start, stop } from "@libp2p/interface"; -import { peerIdFromPrivateKey, peerIdFromString } from "@libp2p/peer-id"; -import { multiaddr } from "@multiformats/multiaddr"; -import { expect } from "aegir/chai"; -import { createIPNSRecord, marshalIPNSRecord } from "ipns"; -import all from "it-all"; -import { CID } from "multiformats/cid"; +import { generateKeyPair } from '@libp2p/crypto/keys' +import { start, stop } from '@libp2p/interface' +import { peerIdFromPrivateKey, peerIdFromString } from '@libp2p/peer-id' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import { createIPNSRecord, marshalIPNSRecord } from 'ipns' +import all from 'it-all' +import { CID } from 'multiformats/cid' import { createDelegatedRoutingV1HttpApiClient, - type DelegatedRoutingV1HttpApiClient, -} from "../src/index.js"; -import { itBrowser } from "./fixtures/it.js"; + type DelegatedRoutingV1HttpApiClient +} from '../src/index.js' +import { itBrowser } from './fixtures/it.js' if (process.env.ECHO_SERVER == null) { - throw new Error("Echo server not configured correctly"); + throw new Error('Echo server not configured correctly') } -const serverUrl = process.env.ECHO_SERVER; +const serverUrl = process.env.ECHO_SERVER -describe("delegated-routing-v1-http-api-client", () => { - let client: DelegatedRoutingV1HttpApiClient; +describe('delegated-routing-v1-http-api-client', () => { + let client: DelegatedRoutingV1HttpApiClient beforeEach(async () => { client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - cacheTTL: 0, - }); - await start(client); - }); + cacheTTL: 0 + }) + await start(client) + }) afterEach(async () => { - await stop(client); - }); - - // it("should find providers", async () => { - // const providers = [ - // { - // Protocol: "transport-bitswap", - // Schema: "bitswap", - // Metadata: "gBI=", - // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - // Addrs: ["/ip4/41.41.41.41/tcp/1234"], - // }, - // { - // Protocol: "transport-bitswap", - // Schema: "peer", - // Metadata: "gBI=", - // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - // Addrs: ["/ip4/42.42.42.42/tcp/1234"], - // }, - // { - // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - // Addrs: ["/ip4/43.43.43.43/tcp/1234"], - // }, - // ]; - - // const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - - // // load providers for the router to fetch - // await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - // method: "POST", - // headers: { - // 'Content-Type': 'application/json' - // }, - // body: JSON.stringify({ Providers: providers }), - // }); - - // await new Promise(resolve => setTimeout(resolve, 100)) - - // const provs = await all(client.getProviders(cid)); - // console.log("Retrieved providers:", provs); - - // expect( - // provs.map((prov) => ({ - // id: prov.ID.toString(), - // addrs: prov.Addrs?.map((ma) => ma.toString()), - // })) - // ).to.deep.equal( - // providers.map((prov) => ({ - // id: prov.ID, - // addrs: prov.Addrs, - // })) - // ); - // }); - it("should find providers", async () => { + await stop(client) + }) + + it('should find providers', async () => { const providers = [ { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] }, { - Protocol: "transport-bitswap", - Schema: "peer", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/42.42.42.42/tcp/1234"], + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] }, { - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/43.43.43.43/tcp/1234"], - }, - ]; - - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/43.43.43.43/tcp/1234'] + } + ] - console.log("Sending providers:", JSON.stringify(providers, null, 2)); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch - const response = await fetch( + await fetch( `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers }), + body: JSON.stringify({ Providers: providers }) } - ); + ) - console.log("Add providers response:", { - status: response.status, - statusText: response.statusText, - body: await response.text(), - }); - - // Add delay to ensure server processes the request - await new Promise((resolve) => setTimeout(resolve, 100)); - - const provs = await all(client.getProviders(cid)); - console.log("Retrieved providers:", JSON.stringify(provs, null, 2)); + await new Promise((resolve) => setTimeout(resolve, 100)) + const provs = await all(client.getProviders(cid)) expect( provs.map((prov) => ({ id: prov.ID.toString(), - addrs: prov.Addrs?.map((ma) => ma.toString()), + addrs: prov.Addrs?.map((ma) => ma.toString()) })) ).to.deep.equal( providers.map((prov) => ({ id: prov.ID, - addrs: prov.Addrs, + addrs: prov.Addrs })) - ); - }); + ) + }) - /*content type test cases */ - it("should handle different Content-Type headers for JSON responses", async () => { + it('should handle different Content-Type headers for JSON responses', async () => { const providers = [ { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], - }, - ]; + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + } + ] - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') const contentTypes = [ - "application/json", - "application/json; charset=utf-8", - "application/json;charset=UTF-8", - ]; + 'application/json', + 'application/json; charset=utf-8', + 'application/json;charset=UTF-8' + ] for (const contentType of contentTypes) { // Add providers with proper payload structure await fetch( `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": contentType, + 'Content-Type': contentType }, - body: JSON.stringify({ Providers: providers }), + body: JSON.stringify({ Providers: providers }) } - ); + ) - await new Promise((resolve) => setTimeout(resolve, 100)); + await new Promise((resolve) => setTimeout(resolve, 100)) - const provs = await all(client.getProviders(cid)); - console.log( - `Retrieved providers for ${contentType}:`, - JSON.stringify(provs, null, 2) - ); + const provs = await all(client.getProviders(cid)) expect(provs).to.have.lengthOf( 1, `Failed for Content-Type: ${contentType}` - ); + ) // Updated assertions to match the transformed structure expect(provs[0]).to.deep.include({ - Schema: "peer", - Metadata: "gBI=", - Protocols: ["transport-bitswap"], // Protocol is moved to Protocols array - }); - expect(provs[0].ID.toString()).to.equal(providers[0].ID); - expect(provs[0].Addrs[0].toString()).to.equal(providers[0].Addrs[0]); + Schema: 'peer', + Metadata: 'gBI=', + Protocols: ['transport-bitswap'] // Protocol is moved to Protocols array + }) + expect(provs[0].ID.toString()).to.equal(providers[0].ID) + expect(provs[0].Addrs[0].toString()).to.equal(providers[0].Addrs[0]) } - }); + }) - it("should handle non-json input", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + it('should handle non-json input', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - // Try to add invalid data const response = await fetch( `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "text/plain", + 'Content-Type': 'text/plain' }, - body: "not json", + body: 'not json' } - ); + ) - // Verify error response - expect(response.status).to.equal(400); - const errorData = await response.json(); - expect(errorData).to.have.property("error"); - expect(errorData).to.have.property("code", "ERR_INVALID_INPUT"); + expect(response.status).to.equal(400) + const errorData = await response.json() + expect(errorData).to.have.property('error') + expect(errorData).to.have.property('code', 'ERR_INVALID_INPUT') - // Verify no providers were added - const provs = await all(client.getProviders(cid)); - expect(provs).to.be.empty; - }); + const provs = await all(client.getProviders(cid)) + expect(provs).to.be.empty() + }) - it("should add filter parameters the query of the request url", async () => { + it('should add filter parameters the query of the request url', async () => { const providers = [ { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: [], + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: [] }, { - Protocol: "transport-bitswap", - Schema: "peer", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/42.42.42.42/tcp/1234"], + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] }, { - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: [], - }, - ]; + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: [] + } + ] - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", - body: providers.map((prov) => JSON.stringify(prov)).join("\n"), - }); + method: 'POST', + body: providers.map((prov) => JSON.stringify(prov)).join('\n') + }) await all( client.getProviders(cid, { - filterProtocols: ["transport-bitswap", "unknown"], - filterAddrs: ["webtransport", "!p2p-circuit"], + filterProtocols: ['transport-bitswap', 'unknown'], + filterAddrs: ['webtransport', '!p2p-circuit'] }) - ); + ) // Check if the correct URL was called with filter parameters const lastCalledUrl = await fetch( `${process.env.ECHO_SERVER}/last-called-url` - ); - const lastCalledUrlText = await lastCalledUrl.text(); + ) + const lastCalledUrlText = await lastCalledUrl.text() - const searchParams = new URLSearchParams(lastCalledUrlText.split("?")[1]); + const searchParams = new URLSearchParams(lastCalledUrlText.split('?')[1]) - expect(searchParams.get("filter-protocols")).to.equal( - "transport-bitswap,unknown" - ); - expect(searchParams.get("filter-addrs")).to.equal( - "webtransport,!p2p-circuit" - ); - }); + expect(searchParams.get('filter-protocols')).to.equal( + 'transport-bitswap,unknown' + ) + expect(searchParams.get('filter-addrs')).to.equal( + 'webtransport,!p2p-circuit' + ) + }) - it("should add filter parameters the query of the request url based on global filter", async () => { + it('should add filter parameters the query of the request url based on global filter', async () => { const client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - filterProtocols: ["transport-bitswap", "unknown"], - filterAddrs: ["tcp", "!p2p-circuit"], - }); - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + filterProtocols: ['transport-bitswap', 'unknown'], + filterAddrs: ['tcp', '!p2p-circuit'] + }) + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - await all(client.getProviders(cid)); + await all(client.getProviders(cid)) // Check if the correct URL was called with filter parameters const lastCalledUrl = await fetch( `${process.env.ECHO_SERVER}/last-called-url` - ); - const lastCalledUrlText = await lastCalledUrl.text(); + ) + const lastCalledUrlText = await lastCalledUrl.text() - const searchParams = new URLSearchParams(lastCalledUrlText.split("?")[1]); + const searchParams = new URLSearchParams(lastCalledUrlText.split('?')[1]) - expect(searchParams.get("filter-protocols")).to.equal( - "transport-bitswap,unknown" - ); - expect(searchParams.get("filter-addrs")).to.equal("tcp,!p2p-circuit"); - }); + expect(searchParams.get('filter-protocols')).to.equal( + 'transport-bitswap,unknown' + ) + expect(searchParams.get('filter-addrs')).to.equal('tcp,!p2p-circuit') + }) - it("should handle non-json input", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + it('should handle non-json input without content-type header', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", - body: "not json", - }); + method: 'POST', + body: 'not json' + }) - const provs = await all(client.getProviders(cid)); - expect(provs).to.be.empty(); - }); + const provs = await all(client.getProviders(cid)) + expect(provs).to.be.empty() + }) - it("should handle bad input providers", async () => { + it('should handle bad input providers', async () => { const providers = [ { - Metadata: "gBI=", + Metadata: 'gBI=', Provider: { - Bad: "field", - }, + Bad: 'field' + } }, { - Metadata: "gBI=", - ContextID: "", + Metadata: 'gBI=', + ContextID: '', Another: { - Bad: "field", - }, - }, - ]; + Bad: 'field' + } + } + ] - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", - body: providers.map((prov) => JSON.stringify(prov)).join("\n"), - }); + method: 'POST', + body: providers.map((prov) => JSON.stringify(prov)).join('\n') + }) - const provs = await all(client.getProviders(cid)); - expect(provs).to.be.empty(); - }); + const provs = await all(client.getProviders(cid)) + expect(provs).to.be.empty() + }) - it("should handle empty input", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + it('should handle empty input', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const provs = await all(client.getProviders(cid)); - expect(provs).to.be.empty(); - }); + const provs = await all(client.getProviders(cid)) + expect(provs).to.be.empty() + }) - it("should conform records to peer schema", async () => { - const privateKey = await generateKeyPair("Ed25519"); + it('should conform records to peer schema', async () => { + const privateKey = await generateKeyPair('Ed25519') const records = [ { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', ID: privateKey.publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], + Addrs: ['/ip4/41.41.41.41/tcp/1234'] }, { - Protocol: "transport-saddle", - Schema: "horse-ride", - Metadata: "gBI=", + Protocol: 'transport-saddle', + Schema: 'horse-ride', + Metadata: 'gBI=', ID: privateKey.publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], + Addrs: ['/ip4/41.41.41.41/tcp/1234'] }, { - Protocols: ["transport-bitswap"], - Schema: "peer", - Metadata: "gBI=", + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', ID: privateKey.publicKey.toString(), - Addrs: ["/ip4/42.42.42.42/tcp/1234"], + Addrs: ['/ip4/42.42.42.42/tcp/1234'] }, { - Protocol: "transport-bitswap", - Schema: "peer", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/42.42.42.42/tcp/1234"], + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] }, { - Schema: "peer", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - }, - ]; + Schema: 'peer', + ID: (await generateKeyPair('Ed25519')).publicKey.toString() + } + ] const peers = [ { - Protocols: ["transport-bitswap"], - Schema: "peer", - Metadata: "gBI=", + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', ID: peerIdFromString(records[0].ID), - Addrs: [multiaddr("/ip4/41.41.41.41/tcp/1234")], + Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] }, { - Protocols: ["transport-saddle"], - Schema: "peer", - Metadata: "gBI=", + Protocols: ['transport-saddle'], + Schema: 'peer', + Metadata: 'gBI=', ID: peerIdFromString(records[1].ID), - Addrs: [multiaddr("/ip4/41.41.41.41/tcp/1234")], + Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] }, { - Protocols: ["transport-bitswap"], - Schema: "peer", - Metadata: "gBI=", + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', ID: peerIdFromString(records[2].ID), - Addrs: [multiaddr("/ip4/42.42.42.42/tcp/1234")], + Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] }, { - Protocols: ["transport-bitswap"], - Schema: "peer", - Metadata: "gBI=", + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', ID: peerIdFromString(records[3].ID), - Addrs: [multiaddr("/ip4/42.42.42.42/tcp/1234")], + Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] }, { Protocols: [], - Schema: "peer", + Schema: 'peer', ID: peerIdFromString(records[4].ID), - Addrs: [], - }, - ]; + Addrs: [] + } + ] // load peer for the router to fetch await fetch( `${process.env.ECHO_SERVER}/add-peers/${privateKey.publicKey.toCID()}`, { - method: "POST", - body: records.map((prov) => JSON.stringify(prov)).join("\n"), + method: 'POST', + body: records.map((prov) => JSON.stringify(prov)).join('\n') } - ); + ) const peerRecords = await all( client.getPeers(peerIdFromPrivateKey(privateKey)) - ); + ) expect( peerRecords.map((peerRecord) => ({ ...peerRecord, ID: peerRecord.ID.toString(), - Addrs: peerRecord.Addrs?.map((ma) => ma.toString()) ?? [], + Addrs: peerRecord.Addrs?.map((ma) => ma.toString()) ?? [] })) ).to.deep.equal( peers.map((peerRecord) => ({ ...peerRecord, ID: peerRecord.ID.toString(), - Addrs: peerRecord.Addrs?.map((ma) => ma.toString()), + Addrs: peerRecord.Addrs?.map((ma) => ma.toString()) })) - ); - }); + ) + }) - it("should get ipns record", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - const privateKey = await generateKeyPair("Ed25519"); - const record = await createIPNSRecord(privateKey, cid, 0, 1000); + it('should get ipns record', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const privateKey = await generateKeyPair('Ed25519') + const record = await createIPNSRecord(privateKey, cid, 0, 1000) // load record for the router to fetch await fetch( `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/vnd.ipfs.ipns-record", + 'Content-Type': 'application/vnd.ipfs.ipns-record' }, - body: marshalIPNSRecord(record), + body: marshalIPNSRecord(record) } - ); + ) - const ipnsRecord = await client.getIPNS(privateKey.publicKey.toCID()); + const ipnsRecord = await client.getIPNS(privateKey.publicKey.toCID()) expect(marshalIPNSRecord(ipnsRecord)).to.equalBytes( marshalIPNSRecord(record) - ); - }); + ) + }) - it("get ipns record fails with bad record", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - const privateKey = await generateKeyPair("Ed25519"); - const otherPrivateKey = await generateKeyPair("Ed25519"); - const record = await createIPNSRecord(otherPrivateKey, cid, 0, 1000); + it('get ipns record fails with bad record', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const privateKey = await generateKeyPair('Ed25519') + const otherPrivateKey = await generateKeyPair('Ed25519') + const record = await createIPNSRecord(otherPrivateKey, cid, 0, 1000) // load record for the router to fetch await fetch( `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/vnd.ipfs.ipns-record", + 'Content-Type': 'application/vnd.ipfs.ipns-record' }, - body: marshalIPNSRecord(record), + body: marshalIPNSRecord(record) } - ); + ) - await expect(client.getIPNS(privateKey.publicKey.toCID())).to.be.rejected(); - }); + await expect(client.getIPNS(privateKey.publicKey.toCID())).to.be.rejected() + }) - it("should put ipns", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - const privateKey = await generateKeyPair("Ed25519"); - const record = await createIPNSRecord(privateKey, cid, 0, 1000); + it('should put ipns', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const privateKey = await generateKeyPair('Ed25519') + const record = await createIPNSRecord(privateKey, cid, 0, 1000) - await client.putIPNS(privateKey.publicKey.toCID(), record); + await client.putIPNS(privateKey.publicKey.toCID(), record) // load record that our client just PUT to remote server const res = await fetch( `${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, { - method: "GET", + method: 'GET', headers: { - Accept: "application/vnd.ipfs.ipns-record", - }, + Accept: 'application/vnd.ipfs.ipns-record' + } } - ); - - const receivedRecord = new Uint8Array(await res.arrayBuffer()); - expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord); - }); - - // it("should deduplicate concurrent requests to the same URL", async () => { - // const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - // const providers = [ - // { - // Protocol: "transport-bitswap", - // Schema: "bitswap", - // Metadata: "gBI=", - // ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - // Addrs: ["/ip4/41.41.41.41/tcp/1234"], - // }, - // ]; - - // // load providers for the router to fetch - // await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - // method: "POST", - // body: providers.map((prov) => JSON.stringify(prov)).join("\n"), - // }); - - // // Reset call count before our test - // await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); - - // // Make multiple concurrent requests - // const results = await Promise.all([ - // all(client.getProviders(cid)), - // all(client.getProviders(cid)), - // all(client.getProviders(cid)), - // all(client.getProviders(cid)), - // ]); - - // // Get the number of times the server was called - // const callCountRes = await fetch( - // `${process.env.ECHO_SERVER}/get-call-count` - // ); - // const callCount = parseInt(await callCountRes.text(), 10); - - // // Verify server was only called once - // expect(callCount).to.equal(1); - - // // Verify all results are the same - // results.forEach((resultProviders) => { - // expect( - // resultProviders.map((prov) => ({ - // id: prov.ID.toString(), - // // eslint-disable-next-line max-nested-callbacks - // addrs: prov.Addrs?.map((ma) => ma.toString()), - // })) - // ).to.deep.equal( - // providers.map((prov) => ({ - // id: prov.ID, - // addrs: prov.Addrs, - // })) - // ); - // }); - // }); -// ... existing code ... - -it("should deduplicate concurrent requests to the same URL", async () => { - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - const providers = [ - { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], - }, - ]; - - // load providers for the router to fetch - await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", - headers: { - "Content-Type": "application/json" // Add this header - }, - body: JSON.stringify({ Providers: providers }), - }); - - // Reset call count before our test - await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); - - // Make multiple concurrent requests - const results = await Promise.all([ - all(client.getProviders(cid)), - all(client.getProviders(cid)), - all(client.getProviders(cid)), - all(client.getProviders(cid)), - ]); - - // Get the number of times the server was called - const callCountRes = await fetch( - `${process.env.ECHO_SERVER}/get-call-count` - ); - const callCount = parseInt(await callCountRes.text(), 10); + ) - // Verify server was only called once - expect(callCount).to.equal(1); + const receivedRecord = new Uint8Array(await res.arrayBuffer()) + expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord) + }) - // Verify all results are the same - results.forEach((resultProviders) => { - expect( - resultProviders.map((prov) => ({ - id: prov.ID.toString(), - addrs: prov.Addrs?.map((ma) => ma.toString()), - })) - ).to.deep.equal( - providers.map((prov) => ({ - id: prov.ID, - addrs: prov.Addrs, - })) - ); - }); -}); + it('should deduplicate concurrent requests to the same URL', async () => { + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const providers = [ + { + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + } + ] - itBrowser("should respect cache TTL", async () => { - const shortTTL = 100; // 100ms TTL for testing + // load providers for the router to fetch + await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' // Add this header + }, + body: JSON.stringify({ Providers: providers }) + }) + + // Reset call count before our test + await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) + + // Make multiple concurrent requests + const results = await Promise.all([ + all(client.getProviders(cid)), + all(client.getProviders(cid)), + all(client.getProviders(cid)), + all(client.getProviders(cid)) + ]) + + // Get the number of times the server was called + const callCountRes = await fetch( + `${process.env.ECHO_SERVER}/get-call-count` + ) + const callCount = parseInt(await callCountRes.text(), 10) + + // Verify server was only called once + expect(callCount).to.equal(1) + + // Verify all results are the same + results.forEach((resultProviders) => { + expect( + resultProviders.map((prov) => ({ + id: prov.ID.toString(), + addrs: prov.Addrs?.map((ma) => ma.toString()) + })) + ).to.deep.equal( + providers.map((prov) => ({ + id: prov.ID, + addrs: prov.Addrs + })) + ) + }) + }) + + itBrowser('should respect cache TTL', async () => { + const shortTTL = 100 // 100ms TTL for testing const clientWithShortTTL = createDelegatedRoutingV1HttpApiClient( new URL(serverUrl), { - cacheTTL: shortTTL, + cacheTTL: shortTTL } - ); - await start(clientWithShortTTL); + ) + await start(clientWithShortTTL) - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') const providers = [ { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], - }, - ]; + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + } + ] // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", - body: providers.map((prov) => JSON.stringify(prov)).join("\n"), - }); + method: 'POST', + body: providers.map((prov) => JSON.stringify(prov)).join('\n') + }) // Reset call count - await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); + await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) // First request should hit the server - await all(clientWithShortTTL.getProviders(cid)); + await all(clientWithShortTTL.getProviders(cid)) // Second and third request should use cache - await all(clientWithShortTTL.getProviders(cid)); - await all(clientWithShortTTL.getProviders(cid)); + await all(clientWithShortTTL.getProviders(cid)) + await all(clientWithShortTTL.getProviders(cid)) let callCount = parseInt( await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), 10 - ); - expect(callCount).to.equal(1); // Only one server call so far + ) + expect(callCount).to.equal(1) // Only one server call so far // Wait for cache to expire - await new Promise((resolve) => setTimeout(resolve, shortTTL + 50)); + await new Promise((resolve) => setTimeout(resolve, shortTTL + 50)) // This request should hit the server again because cache expired - await all(clientWithShortTTL.getProviders(cid)); + await all(clientWithShortTTL.getProviders(cid)) callCount = parseInt( await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), 10 - ); - expect(callCount).to.equal(2); // Second server call after cache expired + ) + expect(callCount).to.equal(2) // Second server call after cache expired - await stop(clientWithShortTTL); - }); -}); + await stop(clientWithShortTTL) + }) +}) diff --git a/packages/client/test/routings.spec.ts b/packages/client/test/routings.spec.ts index 6c1018e..bfc86a8 100644 --- a/packages/client/test/routings.spec.ts +++ b/packages/client/test/routings.spec.ts @@ -1,319 +1,319 @@ /* eslint-disable max-nested-callbacks */ /* eslint-env mocha */ -import { generateKeyPair } from "@libp2p/crypto/keys"; +import { generateKeyPair } from '@libp2p/crypto/keys' import { contentRoutingSymbol, peerRoutingSymbol, start, - stop, -} from "@libp2p/interface"; -import { peerIdFromPrivateKey } from "@libp2p/peer-id"; -import { expect } from "aegir/chai"; + stop +} from '@libp2p/interface' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { expect } from 'aegir/chai' import { createIPNSRecord, marshalIPNSRecord, - multihashToIPNSRoutingKey, -} from "ipns"; -import all from "it-all"; -import { CID } from "multiformats/cid"; -import { concat as uint8ArrayConcat } from "uint8arrays/concat"; -import { fromString as uint8ArrayFromString } from "uint8arrays/from-string"; + multihashToIPNSRoutingKey +} from 'ipns' +import all from 'it-all' +import { CID } from 'multiformats/cid' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import { createDelegatedRoutingV1HttpApiClient, - type DelegatedRoutingV1HttpApiClient, -} from "../src/index.js"; -import type { PeerRouting, ContentRouting } from "@libp2p/interface"; + type DelegatedRoutingV1HttpApiClient +} from '../src/index.js' +import type { PeerRouting, ContentRouting } from '@libp2p/interface' -const serverUrl = process.env.ECHO_SERVER; +const serverUrl = process.env.ECHO_SERVER if (serverUrl == null) { - throw new Error("Echo server not configured correctly"); + throw new Error('Echo server not configured correctly') } -describe("libp2p content-routing", () => { - let client: DelegatedRoutingV1HttpApiClient; +describe('libp2p content-routing', () => { + let client: DelegatedRoutingV1HttpApiClient beforeEach(async () => { client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - cacheTTL: 0, - }); - await start(client); - }); + cacheTTL: 0 + }) + await start(client) + }) afterEach(async () => { - await stop(client); + await stop(client) - const res = await fetch(`${process.env.ECHO_SERVER}/reset-call-count`); - await res.text(); - }); + const res = await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) + await res.text() + }) - it("should provide a content routing implementation", () => { - const routing = getContentRouting(client); + it('should provide a content routing implementation', () => { + const routing = getContentRouting(client) - expect(routing).to.be.ok(); - }); + expect(routing).to.be.ok() + }) - it("should find providers", async () => { - const routing = getContentRouting(client); + it('should find providers', async () => { + const routing = getContentRouting(client) if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } const providers = [ { - Protocol: "transport-bitswap", - Schema: "bitswap", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] }, { - Protocol: "transport-bitswap", - Schema: "peer", - Metadata: "gBI=", - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/42.42.42.42/tcp/1234"], + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] }, { - ID: (await generateKeyPair("Ed25519")).publicKey.toString(), - Addrs: ["/ip4/43.43.43.43/tcp/1234"], - }, - ]; + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/43.43.43.43/tcp/1234'] + } + ] - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch with proper JSON formatting await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers }), - }); + body: JSON.stringify({ Providers: providers }) + }) - const foundProviders = await all(routing.findProviders(cid)); + const foundProviders = await all(routing.findProviders(cid)) expect( foundProviders.map((p) => ({ id: p.id.toString(), - multiaddrs: p.multiaddrs.map((ma) => ma.toString()), + multiaddrs: p.multiaddrs.map((ma) => ma.toString()) })) ).to.deep.equal( providers.map((prov) => ({ id: prov.ID, - multiaddrs: prov.Addrs, + multiaddrs: prov.Addrs })) - ); - }); + ) + }) - it("should provide without error", async () => { - const routing = getContentRouting(client); + it('should provide without error', async () => { + const routing = getContentRouting(client) if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - await expect(routing.provide(cid)).to.eventually.be.undefined(); - }); + await expect(routing.provide(cid)).to.eventually.be.undefined() + }) - it("should put ipns records", async () => { - const routing = getContentRouting(client); + it('should put ipns records', async () => { + const routing = getContentRouting(client) if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - const privateKey = await generateKeyPair("Ed25519"); - const record = await createIPNSRecord(privateKey, cid, 0, 1000); - const key = multihashToIPNSRoutingKey(privateKey.publicKey.toMultihash()); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const privateKey = await generateKeyPair('Ed25519') + const record = await createIPNSRecord(privateKey, cid, 0, 1000) + const key = multihashToIPNSRoutingKey(privateKey.publicKey.toMultihash()) - await routing.put(key, marshalIPNSRecord(record)); + await routing.put(key, marshalIPNSRecord(record)) // load record that our client just PUT to remote server const res = await fetch( `${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, { - method: "GET", + method: 'GET', headers: { - Accept: "application/vnd.ipfs.ipns-record", - }, + Accept: 'application/vnd.ipfs.ipns-record' + } } - ); + ) - const receivedRecord = new Uint8Array(await res.arrayBuffer()); - expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord); - }); + const receivedRecord = new Uint8Array(await res.arrayBuffer()) + expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord) + }) - it("should not put other records", async () => { - const routing = getContentRouting(client); + it('should not put other records', async () => { + const routing = getContentRouting(client) if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } - const privateKey = await generateKeyPair("Ed25519"); + const privateKey = await generateKeyPair('Ed25519') const key = uint8ArrayConcat([ - uint8ArrayFromString("/an-unknown-key/"), - privateKey.publicKey.toMultihash().bytes, - ]); + uint8ArrayFromString('/an-unknown-key/'), + privateKey.publicKey.toMultihash().bytes + ]) - await routing.put(key, Uint8Array.from([0, 1, 2, 3, 4])); + await routing.put(key, Uint8Array.from([0, 1, 2, 3, 4])) - await expect(getServerCallCount()).to.eventually.equal(0); - }); + await expect(getServerCallCount()).to.eventually.equal(0) + }) - it("should get ipns records", async () => { - const routing = getContentRouting(client); + it('should get ipns records', async () => { + const routing = getContentRouting(client) if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } - const cid = CID.parse("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"); - const privateKey = await generateKeyPair("Ed25519"); - const record = await createIPNSRecord(privateKey, cid, 0, 1000); + const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') + const privateKey = await generateKeyPair('Ed25519') + const record = await createIPNSRecord(privateKey, cid, 0, 1000) // load record for the router to fetch await fetch( `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { - method: "POST", + method: 'POST', headers: { - "Content-Type": "application/vnd.ipfs.ipns-record", + 'Content-Type': 'application/vnd.ipfs.ipns-record' }, - body: marshalIPNSRecord(record), + body: marshalIPNSRecord(record) } - ); + ) const key = uint8ArrayConcat([ - uint8ArrayFromString("/ipns/"), - privateKey.publicKey.toMultihash().bytes, - ]); + uint8ArrayFromString('/ipns/'), + privateKey.publicKey.toMultihash().bytes + ]) - const value = await routing.get(key); - expect(value).to.equalBytes(marshalIPNSRecord(record)); - }); + const value = await routing.get(key) + expect(value).to.equalBytes(marshalIPNSRecord(record)) + }) - it("should not get unknown records", async () => { - const routing = getContentRouting(client); + it('should not get unknown records', async () => { + const routing = getContentRouting(client) if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } - const privateKey = await generateKeyPair("Ed25519"); + const privateKey = await generateKeyPair('Ed25519') const key = uint8ArrayConcat([ - uint8ArrayFromString("/am-unknown-key/"), - privateKey.publicKey.toMultihash().bytes, - ]); + uint8ArrayFromString('/am-unknown-key/'), + privateKey.publicKey.toMultihash().bytes + ]) await expect(routing.get(key)).to.eventually.be.rejected.with.property( - "name", - "NotFoundError" - ); + 'name', + 'NotFoundError' + ) - await expect(getServerCallCount()).to.eventually.equal(0); - }); -}); + await expect(getServerCallCount()).to.eventually.equal(0) + }) +}) -describe("libp2p peer-routing", () => { - let client: DelegatedRoutingV1HttpApiClient; +describe('libp2p peer-routing', () => { + let client: DelegatedRoutingV1HttpApiClient beforeEach(async () => { - client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl)); - await start(client); - }); + client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl)) + await start(client) + }) afterEach(async () => { - await stop(client); - }); + await stop(client) + }) - describe("peer routing", () => { - it("should provide a peer routing implementation", () => { - const routing = getPeerRouting(client); + describe('peer routing', () => { + it('should provide a peer routing implementation', () => { + const routing = getPeerRouting(client) - expect(routing).to.be.ok(); - }); + expect(routing).to.be.ok() + }) - it("should find peer info", async () => { - const routing = getPeerRouting(client); + it('should find peer info', async () => { + const routing = getPeerRouting(client) if (routing == null) { - throw new Error("PeerRouting not found"); + throw new Error('PeerRouting not found') } - const privateKey = await generateKeyPair("Ed25519"); - const peerId = peerIdFromPrivateKey(privateKey); + const privateKey = await generateKeyPair('Ed25519') + const peerId = peerIdFromPrivateKey(privateKey) const records = [ { - Protocol: "transport-bitswap", - Schema: "peer", - Metadata: "gBI=", + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', ID: peerId.toString(), - Addrs: ["/ip4/41.41.41.41/tcp/1234"], - }, - ]; + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + } + ] // load peer for the router to fetch await fetch( `${process.env.ECHO_SERVER}/add-peers/${peerId.toCID().toString()}`, { - method: "POST", - body: records.map((prov) => JSON.stringify(prov)).join("\n"), + method: 'POST', + body: records.map((prov) => JSON.stringify(prov)).join('\n') } - ); + ) - const peerInfo = await routing.findPeer(peerId); + const peerInfo = await routing.findPeer(peerId) - expect(peerInfo.id.toString()).to.equal(records[0].ID); + expect(peerInfo.id.toString()).to.equal(records[0].ID) expect(peerInfo.multiaddrs.map((ma) => ma.toString())).to.deep.equal( records[0].Addrs - ); - }); + ) + }) - it("should not get closest peers", async () => { - const routing = getPeerRouting(client); + it('should not get closest peers', async () => { + const routing = getPeerRouting(client) if (routing == null) { - throw new Error("PeerRouting not found"); + throw new Error('PeerRouting not found') } await expect( all(routing.getClosestPeers(Uint8Array.from([0, 1, 2, 3, 4]))) - ).to.eventually.be.empty(); - }); - }); -}); + ).to.eventually.be.empty() + }) + }) +}) -function getContentRouting(obj: any): ContentRouting { - const routing = obj?.[contentRoutingSymbol]; +function getContentRouting (obj: any): ContentRouting { + const routing = obj?.[contentRoutingSymbol] if (routing == null) { - throw new Error("ContentRouting not found"); + throw new Error('ContentRouting not found') } - return routing; + return routing } -function getPeerRouting(obj: any): PeerRouting { - const routing = obj?.[peerRoutingSymbol]; +function getPeerRouting (obj: any): PeerRouting { + const routing = obj?.[peerRoutingSymbol] if (routing == null) { - throw new Error("PeerRouting not found"); + throw new Error('PeerRouting not found') } - return routing; + return routing } -async function getServerCallCount(): Promise { - const res = await fetch(`${process.env.ECHO_SERVER}/get-call-count`); - const body = await res.text(); +async function getServerCallCount (): Promise { + const res = await fetch(`${process.env.ECHO_SERVER}/get-call-count`) + const body = await res.text() - return Number(body); + return Number(body) } From 6c6de7f21cd8be1ea972761a03c5acfc0e958792 Mon Sep 17 00:00:00 2001 From: Neha Kumari Date: Tue, 4 Feb 2025 21:41:50 +0530 Subject: [PATCH 3/9] fix-eslint-issues --- packages/client/.aegir.js | 163 +++++++++------ packages/client/src/client.ts | 6 +- packages/client/test/index.spec.ts | 288 ++++++++++++-------------- packages/client/test/routings.spec.ts | 52 ++--- 4 files changed, 257 insertions(+), 252 deletions(-) diff --git a/packages/client/.aegir.js b/packages/client/.aegir.js index b5b4be1..aad9e54 100644 --- a/packages/client/.aegir.js +++ b/packages/client/.aegir.js @@ -19,77 +19,120 @@ const options = { next(); lastCalledUrl = req.url; }); + // echo.polka.post("/add-providers/:cid", (req, res) => { + // callCount++; + // try { + // console.log("Received POST request body:", req.body); + // console.log("Content-Type:", req.headers["content-type"]); - echo.polka.post("/add-providers/:cid", (req, res) => { - callCount++; + // if (req.headers["content-type"]?.includes("application/json")) { + // const data = + // typeof req.body === "string" + // ? { + // Providers: req.body + // .split("\n") + // .map((line) => JSON.parse(line)), + // } + // : req.body; + // providers.set(req.params.cid, data); + // res.end(JSON.stringify({ success: true })); + // } else { + // res.statusCode = 400; + // res.end( + // JSON.stringify({ + // error: "Invalid content type. Expected application/json", + // code: "ERR_INVALID_INPUT", + // }) + // ); + // providers.delete(req.params.cid); + // } + // } catch (err) { + // console.error("Error in add-providers:", err); + // res.statusCode = 400; + // res.end( + // JSON.stringify({ + // error: err.message, + // code: "ERR_INVALID_INPUT", + // }) + // ); + // providers.delete(req.params.cid); + // } + // }); + echo.polka.post('/add-providers/:cid', (req, res) => { + callCount++ try { - console.log("Received POST request body:", req.body); - console.log("Content-Type:", req.headers["content-type"]); - - // Only process if content-type is application/json - if (req.headers["content-type"]?.includes("application/json")) { - const data = - typeof req.body === "string" - ? { - Providers: req.body - .split("\n") - .map((line) => JSON.parse(line)), - } - : req.body; - providers.set(req.params.cid, data); - res.end(JSON.stringify({ success: true })); - } else { - res.statusCode = 400; - res.end( - JSON.stringify({ - error: "Invalid content type. Expected application/json", - code: "ERR_INVALID_INPUT", - }) - ); - // Clear any existing providers for this CID - providers.delete(req.params.cid); + if (!req.headers['content-type']?.includes('application/json')) { + res.statusCode = 400 + res.end(JSON.stringify({ + error: 'Invalid content type. Expected application/json', + code: 'ERR_INVALID_INPUT' + })) + providers.delete(req.params.cid) + return } + + const data = typeof req.body === 'string' + ? { Providers: req.body.split('\n').map(line => JSON.parse(line)) } + : req.body + + providers.set(req.params.cid, data) + res.end(JSON.stringify({ success: true })) } catch (err) { - console.error("Error in add-providers:", err); - res.statusCode = 400; - res.end( - JSON.stringify({ - error: err.message, - code: "ERR_INVALID_INPUT", - }) - ); - providers.delete(req.params.cid); + console.error('Error in add-providers:', err) + res.statusCode = 400 + res.end(JSON.stringify({ + error: err.message, + code: 'ERR_INVALID_INPUT' + })) + providers.delete(req.params.cid) } - }); - - echo.polka.get("/routing/v1/providers/:cid", (req, res) => { - callCount++; + }) + echo.polka.get('/routing/v1/providers/:cid', (req, res) => { + callCount++ try { - console.log("GET request for CID:", req.params.cid); - console.log("Accept header:", req.headers.accept); - - const providerData = providers.get(req.params.cid) || { - Providers: [], - }; - - const acceptHeader = req.headers.accept; - if (acceptHeader?.includes("application/x-ndjson")) { - res.setHeader("Content-Type", "application/x-ndjson"); - const providers = Array.isArray(providerData.Providers) - ? providerData.Providers - : []; - res.end(providers.map((p) => JSON.stringify(p)).join("\n")); + const providerData = providers.get(req.params.cid) || { Providers: [] } + const acceptHeader = req.headers.accept + + if (acceptHeader?.includes('application/x-ndjson')) { + res.setHeader('Content-Type', 'application/x-ndjson') + const providers = Array.isArray(providerData.Providers) ? providerData.Providers : [] + res.end(providers.map(p => JSON.stringify(p)).join('\n')) } else { - res.setHeader("Content-Type", "application/json"); - res.end(JSON.stringify(providerData)); + res.setHeader('Content-Type', 'application/json') + res.end(JSON.stringify(providerData)) } } catch (err) { - console.error("Error in get providers:", err); - res.statusCode = 500; - res.end(JSON.stringify({ error: err.message })); + console.error('Error in get providers:', err) + res.statusCode = 500 + res.end(JSON.stringify({ error: err.message })) } - }); + }) + // echo.polka.get("/routing/v1/providers/:cid", (req, res) => { + // callCount++; + // try { + // console.log("GET request for CID:", req.params.cid); + // console.log("Accept header:", req.headers.accept); + // const providerData = providers.get(req.params.cid) || { + // Providers: [], + // }; + // const acceptHeader = req.headers.accept; + // if (acceptHeader?.includes("application/x-ndjson")) { + // res.setHeader("Content-Type", "application/x-ndjson"); + // const providers = Array.isArray(providerData.Providers) + // ? providerData.Providers + // : []; + // res.end(providers.map((p) => JSON.stringify(p)).join("\n")); + // } else { + // res.setHeader("Content-Type", "application/json"); + // res.end(JSON.stringify(providerData)); + // } + // } catch (err) { + // console.error("Error in get providers:", err); + // res.statusCode = 500; + // res.end(JSON.stringify({ error: err.message })); + // } + // }); echo.polka.post("/add-peers/:peerId", (req, res) => { callCount++; peers.set(req.params.peerId, req.body); diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 82a9f60..3d346bb 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -125,7 +125,6 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV if (res == null) { throw new BadResponseError('No response received') } - if (!res.ok) { if (res.status === 404) { // https://specs.ipfs.tech/routing/http-routing-v1/#response-status-codes @@ -159,16 +158,19 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV yield record } } - } else { + } else if (contentType.includes('application/x-ndjson')) { for await (const provider of ndjson(toIt(res.body))) { const record = this.#conformToPeerSchema(provider) if (record != null) { yield record } } + } else { + throw new BadResponseError(`Unsupported Content-Type: ${contentType}`) } } catch (err) { log.error('getProviders errored:', err) + throw err } finally { signal.clear() onFinish.resolve() diff --git a/packages/client/test/index.spec.ts b/packages/client/test/index.spec.ts index 8be08c9..f4313ce 100644 --- a/packages/client/test/index.spec.ts +++ b/packages/client/test/index.spec.ts @@ -35,26 +35,22 @@ describe('delegated-routing-v1-http-api-client', () => { }) it('should find providers', async () => { - const providers = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, - { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, - { - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/43.43.43.43/tcp/1234'] - } - ] + const providers = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }, { + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] + }, { + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/43.43.43.43/tcp/1234'] + }] const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') @@ -87,15 +83,13 @@ describe('delegated-routing-v1-http-api-client', () => { }) it('should handle different Content-Type headers for JSON responses', async () => { - const providers = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - } - ] + const providers = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }] const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') @@ -127,12 +121,6 @@ describe('delegated-routing-v1-http-api-client', () => { `Failed for Content-Type: ${contentType}` ) - // Updated assertions to match the transformed structure - expect(provs[0]).to.deep.include({ - Schema: 'peer', - Metadata: 'gBI=', - Protocols: ['transport-bitswap'] // Protocol is moved to Protocols array - }) expect(provs[0].ID.toString()).to.equal(providers[0].ID) expect(provs[0].Addrs[0].toString()).to.equal(providers[0].Addrs[0]) } @@ -162,26 +150,22 @@ describe('delegated-routing-v1-http-api-client', () => { }) it('should add filter parameters the query of the request url', async () => { - const providers = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: [] - }, - { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, - { - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: [] - } - ] + const providers = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: [] + }, { + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] + }, { + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: [] + }] const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') @@ -251,21 +235,18 @@ describe('delegated-routing-v1-http-api-client', () => { }) it('should handle bad input providers', async () => { - const providers = [ - { - Metadata: 'gBI=', - Provider: { - Bad: 'field' - } - }, - { - Metadata: 'gBI=', - ContextID: '', - Another: { - Bad: 'field' - } + const providers = [{ + Metadata: 'gBI=', + Provider: { + Bad: 'field' } - ] + }, { + Metadata: 'gBI=', + ContextID: '', + Another: { + Bad: 'field' + } + }] const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') @@ -289,77 +270,65 @@ describe('delegated-routing-v1-http-api-client', () => { it('should conform records to peer schema', async () => { const privateKey = await generateKeyPair('Ed25519') - const records = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: privateKey.publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, - { - Protocol: 'transport-saddle', - Schema: 'horse-ride', - Metadata: 'gBI=', - ID: privateKey.publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, - { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: privateKey.publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, - { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, - { - Schema: 'peer', - ID: (await generateKeyPair('Ed25519')).publicKey.toString() - } - ] - - const peers = [ - { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[0].ID), - Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] - }, - { - Protocols: ['transport-saddle'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[1].ID), - Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] - }, - { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[2].ID), - Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] - }, - { - Protocols: ['transport-bitswap'], - Schema: 'peer', - Metadata: 'gBI=', - ID: peerIdFromString(records[3].ID), - Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] - }, - { - Protocols: [], - Schema: 'peer', - ID: peerIdFromString(records[4].ID), - Addrs: [] - } - ] + const records = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: privateKey.publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }, { + Protocol: 'transport-saddle', + Schema: 'horse-ride', + Metadata: 'gBI=', + ID: privateKey.publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }, { + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', + ID: privateKey.publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] + }, { + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] + }, { + Schema: 'peer', + ID: (await generateKeyPair('Ed25519')).publicKey.toString() + }] + + const peers = [{ + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', + ID: peerIdFromString(records[0].ID), + Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] + }, { + Protocols: ['transport-saddle'], + Schema: 'peer', + Metadata: 'gBI=', + ID: peerIdFromString(records[1].ID), + Addrs: [multiaddr('/ip4/41.41.41.41/tcp/1234')] + }, { + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', + ID: peerIdFromString(records[2].ID), + Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] + }, { + Protocols: ['transport-bitswap'], + Schema: 'peer', + Metadata: 'gBI=', + ID: peerIdFromString(records[3].ID), + Addrs: [multiaddr('/ip4/42.42.42.42/tcp/1234')] + }, { + Protocols: [], + Schema: 'peer', + ID: peerIdFromString(records[4].ID), + Addrs: [] + }] // load peer for the router to fetch await fetch( @@ -456,15 +425,13 @@ describe('delegated-routing-v1-http-api-client', () => { it('should deduplicate concurrent requests to the same URL', async () => { const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const providers = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - } - ] + const providers = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }] // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { @@ -522,28 +489,27 @@ describe('delegated-routing-v1-http-api-client', () => { await start(clientWithShortTTL) const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const providers = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - } - ] + const providers = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }] // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - body: providers.map((prov) => JSON.stringify(prov)).join('\n') + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ Providers: providers }) }) // Reset call count await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) - // First request should hit the server await all(clientWithShortTTL.getProviders(cid)) - // Second and third request should use cache await all(clientWithShortTTL.getProviders(cid)) await all(clientWithShortTTL.getProviders(cid)) diff --git a/packages/client/test/routings.spec.ts b/packages/client/test/routings.spec.ts index bfc86a8..3f56fb0 100644 --- a/packages/client/test/routings.spec.ts +++ b/packages/client/test/routings.spec.ts @@ -61,26 +61,22 @@ describe('libp2p content-routing', () => { throw new Error('ContentRouting not found') } - const providers = [ - { - Protocol: 'transport-bitswap', - Schema: 'bitswap', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - }, - { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/42.42.42.42/tcp/1234'] - }, - { - ID: (await generateKeyPair('Ed25519')).publicKey.toString(), - Addrs: ['/ip4/43.43.43.43/tcp/1234'] - } - ] + const providers = [{ + Protocol: 'transport-bitswap', + Schema: 'bitswap', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }, { + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/42.42.42.42/tcp/1234'] + }, { + ID: (await generateKeyPair('Ed25519')).publicKey.toString(), + Addrs: ['/ip4/43.43.43.43/tcp/1234'] + }] const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') @@ -250,15 +246,13 @@ describe('libp2p peer-routing', () => { const privateKey = await generateKeyPair('Ed25519') const peerId = peerIdFromPrivateKey(privateKey) - const records = [ - { - Protocol: 'transport-bitswap', - Schema: 'peer', - Metadata: 'gBI=', - ID: peerId.toString(), - Addrs: ['/ip4/41.41.41.41/tcp/1234'] - } - ] + const records = [{ + Protocol: 'transport-bitswap', + Schema: 'peer', + Metadata: 'gBI=', + ID: peerId.toString(), + Addrs: ['/ip4/41.41.41.41/tcp/1234'] + }] // load peer for the router to fetch await fetch( From 16df06c7d9c947ef2b8a7c80948c3d53a388e23b Mon Sep 17 00:00:00 2001 From: Neha Kumari Date: Thu, 6 Feb 2025 00:46:58 +0530 Subject: [PATCH 4/9] fixes-&-improve-code --- packages/client/.aegir.js | 199 +++++++-------------- packages/client/src/client.ts | 2 +- packages/client/test/index.spec.ts | 243 +++++++++----------------- packages/client/test/routings.spec.ts | 99 ++++------- 4 files changed, 186 insertions(+), 357 deletions(-) diff --git a/packages/client/.aegir.js b/packages/client/.aegir.js index aad9e54..2937dfe 100644 --- a/packages/client/.aegir.js +++ b/packages/client/.aegir.js @@ -1,63 +1,24 @@ -import EchoServer from "aegir/echo-server"; -import body from "body-parser"; +import EchoServer from 'aegir/echo-server' +import body from 'body-parser' /** @type {import('aegir').PartialOptions} */ const options = { test: { before: async () => { - let callCount = 0; - let lastCalledUrl = ""; - const providers = new Map(); - const peers = new Map(); - const ipnsGet = new Map(); - const ipnsPut = new Map(); - const echo = new EchoServer(); - echo.polka.use(body.raw({ type: "application/vnd.ipfs.ipns-record" })); - echo.polka.use(body.text()); - echo.polka.use(body.json()); + let callCount = 0 + let lastCalledUrl = '' + const providers = new Map() + const peers = new Map() + const ipnsGet = new Map() + const ipnsPut = new Map() + const echo = new EchoServer() + echo.polka.use(body.raw({ type: 'application/vnd.ipfs.ipns-record'})) + echo.polka.use(body.text()) + echo.polka.use(body.json()) echo.polka.use((req, res, next) => { - next(); - lastCalledUrl = req.url; - }); - // echo.polka.post("/add-providers/:cid", (req, res) => { - // callCount++; - // try { - // console.log("Received POST request body:", req.body); - // console.log("Content-Type:", req.headers["content-type"]); - - // if (req.headers["content-type"]?.includes("application/json")) { - // const data = - // typeof req.body === "string" - // ? { - // Providers: req.body - // .split("\n") - // .map((line) => JSON.parse(line)), - // } - // : req.body; - // providers.set(req.params.cid, data); - // res.end(JSON.stringify({ success: true })); - // } else { - // res.statusCode = 400; - // res.end( - // JSON.stringify({ - // error: "Invalid content type. Expected application/json", - // code: "ERR_INVALID_INPUT", - // }) - // ); - // providers.delete(req.params.cid); - // } - // } catch (err) { - // console.error("Error in add-providers:", err); - // res.statusCode = 400; - // res.end( - // JSON.stringify({ - // error: err.message, - // code: "ERR_INVALID_INPUT", - // }) - // ); - // providers.delete(req.params.cid); - // } - // }); + next() + lastCalledUrl = req.url + }) echo.polka.post('/add-providers/:cid', (req, res) => { callCount++ try { @@ -107,94 +68,68 @@ const options = { res.end(JSON.stringify({ error: err.message })) } }) - // echo.polka.get("/routing/v1/providers/:cid", (req, res) => { - // callCount++; - // try { - // console.log("GET request for CID:", req.params.cid); - // console.log("Accept header:", req.headers.accept); - - // const providerData = providers.get(req.params.cid) || { - // Providers: [], - // }; - // const acceptHeader = req.headers.accept; - // if (acceptHeader?.includes("application/x-ndjson")) { - // res.setHeader("Content-Type", "application/x-ndjson"); - // const providers = Array.isArray(providerData.Providers) - // ? providerData.Providers - // : []; - // res.end(providers.map((p) => JSON.stringify(p)).join("\n")); - // } else { - // res.setHeader("Content-Type", "application/json"); - // res.end(JSON.stringify(providerData)); - // } - // } catch (err) { - // console.error("Error in get providers:", err); - // res.statusCode = 500; - // res.end(JSON.stringify({ error: err.message })); - // } - // }); - echo.polka.post("/add-peers/:peerId", (req, res) => { - callCount++; - peers.set(req.params.peerId, req.body); - res.end(); - }); - echo.polka.get("/routing/v1/peers/:peerId", (req, res) => { - callCount++; - const records = peers.get(req.params.peerId) ?? "[]"; - peers.delete(req.params.peerId); + echo.polka.post('/add-peers/:peerId', (req, res) => { + callCount++ + peers.set(req.params.peerId, req.body) + res.end() + }) + echo.polka.get('/routing/v1/peers/:peerId', (req, res) => { + callCount++ + const records = peers.get(req.params.peerId) ?? '[]' + peers.delete(req.params.peerId) - res.end(records); - }); - echo.polka.post("/add-ipns/:peerId", (req, res) => { - callCount++; - ipnsGet.set(req.params.peerId, req.body); - res.end(); - }); - echo.polka.get("/routing/v1/ipns/:peerId", (req, res) => { - callCount++; - const record = ipnsGet.get(req.params.peerId) ?? ""; - ipnsGet.delete(req.params.peerId); + res.end(records) + }) + echo.polka.post('/add-ipns/:peerId', (req, res) => { + callCount++ + ipnsGet.set(req.params.peerId, req.body) + res.end() + }) + echo.polka.get('/routing/v1/ipns/:peerId', (req, res) => { + callCount++ + const record = ipnsGet.get(req.params.peerId) ?? '' + ipnsGet.delete(req.params.peerId) - res.end(record); - }); - echo.polka.put("/routing/v1/ipns/:peerId", (req, res) => { - callCount++; - ipnsPut.set(req.params.peerId, req.body); - res.end(); - }); - echo.polka.get("/get-ipns/:peerId", (req, res) => { - callCount++; - const record = ipnsPut.get(req.params.peerId) ?? ""; - ipnsPut.delete(req.params.peerId); + res.end(record) + }) + echo.polka.put('/routing/v1/ipns/:peerId', (req, res) => { + callCount++ + ipnsPut.set(req.params.peerId, req.body) + res.end() + }) + echo.polka.get('/get-ipns/:peerId', (req, res) => { + callCount++ + const record = ipnsPut.get(req.params.peerId) ?? '' + ipnsPut.delete(req.params.peerId) - res.end(record); - }); - echo.polka.get("/get-call-count", (req, res) => { - res.end(callCount.toString()); - }); - echo.polka.get("/reset-call-count", (req, res) => { - callCount = 0; - res.end(); - }); - echo.polka.get("/last-called-url", (req, res) => { - res.end(lastCalledUrl); - }); + res.end(record) + }) + echo.polka.get('/get-call-count', (req, res) => { + res.end(callCount.toString()) + }) + echo.polka.get('/reset-call-count', (req, res) => { + callCount = 0 + res.end() + }) + echo.polka.get('/last-called-url', (req, res) => { + res.end(lastCalledUrl) + }) - await echo.start(); + await echo.start() return { env: { - ECHO_SERVER: `http://${echo.host}:${echo.port}`, + ECHO_SERVER: `http://${echo.host}:${echo.port}` }, - echo, - }; + echo + } }, after: async (_, beforeResult) => { if (beforeResult.echo != null) { - await beforeResult.echo.stop(); + await beforeResult.echo.stop() } - }, - }, -}; + } + } +} -export default options; +export default options diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 3d346bb..bad10b8 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -170,7 +170,6 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV } } catch (err) { log.error('getProviders errored:', err) - throw err } finally { signal.clear() onFinish.resolve() @@ -397,6 +396,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV const requestMethod = options.method ?? 'GET' const key = `${requestMethod}-${url}` + // Only try to use cache for GET requests if (requestMethod === 'GET') { const cachedResponse = await this.cache?.match(url) if (cachedResponse?.ok === true) { diff --git a/packages/client/test/index.spec.ts b/packages/client/test/index.spec.ts index f4313ce..259df98 100644 --- a/packages/client/test/index.spec.ts +++ b/packages/client/test/index.spec.ts @@ -8,10 +8,7 @@ import { expect } from 'aegir/chai' import { createIPNSRecord, marshalIPNSRecord } from 'ipns' import all from 'it-all' import { CID } from 'multiformats/cid' -import { - createDelegatedRoutingV1HttpApiClient, - type DelegatedRoutingV1HttpApiClient -} from '../src/index.js' +import { createDelegatedRoutingV1HttpApiClient, type DelegatedRoutingV1HttpApiClient } from '../src/index.js' import { itBrowser } from './fixtures/it.js' if (process.env.ECHO_SERVER == null) { @@ -24,9 +21,7 @@ describe('delegated-routing-v1-http-api-client', () => { let client: DelegatedRoutingV1HttpApiClient beforeEach(async () => { - client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - cacheTTL: 0 - }) + client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { cacheTTL: 0 }) await start(client) }) @@ -55,31 +50,22 @@ describe('delegated-routing-v1-http-api-client', () => { const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch - await fetch( - `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ Providers: providers }) - } - ) + await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ Providers: providers}) + }) - await new Promise((resolve) => setTimeout(resolve, 100)) const provs = await all(client.getProviders(cid)) - - expect( - provs.map((prov) => ({ - id: prov.ID.toString(), - addrs: prov.Addrs?.map((ma) => ma.toString()) - })) - ).to.deep.equal( - providers.map((prov) => ({ - id: prov.ID, - addrs: prov.Addrs - })) - ) + expect(provs.map(prov => ({ + id: prov.ID.toString(), + addrs: prov.Addrs?.map(ma => ma.toString()) + }))).to.deep.equal(providers.map(prov => ({ + id: prov.ID, + addrs: prov.Addrs + }))) }) it('should handle different Content-Type headers for JSON responses', async () => { @@ -92,7 +78,6 @@ describe('delegated-routing-v1-http-api-client', () => { }] const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const contentTypes = [ 'application/json', 'application/json; charset=utf-8', @@ -101,26 +86,18 @@ describe('delegated-routing-v1-http-api-client', () => { for (const contentType of contentTypes) { // Add providers with proper payload structure - await fetch( - `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, - { + await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', headers: { 'Content-Type': contentType }, body: JSON.stringify({ Providers: providers }) - } - ) + }) await new Promise((resolve) => setTimeout(resolve, 100)) - const provs = await all(client.getProviders(cid)) - expect(provs).to.have.lengthOf( - 1, - `Failed for Content-Type: ${contentType}` - ) - + expect(provs).to.have.lengthOf(1, `Failed for Content-Type: ${contentType}`) expect(provs[0].ID.toString()).to.equal(providers[0].ID) expect(provs[0].Addrs[0].toString()).to.equal(providers[0].Addrs[0]) } @@ -129,16 +106,13 @@ describe('delegated-routing-v1-http-api-client', () => { it('should handle non-json input', async () => { const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - const response = await fetch( - `${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, - { + const response = await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', headers: { 'Content-Type': 'text/plain' }, body: 'not json' - } - ) + }) expect(response.status).to.equal(400) const errorData = await response.json() @@ -172,30 +146,19 @@ describe('delegated-routing-v1-http-api-client', () => { // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - body: providers.map((prov) => JSON.stringify(prov)).join('\n') + body: providers.map(prov => JSON.stringify(prov)).join('\n') }) - await all( - client.getProviders(cid, { - filterProtocols: ['transport-bitswap', 'unknown'], - filterAddrs: ['webtransport', '!p2p-circuit'] - }) - ) + await all(client.getProviders(cid, { filterProtocols: ['transport-bitswap', 'unknown'], filterAddrs: ['webtransport', '!p2p-circuit'] })) // Check if the correct URL was called with filter parameters - const lastCalledUrl = await fetch( - `${process.env.ECHO_SERVER}/last-called-url` - ) + const lastCalledUrl = await fetch(`${process.env.ECHO_SERVER}/last-called-url`) const lastCalledUrlText = await lastCalledUrl.text() const searchParams = new URLSearchParams(lastCalledUrlText.split('?')[1]) - expect(searchParams.get('filter-protocols')).to.equal( - 'transport-bitswap,unknown' - ) - expect(searchParams.get('filter-addrs')).to.equal( - 'webtransport,!p2p-circuit' - ) + expect(searchParams.get('filter-protocols')).to.equal('transport-bitswap,unknown') + expect(searchParams.get('filter-addrs')).to.equal('webtransport,!p2p-circuit') }) it('should add filter parameters the query of the request url based on global filter', async () => { @@ -208,16 +171,12 @@ describe('delegated-routing-v1-http-api-client', () => { await all(client.getProviders(cid)) // Check if the correct URL was called with filter parameters - const lastCalledUrl = await fetch( - `${process.env.ECHO_SERVER}/last-called-url` - ) + const lastCalledUrl = await fetch(`${process.env.ECHO_SERVER}/last-called-url`) const lastCalledUrlText = await lastCalledUrl.text() const searchParams = new URLSearchParams(lastCalledUrlText.split('?')[1]) - expect(searchParams.get('filter-protocols')).to.equal( - 'transport-bitswap,unknown' - ) + expect(searchParams.get('filter-protocols')).to.equal('transport-bitswap,unknown') expect(searchParams.get('filter-addrs')).to.equal('tcp,!p2p-circuit') }) @@ -253,7 +212,7 @@ describe('delegated-routing-v1-http-api-client', () => { // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - body: providers.map((prov) => JSON.stringify(prov)).join('\n') + body: providers.map(prov => JSON.stringify(prov)).join('\n') }) const provs = await all(client.getProviders(cid)) @@ -331,30 +290,21 @@ describe('delegated-routing-v1-http-api-client', () => { }] // load peer for the router to fetch - await fetch( - `${process.env.ECHO_SERVER}/add-peers/${privateKey.publicKey.toCID()}`, - { - method: 'POST', - body: records.map((prov) => JSON.stringify(prov)).join('\n') - } - ) - - const peerRecords = await all( - client.getPeers(peerIdFromPrivateKey(privateKey)) - ) - expect( - peerRecords.map((peerRecord) => ({ - ...peerRecord, - ID: peerRecord.ID.toString(), - Addrs: peerRecord.Addrs?.map((ma) => ma.toString()) ?? [] - })) - ).to.deep.equal( - peers.map((peerRecord) => ({ - ...peerRecord, - ID: peerRecord.ID.toString(), - Addrs: peerRecord.Addrs?.map((ma) => ma.toString()) - })) - ) + await fetch(`${process.env.ECHO_SERVER}/add-peers/${privateKey.publicKey.toCID()}`, { + method: 'POST', + body: records.map(prov => JSON.stringify(prov)).join('\n') + }) + + const peerRecords = await all(client.getPeers(peerIdFromPrivateKey(privateKey))) + expect(peerRecords.map(peerRecord => ({ + ...peerRecord, + ID: peerRecord.ID.toString(), + Addrs: peerRecord.Addrs?.map(ma => ma.toString()) ?? [] + }))).to.deep.equal(peers.map(peerRecord => ({ + ...peerRecord, + ID: peerRecord.ID.toString(), + Addrs: peerRecord.Addrs?.map(ma => ma.toString()) + }))) }) it('should get ipns record', async () => { @@ -363,21 +313,16 @@ describe('delegated-routing-v1-http-api-client', () => { const record = await createIPNSRecord(privateKey, cid, 0, 1000) // load record for the router to fetch - await fetch( - `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/vnd.ipfs.ipns-record' - }, - body: marshalIPNSRecord(record) - } - ) + await fetch(`${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/vnd.ipfs.ipns-record' + }, + body: marshalIPNSRecord(record) + }) const ipnsRecord = await client.getIPNS(privateKey.publicKey.toCID()) - expect(marshalIPNSRecord(ipnsRecord)).to.equalBytes( - marshalIPNSRecord(record) - ) + expect(marshalIPNSRecord(ipnsRecord)).to.equalBytes(marshalIPNSRecord(record)) }) it('get ipns record fails with bad record', async () => { @@ -387,16 +332,13 @@ describe('delegated-routing-v1-http-api-client', () => { const record = await createIPNSRecord(otherPrivateKey, cid, 0, 1000) // load record for the router to fetch - await fetch( - `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/vnd.ipfs.ipns-record' - }, - body: marshalIPNSRecord(record) - } - ) + await fetch(`${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/vnd.ipfs.ipns-record' + }, + body: marshalIPNSRecord(record) + }) await expect(client.getIPNS(privateKey.publicKey.toCID())).to.be.rejected() }) @@ -409,15 +351,12 @@ describe('delegated-routing-v1-http-api-client', () => { await client.putIPNS(privateKey.publicKey.toCID(), record) // load record that our client just PUT to remote server - const res = await fetch( - `${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, - { - method: 'GET', - headers: { - Accept: 'application/vnd.ipfs.ipns-record' - } + const res = await fetch(`${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, { + method: 'GET', + headers: { + Accept: 'application/vnd.ipfs.ipns-record' } - ) + }) const receivedRecord = new Uint8Array(await res.arrayBuffer()) expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord) @@ -437,9 +376,9 @@ describe('delegated-routing-v1-http-api-client', () => { await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', headers: { - 'Content-Type': 'application/json' // Add this header + 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers }) + body: JSON.stringify({ Providers: providers}) }) // Reset call count before our test @@ -454,38 +393,30 @@ describe('delegated-routing-v1-http-api-client', () => { ]) // Get the number of times the server was called - const callCountRes = await fetch( - `${process.env.ECHO_SERVER}/get-call-count` - ) + const callCountRes = await fetch(`${process.env.ECHO_SERVER}/get-call-count`) const callCount = parseInt(await callCountRes.text(), 10) // Verify server was only called once expect(callCount).to.equal(1) // Verify all results are the same - results.forEach((resultProviders) => { - expect( - resultProviders.map((prov) => ({ - id: prov.ID.toString(), - addrs: prov.Addrs?.map((ma) => ma.toString()) - })) - ).to.deep.equal( - providers.map((prov) => ({ - id: prov.ID, - addrs: prov.Addrs - })) - ) + results.forEach(resultProviders => { + expect(resultProviders.map(prov => ({ + id: prov.ID.toString(), + // eslint-disable-next-line max-nested-callbacks + addrs: prov.Addrs?.map(ma => ma.toString()) + }))).to.deep.equal(providers.map(prov => ({ + id: prov.ID, + addrs: prov.Addrs + }))) }) }) itBrowser('should respect cache TTL', async () => { const shortTTL = 100 // 100ms TTL for testing - const clientWithShortTTL = createDelegatedRoutingV1HttpApiClient( - new URL(serverUrl), - { - cacheTTL: shortTTL - } - ) + const clientWithShortTTL = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { + cacheTTL: shortTTL + }) await start(clientWithShortTTL) const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') @@ -503,33 +434,29 @@ describe('delegated-routing-v1-http-api-client', () => { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers }) + body: JSON.stringify({ Providers: providers}) }) // Reset call count await fetch(`${process.env.ECHO_SERVER}/reset-call-count`) + // First request should hit the server await all(clientWithShortTTL.getProviders(cid)) + // Second and third request should use cache await all(clientWithShortTTL.getProviders(cid)) await all(clientWithShortTTL.getProviders(cid)) - let callCount = parseInt( - await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), - 10 - ) + let callCount = parseInt(await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), 10) expect(callCount).to.equal(1) // Only one server call so far // Wait for cache to expire - await new Promise((resolve) => setTimeout(resolve, shortTTL + 50)) + await new Promise(resolve => setTimeout(resolve, shortTTL + 50)) // This request should hit the server again because cache expired await all(clientWithShortTTL.getProviders(cid)) - callCount = parseInt( - await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), - 10 - ) + callCount = parseInt(await (await fetch(`${process.env.ECHO_SERVER}/get-call-count`)).text(), 10) expect(callCount).to.equal(2) // Second server call after cache expired await stop(clientWithShortTTL) diff --git a/packages/client/test/routings.spec.ts b/packages/client/test/routings.spec.ts index 3f56fb0..1244255 100644 --- a/packages/client/test/routings.spec.ts +++ b/packages/client/test/routings.spec.ts @@ -2,27 +2,15 @@ /* eslint-env mocha */ import { generateKeyPair } from '@libp2p/crypto/keys' -import { - contentRoutingSymbol, - peerRoutingSymbol, - start, - stop -} from '@libp2p/interface' +import { contentRoutingSymbol, peerRoutingSymbol, start, stop } from '@libp2p/interface' import { peerIdFromPrivateKey } from '@libp2p/peer-id' import { expect } from 'aegir/chai' -import { - createIPNSRecord, - marshalIPNSRecord, - multihashToIPNSRoutingKey -} from 'ipns' +import { createIPNSRecord, marshalIPNSRecord, multihashToIPNSRoutingKey } from 'ipns' import all from 'it-all' import { CID } from 'multiformats/cid' import { concat as uint8ArrayConcat } from 'uint8arrays/concat' import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' -import { - createDelegatedRoutingV1HttpApiClient, - type DelegatedRoutingV1HttpApiClient -} from '../src/index.js' +import { createDelegatedRoutingV1HttpApiClient, type DelegatedRoutingV1HttpApiClient } from '../src/index.js' import type { PeerRouting, ContentRouting } from '@libp2p/interface' const serverUrl = process.env.ECHO_SERVER @@ -35,9 +23,7 @@ describe('libp2p content-routing', () => { let client: DelegatedRoutingV1HttpApiClient beforeEach(async () => { - client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { - cacheTTL: 0 - }) + client = createDelegatedRoutingV1HttpApiClient(new URL(serverUrl), { cacheTTL: 0 }) await start(client) }) @@ -80,7 +66,7 @@ describe('libp2p content-routing', () => { const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - // load providers for the router to fetch with proper JSON formatting + // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', headers: { @@ -89,18 +75,14 @@ describe('libp2p content-routing', () => { body: JSON.stringify({ Providers: providers }) }) - const foundProviders = await all(routing.findProviders(cid)) - expect( - foundProviders.map((p) => ({ - id: p.id.toString(), - multiaddrs: p.multiaddrs.map((ma) => ma.toString()) - })) - ).to.deep.equal( - providers.map((prov) => ({ - id: prov.ID, - multiaddrs: prov.Addrs - })) - ) + const provs = await all(routing.findProviders(cid)) + expect(provs.map(prov => ({ + id: prov.id.toString(), + multiaddrs: prov.multiaddrs.map(ma => ma.toString()) + }))).to.deep.equal(providers.map(prov => ({ + id: prov.ID, + multiaddrs: prov.Addrs + }))) }) it('should provide without error', async () => { @@ -130,15 +112,12 @@ describe('libp2p content-routing', () => { await routing.put(key, marshalIPNSRecord(record)) // load record that our client just PUT to remote server - const res = await fetch( - `${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, - { - method: 'GET', - headers: { - Accept: 'application/vnd.ipfs.ipns-record' - } + const res = await fetch(`${process.env.ECHO_SERVER}/get-ipns/${privateKey.publicKey.toCID()}`, { + method: 'GET', + headers: { + Accept: 'application/vnd.ipfs.ipns-record' } - ) + }) const receivedRecord = new Uint8Array(await res.arrayBuffer()) expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord) @@ -174,16 +153,13 @@ describe('libp2p content-routing', () => { const record = await createIPNSRecord(privateKey, cid, 0, 1000) // load record for the router to fetch - await fetch( - `${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/vnd.ipfs.ipns-record' - }, - body: marshalIPNSRecord(record) - } - ) + await fetch(`${process.env.ECHO_SERVER}/add-ipns/${privateKey.publicKey.toCID()}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/vnd.ipfs.ipns-record' + }, + body: marshalIPNSRecord(record) + }) const key = uint8ArrayConcat([ uint8ArrayFromString('/ipns/'), @@ -208,10 +184,8 @@ describe('libp2p content-routing', () => { privateKey.publicKey.toMultihash().bytes ]) - await expect(routing.get(key)).to.eventually.be.rejected.with.property( - 'name', - 'NotFoundError' - ) + await expect(routing.get(key)).to.eventually.be.rejected + .with.property('name', 'NotFoundError') await expect(getServerCallCount()).to.eventually.equal(0) }) @@ -255,20 +229,15 @@ describe('libp2p peer-routing', () => { }] // load peer for the router to fetch - await fetch( - `${process.env.ECHO_SERVER}/add-peers/${peerId.toCID().toString()}`, - { - method: 'POST', - body: records.map((prov) => JSON.stringify(prov)).join('\n') - } - ) + await fetch(`${process.env.ECHO_SERVER}/add-peers/${peerId.toCID().toString()}`, { + method: 'POST', + body: records.map(prov => JSON.stringify(prov)).join('\n') + }) const peerInfo = await routing.findPeer(peerId) expect(peerInfo.id.toString()).to.equal(records[0].ID) - expect(peerInfo.multiaddrs.map((ma) => ma.toString())).to.deep.equal( - records[0].Addrs - ) + expect(peerInfo.multiaddrs.map(ma => ma.toString())).to.deep.equal(records[0].Addrs) }) it('should not get closest peers', async () => { @@ -278,9 +247,7 @@ describe('libp2p peer-routing', () => { throw new Error('PeerRouting not found') } - await expect( - all(routing.getClosestPeers(Uint8Array.from([0, 1, 2, 3, 4]))) - ).to.eventually.be.empty() + await expect(all(routing.getClosestPeers(Uint8Array.from([0, 1, 2, 3, 4])))).to.eventually.be.empty() }) }) }) From f9bce428607aa3c1f337ba24111aa27335069bac Mon Sep 17 00:00:00 2001 From: Neha Kumari Date: Thu, 6 Feb 2025 18:22:26 +0530 Subject: [PATCH 5/9] fix: cache ok responses --- packages/client/src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index bad10b8..b8fa3ea 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -397,7 +397,7 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV const key = `${requestMethod}-${url}` // Only try to use cache for GET requests - if (requestMethod === 'GET') { + if (requestMethod === 'GET' && this.cache != null) { const cachedResponse = await this.cache?.match(url) if (cachedResponse?.ok === true) { // Check if the cached response has expired From ebb999710e9595ccd57d00ca8e4739f9e4e2a68b Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Mon, 10 Feb 2025 14:24:23 -0600 Subject: [PATCH 6/9] chore: lint fix --- packages/client/test/index.spec.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/client/test/index.spec.ts b/packages/client/test/index.spec.ts index 259df98..a4033b4 100644 --- a/packages/client/test/index.spec.ts +++ b/packages/client/test/index.spec.ts @@ -55,7 +55,7 @@ describe('delegated-routing-v1-http-api-client', () => { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers}) + body: JSON.stringify({ Providers: providers }) }) const provs = await all(client.getProviders(cid)) @@ -87,12 +87,12 @@ describe('delegated-routing-v1-http-api-client', () => { for (const contentType of contentTypes) { // Add providers with proper payload structure await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - headers: { - 'Content-Type': contentType - }, - body: JSON.stringify({ Providers: providers }) - }) + method: 'POST', + headers: { + 'Content-Type': contentType + }, + body: JSON.stringify({ Providers: providers }) + }) await new Promise((resolve) => setTimeout(resolve, 100)) const provs = await all(client.getProviders(cid)) @@ -107,12 +107,12 @@ describe('delegated-routing-v1-http-api-client', () => { const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') const response = await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - headers: { - 'Content-Type': 'text/plain' - }, - body: 'not json' - }) + method: 'POST', + headers: { + 'Content-Type': 'text/plain' + }, + body: 'not json' + }) expect(response.status).to.equal(400) const errorData = await response.json() @@ -378,7 +378,7 @@ describe('delegated-routing-v1-http-api-client', () => { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers}) + body: JSON.stringify({ Providers: providers }) }) // Reset call count before our test @@ -434,7 +434,7 @@ describe('delegated-routing-v1-http-api-client', () => { headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ Providers: providers}) + body: JSON.stringify({ Providers: providers }) }) // Reset call count From b88cd64de2a771d079d9450b228e7aeb3e002d0d Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Mon, 10 Feb 2025 15:33:57 -0600 Subject: [PATCH 7/9] chore: reduce number of changes --- packages/client/.aegir.js | 24 ++++++++--------- packages/client/test/index.spec.ts | 37 +++------------------------ packages/client/test/routings.spec.ts | 5 +--- 3 files changed, 15 insertions(+), 51 deletions(-) diff --git a/packages/client/.aegir.js b/packages/client/.aegir.js index 2937dfe..1aeb139 100644 --- a/packages/client/.aegir.js +++ b/packages/client/.aegir.js @@ -22,20 +22,16 @@ const options = { echo.polka.post('/add-providers/:cid', (req, res) => { callCount++ try { - if (!req.headers['content-type']?.includes('application/json')) { - res.statusCode = 400 - res.end(JSON.stringify({ - error: 'Invalid content type. Expected application/json', - code: 'ERR_INVALID_INPUT' - })) - providers.delete(req.params.cid) - return + + let data + try { + // when passed data from a test where `body=providers.map(prov => JSON.stringify(prov)).join('\n')` + data = { Providers: req.body.split('\n').map(line => JSON.parse(line)) } + } catch (err) { + // when passed data from a test where `body=JSON.stringify({ Providers: providers })` + data = req.body } - - const data = typeof req.body === 'string' - ? { Providers: req.body.split('\n').map(line => JSON.parse(line)) } - : req.body - + providers.set(req.params.cid, data) res.end(JSON.stringify({ success: true })) } catch (err) { @@ -53,7 +49,7 @@ const options = { try { const providerData = providers.get(req.params.cid) || { Providers: [] } const acceptHeader = req.headers.accept - + if (acceptHeader?.includes('application/x-ndjson')) { res.setHeader('Content-Type', 'application/x-ndjson') const providers = Array.isArray(providerData.Providers) ? providerData.Providers : [] diff --git a/packages/client/test/index.spec.ts b/packages/client/test/index.spec.ts index a4033b4..cae1397 100644 --- a/packages/client/test/index.spec.ts +++ b/packages/client/test/index.spec.ts @@ -52,10 +52,7 @@ describe('delegated-routing-v1-http-api-client', () => { // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ Providers: providers }) + body: providers.map(prov => JSON.stringify(prov)).join('\n') }) const provs = await all(client.getProviders(cid)) @@ -103,26 +100,6 @@ describe('delegated-routing-v1-http-api-client', () => { } }) - it('should handle non-json input', async () => { - const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') - - const response = await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { - method: 'POST', - headers: { - 'Content-Type': 'text/plain' - }, - body: 'not json' - }) - - expect(response.status).to.equal(400) - const errorData = await response.json() - expect(errorData).to.have.property('error') - expect(errorData).to.have.property('code', 'ERR_INVALID_INPUT') - - const provs = await all(client.getProviders(cid)) - expect(provs).to.be.empty() - }) - it('should add filter parameters the query of the request url', async () => { const providers = [{ Protocol: 'transport-bitswap', @@ -180,7 +157,7 @@ describe('delegated-routing-v1-http-api-client', () => { expect(searchParams.get('filter-addrs')).to.equal('tcp,!p2p-circuit') }) - it('should handle non-json input without content-type header', async () => { + it('should handle non-json input', async () => { const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn') // load providers for the router to fetch @@ -375,10 +352,7 @@ describe('delegated-routing-v1-http-api-client', () => { // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ Providers: providers }) + body: providers.map(prov => JSON.stringify(prov)).join('\n') }) // Reset call count before our test @@ -431,10 +405,7 @@ describe('delegated-routing-v1-http-api-client', () => { // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ Providers: providers }) + body: providers.map(prov => JSON.stringify(prov)).join('\n') }) // Reset call count diff --git a/packages/client/test/routings.spec.ts b/packages/client/test/routings.spec.ts index 1244255..9dac3b6 100644 --- a/packages/client/test/routings.spec.ts +++ b/packages/client/test/routings.spec.ts @@ -69,10 +69,7 @@ describe('libp2p content-routing', () => { // load providers for the router to fetch await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, { method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ Providers: providers }) + body: providers.map(prov => JSON.stringify(prov)).join('\n') }) const provs = await all(routing.findProviders(cid)) From bf2fa2dd948040df3e80c6af6e9c456a4f27aa01 Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Mon, 10 Feb 2025 15:43:24 -0600 Subject: [PATCH 8/9] chore: revert response cache change --- packages/client/src/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index b8fa3ea..83b767b 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -397,9 +397,9 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV const key = `${requestMethod}-${url}` // Only try to use cache for GET requests - if (requestMethod === 'GET' && this.cache != null) { + if (requestMethod === 'GET') { const cachedResponse = await this.cache?.match(url) - if (cachedResponse?.ok === true) { + if (cachedResponse != null) { // Check if the cached response has expired const expires = parseInt(cachedResponse.headers.get('x-cache-expires') ?? '0', 10) if (expires > Date.now()) { From e2860dbb439591853f6aed1c563dbf38b4159300 Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Tue, 11 Feb 2025 08:26:57 -0600 Subject: [PATCH 9/9] chore: remove unused package --- packages/client/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/client/package.json b/packages/client/package.json index 5c1b5b2..9198c2b 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -142,7 +142,6 @@ "@libp2p/logger": "^5.0.1", "@libp2p/peer-id": "^5.0.1", "@multiformats/multiaddr": "^12.3.1", - "@playwright/test": "^1.50.1", "any-signal": "^4.1.1", "browser-readablestream-to-it": "^2.0.7", "ipns": "^10.0.0",