@coinbase/create-cdp-app 0.0.39 → 0.0.41
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.
- package/dist/index.js +85 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/template-react-native/_gitignore +4 -0
- package/template-react-native/android/_gitignore +0 -16
- package/template-react-native/android/app/build.gradle +0 -177
- package/template-react-native/android/app/debug.keystore +0 -0
- package/template-react-native/android/app/proguard-rules.pro +0 -14
- package/template-react-native/android/app/src/debug/AndroidManifest.xml +0 -7
- package/template-react-native/android/app/src/main/AndroidManifest.xml +0 -25
- package/template-react-native/android/app/src/main/java/com/anonymous/reactnativeexpo/MainActivity.kt +0 -61
- package/template-react-native/android/app/src/main/java/com/anonymous/reactnativeexpo/MainApplication.kt +0 -57
- package/template-react-native/android/app/src/main/res/drawable/ic_launcher_background.xml +0 -6
- package/template-react-native/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
- package/template-react-native/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png +0 -0
- package/template-react-native/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png +0 -0
- package/template-react-native/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png +0 -0
- package/template-react-native/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png +0 -0
- package/template-react-native/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +0 -5
- package/template-react-native/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +0 -5
- package/template-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp +0 -0
- package/template-react-native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- package/template-react-native/android/app/src/main/res/values/colors.xml +0 -6
- package/template-react-native/android/app/src/main/res/values/strings.xml +0 -5
- package/template-react-native/android/app/src/main/res/values/styles.xml +0 -10
- package/template-react-native/android/app/src/main/res/values-night/colors.xml +0 -1
- package/template-react-native/android/build.gradle +0 -37
- package/template-react-native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/template-react-native/android/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/template-react-native/android/gradle.properties +0 -59
- package/template-react-native/android/gradlew +0 -251
- package/template-react-native/android/gradlew.bat +0 -94
- package/template-react-native/android/settings.gradle +0 -39
- package/template-react-native/ios/.xcode.env +0 -11
- package/template-react-native/ios/Podfile +0 -64
- package/template-react-native/ios/Podfile.lock +0 -2131
- package/template-react-native/ios/Podfile.properties.json +0 -5
- package/template-react-native/ios/_gitignore +0 -30
- package/template-react-native/ios/reactnativeexpo/AppDelegate.swift +0 -70
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/AppIcon.appiconset/Contents.json +0 -14
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/Contents.json +0 -6
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/SplashScreenBackground.colorset/Contents.json +0 -20
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/SplashScreenLogo.imageset/Contents.json +0 -23
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/SplashScreenLogo.imageset/image.png +0 -0
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/SplashScreenLogo.imageset/image@2x.png +0 -0
- package/template-react-native/ios/reactnativeexpo/Images.xcassets/SplashScreenLogo.imageset/image@3x.png +0 -0
- package/template-react-native/ios/reactnativeexpo/Info.plist +0 -74
- package/template-react-native/ios/reactnativeexpo/PrivacyInfo.xcprivacy +0 -48
- package/template-react-native/ios/reactnativeexpo/SplashScreen.storyboard +0 -44
- package/template-react-native/ios/reactnativeexpo/Supporting/Expo.plist +0 -12
- package/template-react-native/ios/reactnativeexpo/reactnativeexpo-Bridging-Header.h +0 -3
- package/template-react-native/ios/reactnativeexpo/reactnativeexpo.entitlements +0 -5
- package/template-react-native/ios/reactnativeexpo.xcodeproj/project.pbxproj +0 -545
- package/template-react-native/ios/reactnativeexpo.xcodeproj/xcshareddata/xcschemes/reactnativeexpo.xcscheme +0 -88
- package/template-react-native/ios/reactnativeexpo.xcworkspace/contents.xcworkspacedata +0 -10
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -492,8 +493,8 @@ async function init() {
|
|
|
492
493
|
apiKeyId,
|
|
493
494
|
apiKeySecret
|
|
494
495
|
} = await getAppDetails();
|
|
495
|
-
console.log(`
|
|
496
|
-
Scaffolding app in ${targetDirectory}...`);
|
|
496
|
+
console.log(yellow(`
|
|
497
|
+
Scaffolding app in ${targetDirectory}...`));
|
|
497
498
|
const root = prepareAppDirectory(targetDirectory);
|
|
498
499
|
const templateDir = path.resolve(fileURLToPath(import.meta.url), "../..", `template-${template}`);
|
|
499
500
|
copyTemplateFiles({
|
|
@@ -506,6 +507,9 @@ Scaffolding app in ${targetDirectory}...`);
|
|
|
506
507
|
apiKeyId,
|
|
507
508
|
apiKeySecret
|
|
508
509
|
});
|
|
510
|
+
console.log(green("✓ Creating project using template: " + template));
|
|
511
|
+
await installDependencies(root);
|
|
512
|
+
await initializeGit(root);
|
|
509
513
|
printNextSteps(root, template);
|
|
510
514
|
}
|
|
511
515
|
function printNextSteps(appRoot, template) {
|
|
@@ -514,7 +518,6 @@ function printNextSteps(appRoot, template) {
|
|
|
514
518
|
if (appRoot !== process.cwd()) {
|
|
515
519
|
console.log(`cd ${path.relative(process.cwd(), appRoot)}`);
|
|
516
520
|
}
|
|
517
|
-
console.log(`${packageManager} install`);
|
|
518
521
|
if (template === "react-native") {
|
|
519
522
|
const startCommand = packageManager === "npm" ? "npm run ios # or npm run android" : `${packageManager} run ios # or ${packageManager} run android`;
|
|
520
523
|
console.log(startCommand);
|
|
@@ -563,15 +566,6 @@ function copyTemplateFiles({
|
|
|
563
566
|
apiKeyId,
|
|
564
567
|
apiKeySecret
|
|
565
568
|
});
|
|
566
|
-
console.log("Copying CDP Project ID to .env");
|
|
567
|
-
if (apiKeyId && apiKeySecret) {
|
|
568
|
-
console.log("Copying CDP API credentials to .env");
|
|
569
|
-
}
|
|
570
|
-
if (accountType === "evm-smart") {
|
|
571
|
-
console.log("Configuring Smart Accounts in environment");
|
|
572
|
-
} else if (accountType === "solana") {
|
|
573
|
-
console.log("Configuring Solana accounts in environment");
|
|
574
|
-
}
|
|
575
569
|
writeFileToTarget(".env", customizedEnv);
|
|
576
570
|
} else if (file === "app.json" && isReactNative && (reactNativeCustomizations == null ? void 0 : reactNativeCustomizations.appJson)) {
|
|
577
571
|
writeFileToTarget(file, reactNativeCustomizations.appJson);
|
|
@@ -583,11 +577,6 @@ function copyTemplateFiles({
|
|
|
583
577
|
const configFileName = isNextjs ? "src/components/Providers.tsx" : "src/config.ts";
|
|
584
578
|
const customizedConfig = customizeConfig(templateDir, accountType, isNextjs);
|
|
585
579
|
if (customizedConfig) {
|
|
586
|
-
if (accountType === "evm-smart") {
|
|
587
|
-
console.log("Configuring Smart Accounts in application config");
|
|
588
|
-
} else if (accountType === "solana") {
|
|
589
|
-
console.log("Configuring Solana accounts in application config");
|
|
590
|
-
}
|
|
591
580
|
writeFileToTarget(configFileName, customizedConfig);
|
|
592
581
|
}
|
|
593
582
|
}
|
|
@@ -667,6 +656,85 @@ function generateTransactionComponent(accountType) {
|
|
|
667
656
|
return `export { default } from "./EOATransaction";`;
|
|
668
657
|
}
|
|
669
658
|
}
|
|
659
|
+
async function initializeGit(appRoot) {
|
|
660
|
+
return new Promise((resolve) => {
|
|
661
|
+
console.log(yellow("\nInitializing git repository..."));
|
|
662
|
+
const gitInit = spawn("git", ["init"], {
|
|
663
|
+
cwd: appRoot,
|
|
664
|
+
stdio: "pipe"
|
|
665
|
+
});
|
|
666
|
+
gitInit.on("close", (code) => {
|
|
667
|
+
if (code === 0) {
|
|
668
|
+
console.log(green("✓ Git repository initialized"));
|
|
669
|
+
const gitAdd = spawn("git", ["add", "."], {
|
|
670
|
+
cwd: appRoot,
|
|
671
|
+
stdio: "pipe"
|
|
672
|
+
});
|
|
673
|
+
gitAdd.on("close", (addCode) => {
|
|
674
|
+
if (addCode === 0) {
|
|
675
|
+
const gitCommit = spawn("git", ["commit", "-m", "Initial commit from Create CDP App"], {
|
|
676
|
+
cwd: appRoot,
|
|
677
|
+
stdio: "pipe",
|
|
678
|
+
env: {
|
|
679
|
+
...process.env
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
gitCommit.on("close", (commitCode) => {
|
|
683
|
+
if (commitCode !== 0) {
|
|
684
|
+
console.log(yellow("⚠ Could not automatically create initial commit"));
|
|
685
|
+
}
|
|
686
|
+
resolve();
|
|
687
|
+
});
|
|
688
|
+
gitCommit.on("error", () => {
|
|
689
|
+
console.log(yellow("⚠ Could not automatically create initial commit"));
|
|
690
|
+
resolve();
|
|
691
|
+
});
|
|
692
|
+
} else {
|
|
693
|
+
console.log(yellow("⚠ Could not automatically add files to git"));
|
|
694
|
+
resolve();
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
gitAdd.on("error", () => {
|
|
698
|
+
console.log(yellow("⚠ Could not automatically add files to git"));
|
|
699
|
+
resolve();
|
|
700
|
+
});
|
|
701
|
+
} else {
|
|
702
|
+
console.log(yellow("⚠ Could not initialize git repository"));
|
|
703
|
+
resolve();
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
gitInit.on("error", () => {
|
|
707
|
+
console.log(yellow("⚠ Git not found - skipping git initialization"));
|
|
708
|
+
resolve();
|
|
709
|
+
});
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
async function installDependencies(appRoot) {
|
|
713
|
+
const packageManager = detectPackageManager();
|
|
714
|
+
return new Promise((resolve) => {
|
|
715
|
+
console.log(yellow(`
|
|
716
|
+
Installing dependencies with ${packageManager}...`));
|
|
717
|
+
const child = spawn(packageManager, ["install"], {
|
|
718
|
+
cwd: appRoot,
|
|
719
|
+
stdio: "inherit"
|
|
720
|
+
});
|
|
721
|
+
child.on("close", (code) => {
|
|
722
|
+
if (code === 0) {
|
|
723
|
+
console.log(green("✓ Dependencies installed successfully"));
|
|
724
|
+
resolve();
|
|
725
|
+
} else {
|
|
726
|
+
console.log(yellow("⚠ Failed to install dependencies"));
|
|
727
|
+
console.log(`You can manually install dependencies by running: ${packageManager} install`);
|
|
728
|
+
resolve();
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
child.on("error", (error) => {
|
|
732
|
+
console.log(yellow(`⚠ Could not run ${packageManager}: ${error.message}`));
|
|
733
|
+
console.log(`You can manually install dependencies by running: ${packageManager} install`);
|
|
734
|
+
resolve();
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
}
|
|
670
738
|
init().catch((e) => {
|
|
671
739
|
console.error(e);
|
|
672
740
|
process.exit(1);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/utils.ts","../src/getAppDetails.ts","../src/index.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/**\n * Prepare the app directory\n *\n * @param targetDir - The target directory for the app\n * @param shouldOverwrite - Whether to overwrite the existing directory\n * @returns The path to the prepared app directory\n */\nexport function prepareAppDirectory(targetDir: string, shouldOverwrite: boolean): string {\n const root = path.join(process.cwd(), targetDir);\n\n if (shouldOverwrite) {\n emptyDir(root);\n } else if (!fs.existsSync(root)) {\n fs.mkdirSync(root, { recursive: true });\n }\n\n return root;\n}\n\n/**\n * Customize package.json for the new app\n *\n * @param templateDir - The directory containing the template files\n * @param appName - The name of the app\n * @param includeSdk - Whether to include the CDP SDK in the dependencies\n * @returns The customized package.json content\n */\nexport function customizePackageJson(\n templateDir: string,\n appName: string,\n includeSdk?: boolean,\n): string {\n const packageJsonPath = path.join(templateDir, \"package.json\");\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n packageJson.name = appName;\n if (includeSdk) {\n packageJson.dependencies[\"@coinbase/cdp-sdk\"] = \"latest\";\n }\n return JSON.stringify(packageJson, null, 2) + \"\\n\";\n}\n\n/**\n * Set up the .env file for the new app\n *\n * @param params - The parameters for the function\n * @param params.templateDir - The directory containing the template files\n * @param params.projectId - The CDP Project ID\n * @param params.accountType - The account type to configure\n * @param params.apiKeyId - The API Key ID\n * @param params.apiKeySecret - The API Key Secret\n * @returns The customized .env content\n */\nexport function customizeEnv({\n templateDir,\n projectId,\n accountType,\n apiKeyId,\n apiKeySecret,\n}: {\n templateDir: string;\n projectId: string;\n accountType: string;\n apiKeyId?: string;\n apiKeySecret?: string;\n}): string {\n const exampleEnvPath = path.join(templateDir, \"env.example\");\n const exampleEnv = fs.readFileSync(exampleEnvPath, \"utf-8\");\n\n let envContent = exampleEnv.replace(/(.*PROJECT_ID=).*(\\r?\\n|$)/, `$1${projectId}\\n`);\n\n let prefix: string;\n if (templateDir.includes(\"nextjs\")) {\n prefix = \"NEXT_PUBLIC_\";\n } else if (templateDir.includes(\"react-native\")) {\n prefix = \"EXPO_PUBLIC_\";\n } else {\n prefix = \"VITE_\";\n }\n // Handle account type configuration\n if (accountType === \"solana\") {\n // For Solana-only accounts, remove Ethereum line and enable Solana\n envContent = envContent.replace(\n new RegExp(`${prefix}CDP_CREATE_ETHEREUM_ACCOUNT_TYPE=.*(\\r?\\n|$)`, \"g\"),\n \"\",\n );\n envContent = envContent.replace(\n new RegExp(`(${prefix}CDP_CREATE_SOLANA_ACCOUNT=).*(\\r?\\n|$)`),\n `$1true\\n`,\n );\n } else {\n // For EVM accounts (evm-eoa or evm-smart), set the Ethereum type and remove Solana line\n const ethereumType = accountType === \"evm-smart\" ? \"smart\" : \"eoa\";\n envContent = envContent.replace(\n new RegExp(`(${prefix}CDP_CREATE_ETHEREUM_ACCOUNT_TYPE=).*(\\r?\\n|$)`),\n `$1${ethereumType}\\n`,\n );\n envContent = envContent.replace(\n new RegExp(`${prefix}CDP_CREATE_SOLANA_ACCOUNT=.*(\\r?\\n|$)`, \"g\"),\n \"\",\n );\n }\n\n // Replace CDP API credentials if provided\n if (apiKeyId && apiKeySecret) {\n // Replace the commented API Key ID\n envContent = envContent.replace(/# CDP_API_KEY_ID=.*/, `CDP_API_KEY_ID=${apiKeyId}`);\n // Replace the commented API Key Secret\n envContent = envContent.replace(\n /# CDP_API_KEY_SECRET=.*/,\n `CDP_API_KEY_SECRET=${apiKeySecret}`,\n );\n }\n\n return envContent;\n}\n\n/**\n * Customize configuration files for account types\n *\n * @param templateDir - The directory containing the template files\n * @param accountType - The account type to configure\n * @param isNextjs - Whether this is a Next.js template\n * @returns The customized config content\n */\nexport function customizeConfig(\n templateDir: string,\n accountType: string,\n isNextjs: boolean,\n): string | null {\n if (accountType === \"evm-eoa\") return null;\n\n const configFileName = isNextjs ? \"src/components/Providers.tsx\" : \"src/config.ts\";\n const configPath = path.join(templateDir, configFileName);\n\n if (!fs.existsSync(configPath)) return null;\n\n let configContent = fs.readFileSync(configPath, \"utf-8\");\n\n if (isNextjs) {\n // For Next.js Providers.tsx - generate config based on account type\n const ethereumConfig =\n accountType !== \"solana\"\n ? `\n ethereum: {\n createOnLogin: process.env.NEXT_PUBLIC_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE === \"smart\" ? \"smart\" : \"eoa\",\n },`\n : \"\";\n\n const solanaConfig =\n accountType === \"solana\"\n ? `\n solana: {\n createOnLogin: process.env.NEXT_PUBLIC_CDP_CREATE_SOLANA_ACCOUNT === \"true\" ? true : false,\n },`\n : \"\";\n\n configContent = configContent.replace(\n /const CDP_CONFIG: Config = \\{[\\s\\S]*?\\};/,\n `const CDP_CONFIG: Config = {\n projectId: process.env.NEXT_PUBLIC_CDP_PROJECT_ID ?? \"\",${ethereumConfig}${solanaConfig}\n appName: \"CDP Next.js StarterKit\",\n appLogoUrl: \"http://localhost:3000/logo.svg\",\n authMethods: [\"email\", \"sms\"],\n};`,\n );\n } else {\n // For React config.ts - generate config based on account type\n const ethereumConfig =\n accountType !== \"solana\"\n ? `\n ethereum: {\n createOnLogin: import.meta.env.VITE_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE === \"smart\" ? \"smart\" : \"eoa\",\n },`\n : \"\";\n\n const solanaConfig =\n accountType === \"solana\"\n ? `\n solana: {\n createOnLogin: import.meta.env.VITE_CDP_CREATE_SOLANA_ACCOUNT === \"true\" ? true : false,\n },`\n : \"\";\n\n configContent = configContent.replace(\n /export const CDP_CONFIG: Config = \\{[\\s\\S]*?\\};/,\n `export const CDP_CONFIG: Config = {\n projectId: import.meta.env.VITE_CDP_PROJECT_ID,${ethereumConfig}${solanaConfig}\n appName: \"CDP React StarterKit\",\n appLogoUrl: \"http://localhost:3000/logo.svg\",\n authMethods: [\"email\", \"sms\"],\n};`,\n );\n }\n\n return configContent;\n}\n\n/**\n * Customize SignedInScreen to import the correct transaction component\n *\n * @param templateDir - The directory containing the template files\n * @param accountType - The account type to configure\n * @param isNextjs - Whether this is a Next.js template\n * @param fileName - The specific file name to customize\n * @returns The customized SignedInScreen content\n */\nexport function customizeSignedInScreen(\n templateDir: string,\n accountType: string,\n isNextjs: boolean,\n fileName: string = \"SignedInScreen.tsx\",\n): string {\n const signedInScreenPath = isNextjs\n ? path.join(templateDir, `src/components/${fileName}`)\n : path.join(templateDir, `src/${fileName}`);\n\n let content = fs.readFileSync(signedInScreenPath, \"utf-8\");\n\n // Determine the correct component import based on account type\n let componentPath: string;\n\n if (accountType === \"solana\") {\n componentPath = isNextjs ? \"@/components/SolanaTransaction\" : \"./SolanaTransaction\";\n } else if (accountType === \"evm-smart\") {\n componentPath = isNextjs ? \"@/components/SmartAccountTransaction\" : \"./SmartAccountTransaction\";\n } else {\n componentPath = isNextjs ? \"@/components/EOATransaction\" : \"./EOATransaction\";\n }\n\n const componentImport = `const TransactionComponent = lazy(() => import(\"${componentPath}\"));`;\n\n // Replace the conditional import logic with a single direct import\n if (isNextjs) {\n // Handle both SignedInScreen and SignedInScreenWithOnramp patterns\n content = content.replace(\n /\\/\\/ Dynamically (import components based on configuration|determine component path)[\\s\\S]*?const TransactionComponent = lazy\\(\\(\\) => (\\{[\\s\\S]*?\\}|import\\(\\/\\* @vite-ignore \\*\\/ getComponentPath\\(\\)\\))\\);/,\n componentImport,\n );\n } else {\n content = content.replace(\n /\\/\\/ Dynamically determine component path to avoid Vite static analysis[\\s\\S]*?const TransactionComponent = lazy\\(\\(\\) => import\\(\\/\\* @vite-ignore \\*\\/ getComponentPath\\(\\)\\)\\);/,\n componentImport,\n );\n }\n\n return content;\n}\n\n/**\n * Copy a file or directory recursively\n *\n * @param filePath - The source path\n * @param destPath - The destination path\n */\nexport function copyFile(filePath: string, destPath: string): void {\n const stat = fs.statSync(filePath);\n if (stat.isDirectory()) {\n copyDir(filePath, destPath);\n } else {\n fs.copyFileSync(filePath, destPath);\n }\n}\n\n/**\n * Copy a file or directory recursively with selective filtering for transaction components\n *\n * @param params - The parameters for the function\n * @param params.filePath - The source path\n * @param params.destPath - The destination path\n * @param params.accountType - The account type to use\n * @param params.enableOnramp - Whether to include Onramp\n */\nexport function copyFileSelectively({\n filePath,\n destPath,\n accountType,\n enableOnramp,\n}: {\n filePath: string;\n destPath: string;\n accountType: string;\n enableOnramp?: boolean;\n}): void {\n const stat = fs.statSync(filePath);\n if (stat.isDirectory()) {\n const baseDir = path.basename(filePath);\n // skip api and lib directories if Onramp is not enabled\n if (!enableOnramp && (baseDir === \"api\" || baseDir === \"lib\")) return;\n // copy the directory\n copyDirSelectively({ srcDir: filePath, destDir: destPath, accountType, enableOnramp });\n } else {\n const fileName = path.basename(filePath);\n\n // Skip transaction components that don't match the user's choice\n if (accountType === \"evm-smart\" && fileName === \"EOATransaction.tsx\") return;\n if (accountType === \"evm-smart\" && fileName === \"SolanaTransaction.tsx\") return;\n if (accountType === \"evm-eoa\" && fileName === \"SmartAccountTransaction.tsx\") return;\n if (accountType === \"evm-eoa\" && fileName === \"SolanaTransaction.tsx\") return;\n if (accountType === \"solana\" && fileName === \"EOATransaction.tsx\") return;\n if (accountType === \"solana\" && fileName === \"SmartAccountTransaction.tsx\") return;\n\n // Skip Onramp files if the user didn't enable Onramp\n if (!enableOnramp && [\"FundWallet.tsx\", \"SignedInScreenWithOnramp.tsx\"].includes(fileName))\n return;\n // Onramp-specific SignedInScreen\n if (enableOnramp) {\n // Skip the default SignedInScreen.tsx file\n if (fileName === \"SignedInScreen.tsx\") return;\n // Copy the SignedInScreenWithOnramp.tsx file to SignedInScreen.tsx\n if (fileName === \"SignedInScreenWithOnramp.tsx\") {\n const newDestPath = destPath.replace(\"SignedInScreenWithOnramp.tsx\", \"SignedInScreen.tsx\");\n fs.copyFileSync(filePath, newDestPath);\n return;\n }\n }\n\n fs.copyFileSync(filePath, destPath);\n }\n}\n\n/**\n * Copy a directory recursively\n *\n * @param srcDir - The source directory path\n * @param destDir - The destination directory path\n */\nfunction copyDir(srcDir: string, destDir: string): void {\n fs.mkdirSync(destDir, { recursive: true });\n for (const file of fs.readdirSync(srcDir)) {\n const srcFile = path.resolve(srcDir, file);\n const destFile = path.resolve(destDir, file);\n copyFile(srcFile, destFile);\n }\n}\n\n/**\n * Copy a directory recursively with selective filtering\n *\n * @param params - The parameters for the function\n * @param params.srcDir - The source directory path\n * @param params.destDir - The destination directory path\n * @param params.accountType - The account type to use\n * @param params.enableOnramp - Whether to include Onramp\n */\nfunction copyDirSelectively({\n srcDir,\n destDir,\n accountType,\n enableOnramp,\n}: {\n srcDir: string;\n destDir: string;\n accountType: string;\n enableOnramp?: boolean;\n}): void {\n fs.mkdirSync(destDir, { recursive: true });\n for (const file of fs.readdirSync(srcDir)) {\n const srcFile = path.resolve(srcDir, file);\n const destFile = path.resolve(destDir, file);\n copyFileSelectively({ filePath: srcFile, destPath: destFile, accountType, enableOnramp });\n }\n}\n\n/**\n * Check if a directory is empty\n *\n * @param dirPath - The path to the directory\n * @returns True if the directory is empty, false otherwise\n */\nexport function isDirEmpty(dirPath: string): boolean {\n const files = fs.readdirSync(dirPath);\n return files.length === 0 || (files.length === 1 && files[0] === \".git\");\n}\n\n/**\n * Empty a directory while preserving .git\n *\n * @param dirPath - The path to the directory\n */\nfunction emptyDir(dirPath: string): void {\n if (!fs.existsSync(dirPath)) {\n return;\n }\n for (const file of fs.readdirSync(dirPath)) {\n if (file === \".git\") {\n continue;\n }\n fs.rmSync(path.resolve(dirPath, file), { recursive: true, force: true });\n }\n}\n\n/**\n * Customize React Native specific files with unique bundle identifier\n *\n * @param templateDir - The directory containing the template files\n * @param appName - The name of the app\n * @returns Object containing customized file contents and new package path\n */\nexport function customizeReactNativeFiles(\n templateDir: string,\n appName: string,\n): {\n appJson?: string;\n infoPlist?: string;\n buildGradle?: string;\n mainActivity?: string;\n mainApplication?: string;\n xcodeProject?: string;\n newPackagePath: string;\n safeBundleId: string;\n} {\n const username = os.userInfo().username || \"user\";\n const cleanUsername = username.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n const cleanAppName = appName.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n const safeBundleId = `com.${cleanUsername}.${cleanAppName}`;\n const newPackagePath = `com/${cleanUsername}/${cleanAppName}`;\n\n const customizedFiles: {\n appJson?: string;\n infoPlist?: string;\n buildGradle?: string;\n mainActivity?: string;\n mainApplication?: string;\n xcodeProject?: string;\n newPackagePath: string;\n safeBundleId: string;\n } = { safeBundleId, newPackagePath };\n\n // Customize app.json\n const appJsonPath = path.join(templateDir, \"app.json\");\n if (fs.existsSync(appJsonPath)) {\n const appJsonContent = fs.readFileSync(appJsonPath, \"utf-8\");\n customizedFiles.appJson = appJsonContent\n .replace(/com\\.anonymous\\.reactnativeexpo/g, safeBundleId)\n .replace(/\"name\": \"react-native-expo\"/g, `\"name\": \"${appName}\"`);\n }\n\n // Customize iOS Info.plist\n const infoPlistPath = path.join(templateDir, \"ios/reactnativeexpo/Info.plist\");\n if (fs.existsSync(infoPlistPath)) {\n const infoPlistContent = fs.readFileSync(infoPlistPath, \"utf-8\");\n customizedFiles.infoPlist = infoPlistContent.replace(\n /com\\.anonymous\\.reactnativeexpo/g,\n safeBundleId,\n );\n }\n\n // Customize Android build.gradle\n const buildGradlePath = path.join(templateDir, \"android/app/build.gradle\");\n if (fs.existsSync(buildGradlePath)) {\n const buildGradleContent = fs.readFileSync(buildGradlePath, \"utf-8\");\n customizedFiles.buildGradle = buildGradleContent.replace(\n /com\\.anonymous\\.reactnativeexpo/g,\n safeBundleId,\n );\n }\n\n // Customize MainActivity.kt\n const mainActivityPath = path.join(\n templateDir,\n \"android/app/src/main/java/com/anonymous/reactnativeexpo/MainActivity.kt\",\n );\n if (fs.existsSync(mainActivityPath)) {\n const mainActivityContent = fs.readFileSync(mainActivityPath, \"utf-8\");\n customizedFiles.mainActivity = mainActivityContent.replace(\n /package com\\.anonymous\\.reactnativeexpo/g,\n `package ${safeBundleId}`,\n );\n }\n\n // Customize MainApplication.kt\n const mainApplicationPath = path.join(\n templateDir,\n \"android/app/src/main/java/com/anonymous/reactnativeexpo/MainApplication.kt\",\n );\n if (fs.existsSync(mainApplicationPath)) {\n const mainApplicationContent = fs.readFileSync(mainApplicationPath, \"utf-8\");\n customizedFiles.mainApplication = mainApplicationContent.replace(\n /package com\\.anonymous\\.reactnativeexpo/g,\n `package ${safeBundleId}`,\n );\n }\n\n // Customize iOS Xcode project file - only replace bundle identifier\n const xcodeProjectPath = path.join(templateDir, \"ios/reactnativeexpo.xcodeproj/project.pbxproj\");\n if (fs.existsSync(xcodeProjectPath)) {\n const xcodeProjectContent = fs.readFileSync(xcodeProjectPath, \"utf-8\");\n customizedFiles.xcodeProject = xcodeProjectContent.replace(\n /com\\.anonymous\\.reactnativeexpo/g,\n safeBundleId,\n );\n }\n\n return customizedFiles;\n}\n\n/**\n * Detect which package manager invoked the create command\n *\n * @returns The detected package manager or 'pnpm' as default\n */\nexport function detectPackageManager(): \"npm\" | \"pnpm\" | \"yarn\" {\n const userAgent = process.env.npm_config_user_agent;\n\n if (userAgent) {\n if (userAgent.startsWith(\"yarn\")) return \"yarn\";\n if (userAgent.startsWith(\"pnpm\")) return \"pnpm\";\n if (userAgent.startsWith(\"npm\")) return \"npm\";\n }\n\n return \"npm\"; // Default to npm if we can't detect\n}\n","#!/usr/bin/env node\n\nimport fs from \"node:fs\";\n\nimport { green, red, reset, yellow } from \"kolorist\";\nimport minimist from \"minimist\";\nimport prompts from \"prompts\";\n\nimport { isDirEmpty } from \"./utils.js\";\n\nconst defaultTargetDir = \"cdp-app\";\n\n// Available templates for app creation\nconst TEMPLATES = [\n {\n name: \"react\",\n display: \"React Single Page App\",\n color: green,\n },\n {\n name: \"nextjs\",\n display: \"Next.js Full Stack App\",\n color: green,\n },\n {\n name: \"react-native\",\n display: \"React Native with Expo\",\n color: green,\n },\n] as const;\n\nconst TEMPLATE_NAMES = TEMPLATES.map(template => template.name);\n\ntype TemplateName = (typeof TEMPLATE_NAMES)[number];\n\n// Account types that can be created\nconst ACCOUNT_TYPES = [\n {\n value: \"evm-eoa\",\n title: \"EVM EOA (Regular Accounts)\",\n description: \"Traditional Ethereum-compatible accounts\",\n },\n {\n value: \"evm-smart\",\n title: \"EVM Smart Accounts\",\n description: \"Account abstraction with gasless transactions and improved UX\",\n },\n {\n value: \"solana\",\n title: \"Solana Accounts\",\n description: \"Native Solana blockchain accounts\",\n },\n] as const;\n\ntype AccountType = (typeof ACCOUNT_TYPES)[number][\"value\"];\n\n/**\n * App options\n */\nexport interface AppOptions {\n appName: string;\n template: TemplateName;\n targetDirectory: string;\n projectId: string;\n accountType: AccountType;\n enableOnramp: boolean;\n apiKeyId?: string;\n apiKeySecret?: string;\n}\n\ntype CommandLineArgs = {\n \"project-id\": string;\n template: TemplateName;\n \"account-type\"?: AccountType;\n onramp?: boolean;\n};\n\nconst uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Get app details from command line arguments or prompt the user\n *\n * @returns The app details\n */\nexport async function getAppDetails(): Promise<AppOptions> {\n const argv = minimist<CommandLineArgs>(process.argv.slice(2));\n\n // Get target directory from command line args (first non-option argument)\n let targetDir = argv._[0];\n const defaultAppName = targetDir ?? defaultTargetDir;\n let templateFromArgs: TemplateName | undefined = undefined;\n let projectIdFromArgs: string | undefined = undefined;\n let enableOnrampFromArgs: boolean | undefined = undefined;\n let accountTypeFromArgs: AccountType | undefined = undefined;\n\n // Validate template from argv\n if (argv.template) {\n if (!TEMPLATE_NAMES.includes(argv.template)) {\n console.log(\n yellow(\n `✖ Invalid template provided: \"${argv.template}\". Please choose from: ${TEMPLATE_NAMES.join(\", \")}.`,\n ),\n );\n } else {\n templateFromArgs = argv.template;\n }\n }\n\n // Validate projectId from argv\n if (argv[\"project-id\"]) {\n if (!uuidRegex.test(argv[\"project-id\"])) {\n console.log(\n yellow(`✖ Invalid Project ID provided: \"${argv.projectId}\". Please enter a valid UUID.`),\n );\n } else {\n projectIdFromArgs = argv[\"project-id\"];\n }\n }\n\n // Validate account type from argv\n if (argv[\"account-type\"]) {\n const validAccountTypes = ACCOUNT_TYPES.map(type => type.value);\n if (!validAccountTypes.includes(argv[\"account-type\"])) {\n console.log(\n yellow(\n `✖ Invalid account type provided: \"${argv[\"account-type\"]}\". Please choose from: ${validAccountTypes.join(\", \")}.`,\n ),\n );\n } else {\n accountTypeFromArgs = argv[\"account-type\"];\n }\n }\n\n // Validate compatible template for onramp\n if (argv[\"onramp\"] !== undefined) {\n if (!argv[\"onramp\"]) {\n enableOnrampFromArgs = false;\n } else {\n // if template is not provided and onramp is enabled, force nextjs template\n if (!templateFromArgs) {\n templateFromArgs = \"nextjs\";\n }\n if (templateFromArgs !== \"nextjs\") {\n console.log(yellow(`✖ Onramp is only supported with the Next.js template.`));\n } else {\n enableOnrampFromArgs = true;\n }\n }\n }\n\n try {\n const result = await prompts(\n [\n {\n type: targetDir ? null : \"text\",\n name: \"appName\",\n message: reset(\"App Name:\"),\n initial: defaultAppName,\n onState: state => {\n targetDir = String(state.value).trim() || defaultAppName;\n },\n },\n {\n type: templateFromArgs ? null : \"select\",\n name: \"template\",\n message: reset(\"Template:\"),\n initial: 0,\n choices: TEMPLATES.map(template => ({\n title: template.color(template.display),\n value: template.name,\n })),\n },\n {\n type: projectIdFromArgs ? null : \"text\",\n name: \"projectId\",\n message: reset(\n \"CDP Project ID (Find your project ID at https://portal.cdp.coinbase.com/projects/overview):\",\n ),\n validate: value => {\n if (!value) {\n return \"Project ID is required\";\n } else if (!uuidRegex.test(value)) {\n return \"Project ID must be a valid UUID\";\n }\n return true;\n },\n initial: \"\",\n },\n {\n type: accountTypeFromArgs ? null : \"select\",\n name: \"accountType\",\n message: reset(\"Account Type:\"),\n initial: 0,\n choices: ACCOUNT_TYPES.map(accountType => ({\n title: accountType.title,\n description: accountType.description,\n value: accountType.value,\n })),\n },\n {\n type: (_, { template }: { template?: string }) =>\n enableOnrampFromArgs !== undefined || (templateFromArgs || template) !== \"nextjs\"\n ? null\n : \"confirm\",\n name: \"enableOnramp\",\n message: reset(\"Enable Coinbase Onramp? (Onramp enables users to buy crypto with fiat):\"),\n initial: false,\n },\n {\n type: (_, { enableOnramp }: { enableOnramp?: boolean }) =>\n enableOnramp || enableOnrampFromArgs ? \"text\" : null,\n name: \"apiKeyId\",\n message: reset(\"CDP API Key ID (Create at https://portal.cdp.coinbase.com/api-keys):\"),\n validate: value => {\n if (!value) {\n return \"API Key ID is required for Onramp\";\n }\n return true;\n },\n },\n {\n type: (_, { enableOnramp }: { enableOnramp?: boolean }) =>\n enableOnramp || enableOnrampFromArgs ? \"password\" : null,\n name: \"apiKeySecret\",\n message: reset(\"CDP API Key Secret (paste your private key - it will be hidden):\"),\n validate: value => {\n if (!value) {\n return \"API Key Secret is required for Onramp\";\n }\n return true;\n },\n },\n {\n type: (_, { template }: { template?: string }) =>\n (templateFromArgs || template) === \"react-native\" ? null : \"confirm\",\n name: \"corsConfirmation\",\n message: reset(\n \"Confirm you have whitelisted 'http://localhost:3000' at https://portal.cdp.coinbase.com/products/embedded-wallets/domains:\",\n ),\n initial: true,\n },\n {\n type: () => (!fs.existsSync(targetDir) || isDirEmpty(targetDir) ? null : \"confirm\"),\n name: \"overwrite\",\n message: () =>\n (targetDir === \".\" ? \"Current directory\" : `Target directory \"${targetDir}\"`) +\n \" is not empty. Remove existing files and continue?\",\n },\n {\n type: (_, { overwrite }: { overwrite?: boolean }) => {\n if (overwrite === false) {\n throw new Error(red(\"✖\") + \" Operation cancelled\");\n }\n return null;\n },\n name: \"overwriteChecker\",\n },\n ],\n {\n onCancel: () => {\n throw new Error(red(\"✖\") + \" Operation cancelled\");\n },\n },\n );\n\n return {\n appName: result.appName || targetDir,\n template: templateFromArgs || result.template,\n targetDirectory: targetDir,\n projectId: projectIdFromArgs || result.projectId,\n accountType: accountTypeFromArgs || result.accountType,\n enableOnramp: enableOnrampFromArgs ?? result.enableOnramp ?? false,\n apiKeyId: result.apiKeyId,\n apiKeySecret: result.apiKeySecret,\n };\n } catch (cancelled: unknown) {\n if (cancelled instanceof Error) {\n console.log(cancelled.message);\n }\n process.exit(0);\n }\n}\n","#!/usr/bin/env node\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { green } from \"kolorist\";\n\nimport { getAppDetails } from \"./getAppDetails.js\";\nimport {\n prepareAppDirectory,\n customizePackageJson,\n copyFileSelectively,\n customizeEnv,\n customizeConfig,\n customizeSignedInScreen,\n customizeReactNativeFiles,\n detectPackageManager,\n} from \"./utils.js\";\n\nconst fileRenames: Record<string, string | undefined> = {\n _gitignore: \".gitignore\",\n};\n\n/**\n * Initialize a new CDP app\n */\nasync function init(): Promise<void> {\n const {\n appName,\n template,\n targetDirectory,\n projectId,\n accountType,\n enableOnramp,\n apiKeyId,\n apiKeySecret,\n } = await getAppDetails();\n\n console.log(`\\nScaffolding app in ${targetDirectory}...`);\n\n const root = prepareAppDirectory(targetDirectory, false);\n const templateDir = path.resolve(fileURLToPath(import.meta.url), \"../..\", `template-${template}`);\n\n copyTemplateFiles({\n templateDir,\n root,\n appName,\n projectId,\n accountType,\n enableOnramp,\n apiKeyId,\n apiKeySecret,\n });\n printNextSteps(root, template);\n}\n\n/**\n * Print next steps for the user\n *\n * @param appRoot - The root directory of the app\n * @param template - The template that was used\n */\nfunction printNextSteps(appRoot: string, template: string): void {\n const packageManager = detectPackageManager();\n\n console.log(green(\"\\nDone. Now run your app:\\n\"));\n if (appRoot !== process.cwd()) {\n console.log(`cd ${path.relative(process.cwd(), appRoot)}`);\n }\n\n console.log(`${packageManager} install`);\n\n if (template === \"react-native\") {\n const startCommand =\n packageManager === \"npm\"\n ? \"npm run ios # or npm run android\"\n : `${packageManager} run ios # or ${packageManager} run android`;\n console.log(startCommand);\n } else {\n const devCommand = packageManager === \"npm\" ? \"npm run dev\" : `${packageManager} dev`;\n console.log(devCommand);\n }\n}\n\n/**\n * Copy template files to the app directory\n *\n * @param params - The parameters for the function\n * @param params.templateDir - The directory containing the template files\n * @param params.root - The root directory of the app\n * @param params.appName - The name of the app\n * @param params.projectId - The CDP Project ID\n * @param params.accountType - The account type to configure\n * @param params.enableOnramp - Whether to include Onramp\n * @param params.apiKeyId - The API Key ID\n * @param params.apiKeySecret - The API Key Secret\n */\nfunction copyTemplateFiles({\n templateDir,\n root,\n appName,\n projectId,\n accountType,\n enableOnramp,\n apiKeyId,\n apiKeySecret,\n}: {\n templateDir: string;\n root: string;\n appName: string;\n projectId?: string;\n accountType: string;\n enableOnramp?: boolean;\n apiKeyId?: string;\n apiKeySecret?: string;\n}): void {\n const writeFileToTarget = (file: string, content?: string) => {\n const targetPath = path.join(root, fileRenames[file] ?? file);\n if (content) {\n fs.writeFileSync(targetPath, content);\n } else {\n copyFileSelectively({\n filePath: path.join(templateDir, file),\n destPath: targetPath,\n accountType,\n enableOnramp,\n });\n }\n };\n\n const isNextjs = templateDir.includes(\"nextjs\");\n const isReactNative = templateDir.includes(\"react-native\");\n\n // Get React Native customizations if needed\n const reactNativeCustomizations = isReactNative\n ? customizeReactNativeFiles(templateDir, appName)\n : null;\n\n const files = fs.readdirSync(templateDir);\n for (const file of files) {\n if (file === \"package.json\") {\n const customizedPackageJson = customizePackageJson(templateDir, appName, enableOnramp);\n writeFileToTarget(file, customizedPackageJson);\n } else if (file === \"env.example\" && projectId) {\n writeFileToTarget(file);\n const customizedEnv = customizeEnv({\n templateDir,\n projectId,\n accountType,\n apiKeyId,\n apiKeySecret,\n });\n console.log(\"Copying CDP Project ID to .env\");\n if (apiKeyId && apiKeySecret) {\n console.log(\"Copying CDP API credentials to .env\");\n }\n if (accountType === \"evm-smart\") {\n console.log(\"Configuring Smart Accounts in environment\");\n } else if (accountType === \"solana\") {\n console.log(\"Configuring Solana accounts in environment\");\n }\n writeFileToTarget(\".env\", customizedEnv);\n } else if (file === \"app.json\" && isReactNative && reactNativeCustomizations?.appJson) {\n writeFileToTarget(file, reactNativeCustomizations.appJson);\n } else {\n writeFileToTarget(file);\n }\n }\n\n // Handle account type configuration in config files\n if (accountType !== \"evm-eoa\" && !isReactNative) {\n const configFileName = isNextjs ? \"src/components/Providers.tsx\" : \"src/config.ts\";\n const customizedConfig = customizeConfig(templateDir, accountType, isNextjs);\n if (customizedConfig) {\n if (accountType === \"evm-smart\") {\n console.log(\"Configuring Smart Accounts in application config\");\n } else if (accountType === \"solana\") {\n console.log(\"Configuring Solana accounts in application config\");\n }\n writeFileToTarget(configFileName, customizedConfig);\n }\n }\n\n // Generate the appropriate Transaction.tsx component\n if (isReactNative) {\n // For React Native, create the Transaction.tsx barrel file\n const transactionContent = generateTransactionComponent(accountType);\n writeFileToTarget(\"Transaction.tsx\", transactionContent);\n } else {\n /*\n * Customize SignedInScreen to import the correct transaction component\n * If onramp is enabled for Next.js, use the onramp version as the main SignedInScreen\n */\n if (isNextjs && enableOnramp) {\n const signedInScreenFileName = \"src/components/SignedInScreen.tsx\";\n const customizedOnrampScreen = customizeSignedInScreen(\n templateDir,\n accountType,\n isNextjs,\n \"SignedInScreenWithOnramp.tsx\",\n );\n writeFileToTarget(signedInScreenFileName, customizedOnrampScreen);\n } else {\n // Use regular SignedInScreen\n const signedInScreenFileName = isNextjs\n ? \"src/components/SignedInScreen.tsx\"\n : \"src/SignedInScreen.tsx\";\n const customizedSignedInScreen = customizeSignedInScreen(templateDir, accountType, isNextjs);\n writeFileToTarget(signedInScreenFileName, customizedSignedInScreen);\n }\n }\n\n // Apply React Native specific customizations\n if (isReactNative && reactNativeCustomizations) {\n // Write customized React Native files\n if (reactNativeCustomizations.infoPlist) {\n writeFileToTarget(\"ios/reactnativeexpo/Info.plist\", reactNativeCustomizations.infoPlist);\n }\n if (reactNativeCustomizations.buildGradle) {\n writeFileToTarget(\"android/app/build.gradle\", reactNativeCustomizations.buildGradle);\n }\n if (reactNativeCustomizations.xcodeProject) {\n writeFileToTarget(\n \"ios/reactnativeexpo.xcodeproj/project.pbxproj\",\n reactNativeCustomizations.xcodeProject,\n );\n }\n\n // Create new package directory structure for Android Kotlin files\n const newPackageDir = path.join(\n root,\n \"android/app/src/main/java\",\n reactNativeCustomizations.newPackagePath,\n );\n fs.mkdirSync(newPackageDir, { recursive: true });\n\n if (reactNativeCustomizations.mainActivity) {\n const newMainActivityPath = path.join(\n \"android/app/src/main/java\",\n reactNativeCustomizations.newPackagePath,\n \"MainActivity.kt\",\n );\n writeFileToTarget(newMainActivityPath, reactNativeCustomizations.mainActivity);\n }\n if (reactNativeCustomizations.mainApplication) {\n const newMainApplicationPath = path.join(\n \"android/app/src/main/java\",\n reactNativeCustomizations.newPackagePath,\n \"MainApplication.kt\",\n );\n writeFileToTarget(newMainApplicationPath, reactNativeCustomizations.mainApplication);\n }\n\n // Remove old package directory\n const oldPackageDir = path.join(\n root,\n \"android/app/src/main/java/com/anonymous/reactnativeexpo\",\n );\n if (fs.existsSync(oldPackageDir)) {\n fs.rmSync(oldPackageDir, { recursive: true, force: true });\n }\n\n // Update android/gradlew permissions so that the template is runnable\n const gradlewPath = path.join(root, \"android\", \"gradlew\");\n if (fs.existsSync(gradlewPath)) {\n fs.chmodSync(gradlewPath, 0o755);\n }\n }\n}\n\n/**\n * Generate the appropriate Transaction component based on account type\n *\n * @param accountType - The account type to generate component for\n * @returns The generated Transaction component content\n */\nfunction generateTransactionComponent(accountType: string): string {\n if (accountType === \"evm-smart\") {\n return `export { default } from \"./SmartAccountTransaction\";`;\n } else if (accountType === \"solana\") {\n return `export { default } from \"./SolanaTransaction\";`;\n } else {\n return `export { default } from \"./EOATransaction\";`;\n }\n}\n\ninit().catch(e => {\n console.error(e);\n process.exit(1);\n});\n"],"names":[],"mappings":";;;;;;;;AAWgB,SAAA,oBAAoB,WAAmB,iBAAkC;AACvF,QAAM,OAAO,KAAK,KAAK,QAAQ,OAAO,SAAS;AAIpC,MAAA,CAAC,GAAG,WAAW,IAAI,GAAG;AAC/B,OAAG,UAAU,MAAM,EAAE,WAAW,MAAM;AAAA,EAAA;AAGjC,SAAA;AACT;AAUgB,SAAA,qBACd,aACA,SACA,YACQ;AACR,QAAM,kBAAkB,KAAK,KAAK,aAAa,cAAc;AAC7D,QAAM,cAAc,KAAK,MAAM,GAAG,aAAa,iBAAiB,OAAO,CAAC;AACxE,cAAY,OAAO;AACnB,MAAI,YAAY;AACF,gBAAA,aAAa,mBAAmB,IAAI;AAAA,EAAA;AAElD,SAAO,KAAK,UAAU,aAAa,MAAM,CAAC,IAAI;AAChD;AAaO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMW;AACT,QAAM,iBAAiB,KAAK,KAAK,aAAa,aAAa;AAC3D,QAAM,aAAa,GAAG,aAAa,gBAAgB,OAAO;AAE1D,MAAI,aAAa,WAAW,QAAQ,8BAA8B,KAAK,SAAS;AAAA,CAAI;AAEhF,MAAA;AACA,MAAA,YAAY,SAAS,QAAQ,GAAG;AACzB,aAAA;AAAA,EACA,WAAA,YAAY,SAAS,cAAc,GAAG;AACtC,aAAA;AAAA,EAAA,OACJ;AACI,aAAA;AAAA,EAAA;AAGX,MAAI,gBAAgB,UAAU;AAE5B,iBAAa,WAAW;AAAA,MACtB,IAAI,OAAO,GAAG,MAAM;AAAA,MAAgD,GAAG;AAAA,MACvE;AAAA,IACF;AACA,iBAAa,WAAW;AAAA,MACtB,IAAI,OAAO,IAAI,MAAM;AAAA,IAAwC;AAAA,MAC7D;AAAA;AAAA,IACF;AAAA,EAAA,OACK;AAEC,UAAA,eAAe,gBAAgB,cAAc,UAAU;AAC7D,iBAAa,WAAW;AAAA,MACtB,IAAI,OAAO,IAAI,MAAM;AAAA,IAA+C;AAAA,MACpE,KAAK,YAAY;AAAA;AAAA,IACnB;AACA,iBAAa,WAAW;AAAA,MACtB,IAAI,OAAO,GAAG,MAAM;AAAA,MAAyC,GAAG;AAAA,MAChE;AAAA,IACF;AAAA,EAAA;AAIF,MAAI,YAAY,cAAc;AAE5B,iBAAa,WAAW,QAAQ,uBAAuB,kBAAkB,QAAQ,EAAE;AAEnF,iBAAa,WAAW;AAAA,MACtB;AAAA,MACA,sBAAsB,YAAY;AAAA,IACpC;AAAA,EAAA;AAGK,SAAA;AACT;AAUgB,SAAA,gBACd,aACA,aACA,UACe;AACX,MAAA,gBAAgB,UAAkB,QAAA;AAEhC,QAAA,iBAAiB,WAAW,iCAAiC;AACnE,QAAM,aAAa,KAAK,KAAK,aAAa,cAAc;AAExD,MAAI,CAAC,GAAG,WAAW,UAAU,EAAU,QAAA;AAEvC,MAAI,gBAAgB,GAAG,aAAa,YAAY,OAAO;AAEvD,MAAI,UAAU;AAEN,UAAA,iBACJ,gBAAgB,WACZ;AAAA;AAAA;AAAA,QAIA;AAEA,UAAA,eACJ,gBAAgB,WACZ;AAAA;AAAA;AAAA,QAIA;AAEN,oBAAgB,cAAc;AAAA,MAC5B;AAAA,MACA;AAAA,4DACsD,cAAc,GAAG,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,IAKrF;AAAA,EAAA,OACK;AAEC,UAAA,iBACJ,gBAAgB,WACZ;AAAA;AAAA;AAAA,QAIA;AAEA,UAAA,eACJ,gBAAgB,WACZ;AAAA;AAAA;AAAA,QAIA;AAEN,oBAAgB,cAAc;AAAA,MAC5B;AAAA,MACA;AAAA,mDAC6C,cAAc,GAAG,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,IAK5E;AAAA,EAAA;AAGK,SAAA;AACT;AAWO,SAAS,wBACd,aACA,aACA,UACA,WAAmB,sBACX;AACR,QAAM,qBAAqB,WACvB,KAAK,KAAK,aAAa,kBAAkB,QAAQ,EAAE,IACnD,KAAK,KAAK,aAAa,OAAO,QAAQ,EAAE;AAE5C,MAAI,UAAU,GAAG,aAAa,oBAAoB,OAAO;AAGrD,MAAA;AAEJ,MAAI,gBAAgB,UAAU;AAC5B,oBAAgB,WAAW,mCAAmC;AAAA,EAAA,WACrD,gBAAgB,aAAa;AACtC,oBAAgB,WAAW,yCAAyC;AAAA,EAAA,OAC/D;AACL,oBAAgB,WAAW,gCAAgC;AAAA,EAAA;AAGvD,QAAA,kBAAkB,mDAAmD,aAAa;AAGxF,MAAI,UAAU;AAEZ,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EAAA,OACK;AACL,cAAU,QAAQ;AAAA,MAChB;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAGK,SAAA;AACT;AA0BO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKS;AACD,QAAA,OAAO,GAAG,SAAS,QAAQ;AAC7B,MAAA,KAAK,eAAe;AAChB,UAAA,UAAU,KAAK,SAAS,QAAQ;AAEtC,QAAI,CAAC,iBAAiB,YAAY,SAAS,YAAY,OAAQ;AAE/D,uBAAmB,EAAE,QAAQ,UAAU,SAAS,UAAU,aAAa,cAAc;AAAA,EAAA,OAChF;AACC,UAAA,WAAW,KAAK,SAAS,QAAQ;AAGnC,QAAA,gBAAgB,eAAe,aAAa,qBAAsB;AAClE,QAAA,gBAAgB,eAAe,aAAa,wBAAyB;AACrE,QAAA,gBAAgB,aAAa,aAAa,8BAA+B;AACzE,QAAA,gBAAgB,aAAa,aAAa,wBAAyB;AACnE,QAAA,gBAAgB,YAAY,aAAa,qBAAsB;AAC/D,QAAA,gBAAgB,YAAY,aAAa,8BAA+B;AAG5E,QAAI,CAAC,gBAAgB,CAAC,kBAAkB,8BAA8B,EAAE,SAAS,QAAQ;AACvF;AAEF,QAAI,cAAc;AAEhB,UAAI,aAAa,qBAAsB;AAEvC,UAAI,aAAa,gCAAgC;AAC/C,cAAM,cAAc,SAAS,QAAQ,gCAAgC,oBAAoB;AACtF,WAAA,aAAa,UAAU,WAAW;AACrC;AAAA,MAAA;AAAA,IACF;AAGC,OAAA,aAAa,UAAU,QAAQ;AAAA,EAAA;AAEtC;AA0BA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKS;AACP,KAAG,UAAU,SAAS,EAAE,WAAW,MAAM;AACzC,aAAW,QAAQ,GAAG,YAAY,MAAM,GAAG;AACzC,UAAM,UAAU,KAAK,QAAQ,QAAQ,IAAI;AACzC,UAAM,WAAW,KAAK,QAAQ,SAAS,IAAI;AAC3C,wBAAoB,EAAE,UAAU,SAAS,UAAU,UAAU,aAAa,cAAc;AAAA,EAAA;AAE5F;AAQO,SAAS,WAAW,SAA0B;AAC7C,QAAA,QAAQ,GAAG,YAAY,OAAO;AAC7B,SAAA,MAAM,WAAW,KAAM,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM;AACnE;AA0BgB,SAAA,0BACd,aACA,SAUA;AACA,QAAM,WAAW,GAAG,SAAS,EAAE,YAAY;AAC3C,QAAM,gBAAgB,SAAS,YAAc,EAAA,QAAQ,cAAc,EAAE;AACrE,QAAM,eAAe,QAAQ,YAAc,EAAA,QAAQ,cAAc,EAAE;AACnE,QAAM,eAAe,OAAO,aAAa,IAAI,YAAY;AACzD,QAAM,iBAAiB,OAAO,aAAa,IAAI,YAAY;AAErD,QAAA,kBASF,EAAE,cAAc,eAAe;AAGnC,QAAM,cAAc,KAAK,KAAK,aAAa,UAAU;AACjD,MAAA,GAAG,WAAW,WAAW,GAAG;AAC9B,UAAM,iBAAiB,GAAG,aAAa,aAAa,OAAO;AAC3C,oBAAA,UAAU,eACvB,QAAQ,oCAAoC,YAAY,EACxD,QAAQ,gCAAgC,YAAY,OAAO,GAAG;AAAA,EAAA;AAInE,QAAM,gBAAgB,KAAK,KAAK,aAAa,gCAAgC;AACzE,MAAA,GAAG,WAAW,aAAa,GAAG;AAChC,UAAM,mBAAmB,GAAG,aAAa,eAAe,OAAO;AAC/D,oBAAgB,YAAY,iBAAiB;AAAA,MAC3C;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,QAAM,kBAAkB,KAAK,KAAK,aAAa,0BAA0B;AACrE,MAAA,GAAG,WAAW,eAAe,GAAG;AAClC,UAAM,qBAAqB,GAAG,aAAa,iBAAiB,OAAO;AACnE,oBAAgB,cAAc,mBAAmB;AAAA,MAC/C;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,QAAM,mBAAmB,KAAK;AAAA,IAC5B;AAAA,IACA;AAAA,EACF;AACI,MAAA,GAAG,WAAW,gBAAgB,GAAG;AACnC,UAAM,sBAAsB,GAAG,aAAa,kBAAkB,OAAO;AACrE,oBAAgB,eAAe,oBAAoB;AAAA,MACjD;AAAA,MACA,WAAW,YAAY;AAAA,IACzB;AAAA,EAAA;AAIF,QAAM,sBAAsB,KAAK;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AACI,MAAA,GAAG,WAAW,mBAAmB,GAAG;AACtC,UAAM,yBAAyB,GAAG,aAAa,qBAAqB,OAAO;AAC3E,oBAAgB,kBAAkB,uBAAuB;AAAA,MACvD;AAAA,MACA,WAAW,YAAY;AAAA,IACzB;AAAA,EAAA;AAIF,QAAM,mBAAmB,KAAK,KAAK,aAAa,+CAA+C;AAC3F,MAAA,GAAG,WAAW,gBAAgB,GAAG;AACnC,UAAM,sBAAsB,GAAG,aAAa,kBAAkB,OAAO;AACrE,oBAAgB,eAAe,oBAAoB;AAAA,MACjD;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAGK,SAAA;AACT;AAOO,SAAS,uBAAgD;AACxD,QAAA,YAAY,QAAQ,IAAI;AAE9B,MAAI,WAAW;AACb,QAAI,UAAU,WAAW,MAAM,EAAU,QAAA;AACzC,QAAI,UAAU,WAAW,MAAM,EAAU,QAAA;AACzC,QAAI,UAAU,WAAW,KAAK,EAAU,QAAA;AAAA,EAAA;AAGnC,SAAA;AACT;ACzfA,MAAM,mBAAmB;AAGzB,MAAM,YAAY;AAAA,EAChB;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,EAAA;AAEX;AAEA,MAAM,iBAAiB,UAAU,IAAI,CAAA,aAAY,SAAS,IAAI;AAK9D,MAAM,gBAAgB;AAAA,EACpB;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,aAAa;AAAA,EAAA;AAEjB;AAyBA,MAAM,YAAY;AAOlB,eAAsB,gBAAqC;AACzD,QAAM,OAAO,SAA0B,QAAQ,KAAK,MAAM,CAAC,CAAC;AAGxD,MAAA,YAAY,KAAK,EAAE,CAAC;AACxB,QAAM,iBAAiB,aAAa;AACpC,MAAI,mBAA6C;AACjD,MAAI,oBAAwC;AAC5C,MAAI,uBAA4C;AAChD,MAAI,sBAA+C;AAGnD,MAAI,KAAK,UAAU;AACjB,QAAI,CAAC,eAAe,SAAS,KAAK,QAAQ,GAAG;AACnC,cAAA;AAAA,QACN;AAAA,UACE,iCAAiC,KAAK,QAAQ,0BAA0B,eAAe,KAAK,IAAI,CAAC;AAAA,QAAA;AAAA,MAErG;AAAA,IAAA,OACK;AACL,yBAAmB,KAAK;AAAA,IAAA;AAAA,EAC1B;AAIE,MAAA,KAAK,YAAY,GAAG;AACtB,QAAI,CAAC,UAAU,KAAK,KAAK,YAAY,CAAC,GAAG;AAC/B,cAAA;AAAA,QACN,OAAO,mCAAmC,KAAK,SAAS,+BAA+B;AAAA,MACzF;AAAA,IAAA,OACK;AACL,0BAAoB,KAAK,YAAY;AAAA,IAAA;AAAA,EACvC;AAIE,MAAA,KAAK,cAAc,GAAG;AACxB,UAAM,oBAAoB,cAAc,IAAI,CAAA,SAAQ,KAAK,KAAK;AAC9D,QAAI,CAAC,kBAAkB,SAAS,KAAK,cAAc,CAAC,GAAG;AAC7C,cAAA;AAAA,QACN;AAAA,UACE,qCAAqC,KAAK,cAAc,CAAC,0BAA0B,kBAAkB,KAAK,IAAI,CAAC;AAAA,QAAA;AAAA,MAEnH;AAAA,IAAA,OACK;AACL,4BAAsB,KAAK,cAAc;AAAA,IAAA;AAAA,EAC3C;AAIE,MAAA,KAAK,QAAQ,MAAM,QAAW;AAC5B,QAAA,CAAC,KAAK,QAAQ,GAAG;AACI,6BAAA;AAAA,IAAA,OAClB;AAEL,UAAI,CAAC,kBAAkB;AACF,2BAAA;AAAA,MAAA;AAErB,UAAI,qBAAqB,UAAU;AACzB,gBAAA,IAAI,OAAO,uDAAuD,CAAC;AAAA,MAAA,OACtE;AACkB,+BAAA;AAAA,MAAA;AAAA,IACzB;AAAA,EACF;AAGE,MAAA;AACF,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,QACE;AAAA,UACE,MAAM,YAAY,OAAO;AAAA,UACzB,MAAM;AAAA,UACN,SAAS,MAAM,WAAW;AAAA,UAC1B,SAAS;AAAA,UACT,SAAS,CAAS,UAAA;AAChB,wBAAY,OAAO,MAAM,KAAK,EAAE,KAAU,KAAA;AAAA,UAAA;AAAA,QAE9C;AAAA,QACA;AAAA,UACE,MAAM,mBAAmB,OAAO;AAAA,UAChC,MAAM;AAAA,UACN,SAAS,MAAM,WAAW;AAAA,UAC1B,SAAS;AAAA,UACT,SAAS,UAAU,IAAI,CAAa,cAAA;AAAA,YAClC,OAAO,SAAS,MAAM,SAAS,OAAO;AAAA,YACtC,OAAO,SAAS;AAAA,UAAA,EAChB;AAAA,QACJ;AAAA,QACA;AAAA,UACE,MAAM,oBAAoB,OAAO;AAAA,UACjC,MAAM;AAAA,UACN,SAAS;AAAA,YACP;AAAA,UACF;AAAA,UACA,UAAU,CAAS,UAAA;AACjB,gBAAI,CAAC,OAAO;AACH,qBAAA;AAAA,YACE,WAAA,CAAC,UAAU,KAAK,KAAK,GAAG;AAC1B,qBAAA;AAAA,YAAA;AAEF,mBAAA;AAAA,UACT;AAAA,UACA,SAAS;AAAA,QACX;AAAA,QACA;AAAA,UACE,MAAM,sBAAsB,OAAO;AAAA,UACnC,MAAM;AAAA,UACN,SAAS,MAAM,eAAe;AAAA,UAC9B,SAAS;AAAA,UACT,SAAS,cAAc,IAAI,CAAgB,iBAAA;AAAA,YACzC,OAAO,YAAY;AAAA,YACnB,aAAa,YAAY;AAAA,YACzB,OAAO,YAAY;AAAA,UAAA,EACnB;AAAA,QACJ;AAAA,QACA;AAAA,UACE,MAAM,CAAC,GAAG,EAAE,SACV,MAAA,yBAAyB,WAAc,oBAAoB,cAAc,WACrE,OACA;AAAA,UACN,MAAM;AAAA,UACN,SAAS,MAAM,yEAAyE;AAAA,UACxF,SAAS;AAAA,QACX;AAAA,QACA;AAAA,UACE,MAAM,CAAC,GAAG,EAAE,aACV,MAAA,gBAAgB,uBAAuB,SAAS;AAAA,UAClD,MAAM;AAAA,UACN,SAAS,MAAM,sEAAsE;AAAA,UACrF,UAAU,CAAS,UAAA;AACjB,gBAAI,CAAC,OAAO;AACH,qBAAA;AAAA,YAAA;AAEF,mBAAA;AAAA,UAAA;AAAA,QAEX;AAAA,QACA;AAAA,UACE,MAAM,CAAC,GAAG,EAAE,aACV,MAAA,gBAAgB,uBAAuB,aAAa;AAAA,UACtD,MAAM;AAAA,UACN,SAAS,MAAM,kEAAkE;AAAA,UACjF,UAAU,CAAS,UAAA;AACjB,gBAAI,CAAC,OAAO;AACH,qBAAA;AAAA,YAAA;AAEF,mBAAA;AAAA,UAAA;AAAA,QAEX;AAAA,QACA;AAAA,UACE,MAAM,CAAC,GAAG,EAAE,SACT,OAAA,oBAAoB,cAAc,iBAAiB,OAAO;AAAA,UAC7D,MAAM;AAAA,UACN,SAAS;AAAA,YACP;AAAA,UACF;AAAA,UACA,SAAS;AAAA,QACX;AAAA,QACA;AAAA,UACE,MAAM,MAAO,CAAC,GAAG,WAAW,SAAS,KAAK,WAAW,SAAS,IAAI,OAAO;AAAA,UACzE,MAAM;AAAA,UACN,SAAS,OACN,cAAc,MAAM,sBAAsB,qBAAqB,SAAS,OACzE;AAAA,QACJ;AAAA,QACA;AAAA,UACE,MAAM,CAAC,GAAG,EAAE,gBAAyC;AACnD,gBAAI,cAAc,OAAO;AACvB,oBAAM,IAAI,MAAM,IAAI,GAAG,IAAI,sBAAsB;AAAA,YAAA;AAE5C,mBAAA;AAAA,UACT;AAAA,UACA,MAAM;AAAA,QAAA;AAAA,MAEV;AAAA,MACA;AAAA,QACE,UAAU,MAAM;AACd,gBAAM,IAAI,MAAM,IAAI,GAAG,IAAI,sBAAsB;AAAA,QAAA;AAAA,MACnD;AAAA,IAEJ;AAEO,WAAA;AAAA,MACL,SAAS,OAAO,WAAW;AAAA,MAC3B,UAAU,oBAAoB,OAAO;AAAA,MACrC,iBAAiB;AAAA,MACjB,WAAW,qBAAqB,OAAO;AAAA,MACvC,aAAa,uBAAuB,OAAO;AAAA,MAC3C,cAAc,wBAAwB,OAAO,gBAAgB;AAAA,MAC7D,UAAU,OAAO;AAAA,MACjB,cAAc,OAAO;AAAA,IACvB;AAAA,WACO,WAAoB;AAC3B,QAAI,qBAAqB,OAAO;AACtB,cAAA,IAAI,UAAU,OAAO;AAAA,IAAA;AAE/B,YAAQ,KAAK,CAAC;AAAA,EAAA;AAElB;ACrQA,MAAM,cAAkD;AAAA,EACtD,YAAY;AACd;AAKA,eAAe,OAAsB;AAC7B,QAAA;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,MAAM,cAAc;AAExB,UAAQ,IAAI;AAAA,qBAAwB,eAAe,KAAK;AAElD,QAAA,OAAO,oBAAoB,eAAsB;AACjD,QAAA,cAAc,KAAK,QAAQ,cAAc,YAAY,GAAG,GAAG,SAAS,YAAY,QAAQ,EAAE;AAE9E,oBAAA;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AACD,iBAAe,MAAM,QAAQ;AAC/B;AAQA,SAAS,eAAe,SAAiB,UAAwB;AAC/D,QAAM,iBAAiB,qBAAqB;AAEpC,UAAA,IAAI,MAAM,6BAA6B,CAAC;AAC5C,MAAA,YAAY,QAAQ,OAAO;AACrB,YAAA,IAAI,MAAM,KAAK,SAAS,QAAQ,IAAI,GAAG,OAAO,CAAC,EAAE;AAAA,EAAA;AAGnD,UAAA,IAAI,GAAG,cAAc,UAAU;AAEvC,MAAI,aAAa,gBAAgB;AAC/B,UAAM,eACJ,mBAAmB,QACf,qCACA,GAAG,cAAc,iBAAiB,cAAc;AACtD,YAAQ,IAAI,YAAY;AAAA,EAAA,OACnB;AACL,UAAM,aAAa,mBAAmB,QAAQ,gBAAgB,GAAG,cAAc;AAC/E,YAAQ,IAAI,UAAU;AAAA,EAAA;AAE1B;AAeA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GASS;AACD,QAAA,oBAAoB,CAAC,MAAc,YAAqB;AAC5D,UAAM,aAAa,KAAK,KAAK,MAAM,YAAY,IAAI,KAAK,IAAI;AAC5D,QAAI,SAAS;AACR,SAAA,cAAc,YAAY,OAAO;AAAA,IAAA,OAC/B;AACe,0BAAA;AAAA,QAClB,UAAU,KAAK,KAAK,aAAa,IAAI;AAAA,QACrC,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MAAA,CACD;AAAA,IAAA;AAAA,EAEL;AAEM,QAAA,WAAW,YAAY,SAAS,QAAQ;AACxC,QAAA,gBAAgB,YAAY,SAAS,cAAc;AAGzD,QAAM,4BAA4B,gBAC9B,0BAA0B,aAAa,OAAO,IAC9C;AAEE,QAAA,QAAQ,GAAG,YAAY,WAAW;AACxC,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,gBAAgB;AAC3B,YAAM,wBAAwB,qBAAqB,aAAa,SAAS,YAAY;AACrF,wBAAkB,MAAM,qBAAqB;AAAA,IAAA,WACpC,SAAS,iBAAiB,WAAW;AAC9C,wBAAkB,IAAI;AACtB,YAAM,gBAAgB,aAAa;AAAA,QACjC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD;AACD,cAAQ,IAAI,gCAAgC;AAC5C,UAAI,YAAY,cAAc;AAC5B,gBAAQ,IAAI,qCAAqC;AAAA,MAAA;AAEnD,UAAI,gBAAgB,aAAa;AAC/B,gBAAQ,IAAI,2CAA2C;AAAA,MAAA,WAC9C,gBAAgB,UAAU;AACnC,gBAAQ,IAAI,4CAA4C;AAAA,MAAA;AAE1D,wBAAkB,QAAQ,aAAa;AAAA,IAC9B,WAAA,SAAS,cAAc,kBAAiB,uEAA2B,UAAS;AACnE,wBAAA,MAAM,0BAA0B,OAAO;AAAA,IAAA,OACpD;AACL,wBAAkB,IAAI;AAAA,IAAA;AAAA,EACxB;AAIE,MAAA,gBAAgB,aAAa,CAAC,eAAe;AACzC,UAAA,iBAAiB,WAAW,iCAAiC;AACnE,UAAM,mBAAmB,gBAAgB,aAAa,aAAa,QAAQ;AAC3E,QAAI,kBAAkB;AACpB,UAAI,gBAAgB,aAAa;AAC/B,gBAAQ,IAAI,kDAAkD;AAAA,MAAA,WACrD,gBAAgB,UAAU;AACnC,gBAAQ,IAAI,mDAAmD;AAAA,MAAA;AAEjE,wBAAkB,gBAAgB,gBAAgB;AAAA,IAAA;AAAA,EACpD;AAIF,MAAI,eAAe;AAEX,UAAA,qBAAqB,6BAA6B,WAAW;AACnE,sBAAkB,mBAAmB,kBAAkB;AAAA,EAAA,OAClD;AAKL,QAAI,YAAY,cAAc;AAC5B,YAAM,yBAAyB;AAC/B,YAAM,yBAAyB;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,wBAAkB,wBAAwB,sBAAsB;AAAA,IAAA,OAC3D;AAEC,YAAA,yBAAyB,WAC3B,sCACA;AACJ,YAAM,2BAA2B,wBAAwB,aAAa,aAAa,QAAQ;AAC3F,wBAAkB,wBAAwB,wBAAwB;AAAA,IAAA;AAAA,EACpE;AAIF,MAAI,iBAAiB,2BAA2B;AAE9C,QAAI,0BAA0B,WAAW;AACrB,wBAAA,kCAAkC,0BAA0B,SAAS;AAAA,IAAA;AAEzF,QAAI,0BAA0B,aAAa;AACvB,wBAAA,4BAA4B,0BAA0B,WAAW;AAAA,IAAA;AAErF,QAAI,0BAA0B,cAAc;AAC1C;AAAA,QACE;AAAA,QACA,0BAA0B;AAAA,MAC5B;AAAA,IAAA;AAIF,UAAM,gBAAgB,KAAK;AAAA,MACzB;AAAA,MACA;AAAA,MACA,0BAA0B;AAAA,IAC5B;AACA,OAAG,UAAU,eAAe,EAAE,WAAW,MAAM;AAE/C,QAAI,0BAA0B,cAAc;AAC1C,YAAM,sBAAsB,KAAK;AAAA,QAC/B;AAAA,QACA,0BAA0B;AAAA,QAC1B;AAAA,MACF;AACkB,wBAAA,qBAAqB,0BAA0B,YAAY;AAAA,IAAA;AAE/E,QAAI,0BAA0B,iBAAiB;AAC7C,YAAM,yBAAyB,KAAK;AAAA,QAClC;AAAA,QACA,0BAA0B;AAAA,QAC1B;AAAA,MACF;AACkB,wBAAA,wBAAwB,0BAA0B,eAAe;AAAA,IAAA;AAIrF,UAAM,gBAAgB,KAAK;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AACI,QAAA,GAAG,WAAW,aAAa,GAAG;AAChC,SAAG,OAAO,eAAe,EAAE,WAAW,MAAM,OAAO,MAAM;AAAA,IAAA;AAI3D,UAAM,cAAc,KAAK,KAAK,MAAM,WAAW,SAAS;AACpD,QAAA,GAAG,WAAW,WAAW,GAAG;AAC3B,SAAA,UAAU,aAAa,GAAK;AAAA,IAAA;AAAA,EACjC;AAEJ;AAQA,SAAS,6BAA6B,aAA6B;AACjE,MAAI,gBAAgB,aAAa;AACxB,WAAA;AAAA,EAAA,WACE,gBAAgB,UAAU;AAC5B,WAAA;AAAA,EAAA,OACF;AACE,WAAA;AAAA,EAAA;AAEX;AAEA,OAAO,MAAM,CAAK,MAAA;AAChB,UAAQ,MAAM,CAAC;AACf,UAAQ,KAAK,CAAC;AAChB,CAAC;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/utils.ts","../src/getAppDetails.ts","../src/index.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\n/**\n * Prepare the app directory\n *\n * @param targetDir - The target directory for the app\n * @param shouldOverwrite - Whether to overwrite the existing directory\n * @returns The path to the prepared app directory\n */\nexport function prepareAppDirectory(targetDir: string, shouldOverwrite: boolean): string {\n const root = path.join(process.cwd(), targetDir);\n\n if (shouldOverwrite) {\n emptyDir(root);\n } else if (!fs.existsSync(root)) {\n fs.mkdirSync(root, { recursive: true });\n }\n\n return root;\n}\n\n/**\n * Customize package.json for the new app\n *\n * @param templateDir - The directory containing the template files\n * @param appName - The name of the app\n * @param includeSdk - Whether to include the CDP SDK in the dependencies\n * @returns The customized package.json content\n */\nexport function customizePackageJson(\n templateDir: string,\n appName: string,\n includeSdk?: boolean,\n): string {\n const packageJsonPath = path.join(templateDir, \"package.json\");\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n packageJson.name = appName;\n if (includeSdk) {\n packageJson.dependencies[\"@coinbase/cdp-sdk\"] = \"latest\";\n }\n return JSON.stringify(packageJson, null, 2) + \"\\n\";\n}\n\n/**\n * Set up the .env file for the new app\n *\n * @param params - The parameters for the function\n * @param params.templateDir - The directory containing the template files\n * @param params.projectId - The CDP Project ID\n * @param params.accountType - The account type to configure\n * @param params.apiKeyId - The API Key ID\n * @param params.apiKeySecret - The API Key Secret\n * @returns The customized .env content\n */\nexport function customizeEnv({\n templateDir,\n projectId,\n accountType,\n apiKeyId,\n apiKeySecret,\n}: {\n templateDir: string;\n projectId: string;\n accountType: string;\n apiKeyId?: string;\n apiKeySecret?: string;\n}): string {\n const exampleEnvPath = path.join(templateDir, \"env.example\");\n const exampleEnv = fs.readFileSync(exampleEnvPath, \"utf-8\");\n\n let envContent = exampleEnv.replace(/(.*PROJECT_ID=).*(\\r?\\n|$)/, `$1${projectId}\\n`);\n\n let prefix: string;\n if (templateDir.includes(\"nextjs\")) {\n prefix = \"NEXT_PUBLIC_\";\n } else if (templateDir.includes(\"react-native\")) {\n prefix = \"EXPO_PUBLIC_\";\n } else {\n prefix = \"VITE_\";\n }\n // Handle account type configuration\n if (accountType === \"solana\") {\n // For Solana-only accounts, remove Ethereum line and enable Solana\n envContent = envContent.replace(\n new RegExp(`${prefix}CDP_CREATE_ETHEREUM_ACCOUNT_TYPE=.*(\\r?\\n|$)`, \"g\"),\n \"\",\n );\n envContent = envContent.replace(\n new RegExp(`(${prefix}CDP_CREATE_SOLANA_ACCOUNT=).*(\\r?\\n|$)`),\n `$1true\\n`,\n );\n } else {\n // For EVM accounts (evm-eoa or evm-smart), set the Ethereum type and remove Solana line\n const ethereumType = accountType === \"evm-smart\" ? \"smart\" : \"eoa\";\n envContent = envContent.replace(\n new RegExp(`(${prefix}CDP_CREATE_ETHEREUM_ACCOUNT_TYPE=).*(\\r?\\n|$)`),\n `$1${ethereumType}\\n`,\n );\n envContent = envContent.replace(\n new RegExp(`${prefix}CDP_CREATE_SOLANA_ACCOUNT=.*(\\r?\\n|$)`, \"g\"),\n \"\",\n );\n }\n\n // Replace CDP API credentials if provided\n if (apiKeyId && apiKeySecret) {\n // Replace the commented API Key ID\n envContent = envContent.replace(/# CDP_API_KEY_ID=.*/, `CDP_API_KEY_ID=${apiKeyId}`);\n // Replace the commented API Key Secret\n envContent = envContent.replace(\n /# CDP_API_KEY_SECRET=.*/,\n `CDP_API_KEY_SECRET=${apiKeySecret}`,\n );\n }\n\n return envContent;\n}\n\n/**\n * Customize configuration files for account types\n *\n * @param templateDir - The directory containing the template files\n * @param accountType - The account type to configure\n * @param isNextjs - Whether this is a Next.js template\n * @returns The customized config content\n */\nexport function customizeConfig(\n templateDir: string,\n accountType: string,\n isNextjs: boolean,\n): string | null {\n if (accountType === \"evm-eoa\") return null;\n\n const configFileName = isNextjs ? \"src/components/Providers.tsx\" : \"src/config.ts\";\n const configPath = path.join(templateDir, configFileName);\n\n if (!fs.existsSync(configPath)) return null;\n\n let configContent = fs.readFileSync(configPath, \"utf-8\");\n\n if (isNextjs) {\n // For Next.js Providers.tsx - generate config based on account type\n const ethereumConfig =\n accountType !== \"solana\"\n ? `\n ethereum: {\n createOnLogin: process.env.NEXT_PUBLIC_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE === \"smart\" ? \"smart\" : \"eoa\",\n },`\n : \"\";\n\n const solanaConfig =\n accountType === \"solana\"\n ? `\n solana: {\n createOnLogin: process.env.NEXT_PUBLIC_CDP_CREATE_SOLANA_ACCOUNT === \"true\" ? true : false,\n },`\n : \"\";\n\n configContent = configContent.replace(\n /const CDP_CONFIG: Config = \\{[\\s\\S]*?\\};/,\n `const CDP_CONFIG: Config = {\n projectId: process.env.NEXT_PUBLIC_CDP_PROJECT_ID ?? \"\",${ethereumConfig}${solanaConfig}\n appName: \"CDP Next.js StarterKit\",\n appLogoUrl: \"http://localhost:3000/logo.svg\",\n authMethods: [\"email\", \"sms\"],\n};`,\n );\n } else {\n // For React config.ts - generate config based on account type\n const ethereumConfig =\n accountType !== \"solana\"\n ? `\n ethereum: {\n createOnLogin: import.meta.env.VITE_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE === \"smart\" ? \"smart\" : \"eoa\",\n },`\n : \"\";\n\n const solanaConfig =\n accountType === \"solana\"\n ? `\n solana: {\n createOnLogin: import.meta.env.VITE_CDP_CREATE_SOLANA_ACCOUNT === \"true\" ? true : false,\n },`\n : \"\";\n\n configContent = configContent.replace(\n /export const CDP_CONFIG: Config = \\{[\\s\\S]*?\\};/,\n `export const CDP_CONFIG: Config = {\n projectId: import.meta.env.VITE_CDP_PROJECT_ID,${ethereumConfig}${solanaConfig}\n appName: \"CDP React StarterKit\",\n appLogoUrl: \"http://localhost:3000/logo.svg\",\n authMethods: [\"email\", \"sms\"],\n};`,\n );\n }\n\n return configContent;\n}\n\n/**\n * Customize SignedInScreen to import the correct transaction component\n *\n * @param templateDir - The directory containing the template files\n * @param accountType - The account type to configure\n * @param isNextjs - Whether this is a Next.js template\n * @param fileName - The specific file name to customize\n * @returns The customized SignedInScreen content\n */\nexport function customizeSignedInScreen(\n templateDir: string,\n accountType: string,\n isNextjs: boolean,\n fileName: string = \"SignedInScreen.tsx\",\n): string {\n const signedInScreenPath = isNextjs\n ? path.join(templateDir, `src/components/${fileName}`)\n : path.join(templateDir, `src/${fileName}`);\n\n let content = fs.readFileSync(signedInScreenPath, \"utf-8\");\n\n // Determine the correct component import based on account type\n let componentPath: string;\n\n if (accountType === \"solana\") {\n componentPath = isNextjs ? \"@/components/SolanaTransaction\" : \"./SolanaTransaction\";\n } else if (accountType === \"evm-smart\") {\n componentPath = isNextjs ? \"@/components/SmartAccountTransaction\" : \"./SmartAccountTransaction\";\n } else {\n componentPath = isNextjs ? \"@/components/EOATransaction\" : \"./EOATransaction\";\n }\n\n const componentImport = `const TransactionComponent = lazy(() => import(\"${componentPath}\"));`;\n\n // Replace the conditional import logic with a single direct import\n if (isNextjs) {\n // Handle both SignedInScreen and SignedInScreenWithOnramp patterns\n content = content.replace(\n /\\/\\/ Dynamically (import components based on configuration|determine component path)[\\s\\S]*?const TransactionComponent = lazy\\(\\(\\) => (\\{[\\s\\S]*?\\}|import\\(\\/\\* @vite-ignore \\*\\/ getComponentPath\\(\\)\\))\\);/,\n componentImport,\n );\n } else {\n content = content.replace(\n /\\/\\/ Dynamically determine component path to avoid Vite static analysis[\\s\\S]*?const TransactionComponent = lazy\\(\\(\\) => import\\(\\/\\* @vite-ignore \\*\\/ getComponentPath\\(\\)\\)\\);/,\n componentImport,\n );\n }\n\n return content;\n}\n\n/**\n * Copy a file or directory recursively\n *\n * @param filePath - The source path\n * @param destPath - The destination path\n */\nexport function copyFile(filePath: string, destPath: string): void {\n const stat = fs.statSync(filePath);\n if (stat.isDirectory()) {\n copyDir(filePath, destPath);\n } else {\n fs.copyFileSync(filePath, destPath);\n }\n}\n\n/**\n * Copy a file or directory recursively with selective filtering for transaction components\n *\n * @param params - The parameters for the function\n * @param params.filePath - The source path\n * @param params.destPath - The destination path\n * @param params.accountType - The account type to use\n * @param params.enableOnramp - Whether to include Onramp\n */\nexport function copyFileSelectively({\n filePath,\n destPath,\n accountType,\n enableOnramp,\n}: {\n filePath: string;\n destPath: string;\n accountType: string;\n enableOnramp?: boolean;\n}): void {\n const stat = fs.statSync(filePath);\n if (stat.isDirectory()) {\n const baseDir = path.basename(filePath);\n // skip api and lib directories if Onramp is not enabled\n if (!enableOnramp && (baseDir === \"api\" || baseDir === \"lib\")) return;\n // copy the directory\n copyDirSelectively({ srcDir: filePath, destDir: destPath, accountType, enableOnramp });\n } else {\n const fileName = path.basename(filePath);\n\n // Skip transaction components that don't match the user's choice\n if (accountType === \"evm-smart\" && fileName === \"EOATransaction.tsx\") return;\n if (accountType === \"evm-smart\" && fileName === \"SolanaTransaction.tsx\") return;\n if (accountType === \"evm-eoa\" && fileName === \"SmartAccountTransaction.tsx\") return;\n if (accountType === \"evm-eoa\" && fileName === \"SolanaTransaction.tsx\") return;\n if (accountType === \"solana\" && fileName === \"EOATransaction.tsx\") return;\n if (accountType === \"solana\" && fileName === \"SmartAccountTransaction.tsx\") return;\n\n // Skip Onramp files if the user didn't enable Onramp\n if (!enableOnramp && [\"FundWallet.tsx\", \"SignedInScreenWithOnramp.tsx\"].includes(fileName))\n return;\n // Onramp-specific SignedInScreen\n if (enableOnramp) {\n // Skip the default SignedInScreen.tsx file\n if (fileName === \"SignedInScreen.tsx\") return;\n // Copy the SignedInScreenWithOnramp.tsx file to SignedInScreen.tsx\n if (fileName === \"SignedInScreenWithOnramp.tsx\") {\n const newDestPath = destPath.replace(\"SignedInScreenWithOnramp.tsx\", \"SignedInScreen.tsx\");\n fs.copyFileSync(filePath, newDestPath);\n return;\n }\n }\n\n fs.copyFileSync(filePath, destPath);\n }\n}\n\n/**\n * Copy a directory recursively\n *\n * @param srcDir - The source directory path\n * @param destDir - The destination directory path\n */\nfunction copyDir(srcDir: string, destDir: string): void {\n fs.mkdirSync(destDir, { recursive: true });\n for (const file of fs.readdirSync(srcDir)) {\n const srcFile = path.resolve(srcDir, file);\n const destFile = path.resolve(destDir, file);\n copyFile(srcFile, destFile);\n }\n}\n\n/**\n * Copy a directory recursively with selective filtering\n *\n * @param params - The parameters for the function\n * @param params.srcDir - The source directory path\n * @param params.destDir - The destination directory path\n * @param params.accountType - The account type to use\n * @param params.enableOnramp - Whether to include Onramp\n */\nfunction copyDirSelectively({\n srcDir,\n destDir,\n accountType,\n enableOnramp,\n}: {\n srcDir: string;\n destDir: string;\n accountType: string;\n enableOnramp?: boolean;\n}): void {\n fs.mkdirSync(destDir, { recursive: true });\n for (const file of fs.readdirSync(srcDir)) {\n const srcFile = path.resolve(srcDir, file);\n const destFile = path.resolve(destDir, file);\n copyFileSelectively({ filePath: srcFile, destPath: destFile, accountType, enableOnramp });\n }\n}\n\n/**\n * Check if a directory is empty\n *\n * @param dirPath - The path to the directory\n * @returns True if the directory is empty, false otherwise\n */\nexport function isDirEmpty(dirPath: string): boolean {\n const files = fs.readdirSync(dirPath);\n return files.length === 0 || (files.length === 1 && files[0] === \".git\");\n}\n\n/**\n * Empty a directory while preserving .git\n *\n * @param dirPath - The path to the directory\n */\nfunction emptyDir(dirPath: string): void {\n if (!fs.existsSync(dirPath)) {\n return;\n }\n for (const file of fs.readdirSync(dirPath)) {\n if (file === \".git\") {\n continue;\n }\n fs.rmSync(path.resolve(dirPath, file), { recursive: true, force: true });\n }\n}\n\n/**\n * Customize React Native specific files with unique bundle identifier\n *\n * @param templateDir - The directory containing the template files\n * @param appName - The name of the app\n * @returns Object containing customized file contents and new package path\n */\nexport function customizeReactNativeFiles(\n templateDir: string,\n appName: string,\n): {\n appJson?: string;\n infoPlist?: string;\n buildGradle?: string;\n mainActivity?: string;\n mainApplication?: string;\n xcodeProject?: string;\n newPackagePath: string;\n safeBundleId: string;\n} {\n const username = os.userInfo().username || \"user\";\n const cleanUsername = username.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n const cleanAppName = appName.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n const safeBundleId = `com.${cleanUsername}.${cleanAppName}`;\n const newPackagePath = `com/${cleanUsername}/${cleanAppName}`;\n\n const customizedFiles: {\n appJson?: string;\n infoPlist?: string;\n buildGradle?: string;\n mainActivity?: string;\n mainApplication?: string;\n xcodeProject?: string;\n newPackagePath: string;\n safeBundleId: string;\n } = { safeBundleId, newPackagePath };\n\n // Customize app.json\n const appJsonPath = path.join(templateDir, \"app.json\");\n if (fs.existsSync(appJsonPath)) {\n const appJsonContent = fs.readFileSync(appJsonPath, \"utf-8\");\n customizedFiles.appJson = appJsonContent\n .replace(/com\\.anonymous\\.reactnativeexpo/g, safeBundleId)\n .replace(/\"name\": \"react-native-expo\"/g, `\"name\": \"${appName}\"`);\n }\n\n // Customize iOS Info.plist\n const infoPlistPath = path.join(templateDir, \"ios/reactnativeexpo/Info.plist\");\n if (fs.existsSync(infoPlistPath)) {\n const infoPlistContent = fs.readFileSync(infoPlistPath, \"utf-8\");\n customizedFiles.infoPlist = infoPlistContent.replace(\n /com\\.anonymous\\.reactnativeexpo/g,\n safeBundleId,\n );\n }\n\n // Customize Android build.gradle\n const buildGradlePath = path.join(templateDir, \"android/app/build.gradle\");\n if (fs.existsSync(buildGradlePath)) {\n const buildGradleContent = fs.readFileSync(buildGradlePath, \"utf-8\");\n customizedFiles.buildGradle = buildGradleContent.replace(\n /com\\.anonymous\\.reactnativeexpo/g,\n safeBundleId,\n );\n }\n\n // Customize MainActivity.kt\n const mainActivityPath = path.join(\n templateDir,\n \"android/app/src/main/java/com/anonymous/reactnativeexpo/MainActivity.kt\",\n );\n if (fs.existsSync(mainActivityPath)) {\n const mainActivityContent = fs.readFileSync(mainActivityPath, \"utf-8\");\n customizedFiles.mainActivity = mainActivityContent.replace(\n /package com\\.anonymous\\.reactnativeexpo/g,\n `package ${safeBundleId}`,\n );\n }\n\n // Customize MainApplication.kt\n const mainApplicationPath = path.join(\n templateDir,\n \"android/app/src/main/java/com/anonymous/reactnativeexpo/MainApplication.kt\",\n );\n if (fs.existsSync(mainApplicationPath)) {\n const mainApplicationContent = fs.readFileSync(mainApplicationPath, \"utf-8\");\n customizedFiles.mainApplication = mainApplicationContent.replace(\n /package com\\.anonymous\\.reactnativeexpo/g,\n `package ${safeBundleId}`,\n );\n }\n\n // Customize iOS Xcode project file - only replace bundle identifier\n const xcodeProjectPath = path.join(templateDir, \"ios/reactnativeexpo.xcodeproj/project.pbxproj\");\n if (fs.existsSync(xcodeProjectPath)) {\n const xcodeProjectContent = fs.readFileSync(xcodeProjectPath, \"utf-8\");\n customizedFiles.xcodeProject = xcodeProjectContent.replace(\n /com\\.anonymous\\.reactnativeexpo/g,\n safeBundleId,\n );\n }\n\n return customizedFiles;\n}\n\n/**\n * Detect which package manager invoked the create command\n *\n * @returns The detected package manager or 'npm' as default\n */\nexport function detectPackageManager(): \"npm\" | \"pnpm\" | \"yarn\" {\n const userAgent = process.env.npm_config_user_agent;\n\n if (userAgent) {\n if (userAgent.startsWith(\"yarn\")) return \"yarn\";\n if (userAgent.startsWith(\"pnpm\")) return \"pnpm\";\n if (userAgent.startsWith(\"npm\")) return \"npm\";\n }\n\n return \"npm\"; // Default to npm if we can't detect\n}\n","#!/usr/bin/env node\n\nimport fs from \"node:fs\";\n\nimport { green, red, reset, yellow } from \"kolorist\";\nimport minimist from \"minimist\";\nimport prompts from \"prompts\";\n\nimport { isDirEmpty } from \"./utils.js\";\n\nconst defaultTargetDir = \"cdp-app\";\n\n// Available templates for app creation\nconst TEMPLATES = [\n {\n name: \"react\",\n display: \"React Single Page App\",\n color: green,\n },\n {\n name: \"nextjs\",\n display: \"Next.js Full Stack App\",\n color: green,\n },\n {\n name: \"react-native\",\n display: \"React Native with Expo\",\n color: green,\n },\n] as const;\n\nconst TEMPLATE_NAMES = TEMPLATES.map(template => template.name);\n\ntype TemplateName = (typeof TEMPLATE_NAMES)[number];\n\n// Account types that can be created\nconst ACCOUNT_TYPES = [\n {\n value: \"evm-eoa\",\n title: \"EVM EOA (Regular Accounts)\",\n description: \"Traditional Ethereum-compatible accounts\",\n },\n {\n value: \"evm-smart\",\n title: \"EVM Smart Accounts\",\n description: \"Account abstraction with gasless transactions and improved UX\",\n },\n {\n value: \"solana\",\n title: \"Solana Accounts\",\n description: \"Native Solana blockchain accounts\",\n },\n] as const;\n\ntype AccountType = (typeof ACCOUNT_TYPES)[number][\"value\"];\n\n/**\n * App options\n */\nexport interface AppOptions {\n appName: string;\n template: TemplateName;\n targetDirectory: string;\n projectId: string;\n accountType: AccountType;\n enableOnramp: boolean;\n apiKeyId?: string;\n apiKeySecret?: string;\n}\n\ntype CommandLineArgs = {\n \"project-id\": string;\n template: TemplateName;\n \"account-type\"?: AccountType;\n onramp?: boolean;\n};\n\nconst uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Get app details from command line arguments or prompt the user\n *\n * @returns The app details\n */\nexport async function getAppDetails(): Promise<AppOptions> {\n const argv = minimist<CommandLineArgs>(process.argv.slice(2));\n\n // Get target directory from command line args (first non-option argument)\n let targetDir = argv._[0];\n const defaultAppName = targetDir ?? defaultTargetDir;\n let templateFromArgs: TemplateName | undefined = undefined;\n let projectIdFromArgs: string | undefined = undefined;\n let enableOnrampFromArgs: boolean | undefined = undefined;\n let accountTypeFromArgs: AccountType | undefined = undefined;\n\n // Validate template from argv\n if (argv.template) {\n if (!TEMPLATE_NAMES.includes(argv.template)) {\n console.log(\n yellow(\n `✖ Invalid template provided: \"${argv.template}\". Please choose from: ${TEMPLATE_NAMES.join(\", \")}.`,\n ),\n );\n } else {\n templateFromArgs = argv.template;\n }\n }\n\n // Validate projectId from argv\n if (argv[\"project-id\"]) {\n if (!uuidRegex.test(argv[\"project-id\"])) {\n console.log(\n yellow(`✖ Invalid Project ID provided: \"${argv.projectId}\". Please enter a valid UUID.`),\n );\n } else {\n projectIdFromArgs = argv[\"project-id\"];\n }\n }\n\n // Validate account type from argv\n if (argv[\"account-type\"]) {\n const validAccountTypes = ACCOUNT_TYPES.map(type => type.value);\n if (!validAccountTypes.includes(argv[\"account-type\"])) {\n console.log(\n yellow(\n `✖ Invalid account type provided: \"${argv[\"account-type\"]}\". Please choose from: ${validAccountTypes.join(\", \")}.`,\n ),\n );\n } else {\n accountTypeFromArgs = argv[\"account-type\"];\n }\n }\n\n // Validate compatible template for onramp\n if (argv[\"onramp\"] !== undefined) {\n if (!argv[\"onramp\"]) {\n enableOnrampFromArgs = false;\n } else {\n // if template is not provided and onramp is enabled, force nextjs template\n if (!templateFromArgs) {\n templateFromArgs = \"nextjs\";\n }\n if (templateFromArgs !== \"nextjs\") {\n console.log(yellow(`✖ Onramp is only supported with the Next.js template.`));\n } else {\n enableOnrampFromArgs = true;\n }\n }\n }\n\n try {\n const result = await prompts(\n [\n {\n type: targetDir ? null : \"text\",\n name: \"appName\",\n message: reset(\"App Name:\"),\n initial: defaultAppName,\n onState: state => {\n targetDir = String(state.value).trim() || defaultAppName;\n },\n },\n {\n type: templateFromArgs ? null : \"select\",\n name: \"template\",\n message: reset(\"Template:\"),\n initial: 0,\n choices: TEMPLATES.map(template => ({\n title: template.color(template.display),\n value: template.name,\n })),\n },\n {\n type: projectIdFromArgs ? null : \"text\",\n name: \"projectId\",\n message: reset(\n \"CDP Project ID (Find your project ID at https://portal.cdp.coinbase.com/projects/overview):\",\n ),\n validate: value => {\n if (!value) {\n return \"Project ID is required\";\n } else if (!uuidRegex.test(value)) {\n return \"Project ID must be a valid UUID\";\n }\n return true;\n },\n initial: \"\",\n },\n {\n type: accountTypeFromArgs ? null : \"select\",\n name: \"accountType\",\n message: reset(\"Account Type:\"),\n initial: 0,\n choices: ACCOUNT_TYPES.map(accountType => ({\n title: accountType.title,\n description: accountType.description,\n value: accountType.value,\n })),\n },\n {\n type: (_, { template }: { template?: string }) =>\n enableOnrampFromArgs !== undefined || (templateFromArgs || template) !== \"nextjs\"\n ? null\n : \"confirm\",\n name: \"enableOnramp\",\n message: reset(\"Enable Coinbase Onramp? (Onramp enables users to buy crypto with fiat):\"),\n initial: false,\n },\n {\n type: (_, { enableOnramp }: { enableOnramp?: boolean }) =>\n enableOnramp || enableOnrampFromArgs ? \"text\" : null,\n name: \"apiKeyId\",\n message: reset(\"CDP API Key ID (Create at https://portal.cdp.coinbase.com/api-keys):\"),\n validate: value => {\n if (!value) {\n return \"API Key ID is required for Onramp\";\n }\n return true;\n },\n },\n {\n type: (_, { enableOnramp }: { enableOnramp?: boolean }) =>\n enableOnramp || enableOnrampFromArgs ? \"password\" : null,\n name: \"apiKeySecret\",\n message: reset(\"CDP API Key Secret (paste your private key - it will be hidden):\"),\n validate: value => {\n if (!value) {\n return \"API Key Secret is required for Onramp\";\n }\n return true;\n },\n },\n {\n type: (_, { template }: { template?: string }) =>\n (templateFromArgs || template) === \"react-native\" ? null : \"confirm\",\n name: \"corsConfirmation\",\n message: reset(\n \"Confirm you have whitelisted 'http://localhost:3000' at https://portal.cdp.coinbase.com/products/embedded-wallets/domains:\",\n ),\n initial: true,\n },\n {\n type: () => (!fs.existsSync(targetDir) || isDirEmpty(targetDir) ? null : \"confirm\"),\n name: \"overwrite\",\n message: () =>\n (targetDir === \".\" ? \"Current directory\" : `Target directory \"${targetDir}\"`) +\n \" is not empty. Remove existing files and continue?\",\n },\n {\n type: (_, { overwrite }: { overwrite?: boolean }) => {\n if (overwrite === false) {\n throw new Error(red(\"✖\") + \" Operation cancelled\");\n }\n return null;\n },\n name: \"overwriteChecker\",\n },\n ],\n {\n onCancel: () => {\n throw new Error(red(\"✖\") + \" Operation cancelled\");\n },\n },\n );\n\n return {\n appName: result.appName || targetDir,\n template: templateFromArgs || result.template,\n targetDirectory: targetDir,\n projectId: projectIdFromArgs || result.projectId,\n accountType: accountTypeFromArgs || result.accountType,\n enableOnramp: enableOnrampFromArgs ?? result.enableOnramp ?? false,\n apiKeyId: result.apiKeyId,\n apiKeySecret: result.apiKeySecret,\n };\n } catch (cancelled: unknown) {\n if (cancelled instanceof Error) {\n console.log(cancelled.message);\n }\n process.exit(0);\n }\n}\n","#!/usr/bin/env node\n\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { green, yellow } from \"kolorist\";\n\nimport { getAppDetails } from \"./getAppDetails.js\";\nimport {\n prepareAppDirectory,\n customizePackageJson,\n copyFileSelectively,\n customizeEnv,\n customizeConfig,\n customizeSignedInScreen,\n customizeReactNativeFiles,\n detectPackageManager,\n} from \"./utils.js\";\n\nconst fileRenames: Record<string, string | undefined> = {\n _gitignore: \".gitignore\",\n};\n\n/**\n * Initialize a new CDP app\n */\nasync function init(): Promise<void> {\n const {\n appName,\n template,\n targetDirectory,\n projectId,\n accountType,\n enableOnramp,\n apiKeyId,\n apiKeySecret,\n } = await getAppDetails();\n\n console.log(yellow(`\\nScaffolding app in ${targetDirectory}...`));\n\n const root = prepareAppDirectory(targetDirectory, false);\n const templateDir = path.resolve(fileURLToPath(import.meta.url), \"../..\", `template-${template}`);\n\n copyTemplateFiles({\n templateDir,\n root,\n appName,\n projectId,\n accountType,\n enableOnramp,\n apiKeyId,\n apiKeySecret,\n });\n\n console.log(green(\"✓ Creating project using template: \" + template));\n\n await installDependencies(root);\n\n await initializeGit(root);\n\n printNextSteps(root, template);\n}\n\n/**\n * Print next steps for the user\n *\n * @param appRoot - The root directory of the app\n * @param template - The template that was used\n */\nfunction printNextSteps(appRoot: string, template: string): void {\n const packageManager = detectPackageManager();\n\n console.log(green(\"\\nDone. Now run your app:\\n\"));\n if (appRoot !== process.cwd()) {\n console.log(`cd ${path.relative(process.cwd(), appRoot)}`);\n }\n\n if (template === \"react-native\") {\n const startCommand =\n packageManager === \"npm\"\n ? \"npm run ios # or npm run android\"\n : `${packageManager} run ios # or ${packageManager} run android`;\n console.log(startCommand);\n } else {\n const devCommand = packageManager === \"npm\" ? \"npm run dev\" : `${packageManager} dev`;\n console.log(devCommand);\n }\n}\n\n/**\n * Copy template files to the app directory\n *\n * @param params - The parameters for the function\n * @param params.templateDir - The directory containing the template files\n * @param params.root - The root directory of the app\n * @param params.appName - The name of the app\n * @param params.projectId - The CDP Project ID\n * @param params.accountType - The account type to configure\n * @param params.enableOnramp - Whether to include Onramp\n * @param params.apiKeyId - The API Key ID\n * @param params.apiKeySecret - The API Key Secret\n */\nfunction copyTemplateFiles({\n templateDir,\n root,\n appName,\n projectId,\n accountType,\n enableOnramp,\n apiKeyId,\n apiKeySecret,\n}: {\n templateDir: string;\n root: string;\n appName: string;\n projectId?: string;\n accountType: string;\n enableOnramp?: boolean;\n apiKeyId?: string;\n apiKeySecret?: string;\n}): void {\n const writeFileToTarget = (file: string, content?: string) => {\n const targetPath = path.join(root, fileRenames[file] ?? file);\n if (content) {\n fs.writeFileSync(targetPath, content);\n } else {\n copyFileSelectively({\n filePath: path.join(templateDir, file),\n destPath: targetPath,\n accountType,\n enableOnramp,\n });\n }\n };\n\n const isNextjs = templateDir.includes(\"nextjs\");\n const isReactNative = templateDir.includes(\"react-native\");\n\n // Get React Native customizations if needed\n const reactNativeCustomizations = isReactNative\n ? customizeReactNativeFiles(templateDir, appName)\n : null;\n\n const files = fs.readdirSync(templateDir);\n for (const file of files) {\n if (file === \"package.json\") {\n const customizedPackageJson = customizePackageJson(templateDir, appName, enableOnramp);\n writeFileToTarget(file, customizedPackageJson);\n } else if (file === \"env.example\" && projectId) {\n writeFileToTarget(file);\n const customizedEnv = customizeEnv({\n templateDir,\n projectId,\n accountType,\n apiKeyId,\n apiKeySecret,\n });\n writeFileToTarget(\".env\", customizedEnv);\n } else if (file === \"app.json\" && isReactNative && reactNativeCustomizations?.appJson) {\n writeFileToTarget(file, reactNativeCustomizations.appJson);\n } else {\n writeFileToTarget(file);\n }\n }\n\n // Handle account type configuration in config files\n if (accountType !== \"evm-eoa\" && !isReactNative) {\n const configFileName = isNextjs ? \"src/components/Providers.tsx\" : \"src/config.ts\";\n const customizedConfig = customizeConfig(templateDir, accountType, isNextjs);\n if (customizedConfig) {\n writeFileToTarget(configFileName, customizedConfig);\n }\n }\n\n // Generate the appropriate Transaction.tsx component\n if (isReactNative) {\n // For React Native, create the Transaction.tsx barrel file\n const transactionContent = generateTransactionComponent(accountType);\n writeFileToTarget(\"Transaction.tsx\", transactionContent);\n } else {\n /*\n * Customize SignedInScreen to import the correct transaction component\n * If onramp is enabled for Next.js, use the onramp version as the main SignedInScreen\n */\n if (isNextjs && enableOnramp) {\n const signedInScreenFileName = \"src/components/SignedInScreen.tsx\";\n const customizedOnrampScreen = customizeSignedInScreen(\n templateDir,\n accountType,\n isNextjs,\n \"SignedInScreenWithOnramp.tsx\",\n );\n writeFileToTarget(signedInScreenFileName, customizedOnrampScreen);\n } else {\n // Use regular SignedInScreen\n const signedInScreenFileName = isNextjs\n ? \"src/components/SignedInScreen.tsx\"\n : \"src/SignedInScreen.tsx\";\n const customizedSignedInScreen = customizeSignedInScreen(templateDir, accountType, isNextjs);\n writeFileToTarget(signedInScreenFileName, customizedSignedInScreen);\n }\n }\n\n // Apply React Native specific customizations\n if (isReactNative && reactNativeCustomizations) {\n // Write customized React Native files\n if (reactNativeCustomizations.infoPlist) {\n writeFileToTarget(\"ios/reactnativeexpo/Info.plist\", reactNativeCustomizations.infoPlist);\n }\n if (reactNativeCustomizations.buildGradle) {\n writeFileToTarget(\"android/app/build.gradle\", reactNativeCustomizations.buildGradle);\n }\n if (reactNativeCustomizations.xcodeProject) {\n writeFileToTarget(\n \"ios/reactnativeexpo.xcodeproj/project.pbxproj\",\n reactNativeCustomizations.xcodeProject,\n );\n }\n\n // Create new package directory structure for Android Kotlin files\n const newPackageDir = path.join(\n root,\n \"android/app/src/main/java\",\n reactNativeCustomizations.newPackagePath,\n );\n fs.mkdirSync(newPackageDir, { recursive: true });\n\n if (reactNativeCustomizations.mainActivity) {\n const newMainActivityPath = path.join(\n \"android/app/src/main/java\",\n reactNativeCustomizations.newPackagePath,\n \"MainActivity.kt\",\n );\n writeFileToTarget(newMainActivityPath, reactNativeCustomizations.mainActivity);\n }\n if (reactNativeCustomizations.mainApplication) {\n const newMainApplicationPath = path.join(\n \"android/app/src/main/java\",\n reactNativeCustomizations.newPackagePath,\n \"MainApplication.kt\",\n );\n writeFileToTarget(newMainApplicationPath, reactNativeCustomizations.mainApplication);\n }\n\n // Remove old package directory\n const oldPackageDir = path.join(\n root,\n \"android/app/src/main/java/com/anonymous/reactnativeexpo\",\n );\n if (fs.existsSync(oldPackageDir)) {\n fs.rmSync(oldPackageDir, { recursive: true, force: true });\n }\n\n // Update android/gradlew permissions so that the template is runnable\n const gradlewPath = path.join(root, \"android\", \"gradlew\");\n if (fs.existsSync(gradlewPath)) {\n fs.chmodSync(gradlewPath, 0o755);\n }\n }\n}\n\n/**\n * Generate the appropriate Transaction component based on account type\n *\n * @param accountType - The account type to generate component for\n * @returns The generated Transaction component content\n */\nfunction generateTransactionComponent(accountType: string): string {\n if (accountType === \"evm-smart\") {\n return `export { default } from \"./SmartAccountTransaction\";`;\n } else if (accountType === \"solana\") {\n return `export { default } from \"./SolanaTransaction\";`;\n } else {\n return `export { default } from \"./EOATransaction\";`;\n }\n}\n\n/**\n * Initialize a git repository in the app directory\n *\n * @param appRoot - The root directory of the app\n */\nasync function initializeGit(appRoot: string): Promise<void> {\n return new Promise(resolve => {\n console.log(yellow(\"\\nInitializing git repository...\"));\n\n const gitInit = spawn(\"git\", [\"init\"], {\n cwd: appRoot,\n stdio: \"pipe\",\n });\n\n gitInit.on(\"close\", code => {\n if (code === 0) {\n console.log(green(\"✓ Git repository initialized\"));\n\n const gitAdd = spawn(\"git\", [\"add\", \".\"], {\n cwd: appRoot,\n stdio: \"pipe\",\n });\n\n gitAdd.on(\"close\", addCode => {\n if (addCode === 0) {\n const gitCommit = spawn(\"git\", [\"commit\", \"-m\", \"Initial commit from Create CDP App\"], {\n cwd: appRoot,\n stdio: \"pipe\",\n env: {\n ...process.env,\n },\n });\n\n gitCommit.on(\"close\", commitCode => {\n if (commitCode !== 0) {\n console.log(yellow(\"⚠ Could not automatically create initial commit\"));\n }\n resolve();\n });\n\n gitCommit.on(\"error\", () => {\n console.log(yellow(\"⚠ Could not automatically create initial commit\"));\n resolve();\n });\n } else {\n console.log(yellow(\"⚠ Could not automatically add files to git\"));\n resolve();\n }\n });\n\n gitAdd.on(\"error\", () => {\n console.log(yellow(\"⚠ Could not automatically add files to git\"));\n resolve();\n });\n } else {\n console.log(yellow(\"⚠ Could not initialize git repository\"));\n resolve(); // Don't fail the entire process if git init fails\n }\n });\n\n gitInit.on(\"error\", () => {\n console.log(yellow(\"⚠ Git not found - skipping git initialization\"));\n resolve(); // Don't fail if git is not installed\n });\n });\n}\n\n/**\n * Install dependencies in the app directory\n *\n * @param appRoot - The root directory of the app\n */\nasync function installDependencies(appRoot: string): Promise<void> {\n const packageManager = detectPackageManager();\n\n return new Promise(resolve => {\n console.log(yellow(`\\nInstalling dependencies with ${packageManager}...`));\n\n const child = spawn(packageManager, [\"install\"], {\n cwd: appRoot,\n stdio: \"inherit\",\n });\n\n child.on(\"close\", code => {\n if (code === 0) {\n console.log(green(\"✓ Dependencies installed successfully\"));\n resolve();\n } else {\n console.log(yellow(\"⚠ Failed to install dependencies\"));\n console.log(`You can manually install dependencies by running: ${packageManager} install`);\n resolve(); // Don't fail the entire process if dependency installation fails\n }\n });\n\n child.on(\"error\", error => {\n console.log(yellow(`⚠ Could not run ${packageManager}: ${error.message}`));\n console.log(`You can manually install dependencies by running: ${packageManager} install`);\n resolve(); // Don't fail if package manager is not found\n });\n });\n}\n\ninit().catch(e => {\n console.error(e);\n process.exit(1);\n});\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
apply plugin: "com.android.application"
|
|
2
|
-
apply plugin: "org.jetbrains.kotlin.android"
|
|
3
|
-
apply plugin: "com.facebook.react"
|
|
4
|
-
|
|
5
|
-
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* This is the configuration block to customize your React Native Android app.
|
|
9
|
-
* By default you don't need to apply any configuration, just uncomment the lines you need.
|
|
10
|
-
*/
|
|
11
|
-
react {
|
|
12
|
-
entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
|
|
13
|
-
reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
|
14
|
-
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
|
|
15
|
-
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
|
16
|
-
|
|
17
|
-
enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean()
|
|
18
|
-
// Use Expo CLI to bundle the app, this ensures the Metro config
|
|
19
|
-
// works correctly with Expo projects.
|
|
20
|
-
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
|
|
21
|
-
bundleCommand = "export:embed"
|
|
22
|
-
|
|
23
|
-
/* Folders */
|
|
24
|
-
// The root of your project, i.e. where "package.json" lives. Default is '../..'
|
|
25
|
-
// root = file("../../")
|
|
26
|
-
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
|
|
27
|
-
// reactNativeDir = file("../../node_modules/react-native")
|
|
28
|
-
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
|
|
29
|
-
// codegenDir = file("../../node_modules/@react-native/codegen")
|
|
30
|
-
|
|
31
|
-
/* Variants */
|
|
32
|
-
// The list of variants to that are debuggable. For those we're going to
|
|
33
|
-
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
|
|
34
|
-
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
|
|
35
|
-
// debuggableVariants = ["liteDebug", "prodDebug"]
|
|
36
|
-
|
|
37
|
-
/* Bundling */
|
|
38
|
-
// A list containing the node command and its flags. Default is just 'node'.
|
|
39
|
-
// nodeExecutableAndArgs = ["node"]
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
// The path to the CLI configuration file. Default is empty.
|
|
43
|
-
// bundleConfig = file(../rn-cli.config.js)
|
|
44
|
-
//
|
|
45
|
-
// The name of the generated asset file containing your JS bundle
|
|
46
|
-
// bundleAssetName = "MyApplication.android.bundle"
|
|
47
|
-
//
|
|
48
|
-
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
|
|
49
|
-
// entryFile = file("../js/MyApplication.android.js")
|
|
50
|
-
//
|
|
51
|
-
// A list of extra flags to pass to the 'bundle' commands.
|
|
52
|
-
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
|
|
53
|
-
// extraPackagerArgs = []
|
|
54
|
-
|
|
55
|
-
/* Hermes Commands */
|
|
56
|
-
// The hermes compiler command to run. By default it is 'hermesc'
|
|
57
|
-
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
|
|
58
|
-
//
|
|
59
|
-
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
|
60
|
-
// hermesFlags = ["-O", "-output-source-map"]
|
|
61
|
-
|
|
62
|
-
/* Autolinking */
|
|
63
|
-
autolinkLibrariesWithApp()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
|
68
|
-
*/
|
|
69
|
-
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* The preferred build flavor of JavaScriptCore (JSC)
|
|
73
|
-
*
|
|
74
|
-
* For example, to use the international variant, you can use:
|
|
75
|
-
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
|
76
|
-
*
|
|
77
|
-
* The international variant includes ICU i18n library and necessary data
|
|
78
|
-
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
|
79
|
-
* give correct results when using with locales other than en-US. Note that
|
|
80
|
-
* this variant is about 6MiB larger per architecture than default.
|
|
81
|
-
*/
|
|
82
|
-
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
|
83
|
-
|
|
84
|
-
android {
|
|
85
|
-
ndkVersion rootProject.ext.ndkVersion
|
|
86
|
-
|
|
87
|
-
buildToolsVersion rootProject.ext.buildToolsVersion
|
|
88
|
-
compileSdk rootProject.ext.compileSdkVersion
|
|
89
|
-
|
|
90
|
-
namespace 'com.anonymous.reactnativeexpo'
|
|
91
|
-
defaultConfig {
|
|
92
|
-
applicationId 'com.anonymous.reactnativeexpo'
|
|
93
|
-
minSdkVersion rootProject.ext.minSdkVersion
|
|
94
|
-
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
95
|
-
versionCode 1
|
|
96
|
-
versionName "1.0.0"
|
|
97
|
-
}
|
|
98
|
-
signingConfigs {
|
|
99
|
-
debug {
|
|
100
|
-
storeFile file('debug.keystore')
|
|
101
|
-
storePassword 'android'
|
|
102
|
-
keyAlias 'androiddebugkey'
|
|
103
|
-
keyPassword 'android'
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
buildTypes {
|
|
107
|
-
debug {
|
|
108
|
-
signingConfig signingConfigs.debug
|
|
109
|
-
}
|
|
110
|
-
release {
|
|
111
|
-
// Caution! In production, you need to generate your own keystore file.
|
|
112
|
-
// see https://reactnative.dev/docs/signed-apk-android.
|
|
113
|
-
signingConfig signingConfigs.debug
|
|
114
|
-
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
|
115
|
-
minifyEnabled enableProguardInReleaseBuilds
|
|
116
|
-
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
|
117
|
-
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
packagingOptions {
|
|
121
|
-
jniLibs {
|
|
122
|
-
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
androidResources {
|
|
126
|
-
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Apply static values from `gradle.properties` to the `android.packagingOptions`
|
|
131
|
-
// Accepts values in comma delimited lists, example:
|
|
132
|
-
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
|
|
133
|
-
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
|
|
134
|
-
// Split option: 'foo,bar' -> ['foo', 'bar']
|
|
135
|
-
def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
|
|
136
|
-
// Trim all elements in place.
|
|
137
|
-
for (i in 0..<options.size()) options[i] = options[i].trim();
|
|
138
|
-
// `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
|
|
139
|
-
options -= ""
|
|
140
|
-
|
|
141
|
-
if (options.length > 0) {
|
|
142
|
-
println "android.packagingOptions.$prop += $options ($options.length)"
|
|
143
|
-
// Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
|
|
144
|
-
options.each {
|
|
145
|
-
android.packagingOptions[prop] += it
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
dependencies {
|
|
151
|
-
// The version of react-native is set by the React Native Gradle Plugin
|
|
152
|
-
implementation("com.facebook.react:react-android")
|
|
153
|
-
|
|
154
|
-
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
|
|
155
|
-
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
|
|
156
|
-
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
|
|
157
|
-
|
|
158
|
-
if (isGifEnabled) {
|
|
159
|
-
// For animated gif support
|
|
160
|
-
implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}")
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (isWebpEnabled) {
|
|
164
|
-
// For webp support
|
|
165
|
-
implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}")
|
|
166
|
-
if (isWebpAnimatedEnabled) {
|
|
167
|
-
// Animated webp support
|
|
168
|
-
implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}")
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (hermesEnabled.toBoolean()) {
|
|
173
|
-
implementation("com.facebook.react:hermes-android")
|
|
174
|
-
} else {
|
|
175
|
-
implementation jscFlavor
|
|
176
|
-
}
|
|
177
|
-
}
|
|
Binary file
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Add project specific ProGuard rules here.
|
|
2
|
-
# By default, the flags in this file are appended to flags specified
|
|
3
|
-
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
|
|
4
|
-
# You can edit the include path and order by changing the proguardFiles
|
|
5
|
-
# directive in build.gradle.
|
|
6
|
-
#
|
|
7
|
-
# For more details, see
|
|
8
|
-
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
9
|
-
|
|
10
|
-
# react-native-reanimated
|
|
11
|
-
-keep class com.swmansion.reanimated.** { *; }
|
|
12
|
-
-keep class com.facebook.react.turbomodule.** { *; }
|
|
13
|
-
|
|
14
|
-
# Add any project specific keep options here:
|