@blu1606/create-walrus-app 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/generator/file-ops.d.ts +8 -0
  2. package/dist/generator/file-ops.js +20 -0
  3. package/dist/generator/index.js +37 -22
  4. package/dist/generator/layers.d.ts +15 -2
  5. package/dist/generator/layers.js +38 -47
  6. package/dist/generator/types.d.ts +9 -1
  7. package/dist/index.js +1 -2
  8. package/dist/post-install/git.d.ts +8 -0
  9. package/dist/post-install/git.js +2 -0
  10. package/dist/post-install/index.d.ts +0 -1
  11. package/dist/post-install/index.js +7 -15
  12. package/dist/post-install/messages.js +1 -1
  13. package/dist/post-install/walrus-deploy.d.ts +6 -0
  14. package/dist/post-install/walrus-deploy.js +77 -0
  15. package/package.json +3 -3
  16. package/{templates/base → presets/react-mysten-gallery}/.env.example +31 -31
  17. package/presets/react-mysten-gallery/.gitkeep +4 -0
  18. package/presets/react-mysten-gallery/README.md +107 -0
  19. package/presets/react-mysten-gallery/package.json +35 -0
  20. package/presets/react-mysten-gallery/scripts/setup-walrus-deploy.sh +286 -0
  21. package/presets/react-mysten-gallery/src/App.tsx +23 -0
  22. package/presets/react-mysten-gallery/src/components/features/file-card.tsx +89 -0
  23. package/{templates/gallery/src/components/GalleryGrid.tsx → presets/react-mysten-gallery/src/components/features/gallery-grid.tsx} +5 -5
  24. package/presets/react-mysten-gallery/src/components/features/upload-modal.tsx +69 -0
  25. package/{templates/react/src/components/WalletConnect.tsx → presets/react-mysten-gallery/src/components/features/wallet-connect.tsx} +1 -1
  26. package/presets/react-mysten-gallery/src/components/layout/app-layout.tsx +21 -0
  27. package/{templates/react/src/hooks/useStorage.ts → presets/react-mysten-gallery/src/hooks/use-download.ts} +2 -18
  28. package/presets/react-mysten-gallery/src/hooks/use-upload.ts +49 -0
  29. package/{templates/react/src/hooks/useWallet.ts → presets/react-mysten-gallery/src/hooks/use-wallet.ts} +2 -7
  30. package/presets/react-mysten-gallery/src/index.css +384 -0
  31. package/presets/react-mysten-gallery/src/index.ts +17 -0
  32. package/presets/react-mysten-gallery/src/lib/walrus/adapter.ts +197 -0
  33. package/presets/react-mysten-gallery/src/lib/walrus/client.ts +87 -0
  34. package/presets/react-mysten-gallery/src/lib/walrus/index.ts +4 -0
  35. package/presets/react-mysten-gallery/src/lib/walrus/types.ts +101 -0
  36. package/{templates/react → presets/react-mysten-gallery}/src/main.tsx +0 -1
  37. package/{templates/react → presets/react-mysten-gallery}/src/providers/WalletProvider.tsx +16 -1
  38. package/{templates/base → presets/react-mysten-gallery}/src/utils/env.ts +41 -41
  39. package/{templates/gallery → presets/react-mysten-gallery}/src/utils/index-manager.ts +2 -2
  40. package/presets/react-mysten-gallery/src/utils/mime-type.ts +97 -0
  41. package/presets/react-mysten-gallery/src/utils/preview-generator.ts +134 -0
  42. package/{templates/react → presets/react-mysten-gallery}/tsconfig.json +20 -8
  43. package/presets/react-mysten-simple-upload/.env.example +31 -0
  44. package/presets/react-mysten-simple-upload/.gitkeep +4 -0
  45. package/presets/react-mysten-simple-upload/README.md +84 -0
  46. package/presets/react-mysten-simple-upload/index.html +13 -0
  47. package/{templates/react → presets/react-mysten-simple-upload}/package.json +15 -12
  48. package/presets/react-mysten-simple-upload/scripts/setup-walrus-deploy.sh +286 -0
  49. package/presets/react-mysten-simple-upload/src/App.tsx +27 -0
  50. package/presets/react-mysten-simple-upload/src/components/features/file-preview.tsx +73 -0
  51. package/{templates/simple-upload/src/components/UploadForm.tsx → presets/react-mysten-simple-upload/src/components/features/upload-form.tsx} +15 -5
  52. package/presets/react-mysten-simple-upload/src/components/features/wallet-connect.tsx +21 -0
  53. package/presets/react-mysten-simple-upload/src/components/layout/app-layout.tsx +21 -0
  54. package/presets/react-mysten-simple-upload/src/hooks/use-download.ts +24 -0
  55. package/presets/react-mysten-simple-upload/src/hooks/use-upload.ts +49 -0
  56. package/presets/react-mysten-simple-upload/src/hooks/use-wallet.ts +11 -0
  57. package/presets/react-mysten-simple-upload/src/index.css +252 -0
  58. package/presets/react-mysten-simple-upload/src/index.ts +16 -0
  59. package/presets/react-mysten-simple-upload/src/lib/walrus/adapter.ts +197 -0
  60. package/presets/react-mysten-simple-upload/src/lib/walrus/client.ts +87 -0
  61. package/presets/react-mysten-simple-upload/src/lib/walrus/index.ts +4 -0
  62. package/{templates/base/src/adapters/storage.ts → presets/react-mysten-simple-upload/src/lib/walrus/types.ts} +83 -58
  63. package/presets/react-mysten-simple-upload/src/main.tsx +16 -0
  64. package/presets/react-mysten-simple-upload/src/providers/QueryProvider.tsx +18 -0
  65. package/presets/react-mysten-simple-upload/src/providers/WalletProvider.tsx +52 -0
  66. package/presets/react-mysten-simple-upload/src/utils/env.ts +41 -0
  67. package/presets/react-mysten-simple-upload/src/utils/mime-type.ts +97 -0
  68. package/presets/react-mysten-simple-upload/tsconfig.json +39 -0
  69. package/presets/react-mysten-simple-upload/tsconfig.node.json +10 -0
  70. package/presets/react-mysten-simple-upload/vite.config.ts +19 -0
  71. package/templates/base/README.md +0 -54
  72. package/templates/base/package.json +0 -19
  73. package/templates/base/src/types/index.ts +0 -9
  74. package/templates/base/src/types/walrus.ts +0 -22
  75. package/templates/base/src/utils/format.ts +0 -29
  76. package/templates/base/tsconfig.json +0 -19
  77. package/templates/gallery/README.md +0 -44
  78. package/templates/gallery/package.json +0 -6
  79. package/templates/gallery/src/App.tsx +0 -21
  80. package/templates/gallery/src/components/FileCard.tsx +0 -27
  81. package/templates/gallery/src/components/UploadModal.tsx +0 -45
  82. package/templates/gallery/src/styles.css +0 -58
  83. package/templates/gallery/src/types/gallery.ts +0 -13
  84. package/templates/react/.eslintrc.json +0 -26
  85. package/templates/react/README.md +0 -80
  86. package/templates/react/src/App.tsx +0 -14
  87. package/templates/react/src/components/Layout.tsx +0 -21
  88. package/templates/react/src/dapp-kit.css +0 -1
  89. package/templates/react/src/index.css +0 -50
  90. package/templates/react/src/index.ts +0 -10
  91. package/templates/sdk-mysten/README.md +0 -65
  92. package/templates/sdk-mysten/package.json +0 -14
  93. package/templates/sdk-mysten/src/adapter.ts +0 -80
  94. package/templates/sdk-mysten/src/client.ts +0 -45
  95. package/templates/sdk-mysten/src/config.ts +0 -33
  96. package/templates/sdk-mysten/src/index.ts +0 -11
  97. package/templates/sdk-mysten/src/types.ts +0 -19
  98. package/templates/sdk-mysten/test/adapter.test.ts +0 -20
  99. package/templates/simple-upload/README.md +0 -24
  100. package/templates/simple-upload/package.json +0 -6
  101. package/templates/simple-upload/src/App.tsx +0 -27
  102. package/templates/simple-upload/src/components/FilePreview.tsx +0 -40
  103. package/templates/simple-upload/src/styles.css +0 -33
  104. /package/{templates/react → presets/react-mysten-gallery}/index.html +0 -0
  105. /package/{templates/react → presets/react-mysten-gallery}/src/providers/QueryProvider.tsx +0 -0
  106. /package/{templates/react → presets/react-mysten-gallery}/tsconfig.node.json +0 -0
  107. /package/{templates/react → presets/react-mysten-gallery}/vite.config.ts +0 -0
@@ -1,3 +1,7 @@
1
+ export interface EnvCopyResult {
2
+ created: boolean;
3
+ reason?: 'no-source' | 'already-exists';
4
+ }
1
5
  /**
2
6
  * Recursively copy directory, excluding certain files
3
7
  */
@@ -10,3 +14,7 @@ export declare function isDirectoryEmpty(dir: string): Promise<boolean>;
10
14
  * Create directory if it doesn't exist
11
15
  */
12
16
  export declare function ensureDirectory(dir: string): Promise<void>;
17
+ /**
18
+ * Copy .env.example to .env if it doesn't exist
19
+ */
20
+ export declare function copyEnvFile(targetDir: string): Promise<EnvCopyResult>;
@@ -38,3 +38,23 @@ export async function isDirectoryEmpty(dir) {
38
38
  export async function ensureDirectory(dir) {
39
39
  await fs.ensureDir(dir);
40
40
  }
41
+ /**
42
+ * Copy .env.example to .env if it doesn't exist
43
+ */
44
+ export async function copyEnvFile(targetDir) {
45
+ const envExamplePath = path.join(targetDir, '.env.example');
46
+ const envPath = path.join(targetDir, '.env');
47
+ // Check if .env.example exists
48
+ const hasExample = await fs.pathExists(envExamplePath);
49
+ if (!hasExample) {
50
+ return { created: false, reason: 'no-source' };
51
+ }
52
+ // Check if .env already exists
53
+ const hasEnv = await fs.pathExists(envPath);
54
+ if (hasEnv) {
55
+ return { created: false, reason: 'already-exists' };
56
+ }
57
+ // Copy file
58
+ await fs.copy(envExamplePath, envPath);
59
+ return { created: true };
60
+ }
@@ -1,9 +1,7 @@
1
- import path from 'node:path';
2
1
  import fs from 'fs-extra';
3
2
  import { logger } from '../utils/logger.js';
4
- import { resolveLayers } from './layers.js';
5
- import { copyDirectory, ensureDirectory, isDirectoryEmpty, } from './file-ops.js';
6
- import { mergePackageJsonFiles } from './merge.js';
3
+ import { resolvePresetPath, getPresetName } from './layers.js';
4
+ import { copyDirectory, ensureDirectory, isDirectoryEmpty, copyEnvFile, } from './file-ops.js';
7
5
  import { buildVariables, transformDirectory } from './transform.js';
8
6
  export async function generateProject(options) {
9
7
  const { context, targetDir, dryRun = false } = options;
@@ -17,26 +15,21 @@ export async function generateProject(options) {
17
15
  }
18
16
  await ensureDirectory(targetDir);
19
17
  }
20
- // Resolve layers
21
- const layers = resolveLayers(context);
22
- logger.info(`📦 Layers: ${layers.map((l) => l.name).join(' + ')}`);
23
- let filesCreated = 0;
24
- // Copy layers sequentially (later layers override)
25
- for (const layer of layers) {
26
- if (!(await fs.pathExists(layer.path))) {
27
- logger.warn(`⚠️ Layer not found: ${layer.path} (skipping)`);
28
- continue;
29
- }
30
- logger.info(`📁 Copying layer: ${layer.name}`);
31
- if (!dryRun) {
32
- const count = await copyDirectory(layer.path, targetDir);
33
- filesCreated += count;
34
- }
18
+ // Resolve preset path
19
+ const presetName = getPresetName(context);
20
+ const presetPath = resolvePresetPath(context);
21
+ logger.info(`📦 Using preset: ${presetName}`);
22
+ // Validate preset exists
23
+ if (!(await fs.pathExists(presetPath))) {
24
+ throw new Error(`Preset not found: ${presetName}\n` +
25
+ `Expected at: ${presetPath}\n` +
26
+ `Available presets: Check packages/cli/presets/`);
35
27
  }
36
- // Merge package.json from all layers
37
- logger.info('🔗 Merging package.json files');
28
+ let filesCreated = 0;
29
+ // Copy preset directory to target
30
+ logger.info(`📁 Copying preset files...`);
38
31
  if (!dryRun) {
39
- await mergePackageJsonFiles(layers.map((l) => l.path), path.join(targetDir, 'package.json'));
32
+ filesCreated = await copyDirectory(presetPath, targetDir);
40
33
  }
41
34
  // Transform template variables
42
35
  logger.info('✏️ Transforming template variables');
@@ -44,8 +37,30 @@ export async function generateProject(options) {
44
37
  const vars = buildVariables(context);
45
38
  await transformDirectory(targetDir, vars);
46
39
  }
40
+ // Copy .env.example to .env
41
+ logger.info('🔐 Setting up environment file');
42
+ if (!dryRun) {
43
+ try {
44
+ const envResult = await copyEnvFile(targetDir);
45
+ if (envResult.created) {
46
+ logger.success('✓ Created .env from .env.example');
47
+ }
48
+ else if (envResult.reason === 'already-exists') {
49
+ logger.info('ℹ️ .env already exists, skipped');
50
+ }
51
+ // Silent if no-source (not all presets have .env.example)
52
+ }
53
+ catch (envError) {
54
+ // Non-critical: continue generation even if env copy fails
55
+ logger.warn(`⚠️ Could not copy .env file: ${envError}`);
56
+ }
57
+ }
58
+ else {
59
+ logger.info('(dry-run) Would copy .env.example to .env');
60
+ }
47
61
  logger.success(`✓ Project generated successfully!`);
48
62
  logger.info(`📂 Files created: ${filesCreated}`);
63
+ logger.info(`📦 Preset used: ${presetName}`);
49
64
  return {
50
65
  success: true,
51
66
  projectPath: targetDir,
@@ -1,3 +1,16 @@
1
1
  import type { Context } from '../types.js';
2
- import type { Layer } from './types.js';
3
- export declare function resolveLayers(context: Context): Layer[];
2
+ /**
3
+ * Generate preset name from context
4
+ * Format: {framework}-{sdk}-{useCase}[-optional-features]
5
+ *
6
+ * Examples:
7
+ * - react-mysten-simple-upload
8
+ * - react-mysten-gallery-enoki
9
+ * - vue-mysten-gallery-tailwind
10
+ */
11
+ export declare function getPresetName(context: Context): string;
12
+ /**
13
+ * Resolve preset path from context
14
+ * Returns the absolute path to the preset directory
15
+ */
16
+ export declare function resolvePresetPath(context: Context): string;
@@ -2,58 +2,49 @@ import path from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  const __filename = fileURLToPath(import.meta.url);
4
4
  const __dirname = path.dirname(__filename);
5
- // Templates are in packages/cli/templates (published with package)
6
- const TEMPLATE_ROOT = path.join(__dirname, '../../templates');
5
+ // Presets are in packages/cli/presets (published with package)
6
+ const PRESETS_ROOT = path.join(__dirname, '../../presets');
7
7
  /**
8
- * Validate that a layer path is within the template root (prevent path traversal)
8
+ * Validate that a preset path is within the presets root (prevent path traversal)
9
9
  */
10
- function validateLayerPath(layerPath) {
11
- const normalized = path.resolve(layerPath);
12
- const root = path.resolve(TEMPLATE_ROOT);
10
+ function validatePresetPath(presetPath) {
11
+ const normalized = path.resolve(presetPath);
12
+ const root = path.resolve(PRESETS_ROOT);
13
13
  if (!normalized.startsWith(root)) {
14
- throw new Error(`Invalid layer path: ${layerPath} is outside template root`);
14
+ throw new Error(`Invalid preset path: ${presetPath} is outside presets root`);
15
15
  }
16
16
  }
17
- export function resolveLayers(context) {
18
- const layers = [
19
- {
20
- name: 'base',
21
- path: path.join(TEMPLATE_ROOT, 'base'),
22
- priority: 1,
23
- },
24
- {
25
- name: `sdk-${context.sdk}`,
26
- path: path.join(TEMPLATE_ROOT, `sdk-${context.sdk}`),
27
- priority: 2,
28
- },
29
- {
30
- name: context.framework,
31
- path: path.join(TEMPLATE_ROOT, context.framework),
32
- priority: 3,
33
- },
34
- {
35
- name: context.useCase,
36
- path: path.join(TEMPLATE_ROOT, context.useCase),
37
- priority: 4,
38
- },
39
- ];
40
- // Optional: Tailwind layer
41
- if (context.tailwind) {
42
- layers.push({
43
- name: 'tailwind',
44
- path: path.join(TEMPLATE_ROOT, 'tailwind'),
45
- priority: 5,
46
- });
47
- }
48
- // Optional: Analytics layer
17
+ /**
18
+ * Generate preset name from context
19
+ * Format: {framework}-{sdk}-{useCase}[-optional-features]
20
+ *
21
+ * Examples:
22
+ * - react-mysten-simple-upload
23
+ * - react-mysten-gallery-enoki
24
+ * - vue-mysten-gallery-tailwind
25
+ */
26
+ export function getPresetName(context) {
27
+ const parts = [context.framework, context.sdk, context.useCase];
28
+ // Add optional features in alphabetical order
29
+ const optionalFeatures = [];
49
30
  if (context.analytics) {
50
- layers.push({
51
- name: 'analytics',
52
- path: path.join(TEMPLATE_ROOT, 'analytics'),
53
- priority: 6,
54
- });
31
+ optionalFeatures.push('analytics');
55
32
  }
56
- // Validate all layer paths before returning
57
- layers.forEach((layer) => validateLayerPath(layer.path));
58
- return layers;
33
+ if (context.tailwind) {
34
+ optionalFeatures.push('tailwind');
35
+ }
36
+ // Sort for consistency
37
+ optionalFeatures.sort();
38
+ return [...parts, ...optionalFeatures].join('-');
39
+ }
40
+ /**
41
+ * Resolve preset path from context
42
+ * Returns the absolute path to the preset directory
43
+ */
44
+ export function resolvePresetPath(context) {
45
+ const presetName = getPresetName(context);
46
+ const presetPath = path.join(PRESETS_ROOT, presetName);
47
+ // Validate path for security
48
+ validatePresetPath(presetPath);
49
+ return presetPath;
59
50
  }
@@ -1,4 +1,8 @@
1
1
  import type { Context } from '../types.js';
2
+ /**
3
+ * @deprecated Layer-based architecture replaced with presets
4
+ * This interface is kept for backward compatibility but no longer used
5
+ */
2
6
  export interface Layer {
3
7
  name: string;
4
8
  path: string;
@@ -6,7 +10,11 @@ export interface Layer {
6
10
  }
7
11
  export interface GeneratorOptions {
8
12
  context: Context;
9
- templateDir: string;
13
+ /**
14
+ * @deprecated templateDir no longer used (presets are resolved automatically)
15
+ * Kept for backward compatibility
16
+ */
17
+ templateDir?: string;
10
18
  targetDir: string;
11
19
  dryRun?: boolean;
12
20
  }
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ program
27
27
  // .option('--analytics', 'Include Blockberry analytics', false)
28
28
  // .option('--no-tailwind', 'Exclude Tailwind CSS')
29
29
  .option('--skip-install', 'Skip dependency installation', false)
30
- .option('--skip-git', 'Skip git initialization', false)
30
+ .option('--skip-git', '[DEPRECATED] No longer used - git initialization removed', false)
31
31
  .option('--skip-validation', 'Skip project validation', false)
32
32
  .option('-p, --package-manager <pm>', 'Package manager to use (npm | pnpm | yarn | bun)')
33
33
  .action(async (projectNameArg, options) => {
@@ -59,7 +59,6 @@ program
59
59
  logger.info('\n🏗️ Generating your Walrus application...\n');
60
60
  const result = await generateProject({
61
61
  context,
62
- templateDir: join(__dirname, '../templates'),
63
62
  targetDir: context.projectPath,
64
63
  });
65
64
  // Clear tracking after completion
@@ -1,12 +1,20 @@
1
+ /**
2
+ * @deprecated Git initialization has been removed from create-walrus-app.
3
+ * Users should manually initialize git if needed: `git init && git add . && git commit -m "Initial commit"`
4
+ *
5
+ * This file is kept for backwards compatibility but is no longer used by the CLI.
6
+ */
1
7
  export interface GitResult {
2
8
  success: boolean;
3
9
  error?: Error;
4
10
  }
5
11
  /**
6
12
  * Initialize git repository
13
+ * @deprecated Git initialization has been removed from create-walrus-app post-install flow.
7
14
  */
8
15
  export declare function initializeGit(projectPath: string): Promise<GitResult>;
9
16
  /**
10
17
  * Create initial commit
18
+ * @deprecated Git initialization has been removed from create-walrus-app post-install flow.
11
19
  */
12
20
  export declare function createInitialCommit(projectPath: string): Promise<GitResult>;
@@ -14,6 +14,7 @@ async function isGitAvailable() {
14
14
  }
15
15
  /**
16
16
  * Initialize git repository
17
+ * @deprecated Git initialization has been removed from create-walrus-app post-install flow.
17
18
  */
18
19
  export async function initializeGit(projectPath) {
19
20
  // Check if git is available
@@ -52,6 +53,7 @@ export async function initializeGit(projectPath) {
52
53
  }
53
54
  /**
54
55
  * Create initial commit
56
+ * @deprecated Git initialization has been removed from create-walrus-app post-install flow.
55
57
  */
56
58
  export async function createInitialCommit(projectPath) {
57
59
  if (!(await fs.pathExists(path.join(projectPath, '.git')))) {
@@ -9,7 +9,6 @@ export interface PostInstallOptions {
9
9
  export interface PostInstallResult {
10
10
  success: boolean;
11
11
  installed: boolean;
12
- gitInitialized: boolean;
13
12
  validated: boolean;
14
13
  error?: Error;
15
14
  }
@@ -1,14 +1,13 @@
1
1
  import { logger } from '../utils/logger.js';
2
2
  import { installDependencies } from './package-manager.js';
3
- import { initializeGit, createInitialCommit } from './git.js';
4
3
  import { validateProject } from './validator.js';
5
4
  import { displaySuccess, displayError } from './messages.js';
5
+ import { setupWalrusDeploy } from './walrus-deploy.js';
6
6
  export async function runPostInstall(options) {
7
- const { context, projectPath, skipInstall = false, skipGit = false, skipValidation = false, } = options;
7
+ const { context, projectPath, skipInstall = false, skipValidation = false, } = options;
8
8
  const result = {
9
9
  success: true,
10
10
  installed: false,
11
- gitInitialized: false,
12
11
  validated: false,
13
12
  };
14
13
  try {
@@ -23,18 +22,7 @@ export async function runPostInstall(options) {
23
22
  logger.info(` ${context.packageManager} install`);
24
23
  }
25
24
  }
26
- // Step 2: Initialize git
27
- if (!skipGit) {
28
- const gitResult = await initializeGit(projectPath);
29
- result.gitInitialized = gitResult.success;
30
- if (gitResult.success) {
31
- const commitResult = await createInitialCommit(projectPath);
32
- if (!commitResult.success) {
33
- logger.warn('⚠️ Initial commit failed, but git repo was created');
34
- }
35
- }
36
- }
37
- // Step 3: Validate project
25
+ // Step 2: Validate project
38
26
  if (!skipValidation && result.installed) {
39
27
  const validationResult = await validateProject(projectPath);
40
28
  result.validated = validationResult.valid;
@@ -43,6 +31,10 @@ export async function runPostInstall(options) {
43
31
  validationResult.errors.forEach((err) => logger.warn(` - ${err}`));
44
32
  }
45
33
  }
34
+ // Step 3: Setup Walrus deployment (interactive prompt)
35
+ if (result.installed) {
36
+ await setupWalrusDeploy(projectPath, context);
37
+ }
46
38
  // Display success message
47
39
  displaySuccess(context);
48
40
  return result;
@@ -16,6 +16,7 @@ export function displaySuccess(context) {
16
16
  console.log('\n' + kleur.bold('🚀 Next Steps:'));
17
17
  console.log(` ${kleur.gray('1.')} cd ${kleur.cyan(projectName)}`);
18
18
  console.log(` ${kleur.gray('2.')} ${kleur.cyan(getRunCommand(packageManager, 'dev'))}`);
19
+ console.log(` ${kleur.gray('Note:')} .env file created automatically`);
19
20
  console.log('\n' + kleur.bold('📚 Helpful Commands:'));
20
21
  console.log(` ${kleur.cyan(getRunCommand(packageManager, 'dev'))} - Start development server`);
21
22
  console.log(` ${kleur.cyan(getRunCommand(packageManager, 'build'))} - Build for production`);
@@ -25,7 +26,6 @@ export function displaySuccess(context) {
25
26
  console.log(` Sui Docs: ${kleur.cyan('https://docs.sui.io')}`);
26
27
  console.log(` Sui Faucet: ${kleur.cyan('https://faucet.testnet.sui.io')}`);
27
28
  console.log('\n' + kleur.bold('💡 Tips:'));
28
- console.log(` - Copy ${kleur.cyan('.env.example')} to ${kleur.cyan('.env')}`);
29
29
  console.log(` - Install Sui Wallet browser extension`);
30
30
  console.log(` - Get testnet SUI from the faucet`);
31
31
  console.log('\n' + kleur.green('━'.repeat(60)) + '\n');
@@ -0,0 +1,6 @@
1
+ import type { Context } from '../types.js';
2
+ /**
3
+ * Prompts user to setup Walrus Sites deployment
4
+ * Runs setup-walrus-deploy.sh script if user confirms
5
+ */
6
+ export declare function setupWalrusDeploy(projectPath: string, _context: Context): Promise<void>;
@@ -0,0 +1,77 @@
1
+ import prompts from 'prompts';
2
+ import { spawn } from 'cross-spawn';
3
+ import { join } from 'node:path';
4
+ import { existsSync, chmodSync } from 'node:fs';
5
+ import { logger } from '../utils/logger.js';
6
+ /**
7
+ * Prompts user to setup Walrus Sites deployment
8
+ * Runs setup-walrus-deploy.sh script if user confirms
9
+ */
10
+ export async function setupWalrusDeploy(projectPath, _context) {
11
+ try {
12
+ const isInteractive = Boolean(process.stdin.isTTY);
13
+ // Skip in non-interactive mode
14
+ if (!isInteractive) {
15
+ return;
16
+ }
17
+ console.log(''); // Newline for better spacing
18
+ const response = await prompts({
19
+ type: 'confirm',
20
+ name: 'setup',
21
+ message: 'Setup Walrus Sites deployment? (testnet)',
22
+ initial: false,
23
+ }, {
24
+ onCancel: () => {
25
+ logger.info('Skipping Walrus deployment setup');
26
+ return false;
27
+ },
28
+ });
29
+ if (!response.setup) {
30
+ logger.info('You can setup later by running: pnpm setup-walrus-deploy');
31
+ return;
32
+ }
33
+ // Run the setup script
34
+ const scriptPath = join(projectPath, 'scripts', 'setup-walrus-deploy.sh');
35
+ if (!existsSync(scriptPath)) {
36
+ logger.warn('⚠️ setup-walrus-deploy.sh not found in project scripts/');
37
+ return;
38
+ }
39
+ // Make script executable (Unix/macOS)
40
+ try {
41
+ chmodSync(scriptPath, 0o755);
42
+ }
43
+ catch (error) {
44
+ // Ignore on Windows
45
+ }
46
+ logger.info('🦭 Running Walrus deployment setup...\n');
47
+ // Execute setup script
48
+ const child = spawn('bash', [scriptPath, projectPath], {
49
+ cwd: projectPath,
50
+ stdio: 'inherit', // Show output in real-time
51
+ shell: true,
52
+ });
53
+ await new Promise((resolve, reject) => {
54
+ child.on('close', (code) => {
55
+ if (code === 0) {
56
+ logger.success('\n✅ Walrus deployment setup complete!');
57
+ resolve();
58
+ }
59
+ else {
60
+ logger.warn(`\n⚠️ Setup exited with code ${code}. You can retry with: pnpm setup-walrus-deploy`);
61
+ resolve(); // Don't fail the whole installation
62
+ }
63
+ });
64
+ child.on('error', (error) => {
65
+ logger.error(`Setup script error: ${error.message}`);
66
+ reject(error);
67
+ });
68
+ });
69
+ }
70
+ catch (error) {
71
+ // Non-fatal: log and continue
72
+ logger.warn('⚠️ Walrus deployment setup skipped due to error');
73
+ if (error instanceof Error) {
74
+ logger.warn(error.message);
75
+ }
76
+ }
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blu1606/create-walrus-app",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Interactive CLI for scaffolding Walrus applications",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "files": [
10
10
  "dist",
11
- "templates",
11
+ "presets",
12
12
  "README.md"
13
13
  ],
14
14
  "keywords": [
@@ -22,7 +22,7 @@
22
22
  "license": "MIT",
23
23
  "repository": {
24
24
  "type": "git",
25
- "url": "https://github.com/blu1606/walrus-starter-kit.git",
25
+ "url": "https://github.com/Walrus-starter-kit/walrus-starter-kit.git",
26
26
  "directory": "packages/cli"
27
27
  },
28
28
  "dependencies": {
@@ -1,31 +1,31 @@
1
- ## ==============================================
2
- ## Walrus Application - Environment Configuration
3
- ## ==============================================
4
-
5
- ## WALRUS NETWORK SETTINGS
6
- ## Network: testnet | mainnet | devnet
7
- VITE_WALRUS_NETWORK=testnet
8
-
9
- ## Walrus Aggregator URL (for downloads)
10
- VITE_WALRUS_AGGREGATOR=https://aggregator.walrus-testnet.walrus.space
11
-
12
- ## Walrus Publisher URL (for uploads)
13
- VITE_WALRUS_PUBLISHER=https://publisher.walrus-testnet.walrus.space
14
-
15
- ## SUI BLOCKCHAIN SETTINGS
16
- ## Sui Network: testnet | mainnet | devnet
17
- VITE_SUI_NETWORK=testnet
18
-
19
- ## Sui RPC URL (for wallet interactions)
20
- VITE_SUI_RPC=https://fullnode.testnet.sui.io:443
21
-
22
- ## OPTIONAL FEATURES
23
- ## Blockberry Analytics API Key (leave empty to disable)
24
- VITE_BLOCKBERRY_KEY=
25
-
26
- ## ==============================================
27
- ## PREREQUISITES
28
- ## ==============================================
29
- ## 1. Install Sui Wallet browser extension
30
- ## 2. Get testnet SUI from faucet: https://faucet.testnet.sui.io/
31
- ## 3. Copy this file to .env and fill in any optional values
1
+ ## ==============================================
2
+ ## Walrus Application - Environment Configuration
3
+ ## ==============================================
4
+
5
+ ## WALRUS NETWORK SETTINGS
6
+ ## Network: testnet | mainnet | devnet
7
+ VITE_WALRUS_NETWORK=testnet
8
+
9
+ ## Walrus Aggregator URL (for downloads)
10
+ VITE_WALRUS_AGGREGATOR=https://aggregator.walrus-testnet.walrus.space
11
+
12
+ ## Walrus Publisher URL (for uploads)
13
+ VITE_WALRUS_PUBLISHER=https://publisher.walrus-testnet.walrus.space
14
+
15
+ ## SUI BLOCKCHAIN SETTINGS
16
+ ## Sui Network: testnet | mainnet | devnet
17
+ VITE_SUI_NETWORK=testnet
18
+
19
+ ## Sui RPC URL (for wallet interactions)
20
+ VITE_SUI_RPC=https://fullnode.testnet.sui.io:443
21
+
22
+ ## OPTIONAL FEATURES
23
+ ## Blockberry Analytics API Key (leave empty to disable)
24
+ VITE_BLOCKBERRY_KEY=
25
+
26
+ ## ==============================================
27
+ ## PREREQUISITES
28
+ ## ==============================================
29
+ ## 1. Install Sui Wallet browser extension
30
+ ## 2. Get testnet SUI from faucet: https://faucet.testnet.sui.io/
31
+ ## 3. Copy this file to .env and fill in any optional values
@@ -0,0 +1,4 @@
1
+ # Preset: react-mysten-simple-upload
2
+
3
+ Structure created based on 2025/2026 React standards.
4
+ Populate with code from layer merging or manual upload.