From 3bd88c079b1319dd3048628aab533dc8531c99bf Mon Sep 17 00:00:00 2001 From: Michal Bajer Date: Tue, 24 Oct 2023 11:35:03 +0000 Subject: [PATCH] build(deps): replace ipfs-http-client with kubo-rpc-client - Replace deprecated ipfs-http-client with kubo-rpc-client. - kubo-rpc-client must be imported dynamically since it's ESM-only and we still use CJS. Depends on: #2821 Signed-off-by: Michal Bajer --- .cspell.json | 4 + .../package.json | 6 +- .../src/main/typescript/i-ipfs-http-client.ts | 48 ----- .../main/typescript/kubo-rpc-client-types.ts | 127 +++++++++++++ .../typescript/plugin-object-store-ipfs.ts | 70 +++++--- .../src/main/typescript/public-api.ts | 6 +- .../fixtures/mock/ipfs/ipfs-files-api-mock.ts | 157 ---------------- .../plugin-object-store-ipfs.test.ts | 7 +- .../unit/plugin-object-store-ipfs.test.ts | 15 +- package.json | 3 +- yarn.lock | 169 ++++++++++-------- 11 files changed, 305 insertions(+), 307 deletions(-) delete mode 100644 extensions/cactus-plugin-object-store-ipfs/src/main/typescript/i-ipfs-http-client.ts create mode 100644 extensions/cactus-plugin-object-store-ipfs/src/main/typescript/kubo-rpc-client-types.ts delete mode 100644 extensions/cactus-plugin-object-store-ipfs/src/test/typescript/fixtures/mock/ipfs/ipfs-files-api-mock.ts diff --git a/.cspell.json b/.cspell.json index b44e387a7d7..4a1e7a022b2 100644 --- a/.cspell.json +++ b/.cspell.json @@ -70,6 +70,8 @@ "ipaddress", "ipfs", "IPFSHTTP", + "IPLD", + "ipld", "Iroha", "Irohad", "isready", @@ -83,6 +85,7 @@ "KEYUTIL", "KJUR", "Knetic", + "kubo", "LEDGERBLOCKACK", "leveldb", "lmify", @@ -146,6 +149,7 @@ "txqueue", "Uisrs", "undici", + "unixfs", "Unmarshal", "uuidv", "vscc", diff --git a/extensions/cactus-plugin-object-store-ipfs/package.json b/extensions/cactus-plugin-object-store-ipfs/package.json index eb2ca7205fd..740120f5143 100644 --- a/extensions/cactus-plugin-object-store-ipfs/package.json +++ b/extensions/cactus-plugin-object-store-ipfs/package.json @@ -59,17 +59,19 @@ "@hyperledger/cactus-core": "2.0.0-alpha.2", "@hyperledger/cactus-core-api": "2.0.0-alpha.2", "axios": "1.5.1", - "ipfs-http-client": "60.0.1", + "kubo-rpc-client": "3.0.1", "run-time-error": "1.4.0", "typescript-optional": "2.0.1", "uuid": "8.3.2" }, "devDependencies": { "@hyperledger/cactus-test-tooling": "2.0.0-alpha.2", + "@multiformats/multiaddr": "11.6.1", "@types/express": "4.17.19", "express": "4.18.2", "ipfs-core-types": "0.14.1", - "multiformats": "9.4.9" + "ipfs-unixfs": "9.0.1", + "multiformats": "11.0.2" }, "engines": { "node": ">=10", diff --git a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/i-ipfs-http-client.ts b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/i-ipfs-http-client.ts deleted file mode 100644 index 42a4325b6c7..00000000000 --- a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/i-ipfs-http-client.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { IPFS } from "ipfs-core-types"; -import type { EndpointConfig, IPFSHTTPClient } from "ipfs-http-client"; - -export interface IIpfsHttpClient extends IPFS { - getEndpointConfig: () => EndpointConfig; -} - -export function isIpfsHttpClientOptions(x: unknown): x is IPFSHTTPClient { - if (!x) { - return false; - } - return ( - typeof (x as IIpfsHttpClient).add === "function" && - typeof (x as IIpfsHttpClient).addAll === "function" && - typeof (x as IIpfsHttpClient).bitswap === "object" && - typeof (x as IIpfsHttpClient).block === "object" && - typeof (x as IIpfsHttpClient).bootstrap === "object" && - typeof (x as IIpfsHttpClient).cat === "function" && - typeof (x as IIpfsHttpClient).commands === "function" && - typeof (x as IIpfsHttpClient).config === "object" && - typeof (x as IIpfsHttpClient).dag === "object" && - typeof (x as IIpfsHttpClient).dht === "object" && - typeof (x as IIpfsHttpClient).diag === "object" && - typeof (x as IIpfsHttpClient).dns === "function" && - typeof (x as IIpfsHttpClient).files === "object" && - typeof (x as IIpfsHttpClient).get === "function" && - typeof (x as IIpfsHttpClient).getEndpointConfig === "function" && - typeof (x as IIpfsHttpClient).id === "function" && - typeof (x as IIpfsHttpClient).isOnline === "function" && - typeof (x as IIpfsHttpClient).key === "object" && - typeof (x as IIpfsHttpClient).log === "object" && - typeof (x as IIpfsHttpClient).ls === "function" && - typeof (x as IIpfsHttpClient).mount === "function" && - typeof (x as IIpfsHttpClient).name === "object" && - typeof (x as IIpfsHttpClient).object === "object" && - typeof (x as IIpfsHttpClient).pin === "object" && - typeof (x as IIpfsHttpClient).ping === "function" && - typeof (x as IIpfsHttpClient).pubsub === "object" && - // typeof (x as IIpfsHttpClient).refs === "function" && - typeof (x as IIpfsHttpClient).repo === "object" && - typeof (x as IIpfsHttpClient).resolve === "function" && - typeof (x as IIpfsHttpClient).start === "function" && - typeof (x as IIpfsHttpClient).stats === "object" && - typeof (x as IIpfsHttpClient).stop === "function" && - typeof (x as IIpfsHttpClient).swarm === "object" && - typeof (x as IIpfsHttpClient).version === "function" - ); -} diff --git a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/kubo-rpc-client-types.ts b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/kubo-rpc-client-types.ts new file mode 100644 index 00000000000..5f3a547b75b --- /dev/null +++ b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/kubo-rpc-client-types.ts @@ -0,0 +1,127 @@ +/** + * Since kubo-rpc-client uses ESM only, we can't import it to get types (since we use CJS). + * To fix this we define required types here, based on their counterparts in kubo-rpc-client. + */ + +import type { Multiaddr } from "@multiformats/multiaddr"; +import type { MultihashHasher } from "multiformats/hashes/interface"; +import type { Agent as HttpAgent } from "http"; +import type { Agent as HttpsAgent } from "https"; +import type { CID } from "multiformats/cid"; +import type { Mtime } from "ipfs-unixfs"; + +///////////////////////////////////// +// Types from kubo-rpc-client +///////////////////////////////////// +// Some are simplified when details are not needed + +export type MultibaseCodec = + import("multiformats/bases/interface").MultibaseCodec; +export type BlockCodec< + T1 = any, + T2 = any, +> = import("multiformats/codecs/interface").BlockCodec; + +export interface LoadBaseFn { + (codeOrName: number | string): Promise>; +} +export interface LoadCodecFn { + (codeOrName: number | string): Promise>; +} +export interface LoadHasherFn { + (codeOrName: number | string): Promise; +} + +export interface IPLDOptions { + loadBase: LoadBaseFn; + loadCodec: LoadCodecFn; + loadHasher: LoadHasherFn; + bases: Array>; + codecs: Array>; + hashers: MultihashHasher[]; +} + +export interface Options { + host?: string; + port?: number; + protocol?: string; + headers?: Headers | Record; + timeout?: number | string; + apiPath?: string; + url?: URL | string | Multiaddr; + ipld?: Partial; + agent?: HttpAgent | HttpsAgent; +} + +export type IPFSPath = CID | string; + +export interface StatResult { + cid: CID; + size: number; + cumulativeSize: number; + type: "directory" | "file"; + blocks: number; + withLocality: boolean; + local?: boolean; + sizeLocal?: number; + mode?: number; + mtime?: Mtime; +} + +///////////////////////////////////////////////////////// +// LikeIpfsHttpClient instead of full IpfsHttpClient +///////////////////////////////////////////////////////// + +/** + * Connector only needs these methods to work. + * More methods can be added in the future. + */ +export interface LikeIpfsHttpClientFile { + read: ( + ipfsPath: IPFSPath, + options?: Record, + ) => AsyncIterable; + + write: ( + ipfsPath: string, + content: + | string + | Uint8Array + | Blob + | AsyncIterable + | Iterable, + options?: Record, + ) => Promise; + + stat: ( + ipfsPath: IPFSPath, + options?: Record, + ) => Promise; +} + +export function isLikeIpfsHttpClientFile( + x: unknown, +): x is LikeIpfsHttpClientFile { + if (!x) { + return false; + } + return ( + typeof (x as LikeIpfsHttpClientFile).read === "function" && + typeof (x as LikeIpfsHttpClientFile).write === "function" && + typeof (x as LikeIpfsHttpClientFile).stat === "function" + ); +} + +/** + * Only files API is used + */ +export interface LikeIpfsHttpClient { + files: LikeIpfsHttpClientFile; +} + +export function isLikeIpfsHttpClient(x: unknown): x is LikeIpfsHttpClient { + if (!x) { + return false; + } + return isLikeIpfsHttpClientFile((x as LikeIpfsHttpClient).files); +} diff --git a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/plugin-object-store-ipfs.ts b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/plugin-object-store-ipfs.ts index 185b9568681..11faa25607e 100644 --- a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/plugin-object-store-ipfs.ts +++ b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/plugin-object-store-ipfs.ts @@ -1,7 +1,5 @@ import path from "path"; import type { Express } from "express"; -import { create, IPFSHTTPClient } from "ipfs-http-client"; -import type { Options } from "ipfs-http-client"; import { RuntimeError } from "run-time-error"; import { Logger, Checks, LoggerProvider } from "@hyperledger/cactus-common"; import type { LogLevelDesc } from "@hyperledger/cactus-common"; @@ -22,7 +20,11 @@ import OAS from "../json/openapi.json"; import { GetObjectEndpointV1 } from "./web-services/get-object-endpoint-v1"; import { SetObjectEndpointV1 } from "./web-services/set-object-endpoint-v1"; import { HasObjectEndpointV1 } from "./web-services/has-object-endpoint-v1"; -import { isIpfsHttpClientOptions } from "./i-ipfs-http-client"; +import { + LikeIpfsHttpClient, + isLikeIpfsHttpClient, + Options, +} from "./kubo-rpc-client-types"; export const K_IPFS_JS_HTTP_ERROR_FILE_DOES_NOT_EXIST = "HTTPError: file does not exist"; @@ -30,13 +32,13 @@ export const K_IPFS_JS_HTTP_ERROR_FILE_DOES_NOT_EXIST = export interface IPluginObjectStoreIpfsOptions extends ICactusPluginOptions { readonly logLevel?: LogLevelDesc; readonly parentDir: string; - readonly ipfsClientOrOptions: Options | IPFSHTTPClient; + readonly ipfsClientOrOptions: Options | LikeIpfsHttpClient; } export class PluginObjectStoreIpfs implements IPluginObjectStore { public static readonly CLASS_NAME = "PluginObjectStoreIpfs"; - private readonly ipfs: IPFSHTTPClient; + private ipfs: LikeIpfsHttpClient | undefined; private readonly log: Logger; private readonly instanceId: string; private readonly parentDir: string; @@ -45,6 +47,41 @@ export class PluginObjectStoreIpfs implements IPluginObjectStore { return PluginObjectStoreIpfs.CLASS_NAME; } + /** + * We use dynamic import for kubo-rpc-client since it's ESM and we can't import it normally. + * This methods will load the module and initialize local IPFS client based on ctor arguments. + */ + private async initIpfs(): Promise { + if (isLikeIpfsHttpClient(this.opts.ipfsClientOrOptions)) { + this.ipfs = this.opts.ipfsClientOrOptions; + } else if (this.opts.ipfsClientOrOptions) { + // Force no transpilation (see https://github.com/microsoft/TypeScript/issues/43329) + const kuboRpcModule = await (eval('import("kubo-rpc-client")') as Promise< + typeof import("kubo-rpc-client") + >); + this.ipfs = kuboRpcModule.create(this.opts.ipfsClientOrOptions); + } else { + const errorMessage = `initIpfs Need either "ipfsClient" or "ipfsClientOptions" to construct ${this.className} Neither was provided.`; + throw new RuntimeError(errorMessage); + } + } + + /** + * Get IPFS client or initialize it from constructor args. + * @returns `LikeIpfsHttpClient` or exception + */ + private async getIpfs(): Promise { + if (!this.ipfs) { + await this.initIpfs(); + } + + if (!this.ipfs) { + throw new Error("Could not instantiate ipfs http client"); + } + + return this.ipfs; + } + constructor(public readonly opts: IPluginObjectStoreIpfsOptions) { const fnTag = `${this.className}#constructor()`; Checks.truthy(opts, `${fnTag} arg options`); @@ -52,18 +89,6 @@ export class PluginObjectStoreIpfs implements IPluginObjectStore { Checks.nonBlankString(opts.parentDir, `${fnTag} options.parentDir`); Checks.truthy(opts.ipfsClientOrOptions, `${fnTag} ipfsClientOrOptions`); - if (isIpfsHttpClientOptions(opts.ipfsClientOrOptions)) { - this.ipfs = opts.ipfsClientOrOptions; - } else if (opts.ipfsClientOrOptions) { - this.ipfs = create({ - ...(this.opts.ipfsClientOrOptions as Options), - }); - } else { - const errorMessage = `${fnTag} Need either "ipfsClient" or "ipfsClientOptions" to construct ${this.className} Neither was provided.`; - throw new RuntimeError(errorMessage); - } - Checks.truthy(this.ipfs, `${fnTag} arg options.backend`); - const level = this.opts.logLevel || "INFO"; const label = this.className; this.log = LoggerProvider.getOrCreate({ level, label }); @@ -79,7 +104,7 @@ export class PluginObjectStoreIpfs implements IPluginObjectStore { } public async onPluginInit(): Promise { - return; // no-op + return this.initIpfs(); } public async registerWebServices( @@ -130,7 +155,8 @@ export class PluginObjectStoreIpfs implements IPluginObjectStore { public async get(req: GetObjectRequestV1): Promise { const keyPath = this.getKeyPath(req); - const chunksIterable = this.ipfs.files.read(keyPath); + const ipfs = await this.getIpfs(); + const chunksIterable = ipfs.files.read(keyPath); const chunks = []; for await (const chunk of chunksIterable) { chunks.push(chunk); @@ -151,7 +177,8 @@ export class PluginObjectStoreIpfs implements IPluginObjectStore { const checkedAt = new Date().toJSON(); const keyPath = this.getKeyPath(req); try { - const statResult = await this.ipfs.files.stat(keyPath); + const ipfs = await this.getIpfs(); + const statResult = await ipfs.files.stat(keyPath); this.log.debug(`StatResult for ${req.key}: %o`, statResult); return { key: req.key, checkedAt, isPresent: true }; } catch (ex) { @@ -170,7 +197,8 @@ export class PluginObjectStoreIpfs implements IPluginObjectStore { try { this.log.debug(`Seting object ${keyPath} in IPFS...`); const buffer = Buffer.from(req.value, "base64"); - await this.ipfs.files.write(keyPath, buffer, { + const ipfs = await this.getIpfs(); + await ipfs.files.write(keyPath, buffer, { create: true, parents: true, }); diff --git a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/public-api.ts b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/public-api.ts index 46e031206d6..3a2fd6d45c0 100755 --- a/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/public-api.ts +++ b/extensions/cactus-plugin-object-store-ipfs/src/main/typescript/public-api.ts @@ -1,5 +1,9 @@ export * from "./generated/openapi/typescript-axios/index"; -export { IIpfsHttpClient } from "./i-ipfs-http-client"; +export { + Options, + LikeIpfsHttpClientFile, + LikeIpfsHttpClient, +} from "./kubo-rpc-client-types"; import { IPluginFactoryOptions } from "@hyperledger/cactus-core-api"; export { PluginObjectStoreIpfs, diff --git a/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/fixtures/mock/ipfs/ipfs-files-api-mock.ts b/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/fixtures/mock/ipfs/ipfs-files-api-mock.ts deleted file mode 100644 index e0245e4a25e..00000000000 --- a/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/fixtures/mock/ipfs/ipfs-files-api-mock.ts +++ /dev/null @@ -1,157 +0,0 @@ -// Needed to disable the no-unused-vars check here because the file is full -// of unused method parameters given how this is a mock which doesn't do -// anything for the most part and that's by design. -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { CID } from "multiformats/cid"; -import { - API as FilesAPI, - ChmodOptions, - CpOptions, - MFSEntry, - MkdirOptions, - MvOptions, - ReadOptions, - RmOptions, - StatOptions, - StatResult, - TouchOptions, - WriteOptions, -} from "ipfs-core-types/src/files"; - -import { AbortOptions } from "ipfs-core-types"; -import { IPFSPath } from "ipfs-core-types/src/utils"; -import { RuntimeError } from "run-time-error"; - -import { Logger, Checks, LogLevelDesc } from "@hyperledger/cactus-common"; -import { LoggerProvider } from "@hyperledger/cactus-common"; -import { K_IPFS_JS_HTTP_ERROR_FILE_DOES_NOT_EXIST } from "../../../../../main/typescript/plugin-object-store-ipfs"; - -export interface IFilesApiMockOptions { - logLevel?: LogLevelDesc; -} - -export class FilesApiMock implements FilesAPI { - public static readonly CLASS_NAME = "FilesApiMock"; - - private readonly log: Logger; - private readonly data: Map; - - public get className(): string { - return FilesApiMock.CLASS_NAME; - } - - constructor(public readonly options: IFilesApiMockOptions) { - const fnTag = `${this.className}#constructor()`; - Checks.truthy(options, `${fnTag} arg options`); - - this.data = new Map(); - - const level = this.options.logLevel || "INFO"; - const label = this.className; - this.log = LoggerProvider.getOrCreate({ level, label }); - this.log.debug(`Instantiated ${this.className} OK`); - } - - public async chmod( - path: string, - mode: string | number, - options?: ChmodOptions | undefined, - ): Promise { - throw new RuntimeError("Method chmod() not implemented"); - } - - public async cp( - from: IPFSPath | IPFSPath[], - to: string, - options?: CpOptions | undefined, - ): Promise { - throw new RuntimeError("Method cp() not implemented"); - } - - public async mkdir( - path: string, - options?: MkdirOptions | undefined, - ): Promise { - throw new RuntimeError("Method mkdir() not implemented"); - } - - public async stat( - ipfsPath: IPFSPath, - options?: StatOptions | undefined, - ): Promise { - if (typeof ipfsPath !== "string") { - throw new RuntimeError("Sorry, the mock only supports string IPFS paths"); - } - if (this.data.has(ipfsPath)) { - return {} as StatResult; - } else { - throw new RuntimeError(K_IPFS_JS_HTTP_ERROR_FILE_DOES_NOT_EXIST); - } - } - - public async touch( - ipfsPath: string, - options?: TouchOptions | undefined, - ): Promise { - throw new RuntimeError("Method touch() not implemented"); - } - - public async rm( - ipfsPaths: string | string[], - options?: RmOptions | undefined, - ): Promise { - throw new RuntimeError("Method rm() not implemented"); - } - - public async *read( - ipfsPath: IPFSPath, - options?: ReadOptions | undefined, - ): AsyncIterable { - if (typeof ipfsPath !== "string") { - throw new RuntimeError("Sorry, the mock only supports string IPFS paths"); - } - const buffer = this.data.get(ipfsPath); - if (!buffer) { - throw new RuntimeError(K_IPFS_JS_HTTP_ERROR_FILE_DOES_NOT_EXIST); - } - yield buffer; - } - - public async write( - ipfsPath: string, - content: - | string - | Uint8Array - | AsyncIterable - | Blob - | Iterable, - options?: WriteOptions | undefined, - ): Promise { - if (!(content instanceof Buffer)) { - throw new RuntimeError("Sorry, this mock only supports Buffer content."); - } - this.data.set(ipfsPath, content); - } - - public async mv( - from: string | string[], - to: string, - options?: MvOptions | undefined, - ): Promise { - throw new RuntimeError("Method mv() not implemented"); - } - - public async flush( - ipfsPath: string, - options?: AbortOptions | undefined, - ): Promise { - throw new RuntimeError("Method flush() not implemented"); - } - - public ls( - ipfsPath: IPFSPath, - options?: AbortOptions | undefined, - ): AsyncIterable { - throw new RuntimeError("Method ls() not implemented"); - } -} diff --git a/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/integration/plugin-object-store-ipfs.test.ts b/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/integration/plugin-object-store-ipfs.test.ts index 4cfe3d2ee20..febb73b7d45 100644 --- a/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/integration/plugin-object-store-ipfs.test.ts +++ b/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/integration/plugin-object-store-ipfs.test.ts @@ -1,6 +1,5 @@ import test, { Test } from "tape-promise/tape"; -import { create } from "ipfs-http-client"; import express from "express"; import bodyParser from "body-parser"; import http from "http"; @@ -58,7 +57,11 @@ test(testCase, async (t: Test) => { t.comment(`Go IPFS Test Container API URL: ${ipfsApiUrl}`); t.comment(`Go IPFS Test Container Gateway URL: ${ipfsGatewayUrl}`); - const ipfsClientOrOptions = create({ + // Force no transpilation (see https://github.com/microsoft/TypeScript/issues/43329) + const kuboRpcModule = await (eval('import("kubo-rpc-client")') as Promise< + typeof import("kubo-rpc-client") + >); + const ipfsClientOrOptions = kuboRpcModule.create({ url: ipfsApiUrl, }); const instanceId = uuidv4(); diff --git a/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/unit/plugin-object-store-ipfs.test.ts b/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/unit/plugin-object-store-ipfs.test.ts index fd5ce1eee6f..d86dce01791 100644 --- a/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/unit/plugin-object-store-ipfs.test.ts +++ b/extensions/cactus-plugin-object-store-ipfs/src/test/typescript/unit/plugin-object-store-ipfs.test.ts @@ -3,7 +3,6 @@ import http from "http"; import test, { Test } from "tape-promise/tape"; import { v4 as uuidv4 } from "uuid"; -import { create } from "ipfs-http-client"; import express from "express"; import bodyParser from "body-parser"; @@ -16,9 +15,13 @@ import type { IPluginObjectStoreIpfsOptions } from "../../../main/typescript"; import { DefaultApi as ObjectStoreIpfsApi } from "../../../main/typescript/public-api"; -test("PluginObjectStoreIpfs", (t1: Test) => { +test("PluginObjectStoreIpfs", async (t1: Test) => { const logLevel: LogLevelDesc = "TRACE"; - const ipfsClientOrOptions = create(); + // Force no transpilation (see https://github.com/microsoft/TypeScript/issues/43329) + const kuboRpcModule = await (eval('import("kubo-rpc-client")') as Promise< + typeof import("kubo-rpc-client") + >); + const ipfsClientOrOptions = kuboRpcModule.create(); t1.doesNotThrow( () => new PluginObjectStoreIpfs({ @@ -50,8 +53,12 @@ test("PluginObjectStoreIpfs", (t1: Test) => { }); test.skip("get,set,has,delete alters state as expected", async (t: Test) => { + // Force no transpilation (see https://github.com/microsoft/TypeScript/issues/43329) + const kuboRpcModule = await (eval('import("kubo-rpc-client")') as Promise< + typeof import("kubo-rpc-client") + >); const options: IPluginObjectStoreIpfsOptions = { - ipfsClientOrOptions: create(), // FIXME: use an actual mock IPFS client + ipfsClientOrOptions: kuboRpcModule.create(), // FIXME: use an actual mock IPFS client instanceId: uuidv4(), parentDir: "/" + uuidv4(), logLevel, diff --git a/package.json b/package.json index 0da3210d8e1..c27cca1d6b4 100644 --- a/package.json +++ b/package.json @@ -78,11 +78,12 @@ }, "resolutions": { "ansi-html": ">0.0.8", - "axios": ">=0.22.0", + "axios": ">=0.27.2", "glob-parent": "5.1.2", "http-cache-semantics": ">=4.1.1", "lodash": ">=4.17.21", "minimist": ">=1.2.6", + "nano": ">=10.0.0", "node-forge": ">=1.3.0", "protobufjs": ">=7.2.5", "underscore": "1.13.2" diff --git a/yarn.lock b/yarn.lock index cc33f860805..3389604a5de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8026,12 +8026,14 @@ __metadata: "@hyperledger/cactus-core": 2.0.0-alpha.2 "@hyperledger/cactus-core-api": 2.0.0-alpha.2 "@hyperledger/cactus-test-tooling": 2.0.0-alpha.2 + "@multiformats/multiaddr": 11.6.1 "@types/express": 4.17.19 axios: 1.5.1 express: 4.18.2 ipfs-core-types: 0.14.1 - ipfs-http-client: 60.0.1 - multiformats: 9.4.9 + ipfs-unixfs: 9.0.1 + kubo-rpc-client: 3.0.1 + multiformats: 11.0.2 run-time-error: 1.4.0 typescript-optional: 2.0.1 uuid: 8.3.2 @@ -9656,6 +9658,23 @@ __metadata: languageName: node linkType: hard +"@libp2p/crypto@npm:^1.0.11": + version: 1.0.17 + resolution: "@libp2p/crypto@npm:1.0.17" + dependencies: + "@libp2p/interface-keys": ^1.0.2 + "@libp2p/interfaces": ^3.2.0 + "@noble/ed25519": ^1.6.0 + "@noble/secp256k1": ^1.5.4 + multiformats: ^11.0.0 + node-forge: ^1.1.0 + protons-runtime: ^5.0.0 + uint8arraylist: ^2.4.3 + uint8arrays: ^4.0.2 + checksum: 178474409ffe56ba6fb6b0f691e0b5de7fafb61c18a1a1197d75d0f9471e614c67d77fce84e337238d0835ba4b7bbc7f4b72ff9447968706c2ba190ed93cf650 + languageName: node + linkType: hard + "@libp2p/interface-connection@npm:^4.0.0": version: 4.0.0 resolution: "@libp2p/interface-connection@npm:4.0.0" @@ -9679,6 +9698,13 @@ __metadata: languageName: node linkType: hard +"@libp2p/interface-keys@npm:^1.0.2": + version: 1.0.8 + resolution: "@libp2p/interface-keys@npm:1.0.8" + checksum: 08c2976b3436b6e4e6159d1c817bb9e41af41d159cb94afaa8c63cf0fbf8842b0e5ca758d6c38453a59d8e4e87cec3117e3c574d316b94fed8db842a77f6efb0 + languageName: node + linkType: hard + "@libp2p/interface-peer-id@npm:^2.0.0, @libp2p/interface-peer-id@npm:^2.0.2": version: 2.0.2 resolution: "@libp2p/interface-peer-id@npm:2.0.2" @@ -10012,7 +10038,7 @@ __metadata: languageName: node linkType: hard -"@multiformats/multiaddr@npm:^11.1.5": +"@multiformats/multiaddr@npm:11.6.1, @multiformats/multiaddr@npm:^11.1.5": version: 11.6.1 resolution: "@multiformats/multiaddr@npm:11.6.1" dependencies: @@ -10135,6 +10161,13 @@ __metadata: languageName: node linkType: hard +"@noble/ed25519@npm:^1.6.0": + version: 1.7.3 + resolution: "@noble/ed25519@npm:1.7.3" + checksum: 45169927d51de513e47bbeebff3a603433c4ac7579e1b8c5034c380a0afedbe85e6959be3d69584a7a5ed6828d638f8f28879003b9bb2fb5f22d8aa2d88fd5fe + languageName: node + linkType: hard + "@noble/hashes@npm:1.1.2": version: 1.1.2 resolution: "@noble/hashes@npm:1.1.2" @@ -10156,7 +10189,7 @@ __metadata: languageName: node linkType: hard -"@noble/secp256k1@npm:1.7.1, @noble/secp256k1@npm:~1.7.0": +"@noble/secp256k1@npm:1.7.1, @noble/secp256k1@npm:^1.5.4, @noble/secp256k1@npm:~1.7.0": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" checksum: d2301f1f7690368d8409a3152450458f27e54df47e3f917292de3de82c298770890c2de7c967d237eff9c95b70af485389a9695f73eb05a43e2bd562d18b18cb @@ -13683,7 +13716,7 @@ __metadata: languageName: node linkType: hard -"@types/tough-cookie@npm:*, @types/tough-cookie@npm:^4.0.0": +"@types/tough-cookie@npm:*": version: 4.0.1 resolution: "@types/tough-cookie@npm:4.0.1" checksum: 7570c1c2d74201f4ead3512cf8e4c99e97d92ab8a02ae2fb987fd720ced0ca1a2baf250c98a861a170b86762606c9bf6d32207675f13dffc5ab75c08c96578d2 @@ -15149,7 +15182,7 @@ __metadata: languageName: node linkType: hard -"any-signal@npm:^3.0.0": +"any-signal@npm:^3.0.0, any-signal@npm:^3.0.1": version: 3.0.1 resolution: "any-signal@npm:3.0.1" checksum: 073eb14c365b7552f9f16fbf36cd76171e4a0fe156a8faa865fe1d5ac4ed2f5c5ab6e3faad0ac0d4c69511b5892971c5573baa8a1cbf85fe250d0c54ff0734ff @@ -16056,21 +16089,7 @@ __metadata: languageName: node linkType: hard -"axios-cookiejar-support@npm:^1.0.1": - version: 1.0.1 - resolution: "axios-cookiejar-support@npm:1.0.1" - dependencies: - is-redirect: ^1.0.0 - pify: ^5.0.0 - peerDependencies: - "@types/tough-cookie": ">=2.3.3" - axios: ">=0.16.2" - tough-cookie: ">=2.3.3" - checksum: 5479790240d108fc3ff1e393dc57ec51524f080ae3492f9d0aece876dab68513d79e99db72b642c72d6bc82d82dd64f26bd32eddc783739b0ab13ac9d5179dba - languageName: node - linkType: hard - -"axios@npm:>=0.22.0": +"axios@npm:>=0.27.2": version: 1.5.1 resolution: "axios@npm:1.5.1" dependencies: @@ -28510,7 +28529,7 @@ __metadata: languageName: node linkType: hard -"ipfs-core-utils@npm:^0.18.1": +"ipfs-core-utils@npm:^0.18.0, ipfs-core-utils@npm:^0.18.1": version: 0.18.1 resolution: "ipfs-core-utils@npm:0.18.1" dependencies: @@ -28565,7 +28584,7 @@ __metadata: languageName: node linkType: hard -"ipfs-unixfs@npm:^9.0.0": +"ipfs-unixfs@npm:9.0.1, ipfs-unixfs@npm:^9.0.0": version: 9.0.1 resolution: "ipfs-unixfs@npm:9.0.1" dependencies: @@ -28575,7 +28594,7 @@ __metadata: languageName: node linkType: hard -"ipfs-utils@npm:^9.0.13": +"ipfs-utils@npm:^9.0.13, ipfs-utils@npm:^9.0.7": version: 9.0.14 resolution: "ipfs-utils@npm:9.0.14" dependencies: @@ -29311,13 +29330,6 @@ __metadata: languageName: node linkType: hard -"is-redirect@npm:^1.0.0": - version: 1.0.0 - resolution: "is-redirect@npm:1.0.0" - checksum: 25dd3d9943f57ef0f29d28e2d9deda8288e0c7098ddc65abec3364ced9a6491ea06cfaf5110c61fc40ec1fde706b73cee5d171f85278edbf4e409b85725bfea7 - languageName: node - linkType: hard - "is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" @@ -32027,6 +32039,33 @@ __metadata: languageName: node linkType: hard +"kubo-rpc-client@npm:3.0.1": + version: 3.0.1 + resolution: "kubo-rpc-client@npm:3.0.1" + dependencies: + "@ipld/dag-cbor": ^9.0.0 + "@ipld/dag-json": ^10.0.0 + "@ipld/dag-pb": ^4.0.0 + "@libp2p/crypto": ^1.0.11 + "@libp2p/logger": ^2.0.5 + "@libp2p/peer-id": ^2.0.0 + "@multiformats/multiaddr": ^11.1.5 + any-signal: ^3.0.1 + dag-jose: ^4.0.0 + err-code: ^3.0.1 + ipfs-core-utils: ^0.18.0 + ipfs-utils: ^9.0.7 + it-first: ^2.0.0 + it-last: ^2.0.0 + merge-options: ^3.0.4 + multiformats: ^11.0.0 + parse-duration: ^1.0.2 + stream-to-it: ^0.2.4 + uint8arrays: ^4.0.3 + checksum: 19de983eccf131c7a53f7c73bc8446ccd49436d32d6bb215f93fe2084fbff196d3d722bee11c22c3c48531a2d71c7521241a299b08fa9302907a3a0478fb51a3 + languageName: node + linkType: hard + "kuler@npm:^2.0.0": version: 2.0.0 resolution: "kuler@npm:2.0.0" @@ -34642,14 +34681,7 @@ __metadata: languageName: node linkType: hard -"multiformats@npm:9.4.9": - version: 9.4.9 - resolution: "multiformats@npm:9.4.9" - checksum: 93dec933ef5849cab1e1cf4374f08f1943905d609cce16eb4ada2742163e5d89254fec65a380a9e2e3968affa349020ffdbf91a9813d3583c45630fa9bea71c3 - languageName: node - linkType: hard - -"multiformats@npm:^11.0.0, multiformats@npm:^11.0.2": +"multiformats@npm:11.0.2, multiformats@npm:^11.0.0, multiformats@npm:^11.0.2": version: 11.0.2 resolution: "multiformats@npm:11.0.2" checksum: e587bbe709f29e42ae3c22458c960070269027d962183afc49a83b8ba26c31525e81ce2ac71082a52ba0a75e9aed4d0d044cac68d32656fdcd5cd340fb367fac @@ -34783,29 +34815,14 @@ __metadata: languageName: node linkType: hard -"nano@npm:^10.0.0": - version: 10.0.0 - resolution: "nano@npm:10.0.0" - dependencies: - "@types/tough-cookie": ^4.0.0 - axios: ^0.26.1 - axios-cookiejar-support: ^1.0.1 - qs: ^6.10.3 - tough-cookie: ^4.0.0 - checksum: 73cb0bbd209649622e15b8a481ca65579cfd14152ad2f3a63d379751a00c0b1156006322efa0823e2d1fb0328a962e552503675b647e1d8a304b26dea0a6c0bd - languageName: node - linkType: hard - -"nano@npm:^9.0.5": - version: 9.0.5 - resolution: "nano@npm:9.0.5" +"nano@npm:>=10.0.0": + version: 10.1.2 + resolution: "nano@npm:10.1.2" dependencies: - "@types/tough-cookie": ^4.0.0 - axios: ^0.21.1 - axios-cookiejar-support: ^1.0.1 - qs: ^6.9.4 - tough-cookie: ^4.0.0 - checksum: 31bc5e2f784a6b3a9a872b24860152c31c4d5e3e3e096a3b1fc2660252c69b498c1094525972669fd3bfebe853a1471f5d20daf108d39067c505e58d4f2e4b8d + axios: ^1.2.2 + node-abort-controller: ^3.0.1 + qs: ^6.11.0 + checksum: bf866bbeecd376d372974f347c3d4601c3058207bbe660fac46f69676420815ddeedce98f056be9aaefbfbb8d05bef342ce0ac492aa04133b92737454e7f61ce languageName: node linkType: hard @@ -37088,6 +37105,13 @@ __metadata: languageName: node linkType: hard +"parse-duration@npm:^1.0.2": + version: 1.1.0 + resolution: "parse-duration@npm:1.1.0" + checksum: 3cfc10aa61b3a06373a347289e1704de47d5d845c79330bbab20b54c02567f3710ba84544a3a44a986c3381c68670d89542fe9de607fb0814e52f78b34893cd9 + languageName: node + linkType: hard + "parse-glob@npm:^3.0.4": version: 3.0.4 resolution: "parse-glob@npm:3.0.4" @@ -37623,13 +37647,6 @@ __metadata: languageName: node linkType: hard -"pify@npm:^5.0.0": - version: 5.0.0 - resolution: "pify@npm:5.0.0" - checksum: 443e3e198ad6bfa8c0c533764cf75c9d5bc976387a163792fb553ffe6ce923887cf14eebf5aea9b7caa8eab930da8c33612990ae85bd8c2bc18bedb9eae94ecb - languageName: node - linkType: hard - "pify@npm:^6.1.0": version: 6.1.0 resolution: "pify@npm:6.1.0" @@ -39444,6 +39461,16 @@ __metadata: languageName: node linkType: hard +"protons-runtime@npm:^5.0.0": + version: 5.0.5 + resolution: "protons-runtime@npm:5.0.5" + dependencies: + uint8arraylist: ^2.4.3 + uint8arrays: ^4.0.6 + checksum: 3709164d2cde019a065b0a1a5872e70eeb188c71c45f699b86f4aa389d2f4282a46022998370131afa0e04173fbb56feec903e81fd3e8021ae8ddcba73f87ded + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.5, proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -39603,7 +39630,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.10.3, qs@npm:^6.9.4": +"qs@npm:^6.11.0": version: 6.11.2 resolution: "qs@npm:6.11.2" dependencies: @@ -43696,7 +43723,7 @@ __metadata: languageName: node linkType: hard -"stream-to-it@npm:^0.2.2": +"stream-to-it@npm:^0.2.2, stream-to-it@npm:^0.2.4": version: 0.2.4 resolution: "stream-to-it@npm:0.2.4" dependencies: @@ -46343,7 +46370,7 @@ __metadata: languageName: node linkType: hard -"uint8arrays@npm:^4.0.2": +"uint8arrays@npm:^4.0.2, uint8arrays@npm:^4.0.3, uint8arrays@npm:^4.0.6": version: 4.0.6 resolution: "uint8arrays@npm:4.0.6" dependencies: