# Project export: ArtistX

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: Would you invest $10 in Drake if you knew him 15 years ago?
- Devpost: https://devpost.com/software/artistx-7t6wuh
- GitHub: https://github.com/basebala/artist_equity
- Video: https://www.youtube.com/embed/pigNJ8-TPH8?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Nihal Boina (5 commits)

## Devpost submission (written by the team)

### Inspiration

Would you invest in Drake if you knew him before he was famous? In the U.S., over 2 million arts (musicians) graduates exist, but less than 10% earn their primary income as artists, facing significant income disparities from streaming platforms like Spotify, where only 28% earning over $10,000/year are independent artists. Today, there are more and more up and coming artists who could be the next big thing, but it is notoriously difficult to make a successful career out of it. However, there is a demand, as people are continuously looking for undiscovered artists and their novel music. We wanted to provide a platform where people could discover using Spotify API and support their favorite rising artists to make people's dreams come true. Fans, crucial for artist success, find limited ways to influence or financially support their favorites directly, with 40% wanting to but unsure how, underscoring the need for platforms that facilitate better artist-fan engagement and support.

### What it does

ArtistX is conceptualized as an Initial Artist Offering (IAO) platform, allowing fans to invest directly in an artist as an individual, rather than in their artwork. Each coin on ArtistEQ is linked to an artist and has a value correlated with key metrics like monthly Spotify listeners, number of album streams, etc. Fans are incentivized with dividends based on the future growth of these statistics, alongside other exclusive benefits like concert tickets, ArtistX coin-holder monthly mixers, and governance on items such as concert locations, merchandise designs, etc.

### How we built it

The platform operates on Caldera, XRPL Ledger by Ripple and Algorand along with React Frontend. We built smart contract on solidity to facilitate governance tokens for fans like voting rights according to invested proportion and deployed them on caldera Caldera to lower transaction fees and increase speed. We also deployed an Automated market maker on ripple which provides liquidity to the pool 24/7. We used Algorand for issuance of tokens and new artist coins as well as facilitating Buy/Sell.

### Challenges we ran into

We had a problem figuring out how to integrate multiple blockchain Ledgers but were eventually able to sort it out with the help of mentors.

### Accomplishments we're proud of

We managed to create a AMM driven by an algorithm that provides 24/7 liquidity eradicating order-book system.To complete a proof of concept, we did interviews of 50+ stakeholders namely Artists and Fans from a Music Club at Berkeley . The survey helped us get first-hand inputs on the problems faced by these stakeholders. Origami (Artist): “ I have been trying to pursue music as a full-time profession but I’m unable to do so because of low income to support family, healthcare expenses, low revenue from digital music.” Divyesh Murugan (Fan): “ I go to Cornerstone to specifically see this jazz artist and know the potential they have and wouldn’t mind supporting them financially.”

### What we learned

We learnt how to built on cross function chains while reducing transaction costs for our users and increasing speed in Peer to Peer Decentralised transactions.

### What's next

We want to actually put artists on the platform to start making an impact for them. In the long run, we'd like to expand to all types of artists, not just musicians.

## README (from the GitHub repository)

This repository contains all the files for our project, ArtistX, that was awarded the Fintech Award ($5000) at Big Ideas 2024 and the Ripple Award at CalHacks 2023.


## Detected evidence (automated analysis)

Indexed codebase: 56 recognized source files, 143 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Solidity (language) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (77 of 77)

```
.DS_Store
.gitignore
.vscode/settings.json
convex.json
hardhat/artifacts/build-info/4a7d7b98b27872c354cbaeefbf7fdd87.json
hardhat/artifacts/build-info/7fccb550106afc29e140f19667fd2767.json
hardhat/artifacts/contracts/new_contract.sol/new_contract.dbg.json
hardhat/artifacts/contracts/new_contract.sol/new_contract.json
hardhat/artifacts/contracts/your_contract.sol/your_contract.dbg.json
hardhat/artifacts/contracts/your_contract.sol/your_contract.json
hardhat/cache/solidity-files-cache.json
hardhat/contracts/new_contract.sol
hardhat/contracts/your_contract.sol
hardhat/hardhat.config.js
hardhat/package.json
hardhat/scripts/deploy.js
hardhat/secrets.json
package.json
public/index.html
public/manifest.json
public/robots.txt
README.md
src/.DS_Store
src/algo_acct.py
src/algos.js
src/amm.js
src/api.py
src/App.css
src/App.js
src/app.py
src/App.test.js
src/ArtistTab.js
src/CoinList.css
src/CoinList.js
src/compile_contract.py
src/convex/_generated/api.d.ts
src/convex/_generated/api.js
src/convex/_generated/dataModel.d.ts
src/convex/_generated/server.d.ts
src/convex/_generated/server.js
src/convex/artists.ts
src/convex/crons.ts
src/convex/logs.ts
src/convex/README.md
src/convex/schema.ts
src/convex/test.ts
src/convex/tsconfig.json
src/convex/users.ts
src/deploy_algo.py
src/DiscoveryTab.js
src/index.css
src/index.js
src/Integration.js
src/LoginScreen.js
src/newApp.js
src/package.json
src/PortfolioTab.css
src/PortfolioTab.js
src/react-app-env.d.ts
src/RegisterScreen.js
src/reportWebVitals.js
src/rl.css
src/server.js
src/setupTests.js
src/trading_contract.py
src/utils.py
src/xrpl tutorial/dex.js
src/xrpl_february/pyripple.py
src/xrpl_february/test_ripple.py
src/xrpl_february/test_wallet_1_0.js
src/xrpl_tutorial.js/dex.js
src/xrpl_tutorial.js/exchange.js
src/xrpl_tutorial.js/tokens.js
src/xrpl_tutorial.js/tutorial.js
src/xrpl_tutorial.js/xrpl_ex.js
test.jsonl
tsconfig.json
```

### Dependencies

- hardhat/package.json: @nomiclabs/hardhat-ethers@^2.2.3, ethers@^5.7.2, hardhat@^2.20.1
- package.json: @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, convex@^1.9.0, cors@^2.8.5, react@^18.2.0, react-dom@^18.2.0, react-router-dom@^6.18.0, react-scripts@^3.0.1, request@^2.88.2, style-components@^0.1.0, styled@^1.0.0, styled-components@^6.1.0, web-vitals@^2.1.4, web3@^4.2.0, xrpl@^2.14.1
- src/package.json: cors@^2.8.5, express@^4.18.2

### Recent commits (newest first)

- Add project description for ArtistX
- solidity
- all apis
- users finished:
- yo
- r1 api
- done?
- aanegola
- done
- 1:

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "my-first-react-appv",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "convex": "^1.9.0",
    "cors": "^2.8.5",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.18.0",
    "react-scripts": "^3.0.1",
    "request": "^2.88.2",
    "style-components": "^0.1.0",
    "styled": "^1.0.0",
    "styled-components": "^6.1.0",
    "web-vitals": "^2.1.4",
    "web3": "^4.2.0",
    "xrpl": "^2.14.1"
  },
  "scripts": {
    "start": "react-scripts --openssl-legacy-provider start",
    "build": "react-scripts --openssl-legacy-provider build"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### src/package.json

```
{
  "name": "src",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.18.2"
  }
}


```

### hardhat/package.json

```
{
  "name": "hardhat",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@nomiclabs/hardhat-ethers": "^2.2.3",
    "ethers": "^5.7.2",
    "hardhat": "^2.20.1"
  }
}

```

### src/server.js

```javascript
const express = require("express");
const cors = require("cors");
const app = express();

app.use(cors());
app.use(express.json());

app.get("/message", (req, res) => {
  res.json({ message: "Hello from server aarush is a nigger!" });
});

app.listen(8000, () => {
  console.log(`Server is running on port 8000.`);
});
```

### src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### src/App.js

```javascript
import React, {useEffect, useState } from 'react';
import './App.css';
import axios from 'axios';
import CoinList from './CoinList';
import LoginScreen from './LoginScreen';
import RegisterScreen from './RegisterScreen';
import PortfolioTab from './PortfolioTab'; // Import the PortfolioTab component
import DiscoveryTab from './DiscoveryTab'; // Import the DiscoveryTab component
import styled from 'styled-components';


const Container = styled.div`
  font-family: Arial, sans-serif;
  text-align: center;
  padding: 20px;
`;

const Header = styled.h1`
  font-size: 36px;
  margin: 20px 0;
`;

const TabButtons = styled.div`
  display: flex;
  justify-content: center;
  gap: 10px;
  margin: 20px;
`;

const Button = styled.button`
  background-color: #3498db;
  color: white;
  border: none;
  padding: 10px 20px;
  cursor: pointer;
  border-radius: 5px;
  transition: background-color 0.3s;
  &:hover {
    background-color: #2980b9;
  }
`;

const Balance = styled.div`
  margin: 20px 0;
  font-size: 18px;
`;

function App() {
  const [isRegistered, setIsRegistered] = useState(false);
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [transactions, setTransactions] = useState([]);
  const [users, setUsers] = useState([
    { username: 'demo1', password: 'password1', coins: {} },
    { username: 'demo2', password: 'password2', coins: {} },
    { username: 'demo3', password: 'password3', coins: {} },
    { username: 'demo4', password: 'password4', coins: {} },
    { username: 'demo5', password: 'password5', coins: {} },
  ]);
  const [currentUser, setCurrentUser] = useState(null);
  const initialBalance = 10000;
  const userWallet = { 'DRAKE': 0, 'KANYE': 0, 'MABU': 0 };

  const starter = [
    { name: 'Aubrey Drake Graham', symbol: 'DRAKE', price: 150.25, marketcap: 150250, imageurl: "https://hips.hearstapps.com/hmg-prod/images/drake_photo_by_prince_williams_wireimage_getty_479503454.jpg" },
    { name: 'Kanye Omari West', symbol: 'KANYE', price: 2750.30, marketcap: 2570300, imageurl: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Kanye_West_at_the_2009_Tribeca_Film_Festival_%28crop_2%29.jpg/1200px-Kanye_West_at_the_2009_Tribeca_Film_Festival_%28crop_2%29.jpg" },
    { name: 'Mathematical Disrespect', symbol: 'MABU', price: 3300.10, marketcap: 3300100, imageurl: "http://t2.gstatic.com/images?q=tbn:ANd9GcQL013wPzhUy9F2qEv6ebofvmeDCyizTkzD16cX1luPJ26cSvJpBs6d2GtaTuF6rcPYmhVRpQ" },
  ];

  const [balance, setBalance] = useState(initialBalance);
  const [userCoins, setUserCoins] = useState(userWallet);
  const [initialCoins, setCoinsGlobal] = useState(starter);

  const [activeTab, setActiveTab] = useState('coinList');

  const handleRegister = (username, password) => {
    setUsers([...users, { username, password, balance: initialBalance, coins: {} }]);
    setIsRegistered(true);
    setCurrentUser({ username, password, balance: initialBalance, coins: {} });
  };


  const handleLogin = (username, password) => {
    const user = users.find((user) => user.username === username && user.password === password);

    if (user) {
      setIsLoggedIn(true);
      setCurrentUser(user);
    } else {
      alert('Invalid credentials. Please try again.');
    }
  };

  const updateBalance = (amount, coinName, boughtOrSold) => {
    setBalance((prevBalance) => prevBalance + amount);

    const updatedUserCoins = { ...userCoins };
    updatedUserCoins[coinName] = updatedUserCoins[coinName] + boughtOrSold;
    setUserCoins(updatedUserCoins);

    setTransactions((prevTransactions) => [
      ...prevTransactions,
      { amount, coinName, timestamp: new Date() },
    ]);
  };

  const updateGlobalCoins = (newCoins) => {
    setCoinsGlobal(newCoins);
  };

  const handleLogout = () => {
    setIsLoggedIn(false);
    setTransactions([]);
  };

  

  const renderActiveTab = () => {
    if (activeTab === 'coinList') {
      return (
        <CoinList
          balance={balance}
          updateBalance={updateBalance}
          userCoins={userCoins}
          curCoins={initialCoins}
          updateFunction={updateGlobalCoins}
        />
      );
    } else if (activeTab === 'portfolio') {
      return <PortfolioTab userCoins={userCoins} curCoins={initialCoins} />;
    }
    else if (activeTab === 'discovery') {
      return <DiscoveryTab />;
    }
  };

  return (
    <Container>
      <Header>ArtistX</Header>
      <TabButtons>
        <Button onClick={() => setActiveTab('coinList')}>Coin List</Button>
        <Button onClick={() => setActiveTab('portfolio')}>Portfolio</Button>
        <Button onClick={() => setActiveTab('discovery')}>Discovery</Button>
      </TabButtons>
      {isLoggedIn ? (
        <>
          <Button onClick={handleLogout}>Logout</Button>
          <h5></h5>
          {renderActiveTab()}
        </>
      ) : isRegistered ? (
        <LoginScreen onLogin={handleLogin} />
      ) : (
        <RegisterScreen onRegister={handleRegister} />
      )}
    </Container>
  );
}

export default App;

```

### src/app.py

```python
from flask import Flask, jsonify, request
from flask_cors import CORS
from utils import get_accounts, get_algod_client
from algosdk import account, mnemonic
from algosdk import transaction
from algosdk.v2client import algod
import random

app = Flask(__name__)
CORS(app)  # Enable CORS for all routes
hi = 10
balance = 10000
portfolio = 0

private_key, address = account.generate_account()
accts = get_accounts()
acct3 = accts.pop()
acct2 = accts.pop()
acct1 = accts.pop()
print(acct3.address)
# Create a new algod client, configured to connect to our local sandbox
algod_address = "http://localhost:4001"
algod_token = "a" * 64
algod_client = algod.AlgodClient(algod_token, algod_address)

# Or, if necessary, pass alternate headers

# Create a new client with an alternate api key header
special_algod_client = algod.AlgodClient(
    "", algod_address, headers={"X-API-Key": algod_token}
)
account_info = algod_client.account_info(acct1.address)
#print(f"Account balance: {account_info.get('assets')} microAlgos")

artistData = {
    'Drake': {
        'image': 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQLKUMfmMV0fyTzTfPziofp2H5IK5xK59gghxbywSLu&s',
        'marketCap': 10000000000,
        'timeOnPlatform': 100,
        'growth': 1,
        'buys': 50,
        'sells': 30,
    },
    'Adele': {
        'image': 'https://upload.wikimedia.org/wikipedia/commons/5/52/Adele_for_Vogue_in_2021.png',
        'marketCap': 8000000000,
        'timeOnPlatform': 365,
        'growth': 1.3,
        'buys': 30,
        'sells': 40,
    },
    'Ed Sheeran': {
        'image': 'https://cdn.britannica.com/17/249617-050-4575AB4C/Ed-Sheeran-performs-Rockefeller-Plaza-Today-Show-New-York-2023.jpg',
        'marketCap': 9500000000,
        'timeOnPlatform': 485,
        'growth': 0.67,
        'buys': 45,
        'sells': 25,
    },
    'Kanye West': {
        'image': 'https://imageio.forbes.com/specials-images/imageserve/5ed00f17d4a99d0006d2e738/0x0.jpg?format=jpg&crop=4666,4663,x154,y651,safe&height=416&width=416&fit=bounds',
        'marketCap': 120000000000,
        'timeOnPlatform': 128,
        'growth': 1.2,
        'buys': 70,
        'sells': 25,
    },
    'Ariana Grande': {
        'image': 'https://hips.hearstapps.com/hmg-prod/images/ariana_grande_photo_jon_kopaloff_getty_images_465687098.jpg',
        'marketCap': 11000000000,
        'timeOnPlatform': 236,
        'growth': 1.11,
        'buys': 60,
        'sells': 35,
    },
    'Taylor Swift': {
        'image': 'https://www.bu.edu/files/2023/11/Taylor-Swift-Mania-feat-1200x1200.jpg',
        'marketCap': 10500000000,
        'timeOnPlatform': 1934,
        'growth': 1.05,
        'buys': 80,
        'sells': 15,
    },
    'Beyonce': {
        'image': 'https://cdn.britannica.com/51/188751-050-D4E1CFBC/Beyonce-2010.jpg',
        'marketCap': 8500000000,
        'timeOnPlatform': 1023,
        'growth': 1.06,
        'buys': 75,
        'sells': 30,
    },
    'Justin Bieber': {
        'image': 'https://hips.hearstapps.com/hmg-prod/images/justin-bieber-gettyimages-1202421980.jpg?crop=1xw:1.0xh;center,top&resize=640:*',
        'marketCap': 9000000000,
        'timeOnPlatform': 24,
        'growth': 0.98,
        'buys': 40,
        'sells': 45,
    },
    'Rihanna': {
        'image': 'https://cdn.britannica.com/83/211883-050-46933F1A/Rihanna-Barbadian-singer-Robyn-Fenty.jpg',
        'marketCap': 9500000000,
        'timeOnPlatform': 1,
        'growth': 0.96,
        'buys': 70,
        'sells': 20,
    },
    'Eminem': {
        'image': 'https://hips.hearstapps.com/hmg-prod/images/eminem-a-k-a-marshall-bruce-mathers-iii-attends-a-ceremony-news-photo-1698936282.jpg?crop=1.00xw:0.667xh;0,0.0380xh&resize=640:*',
        'marketCap': 10500000000,
        'timeOnPlatform': 10500000000,
        'growth': 0.94,
        'buys': 95,
        'sells': 40,
    },
    'Lady Gaga': {
        'image': 'https://m.media-amazon.com/images/M/MV5BMTg1NjQwMzU4MF5BMl5BanBnXkFtZTgwNTk5NjQ4NjE@._V1_.jpg',
        'marketCap': 100000000000,
        'timeOnPlatform': 782,
        'growth': 0.99,
        'buys': 85,
        'sells': 55,
    },
    'The Weeknd': {
        'image': 'https://imageio.forbes.com/specials-images/imageserve/63b5b6b978458c2d14126109/-Avatar--The-Way-of-Water--Premiere---ArrivalsThe-Weeknd-at-the-premiere-of--Avatar-/0x0.jpg?crop=1591,894,x0,y2,safe&height=399&width=711&fit=bounds',
        'marketCap': 110000000000,
        'timeOnPlatform': 237,
        'growth': 0.995,
        'buys': 65,
        'sells': 35,
    },
}


for a1 in account_info.get('assets'):
    sp = algod_client.suggested_params()
    # Create opt-in transaction
    # asset transfer from me to me for asset id we want to opt-in to with amt==0
    optin_txn = transaction.AssetOptInTxn(
        sender=acct2.address, sp=sp, index=a1['asset-id']
    )
    signed_optin_txn = optin_txn.sign(acct2.private_key)
    txid = algod_client.send_transaction(signed_optin_txn)
    print(f"Sent opt in transaction with txid: {txid}")

    # Wait for the transaction to be confirmed
    results = transaction.wait_for_confirmation(algod_client, txid, 4)
    print(f"Result confirmed in round: {results['confirmed-round']}")
    asset_info = algod_client.asset_info(a1['asset-id'])
    asset_params = asset_info["params"]
    if asset_params['name'] in artistData:
        print(asset_params['name'], a1['amount'])
        artistData[asset_params['name']]['coins'] = a1['amount'] 
        artistData[asset_params['name']]['coinID'] = a1['asset-id']

for artist in artistData:
    artistData[artist]['price'] = random.randint(30, 60)
    artistData[artist]['name'] = artist
    artistData[artist]['held'] = 0
    artistData[artist]['divFactor'] = random.randint(10, 20)
    artistData[artist]['div'] = 0

artistDataListed = [artistData[i] for i in artistData if artistData[i]['held']]

@app.route('/api/message', methods=['GET'])
def get_message():
    # Logic to generate a message
    global hi
    message 
[truncated — 5485 more characters]
```

### src/convex/_generated/server.js

```javascript
/* eslint-disable */
/**
 * Generated utilities for implementing server-side Convex query and mutation functions.
 *
 * THIS CODE IS AUTOMATICALLY GENERATED.
 *
 * Generated by convex@1.9.0.
 * To regenerate, run `npx convex dev`.
 * @module
 */

import {
  actionGeneric,
  httpActionGeneric,
  queryGeneric,
  mutationGeneric,
  internalActionGeneric,
  internalMutationGeneric,
  internalQueryGeneric,
} from "convex/server";

/**
 * Define a query in this Convex app's public API.
 *
 * This function will be allowed to read your Convex database and will be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const query = queryGeneric;

/**
 * Define a query that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to read from your Convex database. It will not be accessible from the client.
 *
 * @param func - The query function. It receives a {@link QueryCtx} as its first argument.
 * @returns The wrapped query. Include this as an `export` to name it and make it accessible.
 */
export const internalQuery = internalQueryGeneric;

/**
 * Define a mutation in this Convex app's public API.
 *
 * This function will be allowed to modify your Convex database and will be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const mutation = mutationGeneric;

/**
 * Define a mutation that is only accessible from other Convex functions (but not from the client).
 *
 * This function will be allowed to modify your Convex database. It will not be accessible from the client.
 *
 * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
 * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
 */
export const internalMutation = internalMutationGeneric;

/**
 * Define an action in this Convex app's public API.
 *
 * An action is a function which can execute any JavaScript code, including non-deterministic
 * code and code with side-effects, like calling third-party services.
 * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
 * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
 *
 * @param func - The action. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped action. Include this as an `export` to name it and make it accessible.
 */
export const action = actionGeneric;

/**
 * Define an action that is only accessible from other Convex functions (but not from the client).
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument.
 * @returns The wrapped function. Include this as an `export` to name it and make it accessible.
 */
export const internalAction = internalActionGeneric;

/**
 * Define a Convex HTTP action.
 *
 * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object
 * as its second.
 * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`.
 */
export const httpAction = httpActionGeneric;

```

### src/react-app-env.d.ts

```typescript
/// <reference types="react-scripts" />

```

### src/ArtistTab.js

```javascript
import React, { useState } from 'react';

const ArtistTab = () => {
    return (
        <h2>Coming Soon!</h2>
    );
};
export default ArtistTab;

```

[47 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]