From 5e36ffb44360ec2205bb620ead494aef3d516564 Mon Sep 17 00:00:00 2001 From: Arnaud Date: Thu, 15 Aug 2024 12:08:45 +0200 Subject: [PATCH] Apply prettier format --- .editorconfig | 10 - package-lock.json | 18 +- package.json | 8 +- prettier.config.cjs | 4 + src/api/config.ts | 8 +- src/disk/disk.ts | 28 +- src/errors/errors.ts | 64 ++-- src/fetch-safe/fetch-safe.test.ts | 145 ++++---- src/fetch-safe/fetch-safe.ts | 59 ++-- src/index.ts | 33 +- src/marketplace/marketplace.test.ts | 529 ++++++++++++++-------------- src/marketplace/marketplace.ts | 300 ++++++++-------- src/marketplace/types.ts | 295 ++++++++-------- src/values/values.ts | 5 +- 14 files changed, 786 insertions(+), 720 deletions(-) delete mode 100644 .editorconfig create mode 100644 prettier.config.cjs diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 63a0dd2..0000000 --- a/.editorconfig +++ /dev/null @@ -1,10 +0,0 @@ -# top-most EditorConfig file -root = true - -# Unix-style newlines with a newline ending every file -[*] -indent_style = tab -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true diff --git a/package-lock.json b/package-lock.json index 710b21e..fd057d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,11 +14,12 @@ "devDependencies": { "@faker-js/faker": "^8.4.1", "@tsconfig/strictest": "^2.0.5", + "prettier": "^3.3.3", "tsup": "^8.2.3", "typescript": "^5.5.4" }, "engines": { - "node": ">=20" + "node": ">=18" } }, "node_modules/@esbuild/aix-ppc64": { @@ -1568,6 +1569,21 @@ } } }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index 7f824e5..e360a5e 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,12 @@ "scripts": { "prepack": "npm run build", "prebuild": "rm -Rf dist/*", - "build": "tsup tsup src/index.ts --format esm,cjs --dts --minify", + "build": "tsup tsup src/index.ts --format esm,cjs --dts", "compile": "tsc --noEmit", "pretest": "npm run build", "test": "node --test", - "watch": "tsc --watch" + "watch": "tsc --watch", + "format": "prettier --write ./src" }, "keywords": [ "Codex", @@ -48,10 +49,11 @@ "devDependencies": { "@faker-js/faker": "^8.4.1", "@tsconfig/strictest": "^2.0.5", + "prettier": "^3.3.3", "tsup": "^8.2.3", "typescript": "^5.5.4" }, "dependencies": { "valibot": "^0.36.0" } -} \ No newline at end of file +} diff --git a/prettier.config.cjs b/prettier.config.cjs new file mode 100644 index 0000000..678b58b --- /dev/null +++ b/prettier.config.cjs @@ -0,0 +1,4 @@ +module.exports = { + trailingComma: 'es5', + bracketSameLine: true, +}; \ No newline at end of file diff --git a/src/api/config.ts b/src/api/config.ts index be5159f..ef34341 100644 --- a/src/api/config.ts +++ b/src/api/config.ts @@ -1,5 +1,5 @@ export const Api = { - config: { - prefix: "/api/codex/v1" - } -} \ No newline at end of file + config: { + prefix: "/api/codex/v1", + }, +}; diff --git a/src/disk/disk.ts b/src/disk/disk.ts index 58ad17b..c3abc8b 100644 --- a/src/disk/disk.ts +++ b/src/disk/disk.ts @@ -1,19 +1,19 @@ -import type { SafeValue } from "../values/values" +import type { SafeValue } from "../values/values"; export class Disk { - readonly url: string + readonly url: string; - constructor(url: string) { - this.url = url - } + constructor(url: string) { + this.url = url; + } - async available(): Promise> { - return { - error: false, - data: { - full: 500, - used: 200 - } - } - } + async available(): Promise> { + return { + error: false, + data: { + full: 500, + used: 200, + }, + }; + } } diff --git a/src/errors/errors.ts b/src/errors/errors.ts index 901ff73..7ce6622 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -1,37 +1,39 @@ -import { type InferIssue } from "valibot" +import { type InferIssue } from "valibot"; type ValidationError = { - expected: string - received: string - message: string - path: string -} + expected: string; + received: string; + message: string; + path: string; +}; /** - * The CodexError which can be error object of 3 types: - * `error`: Object containing the error message - * `api`: Object containing the api error message and the status code - * `validation`: Object containing the error message and a field `errors` of type ValidationError - * containing the error message for each fields. + * The CodexError which can be error object of 3 types: + * `error`: Object containing the error message + * `api`: Object containing the api error message and the status code + * `validation`: Object containing the error message and a field `errors` of type ValidationError + * containing the error message for each fields. */ -export type CodexError = { - type: "error" - message: string -} | { - type: "api" - message: string - status: number -} | { - type: "validation" - message: string - errors: ValidationError[] -} - -export const CodexValibotIssuesMap = (issues: InferIssue[]) => issues.map(i => ({ - expected: i.expected, - received: i.received, - message: i.message, - path: i.path.map((item: { key: string }) => item.key).join('.') -})) - +export type CodexError = + | { + type: "error"; + message: string; + } + | { + type: "api"; + message: string; + status: number; + } + | { + type: "validation"; + message: string; + errors: ValidationError[]; + }; +export const CodexValibotIssuesMap = (issues: InferIssue[]) => + issues.map((i) => ({ + expected: i.expected, + received: i.received, + message: i.message, + path: i.path.map((item: { key: string }) => item.key).join("."), + })); diff --git a/src/fetch-safe/fetch-safe.test.ts b/src/fetch-safe/fetch-safe.test.ts index 5055b32..0ec285a 100644 --- a/src/fetch-safe/fetch-safe.test.ts +++ b/src/fetch-safe/fetch-safe.test.ts @@ -1,88 +1,95 @@ import assert from "assert"; import { describe, it } from "node:test"; -import { Fetch } from '../fetch-safe/fetch-safe'; +import { Fetch } from "../fetch-safe/fetch-safe"; class MockResponse implements Response { - headers: Headers = new Headers() - ok: boolean; - redirected = false - status: number; - statusText = ""; - type = "basic" as "basic" - url = "" - body = null; - bodyUsed = false; - _text: string + headers: Headers = new Headers(); + ok: boolean; + redirected = false; + status: number; + statusText = ""; + type = "basic" as "basic"; + url = ""; + body = null; + bodyUsed = false; + _text: string; - constructor(ok: boolean, status: number, text: string) { - this.ok = ok - this.status = status - this._text = text - } + constructor(ok: boolean, status: number, text: string) { + this.ok = ok; + this.status = status; + this._text = text; + } - clone(): Response { - throw new Error("Method not implemented."); - } + clone(): Response { + throw new Error("Method not implemented."); + } - arrayBuffer(): Promise { - throw new Error("Method not implemented."); - } + arrayBuffer(): Promise { + throw new Error("Method not implemented."); + } - blob(): Promise { - throw new Error("Method not implemented."); - } + blob(): Promise { + throw new Error("Method not implemented."); + } - formData(): Promise { - throw new Error("Method not implemented."); - } + formData(): Promise { + throw new Error("Method not implemented."); + } - json(): Promise { - return Promise.resolve(JSON.parse(this._text)) - } + json(): Promise { + return Promise.resolve(JSON.parse(this._text)); + } - text(): Promise { - return Promise.resolve(this._text) - } + text(): Promise { + return Promise.resolve(this._text); + } } describe("fetch", () => { - it("returns an error when the http call failed", async (t) => { - global.fetch = t.mock.fn(() => - Promise.resolve(new MockResponse(false, 500, "error")), - ); + it("returns an error when the http call failed", async (t) => { + global.fetch = t.mock.fn(() => + Promise.resolve(new MockResponse(false, 500, "error")) + ); - const result = await Fetch.safe("http://localhost:3000/some-url", { method: "GET" }) - const error = { - type: "api", - message: "error", - status: 500 - } + const result = await Fetch.safe("http://localhost:3000/some-url", { + method: "GET", + }); + const error = { + type: "api", + message: "error", + status: 500, + }; - assert.deepStrictEqual(result, { error: true, data: error }); + assert.deepStrictEqual(result, { error: true, data: error }); + }); + + it("returns an error when the json parsing failed", async (t) => { + global.fetch = t.mock.fn(() => + Promise.resolve(new MockResponse(true, 200, "")) + ); + + const result = await Fetch.safe("http://localhost:3000/some-url", { + method: "GET", + }); + const error = { + type: "error", + message: "Unexpected end of JSON input", + }; + + assert.deepStrictEqual(result, { error: true, data: error }); + }); + + it("returns the data when the fetch succeed", async (t) => { + global.fetch = t.mock.fn(() => + Promise.resolve( + new MockResponse(true, 200, JSON.stringify({ hello: "world" })) + ) + ); + + const result = await Fetch.safe("http://localhost:3000/some-url", { + method: "GET", }); - it("returns an error when the json parsing failed", async (t) => { - global.fetch = t.mock.fn(() => - Promise.resolve(new MockResponse(true, 200, "")), - ); - - const result = await Fetch.safe("http://localhost:3000/some-url", { method: "GET" }) - const error = { - type: "error", - message: "Unexpected end of JSON input" - } - - assert.deepStrictEqual(result, { error: true, data: error }); - }); - - - it("returns the data when the fetch succeed", async (t) => { - global.fetch = t.mock.fn(() => - Promise.resolve(new MockResponse(true, 200, JSON.stringify({ hello: "world" }))), - ); - - const result = await Fetch.safe("http://localhost:3000/some-url", { method: "GET" }) - - assert.deepStrictEqual(result, { error: false, data: { hello: "world" } }); - }); + assert.deepStrictEqual(result, { error: false, data: { hello: "world" } }); + }); }); diff --git a/src/fetch-safe/fetch-safe.ts b/src/fetch-safe/fetch-safe.ts index e68a1df..de5da48 100644 --- a/src/fetch-safe/fetch-safe.ts +++ b/src/fetch-safe/fetch-safe.ts @@ -1,34 +1,37 @@ -import { type SafeValue } from "../values/values" +import { type SafeValue } from "../values/values"; export const Fetch = { - async safe(url: string, init: RequestInit): Promise> { - const res = await fetch(url, init) + async safe( + url: string, + init: RequestInit + ): Promise> { + const res = await fetch(url, init); - if (!res.ok) { - const message = await res.text() + if (!res.ok) { + const message = await res.text(); - return { - error: true, - data: { - type: "api", - message, - status: res.status - } - } - } + return { + error: true, + data: { + type: "api", + message, + status: res.status, + }, + }; + } - try { - const json = await res.json() + try { + const json = await res.json(); - return { error: false, data: json } - } catch (e) { - return { - error: true, - data: { - type: "error", - message: e instanceof Error ? e.message : "JSON parsing error :" + e - } - } - } - } -} + return { error: false, data: json }; + } catch (e) { + return { + error: true, + data: { + type: "error", + message: e instanceof Error ? e.message : "JSON parsing error :" + e, + }, + }; + } + }, +}; diff --git a/src/index.ts b/src/index.ts index c6db1b1..2a931b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,26 +5,25 @@ export * from "./fetch-safe/fetch-safe"; export * from "./marketplace/types"; export class Codex { - readonly url: string - private _marketplace: Marketplace | null - readonly disk: Disk + readonly url: string; + private _marketplace: Marketplace | null; + readonly disk: Disk; - constructor(url: string) { - this.url = url - this._marketplace = null - this.disk = new Disk(url) - } + constructor(url: string) { + this.url = url; + this._marketplace = null; + this.disk = new Disk(url); + } - async marketplace() { - if (this._marketplace) { - return this._marketplace - } + async marketplace() { + if (this._marketplace) { + return this._marketplace; + } - const module = await import("./marketplace/marketplace") + const module = await import("./marketplace/marketplace"); - this._marketplace = new module.Marketplace(this.url) + this._marketplace = new module.Marketplace(this.url); - return module.Marketplace - } + return module.Marketplace; + } } - diff --git a/src/marketplace/marketplace.test.ts b/src/marketplace/marketplace.test.ts index 0af2438..23e8d54 100644 --- a/src/marketplace/marketplace.test.ts +++ b/src/marketplace/marketplace.test.ts @@ -36,343 +36,354 @@ import { Marketplace } from "./marketplace"; // } function createStorageRequest() { - return { - cid: faker.string.alphanumeric(64), - duration: faker.number.int({ min: 1 }), - reward: faker.number.int(), - proofProbability: faker.number.int(), - nodes: faker.number.int(), - tolerance: faker.number.int(), - expiry: faker.number.int({ min: 1 }), - collateral: faker.number.int() - } + return { + cid: faker.string.alphanumeric(64), + duration: faker.number.int({ min: 1 }), + reward: faker.number.int(), + proofProbability: faker.number.int(), + nodes: faker.number.int(), + tolerance: faker.number.int(), + expiry: faker.number.int({ min: 1 }), + collateral: faker.number.int(), + }; } function missingNumberValidationError(field: string) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: [ - { - path: field, - expected: 'number', - message: 'Invalid type: Expected number but received undefined', - received: 'undefined' - }, - ] - } - } + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: [ + { + path: field, + expected: "number", + message: "Invalid type: Expected number but received undefined", + received: "undefined", + }, + ], + }, + }; } function extraValidationError(field: string, value: unknown) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: [ - { - path: field, - expected: 'never', - message: `Invalid type: Expected never but received "${value}"`, - received: `"${value}"` - }, - ] - } - } + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: [ + { + path: field, + expected: "never", + message: `Invalid type: Expected never but received "${value}"`, + received: `"${value}"`, + }, + ], + }, + }; } function missingStringValidationError(field: string) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: [ - { - path: field, - expected: 'string', - message: 'Invalid type: Expected string but received undefined', - received: 'undefined' - } - ] - } - } + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: [ + { + path: field, + expected: "string", + message: "Invalid type: Expected string but received undefined", + received: "undefined", + }, + ], + }, + }; } function mistypeNumberValidationError(field: string, value: string) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: [ - { - path: field, - expected: 'number', - message: `Invalid type: Expected number but received "${value}"`, - received: `"${value}"` - }, - ] - } - } + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: [ + { + path: field, + expected: "number", + message: `Invalid type: Expected number but received "${value}"`, + received: `"${value}"`, + }, + ], + }, + }; } function minNumberValidationError(field: string, min: number) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: [ - { - path: field, - expected: '>=' + min, - message: 'Invalid value: Expected >=1 but received 0', - received: '0' - } - ] - } - } + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: [ + { + path: field, + expected: ">=" + min, + message: "Invalid value: Expected >=1 but received 0", + received: "0", + }, + ], + }, + }; } function createAvailability() { - return { - "id": faker.finance.ethereumAddress(), - "availabilityId": faker.finance.ethereumAddress(), - "size": faker.number.int({ min: 3000, max: 300000 }), - "requestId": faker.finance.ethereumAddress(), - "slotIndex": faker.number.int({ min: 0, max: 9 }) - } + return { + id: faker.finance.ethereumAddress(), + availabilityId: faker.finance.ethereumAddress(), + size: faker.number.int({ min: 3000, max: 300000 }), + requestId: faker.finance.ethereumAddress(), + slotIndex: faker.number.int({ min: 0, max: 9 }), + }; } describe("marketplace", () => { - const marketplace = new Marketplace("http://localhost:3000") + const marketplace = new Marketplace("http://localhost:3000"); - it("returns an error when trying to create an availability without total size", async () => { - const response = await marketplace.createAvailability({ - duration: 3000, - maxCollateral: 1, - minPrice: 100, - } as any) + it("returns an error when trying to create an availability without total size", async () => { + const response = await marketplace.createAvailability({ + duration: 3000, + maxCollateral: 1, + minPrice: 100, + } as any); - assert.deepStrictEqual(response, missingNumberValidationError("totalSize")); - }); + assert.deepStrictEqual(response, missingNumberValidationError("totalSize")); + }); - it.only("returns an error when trying to create an availability with an invalid number valid", async () => { - const response = await marketplace.createAvailability({ - duration: 3000, - maxCollateral: 1, - minPrice: 100, - totalSize: "abc" - } as any) + it.only("returns an error when trying to create an availability with an invalid number valid", async () => { + const response = await marketplace.createAvailability({ + duration: 3000, + maxCollateral: 1, + minPrice: 100, + totalSize: "abc", + } as any); - assert.deepStrictEqual(response, mistypeNumberValidationError("totalSize", "abc")); - }); + assert.deepStrictEqual( + response, + mistypeNumberValidationError("totalSize", "abc") + ); + }); - it("returns an error when trying to create an availability with zero total size", async () => { - const response = await marketplace.createAvailability({ - duration: 3000, - maxCollateral: 1, - minPrice: 100, - totalSize: 0 - }) + it("returns an error when trying to create an availability with zero total size", async () => { + const response = await marketplace.createAvailability({ + duration: 3000, + maxCollateral: 1, + minPrice: 100, + totalSize: 0, + }); - assert.deepStrictEqual(response, minNumberValidationError("totalSize", 1)) - }); + assert.deepStrictEqual(response, minNumberValidationError("totalSize", 1)); + }); - it("returns an error when trying to create an availability without duration", async () => { - const response = await marketplace.createAvailability({ - totalSize: 3000, - maxCollateral: 1, - minPrice: 100, - } as any) + it("returns an error when trying to create an availability without duration", async () => { + const response = await marketplace.createAvailability({ + totalSize: 3000, + maxCollateral: 1, + minPrice: 100, + } as any); - console.info(response.error) + console.info(response.error); - assert.deepStrictEqual(response, missingNumberValidationError("duration")); - }); + assert.deepStrictEqual(response, missingNumberValidationError("duration")); + }); - it("returns an error when trying to create an availability with zero duration", async () => { - const response = await marketplace.createAvailability({ - duration: 0, - maxCollateral: 1, - minPrice: 100, - totalSize: 3000 - }) + it("returns an error when trying to create an availability with zero duration", async () => { + const response = await marketplace.createAvailability({ + duration: 0, + maxCollateral: 1, + minPrice: 100, + totalSize: 3000, + }); - assert.deepStrictEqual(response, minNumberValidationError("duration", 1)) - }); + assert.deepStrictEqual(response, minNumberValidationError("duration", 1)); + }); - it("returns an error when trying to create an availability without min price", async () => { - const response = await marketplace.createAvailability({ - totalSize: 3000, - maxCollateral: 1, - duration: 100, - } as any) + it("returns an error when trying to create an availability without min price", async () => { + const response = await marketplace.createAvailability({ + totalSize: 3000, + maxCollateral: 1, + duration: 100, + } as any); - assert.deepStrictEqual(response, missingNumberValidationError("minPrice")); - }); + assert.deepStrictEqual(response, missingNumberValidationError("minPrice")); + }); - it("returns an error when trying to create an availability without max collateral", async () => { - const response = await marketplace.createAvailability({ - totalSize: 3000, - minPrice: 100, - duration: 100, - } as any) + it("returns an error when trying to create an availability without max collateral", async () => { + const response = await marketplace.createAvailability({ + totalSize: 3000, + minPrice: 100, + duration: 100, + } as any); - assert.deepStrictEqual(response, missingNumberValidationError("maxCollateral")); - }); + assert.deepStrictEqual( + response, + missingNumberValidationError("maxCollateral") + ); + }); - it("returns an error when trying to create an availability with an extra field", async () => { - const response = await marketplace.createAvailability({ - maxCollateral: 1, - totalSize: 3000, - minPrice: 100, - duration: 100, - hello: "world" - } as any) + it("returns an error when trying to create an availability with an extra field", async () => { + const response = await marketplace.createAvailability({ + maxCollateral: 1, + totalSize: 3000, + minPrice: 100, + duration: 100, + hello: "world", + } as any); - assert.deepStrictEqual(response, extraValidationError("hello", "world")); - }); + assert.deepStrictEqual(response, extraValidationError("hello", "world")); + }); - it("returns a response when the request succeed", async (t) => { - const data = { ...createAvailability(), freeSize: 1000 } + it("returns a response when the request succeed", async (t) => { + const data = { ...createAvailability(), freeSize: 1000 }; - t.mock.method(Fetch, "safe", () => - Promise.resolve({ error: false, data }), - ); + t.mock.method(Fetch, "safe", () => Promise.resolve({ error: false, data })); - const response = await marketplace.createAvailability({ - maxCollateral: 1, - totalSize: 3000, - minPrice: 100, - duration: 100, - }) + const response = await marketplace.createAvailability({ + maxCollateral: 1, + totalSize: 3000, + minPrice: 100, + duration: 100, + }); - assert.deepStrictEqual(response, { error: false, data }); - }); + assert.deepStrictEqual(response, { error: false, data }); + }); - it("returns a response when the create availability succeed", async (t) => { - const data = { ...createAvailability(), freeSize: 1000 } + it("returns a response when the create availability succeed", async (t) => { + const data = { ...createAvailability(), freeSize: 1000 }; - t.mock.method(Fetch, "safe", () => - Promise.resolve({ error: false, data }), - ); + t.mock.method(Fetch, "safe", () => Promise.resolve({ error: false, data })); - const response = await marketplace.createAvailability({ - maxCollateral: 1, - totalSize: 3000, - minPrice: 100, - duration: 100, - }) + const response = await marketplace.createAvailability({ + maxCollateral: 1, + totalSize: 3000, + minPrice: 100, + duration: 100, + }); - assert.deepStrictEqual(response, { error: false, data }); - }); + assert.deepStrictEqual(response, { error: false, data }); + }); - it("returns an error when trying to update an availability without id", async () => { - const response = await marketplace.updateAvailability({ - } as any) + it("returns an error when trying to update an availability without id", async () => { + const response = await marketplace.updateAvailability({} as any); - assert.deepStrictEqual(response, missingStringValidationError("id")); - }); + assert.deepStrictEqual(response, missingStringValidationError("id")); + }); - it("returns an error when trying to update an availability with zero total size", async () => { - const response = await marketplace.updateAvailability({ - id: faker.string.alphanumeric(64), - totalSize: 0 - }) + it("returns an error when trying to update an availability with zero total size", async () => { + const response = await marketplace.updateAvailability({ + id: faker.string.alphanumeric(64), + totalSize: 0, + }); - assert.deepStrictEqual(response, minNumberValidationError("totalSize", 1)) - }); + assert.deepStrictEqual(response, minNumberValidationError("totalSize", 1)); + }); - it("returns an error when trying to update an availability with zero duration", async () => { - const response = await marketplace.updateAvailability({ - id: faker.string.alphanumeric(64), - duration: 0 - }) + it("returns an error when trying to update an availability with zero duration", async () => { + const response = await marketplace.updateAvailability({ + id: faker.string.alphanumeric(64), + duration: 0, + }); - assert.deepStrictEqual(response, minNumberValidationError("duration", 1)) - }); + assert.deepStrictEqual(response, minNumberValidationError("duration", 1)); + }); - it("returns a response when the update availability succeed", async (t) => { - const data = createAvailability() + it("returns a response when the update availability succeed", async (t) => { + const data = createAvailability(); - t.mock.method(Fetch, "safe", () => - Promise.resolve({ error: false, data }), - ); + t.mock.method(Fetch, "safe", () => Promise.resolve({ error: false, data })); - const response = await marketplace.updateAvailability({ - id: faker.string.alphanumeric(64), - totalSize: 3000, - }) + const response = await marketplace.updateAvailability({ + id: faker.string.alphanumeric(64), + totalSize: 3000, + }); - assert.deepStrictEqual(response, { error: false, data }); - }); + assert.deepStrictEqual(response, { error: false, data }); + }); - it("returns an error when trying to create a storage request without cid", async () => { - const { cid, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request without cid", async () => { + const { cid, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest(rest as any) + const response = await marketplace.createStorageRequest(rest as any); - assert.deepStrictEqual(response, missingStringValidationError("cid")); - }); + assert.deepStrictEqual(response, missingStringValidationError("cid")); + }); - it("returns an error when trying to create a storage request without duration", async () => { - const { duration, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request without duration", async () => { + const { duration, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest(rest as any) + const response = await marketplace.createStorageRequest(rest as any); - assert.deepStrictEqual(response, missingNumberValidationError("duration")); - }); + assert.deepStrictEqual(response, missingNumberValidationError("duration")); + }); - it("returns an error when trying to create a storage request with zero duration", async () => { - const { duration, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request with zero duration", async () => { + const { duration, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest({ ...rest, duration: 0 }) + const response = await marketplace.createStorageRequest({ + ...rest, + duration: 0, + }); - assert.deepStrictEqual(response, minNumberValidationError("duration", 1)); - }); + assert.deepStrictEqual(response, minNumberValidationError("duration", 1)); + }); - it("returns an error when trying to create a storage request without reward", async () => { - const { reward, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request without reward", async () => { + const { reward, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest(rest as any) + const response = await marketplace.createStorageRequest(rest as any); - assert.deepStrictEqual(response, missingNumberValidationError("reward")); - }); + assert.deepStrictEqual(response, missingNumberValidationError("reward")); + }); - it("returns an error when trying to create a storage request without proof probability", async () => { - const { proofProbability, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request without proof probability", async () => { + const { proofProbability, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest(rest as any) + const response = await marketplace.createStorageRequest(rest as any); - assert.deepStrictEqual(response, missingNumberValidationError("proofProbability")); - }); + assert.deepStrictEqual( + response, + missingNumberValidationError("proofProbability") + ); + }); - it("returns an error when trying to create a storage request without expiry", async () => { - const { expiry, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request without expiry", async () => { + const { expiry, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest(rest as any) + const response = await marketplace.createStorageRequest(rest as any); - assert.deepStrictEqual(response, missingNumberValidationError("expiry")); - }); + assert.deepStrictEqual(response, missingNumberValidationError("expiry")); + }); - it("returns an error when trying to create a storage request with zero expiry", async () => { - const { expiry, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request with zero expiry", async () => { + const { expiry, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest({ ...rest, expiry: 0 }) + const response = await marketplace.createStorageRequest({ + ...rest, + expiry: 0, + }); - assert.deepStrictEqual(response, minNumberValidationError("expiry", 1)); - }); + assert.deepStrictEqual(response, minNumberValidationError("expiry", 1)); + }); - it("returns an error when trying to create a storage request without collateral", async () => { - const { collateral, ...rest } = createStorageRequest() + it("returns an error when trying to create a storage request without collateral", async () => { + const { collateral, ...rest } = createStorageRequest(); - const response = await marketplace.createStorageRequest(rest as any) + const response = await marketplace.createStorageRequest(rest as any); - assert.deepStrictEqual(response, missingNumberValidationError("collateral")); - }); + assert.deepStrictEqual( + response, + missingNumberValidationError("collateral") + ); + }); }); diff --git a/src/marketplace/marketplace.ts b/src/marketplace/marketplace.ts index b37a1ef..63225ba 100644 --- a/src/marketplace/marketplace.ts +++ b/src/marketplace/marketplace.ts @@ -1,167 +1,189 @@ -import * as v from 'valibot' -import { Api } from "../api/config" -import { CodexValibotIssuesMap } from '../errors/errors' -import { Fetch } from "../fetch-safe/fetch-safe" -import type { SafeValue } from "../values/values" -import { type CodexAvailability, type CodexAvailabilityCreateResponse, CodexCreateAvailabilityInput, CodexCreateStorageRequestInput, type CodexCreateStorageRequestResponse, type CodexPurchase, type CodexReservation, type CodexSlot, CodexUpdateAvailabilityInput } from "./types" +import * as v from "valibot"; +import { Api } from "../api/config"; +import { CodexValibotIssuesMap } from "../errors/errors"; +import { Fetch } from "../fetch-safe/fetch-safe"; +import type { SafeValue } from "../values/values"; +import { + type CodexAvailability, + type CodexAvailabilityCreateResponse, + CodexCreateAvailabilityInput, + CodexCreateStorageRequestInput, + type CodexCreateStorageRequestResponse, + type CodexPurchase, + type CodexReservation, + type CodexSlot, + CodexUpdateAvailabilityInput, +} from "./types"; export class Marketplace { - readonly url: string + readonly url: string; - constructor(url: string) { - this.url = url - } + constructor(url: string) { + this.url = url; + } - /** - * Returns active slots - */ - async activeSlots(): Promise> { - const url = this.url + Api.config.prefix + "/sales/slots" + /** + * Returns active slots + */ + async activeSlots(): Promise> { + const url = this.url + Api.config.prefix + "/sales/slots"; - return Fetch.safe(url, { - method: "GET" - }) - } + return Fetch.safe(url, { + method: "GET", + }); + } - /** - * Returns active slot with id {slotId} for the host - */ - async activeSlot(slotId: string): Promise> { - const url = this.url + Api.config.prefix + "/sales/slots/" + slotId + /** + * Returns active slot with id {slotId} for the host + */ + async activeSlot(slotId: string): Promise> { + const url = this.url + Api.config.prefix + "/sales/slots/" + slotId; - return Fetch.safe(url, { - method: "GET" - }) - } + return Fetch.safe(url, { + method: "GET", + }); + } - /** - * Returns storage that is for sale - */ - async availabilities(): Promise> { - const url = this.url + Api.config.prefix + "/sales/availability" + /** + * Returns storage that is for sale + */ + async availabilities(): Promise> { + const url = this.url + Api.config.prefix + "/sales/availability"; - return Fetch.safe(url, { - method: "GET" - }) - } + return Fetch.safe(url, { + method: "GET", + }); + } - /** - * Offers storage for sale - */ - async createAvailability(input: CodexCreateAvailabilityInput) - : Promise> { - const result = v.safeParse(CodexCreateAvailabilityInput, input) + /** + * Offers storage for sale + */ + async createAvailability( + input: CodexCreateAvailabilityInput, + ): Promise> { + const result = v.safeParse(CodexCreateAvailabilityInput, input); - if (!result.success) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: CodexValibotIssuesMap(result.issues) - } - } - } + if (!result.success) { + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: CodexValibotIssuesMap(result.issues), + }, + }; + } - const url = this.url + Api.config.prefix + "/sales/availability" + const url = this.url + Api.config.prefix + "/sales/availability"; - return Fetch.safe(url, { - method: "POST", - headers: { - "content-type": "application/json" - }, - body: JSON.stringify(result.output) - }) - } + return Fetch.safe(url, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(result.output), + }); + } - /** - * The new parameters will be only considered for new requests. - * Existing Requests linked to this Availability will continue as is. - */ - async updateAvailability(input: CodexUpdateAvailabilityInput): Promise> { - const result = v.safeParse(CodexUpdateAvailabilityInput, input) + /** + * The new parameters will be only considered for new requests. + * Existing Requests linked to this Availability will continue as is. + */ + async updateAvailability( + input: CodexUpdateAvailabilityInput, + ): Promise> { + const result = v.safeParse(CodexUpdateAvailabilityInput, input); - if (!result.success) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: CodexValibotIssuesMap(result.issues) - } - } - } + if (!result.success) { + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: CodexValibotIssuesMap(result.issues), + }, + }; + } - const url = this.url + Api.config.prefix + "/sales/availability/" + result.output.id + const url = + this.url + Api.config.prefix + "/sales/availability/" + result.output.id; - return Fetch.safe(url, { - method: "POST", - headers: { - "content-type": "application/json" - }, - body: JSON.stringify(result.output) - }) - } + return Fetch.safe(url, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(result.output), + }); + } - /** - * Return's list of Reservations for ongoing Storage Requests that the node hosts. - */ - async reservations(availabilityId: string): Promise> { - const url = this.url + Api.config.prefix + `/sales/availability/${availabilityId}/reservations` + /** + * Return's list of Reservations for ongoing Storage Requests that the node hosts. + */ + async reservations( + availabilityId: string, + ): Promise> { + const url = + this.url + + Api.config.prefix + + `/sales/availability/${availabilityId}/reservations`; - return Fetch.safe(url, { - method: "GET" - }) - } + return Fetch.safe(url, { + method: "GET", + }); + } - /** - * Returns list of purchase IDs - */ - async purchaseIds(): Promise> { - const url = this.url + Api.config.prefix + `/storage/purchases` + /** + * Returns list of purchase IDs + */ + async purchaseIds(): Promise> { + const url = this.url + Api.config.prefix + `/storage/purchases`; - return Fetch.safe(url, { - method: "GET" - }) - } + return Fetch.safe(url, { + method: "GET", + }); + } - /** - * Returns purchase details - */ - async purchaseDetail(purchaseId: string): Promise> { - const url = this.url + Api.config.prefix + `/storage/purchases/` + purchaseId + /** + * Returns purchase details + */ + async purchaseDetail(purchaseId: string): Promise> { + const url = + this.url + Api.config.prefix + `/storage/purchases/` + purchaseId; - return Fetch.safe(url, { - method: "GET" - }) - } + return Fetch.safe(url, { + method: "GET", + }); + } - /** - * Creates a new request for storage. - */ - async createStorageRequest(input: CodexCreateStorageRequestInput): Promise> { - const result = v.safeParse(CodexCreateStorageRequestInput, input) + /** + * Creates a new request for storage. + */ + async createStorageRequest( + input: CodexCreateStorageRequestInput, + ): Promise> { + const result = v.safeParse(CodexCreateStorageRequestInput, input); - if (!result.success) { - return { - error: true, - data: { - type: "validation", - message: "Cannot validate the input", - errors: CodexValibotIssuesMap(result.issues) - } - } - } + if (!result.success) { + return { + error: true, + data: { + type: "validation", + message: "Cannot validate the input", + errors: CodexValibotIssuesMap(result.issues), + }, + }; + } - const { cid, ...body } = result.output - const url = this.url + Api.config.prefix + "/storage/request/" + cid + const { cid, ...body } = result.output; + const url = this.url + Api.config.prefix + "/storage/request/" + cid; - return Fetch.safe(url, { - method: "POST", - headers: { - "content-type": "application/json" - }, - body: JSON.stringify(body) - }) - } + return Fetch.safe(url, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(body), + }); + } } diff --git a/src/marketplace/types.ts b/src/marketplace/types.ts index 219d457..0897af0 100644 --- a/src/marketplace/types.ts +++ b/src/marketplace/types.ts @@ -1,195 +1,204 @@ -import * as v from 'valibot'; +import * as v from "valibot"; export type CodexStorageRequest = { - id: string + id: string; - /** - * Address of Ethereum address - */ - client: string + /** + * Address of Ethereum address + */ + client: string; - ask: { - /** - * Number of slots that the tequest want to have the content spread over. - */ - slots: number + ask: { + /** + * Number of slots that the tequest want to have the content spread over. + */ + slots: number; - /** - * Amount of storage per slot (in bytes) as decimal string. - */ - slotSize: string + /** + * Amount of storage per slot (in bytes) as decimal string. + */ + slotSize: string; - /** - * The duration of the storage request in seconds. - */ - duration: string + /** + * The duration of the storage request in seconds. + */ + duration: string; - /** - * How often storage proofs are required as decimal string (in periods). - */ - proofProbability: string + /** + * How often storage proofs are required as decimal string (in periods). + */ + proofProbability: string; - /** - * The maximum amount of tokens paid per second per slot to hosts - * the client is willing to pay. - */ - reward: string + /** + * The maximum amount of tokens paid per second per slot to hosts + * the client is willing to pay. + */ + reward: string; - /** - * Max slots that can be lost without data considered to be lost. - */ - maxSlotLoss: number - }, + /** + * Max slots that can be lost without data considered to be lost. + */ + maxSlotLoss: number; + }; - content: { - /** - * Unique Content ID - */ - cid: string + content: { + /** + * Unique Content ID + */ + cid: string; - /** - * Erasure code parameters - */ - erasure: { - /** - * Total number of chunks generated by the erasure code process. - */ - totalChunks: number - }, + /** + * Erasure code parameters + */ + erasure: { + /** + * Total number of chunks generated by the erasure code process. + */ + totalChunks: number; + }; - /** - * Parameters for Proof of Retrievability - */ - por: { - u: string - publicKey: string - name: string - } - }, + /** + * Parameters for Proof of Retrievability + */ + por: { + u: string; + publicKey: string; + name: string; + }; + }; - /* Number as decimal string that represents expiry threshold in seconds from when the Request is submitted. - * When the threshold is reached and the Request does not find requested amount of nodes to host the data, the Request is voided. - * The number of seconds can not be higher then the Request's duration itself. - */ - expiry: string, + /* Number as decimal string that represents expiry threshold in seconds from when the Request is submitted. + * When the threshold is reached and the Request does not find requested amount of nodes to host the data, the Request is voided. + * The number of seconds can not be higher then the Request's duration itself. + */ + expiry: string; - /** - * Random data - */ - nonce: string -} + /** + * Random data + */ + nonce: string; +}; /** * A storage slot is a portion of a storage contract that needs to be fulfilled * by a host. To initiate a contract, all the slots must be filled. */ export type CodexSlot = { - id: string + id: string; - request: CodexStorageRequest, + request: CodexStorageRequest; - /** - * The slot index as hexadecimal string - */ - slotIndex: "string" -} + /** + * The slot index as hexadecimal string + */ + slotIndex: "string"; +}; /** * Storage availability for sell. */ export type CodexAvailability = { - id: string + id: string; - /** - * Size of available storage in bytes - */ - totalSize: string + /** + * Size of available storage in bytes + */ + totalSize: string; - /** - * Maximum time the storage should be sold for (in seconds) - */ - duration: string + /** + * Maximum time the storage should be sold for (in seconds) + */ + duration: string; - /** - * Minimum price to be paid (in amount of tokens) - */ - minPrice: string + /** + * Minimum price to be paid (in amount of tokens) + */ + minPrice: string; - /** - * Maximum collateral user is willing to pay per filled Slot (in amount of tokens) - */ - maxCollateral: string -} + /** + * Maximum collateral user is willing to pay per filled Slot (in amount of tokens) + */ + maxCollateral: string; +}; export type CodexAvailabilityCreateResponse = CodexAvailability & { - id: string + id: string; - /** - * Unused size of availability's storage in bytes as decimal string - */ - freeSize: string -} + /** + * Unused size of availability's storage in bytes as decimal string + */ + freeSize: string; +}; export const CodexCreateAvailabilityInput = v.strictObject({ - totalSize: v.pipe(v.number(), v.minValue(1)), - duration: v.pipe(v.number(), v.minValue(1)), - minPrice: v.number(), - maxCollateral: v.number(), -}) + totalSize: v.pipe(v.number(), v.minValue(1)), + duration: v.pipe(v.number(), v.minValue(1)), + minPrice: v.number(), + maxCollateral: v.number(), +}); -export type CodexCreateAvailabilityInput = v.InferOutput; +export type CodexCreateAvailabilityInput = v.InferOutput< + typeof CodexCreateAvailabilityInput +>; export const CodexUpdateAvailabilityInput = v.strictObject({ - id: v.string(), - totalSize: v.optional(v.pipe(v.number(), v.minValue(1))), - duration: v.optional(v.pipe(v.number(), v.minValue(1))), - minPrice: v.optional(v.number()), - maxCollateral: v.optional(v.number()), -}) + id: v.string(), + totalSize: v.optional(v.pipe(v.number(), v.minValue(1))), + duration: v.optional(v.pipe(v.number(), v.minValue(1))), + minPrice: v.optional(v.number()), + maxCollateral: v.optional(v.number()), +}); -export type CodexUpdateAvailabilityInput = v.InferOutput; +export type CodexUpdateAvailabilityInput = v.InferOutput< + typeof CodexUpdateAvailabilityInput +>; export type CodexReservation = { - id: string - availabilityId: string - requestId: string + id: string; + availabilityId: string; + requestId: string; - /** - * Size in bytes - */ - size: string + /** + * Size in bytes + */ + size: string; - /** - * Slot Index as hexadecimal string - */ - slotIndex: string -} + /** + * Slot Index as hexadecimal string + */ + slotIndex: string; +}; export type CodexPurchase = { - /** - * Description of the request's state - */ - state: string + /** + * Description of the request's state + */ + state: string; - /** - * If request failed, then here is presented the error message - */ - error: string + /** + * If request failed, then here is presented the error message + */ + error: string; - request: CodexStorageRequest -} + request: CodexStorageRequest; +}; export const CodexCreateStorageRequestInput = v.strictObject({ - cid: v.string(), - duration: v.pipe(v.number(), v.minValue(1)), - reward: v.number(), - proofProbability: v.number(), - nodes: v.optional(v.number(), 1), - tolerance: v.optional(v.number(), 0), - expiry: v.pipe(v.number(), v.minValue(1)), - collateral: v.number(), -}) + cid: v.string(), + duration: v.pipe(v.number(), v.minValue(1)), + reward: v.number(), + proofProbability: v.number(), + nodes: v.optional(v.number(), 1), + tolerance: v.optional(v.number(), 0), + expiry: v.pipe(v.number(), v.minValue(1)), + collateral: v.number(), +}); -export type CodexCreateStorageRequestInput = v.InferOutput; +export type CodexCreateStorageRequestInput = v.InferOutput< + typeof CodexCreateStorageRequestInput +>; -export type CodexCreateStorageRequestResponse = Omit \ No newline at end of file +export type CodexCreateStorageRequestResponse = Omit< + CodexCreateStorageRequestInput, + "cid" +>; diff --git a/src/values/values.ts b/src/values/values.ts index 6ee02dc..be68fa5 100644 --- a/src/values/values.ts +++ b/src/values/values.ts @@ -6,5 +6,6 @@ import { type CodexError } from "../errors/errors"; * If the value represents an error, `error` is true and `data` will contain the error. * If the value is not an error, `error` is false and `data` will contain the requested data. */ -export type SafeValue = { error: false, data: T } | { error: true, data: CodexError } - +export type SafeValue = + | { error: false; data: T } + | { error: true; data: CodexError };