@getpara/create-para-app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ const EVM_DEPS = ['@getpara/evm-wallet-connectors', '@tanstack/react-query', 'wagmi', '@getpara/react-sdk'];
5
+ const SOLANA_DEPS = [
6
+ '@getpara/react-sdk',
7
+ '@getpara/solana-wallet-connectors',
8
+ '@solana-mobile/wallet-adapter-mobile',
9
+ '@solana/wallet-adapter-base',
10
+ '@solana/wallet-adapter-react',
11
+ '@solana/wallet-adapter-walletconnect',
12
+ '@solana/web3.js',
13
+ '@tanstack/react-query',
14
+ ];
15
+ const COSMOS_DEPS = [
16
+ '@getpara/core-sdk',
17
+ '@getpara/cosmos-wallet-connectors',
18
+ '@getpara/graz',
19
+ '@getpara/react-sdk',
20
+ '@getpara/user-management-client',
21
+ '@cosmjs/cosmwasm-stargate',
22
+ '@cosmjs/launchpad',
23
+ '@cosmjs/proto-signing',
24
+ '@cosmjs/stargate',
25
+ '@cosmjs/tendermint-rpc',
26
+ '@leapwallet/cosmos-social-login-capsule-provider',
27
+ 'long',
28
+ 'starknet',
29
+ ];
30
+ const BASE_DEPS = ['@getpara/react-sdk'];
31
+
32
+ export async function updatePackageJsonDependencies(
33
+ projectName: string,
34
+ networks: string[],
35
+ externalWalletSupport: boolean,
36
+ ) {
37
+ const pkgPath = path.join(projectName, 'package.json');
38
+ const exists = await fs.pathExists(pkgPath);
39
+ if (!exists) {
40
+ return;
41
+ }
42
+ const pkgData = await fs.readJSON(pkgPath);
43
+ pkgData.dependencies = pkgData.dependencies || {};
44
+ if (!externalWalletSupport) {
45
+ BASE_DEPS.forEach(dep => {
46
+ pkgData.dependencies[dep] = pkgData.dependencies[dep] || 'latest';
47
+ });
48
+ } else {
49
+ if (networks.includes('evm')) {
50
+ EVM_DEPS.forEach(dep => {
51
+ pkgData.dependencies[dep] = pkgData.dependencies[dep] || 'latest';
52
+ });
53
+ }
54
+ if (networks.includes('solana')) {
55
+ SOLANA_DEPS.forEach(dep => {
56
+ pkgData.dependencies[dep] = pkgData.dependencies[dep] || 'latest';
57
+ });
58
+ }
59
+ if (networks.includes('cosmos')) {
60
+ COSMOS_DEPS.forEach(dep => {
61
+ pkgData.dependencies[dep] = pkgData.dependencies[dep] || 'latest';
62
+ });
63
+ }
64
+ if (!networks.includes('evm') && !networks.includes('solana') && !networks.includes('cosmos')) {
65
+ BASE_DEPS.forEach(dep => {
66
+ pkgData.dependencies[dep] = pkgData.dependencies[dep] || 'latest';
67
+ });
68
+ }
69
+ }
70
+ await fs.writeJSON(pkgPath, pkgData, { spaces: 2 });
71
+ }
@@ -0,0 +1,13 @@
1
+ import { logInfo } from '../utils/logger.js';
2
+ import { sdkSetupNextjs } from './sdkSetupNextjs.js';
3
+ import { sdkSetupVite } from './sdkSetupVite.js';
4
+
5
+ export async function runSDKSetup(config) {
6
+ const { projectName, template } = config;
7
+ logInfo(`🔌 Integrating Para SDK into project ${projectName}...`);
8
+ if (template === 'vite-react') {
9
+ await sdkSetupVite(config);
10
+ } else {
11
+ await sdkSetupNextjs(config);
12
+ }
13
+ }
@@ -0,0 +1,122 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { logHeader, logSection, logSubsection, logStep } from '../utils/logger.js';
4
+ import { formatWithPrettier } from '../utils/formatting.js';
5
+ import { updatePackageJsonDependencies } from './packageJsonHelpers.js';
6
+ import {
7
+ getEnvFileContent,
8
+ getParaClientCode,
9
+ getWalletProviderCodeNextjs,
10
+ getHelloParaFile,
11
+ getHomeFile,
12
+ getStylesNonTailwind,
13
+ } from './codeGenerators.js';
14
+
15
+ export async function sdkSetupNextjs(config) {
16
+ const {
17
+ projectName,
18
+ networks,
19
+ evmSigner,
20
+ apiKey,
21
+ noTypescript,
22
+ noAppRouter,
23
+ noSrcDir,
24
+ externalWalletSupport,
25
+ tailwind,
26
+ app,
27
+ } = config;
28
+
29
+ const envContent = getEnvFileContent(apiKey, true);
30
+ const envPath = path.join(projectName, '.env');
31
+ await fs.outputFile(envPath, envContent);
32
+
33
+ const clientDir = path.join(projectName, 'src', 'client');
34
+ await fs.ensureDir(clientDir);
35
+ const paraClient = getParaClientCode(true, !noTypescript);
36
+ {
37
+ const filePath = path.join(clientDir, `para.${noTypescript ? 'js' : 'ts'}`);
38
+ const formatted = await formatWithPrettier(paraClient, filePath);
39
+ await fs.outputFile(filePath, formatted);
40
+ }
41
+
42
+ if (externalWalletSupport) {
43
+ const compDir = path.join(projectName, 'src', 'components');
44
+ await fs.ensureDir(compDir);
45
+ const results = getWalletProviderCodeNextjs(networks, noAppRouter);
46
+ for (const r of results) {
47
+ const fileExt = noTypescript ? 'jsx' : 'tsx';
48
+ const filePath = path.join(compDir, `${r.fileName}.${fileExt}`);
49
+ const formatted = await formatWithPrettier(r.code, filePath);
50
+ await fs.outputFile(filePath, formatted);
51
+ }
52
+ }
53
+
54
+ const componentsDir = path.join(projectName, 'src', 'components');
55
+ await fs.ensureDir(componentsDir);
56
+ const helloParaCode = getHelloParaFile(!!tailwind, !noTypescript, true);
57
+ {
58
+ const filePath = path.join(componentsDir, `HelloPara.${noTypescript ? 'jsx' : 'tsx'}`);
59
+ const formatted = await formatWithPrettier(helloParaCode, filePath);
60
+ await fs.outputFile(filePath, formatted);
61
+ }
62
+
63
+ const homeCode = getHomeFile(!!tailwind, !noTypescript, !!externalWalletSupport);
64
+ let mainPath = '';
65
+ if (noAppRouter) {
66
+ if (noSrcDir) {
67
+ mainPath = path.join(projectName, 'pages', `index.${noTypescript ? 'jsx' : 'tsx'}`);
68
+ } else {
69
+ mainPath = path.join(projectName, 'src', 'pages', `index.${noTypescript ? 'jsx' : 'tsx'}`);
70
+ }
71
+ } else {
72
+ if (noSrcDir) {
73
+ mainPath = path.join(projectName, 'app', `page.${noTypescript ? 'jsx' : 'tsx'}`);
74
+ } else {
75
+ mainPath = path.join(projectName, 'src', 'app', `page.${noTypescript ? 'jsx' : 'tsx'}`);
76
+ }
77
+ }
78
+ const formattedHome = await formatWithPrettier(homeCode, mainPath);
79
+ await fs.writeFile(mainPath, formattedHome);
80
+
81
+ let cssFilePath = '';
82
+ if (tailwind) {
83
+ if (app) {
84
+ cssFilePath = path.join(projectName, 'src', 'app', 'globals.css');
85
+ } else {
86
+ cssFilePath = path.join(projectName, 'styles', 'globals.css');
87
+ }
88
+ if (!(await fs.pathExists(cssFilePath))) {
89
+ await fs.outputFile(cssFilePath, '');
90
+ }
91
+ } else {
92
+ if (app) {
93
+ cssFilePath = path.join(projectName, 'src', 'app', 'globals.css');
94
+ } else {
95
+ cssFilePath = path.join(projectName, 'src', 'global.css');
96
+ }
97
+ if (!(await fs.pathExists(cssFilePath))) {
98
+ await fs.outputFile(cssFilePath, '');
99
+ }
100
+ const stylesContent = getStylesNonTailwind();
101
+ const existing = await fs.readFile(cssFilePath, 'utf-8');
102
+ const appended = `${existing.trim()}\n\n${stylesContent}`;
103
+ const formattedStyles = await formatWithPrettier(appended, cssFilePath);
104
+ await fs.writeFile(cssFilePath, formattedStyles);
105
+ }
106
+
107
+ await updatePackageJsonDependencies(projectName, networks, externalWalletSupport);
108
+ logSection('🛠 Configuration Details:');
109
+ logSubsection('Project Type', 'nextjs');
110
+ logSubsection('Supported Networks', networks.join(', ') || 'None');
111
+ if (networks.includes('evm')) {
112
+ logSubsection('EVM Signer', evmSigner);
113
+ }
114
+ logSubsection('API Key', apiKey);
115
+
116
+ logSection('➡️ Next Steps:');
117
+ logStep(`1. cd ${projectName}`);
118
+ logStep(`2. Install dependencies if skipped (e.g., "yarn install" or "npm install")`);
119
+ logStep(`3. Refer to https://docs.getpara.com/integration-guides/create-para-app for further instructions.`);
120
+
121
+ logHeader('✅ SDK integration complete with ParaModal usage.');
122
+ }
@@ -0,0 +1,87 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { logHeader, logSection, logSubsection, logStep, logInfo } from '../utils/logger.js';
4
+ import { formatWithPrettier } from '../utils/formatting.js';
5
+ import { updatePackageJsonDependencies } from './packageJsonHelpers.js';
6
+ import {
7
+ getEnvFileContent,
8
+ getParaClientCode,
9
+ getWalletProviderCodeVite,
10
+ getHelloParaFile,
11
+ getHomeFile,
12
+ getStylesNonTailwind,
13
+ } from './codeGenerators.js';
14
+
15
+ export async function sdkSetupVite(config) {
16
+ const { projectName, networks, evmSigner, apiKey, noTypescript, noSrcDir, externalWalletSupport, tailwind } = config;
17
+
18
+ const envContent = getEnvFileContent(apiKey, false);
19
+ const envPath = path.join(projectName, '.env');
20
+ await fs.outputFile(envPath, envContent);
21
+
22
+ const clientDir = path.join(projectName, 'src', 'client');
23
+ await fs.ensureDir(clientDir);
24
+ const paraClient = getParaClientCode(false, !noTypescript);
25
+ {
26
+ const filePath = path.join(clientDir, `para.${noTypescript ? 'js' : 'ts'}`);
27
+ const formatted = await formatWithPrettier(paraClient, filePath);
28
+ await fs.outputFile(filePath, formatted);
29
+ }
30
+
31
+ if (externalWalletSupport) {
32
+ const compDir = path.join(projectName, 'src', 'components');
33
+ await fs.ensureDir(compDir);
34
+ const providerCode = getWalletProviderCodeVite(networks);
35
+ const filePath = path.join(compDir, `ParaWalletsProvider.${noTypescript ? 'jsx' : 'tsx'}`);
36
+ const formatted = await formatWithPrettier(providerCode, filePath);
37
+ await fs.outputFile(filePath, formatted);
38
+ }
39
+
40
+ const compDir = path.join(projectName, 'src', 'components');
41
+ await fs.ensureDir(compDir);
42
+ const helloParaCode = getHelloParaFile(!!tailwind, !noTypescript, false);
43
+ {
44
+ const filePath = path.join(compDir, `HelloPara.${noTypescript ? 'jsx' : 'tsx'}`);
45
+ const formatted = await formatWithPrettier(helloParaCode, filePath);
46
+ await fs.outputFile(filePath, formatted);
47
+ }
48
+
49
+ const homeCode = getHomeFile(!!tailwind, !noTypescript, !!externalWalletSupport);
50
+ const mainFileDir = noSrcDir ? projectName : path.join(projectName, 'src');
51
+ const mainFilePath = path.join(mainFileDir, `App.${noTypescript ? 'jsx' : 'tsx'}`);
52
+ const exists = await fs.pathExists(mainFilePath);
53
+ if (!exists) {
54
+ logInfo(`Could not find ${mainFilePath} to replace.`);
55
+ } else {
56
+ const formatted = await formatWithPrettier(homeCode, mainFilePath);
57
+ await fs.writeFile(mainFilePath, formatted);
58
+ }
59
+
60
+ if (!tailwind) {
61
+ const indexCssPath = path.join(projectName, 'src', 'index.css');
62
+ const existsCss = await fs.pathExists(indexCssPath);
63
+ if (!existsCss) {
64
+ await fs.outputFile(indexCssPath, '');
65
+ }
66
+ const existing = await fs.readFile(indexCssPath, 'utf-8');
67
+ const newStyles = `${existing.trim()}\n\n${getStylesNonTailwind()}`;
68
+ const formattedStyles = await formatWithPrettier(newStyles, indexCssPath);
69
+ await fs.writeFile(indexCssPath, formattedStyles);
70
+ }
71
+
72
+ await updatePackageJsonDependencies(projectName, networks, externalWalletSupport);
73
+ logSection('🛠 Configuration Details:');
74
+ logSubsection('Project Type', 'vite-react');
75
+ logSubsection('Supported Networks', networks.join(', ') || 'None');
76
+ if (networks.includes('evm')) {
77
+ logSubsection('EVM Signer', evmSigner);
78
+ }
79
+ logSubsection('API Key', apiKey);
80
+
81
+ logSection('➡️ Next Steps:');
82
+ logStep(`1. cd ${projectName}`);
83
+ logStep(`2. Install dependencies if skipped (e.g., "yarn install" or "npm install")`);
84
+ logStep(`3. Refer to https://docs.getpara.com/integration-guides/create-para-app for further instructions.`);
85
+
86
+ logHeader('✅ SDK integration complete with ParaModal usage.');
87
+ }
@@ -0,0 +1,113 @@
1
+ import inquirer, { DistinctQuestion } from 'inquirer';
2
+
3
+ interface InteractiveAnswers {
4
+ projectName: string;
5
+ networks: string[];
6
+ evmSigner?: string;
7
+ externalWalletSupport: boolean;
8
+ apiKey: string;
9
+ template: string;
10
+ }
11
+
12
+ export async function promptInteractive(config: {
13
+ projectName?: string;
14
+ template?: string;
15
+ networks?: string[];
16
+ evmSigner?: string;
17
+ externalWalletSupport?: boolean;
18
+ apiKey?: string;
19
+ }): Promise<InteractiveAnswers> {
20
+ const template = config.template || 'nextjs';
21
+ const defaultName = config.projectName || `para-${template}-template`;
22
+
23
+ const questions: DistinctQuestion<InteractiveAnswers>[] = [];
24
+
25
+ if (!config.template) {
26
+ questions.push({
27
+ type: 'list',
28
+ name: 'template',
29
+ message: 'Select a project type:',
30
+ choices: ['nextjs', 'vite-react'],
31
+ default: 'nextjs',
32
+ });
33
+ }
34
+
35
+ if (!config.projectName) {
36
+ questions.push({
37
+ type: 'input',
38
+ name: 'projectName',
39
+ message: 'Enter your project name:',
40
+ default: answers => {
41
+ const selectedTemplate = answers.template || config.template || 'nextjs';
42
+ return `para-${selectedTemplate}-template`;
43
+ },
44
+ });
45
+ }
46
+
47
+ if (!config.networks || !config.networks.length) {
48
+ questions.push({
49
+ type: 'checkbox',
50
+ name: 'networks',
51
+ message: 'Select supported networks:',
52
+ choices: [
53
+ { name: 'EVM', value: 'evm' },
54
+ { name: 'Cosmos', value: 'cosmos' },
55
+ { name: 'Solana', value: 'solana' },
56
+ ],
57
+ });
58
+ }
59
+
60
+ if (config.networks && config.networks.includes('evm') && !config.evmSigner) {
61
+ questions.push({
62
+ type: 'list',
63
+ name: 'evmSigner',
64
+ message: 'Select signer for EVM:',
65
+ choices: ['ethers', 'viem'],
66
+ default: 'ethers',
67
+ });
68
+ }
69
+
70
+ if (config.externalWalletSupport === undefined) {
71
+ questions.push({
72
+ type: 'confirm',
73
+ name: 'externalWalletSupport',
74
+ message: 'Enable external wallet support?',
75
+ default: false,
76
+ when: answers => {
77
+ const nets = answers.networks || config.networks;
78
+ return Array.isArray(nets) && nets.length > 0;
79
+ },
80
+ });
81
+ }
82
+
83
+ if (!config.apiKey) {
84
+ questions.push({
85
+ type: 'input',
86
+ name: 'apiKey',
87
+ message: 'Enter your API key:',
88
+ validate: input => (input ? true : 'API key cannot be empty'),
89
+ });
90
+ }
91
+
92
+ if (!questions.length) {
93
+ return {
94
+ projectName: config.projectName || defaultName,
95
+ template,
96
+ networks: config.networks || [],
97
+ evmSigner: config.evmSigner,
98
+ externalWalletSupport: !!config.externalWalletSupport,
99
+ apiKey: config.apiKey || '',
100
+ };
101
+ }
102
+
103
+ const answers = await inquirer.prompt<InteractiveAnswers>(questions);
104
+
105
+ return {
106
+ template: answers.template || template,
107
+ projectName: answers.projectName || config.projectName || defaultName,
108
+ networks: answers.networks || config.networks || [],
109
+ evmSigner: answers.evmSigner || config.evmSigner,
110
+ externalWalletSupport: answers.externalWalletSupport ?? config.externalWalletSupport ?? false,
111
+ apiKey: answers.apiKey || config.apiKey || '',
112
+ };
113
+ }
@@ -0,0 +1,54 @@
1
+ import { execCommand } from '../utils/exec.js';
2
+ import { logInfo } from '../utils/logger.js';
3
+
4
+ export async function scaffoldNextjs(config) {
5
+ logInfo(`🔧 Scaffolding Next.js app for project ${config.projectName}...`);
6
+ const versionTag = config.useLatest ? 'latest' : 'latest';
7
+
8
+ // Start with these flags for a default Next.js TS, ESLint, Tailwind, src, app setup
9
+ const baseFlags = new Set(['--typescript', '--eslint', '--tailwind', '--src-dir', '--app', '--no-turbopack', '--yes']);
10
+
11
+ // If user wants no typescript => remove --typescript, add --javascript
12
+ if (!config.typescript) {
13
+ baseFlags.delete('--typescript');
14
+ baseFlags.add('--javascript');
15
+ }
16
+ if (!config.eslint) {
17
+ baseFlags.delete('--eslint');
18
+ }
19
+ if (!config.tailwind) {
20
+ baseFlags.delete('--tailwind');
21
+ }
22
+ if (!config.srcDir) {
23
+ baseFlags.delete('--src-dir');
24
+ }
25
+ if (!config.app) {
26
+ baseFlags.delete('--app');
27
+ }
28
+
29
+ let cmd = `npx create-next-app@${versionTag} ${config.projectName}`;
30
+ for (const f of baseFlags) {
31
+ cmd += ` ${f}`;
32
+ }
33
+
34
+ if (config.noGit) {
35
+ cmd += ' --no-git';
36
+ }
37
+ if (config.skipDeps) {
38
+ cmd += ' --skip-install';
39
+ }
40
+ if (config.packageManager && config.packageManager !== 'yarn') {
41
+ if (config.packageManager === 'npm') {
42
+ cmd += ' --use-npm';
43
+ } else if (config.packageManager === 'pnpm') {
44
+ cmd += ' --use-pnpm';
45
+ } else if (config.packageManager === 'bun') {
46
+ // create-next-app doesn't have a built-in --use-bun, we might skip or log a warning
47
+ logInfo('Warning: create-next-app does not officially support "--use-bun". Using npm instead.');
48
+ cmd += ' --use-npm';
49
+ }
50
+ }
51
+
52
+ logInfo(`💻 Executing command: ${cmd}`);
53
+ await execCommand(cmd);
54
+ }
@@ -0,0 +1,33 @@
1
+ import { execCommand } from '../utils/exec.js';
2
+ import { logInfo } from '../utils/logger.js';
3
+
4
+ export async function scaffoldViteReact(config) {
5
+ logInfo(`🔧 Scaffolding Vite React app for project ${config.projectName}...`);
6
+ const versionTag = config.useLatest ? 'latest' : 'latest';
7
+
8
+ const templateName = config.typescript ? 'react-ts' : 'react';
9
+
10
+ let cmd = '';
11
+ if (config.packageManager === 'yarn') {
12
+ cmd = `yarn create vite ${config.projectName} --template ${templateName}`;
13
+ } else if (config.packageManager === 'npm') {
14
+ cmd = `npm create vite@${versionTag} ${config.projectName} --template ${templateName}`;
15
+ } else if (config.packageManager === 'pnpm') {
16
+ cmd = `pnpm dlx create-vite@${versionTag} ${config.projectName} --template ${templateName}`;
17
+ } else if (config.packageManager === 'bun') {
18
+ logInfo('Warning: "bun create vite" not officially tested. Using npm create instead.');
19
+ cmd = `npm create vite@${versionTag} ${config.projectName} --template ${templateName}`;
20
+ } else {
21
+ cmd = `npm create vite@${versionTag} ${config.projectName} --template ${templateName}`;
22
+ }
23
+
24
+ if (config.noGit) {
25
+ cmd += ' --no-git';
26
+ }
27
+ if (config.skipDeps) {
28
+ cmd += ' --skip-install';
29
+ }
30
+
31
+ logInfo(`💻 Executing command: ${cmd}`);
32
+ await execCommand(cmd);
33
+ }
@@ -0,0 +1,6 @@
1
+ import { execa } from 'execa';
2
+
3
+ export async function execCommand(command: string) {
4
+ const [cmd, ...args] = command.split(' ');
5
+ await execa(cmd, args, { stdio: 'inherit' });
6
+ }
@@ -0,0 +1,18 @@
1
+ import prettier from 'prettier';
2
+
3
+ export async function formatWithPrettier(code: string, filePath: string): Promise<string> {
4
+ let parser = 'babel';
5
+ if (filePath.endsWith('.ts')) {
6
+ parser = 'typescript';
7
+ } else if (filePath.endsWith('.tsx')) {
8
+ parser = 'babel-ts';
9
+ } else if (filePath.endsWith('.js')) {
10
+ parser = 'babel';
11
+ } else if (filePath.endsWith('.jsx')) {
12
+ parser = 'babel';
13
+ }
14
+ return prettier.format(code, {
15
+ parser,
16
+ singleQuote: true,
17
+ });
18
+ }
@@ -0,0 +1,25 @@
1
+ import chalk from 'chalk';
2
+
3
+ export function logHeader(message: string) {
4
+ console.log(chalk.bold.magentaBright(`\n${message}\n`));
5
+ }
6
+
7
+ export function logSection(message: string) {
8
+ console.log(chalk.bold.cyanBright(`\n${message}`));
9
+ }
10
+
11
+ export function logSubsection(key: string, value: string) {
12
+ console.log(chalk.green(`${key}: `) + chalk.white(`${value}`));
13
+ }
14
+
15
+ export function logStep(step: string) {
16
+ console.log(chalk.yellow(step));
17
+ }
18
+
19
+ export function logInfo(message: string) {
20
+ console.log(chalk.cyanBright(`- ${message}`));
21
+ }
22
+
23
+ export function logError(message: string) {
24
+ console.error(chalk.redBright(`❌ ${message}`));
25
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "ESNext", // your override for ESM
5
+ "resolveJsonModule": true,
6
+ "declaration": false,
7
+ "outDir": "./dist",
8
+ "rootDir": "./src", // <--- Add this line
9
+ "lib": ["dom"]
10
+ },
11
+ "include": ["src/**/*.ts"],
12
+ "ts-node": {
13
+ "esm": true,
14
+ "compilerOptions": {
15
+ "module": "ESNext"
16
+ }
17
+ }
18
+ }