added gitignore

This commit is contained in:
Kumaraguru 2024-10-31 02:19:42 +00:00
commit 9dc5c0a997
No known key found for this signature in database
GPG Key ID: 4E4555A84ECD28F7
7 changed files with 1091 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
datadir

51
README.md Normal file
View File

@ -0,0 +1,51 @@
# Codex Storage CLI
![CodexCLI](/images/screenshot.png)
This CLI is the easiest way to get started with [Codex](https://codex.storage). Get your node up and running in a matter of seconds and start interacting with the Codex Testnet by uploading and downloading files from the other peers in the network.
> ⚠️ Note : Codex is currently in testnet and there is no guarentee for files stored on the Codex test network. All the files uploaded to Codex are not encrypted by default and hence, the files are publicly accessible. By using this application, you agree to acknowledge the [disclaimer](https://github.com/codex-storage/codex-testnet-starter/blob/master/DISCLAIMER.md).
## How it works?
Run the Codex Storage CLI in your terminal
```
npx codexstorage
```
#### Downloading and running the Codex node
A CLI interface would appear with multiple options. Start by downloading the Codex binaries by using option 1.
![Installing]()
Once you are done downloading the binaries, you can go ahead and try running the Codex node by choosing option 2. You will be asked to enter your listening (default : 8070) and discovery (default : 8090) ports during this step.
![Running]()
#### Checking the node status
Now that your node is running, keep the terminal window open and start another instance of the Codex CLI by using the first command. We will be using this terminal to interact with the Codex node that is active.
You can checkout the node status to ensure that the node is discoverable and connected to the other peers in the Codex test network.
![Status]()
If you face any issues (peer discovery, port forwarding etc.,), join our [discord server](https://discord.gg/codex-storage) and ask for help.
#### Uploading and downloading files from the testnet
To upload a new file into the testnet, select option 4 and enter the file's relative path. A unique CID will be displayed once the file is uploaded.
![Upload]()
To download a file from the testnet, select option 5 and enter the file's CID.
![Download]()
If you wish to view all the files that are stored in your local node, choose option 6 to display all the available CIDs.
#### What's next?
More features will be added soon!

BIN
images/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

397
index.js Normal file
View File

@ -0,0 +1,397 @@
#!/usr/bin/env node
import inquirer from 'inquirer';
import { exec } from 'child_process';
import { promisify } from 'util';
import os from 'os';
import { createSpinner } from 'nanospinner';
import chalk from 'chalk';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import axios from 'axios';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const execAsync = promisify(exec);
const platform = os.platform();
const ASCII_ART = `
+--------------------------------------------------------------------+
| Docs : docs.codex.storage | Discord : discord.gg/codex-storage |
+--------------------------------------------------------------------+
`;
async function runCommand(command) {
try {
const { stdout, stderr } = await execAsync(command);
return stdout;
} catch (error) {
console.error('Error:', error.message);
throw error;
}
}
async function showNavigationMenu() {
console.log('\n')
const { choice } = await inquirer.prompt([
{
type: 'list',
name: 'choice',
message: 'What would you like to do?',
choices: [
'1. Back to main menu',
'2. Exit'
]
}
]);
switch (choice.split('.')[0]) {
case '1':
return main(); // Returns to main menu
case '2':
console.log(chalk.cyanBright('\nGoodbye! 👋\n'));
process.exit(0);
}
}
async function checkCodexInstallation() {
try {
const version = await runCommand('codex --version');
console.log(chalk.green('Codex is already installed. Version:'));
console.log(chalk.green(version));
await showNavigationMenu();
} catch (error) {
console.log(chalk.cyanBright('Codex is not installed, proceeding with installation...'));
await installCodex();
}
}
async function installCodex() { // TODO : TEST INSTALLATION TO SEE IF BACKGROUND SHELL WORKS CORRECTLY
if (platform === 'win32') {
console.log(chalk.yellow('Coming soon for Windows!'));
return;
}
try {
console.log(chalk.cyanBright('Downloading Codex binaries...'));
const downloadCommand = 'curl -# -L https://get.codex.storage/install.sh | bash';
await runCommand(downloadCommand);
console.log(chalk.green('Codex binaries downloaded'));
console.log(chalk.cyanBright('Installing dependencies...'));
await runCommand('sudo apt update && sudo apt install libgomp1');
console.log(chalk.green('Dependencies installed'));
const version = await runCommand('codex --version');
console.log(chalk.green('Codex is successfully installed. Version:'));
console.log(chalk.cyanBright(version));
} catch (error) {
console.error(chalk.red('Failed to install Codex:', error.message));
}
}
async function isNodeRunning() {
try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
return response.status === 200;
} catch (error) {
return false;
}
}
async function runCodex() {
// Check if a Codex node is already running
const nodeAlreadyRunning = await isNodeRunning();
if (nodeAlreadyRunning) {
console.log(chalk.green('A Codex node is already running.'));
await showNavigationMenu();
}
else {
const { discPort, listenPort } = await inquirer.prompt([
{
type: 'number',
name: 'discPort',
message: 'Enter the discovery port (default is 8090):',
default: 8090
},
{
type: 'number',
name: 'listenPort',
message: 'Enter the listening port (default is 8070):',
default: 8070
}
]);
try {
const command = `codex \
--data-dir=datadir \
--disc-port=${discPort} \
--listen-addrs=/ip4/0.0.0.0/tcp/${listenPort} \
--nat=\`curl -s https://ip.codex.storage\` \
--api-cors-origin="*" \
--bootstrap-node=spr:CiUIAhIhAiJvIcA_ZwPZ9ugVKDbmqwhJZaig5zKyLiuaicRcCGqLEgIDARo8CicAJQgCEiECIm8hwD9nA9n26BUoNuarCEllqKDnMrIuK5qJxFwIaosQ3d6esAYaCwoJBJ_f8zKRAnU6KkYwRAIgM0MvWNJL296kJ9gWvfatfmVvT-A7O2s8Mxp8l9c8EW0CIC-h-H-jBVSgFjg3Eny2u33qF7BDnWFzo7fGfZ7_qc9P`;
console.log(chalk.cyanBright('\n\n Starting Codex node...'));
console.log(chalk.cyanBright('\n Please keep this terminal open. Start a new terminal to start interacting with the node'));
console.log(chalk.cyanBright('\n Press CTRL+C to stop the node'));
await runCommand(command);
// TODO : HANDLE THIS CHECKING PART
const peerIdResponse = await runCommand('curl http://localhost:8080/api/codex/v1/peerid -w \'\\n\'');
console.log(chalk.green('Codex node is successfully running. Peer ID:'));
console.log(chalk.cyanBright(peerIdResponse.trim()));
await showNavigationMenu();
} catch (error) {
console.error(chalk.red('Failed to run Codex:', error.message));
await showNavigationMenu();
}
}
}
async function checkNodeStatus() {
if (platform === 'win32') {
console.log(chalk.yellow('Coming soon for Windows!'));
return;
}
try {
const spinner = createSpinner('Checking node status...').start();
const response = await runCommand('curl http://localhost:8080/api/codex/v1/debug/info -w \'\\n\'');
spinner.success();
// Parse the JSON response
const data = JSON.parse(response);
// Determine if node is online and discoverable based on the connected peers
const peerCount = data.table.nodes.length;
const isOnline = peerCount > 2;
// Display node status based on connected peers
const statusMessage = isOnline
? chalk.bgGreen(" Node status : ONLINE & DISCOVERABLE ")
: chalk.bgRed(" Node status : OFFLINE ");
const peerMessage = `Connected peers : ${peerCount}`;
console.log('\n' + chalk.bold.cyanBright('📊 Node Status Summary'));
console.log('━'.repeat(50));
// Version Information
console.log(chalk.bold.cyanBright('🔹 Version Info'));
console.log(` Version: ${data.codex.version}`);
console.log(` Revision: ${data.codex.revision}\n`);
// Local Node Information
console.log(chalk.bold.cyanBright('🔹 Local Node'));
console.log(` Node ID: ${data.table.localNode.nodeId}`);
console.log(` Peer ID: ${data.table.localNode.peerId}`);
console.log(` Listening Address: ${data.table.localNode.address}\n`);
// Network Information
console.log(chalk.bold.cyanBright('🔹 Network Status'));
console.log(` Public IP: ${data.announceAddresses[0].split('/')[2]}`);
console.log(` Port: ${data.announceAddresses[0].split('/')[4]}\n`);
// Connected Peers Details
if (peerCount > 0) {
console.log(chalk.bold.cyanBright('🔹 Connected Peers'));
data.table.nodes.forEach((node, index) => {
console.log(` ${index + 1}. Peer ${chalk.cyan(node.peerId)}`);
console.log(` Address: ${node.address}`);
console.log(` Status: ${node.seen ? chalk.green('Active') : chalk.gray('Inactive')}`);
if (index < peerCount - 1) console.log(''); // Add spacing between peers
});
} else {
console.log(chalk.red('No connected peers.'));
}
console.log('━'.repeat(50));
await showNavigationMenu();
} catch (error) {
console.error(chalk.red('Failed to check node status:', error.message));
await showNavigationMenu();
}
}
async function uploadFile() {
if (platform === 'win32') {
console.log(chalk.yellow('Coming soon for Windows!'));
return;
}
console.log(chalk.bgYellow('\n ⚠️ Warning: Codex does not encrypt files. Anything uploaded will be available publicly on testnet. The testnet does not provide any guarentees - please do not use in production ⚠️ \n'));
const { filePath } = await inquirer.prompt([
{
type: 'input',
name: 'filePath',
message: 'Enter the file path to upload:',
validate: input => input.length > 0
}
]);
try {
const spinner = createSpinner('Uploading file').start();
// TODO : Upload along with metadata like file name, extension etc.,
const result = await runCommand(`curl -X POST http://localhost:8080/api/codex/v1/data -H 'Content-Type: application/octet-stream' -w '\\n' -T ${filePath}`);
spinner.success();
console.log(chalk.green('Successfully uploaded!'));
console.log(chalk.bgGreen('\nCID:', result.trim()));
await showNavigationMenu();
} catch (error) {
console.error(chalk.red('Failed to upload file:', error.message));
await showNavigationMenu();
}
}
async function downloadFile() {
if (platform === 'win32') {
console.log(chalk.yellow('Coming soon for Windows!'));
return;
}
const { cid } = await inquirer.prompt([
{
type: 'input',
name: 'cid',
message: 'Enter the CID:',
validate: input => input.length > 0
}
]);
try {
const spinner = createSpinner('Downloading file').start();
await runCommand(`curl "http://localhost:8080/api/codex/v1/data/${cid}/network/stream" -o "${cid}.png"`);
spinner.success();
console.log(chalk.green(`Successfully downloaded!`));
console.log(chalk.bgGreen(`\nFile saved as ${cid}.png`));
await showNavigationMenu();
} catch (error) {
console.error(chalk.red('Failed to download file:', error.message));
await showNavigationMenu();
}
}
async function showLocalFiles() {
if (platform === 'win32') {
console.log(chalk.yellow('Coming soon for Windows!'));
return;
}
try {
const spinner = createSpinner('Fetching local files...').start();
const filesResponse = await runCommand('curl http://localhost:8080/api/codex/v1/data -w \'\\n\'');
spinner.success();
// Parse the JSON response
const filesData = JSON.parse(filesResponse);
if (filesData.content && filesData.content.length > 0) {
console.log(chalk.cyanBright('\nLocal Files:'));
console.log('━'.repeat(50));
// Iterate through each file and display information
filesData.content.forEach((file, index) => {
const { cid, manifest } = file;
const { rootHash, originalBytes, blockSize, protected: isProtected, filename, mimetype, uploadedAt } = manifest;
// Convert the UNIX timestamp to a readable format
const uploadedDate = new Date(uploadedAt * 1000).toLocaleString();
console.log(`📁 File ${index + 1}:`);
console.log(` Filename : ${chalk.green(filename)}`);
console.log(` CID : ${chalk.cyan(cid)}`);
console.log(` Root Hash : ${chalk.cyan(rootHash)}`);
console.log(` Original Bytes : ${chalk.yellow(originalBytes)}`);
console.log(` Block Size : ${chalk.yellow(blockSize)}`);
console.log(` Protected : ${chalk.yellow(isProtected ? 'Yes' : 'No')}`);
console.log(` MIME Type : ${chalk.green(mimetype)}`);
console.log(` Uploaded At : ${chalk.magenta(uploadedDate)}`);
console.log('━'.repeat(50));
});
await showNavigationMenu();
} else {
console.log(chalk.red('No local files found.'));
await showNavigationMenu();
}
} catch (error) {
console.error(chalk.red('Failed to show local files:', error.message));
await showNavigationMenu();
}
}
async function main() {
while (true) {
console.log('\n' + chalk.cyanBright(ASCII_ART));
const { choice } = await inquirer.prompt([
{
type: 'list',
name: 'choice',
message: 'Select an option:',
choices: [
'1. Install Codex node',
'2. Run Codex node',
'3. Check node status',
'4. Upload a file',
'5. Download a file',
'6. Show local data',
'7. Exit'
]
}
]);
if (choice.startsWith('7.')) {
console.log(chalk.cyanBright('\nGoodbye! 👋\n'));
break;
}
switch (choice.split('.')[0]) {
case '1':
await checkCodexInstallation();
break;
case '2':
await runCodex();
return;
case '3':
await checkNodeStatus();
break;
case '4':
await uploadFile();
break;
case '5':
await downloadFile();
break;
case '6':
await showLocalFiles();
break;
}
console.log('\n'); // Add some spacing between operations
}
}
// Run the CLI
main().catch(console.error);

619
package-lock.json generated Normal file
View File

@ -0,0 +1,619 @@
{
"name": "codexstorage",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codexstorage",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"axios": "^1.7.7",
"chalk": "^5.3.0",
"inquirer": "^12.0.1",
"nanospinner": "^1.1.0"
},
"bin": {
"codexstorage": "index.js"
}
},
"node_modules/@inquirer/checkbox": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.0.1.tgz",
"integrity": "sha512-ehJjmNPdguajc1hStvjN7DJNVjwG5LC1mgGMGFjCmdkn2fxB2GtULftMnlaqNmvMdPpqdaSoOFpl86VkLtG4pQ==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/figures": "^1.0.7",
"@inquirer/type": "^3.0.0",
"ansi-escapes": "^4.3.2",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/confirm": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.0.1.tgz",
"integrity": "sha512-6ycMm7k7NUApiMGfVc32yIPp28iPKxhGRMqoNDiUjq2RyTAkbs5Fx0TdzBqhabcKvniDdAAvHCmsRjnNfTsogw==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/core": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.0.1.tgz",
"integrity": "sha512-KKTgjViBQUi3AAssqjUFMnMO3CM3qwCHvePV9EW+zTKGKafFGFF01sc1yOIYjLJ7QU52G/FbzKc+c01WLzXmVQ==",
"dependencies": {
"@inquirer/figures": "^1.0.7",
"@inquirer/type": "^3.0.0",
"ansi-escapes": "^4.3.2",
"cli-width": "^4.1.0",
"mute-stream": "^2.0.0",
"signal-exit": "^4.1.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^6.2.0",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@inquirer/editor": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.0.1.tgz",
"integrity": "sha512-qAHHJ6hs343eNtCKgV2wV5CImFxYG8J1pl/YCeI5w9VoW7QpulRUU26+4NsMhjR6zDRjKBsH/rRjCIcaAOHsrg==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0",
"external-editor": "^3.1.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/expand": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.1.tgz",
"integrity": "sha512-9anjpdc802YInXekwePsa5LWySzVMHbhVS6v6n5IJxrl8w09mODOeP69wZ1d0WrOvot2buQSmYp4lW/pq8y+zQ==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/figures": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.7.tgz",
"integrity": "sha512-m+Trk77mp54Zma6xLkLuY+mvanPxlE4A7yNKs2HBiyZ4UkVs28Mv5c/pgWrHeInx+USHeX/WEPzjrWrcJiQgjw==",
"engines": {
"node": ">=18"
}
},
"node_modules/@inquirer/input": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.0.1.tgz",
"integrity": "sha512-m+SliZ2m43cDRIpAdQxfv5QOeAQCuhS8TGLvtzEP1An4IH1kBES4RLMRgE/fC+z29aN8qYG8Tq/eXQQKTYwqAg==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/number": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.1.tgz",
"integrity": "sha512-gF3erqfm0snpwBjbyKXUUe17QJ7ebm49btXApajrM0rgCCoYX0o9W5NCuYNae87iPxaIJVjtuoQ42DX32IdbMA==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/password": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.1.tgz",
"integrity": "sha512-D7zUuX4l4ZpL3D7/SWu9ibijP09jigwHi/gfUHLx5GMS5oXzuMfPV2xPMG1tskco4enTx70HA0VtMXecerpvbg==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0",
"ansi-escapes": "^4.3.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/prompts": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.0.1.tgz",
"integrity": "sha512-cu2CpGC2hz7WTt2VBvdkzahDvYice6vYA/8Dm7Fy3tRNzKuQTF2EY3CV4H2GamveWE6tA2XzyXtbWX8+t4WMQg==",
"dependencies": {
"@inquirer/checkbox": "^4.0.1",
"@inquirer/confirm": "^5.0.1",
"@inquirer/editor": "^4.0.1",
"@inquirer/expand": "^4.0.1",
"@inquirer/input": "^4.0.1",
"@inquirer/number": "^3.0.1",
"@inquirer/password": "^4.0.1",
"@inquirer/rawlist": "^4.0.1",
"@inquirer/search": "^3.0.1",
"@inquirer/select": "^4.0.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/rawlist": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.0.1.tgz",
"integrity": "sha512-0LuMOgaWs7W8JNcbiKkoFwyWFDEeCmLqDCygF0hidQUVa6J5grFVRZxrpompiWDFM49Km2rf7WoZwRo1uf1yWQ==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/type": "^3.0.0",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/search": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.1.tgz",
"integrity": "sha512-ehMqjiO0pAf+KtdONKeCLVy4i3fy3feyRRhDrvzWhiwB8JccgKn7eHFr39l+Nx/FaZAhr0YxIJvkK5NuNvG+Ww==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/figures": "^1.0.7",
"@inquirer/type": "^3.0.0",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/select": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.0.1.tgz",
"integrity": "sha512-tVRatFRGU49bxFCKi/3P+C0E13KZduNFbWuHWRx0L2+jbiyKRpXgHp9qiRHWRk/KarhYBXzH/di6w3VQ5aJd5w==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/figures": "^1.0.7",
"@inquirer/type": "^3.0.0",
"ansi-escapes": "^4.3.2",
"yoctocolors-cjs": "^2.1.2"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@inquirer/type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.0.tgz",
"integrity": "sha512-YYykfbw/lefC7yKj7nanzQXILM7r3suIvyFlCcMskc99axmsSewXWkAfXKwMbgxL76iAFVmRwmYdwNZNc8gjog==",
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/@types/node": {
"version": "22.8.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.1.tgz",
"integrity": "sha512-k6Gi8Yyo8EtrNtkHXutUu2corfDf9su95VYVP10aGYMMROM6SAItZi0w1XszA6RtWTHSVp5OeFof37w0IEqCQg==",
"peer": true,
"dependencies": {
"undici-types": "~6.19.8"
}
},
"node_modules/ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
"integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
"dependencies": {
"type-fest": "^0.21.3"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/chalk": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
"integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chardet": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
},
"node_modules/cli-width": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
"integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
"engines": {
"node": ">= 12"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/external-editor": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
"integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
"dependencies": {
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
},
"engines": {
"node": ">=4"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inquirer": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.0.1.tgz",
"integrity": "sha512-o11Jc2Go6wDZA17SWofiJ6L8k7mB8lsdKB/QY0bI+8e+ATiAvQzmROjqoTd1iAY8RI6N/EDcQcxbQa4JYviDWg==",
"dependencies": {
"@inquirer/core": "^10.0.1",
"@inquirer/prompts": "^7.0.1",
"@inquirer/type": "^3.0.0",
"ansi-escapes": "^4.3.2",
"mute-stream": "^2.0.0",
"run-async": "^3.0.0",
"rxjs": "^7.8.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@types/node": ">=18"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"engines": {
"node": ">=8"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mute-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
"integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
"engines": {
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/nanospinner": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/nanospinner/-/nanospinner-1.1.0.tgz",
"integrity": "sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==",
"dependencies": {
"picocolors": "^1.0.0"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/run-async": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
"integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/rxjs": {
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/tslib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
"integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="
},
"node_modules/type-fest": {
"version": "0.21.3",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
"integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
"peer": true
},
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yoctocolors-cjs": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz",
"integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}

22
package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "codexstorage",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"bin": {
"codexstorage": "./index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.7.7",
"chalk": "^5.3.0",
"inquirer": "^12.0.1",
"nanospinner": "^1.1.0"
}
}