mirror of
https://github.com/logos-storage/logos-storage-js.git
synced 2026-01-06 23:43:09 +00:00
Drastically reduce the bundle size by replacing Typebox with Valibot.
This commit is contained in:
parent
aa831228ea
commit
7c40e4af5f
12
package-lock.json
generated
12
package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "^0.32.35"
|
"valibot": "^0.36.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@faker-js/faker": "^8.4.1",
|
"@faker-js/faker": "^8.4.1",
|
||||||
@ -36,11 +36,6 @@
|
|||||||
"npm": ">=6.14.13"
|
"npm": ">=6.14.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sinclair/typebox": {
|
|
||||||
"version": "0.32.35",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.35.tgz",
|
|
||||||
"integrity": "sha512-Ul3YyOTU++to8cgNkttakC0dWvpERr6RYoHO2W47DLbFvrwBDJUY31B1sImH6JZSYc4Kt4PyHtoPNu+vL2r2dA=="
|
|
||||||
},
|
|
||||||
"node_modules/@tsconfig/strictest": {
|
"node_modules/@tsconfig/strictest": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/strictest/-/strictest-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/strictest/-/strictest-2.0.5.tgz",
|
||||||
@ -59,6 +54,11 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.17"
|
"node": ">=14.17"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/valibot": {
|
||||||
|
"version": "0.36.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/valibot/-/valibot-0.36.0.tgz",
|
||||||
|
"integrity": "sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,6 @@
|
|||||||
"typescript": "^5.5.4"
|
"typescript": "^5.5.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sinclair/typebox": "^0.32.35"
|
"valibot": "^0.36.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { ValueErrorIterator } from "@sinclair/typebox/build/cjs/errors"
|
import { type InferIssue } from "valibot"
|
||||||
|
|
||||||
type ValidationError = {
|
type ValidationError = {
|
||||||
path: string
|
expected: string
|
||||||
|
received: string
|
||||||
message: string
|
message: string
|
||||||
|
path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,27 +27,11 @@ export type CodexError = {
|
|||||||
errors: ValidationError[]
|
errors: ValidationError[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodexValidationErrors = {
|
export const CodexValibotIssuesMap = (issues: InferIssue<any>[]) => issues.map(i => ({
|
||||||
map(iterator: ValueErrorIterator) {
|
expected: i.expected,
|
||||||
let error
|
received: i.received,
|
||||||
const errors = []
|
message: i.message,
|
||||||
|
path: i.path.map((item: { key: string }) => item.key).join('.')
|
||||||
|
}))
|
||||||
|
|
||||||
while (error = iterator.First()) {
|
|
||||||
errors.push({
|
|
||||||
path: error.path,
|
|
||||||
message: error.message
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// export class CodexError extends Error {
|
|
||||||
// readonly status: number | null
|
|
||||||
|
|
||||||
// constructor(message: string, status: number | null = null) {
|
|
||||||
// super(message)
|
|
||||||
// this.status = status
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@ -56,13 +56,29 @@ function missingNumberValidationError(field: string) {
|
|||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
path: "/" + field,
|
path: field,
|
||||||
message: "Expected required property"
|
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,
|
path: field,
|
||||||
message: "Expected number"
|
expected: 'never',
|
||||||
}
|
message: `Invalid type: Expected never but received "${value}"`,
|
||||||
|
received: `"${value}"`
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,19 +92,17 @@ function missingStringValidationError(field: string) {
|
|||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
path: "/" + field,
|
path: field,
|
||||||
message: "Expected required property"
|
expected: 'string',
|
||||||
},
|
message: 'Invalid type: Expected string but received undefined',
|
||||||
{
|
received: 'undefined'
|
||||||
path: "/" + field,
|
|
||||||
message: "Expected string"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mistypeNumberValidationError(field: string) {
|
function mistypeNumberValidationError(field: string, value: string) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
data: {
|
data: {
|
||||||
@ -96,8 +110,10 @@ function mistypeNumberValidationError(field: string) {
|
|||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
path: "/" + field,
|
path: field,
|
||||||
message: "Expected number"
|
expected: 'number',
|
||||||
|
message: `Invalid type: Expected number but received "${value}"`,
|
||||||
|
received: `"${value}"`
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -112,8 +128,10 @@ function minNumberValidationError(field: string, min: number) {
|
|||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
path: "/" + field,
|
path: field,
|
||||||
message: "Expected number to be greater or equal to " + min
|
expected: '>=' + min,
|
||||||
|
message: 'Invalid value: Expected >=1 but received 0',
|
||||||
|
received: '0'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -143,7 +161,7 @@ describe("marketplace", () => {
|
|||||||
assert.deepStrictEqual(response, missingNumberValidationError("totalSize"));
|
assert.deepStrictEqual(response, missingNumberValidationError("totalSize"));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns an error when trying to create an availability with an invalid number valid", async () => {
|
it.only("returns an error when trying to create an availability with an invalid number valid", async () => {
|
||||||
const response = await marketplace.createAvailability({
|
const response = await marketplace.createAvailability({
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
maxCollateral: 1,
|
maxCollateral: 1,
|
||||||
@ -151,7 +169,7 @@ describe("marketplace", () => {
|
|||||||
totalSize: "abc"
|
totalSize: "abc"
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
assert.deepStrictEqual(response, mistypeNumberValidationError("totalSize"));
|
assert.deepStrictEqual(response, mistypeNumberValidationError("totalSize", "abc"));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns an error when trying to create an availability with zero total size", async () => {
|
it("returns an error when trying to create an availability with zero total size", async () => {
|
||||||
@ -172,6 +190,8 @@ describe("marketplace", () => {
|
|||||||
minPrice: 100,
|
minPrice: 100,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
console.info(response.error)
|
||||||
|
|
||||||
assert.deepStrictEqual(response, missingNumberValidationError("duration"));
|
assert.deepStrictEqual(response, missingNumberValidationError("duration"));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -206,6 +226,18 @@ describe("marketplace", () => {
|
|||||||
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)
|
||||||
|
|
||||||
|
assert.deepStrictEqual(response, extraValidationError("hello", "world"));
|
||||||
|
});
|
||||||
|
|
||||||
it("returns a response when the request succeed", async (t) => {
|
it("returns a response when the request succeed", async (t) => {
|
||||||
const data = { ...createAvailability(), freeSize: 1000 }
|
const data = { ...createAvailability(), freeSize: 1000 }
|
||||||
|
|
||||||
@ -218,8 +250,7 @@ describe("marketplace", () => {
|
|||||||
totalSize: 3000,
|
totalSize: 3000,
|
||||||
minPrice: 100,
|
minPrice: 100,
|
||||||
duration: 100,
|
duration: 100,
|
||||||
hello: "world"
|
})
|
||||||
} as any)
|
|
||||||
|
|
||||||
assert.deepStrictEqual(response, { error: false, data });
|
assert.deepStrictEqual(response, { error: false, data });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Value } from '@sinclair/typebox/value'
|
import * as v from 'valibot'
|
||||||
import { Api } from "../api/config"
|
import { Api } from "../api/config"
|
||||||
import { CodexValidationErrors } from '../errors/errors'
|
import { CodexValibotIssuesMap } from '../errors/errors'
|
||||||
import { Fetch } from "../fetch-safe/fetch-safe"
|
import { Fetch } from "../fetch-safe/fetch-safe"
|
||||||
import { SafeValue } from "../values/values"
|
import { SafeValue } from "../values/values"
|
||||||
import { CodexAvailability, CodexAvailabilityCreateResponse, CodexCreateAvailabilityInput, CodexCreateStorageRequestInput, CodexCreateStorageRequestResponse, CodexPurchase, CodexReservation, CodexSlot, CodexUpdateAvailabilityInput } from "./types"
|
import { CodexAvailability, CodexAvailabilityCreateResponse, CodexCreateAvailabilityInput, CodexCreateStorageRequestInput, CodexCreateStorageRequestResponse, CodexPurchase, CodexReservation, CodexSlot, CodexUpdateAvailabilityInput } from "./types"
|
||||||
@ -50,17 +50,15 @@ export class Marketplace {
|
|||||||
*/
|
*/
|
||||||
async createAvailability(input: CodexCreateAvailabilityInput)
|
async createAvailability(input: CodexCreateAvailabilityInput)
|
||||||
: Promise<SafeValue<CodexAvailabilityCreateResponse>> {
|
: Promise<SafeValue<CodexAvailabilityCreateResponse>> {
|
||||||
const cleaned = Value.Clean(CodexCreateAvailabilityInput, input)
|
const result = v.safeParse(CodexCreateAvailabilityInput, input)
|
||||||
|
|
||||||
if (!Value.Check(CodexCreateAvailabilityInput, cleaned)) {
|
|
||||||
const iterator = Value.Errors(CodexCreateAvailabilityInput, cleaned)
|
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
data: {
|
data: {
|
||||||
type: "validation",
|
type: "validation",
|
||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: CodexValidationErrors.map(iterator)
|
errors: CodexValibotIssuesMap(result.issues)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,7 +70,7 @@ export class Marketplace {
|
|||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json"
|
"content-type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify(cleaned)
|
body: JSON.stringify(result.output)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,29 +79,27 @@ export class Marketplace {
|
|||||||
* Existing Requests linked to this Availability will continue as is.
|
* Existing Requests linked to this Availability will continue as is.
|
||||||
*/
|
*/
|
||||||
async updateAvailability(input: CodexUpdateAvailabilityInput): Promise<SafeValue<CodexAvailability>> {
|
async updateAvailability(input: CodexUpdateAvailabilityInput): Promise<SafeValue<CodexAvailability>> {
|
||||||
const cleaned = Value.Clean(CodexUpdateAvailabilityInput, input)
|
const result = v.safeParse(CodexUpdateAvailabilityInput, input)
|
||||||
|
|
||||||
if (!Value.Check(CodexUpdateAvailabilityInput, cleaned)) {
|
|
||||||
const iterator = Value.Errors(CodexUpdateAvailabilityInput, cleaned)
|
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
data: {
|
data: {
|
||||||
type: "validation",
|
type: "validation",
|
||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: CodexValidationErrors.map(iterator)
|
errors: CodexValibotIssuesMap(result.issues)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = this.url + Api.config.prefix + "/sales/availability/" + cleaned.id
|
const url = this.url + Api.config.prefix + "/sales/availability/" + result.output.id
|
||||||
|
|
||||||
return Fetch.safe<CodexAvailability>(url, {
|
return Fetch.safe<CodexAvailability>(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json"
|
"content-type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify(cleaned)
|
body: JSON.stringify(result.output)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,22 +140,20 @@ export class Marketplace {
|
|||||||
* Creates a new request for storage.
|
* Creates a new request for storage.
|
||||||
*/
|
*/
|
||||||
async createStorageRequest(input: CodexCreateStorageRequestInput): Promise<SafeValue<CodexCreateStorageRequestResponse>> {
|
async createStorageRequest(input: CodexCreateStorageRequestInput): Promise<SafeValue<CodexCreateStorageRequestResponse>> {
|
||||||
const cleaned = Value.Clean(CodexCreateStorageRequestInput, input)
|
const result = v.safeParse(CodexCreateStorageRequestInput, input)
|
||||||
|
|
||||||
if (!Value.Check(CodexCreateStorageRequestInput, cleaned)) {
|
|
||||||
const iterator = Value.Errors(CodexCreateStorageRequestInput, cleaned)
|
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
data: {
|
data: {
|
||||||
type: "validation",
|
type: "validation",
|
||||||
message: "Cannot validate the input",
|
message: "Cannot validate the input",
|
||||||
errors: CodexValidationErrors.map(iterator)
|
errors: CodexValibotIssuesMap(result.issues)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { cid, ...body } = cleaned
|
const { cid, ...body } = result.output
|
||||||
const url = this.url + Api.config.prefix + "/storage/request/" + cid
|
const url = this.url + Api.config.prefix + "/storage/request/" + cid
|
||||||
|
|
||||||
return Fetch.safe<CodexCreateStorageRequestResponse>(url, {
|
return Fetch.safe<CodexCreateStorageRequestResponse>(url, {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Static, Type } from "@sinclair/typebox"
|
import * as v from 'valibot';
|
||||||
|
|
||||||
export type CodexStorageRequest = {
|
export type CodexStorageRequest = {
|
||||||
id: string
|
id: string
|
||||||
@ -130,24 +130,24 @@ export type CodexAvailabilityCreateResponse = CodexAvailability & {
|
|||||||
freeSize: string
|
freeSize: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodexCreateAvailabilityInput = Type.Object({
|
export const CodexCreateAvailabilityInput = v.strictObject({
|
||||||
totalSize: Type.Number({ minimum: 1 }),
|
totalSize: v.pipe(v.number(), v.minValue(1)),
|
||||||
duration: Type.Number({ minimum: 1 }),
|
duration: v.pipe(v.number(), v.minValue(1)),
|
||||||
minPrice: Type.Number(),
|
minPrice: v.number(),
|
||||||
maxCollateral: Type.Number()
|
maxCollateral: v.number(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type CodexCreateAvailabilityInput = Static<typeof CodexCreateAvailabilityInput>
|
export type CodexCreateAvailabilityInput = v.InferOutput<typeof CodexCreateAvailabilityInput>;
|
||||||
|
|
||||||
export const CodexUpdateAvailabilityInput = Type.Object({
|
export const CodexUpdateAvailabilityInput = v.strictObject({
|
||||||
id: Type.String(),
|
id: v.string(),
|
||||||
totalSize: Type.Optional(Type.Number({ minimum: 1 })),
|
totalSize: v.optional(v.pipe(v.number(), v.minValue(1))),
|
||||||
duration: Type.Optional(Type.Number({ minimum: 1 })),
|
duration: v.optional(v.pipe(v.number(), v.minValue(1))),
|
||||||
minPrice: Type.Optional(Type.Number()),
|
minPrice: v.optional(v.number()),
|
||||||
maxCollateral: Type.Optional(Type.Number())
|
maxCollateral: v.optional(v.number()),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type CodexUpdateAvailabilityInput = Static<typeof CodexUpdateAvailabilityInput>
|
export type CodexUpdateAvailabilityInput = v.InferOutput<typeof CodexUpdateAvailabilityInput>;
|
||||||
|
|
||||||
export type CodexReservation = {
|
export type CodexReservation = {
|
||||||
id: string
|
id: string
|
||||||
@ -179,17 +179,17 @@ export type CodexPurchase = {
|
|||||||
request: CodexStorageRequest
|
request: CodexStorageRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodexCreateStorageRequestInput = Type.Object({
|
export const CodexCreateStorageRequestInput = v.strictObject({
|
||||||
cid: Type.String(),
|
cid: v.string(),
|
||||||
duration: Type.Number({ minimum: 1 }),
|
duration: v.pipe(v.number(), v.minValue(1)),
|
||||||
reward: Type.Number(),
|
reward: v.number(),
|
||||||
proofProbability: Type.Number(),
|
proofProbability: v.number(),
|
||||||
nodes: Type.Optional(Type.Number({ default: 1 })),
|
nodes: v.optional(v.number(), 1),
|
||||||
tolerance: Type.Optional(Type.Number({ default: 0 })),
|
tolerance: v.optional(v.number(), 0),
|
||||||
expiry: Type.Number({ minimum: 1 }),
|
expiry: v.pipe(v.number(), v.minValue(1)),
|
||||||
collateral: Type.Number()
|
collateral: v.number(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type CodexCreateStorageRequestInput = Static<typeof CodexCreateStorageRequestInput>
|
export type CodexCreateStorageRequestInput = v.InferOutput<typeof CodexCreateStorageRequestInput>;
|
||||||
|
|
||||||
export type CodexCreateStorageRequestResponse = Omit<CodexCreateStorageRequestInput, "cid">
|
export type CodexCreateStorageRequestResponse = Omit<CodexCreateStorageRequestInput, "cid">
|
||||||
@ -11,5 +11,8 @@
|
|||||||
"DOM",
|
"DOM",
|
||||||
],
|
],
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
}
|
// "module": "ES2015",
|
||||||
|
// "moduleResolution": "Bundler"
|
||||||
|
},
|
||||||
|
"buildOptions": {}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user