@semaphore-protocol/cli 4.0.0-beta.8 → 4.0.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.
- package/README.md +18 -4
- package/dist/index.js +47 -8
- package/package.json +3 -3
- package/src/checkLatestVersion.ts +4 -4
- package/src/getGroupIds.ts +7 -3
- package/src/index.ts +13 -1
- package/src/inquirerPrompts.ts +20 -0
- package/src/spinner.ts +5 -0
package/README.md
CHANGED
|
@@ -46,23 +46,25 @@
|
|
|
46
46
|
</h4>
|
|
47
47
|
</div>
|
|
48
48
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
49
|
+
| Semaphore CLI simplifies the process of setting up Semaphore projects and retrieving on-chain group data, reducing setup time from minutes to seconds. |
|
|
50
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
51
51
|
|
|
52
52
|
## 🛠 Install
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
To install Semaphore CLI globally:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
57
|
npm i -g @semaphore-protocol/cli
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Alternatively, you can use `npx` to run commands without installing the package globally:
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
63
|
npx @semaphore-protocol/cli create my-app
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
This command sets up a new project in the `my-app` directory using the `monorepo-ethers` template.
|
|
67
|
+
|
|
66
68
|
## 📜 Usage
|
|
67
69
|
|
|
68
70
|
```
|
|
@@ -82,3 +84,15 @@ Commands:
|
|
|
82
84
|
get-proofs [options] [group-id] Get the proofs of a group from a supported network (e.g. sepolia or arbitrum).
|
|
83
85
|
help [command] Display help for a specific command.
|
|
84
86
|
```
|
|
87
|
+
|
|
88
|
+
## 🌐 Supported Networks
|
|
89
|
+
|
|
90
|
+
Semaphore CLI supports multiple Ethereum networks. Use the `get-groups` command to interact with groups on networks like Sepolia or Arbitrum.
|
|
91
|
+
|
|
92
|
+
## 📦 Supported Templates
|
|
93
|
+
|
|
94
|
+
When creating a new project, you can choose from several templates designed to integrate seamlessly with Semaphore's privacy protocols:
|
|
95
|
+
|
|
96
|
+
- **monorepo-ethers**: Hardhat + Next.js + SemaphoreEthers
|
|
97
|
+
- **monorepo-subgraph**: Hardhat + Next.js + SemaphoreSubgraph
|
|
98
|
+
- **contracts-hardhat**: Hardhat only, focused on smart contract development.
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @module @semaphore-protocol/cli
|
|
5
|
-
* @version 4.0.0
|
|
5
|
+
* @version 4.0.0
|
|
6
6
|
* @file A command line tool to set up your Semaphore project and get group data.
|
|
7
7
|
* @copyright Ethereum Foundation 2024
|
|
8
8
|
* @license MIT
|
|
@@ -15,7 +15,7 @@ import chalk from 'chalk';
|
|
|
15
15
|
import { program } from 'commander';
|
|
16
16
|
import decompress from 'decompress';
|
|
17
17
|
import figlet from 'figlet';
|
|
18
|
-
import { readFileSync, existsSync, unlinkSync, copyFileSync } from 'fs';
|
|
18
|
+
import { readFileSync, existsSync, unlinkSync, copyFileSync, writeFileSync } from 'fs';
|
|
19
19
|
import logSymbols from 'log-symbols';
|
|
20
20
|
import pacote from 'pacote';
|
|
21
21
|
import { dirname } from 'path';
|
|
@@ -29,10 +29,10 @@ import inquirer from 'inquirer';
|
|
|
29
29
|
|
|
30
30
|
const cliRegistryURL = "https://registry.npmjs.org/-/package/@semaphore-protocol/cli/dist-tags";
|
|
31
31
|
/**
|
|
32
|
-
* Checks the
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* @param currentVersion The current version of the CLI.
|
|
32
|
+
* Checks for the latest version of the CLI tool against the registry. It first attempts to fetch the version directly
|
|
33
|
+
* via an API call. If this fails, possibly due to network restrictions, it falls back to using the `npm view` command.
|
|
34
|
+
* This method ensures that users behind a firewall or using a private registry can still check for updates.
|
|
35
|
+
* @param currentVersion The current version of the CLI being used.
|
|
36
36
|
*/
|
|
37
37
|
async function checkLatestVersion(currentVersion) {
|
|
38
38
|
let latestVersion;
|
|
@@ -55,6 +55,11 @@ async function checkLatestVersion(currentVersion) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* A utility class for managing a CLI spinner. This class encapsulates the functionality of the `ora` spinner,
|
|
60
|
+
* providing methods to start and stop the spinner. It is used to give visual feedback to the user during operations
|
|
61
|
+
* that have a noticeable delay, such as network requests.
|
|
62
|
+
*/
|
|
58
63
|
class Spinner {
|
|
59
64
|
constructor(text) {
|
|
60
65
|
this.ora = ora({
|
|
@@ -72,8 +77,11 @@ class Spinner {
|
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
80
|
+
* Retrieves all group IDs from the Semaphore protocol on a specified network. This function first attempts to
|
|
81
|
+
* fetch the group IDs using the SemaphoreSubgraph interface. If that fails, it tries the SemaphoreEthers interface
|
|
82
|
+
* as a fallback. This dual-method approach ensures higher reliability in fetching data across different network conditions.
|
|
83
|
+
* @param network The blockchain network from which to fetch the group IDs.
|
|
84
|
+
* @returns A promise that resolves to an array of group IDs or null if an error occurs.
|
|
77
85
|
*/
|
|
78
86
|
async function getGroupIds(network) {
|
|
79
87
|
let groupIds;
|
|
@@ -99,6 +107,10 @@ async function getGroupIds(network) {
|
|
|
99
107
|
return groupIds;
|
|
100
108
|
}
|
|
101
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Prompts the user to input the name of their project. Provides a default name of "my-app".
|
|
112
|
+
* @returns A promise that resolves to the user's input for the project name.
|
|
113
|
+
*/
|
|
102
114
|
async function getProjectName() {
|
|
103
115
|
const { projectName } = await inquirer.prompt({
|
|
104
116
|
name: "projectName",
|
|
@@ -108,6 +120,12 @@ async function getProjectName() {
|
|
|
108
120
|
});
|
|
109
121
|
return projectName;
|
|
110
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Prompts the user to select a template from a list of supported templates. Each template is presented
|
|
125
|
+
* with its value and name for better clarity.
|
|
126
|
+
* @param supportedTemplates An array of objects, each containing a 'value' and 'name' property for the template.
|
|
127
|
+
* @returns A promise that resolves to the selected template's value.
|
|
128
|
+
*/
|
|
111
129
|
async function getSupportedTemplate(supportedTemplates) {
|
|
112
130
|
const { selectedTemplate } = await inquirer.prompt({
|
|
113
131
|
name: "selectedTemplate",
|
|
@@ -121,6 +139,11 @@ async function getSupportedTemplate(supportedTemplates) {
|
|
|
121
139
|
});
|
|
122
140
|
return selectedTemplate;
|
|
123
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Prompts the user to select a network from a list of supported networks.
|
|
144
|
+
* @param supportedNetworks An array of strings representing the supported networks.
|
|
145
|
+
* @returns A promise that resolves to the selected network.
|
|
146
|
+
*/
|
|
124
147
|
async function getSupportedNetwork(supportedNetworks) {
|
|
125
148
|
const { selectedNetwork } = await inquirer.prompt({
|
|
126
149
|
name: "selectedNetwork",
|
|
@@ -131,6 +154,11 @@ async function getSupportedNetwork(supportedNetworks) {
|
|
|
131
154
|
});
|
|
132
155
|
return selectedNetwork;
|
|
133
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Prompts the user to select a group ID from a list of existing group IDs.
|
|
159
|
+
* @param groupIds An array of strings representing the group IDs.
|
|
160
|
+
* @returns A promise that resolves to the selected group ID.
|
|
161
|
+
*/
|
|
134
162
|
async function getGroupId(groupIds) {
|
|
135
163
|
const { selectedGroupId } = await inquirer.prompt({
|
|
136
164
|
name: "selectedGroupId",
|
|
@@ -142,8 +170,10 @@ async function getGroupId(groupIds) {
|
|
|
142
170
|
return selectedGroupId;
|
|
143
171
|
}
|
|
144
172
|
|
|
173
|
+
// Define the path to the package.json file to extract metadata for the CLI.
|
|
145
174
|
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`;
|
|
146
175
|
const { description, version } = JSON.parse(readFileSync(`${packagePath}/package.json`, "utf8"));
|
|
176
|
+
// List of supported templates for project creation.
|
|
147
177
|
const supportedTemplates = [
|
|
148
178
|
{
|
|
149
179
|
value: "monorepo-ethers",
|
|
@@ -158,6 +188,7 @@ const supportedTemplates = [
|
|
|
158
188
|
name: "Hardhat"
|
|
159
189
|
}
|
|
160
190
|
];
|
|
191
|
+
// Setup the CLI program with basic information and help text.
|
|
161
192
|
program
|
|
162
193
|
.name("semaphore")
|
|
163
194
|
.description(description)
|
|
@@ -171,6 +202,7 @@ program
|
|
|
171
202
|
console.info(`\n ${logSymbols.error}`, message);
|
|
172
203
|
}
|
|
173
204
|
});
|
|
205
|
+
// Define the 'create' command to scaffold new Semaphore projects.
|
|
174
206
|
program
|
|
175
207
|
.command("create")
|
|
176
208
|
.description("Create a Semaphore project with a supported template.")
|
|
@@ -196,15 +228,22 @@ program
|
|
|
196
228
|
}
|
|
197
229
|
spinner.start();
|
|
198
230
|
await checkLatestVersion(version);
|
|
231
|
+
// Extract the template package into the project directory.
|
|
199
232
|
await pacote.extract(`@semaphore-protocol/cli-template-${template}@${version}`, `${currentDirectory}/${projectDirectory}`);
|
|
233
|
+
// Decompress the template files after extraction.
|
|
200
234
|
await decompress(`${currentDirectory}/${projectDirectory}/files.tgz`, `${currentDirectory}/${projectDirectory}`);
|
|
235
|
+
// Clean up the compressed file after extraction.
|
|
201
236
|
unlinkSync(`${currentDirectory}/${projectDirectory}/files.tgz`);
|
|
237
|
+
// Copy the example environment file to the actual environment file.
|
|
202
238
|
copyFileSync(`${currentDirectory}/${projectDirectory}/.env.example`, `${currentDirectory}/${projectDirectory}/.env`);
|
|
239
|
+
// Create an empty yarn.lock file to install dependencies successfully
|
|
240
|
+
writeFileSync(`${currentDirectory}/${projectDirectory}/yarn.lock`, "");
|
|
203
241
|
spinner.stop();
|
|
204
242
|
console.info(`\n ${logSymbols.success}`, `Your project is ready!\n`);
|
|
205
243
|
console.info(` Please, install your dependencies by running:\n`);
|
|
206
244
|
console.info(` ${chalk.cyan("cd")} ${projectDirectory}`);
|
|
207
245
|
console.info(` ${chalk.cyan("yarn install")}\n`);
|
|
246
|
+
// Read the package.json to list available npm scripts.
|
|
208
247
|
const { scripts } = JSON.parse(readFileSync(`${currentDirectory}/${projectDirectory}/package.json`, "utf8"));
|
|
209
248
|
if (scripts) {
|
|
210
249
|
console.info(` Available scripts:\n`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semaphore-protocol/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0.0
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"description": "A command line tool to set up your Semaphore project and get group data.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"rollup-plugin-cleanup": "^3.2.1"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@semaphore-protocol/data": "4.0.0
|
|
45
|
-
"@semaphore-protocol/utils": "4.0.0
|
|
44
|
+
"@semaphore-protocol/data": "4.0.0",
|
|
45
|
+
"@semaphore-protocol/utils": "4.0.0",
|
|
46
46
|
"axios": "^1.6.7",
|
|
47
47
|
"boxen": "^7.1.1",
|
|
48
48
|
"chalk": "^5.3.0",
|
|
@@ -7,10 +7,10 @@ import { lt as semverLt } from "semver"
|
|
|
7
7
|
const cliRegistryURL = "https://registry.npmjs.org/-/package/@semaphore-protocol/cli/dist-tags"
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Checks the
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* @param currentVersion The current version of the CLI.
|
|
10
|
+
* Checks for the latest version of the CLI tool against the registry. It first attempts to fetch the version directly
|
|
11
|
+
* via an API call. If this fails, possibly due to network restrictions, it falls back to using the `npm view` command.
|
|
12
|
+
* This method ensures that users behind a firewall or using a private registry can still check for updates.
|
|
13
|
+
* @param currentVersion The current version of the CLI being used.
|
|
14
14
|
*/
|
|
15
15
|
export default async function checkLatestVersion(currentVersion: string) {
|
|
16
16
|
let latestVersion: string
|
package/src/getGroupIds.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { SemaphoreSubgraph, SemaphoreEthers } from "@semaphore-protocol/data"
|
|
2
|
+
import { SupportedNetwork } from "@semaphore-protocol/utils"
|
|
2
3
|
import logSymbols from "log-symbols"
|
|
3
4
|
import Spinner from "./spinner.js"
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* Retrieves all group IDs from the Semaphore protocol on a specified network. This function first attempts to
|
|
8
|
+
* fetch the group IDs using the SemaphoreSubgraph interface. If that fails, it tries the SemaphoreEthers interface
|
|
9
|
+
* as a fallback. This dual-method approach ensures higher reliability in fetching data across different network conditions.
|
|
10
|
+
* @param network The blockchain network from which to fetch the group IDs.
|
|
11
|
+
* @returns A promise that resolves to an array of group IDs or null if an error occurs.
|
|
8
12
|
*/
|
|
9
|
-
export default async function getGroupIds(network): Promise<string[]> {
|
|
13
|
+
export default async function getGroupIds(network: SupportedNetwork): Promise<string[]> {
|
|
10
14
|
let groupIds: string[]
|
|
11
15
|
|
|
12
16
|
const spinner = new Spinner("Fetching groups")
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import chalk from "chalk"
|
|
|
4
4
|
import { program } from "commander"
|
|
5
5
|
import decompress from "decompress"
|
|
6
6
|
import figlet from "figlet"
|
|
7
|
-
import { copyFileSync, existsSync, readFileSync, unlinkSync } from "fs"
|
|
7
|
+
import { copyFileSync, existsSync, readFileSync, unlinkSync, writeFileSync } from "fs"
|
|
8
8
|
import logSymbols from "log-symbols"
|
|
9
9
|
import pacote from "pacote"
|
|
10
10
|
import { dirname } from "path"
|
|
@@ -14,9 +14,11 @@ import getGroupIds from "./getGroupIds.js"
|
|
|
14
14
|
import { getGroupId, getProjectName, getSupportedNetwork, getSupportedTemplate } from "./inquirerPrompts.js"
|
|
15
15
|
import Spinner from "./spinner.js"
|
|
16
16
|
|
|
17
|
+
// Define the path to the package.json file to extract metadata for the CLI.
|
|
17
18
|
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
|
|
18
19
|
const { description, version } = JSON.parse(readFileSync(`${packagePath}/package.json`, "utf8"))
|
|
19
20
|
|
|
21
|
+
// List of supported templates for project creation.
|
|
20
22
|
const supportedTemplates = [
|
|
21
23
|
{
|
|
22
24
|
value: "monorepo-ethers",
|
|
@@ -32,6 +34,7 @@ const supportedTemplates = [
|
|
|
32
34
|
}
|
|
33
35
|
]
|
|
34
36
|
|
|
37
|
+
// Setup the CLI program with basic information and help text.
|
|
35
38
|
program
|
|
36
39
|
.name("semaphore")
|
|
37
40
|
.description(description)
|
|
@@ -46,6 +49,7 @@ program
|
|
|
46
49
|
}
|
|
47
50
|
})
|
|
48
51
|
|
|
52
|
+
// Define the 'create' command to scaffold new Semaphore projects.
|
|
49
53
|
program
|
|
50
54
|
.command("create")
|
|
51
55
|
.description("Create a Semaphore project with a supported template.")
|
|
@@ -78,20 +82,27 @@ program
|
|
|
78
82
|
|
|
79
83
|
await checkLatestVersion(version)
|
|
80
84
|
|
|
85
|
+
// Extract the template package into the project directory.
|
|
81
86
|
await pacote.extract(
|
|
82
87
|
`@semaphore-protocol/cli-template-${template}@${version}`,
|
|
83
88
|
`${currentDirectory}/${projectDirectory}`
|
|
84
89
|
)
|
|
85
90
|
|
|
91
|
+
// Decompress the template files after extraction.
|
|
86
92
|
await decompress(`${currentDirectory}/${projectDirectory}/files.tgz`, `${currentDirectory}/${projectDirectory}`)
|
|
87
93
|
|
|
94
|
+
// Clean up the compressed file after extraction.
|
|
88
95
|
unlinkSync(`${currentDirectory}/${projectDirectory}/files.tgz`)
|
|
89
96
|
|
|
97
|
+
// Copy the example environment file to the actual environment file.
|
|
90
98
|
copyFileSync(
|
|
91
99
|
`${currentDirectory}/${projectDirectory}/.env.example`,
|
|
92
100
|
`${currentDirectory}/${projectDirectory}/.env`
|
|
93
101
|
)
|
|
94
102
|
|
|
103
|
+
// Create an empty yarn.lock file to install dependencies successfully
|
|
104
|
+
writeFileSync(`${currentDirectory}/${projectDirectory}/yarn.lock`, "")
|
|
105
|
+
|
|
95
106
|
spinner.stop()
|
|
96
107
|
|
|
97
108
|
console.info(`\n ${logSymbols.success}`, `Your project is ready!\n`)
|
|
@@ -99,6 +110,7 @@ program
|
|
|
99
110
|
console.info(` ${chalk.cyan("cd")} ${projectDirectory}`)
|
|
100
111
|
console.info(` ${chalk.cyan("yarn install")}\n`)
|
|
101
112
|
|
|
113
|
+
// Read the package.json to list available npm scripts.
|
|
102
114
|
const { scripts } = JSON.parse(readFileSync(`${currentDirectory}/${projectDirectory}/package.json`, "utf8"))
|
|
103
115
|
|
|
104
116
|
if (scripts) {
|
package/src/inquirerPrompts.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import inquirer from "inquirer"
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Prompts the user to input the name of their project. Provides a default name of "my-app".
|
|
5
|
+
* @returns A promise that resolves to the user's input for the project name.
|
|
6
|
+
*/
|
|
3
7
|
export async function getProjectName() {
|
|
4
8
|
const { projectName } = await inquirer.prompt({
|
|
5
9
|
name: "projectName",
|
|
@@ -10,6 +14,12 @@ export async function getProjectName() {
|
|
|
10
14
|
return projectName
|
|
11
15
|
}
|
|
12
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Prompts the user to select a template from a list of supported templates. Each template is presented
|
|
19
|
+
* with its value and name for better clarity.
|
|
20
|
+
* @param supportedTemplates An array of objects, each containing a 'value' and 'name' property for the template.
|
|
21
|
+
* @returns A promise that resolves to the selected template's value.
|
|
22
|
+
*/
|
|
13
23
|
export async function getSupportedTemplate(supportedTemplates: { value: string; name: string }[]) {
|
|
14
24
|
const { selectedTemplate } = await inquirer.prompt({
|
|
15
25
|
name: "selectedTemplate",
|
|
@@ -24,6 +34,11 @@ export async function getSupportedTemplate(supportedTemplates: { value: string;
|
|
|
24
34
|
return selectedTemplate
|
|
25
35
|
}
|
|
26
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Prompts the user to select a network from a list of supported networks.
|
|
39
|
+
* @param supportedNetworks An array of strings representing the supported networks.
|
|
40
|
+
* @returns A promise that resolves to the selected network.
|
|
41
|
+
*/
|
|
27
42
|
export async function getSupportedNetwork(supportedNetworks: string[]) {
|
|
28
43
|
const { selectedNetwork } = await inquirer.prompt({
|
|
29
44
|
name: "selectedNetwork",
|
|
@@ -35,6 +50,11 @@ export async function getSupportedNetwork(supportedNetworks: string[]) {
|
|
|
35
50
|
return selectedNetwork
|
|
36
51
|
}
|
|
37
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Prompts the user to select a group ID from a list of existing group IDs.
|
|
55
|
+
* @param groupIds An array of strings representing the group IDs.
|
|
56
|
+
* @returns A promise that resolves to the selected group ID.
|
|
57
|
+
*/
|
|
38
58
|
export async function getGroupId(groupIds: string[]) {
|
|
39
59
|
const { selectedGroupId } = await inquirer.prompt({
|
|
40
60
|
name: "selectedGroupId",
|
package/src/spinner.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import ora, { Ora } from "ora"
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A utility class for managing a CLI spinner. This class encapsulates the functionality of the `ora` spinner,
|
|
5
|
+
* providing methods to start and stop the spinner. It is used to give visual feedback to the user during operations
|
|
6
|
+
* that have a noticeable delay, such as network requests.
|
|
7
|
+
*/
|
|
3
8
|
export default class Spinner {
|
|
4
9
|
private ora: Ora
|
|
5
10
|
|