Compare commits

...

15 Commits

Author SHA1 Message Date
muzam
027b2c8ed4 remove console log 2021-12-21 17:07:45 +05:30
muzam
b4ca360661 Implement read-only editors for some headers. 2021-12-16 22:30:03 +05:30
muzam
ad947be0bc Only fetch extra headers on template files. 2021-12-16 18:52:16 +05:30
muzam
f739d4da34 Fetch templates and header files according to selection. 2021-12-16 18:26:58 +05:30
Valtteri Karesto
fdb1eb01a4 Merge pull request #34 from eqlabs/feat/zip
Implemented download as zip.
2021-12-15 15:02:23 +02:00
Valtteri Karesto
920d359966 Merge pull request #38 from eqlabs/feat/controlled-dialog
Filename Dialog fixes and improvements.
2021-12-15 13:16:49 +02:00
muzam
9e1dbc8765 minor fixes 2021-12-15 15:49:55 +05:30
muzam
10ea77fd8d Error and loading states in download as zip. 2021-12-15 15:38:19 +05:30
muzam
50de7ebf15 Merge branch 'feat/controlled-dialog' into feat/zip 2021-12-14 22:19:05 +05:30
muzam
7db07e3f92 Merge branch 'main' into feat/controlled-dialog 2021-12-14 21:29:31 +05:30
Valtteri Karesto
6ad7c67672 hotfix: fixes faucet url 2021-12-14 16:36:37 +02:00
Valtteri Karesto
10f279a6b4 Merge pull request #33 from eqlabs/feat/add-language-client
Add example of language server
2021-12-14 16:17:16 +02:00
muzam
792c093cfd Input filename validation and default extension. 2021-12-14 16:43:43 +05:30
muzam
a11a641608 New file dialog confirms on pressing Enter. 2021-12-14 15:33:39 +05:30
muzam
8ac7e82221 Implemented download as zip 2021-12-13 16:21:28 +05:30
15 changed files with 335 additions and 198 deletions

View File

@@ -70,7 +70,7 @@ const StyledTitle = styled(DialogPrimitive.Title, {
}); });
const StyledDescription = styled(DialogPrimitive.Description, { const StyledDescription = styled(DialogPrimitive.Description, {
margin: "10px 0 20px", margin: "10px 0 10px",
color: "$mauve11", color: "$mauve11",
fontSize: 15, fontSize: 15,
lineHeight: 1.5, lineHeight: 1.5,

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useCallback } from "react";
import { import {
Plus, Plus,
Share, Share,
@@ -26,11 +26,7 @@ import NewWindow from "react-new-window";
import { signOut, useSession } from "next-auth/react"; import { signOut, useSession } from "next-auth/react";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import { import { createNewFile, syncToGist, updateEditorSettings, downloadAsZip } from "../state/actions";
createNewFile,
syncToGist,
updateEditorSettings,
} from "../state/actions";
import state from "../state"; import state from "../state";
import Box from "./Box"; import Box from "./Box";
import Button from "./Button"; import Button from "./Button";
@@ -46,6 +42,7 @@ import {
import Flex from "./Flex"; import Flex from "./Flex";
import Stack from "./Stack"; import Stack from "./Stack";
import Input from "./Input"; import Input from "./Input";
import Text from "./Text";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import { import {
AlertDialog, AlertDialog,
@@ -55,11 +52,22 @@ import {
AlertDialogCancel, AlertDialogCancel,
AlertDialogAction, AlertDialogAction,
} from "./AlertDialog"; } from "./AlertDialog";
import { styled } from "../stitches.config";
const DEFAULT_EXTENSION = ".c";
const ErrorText = styled(Text, {
color: "$red9",
mt: "$1",
display: "block",
});
const EditorNavigation = ({ showWat }: { showWat?: boolean }) => { const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
const snap = useSnapshot(state); const snap = useSnapshot(state);
const [createNewAlertOpen, setCreateNewAlertOpen] = useState(false); const [createNewAlertOpen, setCreateNewAlertOpen] = useState(false);
const [editorSettingsOpen, setEditorSettingsOpen] = useState(false); const [editorSettingsOpen, setEditorSettingsOpen] = useState(false);
const [isNewfileDialogOpen, setIsNewfileDialogOpen] = useState(false);
const [newfileError, setNewfileError] = useState<string | null>(null);
const [filename, setFilename] = useState(""); const [filename, setFilename] = useState("");
const { data: session, status } = useSession(); const { data: session, status } = useSession();
const [popup, setPopUp] = useState(false); const [popup, setPopUp] = useState(false);
@@ -69,6 +77,36 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
setPopUp(false); setPopUp(false);
} }
}, [session, popup]); }, [session, popup]);
// when filename changes, reset error
useEffect(() => {
setNewfileError(null);
}, [filename, setNewfileError]);
const validateFilename = useCallback(
(filename: string): { error: string | null } => {
if (snap.files.find(file => file.name === filename)) {
return { error: "Filename already exists." };
}
// More checks in future
return { error: null };
},
[snap.files]
);
const handleConfirm = useCallback(() => {
// add default extension in case omitted
let _filename = filename.includes(".") ? filename : filename + DEFAULT_EXTENSION;
const chk = validateFilename(_filename);
if (chk.error) {
setNewfileError(`Error: ${chk.error}`);
return;
}
setIsNewfileDialogOpen(false);
createNewFile(_filename);
setFilename("");
}, [filename, setIsNewfileDialogOpen, setFilename, validateFilename]);
const files = snap.files; const files = snap.files;
return ( return (
<Flex css={{ flexShrink: 0, gap: "$0" }}> <Flex css={{ flexShrink: 0, gap: "$0" }}>
@@ -101,9 +139,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
return ( return (
<Button <Button
size="sm" size="sm"
outline={ outline={showWat ? snap.activeWat !== index : snap.active !== index}
showWat ? snap.activeWat !== index : snap.active !== index
}
onClick={() => (state.active = index)} onClick={() => (state.active = index)}
key={file.name + index} key={file.name + index}
css={{ css={{
@@ -138,8 +174,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
// If deleted file is behind active tab // If deleted file is behind active tab
// we keep the current state otherwise // we keep the current state otherwise
// select previous file on the list // select previous file on the list
state.active = state.active = index > snap.active ? snap.active : snap.active - 1;
index > snap.active ? snap.active : snap.active - 1;
}} }}
> >
<X size="9px" weight="bold" /> <X size="9px" weight="bold" />
@@ -149,15 +184,10 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
); );
})} })}
{!showWat && ( {!showWat && (
<Dialog> <Dialog open={isNewfileDialogOpen} onOpenChange={setIsNewfileDialogOpen}>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button <Button ghost size="sm" css={{ alignItems: "center", px: "$2", mr: "$3" }}>
ghost <Plus size="16px" /> {snap.files.length === 0 && "Add new file"}
size="sm"
css={{ alignItems: "center", px: "$2", mr: "$3" }}
>
<Plus size="16px" />{" "}
{snap.files.length === 0 && "Add new file"}
</Button> </Button>
</DialogTrigger> </DialogTrigger>
<DialogContent> <DialogContent>
@@ -166,8 +196,14 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
<label>Filename</label> <label>Filename</label>
<Input <Input
value={filename} value={filename}
onChange={(e) => setFilename(e.target.value)} onChange={e => setFilename(e.target.value)}
onKeyPress={e => {
if (e.key === "Enter") {
handleConfirm();
}
}}
/> />
<ErrorText>{newfileError}</ErrorText>
</DialogDescription> </DialogDescription>
<Flex <Flex
@@ -180,18 +216,12 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
<DialogClose asChild> <DialogClose asChild>
<Button outline>Cancel</Button> <Button outline>Cancel</Button>
</DialogClose> </DialogClose>
<DialogClose asChild> <Button
<Button variant="primary"
variant="primary" onClick={handleConfirm}
onClick={() => { >
createNewFile(filename); Create file
// reset </Button>
setFilename("");
}}
>
Create file
</Button>
</DialogClose>
</Flex> </Flex>
<DialogClose asChild> <DialogClose asChild>
<Box css={{ position: "absolute", top: "$3", right: "$3" }}> <Box css={{ position: "absolute", top: "$3", right: "$3" }}>
@@ -211,9 +241,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
zIndex: 1, zIndex: 1,
}} }}
> >
<Container <Container css={{ width: "unset", display: "flex", alignItems: "center" }}>
css={{ width: "unset", display: "flex", alignItems: "center" }}
>
{status === "authenticated" ? ( {status === "authenticated" ? (
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
@@ -246,15 +274,10 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem disabled onClick={() => signOut()}> <DropdownMenuItem disabled onClick={() => signOut()}>
<User size="16px" /> {session?.user?.username} ( <User size="16px" /> {session?.user?.username} ({session?.user.name})
{session?.user.name})
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onClick={() => onClick={() => window.open(`http://gist.github.com/${session?.user.username}`)}
window.open(
`http://gist.github.com/${session?.user.username}`
)
}
> >
<ArrowSquareOut size="16px" /> <ArrowSquareOut size="16px" />
Go to your Gist Go to your Gist
@@ -268,12 +291,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
) : ( ) : (
<Button <Button outline size="sm" css={{ mr: "$3" }} onClick={() => setPopUp(true)}>
outline
size="sm"
css={{ mr: "$3" }}
onClick={() => setPopUp(true)}
>
<GithubLogo size="16px" /> Login <GithubLogo size="16px" /> Login
</Button> </Button>
)} )}
@@ -312,7 +330,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
}, },
}} }}
> >
<Button outline size="sm" css={{ alignItems: "center" }}> <Button isLoading={snap.zipLoading} onClick={downloadAsZip} outline size="sm" css={{ alignItems: "center" }}>
<DownloadSimple size="16px" /> <DownloadSimple size="16px" />
</Button> </Button>
<Button <Button
@@ -320,9 +338,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
size="sm" size="sm"
css={{ alignItems: "center" }} css={{ alignItems: "center" }}
onClick={() => { onClick={() => {
navigator.clipboard.writeText( navigator.clipboard.writeText(`${window.location.origin}/develop/${snap.gistId}`);
`${window.location.origin}/develop/${snap.gistId}`
);
toast.success("Copied share link to clipboard!"); toast.success("Copied share link to clipboard!");
}} }}
> >
@@ -352,7 +368,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
</Button> </Button>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem> <DropdownMenuItem disabled={snap.zipLoading} onClick={downloadAsZip}>
<DownloadSimple size="16px" /> Download as ZIP <DownloadSimple size="16px" /> Download as ZIP
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
@@ -367,9 +383,7 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
Copy share link to clipboard Copy share link to clipboard
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
disabled={ disabled={session?.user.username !== snap.gistOwner || !snap.gistId}
session?.user.username !== snap.gistOwner || !snap.gistId
}
onClick={() => { onClick={() => {
syncToGist(session); syncToGist(session);
}} }}
@@ -395,21 +409,15 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
</DropdownMenu> </DropdownMenu>
</Stack> </Stack>
{popup && !session ? ( {popup && !session ? <NewWindow center="parent" url="/sign-in" /> : null}
<NewWindow center="parent" url="/sign-in" />
) : null}
</Container> </Container>
</Flex> </Flex>
<AlertDialog <AlertDialog open={createNewAlertOpen} onOpenChange={value => setCreateNewAlertOpen(value)}>
open={createNewAlertOpen}
onOpenChange={(value) => setCreateNewAlertOpen(value)}
>
<AlertDialogContent> <AlertDialogContent>
<AlertDialogTitle>Are you sure?</AlertDialogTitle> <AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription> <AlertDialogDescription>
This action will create new <strong>public</strong> Github Gist from This action will create new <strong>public</strong> Github Gist from your current saved
your current saved files. You can delete gist anytime from your files. You can delete gist anytime from your GitHub Gists page.
GitHub Gists page.
</AlertDialogDescription> </AlertDialogDescription>
<Flex css={{ justifyContent: "flex-end", gap: "$3" }}> <Flex css={{ justifyContent: "flex-end", gap: "$3" }}>
<AlertDialogCancel asChild> <AlertDialogCancel asChild>
@@ -443,8 +451,8 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
type="number" type="number"
min="1" min="1"
value={editorSettings.tabSize} value={editorSettings.tabSize}
onChange={(e) => onChange={e =>
setEditorSettings((curr) => ({ setEditorSettings(curr => ({
...curr, ...curr,
tabSize: Number(e.target.value), tabSize: Number(e.target.value),
})) }))
@@ -454,18 +462,12 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
<Flex css={{ marginTop: 25, justifyContent: "flex-end", gap: "$3" }}> <Flex css={{ marginTop: 25, justifyContent: "flex-end", gap: "$3" }}>
<DialogClose asChild> <DialogClose asChild>
<Button <Button outline onClick={() => updateEditorSettings(editorSettings)}>
outline
onClick={() => updateEditorSettings(editorSettings)}
>
Cancel Cancel
</Button> </Button>
</DialogClose> </DialogClose>
<DialogClose asChild> <DialogClose asChild>
<Button <Button variant="primary" onClick={() => updateEditorSettings(editorSettings)}>
variant="primary"
onClick={() => updateEditorSettings(editorSettings)}
>
Save changes Save changes
</Button> </Button>
</DialogClose> </DialogClose>

View File

@@ -11,6 +11,7 @@ import Container from "./Container";
import dark from "../theme/editor/amy.json"; import dark from "../theme/editor/amy.json";
import light from "../theme/editor/xcode_default.json"; import light from "../theme/editor/xcode_default.json";
import { saveFile } from "../state/actions"; import { saveFile } from "../state/actions";
import { apiHeaderFiles } from "../state/constants";
import state from "../state"; import state from "../state";
import EditorNavigation from "./EditorNavigation"; import EditorNavigation from "./EditorNavigation";
@@ -26,12 +27,26 @@ loader.config({
}, },
}); });
const validateWritability = (editor: monaco.editor.IStandaloneCodeEditor) => {
const currPath = editor.getModel()?.uri.path;
if (apiHeaderFiles.find(h => currPath?.endsWith(h))) {
editor.updateOptions({ readOnly: true });
} else {
editor.updateOptions({ readOnly: false });
}
};
const HooksEditor = () => { const HooksEditor = () => {
const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>(); const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
const subscriptionRef = useRef<ReconnectingWebSocket | null>(null); const subscriptionRef = useRef<ReconnectingWebSocket | null>(null);
const snap = useSnapshot(state); const snap = useSnapshot(state);
const router = useRouter(); const router = useRouter();
const { theme } = useTheme(); const { theme } = useTheme();
useEffect(() => {
if (editorRef.current) validateWritability(editorRef.current);
}, [snap.active]);
useEffect(() => { useEffect(() => {
return () => { return () => {
subscriptionRef?.current?.close(); subscriptionRef?.current?.close();
@@ -58,9 +73,9 @@ const HooksEditor = () => {
language={snap.files?.[snap.active]?.language} language={snap.files?.[snap.active]?.language}
path={`file://tmp/c/${snap.files?.[snap.active]?.name}`} path={`file://tmp/c/${snap.files?.[snap.active]?.name}`}
defaultValue={snap.files?.[snap.active]?.content} defaultValue={snap.files?.[snap.active]?.content}
beforeMount={(monaco) => { beforeMount={monaco => {
if (!snap.editorCtx) { if (!snap.editorCtx) {
snap.files.forEach((file) => snap.files.forEach(file =>
monaco.editor.createModel( monaco.editor.createModel(
file.content, file.content,
file.language, file.language,
@@ -86,7 +101,7 @@ const HooksEditor = () => {
// listen when the web socket is opened // listen when the web socket is opened
listen({ listen({
webSocket: webSocket as WebSocket, webSocket: webSocket as WebSocket,
onConnection: (connection) => { onConnection: connection => {
// create and start the language client // create and start the language client
const languageClient = createLanguageClient(connection); const languageClient = createLanguageClient(connection);
const disposable = languageClient.start(); const disposable = languageClient.start();
@@ -125,12 +140,10 @@ const HooksEditor = () => {
enabled: true, enabled: true,
}, },
}); });
editor.addCommand( editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, saveFile();
() => { });
saveFile(); validateWritability(editor)
}
);
}} }}
theme={theme === "dark" ? "dark" : "light"} theme={theme === "dark" ? "dark" : "light"}
/> />
@@ -148,9 +161,7 @@ const HooksEditor = () => {
<Box css={{ display: "inline-flex", pl: "35px" }}> <Box css={{ display: "inline-flex", pl: "35px" }}>
<ArrowBendLeftUp size={30} /> <ArrowBendLeftUp size={30} />
</Box> </Box>
<Box <Box css={{ pl: "0px", pt: "15px", flex: 1, display: "inline-flex" }}>
css={{ pl: "0px", pt: "15px", flex: 1, display: "inline-flex" }}
>
<Text <Text
css={{ css={{
fontSize: "14px", fontSize: "14px",

View File

@@ -27,6 +27,7 @@ import {
DialogTrigger, DialogTrigger,
} from "./Dialog"; } from "./Dialog";
import PanelBox from "./PanelBox"; import PanelBox from "./PanelBox";
import { templateFileIds } from '../state/constants';
const Navigation = () => { const Navigation = () => {
const router = useRouter(); const router = useRouter();
@@ -82,12 +83,8 @@ const Navigation = () => {
<Spinner /> <Spinner />
) : ( ) : (
<> <>
<Heading css={{ lineHeight: 1 }}> <Heading css={{ lineHeight: 1 }}>{snap.files?.[0]?.name || "XRPL Hooks"}</Heading>
{snap.files?.[0]?.name || "XRPL Hooks"} <Text css={{ fontSize: "$xs", color: "$mauve10", lineHeight: 1 }}>
</Heading>
<Text
css={{ fontSize: "$xs", color: "$mauve10", lineHeight: 1 }}
>
{snap.files.length > 0 ? "Gist: " : "Playground"} {snap.files.length > 0 ? "Gist: " : "Playground"}
<Text css={{ color: "$mauve12" }}> <Text css={{ color: "$mauve12" }}>
{snap.files.length > 0 && {snap.files.length > 0 &&
@@ -99,10 +96,7 @@ const Navigation = () => {
</Flex> </Flex>
{router.isReady && ( {router.isReady && (
<ButtonGroup css={{ marginLeft: "auto" }}> <ButtonGroup css={{ marginLeft: "auto" }}>
<Dialog <Dialog open={snap.mainModalOpen} onOpenChange={open => (state.mainModalOpen = open)}>
open={snap.mainModalOpen}
onOpenChange={(open) => (state.mainModalOpen = open)}
>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button outline> <Button outline>
<FolderOpen size="15px" /> <FolderOpen size="15px" />
@@ -163,12 +157,9 @@ const Navigation = () => {
mb: "$7", mb: "$7",
}} }}
> >
Hooks add smart contract functionality to the XRP Hooks add smart contract functionality to the XRP Ledger.
Ledger.
</Text> </Text>
<Flex <Flex css={{ flexDirection: "column", gap: "$2", mt: "$2" }}>
css={{ flexDirection: "column", gap: "$2", mt: "$2" }}
>
<Text <Text
css={{ css={{
display: "inline-flex", display: "inline-flex",
@@ -253,43 +244,29 @@ const Navigation = () => {
}, },
}} }}
> >
<PanelBox <PanelBox as="a" href={`/develop/${templateFileIds.starter}`}>
as="a"
href="/develop/be088224fb37c0075e84491da0e602c1"
>
<Heading>Starter</Heading> <Heading>Starter</Heading>
<Text> <Text>Just an empty starter with essential imports</Text>
Just an empty starter with essential imports
</Text>
</PanelBox> </PanelBox>
<PanelBox <PanelBox as="a" href={`/develop/${templateFileIds.starter}`}>
as="a"
href="/develop/be088224fb37c0075e84491da0e602c1"
>
<Heading>Firewall</Heading> <Heading>Firewall</Heading>
<Text> <Text>This Hook essentially checks a blacklist of accounts</Text>
This Hook essentially checks a blacklist of accounts
</Text>
</PanelBox> </PanelBox>
<PanelBox <PanelBox as="a" href={`/develop/${templateFileIds.accept}`}>
as="a"
href="/develop/be088224fb37c0075e84491da0e602c1"
>
<Heading>Accept</Heading> <Heading>Accept</Heading>
<Text> <Text>This hook just accepts any transaction coming through it</Text>
This hook just accepts any transaction coming through
it
</Text>
</PanelBox> </PanelBox>
<PanelBox <PanelBox as="a" href={`/develop/${templateFileIds.notary}`}>
as="a" <Heading>Notary</Heading>
href="/develop/be088224fb37c0075e84491da0e602c1" <Text>Collecting signatures for multi-sign transactions</Text>
> </PanelBox>
<Heading>Accept</Heading> <PanelBox as="a" href={`/develop/${templateFileIds.carbon}`}>
<Text> <Heading>Carbon</Heading>
This hook just accepts any transaction coming through <Text>Send a percentage of sum to an address</Text>
it </PanelBox>
</Text> <PanelBox as="a" href={`/develop/${templateFileIds.peggy}`}>
<Heading>Peggy</Heading>
<Text>An oracle based stabe coin hook</Text>
</PanelBox> </PanelBox>
</Flex> </Flex>
</Flex> </Flex>
@@ -336,42 +313,18 @@ const Navigation = () => {
}} }}
> >
<ButtonGroup> <ButtonGroup>
<Link <Link href={gistId ? `/develop/${gistId}` : "/develop"} passHref shallow>
href={gistId ? `/develop/${gistId}` : "/develop"} <Button as="a" outline={!router.pathname.includes("/develop")} uppercase>
passHref
shallow
>
<Button
as="a"
outline={!router.pathname.includes("/develop")}
uppercase
>
Develop Develop
</Button> </Button>
</Link> </Link>
<Link <Link href={gistId ? `/deploy/${gistId}` : "/deploy"} passHref shallow>
href={gistId ? `/deploy/${gistId}` : "/deploy"} <Button as="a" outline={!router.pathname.includes("/deploy")} uppercase>
passHref
shallow
>
<Button
as="a"
outline={!router.pathname.includes("/deploy")}
uppercase
>
Deploy Deploy
</Button> </Button>
</Link> </Link>
<Link <Link href={gistId ? `/test/${gistId}` : "/test"} passHref shallow>
href={gistId ? `/test/${gistId}` : "/test"} <Button as="a" outline={!router.pathname.includes("/test")} uppercase>
passHref
shallow
>
<Button
as="a"
outline={!router.pathname.includes("/test")}
uppercase
>
Test Test
</Button> </Button>
</Link> </Link>

View File

@@ -20,6 +20,8 @@
"@radix-ui/react-dropdown-menu": "^0.1.1", "@radix-ui/react-dropdown-menu": "^0.1.1",
"@radix-ui/react-id": "^0.1.1", "@radix-ui/react-id": "^0.1.1",
"@stitches/react": "^1.2.6-0", "@stitches/react": "^1.2.6-0",
"file-saver": "^2.0.5",
"jszip": "^3.7.1",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"dinero.js": "^1.9.1", "dinero.js": "^1.9.1",
"monaco-editor": "^0.30.1", "monaco-editor": "^0.30.1",
@@ -45,9 +47,10 @@
"vscode-uri": "^3.0.2", "vscode-uri": "^3.0.2",
"wabt": "1.0.16", "wabt": "1.0.16",
"xrpl-accountlib": "^1.2.3", "xrpl-accountlib": "^1.2.3",
"xrpl-client": "^1.9.2" "xrpl-client": "^1.9.3"
}, },
"devDependencies": { "devDependencies": {
"@types/file-saver": "^2.0.4",
"@types/dinero.js": "^1.9.0", "@types/dinero.js": "^1.9.0",
"@types/pako": "^1.0.2", "@types/pako": "^1.0.2",
"@types/react": "17.0.31", "@types/react": "17.0.31",

View File

@@ -1,3 +1,4 @@
import Router from "next/router";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import state, { FaucetAccountRes } from '../index'; import state, { FaucetAccountRes } from '../index';
@@ -31,30 +32,35 @@ export const addFaucetAccount = async (showToast: boolean = false) => {
if (state.accounts.length > 4) { if (state.accounts.length > 4) {
return toast.error("You can only have maximum 5 accounts"); return toast.error("You can only have maximum 5 accounts");
} }
const toastId = showToast ? toast.loading("Creating account") : ""; if (typeof window !== 'undefined') {
const res = await fetch(`${process.env.NEXT_PUBLIC_SITE_URL}/api/faucet`, {
method: "POST",
}); const toastId = showToast ? toast.loading("Creating account") : "";
const json: FaucetAccountRes | { error: string } = await res.json(); console.log(Router)
if ("error" in json) { const res = await fetch(`${window.location.origin}/api/faucet`, {
if (showToast) { method: "POST",
return toast.error(json.error, { id: toastId });
} else {
return;
}
} else {
if (showToast) {
toast.success("New account created", { id: toastId });
}
state.accounts.push({
name: names[state.accounts.length],
xrp: (json.xrp || 0 * 1000000).toString(),
address: json.address,
secret: json.secret,
sequence: 1,
hooks: [],
isLoading: false,
}); });
const json: FaucetAccountRes | { error: string } = await res.json();
if ("error" in json) {
if (showToast) {
return toast.error(json.error, { id: toastId });
} else {
return;
}
} else {
if (showToast) {
toast.success("New account created", { id: toastId });
}
state.accounts.push({
name: names[state.accounts.length],
xrp: (json.xrp || 0 * 1000000).toString(),
address: json.address,
secret: json.secret,
sequence: 1,
hooks: [],
isLoading: false,
});
}
} }
}; };

View File

@@ -0,0 +1,19 @@
import { createZip } from '../../utils/zip';
import { guessZipFileName } from '../../utils/helpers';
import state from '..'
import toast from 'react-hot-toast';
export const downloadAsZip = async () => {
try {
state.zipLoading = true
// TODO do something about file/gist loading state
const files = state.files.map(({ name, content }) => ({ name, content }));
const zipped = await createZip(files);
const zipFileName = guessZipFileName(files);
zipped.saveFile(zipFileName);
} catch (error) {
toast.error('Error occured while creating zip file, try again later')
} finally {
state.zipLoading = false
}
};

View File

@@ -1,6 +1,8 @@
import { Octokit } from "@octokit/core"; import { Octokit } from "@octokit/core";
import Router from "next/router"; import Router from "next/router";
import state from '../index'; import state from '../index';
import { templateFileIds } from '../constants';
const octokit = new Octokit(); const octokit = new Octokit();
@@ -17,6 +19,17 @@ export const fetchFiles = (gistId: string) => {
octokit octokit
.request("GET /gists/{gist_id}", { gist_id: gistId }) .request("GET /gists/{gist_id}", { gist_id: gistId })
.then(res => {
if (!Object.values(templateFileIds).includes(gistId)) {
return res
}
// in case of templates, fetch header file(s) and append to res
return octokit.request("GET /gists/{gist_id}", { gist_id: templateFileIds.headers }).then(({ data: { files: headerFiles } }) => {
const files = { ...res.data.files, ...headerFiles }
res.data.files = files
return res
})
})
.then((res) => { .then((res) => {
if (res.data.files && Object.keys(res.data.files).length > 0) { if (res.data.files && Object.keys(res.data.files).length > 0) {
const files = Object.keys(res.data.files).map((filename) => ({ const files = Object.keys(res.data.files).map((filename) => ({
@@ -44,6 +57,7 @@ export const fetchFiles = (gistId: string) => {
state.loading = false; state.loading = false;
}) })
.catch((err) => { .catch((err) => {
// console.error(err)
state.loading = false; state.loading = false;
state.logs.push({ state.logs.push({
type: "error", type: "error",

View File

@@ -7,6 +7,7 @@ import { importAccount } from "./importAccount";
import { saveFile } from "./saveFile"; import { saveFile } from "./saveFile";
import { syncToGist } from "./syncToGist"; import { syncToGist } from "./syncToGist";
import { updateEditorSettings } from "./updateEditorSettings"; import { updateEditorSettings } from "./updateEditorSettings";
import { downloadAsZip } from "./downloadAsZip";
export { export {
addFaucetAccount, addFaucetAccount,
@@ -17,5 +18,6 @@ export {
importAccount, importAccount,
saveFile, saveFile,
syncToGist, syncToGist,
updateEditorSettings updateEditorSettings,
downloadAsZip
}; };

1
state/constants/index.ts Normal file
View File

@@ -0,0 +1 @@
export * from './templates'

View File

@@ -0,0 +1,11 @@
export const templateFileIds = {
'starter': '1d14e51e2e02dc0a508cb0733767a914', // TODO currently same as accept
'accept': '1d14e51e2e02dc0a508cb0733767a914',
'firewall': 'bcd6d0c0fcbe52545ddb802481ff9d26',
'notary': 'a789c75f591eeab7932fd702ed8cf9ea',
'carbon': '43925143fa19735d8c6505c34d3a6a47',
'peggy': 'ceaf352e2a65741341033ab7ef05c448',
'headers': '9b448e8a55fab11ef5d1274cb59f9cf3'
}
export const apiHeaderFiles = ['hookapi.h', 'sfcodes.h', 'hookmacro.h']

View File

@@ -45,6 +45,7 @@ export interface IState {
activeWat: number; activeWat: number;
loading: boolean; loading: boolean;
gistLoading: boolean; gistLoading: boolean;
zipLoading: boolean;
compiling: boolean; compiling: boolean;
logs: ILog[]; logs: ILog[];
deployLogs: ILog[]; deployLogs: ILog[];
@@ -59,7 +60,7 @@ export interface IState {
} }
// let localStorageState: null | string = null; // let localStorageState: null | string = null;
let initialState = { let initialState: IState = {
files: [], files: [],
active: 0, active: 0,
activeWat: 0, activeWat: 0,
@@ -72,6 +73,7 @@ let initialState = {
gistOwner: undefined, gistOwner: undefined,
gistName: undefined, gistName: undefined,
gistLoading: false, gistLoading: false,
zipLoading: false,
editorSettings: { editorSettings: {
tabSize: 2, tabSize: 2,
}, },

9
utils/helpers.ts Normal file
View File

@@ -0,0 +1,9 @@
interface File {
name: string
}
export const guessZipFileName = (files: File[]) => {
let parts = (files.filter(f => f.name.endsWith('.c'))[0]?.name || 'hook').split('.')
parts = parts.length > 1 ? parts.slice(0, -1) : parts
return parts.join('')
}

32
utils/zip.ts Normal file
View File

@@ -0,0 +1,32 @@
import JSZip, { JSZipFileOptions } from 'jszip'
import { saveAs } from 'file-saver'
interface File {
name: string
content: any
options?: JSZipFileOptions
}
interface Zipped {
saveFile: (filename: string) => void
data: Blob
}
export const createZip = async (files: File[]): Promise<Zipped> => {
const zip = new JSZip()
files.forEach(({ name, content, options }) => {
zip.file(name, content, options)
})
const data = await zip.generateAsync({ type: "blob" })
return {
saveFile: (filename: string) =>
saveAs(data, filename),
data
}
}

View File

@@ -809,6 +809,11 @@
resolved "https://registry.yarnpkg.com/@types/dinero.js/-/dinero.js-1.9.0.tgz#e11356764339e3d361d38bd54910282b106dc321" resolved "https://registry.yarnpkg.com/@types/dinero.js/-/dinero.js-1.9.0.tgz#e11356764339e3d361d38bd54910282b106dc321"
integrity sha512-H2XdE6N/A2wJ/TJhGqeHDMUhCaey2R/Lcq9ichGBncKsFGvqrroXZWPNdDkCcgQOBPoCD4n9QuSBUC/35wuJiw== integrity sha512-H2XdE6N/A2wJ/TJhGqeHDMUhCaey2R/Lcq9ichGBncKsFGvqrroXZWPNdDkCcgQOBPoCD4n9QuSBUC/35wuJiw==
"@types/file-saver@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.4.tgz#aaf9b96296150d737b2fefa535ced05ed8013d84"
integrity sha512-sPZYQEIF/SOnLAvaz9lTuydniP+afBMtElRTdYkeV1QtEgvtJ7qolCPjly6O32QI8CbEmP5O/fztMXEDWfEcrg==
"@types/json5@^0.0.29": "@types/json5@^0.0.29":
version "0.0.29" version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -1516,6 +1521,11 @@ core-js@^2.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
create-ecdh@^4.0.0: create-ecdh@^4.0.0:
version "4.0.4" version "4.0.4"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e"
@@ -2157,6 +2167,11 @@ file-entry-cache@^6.0.1:
dependencies: dependencies:
flat-cache "^3.0.4" flat-cache "^3.0.4"
file-saver@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
file-uri-to-path@1.0.0: file-uri-to-path@1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@@ -2481,6 +2496,11 @@ image-size@1.0.0:
dependencies: dependencies:
queue "6.0.2" queue "6.0.2"
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
import-fresh@^3.0.0, import-fresh@^3.2.1: import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@@ -2700,6 +2720,11 @@ is-wsl@^2.1.1:
dependencies: dependencies:
is-docker "^2.0.0" is-docker "^2.0.0"
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isexe@^2.0.0: isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -2790,6 +2815,16 @@ jsonwebtoken@^8.5.1:
array-includes "^3.1.3" array-includes "^3.1.3"
object.assign "^4.1.2" object.assign "^4.1.2"
jszip@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9"
integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==
dependencies:
lie "~3.3.0"
pako "~1.0.2"
readable-stream "~2.3.6"
set-immediate-shim "~1.0.1"
jwa@^1.4.1: jwa@^1.4.1:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
@@ -2834,6 +2869,13 @@ levn@^0.4.1:
prelude-ls "^1.2.1" prelude-ls "^1.2.1"
type-check "~0.4.0" type-check "~0.4.0"
lie@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
dependencies:
immediate "~3.0.5"
loader-utils@1.2.3: loader-utils@1.2.3:
version "1.2.3" version "1.2.3"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
@@ -3365,7 +3407,7 @@ pako@^2.0.4:
resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d" resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d"
integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg== integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==
pako@~1.0.5: pako@~1.0.2, pako@~1.0.5:
version "1.0.11" version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@@ -3523,6 +3565,11 @@ pretty-format@^3.8.0:
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385"
integrity sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U= integrity sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U=
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process@0.11.10: process@0.11.10:
version "0.11.10" version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@@ -3712,6 +3759,19 @@ readable-stream@^3.5.0, readable-stream@^3.6.0:
string_decoder "^1.1.1" string_decoder "^1.1.1"
util-deprecate "^1.0.1" util-deprecate "^1.0.1"
readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readdirp@~3.5.0: readdirp@~3.5.0:
version "3.5.0" version "3.5.0"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
@@ -3927,7 +3987,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2,
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.1: safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2" version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
@@ -3962,6 +4022,11 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5:
dependencies: dependencies:
lru-cache "^6.0.0" lru-cache "^6.0.0"
set-immediate-shim@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=
setimmediate@^1.0.4: setimmediate@^1.0.4:
version "1.0.5" version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
@@ -4152,6 +4217,13 @@ string_decoder@1.3.0, string_decoder@^1.1.1:
dependencies: dependencies:
safe-buffer "~5.2.0" safe-buffer "~5.2.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
@@ -4428,7 +4500,7 @@ utf-8-validate@^5.0.2:
dependencies: dependencies:
node-gyp-build "^4.3.0" node-gyp-build "^4.3.0"
util-deprecate@^1.0.1: util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
@@ -4642,10 +4714,10 @@ xrpl-accountlib@^1.2.3:
xrpl-secret-numbers "^0.3.3" xrpl-secret-numbers "^0.3.3"
xrpl-sign-keypairs "^2.0.0" xrpl-sign-keypairs "^2.0.0"
xrpl-client@^1.9.2: xrpl-client@^1.9.3:
version "1.9.2" version "1.9.3"
resolved "https://registry.yarnpkg.com/xrpl-client/-/xrpl-client-1.9.2.tgz#c018510b050e678e09b8640533a57c50d4e586e9" resolved "https://registry.yarnpkg.com/xrpl-client/-/xrpl-client-1.9.3.tgz#1f2c17f7677d271a854e74d6035d6334cacf1629"
integrity sha512-foFrFqfYxpkj8La9k1G9ZJEbVOHJpvIIt0koNaw/3nlTUUnbyTENtr112CnHEh+z2JMqJxBB9JpmZavGDhMlKg== integrity sha512-TouyBeXuDXZWvO+4HrlvfrVtoXXyi9ny4+vpZoMCd2EbljsdFFTU6ujAqu81BvujkathKMTHiB81cR1bTL8ypw==
dependencies: dependencies:
debug "^4.1.1" debug "^4.1.1"
websocket "^1.0.34" websocket "^1.0.34"