mirror of
https://github.com/logos-storage/logos-storage-marketplace-ui.git
synced 2026-06-07 17:19:35 +00:00
Merge pull request #24 from codex-storage/bug/fix-node-space-allocation-size-calculation
Bug/fix node space allocation size calculation
This commit is contained in:
commit
a7349c79ef
@ -1,6 +1,5 @@
|
||||
import { CodexNodeSpace } from "@codex-storage/sdk-js";
|
||||
import { AvailabilityState } from "./types";
|
||||
import { GB, TB } from "../../utils/constants";
|
||||
import { SpaceAllocation } from "@codex-storage/marketplace-ui-components";
|
||||
import "./AvailabilitySpaceAllocation.css";
|
||||
import { availabilityUnit } from "./availability.domain";
|
||||
@ -24,15 +23,15 @@ export function AvailabilitySpaceAllocation({ availability, space }: Props) {
|
||||
const spaceData = [
|
||||
{
|
||||
title: "Space allocated",
|
||||
size: allocated,
|
||||
size: Math.trunc(allocated),
|
||||
},
|
||||
{
|
||||
title: "New space allocation",
|
||||
size: size,
|
||||
size: Math.trunc(size),
|
||||
},
|
||||
{
|
||||
title: "Remaining space",
|
||||
size: remaining,
|
||||
size: Math.trunc(remaining),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -5,16 +5,15 @@ import { AvailabilityState } from "./types";
|
||||
export const availabilityUnit = (unit: "gb" | "tb") =>
|
||||
unit === "gb" ? GB : TB;
|
||||
|
||||
export const availabilityMax = (space: CodexNodeSpace, unit: "gb" | "tb") => {
|
||||
const bytes = availabilityUnit(unit);
|
||||
return space.quotaMaxBytes / bytes - space.quotaReservedBytes / bytes;
|
||||
};
|
||||
export const availabilityMax = (space: CodexNodeSpace) =>
|
||||
space.quotaMaxBytes - space.quotaReservedBytes - space.quotaUsedBytes;
|
||||
|
||||
export const isAvailabilityValid = (
|
||||
totalSize: string | number,
|
||||
availability: AvailabilityState,
|
||||
max: number
|
||||
) => {
|
||||
const size = parseFloat(totalSize.toString());
|
||||
const unit = availabilityUnit(availability.totalSizeUnit);
|
||||
const size = parseFloat(availability.totalSize.toString()) * unit;
|
||||
|
||||
return size > 0 && size <= max;
|
||||
};
|
||||
|
||||
@ -1,100 +0,0 @@
|
||||
import {
|
||||
SpaceAllocation,
|
||||
Spinner,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Promises } from "../../utils/promises";
|
||||
import { AvailabilityCreate } from "../Availability/AvailabilityCreate";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import { Strings } from "../../utils/strings";
|
||||
import { AvailabilitiesTable } from "../Availability/AvailabilitiesTable";
|
||||
import "./Availabilities.css";
|
||||
|
||||
const defaultSpace = {
|
||||
quotaMaxBytes: 0,
|
||||
quotaReservedBytes: 0,
|
||||
quotaUsedBytes: 0,
|
||||
totalBlocks: 0,
|
||||
};
|
||||
|
||||
export function Availabilities() {
|
||||
{
|
||||
// Error will be catched in ErrorBounday
|
||||
const { data: availabilities = [], isPending } = useQuery({
|
||||
queryFn: () =>
|
||||
CodexSdk.marketplace
|
||||
.availabilities()
|
||||
.then((s) => Promises.rejectOnError(s))
|
||||
.then((res) => res.sort((a, b) => b.totalSize - a.totalSize)),
|
||||
queryKey: ["availabilities"],
|
||||
initialData: [],
|
||||
|
||||
// No need to retry because if the connection to the node
|
||||
// is back again, all the queries will be invalidated.
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Refreshing when focus returns can be useful if a user comes back
|
||||
// to the UI after performing an operation in the terminal.
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
// Error will be catched in ErrorBounday
|
||||
const { data: space = defaultSpace } = useQuery({
|
||||
queryFn: () =>
|
||||
CodexSdk.data.space().then((s) => Promises.rejectOnError(s)),
|
||||
queryKey: ["space"],
|
||||
initialData: defaultSpace,
|
||||
|
||||
// No need to retry because if the connection to the node
|
||||
// is back again, all the queries will be invalidated.
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Refreshing when focus returns can be useful if a user comes back
|
||||
// to the UI after performing an operation in the terminal.
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
const allocation = availabilities
|
||||
.map((a) => ({
|
||||
title: Strings.shortId(a.id),
|
||||
size: a.totalSize,
|
||||
}))
|
||||
.slice(0, 6);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="availabilities-content">
|
||||
{isPending ? (
|
||||
<div className="purchases-loader">
|
||||
<Spinner width="3rem" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="availabilities-table">
|
||||
<AvailabilitiesTable
|
||||
// onEdit={onOpen}
|
||||
availabilities={availabilities}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="availabilities-space">
|
||||
<div>
|
||||
<SpaceAllocation data={allocation} />
|
||||
</div>
|
||||
<div>
|
||||
<AvailabilityCreate space={space} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
@media (min-width: 801px) {
|
||||
.storageRequest-stepper {
|
||||
.storageRequestCreate {
|
||||
min-width: 700px;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { StorageRequestFileChooser } from "../../components/StorageRequestSetup/StorageRequestFileChooser";
|
||||
import { StorageRequestFileChooser } from "./StorageRequestFileChooser";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { WebStorage } from "../../utils/web-storage";
|
||||
import { STEPPER_DURATION } from "../../utils/constants";
|
||||
@ -10,11 +10,11 @@ import {
|
||||
Stepper,
|
||||
useStepperReducer,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { StorageRequestDone } from "./StorageRequestDone";
|
||||
import { StorageRequestSuccess } from "./StorageRequestSuccess";
|
||||
import { Times } from "../../utils/times";
|
||||
import { useStorageRequestMutation } from "./useStorageRequestMutation";
|
||||
import { Plus } from "lucide-react";
|
||||
import "./StorageRequestStepper.css";
|
||||
import "./StorageRequestCreate.css";
|
||||
import { StorageRequestError } from "./StorageRequestError";
|
||||
|
||||
const CONFIRM_STATE = 2;
|
||||
@ -31,7 +31,7 @@ const defaultStorageRequest: StorageRequest = {
|
||||
expiration: 300,
|
||||
};
|
||||
|
||||
export function StorageRequestStepper() {
|
||||
export function StorageRequestCreate() {
|
||||
const [storageRequest, setStorageRequest] = useState<StorageRequest>(
|
||||
defaultStorageRequest
|
||||
);
|
||||
@ -60,7 +60,7 @@ export function StorageRequestStepper() {
|
||||
const components = [
|
||||
StorageRequestFileChooser,
|
||||
StorageRequestReview,
|
||||
error ? StorageRequestError : StorageRequestDone,
|
||||
error ? StorageRequestError : StorageRequestSuccess,
|
||||
];
|
||||
|
||||
const onNextStep = async (step: number) => {
|
||||
@ -133,7 +133,7 @@ export function StorageRequestStepper() {
|
||||
duration={STEPPER_DURATION}
|
||||
onNextStep={onNextStep}
|
||||
backLabel={backLabel}
|
||||
className="storageRequest-stepper"
|
||||
className="storageRequestCreate"
|
||||
nextLabel={nextLabel}>
|
||||
<Body
|
||||
dispatch={dispatch}
|
||||
@ -36,13 +36,7 @@ export function StorageRequestFileChooser({
|
||||
onStorageRequestChange({ cid: value });
|
||||
};
|
||||
|
||||
const onSuccess = (data: string, file: File) => {
|
||||
// TODO Move this to proxy object
|
||||
WebStorage.set(data, {
|
||||
type: file.type,
|
||||
name: file.name,
|
||||
});
|
||||
|
||||
const onSuccess = (data: string) => {
|
||||
onStorageRequestChange({ cid: data });
|
||||
};
|
||||
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import { Placeholder } from "@codex-storage/marketplace-ui-components";
|
||||
import { CircleCheck } from "lucide-react";
|
||||
import "./StorageRequestDone.css";
|
||||
import "./StorageRequestSuccess.css";
|
||||
import { StorageRequestComponentProps } from "./types";
|
||||
import { useEffect } from "react";
|
||||
|
||||
// TODO rename
|
||||
export function StorageRequestDone({ dispatch }: StorageRequestComponentProps) {
|
||||
export function StorageRequestSuccess({
|
||||
dispatch,
|
||||
}: StorageRequestComponentProps) {
|
||||
useEffect(() => {
|
||||
dispatch({
|
||||
type: "toggle-buttons",
|
||||
@ -1,76 +1,28 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { FilesStorage } from "../utils/file-storage";
|
||||
import { CodexSdk } from "../sdk/codex";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { CodexDataContent } from "@codex-storage/sdk-js";
|
||||
import { CodexDataResponse } from "@codex-storage/sdk-js";
|
||||
import { Promises } from "../utils/promises";
|
||||
|
||||
export function useData() {
|
||||
const { data = [] } = useQuery({
|
||||
queryFn: (): Promise<CodexDataContent[]> => {
|
||||
// TODO refactor
|
||||
return Promise.resolve().then(async () => {
|
||||
const res = await CodexSdk.data.cids();
|
||||
const { data = { content: [] } satisfies CodexDataResponse } =
|
||||
useQuery<CodexDataResponse>({
|
||||
queryFn: (_) =>
|
||||
CodexSdk.data.cids().then((res) => Promises.rejectOnError(res)),
|
||||
queryKey: ["cids"],
|
||||
|
||||
if (res.error) {
|
||||
if (import.meta.env.PROD) {
|
||||
Sentry.captureException(res.data);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
initialData: { content: [] } satisfies CodexDataResponse,
|
||||
|
||||
const metadata = await FilesStorage.list();
|
||||
// No need to retry because if the connection to the node
|
||||
// is back again, all the queries will be invalidated.
|
||||
retry: false,
|
||||
|
||||
return res.data.content.map((content, index) => {
|
||||
if (content.manifest.filename) {
|
||||
return content;
|
||||
}
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
const value = metadata.find(([cid]) => content.cid === cid);
|
||||
// Don't expect something new when coming back to the UI
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
if (!value) {
|
||||
return {
|
||||
cid: content.cid,
|
||||
manifest: {
|
||||
...content.manifest,
|
||||
mimetype: "N/A",
|
||||
uploadedAt: new Date(0, 0, 0, 0, 0, 0).toJSON(),
|
||||
filename: "N/A" + index,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
mimetype = "",
|
||||
name = "",
|
||||
uploadedAt = new Date(0, 0, 0, 0, 0, 0).toJSON(),
|
||||
} = value[1];
|
||||
|
||||
return {
|
||||
cid: content.cid,
|
||||
manifest: {
|
||||
...content.manifest,
|
||||
mimetype,
|
||||
filename: name,
|
||||
uploadedAt: uploadedAt,
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
queryKey: ["cids"],
|
||||
initialData: [],
|
||||
|
||||
// No need to retry because if the connection to the node
|
||||
// is back again, all the queries will be invalidated.
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Don't expect something new when coming back to the UI
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return data;
|
||||
return data.content;
|
||||
}
|
||||
|
||||
147
src/proxy.ts
Normal file
147
src/proxy.ts
Normal file
@ -0,0 +1,147 @@
|
||||
import {
|
||||
CodexData,
|
||||
CodexDataResponse,
|
||||
CodexMarketplace,
|
||||
SafeValue,
|
||||
UploadResponse,
|
||||
} from "@codex-storage/sdk-js";
|
||||
import { CodexSdk as Sdk } from "./sdk/codex";
|
||||
import { Promises } from "./utils/promises";
|
||||
import { WebStorage } from "./utils/web-storage";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { FilesStorage } from "./utils/file-storage";
|
||||
|
||||
class CodexDataMock extends CodexData {
|
||||
override upload(
|
||||
file: File,
|
||||
onProgress?: (loaded: number, total: number) => void
|
||||
): Promise<UploadResponse> {
|
||||
const res = super.upload(file, onProgress);
|
||||
|
||||
return res.then(({ result, abort }) => {
|
||||
return {
|
||||
abort,
|
||||
result: result.then((safe) => {
|
||||
if (!safe.error) {
|
||||
return WebStorage.set(safe.data, {
|
||||
type: file.type,
|
||||
name: file.name,
|
||||
}).then(() => safe);
|
||||
}
|
||||
|
||||
return safe;
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
override async cids(): Promise<SafeValue<CodexDataResponse>> {
|
||||
const res = await super.cids();
|
||||
|
||||
if (res.error) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const metadata = await FilesStorage.list();
|
||||
|
||||
const content = res.data.content.map((content, index) => {
|
||||
if (content.manifest.filename) {
|
||||
return content;
|
||||
}
|
||||
|
||||
const value = metadata.find(([cid]) => content.cid === cid);
|
||||
|
||||
if (!value) {
|
||||
return {
|
||||
cid: content.cid,
|
||||
manifest: {
|
||||
...content.manifest,
|
||||
mimetype: "N/A",
|
||||
uploadedAt: new Date(0, 0, 0, 0, 0, 0).toJSON(),
|
||||
filename: "N/A" + index,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
mimetype = "",
|
||||
name = "",
|
||||
uploadedAt = new Date(0, 0, 0, 0, 0, 0).toJSON(),
|
||||
} = value[1];
|
||||
|
||||
return {
|
||||
cid: content.cid,
|
||||
manifest: {
|
||||
...content.manifest,
|
||||
mimetype,
|
||||
filename: name,
|
||||
uploadedAt: uploadedAt,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return { error: false, data: { content } };
|
||||
}
|
||||
}
|
||||
|
||||
class CodexMarketplaceMock extends CodexMarketplace {
|
||||
// override createStorageRequest(
|
||||
// input: CodexCreateStorageRequestInput
|
||||
// ): Promise<SafeValue<string>> {
|
||||
// return Promise.resolve({
|
||||
// error: true,
|
||||
// data: {
|
||||
// message: "C'est balo",
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// override createAvailability(): Promise<
|
||||
// SafeValue<CodexAvailabilityCreateResponse>
|
||||
// > {
|
||||
// return Promise.resolve({
|
||||
// error: true,
|
||||
// data: {
|
||||
// message: "C'est balo",
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// override reservations(): Promise<SafeValue<CodexReservation[]>> {
|
||||
// return Promise.resolve({
|
||||
// error: false,
|
||||
// data: [
|
||||
// {
|
||||
// id: "0x123456789",
|
||||
// availabilityId: "0x12345678910",
|
||||
// requestId: "0x1234567891011",
|
||||
// /**
|
||||
// * Size in bytes
|
||||
// */
|
||||
// size: 500_000_000 + "",
|
||||
// /**
|
||||
// * Slot Index as hexadecimal string
|
||||
// */
|
||||
// slotIndex: "2",
|
||||
// },
|
||||
// {
|
||||
// id: "0x987654321",
|
||||
// availabilityId: "0x9876543210",
|
||||
// requestId: "0x98765432100",
|
||||
// /**
|
||||
// * Size in bytes
|
||||
// */
|
||||
// size: 500_000_000 + "",
|
||||
// /**
|
||||
// * Slot Index as hexadecimal string
|
||||
// */
|
||||
// slotIndex: "1",
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
export const CodexSdk = {
|
||||
...Sdk,
|
||||
marketplace: new CodexMarketplaceMock(import.meta.env.VITE_CODEX_API_URL),
|
||||
data: new CodexDataMock(import.meta.env.VITE_CODEX_API_URL),
|
||||
};
|
||||
@ -1,7 +1,106 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { Availabilities } from "../../components/Availailibities/Availabilities";
|
||||
import { ErrorBoundary } from "@sentry/react";
|
||||
import { ErrorPlaceholder } from "../../components/ErrorPlaceholder/ErrorPlaceholder";
|
||||
import {
|
||||
SpaceAllocation,
|
||||
Spinner,
|
||||
} from "@codex-storage/marketplace-ui-components";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Promises } from "../../utils/promises";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import { Strings } from "../../utils/strings";
|
||||
import "./availabilities.css";
|
||||
import { AvailabilitiesTable } from "../../components/Availability/AvailabilitiesTable";
|
||||
import { AvailabilityCreate } from "../../components/Availability/AvailabilityCreate";
|
||||
|
||||
const defaultSpace = {
|
||||
quotaMaxBytes: 0,
|
||||
quotaReservedBytes: 0,
|
||||
quotaUsedBytes: 0,
|
||||
totalBlocks: 0,
|
||||
};
|
||||
|
||||
export function Availabilities() {
|
||||
{
|
||||
// Error will be catched in ErrorBounday
|
||||
const { data: availabilities = [], isPending } = useQuery({
|
||||
queryFn: () =>
|
||||
CodexSdk.marketplace
|
||||
.availabilities()
|
||||
.then((s) => Promises.rejectOnError(s))
|
||||
.then((res) => res.sort((a, b) => b.totalSize - a.totalSize)),
|
||||
queryKey: ["availabilities"],
|
||||
initialData: [],
|
||||
|
||||
// No need to retry because if the connection to the node
|
||||
// is back again, all the queries will be invalidated.
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Refreshing when focus returns can be useful if a user comes back
|
||||
// to the UI after performing an operation in the terminal.
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
// Error will be catched in ErrorBounday
|
||||
const { data: space = defaultSpace } = useQuery({
|
||||
queryFn: () =>
|
||||
CodexSdk.data.space().then((s) => Promises.rejectOnError(s)),
|
||||
queryKey: ["space"],
|
||||
initialData: defaultSpace,
|
||||
|
||||
// No need to retry because if the connection to the node
|
||||
// is back again, all the queries will be invalidated.
|
||||
retry: false,
|
||||
|
||||
// The client node should be local, so display the cache value while
|
||||
// making a background request looks good.
|
||||
staleTime: 0,
|
||||
|
||||
// Refreshing when focus returns can be useful if a user comes back
|
||||
// to the UI after performing an operation in the terminal.
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
const allocation = availabilities
|
||||
.map((a) => ({
|
||||
title: Strings.shortId(a.id),
|
||||
size: a.totalSize,
|
||||
}))
|
||||
.slice(0, 6);
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="availabilities-content">
|
||||
{isPending ? (
|
||||
<div className="purchases-loader">
|
||||
<Spinner width="3rem" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="availabilities-table">
|
||||
<AvailabilitiesTable
|
||||
// onEdit={onOpen}
|
||||
availabilities={availabilities}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="availabilities-space">
|
||||
<div>
|
||||
<SpaceAllocation data={allocation} />
|
||||
</div>
|
||||
<div>
|
||||
<AvailabilityCreate space={space} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Route = createFileRoute("/dashboard/availabilities")({
|
||||
component: () => (
|
||||
|
||||
@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { CodexSdk } from "../../sdk/codex";
|
||||
import { Cell, Spinner, Table } from "@codex-storage/marketplace-ui-components";
|
||||
import { StorageRequestStepper } from "../../components/StorageRequestSetup/StorageRequestStepper";
|
||||
import { StorageRequestCreate } from "../../components/StorageRequestSetup/StorageRequestCreate";
|
||||
import "./purchases.css";
|
||||
import { FileCell } from "../../components/FileCellRender/FileCell";
|
||||
import { CustomStateCellRender } from "../../components/CustomStateCellRender/CustomStateCellRender";
|
||||
@ -66,12 +66,10 @@ const Purchases = () => {
|
||||
];
|
||||
}) || [];
|
||||
|
||||
// TODO make name uniforms
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<div className="purchases-actions">
|
||||
<StorageRequestStepper />
|
||||
<StorageRequestCreate />
|
||||
</div>
|
||||
|
||||
<Table headers={headers} cells={cells} />
|
||||
@ -79,8 +77,6 @@ const Purchases = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// TODO make uniforms for availabilities
|
||||
|
||||
export const Route = createFileRoute("/dashboard/purchases")({
|
||||
component: () => (
|
||||
<ErrorBoundary card={true}>
|
||||
|
||||
@ -23,20 +23,11 @@ export const CodexSdk = {
|
||||
return WebStorage.set("codex-node-url", url);
|
||||
},
|
||||
|
||||
// TODO Change this
|
||||
get debug() {
|
||||
return client.debug;
|
||||
},
|
||||
debug: client.debug,
|
||||
|
||||
get data() {
|
||||
return client.data;
|
||||
},
|
||||
data: client.data,
|
||||
|
||||
get node() {
|
||||
return client.node;
|
||||
},
|
||||
node: client.node,
|
||||
|
||||
get marketplace() {
|
||||
return client.marketplace;
|
||||
},
|
||||
marketplace: client.marketplace,
|
||||
};
|
||||
|
||||
@ -17,4 +17,10 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"../sdk/codex": "../proxy",
|
||||
"../../sdk/codex": "../../proxy",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user