diff --git a/.env b/.env new file mode 100644 index 0000000..c1948b4 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +VITE_API_BASE_URL=https://my-public-node-1.projscale.dev/api/v1 \ No newline at end of file diff --git a/.gitignore b/.gitignore index a71e418..948dfab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules .DS_Store dist +.env \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2324b9b..689d7c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@tonconnect/ui-react": "^2.0.2", "@vkruglikov/react-telegram-web-app": "^2.1.9", "axios": "^1.6.7", + "buffer": "^6.0.3", "clsx": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -2054,6 +2055,26 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/big-integer": { "version": "1.6.52", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", @@ -2139,6 +2160,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -3621,6 +3666,26 @@ "react-is": "^16.7.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", diff --git a/package.json b/package.json index 6dd29bb..f4b588b 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@tonconnect/ui-react": "^2.0.2", "@vkruglikov/react-telegram-web-app": "^2.1.9", "axios": "^1.6.7", + "buffer": "^6.0.3", "clsx": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/app/index.tsx b/src/app/index.tsx index 4833d7a..6c66e95 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -1,4 +1,5 @@ import "~/app/styles/globals.css"; +import '~/shared/libs/buffer'; import { useEffect } from "react"; import { useExpand, useWebApp } from "@vkruglikov/react-telegram-web-app"; diff --git a/src/app/styles/globals.css b/src/app/styles/globals.css index bbf4d90..ea8f082 100644 --- a/src/app/styles/globals.css +++ b/src/app/styles/globals.css @@ -26,18 +26,26 @@ /*Input Range*/ /* Custom styles for the range input */ input[type="range"] { - -webkit-appearance: none; /* Remove default appearance */ - width: 100%; /* Full width */ - height: 2px; /* Track height */ - background: linear-gradient( - to right, - white 0%, /* Start color of passed track */ - white var(--value-percentage, 0%), /* End color of passed track */ - gray var(--value-percentage, 0%), /* Start color of remaining track */ - gray 100% /* End color of remaining track */ - ); - border-radius: 9999px; /* Rounded-full track */ - outline: none; /* Remove outline */ + -webkit-appearance: none; + /* Remove default appearance */ + width: 100%; + /* Full width */ + height: 2px; + /* Track height */ + background: linear-gradient(to right, + white 0%, + /* Start color of passed track */ + white var(--value-percentage, 0%), + /* End color of passed track */ + gray var(--value-percentage, 0%), + /* Start color of remaining track */ + gray 100% + /* End color of remaining track */ + ); + border-radius: 9999px; + /* Rounded-full track */ + outline: none; + /* Remove outline */ transition: background 0.3s; } @@ -45,45 +53,64 @@ input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; - width: 9px; /* Thumb width */ - height: 9px; /* Thumb height */ - background: #fff; /* Thumb color (blue-500) */ - border-radius: 9999px; /* Rounded-full thumb */ - cursor: pointer; /* Pointer cursor on hover */ + width: 9px; + /* Thumb width */ + height: 9px; + /* Thumb height */ + background: #fff; + /* Thumb color (blue-500) */ + border-radius: 9999px; + /* Rounded-full thumb */ + cursor: pointer; + /* Pointer cursor on hover */ transition: background 0.3s; } /* For Firefox */ input[type="range"]::-moz-range-thumb { appearance: none; - width: 9px; /* Thumb width */ - height: 9px; /* Thumb height */ - background: #fff; /* Thumb color (blue-500) */ - border-radius: 9999px; /* Rounded-full thumb */ - cursor: pointer; /* Pointer cursor on hover */ + width: 9px; + /* Thumb width */ + height: 9px; + /* Thumb height */ + background: #fff; + /* Thumb color (blue-500) */ + border-radius: 9999px; + /* Rounded-full thumb */ + cursor: pointer; + /* Pointer cursor on hover */ transition: background 0.3s; } input[type="range"]::-moz-range-track { - -webkit-appearance: none; /* Remove default appearance */ - width: 100%; /* Full width */ - height: 2px; /* Track height */ - background: linear-gradient( - to right, - white 0%, /* Start color of passed track */ - white var(--value-percentage, 0%), /* End color of passed track */ - gray var(--value-percentage, 0%), /* Start color of remaining track */ - gray 100% /* End color of remaining track */ - ); - border-radius: 9999px; /* Rounded-full track */ - outline: none; /* Remove outline */ + -webkit-appearance: none; + /* Remove default appearance */ + width: 100%; + /* Full width */ + height: 2px; + /* Track height */ + background: linear-gradient(to right, + white 0%, + /* Start color of passed track */ + white var(--value-percentage, 0%), + /* End color of passed track */ + gray var(--value-percentage, 0%), + /* Start color of remaining track */ + gray 100% + /* End color of remaining track */ + ); + border-radius: 9999px; + /* Rounded-full track */ + outline: none; + /* Remove outline */ transition: background 0.3s; } /* English comment: override react-tag-input classes */ .ReactTags__tagInputField { - @apply bg-transparent text-gray placeholder:text-gray outline-none w-full h-8; - @apply border border-white py-[20px] !important; + @apply bg-[#2B2B2B] outline-none w-full h-8 text-sm !important; + @apply border border-white px-[10px] py-[18px] !important; + @apply whitespace-pre !important; /* English comment: 'bg-transparent' to blend with your dark background 'text-white' to have white text @@ -94,7 +121,7 @@ /* English comment: style for the tag itself when it's rendered */ .ReactTags__selected .ReactTags__tag { - @apply bg-[#363636] text-white text-sm inline-flex items-center px-2 py-1 rounded mr-1; + @apply bg-[#363636] text-white text-sm inline-flex items-center px-2 py-1 mb-2 rounded mr-1 !important; /* English comment: 'bg-[#363636]' to have a dark gray background 'text-white' keeps the text white @@ -105,11 +132,11 @@ } .ReactTags__selected .ReactTags__remove { - @apply ml-1 text-gray hover:text-white cursor-pointer; + @apply ml-1 text-gray hover:text-white cursor-pointer !important; /* English comment: 'ml-1' a small margin to separate the 'x' or close symbol 'text-gray-400' by default, and change to white on hover 'cursor-pointer' so it looks clickable */ } -} +} \ No newline at end of file diff --git a/src/pages/root/steps/presubmit-step/index.tsx b/src/pages/root/steps/presubmit-step/index.tsx index db44819..c9d986c 100644 --- a/src/pages/root/steps/presubmit-step/index.tsx +++ b/src/pages/root/steps/presubmit-step/index.tsx @@ -64,7 +64,7 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => { content: fileUploadResult.content_id_v1, image: coverUploadResult.content_id_v1, price: String(rootStore.price * 10 ** 9), - + hashtags: rootStore.hashtags, royaltyParams: rootStore.royalty.map((member) => ({ ...member, value: member.value * 100, @@ -151,6 +151,24 @@ export const PresubmitStep = ({ prevStep }: PresubmitStepProps) => { )} + {rootStore.author && ( + + + {rootStore.hashtags.map((tag, index) => ( + + {tag} + + ))} + + + )} + { const formSchema = useMemo(() => { const parsePrice = (value: unknown) => { - if (typeof value === "string") { - // Replace commas with dots and parse the value - const parsedValue = parseFloat(value.replace(",", ".")); + if (typeof value === "string" || typeof value === "number") { + const stringValue = value.toString().replace(",", "."); + const parsedValue = parseFloat(stringValue); return isNaN(parsedValue) ? undefined : parsedValue; } return undefined; @@ -37,10 +37,10 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => { return z.object({ price: z.preprocess( parsePrice, - z.number().min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`) + z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`) ), resaleLicensePrice: z - .preprocess(parsePrice, z.number().min(MIN_RESALE_PRICE, `Цена копии должна быть минимум ${MIN_RESALE_PRICE} TON.`)) + .preprocess(parsePrice, z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_RESALE_PRICE, `Цена копии должна быть минимум ${MIN_RESALE_PRICE} TON.`)) .optional(), }); } @@ -48,7 +48,7 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => { return z.object({ price: z.preprocess( parsePrice, - z.number().min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`) + z.number({required_error: 'Цена не соответствует требованиям'}).min(MIN_PRICE, `Цена должна быть минимум ${MIN_PRICE} TON.`) ), }); }, [rootStore.allowResale]); @@ -59,9 +59,9 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => { resolver: zodResolver(formSchema), mode: "onChange", defaultValues: { - price: rootStore.price, + price: rootStore.price || MIN_PRICE, //@ts-expect-error Fix typings - resaleLicensePrice: rootStore?.licenseResalePrice, + resaleLicensePrice: rootStore?.licenseResalePrice || MIN_RESALE_PRICE, }, }); @@ -98,13 +98,22 @@ export const PriceStep = ({ nextStep, prevStep }: PriceStepProps) => { Минимальная стоимость {MIN_PRICE} TON. - Рекомендуемая стоимость {RECOMMENDED_PRICE} TON. + {/* Рекомендуемая стоимость {RECOMMENDED_PRICE} TON. */} + inputMode="decimal" + pattern="[0-9]*[.,]?[0-9]*" + {...form.register("price", { + onChange: (e) => { + const value = e.target.value; + if (!/^\d*[.,]?\d*$/.test(value)) { + e.target.value = value.replace(/[^\d.,]/g, ''); + } + } + })} + /> { + try { + if (!address) return false; + Address.parse(address); + return true; + } catch { + return false; + } +}; + export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => { const [impactOccurred] = useHapticFeedback(); const [isDeleteAllOpen, setDeleteAllOpen] = useState(false); const [isSpreadOpen, setSpreadOpen] = useState(false); + const [addressErrors, setAddressErrors] = useState>({}); const { royalty, setRoyalty, isPercentHintOpen, setPercentHintOpen } = useRootStore(); @@ -42,11 +55,23 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => { }; const handleWalletChange = (index: number, address: string) => { + const isValid = isValidTonAddress(address); + setAddressErrors({ + ...addressErrors, + [index]: !isValid + ? { + type: 'validation', + message: 'Неверный адрес TON' + } + : undefined + }); + const newRoyalty = royalty.map((member, i) => - i === index ? { ...member, address } : member, + i === index ? { ...member, address } : member ); setRoyalty(newRoyalty); }; + const handlePercentChange = (index: number, value: string) => { const percentNumber = parseInt(value, 10) || 0; @@ -67,20 +92,28 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => { const isValid = useMemo(() => { return ( - royalty.every((member) => member.address && member.value >= 0) && + royalty.every((member) => isValidTonAddress(member.address) && member.value >= 0) && royalty.reduce((acc, curr) => acc + curr.value, 0) === 100 ); }, [royalty]); const [tonConnectUI] = useTonConnectUI(); - // Устанавливаем адрес из tonConnectUI.account при загрузке страницы useEffect(() => { - console.log('tonconnectUI', tonConnectUI) - if (tonConnectUI.account) { - setRoyalty([{ address: tonConnectUI.account.address, value: 100 }]); + if (!tonConnectUI.account) return; + + if (royalty.length === 0) { + // First initialization with 100% + setRoyalty([{ + address: Address.parse(tonConnectUI.account.address).toString({ + bounceable: true, + urlSafe: true, + testOnly: false, + }), + value: 100 + }]); } - }, [tonConnectUI.account, setRoyalty]); + }, [tonConnectUI.account, setRoyalty, royalty]); return ( @@ -128,7 +161,7 @@ export const RoyaltyStep = ({ nextStep, prevStep }: RoyaltyStepProps) => { {royalty.map((member, index) => ( - + { value={member.address} onChange={(e) => handleWalletChange(index, e.target.value)} placeholder={"[ Введите адрес криптокошелька TON ]"} - /> + error={addressErrors[index]} + /> diff --git a/src/pages/view-content/index.tsx b/src/pages/view-content/index.tsx index 3808993..5a07966 100644 --- a/src/pages/view-content/index.tsx +++ b/src/pages/view-content/index.tsx @@ -2,7 +2,6 @@ import ReactPlayer from "react-player/lazy"; import { useTonConnectUI } from "@tonconnect/ui-react"; import { useWebApp } from "@vkruglikov/react-telegram-web-app"; -import { Button } from "~/shared/ui/button"; import { usePurchaseContent, useViewContent } from "~/shared/services/content"; import { fromNanoTON } from "~/shared/utils"; import {useCallback, useEffect, useMemo} from "react"; @@ -72,7 +71,43 @@ export const ViewContentPage = () => { }, []); - + useEffect(() => { + const mainButton = WebApp.MainButton; + const secondaryButton = WebApp.SecondaryButton; + + try { + // Set main button color + mainButton.color = '#e40615'; + mainButton.textColor = '#FFFFFF'; + + // Set secondary button color + secondaryButton.color = '#363636'; + secondaryButton.textColor = '#FFFFFF'; + if (!haveLicense) { + mainButton.text = `Купить за ${fromNanoTON(content?.data?.encrypted?.license?.resale?.price)} ТОН`; + mainButton.show(); + mainButton.onClick(handleBuyContent); + } else { + mainButton.hide(); + } + + secondaryButton.text = 'Загрузить свой контент'; + secondaryButton.show(); + secondaryButton.onClick(() => { + WebApp.openTelegramLink('https://t.me/MY_UploaderRobot'); + }); + + return () => { + mainButton.hide(); + mainButton.offClick(handleBuyContent); + secondaryButton.hide(); + secondaryButton.offClick(); + }; + } catch (error) { + console.error('Error setting up Telegram WebApp buttons:', error); + } + }, [content, haveLicense, WebApp, handleBuyContent]); + return ( {content?.data?.content_type.startsWith("audio") && content?.data?.display_options?.metadata?.image && ( @@ -111,7 +146,7 @@ export const ViewContentPage = () => { - {!haveLicense && { }} className={"mb-4 mt-[-20px] h-[48px] bg-darkred"} label={`Загрузить свой контент`} - /> + /> */} ); }; diff --git a/src/shared/libs/buffer/index.ts b/src/shared/libs/buffer/index.ts new file mode 100644 index 0000000..3189d30 --- /dev/null +++ b/src/shared/libs/buffer/index.ts @@ -0,0 +1,2 @@ +import { Buffer } from 'buffer'; +globalThis.Buffer = Buffer; \ No newline at end of file diff --git a/src/shared/services/content/index.ts b/src/shared/services/content/index.ts index 7b91558..bbad153 100644 --- a/src/shared/services/content/index.ts +++ b/src/shared/services/content/index.ts @@ -8,6 +8,7 @@ type UseCreateNewContentPayload = { content: string; image: string; description: string; + hashtags: string[]; price: string; resaleLicensePrice: string; // nanoTON bignum (default = 0) allowResale: boolean; diff --git a/src/shared/stores/root/index.ts b/src/shared/stores/root/index.ts index 2a0d84a..038e113 100644 --- a/src/shared/stores/root/index.ts +++ b/src/shared/stores/root/index.ts @@ -80,7 +80,7 @@ export const useRootStore = create((set) => ({ royalty: [{ address: "", value: 100 }], setRoyalty: (royalty) => set({ royalty }), - price: 0, + price: 0.15, setPrice: (price: number) => set({ price }), allowResale: false, diff --git a/src/shared/ui/hashtag-input/index.tsx b/src/shared/ui/hashtag-input/index.tsx index 33745dd..671b420 100644 --- a/src/shared/ui/hashtag-input/index.tsx +++ b/src/shared/ui/hashtag-input/index.tsx @@ -1,7 +1,6 @@ import { useState } from "react"; -import { WithContext as ReactTags } from "react-tag-input"; +import { WithContext as ReactTags, SEPARATORS } from "react-tag-input"; import { useRootStore } from "~/shared/stores/root"; - // English comment: no extra Tag interface, just cast to any export const HashtagInput = () => { const { hashtags, setHashtags } = useRootStore(); @@ -9,9 +8,7 @@ export const HashtagInput = () => { // English comment: local state as string[] for simplicity const [tags, setTags] = useState(hashtags); - const KeyCodes = { comma: 188, enter: 13 }; - const delimiters = [KeyCodes.comma, KeyCodes.enter]; - + const separators = [SEPARATORS.ENTER, SEPARATORS.COMMA] const handleDelete = (i: number) => { const newTags = tags.filter((_, index) => index !== i); setTags(newTags); @@ -20,20 +17,47 @@ export const HashtagInput = () => { // English comment: pass "any" to the function const handleAddition = (newTag: any) => { - // English comment: newTag might be { id, text, ... } from react-tag-input - const updatedTags = [...tags, newTag?.text || newTag?.id || ""]; + // Clean up text from commas and trim whitespace + const text = newTag?.text || newTag?.id || ""; + const cleanText = text.replace(/,/g, '').trim(); + + // Skip empty tags + if (!cleanText) return; + + const updatedTags = [...tags, cleanText]; setTags(updatedTags); setHashtags(updatedTags); }; + // Simulate Enter keypress for Android + const enterEvent = new KeyboardEvent('keydown', { + key: 'Enter', + code: 'Enter', + bubbles: true, + cancelable: true, + which: 13, + keyCode: 13, + }); + const handleKeyUp = (e: React.KeyboardEvent) => { + if (e.key === 'Unidentified') { + const lastChar = e.currentTarget.value.slice(-1); + if (lastChar === ',') { + e.currentTarget.dispatchEvent(enterEvent); + } + } + }; + return ( ({ id: t, text: t })) as any} - delimiters={delimiters as any} + separators={separators as any} handleDelete={handleDelete as any} handleAddition={handleAddition as any} allowDragDrop={false} - placeholder="[ enter a hashtag ]" + placeholder="[ введите тэги через запятую ]" + inputProps={{ + onKeyUp: handleKeyUp as any + }} /> ); }; diff --git a/vite.config.ts b/vite.config.ts index 64696ac..353f626 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,4 +4,19 @@ import TSPaths from "vite-tsconfig-paths"; export default defineConfig({ plugins: [react(), TSPaths()], -}); + define: { + global: 'globalThis', + }, + resolve: { + alias: { + buffer: 'buffer/', + } + }, + optimizeDeps: { + esbuildOptions: { + define: { + global: 'globalThis' + } + } + } +}); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e3f39f9..b76ae4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -225,10 +225,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@esbuild/darwin-arm64@0.19.12": +"@esbuild/win32-x64@0.19.12": version "0.19.12" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz" - integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g== + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz" + integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" @@ -381,10 +381,10 @@ resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz" integrity sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q== -"@rollup/rollup-darwin-arm64@4.12.0": +"@rollup/rollup-win32-x64-msvc@4.12.0": version "4.12.0" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz" - integrity sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ== + resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz" + integrity sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg== "@ton/core@^0.59.1": version "0.59.1" @@ -860,6 +860,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + big-integer@^1.6.16: version "1.6.52" resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz" @@ -916,6 +921,14 @@ browserslist@^4.22.2, browserslist@^4.23.0, "browserslist@>= 4.21.0": node-releases "^2.0.14" update-browserslist-db "^1.0.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" @@ -1569,11 +1582,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -1764,6 +1772,11 @@ hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0, ignore@^5.2.4: version "5.3.1" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"
Минимальная стоимость {MIN_PRICE} TON.
Рекомендуемая стоимость {RECOMMENDED_PRICE} TON.