From 3569d5317064fd3cb6326bd1ea6e4447fb354071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Dethier?= Date: Thu, 2 Nov 2023 17:20:58 +0100 Subject: [PATCH] feat: prepare for react-native support. logion-network/logion-internal#1046 --- package.json | 1 + packages/client-browser/.eslintrc.json | 5 + packages/client-browser/.npmignore | 6 + packages/client-browser/README.md | 11 ++ packages/client-browser/jasmine.json | 15 ++ packages/client-browser/package.json | 51 ++++++ packages/client-browser/src/index.ts | 49 +++++ packages/client-browser/test/index.spec.ts | 36 ++++ packages/client-browser/tsconfig.json | 11 ++ packages/client-browser/typedoc.json | 6 + packages/client-node/.eslintrc.json | 5 + packages/client-node/.npmignore | 13 ++ packages/client-node/README.md | 11 ++ .../docker-compose.yml | 0 .../{client => client-node}/front_config.js | 0 .../{client => client-node}/front_web1.conf | 0 .../{client => client-node}/front_web2.conf | 0 .../{client => client-node}/front_web3.conf | 0 .../integration/Balance.ts | 9 +- .../integration/DirectLocOpen.ts | 11 +- .../integration/Fees.ts | 4 +- .../integration/LegalOfficer.ts | 5 +- .../integration/Loc.ts | 17 +- .../integration/Main.spec.ts | 0 .../integration/Protection.ts | 2 +- .../integration/Recovery.ts | 2 +- .../integration/TokensRecord.ts | 5 +- .../integration/Utils.ts | 28 +-- .../integration/Vault.ts | 2 +- .../integration/VerifiedIssuer.ts | 6 +- .../integration/Void.ts | 2 +- .../integration/Vote.ts | 2 +- .../client-node/integration/collection-1.txt | 1 + .../client-node/integration/collection-2.txt | 1 + .../client-node/integration/identity-1.txt | 1 + .../client-node/integration/identity-2.txt | 1 + .../integration/test.txt | 0 packages/client-node/integration/test0.txt | 1 + packages/client-node/integration/test123.txt | 1 + packages/client-node/integration/test2.txt | 1 + .../client-node/integration/transaction-1.txt | 1 + .../client-node/integration/transaction-2.txt | 1 + .../jasmine-integration.json | 0 packages/client-node/jasmine.json | 15 ++ packages/client-node/package.json | 53 ++++++ .../scripts/directory_data.sql | 0 .../scripts/init_onchain_data.js | 0 .../scripts/integration_test_db_setup.sh | 0 packages/client-node/src/index.ts | 57 ++++++ .../{client => client-node}/test/file.txt | 0 packages/client-node/test/index.spec.ts | 14 ++ packages/client-node/tsconfig.app.json | 6 + packages/client-node/tsconfig.json | 11 ++ .../tsconfig.test.json | 0 packages/client-node/typedoc.json | 6 + .../{client => client-node}/typescript.js | 0 packages/client/.npmignore | 8 +- .../client/config/ipfs-cluster1/identity.json | 4 - .../client/config/ipfs-cluster1/service.json | 168 ----------------- .../client/config/ipfs-cluster2/identity.json | 4 - .../client/config/ipfs-cluster2/service.json | 168 ----------------- .../client/config/ipfs-cluster3/identity.json | 4 - .../client/config/ipfs-cluster3/service.json | 170 ------------------ packages/client/config/ipfs1/config | 153 ---------------- packages/client/config/ipfs1/datastore_spec | 1 - packages/client/config/ipfs1/swarm.key | 3 - packages/client/config/ipfs1/version | 1 - packages/client/config/ipfs2/config | 153 ---------------- packages/client/config/ipfs2/datastore_spec | 1 - packages/client/config/ipfs2/swarm.key | 3 - packages/client/config/ipfs2/version | 1 - packages/client/config/ipfs3/config | 153 ---------------- packages/client/config/ipfs3/datastore_spec | 1 - packages/client/config/ipfs3/swarm.key | 3 - packages/client/config/ipfs3/version | 1 - packages/client/package.json | 8 +- packages/client/src/ComponentFactory.ts | 82 ++++++++- packages/client/src/Hash.ts | 107 +---------- packages/client/src/LocClient.ts | 110 ++++++++---- packages/client/src/LogionClient.ts | 13 +- packages/client/src/SharedClient.ts | 4 +- packages/client/src/Signer.ts | 14 +- packages/client/src/Types.ts | 2 +- packages/client/test/Hash.spec.ts | 28 ++- packages/client/test/Loc.spec.ts | 49 +++-- packages/client/test/LogionClient.spec.ts | 9 +- packages/client/test/Public.spec.ts | 2 +- packages/client/test/Signer.spec.ts | 6 +- packages/client/test/TestConfigFactory.ts | 17 +- packages/client/test/Utils.ts | 22 ++- packages/client/test/Voter.spec.ts | 2 +- packages/crossmint/.npmignore | 1 + packages/crossmint/package.json | 11 +- packages/extension/.npmignore | 1 + packages/extension/package.json | 11 +- packages/multiversx/.npmignore | 1 + packages/multiversx/README.md | 24 +++ packages/multiversx/package.json | 11 +- packages/node-api/package.json | 4 +- website/package.json | 3 +- yarn.lock | 54 +++++- 101 files changed, 794 insertions(+), 1288 deletions(-) create mode 100644 packages/client-browser/.eslintrc.json create mode 100644 packages/client-browser/.npmignore create mode 100644 packages/client-browser/README.md create mode 100644 packages/client-browser/jasmine.json create mode 100644 packages/client-browser/package.json create mode 100644 packages/client-browser/src/index.ts create mode 100644 packages/client-browser/test/index.spec.ts create mode 100644 packages/client-browser/tsconfig.json create mode 100644 packages/client-browser/typedoc.json create mode 100644 packages/client-node/.eslintrc.json create mode 100644 packages/client-node/.npmignore create mode 100644 packages/client-node/README.md rename packages/{client => client-node}/docker-compose.yml (100%) rename packages/{client => client-node}/front_config.js (100%) rename packages/{client => client-node}/front_web1.conf (100%) rename packages/{client => client-node}/front_web2.conf (100%) rename packages/{client => client-node}/front_web3.conf (100%) rename packages/{client => client-node}/integration/Balance.ts (93%) rename packages/{client => client-node}/integration/DirectLocOpen.ts (95%) rename packages/{client => client-node}/integration/Fees.ts (71%) rename packages/{client => client-node}/integration/LegalOfficer.ts (68%) rename packages/{client => client-node}/integration/Loc.ts (98%) rename packages/{client => client-node}/integration/Main.spec.ts (100%) rename packages/{client => client-node}/integration/Protection.ts (99%) rename packages/{client => client-node}/integration/Recovery.ts (99%) rename packages/{client => client-node}/integration/TokensRecord.ts (94%) rename packages/{client => client-node}/integration/Utils.ts (88%) rename packages/{client => client-node}/integration/Vault.ts (98%) rename packages/{client => client-node}/integration/VerifiedIssuer.ts (97%) rename packages/{client => client-node}/integration/Void.ts (92%) rename packages/{client => client-node}/integration/Vote.ts (95%) create mode 100644 packages/client-node/integration/collection-1.txt create mode 100644 packages/client-node/integration/collection-2.txt create mode 100644 packages/client-node/integration/identity-1.txt create mode 100644 packages/client-node/integration/identity-2.txt rename packages/{client => client-node}/integration/test.txt (100%) create mode 100644 packages/client-node/integration/test0.txt create mode 100644 packages/client-node/integration/test123.txt create mode 100644 packages/client-node/integration/test2.txt create mode 100644 packages/client-node/integration/transaction-1.txt create mode 100644 packages/client-node/integration/transaction-2.txt rename packages/{client => client-node}/jasmine-integration.json (100%) create mode 100644 packages/client-node/jasmine.json create mode 100644 packages/client-node/package.json rename packages/{client => client-node}/scripts/directory_data.sql (100%) rename packages/{client => client-node}/scripts/init_onchain_data.js (100%) rename packages/{client => client-node}/scripts/integration_test_db_setup.sh (100%) create mode 100644 packages/client-node/src/index.ts rename packages/{client => client-node}/test/file.txt (100%) create mode 100644 packages/client-node/test/index.spec.ts create mode 100644 packages/client-node/tsconfig.app.json create mode 100644 packages/client-node/tsconfig.json rename packages/{client => client-node}/tsconfig.test.json (100%) create mode 100644 packages/client-node/typedoc.json rename packages/{client => client-node}/typescript.js (100%) delete mode 100644 packages/client/config/ipfs-cluster1/identity.json delete mode 100644 packages/client/config/ipfs-cluster1/service.json delete mode 100644 packages/client/config/ipfs-cluster2/identity.json delete mode 100644 packages/client/config/ipfs-cluster2/service.json delete mode 100644 packages/client/config/ipfs-cluster3/identity.json delete mode 100644 packages/client/config/ipfs-cluster3/service.json delete mode 100644 packages/client/config/ipfs1/config delete mode 100644 packages/client/config/ipfs1/datastore_spec delete mode 100644 packages/client/config/ipfs1/swarm.key delete mode 100644 packages/client/config/ipfs1/version delete mode 100644 packages/client/config/ipfs2/config delete mode 100644 packages/client/config/ipfs2/datastore_spec delete mode 100644 packages/client/config/ipfs2/swarm.key delete mode 100644 packages/client/config/ipfs2/version delete mode 100644 packages/client/config/ipfs3/config delete mode 100644 packages/client/config/ipfs3/datastore_spec delete mode 100644 packages/client/config/ipfs3/swarm.key delete mode 100644 packages/client/config/ipfs3/version create mode 100644 packages/multiversx/README.md diff --git a/package.json b/package.json index 133c8e8d..cebe3229 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "packageManager": "yarn@3.2.0", "scripts": { "build": "yarn workspaces foreach -t run build", + "clean": "yarn workspaces foreach -t run clean", "lint": "yarn workspaces foreach -t run lint", "test": "yarn workspaces foreach -t run test" } diff --git a/packages/client-browser/.eslintrc.json b/packages/client-browser/.eslintrc.json new file mode 100644 index 00000000..57774ea0 --- /dev/null +++ b/packages/client-browser/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.eslintrc.json" + ] +} diff --git a/packages/client-browser/.npmignore b/packages/client-browser/.npmignore new file mode 100644 index 00000000..6dd95767 --- /dev/null +++ b/packages/client-browser/.npmignore @@ -0,0 +1,6 @@ +/test/** +/src/** +jasmine*.json +tsconfig*.json +.eslintrc.json +typedoc.json diff --git a/packages/client-browser/README.md b/packages/client-browser/README.md new file mode 100644 index 00000000..585a8342 --- /dev/null +++ b/packages/client-browser/README.md @@ -0,0 +1,11 @@ +# Logion Client SDK (browser) + +This project provides a JS/TypeScript SDK enabling an application running in a browser to interact with a logion network. + +## Installation + +Use your favorite package manager (e.g. yarn) and install package `@logion/client-browser` in your JavaScript/TypeScript project. + +## Usage + +See [core client](../client/README.md). diff --git a/packages/client-browser/jasmine.json b/packages/client-browser/jasmine.json new file mode 100644 index 00000000..ff7eff1f --- /dev/null +++ b/packages/client-browser/jasmine.json @@ -0,0 +1,15 @@ +{ + "spec_dir": "test", + "spec_files": [ + "**/*.spec.ts" + ], + "helpers": [ + "../typescript.js" + ], + "stopSpecOnExpectationFailure": false, + "reporters": [ + { + "name": "jasmine-spec-reporter#SpecReporter" + } + ] +} \ No newline at end of file diff --git a/packages/client-browser/package.json b/packages/client-browser/package.json new file mode 100644 index 00000000..2bcb28fa --- /dev/null +++ b/packages/client-browser/package.json @@ -0,0 +1,51 @@ +{ + "name": "@logion/client-browser", + "version": "0.1.0-1", + "description": "logion SDK for client applications running in a browser", + "main": "dist/index.js", + "packageManager": "yarn@3.2.0", + "type": "module", + "scripts": { + "build": "yarn lint && tsc -p tsconfig.json", + "lint": "yarn eslint src/**", + "test": "NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine.json", + "clean": "rm -rf dist" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/logion-network/logion-api.git", + "directory": "packages/client-browser" + }, + "keywords": [ + "logion", + "api", + "client", + "browser" + ], + "author": "Logion Team", + "license": "Apache-2.0", + "dependencies": { + "@logion/client": "workspace:^" + }, + "bugs": { + "url": "https://github.com/logion-network/logion-api/issues" + }, + "homepage": "https://github.com/logion-network/logion-api/packages/client-browser#readme", + "devDependencies": { + "@tsconfig/node18": "^1.0.1", + "@types/jasmine": "^4.0.3", + "@types/node": "^18.6.1", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", + "eslint": "^8.20.0", + "jasmine": "^4.3.0", + "jasmine-spec-reporter": "^7.0.0", + "moq.ts": "^9.0.2", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + }, + "engines": { + "node": ">=18" + }, + "stableVersion": "0.1.0" +} diff --git a/packages/client-browser/src/index.ts b/packages/client-browser/src/index.ts new file mode 100644 index 00000000..cfe68e20 --- /dev/null +++ b/packages/client-browser/src/index.ts @@ -0,0 +1,49 @@ +import { Hash as Hasher } from 'fast-sha256'; +import { AxiosFileUploader, File, FormDataLike, HashAndSize } from "@logion/client"; +import { Hash } from "@logion/node-api"; + +export class BrowserFile extends File { + + constructor(file: Blob) { + super(); + this.file = file; + } + + private file: Blob; + + async getHashAndSize(): Promise { + const unknownStream: any = this.file.stream(); // eslint-disable-line @typescript-eslint/no-explicit-any + const reader = unknownStream.getReader(); + const digest = new Hasher(); + let size = 0n; + let chunk: {done: boolean, value: Buffer} = await reader.read(); + while(!chunk.done) { + size = size + BigInt(chunk.value.length); + digest.update(chunk.value); + chunk = await reader.read(); + } + return { + hash: Hash.fromDigest(digest), + size, + }; + } + + getBlob(): Blob { + return this.file; + } +} + +export class BrowserAxiosFileUploader extends AxiosFileUploader { + + override buildFormData(): FormDataLike { + return new FormData(); + } + + override toFormDataValue(file: File): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + if(file instanceof BrowserFile) { + return Promise.resolve(file.getBlob()); + } else { + return Promise.reject(new Error("Unsupported file type")); + } + } +} diff --git a/packages/client-browser/test/index.spec.ts b/packages/client-browser/test/index.spec.ts new file mode 100644 index 00000000..b21d56c9 --- /dev/null +++ b/packages/client-browser/test/index.spec.ts @@ -0,0 +1,36 @@ +import { Hash } from "@logion/node-api"; +import { Mock, PlayTimes } from "moq.ts"; +import { BrowserFile } from "../src/index.js"; + +const TEST_HASH = Hash.fromHex("0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); + +describe("BrowserFile", () => { + + it("gets hash and size", async () => { + const file = new BrowserFile(BLOB_MOCK); + const hashSize = await file.getHashAndSize(); + expect(hashSize.hash).toEqual(TEST_HASH); + expect(hashSize.size).toBe(4n); + }); +}); + +const READER_MOCK = new Mock() + .setup(instance => instance.read()) + .play(PlayTimes.Once()) + .returns({ done: true }) + + .setup(instance => instance.read()) + .play(PlayTimes.Once()) + .returns({ done: false, value: Buffer.from("test") }) + + .object(); + +const STREAM_MOCK = new Mock() + .setup(instance => instance.getReader()) + .returns(READER_MOCK) + .object(); + +const BLOB_MOCK = new Mock() + .setup(instance => instance.stream()) + .returns(STREAM_MOCK) + .object(); diff --git a/packages/client-browser/tsconfig.json b/packages/client-browser/tsconfig.json new file mode 100644 index 00000000..b26a17bd --- /dev/null +++ b/packages/client-browser/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "lib": ["dom"], + "baseUrl": "." + }, + "include": [ + "./src/**/*" + ] +} diff --git a/packages/client-browser/typedoc.json b/packages/client-browser/typedoc.json new file mode 100644 index 00000000..cf7fcb2c --- /dev/null +++ b/packages/client-browser/typedoc.json @@ -0,0 +1,6 @@ +{ + "name": "Client (Browser)", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/client-node/.eslintrc.json b/packages/client-node/.eslintrc.json new file mode 100644 index 00000000..57774ea0 --- /dev/null +++ b/packages/client-node/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "extends": [ + "../../.eslintrc.json" + ] +} diff --git a/packages/client-node/.npmignore b/packages/client-node/.npmignore new file mode 100644 index 00000000..2d291c7c --- /dev/null +++ b/packages/client-node/.npmignore @@ -0,0 +1,13 @@ +/test/** +/integration/** +/src/** +/scripts/** +docker-compose.yml +front_config.js +front_web*.conf +jasmine*.json +tsconfig*.json +/config/** +.eslintrc.json +typedoc.json +typescript.js diff --git a/packages/client-node/README.md b/packages/client-node/README.md new file mode 100644 index 00000000..585a8342 --- /dev/null +++ b/packages/client-node/README.md @@ -0,0 +1,11 @@ +# Logion Client SDK (browser) + +This project provides a JS/TypeScript SDK enabling an application running in a browser to interact with a logion network. + +## Installation + +Use your favorite package manager (e.g. yarn) and install package `@logion/client-browser` in your JavaScript/TypeScript project. + +## Usage + +See [core client](../client/README.md). diff --git a/packages/client/docker-compose.yml b/packages/client-node/docker-compose.yml similarity index 100% rename from packages/client/docker-compose.yml rename to packages/client-node/docker-compose.yml diff --git a/packages/client/front_config.js b/packages/client-node/front_config.js similarity index 100% rename from packages/client/front_config.js rename to packages/client-node/front_config.js diff --git a/packages/client/front_web1.conf b/packages/client-node/front_web1.conf similarity index 100% rename from packages/client/front_web1.conf rename to packages/client-node/front_web1.conf diff --git a/packages/client/front_web2.conf b/packages/client-node/front_web2.conf similarity index 100% rename from packages/client/front_web2.conf rename to packages/client-node/front_web2.conf diff --git a/packages/client/front_web3.conf b/packages/client-node/front_web3.conf similarity index 100% rename from packages/client/front_web3.conf rename to packages/client-node/front_web3.conf diff --git a/packages/client/integration/Balance.ts b/packages/client-node/integration/Balance.ts similarity index 93% rename from packages/client/integration/Balance.ts rename to packages/client-node/integration/Balance.ts index 0e171ca3..32fbaf3a 100644 --- a/packages/client/integration/Balance.ts +++ b/packages/client-node/integration/Balance.ts @@ -1,9 +1,8 @@ import { Numbers, Currency, CoinBalance } from "@logion/node-api"; +import { BalanceState, waitFor } from "@logion/client"; import { State, REQUESTER_ADDRESS } from "./Utils.js"; -import { ALICE } from "../test/Utils.js"; -import { BalanceState } from "../src/Balance.js"; -import { waitFor } from "../src/Polling.js"; +import { ALICE } from "./Utils.js"; export async function transfers(state: State) { const { client, signer, aliceAccount, requesterAccount } = state; @@ -36,7 +35,7 @@ export async function transfers(state: State) { userState = await userState.transfer({ signer, amount: new Numbers.PrefixedNumber("2", Numbers.KILO), - destination: ALICE.address + destination: ALICE }); checkBalance(userState, "2.99k"); @@ -68,7 +67,7 @@ export async function transferAndCannotPayFees(state: State) { await expectAsync(balanceState.transfer({ signer, amount: new Numbers.PrefixedNumber("1", Numbers.NONE), - destination: ALICE.address, + destination: ALICE, })).toBeRejectedWithError("Not enough funds available to pay fees"); } diff --git a/packages/client/integration/DirectLocOpen.ts b/packages/client-node/integration/DirectLocOpen.ts similarity index 95% rename from packages/client/integration/DirectLocOpen.ts rename to packages/client-node/integration/DirectLocOpen.ts index 59376447..25f1a502 100644 --- a/packages/client/integration/DirectLocOpen.ts +++ b/packages/client-node/integration/DirectLocOpen.ts @@ -1,3 +1,4 @@ +import { NodeFile } from "../src/index.js"; import { State, initRequesterBalance, @@ -5,7 +6,7 @@ import { DIRECT_REQUESTER_ADDRESS, findWithLegalOfficerClient, } from "./Utils.js"; -import { ALICE } from "../test/Utils.js"; +import { ALICE } from "./Utils.js"; import { HashOrContent, ItemsParams, @@ -18,7 +19,7 @@ import { LocData, OpenLoc, waitFor -} from "../src/index.js"; +} from "@logion/client"; import { UUID } from "@logion/node-api"; export async function openIdentityLoc(state: State): Promise { @@ -129,7 +130,7 @@ function checkData(data: LocData, items: ItemsParams) { expect(data.requesterLocId).toBeUndefined(); expect(data.requesterAddress?.address).toEqual(DIRECT_REQUESTER_ADDRESS); expect(data.requesterAddress?.type).toEqual("Polkadot"); - expect(data.ownerAddress).toEqual(ALICE.address); + expect(data.ownerAddress).toEqual(ALICE); expect(data.files.length).toEqual(items.files.length); expect(data.metadata.length).toEqual(items.metadata.length); @@ -153,12 +154,12 @@ function provideItems(name: string, linkedLocs: UUID[]): ItemsParams { { fileName: `${ name }-1.txt`, nature: "Some file nature", - file: HashOrContent.fromContent(Buffer.from(name + "1")), + file: HashOrContent.fromContent(new NodeFile(`integration/${ name }-1.txt`)), }, { fileName: `${ name }-2.txt`, nature: "Some other file nature", - file: HashOrContent.fromContent(Buffer.from(name + "2")), + file: HashOrContent.fromContent(new NodeFile(`integration/${ name }-2.txt`)), }, ], metadata: [ diff --git a/packages/client/integration/Fees.ts b/packages/client-node/integration/Fees.ts similarity index 71% rename from packages/client/integration/Fees.ts rename to packages/client-node/integration/Fees.ts index 4b89d968..dfc59358 100644 --- a/packages/client/integration/Fees.ts +++ b/packages/client-node/integration/Fees.ts @@ -1,10 +1,10 @@ -import { ALICE } from "../test/Utils.js"; +import { ALICE } from "./Utils.js"; import { State, REQUESTER_ADDRESS } from "./Utils.js"; export async function fees(state: State) { const client = state.client; const api = client.logionApi; - const submittable = api.polkadot.tx.balances.transfer(ALICE.address, "10000000"); + const submittable = api.polkadot.tx.balances.transfer(ALICE, "10000000"); const fees = await client.public.fees.estimateWithoutStorage({ origin: REQUESTER_ADDRESS, submittable }); expect(fees.totalFee).toBe(3085311440000000n); } diff --git a/packages/client/integration/LegalOfficer.ts b/packages/client-node/integration/LegalOfficer.ts similarity index 68% rename from packages/client/integration/LegalOfficer.ts rename to packages/client-node/integration/LegalOfficer.ts index 74f6db0a..bef6cae1 100644 --- a/packages/client/integration/LegalOfficer.ts +++ b/packages/client-node/integration/LegalOfficer.ts @@ -1,11 +1,10 @@ -import { ALICE } from "../test/Utils.js"; -import { State } from "./Utils.js"; +import { ALICE, State } from "./Utils.js"; export async function backendConfig(state: State) { const { client, requesterAccount } = state; const authenticatedClient = client.withCurrentAddress(requesterAccount); - const alice = authenticatedClient.getLegalOfficer(ALICE.address); + const alice = authenticatedClient.getLegalOfficer(ALICE); const config = await alice.getConfig(); expect(config.features.iDenfy).toBe(false); diff --git a/packages/client/integration/Loc.ts b/packages/client-node/integration/Loc.ts similarity index 98% rename from packages/client/integration/Loc.ts rename to packages/client-node/integration/Loc.ts index 9cc79787..f97b7a1c 100644 --- a/packages/client/integration/Loc.ts +++ b/packages/client-node/integration/Loc.ts @@ -18,9 +18,10 @@ import { OnchainLocState, AcceptedRequest, HashString -} from "../src/index.js"; +} from "@logion/client"; import { State, TEST_LOGION_CLIENT_CONFIG, findWithLegalOfficerClient, initRequesterBalance } from "./Utils.js"; +import { NodeFile } from "../src/index.js"; export async function requestTransactionLoc(state: State, linkTarget: UUID): Promise { const { alice, aliceAccount, newAccount, signer } = state; @@ -116,7 +117,7 @@ export async function requestTransactionLoc(state: State, linkTarget: UUID): Pro openLoc = await openLoc.addFile({ fileName: "test.txt", nature: "Some file nature", - file: HashOrContent.fromContent(Buffer.from("test")), + file: HashOrContent.fromContent(new NodeFile("integration/test.txt")), }) as OpenLoc; const hash = openLoc.data().files[0].hash; expect(hash.toHex()).toBe("0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); @@ -247,13 +248,13 @@ export async function openTransactionLocWithAutoPublish(state: State, linkTarget draftRequest = await draftRequest.addFile({ fileName: "test.txt", nature: "Some file nature", - file: HashOrContent.fromContent(Buffer.from("test0")), + file: HashOrContent.fromContent(new NodeFile("test0.txt")), }) as DraftRequest; const hash0 = draftRequest.data().files[0].hash; draftRequest = await draftRequest.addFile({ fileName: "test.txt", nature: "Some file nature", - file: HashOrContent.fromContent(Buffer.from("test123")), + file: HashOrContent.fromContent(new NodeFile("test123.txt")), }) as DraftRequest; const hash1 = draftRequest.data().files[1].hash; @@ -466,7 +467,7 @@ export async function collectionLocWithUpload(state: State) { new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent("integration/test.txt"), // Let SDK compute hash and size + hashOrContent: HashOrContent.fromContent(new NodeFile("integration/test.txt")), // Let SDK compute hash and size }) ], itemToken: firstItemToken, @@ -501,8 +502,8 @@ export async function collectionLocWithUpload(state: State) { const secondItemId = Hash.of("second-collection-item"); const secondItemDescription = "Second collection item"; - const secondFileContent = "test2"; - const secondFileHash = Hash.of(secondFileContent); + const secondFile = new NodeFile("integration/test2.txt"); + const secondFileHash = Hash.of("test2"); closedLoc = await closedLoc.addCollectionItem({ itemId: secondItemId, itemDescription: secondItemDescription, @@ -530,7 +531,7 @@ export async function collectionLocWithUpload(state: State) { itemFile: new ItemFileWithContent({ name: "test2.txt", contentType: MimeType.from("text/plain"), - hashOrContent: new HashOrContent({ hash: secondFileHash, content: Buffer.from(secondFileContent) }), // Provide both hash and content to double-check + hashOrContent: new HashOrContent({ hash: secondFileHash, content: secondFile }), // Provide both hash and content to double-check size: 5n, // Provide size to double-check with content }) }); diff --git a/packages/client/integration/Main.spec.ts b/packages/client-node/integration/Main.spec.ts similarity index 100% rename from packages/client/integration/Main.spec.ts rename to packages/client-node/integration/Main.spec.ts diff --git a/packages/client/integration/Protection.ts b/packages/client-node/integration/Protection.ts similarity index 99% rename from packages/client/integration/Protection.ts rename to packages/client-node/integration/Protection.ts index d8cd93c8..03e3e640 100644 --- a/packages/client/integration/Protection.ts +++ b/packages/client-node/integration/Protection.ts @@ -13,7 +13,7 @@ import { FullSigner, LegalOfficer, ProtectionRequest -} from '../src/index.js'; +} from '@logion/client'; import { initRequesterBalance, REQUESTER_ADDRESS, State, TEST_LOGION_CLIENT_CONFIG } from "./Utils.js"; export async function enablesProtection(state: State) { diff --git a/packages/client/integration/Recovery.ts b/packages/client-node/integration/Recovery.ts similarity index 99% rename from packages/client/integration/Recovery.ts rename to packages/client-node/integration/Recovery.ts index 0ace3ef0..e02e7087 100644 --- a/packages/client/integration/Recovery.ts +++ b/packages/client-node/integration/Recovery.ts @@ -11,7 +11,7 @@ import { RejectedProtection, LogionClientConfig, ClaimedRecovery, -} from "../src/index.js"; +} from "@logion/client"; import { acceptRequest, rejectRequest } from "./Protection.js"; import { aliceAcceptsTransfer } from "./Vault.js"; import { initRequesterBalance, NEW_ADDRESS, REQUESTER_ADDRESS, State } from "./Utils.js"; diff --git a/packages/client/integration/TokensRecord.ts b/packages/client-node/integration/TokensRecord.ts similarity index 94% rename from packages/client/integration/TokensRecord.ts rename to packages/client-node/integration/TokensRecord.ts index af5503c0..a01d30f8 100644 --- a/packages/client/integration/TokensRecord.ts +++ b/packages/client-node/integration/TokensRecord.ts @@ -7,8 +7,9 @@ import { MimeType, PendingRequest, AcceptedRequest, OpenLoc -} from "../src/index.js"; +} from "@logion/client"; import { initRequesterBalance, State, TEST_LOGION_CLIENT_CONFIG, ISSUER_ADDRESS } from "./Utils.js"; +import { NodeFile } from "../src/index.js"; export async function tokensRecords(state: State) { const { client, alice, aliceAccount, newAccount, issuerAccount, signer } = state; @@ -47,7 +48,7 @@ export async function tokensRecords(state: State) { new ItemFileWithContent({ name: "report.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(new NodeFile("integration/test.txt")), }) ], signer: state.signer, diff --git a/packages/client/integration/Utils.ts b/packages/client-node/integration/Utils.ts similarity index 88% rename from packages/client/integration/Utils.ts rename to packages/client-node/integration/Utils.ts index 1702ffbc..62296b02 100644 --- a/packages/client/integration/Utils.ts +++ b/packages/client-node/integration/Utils.ts @@ -1,6 +1,5 @@ import { buildApiClass, Currency, Numbers, ValidAccountId } from "@logion/node-api"; import { Keyring } from "@polkadot/api"; -import FormData from "form-data"; import { FullSigner, @@ -11,13 +10,16 @@ import { ISubmittableResult, LogionClient, LegalOfficerClass, - LocRequestState -} from "../src/index.js"; -import { ALICE, BOB, CHARLIE } from "../test/Utils.js"; -import { requireDefined } from "../src/assertions.js"; + LocRequestState, + requireDefined, +} from "@logion/client"; +import { NodeAxiosFileUploader } from "../src/index.js"; +export const ALICE = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"; export const ALICE_SECRET_SEED = "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a"; +export const BOB = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"; export const BOB_SECRET_SEED = "0x398f0c28f98885e046333d4a41c19cee4c37368a9832c6502f6cfd182e2aef89"; +export const CHARLIE = "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y"; export const CHARLIE_SECRET_SEED = "0xbc1ede780f784bb6991a585e4f6e61522c14e1cae6ad0895fb57b9a205a8f938"; class IntegrationTestSignAndSendStrategy implements SignAndSendStrategy { @@ -37,7 +39,7 @@ export function buildSigner(seeds: string []): FullSigner { export const TEST_LOGION_CLIENT_CONFIG: LogionClientConfig = { directoryEndpoint: "http://localhost:8090", rpcEndpoints: [ 'ws://localhost:9944', 'ws://localhost:9945' ], - formDataLikeFactory: () => new FormData(), + buildFileUploader: () => new NodeAxiosFileUploader(), }; export const REQUESTER_ADDRESS = "5DPLBrBxniGbGdFe1Lmdpkt6K3aNjhoNPJrSJ51rwcmhH2Tn"; @@ -85,9 +87,9 @@ export async function setupInitialState(): Promise { const requesterAccount = anonymousClient.logionApi.queries.getValidAccountId(REQUESTER_ADDRESS, "Polkadot"); const directRequesterAccount = anonymousClient.logionApi.queries.getValidAccountId(DIRECT_REQUESTER_ADDRESS, "Polkadot"); const newAccount = anonymousClient.logionApi.queries.getValidAccountId(NEW_ADDRESS, "Polkadot"); - const aliceAccount = anonymousClient.logionApi.queries.getValidAccountId(ALICE.address, "Polkadot"); - const bobAccount = anonymousClient.logionApi.queries.getValidAccountId(BOB.address, "Polkadot"); - const charlieAccount = anonymousClient.logionApi.queries.getValidAccountId(CHARLIE.address, "Polkadot"); + const aliceAccount = anonymousClient.logionApi.queries.getValidAccountId(ALICE, "Polkadot"); + const bobAccount = anonymousClient.logionApi.queries.getValidAccountId(BOB, "Polkadot"); + const charlieAccount = anonymousClient.logionApi.queries.getValidAccountId(CHARLIE, "Polkadot"); const issuerAccount = anonymousClient.logionApi.queries.getValidAccountId(ISSUER_ADDRESS, "Polkadot"); const ethereumAccount = anonymousClient.logionApi.queries.getValidAccountId(ETHEREUM_ADDRESS, "Ethereum"); const client = await anonymousClient.authenticate([ @@ -101,9 +103,9 @@ export async function setupInitialState(): Promise { ethereumAccount, ], signer); const legalOfficers = client.legalOfficers; - const alice = requireDefined(legalOfficers.find(legalOfficer => legalOfficer.address === ALICE.address)); - const bob = requireDefined(legalOfficers.find(legalOfficer => legalOfficer.address === BOB.address)); - const charlie = requireDefined(legalOfficers.find(legalOfficer => legalOfficer.address === CHARLIE.address)); + const alice = requireDefined(legalOfficers.find(legalOfficer => legalOfficer.address === ALICE)); + const bob = requireDefined(legalOfficers.find(legalOfficer => legalOfficer.address === BOB)); + const charlie = requireDefined(legalOfficers.find(legalOfficer => legalOfficer.address === CHARLIE)); return { client, signer, @@ -122,7 +124,7 @@ export async function setupInitialState(): Promise { } export async function initRequesterBalance(config: LogionClientConfig, signer: Signer, requester: string): Promise { - await transferTokens(config, signer, ALICE.address, requester, Currency.toCanonicalAmount(new Numbers.PrefixedNumber("10000", Numbers.NONE))); + await transferTokens(config, signer, ALICE, requester, Currency.toCanonicalAmount(new Numbers.PrefixedNumber("10000", Numbers.NONE))); } async function transferTokens(config: LogionClientConfig, signer: Signer, source: string, destination: string, amount: bigint) { diff --git a/packages/client/integration/Vault.ts b/packages/client-node/integration/Vault.ts similarity index 98% rename from packages/client/integration/Vault.ts rename to packages/client-node/integration/Vault.ts index 452dfba6..b41dfbb5 100644 --- a/packages/client/integration/Vault.ts +++ b/packages/client-node/integration/Vault.ts @@ -1,6 +1,6 @@ import { buildApiClass, Currency } from "@logion/node-api"; +import { ActiveProtection, VaultTransferRequest, WithProtectionParameters } from "@logion/client"; -import { ActiveProtection, VaultTransferRequest, WithProtectionParameters } from "../src/index.js"; import { REQUESTER_ADDRESS, State } from "./Utils.js"; import { checkCoinBalance } from "./Balance.js"; diff --git a/packages/client/integration/VerifiedIssuer.ts b/packages/client-node/integration/VerifiedIssuer.ts similarity index 97% rename from packages/client/integration/VerifiedIssuer.ts rename to packages/client-node/integration/VerifiedIssuer.ts index 347423d0..703fd4cb 100644 --- a/packages/client/integration/VerifiedIssuer.ts +++ b/packages/client-node/integration/VerifiedIssuer.ts @@ -1,12 +1,12 @@ import { Hash } from "@logion/node-api"; import { ClosedLoc, - EditableRequest, HashOrContent, AcceptedRequest, PendingRequest, OpenLoc -} from "../src/index.js"; +} from "@logion/client"; import { State, ISSUER_ADDRESS, initRequesterBalance, TEST_LOGION_CLIENT_CONFIG } from "./Utils.js"; +import { NodeFile } from "../src/index.js"; export async function verifiedIssuer(state: State) { const { alice, aliceAccount, issuerAccount, newAccount, signer } = state; @@ -86,7 +86,7 @@ export async function verifiedIssuer(state: State) { }) as OpenLoc; openIssuerLoc = await openIssuerLoc.deleteMetadata({ nameHash: dataNameHash }) as OpenLoc; - const file = HashOrContent.fromContent(Buffer.from("test")); + const file = HashOrContent.fromContent(new NodeFile("integration/test.txt")); openIssuerLoc = await openIssuerLoc.addFile({ fileName: "test.txt", nature: "Some file nature", diff --git a/packages/client/integration/Void.ts b/packages/client-node/integration/Void.ts similarity index 92% rename from packages/client/integration/Void.ts rename to packages/client-node/integration/Void.ts index 97d3c1e4..f5f73f7b 100644 --- a/packages/client/integration/Void.ts +++ b/packages/client-node/integration/Void.ts @@ -1,4 +1,4 @@ -import { VoidedLoc } from "../src/index.js"; +import { VoidedLoc } from "@logion/client"; import { State } from "./Utils.js"; export async function voidTransactionLoc(state: State) { diff --git a/packages/client/integration/Vote.ts b/packages/client-node/integration/Vote.ts similarity index 95% rename from packages/client/integration/Vote.ts rename to packages/client-node/integration/Vote.ts index 45bf70a5..5a5041f6 100644 --- a/packages/client/integration/Vote.ts +++ b/packages/client-node/integration/Vote.ts @@ -1,4 +1,4 @@ -import { ClosedLoc, PendingVote, Votes, waitFor } from "../src/index.js"; +import { ClosedLoc, PendingVote, Votes, waitFor } from "@logion/client"; import { State } from "./Utils.js"; export async function votingProcess(state: State) { diff --git a/packages/client-node/integration/collection-1.txt b/packages/client-node/integration/collection-1.txt new file mode 100644 index 00000000..bf2a91df --- /dev/null +++ b/packages/client-node/integration/collection-1.txt @@ -0,0 +1 @@ +collection1 \ No newline at end of file diff --git a/packages/client-node/integration/collection-2.txt b/packages/client-node/integration/collection-2.txt new file mode 100644 index 00000000..e1c8a4ab --- /dev/null +++ b/packages/client-node/integration/collection-2.txt @@ -0,0 +1 @@ +collection2 \ No newline at end of file diff --git a/packages/client-node/integration/identity-1.txt b/packages/client-node/integration/identity-1.txt new file mode 100644 index 00000000..1f99b947 --- /dev/null +++ b/packages/client-node/integration/identity-1.txt @@ -0,0 +1 @@ +identity1 \ No newline at end of file diff --git a/packages/client-node/integration/identity-2.txt b/packages/client-node/integration/identity-2.txt new file mode 100644 index 00000000..f47b2dbc --- /dev/null +++ b/packages/client-node/integration/identity-2.txt @@ -0,0 +1 @@ +identity2 \ No newline at end of file diff --git a/packages/client/integration/test.txt b/packages/client-node/integration/test.txt similarity index 100% rename from packages/client/integration/test.txt rename to packages/client-node/integration/test.txt diff --git a/packages/client-node/integration/test0.txt b/packages/client-node/integration/test0.txt new file mode 100644 index 00000000..a39c44cc --- /dev/null +++ b/packages/client-node/integration/test0.txt @@ -0,0 +1 @@ +test0 \ No newline at end of file diff --git a/packages/client-node/integration/test123.txt b/packages/client-node/integration/test123.txt new file mode 100644 index 00000000..0c759a44 --- /dev/null +++ b/packages/client-node/integration/test123.txt @@ -0,0 +1 @@ +test123 \ No newline at end of file diff --git a/packages/client-node/integration/test2.txt b/packages/client-node/integration/test2.txt new file mode 100644 index 00000000..d606037c --- /dev/null +++ b/packages/client-node/integration/test2.txt @@ -0,0 +1 @@ +test2 \ No newline at end of file diff --git a/packages/client-node/integration/transaction-1.txt b/packages/client-node/integration/transaction-1.txt new file mode 100644 index 00000000..5d75f00b --- /dev/null +++ b/packages/client-node/integration/transaction-1.txt @@ -0,0 +1 @@ +transaction1 \ No newline at end of file diff --git a/packages/client-node/integration/transaction-2.txt b/packages/client-node/integration/transaction-2.txt new file mode 100644 index 00000000..ba79bbc7 --- /dev/null +++ b/packages/client-node/integration/transaction-2.txt @@ -0,0 +1 @@ +transaction2 \ No newline at end of file diff --git a/packages/client/jasmine-integration.json b/packages/client-node/jasmine-integration.json similarity index 100% rename from packages/client/jasmine-integration.json rename to packages/client-node/jasmine-integration.json diff --git a/packages/client-node/jasmine.json b/packages/client-node/jasmine.json new file mode 100644 index 00000000..ff7eff1f --- /dev/null +++ b/packages/client-node/jasmine.json @@ -0,0 +1,15 @@ +{ + "spec_dir": "test", + "spec_files": [ + "**/*.spec.ts" + ], + "helpers": [ + "../typescript.js" + ], + "stopSpecOnExpectationFailure": false, + "reporters": [ + { + "name": "jasmine-spec-reporter#SpecReporter" + } + ] +} \ No newline at end of file diff --git a/packages/client-node/package.json b/packages/client-node/package.json new file mode 100644 index 00000000..9fbd30ea --- /dev/null +++ b/packages/client-node/package.json @@ -0,0 +1,53 @@ +{ + "name": "@logion/client-node", + "version": "0.1.0-1", + "description": "logion SDK for Node.JS client applications", + "main": "dist/index.js", + "packageManager": "yarn@3.2.0", + "type": "module", + "scripts": { + "build": "yarn lint && tsc -p tsconfig.json", + "integration-test": "docker-compose up -d && ./scripts/integration_test_db_setup.sh && node ./scripts/init_onchain_data.js && NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine-integration.json ; docker-compose down", + "lint": "yarn eslint src/**", + "test": "NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine.json", + "clean": "rm -rf dist" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/logion-network/logion-api.git", + "directory": "packages/client-browser" + }, + "keywords": [ + "logion", + "api", + "client", + "browser" + ], + "author": "Logion Team", + "license": "Apache-2.0", + "dependencies": { + "@logion/client": "workspace:^", + "form-data": "^4.0.0" + }, + "bugs": { + "url": "https://github.com/logion-network/logion-api/issues" + }, + "homepage": "https://github.com/logion-network/logion-api/packages/client-node#readme", + "devDependencies": { + "@tsconfig/node18": "^1.0.1", + "@types/jasmine": "^4.0.3", + "@types/node": "^18.6.1", + "@typescript-eslint/eslint-plugin": "^6.9.1", + "@typescript-eslint/parser": "^6.9.1", + "eslint": "^8.20.0", + "jasmine": "^4.3.0", + "jasmine-spec-reporter": "^7.0.0", + "moq.ts": "^9.0.2", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + }, + "engines": { + "node": ">=18" + }, + "stableVersion": "0.1.0" +} diff --git a/packages/client/scripts/directory_data.sql b/packages/client-node/scripts/directory_data.sql similarity index 100% rename from packages/client/scripts/directory_data.sql rename to packages/client-node/scripts/directory_data.sql diff --git a/packages/client/scripts/init_onchain_data.js b/packages/client-node/scripts/init_onchain_data.js similarity index 100% rename from packages/client/scripts/init_onchain_data.js rename to packages/client-node/scripts/init_onchain_data.js diff --git a/packages/client/scripts/integration_test_db_setup.sh b/packages/client-node/scripts/integration_test_db_setup.sh similarity index 100% rename from packages/client/scripts/integration_test_db_setup.sh rename to packages/client-node/scripts/integration_test_db_setup.sh diff --git a/packages/client-node/src/index.ts b/packages/client-node/src/index.ts new file mode 100644 index 00000000..a776b2c1 --- /dev/null +++ b/packages/client-node/src/index.ts @@ -0,0 +1,57 @@ +import { File, HashAndSize, AxiosFileUploader, FormDataLike } from "@logion/client"; +import { Hash } from "@logion/node-api"; +import { Hash as Hasher } from 'fast-sha256'; +import FormData from "form-data"; +import fs from "fs"; + +export class NodeFile extends File { + + constructor(path: string) { + super(); + this.path = path; + } + + private path: string; + + async getHashAndSize(): Promise { + const stream = this.getStream(); + return new Promise((resolve, reject) => { + const digest = new Hasher(); + let size = 0n; + stream.on("data", data => { + size = size + BigInt(data.length); + digest.update(data); + }); + stream.on("end", () => resolve({ + hash: Hash.fromDigest(digest), + size + })); + stream.on("error", reject); + }); + } + + getStream(): NodeJS.ReadableStream { + return fs.createReadStream(this.path); + } +} + +export function hashBuffer(buffer: Buffer): Hash { + const digest = new Hasher(); + digest.update(buffer); + return Hash.fromDigest(digest); +} + +export class NodeAxiosFileUploader extends AxiosFileUploader { + + override buildFormData(): FormDataLike { + return new FormData(); + } + + override toFormDataValue(file: File): Promise { // eslint-disable-line @typescript-eslint/no-explicit-any + if(file instanceof NodeFile) { + return Promise.resolve(file.getStream()); + } else { + return Promise.reject(new Error("Unsupported file type")); + } + } +} diff --git a/packages/client/test/file.txt b/packages/client-node/test/file.txt similarity index 100% rename from packages/client/test/file.txt rename to packages/client-node/test/file.txt diff --git a/packages/client-node/test/index.spec.ts b/packages/client-node/test/index.spec.ts new file mode 100644 index 00000000..ac94b77b --- /dev/null +++ b/packages/client-node/test/index.spec.ts @@ -0,0 +1,14 @@ +import { Hash } from "@logion/node-api"; +import { NodeFile } from "../src/index.js"; + +const TEST_HASH = Hash.fromHex("0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); + +describe("NodeFile", () => { + + it("gets hash and size", async () => { + const file = new NodeFile("test/file.txt"); + const hashSize = await file.getHashAndSize(); + expect(hashSize.hash).toEqual(TEST_HASH); + expect(hashSize.size).toBe(4n); + }); +}); diff --git a/packages/client-node/tsconfig.app.json b/packages/client-node/tsconfig.app.json new file mode 100644 index 00000000..8a9680e0 --- /dev/null +++ b/packages/client-node/tsconfig.app.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": [ + "./src/**/*" + ] +} diff --git a/packages/client-node/tsconfig.json b/packages/client-node/tsconfig.json new file mode 100644 index 00000000..b26a17bd --- /dev/null +++ b/packages/client-node/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "lib": ["dom"], + "baseUrl": "." + }, + "include": [ + "./src/**/*" + ] +} diff --git a/packages/client/tsconfig.test.json b/packages/client-node/tsconfig.test.json similarity index 100% rename from packages/client/tsconfig.test.json rename to packages/client-node/tsconfig.test.json diff --git a/packages/client-node/typedoc.json b/packages/client-node/typedoc.json new file mode 100644 index 00000000..19ab30f9 --- /dev/null +++ b/packages/client-node/typedoc.json @@ -0,0 +1,6 @@ +{ + "name": "Client (Node.JS)", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/client/typescript.js b/packages/client-node/typescript.js similarity index 100% rename from packages/client/typescript.js rename to packages/client-node/typescript.js diff --git a/packages/client/.npmignore b/packages/client/.npmignore index f45e1724..14ef9b3b 100644 --- a/packages/client/.npmignore +++ b/packages/client/.npmignore @@ -1,10 +1,6 @@ /test/** -/integration/** /src/** -/scripts/** -docker-compose.yml -front_config.js -front_web*.conf jasmine*.json tsconfig*.json -/config/** \ No newline at end of file +typedoc.json +.eslintrc.json diff --git a/packages/client/config/ipfs-cluster1/identity.json b/packages/client/config/ipfs-cluster1/identity.json deleted file mode 100644 index 21b2a759..00000000 --- a/packages/client/config/ipfs-cluster1/identity.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "id": "12D3KooWHpQ7R7EHsm5KrnPfbEvYAp9C4AD9J42EosATYtEbGzMw", - "private_key": "CAESQESsX1Ey1mlZ64rayr54hxUPELHwEZKKMaMZt2gGpi2Rdt+xIu6KTbbikVMiT85ctUX4A2UnWkpIDticV8RRH5o=" -} \ No newline at end of file diff --git a/packages/client/config/ipfs-cluster1/service.json b/packages/client/config/ipfs-cluster1/service.json deleted file mode 100644 index 9c14feb2..00000000 --- a/packages/client/config/ipfs-cluster1/service.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "cluster": { - "peername": "node1", - "secret": "2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b", - "leave_on_shutdown": false, - "listen_multiaddress": [ - "/ip4/0.0.0.0/tcp/9096", - "/ip4/0.0.0.0/udp/9096/quic" - ], - "enable_relay_hop": true, - "connection_manager": { - "high_water": 400, - "low_water": 100, - "grace_period": "2m0s" - }, - "dial_peer_timeout": "3s", - "state_sync_interval": "5m0s", - "pin_recover_interval": "12m0s", - "replication_factor_min": -1, - "replication_factor_max": -1, - "monitor_ping_interval": "2s", - "peer_watch_interval": "5s", - "mdns_interval": "0", - "disable_repinning": false, - "peer_addresses": [] - }, - "consensus": { - "crdt": { - "cluster_name": "ipfs-cluster", - "trusted_peers": [ - "*" - ], - "batching": { - "max_batch_size": 0, - "max_batch_age": "0s" - }, - "repair_interval": "1h0m0s" - } - }, - "api": { - "ipfsproxy": { - "listen_multiaddress": "/ip4/127.0.0.1/tcp/9095", - "node_multiaddress": "/ip4/127.0.0.1/tcp/5001", - "log_file": "", - "read_timeout": "0s", - "read_header_timeout": "5s", - "write_timeout": "0s", - "idle_timeout": "1m0s", - "max_header_bytes": 4096 - }, - "restapi": { - "http_listen_multiaddress": "/ip4/0.0.0.0/tcp/9094", - "read_timeout": "0s", - "read_header_timeout": "5s", - "write_timeout": "0s", - "idle_timeout": "2m0s", - "max_header_bytes": 4096, - "basic_auth_credentials": null, - "http_log_file": "", - "headers": {}, - "cors_allowed_origins": [ - "*" - ], - "cors_allowed_methods": [ - "GET" - ], - "cors_allowed_headers": [], - "cors_exposed_headers": [ - "Content-Type", - "X-Stream-Output", - "X-Chunked-Output", - "X-Content-Length" - ], - "cors_allow_credentials": true, - "cors_max_age": "0s" - } - }, - "ipfs_connector": { - "ipfshttp": { - "node_multiaddress": "/dns4/client_ipfs1_1/tcp/5001", - "connect_swarms_delay": "30s", - "ipfs_request_timeout": "5m0s", - "pin_timeout": "2m0s", - "unpin_timeout": "3h0m0s", - "repogc_timeout": "24h0m0s", - "informer_trigger_interval": 0 - } - }, - "pin_tracker": { - "stateless": { - "concurrent_pins": 10, - "priority_pin_max_age": "24h0m0s", - "priority_pin_max_retries": 5 - } - }, - "monitor": { - "pubsubmon": { - "check_interval": "15s" - } - }, - "allocator": { - "balanced": { - "allocate_by": [ - "tag:group", - "freespace" - ] - } - }, - "informer": { - "disk": { - "metric_ttl": "30s", - "metric_type": "freespace" - }, - "tags": { - "metric_ttl": "30s", - "tags": { - "group": "default" - } - } - }, - "observations": { - "metrics": { - "enable_stats": false, - "prometheus_endpoint": "/ip4/127.0.0.1/tcp/8888", - "reporting_interval": "2s" - }, - "tracing": { - "enable_tracing": false, - "jaeger_agent_endpoint": "/ip4/0.0.0.0/udp/6831", - "sampling_prob": 0.3, - "service_name": "cluster-daemon" - } - }, - "datastore": { - "leveldb": { - "leveldb_options": { - "block_cache_capacity": 0, - "block_cache_evict_removed": false, - "block_restart_interval": 0, - "block_size": 0, - "compaction_expand_limit_factor": 0, - "compaction_gp_overlaps_factor": 0, - "compaction_l0_trigger": 0, - "compaction_source_limit_factor": 0, - "compaction_table_size": 0, - "compaction_table_size_multiplier": 0, - "compaction_table_size_multiplier_per_level": null, - "compaction_total_size": 0, - "compaction_total_size_multiplier": 0, - "compaction_total_size_multiplier_per_level": null, - "compression": 0, - "disable_buffer_pool": false, - "disable_block_cache": false, - "disable_compaction_backoff": false, - "disable_large_batch_transaction": false, - "iterator_sampling_rate": 0, - "no_sync": false, - "no_write_merge": false, - "open_files_cache_capacity": 0, - "read_only": false, - "strict": 0, - "write_buffer": 0, - "write_l0_pause_trigger": 0, - "write_l0_slowdown_trigger": 0 - } - } - } - } \ No newline at end of file diff --git a/packages/client/config/ipfs-cluster2/identity.json b/packages/client/config/ipfs-cluster2/identity.json deleted file mode 100644 index 85e2023a..00000000 --- a/packages/client/config/ipfs-cluster2/identity.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "id": "12D3KooWGy66BfypN8Q1nGKvH92eAjYcx7ryvyhJoLHF8gHA7AGw", - "private_key": "CAESQHTuyPm35QRrSYxkQ5spp5SBn5FkYEaYhv2e2KiOp0wxaj3bCdfdEL0CdAQ1VmXuZQTIb1/O60hBVg7Fy54MnaA=" -} \ No newline at end of file diff --git a/packages/client/config/ipfs-cluster2/service.json b/packages/client/config/ipfs-cluster2/service.json deleted file mode 100644 index 0bc4e3d4..00000000 --- a/packages/client/config/ipfs-cluster2/service.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "cluster": { - "peername": "node2", - "secret": "2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b", - "leave_on_shutdown": false, - "listen_multiaddress": [ - "/ip4/0.0.0.0/tcp/9096", - "/ip4/0.0.0.0/udp/9096/quic" - ], - "enable_relay_hop": true, - "connection_manager": { - "high_water": 400, - "low_water": 100, - "grace_period": "2m0s" - }, - "dial_peer_timeout": "3s", - "state_sync_interval": "5m0s", - "pin_recover_interval": "12m0s", - "replication_factor_min": -1, - "replication_factor_max": -1, - "monitor_ping_interval": "2s", - "peer_watch_interval": "5s", - "mdns_interval": "0", - "disable_repinning": false, - "peer_addresses": ["/dns4/client_ipfs-cluster1_1/tcp/9096/p2p/12D3KooWHpQ7R7EHsm5KrnPfbEvYAp9C4AD9J42EosATYtEbGzMw"] - }, - "consensus": { - "crdt": { - "cluster_name": "ipfs-cluster", - "trusted_peers": [ - "*" - ], - "batching": { - "max_batch_size": 0, - "max_batch_age": "0s" - }, - "repair_interval": "1h0m0s" - } - }, - "api": { - "ipfsproxy": { - "listen_multiaddress": "/ip4/127.0.0.1/tcp/9095", - "node_multiaddress": "/ip4/127.0.0.1/tcp/5001", - "log_file": "", - "read_timeout": "0s", - "read_header_timeout": "5s", - "write_timeout": "0s", - "idle_timeout": "1m0s", - "max_header_bytes": 4096 - }, - "restapi": { - "http_listen_multiaddress": "/ip4/0.0.0.0/tcp/9094", - "read_timeout": "0s", - "read_header_timeout": "5s", - "write_timeout": "0s", - "idle_timeout": "2m0s", - "max_header_bytes": 4096, - "basic_auth_credentials": null, - "http_log_file": "", - "headers": {}, - "cors_allowed_origins": [ - "*" - ], - "cors_allowed_methods": [ - "GET" - ], - "cors_allowed_headers": [], - "cors_exposed_headers": [ - "Content-Type", - "X-Stream-Output", - "X-Chunked-Output", - "X-Content-Length" - ], - "cors_allow_credentials": true, - "cors_max_age": "0s" - } - }, - "ipfs_connector": { - "ipfshttp": { - "node_multiaddress": "/dns4/client_ipfs2_1/tcp/5001", - "connect_swarms_delay": "30s", - "ipfs_request_timeout": "5m0s", - "pin_timeout": "2m0s", - "unpin_timeout": "3h0m0s", - "repogc_timeout": "24h0m0s", - "informer_trigger_interval": 0 - } - }, - "pin_tracker": { - "stateless": { - "concurrent_pins": 10, - "priority_pin_max_age": "24h0m0s", - "priority_pin_max_retries": 5 - } - }, - "monitor": { - "pubsubmon": { - "check_interval": "15s" - } - }, - "allocator": { - "balanced": { - "allocate_by": [ - "tag:group", - "freespace" - ] - } - }, - "informer": { - "disk": { - "metric_ttl": "30s", - "metric_type": "freespace" - }, - "tags": { - "metric_ttl": "30s", - "tags": { - "group": "default" - } - } - }, - "observations": { - "metrics": { - "enable_stats": false, - "prometheus_endpoint": "/ip4/127.0.0.1/tcp/8888", - "reporting_interval": "2s" - }, - "tracing": { - "enable_tracing": false, - "jaeger_agent_endpoint": "/ip4/0.0.0.0/udp/6831", - "sampling_prob": 0.3, - "service_name": "cluster-daemon" - } - }, - "datastore": { - "leveldb": { - "leveldb_options": { - "block_cache_capacity": 0, - "block_cache_evict_removed": false, - "block_restart_interval": 0, - "block_size": 0, - "compaction_expand_limit_factor": 0, - "compaction_gp_overlaps_factor": 0, - "compaction_l0_trigger": 0, - "compaction_source_limit_factor": 0, - "compaction_table_size": 0, - "compaction_table_size_multiplier": 0, - "compaction_table_size_multiplier_per_level": null, - "compaction_total_size": 0, - "compaction_total_size_multiplier": 0, - "compaction_total_size_multiplier_per_level": null, - "compression": 0, - "disable_buffer_pool": false, - "disable_block_cache": false, - "disable_compaction_backoff": false, - "disable_large_batch_transaction": false, - "iterator_sampling_rate": 0, - "no_sync": false, - "no_write_merge": false, - "open_files_cache_capacity": 0, - "read_only": false, - "strict": 0, - "write_buffer": 0, - "write_l0_pause_trigger": 0, - "write_l0_slowdown_trigger": 0 - } - } - } - } \ No newline at end of file diff --git a/packages/client/config/ipfs-cluster3/identity.json b/packages/client/config/ipfs-cluster3/identity.json deleted file mode 100644 index 2377db52..00000000 --- a/packages/client/config/ipfs-cluster3/identity.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "id": "12D3KooWEtFzvJiyfTCA6KNbM9gRrZ2vw5AheWbd36YmiVUr3Fpq", - "private_key": "CAESQHp9Oz0VWrs3Y/h/3vj45IXJWK67Y2itt/xL25ZOQy6dS0nIONpDDjWgwfMnqEs6qbR/fkbQ1Kpn6xX9FgKeMo4=" -} \ No newline at end of file diff --git a/packages/client/config/ipfs-cluster3/service.json b/packages/client/config/ipfs-cluster3/service.json deleted file mode 100644 index 297790d6..00000000 --- a/packages/client/config/ipfs-cluster3/service.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "cluster": { - "peername": "node03", - "secret": "9100179336d42cbed9c24ab8498028b64898879e6a5fb7876022090a134f6b8f", - "leave_on_shutdown": false, - "listen_multiaddress": [ - "/ip4/0.0.0.0/tcp/9096", - "/ip4/0.0.0.0/udp/9096/quic" - ], - "enable_relay_hop": true, - "connection_manager": { - "high_water": 400, - "low_water": 100, - "grace_period": "2m0s" - }, - "dial_peer_timeout": "3s", - "state_sync_interval": "5m0s", - "pin_recover_interval": "12m0s", - "replication_factor_min": -1, - "replication_factor_max": -1, - "monitor_ping_interval": "2s", - "peer_watch_interval": "5s", - "mdns_interval": "0", - "disable_repinning": false, - "peer_addresses": [ - "/dns4/client_ipfs-cluster1_1/tcp/9096/p2p/12D3KooWHpQ7R7EHsm5KrnPfbEvYAp9C4AD9J42EosATYtEbGzMw", - "/dns4/client_ipfs-cluster2_1/tcp/9096/p2p/12D3KooWGy66BfypN8Q1nGKvH92eAjYcx7ryvyhJoLHF8gHA7AGw"] - }, - "consensus": { - "crdt": { - "cluster_name": "ipfs-cluster", - "trusted_peers": [ - "*" - ], - "batching": { - "max_batch_size": 0, - "max_batch_age": "0s" - }, - "repair_interval": "1h0m0s" - } - }, - "api": { - "ipfsproxy": { - "listen_multiaddress": "/ip4/127.0.0.1/tcp/9095", - "node_multiaddress": "/ip4/127.0.0.1/tcp/5001", - "log_file": "", - "read_timeout": "0s", - "read_header_timeout": "5s", - "write_timeout": "0s", - "idle_timeout": "1m0s", - "max_header_bytes": 4096 - }, - "restapi": { - "http_listen_multiaddress": "/ip4/0.0.0.0/tcp/9094", - "read_timeout": "0s", - "read_header_timeout": "5s", - "write_timeout": "0s", - "idle_timeout": "2m0s", - "max_header_bytes": 4096, - "basic_auth_credentials": null, - "http_log_file": "", - "headers": {}, - "cors_allowed_origins": [ - "*" - ], - "cors_allowed_methods": [ - "GET" - ], - "cors_allowed_headers": [], - "cors_exposed_headers": [ - "Content-Type", - "X-Stream-Output", - "X-Chunked-Output", - "X-Content-Length" - ], - "cors_allow_credentials": true, - "cors_max_age": "0s" - } - }, - "ipfs_connector": { - "ipfshttp": { - "node_multiaddress": "/dns4/client_ipfs3_1/tcp/5001", - "connect_swarms_delay": "30s", - "ipfs_request_timeout": "5m0s", - "pin_timeout": "2m0s", - "unpin_timeout": "3h0m0s", - "repogc_timeout": "24h0m0s", - "informer_trigger_interval": 0 - } - }, - "pin_tracker": { - "stateless": { - "concurrent_pins": 10, - "priority_pin_max_age": "24h0m0s", - "priority_pin_max_retries": 5 - } - }, - "monitor": { - "pubsubmon": { - "check_interval": "15s" - } - }, - "allocator": { - "balanced": { - "allocate_by": [ - "tag:group", - "freespace" - ] - } - }, - "informer": { - "disk": { - "metric_ttl": "30s", - "metric_type": "freespace" - }, - "tags": { - "metric_ttl": "30s", - "tags": { - "group": "default" - } - } - }, - "observations": { - "metrics": { - "enable_stats": false, - "prometheus_endpoint": "/ip4/127.0.0.1/tcp/8888", - "reporting_interval": "2s" - }, - "tracing": { - "enable_tracing": false, - "jaeger_agent_endpoint": "/ip4/0.0.0.0/udp/6831", - "sampling_prob": 0.3, - "service_name": "cluster-daemon" - } - }, - "datastore": { - "leveldb": { - "leveldb_options": { - "block_cache_capacity": 0, - "block_cache_evict_removed": false, - "block_restart_interval": 0, - "block_size": 0, - "compaction_expand_limit_factor": 0, - "compaction_gp_overlaps_factor": 0, - "compaction_l0_trigger": 0, - "compaction_source_limit_factor": 0, - "compaction_table_size": 0, - "compaction_table_size_multiplier": 0, - "compaction_table_size_multiplier_per_level": null, - "compaction_total_size": 0, - "compaction_total_size_multiplier": 0, - "compaction_total_size_multiplier_per_level": null, - "compression": 0, - "disable_buffer_pool": false, - "disable_block_cache": false, - "disable_compaction_backoff": false, - "disable_large_batch_transaction": false, - "iterator_sampling_rate": 0, - "no_sync": false, - "no_write_merge": false, - "open_files_cache_capacity": 0, - "read_only": false, - "strict": 0, - "write_buffer": 0, - "write_l0_pause_trigger": 0, - "write_l0_slowdown_trigger": 0 - } - } - } -} diff --git a/packages/client/config/ipfs1/config b/packages/client/config/ipfs1/config deleted file mode 100644 index d4e772d0..00000000 --- a/packages/client/config/ipfs1/config +++ /dev/null @@ -1,153 +0,0 @@ -{ - "API": { - "HTTPHeaders": {} - }, - "Addresses": { - "API": "/ip4/0.0.0.0/tcp/5001", - "Announce": [], - "AppendAnnounce": [], - "Gateway": "/ip4/0.0.0.0/tcp/8080", - "NoAnnounce": [], - "Swarm": [ - "/ip4/0.0.0.0/tcp/4001", - "/ip6/::/tcp/4001", - "/ip4/0.0.0.0/udp/4001/quic", - "/ip6/::/udp/4001/quic" - ] - }, - "AutoNAT": {}, - "Bootstrap": [], - "DNS": { - "Resolvers": {} - }, - "Datastore": { - "BloomFilterSize": 0, - "GCPeriod": "1h", - "HashOnRead": false, - "Spec": { - "mounts": [ - { - "child": { - "path": "blocks", - "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", - "sync": true, - "type": "flatfs" - }, - "mountpoint": "/blocks", - "prefix": "flatfs.datastore", - "type": "measure" - }, - { - "child": { - "compression": "none", - "path": "datastore", - "type": "levelds" - }, - "mountpoint": "/", - "prefix": "leveldb.datastore", - "type": "measure" - } - ], - "type": "mount" - }, - "StorageGCWatermark": 90, - "StorageMax": "10GB" - }, - "Discovery": { - "MDNS": { - "Enabled": true, - "Interval": 10 - } - }, - "Experimental": { - "AcceleratedDHTClient": false, - "FilestoreEnabled": false, - "GraphsyncEnabled": false, - "Libp2pStreamMounting": false, - "P2pHttpProxy": false, - "StrategicProviding": false, - "UrlstoreEnabled": false - }, - "Gateway": { - "APICommands": [], - "HTTPHeaders": { - "Access-Control-Allow-Headers": [ - "X-Requested-With", - "Range", - "User-Agent" - ], - "Access-Control-Allow-Methods": [ - "GET" - ], - "Access-Control-Allow-Origin": [ - "*" - ] - }, - "NoDNSLink": false, - "NoFetch": false, - "PathPrefixes": [], - "PublicGateways": null, - "RootRedirect": "", - "Writable": false - }, - "Identity": { - "PeerID": "12D3KooWE6cKjo2QTQqFNJFG7ymfndXrY3vZa7kaMgGHPDKmdP9F", - "PrivKey": "CAESQDXX+s+EOczrInLDWnapNt0Gi7Y8quRYrzELjkgN3ePKP5gLvEjqSyfgRKw0k6PejNb0rl8Tpy5IqvxMsoNriJY=" - }, - "Internal": {}, - "Ipns": { - "RecordLifetime": "", - "RepublishPeriod": "", - "ResolveCacheSize": 128 - }, - "Migration": { - "DownloadSources": [], - "Keep": "" - }, - "Mounts": { - "FuseAllowOther": false, - "IPFS": "/ipfs", - "IPNS": "/ipns" - }, - "Peering": { - "Peers": null - }, - "Pinning": { - "RemoteServices": {} - }, - "Plugins": { - "Plugins": null - }, - "Provider": { - "Strategy": "" - }, - "Pubsub": { - "DisableSigning": false, - "Router": "" - }, - "Reprovider": { - "Interval": "12h", - "Strategy": "all" - }, - "Routing": { - "Type": "dht" - }, - "Swarm": { - "AddrFilters": null, - "ConnMgr": { - "GracePeriod": "20s", - "HighWater": 900, - "LowWater": 600, - "Type": "basic" - }, - "DisableBandwidthMetrics": false, - "DisableNatPortMap": false, - "RelayClient": {}, - "RelayService": {}, - "Transports": { - "Multiplexers": {}, - "Network": {}, - "Security": {} - } - } -} \ No newline at end of file diff --git a/packages/client/config/ipfs1/datastore_spec b/packages/client/config/ipfs1/datastore_spec deleted file mode 100644 index 7bf9626c..00000000 --- a/packages/client/config/ipfs1/datastore_spec +++ /dev/null @@ -1 +0,0 @@ -{"mounts":[{"mountpoint":"/blocks","path":"blocks","shardFunc":"/repo/flatfs/shard/v1/next-to-last/2","type":"flatfs"},{"mountpoint":"/","path":"datastore","type":"levelds"}],"type":"mount"} \ No newline at end of file diff --git a/packages/client/config/ipfs1/swarm.key b/packages/client/config/ipfs1/swarm.key deleted file mode 100644 index 2e3e6891..00000000 --- a/packages/client/config/ipfs1/swarm.key +++ /dev/null @@ -1,3 +0,0 @@ -/key/swarm/psk/1.0.0/ -/base16/ -ed4e9d8858ee6cd48cd9f0796eab2bc38bba102b288f263d4ed8bca7a184b4be diff --git a/packages/client/config/ipfs1/version b/packages/client/config/ipfs1/version deleted file mode 100644 index 3cacc0b9..00000000 --- a/packages/client/config/ipfs1/version +++ /dev/null @@ -1 +0,0 @@ -12 \ No newline at end of file diff --git a/packages/client/config/ipfs2/config b/packages/client/config/ipfs2/config deleted file mode 100644 index 02c87e96..00000000 --- a/packages/client/config/ipfs2/config +++ /dev/null @@ -1,153 +0,0 @@ -{ - "API": { - "HTTPHeaders": {} - }, - "Addresses": { - "API": "/ip4/0.0.0.0/tcp/5001", - "Announce": [], - "AppendAnnounce": [], - "Gateway": "/ip4/0.0.0.0/tcp/8080", - "NoAnnounce": [], - "Swarm": [ - "/ip4/0.0.0.0/tcp/4001", - "/ip6/::/tcp/4001", - "/ip4/0.0.0.0/udp/4001/quic", - "/ip6/::/udp/4001/quic" - ] - }, - "AutoNAT": {}, - "Bootstrap": ["/dns4/logion-test_ipfs1_1/tcp/4001/p2p/12D3KooWE6cKjo2QTQqFNJFG7ymfndXrY3vZa7kaMgGHPDKmdP9F"], - "DNS": { - "Resolvers": {} - }, - "Datastore": { - "BloomFilterSize": 0, - "GCPeriod": "1h", - "HashOnRead": false, - "Spec": { - "mounts": [ - { - "child": { - "path": "blocks", - "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", - "sync": true, - "type": "flatfs" - }, - "mountpoint": "/blocks", - "prefix": "flatfs.datastore", - "type": "measure" - }, - { - "child": { - "compression": "none", - "path": "datastore", - "type": "levelds" - }, - "mountpoint": "/", - "prefix": "leveldb.datastore", - "type": "measure" - } - ], - "type": "mount" - }, - "StorageGCWatermark": 90, - "StorageMax": "10GB" - }, - "Discovery": { - "MDNS": { - "Enabled": true, - "Interval": 10 - } - }, - "Experimental": { - "AcceleratedDHTClient": false, - "FilestoreEnabled": false, - "GraphsyncEnabled": false, - "Libp2pStreamMounting": false, - "P2pHttpProxy": false, - "StrategicProviding": false, - "UrlstoreEnabled": false - }, - "Gateway": { - "APICommands": [], - "HTTPHeaders": { - "Access-Control-Allow-Headers": [ - "X-Requested-With", - "Range", - "User-Agent" - ], - "Access-Control-Allow-Methods": [ - "GET" - ], - "Access-Control-Allow-Origin": [ - "*" - ] - }, - "NoDNSLink": false, - "NoFetch": false, - "PathPrefixes": [], - "PublicGateways": null, - "RootRedirect": "", - "Writable": false - }, - "Identity": { - "PeerID": "12D3KooWJL1BQbW7zyQaLWwTA7mVGcWGzNqy1byMmoKCyULuQPqR", - "PrivKey": "CAESQL6BGUBwCtCh3AgJdIaKnJNdeOEIMKpj7XG777kDJTJRfnUwFgNirGrAyqGjAnBEQ59KsMoyBWDmeSOTX62Fs4g=" - }, - "Internal": {}, - "Ipns": { - "RecordLifetime": "", - "RepublishPeriod": "", - "ResolveCacheSize": 128 - }, - "Migration": { - "DownloadSources": [], - "Keep": "" - }, - "Mounts": { - "FuseAllowOther": false, - "IPFS": "/ipfs", - "IPNS": "/ipns" - }, - "Peering": { - "Peers": null - }, - "Pinning": { - "RemoteServices": {} - }, - "Plugins": { - "Plugins": null - }, - "Provider": { - "Strategy": "" - }, - "Pubsub": { - "DisableSigning": false, - "Router": "" - }, - "Reprovider": { - "Interval": "12h", - "Strategy": "all" - }, - "Routing": { - "Type": "dht" - }, - "Swarm": { - "AddrFilters": null, - "ConnMgr": { - "GracePeriod": "20s", - "HighWater": 900, - "LowWater": 600, - "Type": "basic" - }, - "DisableBandwidthMetrics": false, - "DisableNatPortMap": false, - "RelayClient": {}, - "RelayService": {}, - "Transports": { - "Multiplexers": {}, - "Network": {}, - "Security": {} - } - } -} \ No newline at end of file diff --git a/packages/client/config/ipfs2/datastore_spec b/packages/client/config/ipfs2/datastore_spec deleted file mode 100644 index 7bf9626c..00000000 --- a/packages/client/config/ipfs2/datastore_spec +++ /dev/null @@ -1 +0,0 @@ -{"mounts":[{"mountpoint":"/blocks","path":"blocks","shardFunc":"/repo/flatfs/shard/v1/next-to-last/2","type":"flatfs"},{"mountpoint":"/","path":"datastore","type":"levelds"}],"type":"mount"} \ No newline at end of file diff --git a/packages/client/config/ipfs2/swarm.key b/packages/client/config/ipfs2/swarm.key deleted file mode 100644 index 2e3e6891..00000000 --- a/packages/client/config/ipfs2/swarm.key +++ /dev/null @@ -1,3 +0,0 @@ -/key/swarm/psk/1.0.0/ -/base16/ -ed4e9d8858ee6cd48cd9f0796eab2bc38bba102b288f263d4ed8bca7a184b4be diff --git a/packages/client/config/ipfs2/version b/packages/client/config/ipfs2/version deleted file mode 100644 index 3cacc0b9..00000000 --- a/packages/client/config/ipfs2/version +++ /dev/null @@ -1 +0,0 @@ -12 \ No newline at end of file diff --git a/packages/client/config/ipfs3/config b/packages/client/config/ipfs3/config deleted file mode 100644 index e86ccd78..00000000 --- a/packages/client/config/ipfs3/config +++ /dev/null @@ -1,153 +0,0 @@ -{ - "API": { - "HTTPHeaders": {} - }, - "Addresses": { - "API": "/ip4/0.0.0.0/tcp/5001", - "Announce": [], - "AppendAnnounce": [], - "Gateway": "/ip4/0.0.0.0/tcp/8080", - "NoAnnounce": [], - "Swarm": [ - "/ip4/0.0.0.0/tcp/4001", - "/ip6/::/tcp/4001", - "/ip4/0.0.0.0/udp/4001/quic", - "/ip6/::/udp/4001/quic" - ] - }, - "AutoNAT": {}, - "Bootstrap": ["/dns4/logion-test_ipfs1_1/tcp/4001/p2p/12D3KooWE6cKjo2QTQqFNJFG7ymfndXrY3vZa7kaMgGHPDKmdP9F"], - "DNS": { - "Resolvers": {} - }, - "Datastore": { - "BloomFilterSize": 0, - "GCPeriod": "1h", - "HashOnRead": false, - "Spec": { - "mounts": [ - { - "child": { - "path": "blocks", - "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", - "sync": true, - "type": "flatfs" - }, - "mountpoint": "/blocks", - "prefix": "flatfs.datastore", - "type": "measure" - }, - { - "child": { - "compression": "none", - "path": "datastore", - "type": "levelds" - }, - "mountpoint": "/", - "prefix": "leveldb.datastore", - "type": "measure" - } - ], - "type": "mount" - }, - "StorageGCWatermark": 90, - "StorageMax": "10GB" - }, - "Discovery": { - "MDNS": { - "Enabled": true, - "Interval": 10 - } - }, - "Experimental": { - "AcceleratedDHTClient": false, - "FilestoreEnabled": false, - "GraphsyncEnabled": false, - "Libp2pStreamMounting": false, - "P2pHttpProxy": false, - "StrategicProviding": false, - "UrlstoreEnabled": false - }, - "Gateway": { - "APICommands": [], - "HTTPHeaders": { - "Access-Control-Allow-Headers": [ - "X-Requested-With", - "Range", - "User-Agent" - ], - "Access-Control-Allow-Methods": [ - "GET" - ], - "Access-Control-Allow-Origin": [ - "*" - ] - }, - "NoDNSLink": false, - "NoFetch": false, - "PathPrefixes": [], - "PublicGateways": null, - "RootRedirect": "", - "Writable": false - }, - "Identity": { - "PeerID": "12D3KooWJ8tudqDw9sosfBbrA5B2S4eR9ivfa4xdmcH4w4hedmPp", - "PrivKey": "CAESQFwS6MsrGYVNhoIdjwfZJqI7JhHYNfuJYkEsecxBuDGpe5y1DgaRL6n1bYdOck8BJ5anxi4C/00awYGl7g4b8gs=" - }, - "Internal": {}, - "Ipns": { - "RecordLifetime": "", - "RepublishPeriod": "", - "ResolveCacheSize": 128 - }, - "Migration": { - "DownloadSources": [], - "Keep": "" - }, - "Mounts": { - "FuseAllowOther": false, - "IPFS": "/ipfs", - "IPNS": "/ipns" - }, - "Peering": { - "Peers": null - }, - "Pinning": { - "RemoteServices": {} - }, - "Plugins": { - "Plugins": null - }, - "Provider": { - "Strategy": "" - }, - "Pubsub": { - "DisableSigning": false, - "Router": "" - }, - "Reprovider": { - "Interval": "12h", - "Strategy": "all" - }, - "Routing": { - "Type": "dht" - }, - "Swarm": { - "AddrFilters": null, - "ConnMgr": { - "GracePeriod": "20s", - "HighWater": 900, - "LowWater": 600, - "Type": "basic" - }, - "DisableBandwidthMetrics": false, - "DisableNatPortMap": false, - "RelayClient": {}, - "RelayService": {}, - "Transports": { - "Multiplexers": {}, - "Network": {}, - "Security": {} - } - } -} diff --git a/packages/client/config/ipfs3/datastore_spec b/packages/client/config/ipfs3/datastore_spec deleted file mode 100644 index 7bf9626c..00000000 --- a/packages/client/config/ipfs3/datastore_spec +++ /dev/null @@ -1 +0,0 @@ -{"mounts":[{"mountpoint":"/blocks","path":"blocks","shardFunc":"/repo/flatfs/shard/v1/next-to-last/2","type":"flatfs"},{"mountpoint":"/","path":"datastore","type":"levelds"}],"type":"mount"} \ No newline at end of file diff --git a/packages/client/config/ipfs3/swarm.key b/packages/client/config/ipfs3/swarm.key deleted file mode 100644 index 2e3e6891..00000000 --- a/packages/client/config/ipfs3/swarm.key +++ /dev/null @@ -1,3 +0,0 @@ -/key/swarm/psk/1.0.0/ -/base16/ -ed4e9d8858ee6cd48cd9f0796eab2bc38bba102b288f263d4ed8bca7a184b4be diff --git a/packages/client/config/ipfs3/version b/packages/client/config/ipfs3/version deleted file mode 100644 index 3cacc0b9..00000000 --- a/packages/client/config/ipfs3/version +++ /dev/null @@ -1 +0,0 @@ -12 \ No newline at end of file diff --git a/packages/client/package.json b/packages/client/package.json index 0a9040ff..20123f7b 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@logion/client", - "version": "0.33.0", + "version": "0.34.0-1", "description": "logion SDK for client applications", "main": "dist/index.js", "packageManager": "yarn@3.2.0", @@ -9,9 +9,9 @@ "build": "yarn lint && tsc -p tsconfig.app.json", "lint": "yarn eslint src/**", "test": "NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine.json", - "integration-test": "docker-compose up -d && ./scripts/integration_test_db_setup.sh && node ./scripts/init_onchain_data.js && NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine-integration.json ; docker-compose down", "check-publish": "yarn build && yarn pack -n", - "do-publish": "yarn build && yarn npm publish" + "do-publish": "yarn build && yarn npm publish", + "clean": "rm -rf dist" }, "repository": { "type": "git", @@ -44,11 +44,9 @@ "@typescript-eslint/eslint-plugin": "^6.9.1", "@typescript-eslint/parser": "^6.9.1", "eslint": "^8.20.0", - "form-data": "^4.0.0", "jasmine": "^4.3.0", "jasmine-spec-reporter": "^7.0.0", "moq.ts": "^9.0.2", - "ts-node": "^10.9.1", "typescript": "^5.2.2" }, "engines": { diff --git a/packages/client/src/ComponentFactory.ts b/packages/client/src/ComponentFactory.ts index ebe4fb7b..504257d5 100644 --- a/packages/client/src/ComponentFactory.ts +++ b/packages/client/src/ComponentFactory.ts @@ -1,33 +1,101 @@ -import { LogionNodeApiClass, buildApiClass } from "@logion/node-api"; +import { LogionNodeApiClass, buildApiClass, Hash } from "@logion/node-api"; import { AuthenticationClient } from "./AuthenticationClient.js"; import { AxiosFactory } from "./AxiosFactory.js"; import { DirectoryClient } from "./DirectoryClient.js"; import { NetworkState } from "./NetworkState.js"; import { LegalOfficerEndpoint } from "./SharedClient.js"; import { LegalOfficerClass } from "./Types.js"; +import axios from "axios"; +import { newBackendError } from "./Error.js"; + +export interface HashAndSize { + hash: Hash; + size: bigint; +} + +export abstract class File { + + abstract getHashAndSize(): Promise; +} + +export interface FileUploadParameters { + endpoint: string; + files: FileToUpload[]; + fields: NameValue[]; + headers: Record; +} + +export interface FileToUpload { + file: File; + name: string; + field: string; +} + +export interface NameValue { + name: string; + value: string; +} + +export interface FileUploader { + upload(parameters: FileUploadParameters): Promise; +} export interface FormDataLike { append(name: string, value: any, fileName?: string): void; // eslint-disable-line @typescript-eslint/no-explicit-any } -export type FileLike = File | Blob | Buffer | string; // string is the path to the file +export abstract class AxiosFileUploader implements FileUploader { + + async upload(parameters: FileUploadParameters): Promise { + const formData = this.buildFormData(); + for(const file of parameters.files) { + formData.append(file.field, await this.toFormDataValue(file.file), file.name); + } + for(const field of parameters.fields) { + formData.append(field.name, field.value); + } + + try { + await axios.post( + parameters.endpoint, + formData, + { + headers: parameters.headers, + } + ); + } catch(e) { + throw newBackendError(e); + } + } + + abstract buildFormData(): FormDataLike; -export type UploadableData = File | Blob | Buffer | NodeJS.ReadableStream; + abstract toFormDataValue(file: File): Promise; // eslint-disable-line @typescript-eslint/no-explicit-any +} -export interface ComponentFactory { +export interface CoreComponentFactory { buildAxiosFactory: () => AxiosFactory; buildDirectoryClient: (api: LogionNodeApiClass, directoryEndpoint: string, axiosFactory: AxiosFactory, token?: string) => DirectoryClient; buildAuthenticationClient: (api: LogionNodeApiClass, directoryEndpoint: string, legalOfficers: LegalOfficerClass[], axiosFactory: AxiosFactory) => AuthenticationClient; buildNetworkState(nodesUp: LegalOfficerEndpoint[], nodesDown: LegalOfficerEndpoint[]): NetworkState; buildNodeApi(rpcEndpoints: string[]): Promise; - buildFormData: () => FormDataLike; } -export const DefaultComponentFactory: ComponentFactory = { +export const CoreComponentFactoryInstance: CoreComponentFactory = { buildAxiosFactory: () => new AxiosFactory(), buildDirectoryClient: (api: LogionNodeApiClass, directoryEndpoint: string, axiosFactory: AxiosFactory, token?: string) => new DirectoryClient(api, directoryEndpoint, axiosFactory, token), buildAuthenticationClient: (api: LogionNodeApiClass, directoryEndpoint: string, legalOfficers: LegalOfficerClass[], axiosFactory: AxiosFactory) => new AuthenticationClient(api, directoryEndpoint, legalOfficers, axiosFactory), buildNetworkState: (nodesUp: LegalOfficerEndpoint[], nodesDown: LegalOfficerEndpoint[]) => new NetworkState(nodesUp, nodesDown), buildNodeApi: (rpcEndpoints: string[]) => buildApiClass(rpcEndpoints), - buildFormData: () => new FormData(), }; + +export interface ComponentFactory extends CoreComponentFactory { + buildFileUploader: () => FileUploader; +} + +export function buildComponentFactory(buildFileUploader: () => FileUploader): ComponentFactory { + return { + ...CoreComponentFactoryInstance, + buildFileUploader, + }; +} diff --git a/packages/client/src/Hash.ts b/packages/client/src/Hash.ts index 883f1301..a9a716d0 100644 --- a/packages/client/src/Hash.ts +++ b/packages/client/src/Hash.ts @@ -1,51 +1,6 @@ -import { Hash as Hasher } from 'fast-sha256'; -import { FileLike, UploadableData } from "./ComponentFactory.js"; import { Hash } from "@logion/node-api"; import { requireDefined } from './assertions.js'; - -export interface HashAndSize { - hash: Hash; - size: bigint; -} - -export async function hashBlob(file: Blob): Promise { - const unknownStream: any = file.stream(); // eslint-disable-line @typescript-eslint/no-explicit-any - const reader = unknownStream.getReader(); - const digest = new Hasher(); - let size = 0n; - let chunk: {done: boolean, value: Buffer} = await reader.read(); - while(!chunk.done) { - size = size + BigInt(chunk.value.length); - digest.update(chunk.value); - chunk = await reader.read(); - } - return { - hash: Hash.fromDigest(digest), - size, - }; -} - -export function hashBuffer(buffer: Buffer): Hash { - const digest = new Hasher(); - digest.update(buffer); - return Hash.fromDigest(digest); -} - -export async function hashStream(stream: NodeJS.ReadableStream): Promise { - return new Promise((resolve, reject) => { - const digest = new Hasher(); - let size = 0n; - stream.on("data", data => { - size = size + BigInt(data.length); - digest.update(data); - }); - stream.on("end", () => resolve({ - hash: Hash.fromDigest(digest), - size - })); - stream.on("error", reject); - }); -} +import { File, HashAndSize } from "./ComponentFactory.js"; const HASH_OF_EMPTY = Hash.of(""); @@ -61,17 +16,17 @@ export class HashOrContent { return new HashOrContent({ hash }); } - static fromContent(content: FileLike): HashOrContent { + static fromContent(content: File): HashOrContent { return new HashOrContent({ content }); } - static async fromContentFinalized(fileContent: FileLike): Promise { + static async fromContentFinalized(fileContent: File): Promise { const content = new HashOrContent({ content: fileContent }); await content.finalize(); return content; } - constructor(parameters: { hash?: Hash, content?: FileLike }) { + constructor(parameters: { hash?: Hash, content?: File }) { if(!parameters.hash && !parameters.content) { throw new Error("Either of hash or content must be defined"); } @@ -82,7 +37,7 @@ export class HashOrContent { private _hash?: Hash; - private _content?: FileLike; + private _content?: File; private finalized: boolean; @@ -121,62 +76,16 @@ export class HashOrContent { } private async hashContent(): Promise { - if(isBlob(this._content)) { - return hashBlob(this._content as Blob); - } else if(isBuffer(this._content)) { - const buffer = this._content as Buffer; - return { - hash: hashBuffer(buffer), - size: BigInt(buffer.length) - }; - } else if(typeof this._content === "string") { - return hashStream(await buildStream(this._content as string)); - } else { - throw new Error(`Unsupported content type: ${ typeof this._content }`); - } + return this.content.getHashAndSize(); } get content() { - if(!this._content) { - throw new Error("No content available"); - } - this.ensureFinalized(); - return requireDefined(this._content); + return requireDefined(this._content, () => new Error("No content available")); } get size() { - return requireDefined(this._size, () => Error("No content available to compute the size of")); + return requireDefined(this._size, () => new Error("No content available to compute the size of")); } - - async data(): Promise { - if(!this._content) { - throw new Error("No content available"); - } - this.ensureFinalized(); - if(typeof this._content === "string") { - return await buildStream(this._content as string); - } else { - return requireDefined(this._content); - } - } -} - -function isBlob(obj: any): boolean { // eslint-disable-line @typescript-eslint/no-explicit-any - return obj - && obj.stream - && typeof obj.stream === 'function'; -} - -function isBuffer(obj: any): boolean { // eslint-disable-line @typescript-eslint/no-explicit-any - return obj - && obj.constructor - && typeof obj.constructor.isBuffer === 'function' - && obj.constructor.isBuffer(obj); -} - -async function buildStream(path: string): Promise { - const fs = await import('fs'); - return fs.createReadStream(path); } export class HashString { diff --git a/packages/client/src/LocClient.ts b/packages/client/src/LocClient.ts index 275159bf..c6929c1a 100644 --- a/packages/client/src/LocClient.ts +++ b/packages/client/src/LocClient.ts @@ -874,21 +874,35 @@ export class AuthenticatedLocClient extends LocClient { await file.finalize(); - const formData = this.componentFactory.buildFormData(); - formData.append('file', await file.data(), fileName); - formData.append('nature', nature); - formData.append('hash', file.contentHash.toHex()); - formData.append('direct', String(direct)); - - try { - await this.backend().post( - `/api/loc-request/${ locId.toString() }/files`, - formData, - { headers: { "Content-Type": "multipart/form-data" } } - ); - } catch(e) { - throw newBackendError(e); - } + const uploader = this.componentFactory.buildFileUploader(); + await uploader.upload({ + endpoint: `${ this.legalOfficer.node }/api/loc-request/${ locId.toString() }/files`, + files: [ + { + file: file.content, + name: fileName, + field: "file", + } + ], + fields: [ + { + name: "nature", + value: nature, + }, + { + name: "hash", + value: file.contentHash.toHex(), + }, + { + name: "direct", + value: String(direct), + } + ], + headers: { + "Content-Type": "multipart/form-data", + 'Authorization': `Bearer ${this.legalOfficer.token}`, + } + }); } async deleteFile(parameters: RefFileParams & FetchParameters): Promise { @@ -1075,18 +1089,27 @@ export class AuthenticatedLocClient extends LocClient { await file.hashOrContent.finalize(); // Ensure validity - const formData = this.componentFactory.buildFormData(); - formData.append('file', await file.hashOrContent.data(), file.name); - formData.append('hash', file.hashOrContent.contentHash.toHex()); - try { - await this.backend().post( - `/api/collection/${ locId.toString() }/${ itemId.toHex() }/files`, - formData, - { headers: { "Content-Type": "multipart/form-data" } } - ); - } catch(e) { - throw newBackendError(e); - } + const uploader = this.componentFactory.buildFileUploader(); + await uploader.upload({ + endpoint: `${ this.legalOfficer.node }/api/collection/${ locId.toString() }/${ itemId.toHex() }/files`, + files: [ + { + file: file.hashOrContent.content, + name: file.name, + field: "file", + } + ], + fields: [ + { + name: "hash", + value: file.hashOrContent.contentHash.toHex(), + }, + ], + headers: { + "Content-Type": "multipart/form-data", + 'Authorization': `Bearer ${this.legalOfficer.token}`, + } + }); } private validTokenOrThrow(itemToken: ItemTokenWithRestrictedType) { @@ -1301,18 +1324,27 @@ export class AuthenticatedLocClient extends LocClient { await file.hashOrContent.finalize(); // Ensure validity - const formData = this.componentFactory.buildFormData(); - formData.append('file', await file.hashOrContent.data(), file.name); - formData.append('hash', file.hashOrContent.contentHash.toHex()); - try { - await this.backend().post( - `/api/records/${ locId.toString() }/${ recordId.toHex() }/files`, - formData, - { headers: { "Content-Type": "multipart/form-data" } } - ); - } catch(e) { - throw newBackendError(e); - } + const uploader = this.componentFactory.buildFileUploader(); + await uploader.upload({ + endpoint: `${ this.legalOfficer.node }/api/records/${ locId.toString() }/${ recordId.toHex() }/files`, + files: [ + { + file: file.hashOrContent.content, + name: file.name, + field: "file", + } + ], + fields: [ + { + name: "hash", + value: file.hashOrContent.contentHash.toHex(), + }, + ], + headers: { + "Content-Type": "multipart/form-data", + 'Authorization': `Bearer ${this.legalOfficer.token}`, + } + }); } override async getTokensRecordDeliveries(parameters: GetTokensRecordDeliveriesRequest): Promise { diff --git a/packages/client/src/LogionClient.ts b/packages/client/src/LogionClient.ts index 850ef37e..31c7a323 100644 --- a/packages/client/src/LogionClient.ts +++ b/packages/client/src/LogionClient.ts @@ -4,7 +4,7 @@ import { LogionNodeApiClass, UUID, ValidAccountId } from "@logion/node-api"; import { AccountTokens } from "./AuthenticationClient.js"; import { BalanceState, getBalanceState } from "./Balance.js"; -import { ComponentFactory, DefaultComponentFactory } from "./ComponentFactory.js"; +import { ComponentFactory, buildComponentFactory } from "./ComponentFactory.js"; import { DirectoryClient } from "./DirectoryClient.js"; import { initMultiSourceHttpClientState, MultiSourceHttpClient, Token } from "./Http.js"; import { getInitialState, ProtectionState } from "./Recovery.js"; @@ -374,16 +374,9 @@ export class LogionClient { } function getComponentFactory(config: LogionClientConfig): ComponentFactory { - let componentFactory: ComponentFactory; if("__componentFactory" in config) { - componentFactory = (config as any)["__componentFactory"]; // eslint-disable-line @typescript-eslint/no-explicit-any + return (config as any)["__componentFactory"]; // eslint-disable-line @typescript-eslint/no-explicit-any } else { - componentFactory = DefaultComponentFactory; + return buildComponentFactory(config.buildFileUploader); } - - if(config.formDataLikeFactory !== undefined) { - componentFactory.buildFormData = config.formDataLikeFactory; - } - - return componentFactory } diff --git a/packages/client/src/SharedClient.ts b/packages/client/src/SharedClient.ts index dc17b4d9..c65c8729 100644 --- a/packages/client/src/SharedClient.ts +++ b/packages/client/src/SharedClient.ts @@ -3,7 +3,7 @@ import { LogionNodeApiClass, ValidAccountId } from "@logion/node-api"; import { AccountTokens } from "./AuthenticationClient.js"; import { AxiosFactory } from "./AxiosFactory.js"; import { findOrThrow } from "./Collections.js"; -import { ComponentFactory, FormDataLike } from "./ComponentFactory.js"; +import { ComponentFactory, FileUploader } from "./ComponentFactory.js"; import { DirectoryClient } from "./DirectoryClient.js"; import { Endpoint, Token } from "./Http.js"; import { NetworkState } from "./NetworkState.js"; @@ -12,7 +12,7 @@ import { LegalOfficerClass } from "./Types.js"; export interface LogionClientConfig { rpcEndpoints: string[]; directoryEndpoint: string; - formDataLikeFactory?: () => FormDataLike; + buildFileUploader: () => FileUploader; } export interface LegalOfficerEndpoint extends Endpoint { diff --git a/packages/client/src/Signer.ts b/packages/client/src/Signer.ts index cf930090..e53c547c 100644 --- a/packages/client/src/Signer.ts +++ b/packages/client/src/Signer.ts @@ -15,7 +15,7 @@ export interface SignRawParameters { resource: string; operation: string; signedOn: DateTime; - attributes: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any + attributes: string[]; } export type SignatureType = "POLKADOT" | "ETHEREUM" | "CROSSMINT_ETHEREUM" | "MULTIVERSX"; @@ -188,11 +188,19 @@ export class KeyringSigner extends BaseSigner { } } -export function hashAttributes(attributes: any[]): string { // eslint-disable-line @typescript-eslint/no-explicit-any +export function hashAttributes(attributes: string[]): string { const digest = new Hash(); for (let i = 0; i < attributes.length; i++) { - const bytes = new TextEncoder().encode(attributes[i]); + const bytes = encodeString(attributes[i]); digest.update(bytes); } return base64Encode(digest.digest()); } + +function encodeString(str: string): Uint8Array { + const bytes = new Uint8Array(str.length); + for (let i = 0; i < str.length; ++i) { + bytes[i] = str.charCodeAt(i); + } + return bytes; +} diff --git a/packages/client/src/Types.ts b/packages/client/src/Types.ts index 75ac25f3..46bcda57 100644 --- a/packages/client/src/Types.ts +++ b/packages/client/src/Types.ts @@ -69,9 +69,9 @@ export class LegalOfficerClass implements LegalOfficer { readonly name: string; readonly nodeId: string; readonly region: Region; + readonly token: string | undefined; private axiosFactory: AxiosFactory; - private token: string | undefined; private config: BackendConfig | undefined; buildAxiosToNode(): AxiosInstance { diff --git a/packages/client/test/Hash.spec.ts b/packages/client/test/Hash.spec.ts index 7c3ec322..19fa87d9 100644 --- a/packages/client/test/Hash.spec.ts +++ b/packages/client/test/Hash.spec.ts @@ -1,46 +1,40 @@ import { Hash } from "@logion/node-api"; import { HashOrContent, HashString } from "../src/index.js"; +import { MOCK_FILE, MOCK_FILE_HASH } from "./Utils.js"; describe("HashOrContent", () => { - const TEST_HASH = Hash.fromHex("0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); - it("does not need finalize with hash", () => { - const hash = HashOrContent.fromHash(TEST_HASH); + const hash = HashOrContent.fromHash(MOCK_FILE_HASH); expect(hash.hasContent).toBe(false); - expect(hash.contentHash).toEqual(TEST_HASH); + expect(hash.contentHash).toEqual(MOCK_FILE_HASH); expect(() => hash.content).toThrow(); expect(() => hash.size).toThrow(); }); - it("finalizes from Buffer", async () => { - const content = await HashOrContent.fromContentFinalized(Buffer.from("test")); - expect(content.contentHash).toEqual(TEST_HASH); - expect(content.hasContent).toBe(true); - expect(content.size).toBe(4n); - }); - - it("finalizes from path", async () => { - const content = await HashOrContent.fromContentFinalized("test/file.txt"); - expect(content.contentHash).toEqual(TEST_HASH); + it("finalizes from file", async () => { + const content = await HashOrContent.fromContentFinalized(MOCK_FILE); + expect(content.contentHash).toEqual(MOCK_FILE_HASH); expect(content.hasContent).toBe(true); expect(content.size).toBe(4n); }); it("finalizes with matching hash and content", async () => { - const content = new HashOrContent({ hash: TEST_HASH, content: Buffer.from("test") }); + const content = new HashOrContent({ hash: MOCK_FILE_HASH, content: MOCK_FILE }); await content.finalize(); - expect(content.contentHash).toEqual(TEST_HASH); + expect(content.contentHash).toEqual(MOCK_FILE_HASH); expect(content.hasContent).toBe(true); expect(content.size).toBe(4n); }); it("does not finalize with mismatching hash and content", async () => { - const content = new HashOrContent({ hash: TEST_HASH, content: Buffer.from("test2") }); + const content = new HashOrContent({ hash: WRONG_HASH, content: MOCK_FILE }); await expectAsync(content.finalize()).toBeRejected(); }); }); +const WRONG_HASH = Hash.fromHex("0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a09"); + describe("HashString", () => { it("produces valid instance given value only", () => { diff --git a/packages/client/test/Loc.spec.ts b/packages/client/test/Loc.spec.ts index 35cb5955..4120c38e 100644 --- a/packages/client/test/Loc.spec.ts +++ b/packages/client/test/Loc.spec.ts @@ -34,6 +34,8 @@ import { SharedState, FormDataLike, LegalOfficerClass, + FileUploader, + FileUploadParameters, } from "../src/index.js"; import { ALICE, @@ -47,7 +49,7 @@ import { buildValidPolkadotAccountId, ItIsUuid, mockCodecWithToString, - mockCodecWithToBigInt + MOCK_FILE } from "./Utils.js"; import { TestConfigFactory } from "./TestConfigFactory.js"; import { @@ -442,17 +444,14 @@ describe("ClosedCollectionLoc", () => { itemFile: new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(MOCK_FILE), }), }); - aliceAxiosMock.verify(instance => instance.post( - `/api/collection/${ ALICE_CLOSED_COLLECTION_LOC.request.id }/${ ITEM_ID.toHex() }/files`, - It.IsAny(), - It.Is((options: AxiosRequestConfig) => options.headers !== undefined && options.headers["Content-Type"] === "multipart/form-data") - ), - Times.Once(), - ); + uploaderMock.verify(instance => instance.upload(It.Is(params => + params.endpoint.endsWith(`/api/collection/${ ALICE_CLOSED_COLLECTION_LOC.request.id }/${ ITEM_ID.toHex() }/files`) + && params.headers["Content-Type"] === "multipart/form-data" + )),Times.Once()); }); it("checks file hash", async () => { @@ -502,17 +501,14 @@ describe("ClosedCollectionLoc", () => { file: new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(MOCK_FILE), }), }); - aliceAxiosMock.verify(instance => instance.post( - `/api/records/${ ALICE_CLOSED_COLLECTION_LOC.request.id }/${ RECORD_ID.toHex() }/files`, - It.IsAny(), - It.Is((options: AxiosRequestConfig) => options.headers !== undefined && options.headers["Content-Type"] === "multipart/form-data") - ), - Times.Once(), - ); + uploaderMock.verify(instance => instance.upload(It.Is(params => + params.endpoint.endsWith(`/api/records/${ ALICE_CLOSED_COLLECTION_LOC.request.id }/${ RECORD_ID.toHex() }/files`) + && params.headers["Content-Type"] === "multipart/form-data" + )),Times.Once()); }); it("can be voided", async () => { @@ -657,13 +653,14 @@ const RECORD_DESCRIPTION = "Some record description"; const RECORD_FILES: ItemFileWithContent[] = [new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(MOCK_FILE), })]; let aliceAxiosMock: Mock; let bobAxiosMock: Mock; let charlieAxiosMock: Mock; let nodeApiMock: Mock; +let uploaderMock: Mock; async function buildSharedState(isVerifiedIssuer: boolean = false): Promise { const currentAddress = isVerifiedIssuer ? ISSUER : REQUESTER; @@ -680,10 +677,11 @@ async function buildSharedState(isVerifiedIssuer: boolean = false): Promise { factory.setupDefaultNetworkState(); - factory.setupDefaultFormDataFactory(); + factory.setupFileUploaderMock(); factory.setupAuthenticatedDirectoryClientMock(LOGION_CLIENT_CONFIG, token); const axiosFactoryMock = factory.setupAxiosFactoryMock(); + uploaderMock = factory.setupFileUploaderMock(); aliceAxiosMock = new Mock(); const aliceRequests: LocRequest[] = [ @@ -991,19 +989,16 @@ async function testAddMetadata(editable: EditableRequest) { async function testAddFile(editable: EditableRequest) { let newState = await editable.addFile({ - file: HashOrContent.fromContent(Buffer.from("test")), + file: HashOrContent.fromContent(MOCK_FILE), fileName: "test.txt", nature: "Some nature", }); expect(newState).toBeInstanceOf(EditableRequest); - aliceAxiosMock.verify(instance => instance.post( - `/api/loc-request/${ editable.locId }/files`, - It.IsAny(), - It.Is((options: AxiosRequestConfig) => options.headers !== undefined && options.headers["Content-Type"] === "multipart/form-data") - ), - Times.Once(), - ); + uploaderMock.verify(instance => instance.upload(It.Is(params => + params.endpoint.endsWith(`/api/loc-request/${ editable.locId }/files`) + && params.headers["Content-Type"] === "multipart/form-data" + )), Times.Once()); } async function testDeleteMetadata(editable: EditableRequest) { diff --git a/packages/client/test/LogionClient.spec.ts b/packages/client/test/LogionClient.spec.ts index d4d1fd48..a105bffd 100644 --- a/packages/client/test/LogionClient.spec.ts +++ b/packages/client/test/LogionClient.spec.ts @@ -21,7 +21,8 @@ import { buildTestConfig, LOGION_CLIENT_CONFIG, buildValidPolkadotAccountId, - buildSimpleNodeApi + buildSimpleNodeApi, + MOCK_FILE } from './Utils.js'; import { Hash, LogionNodeApiClass } from '@logion/node-api'; @@ -201,7 +202,7 @@ describe("ItemFileWithContent", () => { const item = new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(MOCK_FILE), }); await item.finalize(); expect(item.size).toBe(4n); @@ -211,7 +212,7 @@ describe("ItemFileWithContent", () => { const item = new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(MOCK_FILE), size: 4n, }); await item.finalize(); @@ -222,7 +223,7 @@ describe("ItemFileWithContent", () => { const item = new ItemFileWithContent({ name: "test.txt", contentType: MimeType.from("text/plain"), - hashOrContent: HashOrContent.fromContent(Buffer.from("test")), + hashOrContent: HashOrContent.fromContent(MOCK_FILE), size: 5n, }); await expectAsync(item.finalize()).toBeRejected(); diff --git a/packages/client/test/Public.spec.ts b/packages/client/test/Public.spec.ts index 178ea0d6..883e9329 100644 --- a/packages/client/test/Public.spec.ts +++ b/packages/client/test/Public.spec.ts @@ -175,7 +175,7 @@ async function buildSharedState(): Promise { return await buildTestAuthenticatedSharedSate( (factory: TestConfigFactory) => { factory.setupDefaultNetworkState(); - factory.setupDefaultFormDataFactory(); + factory.setupFileUploaderMock(); factory.setupDirectoryClientMock(LOGION_CLIENT_CONFIG); const axiosFactoryMock = factory.setupAxiosFactoryMock(); diff --git a/packages/client/test/Signer.spec.ts b/packages/client/test/Signer.spec.ts index 199c81fc..a3612918 100644 --- a/packages/client/test/Signer.spec.ts +++ b/packages/client/test/Signer.spec.ts @@ -8,17 +8,17 @@ describe("Signer", () => { }); it("hashes single float", () => { - const result = hashAttributes([1.2]); + const result = hashAttributes(["1.2"]); expect(result).toBe("d6wxm/4ZeeLXmdnmmH5l/rVPYVEcA1UuuumQgmwghZA="); }); it("hashes single integer", () => { - const result = hashAttributes([456]); + const result = hashAttributes(["456"]); expect(result).toBe("s6jg4fmrG/46NvIx9nb3i7MKUZ0rIebFMMDu6Ou0pdA="); }); it("hashes any elements", () => { - const result = hashAttributes(["ABC", 123, true]); + const result = hashAttributes(["ABC", "123", "true"]); expect(result).toBe("L1IAt8dg2CXiUjCoVZ3wf4uIJWocNgsmhmswXmH0oAU="); }); }); diff --git a/packages/client/test/TestConfigFactory.ts b/packages/client/test/TestConfigFactory.ts index af08ca85..dc837c91 100644 --- a/packages/client/test/TestConfigFactory.ts +++ b/packages/client/test/TestConfigFactory.ts @@ -1,17 +1,17 @@ -import { CollectionItem, LogionNodeApiClass, UUID } from "@logion/node-api"; -import FormData from "form-data"; +import { LogionNodeApiClass } from "@logion/node-api"; import { IMock, IPresetBuilder, It, Mock, Times } from "moq.ts"; import { IExpression } from "moq.ts/lib/reflector/expression-reflector"; import { AuthenticationClient, AxiosFactory, ComponentFactory, - DefaultComponentFactory, DirectoryClient, LogionClientConfig, LegalOfficer, LegalOfficerClass, requireDefined, + CoreComponentFactoryInstance, + FileUploader, } from "../src/index.js"; import { buildValidAccountId, mockCodecWithToBigInt, mockCodecWithToHex } from "./Utils.js"; @@ -28,11 +28,11 @@ export class TestConfigFactory { } setupDefaultAxiosInstanceFactory() { - this._componentFactory.setup(instance => instance.buildAxiosFactory).returns(DefaultComponentFactory.buildAxiosFactory); + this._componentFactory.setup(instance => instance.buildAxiosFactory).returns(CoreComponentFactoryInstance.buildAxiosFactory); } setupDefaultNetworkState() { - this._componentFactory.setup(instance => instance.buildNetworkState).returns(DefaultComponentFactory.buildNetworkState); + this._componentFactory.setup(instance => instance.buildNetworkState).returns(CoreComponentFactoryInstance.buildNetworkState); } setupNodeApiMock(config: LogionClientConfig): Mock { @@ -88,8 +88,11 @@ export class TestConfigFactory { return this._componentFactory.verify(expression, times); } - setupDefaultFormDataFactory() { - this._componentFactory.setup(instance => instance.buildFormData()).returns(new FormData()); + setupFileUploaderMock(): Mock { + const uploader = new Mock(); + uploader.setup(instance => instance.upload(It.IsAny())).returns(Promise.resolve()); + this._componentFactory.setup(instance => instance.buildFileUploader()).returns(uploader.object()); + return uploader; } buildLegalOfficerClasses(legalOfficers: LegalOfficer[]) { diff --git a/packages/client/test/Utils.ts b/packages/client/test/Utils.ts index c8f28a20..92ce28dc 100644 --- a/packages/client/test/Utils.ts +++ b/packages/client/test/Utils.ts @@ -15,11 +15,14 @@ import { SuccessfulSubmission, LegalOfficerClass, Signer, - SignParameters + SignParameters, + FileUploader, + HashAndSize, + File } from "../src/index.js"; import { TestConfigFactory } from "./TestConfigFactory.js"; import { It, Mock } from "moq.ts"; -import { AccountType, AnyAccountId, LogionNodeApiClass, UUID, ValidAccountId } from "@logion/node-api"; +import { AccountType, AnyAccountId, Hash, LogionNodeApiClass, UUID, ValidAccountId } from "@logion/node-api"; export const ALICE: LegalOfficer = { name: "Alice", @@ -83,6 +86,7 @@ export function buildAliceAndBobTokens(api: LogionNodeApiClass, expirationDateTi export const LOGION_CLIENT_CONFIG: LogionClientConfig = { rpcEndpoints: [ "wss://rpc.logion.network" ], directoryEndpoint: DIRECTORY_ENDPOINT, + buildFileUploader: () => new Mock().object(), } export function buildTestConfig(setupComponentFactory: (factory: TestConfigFactory) => void): LogionClientConfig { @@ -249,3 +253,17 @@ export function mockSigner(args: { ).returns(Promise.resolve(SUCCESSFUL_SUBMISSION)); return signer; } + +export const MOCK_FILE_HASH = Hash.fromHex("0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"); + +export class MockFile extends File { + + async getHashAndSize(): Promise { + return { + hash: MOCK_FILE_HASH, + size: 4n, + } + } +} + +export const MOCK_FILE = new MockFile(); diff --git a/packages/client/test/Voter.spec.ts b/packages/client/test/Voter.spec.ts index bd85b74f..9d4079aa 100644 --- a/packages/client/test/Voter.spec.ts +++ b/packages/client/test/Voter.spec.ts @@ -61,7 +61,7 @@ async function buildSharedState(): Promise { return await buildTestAuthenticatedSharedSate( (factory: TestConfigFactory) => { factory.setupDefaultNetworkState(); - factory.setupDefaultFormDataFactory(); + factory.setupFileUploaderMock(); factory.setupAuthenticatedDirectoryClientMock(LOGION_CLIENT_CONFIG, token); const axiosFactoryMock = factory.setupAxiosFactoryMock(); diff --git a/packages/crossmint/.npmignore b/packages/crossmint/.npmignore index 7fc33882..e9af8f64 100644 --- a/packages/crossmint/.npmignore +++ b/packages/crossmint/.npmignore @@ -7,3 +7,4 @@ front_config.js front_web*.conf jasmine*.json tsconfig*.json +typedoc.json diff --git a/packages/crossmint/package.json b/packages/crossmint/package.json index 94d963b8..a2a9c707 100644 --- a/packages/crossmint/package.json +++ b/packages/crossmint/package.json @@ -1,6 +1,6 @@ { "name": "@logion/crossmint", - "version": "0.1.27", + "version": "0.1.28-1", "description": "logion SDK for Crossmint", "main": "dist/index.js", "packageManager": "yarn@3.2.0", @@ -8,7 +8,8 @@ "scripts": { "build": "yarn lint && tsc", "lint": "yarn eslint src/**", - "test": "echo 'Nothing to test for the moment'" + "test": "echo 'Nothing to test for the moment'", + "clean": "rm -rf dist" }, "repository": { "type": "git", @@ -22,13 +23,17 @@ "license": "Apache-2.0", "dependencies": { "@crossmint/connect": "^0.0.8", - "@logion/client": "workspace:^" + "@logion/client-browser": "workspace:^" + }, + "peerDependencies": { + "@logion/client-browser": "workspace:^" }, "bugs": { "url": "https://github.com/logion-network/logion-api/issues" }, "homepage": "https://github.com/logion-network/logion-api/packages/extension#readme", "devDependencies": { + "@logion/client-browser": "workspace:^", "@tsconfig/node18": "^1.0.1", "@types/node": "^18.6.1", "@typescript-eslint/eslint-plugin": "^6.9.1", diff --git a/packages/extension/.npmignore b/packages/extension/.npmignore index 7fc33882..e9af8f64 100644 --- a/packages/extension/.npmignore +++ b/packages/extension/.npmignore @@ -7,3 +7,4 @@ front_config.js front_web*.conf jasmine*.json tsconfig*.json +typedoc.json diff --git a/packages/extension/package.json b/packages/extension/package.json index 8f2f86d9..51e748b9 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,6 +1,6 @@ { "name": "@logion/extension", - "version": "0.7.1", + "version": "0.7.2-1", "description": "logion SDK for Polkadot JS extension", "main": "dist/index.js", "packageManager": "yarn@3.2.0", @@ -8,7 +8,8 @@ "scripts": { "build": "yarn lint && tsc", "lint": "yarn eslint src/**", - "test": "echo 'Nothing to test for the moment'" + "test": "echo 'Nothing to test for the moment'", + "clean": "rm -rf dist" }, "repository": { "type": "git", @@ -21,15 +22,19 @@ "author": "Logion Team", "license": "Apache-2.0", "dependencies": { - "@logion/client": "workspace:^", + "@logion/client-browser": "workspace:^", "@polkadot/extension-compat-metamask": "^0.46.5", "@polkadot/extension-dapp": "^0.46.5" }, + "peerDependencies": { + "@logion/client-browser": "workspace:^" + }, "bugs": { "url": "https://github.com/logion-network/logion-api/issues" }, "homepage": "https://github.com/logion-network/logion-api/packages/extension#readme", "devDependencies": { + "@logion/client-browser": "workspace:^", "@tsconfig/node18": "^1.0.1", "@types/node": "^18.6.1", "@typescript-eslint/eslint-plugin": "^6.9.1", diff --git a/packages/multiversx/.npmignore b/packages/multiversx/.npmignore index 7fc33882..e9af8f64 100644 --- a/packages/multiversx/.npmignore +++ b/packages/multiversx/.npmignore @@ -7,3 +7,4 @@ front_config.js front_web*.conf jasmine*.json tsconfig*.json +typedoc.json diff --git a/packages/multiversx/README.md b/packages/multiversx/README.md new file mode 100644 index 00000000..78e24697 --- /dev/null +++ b/packages/multiversx/README.md @@ -0,0 +1,24 @@ +# Logion MultiverX SDK + +This project provides some utility classes enabling the use of the +[MultiversX wallet](hhttps://github.com/multiversx/mx-sdk-js-extension-provider) +with a [logion client](https://github.com/logion-network/logion-api/tree/main/packages/client#readme). + +Note that only message signature is supported. So you will be able to authenticate and interact +with logion off-chain services, but not submit extrinsics to the logion chain. + +## Usage + +Install package `@logion/multiversx` with your favorite package manager and start siging content using the extension. + +```typescript +import { MultiversxSigner } from '@logion/multiversx'; + +const signer = new MultiversxSigner(); +const address = await signer.login(); + +const client = LogionClient.create(...); +const account = client.api.queries.getValidAccountId(address, "Bech32"); + +let authenticatedClient = await client.authenticate([ account ], signer); +``` diff --git a/packages/multiversx/package.json b/packages/multiversx/package.json index a8430a02..302893ab 100644 --- a/packages/multiversx/package.json +++ b/packages/multiversx/package.json @@ -1,6 +1,6 @@ { "name": "@logion/multiversx", - "version": "0.1.8", + "version": "0.1.9-1", "description": "logion SDK for MultiversX", "main": "dist/index.js", "packageManager": "yarn@3.2.0", @@ -8,7 +8,8 @@ "scripts": { "build": "yarn lint && tsc", "lint": "yarn eslint src/**", - "test": "echo 'Nothing to test for the moment'" + "test": "echo 'Nothing to test for the moment'", + "clean": "rm -rf dist" }, "repository": { "type": "git", @@ -21,15 +22,19 @@ "author": "Logion Team", "license": "Apache-2.0", "dependencies": { - "@logion/client": "workspace:^", + "@logion/client-browser": "workspace:^", "@multiversx/sdk-core": "^12.4.3", "@multiversx/sdk-extension-provider": "^2.0.7" }, + "peerDependencies": { + "@logion/client-browser": "workspace:^" + }, "bugs": { "url": "https://github.com/logion-network/logion-api/issues" }, "homepage": "https://github.com/logion-network/logion-api/packages/extension#readme", "devDependencies": { + "@logion/client-browser": "workspace:^", "@tsconfig/node18": "^1.0.1", "@types/node": "^18.6.1", "@typescript-eslint/eslint-plugin": "^6.9.1", diff --git a/packages/node-api/package.json b/packages/node-api/package.json index 1712a590..a42c7dff 100644 --- a/packages/node-api/package.json +++ b/packages/node-api/package.json @@ -28,7 +28,8 @@ "integration-test": "docker-compose up -d && NODE_OPTIONS=--loader=ts-node/esm jasmine --config=jasmine-integration.json ; docker-compose down", "generate:defs-meta": "yarn generate:defs && yarn generate:meta", "generate:defs": "node --loader ts-node/esm ../../node_modules/.bin/polkadot-types-from-defs --endpoint ws://localhost:9944 --input ./src/interfaces/ --package @logion/node-api/dist/interfaces", - "generate:meta": "node --loader ts-node/esm ../../node_modules/.bin/polkadot-types-from-chain --endpoint ws://localhost:9944 --output ./src/interfaces/ --package @logion/node-api/dist/interfaces" + "generate:meta": "node --loader ts-node/esm ../../node_modules/.bin/polkadot-types-from-chain --endpoint ws://localhost:9944 --output ./src/interfaces/ --package @logion/node-api/dist/interfaces", + "clean": "rm -rf dist" }, "repository": { "type": "git", @@ -54,6 +55,7 @@ }, "homepage": "https://github.com/logion-network/logion-api/packages/node-api#readme", "devDependencies": { + "@logion/client-browser": "workspace:^", "@polkadot/typegen": "^10.10.1", "@tsconfig/node18": "^1.0.1", "@types/jasmine": "^4.0.3", diff --git a/website/package.json b/website/package.json index b1bffff3..2231b5f7 100644 --- a/website/package.json +++ b/website/package.json @@ -13,7 +13,8 @@ "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", "typecheck": "tsc", - "api-doc": "typedoc" + "api-doc": "typedoc", + "clean": "rm -rf build" }, "dependencies": { "@docusaurus/core": "^2.4.3", diff --git a/yarn.lock b/yarn.lock index 4de78589..e5e2c960 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3189,6 +3189,45 @@ __metadata: languageName: node linkType: hard +"@logion/client-browser@workspace:^, @logion/client-browser@workspace:packages/client-browser": + version: 0.0.0-use.local + resolution: "@logion/client-browser@workspace:packages/client-browser" + dependencies: + "@logion/client": "workspace:^" + "@tsconfig/node18": ^1.0.1 + "@types/jasmine": ^4.0.3 + "@types/node": ^18.6.1 + "@typescript-eslint/eslint-plugin": ^6.9.1 + "@typescript-eslint/parser": ^6.9.1 + eslint: ^8.20.0 + jasmine: ^4.3.0 + jasmine-spec-reporter: ^7.0.0 + moq.ts: ^9.0.2 + ts-node: ^10.9.1 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + +"@logion/client-node@workspace:packages/client-node": + version: 0.0.0-use.local + resolution: "@logion/client-node@workspace:packages/client-node" + dependencies: + "@logion/client": "workspace:^" + "@tsconfig/node18": ^1.0.1 + "@types/jasmine": ^4.0.3 + "@types/node": ^18.6.1 + "@typescript-eslint/eslint-plugin": ^6.9.1 + "@typescript-eslint/parser": ^6.9.1 + eslint: ^8.20.0 + form-data: ^4.0.0 + jasmine: ^4.3.0 + jasmine-spec-reporter: ^7.0.0 + moq.ts: ^9.0.2 + ts-node: ^10.9.1 + typescript: ^5.2.2 + languageName: unknown + linkType: soft + "@logion/client@workspace:^, @logion/client@workspace:packages/client": version: 0.0.0-use.local resolution: "@logion/client@workspace:packages/client" @@ -3203,13 +3242,11 @@ __metadata: "@typescript-eslint/parser": ^6.9.1 axios: ^0.27.2 eslint: ^8.20.0 - form-data: ^4.0.0 jasmine: ^4.3.0 jasmine-spec-reporter: ^7.0.0 luxon: ^3.0.1 mime-db: ^1.52.0 moq.ts: ^9.0.2 - ts-node: ^10.9.1 typescript: ^5.2.2 languageName: unknown linkType: soft @@ -3219,7 +3256,7 @@ __metadata: resolution: "@logion/crossmint@workspace:packages/crossmint" dependencies: "@crossmint/connect": ^0.0.8 - "@logion/client": "workspace:^" + "@logion/client-browser": "workspace:^" "@tsconfig/node18": ^1.0.1 "@types/node": ^18.6.1 "@typescript-eslint/eslint-plugin": ^6.9.1 @@ -3230,6 +3267,8 @@ __metadata: moq.ts: ^9.0.2 ts-node: ^10.9.1 typescript: ^5.2.2 + peerDependencies: + "@logion/client-browser": "workspace:^" languageName: unknown linkType: soft @@ -3237,7 +3276,7 @@ __metadata: version: 0.0.0-use.local resolution: "@logion/extension@workspace:packages/extension" dependencies: - "@logion/client": "workspace:^" + "@logion/client-browser": "workspace:^" "@polkadot/extension-compat-metamask": ^0.46.5 "@polkadot/extension-dapp": ^0.46.5 "@tsconfig/node18": ^1.0.1 @@ -3250,6 +3289,8 @@ __metadata: moq.ts: ^9.0.2 ts-node: ^10.9.1 typescript: ^5.2.2 + peerDependencies: + "@logion/client-browser": "workspace:^" languageName: unknown linkType: soft @@ -3257,7 +3298,7 @@ __metadata: version: 0.0.0-use.local resolution: "@logion/multiversx@workspace:packages/multiversx" dependencies: - "@logion/client": "workspace:^" + "@logion/client-browser": "workspace:^" "@multiversx/sdk-core": ^12.4.3 "@multiversx/sdk-extension-provider": ^2.0.7 "@tsconfig/node18": ^1.0.1 @@ -3270,6 +3311,8 @@ __metadata: moq.ts: ^9.0.2 ts-node: ^10.9.1 typescript: ^5.2.2 + peerDependencies: + "@logion/client-browser": "workspace:^" languageName: unknown linkType: soft @@ -3277,6 +3320,7 @@ __metadata: version: 0.0.0-use.local resolution: "@logion/node-api@workspace:packages/node-api" dependencies: + "@logion/client-browser": "workspace:^" "@polkadot/api": ^10.10.1 "@polkadot/typegen": ^10.10.1 "@polkadot/util": ^12.5.1