Skip to content
This repository has been archived by the owner on Aug 16, 2024. It is now read-only.

Commit

Permalink
Update to v5.0.0
Browse files Browse the repository at this point in the history
CLI refactor - 1
  • Loading branch information
jamesrp13 authored Jul 30, 2024
2 parents 4c25c76 + 6077284 commit db5e3d5
Show file tree
Hide file tree
Showing 152 changed files with 459 additions and 3,730 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# v5.0.0 (Mon Jul 29 2024)

#### 💥 Breaking Change

- Removes Universal support with associated flags, prompts, and templates
- Adds architectural updates to EVM templates

#### Authors: 1

- pbillingsby ([@PBillingsby](https://github.com/PBillingsby))

# v4.13.0 (Fri Apr 12 2024)

#### 🚀 Enhancement
Expand Down
1 change: 0 additions & 1 deletion core/create-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ export async function createApp(config: CreateMagicAppConfig) {
...(await buildTemplate({
...config,
chain: undefined,
product: undefined,
configuration: undefined,
isChosenTemplateValid: false,
isQuickstart: false,
Expand Down
126 changes: 39 additions & 87 deletions core/utils/templateMappings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
AuthTypePrompt,
BlockchainNetworkPrompt,
ConfigurationPrompt,
ProductPrompt,
ProjectNamePrompt,
PublishableApiKeyPrompt,
} from 'scaffolds/prompts';
Expand All @@ -14,27 +13,16 @@ import DedicatedScaffold, { flags as dedicatedFlags } from '../../scaffolds/next
import FlowDedicatedScaffold, {
flags as flowDedicatedFlags,
} from '../../scaffolds/nextjs-flow-dedicated-wallet/scaffold';
import FlowUniversalScaffold, {
flags as flowUniversalFlags,
} from '../../scaffolds/nextjs-flow-universal-wallet/scaffold';
import SolanaDedicatedScaffold, {
flags as solanaDedicatedFlags,
} from '../../scaffolds/nextjs-solana-dedicated-wallet/scaffold';
import UniversalScaffold, { flags as universalFlags } from '../../scaffolds/nextjs-universal-wallet/scaffold';
import { Timer } from './timer';

export type Chain = 'evm' | 'solana' | 'flow';
export type Template =
| 'nextjs-dedicated-wallet'
| 'nextjs-universal-wallet'
| 'nextjs-solana-dedicated-wallet'
| 'nextjs-flow-universal-wallet'
| 'nextjs-flow-dedicated-wallet';

export type Product = 'universal' | 'dedicated';
export type Template = 'nextjs-dedicated-wallet' | 'nextjs-solana-dedicated-wallet' | 'nextjs-flow-dedicated-wallet';

type ConfigType = CreateMagicAppConfig & {
chain: Chain | undefined;
product: Product | undefined;
configuration: string | undefined;
isChosenTemplateValid: boolean;
isQuickstart: boolean;
Expand All @@ -43,32 +31,16 @@ type ConfigType = CreateMagicAppConfig & {
function mapTemplateToChain(template: string): Chain | undefined {
switch (template) {
case 'nextjs-dedicated-wallet':
case 'nextjs-universal-wallet':
return 'evm';
case 'nextjs-solana-dedicated-wallet':
return 'solana';
case 'nextjs-flow-universal-wallet':
case 'nextjs-flow-dedicated-wallet':
return 'flow';
default:
return undefined;
}
}

function mapTemplateToProduct(template: string): Product | undefined {
switch (template) {
case 'nextjs-dedicated-wallet':
case 'nextjs-solana-dedicated-wallet':
case 'nextjs-flow-dedicated-wallet':
return 'dedicated';
case 'nextjs-universal-wallet':
case 'nextjs-flow-universal-wallet':
return 'universal';
default:
return undefined;
}
}

export async function mapTemplateToScaffold(
template: string,
appData: any,
Expand All @@ -93,11 +65,6 @@ export async function mapTemplateToScaffold(
data.loginMethods = await AuthTypePrompt.loginMethodsPrompt();
}
return new DedicatedScaffold(data);
case 'nextjs-universal-wallet':
if (!data.network) {
data.network = await BlockchainNetworkPrompt.evmNetworkPrompt();
}
return new UniversalScaffold(data);
case 'nextjs-solana-dedicated-wallet':
if (!data.network) {
data.network = await BlockchainNetworkPrompt.solanaNetworkPrompt();
Expand All @@ -106,11 +73,6 @@ export async function mapTemplateToScaffold(
data.loginMethods = await AuthTypePrompt.loginMethodsPrompt();
}
return new SolanaDedicatedScaffold(data);
case 'nextjs-flow-universal-wallet':
if (!data.network) {
data.network = await BlockchainNetworkPrompt.flowNetworkPrompt();
}
return new FlowUniversalScaffold(data);
case 'nextjs-flow-dedicated-wallet':
if (!data.network) {
data.network = await BlockchainNetworkPrompt.flowNetworkPrompt();
Expand All @@ -128,12 +90,8 @@ export function mapTemplateToFlags(template: string): any {
switch (template) {
case 'nextjs-dedicated-wallet':
return dedicatedFlags;
case 'nextjs-universal-wallet':
return universalFlags;
case 'nextjs-solana-dedicated-wallet':
return solanaDedicatedFlags;
case 'nextjs-flow-universal-wallet':
return flowUniversalFlags;
case 'nextjs-flow-dedicated-wallet':
return flowDedicatedFlags;
default:
Expand All @@ -145,7 +103,6 @@ const quickstartConfig = (config: ConfigType): ConfigType => ({
...config,
template: 'nextjs-dedicated-wallet',
network: 'polygon-amoy',
product: 'dedicated',
chain: 'evm',
isChosenTemplateValid: true,
isQuickstart: true,
Expand All @@ -155,14 +112,14 @@ const solanaConfig = async (config: ConfigType): Promise<ConfigType> => ({
...config,
template: 'nextjs-solana-dedicated-wallet',
network: await BlockchainNetworkPrompt.solanaNetworkPrompt(),
product: 'dedicated',
chain: 'solana',
isChosenTemplateValid: true,
isQuickstart: false,
});

export const buildTemplate = async (appConfig: ConfigType): Promise<ConfigType> => {
let config = appConfig;
let config = { ...appConfig };

if (!config.projectName) {
config.projectName = await ProjectNamePrompt.askProjectName();
}
Expand All @@ -171,59 +128,54 @@ export const buildTemplate = async (appConfig: ConfigType): Promise<ConfigType>
config.configuration = await ConfigurationPrompt.askConfiguration();

if (config.configuration === 'quickstart') {
config = quickstartConfig(config);
return config;
return quickstartConfig(config);
}
} else {
config = {
...config,
product: mapTemplateToProduct(config.template),
chain: mapTemplateToChain(config.template),
};
config.chain = mapTemplateToChain(config.template);
}

if (!config.chain && !config.network) {
if (!config.chain) {
config.chain = await BlockchainNetworkPrompt.chainPrompt();
}

if (!config.network) {
if (config.chain === 'solana') {
config = await solanaConfig(config);
} else if (config.chain === 'flow') {
config.network = await BlockchainNetworkPrompt.flowNetworkPrompt();
} else if (config.chain === 'evm') {
config.network = await BlockchainNetworkPrompt.evmNetworkPrompt();
switch (config.chain) {
case 'solana':
config = await solanaConfig(config);
break;
case 'flow':
config.network = await BlockchainNetworkPrompt.flowNetworkPrompt();
break;
case 'evm':
config.network = await BlockchainNetworkPrompt.evmNetworkPrompt();
break;
default:
config.network = await BlockchainNetworkPrompt.evmNetworkPrompt();
break;
}
} else if (
config.network === 'ethereum' ||
config.network === 'ethereum-sepolia' ||
config.network === 'polygon' ||
config.network === 'polygon-amoy' ||
config.network === 'etherlink-testnet'
) {
config.chain = 'evm';
} else if (config.network === 'solana-devnet' || config.network === 'solana-mainnet') {
config.chain = 'solana';
} else {
config.chain = 'flow';
}

if (!config.product) {
config.product = await ProductPrompt.askProduct();

if (config.product === 'universal') {
if (config.chain === 'flow') {
config.template = 'nextjs-flow-universal-wallet';
} else {
config.template = 'nextjs-universal-wallet';
}
} else if (config.chain === 'flow') {
config.template = 'nextjs-flow-dedicated-wallet';
const evmNetworks = [
'ethereum',
'ethereum-sepolia',
'polygon',
'polygon-amoy',
'etherlink-testnet',
'zksync',
'zksync-sepolia',
];
const solanaNetworks = ['solana-devnet', 'solana-mainnet'];

if (evmNetworks.includes(config.network)) {
config.chain = 'evm';
} else if (solanaNetworks.includes(config.network)) {
config.chain = 'solana';
} else {
config.template = 'nextjs-dedicated-wallet';
config.chain = 'flow';
}
config.isChosenTemplateValid = true;
}

config.template = config.chain === 'flow' ? 'nextjs-flow-dedicated-wallet' : 'nextjs-dedicated-wallet';
config.isChosenTemplateValid = true;

return config;
};
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "make-magic",
"version": "4.13.0",
"version": "5.0.0",
"description": "A tool for quickly scaffolding an app with Magic authentication baked-in!",
"repository": "magiclabs/create-magic-app",
"license": "MIT",
Expand Down Expand Up @@ -81,11 +81,17 @@
"dependencies": {
"@segment/analytics-node": "^1.1.0",
"binaryextensions": "^4.18.0",
"ejs": "^3.1.9",
"ejs": "^3.1.10",
"enquirer": "^2.4.0",
"fs-extra": "^11.1.1",
"ora": "^5.1.0",
"pretty-time": "^1.1.0",
"textextensions": "^5.16.0"
},
"resolutions": {
"ejs": "^3.1.10",
"tar": "^6.2.1",
"braces": "^3.0.3",
"merge": "^2.1.1"
}
}
}
10 changes: 0 additions & 10 deletions scaffolds/dev-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,10 @@ export const templateDevData = {
loginMethods: ['EmailOTP', 'SMSOTP'],
projectName: 'My Flow Dedicated Wallet',
},
'nextjs-flow-universal-wallet': {
network: 'flow-testnet',
publishableApiKey: 'pk_live_8D6C562ABCA3140A',
projectName: 'My Flow Universal Wallet',
},
'nextjs-solana-dedicated-wallet': {
network: 'solana-devnet',
publishableApiKey: 'pk_live_FD2D70B32ABE11BD',
loginMethods: ['EmailOTP', 'SMSOTP'],
projectName: 'My Solana Dedicated Wallet',
},
'nextjs-universal-wallet': {
network: 'ethereum-sepolia',
publishableApiKey: 'pk_live_8D6C562ABCA3140A',
projectName: 'My Universal Wallet',
},
};
13 changes: 7 additions & 6 deletions scaffolds/nextjs-dedicated-wallet/scaffold.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Flags } from '../../core/flags';
import BaseScaffold, { ExecaCommand } from '../../core/types/BaseScaffold';
import { AuthTypePrompt, BlockchainNetworkPrompt, PublishableApiKeyPrompt } from '../../scaffolds/prompts';
import { AuthTypePrompt, BlockchainNetworkPrompt, PublishableApiKeyPrompt } from '../prompts';

export type Data = BlockchainNetworkPrompt.Data & PublishableApiKeyPrompt.Data & AuthTypePrompt.Data;

Expand Down Expand Up @@ -41,12 +41,13 @@ export default class DedicatedScaffold extends BaseScaffold {
'./src/components/magic/wallet-methods/Disconnect.tsx',
'./src/components/magic/wallet-methods/GetIdToken.tsx',
'./src/components/magic/wallet-methods/GetMetadata.tsx',
'./src/components/magic/Dashboard.tsx',
'./src/components/magic/DevLinks.tsx',
'./src/components/magic/Header.tsx',
'./src/components/ui/Dashboard.tsx',
'./src/components/ui/DevLinks.tsx',
'./src/components/ui/Header.tsx',
'./src/components/magic/Login.tsx',
'./src/components/magic/MagicProvider.tsx',
'./src/components/magic/MagicDashboardRedirect.tsx',
'./src/hooks/MagicProvider.tsx',
'./src/hooks/Web3.tsx',
'./src/components/ui/MagicDashboardRedirect.tsx',
'./src/pages',
'./src/styles',
'./src/utils',
Expand Down
47 changes: 47 additions & 0 deletions scaffolds/nextjs-dedicated-wallet/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,53 @@ This scaffold is meant to help you bootstrap your own projects with Magic's [Ded

The folder structure of this scaffold is designed to encapsulate all things Magic into one place so you can easily add or remove components and functionality. For example, all Magic-specific components are in the `src/components/magic` directory while generic UI components are in the `src/components/ui` directory.

## Usage

This project uses Next.js but relies on fairly standard React components and hooks. Magic-related components are in the `/src/components/magic` directory, all other UI components are in the `/src/components/ui` directory, utility functions are in `/src/utils` and hooks are in the `/src/hooks` directory.

Use this project as a reference for how to use this template or implement Magic in your own project. Key areas to look at include:

### Custom Hooks
In the `/src/hooks` directory, the `MagicProvider` hook sets up and provides a Magic instance for using the Magic SDK and OAuth extension. Additionally, the `Web3.tsx` hook initializes and provides a Web3 instance using the Magic provider.

### Login Functionality
The `Login.tsx` component, located in `/src/components/magic`, manages the display and functionality of various login methods on the login page. It is a central piece for handling user authentication.

One thing to note is that whenever `getInfo` is called from any of the authentication providers, the user session is rehydrated.

Here is a list of the available authentication methods:
- `Discord.tsx` - Handles authentication using Discord OAuth.
- `Facebook.tsx` - Handles authentication using Facebook OAuth.
- `Google.tsx` - Handles authentication using Google OAuth.
- `Twitch.tsx` - Handles authentication using Twitch OAuth.
- `EmailOTP.tsx` - Handles authentication using email one-time password (OTP).
- `Github.tsx` - Handles authentication using GitHub OAuth.
- `SMSOTP.tsx` - Handles authentication using SMS one-time password (OTP).
- `Twitter.tsx` - Handles authentication using Twitter OAuth.

### User Interaction Components

- `/src/components/magic/auth`: This contains all of the authentication methods.

- `/src/components/magic/cards`: The `SendTransactionCard.tsx` component facilitate transaction processes, `UserInfoCard.tsx` displays user information, `WalletMethodsCard.tsx` manages authentication tokens and user metadata and `SmartContract.tsx` interacts with a basic storage contract.

- `/src/components/magic/wallet-methods`: This directory includes several components that provide specific functionalities:
- `Disconnect.tsx` handles the disconnection of the user's session from the application.
- `GetIdToken.tsx` retrieves the ID token for the authenticated user.
- `GetMetadata.tsx` retrieves metadata information about the authenticated user. This will rehydrate the user session every time it is rendered. It does this when calling the `getInfo` function. The user session is rehydrated whenever `getInfo` is invoked
- `UpdateEmail.tsx` allows the user to update their email address.

### Utility Functions
The `/src/utils` directory includes utility files that support various aspects of the application:
- `common.ts` manages user authentication processes. The `logout` function handle the process of logging out a user and clearing their authentication data, while `saveUserInfo` saves the user's token, login method, and address to local storage.
- `network.ts` defines network configurations and utilities, such as URLs, chain IDs, tokens, and block explorer links.
- `showToast.ts` handles customizable toast notifications.
- `smartContract.ts` contains functions and configurations for interacting with smart contracts, such as retrieving contract IDs, determining testnet status, generating hash links, and defining contract ABIs.

These utilities are essential for supporting various aspects of the application.

### UI Components
The `/src/components/ui` directory contains reusable UI components for building the user interface. This includes components for creating and styling cards (`Card`, `CardHeader`, `CardLabel`), layout elements for the dashboard (`Dashboard`), separators (`Divider`), error messages (`ErrorText`), form elements (`FormButton`, `FormInput`), redirection handling within the Magic dashboard (`MagicDashboardRedirect`), spacing elements (`Spacer`), loading indicators (`Spinner`), and displaying transaction history (`TransactionHistory`).
## Next.js

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
Expand Down
Loading

0 comments on commit db5e3d5

Please sign in to comment.