@sei-js/create-sei 0.0.4 → 1.0.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 (129) hide show
  1. package/.rsyncignore +11 -0
  2. package/CHANGELOG.md +23 -0
  3. package/dist/extensions/precompiles/package.json +44 -0
  4. package/dist/extensions/precompiles/src/components/default/index.tsx +201 -0
  5. package/dist/main.js +48 -29
  6. package/dist/main.test.js +34 -0
  7. package/dist/templates/next-template/.env.example +8 -0
  8. package/dist/templates/next-template/.eslintrc.json +1 -3
  9. package/dist/templates/next-template/.nvmrc +1 -0
  10. package/dist/templates/next-template/README.md +2 -6
  11. package/dist/templates/next-template/biome.json +56 -0
  12. package/dist/templates/next-template/next-env.d.ts +1 -1
  13. package/dist/templates/next-template/next.config.mjs +14 -1
  14. package/dist/templates/next-template/package.json +33 -17
  15. package/dist/templates/next-template/postcss.config.mjs +6 -0
  16. package/dist/templates/next-template/src/app/development/page.tsx +260 -0
  17. package/dist/templates/next-template/src/app/globals.css +16 -0
  18. package/dist/templates/next-template/src/app/layout.tsx +17 -8
  19. package/dist/templates/next-template/src/app/page.tsx +6 -17
  20. package/dist/templates/next-template/src/app/resources/page.tsx +175 -0
  21. package/dist/templates/next-template/src/app/resources/resources.ts +56 -0
  22. package/dist/templates/next-template/src/components/default/examples.ts +63 -0
  23. package/dist/templates/next-template/src/components/default/index.tsx +402 -0
  24. package/dist/templates/next-template/src/components/index.ts +3 -0
  25. package/dist/templates/next-template/src/components/landing/index.tsx +155 -0
  26. package/dist/templates/next-template/src/components/providers/index.ts +1 -0
  27. package/dist/templates/next-template/src/components/providers/providers.tsx +108 -0
  28. package/dist/templates/next-template/src/components/shell/index.ts +1 -0
  29. package/dist/templates/next-template/src/components/shell/shell.tsx +88 -0
  30. package/dist/templates/next-template/tailwind.config.js +5 -0
  31. package/dist/templates/next-template/tsconfig.json +2 -1
  32. package/extensions/precompiles/package.json +44 -0
  33. package/extensions/precompiles/src/components/default/index.tsx +201 -0
  34. package/jest.config.js +14 -0
  35. package/package.json +16 -5
  36. package/src/main.test.ts +38 -0
  37. package/src/main.ts +54 -34
  38. package/templates/next-template/.env.example +8 -0
  39. package/templates/next-template/.eslintrc.json +1 -3
  40. package/templates/next-template/.nvmrc +1 -0
  41. package/templates/next-template/README.md +2 -6
  42. package/templates/next-template/biome.json +56 -0
  43. package/templates/next-template/next-env.d.ts +1 -1
  44. package/templates/next-template/next.config.mjs +14 -1
  45. package/templates/next-template/package.json +33 -17
  46. package/templates/next-template/postcss.config.mjs +6 -0
  47. package/templates/next-template/src/app/development/page.tsx +260 -0
  48. package/templates/next-template/src/app/globals.css +16 -0
  49. package/templates/next-template/src/app/layout.tsx +17 -8
  50. package/templates/next-template/src/app/page.tsx +6 -17
  51. package/templates/next-template/src/app/resources/page.tsx +175 -0
  52. package/templates/next-template/src/app/resources/resources.ts +56 -0
  53. package/templates/next-template/src/components/default/examples.ts +63 -0
  54. package/templates/next-template/src/components/default/index.tsx +402 -0
  55. package/templates/next-template/src/components/index.ts +3 -0
  56. package/templates/next-template/src/components/landing/index.tsx +155 -0
  57. package/templates/next-template/src/components/providers/index.ts +1 -0
  58. package/templates/next-template/src/components/providers/providers.tsx +108 -0
  59. package/templates/next-template/src/components/shell/index.ts +1 -0
  60. package/templates/next-template/src/components/shell/shell.tsx +88 -0
  61. package/templates/next-template/tailwind.config.js +5 -0
  62. package/templates/next-template/tsconfig.json +2 -1
  63. package/.yarn/install-state.gz +0 -0
  64. package/dist/templates/next-template/public/sei-logotype.svg +0 -15
  65. package/dist/templates/next-template/src/app/components/Homepage/Examples.tsx +0 -257
  66. package/dist/templates/next-template/src/app/components/Homepage/Homepage.css +0 -154
  67. package/dist/templates/next-template/src/app/components/Homepage/Homepage.tsx +0 -87
  68. package/dist/templates/next-template/src/app/components/Web3Provider.tsx +0 -74
  69. package/dist/templates/next-template/src/app/components/index.ts +0 -2
  70. package/dist/templates/next-template/src/app/constants/chain.ts +0 -7
  71. package/dist/templates/next-template/src/app/constants/index.ts +0 -1
  72. package/dist/templates/next-template/src/app/index.css +0 -184
  73. package/dist/templates/next-template/yarn.lock +0 -4809
  74. package/dist/templates/vite-template/.eslintrc.cjs +0 -11
  75. package/dist/templates/vite-template/README.md +0 -72
  76. package/dist/templates/vite-template/index.html +0 -12
  77. package/dist/templates/vite-template/package.json +0 -33
  78. package/dist/templates/vite-template/public/sei-logotype.svg +0 -15
  79. package/dist/templates/vite-template/src/App.tsx +0 -21
  80. package/dist/templates/vite-template/src/assets/react.svg +0 -1
  81. package/dist/templates/vite-template/src/components/Homepage/Examples.tsx +0 -255
  82. package/dist/templates/vite-template/src/components/Homepage/Homepage.css +0 -154
  83. package/dist/templates/vite-template/src/components/Homepage/Homepage.tsx +0 -81
  84. package/dist/templates/vite-template/src/components/Web3Provider.tsx +0 -72
  85. package/dist/templates/vite-template/src/constants/chain.ts +0 -6
  86. package/dist/templates/vite-template/src/constants/index.ts +0 -1
  87. package/dist/templates/vite-template/src/index.css +0 -183
  88. package/dist/templates/vite-template/src/main.tsx +0 -12
  89. package/dist/templates/vite-template/src/vite-env.d.ts +0 -1
  90. package/dist/templates/vite-template/tsconfig.app.json +0 -25
  91. package/dist/templates/vite-template/tsconfig.json +0 -11
  92. package/dist/templates/vite-template/tsconfig.node.json +0 -14
  93. package/dist/templates/vite-template/vite.config.ts +0 -10
  94. package/dist/templates/vite-template/yarn.lock +0 -4603
  95. package/templates/next-template/public/sei-logotype.svg +0 -15
  96. package/templates/next-template/src/app/components/Homepage/Examples.tsx +0 -257
  97. package/templates/next-template/src/app/components/Homepage/Homepage.css +0 -154
  98. package/templates/next-template/src/app/components/Homepage/Homepage.tsx +0 -87
  99. package/templates/next-template/src/app/components/Web3Provider.tsx +0 -74
  100. package/templates/next-template/src/app/components/index.ts +0 -2
  101. package/templates/next-template/src/app/constants/chain.ts +0 -7
  102. package/templates/next-template/src/app/constants/index.ts +0 -1
  103. package/templates/next-template/src/app/favicon.ico +0 -0
  104. package/templates/next-template/src/app/index.css +0 -184
  105. package/templates/next-template/yarn.lock +0 -4809
  106. package/templates/vite-template/.eslintrc.cjs +0 -11
  107. package/templates/vite-template/README.md +0 -72
  108. package/templates/vite-template/favicon.ico +0 -0
  109. package/templates/vite-template/index.html +0 -12
  110. package/templates/vite-template/package.json +0 -33
  111. package/templates/vite-template/public/sei-logotype.svg +0 -15
  112. package/templates/vite-template/src/App.tsx +0 -21
  113. package/templates/vite-template/src/assets/react.svg +0 -1
  114. package/templates/vite-template/src/components/Homepage/Examples.tsx +0 -255
  115. package/templates/vite-template/src/components/Homepage/Homepage.css +0 -154
  116. package/templates/vite-template/src/components/Homepage/Homepage.tsx +0 -81
  117. package/templates/vite-template/src/components/Web3Provider.tsx +0 -72
  118. package/templates/vite-template/src/constants/chain.ts +0 -6
  119. package/templates/vite-template/src/constants/index.ts +0 -1
  120. package/templates/vite-template/src/index.css +0 -183
  121. package/templates/vite-template/src/main.tsx +0 -12
  122. package/templates/vite-template/src/vite-env.d.ts +0 -1
  123. package/templates/vite-template/tsconfig.app.json +0 -25
  124. package/templates/vite-template/tsconfig.json +0 -11
  125. package/templates/vite-template/tsconfig.node.json +0 -14
  126. package/templates/vite-template/vite.config.ts +0 -10
  127. package/templates/vite-template/yarn.lock +0 -4603
  128. /package/dist/templates/next-template/{src/app → public}/favicon.ico +0 -0
  129. /package/{dist/templates/vite-template → templates/next-template/public}/favicon.ico +0 -0
@@ -0,0 +1,88 @@
1
+ "use client";
2
+
3
+ import { ActionIcon, AppShell, Container, Group } from "@mantine/core";
4
+ import { ConnectButton } from "@rainbow-me/rainbowkit";
5
+ import { IconBook, IconCode, IconLogout } from "@tabler/icons-react";
6
+ import Image from "next/image";
7
+ import Link from "next/link";
8
+ import type { PropsWithChildren } from "react";
9
+ import { useAccount, useDisconnect } from "wagmi";
10
+
11
+ export default function Shell({ children }: PropsWithChildren) {
12
+ const { address, isConnected } = useAccount();
13
+ const { disconnect } = useDisconnect();
14
+
15
+ return (
16
+ <AppShell header={{ height: 64 }} padding="md">
17
+ <AppShell.Header>
18
+ <Container size="xl" h="100%">
19
+ <Group justify="space-between" align="center" h="100%">
20
+ <Link href="/" aria-label="Sei">
21
+ <Image src="https://cdn.sei.io/assets/sei-icon.svg" alt="Sei" width={28} height={28} style={{ display: "block" }} />
22
+ </Link>
23
+ <Group align="center" gap="md">
24
+ <ActionIcon
25
+ component={Link}
26
+ href="/resources"
27
+ variant="light"
28
+ c="gray"
29
+ size="lg"
30
+ radius="md"
31
+ aria-label="View Resources"
32
+ style={{
33
+ transition: "all 0.2s ease",
34
+ "&:hover": {
35
+ transform: "translateY(-1px)",
36
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
37
+ },
38
+ }}
39
+ >
40
+ <IconBook size={18} />
41
+ </ActionIcon>
42
+ <ActionIcon
43
+ component={Link}
44
+ href="/development"
45
+ variant="light"
46
+ c="gray"
47
+ size="lg"
48
+ radius="md"
49
+ aria-label="View Development Guide"
50
+ style={{
51
+ transition: "all 0.2s ease",
52
+ "&:hover": {
53
+ transform: "translateY(-1px)",
54
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
55
+ },
56
+ }}
57
+ >
58
+ <IconCode size={18} />
59
+ </ActionIcon>
60
+ {isConnected && address ? (
61
+ <ActionIcon
62
+ variant="light"
63
+ c="red"
64
+ size="lg"
65
+ radius="md"
66
+ onClick={() => disconnect()}
67
+ aria-label="Disconnect Wallet"
68
+ style={{
69
+ transition: "all 0.2s ease",
70
+ "&:hover": {
71
+ transform: "translateY(-1px)",
72
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
73
+ },
74
+ }}
75
+ >
76
+ <IconLogout size={18} />
77
+ </ActionIcon>
78
+ ) : (
79
+ <ConnectButton showBalance={{ smallScreen: false, largeScreen: true }} />
80
+ )}
81
+ </Group>
82
+ </Group>
83
+ </Container>
84
+ </AppShell.Header>
85
+ <AppShell.Main>{children}</AppShell.Main>
86
+ </AppShell>
87
+ );
88
+ }
@@ -0,0 +1,5 @@
1
+ // Tailwind v4 uses CSS-first configuration.
2
+ // Custom theme values are defined in src/app/globals.css via @theme.
3
+ // This file is kept as an empty config for compatibility.
4
+ /** @type {import('tailwindcss').Config} */
5
+ module.exports = {};
@@ -19,7 +19,8 @@
19
19
  ],
20
20
  "paths": {
21
21
  "@/*": ["./src/*"]
22
- }
22
+ },
23
+ "target": "ES2017"
23
24
  },
24
25
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
25
26
  "exclude": ["node_modules"]
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "template-next-create-sei-app-precompiles",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "biome lint .",
10
+ "lint:fix": "biome lint --write .",
11
+ "format": "biome format --write .",
12
+ "format:check": "biome format .",
13
+ "check": "biome check .",
14
+ "check:fix": "biome check --write .",
15
+ "deploy": "vercel --prod"
16
+ },
17
+ "dependencies": {
18
+ "@mantine/code-highlight": "^8.2.5",
19
+ "@mantine/core": "^8.2.5",
20
+ "@mantine/hooks": "^8.2.5",
21
+ "@mantine/notifications": "^8.2.5",
22
+ "@rainbow-me/rainbowkit": "^2.2.8",
23
+ "@sei-js/precompiles": "^2.1.2",
24
+ "@tabler/icons-react": "^3.34.1",
25
+ "@tailwindcss/postcss": "^4.1.12",
26
+ "@tanstack/react-query": "^5.85.3",
27
+ "ethers": "^6.15.0",
28
+ "next": "15.4.7",
29
+ "pino-pretty": "^13.1.1",
30
+ "react": "^19.1.1",
31
+ "react-dom": "^19.1.1",
32
+ "viem": "^2.34.0",
33
+ "wagmi": "^2.16.4"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^24.3.0",
37
+ "@types/react": "^19.1.10",
38
+ "@types/react-dom": "^19.1.7",
39
+ "autoprefixer": "^10.4.21",
40
+ "postcss": "^8.4.45",
41
+ "tailwindcss": "^4.1.12",
42
+ "typescript": "^5.9.2"
43
+ }
44
+ }
@@ -0,0 +1,201 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import { CodeHighlight } from '@mantine/code-highlight';
5
+ import { ActionIcon, Badge, Button, Card, Collapse, Container, Flex, Group, Paper, Stack, Text, ThemeIcon, Title } from '@mantine/core';
6
+ import { notifications } from '@mantine/notifications';
7
+ import { BANK_PRECOMPILE_ADDRESS, VIEM_BANK_PRECOMPILE_ABI } from '@sei-js/precompiles';
8
+ import { IconBulb, IconChevronDown, IconChevronUp, IconCopy, IconDatabase } from '@tabler/icons-react';
9
+ import { useState } from 'react';
10
+ import { type ReadContractParameters, formatEther } from 'viem';
11
+ import { useAccount, usePublicClient } from 'wagmi';
12
+
13
+ function Examples() {
14
+ const [supply, setSupply] = useState('');
15
+ const [showCode, setShowCode] = useState(false);
16
+
17
+ const publicClient = usePublicClient();
18
+ const { address } = useAccount();
19
+
20
+ const formatLargeSeiNumber = (num: string, decimals: number): string => {
21
+ if (num.length > 10) {
22
+ return `${(Number(num) / 1000000 / 1000000000).toLocaleString(navigator.language, {
23
+ minimumFractionDigits: decimals,
24
+ maximumFractionDigits: decimals
25
+ })} B`;
26
+ }
27
+ return (Number(num) / 1000000).toLocaleString(navigator.language);
28
+ };
29
+
30
+ const copyToClipboard = (text: string) => {
31
+ try {
32
+ navigator.clipboard.writeText(text).then(() => {
33
+ notifications.show({
34
+ title: 'Copied!',
35
+ message: 'Code copied to clipboard',
36
+ color: 'green'
37
+ });
38
+ });
39
+ } catch (err) {
40
+ console.error('Failed to copy text: ', err);
41
+ notifications.show({
42
+ title: 'Error',
43
+ message: 'Failed to copy to clipboard',
44
+ color: 'red'
45
+ });
46
+ }
47
+ };
48
+
49
+ const getSeiSupply = async () => {
50
+ if (!publicClient) {
51
+ return undefined;
52
+ }
53
+
54
+ const readContractParams: ReadContractParameters = {
55
+ abi: VIEM_BANK_PRECOMPILE_ABI,
56
+ address: BANK_PRECOMPILE_ADDRESS,
57
+ functionName: 'supply',
58
+ args: ['usei']
59
+ };
60
+
61
+ try {
62
+ const result = await publicClient.readContract(readContractParams);
63
+ setSupply((result as bigint).toString());
64
+ } catch (error) {
65
+ console.error('Error fetching supply:', error);
66
+ notifications.show({
67
+ title: 'Error',
68
+ message: 'Failed to fetch SEI supply',
69
+ color: 'red'
70
+ });
71
+ }
72
+ };
73
+
74
+ const codeExample = `// Sei Precompile Example - Bank Precompile
75
+ import { BANK_PRECOMPILE_ADDRESS, VIEM_BANK_PRECOMPILE_ABI } from '@sei-js/precompiles';
76
+ import { usePublicClient } from 'wagmi';
77
+
78
+ const publicClient = usePublicClient();
79
+
80
+ const getSeiSupply = async () => {
81
+ const readContractParams = {
82
+ abi: VIEM_BANK_PRECOMPILE_ABI,
83
+ address: BANK_PRECOMPILE_ADDRESS,
84
+ functionName: 'supply',
85
+ args: ['usei'],
86
+ };
87
+
88
+ const result = await publicClient?.readContract(readContractParams);
89
+ return (result as bigint).toString();
90
+ };`;
91
+
92
+ return (
93
+ <Container size="xl" py="xl" pos="relative">
94
+ <Stack gap="xl">
95
+ {/* Header */}
96
+ <div>
97
+ <Group gap="md" align="center" mb="lg">
98
+ <ThemeIcon size={48} radius="md" c="orange" variant="light">
99
+ <IconBulb size={24} />
100
+ </ThemeIcon>
101
+ <div>
102
+ <Title order={1} fw={700} c="gray.9">
103
+ Sei Precompiles
104
+ </Title>
105
+ <Text size="lg" c="gray.6" mt={4}>
106
+ Access native Sei blockchain functionality through EVM precompiles
107
+ </Text>
108
+ </div>
109
+ </Group>
110
+ </div>
111
+
112
+ {/* Precompile Example Card */}
113
+ <Card shadow="xs" p="lg" radius="md" withBorder>
114
+ <Stack gap="md">
115
+ <Flex justify="space-between" align="flex-start">
116
+ <Stack gap="xs">
117
+ <Group gap="md">
118
+ <ThemeIcon size={40} radius="md" color="orange" variant="light">
119
+ <IconDatabase size={20} />
120
+ </ThemeIcon>
121
+ <Title order={3} fw={600} c="gray.9">
122
+ Bank Precompile
123
+ </Title>
124
+ </Group>
125
+ <Text size="sm" c="gray.6">
126
+ Query total SEI supply using Sei's native{' '}
127
+ <Text component="a" href="https://www.docs.sei.io/dev-interoperability/precompiles/bank" target="_blank" c="orange" td="underline">
128
+ Bank precompile
129
+ </Text>
130
+ </Text>
131
+ </Stack>
132
+ <Badge color="orange" variant="light" size="md" radius="md">
133
+ precompiles
134
+ </Badge>
135
+ </Flex>
136
+
137
+ <Paper p="md" radius="md" withBorder bg="gray.0">
138
+ <Text size="xs" fw={500} c="gray.6">
139
+ Total Supply
140
+ </Text>
141
+ <Flex justify="space-between" align="center">
142
+ <Flex align="baseline" gap="xs">
143
+ {supply ? (
144
+ <>
145
+ <Text fw={700} size="xl" c="gray.9" ff="monospace">
146
+ {formatLargeSeiNumber(supply, 2)}
147
+ </Text>
148
+ <Text size="sm" c="gray.6" fw={500}>
149
+ SEI
150
+ </Text>
151
+ </>
152
+ ) : (
153
+ <Paper px="sm" py={4} bg="white" radius="md" withBorder>
154
+ <Flex align="baseline" gap="xs">
155
+ <Text fw={700} size="xl" c="gray.5" ff="monospace">
156
+ —
157
+ </Text>
158
+ <Text size="sm" c="gray.6" fw={500}>
159
+ SEI
160
+ </Text>
161
+ </Flex>
162
+ </Paper>
163
+ )}
164
+ </Flex>
165
+ <Button onClick={getSeiSupply} size="sm" radius="md" variant="light" color="orange" leftSection={<IconDatabase size={14} />}>
166
+ {supply ? 'Refresh' : 'Query Supply'}
167
+ </Button>
168
+ </Flex>
169
+ </Paper>
170
+
171
+ <Group justify="space-between" align="center" mt="sm">
172
+ <Button
173
+ variant="subtle"
174
+ color="gray"
175
+ size="sm"
176
+ radius="md"
177
+ leftSection={showCode ? <IconChevronUp size={14} /> : <IconChevronDown size={14} />}
178
+ onClick={() => setShowCode(!showCode)}
179
+ >
180
+ {showCode ? 'Hide' : 'View'} Implementation
181
+ </Button>
182
+ {showCode && (
183
+ <ActionIcon variant="subtle" color="gray" size="sm" radius="md" onClick={() => copyToClipboard(codeExample)}>
184
+ <IconCopy size={14} />
185
+ </ActionIcon>
186
+ )}
187
+ </Group>
188
+
189
+ <Collapse in={showCode}>
190
+ <Paper mt="sm" p="md" bg="gray.0" radius="md" withBorder>
191
+ <CodeHighlight code={codeExample} language="tsx" withCopyButton={false} expandCodeLabel="" collapseCodeLabel="" />
192
+ </Paper>
193
+ </Collapse>
194
+ </Stack>
195
+ </Card>
196
+ </Stack>
197
+ </Container>
198
+ );
199
+ }
200
+
201
+ export default Examples;
package/jest.config.js ADDED
@@ -0,0 +1,14 @@
1
+ export default {
2
+ preset: 'ts-jest',
3
+ testEnvironment: 'node',
4
+ transform: {
5
+ '^.+\\.ts$': ['ts-jest', {
6
+ useESM: true
7
+ }]
8
+ },
9
+ extensionsToTreatAsEsm: ['.ts'],
10
+ moduleNameMapper: {
11
+ '^(\\.{1,2}/.*)\\.js$': '$1'
12
+ },
13
+ testPathIgnorePatterns: ['/node_modules/', '/dist/', '/templates/', '/test-smart-contract-app/']
14
+ };
package/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "@sei-js/create-sei",
3
- "version": "0.0.4",
3
+ "version": "1.0.1",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/sei-protocol/sei-js.git",
7
+ "directory": "packages/create-sei"
8
+ },
4
9
  "module": "dist/main.js",
5
10
  "type": "module",
6
11
  "bin": "./dist/main.js",
7
12
  "scripts": {
8
- "build": "tsc && cp -r ./templates ./dist/templates",
9
- "dev": "node --loader ts-node/esm src/main.ts"
13
+ "build": "rm -rf dist && tsc && chmod +x dist/main.js && rsync -av --exclude-from=.rsyncignore ./templates/ ./dist/templates/ && rsync -av --exclude-from=.rsyncignore ./extensions/ ./dist/extensions/",
14
+ "dev": "node --loader ts-node/esm src/main.ts",
15
+ "test": "jest"
10
16
  },
11
17
  "dependencies": {
12
18
  "boxen": "^7.1.1",
@@ -14,7 +20,12 @@
14
20
  "inquirer": "^9.2.15"
15
21
  },
16
22
  "devDependencies": {
17
- "@types/boxen": "^3.0.1",
18
- "@types/inquirer": "^9.0.7"
23
+ "@jest/globals": "^29.7.0",
24
+ "@types/jest": "^29.5.12",
25
+ "@types/node": "^20.14.10",
26
+ "jest": "^29.7.0",
27
+ "ts-jest": "^29.1.2",
28
+ "ts-node": "^10.9.2",
29
+ "typescript": "^5.5.3"
19
30
  }
20
31
  }
@@ -0,0 +1,38 @@
1
+ import { describe, test, expect, beforeEach, afterEach } from '@jest/globals';
2
+ import { promises as fs } from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ describe('Extension System', () => {
6
+ const testDir = path.join(process.cwd(), 'test-output');
7
+ const extensionsDir = path.join(process.cwd(), 'extensions');
8
+
9
+ beforeEach(async () => {
10
+ // Clean up test directory
11
+ try {
12
+ await fs.rm(testDir, { recursive: true, force: true });
13
+ } catch (e) {
14
+ // Directory might not exist
15
+ }
16
+ await fs.mkdir(testDir, { recursive: true });
17
+ });
18
+
19
+ afterEach(async () => {
20
+ // Clean up test directory
21
+ try {
22
+ await fs.rm(testDir, { recursive: true, force: true });
23
+ } catch (e) {
24
+ // Directory might not exist
25
+ }
26
+ });
27
+
28
+ test('should list available extensions', async () => {
29
+ const extensionExists = await fs.access(path.join(extensionsDir, 'precompiles'))
30
+ .then(() => true)
31
+ .catch(() => false);
32
+
33
+ expect(extensionExists).toBe(true);
34
+
35
+ const extensionFiles = await fs.readdir(extensionsDir);
36
+ expect(extensionFiles).toContain('precompiles');
37
+ });
38
+ });
package/src/main.ts CHANGED
@@ -25,29 +25,11 @@ const printWelcomeMessage = () => {
25
25
  );
26
26
  };
27
27
 
28
- enum FrontendScaffolding {
29
- Vite = 'vite',
30
- Next = 'next'
31
- }
32
-
33
28
  interface WizardOptions {
34
29
  name?: string;
35
- framework?: FrontendScaffolding;
30
+ extension?: string;
36
31
  }
37
32
 
38
- const promptFramework = async () => {
39
- const { appFramework } = await inquirer.prompt([
40
- {
41
- type: 'list',
42
- name: 'appFramework',
43
- message: 'Select an app framework to use?',
44
- choices: Object.values(FrontendScaffolding)
45
- }
46
- ]);
47
-
48
- return appFramework;
49
- };
50
-
51
33
  function isValidDirectoryName(dirName) {
52
34
  const illegalRe = /[<>:"/\\|?*]/g;
53
35
  const windowsReservedRe = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
@@ -76,17 +58,30 @@ const validateOptions = (options: WizardOptions): boolean => {
76
58
  }
77
59
  }
78
60
 
79
- if (options.framework) {
80
- const validFrameworks = Object.values(FrontendScaffolding);
81
- if (!validFrameworks.includes(options.framework)) {
82
- console.log(`Invalid Framework '${options.framework}' provided. Framework must be one of: [${validFrameworks.join(', ')}]`);
83
- valid = false;
84
- }
85
- }
86
-
87
61
  return valid;
88
62
  };
89
63
 
64
+ async function listExtensions(): Promise<void> {
65
+ const extensionsPath = path.join(__dirname, 'extensions');
66
+
67
+ try {
68
+ const extensions = await fs.promises.readdir(extensionsPath, { withFileTypes: true });
69
+ const extensionDirs = extensions.filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
70
+
71
+ if (extensionDirs.length === 0) {
72
+ console.log('No extensions available.');
73
+ return;
74
+ }
75
+
76
+ console.log('Available extensions:');
77
+ for (const ext of extensionDirs) {
78
+ console.log(` - ${ext}`);
79
+ }
80
+ } catch (error) {
81
+ console.log('No extensions directory found.');
82
+ }
83
+ }
84
+
90
85
  async function runWizard(options: WizardOptions): Promise<void> {
91
86
  if (!validateOptions(options)) {
92
87
  return;
@@ -112,22 +107,36 @@ async function runWizard(options: WizardOptions): Promise<void> {
112
107
  dAppName = promptResult.dAppName;
113
108
  }
114
109
 
115
- const appFramework = options.framework || (await promptFramework());
116
-
117
- const templateName = `${appFramework}-template`;
110
+ // Copy base template
111
+ const templateName = 'next-template';
118
112
  const templatePath = path.join(__dirname, 'templates', templateName);
119
113
  const dst = path.join(process.cwd(), dAppName);
120
114
  await fs.promises.cp(templatePath, dst, { recursive: true });
121
115
 
122
- console.log(`Project setup complete! Using template ${templateName}\n`);
123
- console.log(`To start your app, run: \n > cd ${dAppName} \n > yarn \n > yarn dev\n`);
116
+ // Apply extension if specified
117
+ if (options.extension) {
118
+ const extensionPath = path.join(__dirname, 'extensions', options.extension);
119
+
120
+ try {
121
+ await fs.promises.access(extensionPath);
122
+ await fs.promises.cp(extensionPath, dst, { recursive: true });
123
+ console.log(`Applied extension: ${options.extension}`);
124
+ } catch (error) {
125
+ console.log(`Warning: Extension '${options.extension}' not found. Continuing with base template.`);
126
+ }
127
+ }
128
+
129
+ const extensionText = options.extension ? ` with ${options.extension} extension` : '';
130
+ console.log(`Project setup complete! Using template ${templateName}${extensionText}\n`);
131
+ console.log(`To start your app, run: \n > cd ${dAppName} \n > pnpm \n > pnpm dev\n`);
124
132
  }
125
133
 
126
134
  program
127
135
  .command('app')
128
136
  .description('Create a new SEI dApp')
129
- .option('-n, --name <name>', 'Specify the name of your dApp. Name must be a valid package name.')
130
- .option('-f, --framework <framework>', `Specify the app framework to use: [${Object.values(FrontendScaffolding).join(', ')}]`)
137
+ .option('--name <name>', 'Specify the name of your dApp. Name must be a valid package name.')
138
+ .option('--extension <extension>', 'Specify an extension to apply to the base template')
139
+
131
140
  .action(async (options: WizardOptions) => {
132
141
  try {
133
142
  await runWizard(options);
@@ -136,4 +145,15 @@ program
136
145
  }
137
146
  });
138
147
 
148
+ program
149
+ .command('list-extensions')
150
+ .description('List all available extensions')
151
+ .action(async () => {
152
+ try {
153
+ await listExtensions();
154
+ } catch (error) {
155
+ console.error('An error occurred:', error);
156
+ }
157
+ });
158
+
139
159
  program.parse(process.argv);
@@ -0,0 +1,8 @@
1
+ # Chain configuration
2
+ # Options: mainnet, testnet, devnet
3
+ # Defaults to mainnet if not set; this example overrides it to testnet
4
+ NEXT_PUBLIC_CHAIN=testnet
5
+
6
+ # WalletConnect Project ID (optional)
7
+ # Get your project ID from https://cloud.walletconnect.com
8
+ NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your-project-id
@@ -1,3 +1 @@
1
- {
2
- "extends": "next/core-web-vitals"
3
- }
1
+ {}
@@ -0,0 +1 @@
1
+ v20
@@ -4,17 +4,13 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next
4
4
 
5
5
  Install dependencies by running
6
6
  ```bash
7
- npm install
8
- #or
9
- yarn
7
+ bun install
10
8
  ```
11
9
 
12
10
  Then, run the development server:
13
11
 
14
12
  ```bash
15
- npm run dev
16
- # or
17
- yarn dev
13
+ bun run dev
18
14
  ```
19
15
 
20
16
  Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
@@ -0,0 +1,56 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.5/schema.json",
3
+ "root": true,
4
+ "assist": {
5
+ "actions": {
6
+ "source": {
7
+ "organizeImports": "on"
8
+ }
9
+ }
10
+ },
11
+ "linter": {
12
+ "enabled": true,
13
+ "rules": {
14
+ "recommended": true,
15
+ "style": {
16
+ "noNonNullAssertion": "off"
17
+ },
18
+ "suspicious": {
19
+ "noExplicitAny": "off"
20
+ }
21
+ }
22
+ },
23
+ "formatter": {
24
+ "enabled": true,
25
+ "formatWithErrors": false,
26
+ "indentStyle": "tab",
27
+ "lineEnding": "lf",
28
+ "lineWidth": 160
29
+ },
30
+ "javascript": {
31
+ "formatter": {
32
+ "jsxQuoteStyle": "double",
33
+ "quoteProperties": "asNeeded",
34
+ "trailingCommas": "es5",
35
+ "semicolons": "always",
36
+ "arrowParentheses": "always",
37
+ "bracketSpacing": true,
38
+ "bracketSameLine": false,
39
+ "quoteStyle": "double"
40
+ }
41
+ },
42
+ "css": {
43
+ "parser": {
44
+ "tailwindDirectives": true
45
+ }
46
+ },
47
+ "json": {
48
+ "formatter": {
49
+ "trailingCommas": "none"
50
+ }
51
+ },
52
+ "files": {
53
+ "includes": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.css", "*.json", "*.md"],
54
+ "ignore": ["node_modules/**", "dist/**", ".next/**", ".yarn/**"]
55
+ }
56
+ }
@@ -2,4 +2,4 @@
2
2
  /// <reference types="next/image-types/global" />
3
3
 
4
4
  // NOTE: This file should not be edited
5
- // see https://nextjs.org/docs/basic-features/typescript for more information.
5
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.