@blu1606/create-walrus-app 2.1.0 → 2.2.1

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 (43) hide show
  1. package/dist/context.js +1 -0
  2. package/dist/generator/layers.js +3 -0
  3. package/dist/index.js +1 -0
  4. package/dist/prompts.js +17 -0
  5. package/dist/types.d.ts +1 -0
  6. package/package.json +1 -1
  7. package/presets/react-mysten-gallery/scripts/setup-walrus-deploy.sh +46 -18
  8. package/presets/react-mysten-simple-upload/scripts/setup-walrus-deploy.sh +43 -15
  9. package/presets/react-mysten-simple-upload-enoki/.env.example +40 -0
  10. package/presets/react-mysten-simple-upload-enoki/.gitkeep +4 -0
  11. package/presets/react-mysten-simple-upload-enoki/README.md +332 -0
  12. package/presets/react-mysten-simple-upload-enoki/index.html +13 -0
  13. package/presets/react-mysten-simple-upload-enoki/package.json +37 -0
  14. package/presets/react-mysten-simple-upload-enoki/scripts/setup-walrus-deploy.sh +314 -0
  15. package/presets/react-mysten-simple-upload-enoki/src/App.tsx +27 -0
  16. package/presets/react-mysten-simple-upload-enoki/src/components/features/enoki-auth-button.tsx +29 -0
  17. package/presets/react-mysten-simple-upload-enoki/src/components/features/file-preview.tsx +73 -0
  18. package/presets/react-mysten-simple-upload-enoki/src/components/features/upload-form.tsx +61 -0
  19. package/presets/react-mysten-simple-upload-enoki/src/components/features/wallet-connect.tsx +38 -0
  20. package/presets/react-mysten-simple-upload-enoki/src/components/layout/app-layout.tsx +21 -0
  21. package/presets/react-mysten-simple-upload-enoki/src/hooks/use-download.ts +24 -0
  22. package/presets/react-mysten-simple-upload-enoki/src/hooks/use-enoki-auth.ts +52 -0
  23. package/presets/react-mysten-simple-upload-enoki/src/hooks/use-upload.ts +45 -0
  24. package/presets/react-mysten-simple-upload-enoki/src/hooks/use-wallet.ts +32 -0
  25. package/presets/react-mysten-simple-upload-enoki/src/index.css +322 -0
  26. package/presets/react-mysten-simple-upload-enoki/src/index.ts +24 -0
  27. package/presets/react-mysten-simple-upload-enoki/src/lib/enoki/constants.ts +23 -0
  28. package/presets/react-mysten-simple-upload-enoki/src/lib/enoki/index.ts +6 -0
  29. package/presets/react-mysten-simple-upload-enoki/src/lib/enoki/storage-adapter.ts +31 -0
  30. package/presets/react-mysten-simple-upload-enoki/src/lib/walrus/adapter.ts +197 -0
  31. package/presets/react-mysten-simple-upload-enoki/src/lib/walrus/client.ts +87 -0
  32. package/presets/react-mysten-simple-upload-enoki/src/lib/walrus/index.ts +4 -0
  33. package/presets/react-mysten-simple-upload-enoki/src/lib/walrus/types.ts +92 -0
  34. package/presets/react-mysten-simple-upload-enoki/src/main.tsx +19 -0
  35. package/presets/react-mysten-simple-upload-enoki/src/providers/EnokiProvider.tsx +23 -0
  36. package/presets/react-mysten-simple-upload-enoki/src/providers/QueryProvider.tsx +18 -0
  37. package/presets/react-mysten-simple-upload-enoki/src/providers/WalletProvider.tsx +52 -0
  38. package/presets/react-mysten-simple-upload-enoki/src/providers/index.ts +7 -0
  39. package/presets/react-mysten-simple-upload-enoki/src/utils/env.ts +41 -0
  40. package/presets/react-mysten-simple-upload-enoki/src/utils/mime-type.ts +97 -0
  41. package/presets/react-mysten-simple-upload-enoki/tsconfig.json +39 -0
  42. package/presets/react-mysten-simple-upload-enoki/tsconfig.node.json +10 -0
  43. package/presets/react-mysten-simple-upload-enoki/vite.config.ts +19 -0
@@ -0,0 +1,52 @@
1
+ import { useEnokiFlow, useZkLogin } from '@mysten/enoki/react';
2
+ import { enokiConfig } from '../lib/enoki/index.js';
3
+
4
+ /**
5
+ * Enoki authentication hook
6
+ *
7
+ * Provides Google OAuth login/logout, zkLogin state, and unified signer interface
8
+ */
9
+ export function useEnokiAuth() {
10
+ const enokiFlow = useEnokiFlow();
11
+ const { address } = useZkLogin();
12
+
13
+ const login = async () => {
14
+ const protocol = window.location.protocol;
15
+ const host = window.location.host;
16
+ const redirectUrl = `${protocol}//${host}/auth`;
17
+
18
+ const authUrl = await enokiFlow.createAuthorizationURL({
19
+ provider: 'google',
20
+ clientId: enokiConfig.VITE_GOOGLE_CLIENT_ID,
21
+ redirectUrl,
22
+ });
23
+
24
+ window.location.href = authUrl;
25
+ };
26
+
27
+ const logout = () => {
28
+ enokiFlow.logout();
29
+ };
30
+
31
+ const getSigner = () => {
32
+ if (!address || !enokiFlow) return null;
33
+
34
+ return {
35
+ address,
36
+ signAndExecuteTransaction: async (args: any) => {
37
+ const result = await enokiFlow.signAndExecuteTransaction({
38
+ transaction: args.transaction,
39
+ });
40
+ return { digest: result.digest };
41
+ },
42
+ };
43
+ };
44
+
45
+ return {
46
+ isEnokiConnected: !!address,
47
+ enokiAddress: address,
48
+ login,
49
+ logout,
50
+ getSigner,
51
+ };
52
+ }
@@ -0,0 +1,45 @@
1
+ import { useMutation } from '@tanstack/react-query';
2
+ import { useSuiClient } from '@mysten/dapp-kit';
3
+ import { storageAdapter } from '../lib/walrus/index.js';
4
+ import type { UploadOptions } from '../lib/walrus/types.js';
5
+ import { useEnokiAuth } from './use-enoki-auth.js';
6
+ import { useWallet } from './use-wallet.js';
7
+
8
+ /**
9
+ * Upload hook with dual auth support
10
+ *
11
+ * Supports both zkLogin (Enoki) and standard wallet authentication
12
+ * Prioritizes zkLogin if both are available
13
+ */
14
+ export function useUpload() {
15
+ const suiClient = useSuiClient();
16
+ const { getSigner: getEnokiSigner } = useEnokiAuth();
17
+ const { getSigner: getWalletSigner } = useWallet();
18
+
19
+ return useMutation({
20
+ mutationFn: async ({
21
+ file,
22
+ options,
23
+ }: {
24
+ file: File;
25
+ options?: UploadOptions;
26
+ }) => {
27
+ // Prioritize zkLogin, fallback to standard wallet
28
+ const signer = getEnokiSigner() || getWalletSigner();
29
+
30
+ if (!signer) {
31
+ throw new Error(
32
+ 'No wallet connected. Please login with Google or connect a wallet.'
33
+ );
34
+ }
35
+
36
+ const blobId = await storageAdapter.upload(file, {
37
+ ...options,
38
+ client: suiClient,
39
+ signer,
40
+ });
41
+
42
+ return { blobId, file };
43
+ },
44
+ });
45
+ }
@@ -0,0 +1,32 @@
1
+ import { useCurrentAccount, useSignAndExecuteTransaction } from '@mysten/dapp-kit';
2
+
3
+ /**
4
+ * Standard Sui wallet hook
5
+ *
6
+ * Provides wallet connection state and unified signer interface
7
+ */
8
+ export function useWallet() {
9
+ const currentAccount = useCurrentAccount();
10
+ const { mutateAsync: signAndExecute } = useSignAndExecuteTransaction();
11
+
12
+ const getSigner = () => {
13
+ if (!currentAccount) return null;
14
+
15
+ return {
16
+ address: currentAccount.address,
17
+ signAndExecuteTransaction: async (args: any) => {
18
+ const result = await signAndExecute({
19
+ transaction: args.transaction,
20
+ });
21
+ return { digest: result.digest };
22
+ },
23
+ };
24
+ };
25
+
26
+ return {
27
+ isConnected: !!currentAccount,
28
+ address: currentAccount?.address,
29
+ account: currentAccount,
30
+ getSigner,
31
+ };
32
+ }
@@ -0,0 +1,322 @@
1
+ /* Dapp Kit styles */
2
+ @import '@mysten/dapp-kit/dist/index.css';
3
+
4
+ /* Google Fonts Import */
5
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;700&display=swap');
6
+
7
+ /* Global styles */
8
+ :root {
9
+ /* Pallette */
10
+ --walrus-bg-primary: #020617;
11
+ /* Deep Trench */
12
+ --walrus-bg-secondary: #0f172a;
13
+ /* Card/Section bg */
14
+ --walrus-surface: #1e293b;
15
+ /* Input, button bg */
16
+ --walrus-surface-hover: #334155;
17
+ /* Hover states */
18
+ --walrus-accent-cyan: #06b6d4;
19
+ /* Arctic Cyan - Primary Highlight */
20
+ --walrus-accent-blue: #4da2ff;
21
+ /* Sui Blue */
22
+ --walrus-accent-purple: #c084fc;
23
+ /* Secondary Accent */
24
+ --walrus-text-primary: #f8fafc;
25
+ /* Main Text */
26
+ --walrus-text-secondary: #94a3b8;
27
+ /* Muted Text */
28
+ --walrus-border: #334155;
29
+ /* Border Color */
30
+ --walrus-warning: #ef4444;
31
+ --walrus-success: #10b981;
32
+ --walrus-error: #ef4444;
33
+
34
+ /* Base Settings */
35
+ font-family: 'Inter', system-ui, sans-serif;
36
+ line-height: 1.5;
37
+ font-weight: 400;
38
+
39
+ color-scheme: dark;
40
+ color: var(--walrus-text-primary);
41
+ background-color: var(--walrus-bg-primary);
42
+
43
+ font-synthesis: none;
44
+ text-rendering: optimizeLegibility;
45
+ -webkit-font-smoothing: antialiased;
46
+ -moz-osx-font-smoothing: grayscale;
47
+ }
48
+
49
+ body {
50
+ margin: 0;
51
+ display: flex;
52
+ place-items: center;
53
+ min-width: 320px;
54
+ min-height: 100vh;
55
+ background-color: var(--walrus-bg-primary);
56
+ color: var(--walrus-text-primary);
57
+ }
58
+
59
+ #root {
60
+ max-width: 1280px;
61
+ margin: 0 auto;
62
+ padding: 2rem;
63
+ text-align: center;
64
+ width: 100%;
65
+ }
66
+
67
+ /* Typography Overrides */
68
+ h1,
69
+ h2,
70
+ h3,
71
+ h4,
72
+ h5,
73
+ h6 {
74
+ font-family: 'JetBrains Mono', monospace;
75
+ color: var(--walrus-text-primary);
76
+ }
77
+
78
+ h1 {
79
+ font-size: 3.2em;
80
+ line-height: 1.1;
81
+ }
82
+
83
+ h2 {
84
+ font-size: 2.5em;
85
+ }
86
+
87
+ h3 {
88
+ font-size: 1.5em;
89
+ }
90
+
91
+ a {
92
+ font-weight: 500;
93
+ color: var(--walrus-accent-blue);
94
+ text-decoration: inherit;
95
+ }
96
+
97
+ a:hover {
98
+ color: var(--walrus-accent-cyan);
99
+ }
100
+
101
+ /* Button Styling */
102
+ button {
103
+ border-radius: 8px;
104
+ border: 1px solid var(--walrus-border);
105
+ padding: 0.6em 1.2em;
106
+ font-size: 1em;
107
+ font-weight: 600;
108
+ font-family: inherit;
109
+ background-color: var(--walrus-surface);
110
+ color: var(--walrus-text-primary);
111
+ cursor: pointer;
112
+ transition: all 0.25s;
113
+ }
114
+
115
+ button:hover:not(:disabled) {
116
+ border-color: var(--walrus-accent-cyan);
117
+ background-color: var(--walrus-surface-hover);
118
+ box-shadow: 0 0 10px rgba(6, 182, 212, 0.2);
119
+ }
120
+
121
+ button:focus,
122
+ button:focus-visible {
123
+ outline: 4px auto var(--walrus-accent-cyan);
124
+ }
125
+
126
+ button:disabled {
127
+ opacity: 0.5;
128
+ cursor: not-allowed;
129
+ background-color: var(--walrus-bg-secondary);
130
+ }
131
+
132
+ /* Form Elements */
133
+ input {
134
+ background-color: var(--walrus-surface);
135
+ border: 1px solid var(--walrus-border);
136
+ color: var(--walrus-text-primary);
137
+ padding: 0.6em;
138
+ border-radius: 8px;
139
+ font-family: inherit;
140
+ font-size: 1em;
141
+ transition: border-color 0.2s;
142
+ }
143
+
144
+ input:focus {
145
+ outline: none;
146
+ border-color: var(--walrus-accent-cyan);
147
+ }
148
+
149
+ /* Utilities / Components */
150
+ .card {
151
+ background-color: var(--walrus-bg-secondary);
152
+ border: 1px solid var(--walrus-border);
153
+ border-radius: 12px;
154
+ padding: 2rem;
155
+ transition: all 0.2s;
156
+ }
157
+
158
+ .card:hover {
159
+ border-color: var(--walrus-accent-cyan);
160
+ box-shadow: 0 0 15px rgba(6, 182, 212, 0.15);
161
+ }
162
+
163
+ .badge {
164
+ display: inline-block;
165
+ padding: 0.2em 0.6em;
166
+ font-size: 0.85em;
167
+ font-weight: 500;
168
+ border-radius: 999px;
169
+ background-color: rgba(192, 132, 252, 0.15);
170
+ color: var(--walrus-accent-purple);
171
+ border: 1px solid rgba(192, 132, 252, 0.3);
172
+ }
173
+
174
+ .text-accent {
175
+ color: var(--walrus-accent-cyan);
176
+ }
177
+
178
+ .text-secondary {
179
+ color: var(--walrus-text-secondary);
180
+ }
181
+
182
+ .text-error {
183
+ color: var(--walrus-error);
184
+ }
185
+
186
+ .text-warning {
187
+ color: var(--walrus-warning);
188
+ }
189
+
190
+ /* App Specific Containers */
191
+ .simple-upload-app {
192
+ max-width: 900px;
193
+ margin: 0 auto;
194
+ display: flex;
195
+ flex-direction: column;
196
+ gap: 2rem;
197
+ }
198
+
199
+ /* Overriding section to look like cards */
200
+ section {
201
+ margin: 0;
202
+ padding: 2rem;
203
+ border: 1px solid var(--walrus-border);
204
+ background-color: var(--walrus-bg-secondary);
205
+ border-radius: 12px;
206
+ transition: border-color 0.2s;
207
+ }
208
+
209
+ section:hover {
210
+ border-color: var(--walrus-surface-hover);
211
+ }
212
+
213
+ section h3 {
214
+ margin-top: 0;
215
+ color: var(--walrus-accent-cyan);
216
+ }
217
+
218
+ .upload-form,
219
+ .file-preview {
220
+ display: flex;
221
+ flex-direction: column;
222
+ gap: 1.5rem;
223
+ align-items: stretch;
224
+ }
225
+
226
+ .file-info {
227
+ background: var(--walrus-bg-primary);
228
+ padding: 1rem;
229
+ border-radius: 8px;
230
+ border: 1px dashed var(--walrus-border);
231
+ text-align: left;
232
+ }
233
+
234
+ .error {
235
+ color: var(--walrus-error);
236
+ background: rgba(239, 68, 68, 0.1);
237
+ padding: 0.5rem;
238
+ border-radius: 4px;
239
+ }
240
+
241
+ .warning {
242
+ color: var(--walrus-warning);
243
+ }
244
+
245
+ /* Code/Pre blocks */
246
+ pre {
247
+ background: var(--walrus-bg-primary) !important;
248
+ color: var(--walrus-text-primary);
249
+ border: 1px solid var(--walrus-border);
250
+ border-radius: 8px;
251
+ font-family: 'JetBrains Mono', monospace;
252
+ }
253
+
254
+ /* Enoki zkLogin Auth Styles */
255
+ .enoki-auth {
256
+ display: flex;
257
+ align-items: center;
258
+ gap: 1rem;
259
+ padding: 0.75rem 1rem;
260
+ background-color: var(--walrus-surface);
261
+ border-radius: 8px;
262
+ border: 1px solid var(--walrus-accent-purple);
263
+ }
264
+
265
+ .enoki-address {
266
+ font-family: 'JetBrains Mono', monospace;
267
+ font-size: 0.875rem;
268
+ color: var(--walrus-accent-purple);
269
+ }
270
+
271
+ .google-login-btn {
272
+ padding: 0.75rem 1.5rem;
273
+ background: linear-gradient(135deg, var(--walrus-accent-blue), var(--walrus-accent-purple));
274
+ border: none;
275
+ border-radius: 8px;
276
+ color: var(--walrus-text-primary);
277
+ font-weight: 600;
278
+ cursor: pointer;
279
+ transition: transform 0.2s, box-shadow 0.2s;
280
+ }
281
+
282
+ .google-login-btn:hover {
283
+ transform: translateY(-2px);
284
+ box-shadow: 0 4px 12px rgba(64, 162, 255, 0.3);
285
+ }
286
+
287
+ .logout-btn {
288
+ padding: 0.5rem 1rem;
289
+ background-color: var(--walrus-surface-hover);
290
+ border: 1px solid var(--walrus-border);
291
+ border-radius: 6px;
292
+ color: var(--walrus-text-secondary);
293
+ cursor: pointer;
294
+ transition: all 0.2s;
295
+ }
296
+
297
+ .logout-btn:hover {
298
+ background-color: var(--walrus-warning);
299
+ color: var(--walrus-text-primary);
300
+ border-color: var(--walrus-warning);
301
+ }
302
+
303
+ .auth-divider {
304
+ display: flex;
305
+ align-items: center;
306
+ margin: 1rem 0;
307
+ color: var(--walrus-text-secondary);
308
+ font-size: 0.875rem;
309
+ gap: 1rem;
310
+ }
311
+
312
+ .auth-divider::before,
313
+ .auth-divider::after {
314
+ content: '';
315
+ flex: 1;
316
+ height: 1px;
317
+ background-color: var(--walrus-border);
318
+ }
319
+
320
+ .auth-divider span {
321
+ padding: 0 0.5rem;
322
+ }
@@ -0,0 +1,24 @@
1
+ // Re-export Walrus library
2
+ export * from './lib/walrus/index.js';
3
+
4
+ // Re-export Enoki library
5
+ export * from './lib/enoki/index.js';
6
+
7
+ // Re-export providers
8
+ export { QueryProvider, WalletProvider, EnokiProvider } from './providers/index.js';
9
+
10
+ // Re-export features
11
+ export { UploadForm } from './components/features/upload-form.js';
12
+ export { FilePreview } from './components/features/file-preview.js';
13
+ export { WalletConnect } from './components/features/wallet-connect.js';
14
+ export { EnokiAuthButton } from './components/features/enoki-auth-button.js';
15
+
16
+ // Re-export hooks
17
+ export { useUpload } from './hooks/use-upload.js';
18
+ export { useDownload, useMetadata } from './hooks/use-download.js';
19
+ export { useWallet } from './hooks/use-wallet.js';
20
+ export { useEnokiAuth } from './hooks/use-enoki-auth.js';
21
+
22
+ // Re-export layout
23
+ export { AppLayout } from './components/layout/app-layout.js';
24
+
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Enoki configuration constants with Zod validation
5
+ */
6
+
7
+ // Environment variable schema
8
+ export const enokiConfigSchema = z.object({
9
+ VITE_ENOKI_API_KEY: z.string().min(1, 'Enoki API key is required'),
10
+ VITE_GOOGLE_CLIENT_ID: z.string().min(1, 'Google Client ID is required'),
11
+ VITE_SUI_NETWORK: z.enum(['mainnet', 'testnet', 'devnet', 'localnet']).default('testnet'),
12
+ VITE_SUI_RPC: z.string().url().optional(),
13
+ });
14
+
15
+ export type EnokiConfig = z.infer<typeof enokiConfigSchema>;
16
+
17
+ // Validate and export config
18
+ export const enokiConfig: EnokiConfig = enokiConfigSchema.parse({
19
+ VITE_ENOKI_API_KEY: import.meta.env.VITE_ENOKI_API_KEY,
20
+ VITE_GOOGLE_CLIENT_ID: import.meta.env.VITE_GOOGLE_CLIENT_ID,
21
+ VITE_SUI_NETWORK: import.meta.env.VITE_SUI_NETWORK || 'testnet',
22
+ VITE_SUI_RPC: import.meta.env.VITE_SUI_RPC,
23
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Enoki library barrel export
3
+ */
4
+
5
+ export { sessionStorageAdapter, type StorageAdapter } from './storage-adapter.js';
6
+ export { enokiConfig, enokiConfigSchema, type EnokiConfig } from './constants.js';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * SessionStorage adapter for Enoki zkLogin wallet persistence
3
+ *
4
+ * Benefits:
5
+ * - Tab-isolated sessions (auto-cleanup on tab close)
6
+ * - Enhanced security vs localStorage
7
+ * - SSR-safe with browser detection
8
+ */
9
+
10
+ export interface StorageAdapter {
11
+ getItem(key: string): Promise<string | null>;
12
+ setItem(key: string, value: string): Promise<void>;
13
+ removeItem(key: string): Promise<void>;
14
+ }
15
+
16
+ export const sessionStorageAdapter: StorageAdapter = {
17
+ async getItem(key: string): Promise<string | null> {
18
+ if (typeof window === 'undefined') return null;
19
+ return sessionStorage.getItem(key);
20
+ },
21
+
22
+ async setItem(key: string, value: string): Promise<void> {
23
+ if (typeof window === 'undefined') return;
24
+ sessionStorage.setItem(key, value);
25
+ },
26
+
27
+ async removeItem(key: string): Promise<void> {
28
+ if (typeof window === 'undefined') return;
29
+ sessionStorage.removeItem(key);
30
+ },
31
+ };