forked from cerc-io/snowballtools-base
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1bb778699 |
@@ -19,7 +19,6 @@
|
||||
"cors": "^2.8.5",
|
||||
"debug": "^4.3.1",
|
||||
"express": "^4.18.2",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-session": "^1.18.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"graphql": "^16.8.1",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'express-async-errors';
|
||||
import 'reflect-metadata';
|
||||
import debug from 'debug';
|
||||
import fs from 'fs';
|
||||
|
||||
@@ -5,16 +5,6 @@ import { authenticateUser, createUser } from '../turnkey-backend';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post('/accesscode', async (req, res) => {
|
||||
console.log('Access Code', req.body);
|
||||
const { accesscode } = req.body;
|
||||
if (accesscode === '444444') {
|
||||
return res.send({ isValid: true });
|
||||
} else {
|
||||
return res.sendStatus(204);
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Turnkey
|
||||
//
|
||||
@@ -29,7 +19,6 @@ router.get('/registration/:email', async (req, res) => {
|
||||
});
|
||||
|
||||
router.post('/register', async (req, res) => {
|
||||
console.log('Register', req.body);
|
||||
const { email, challenge, attestation } = req.body;
|
||||
const user = await createUser(req.app.get('service'), {
|
||||
challenge,
|
||||
@@ -42,7 +31,6 @@ router.post('/register', async (req, res) => {
|
||||
});
|
||||
|
||||
router.post('/authenticate', async (req, res) => {
|
||||
console.log('Authenticate', req.body);
|
||||
const { signedWhoamiRequest } = req.body;
|
||||
const user = await authenticateUser(
|
||||
req.app.get('service'),
|
||||
@@ -78,10 +66,10 @@ router.post('/validate', async (req, res) => {
|
||||
}
|
||||
const newUser = await service.createUser({
|
||||
ethAddress: data.address,
|
||||
email: '',
|
||||
name: '',
|
||||
subOrgId: '',
|
||||
turnkeyWalletId: '',
|
||||
email: data.address,
|
||||
name: data.address,
|
||||
subOrgId: data.address,
|
||||
turnkeyWalletId: data.address, // TODO: fix fields
|
||||
});
|
||||
req.session.userId = newUser.id;
|
||||
} else if (action === 'login') {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Router } from 'express';
|
||||
const router = Router();
|
||||
|
||||
router.get('/version', async (req, res) => {
|
||||
return res.send({ version: '0.0.7' });
|
||||
return res.send({ version: '0.0.2' });
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -112,11 +112,6 @@ export const createAndStartServer = async (
|
||||
app.use('/api/github', githubRouter);
|
||||
app.use('/staging', stagingRouter);
|
||||
|
||||
app.use((err: any, req: any, res: any, next: any) => {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: err.message });
|
||||
});
|
||||
|
||||
httpServer.listen(port, host, () => {
|
||||
log(`Server is listening on ${host}:${port}${server.graphqlPath}`);
|
||||
});
|
||||
|
||||
@@ -414,6 +414,9 @@ export class Service {
|
||||
if (!user) {
|
||||
user = await this.db.addUser({
|
||||
email: data.email,
|
||||
ethAddress: data.email,
|
||||
subOrgId: data.email,
|
||||
turnkeyWalletId: data.email,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ services:
|
||||
restEndpoint: 'http://console.laconic.com:1317'
|
||||
gqlEndpoint: 'http://console.laconic.com:9473/api'
|
||||
userKey: 87d00f66a73e2ca428adeb49ba9164d0ad9a87edc60e33d46ad3031b9c5701fe
|
||||
bondId: 89c75c7bc5759861d10285aff6f9e7227d6855e446b77ad5d8324822dfec7deb
|
||||
bondId: 098c906850b87412f02200e41f449bc79e055eab77acfef32c0b22443bb46661
|
||||
chainId: laconic_9000-1
|
||||
gas: 1200000
|
||||
gas: 550000
|
||||
fees: 200000aphoton
|
||||
|
||||
@@ -64,13 +64,7 @@ echo "Files generated successfully."
|
||||
RECORD_FILE=records/application-record.yml
|
||||
|
||||
# Publish ApplicationRecord
|
||||
publish_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to publish record"
|
||||
exit $rc
|
||||
fi
|
||||
RECORD_ID=$(echo $publish_response | jq -r '.id')
|
||||
RECORD_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
echo "ApplicationRecord published"
|
||||
echo $RECORD_ID
|
||||
|
||||
@@ -79,36 +73,15 @@ REGISTRY_APP_CRN="crn://snowballtools/applications/snowballtools-base-frontend"
|
||||
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${PACKAGE_VERSION}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set name: $REGISTRY_APP_CRN@${PACKAGE_VERSION}"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${LATEST_HASH}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set hash"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
# Set name if latest release
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set release"
|
||||
exit $rc
|
||||
fi
|
||||
echo "$REGISTRY_APP_CRN set for ApplicationRecord"
|
||||
|
||||
# Check if record found for REGISTRY_APP_CRN
|
||||
query_response=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN")
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query name"
|
||||
exit $rc
|
||||
fi
|
||||
APP_RECORD=$(echo $query_response | jq '.[0]')
|
||||
APP_RECORD=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN" | jq '.[0]')
|
||||
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
|
||||
echo "No record found for $REGISTRY_APP_CRN."
|
||||
exit 1
|
||||
@@ -117,11 +90,6 @@ fi
|
||||
RECORD_FILE=records/application-deployment-request.yml
|
||||
|
||||
sleep 2
|
||||
deployment_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query deployment request"
|
||||
exit $rc
|
||||
fi
|
||||
DEPLOYMENT_REQUEST_ID=$(echo $deployment_response | jq -r '.id')
|
||||
DEPLOYMENT_REQUEST_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
echo "ApplicationDeploymentRequest published"
|
||||
echo $DEPLOYMENT_REQUEST_ID
|
||||
|
||||
@@ -44,8 +44,8 @@ record:
|
||||
LACONIC_HOSTED_CONFIG_lit_relay_api_key: 15DDD969-E75F-404D-AAD9-58A37C4FD354_snowball
|
||||
LACONIC_HOSTED_CONFIG_aplchemy_api_key: THvPart_gqI5x02RNYSBntlmwA66I_qc
|
||||
LACONIC_HOSTED_CONFIG_bugsnag_api_key: 8c480cd5386079f9dd44f9581264a073
|
||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: dashboard.staging.apps.snowballtools.com
|
||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
|
||||
LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: localhost
|
||||
LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com/
|
||||
LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
|
||||
meta:
|
||||
note: Added by Snowball @ $CURRENT_DATE_TIME
|
||||
@@ -70,13 +70,7 @@ echo "Files generated successfully."
|
||||
RECORD_FILE=staging-records/application-record.yml
|
||||
|
||||
# Publish ApplicationRecord
|
||||
publish_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to publish record"
|
||||
exit $rc
|
||||
fi
|
||||
RECORD_ID=$(echo $publish_response | jq -r '.id')
|
||||
RECORD_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
echo "ApplicationRecord published"
|
||||
echo $RECORD_ID
|
||||
|
||||
@@ -85,36 +79,15 @@ REGISTRY_APP_CRN="crn://staging-snowballtools/applications/staging-snowballtools
|
||||
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${PACKAGE_VERSION}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set name: $REGISTRY_APP_CRN@${PACKAGE_VERSION}"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN@${LATEST_HASH}" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set hash"
|
||||
exit $rc
|
||||
fi
|
||||
sleep 2
|
||||
# Set name if latest release
|
||||
yarn --silent laconic -c $CONFIG_FILE cns name set "$REGISTRY_APP_CRN" "$RECORD_ID"
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to set release"
|
||||
exit $rc
|
||||
fi
|
||||
echo "$REGISTRY_APP_CRN set for ApplicationRecord"
|
||||
|
||||
# Check if record found for REGISTRY_APP_CRN
|
||||
query_response=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN")
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query name"
|
||||
exit $rc
|
||||
fi
|
||||
APP_RECORD=$(echo $query_response | jq '.[0]')
|
||||
APP_RECORD=$(yarn --silent laconic -c $CONFIG_FILE cns name resolve "$REGISTRY_APP_CRN" | jq '.[0]')
|
||||
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
|
||||
echo "No record found for $REGISTRY_APP_CRN."
|
||||
exit 1
|
||||
@@ -123,11 +96,6 @@ fi
|
||||
RECORD_FILE=staging-records/application-deployment-request.yml
|
||||
|
||||
sleep 2
|
||||
deployment_response=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE)
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "FATAL: Failed to query deployment request"
|
||||
exit $rc
|
||||
fi
|
||||
DEPLOYMENT_REQUEST_ID=$(echo $deployment_response | jq -r '.id')
|
||||
DEPLOYMENT_REQUEST_ID=$(yarn --silent laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE | jq -r '.id')
|
||||
echo "ApplicationDeploymentRequest published"
|
||||
echo $DEPLOYMENT_REQUEST_ID
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
|
||||
import Projects from './pages/org-slug';
|
||||
@@ -11,8 +10,8 @@ import ProjectSearchLayout from './layouts/ProjectSearch';
|
||||
import Index from './pages';
|
||||
import AuthPage from './pages/AuthPage';
|
||||
import { DashboardLayout } from './pages/org-slug/layout';
|
||||
import { useEffect } from 'react';
|
||||
import Web3Provider from 'context/Web3Provider';
|
||||
import { baseUrl } from 'utils/constants';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -60,7 +59,7 @@ function App() {
|
||||
// Hacky way of checking session
|
||||
// TODO: Handle redirect backs
|
||||
useEffect(() => {
|
||||
fetch(`${baseUrl}/auth/session`, {
|
||||
fetch(`${import.meta.env.VITE_SERVER_URL}/auth/session`, {
|
||||
credentials: 'include',
|
||||
}).then((res) => {
|
||||
if (res.status !== 200) {
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import {
|
||||
VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO,
|
||||
VITE_GITHUB_PWA_TEMPLATE_REPO,
|
||||
} from 'utils/constants';
|
||||
|
||||
export default [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Progressive Web App (PWA)',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
repoFullName: `${import.meta.env.VITE_GITHUB_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Image Upload PWA',
|
||||
icon: 'pwa',
|
||||
repoFullName: `${VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
repoFullName: `${import.meta.env.VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO}`,
|
||||
isComingSoon: false,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -14,10 +14,11 @@ import { useToast } from '../../shared/Toast';
|
||||
import { IconWithFrame } from '../../shared/IconWithFrame';
|
||||
import { Heading } from '../../shared/Heading';
|
||||
import { MockConnectGitCard } from './MockConnectGitCard';
|
||||
import { VITE_GITHUB_CLIENT_ID } from 'utils/constants';
|
||||
|
||||
const SCOPES = 'repo user';
|
||||
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${VITE_GITHUB_CLIENT_ID}&scope=${encodeURIComponent(SCOPES)}`;
|
||||
const GITHUB_OAUTH_URL = `https://github.com/login/oauth/authorize?client_id=${
|
||||
import.meta.env.VITE_GITHUB_CLIENT_ID
|
||||
}&scope=${encodeURIComponent(SCOPES)}`;
|
||||
|
||||
interface ConnectAccountInterface {
|
||||
onAuth: (token: string) => void;
|
||||
|
||||
+37
-27
@@ -1,8 +1,13 @@
|
||||
import { CopyBlock, atomOneLight } from 'react-code-blocks';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Modal } from 'components/shared/Modal';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
} from '@snowballtools/material-tailwind-react-fork';
|
||||
|
||||
interface AssignDomainProps {
|
||||
open: boolean;
|
||||
@@ -11,31 +16,36 @@ interface AssignDomainProps {
|
||||
|
||||
const AssignDomainDialog = ({ open, handleOpen }: AssignDomainProps) => {
|
||||
return (
|
||||
<Modal open={open} onOpenChange={handleOpen}>
|
||||
<Modal.Content>
|
||||
<Modal.Header>Assign Domain</Modal.Header>
|
||||
<Modal.Body>
|
||||
In order to assign a domain to your production deployments, configure
|
||||
it in the{' '}
|
||||
{/* TODO: Fix selection of project settings tab on navigation to domains */}
|
||||
<Link to="../settings/domains" className="text-light-blue-800 inline">
|
||||
project settings{' '}
|
||||
</Link>
|
||||
(recommended). If you want to assign to this specific deployment,
|
||||
however, you can do so using our command-line interface:
|
||||
{/* https://github.com/rajinwonderland/react-code-blocks/issues/138 */}
|
||||
<CopyBlock
|
||||
text="snowball alias <deployment> <domain>"
|
||||
language=""
|
||||
showLineNumbers={false}
|
||||
theme={atomOneLight}
|
||||
/>
|
||||
</Modal.Body>
|
||||
<Modal.Footer className="flex justify-start">
|
||||
<Button onClick={handleOpen}>Okay</Button>
|
||||
</Modal.Footer>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
<Dialog open={open} handler={handleOpen}>
|
||||
<DialogHeader>Assign Domain</DialogHeader>
|
||||
<DialogBody>
|
||||
In order to assign a domain to your production deployments, configure it
|
||||
in the{' '}
|
||||
{/* TODO: Fix selection of project settings tab on navigation to domains */}
|
||||
<Link to="../settings/domains" className="text-light-blue-800 inline">
|
||||
project settings{' '}
|
||||
</Link>
|
||||
(recommended). If you want to assign to this specific deployment,
|
||||
however, you can do so using our command-line interface:
|
||||
{/* https://github.com/rajinwonderland/react-code-blocks/issues/138 */}
|
||||
<CopyBlock
|
||||
text="snowball alias <deployment> <domain>"
|
||||
language=""
|
||||
showLineNumbers={false}
|
||||
theme={atomOneLight}
|
||||
/>
|
||||
</DialogBody>
|
||||
<DialogFooter className="flex justify-start">
|
||||
<Button
|
||||
className="rounded-3xl"
|
||||
variant="gradient"
|
||||
color="blue"
|
||||
onClick={handleOpen}
|
||||
>
|
||||
<span>Okay</span>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { useState, ComponentPropsWithRef } from 'react';
|
||||
|
||||
import {
|
||||
Menu,
|
||||
MenuHandler,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
} from '@snowballtools/material-tailwind-react-fork';
|
||||
|
||||
import { useState } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { Deployment, Domain, Environment, Project } from 'gql-client';
|
||||
import { Button } from 'components/shared/Button';
|
||||
import {
|
||||
@@ -18,11 +11,17 @@ import {
|
||||
UndoIcon,
|
||||
CrossCircleIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import {
|
||||
Menu,
|
||||
MenuHandler,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
} from '@snowballtools/material-tailwind-react-fork';
|
||||
import { ComponentPropsWithRef } from 'react';
|
||||
import AssignDomainDialog from './AssignDomainDialog';
|
||||
import { useGQLClient } from 'context/GQLClientContext';
|
||||
import { cn } from 'utils/classnames';
|
||||
import { ChangeStateToProductionDialog } from 'components/projects/Dialog/ChangeStateToProductionDialog';
|
||||
import { useToast } from 'components/shared/Toast';
|
||||
|
||||
interface DeploymentMenuProps extends ComponentPropsWithRef<'div'> {
|
||||
deployment: Deployment;
|
||||
@@ -42,7 +41,6 @@ export const DeploymentMenu = ({
|
||||
...props
|
||||
}: DeploymentMenuProps) => {
|
||||
const client = useGQLClient();
|
||||
const { toast, dismiss } = useToast();
|
||||
|
||||
const [changeToProduction, setChangeToProduction] = useState(false);
|
||||
const [redeployToProduction, setRedeployToProduction] = useState(false);
|
||||
@@ -53,19 +51,9 @@ export const DeploymentMenu = ({
|
||||
const isUpdated = await client.updateDeploymentToProd(deployment.id);
|
||||
if (isUpdated) {
|
||||
await onUpdate();
|
||||
toast({
|
||||
id: 'deployment_changed_to_production',
|
||||
title: 'Deployment changed to production',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.success('Deployment changed to production');
|
||||
} else {
|
||||
toast({
|
||||
id: 'deployment_not_changed_to_production',
|
||||
title: 'Error changing deployment to production',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.error('Unable to change deployment to production');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -73,19 +61,9 @@ export const DeploymentMenu = ({
|
||||
const isRedeployed = await client.redeployToProd(deployment.id);
|
||||
if (isRedeployed) {
|
||||
await onUpdate();
|
||||
toast({
|
||||
id: 'redeployed_to_production',
|
||||
title: 'Redeployed to production',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.success('Redeployed to production');
|
||||
} else {
|
||||
toast({
|
||||
id: 'redeployed_to_production_failed',
|
||||
title: 'Error redeploying to production',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.error('Unable to redeploy to production');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -96,19 +74,9 @@ export const DeploymentMenu = ({
|
||||
);
|
||||
if (isRollbacked) {
|
||||
await onUpdate();
|
||||
toast({
|
||||
id: 'deployment_rolled_back',
|
||||
title: 'Deployment rolled back',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.success('Deployment rolled back');
|
||||
} else {
|
||||
toast({
|
||||
id: 'deployment_rollback_failed',
|
||||
title: 'Error rolling back deployment',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.error('Unable to rollback deployment');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,19 +84,9 @@ export const DeploymentMenu = ({
|
||||
const isDeleted = await client.deleteDeployment(deployment.id);
|
||||
if (isDeleted) {
|
||||
await onUpdate();
|
||||
toast({
|
||||
id: 'deployment_deleted',
|
||||
title: 'Deployment deleted',
|
||||
variant: 'success',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.success('Deleted deployment');
|
||||
} else {
|
||||
toast({
|
||||
id: 'deployment_not_deleted',
|
||||
title: 'Error deleting deployment',
|
||||
variant: 'error',
|
||||
onDismiss: dismiss,
|
||||
});
|
||||
toast.error('Unable to delete deployment');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import { cn } from 'utils/classnames';
|
||||
import { useMediaQuery } from 'usehooks-ts';
|
||||
import { SIDEBAR_MENU } from './constants';
|
||||
import { UserSelect } from 'components/shared/UserSelect';
|
||||
import { baseUrl } from 'utils/constants';
|
||||
|
||||
interface SidebarProps {
|
||||
mobileOpen?: boolean;
|
||||
@@ -84,7 +83,7 @@ export const Sidebar = ({ mobileOpen }: SidebarProps) => {
|
||||
}, [orgSlug]);
|
||||
|
||||
const handleLogOut = useCallback(async () => {
|
||||
await fetch(`${baseUrl}/auth/logout`, {
|
||||
await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/logout`, {
|
||||
method: 'POST',
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
import { VITE_WALLET_CONNECT_ID } from 'utils/constants';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
if (!VITE_WALLET_CONNECT_ID) {
|
||||
if (!import.meta.env.VITE_WALLET_CONNECT_ID) {
|
||||
throw new Error('Error: REACT_APP_WALLET_CONNECT_ID env config is not set');
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import { GQLClientProvider } from './context/GQLClientContext';
|
||||
import { SERVER_GQL_PATH } from './constants';
|
||||
import { Toaster } from 'components/shared/Toast';
|
||||
import { LogErrorBoundary } from 'utils/log-error';
|
||||
import { baseUrl } from 'utils/constants';
|
||||
|
||||
// @ts-ignore
|
||||
console.log(`v-${__VERSION__}`);
|
||||
@@ -23,8 +22,8 @@ const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement,
|
||||
);
|
||||
|
||||
assert(baseUrl, 'VITE_SERVER_URL is not set in env');
|
||||
const gqlEndpoint = `${baseUrl}/${SERVER_GQL_PATH}`;
|
||||
assert(import.meta.env.VITE_SERVER_URL, 'VITE_SERVER_URL is not set in env');
|
||||
const gqlEndpoint = `${import.meta.env.VITE_SERVER_URL}/${SERVER_GQL_PATH}`;
|
||||
|
||||
const gqlClient = new GQLClient({ gqlEndpoint });
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Button } from 'components/shared/Button';
|
||||
import {
|
||||
ArrowRightCircleFilledIcon,
|
||||
LoaderIcon,
|
||||
} from 'components/shared/CustomIcon';
|
||||
import { WavyBorder } from 'components/shared/WavyBorder';
|
||||
import { Input } from 'components/shared/Input';
|
||||
import { verifyAccessCode } from 'utils/accessCode';
|
||||
|
||||
type AccessMethod = 'accesscode' | 'passkey';
|
||||
|
||||
type Err = { type: AccessMethod; message: string };
|
||||
|
||||
type AccessCodeProps = {
|
||||
onCorrectAccessCode: () => void;
|
||||
};
|
||||
|
||||
export const AccessCode: React.FC<AccessCodeProps> = ({
|
||||
onCorrectAccessCode,
|
||||
}) => {
|
||||
const [accessCode, setAccessCode] = useState('');
|
||||
const [error, setError] = useState<Err | null>();
|
||||
const [accessMethod, setAccessMethod] = useState<AccessMethod | false>(false);
|
||||
|
||||
async function validateAccessCode() {
|
||||
setAccessMethod('accesscode');
|
||||
try {
|
||||
const isValidAccessCode = await verifyAccessCode(accessCode);
|
||||
if (isValidAccessCode) {
|
||||
localStorage.setItem('accessCode', accessCode);
|
||||
onCorrectAccessCode();
|
||||
} else {
|
||||
setError({
|
||||
type: 'accesscode',
|
||||
message: 'Invalid access code',
|
||||
});
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError({ type: 'accesscode', message: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
const loading = accessMethod;
|
||||
const isValidAccessCodeLength = accessCode.length === 6;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
|
||||
<div className="self-stretch text-center text-sky-950 text-2xl font-medium font-display leading-tight">
|
||||
Access Code
|
||||
</div>
|
||||
</div>
|
||||
<WavyBorder className="self-stretch" variant="stroke" />
|
||||
<div className="self-stretch p-4 xs:p-6 flex-col justify-center items-center gap-8 flex">
|
||||
<div className="self-stretch flex-col gap-8 flex">
|
||||
<div className="flex-col justify-start items-start gap-2 inline-flex">
|
||||
<Input
|
||||
value={accessCode}
|
||||
onChange={(e) => setAccessCode(e.target.value)}
|
||||
disabled={!!loading}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
rightIcon={
|
||||
loading && loading === 'accesscode' ? (
|
||||
<LoaderIcon className="animate-spin" />
|
||||
) : (
|
||||
<ArrowRightCircleFilledIcon height="16" />
|
||||
)
|
||||
}
|
||||
onClick={() => {
|
||||
validateAccessCode();
|
||||
}}
|
||||
variant={'secondary'}
|
||||
disabled={!accessCode || !isValidAccessCodeLength || !!loading}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
{error && error.type === 'accesscode' && (
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="justify-center items-center gap-2 inline-flex">
|
||||
<div className="text-red-500 text-sm">
|
||||
Error: {error.message}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { AccessCode } from './AccessCode';
|
||||
import { SignUp } from './SignUp';
|
||||
|
||||
type AccessSignUpProps = {
|
||||
onDone: () => void;
|
||||
};
|
||||
|
||||
export const AccessSignUp: React.FC<AccessSignUpProps> = ({ onDone }) => {
|
||||
const [isValidAccessCode, setIsValidAccessCode] = useState<boolean>(
|
||||
!!localStorage.getItem('accessCode'),
|
||||
);
|
||||
|
||||
return isValidAccessCode ? (
|
||||
<SignUp onDone={onDone} />
|
||||
) : (
|
||||
<AccessCode onCorrectAccessCode={() => setIsValidAccessCode(true)} />
|
||||
);
|
||||
};
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
turnkeySignin,
|
||||
turnkeySignup,
|
||||
} from 'utils/turnkey-frontend';
|
||||
import { verifyAccessCode } from 'utils/accessCode';
|
||||
|
||||
type Provider = 'google' | 'github' | 'apple' | 'email';
|
||||
|
||||
@@ -112,29 +111,6 @@ export const SignUp = ({ onDone }: Props) => {
|
||||
const loading = provider;
|
||||
const emailValid = /.@./.test(email);
|
||||
|
||||
useEffect(() => {
|
||||
const validateAccessCode = async () => {
|
||||
const accessCode = localStorage.getItem('accessCode');
|
||||
if (!accessCode) {
|
||||
redirectToSignup();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await verifyAccessCode(accessCode);
|
||||
} catch (err: any) {
|
||||
redirectToSignup();
|
||||
}
|
||||
};
|
||||
|
||||
const redirectToSignup = () => {
|
||||
localStorage.removeItem('accessCode');
|
||||
window.location.href = '/signup';
|
||||
};
|
||||
|
||||
validateAccessCode();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="self-stretch p-3 xs:p-6 flex-col justify-center items-center gap-5 flex">
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { snowball } from 'utils/use-snowball';
|
||||
import { Login } from './Login';
|
||||
import { SignUp } from './SignUp';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Done } from './Done';
|
||||
import { AccessSignUp } from './AccessSignUp';
|
||||
|
||||
type Screen = 'login' | 'signup' | 'success';
|
||||
|
||||
const DASHBOARD_URL = '/';
|
||||
|
||||
export const SnowballAuth: React.FC = () => {
|
||||
export const SnowballAuth = () => {
|
||||
const path = window.location.pathname;
|
||||
const [screen, setScreen] = useState<Screen>(
|
||||
path === '/login' ? 'login' : 'signup',
|
||||
@@ -31,7 +30,7 @@ export const SnowballAuth: React.FC = () => {
|
||||
|
||||
if (screen === 'signup') {
|
||||
return (
|
||||
<AccessSignUp
|
||||
<SignUp
|
||||
onDone={() => {
|
||||
setScreen('success');
|
||||
}}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { baseUrl } from './constants';
|
||||
|
||||
export async function verifyAccessCode(
|
||||
accesscode: string,
|
||||
): Promise<boolean | null> {
|
||||
const res = await fetch(`${baseUrl}/auth/accesscode`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
accesscode,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'include',
|
||||
});
|
||||
// If API returns a non-empty 200, this is a valid access code.
|
||||
if (res.status == 200) {
|
||||
const isValid = (await res.json()).isValid as boolean;
|
||||
console.log('isValid', isValid);
|
||||
return isValid;
|
||||
} else if (res.status === 204) {
|
||||
return null;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unexpected response from access code endpoint: ${res.status}: ${await res.text()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export const baseUrl = import.meta.env.VITE_SERVER_URL;
|
||||
export const PASSKEY_WALLET_RPID = import.meta.env.VITE_PASSKEY_WALLET_RPID!;
|
||||
export const TURNKEY_BASE_URL = import.meta.env.VITE_TURNKEY_API_BASE_URL!;
|
||||
export const VITE_GITHUB_PWA_TEMPLATE_REPO = import.meta.env
|
||||
.VITE_GITHUB_PWA_TEMPLATE_REPO;
|
||||
export const VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO = import.meta.env
|
||||
.VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO;
|
||||
export const VITE_GITHUB_CLIENT_ID = import.meta.env.VITE_GITHUB_CLIENT_ID;
|
||||
export const VITE_WALLET_CONNECT_ID = import.meta.env.VITE_WALLET_CONNECT_ID;
|
||||
export const VITE_BUGSNAG_API_KEY = import.meta.env.VITE_BUGSNAG_API_KEY;
|
||||
export const VITE_LIT_RELAY_API_KEY = import.meta.env.VITE_LIT_RELAY_API_KEY;
|
||||
@@ -1,21 +1,21 @@
|
||||
import React from 'react';
|
||||
import Bugsnag from '@bugsnag/js';
|
||||
import BugsnagPluginReact from '@bugsnag/plugin-react';
|
||||
import BugsnagPerformance from '@bugsnag/browser-performance';
|
||||
import React from 'react';
|
||||
|
||||
import { VITE_BUGSNAG_API_KEY } from './constants';
|
||||
const bugsnagApiKey = import.meta.env.VITE_BUGSNAG_API_KEY;
|
||||
|
||||
if (VITE_BUGSNAG_API_KEY) {
|
||||
if (bugsnagApiKey) {
|
||||
Bugsnag.start({
|
||||
apiKey: VITE_BUGSNAG_API_KEY,
|
||||
apiKey: bugsnagApiKey,
|
||||
plugins: [new BugsnagPluginReact()],
|
||||
});
|
||||
BugsnagPerformance.start({ apiKey: VITE_BUGSNAG_API_KEY });
|
||||
BugsnagPerformance.start({ apiKey: bugsnagApiKey });
|
||||
}
|
||||
|
||||
export const errorLoggingEnabled = !!VITE_BUGSNAG_API_KEY;
|
||||
export const errorLoggingEnabled = !!bugsnagApiKey;
|
||||
|
||||
export const LogErrorBoundary = VITE_BUGSNAG_API_KEY
|
||||
export const LogErrorBoundary = bugsnagApiKey
|
||||
? Bugsnag.getPlugin('react')!.createErrorBoundary(React)
|
||||
: ({ children }: any) => children;
|
||||
|
||||
@@ -28,7 +28,7 @@ export function logError(error: Error) {
|
||||
}
|
||||
console.error(...errors);
|
||||
|
||||
if (VITE_BUGSNAG_API_KEY) {
|
||||
if (import.meta.env.VITE_BUGSNAG_API_KEY) {
|
||||
Bugsnag.notify(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import { SiweMessage } from 'siwe';
|
||||
import { PKPEthersWallet } from '@lit-protocol/pkp-ethers';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { baseUrl } from './constants';
|
||||
|
||||
const domain = window.location.host;
|
||||
const origin = window.location.origin;
|
||||
|
||||
@@ -19,7 +17,7 @@ export async function signInWithEthereum(
|
||||
);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
const res = await fetch(`${baseUrl}/auth/validate`, {
|
||||
const res = await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/validate`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { TurnkeyClient, getWebAuthnAttestation } from '@turnkey/http';
|
||||
import { WebauthnStamper } from '@turnkey/webauthn-stamper';
|
||||
|
||||
import { baseUrl, PASSKEY_WALLET_RPID, TURNKEY_BASE_URL } from './constants';
|
||||
const baseUrl = import.meta.env.VITE_SERVER_URL;
|
||||
|
||||
const PASSKEY_WALLET_RPID = import.meta.env.VITE_PASSKEY_WALLET_RPID!;
|
||||
const TURNKEY_BASE_URL = import.meta.env.VITE_TURNKEY_API_BASE_URL!;
|
||||
|
||||
// All algorithms can be found here: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
|
||||
// We only support ES256, which is listed here
|
||||
|
||||
@@ -5,17 +5,16 @@ import {
|
||||
LitGoogleAuth,
|
||||
LitPasskeyAuth,
|
||||
} from '@snowballtools/auth-lit';
|
||||
import { VITE_LIT_RELAY_API_KEY } from './constants';
|
||||
|
||||
export const snowball = Snowball.withAuth({
|
||||
google: LitGoogleAuth.configure({
|
||||
litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
||||
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
}),
|
||||
// apple: LitAppleAuth.configure({
|
||||
// litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
||||
// litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
// }),
|
||||
passkey: LitPasskeyAuth.configure({
|
||||
litRelayApiKey: VITE_LIT_RELAY_API_KEY!,
|
||||
litRelayApiKey: import.meta.env.VITE_LIT_RELAY_API_KEY!,
|
||||
}),
|
||||
}).create({
|
||||
initialChain: SnowballChain.sepolia,
|
||||
|
||||
@@ -10575,11 +10575,6 @@ exponential-backoff@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6"
|
||||
integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==
|
||||
|
||||
express-async-errors@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41"
|
||||
integrity sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==
|
||||
|
||||
express-session@^1.18.0:
|
||||
version "1.18.0"
|
||||
resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.18.0.tgz#a6ae39d9091f2efba5f20fc5c65a3ce7c9ce16a3"
|
||||
|
||||
Reference in New Issue
Block a user