@farcaster/create-mini-app 0.0.0-canary-20250627225801

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/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # @farcaster/create-mini-app
2
+
3
+ ## 0.0.0-canary-20250627225801
4
+
5
+ ### Patch Changes
6
+
7
+ - [#402](https://github.com/farcasterxyz/miniapps/pull/402) [`0f94fc1`](https://github.com/farcasterxyz/miniapps/commit/0f94fc15b590a551dffb545be9f04fcf9ea41689) Thanks [@PirosB3](https://github.com/PirosB3)! - Enforce Node.js version
8
+
9
+ ## 0.0.8
10
+
11
+ ### Patch Changes
12
+
13
+ - [#143](https://github.com/farcasterxyz/frames/pull/143) [`9253759`](https://github.com/farcasterxyz/frames/commit/925375929d1ee9f7ab7b70df95222624f0fded9a) Thanks [@deodad](https://github.com/deodad)! - Added sections on farcaster.json and Frame Embed to README
14
+ - [#144](https://github.com/farcasterxyz/frames/pull/144) [`3a9178b`](https://github.com/farcasterxyz/frames/commit/3a9178b14585acdf3158577101e0eed45f8513bc) Thanks [@deodad](https://github.com/deodad)! - added support for @neynar/create-farcaster-mini-app
15
+
16
+ ## 0.0.7
17
+
18
+ ### Patch Changes
19
+
20
+ - [`79e0b7a`](https://github.com/farcasterxyz/frames/commit/79e0b7aed34a9623aaace90677eafda8e4e1f09c) Thanks [@deodad](https://github.com/deodad)! - fixed lint warnings
21
+
22
+ ## 0.0.6
23
+
24
+ ### Patch Changes
25
+
26
+ - [`4c854ce`](https://github.com/farcasterxyz/frames/commit/4c854ce141f1448194f7d880aecb009e2a64f677) Thanks [@deodad](https://github.com/deodad)! - fixed lint warnings
27
+
28
+ ## 0.0.5
29
+
30
+ ### Patch Changes
31
+
32
+ - [#140](https://github.com/farcasterxyz/frames/pull/140) [`5450e82`](https://github.com/farcasterxyz/frames/commit/5450e8238e1a257938fb197754535692cda54ca9) Thanks [@deodad](https://github.com/deodad)! - converted to esm
33
+
34
+ ## 0.0.4
35
+
36
+ ### Patch Changes
37
+
38
+ - [`34563f5`](https://github.com/farcasterxyz/frames/commit/34563f5944b063912b65ff5fe424149ef9341809) Thanks [@deodad](https://github.com/deodad)! - removed unneeded buffer polyfill
39
+
40
+ ## 0.0.3
41
+
42
+ ### Patch Changes
43
+
44
+ - [`3ba1faa`](https://github.com/farcasterxyz/frames/commit/3ba1faa8fec42959705c7caecfb881087bb864a0) Thanks [@deodad](https://github.com/deodad)! - fixed build
45
+
46
+ ## 0.0.2
47
+
48
+ ### Patch Changes
49
+
50
+ - [`5afecac`](https://github.com/farcasterxyz/frames/commit/5afecac76d94f86246077c7b90c1071ba1710578) Thanks [@deodad](https://github.com/deodad)! - fixed build
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Merkle Manufactory Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # @farcaster/create-mini-app
2
+
3
+ Get up and running quickly with [Mini Apps](https://miniapps.farcaster.xyz) by using the `@farcaster/create-mini-app` CLI.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm create @farcaster/mini-app
9
+ # or
10
+ pnpm create @farcaster/mini-app
11
+ # or
12
+ yarn create @farcaster/mini-app
13
+ ```
14
+
15
+ ## Documentation
16
+
17
+ For documentation and guides, visit [miniapps.farcaster.xyz](https://miniapps.farcaster.xyz/docs/getting-started).
package/bin.ts ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module'
3
+ import { cac } from 'cac'
4
+ import { type InitParameters, init } from './init.js'
5
+
6
+ const require = createRequire(import.meta.url)
7
+ const pkg = require('../package.json')
8
+
9
+ const cli = cac('create-vocs')
10
+
11
+ cli.usage('[options]').option('-n, --name [name]', 'Name of project')
12
+
13
+ cli.help()
14
+ cli.version(pkg.version)
15
+
16
+ const { options } = cli.parse()
17
+
18
+ if (!options.help) init(options as InitParameters)
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { cac } from 'cac';
4
+ import { init } from './init.js';
5
+ const require = createRequire(import.meta.url);
6
+ const pkg = require('../package.json');
7
+ const cli = cac('create-vocs');
8
+ cli.usage('[options]').option('-n, --name [name]', 'Name of project');
9
+ cli.help();
10
+ cli.version(pkg.version);
11
+ const { options } = cli.parse();
12
+ if (!options.help)
13
+ init(options);
14
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AACzB,OAAO,EAAuB,IAAI,EAAE,MAAM,WAAW,CAAA;AAErD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;AAEtC,MAAM,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,CAAA;AAE9B,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,CAAA;AAErE,GAAG,CAAC,IAAI,EAAE,CAAA;AACV,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AAExB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAA;AAE/B,IAAI,CAAC,OAAO,CAAC,IAAI;IAAE,IAAI,CAAC,OAAyB,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export { init, type InitParameters } from './init.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { init } from './init.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,WAAW,CAAA"}
package/dist/init.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export type InitParameters = {
2
+ name: string;
3
+ };
4
+ export declare function init(params: InitParameters): Promise<void>;
5
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../init.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE7C,wBAAsB,IAAI,CAAC,MAAM,EAAE,cAAc,iBAmEhD"}
package/dist/init.js ADDED
@@ -0,0 +1,97 @@
1
+ import { resolve } from 'node:path';
2
+ import { intro, log, outro, select, text } from '@clack/prompts';
3
+ import { init as initNeynar } from '@neynar/create-farcaster-mini-app';
4
+ import { default as fs } from 'fs-extra';
5
+ import pc from 'picocolors';
6
+ export async function init(params) {
7
+ intro('Welcome to Farcaster Mini Apps!');
8
+ const projectType = await select({
9
+ message: 'Select a template:',
10
+ options: [
11
+ {
12
+ value: 'basic',
13
+ label: 'Basic static site (Vite + TS + React + Wagmi)',
14
+ },
15
+ {
16
+ value: 'neynar',
17
+ label: 'Fully featured with Neynar integration (Next)',
18
+ },
19
+ ],
20
+ });
21
+ if (projectType === 'neynar') {
22
+ await initNeynar();
23
+ return;
24
+ }
25
+ const templateDir = resolve(import.meta.dirname, '../templates/default');
26
+ const displayName = params.name ||
27
+ (await text({
28
+ message: 'Enter the name of your project',
29
+ validate(value) {
30
+ if (!value)
31
+ return 'Please enter a name.';
32
+ return;
33
+ },
34
+ }));
35
+ const name = kebabcase(displayName);
36
+ const destDir = resolve(process.cwd(), name);
37
+ // Copy contents
38
+ fs.copySync(templateDir, destDir);
39
+ // Replace dotfiles
40
+ for (const file of fs.readdirSync(destDir)) {
41
+ if (!file.startsWith('_'))
42
+ continue;
43
+ fs.renameSync(resolve(destDir, file), resolve(destDir, `.${file.slice(1)}`));
44
+ }
45
+ // Replace package.json properties
46
+ const pkgJson = fs.readJsonSync(resolve(destDir, 'package.json'));
47
+ pkgJson.name = name;
48
+ fs.writeJsonSync(resolve(destDir, 'package.json'), pkgJson, { spaces: 2 });
49
+ // Wrap up
50
+ log.success(`Project successfully scaffolded in ${pc.blue(destDir)}!`);
51
+ const pkgManager = detectPackageManager();
52
+ log.message('Next steps:');
53
+ log.step(`1. ${pc.blue(`cd ./${name}`)} - Navigate to project`);
54
+ log.step(`2. ${pc.blue(pkgManagerInstallCommand(pkgManager))} - Install dependencies`);
55
+ log.step(`3. ${pc.blue(pkgManagerRunCommand(pkgManager, 'dev'))} - Start dev server`);
56
+ log.step(`4. Head to ${pc.blue('http://localhost:5173')}`);
57
+ outro('Happy Mini App building!');
58
+ }
59
+ function detectPackageManager() {
60
+ const userAgent = process.env.npm_config_user_agent;
61
+ if (!userAgent)
62
+ return 'npm';
63
+ if (userAgent.includes('bun'))
64
+ return 'bun';
65
+ if (userAgent.includes('yarn'))
66
+ return 'yarn';
67
+ if (userAgent.includes('pnpm'))
68
+ return 'pnpm';
69
+ if (userAgent.includes('npm'))
70
+ return 'npm';
71
+ return 'npm';
72
+ }
73
+ function pkgManagerInstallCommand(pkgManager) {
74
+ if (pkgManager === 'bun')
75
+ return 'bun install';
76
+ if (pkgManager === 'yarn')
77
+ return 'yarn';
78
+ if (pkgManager === 'pnpm')
79
+ return 'pnpm install';
80
+ return 'npm install';
81
+ }
82
+ function pkgManagerRunCommand(pkgManager, command) {
83
+ if (pkgManager === 'bun')
84
+ return `bun run ${command}`;
85
+ if (pkgManager === 'yarn')
86
+ return `yarn ${command}`;
87
+ if (pkgManager === 'pnpm')
88
+ return `pnpm ${command}`;
89
+ return `npm run ${command}`;
90
+ }
91
+ function kebabcase(str) {
92
+ return str
93
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
94
+ .replace(/[\s_]+/g, '-')
95
+ .toLowerCase();
96
+ }
97
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../init.ts"],"names":[],"mappings":"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"}
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { init, type InitParameters } from './init.js'
package/init.ts ADDED
@@ -0,0 +1,109 @@
1
+ import { resolve } from 'node:path'
2
+ import { intro, log, outro, select, text } from '@clack/prompts'
3
+ import { init as initNeynar } from '@neynar/create-farcaster-mini-app'
4
+ import { default as fs } from 'fs-extra'
5
+ import pc from 'picocolors'
6
+
7
+ export type InitParameters = { name: string }
8
+
9
+ export async function init(params: InitParameters) {
10
+ intro('Welcome to Farcaster Mini Apps!')
11
+
12
+ const projectType = await select({
13
+ message: 'Select a template:',
14
+ options: [
15
+ {
16
+ value: 'basic',
17
+ label: 'Basic static site (Vite + TS + React + Wagmi)',
18
+ },
19
+ {
20
+ value: 'neynar',
21
+ label: 'Fully featured with Neynar integration (Next)',
22
+ },
23
+ ],
24
+ })
25
+
26
+ if (projectType === 'neynar') {
27
+ await initNeynar()
28
+ return
29
+ }
30
+
31
+ const templateDir = resolve(import.meta.dirname, '../templates/default')
32
+
33
+ const displayName =
34
+ params.name ||
35
+ ((await text({
36
+ message: 'Enter the name of your project',
37
+ validate(value) {
38
+ if (!value) return 'Please enter a name.'
39
+ return
40
+ },
41
+ })) as string)
42
+ const name = kebabcase(displayName)
43
+
44
+ const destDir = resolve(process.cwd(), name)
45
+
46
+ // Copy contents
47
+ fs.copySync(templateDir, destDir)
48
+
49
+ // Replace dotfiles
50
+ for (const file of fs.readdirSync(destDir)) {
51
+ if (!file.startsWith('_')) continue
52
+ fs.renameSync(resolve(destDir, file), resolve(destDir, `.${file.slice(1)}`))
53
+ }
54
+
55
+ // Replace package.json properties
56
+ const pkgJson = fs.readJsonSync(resolve(destDir, 'package.json'))
57
+ pkgJson.name = name
58
+ fs.writeJsonSync(resolve(destDir, 'package.json'), pkgJson, { spaces: 2 })
59
+
60
+ // Wrap up
61
+ log.success(`Project successfully scaffolded in ${pc.blue(destDir)}!`)
62
+
63
+ const pkgManager = detectPackageManager()
64
+
65
+ log.message('Next steps:')
66
+ log.step(`1. ${pc.blue(`cd ./${name}`)} - Navigate to project`)
67
+ log.step(
68
+ `2. ${pc.blue(pkgManagerInstallCommand(pkgManager))} - Install dependencies`,
69
+ )
70
+ log.step(
71
+ `3. ${pc.blue(pkgManagerRunCommand(pkgManager, 'dev'))} - Start dev server`,
72
+ )
73
+ log.step(`4. Head to ${pc.blue('http://localhost:5173')}`)
74
+
75
+ outro('Happy Mini App building!')
76
+ }
77
+
78
+ type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun'
79
+
80
+ function detectPackageManager(): PackageManager {
81
+ const userAgent = process.env.npm_config_user_agent
82
+ if (!userAgent) return 'npm'
83
+ if (userAgent.includes('bun')) return 'bun'
84
+ if (userAgent.includes('yarn')) return 'yarn'
85
+ if (userAgent.includes('pnpm')) return 'pnpm'
86
+ if (userAgent.includes('npm')) return 'npm'
87
+ return 'npm'
88
+ }
89
+
90
+ function pkgManagerInstallCommand(pkgManager: PackageManager) {
91
+ if (pkgManager === 'bun') return 'bun install'
92
+ if (pkgManager === 'yarn') return 'yarn'
93
+ if (pkgManager === 'pnpm') return 'pnpm install'
94
+ return 'npm install'
95
+ }
96
+
97
+ function pkgManagerRunCommand(pkgManager: PackageManager, command: string) {
98
+ if (pkgManager === 'bun') return `bun run ${command}`
99
+ if (pkgManager === 'yarn') return `yarn ${command}`
100
+ if (pkgManager === 'pnpm') return `pnpm ${command}`
101
+ return `npm run ${command}`
102
+ }
103
+
104
+ function kebabcase(str: string) {
105
+ return str
106
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
107
+ .replace(/[\s_]+/g, '-')
108
+ .toLowerCase()
109
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@farcaster/create-mini-app",
3
+ "version": "0.0.0-canary-20250627225801",
4
+ "description": "Create Farcaster Mini Apps with one command",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "create-mini-app": "./dist/bin.js"
9
+ },
10
+ "keywords": [
11
+ "farcaster",
12
+ "mini-apps",
13
+ "mini apps",
14
+ "web3",
15
+ "cli"
16
+ ],
17
+ "license": "MIT",
18
+ "devDependencies": {
19
+ "@types/fs-extra": "^11.0.4",
20
+ "typescript": "^5.8.3",
21
+ "@farcaster/tsconfig": "0.0.5"
22
+ },
23
+ "dependencies": {
24
+ "@clack/prompts": "^0.10.0",
25
+ "@neynar/create-farcaster-mini-app": "^1.2.7",
26
+ "cac": "^6.7.14",
27
+ "fs-extra": "^11.3.0",
28
+ "picocolors": "^1.1.1"
29
+ },
30
+ "engines": {
31
+ "node": ">=22.11.0"
32
+ },
33
+ "scripts": {
34
+ "build": "pnpm run clean && tsc --project tsconfig.build.json",
35
+ "check:types": "tsc --noEmit",
36
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
37
+ "dev": "pnpm run src/cli.ts"
38
+ }
39
+ }
@@ -0,0 +1,23 @@
1
+ This is a [Vite](https://vitejs.dev) project bootstrapped with [`@farcaster/create-mini-app`](https://github.com/farcasterxyz/miniapps/tree/main/packages/create-mini-app).
2
+
3
+ For documentation and guides, visit [miniapps.farcaster.xyz](https://miniapps.farcaster.xyz/docs/getting-started).
4
+
5
+ ## `farcaster.json`
6
+
7
+ The `/.well-known/farcaster.json` is served from the [public
8
+ directory](https://vite.dev/guide/assets) and can be updated by editing
9
+ `./public/.well-known/farcaster.json`.
10
+
11
+ You can also use the `public` directory to serve a static image for `splashBackgroundImageUrl`.
12
+
13
+ ## Frame Embed
14
+
15
+ Add a the `fc:frame` in `index.html` to make your root app URL sharable in feeds:
16
+
17
+ ```html
18
+ <head>
19
+ <!--- other tags --->
20
+ <meta name="fc:frame" content='{"version":"next","imageUrl":"https://placehold.co/900x600.png?text=Frame%20Image","button":{"title":"Open","action":{"type":"launch_frame","name":"App Name","url":"https://app.com"}}}' />
21
+ </head>
22
+ ```
23
+
@@ -0,0 +1 @@
1
+ VITE_WC_PROJECT_ID=
@@ -0,0 +1,24 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
@@ -0,0 +1 @@
1
+ legacy-peer-deps = true
@@ -0,0 +1,13 @@
1
+ {
2
+ "formatter": {
3
+ "enabled": true,
4
+ "indentStyle": "space",
5
+ "lineWidth": 120
6
+ },
7
+ "linter": {
8
+ "enabled": true
9
+ },
10
+ "organizeImports": {
11
+ "enabled": true
12
+ }
13
+ }
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Create Mini App</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "default",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "lint": "biome check src",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@farcaster/frame-sdk": "latest",
14
+ "@farcaster/frame-wagmi-connector": "latest",
15
+ "@tanstack/react-query": "5.45.1",
16
+ "react": "^18.3.1",
17
+ "react-dom": "^18.3.1",
18
+ "viem": "latest",
19
+ "wagmi": "latest"
20
+ },
21
+ "devDependencies": {
22
+ "@biomejs/biome": "^1.8.0",
23
+ "@types/react": "^18.3.1",
24
+ "@types/react-dom": "^18.3.0",
25
+ "@vitejs/plugin-react": "^4.2.1",
26
+ "@wagmi/cli": "latest",
27
+ "typescript": "^5.8.3",
28
+ "vite": "^5.2.11"
29
+ }
30
+ }
@@ -0,0 +1,63 @@
1
+ import { sdk } from "@farcaster/frame-sdk";
2
+ import { useEffect } from "react";
3
+ import { useAccount, useConnect, useSignMessage } from "wagmi";
4
+
5
+ function App() {
6
+ useEffect(() => {
7
+ sdk.actions.ready();
8
+ }, []);
9
+
10
+ return (
11
+ <>
12
+ <div>Mini App + Vite + TS + React + Wagmi</div>
13
+ <ConnectMenu />
14
+ </>
15
+ );
16
+ }
17
+
18
+ function ConnectMenu() {
19
+ const { isConnected, address } = useAccount();
20
+ const { connect, connectors } = useConnect();
21
+
22
+ if (isConnected) {
23
+ return (
24
+ <>
25
+ <div>Connected account:</div>
26
+ <div>{address}</div>
27
+ <SignButton />
28
+ </>
29
+ );
30
+ }
31
+
32
+ return (
33
+ <button type="button" onClick={() => connect({ connector: connectors[0] })}>
34
+ Connect
35
+ </button>
36
+ );
37
+ }
38
+
39
+ function SignButton() {
40
+ const { signMessage, isPending, data, error } = useSignMessage();
41
+
42
+ return (
43
+ <>
44
+ <button type="button" onClick={() => signMessage({ message: "hello world" })} disabled={isPending}>
45
+ {isPending ? "Signing..." : "Sign message"}
46
+ </button>
47
+ {data && (
48
+ <>
49
+ <div>Signature</div>
50
+ <div>{data}</div>
51
+ </>
52
+ )}
53
+ {error && (
54
+ <>
55
+ <div>Error</div>
56
+ <div>{error.message}</div>
57
+ </>
58
+ )}
59
+ </>
60
+ );
61
+ }
62
+
63
+ export default App;
@@ -0,0 +1,21 @@
1
+ :root {
2
+ background-color: #181818;
3
+ color: rgba(255, 255, 255, 0.87);
4
+ color-scheme: light dark;
5
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
6
+ font-synthesis: none;
7
+ font-weight: 400;
8
+ line-height: 1.5;
9
+ text-rendering: optimizeLegibility;
10
+
11
+ -webkit-font-smoothing: antialiased;
12
+ -moz-osx-font-smoothing: grayscale;
13
+ -webkit-text-size-adjust: 100%;
14
+ }
15
+
16
+ @media (prefers-color-scheme: light) {
17
+ :root {
18
+ background-color: #f8f8f8;
19
+ color: #181818;
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2
+ import React from "react";
3
+ import ReactDOM from "react-dom/client";
4
+ import { WagmiProvider } from "wagmi";
5
+
6
+ import App from "./App.tsx";
7
+ import { config } from "./wagmi.ts";
8
+
9
+ import "./index.css";
10
+
11
+ const queryClient = new QueryClient();
12
+
13
+ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
14
+ <React.StrictMode>
15
+ <WagmiProvider config={config}>
16
+ <QueryClientProvider client={queryClient}>
17
+ <App />
18
+ </QueryClientProvider>
19
+ </WagmiProvider>
20
+ </React.StrictMode>,
21
+ );
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,18 @@
1
+ import { farcasterFrame } from "@farcaster/frame-wagmi-connector";
2
+ import { http, createConfig } from "wagmi";
3
+ import { base, mainnet } from "wagmi/chains";
4
+
5
+ export const config = createConfig({
6
+ chains: [base, mainnet],
7
+ connectors: [farcasterFrame()],
8
+ transports: {
9
+ [base.id]: http(),
10
+ [mainnet.id]: http(),
11
+ },
12
+ });
13
+
14
+ declare module "wagmi" {
15
+ interface Register {
16
+ config: typeof config;
17
+ }
18
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["src"],
24
+ "references": [{ "path": "./tsconfig.node.json" }]
25
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true
8
+ },
9
+ "include": ["vite.config.ts"]
10
+ }
@@ -0,0 +1,10 @@
1
+ import react from "@vitejs/plugin-react";
2
+ import { defineConfig } from "vite";
3
+
4
+ // https://vitejs.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ server: {
8
+ allowedHosts: true,
9
+ },
10
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "@farcaster/tsconfig/node.json",
3
+ "exclude": ["dist", "node_modules"],
4
+ "include": ["*"],
5
+ "compilerOptions": {
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "outDir": "./dist",
9
+ "sourceMap": true
10
+ }
11
+ }