@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
@@ -0,0 +1,84 @@
1
+ # {{projectName}}
2
+
3
+ This is a Simple Upload Walrus application.
4
+
5
+ ## Features
6
+
7
+ - Upload any file to Walrus
8
+ - Get Blob ID after upload
9
+ - Download file by Blob ID
10
+ - File size display
11
+
12
+ ## Usage
13
+
14
+ 1. Click "Choose File" and select a file
15
+ 2. Click "Upload to Walrus"
16
+ 3. Copy the Blob ID from the success message
17
+ 4. Paste Blob ID in the download section
18
+ 5. Click "Download File"
19
+
20
+ ## Code Structure
21
+
22
+ - `UploadForm.tsx` - File upload UI
23
+ - `FilePreview.tsx` - Download UI
24
+ - `App.tsx` - Main app layout
25
+
26
+ ## Deploy to Walrus Sites
27
+
28
+ ### First-time Setup
29
+
30
+ ```bash
31
+ pnpm setup-walrus-deploy
32
+ ```
33
+
34
+ This will automatically:
35
+ - Install Bun (if not already installed)
36
+ - Download site-builder binary for your OS
37
+ - Clone Walrus Sites portal to `~/.walrus/portal`
38
+ - Add deployment scripts to package.json
39
+
40
+ ### Configure SUI Private Key
41
+
42
+ Edit the portal configuration:
43
+
44
+ **Linux/macOS:**
45
+ ```bash
46
+ nano ~/.walrus/portal/.env
47
+ ```
48
+
49
+ **Windows:**
50
+ ```bash
51
+ notepad %USERPROFILE%\.walrus\portal\.env
52
+ ```
53
+
54
+ Add your private key:
55
+ ```env
56
+ SUI_PRIVATE_KEY=0x...
57
+ WALRUS_NETWORK=testnet
58
+ ```
59
+
60
+ ### Build & Deploy
61
+
62
+ ```bash
63
+ # Build production bundle
64
+ pnpm build
65
+
66
+ # Deploy to Walrus Sites (testnet, 10 epochs)
67
+ pnpm deploy:walrus
68
+ ```
69
+
70
+ ### Preview Locally
71
+
72
+ ```bash
73
+ pnpm walrus:portal
74
+ ```
75
+
76
+ This starts the local portal server to preview your deployed site.
77
+
78
+ ## Available Scripts
79
+
80
+ - `pnpm dev` - Start development server
81
+ - `pnpm build` - Build for production
82
+ - `pnpm setup-walrus-deploy` - One-time deployment setup
83
+ - `pnpm deploy:walrus` - Deploy to Walrus Sites
84
+ - `pnpm walrus:portal` - Start local portal preview
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Walrus App</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -2,31 +2,34 @@
2
2
  "name": "{{projectName}}",
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
+ "description": "Walrus application scaffolded with create-walrus-app",
5
6
  "type": "module",
6
7
  "scripts": {
7
- "dev": "vite",
8
8
  "build": "tsc && vite build",
9
- "preview": "vite preview",
9
+ "dev": "vite",
10
10
  "lint": "eslint . --ext .ts,.tsx",
11
- "type-check": "tsc --noEmit"
11
+ "preview": "vite preview",
12
+ "type-check": "tsc --noEmit",
13
+ "setup-walrus-deploy": "bash scripts/setup-walrus-deploy.sh"
12
14
  },
13
15
  "dependencies": {
14
- "react": "^18.2.0",
15
- "react-dom": "^18.2.0",
16
- "@tanstack/react-query": "^5.17.0",
17
16
  "@mysten/dapp-kit": "^0.14.0",
18
- "@mysten/sui": "^1.10.0"
17
+ "@mysten/sui": "^1.10.0",
18
+ "@mysten/walrus": "^0.9.0",
19
+ "@tanstack/react-query": "^5.17.0",
20
+ "react": "^18.2.0",
21
+ "react-dom": "^18.2.0"
19
22
  },
20
23
  "devDependencies": {
21
24
  "@types/react": "^18.2.48",
22
25
  "@types/react-dom": "^18.2.18",
23
- "@vitejs/plugin-react": "^4.2.1",
24
- "vite": "^5.0.11",
25
- "typescript": "^5.3.3",
26
- "eslint": "^8.56.0",
27
26
  "@typescript-eslint/eslint-plugin": "^6.19.0",
28
27
  "@typescript-eslint/parser": "^6.19.0",
28
+ "@vitejs/plugin-react": "^4.2.1",
29
+ "eslint": "^8.56.0",
29
30
  "eslint-plugin-react": "^7.33.2",
30
- "eslint-plugin-react-hooks": "^4.6.0"
31
+ "eslint-plugin-react-hooks": "^4.6.0",
32
+ "typescript": "^5.3.3",
33
+ "vite": "^5.0.11"
31
34
  }
32
35
  }
@@ -0,0 +1,286 @@
1
+ #!/bin/bash
2
+ # setup-walrus-deploy.sh - Zero-config Walrus Sites deployment setup (testnet)
3
+ # Auto-installs dependencies, downloads tools, clones portal
4
+ # Supports: Linux, macOS, Windows (Git Bash/WSL)
5
+
6
+ set -e # Exit on error
7
+
8
+ echo "🦭 Walrus Sites Zero-Config Setup (testnet)"
9
+ echo ""
10
+
11
+ # ============================================================================
12
+ # 1. Detect OS & Architecture
13
+ # ============================================================================
14
+ detect_os() {
15
+ OS=$(uname -s | tr '[:upper:]' '[:lower:]')
16
+ ARCH=$(uname -m)
17
+
18
+ case "$OS" in
19
+ linux*) OS_TYPE="linux" ;;
20
+ darwin*) OS_TYPE="macos" ;;
21
+ mingw*|msys*|cygwin*) OS_TYPE="windows" ;;
22
+ *)
23
+ echo "❌ Unsupported OS: $OS"
24
+ exit 1
25
+ ;;
26
+ esac
27
+
28
+ echo "✅ Detected: $OS_TYPE ($ARCH)"
29
+ }
30
+
31
+ # ============================================================================
32
+ # 2. Auto-install Bun (if not exists)
33
+ # ============================================================================
34
+ setup_bun() {
35
+ if command -v bun &>/dev/null; then
36
+ echo "✅ Bun already installed: $(bun --version)"
37
+ return 0
38
+ fi
39
+
40
+ echo "📥 Installing Bun..."
41
+ if [ "$OS_TYPE" = "windows" ]; then
42
+ # Windows (PowerShell install via Git Bash)
43
+ powershell -c "irm bun.sh/install.ps1 | iex"
44
+ else
45
+ # Linux/macOS
46
+ curl -fsSL https://bun.sh/install | bash
47
+ fi
48
+
49
+ # Add to PATH for current session
50
+ if [ "$OS_TYPE" = "windows" ]; then
51
+ export PATH="$USERPROFILE/.bun/bin:$PATH"
52
+ else
53
+ export BUN_INSTALL="$HOME/.bun"
54
+ export PATH="$BUN_INSTALL/bin:$PATH"
55
+ fi
56
+
57
+ # Verify installation
58
+ if command -v bun &>/dev/null; then
59
+ echo "✅ Bun installed: $(bun --version)"
60
+ else
61
+ echo "⚠️ Bun installed but not in PATH. Restart terminal or run:"
62
+ echo " export PATH=\"\$HOME/.bun/bin:\$PATH\""
63
+ fi
64
+ }
65
+
66
+ # ============================================================================
67
+ # 3. Download site-builder binary (if not exists)
68
+ # ============================================================================
69
+ setup_site_builder() {
70
+ # Set install directory based on OS
71
+ if [ "$OS_TYPE" = "windows" ]; then
72
+ WALRUS_BIN="$USERPROFILE/.walrus/bin"
73
+ SITE_BUILDER="$WALRUS_BIN/site-builder.exe"
74
+ else
75
+ WALRUS_BIN="$HOME/.walrus/bin"
76
+ SITE_BUILDER="$WALRUS_BIN/site-builder"
77
+ fi
78
+
79
+ # Check if already exists
80
+ if [ -f "$SITE_BUILDER" ]; then
81
+ echo "✅ site-builder already exists: $SITE_BUILDER"
82
+ chmod +x "$SITE_BUILDER" 2>/dev/null || true
83
+ return 0
84
+ fi
85
+
86
+ echo "📥 Downloading site-builder for $OS_TYPE..."
87
+ mkdir -p "$WALRUS_BIN"
88
+
89
+ # Select binary based on OS
90
+ case "$OS_TYPE" in
91
+ linux) BINARY_NAME="site-builder-linux" ;;
92
+ macos) BINARY_NAME="site-builder-macos" ;;
93
+ windows) BINARY_NAME="site-builder-windows.exe" ;;
94
+ esac
95
+
96
+ DOWNLOAD_URL="https://github.com/MystenLabs/walrus-sites/releases/latest/download/$BINARY_NAME"
97
+
98
+ # Download with retry
99
+ if ! curl -fsSL -o "$SITE_BUILDER" "$DOWNLOAD_URL"; then
100
+ echo "❌ Failed to download site-builder from: $DOWNLOAD_URL"
101
+ exit 1
102
+ fi
103
+
104
+ chmod +x "$SITE_BUILDER"
105
+ echo "✅ site-builder installed: $SITE_BUILDER"
106
+
107
+ # Add to PATH hint (won't persist after script)
108
+ if [ "$OS_TYPE" = "windows" ]; then
109
+ export PATH="$USERPROFILE/.walrus/bin:$PATH"
110
+ else
111
+ export PATH="$HOME/.walrus/bin:$PATH"
112
+ fi
113
+ }
114
+
115
+ # ============================================================================
116
+ # 4. Clone Walrus Portal (if not exists)
117
+ # ============================================================================
118
+ setup_portal() {
119
+ if [ "$OS_TYPE" = "windows" ]; then
120
+ PORTAL_DIR="$USERPROFILE/.walrus/portal"
121
+ else
122
+ PORTAL_DIR="$HOME/.walrus/portal"
123
+ fi
124
+
125
+ if [ -d "$PORTAL_DIR" ]; then
126
+ echo "✅ Portal already exists: $PORTAL_DIR"
127
+ echo " Updating..."
128
+ cd "$PORTAL_DIR"
129
+ git pull --quiet || echo "⚠️ Git pull failed (may be offline)"
130
+ else
131
+ echo "📂 Cloning Walrus Sites portal..."
132
+ mkdir -p "$(dirname "$PORTAL_DIR")"
133
+
134
+ # Clone with depth=1 for faster download
135
+ if ! git clone --depth=1 https://github.com/MystenLabs/walrus-sites.git "$PORTAL_DIR"; then
136
+ echo "❌ Failed to clone portal repository"
137
+ exit 1
138
+ fi
139
+
140
+ cd "$PORTAL_DIR"
141
+ echo "✅ Portal cloned to: $PORTAL_DIR"
142
+ fi
143
+
144
+ # Setup .env if not exists
145
+ if [ ! -f ".env" ]; then
146
+ if [ -f ".env.example" ]; then
147
+ cp .env.example .env
148
+ echo "✅ Created .env from .env.example"
149
+ else
150
+ # Create minimal .env
151
+ cat > .env << 'EOF'
152
+ # Walrus Portal Configuration (Testnet)
153
+ WALRUS_NETWORK=testnet
154
+ SUI_PRIVATE_KEY=
155
+
156
+ # Optional: Uncomment to customize
157
+ # PORTAL_PORT=3000
158
+ EOF
159
+ echo "✅ Created .env template"
160
+ fi
161
+
162
+ echo ""
163
+ echo "⚠️ ACTION REQUIRED:"
164
+ echo " Edit $PORTAL_DIR/.env"
165
+ echo " Add your SUI_PRIVATE_KEY=0x..."
166
+ echo ""
167
+ else
168
+ echo "✅ .env already configured"
169
+ fi
170
+
171
+ # Install portal dependencies
172
+ echo "📦 Installing portal dependencies..."
173
+ if ! bun install --silent; then
174
+ echo "❌ Bun install failed"
175
+ exit 1
176
+ fi
177
+
178
+ echo "✅ Portal dependencies installed"
179
+ }
180
+
181
+ # ============================================================================
182
+ # 5. Add npm scripts to project package.json
183
+ # ============================================================================
184
+ add_project_scripts() {
185
+ PROJECT_DIR="${1:-.}" # Default to current directory
186
+ cd "$PROJECT_DIR" || { echo "❌ Invalid project directory"; exit 1; }
187
+
188
+ if [ ! -f "package.json" ]; then
189
+ echo "❌ No package.json found in $PROJECT_DIR"
190
+ exit 1
191
+ fi
192
+
193
+ echo "📝 Adding Walrus deploy scripts to package.json..."
194
+
195
+ # Use Node.js to safely modify package.json (guaranteed to exist in Node projects)
196
+ node -e "
197
+ const fs = require('fs');
198
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
199
+
200
+ pkg.scripts = pkg.scripts || {};
201
+
202
+ // Add scripts (only if not already exists)
203
+ if (!pkg.scripts['setup-walrus-deploy']) {
204
+ pkg.scripts['setup-walrus-deploy'] = 'bash scripts/setup-walrus-deploy.sh';
205
+ }
206
+
207
+ if (!pkg.scripts['deploy:walrus']) {
208
+ const siteBuilderPath = process.platform === 'win32'
209
+ ? '%USERPROFILE%/.walrus/bin/site-builder.exe'
210
+ : '~/.walrus/bin/site-builder';
211
+ pkg.scripts['deploy:walrus'] = siteBuilderPath + ' --context=testnet deploy ./dist --epochs 10';
212
+ }
213
+
214
+ if (!pkg.scripts['walrus:portal']) {
215
+ const portalPath = process.platform === 'win32'
216
+ ? 'cd %USERPROFILE%/.walrus/portal'
217
+ : 'cd ~/.walrus/portal';
218
+ pkg.scripts['walrus:portal'] = portalPath + ' && bun run server';
219
+ }
220
+
221
+ fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\\n');
222
+ " || {
223
+ echo "❌ Failed to update package.json"
224
+ exit 1
225
+ }
226
+
227
+ echo "✅ Scripts added to package.json:"
228
+ echo " - setup-walrus-deploy"
229
+ echo " - deploy:walrus"
230
+ echo " - walrus:portal"
231
+ }
232
+
233
+ # ============================================================================
234
+ # Main Execution
235
+ # ============================================================================
236
+ main() {
237
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
238
+
239
+ # Trap errors
240
+ trap 'echo "❌ Setup failed at line $LINENO"' ERR
241
+
242
+ # Prerequisites check
243
+ if ! command -v git &>/dev/null; then
244
+ echo "❌ Git not found. Install: https://git-scm.com"
245
+ exit 1
246
+ fi
247
+
248
+ if ! command -v node &>/dev/null; then
249
+ echo "❌ Node.js not found. Install: https://nodejs.org"
250
+ exit 1
251
+ fi
252
+
253
+ # Run setup steps
254
+ detect_os
255
+ setup_bun
256
+ setup_site_builder
257
+ setup_portal
258
+ add_project_scripts "$@"
259
+
260
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
261
+ echo ""
262
+ echo "🎉 Setup Complete!"
263
+ echo ""
264
+ echo "Next Steps:"
265
+ echo " 1. Configure your SUI private key:"
266
+ if [ "$OS_TYPE" = "windows" ]; then
267
+ echo " notepad %USERPROFILE%\\.walrus\\portal\\.env"
268
+ else
269
+ echo " nano ~/.walrus/portal/.env"
270
+ fi
271
+ echo " Add: SUI_PRIVATE_KEY=0x..."
272
+ echo ""
273
+ echo " 2. Build your project:"
274
+ echo " pnpm build"
275
+ echo ""
276
+ echo " 3. Deploy to Walrus Sites:"
277
+ echo " pnpm deploy:walrus"
278
+ echo ""
279
+ echo " 4. (Optional) Preview locally:"
280
+ echo " pnpm walrus:portal"
281
+ echo ""
282
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
283
+ }
284
+
285
+ # Run main with all script arguments
286
+ main "$@"
@@ -0,0 +1,27 @@
1
+ import { AppLayout } from './components/layout/app-layout.js';
2
+ import { UploadForm } from './components/features/upload-form.js';
3
+ import { FilePreview } from './components/features/file-preview.js';
4
+ import './index.css';
5
+
6
+ function App() {
7
+ return (
8
+ <AppLayout>
9
+ <div className="simple-upload-app">
10
+ <h2><span className="text-accent">📤</span> Simple Upload</h2>
11
+ <p className="text-secondary">Upload a file to <span className="text-accent">Walrus</span> and download it by <span className="text-accent">Blob ID</span></p>
12
+
13
+ <section className="upload-section">
14
+ <h3>Upload File</h3>
15
+ <UploadForm />
16
+ </section>
17
+
18
+ <section className="download-section">
19
+ <h3>Download File</h3>
20
+ <FilePreview />
21
+ </section>
22
+ </div>
23
+ </AppLayout>
24
+ );
25
+ }
26
+
27
+ export default App;
@@ -0,0 +1,73 @@
1
+ import { useState } from 'react';
2
+ import { useDownload, useMetadata } from '../../hooks/use-download.js';
3
+
4
+ export function FilePreview() {
5
+ const [blobId, setBlobId] = useState('');
6
+ const { data, isLoading, error } = useDownload(blobId);
7
+ const { data: metadata } = useMetadata(blobId);
8
+
9
+ const handleDownload = () => {
10
+ if (!data) return;
11
+
12
+ // Use original filename from metadata if available
13
+ let filename = metadata?.fileName || `walrus-${blobId.slice(0, 8)}`;
14
+
15
+ // If metadata doesn't have filename, auto-detect from content type
16
+ if (!metadata?.fileName) {
17
+ const contentType = metadata?.contentType || 'application/octet-stream';
18
+
19
+ if (contentType.startsWith('image/')) {
20
+ filename += `.${contentType.split('/')[1]}`;
21
+ } else if (contentType.startsWith('text/')) {
22
+ filename += '.txt';
23
+ } else if (contentType.includes('json')) {
24
+ filename += '.json';
25
+ } else {
26
+ filename += '.bin';
27
+ }
28
+ }
29
+
30
+ const contentType = metadata?.contentType || 'application/octet-stream';
31
+ const blob = new Blob([data as Uint8Array], { type: contentType });
32
+ const url = URL.createObjectURL(blob);
33
+ const a = document.createElement('a');
34
+ a.href = url;
35
+ a.download = filename;
36
+ a.click();
37
+ URL.revokeObjectURL(url);
38
+ };
39
+
40
+ // Auto-detect if data is text or JSON for preview
41
+ const canPreview = data && (typeof data === 'string' || data instanceof Uint8Array);
42
+ const preview = canPreview && typeof data === 'string'
43
+ ? data.slice(0, 200) // Show first 200 chars for text
44
+ : null;
45
+
46
+ return (
47
+ <div className="file-preview">
48
+ <input
49
+ type="text"
50
+ placeholder="Enter Blob ID"
51
+ value={blobId}
52
+ onChange={(e) => setBlobId(e.target.value)}
53
+ />
54
+
55
+ {isLoading && <p className="text-secondary">Loading...</p>}
56
+ {error && <p className="error">Error: {error.message}</p>}
57
+
58
+ {data && (
59
+ <div className="preview-content icon-list">
60
+ <p className="text-success">✓ Blob found <span className="text-secondary">({data.byteLength || data.length} bytes)</span></p>
61
+ {metadata?.fileName && <p className="text-secondary">File: <span className="text-accent">{metadata.fileName}</span></p>}
62
+ {metadata?.contentType && <p className="text-secondary">Type: <span className="text-accent">{metadata.contentType}</span></p>}
63
+ {preview && (
64
+ <pre>
65
+ {preview}...
66
+ </pre>
67
+ )}
68
+ <button onClick={handleDownload}>Download File</button>
69
+ </div>
70
+ )}
71
+ </div>
72
+ );
73
+ }
@@ -1,9 +1,11 @@
1
1
  import { useState } from 'react';
2
- import { useUpload } from '../hooks/useStorage.js';
2
+ import { useUpload } from '../../hooks/use-upload.js';
3
+ import { useWallet } from '../../hooks/use-wallet.js';
3
4
 
4
5
  export function UploadForm() {
5
6
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
6
7
  const upload = useUpload();
8
+ const { isConnected } = useWallet();
7
9
 
8
10
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
9
11
  const file = e.target.files?.[0];
@@ -33,16 +35,24 @@ export function UploadForm() {
33
35
 
34
36
  {selectedFile && (
35
37
  <div className="file-info">
36
- <p>Selected: {selectedFile.name}</p>
37
- <p>Size: {(selectedFile.size / 1024).toFixed(2)} KB</p>
38
+ <p className="text-secondary">Selected: <span className="text-accent">{selectedFile.name}</span></p>
39
+ <p className="text-secondary">Size: <span className="text-accent">{(selectedFile.size / 1024).toFixed(2)} KB</span></p>
38
40
  </div>
39
41
  )}
40
42
 
43
+ {!isConnected && (
44
+ <p className="warning">⚠️ Please connect your wallet to upload files</p>
45
+ )}
46
+
41
47
  <button
42
48
  onClick={handleUpload}
43
- disabled={!selectedFile || upload.isPending}
49
+ disabled={!selectedFile || !isConnected || upload.isPending}
44
50
  >
45
- {upload.isPending ? 'Uploading...' : 'Upload to Walrus'}
51
+ {!isConnected
52
+ ? 'Connect Wallet First'
53
+ : upload.isPending
54
+ ? 'Uploading...'
55
+ : 'Upload to Walrus'}
46
56
  </button>
47
57
 
48
58
  {upload.isError && <p className="error">Error: {upload.error.message}</p>}
@@ -0,0 +1,21 @@
1
+ import { ConnectButton } from '@mysten/dapp-kit';
2
+ import { useWallet } from '../../hooks/use-wallet.js';
3
+
4
+ export function WalletConnect() {
5
+ const { isConnected, address } = useWallet();
6
+
7
+ return (
8
+ <div className="wallet-connect">
9
+ {isConnected ? (
10
+ <div className="wallet-info">
11
+ <span>
12
+ Connected: {address?.slice(0, 6)}...{address?.slice(-4)}
13
+ </span>
14
+ </div>
15
+ ) : (
16
+ <p>Please connect your wallet</p>
17
+ )}
18
+ <ConnectButton />
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from 'react';
2
+ import { WalletConnect } from '../features/wallet-connect.js';
3
+
4
+ interface LayoutProps {
5
+ children: ReactNode;
6
+ }
7
+
8
+ export function AppLayout({ children }: LayoutProps) {
9
+ return (
10
+ <div className="app-layout">
11
+ <header className="app-header">
12
+ <h1><span className="text-secondary">🌊</span> <span className="text-accent">Walrus</span> App</h1>
13
+ <WalletConnect />
14
+ </header>
15
+ <main className="app-main">{children}</main>
16
+ <footer className="app-footer">
17
+ <p className="text-secondary">Powered by <span className="text-accent">Walrus</span> & <span style={{ color: 'var(--walrus-accent-blue)' }}>Sui</span></p>
18
+ </footer>
19
+ </div>
20
+ );
21
+ }
@@ -0,0 +1,24 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { storageAdapter } from '../lib/walrus/index.js';
3
+
4
+ export function useDownload(blobId: string | null) {
5
+ return useQuery({
6
+ queryKey: ['blob', blobId],
7
+ queryFn: async () => {
8
+ if (!blobId) throw new Error('No blob ID provided');
9
+ return await storageAdapter.download(blobId);
10
+ },
11
+ enabled: !!blobId,
12
+ });
13
+ }
14
+
15
+ export function useMetadata(blobId: string | null) {
16
+ return useQuery({
17
+ queryKey: ['metadata', blobId],
18
+ queryFn: async () => {
19
+ if (!blobId) throw new Error('No blob ID provided');
20
+ return await storageAdapter.getMetadata(blobId);
21
+ },
22
+ enabled: !!blobId,
23
+ });
24
+ }