diff --git a/.github/lighthouse/budget.json b/.github/lighthouse/budget.json deleted file mode 100644 index 2a9ae723f..000000000 --- a/.github/lighthouse/budget.json +++ /dev/null @@ -1,27 +0,0 @@ -[ - { - "path": "/*", - "timings": [ - { - "metric": "interactive", - "budget": 3000 - }, - { - "metric": "first-contentful-paint", - "budget": 1800 - } - ], - "resourceSizes": [ - { - "resourceType": "script", - "budget": 100 - } - ], - "resourceCounts": [ - { - "resourceType": "third-party", - "budget": 4 - } - ] - } -] diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml deleted file mode 100644 index b82adc759..000000000 --- a/.github/workflows/lighthouse.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Vercel Preview URL Lighthouse Audit - -on: - pull_request - -jobs: - generate_lighthouse_audit: - timeout-minutes: 30 - runs-on: ubuntu-latest - steps: - # - name: Add comment to PR - # id: loading_comment_to_pr - # uses: marocchino/sticky-pull-request-comment@v2.9.0 - # with: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # number: ${{ github.event.issue.number }} - # header: lighthouse - # message: | - # Running Lighthouse audit... - - name: Wait for 5 minutes - run: sleep 300 - - name: Capture Vercel preview URL - id: vercel_preview_url - uses: zentered/vercel-preview-url@v1.1.9 - env: - VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} - with: - vercel_project_id: prj_Bf0q4Q5mAwPh404L36RsGFOB84Qu - vercel_team_id: team_7PAgeqjbXkY6qdxNIEKLbVSC - - name: Get URL - run: echo "https://${{ steps.vercel_preview_url.outputs.preview_url }}" - - uses: actions/checkout@v4 - - name: Audit preview URL with Lighthouse - id: lighthouse_audit - uses: treosh/lighthouse-ci-action@11.4.0 - with: - urls: | - "https://${{ steps.vercel_preview_url.outputs.preview_url }}" - "https://${{ steps.vercel_preview_url.outputs.preview_url }}/about" - "https://${{ steps.vercel_preview_url.outputs.preview_url }}/security" - "https://${{ steps.vercel_preview_url.outputs.preview_url }}/bitcash-bitlauncher" - "https://${{ steps.vercel_preview_url.outputs.preview_url }}/blog" - "https://${{ steps.vercel_preview_url.outputs.preview_url }}/blog/ai" - # budgetPath: '.github/lighthouse/budget.json' - uploadArtifacts: true - temporaryPublicStorage: true - - name: Format lighthouse score - id: format_lighthouse_score - uses: actions/github-script@v7.0.1 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - const manifest = ${{ steps.lighthouse_audit.outputs.manifest }}; - const links = ${{ steps.lighthouse_audit.outputs.links }}; - - const formatResult = (res) => Math.round((res * 100)); - const score = res => res >= 90 ? '🟢' : res >= 50 ? '🟠' : '🔴'; - - let comment = '⚡️ Lighthouse report\n' - - manifest.forEach(result => { - const pageLink = result.url; - comment += `\nPage: ${pageLink}\n`; - comment += `Report ${links[pageLink]}\n`; - comment += '| Category | Score |\n'; - comment += '| --- | --- |\n'; - - Object.keys(result.summary).forEach(key => result.summary[key] = formatResult(result.summary[key])); - comment += `| ${score(result.summary.performance)} Performance | ${result.summary.performance} |\n`; - comment += `| ${score(result.summary.accessibility)} Accessibility | ${result.summary.accessibility} |\n`; - comment += `| ${score(result.summary['best-practices'])} Best practices | ${result.summary['best-practices']} |\n`; - comment += `| ${score(result.summary.seo)} SEO | ${result.summary.seo} |\n`; - comment += `| ${score(result.summary.pwa)} PWA | ${result.summary.pwa} |\n`; - }); - - core.setOutput("comment", comment); - - name: Add comment to PR - id: comment_to_pr - uses: marocchino/sticky-pull-request-comment@v2.9.0 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - number: ${{ github.event.issue.number }} - header: lighthouse - message: | - ${{ steps.format_lighthouse_score.outputs.comment }} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index fa9f49187..6c70aba17 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,7 @@ }, "editor.codeActionsOnSave": { "source.organizeImports.biome": "explicit" - } + }, + "editor.insertSpaces": true, + "editor.tabSize": 2 } diff --git a/README.md b/README.md index 57e9d3fcd..1f0756e76 100644 --- a/README.md +++ b/README.md @@ -41,12 +41,6 @@ The Faucet application serves as a utility for distributing test tokens or curre The Indexer application is responsible for indexing blockchain data. It listens to the blockchain network, extracts relevant data from blocks, transactions, and events, and stores it in a structured format for easy querying and analysis. -#### Supabase (`/apps/supabase`) - -This application integrates with Supabase, a scalable and open-source Firebase alternative, providing real-time database functionality, authentication, storage, and more. It's designed to leverage Supabase services for backend functionalities. - -For more database schema details, refer to the [Database Schema](/apps/supabase/README.md) diagram. - #### Webapp (`/apps/webapp`) The Webapp is a front-end application that provides a user interface for interacting with the project's services. It includes features such as displaying blockchain data, interacting with smart contracts, and utilizing the Faucet for test tokens. @@ -55,25 +49,33 @@ Please refer to the [webapp README.md](/apps/webapp/README.md) for more details ### Packages -#### Config TypeScript (`/packages/config-typescript`) +#### Alchemy (`/packages/alchemy`) + +This package integrates with the Alchemy SDK, providing a robust interface for interacting with Ethereum and other blockchain networks. It includes utilities for creating and managing blockchain interactions, leveraging Alchemy's powerful API services. + +#### Config TypeScript (`/packages/tsconfig`) -This package offers a shared TypeScript configuration to standardize TypeScript compilation options across the project. +This package offers shared TypeScript configurations to standardize TypeScript compilation options across the project. It includes specific configurations for different environments and Node.js versions. -#### Smartsale Contracts (`/packages/app-contracts`) +#### Jobs (`/packages/jobs`) -Contains smart contracts for the Smartsale platform, including auction contracts, ERC20 tokens, and other blockchain-based contracts. These are essential for the project's blockchain functionalities. +The Jobs package contains background tasks and scheduled processes for the SmartSale platform. It utilizes Trigger.dev for managing and deploying these jobs, ensuring efficient handling of asynchronous operations and scheduled tasks. -#### Smartsale Env (`/packages/app-env`) +#### Supabase (`/packages/supabase`) -Provides environment configurations and utilities for the Smartsale platform, ensuring that different environments (development, testing, production) can be managed and configured efficiently. +This package integrates with Supabase, providing real-time database functionality, authentication, and storage services. It includes type generation and schema validation tools to ensure type safety when interacting with the Supabase backend. -#### Smartsale Lib (`/packages/app-lib`) +#### Tokens (`/packages/tokens`) -A library of reusable code for the Smartsale platform, including utility functions, blockchain interaction helpers, and common components used across the project. +The Tokens package contains definitions, interfaces, and utilities related to the various tokens used within the SmartSale ecosystem. This includes ERC20 token implementations, token standards, and related blockchain interactions. -#### TSConfig (`/packages/tsconfig`) +For more details on specific packages, refer to their respective README files: -Houses TypeScript configuration files used to compile TypeScript projects within the monorepo. It ensures consistency in TypeScript compilation settings. +- [Alchemy](./packages/alchemy/README.md) +- [Jobs](./packages/jobs/README.md) +- [Supabase](./packages/supabase/README.md) +- [Tokens](./packages/tokens/README.md) +You can also check their package.json configurations for additional information. ### Hardhat (`/hardhat`) diff --git a/apps/faucet/.gitignore b/apps/faucet/.gitignore index a547bf36d..ea93fc9b6 100644 --- a/apps/faucet/.gitignore +++ b/apps/faucet/.gitignore @@ -8,7 +8,8 @@ pnpm-debug.log* lerna-debug.log* node_modules -dist +dist/** +!dist/.keep dist-ssr *.local diff --git a/apps/faucet/package.json b/apps/faucet/package.json index 2775c0ccd..7c336afe9 100644 --- a/apps/faucet/package.json +++ b/apps/faucet/package.json @@ -24,7 +24,7 @@ "react": "18.x", "react-dom": "18.x", "app-env": "workspace:*", - "app-contracts": "workspace:*", + "@repo/contracts": "workspace:*", "tailwind-merge": "^2.4.0", "tailwindcss": "^3.4.6", "tailwindcss-animate": "^1.0.7", diff --git a/apps/faucet/src/components/add-token-to-metamask.tsx b/apps/faucet/src/components/add-token-to-metamask.tsx index e3441f1b9..24f31a26e 100644 --- a/apps/faucet/src/components/add-token-to-metamask.tsx +++ b/apps/faucet/src/components/add-token-to-metamask.tsx @@ -1,4 +1,4 @@ -import type { EVMTokenContractData } from 'app-contracts' +import type { EVMTokenContractData } from '@repo/contracts' import { useSwitchChain } from 'wagmi' import { Button } from './ui/button' diff --git a/apps/faucet/src/components/faucet-form.tsx b/apps/faucet/src/components/faucet-form.tsx index 7e955b4ed..147a26d49 100644 --- a/apps/faucet/src/components/faucet-form.tsx +++ b/apps/faucet/src/components/faucet-form.tsx @@ -7,7 +7,7 @@ import { TestnetMBOTSPL, TestnetUSDCred, TestnetUSDT, -} from 'app-contracts' +} from '@repo/contracts' import { useEffect, useState } from 'react' import { parseUnits } from 'viem' import { useAccount, useSwitchChain, useWriteContract } from 'wagmi' diff --git a/apps/faucet/src/components/token-select.tsx b/apps/faucet/src/components/token-select.tsx index 00d57ea49..ce9ee964c 100644 --- a/apps/faucet/src/components/token-select.tsx +++ b/apps/faucet/src/components/token-select.tsx @@ -8,7 +8,7 @@ import { SelectValue, } from '@/components/ui/select' import type { SelectProps } from '@radix-ui/react-select' -import type { TokenContractData } from 'app-contracts' +import type { TokenContractData } from '@repo/contracts' export function TokenSelect({ options, ...props }: TokenSelectParams) { return ( diff --git a/apps/faucet/src/hooks/use-usdt-balance.ts b/apps/faucet/src/hooks/use-usdt-balance.ts index acac7e1b5..760776b5e 100644 --- a/apps/faucet/src/hooks/use-usdt-balance.ts +++ b/apps/faucet/src/hooks/use-usdt-balance.ts @@ -1,4 +1,4 @@ -import { TestnetUSDCred } from 'app-contracts' +import { TestnetUSDCred } from '@repo/contracts' import { formatUnits } from 'viem' import { useAccount, useReadContract } from 'wagmi' diff --git a/apps/indexer/.env-sample b/apps/indexer/.env-sample index 0cd94f8ad..62b31dfe3 100644 --- a/apps/indexer/.env-sample +++ b/apps/indexer/.env-sample @@ -4,4 +4,6 @@ SEPOLIA_RPC=https://eth-sepolia.g.alchemy.com/v2/xxx ISSUER_KEY=xxx ISSUER_ADDRESS=0x DFUSE_API_KEY=server_xxx -ALCHEMY_ACTIVITY_SIGNING_KEY=xxx \ No newline at end of file +ALCHEMY_ACTIVITY_SIGNING_KEY=xxx +TRIGGER_SECRET_KEY=1234567890 +PRESALE_ADDRESS=0x diff --git a/apps/indexer/Dockerfile b/apps/indexer/Dockerfile index bfa217ddb..47987fd71 100644 --- a/apps/indexer/Dockerfile +++ b/apps/indexer/Dockerfile @@ -6,24 +6,25 @@ WORKDIR /app # Copy the package.json files for the workspaces COPY package.json . -COPY apps/supabase/package.json ./apps/supabase/package.json COPY apps/indexer/package.json ./apps/indexer/package.json -COPY apps/trigger/package.json ./apps/trigger/package.json +COPY packages/jobs/package.json ./packages/jobs/package.json +COPY packages/supabase/package.json ./packages/supabase/package.json +COPY packages/alchemy/package.json ./packages/alchemy/package.json COPY packages/app-env/package.json ./packages/app-env/package.json -COPY packages/app-contracts/package.json ./packages/app-contracts/package.json -COPY packages/app-lib/package.json ./packages/app-lib/package.json -COPY packages/config-typescript/package.json ./packages/config-typescript/package.json - +COPY packages/contracts/package.json ./packages/contracts/package.json +COPY packages/utils/package.json ./packages/utils/package.json +COPY packages/tsconfig/package.json ./packages/tsconfig/package.json +COPY packages/tokens/package.json ./packages/tokens/package.json # Copy the lock file COPY bun.lockb . # Install dependencies for the entire monorepo RUN mkdir hardhat -RUN npm install -g bun ts-node tsconfig-paths +RUN npm install -g bun +RUN bun install -g ts-node tsconfig-paths ts-node-dev RUN bun install # Copy the specific workspaces -COPY apps/supabase ./apps/supabase COPY apps/indexer ./apps/indexer COPY apps/trigger ./apps/trigger COPY packages/ ./packages/ diff --git a/apps/indexer/README.md b/apps/indexer/README.md index 52353ed14..11f536e22 100644 --- a/apps/indexer/README.md +++ b/apps/indexer/README.md @@ -1,5 +1,20 @@ # Bitlauncher Indexer +The Bitlauncher Indexer is a critical component of our blockchain data processing ecosystem. It's an advanced, high-performance system designed to efficiently capture, process, and store blockchain events in real-time. By continuously monitoring the blockchain, the indexer ensures that the Bitlauncher platform always has access to the most up-to-date and accurate on-chain data. + +Key responsibilities of the Bitlauncher Indexer include: + +- Real-time event monitoring: Continuously listens for new blocks and transactions on the blockchain. +- Smart contract interaction tracking: Indexes and processes events related to specific smart contracts. +- Token transfer tracking: Monitors and records all token transfer activities. +- Data normalization: Transforms raw blockchain data into a structured format for easy querying and analysis. +- Historical data management: Maintains a comprehensive historical record of blockchain activities. +- API integration: Provides a robust API for other components of the Bitlauncher platform to access indexed data. +- Performance optimization: Ensures high throughput and low latency in data processing and retrieval. +- Scalability: Designed to handle increasing blockchain activity and data volume. + +## Getting Started§ + ```bash # Copy environment variables. Put your dfuse credentials on it cp .env-sample .env diff --git a/apps/indexer/package.json b/apps/indexer/package.json index 9c35bb56a..21b6828a5 100644 --- a/apps/indexer/package.json +++ b/apps/indexer/package.json @@ -15,6 +15,9 @@ "dependencies": { "@dfuse/client": "^0.3.21", "@repo/supabase": "workspace:*", + "@repo/jobs": "workspace:*", + "@repo/alchemy": "workspace:*", + "@repo/tokens": "workspace:*", "@repo/trigger": "workspace:*", "@sentry/integrations": "^7.114.0", "@sentry/node": "^8.19.0", @@ -22,9 +25,9 @@ "@supabase/supabase-js": "^2.44.4", "@trigger.dev/sdk": "^2.3.19", "@types/pino-http": "^5.8.4", - "app-contracts": "workspace:*", + "@repo/contracts": "workspace:*", "app-env": "workspace:*", - "app-lib": "workspace:*", + "@repo/utils": "workspace:*", "axios": "^1.7.2", "bn.js": "^5.2.1", "express": "^4.19.2", @@ -35,7 +38,8 @@ "pino-http": "^10.2.0", "resend": "^3.5.0", "viem": "latest", - "ws": "^8.18.0" + "ws": "^8.18.0", + "zod": "^3.23.8" }, "devDependencies": { "@types/express": "^4.17.21", @@ -46,7 +50,7 @@ "rimraf": "^6.0.1", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0", - "@repo/typescript-config": "workspace:*", + "@repo/tsconfig": "workspace:*", "tsconfig-paths": "^4.2.0", "typescript": "^5.5.4" } diff --git a/apps/indexer/src/api/alchemy.ts b/apps/indexer/src/api/alchemy.ts new file mode 100644 index 000000000..51de3c1ea --- /dev/null +++ b/apps/indexer/src/api/alchemy.ts @@ -0,0 +1,150 @@ +import crypto from 'crypto' + +import type { + AlchemyActivityEvent, + AlchemyNetwork, + AlchemyWebhookEvent, +} from '@repo/alchemy' + +import { addressActivityTask } from '@repo/jobs' +import { evmTokens } from '@repo/tokens' +import { prodChains } from 'app-env' +import type { Request, Response } from 'express' +import { getAddress } from 'viem' +import { appConfig } from '~/config' +import { logger } from '~/lib/logger' +import { + getPresaleData, + isAddressRegisteredForPresale, +} from '~/lib/supabase-client' +// import {isAddressRegisteredForPresale} from '~/src/lib/supabase-client'; + +// Mapping of chain IDs to Alchemy SDK Network types +const chainIdToNetwork: Record = { + 1: 'ETH_MAINNET', + 137: 'MATIC_MAINNET', + 42161: 'ARB_MAINNET', + 10: 'OPT_MAINNET', + 8453: 'BASE_MAINNET', + 43114: 'MATIC_MAINNET', + 56: 'BNB_MAINNET', +} + +// Create an array of supported networks based on production chains +const networks: AlchemyNetwork[] = prodChains.map((chain) => { + const network = chainIdToNetwork[chain.id] + if (!network) throw new Error(`Unsupported chain ID: ${chain.id}`) + return network +}) +logger.info(`Supported networks: ${networks.join(', ')}`) + +/** + * Handles incoming Alchemy webhook requests. + * Validates the signature, logs the request, and triggers the address activity task. + * @param req - The incoming request object + * @param res - The response object + */ +export async function alchemyWebhook(req: Request, res: Response) { + // Parse the incoming webhook event + const evt = req.body as AlchemyWebhookEvent + logger.info(`Alchemy webhook received: ${JSON.stringify(evt)}`) + + // TODO: restore alchemy signature validation + // Validate the Alchemy signature + if (!validateAlchemySignature(req)) + return res.status(401).send('Unauthorized') + + // Extract network and activity from the event + const { network, activity } = evt.event as AlchemyActivityEvent + + // Validate event type and network + const isAddressActivity = evt.type === 'ADDRESS_ACTIVITY' + const isValidNetwork = networks.includes(network) + + if (!isAddressActivity || !isValidNetwork) { + const errorMsg = !isAddressActivity + ? `event type: ${evt.type}` + : `network: ${network}` + logger.error(`Invalid: ${errorMsg}`) + return res.status(401).send('Unauthorized') + } + + // Validate each transaction in the activity + for (const txn of activity) { + // Check if the asset is valid (USDC or USDT) + const isValidAsset = txn.asset === 'USDC' || txn.asset === 'USDT' + // Ensure the transaction is not sent to the presale address + const isValidToAddress = txn.toAddress !== appConfig.presaleAddress + // Get the token address from the transaction + const txnTokenAddress = + txn.rawContract?.address && getAddress(txn.rawContract.address) + + // Check if the token is supported + const isSupportedToken = + txnTokenAddress && + evmTokens.some((token) => txnTokenAddress === getAddress(token.address)) + + // Check if the sender is registered for the presale + const isRegisteredForPresale = await isAddressRegisteredForPresale( + txn.fromAddress, + 1, + ) + + // Get presale data and validate amount and timing + const presaleData = await getPresaleData(1) + const isValidAmount = txn.value <= presaleData.max_allocation + const currentTimestamp = Math.floor(Date.now() / 1000) // Current time in seconds + const isWithinPresalePeriod = + currentTimestamp >= Number(presaleData.start_timestamptz) && + currentTimestamp <= Number(presaleData.end_timestamptz) + + // Collect all validation errors + const validationErrors = [ + !isValidAsset && `asset: ${txn.asset}`, + !isValidToAddress && `to address: ${txn.toAddress}`, + !isSupportedToken && `token: ${txnTokenAddress}`, + !txn.log && 'missing transaction log', + !isRegisteredForPresale && 'address is not registered for presale', + !isValidAmount && + `amount exceeds max allocation: ${txn.value} > ${presaleData.max_allocation}`, + !isWithinPresalePeriod && + `transaction outside presale period: current time ${currentTimestamp}, presale start ${presaleData.start_timestamptz}, presale end ${presaleData.end_timestamptz}`, + ].filter(Boolean) + + // If there are any validation errors, log them and return unauthorized + if (validationErrors.length) { + logger.error(`Invalid transaction: ${validationErrors.join(', ')}`) + return res.status(401).send('Unauthorized') + } + + // Trigger the address activity task + const handle = await addressActivityTask.trigger(req.body) + logger.info(`Triggered address activity task: ${JSON.stringify(handle)}`) + } + + logger.info(`Webhook ${evt.id} processed`) + + // Send a success response + res.status(200).send(`Webhook ${evt.id} processed`) +} + +/** + * Validates the Alchemy webhook signature. + * @param req - The incoming request object + * @returns boolean - True if the signature is valid, false otherwise + */ +function validateAlchemySignature(req: Request): boolean { + // Extract the Alchemy signature from the request headers + const alchemySignature = req.headers['x-alchemy-signature'] as string + // Stringify the request body + const payload = JSON.stringify(req.body) + // Create an HMAC using the Alchemy signing key + const hmac = crypto.createHmac( + 'sha256', + appConfig.evm.alchemy.activitySigningKey, + ) + // Update the HMAC with the payload + hmac.update(payload) + // Compare the calculated signature with the provided signature + return alchemySignature === hmac.digest('hex') +} diff --git a/apps/indexer/src/routes/healthcheck.ts b/apps/indexer/src/api/healthcheck.ts similarity index 100% rename from apps/indexer/src/routes/healthcheck.ts rename to apps/indexer/src/api/healthcheck.ts diff --git a/apps/indexer/src/api/index.ts b/apps/indexer/src/api/index.ts new file mode 100644 index 000000000..f8db0cdd8 --- /dev/null +++ b/apps/indexer/src/api/index.ts @@ -0,0 +1,98 @@ +import express, { + type NextFunction, + type Response, + type Request, +} from 'express' +import rateLimit from 'express-rate-limit' +import helmet from 'helmet' +import pinoHttp from 'pino-http' +import { logger } from '~/lib/logger' +import { setupSentryErrorHandler } from '~/lib/sentry' +import { alchemyWebhook } from './alchemy' +import { healthcheck } from './healthcheck' + +export function startExpress() { + const app = express() + const port = 8080 + + // Trust proxy + app.set('trust proxy', 1) + + // Security Middlewares + app.use(helmet()) + app.use(express.json({ limit: '1mb' })) + + // Rate limiting + app.use( + rateLimit({ + windowMs: 60 * 1000, // 1 minute + max: 100, // limit each IP to 100 requests per windowMs + standardHeaders: true, + legacyHeaders: false, + }), + ) + + // Sentry error handler + setupSentryErrorHandler(app) + + // Logging middleware + // app.use(pinoHttp({ + // logger, + // serializers: { + // req: (req) => JSON.stringify({ + // method: req.method, + // url: req.url, + // headers: req.headers, + // }), + // res: (res) => JSON.stringify({ + // statusCode: res.statusCode, + // }), + // err: (err) => JSON.stringify({ + // type: err.constructor.name, + // message: err.message, + // stack: err.stack, + // }), + // }, + // })) + + // Routes + app.get('/', healthcheck) + app.post('/alchemy', alchemyWebhook) + + // Error handling middleware + app.use((err: Error, req: Request, res: Response, next: NextFunction) => { + logger.error( + { err, req: { method: req.method, url: req.url } }, + 'Unhandled error', + ) + res.status(500).json({ error: 'Internal Server Error' }) + }) + + // Start the server + const server = app.listen(port, () => { + logger.info(`Server running at http://localhost:${port}`) + }) + + // Handle unhandled promise rejections + process.on('unhandledRejection', (reason: any, promise: Promise) => { + logger.error({ reason, promise }, 'Unhandled Rejection') + // Optionally, you can choose to exit the process + // process.exit(1) + }) + + // Handle uncaught exceptions + process.on('uncaughtException', (error: Error) => { + logger.error(JSON.stringify(error), 'Uncaught Exception') + // It's generally recommended to exit the process on uncaught exceptions + process.exit(1) + }) + + // Graceful shutdown + process.on('SIGTERM', () => { + logger.info('SIGTERM signal received: closing HTTP server') + server.close(() => { + logger.info('HTTP server closed') + process.exit(0) + }) + }) +} diff --git a/apps/indexer/src/config.ts b/apps/indexer/src/config.ts index b553a7af1..aee2589c2 100644 --- a/apps/indexer/src/config.ts +++ b/apps/indexer/src/config.ts @@ -1,22 +1,63 @@ import { smartsaleEnv } from 'app-env' import type { Address } from 'viem' +import { isAddress } from 'viem' import { privateKeyToAccount } from 'viem/accounts' +import { z } from 'zod' +import { logger } from './lib/logger' + +const envSchema = z.object({ + SENTRY_DSN: z.string().min(1), + DFUSE_API_KEY: z.string().min(1), + TRIGGER_SECRET_KEY: z.string().min(1), + SEPOLIA_RPC: z.string().url(), + ISSUER_KEY: z + .string() + .min(1) + .length(64) + .regex(/^[a-f0-9]+$/i, 'Invalid issuer key format'), + ISSUER_ADDRESS: z + .string() + .refine( + (value): value is Address => isAddress(value), + 'Invalid issuer address', + ), + PRESALE_ADDRESS: z + .string() + .refine( + (value): value is Address => isAddress(value), + 'Invalid presale address', + ), + + ALCHEMY_ACTIVITY_SIGNING_KEY: z.string().min(1), +}) + +const parsedEnv = envSchema.safeParse(process.env) +if (!parsedEnv.success) { + logger.error( + `Environment validation failed: ${JSON.stringify(parsedEnv.error.format())}`, + ) + process.exit(1) +} export const appConfig = { + presaleAddress: parsedEnv.data.PRESALE_ADDRESS, sentry: { - dsn: process.env.SENTRY_DSN || '', + dsn: parsedEnv.data.SENTRY_DSN, }, eos: { - dfuseKey: process.env.DFUSE_API_KEY || '', + dfuseKey: parsedEnv.data.DFUSE_API_KEY, + }, + trigger: { + secretKey: parsedEnv.data.TRIGGER_SECRET_KEY, }, evm: { eosApi: 'https://api.testnet.evm.eosnetwork.com', - sepoliaApi: process.env.SEPOLIA_RPC || '', - issuerKey: process.env.ISSUER_KEY || '', - issuerAddress: (process.env.ISSUER_ADDRESS || '') as Address, - issuerAccount: privateKeyToAccount(`0x${process.env.ISSUER_KEY}`), + sepoliaApi: parsedEnv.data.SEPOLIA_RPC, + issuerKey: parsedEnv.data.ISSUER_KEY, + issuerAddress: parsedEnv.data.ISSUER_ADDRESS as Address, + issuerAccount: privateKeyToAccount(`0x${parsedEnv.data.ISSUER_KEY}`), alchemy: { - activitySigningKey: process.env.ALCHEMY_ACTIVITY_SIGNING_KEY || '', + activitySigningKey: parsedEnv.data.ALCHEMY_ACTIVITY_SIGNING_KEY, }, }, ...smartsaleEnv.test, diff --git a/apps/indexer/src/index.ts b/apps/indexer/src/index.ts index d4901d186..956bc5a98 100644 --- a/apps/indexer/src/index.ts +++ b/apps/indexer/src/index.ts @@ -1,9 +1,9 @@ -import { getErrorMessage } from 'app-lib' +import { getErrorMessage } from '@repo/utils' +import { startExpress } from './api' import { logger } from './lib/logger' -import { startExpress } from './routes/index' async function main() { - logger.info(`Launchpad indexer starting up ...`) + logger.info('Launchpad indexer starting up ...') try { startExpress() // startPresaleService() diff --git a/apps/indexer/src/lib/supabase-client.ts b/apps/indexer/src/lib/supabase-client.ts index 850c8ffc3..bf588c328 100644 --- a/apps/indexer/src/lib/supabase-client.ts +++ b/apps/indexer/src/lib/supabase-client.ts @@ -46,16 +46,54 @@ export async function upsertOrder(data: TablesInsert<'order'>) { return data } -export async function upsertTransfers(data: TablesInsert<'transfer'>) { - console.log('upsert transfers', data) - const { data: result, error } = await supabase - .from('transfer') - .upsert(data, { onConflict: 'trx_hash' }) - .select() +// export async function upsertTransfers(data: TablesInsert<'transfer'>) { +// console.log('upsert transfers', data) +// const { data: result, error } = await supabase +// .from('transfer') +// .upsert(data, { onConflict: 'trx_hash' }) +// .select() - if (error) console.error('Error:', error) +// if (error) console.error('Error:', error) - console.log('Result:', result) +// console.log('Result:', result) + +// return data +// } + +export async function isAddressRegisteredForPresale( + address: string, + projectId: number, +): Promise { + const { data, error } = await supabase + .from('whitelist') + .select('*') + .eq('address', address) + .eq('id', projectId) + .single() + + if (error) { + if (error.code === 'PGRST116') { + // No matching row found, address is not registered + return false + } + console.error('Error checking presale registration:', error) + throw error + } + + return !!data +} + +export async function getPresaleData(projectId: number) { + const { data, error } = await supabase + .from('presale') + .select('*') + .eq('id', projectId) + .single() + + if (error) { + console.error('Error checking presale data:', error) + throw error + } return data } diff --git a/apps/indexer/src/modules/auction/auction-indexer.ts b/apps/indexer/src/modules/auction/auction-indexer.ts index b9384c63e..2c4137acf 100644 --- a/apps/indexer/src/modules/auction/auction-indexer.ts +++ b/apps/indexer/src/modules/auction/auction-indexer.ts @@ -1,7 +1,7 @@ -import { TestnetEasyAuction } from 'app-contracts' +import { TestnetEasyAuction } from '@repo/contracts' import { eosEvmTestnet } from 'app-env' import BN from 'bn.js' -import { http, type Log, createPublicClient, stringify } from 'viem' +import { createPublicClient, http, stringify, type Log } from 'viem' import { upsertAuctionDetail, upsertOrder } from '~/lib/supabase-client' import { bigintToPostgresTimestamp, diff --git a/apps/indexer/src/modules/auction/easyauction.ts b/apps/indexer/src/modules/auction/easyauction.ts index 970900370..e1cdf14ef 100644 --- a/apps/indexer/src/modules/auction/easyauction.ts +++ b/apps/indexer/src/modules/auction/easyauction.ts @@ -1,6 +1,6 @@ -import { TestnetEasyAuction } from 'app-contracts' +import { TestnetEasyAuction } from '@repo/contracts' import { eosEvmTestnet } from 'app-env' -import { http, createPublicClient, getContract } from 'viem' +import { createPublicClient, getContract, http } from 'viem' const client = createPublicClient({ chain: eosEvmTestnet, diff --git a/apps/indexer/src/modules/presale/evm-contributions.ts b/apps/indexer/src/modules/presale/evm-contributions.ts index 9783f7edb..7f4b59701 100644 --- a/apps/indexer/src/modules/presale/evm-contributions.ts +++ b/apps/indexer/src/modules/presale/evm-contributions.ts @@ -1,14 +1,13 @@ -import { type EVMTokenContractData, appContracts } from 'app-contracts' +import { type EVMTokenContractData, appContracts } from '@repo/contracts' import { - http, type Address, type Log, type PublicClient, createPublicClient, - parseAbiItem, - stringify, + http, + parseAbiItem } from 'viem' -import { upsertTransfers } from '~/lib/supabase-client' +// import { upsertTransfers } from '~/lib/supabase-client' import { runPromisesInSeries } from '~/lib/utils' import type { TransferEvent } from '~/modules/auction/auction.type' import { issuePresaleTokens } from './presale-issuer' @@ -104,16 +103,16 @@ async function handleTransfer(log: TransferEvent, token: EVMTokenContractData) { log.args.value, )) as Address - upsertTransfers({ - trx_hash: log.transactionHash!, - from: log.args.from as Address, - to: log.args.to as Address, - amount: Number(log.args.value), - token: log.address, - chain_id: token.chainId, - type: 'presale', - bl_presale_trx, - }) + // upsertTransfers({ + // trx_hash: log.transactionHash!, + // from: log.args.from as Address, + // to: log.args.to as Address, + // amount: Number(log.args.value), + // token: log.address, + // chain_id: token.chainId, + // type: 'presale', + // bl_presale_trx, + // }) // console.log('result', result) // if (result.usdcred_trx || data.from === '0x0000000000000000000000000000000000000000') return diff --git a/apps/indexer/src/modules/presale/presale-issuer.ts b/apps/indexer/src/modules/presale/presale-issuer.ts index 9bbe3e4e8..7e001d6ad 100644 --- a/apps/indexer/src/modules/presale/presale-issuer.ts +++ b/apps/indexer/src/modules/presale/presale-issuer.ts @@ -1,4 +1,4 @@ -import { TestnetBLPL } from 'app-contracts' +import { TestnetBLPL } from '@repo/contracts' import { eosEvmTestnet } from 'app-env' import { createWalletClient } from 'viem' import { http, type Address } from 'viem' diff --git a/apps/indexer/src/modules/swaps/cred-issuer.ts b/apps/indexer/src/modules/swaps/cred-issuer.ts index d67c5a958..fb9b5c3ce 100644 --- a/apps/indexer/src/modules/swaps/cred-issuer.ts +++ b/apps/indexer/src/modules/swaps/cred-issuer.ts @@ -1,4 +1,4 @@ -import { TestnetUSDCred } from 'app-contracts' +import { TestnetUSDCred } from '@repo/contracts' import { eosEvmTestnet } from 'app-env' import { createWalletClient } from 'viem' import { http, type Address } from 'viem' diff --git a/apps/indexer/src/modules/swaps/evm-transfers.ts b/apps/indexer/src/modules/swaps/evm-transfers.ts index 9494a0717..91dce8991 100644 --- a/apps/indexer/src/modules/swaps/evm-transfers.ts +++ b/apps/indexer/src/modules/swaps/evm-transfers.ts @@ -1,18 +1,16 @@ import { type EVMTokenContractData, - SepoliaUSDT, - TestnetUSDT, - appContracts, -} from 'app-contracts' + appContracts +} from '@repo/contracts' import { runPromisesInSeries } from '~/lib/utils' import { appChains } from 'app-env' import { - http, type Address, type Log, type PublicClient, createPublicClient, + http, parseAbiItem, stringify, } from 'viem' diff --git a/apps/indexer/tsconfig.json b/apps/indexer/tsconfig.json index d14168838..6432ecae3 100644 --- a/apps/indexer/tsconfig.json +++ b/apps/indexer/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../packages/config-typescript/node16.json", + "extends": "../../packages/tsconfig/node16.json", "include": ["./src/**/*", "src/lib/utils.ts"], "exclude": ["node_modules"], "compilerOptions": { diff --git a/apps/trigger/package.json b/apps/trigger/package.json index 8661d531a..8ed853c01 100644 --- a/apps/trigger/package.json +++ b/apps/trigger/package.json @@ -9,9 +9,9 @@ "deploy:prod": "bunx trigger.dev@beta deploy --env prod" }, "dependencies": { - "app-contracts": "workspace:*", + "@repo/alchemy": "workspace:*", "app-env": "workspace:*", - "app-lib": "workspace:*", + "@repo/utils": "workspace:*", "@trigger.dev/sdk": "3.0.0-beta.55", "viem": "latest" } diff --git a/apps/trigger/tsconfig.json b/apps/trigger/tsconfig.json index 97c2d81b0..c24fa5e65 100644 --- a/apps/trigger/tsconfig.json +++ b/apps/trigger/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../packages/config-typescript/node16.json", + "extends": "@repo/tsconfig/node16.json", "include": ["./src/**/*", "src/lib/utils.ts", "trigger.config.ts"], "exclude": ["node_modules"], "compilerOptions": { diff --git a/apps/webapp/actions.ts b/apps/webapp/actions.ts index 62c9f3ea9..5ad424bb7 100644 --- a/apps/webapp/actions.ts +++ b/apps/webapp/actions.ts @@ -3,7 +3,7 @@ import { handleAxiosError } from '@/lib/utils' import { createSupabaseServerClient } from '@/services/supabase' import { presaleInsertSchema } from '@repo/supabase' -import { fromEntries } from 'app-lib' +import { fromEntries } from '@repo/utils' import axios from 'axios' import { cookies } from 'next/headers' import { Resend } from 'resend' diff --git a/apps/webapp/app/(routes)/[lang]/[project]/auction/page.tsx b/apps/webapp/app/(routes)/[lang]/[project]/auction/page.tsx index 773e51b7c..4e4f7fd42 100644 --- a/apps/webapp/app/(routes)/[lang]/[project]/auction/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/[project]/auction/page.tsx @@ -17,6 +17,8 @@ import { getProjectBySlug, getProjects, } from '@/lib/projects' +import { createSupabaseServerClient } from '@/services/supabase' +import { getPresaleData } from '@/services/supabase/service' import type { ProjectPageParams, ProjectPageProps } from '@/types/routing.type' import { redirect } from 'next/navigation' @@ -25,6 +27,8 @@ export default async function AuctionPage({ params }: ProjectPageProps) { const p = await getProjectBySlug(params.project, dict) if (!p || (!p.auctionId && !p.registrationOpen)) redirect('/') const project = p as ProjectWithAuction + const supabase = await createSupabaseServerClient() + const presaleData = await getPresaleData({ projectId: project.id, supabase }) return (
@@ -32,9 +36,9 @@ export default async function AuctionPage({ params }: ProjectPageProps) {
- + - + diff --git a/apps/webapp/app/(routes)/[lang]/[project]/page.tsx b/apps/webapp/app/(routes)/[lang]/[project]/page.tsx index 76d269e24..feb8992e4 100644 --- a/apps/webapp/app/(routes)/[lang]/[project]/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/[project]/page.tsx @@ -17,10 +17,13 @@ import { redirect } from 'next/navigation' export default async function ProjectPage({ params }: ProjectPageProps) { const dict = await getDictionary(params.lang) const project = await getProjectBySlug(params.project, dict) - if (!project) redirect('/') + if (!project || !project.content) redirect('/') - const projectContentObjectKeys = Object.keys(project.content!) - const projectContent = project.content! + const projectContentObjectKeys = Object.keys(project.content) + const projectContent = project.content + + // is presale upcoming + // const isPresaleUpcoming = new Date(project.presaleData.start_timestamptz) > new Date() return ( <> @@ -28,7 +31,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
- +
@@ -56,7 +59,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) { !isLastItem && 'backdrop-x my-10 overflow-hidden rounded-3xl bg-primary/70 pb-10', index % 2 !== 0 - ? `backdrop-x rounded-3xl bg-primary/70 pb-10` + ? 'backdrop-x rounded-3xl bg-primary/70 pb-10' : '', )} > diff --git a/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx b/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx index 6a7c92866..954d95250 100644 --- a/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/[project]/presale/page.tsx @@ -6,6 +6,8 @@ import { Countdown } from '@/components/shared/countdown' import { Card, CardContent } from '@/components/ui/card' import { getDictionary } from '@/dictionaries' import { type ProjectWithAuction, getProjectBySlug } from '@/lib/projects' +import { createSupabaseServerClient } from '@/services/supabase/server' +import { getPresaleData, getProjectData } from '@/services/supabase/service' import type { ProjectPageProps } from '@/types/routing.type' import { redirect } from 'next/navigation' @@ -16,15 +18,22 @@ export default async function ProjectPage({ params }: ProjectPageProps) { dict, )) as ProjectWithAuction if (!project) redirect('/') + const supabase = await createSupabaseServerClient() + const presaleData = await getPresaleData({ projectId: project.id, supabase }) + const projectData = await getProjectData({ projectId: project.id, supabase }) + if (!project) redirect('/') return (
- + - + diff --git a/apps/webapp/app/(routes)/[lang]/about/about-bitlauncher/page.tsx b/apps/webapp/app/(routes)/[lang]/about/about-bitlauncher/page.tsx index 846781a3a..3c66161ae 100644 --- a/apps/webapp/app/(routes)/[lang]/about/about-bitlauncher/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/about/about-bitlauncher/page.tsx @@ -9,7 +9,7 @@ import type { Metadata } from 'next' export default async function AboutBitlauncher({ params }: CommonPageProps) { const dict = await getDictionary(params.lang) return ( -
+
+ Bitlauncher is a pioneering launchpad dedicated to + transforming the landscape of artificial intelligence (AI) and + cryptocurrency. We are on a mission to empower the next wave of AI + innovation by providing open-source AI projects with equitable fundraising + opportunities and decentralized organization through the use of blockchain + technology. + + ), + paragraph2: ( + <> + At Bitlauncher, we{' '} + + combine the transformative powers of AI and cryptocurrency + {' '} + to address the unique challenges faced by AI startups. By integrating + tokenization and decentralized autonomous organizations (DAOs), we create + a seamless synergy that enables these startups to overcome funding + barriers, accelerate their growth, and harness global resources. + + ), + paragraph3: ( + <> + Our platform is built on a foundation of{' '} + transparency, inclusivity, and community-driven progress.{' '} + We foster a collaborative environment where developers, contributors, and + AI enthusiasts can come together to share resources, exchange ideas, and + shape the future of technology. + + ), image: { - alt: 'dBoard', + alt: 'about-bg', src: '/images/about-bg.svg', width: 610, height: 468, diff --git a/apps/webapp/app/(routes)/[lang]/blog/[category]/page.tsx b/apps/webapp/app/(routes)/[lang]/blog/[category]/page.tsx index 8776864d0..dc29c8e0d 100644 --- a/apps/webapp/app/(routes)/[lang]/blog/[category]/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/blog/[category]/page.tsx @@ -8,7 +8,6 @@ import { getPageSeoText, } from '@/services/datocms' import type { Metadata } from 'next' -import Image from 'next/image' import { notFound } from 'next/navigation' export default async function Page(props: CategoryPageProps) { @@ -23,17 +22,17 @@ export default async function Page(props: CategoryPageProps) { if (!pageSeo) notFound() return ( - <> +
- -
+
-
- +
+ ) } diff --git a/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx b/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx index cb0cf6067..5355e5685 100644 --- a/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/learn/security/page.tsx @@ -1,10 +1,10 @@ -import { WhyChooseUs } from '@/components/routes/home/why-choose-us' +import { LearnSection } from '@/components/layout/section/learn-section' +import StepsSection from '@/components/layout/section/steps-section' import { BgHeader } from '@/components/shared/bg-header' import { PageContent } from '@/components/shared/content' import { getDictionary } from '@/dictionaries' import type { CommonPageProps } from '@/types/routing.type' import type { Metadata } from 'next' -import React from 'react' export default async function SecurityTips({ params }: CommonPageProps) { const dict = await getDictionary(params.lang) @@ -13,13 +13,19 @@ export default async function SecurityTips({ params }: CommonPageProps) { return ( <> - -
- +
+ +
+ +
+
+
+ +
) diff --git a/apps/webapp/app/(routes)/[lang]/page.tsx b/apps/webapp/app/(routes)/[lang]/page.tsx index 6730324bc..20821ff56 100644 --- a/apps/webapp/app/(routes)/[lang]/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/page.tsx @@ -3,6 +3,10 @@ import { Categories } from '@/components/_wip/categories' import { FeatureOne } from '@/components/_wip/feature-one' import { FeatureThree } from '@/components/_wip/feature-three' import { FeatureTwo } from '@/components/_wip/feature-two' +import { RecentArticles } from '@/components/layout/section/article-section' +import { FAQ } from '@/components/layout/section/faq-section' +import { LearnSection } from '@/components/layout/section/learn-section' +import StepsSection from '@/components/layout/section/steps-section' import { NewHomeHero } from '@/components/routes/home/hero/index' import { getDictionary } from '@/dictionaries' import type { Lang } from '@/dictionaries/locales' @@ -33,17 +37,17 @@ export default async function IndexPage({ params: { lang } }: IndexPageProps) { const projects = getProjects(dict) return ( -
+
- {appConfig.features.sections ? ( - <> - - - - ) : null} + + + + + + {appConfig.features.explorations ? ( <> diff --git a/apps/webapp/app/(routes)/[lang]/whitepaper/page.tsx b/apps/webapp/app/(routes)/[lang]/whitepaper/page.tsx index 736a457ad..d8b1c3e91 100644 --- a/apps/webapp/app/(routes)/[lang]/whitepaper/page.tsx +++ b/apps/webapp/app/(routes)/[lang]/whitepaper/page.tsx @@ -10,15 +10,17 @@ export default async function BitlauncherWhitePaper({ const dict = await getDictionary(params.lang) return ( <> - +
+ -
- -
+
+ +
+
) } diff --git a/apps/webapp/app/actions/save-deposit.ts b/apps/webapp/app/actions/save-deposit.ts index 5598efd3b..e732cb7e2 100644 --- a/apps/webapp/app/actions/save-deposit.ts +++ b/apps/webapp/app/actions/save-deposit.ts @@ -4,17 +4,19 @@ import { createSupabaseServerClient } from '@/services/supabase' import { type Tables, type TablesInsert, - transferInsertSchema, + presaleDepositInsertSchema, } from '@repo/supabase' -export async function saveDeposit(transfer: TablesInsert<'transfer'>): Promise<{ +export async function saveDeposit( + transfer: TablesInsert<'presale_deposit'>, +): Promise<{ success: boolean message: string - data?: Tables<'transfer'> + data?: Tables<'presale_deposit'> error?: any }> { try { - const parseResult = transferInsertSchema.safeParse(transfer) + const parseResult = presaleDepositInsertSchema.safeParse(transfer) if (!parseResult.success) { return { success: false, @@ -24,8 +26,28 @@ export async function saveDeposit(transfer: TablesInsert<'transfer'>): Promise<{ } const supabase = await createSupabaseServerClient() + const transaction = await supabase + .from('transaction') + .upsert( + { + hash: parseResult.data.deposit_hash, + trx_type: 'presale_deposit', + ...parseResult.data, + }, + { onConflict: 'hash' }, + ) + .select() + + if (transaction.error) { + return { + success: false, + message: 'Database operation failed', + error: 'transaction.error', + } + } + const { data, error } = await supabase - .from('transfer') + .from('presale_deposit') .upsert(parseResult.data, { onConflict: 'trx_hash' }) .select() diff --git a/apps/webapp/app/globals.css b/apps/webapp/app/globals.css index 76383a63c..491bd1b2a 100644 --- a/apps/webapp/app/globals.css +++ b/apps/webapp/app/globals.css @@ -123,7 +123,7 @@ html { body, p { - @apply font-futura-pt-demi text-base font-normal; + @apply text-base font-normal font-futura-pt-demi; } h1, @@ -132,7 +132,7 @@ h3, h4, h5, h6 { - @apply font-bold tracking-tight; + @apply tracking-tight font-futura-pt-bold; } .open-sans { @@ -191,17 +191,17 @@ input[type="number"] { } .newsletter-wrapper { - @apply mx-auto box-content flex flex-col items-center px-0 sm:rounded-3xl sm:text-center; + @apply box-content flex flex-col items-center px-0 mx-auto sm:rounded-3xl sm:text-center; background: url("/images/newsletter-bg.webp") center center no-repeat; background-size: cover; } .narrow-container { - @apply container md:px-20; + @apply container md:px-10 xl:px-20; } .content-container { - @apply mx-auto flex w-full max-w-screen-md flex-col gap-10 px-5 py-10 md:py-24; + @apply flex flex-col w-full max-w-screen-md gap-10 px-5 py-10 mx-auto md:py-24; } /** Scrollbar Styling */ @@ -245,6 +245,17 @@ input[type="number"] { } } +iframe[title="reCAPTCHA"], +.grecaptcha-badge { + display: relative; + z-index: 0; + opacity: 0.333; + + &:hover { + opacity: 1; + } +} + /** Tooltip Styling */ *[data-title]::after { @@ -283,12 +294,31 @@ input[type="number"] { } /* TYPOGRAPHY */ + +.heroHeading { + @apply text-6xl font-bold leading-[76px]; +} + .heading { - @apply text-4xl font-bold md:text-5xl; + @apply text-4xl font-bold leading-normal md:text-4xl; +} + +.newsletterHeading { + @apply text-center text-[40.50px] font-extrabold leading-[45px] md:text-4xl sm:text-4xl; +} + +/* Heading in About - Security - Whitepaper */ +.sectionsHeading { + @apply text-[4.188rem] font-normal leading-normal md:text-[4.3504rem] lg:text-[5.438rem]; +} + +/* Subheading in About - Security - Whitepaper */ +.sectionsSubheading { + @apply text-start text-2xl font-medium leading-[42.35px] text-[#ff51ed] md:text-[2.188rem]; } .heading2 { - @apply text-2xl font-bold md:text-4xl; + @apply text-2xl font-bold leading-[42px] md:text-4xl; } .heading3 { @@ -308,10 +338,10 @@ input[type="number"] { } .mobile-nav { - height: calc(100vh - 64px) !important; + height: calc(100vh - 70px) !important; width: 100vw; overflow: hidden; - @apply fixed inset-x-0 top-16 flex flex-col items-center justify-evenly overflow-hidden bg-background pb-20; + @apply fixed inset-x-0 flex flex-col items-center pb-20 overflow-hidden top-16 justify-evenly bg-background; } /* INFOPAGES BG COVER*/ diff --git a/apps/webapp/components/_wip/early-access-landing.tsx b/apps/webapp/components/_wip/early-access-landing.tsx index e991dfb8b..b00fa9131 100644 --- a/apps/webapp/components/_wip/early-access-landing.tsx +++ b/apps/webapp/components/_wip/early-access-landing.tsx @@ -31,7 +31,7 @@ function Section({

{title}

-

+

{description}

@@ -54,7 +54,7 @@ function Section({
  • {project.name}

    -

    +

    {project.description}

    diff --git a/apps/webapp/components/_wip/feature-three.tsx b/apps/webapp/components/_wip/feature-three.tsx index 8397cf705..14ccdd481 100644 --- a/apps/webapp/components/_wip/feature-three.tsx +++ b/apps/webapp/components/_wip/feature-three.tsx @@ -11,7 +11,7 @@ export function FeatureThree() {

    Trusted by over 600 million users and 10,000 teams

    -

    +

    Our rigorous security and compliance standards are at the heart of all we do. We work tirelessly to protect you and your customers.

    @@ -75,7 +75,7 @@ export function FeatureThree() {

    99.99% uptime

    -

    +

    For Landwind, with zero maintenance downtime

  • @@ -91,7 +91,7 @@ export function FeatureThree() {

    600M+ Users

    -

    +

    Trusted by over 600 milion users around the world

    @@ -111,7 +111,7 @@ export function FeatureThree() {

    100+ countries

    -

    +

    Have used Landwind to create functional websites

    @@ -127,7 +127,7 @@ export function FeatureThree() {

    5+ Million

    -

    +

    Transactions per day

    diff --git a/apps/webapp/components/_wip/landing-page.tsx b/apps/webapp/components/_wip/landing-page.tsx index 61f69df9f..d903e0a9c 100644 --- a/apps/webapp/components/_wip/landing-page.tsx +++ b/apps/webapp/components/_wip/landing-page.tsx @@ -12,16 +12,14 @@ export function LandingPage({ content }: LandingPageProps) {

    {content.header}

    -

    +

    {content.description}

    {content.sections.map((section) => (

    {section.subHeader}

    -

    - {section.text} -

    +

    {section.text}

    ))}
    diff --git a/apps/webapp/components/_wip/landing-page2.tsx b/apps/webapp/components/_wip/landing-page2.tsx index b7bfa5bd4..009122122 100644 --- a/apps/webapp/components/_wip/landing-page2.tsx +++ b/apps/webapp/components/_wip/landing-page2.tsx @@ -13,7 +13,7 @@ export function LandingPage2({ content }: LandingPage2Props) {

    {content.heading}

    -

    +

    {content.description}

    diff --git a/apps/webapp/components/_wip/tokenization-landing.tsx b/apps/webapp/components/_wip/tokenization-landing.tsx index 3bfa23f57..0304a29ba 100644 --- a/apps/webapp/components/_wip/tokenization-landing.tsx +++ b/apps/webapp/components/_wip/tokenization-landing.tsx @@ -15,7 +15,7 @@ export function TokenizationLanding() {

    {section.title}

    -

    +

    {section.description}

    @@ -27,9 +27,7 @@ export function TokenizationLanding() {
  • {detail.header}

    -

    - {detail.content} -

    +

    {detail.content}

  • ))} diff --git a/apps/webapp/components/dialogs/register.tsx b/apps/webapp/components/dialogs/register.tsx index 77ced29e3..854fac523 100644 --- a/apps/webapp/components/dialogs/register.tsx +++ b/apps/webapp/components/dialogs/register.tsx @@ -9,7 +9,7 @@ import { DialogTitle, } from '@/components/ui/dialog' import { useSession } from '@/hooks/use-session' -import { runtimeEnv } from 'app-lib' +import { runtimeEnv } from '@repo/utils' import { useRouter } from 'next/navigation' import QRCode from 'react-qr-code' import { useEffectOnce } from 'react-use' diff --git a/apps/webapp/components/layout/footer/footer.tsx b/apps/webapp/components/layout/footer/footer.tsx index 486bd3053..dcc4b06da 100644 --- a/apps/webapp/components/layout/footer/footer.tsx +++ b/apps/webapp/components/layout/footer/footer.tsx @@ -1,11 +1,6 @@ -import { LearnSection } from '@/components/layout/footer/learn-section' import { getDictionary } from '@/dictionaries' import type { Lang } from '@/dictionaries/locales' -import { appConfig } from '@/lib/config' import dynamic from 'next/dynamic' -import { FAQ } from './faq' -import Participate from './participate' -import { RecentArticles } from './recent' const DynamicNewsletter = dynamic(() => import('./newsletter') as any, { ssr: false, @@ -15,19 +10,6 @@ export default async function Footer({ params }: { params: { lang: Lang } }) { const dict = await getDictionary(params.lang) return (
    -
    - {/* Call to action, how it works sections */} - - {appConfig.features.learn ? ( - <> - - - ) : null} - - - {/* Media and other */} - -
    ) diff --git a/apps/webapp/components/layout/footer/learn-section.tsx b/apps/webapp/components/layout/footer/learn-section.tsx deleted file mode 100644 index 8e222a0c1..000000000 --- a/apps/webapp/components/layout/footer/learn-section.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import Image from 'next/image' -import Link from 'next/link' -import { Section } from '../../shared/section' - -export function LearnSection() { - return ( -
    -
    -
    - - -
    - - - - {content.cards[0].title} - - - - {content.cards[0].title} - -
    - - -
    - {content.cards[0].paragraphs.map((p) => ( -

    - {p} -

    - ))} -
    -
    -
    - - - -
    - - -
    - - - {content.cards[1].title} - -
    - - - - - {content.cards[1].title} - -
    - - - - -
    - - - {content.cards[2].title} - -
    - - - - - {content.cards[2].title} - -
    - - -
    -
    -
    - ) -} - -const content = { - sectionTitle: 'Learn More About Bitlauncher', - cards: [ - { - title: 'How to Participate in a Bitlauncher IDO?', - paragraphs: [ - "A good place to start is: what is Bitlauncher? (We'll give you the brief version). Bitlauncher is a platform that connects young projects with early community members through initial decentralized offerings (IDOS). It provides a unique opportunity for contributors to engage with up-and-coming tech innovations.", - 'By participating in an IDO on Bitlauncher, users can gain early access to tokens from new blockchain projects. This early access can potentially lead to significant benefits if the projects grow in value and popularity. Bitlauncher aims to democratize the investment process, making it accessible to a broader audience.', - ], - images: [ - '/images/home/platform-circles.webp', - '/images/home/platform-circles.png', - ], - }, - { - title: 'How to buy the Bitlauncher $BL token?', - paragraphs: [], - images: ['/images/home/bl-coins.webp', '/images/home/bl-coins.png'], - }, - { - title: 'What is an IDO (Initial Decentralized Offering)?', - paragraphs: [], - images: ['/images/home/glass.webp', '/images/home/glass.png'], - }, - ], -} diff --git a/apps/webapp/components/layout/footer/newsletter.tsx b/apps/webapp/components/layout/footer/newsletter.tsx index f29db7daf..cdb8e6ce6 100644 --- a/apps/webapp/components/layout/footer/newsletter.tsx +++ b/apps/webapp/components/layout/footer/newsletter.tsx @@ -89,7 +89,7 @@ export default function Newsletter({ lang }: LangProp) { return (
    -
    +
    -

    - Sign up for our newsletter -

    +

    Sign up for our newsletter

    To stay up to date with our progress, announcements and exclusive discounts, sign up with your email below: diff --git a/apps/webapp/components/layout/header/bitcash-access.tsx b/apps/webapp/components/layout/header/bitcash-access.tsx index e530308af..70da8027e 100644 --- a/apps/webapp/components/layout/header/bitcash-access.tsx +++ b/apps/webapp/components/layout/header/bitcash-access.tsx @@ -7,11 +7,10 @@ import { IconDownRightArrow } from '@/components/ui/icons' import { useErc20Balance } from '@/hooks/use-balance' import { useSession } from '@/hooks/use-session' import { cn } from '@/lib/utils' -import { TestnetUSDCred } from 'app-contracts' -import { runtimeEnv } from 'app-lib' +import { TestnetUSDCred } from '@repo/contracts' +import { runtimeEnv } from '@repo/utils' import type { VariantProps } from 'class-variance-authority' import { LucideWallet } from 'lucide-react' -import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useEffect, useState } from 'react' // import { bitcashLogin } from '@/lib/esr' diff --git a/apps/webapp/components/layout/header/index.tsx b/apps/webapp/components/layout/header/index.tsx index 3d8c90c5a..bdb2ecddd 100644 --- a/apps/webapp/components/layout/header/index.tsx +++ b/apps/webapp/components/layout/header/index.tsx @@ -14,28 +14,28 @@ import { Navigation } from './new-nav' export function Header({ lang, dict }: HeaderProps) { return ( -

    -
    -
    +
    +
    + {/* Left Section with Icon */} +
    -
    + {/* Center Section (Navigation Links) */} +
    {/* // ? Development only */} {appConfig.features.newNavStruct ? ( ) : ( - // ? Production only until development of newNavStruct is complete (UI/UX + content upt) )}
    - {/* Desktop action buttons */} -
    + {/* Right Section (Buttons/Language Selector) */} +
    - {/* */} Login}> @@ -46,7 +46,7 @@ export function Header({ lang, dict }: HeaderProps) {
    -
    +
    ) } diff --git a/apps/webapp/components/layout/header/nav-links.tsx b/apps/webapp/components/layout/header/nav-links.tsx index 2c3ad6307..1f5243df7 100644 --- a/apps/webapp/components/layout/header/nav-links.tsx +++ b/apps/webapp/components/layout/header/nav-links.tsx @@ -5,7 +5,7 @@ import { useSession } from '@/hooks/use-session' import { appConfig } from '@/lib/config' import type { LangProp } from '@/types/routing.type' import { useAccountModal, useConnectModal } from '@rainbow-me/rainbowkit' -import { formatAddress } from 'app-lib' +import { formatAddress } from '@repo/utils' import Link from 'next/link' import { useRouter } from 'next/navigation' import { v4 as uuidv4 } from 'uuid' diff --git a/apps/webapp/components/layout/providers.tsx b/apps/webapp/components/layout/providers.tsx index 13aaeed6e..95265c7e3 100644 --- a/apps/webapp/components/layout/providers.tsx +++ b/apps/webapp/components/layout/providers.tsx @@ -5,6 +5,7 @@ import { MobileNavProvider } from '@/hooks/use-mobile-navigation' import { SessionProvider } from '@/hooks/use-session' import { UseSigningRequestProvider } from '@/hooks/use-signing-request' import { appConfig } from '@/lib/config' +import multibase, { MultibaseProvider } from '@multibase/js' import { RainbowKitProvider, type Theme, @@ -94,6 +95,17 @@ const customRainbowKitTheme = merge(lightTheme(), { // } } as Theme) +if (typeof window !== 'undefined') { + const multibaseKey = appConfig.multibase.key + + if (!multibaseKey) { + console.error('Missing MULTIBASE_API_KEY') + } else { + multibase.init(multibaseKey) + console.info('Multibase Initialized') + } +} + export function Providers({ children, ...props }: ThemeProviderProps) { return ( @@ -108,11 +120,13 @@ export function Providers({ children, ...props }: ThemeProviderProps) { appName: 'Bitlauncher', }} > - - - {children} - - + + + + {children} + + + diff --git a/apps/webapp/components/layout/footer/recent.tsx b/apps/webapp/components/layout/section/article-section.tsx similarity index 100% rename from apps/webapp/components/layout/footer/recent.tsx rename to apps/webapp/components/layout/section/article-section.tsx diff --git a/apps/webapp/components/layout/footer/faq.tsx b/apps/webapp/components/layout/section/faq-section.tsx similarity index 69% rename from apps/webapp/components/layout/footer/faq.tsx rename to apps/webapp/components/layout/section/faq-section.tsx index cb1047870..ad8dc1409 100644 --- a/apps/webapp/components/layout/footer/faq.tsx +++ b/apps/webapp/components/layout/section/faq-section.tsx @@ -1,11 +1,11 @@ -import { Section } from '@/components/shared/section' +import { Section } from '@/components/shared/section'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, -} from '@/components/ui/accordion' -import type { LangProp } from '@/types/routing.type' +} from '@/components/ui/accordion'; +import type { LangProp } from '@/types/routing.type'; export function FAQ({ lang, dict }: FAQProps) { return ( @@ -19,10 +19,10 @@ export function FAQ({ lang, dict }: FAQProps) { {dict.faq.questions.map( (item: { question: string; answer: string }, index: number) => ( - + {item.question} - + {item.answer} diff --git a/apps/webapp/components/layout/section/learn-section.tsx b/apps/webapp/components/layout/section/learn-section.tsx new file mode 100644 index 000000000..c3075b182 --- /dev/null +++ b/apps/webapp/components/layout/section/learn-section.tsx @@ -0,0 +1,119 @@ +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' +import Image from 'next/image' +import Link from 'next/link' +import { Section } from '../../shared/section' + +export function LearnSection() { + const mainCard = content.cards[0] + const secondaryCards = content.cards.filter((_, i) => i > 0) + return ( +
    +
    + + +
    + + + + {mainCard.title} + + + + {mainCard.title} + +
    + + +
    + {mainCard.paragraphs.map((p, i) => ( +

    + {p} +

    + ))} +
    +
    +
    + + + +
    + {secondaryCards.map((card, i) => ( + + +
    + + + {card.title} + +
    + + + + + {card.title} + +
    + + + ))} +
    +
    +
    + ) +} + +const content = { + sectionTitle: 'Learn More About Bitlauncher', + cards: [ + { + title: 'How to Partcipate in the Bitlauncher Presale?', + paragraphs: [ + "A good place to start is: what is Bitlauncher? (We'll give you the brief version). Bitlauncher is a platform that connects young projects with early community members through initial decentralized offerings (IDOS). It provides a unique opportunity for contributors to engage with up-and-coming tech innovations.", + 'By participating in an IDO on Bitlauncher, users can gain early access to tokens from new blockchain projects. This early access can potentially lead to significant benefits if the projects grow in value and popularity. Bitlauncher aims to democratize the investment process, making it accessible to a broader audience.', + ], + images: [ + '/images/home/platform-circles.webp', + '/images/home/platform-circles.png', + ], + articleLink: + '/blog/bitlauncher/welcome-to-the-bitlauncher-presale-starting-august-31st', + }, + { + title: 'What is the Bitlauncher ($BL) Token?', + paragraphs: [], + images: ['/images/home/bl-coins.webp', '/images/home/bl-coins.png'], + articleLink: '/blog/bitlauncher/what-is-the-bitlauncher-bl-token', + }, + { + title: 'What is a Public Token Presale?', + paragraphs: [], + images: ['/images/home/glass.webp', '/images/home/glass.png'], + articleLink: '/blog/bitlauncher/what-is-a-public-token-presale', + }, + ], +} diff --git a/apps/webapp/components/layout/footer/short-video.tsx b/apps/webapp/components/layout/section/short-video-section.tsx similarity index 100% rename from apps/webapp/components/layout/footer/short-video.tsx rename to apps/webapp/components/layout/section/short-video-section.tsx diff --git a/apps/webapp/components/layout/footer/participate.tsx b/apps/webapp/components/layout/section/steps-section.tsx similarity index 79% rename from apps/webapp/components/layout/footer/participate.tsx rename to apps/webapp/components/layout/section/steps-section.tsx index 919662aef..a3603b899 100644 --- a/apps/webapp/components/layout/footer/participate.tsx +++ b/apps/webapp/components/layout/section/steps-section.tsx @@ -8,7 +8,7 @@ import type { Lang } from '@/dictionaries/locales' import { cn } from '@/lib/utils' import Link from 'next/link' -export default function Participate({ lang, dict }: ParticipateProps) { +export default function StepsSection({ lang, dict }: StepsSectionProps) { return (
    (
    -

    +

    {step.title}

    -

    +

    {step.description}

    {index > 0 ? ( @@ -60,7 +60,7 @@ export default function Participate({ lang, dict }: ParticipateProps) { ) } -export interface ParticipateProps { +export interface StepsSectionProps { dict: any lang: Lang } diff --git a/apps/webapp/components/layout/session/register-dialog-content.tsx b/apps/webapp/components/layout/session/register-dialog-content.tsx index 342fd8466..08f2bea79 100644 --- a/apps/webapp/components/layout/session/register-dialog-content.tsx +++ b/apps/webapp/components/layout/session/register-dialog-content.tsx @@ -9,7 +9,7 @@ import { DialogTitle, } from '@/components/ui/dialog' import { useSession } from '@/hooks/use-session' -import { runtimeEnv } from 'app-lib' +import { runtimeEnv } from '@repo/utils' import { useRouter } from 'next/navigation' import QRCode from 'react-qr-code' import { useEffectOnce } from 'react-use' diff --git a/apps/webapp/components/layout/session/session-button.tsx b/apps/webapp/components/layout/session/session-button.tsx index 9c6e6d3bf..20122c545 100644 --- a/apps/webapp/components/layout/session/session-button.tsx +++ b/apps/webapp/components/layout/session/session-button.tsx @@ -7,10 +7,9 @@ import { PopoverTrigger, } from '@/components/ui/popover' import { useSession } from '@/hooks/use-session' -import { appConfig } from '@/lib/config' import { cn } from '@/lib/utils' import { useAccountModal } from '@rainbow-me/rainbowkit' -import { formatAddress } from 'app-lib' +import { formatAddress } from '@repo/utils' import { User, Wallet } from 'lucide-react' import { useRouter } from 'next/navigation' import { isMobile } from 'react-device-detect' diff --git a/apps/webapp/components/routes/about/about-bitlauncher/index.tsx b/apps/webapp/components/routes/about/about-bitlauncher/index.tsx index 096a49bae..97dff2723 100644 --- a/apps/webapp/components/routes/about/about-bitlauncher/index.tsx +++ b/apps/webapp/components/routes/about/about-bitlauncher/index.tsx @@ -1,8 +1,11 @@ +import { LearnSection } from '@/components/layout/section/learn-section' +import StepsSection from '@/components/layout/section/steps-section' import { Banner } from '@/components/shared/banner' import { CommunityCard } from '@/components/shared/community-card' import { getDictionary } from '@/dictionaries' import type { Lang } from '@/dictionaries/locales' import Image from 'next/image' +import Balancer from 'react-wrap-balancer' export async function AboutBitlauncherPageLanding({ content, @@ -12,37 +15,21 @@ export async function AboutBitlauncherPageLanding({ const dict = await getDictionary(lang) return ( <> -
    -
    +
    +
    -

    {content.title}

    -
    - Bitlauncher is a pioneering launchpad dedicated to - transforming the landscape of artificial intelligence (AI) and - cryptocurrency. We are on a mission to empower the next wave of AI - innovation by providing open-source AI projects with equitable - fundraising opportunities and decentralized organization through - the use of blockchain technology. +

    + {' '} + {content.title} +

    +
    + {content.paragraph}

    - At Bitlauncher, we{' '} - combine the transformative powers of AI and cryptocurrency{' '} - to address the unique challenges faced by AI startups. By - integrating tokenization and decentralized autonomous - organizations (DAOs), we create a seamless synergy that enables - these startups to overcome funding barriers, accelerate their - growth, and harness global resources. -
    -
    - Our platform is built on a foundation of{' '} - - transparency, inclusivity, and community-driven progress - - . We foster a collaborative environment where developers, - contributors, and AI enthusiasts can come together to share - resources, exchange ideas, and shape the future of technology. + {content.paragraph2}

    + {content.paragraph3}
    @@ -51,8 +38,10 @@ export async function AboutBitlauncherPageLanding({
    + + +
    - ) } @@ -66,7 +55,9 @@ interface Image { export interface AboutBitlauncherPageContent { title: string - description: string + paragraph: React.ReactNode + paragraph2: React.ReactNode + paragraph3: React.ReactNode image: Image } diff --git a/apps/webapp/components/routes/blog/article/index.tsx b/apps/webapp/components/routes/blog/article/index.tsx index 70a5c657a..53c507c70 100644 --- a/apps/webapp/components/routes/blog/article/index.tsx +++ b/apps/webapp/components/routes/blog/article/index.tsx @@ -1,6 +1,5 @@ import { LazyImage } from '@/components/shared/lazy-image' import { Tag } from '@/components/shared/tag' -import { Button } from '@/components/ui/button' import type { Lang } from '@/dictionaries/locales' import { readingTime } from '@/lib/blog' import { cn } from '@/lib/utils' @@ -8,7 +7,6 @@ import type { BlogArticleRecord } from '@/services/datocms' import { render as toPlainText } from 'datocms-structured-text-to-plain-text' import { isHeading, isParagraph } from 'datocms-structured-text-utils' import type { StaticImport } from 'next/dist/shared/lib/get-img-props' -import Image from 'next/image' import Link from 'next/link' import { Suspense } from 'react' import { @@ -75,180 +73,188 @@ export function BlogPage({ } }) return ( -
    -
    -
    -
    -

    - {title} -
    -

    - - {blogContent.description} - -
    +
    +
    +
    +

    + {title} +
    +

    +

    + {blogContent.description} +

    +
    -
    - - {blogContent.authorName} - - - {new Date(blogContent._publishedAt).toLocaleDateString('en-US', { - month: 'short', - day: '2-digit', - year: 'numeric', - })}{' '} - ∙ {readingTime(blogContent)} min read - +
    + + {blogContent.authorName} + + + {new Date(blogContent._publishedAt).toLocaleDateString('en-US', { + month: 'short', + day: '2-digit', + year: 'numeric', + })}{' '} + ∙ {readingTime(blogContent)} min read + -
    - {blogContent.topics?.map((topic, index) => ( - - ))} -
    +
    + {blogContent.topics?.map((topic, index) => ( + + ))}
    +
    -
    -
    - {blogContent?.contentBlock?.map( - ({ mainContent, topImages }, ind: number) => { - // if (ind >= 2) return null +
    +
    + {blogContent?.contentBlock?.map( + ({ mainContent, topImages }, ind: number) => { + // if (ind >= 2) return null - mainContent.value.document.children = - mainContent.value.document.children.map((item) => { - if (item.type !== 'paragraph') return item + mainContent.value.document.children = + mainContent.value.document.children.map((item) => { + if (item.type !== 'paragraph') return item - const sanitizedChildren = item.children?.map((child) => { - if (child.type !== 'span') return child - if (typeof child.value === 'string') return child + const sanitizedChildren = item.children?.map((child) => { + if (child.type !== 'span') return child + if (typeof child.value === 'string') return child - if (Array.isArray(child.value)) { - return { - ...child, - value: (child.value as string[]).join(' '), - } + if (Array.isArray(child.value)) { + return { + ...child, + value: (child.value as string[]).join(' '), } - return child - }) - return { ...item, children: sanitizedChildren } - }) as any + } + return child + }) + return { ...item, children: sanitizedChildren } + }) as any - // console.log(`================ ${ind} =================`) - // console.log( - // JSON.stringify(mainContent.value.document.children) - // ) - return ( -
    - {topImages.map( - ( - image: { url: string | StaticImport; alt: string }, - index, - ) => ( -
    - {/* {image?.alt */} - -
    - ), - )} -
    - {/* { mainContent.value.document.children.values} */} - { - const HeadingTag = `h${node.level}` as any - const anchor = toPlainText(node) - ?.trim() - .toLowerCase() - .replace(/ /g, '-') - .replace(/[^\w-]+/g, '') - .replace(/-$/, '') - return ( - // add types to ref and key props to satisfy React requirements - - {children} - - ) - }, - ), - renderNodeRule(isParagraph, ({ children, key }) => { + // console.log(`================ ${ind} =================`) + // console.log( + // JSON.stringify(mainContent.value.document.children) + // ) + return ( +
    + {topImages.map( + ( + image: { url: string | StaticImport; alt: string }, + index, + ) => ( +
    + {/* {image?.alt */} + +
    + ), + )} +
    + {/* { mainContent.value.document.children.values} */} + { + const HeadingTag = `h${node.level}` as any + const anchor = toPlainText(node) + ?.trim() + .toLowerCase() + .replace(/ /g, '-') + .replace(/[^\w-]+/g, '') + .replace(/-$/, '') return ( -

    + // add types to ref and key props to satisfy React requirements + {children} -

    + ) - }), - ]} - /> -
    + }, + ), + renderNodeRule(isParagraph, ({ children, key }) => { + return ( +

    + {children} +

    + ) + }), + ]} + />
    - ) - }, - )} -
    +
    + ) + }, + )} +
    -
    - +
    + -
    - - Share this article - - Loading...
    }> - - -
    +
    + + Share this article + + Loading...
    }> + +
    -
    +
    {relatedBlogs.length > 0 && ( -
    -
    +
    +
    /Related stories See All Stories >
    -
      - {relatedBlogs?.slice(0, 5).map((post) => ( +
        + {relatedBlogs?.slice(0, 5).map((post, index) => ( ))}
    )} -
    +
    ) } diff --git a/apps/webapp/components/routes/blog/blog-sections.tsx b/apps/webapp/components/routes/blog/blog-sections.tsx index ff741d476..9c233c471 100644 --- a/apps/webapp/components/routes/blog/blog-sections.tsx +++ b/apps/webapp/components/routes/blog/blog-sections.tsx @@ -39,7 +39,7 @@ export function BlogSections({
    -
    +
      {section?.articles // ?.slice(0, 4) ?.map((post, index) => ( @@ -49,9 +49,13 @@ export function BlogSections({ key={post.id + '-' + index} lang={lang} meta={true} + className={cn( + index === 3 ? 'md:hidden xl:block' : '', + index === 4 ? 'lg:hidden 2xl:block' : '', + )} /> ))} -
    +
    ), )} diff --git a/apps/webapp/components/routes/blog/category.tsx b/apps/webapp/components/routes/blog/category.tsx index e45e75c88..20f079e87 100644 --- a/apps/webapp/components/routes/blog/category.tsx +++ b/apps/webapp/components/routes/blog/category.tsx @@ -95,6 +95,10 @@ export function CategoryComponent({ params, sections }: BlogCategoryPageProps) { key={index} lang={params.lang} meta={true} + className={cn( + index === 3 ? 'md:hidden xl:block' : '', + index === 4 ? 'lg:hidden 2xl:block' : '', + )} /> ))} diff --git a/apps/webapp/components/routes/blog/hero-section/index.tsx b/apps/webapp/components/routes/blog/hero-section/index.tsx index 630c185f7..5de90017d 100644 --- a/apps/webapp/components/routes/blog/hero-section/index.tsx +++ b/apps/webapp/components/routes/blog/hero-section/index.tsx @@ -20,7 +20,7 @@ export function HeroSection({ recent, lang }: HeroSectionProps) { ), )} diff --git a/apps/webapp/components/routes/home/auction-card.tsx b/apps/webapp/components/routes/home/auction-card.tsx index 87e723b46..cf42d84ec 100644 --- a/apps/webapp/components/routes/home/auction-card.tsx +++ b/apps/webapp/components/routes/home/auction-card.tsx @@ -2,7 +2,7 @@ import type { Project } from '@/lib/projects' import { cn } from '@/lib/utils' import Image from 'next/image' import Link from 'next/link' -import React, { Suspense } from 'react' +import { Suspense } from 'react' import { isMobile } from 'react-device-detect' import Balancer from 'react-wrap-balancer' import { AuctionCardButtons } from './auction-card-buttons' @@ -29,7 +29,7 @@ export function AuctionCard({ const isFutureOrComingAuction = badgeText.match(/(FUTURE|COMING SOON)/) return ( -
    +
    {badgeText}}> - + -
    +

    {title}

    -

    {pitch}

    +

    {pitch}

      diff --git a/apps/webapp/components/routes/home/features.tsx b/apps/webapp/components/routes/home/features.tsx index 74be7116f..f8211ac30 100644 --- a/apps/webapp/components/routes/home/features.tsx +++ b/apps/webapp/components/routes/home/features.tsx @@ -29,7 +29,7 @@ export function Features({ lang, dict }: FeaturesProps) {

      {content.title}

      -

      +

      {content.description}

    diff --git a/apps/webapp/components/routes/home/hero/index.tsx b/apps/webapp/components/routes/home/hero/index.tsx index 18770ead4..1221929e3 100644 --- a/apps/webapp/components/routes/home/hero/index.tsx +++ b/apps/webapp/components/routes/home/hero/index.tsx @@ -10,12 +10,14 @@ import Image from 'next/image' import { Suspense } from 'react' import Balancer from 'react-wrap-balancer' +// ? Hero must be always minimum of 90vh and reducing it by coyunting the height of the header. +// ? This way user would be able to see a hint of the next section. export function NewHomeHero() { return ( -
    -
    +
    +
    -

    +

    EARLY ACCESS TO
    THE NEXT GLOBAL
    @@ -33,7 +35,7 @@ export function NewHomeHero() { className="relative object-contain h-[400px] w-[400px]" />

    -
    +
    { + label: string + className?: string +} + +export function MotionFigcaption({ + label, + color, + size, + className, +}: MotionFigcaptionProps) { return ( {label} diff --git a/apps/webapp/components/routes/home/why-choose-us.tsx b/apps/webapp/components/routes/home/why-choose-us.tsx index 331264efc..5b6b792ef 100644 --- a/apps/webapp/components/routes/home/why-choose-us.tsx +++ b/apps/webapp/components/routes/home/why-choose-us.tsx @@ -8,22 +8,24 @@ export function WhyChooseUs({ lang, dict }: WhyChooseUsProps) { const content = dict.whyChooseUs return (
    -
    +
      {content.features.map((feature: Feature) => { const IconComponent = Icons[feature.icon] as React.ElementType return ( - - -

      - {feature.title} -

      -

      - {feature.description} -

      -
      +
    • + + +

      + {feature.title} +

      +

      + {feature.description} +

      +
      +
    • ) })} -
    +
    ) } diff --git a/apps/webapp/components/routes/project/auction/auction-bids.tsx b/apps/webapp/components/routes/project/auction/auction-bids.tsx index 8ba02b31c..d4c2d1f0c 100644 --- a/apps/webapp/components/routes/project/auction/auction-bids.tsx +++ b/apps/webapp/components/routes/project/auction/auction-bids.tsx @@ -10,10 +10,10 @@ import { } from '@/components/ui/table' import type { ProjectWithAuction } from '@/lib/projects' import { cn } from '@/lib/utils' +import { TestnetEasyAuction, TestnetUSDCred } from '@repo/contracts' +import { toSmallestUnit } from '@repo/utils' import { readContract, writeContract } from '@wagmi/core' import { erc20Abi } from 'abitype/abis' -import { TestnetEasyAuction, TestnetUSDCred } from 'app-contracts' -import { toSmallestUnit } from 'app-lib' import { useEffect, useState } from 'react' import toast from 'react-hot-toast' import type { Address } from 'viem' diff --git a/apps/webapp/components/routes/project/auction/auction-orders.tsx b/apps/webapp/components/routes/project/auction/auction-orders.tsx index 077a35d5f..7e9952677 100644 --- a/apps/webapp/components/routes/project/auction/auction-orders.tsx +++ b/apps/webapp/components/routes/project/auction/auction-orders.tsx @@ -8,8 +8,8 @@ import { TableRow, } from '@/components/ui/table' import { useSupabaseClient } from '@/services/supabase' -import { TestnetEasyAuction } from 'app-contracts' -import { formatAddress } from 'app-lib' +import { TestnetEasyAuction } from '@repo/contracts' +import { formatAddress } from '@repo/utils' import BN from 'bn.js' import { format } from 'date-fns' import Link from 'next/link' diff --git a/apps/webapp/components/routes/project/copy-shorlink.tsx b/apps/webapp/components/routes/project/copy-shorlink.tsx index 0fc4ca3d9..1c59cfb0e 100644 --- a/apps/webapp/components/routes/project/copy-shorlink.tsx +++ b/apps/webapp/components/routes/project/copy-shorlink.tsx @@ -1,21 +1,17 @@ 'use client' -import { AnimatePresence } from 'framer-motion' -import { LucideCheck, LucideLoader2, LucideShare, LucideX } from 'lucide-react' -import { useState } from 'react' - import { generateShortLink } from '@/actions' import { useSession } from '@/hooks/use-session' import { useSupabaseClient } from '@/services/supabase/client' -import { uniq } from 'lodash' +import { AnimatePresence } from 'framer-motion' +import { LucideCheck, LucideLoader2, LucideShare, LucideX } from 'lucide-react' import { useParams } from 'next/navigation' -import { useAccount } from 'wagmi' +import { useState } from 'react' export function CopyShortlinkIcon() { const [status, setStatus] = useState< 'default' | 'loading' | 'copied' | 'error' >('default') const { session } = useSession() - const { address } = useAccount() const supabase = useSupabaseClient() const existingParams = useParams() // Get existing query parameters const param = session @@ -24,11 +20,10 @@ export function CopyShortlinkIcon() { const checkShareLink = async () => { const { data, error } = await supabase - .from('user') + .from('account') // select shareLink from user where linkPath = 'https://bitlauncher.ai${window.location.pathname}${param}' - .select('id, account, address, short_link') + .select('account, short_link') .eq('account', session?.account || '') - .contains('address', [address || '']) .single() if (error) { @@ -43,27 +38,19 @@ export function CopyShortlinkIcon() { if (!data.short_link) { const { data: dubCoShortLink, error: dubCoError } = await generateShortLink( - 'https://bitlauncher.ai' + window.location.pathname + param, + `https://bitlauncher.ai${window.location.pathname}${param}`, ) if (dubCoError) { - console.error('❌ Failed to check share link:', dubCoError) + console.error('❌ Failed to generate short link:', dubCoError) setStatus('error') return { data: null, error: dubCoError } } - // ? Doing upsert (account, address) for current users with active sessions - const updatedAddresses = [ - ...(data?.address.length - ? [...data?.address, address as string] - : [address as string]), - ] - await supabase.from('user').upsert( + await supabase.from('account').upsert( { - id: data.id, account: session?.account || '', - address: uniq(updatedAddresses), short_link: dubCoShortLink?.shortLink, }, { @@ -97,6 +84,8 @@ export function CopyShortlinkIcon() { return (
    ) } - -const tokens = - appConfig.env === 'dev' ? ['USDT', 'BITUSD'] : ['USDT', 'USDC', 'BITUSD'] diff --git a/apps/webapp/components/routes/project/presale/presale-transactions-card.tsx b/apps/webapp/components/routes/project/presale/presale-transactions-card.tsx index f071a13bc..34e9b21bd 100644 --- a/apps/webapp/components/routes/project/presale/presale-transactions-card.tsx +++ b/apps/webapp/components/routes/project/presale/presale-transactions-card.tsx @@ -15,13 +15,10 @@ import { TableHeader, TableRow, } from '@/components/ui/table' -import { appConfig } from '@/lib/config' import { useSupabaseClient } from '@/services/supabase' import type { Tables } from '@repo/supabase' -import { formatAddress } from 'app-lib' import { useEffect, useState } from 'react' import { useAccount } from 'wagmi' -import { TestnetBLPL } from '../../../../../../packages/app-contracts/src/dev/tokens/testnet-blpl' export function PresaleTransactionsCard() { const { address } = useAccount() @@ -77,18 +74,18 @@ export function PresaleTransactionsCard() { ...prev, ]) } else if (payload.eventType === 'UPDATE') { - setTransactions((prev) => - prev - .map((t) => + setTransactions( + (prev) => + prev.map((t) => t.trx_hash === payload.new.trx_hash ? (payload.new as Tables<'transfer'>) : t, - ) - .sort( - (a, b) => - new Date(b.created_at).getTime() - - new Date(a.created_at).getTime(), ), + // .sort( + // (a, b) => + // new Date(b.created_at).getTime() - + // new Date(a.created_at).getTime(), + // ), ) } else if (payload.eventType === 'DELETE') { setTransactions((prev) => @@ -157,59 +154,60 @@ export function PresaleTransactionsCard() { } function TransactionRow({ transaction }: { transaction: Tables<'transfer'> }) { - const chain = transaction.chain_id - ? appConfig.chains.get(transaction.chain_id) - : null - return ( - - -
    - {formatAddress(transaction.from ?? '')} -
    -
    + return <> + // const chain = transaction.chain_id + // ? appConfig.chains.get(transaction.chain_id) + // : null + // return ( + // + // + //
    + // {formatAddress(transaction.from ?? '')} + //
    + //
    - - {transaction.amount !== null - ? (transaction.amount / 1000000).toFixed(6) - : 'N/A'} - + // + // {transaction.amount !== null + // ? (transaction.amount / 1000000).toFixed(6) + // : 'N/A'} + // - - {chain?.blockExplorers?.default ? ( - - {formatAddress(transaction.trx_hash)} - - ) : ( - formatAddress(transaction.trx_hash) - )} - + // + // {chain?.blockExplorers?.default ? ( + // + // {formatAddress(transaction.trx_hash)} + // + // ) : ( + // formatAddress(transaction.trx_hash) + // )} + // - - {TestnetBLPL.chain?.blockExplorers?.default && - transaction.bl_presale_trx ? ( - - {formatAddress(transaction.bl_presale_trx)} - - ) : transaction.bl_presale_trx ? ( - formatAddress(transaction.bl_presale_trx) - ) : ( - 'pending' - )} - - - {new Date(transaction.created_at).toLocaleDateString()} - - {chain?.name} -
    - ) + // + // {TestnetBLPL.chain?.blockExplorers?.default && + // transaction.bl_presale_trx ? ( + // + // {formatAddress(transaction.bl_presale_trx)} + // + // ) : transaction.bl_presale_trx ? ( + // formatAddress(transaction.bl_presale_trx) + // ) : ( + // 'pending' + // )} + // + // + // {new Date(transaction.created_at).toLocaleDateString()} + // + // {chain?.name} + //
    + // ) } diff --git a/apps/webapp/components/routes/project/project-header.tsx b/apps/webapp/components/routes/project/project-header.tsx index 423a43160..d2498deee 100644 --- a/apps/webapp/components/routes/project/project-header.tsx +++ b/apps/webapp/components/routes/project/project-header.tsx @@ -30,7 +30,7 @@ export function ProjectHeader({ {project.pitch} {project.title.toUpperCase()} diff --git a/apps/webapp/components/routes/project/project-pills.tsx b/apps/webapp/components/routes/project/project-pills.tsx index 55bc08217..fa0f485e3 100644 --- a/apps/webapp/components/routes/project/project-pills.tsx +++ b/apps/webapp/components/routes/project/project-pills.tsx @@ -24,7 +24,7 @@ export function ProjectPills({ project }: { project: Project }) { ] return ( -
    +
    {links.map((l, index) => (
    ) } diff --git a/apps/webapp/components/shared/content.tsx b/apps/webapp/components/shared/content.tsx index 259fcd699..53aa35cb4 100644 --- a/apps/webapp/components/shared/content.tsx +++ b/apps/webapp/components/shared/content.tsx @@ -20,7 +20,7 @@ export function PageContent({ data }: { data: PageContentData }) { > {item.text} -
    +
    ) diff --git a/apps/webapp/components/shared/countdown.tsx b/apps/webapp/components/shared/countdown.tsx index ddeb85279..d8b3f7d1d 100644 --- a/apps/webapp/components/shared/countdown.tsx +++ b/apps/webapp/components/shared/countdown.tsx @@ -1,9 +1,12 @@ 'use client' -import { useEffect, useState } from 'react' +import { differenceInSeconds } from 'date-fns'; +import { useEffect, useState } from 'react'; -export function Countdown() { - const targetDate = new Date('July 30, 2024') +export function Countdown({ + targetDate, + heading, +}: { targetDate: Date; heading: string }) { const [timeLeft, setTimeLeft] = useState({ days: '00', hours: '00', @@ -14,39 +17,36 @@ export function Countdown() { useEffect(() => { const interval = setInterval(() => { const now = new Date() - const timeDiff = targetDate.getTime() - now.getTime() + const timeDiff = differenceInSeconds(targetDate, now) if (timeDiff > 0) { - const days = Math.floor(timeDiff / (1000 * 60 * 60 * 24)) + const days = Math.floor(timeDiff / (24 * 60 * 60)) .toString() .padStart(2, '0') - const hours = Math.floor( - (timeDiff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60), - ) + const hours = Math.floor((timeDiff % (24 * 60 * 60)) / (60 * 60)) .toString() .padStart(2, '0') - const minutes = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60)) - .toString() - .padStart(2, '0') - const seconds = Math.floor((timeDiff % (1000 * 60)) / 1000) + const minutes = Math.floor((timeDiff % (60 * 60)) / 60) .toString() .padStart(2, '0') + const seconds = (timeDiff % 60).toString().padStart(2, '0') setTimeLeft({ days, hours, minutes, seconds }) } else { clearInterval(interval) + setTimeLeft({ days: '00', hours: '00', minutes: '00', seconds: '00' }) } }, 1000) return () => clearInterval(interval) - }, []) + }, [targetDate]) return (

    {/* */} - Pre-Sale Countdown + {heading}

    diff --git a/apps/webapp/components/shared/media-card.tsx b/apps/webapp/components/shared/media-card.tsx index 41a52bcf5..4082dd4a1 100644 --- a/apps/webapp/components/shared/media-card.tsx +++ b/apps/webapp/components/shared/media-card.tsx @@ -1,6 +1,6 @@ import { VideoDialog } from '@/components/dialogs/video-dialog' import { Card, CardContent } from '@/components/ui/card' -import { cn } from '@/lib/utils' // Import the utility function +import { cn } from '@/lib/utils'; // Import the utility function import type { YouTubePlaylistItem } from '@/services/youtube/index' import type { LangProp } from '@/types/routing.type' import Image from 'next/image' @@ -12,30 +12,27 @@ export function MediaCard({ video, lang, className }: MediaCardProps) { lang={lang} video={video} trigger={ - -
    -
    - {video.snippet.title} -
    -
    - -

    - {video.snippet.title} -

    -
    -
    +
  • + +
    +
    + {video.snippet.title} +
    +
    + +

    + {video.snippet.title} +

    +
    +
    +
  • } /> ) diff --git a/apps/webapp/components/shared/media-sections.tsx b/apps/webapp/components/shared/media-sections.tsx index a70c42403..721ad2c59 100644 --- a/apps/webapp/components/shared/media-sections.tsx +++ b/apps/webapp/components/shared/media-sections.tsx @@ -13,7 +13,7 @@ export function MediaSections({ sections, lang }: MediaSectionsProps) { section?.videos?.length > 0 && (
    - + / {section.title}
    -
      +
        {section?.videos?.map((video, index) => ( = 2 && 'hidden sm:block', - index >= 4 && 'md:block', - index >= 5 && 'xl:block', + index === 3 ? 'md:hidden xl:block' : '', + index >= 4 && 'md:block lg:hidden 2xl:block', )} /> ))} diff --git a/apps/webapp/components/shared/section.tsx b/apps/webapp/components/shared/section.tsx index e562e17d1..14e6da22f 100644 --- a/apps/webapp/components/shared/section.tsx +++ b/apps/webapp/components/shared/section.tsx @@ -4,10 +4,10 @@ import Balancer from 'react-wrap-balancer' export function Section({ heading, children }: SectionProps) { return (
        -

        +

        {heading}

        -
        +
        {children}
        ) diff --git a/apps/webapp/components/ui/dropdown-menu.tsx b/apps/webapp/components/ui/dropdown-menu.tsx index ab65fc3cf..bc1f888fe 100644 --- a/apps/webapp/components/ui/dropdown-menu.tsx +++ b/apps/webapp/components/ui/dropdown-menu.tsx @@ -171,7 +171,7 @@ const DropdownMenuShortcut = ({ return ( , - ) => - identify({ - address, - properties, - }) + ) => identify(address, properties) const trackInteraction = ( label: string, diff --git a/apps/webapp/hooks/use-place-order.ts b/apps/webapp/hooks/use-place-order.ts index 6b5202d37..8beea7486 100644 --- a/apps/webapp/hooks/use-place-order.ts +++ b/apps/webapp/hooks/use-place-order.ts @@ -1,4 +1,4 @@ -import { TestnetEasyAuction } from 'app-contracts' +import { TestnetEasyAuction } from '@repo/contracts' import { Address } from 'viem' import { useWriteContract } from 'wagmi' diff --git a/apps/webapp/hooks/use-session.tsx b/apps/webapp/hooks/use-session.tsx index ed603ed21..f6224d6d8 100644 --- a/apps/webapp/hooks/use-session.tsx +++ b/apps/webapp/hooks/use-session.tsx @@ -6,11 +6,9 @@ import { useSupabaseClient } from '@/services/supabase' import { createContextHook } from '@blockmatic/hooks-utils' import { useConnectModal } from '@rainbow-me/rainbowkit' import type { Tables } from '@repo/supabase' -import { uniq } from 'lodash' import { usePathname, useRouter, useSearchParams } from 'next/navigation' import React, { type ReactNode, useEffect, useState } from 'react' import { isMobile } from 'react-device-detect' -import toast from 'react-hot-toast' import { useAsync, useLocalStorage, useToggle } from 'react-use' import { v4 as uuidv4 } from 'uuid' import { type Config, type UseAccountReturnType, useAccount } from 'wagmi' @@ -53,41 +51,25 @@ function useSessionFn() { console.log('🔐 verifyAccount') let user - const updatedAddresses = [] try { user = await supabase - .from('user') - .select('id, address') + .from('account') + .select('account') .eq('account', session.account) .single() - updatedAddresses.push( - ...(user?.data?.address.length - ? [...user?.data?.address, account.address as string] - : [account.address as string]), - ) } catch (error) { console.error('🔐 verifyAccount error', error) } - await supabase.from('user').upsert( + await supabase.from('account').upsert( { - id: user?.data?.id, account: session.account, - address: uniq(updatedAddresses.filter(Boolean)), }, { onConflict: 'account', }, ) - - // * If the address is new, we show the toaster. - if ( - account.address && - !user?.data?.address.includes(account.address as string) - ) { - toast('Address linked successfully!', { icon: '🔗' }) - } } useEffect(() => { diff --git a/apps/webapp/lib/config.ts b/apps/webapp/lib/config.ts index 4b1783b74..34fa1fe55 100644 --- a/apps/webapp/lib/config.ts +++ b/apps/webapp/lib/config.ts @@ -6,7 +6,7 @@ export const appConfig = { env, eosRpc: 'https://eos.greymass.com', multibase: { - key: process.env.MULTIBASE_API_KEY || '', + key: process.env.NEXT_PUBLIC_MULTIBASE_API_KEY || '', }, features: { enableWalletAccess: diff --git a/apps/webapp/lib/projects.ts b/apps/webapp/lib/projects.ts index 88a56e206..dec4e1a0d 100644 --- a/apps/webapp/lib/projects.ts +++ b/apps/webapp/lib/projects.ts @@ -1,4 +1,4 @@ -import { TestnetMBOTSPL, type TokenContractData } from 'app-contracts' +import { TestnetMBOTSPL, type TokenContractData } from '@repo/contracts' import { merge } from 'lodash' import type { StaticImageData } from 'next/image' import BitcashPic from '../assets/img/bitcash.webp' @@ -27,6 +27,7 @@ export const projects: Project[] = [ twitterUsername: 'bitcashorg', telegramGroup: 'bitlauncher', discordServer: 'KuR48XUxnG', + presaleId: 1, // in database }, { id: 2, @@ -94,6 +95,7 @@ export interface Project { presaleOpen?: boolean registrationOpen?: boolean auctionClosed?: boolean + presaleId?: number } export interface ContentSection { diff --git a/apps/webapp/package.json b/apps/webapp/package.json index 66c8dd0d1..3b096a2ad 100644 --- a/apps/webapp/package.json +++ b/apps/webapp/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "launchpad-webapp", - "version": "1.0.0", + "version": "1.1.0", "scripts": { "dev": "rm -rf .next && next dev --turbo", "build": "next build", @@ -14,6 +14,7 @@ "type-check:watch": "tsc --noEmit -w", "translate": "bun run scripts/translate.ts", "translate:category": "bun run scripts/translate-category.ts", + "gen-cms": "bun run scripts/gen-cms.ts", "vercel:install": "npm i -g node-gyp; bun install" }, "dependencies": { @@ -24,7 +25,7 @@ "@genql/runtime": "^2.10.0", "@headlessui/react": "^2.1.2", "@hookform/resolvers": "^3.9.0", - "@multibase/js": "^0.1.15", + "@multibase/js": "latest", "@next/bundle-analyzer": "^14.2.5", "@next/env": "14.2.5", "@next/third-parties": "latest", @@ -40,9 +41,11 @@ "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.2", "@rainbow-me/rainbowkit": "2.x", + "@repo/contracts": "workspace:*", + "@repo/tokens": "workspace:*", + "@repo/utils": "workspace:*", "@supabase/ssr": "^0.4.0", "@supabase/supabase-js": "^2.44.4", - "@tailwindcss/typography": "0.5.13", "@tanstack/react-query": "^5.51.11", "@vercel/analytics": "^1.3.1", "@vercel/og": "^0.6.2", @@ -50,6 +53,7 @@ "@wagmi/connectors": "5.0.26", "@wharfkit/antelope": "^1.0.8", "ai": "^3.2.35", + "app-env": "workspace:*", "axios": "^1.7.2", "camelize-ts": "^3.0.0", "class-variance-authority": "^0.7.0", @@ -67,6 +71,7 @@ "next": "14.2.5", "next-share": "^0.27.0", "next-themes": "^0.3.0", + "nookies": "^2.5.2", "pako": "^2.1.0", "pino-pretty": "^11.2.1", "react": "18.x", @@ -84,18 +89,15 @@ "resend": "^3.5.0", "server-only": "^0.0.1", "sharp": "^0.33.4", - "app-contracts": "workspace:*", - "app-env": "workspace:*", - "app-lib": "workspace:*", "uuid": "^10.0.0", "vconsole": "^3.15.1", "vercel": "^35.1.0", "viem": "latest", "wagmi": "2.9.3", - "zod": "^3.23.8", - "nookies": "^2.5.2" + "zod": "^3.23.8" }, "devDependencies": { + "@genql/cli": "^6.3.3", "@tailwindcss/typography": "^0.5.13", "@types/lodash": "^4.17.7", "@types/negotiator": "^0.6.3", diff --git a/apps/webapp/scripts/cms-ql.sh b/apps/webapp/scripts/cms-ql.sh new file mode 100755 index 000000000..f1129deeb --- /dev/null +++ b/apps/webapp/scripts/cms-ql.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +# cms-ql.sh: Utility script for generating GraphQL types +# Usage: ./cms-ql.sh +# Dependencies: GraphQL schema must be properly configured +# eval $(grep '^NEXT_PUBLIC_CMS_GRAPHQL_API' ./.env) && genql --endpoint $NEXT_PUBLIC_CMS_GRAPHQL_API --output ./graphql/generated/cms -H 'content-type: application/json' +# eval $(grep '^NEXT_PUBLIC_CMS_GRAPHQL_API' ./.env) && eval $(grep '^NEXT_PUBLIC_CMS_API_KEY' ./.env) && genql --endpoint $NEXT_PUBLIC_GRAPHQL_API --output ./graphql/generated/cms -H 'content-type: application/json' -H 'Authorization: Bearer $NEXT_PUBLIC_CMS_API_KEY' +eval $(grep '^NEXT_PUBLIC_CMS_GRAPHQL_API' ./.env) && \ +eval $(grep '^NEXT_PUBLIC_CMS_API_KEY' ./.env) && \ +npx --verbose genql --endpoint $NEXT_PUBLIC_CMS_GRAPHQL_API \ +--output ./services/datocms/graphql/generated/cms \ +-H 'content-type: application/json' \ +-H "'Authorization: Bearer $NEXT_PUBLIC_CMS_API_KEY'" \ No newline at end of file diff --git a/apps/webapp/scripts/translate.ts b/apps/webapp/scripts/translate.ts index 932c30317..eb24fa969 100644 --- a/apps/webapp/scripts/translate.ts +++ b/apps/webapp/scripts/translate.ts @@ -1,4 +1,3 @@ -import * as path from 'path' import { type Lang, locales } from '@/dictionaries/locales' import { promiseAllWithConcurrencyLimit } from '@/lib/utils' import { anthropicTranslate } from '@/services/anthropic' @@ -9,9 +8,10 @@ import { extractTitleAndDescriptionNested, injectTextAfterTranslation, } from '@/services/datocms/translation/utils' -import { getErrorMessage } from 'app-lib' +import { getErrorMessage } from '@repo/utils' import * as fs from 'fs/promises' import _ from 'lodash' +import * as path from 'path' async function processFile( file: string, diff --git a/apps/webapp/services/datocms/datacms-blog-category.service.ts b/apps/webapp/services/datocms/datacms-blog-category.service.ts index fb6cbd927..9d943ee09 100644 --- a/apps/webapp/services/datocms/datacms-blog-category.service.ts +++ b/apps/webapp/services/datocms/datacms-blog-category.service.ts @@ -6,6 +6,7 @@ import type { BlogBitcashRecord, BlogBitcoinModelFilter, BlogBitcoinRecord, + BlogBitlauncherRecord, BlogCryptoModelFilter, BlogInvestingRecord, BlogNewsModelFilter, @@ -55,6 +56,9 @@ export async function getBlogCategory( case 'bitcash': categoryRecordName = 'allBlogBitcashes' break + case 'bitlauncher': + categoryRecordName = 'allBlogBitlaunchers' + break case 'ai-research': categoryRecordName = 'allResearchAis' break @@ -121,10 +125,10 @@ export async function getBlogCategory( throw new Error('No records has been found for ' + category) } } catch (err) { - // console.log( - // 'datocms-blog-category.service::getBlogCategory::[ERROR]:: ' + category, - // err - // ) + console.log( + 'datocms-blog-category.service::getBlogCategory::[ERROR]:: ' + category, + err, + ) error = (err as Error).message } finally { @@ -419,6 +423,53 @@ export async function getBlogCategories(): Promise { }, }, + allBlogBitlaunchers: { + __args: { + orderBy: ['_publishedAt_DESC'], + locale: 'en', + fallbackLocales: ['en'], + }, + id: true, + topics: true, + title: true, + slug: true, + authorName: true, + authorPicture: { + url: true, + }, + _publishedAt: true, + description: true, + thumbnail: { + url: true, + }, + contentBlock: { + mainContent: { + value: true, + }, + topImages: { + basename: true, + height: true, + width: true, + filename: true, + format: true, + alt: true, + url: true, + }, + }, + seo: { + description: true, + title: true, + twitterCard: true, + image: { + width: true, + height: true, + title: true, + alt: true, + url: true, + }, + }, + }, + allBlogBitcashes: { __args: { orderBy: ['_publishedAt_DESC'], @@ -525,6 +576,7 @@ export async function getBlogCategories(): Promise { allBlogStartups: [defaultBlogArticle], allBlogAis: [defaultBlogArticle], allBlogNews: [defaultBlogArticle], + allBlogBitlaunchers: [defaultBlogArticle], allBlogBitcashes: [defaultBlogArticle], allResearchAis: [defaultBlogArticle], } @@ -609,6 +661,7 @@ export interface BlogArticleRecord { id: | BlogAiRecord['id'] | BlogNewsRecord['id'] + | BlogBitlauncherRecord['id'] | BlogBitcashRecord['id'] | BlogBitcoinRecord['id'] | BlogStartupRecord['id'] @@ -637,6 +690,7 @@ export interface getBlogCategoriesTypes { allBlogStartups: BlogArticleRecord[] allBlogAis: BlogArticleRecord[] allBlogNews: BlogArticleRecord[] + allBlogBitlaunchers: BlogArticleRecord[] allBlogBitcashes: BlogArticleRecord[] allResearchAis: BlogArticleRecord[] } diff --git a/apps/webapp/services/datocms/datocms-all-articles.service.ts b/apps/webapp/services/datocms/datocms-all-articles.service.ts index 0e2ddb6d3..204264a03 100644 --- a/apps/webapp/services/datocms/datocms-all-articles.service.ts +++ b/apps/webapp/services/datocms/datocms-all-articles.service.ts @@ -85,6 +85,7 @@ const categoryMap: Record = { ai: 'allBlogAis', news: 'allBlogNews', bitcash: 'allBlogBitcashes', + bitlauncher: 'allBlogBitlaunchers', 'ai-research': 'allResearchAis', } diff --git a/apps/webapp/services/datocms/datocms-blog.service.ts b/apps/webapp/services/datocms/datocms-blog.service.ts index e2d753cb2..a15a389cd 100644 --- a/apps/webapp/services/datocms/datocms-blog.service.ts +++ b/apps/webapp/services/datocms/datocms-blog.service.ts @@ -1,9 +1,9 @@ -import * as fs from 'fs' -import path from 'path' import type { Lang } from '@/dictionaries/locales' import { getFilePath, parseFile } from '@/lib/file' -import { getErrorMessage } from 'app-lib' +import { getErrorMessage } from '@repo/utils' +import * as fs from 'fs' import { uniq } from 'lodash' +import path from 'path' import { type BlogArticleRecord, getBlogCategory, @@ -21,9 +21,10 @@ export const getBlogData = async () => { { investingData, investingError }, { startupData, startupError }, { aiData, aiError }, - { newsData, newsError }, + // { newsData, newsError }, { bitcashData, bitcashError }, { aiResearchData, researchError }, + { bitlauncherData, bitlauncherError }, ] = await Promise.all([ getLayoutText(), getPageSeoText('home'), @@ -32,9 +33,10 @@ export const getBlogData = async () => { getBlogCategory('investing', undefined, 5), getBlogCategory('startup', undefined, 5), getBlogCategory('ai', undefined, 5), - getBlogCategory('news', undefined, 5), + // getBlogCategory('news', undefined, 5), getBlogCategory('bitcash', undefined, 5), getBlogCategory('ai-research', undefined, 5), + getBlogCategory('bitlauncher', undefined, 5), ]) return { i18n, @@ -49,12 +51,14 @@ export const getBlogData = async () => { startupError, aiData, aiError, - newsData, - newsError, + // newsData, + // newsError, bitcashData, bitcashError, aiResearchData, researchError, + bitlauncherError, + bitlauncherData, } } @@ -64,33 +68,41 @@ export async function getArticleSections( const dirPath = `/dictionaries/${lang}/blog/` const fileName = `blog-index.json` const filePath = path.resolve(dirPath, fileName) - // return cached translations + let fileContents: { sections: ArticlesSection[] } | undefined + // return cached translations try { - const fileContents = parseFile(filePath) - return fileContents.sections + // ? The idea is to get the file contents and return it if it exists and it should be up to date with the latest on DatoCMS, so we can reduce the amount of requests to DatoCMS + fileContents = parseFile(filePath) + // ? Due we are not updating the file contents frequently, we can return the file contents directly + // console.info('in', process.env.NODE_ENV) + if (process.env.NODE_ENV === 'production') { + return fileContents?.sections as ArticlesSection[] + } } catch (error) { - // console.log('😬 translation not found', getErrorMessage(error)) + console.log('😬 translation not found', getErrorMessage(error)) try { + console.log('😬 trying english version', { dirPath, filePath, fileName }) const englishVersion = parseFile(`/dictionaries/en/blog/${fileName}`) if (englishVersion) { - // console.log('😬 returning english version') + console.log('😬 returning english version') return englishVersion.sections } } catch (error) { - console.log('❌ error', error) - return [] + console.error('❌ Failed to get cached file. Fetching new data', error) } } + const { bitcoinData, cryptoData, investingData, startupData, aiData, - newsData, + // newsData, bitcashData, aiResearchData, + bitlauncherData, } = await getBlogData() const sections: ArticlesSection[] = [ @@ -104,10 +116,15 @@ export async function getArticleSections( slug: 'ai-research', articles: (aiResearchData?.slice(0, 4) || []) as BlogArticleRecord[], }, + // { + // name: 'News', + // slug: 'news', + // articles: (newsData?.slice(0, 4) || []) as BlogArticleRecord[], + // }, { - name: 'News', - slug: 'news', - articles: (newsData?.slice(0, 4) || []) as BlogArticleRecord[], + name: 'Bitlauncher', + slug: 'bitlauncher', + articles: (bitlauncherData?.slice(0, 4) || []) as BlogArticleRecord[], }, { name: 'Bitcash', @@ -142,10 +159,37 @@ export async function getArticleSections( }) }) - fs.mkdirSync(dirPath, { recursive: true }) - fs.writeFileSync(filePath, JSON.stringify({ sections }, null, 2)) + // Check file sections against new sections. If no section found on files, then we update the sections + const fileSections = fileContents?.sections || [] + const updatedSections = sections.map((section) => { + const fileSection = fileSections?.find( + (fs) => + fs.name === section.name && + fs.articles[0]._publishedAt === section.articles[0]._publishedAt, + ) + if (fileSection) { + return fileSection + } + return section + }) + fileContents = { + sections: updatedSections, + } - return sections + // TODO: Fix cache file update on production build. + // ! It's not updating the file and we might choose to add cache to the user's browser instead. + // ? Or moving this to actions.ts + try { + fs.mkdirSync(getFilePath(dirPath), { recursive: true }) + fs.writeFileSync( + getFilePath(filePath), + JSON.stringify(fileContents, null, 2), + ) + } catch (error) { + console.error('❌❌❌❌ Failed to update cache on file.', error) + } + + return sections as ArticlesSection[] } export async function getRecentArticleSections(): Promise { @@ -155,7 +199,7 @@ export async function getRecentArticleSections(): Promise { investingData, startupData, aiData, - newsData, + // newsData, bitcashData, aiResearchData, } = await getBlogData() @@ -199,19 +243,26 @@ export async function getBlogCategoryLandingData(lang: Lang, category: string) { const filePath = path.resolve(dirPath, fileName) // console.log('getBlogCategoryLandingData', { dirPath, filePath }) + let fileContents: { sections: ArticlesSection[] } | undefined // return cached translations try { - const fileContents = parseFile(filePath) - return fileContents + // ? The idea is to get the file contents and return it if it exists and it should be up to date with the latest on DatoCMS, so we can reduce the amount of requests to DatoCMS + fileContents = parseFile(filePath) + // ? Due we are not updating the file contents frequently, we can return the file contents directly + // console.info('in', process.env.NODE_ENV) + if (process.env.NODE_ENV === 'production') { + return fileContents?.sections as ArticlesSection[] + } } catch (error) { // console.log('error', error) try { const englishVersion = parseFile( `/dictionaries/en/blog/${category}/${fileName}`, ) - if (englishVersion) return englishVersion - } catch (error) {} + } catch (error) { + console.error('❌ Failed to get cached file. Fetching new data', error) + } } // replacing category kebab case with camel case @@ -250,10 +301,37 @@ export async function getBlogCategoryLandingData(lang: Lang, category: string) { } }) - const result = { sections, pageSeo } + // Check file sections against new sections. If no section found on files, then we update the sections + const fileSections = fileContents?.sections || [] + const updatedSections = sections.map((section) => { + const fileSection = fileSections?.find( + (fs) => + fs.name === section.name && + fs.articles[0]._publishedAt === section.articles[0]._publishedAt, + ) + if (fileSection) { + return fileSection + } + return section + }) + fileContents = { + sections: updatedSections, + } + + const result = { + sections: fileContents?.sections as ArticlesSection[], + pageSeo, + } - fs.mkdirSync(getFilePath(dirPath), { recursive: true }) - fs.writeFileSync(getFilePath(filePath), JSON.stringify(result, null, 2)) + // TODO: Fix cache file update on production build. + // ! It's not updating the file and we might choose to add cache to the user's browser instead. + // ? Or moving this to actions.ts + try { + fs.mkdirSync(getFilePath(dirPath), { recursive: true }) + fs.writeFileSync(getFilePath(filePath), JSON.stringify(result, null, 2)) + } catch (error) { + console.error('❌❌❌❌ Failed to update cache on file.', error) + } return result } @@ -269,19 +347,29 @@ export async function getBlogArticleData( category: string, slug: string, ) { - const dirPath = `dictionaries/${lang}/blog/${category}` + const dirPath = `/dictionaries/${lang}/blog/${category}` const fileName = `${slug}.json` const filePath = path.resolve(dirPath, fileName) + let fileContents: BlogArticleData | undefined // return cached translations try { - const fileContents: BlogArticleData = parseFile(filePath) - return fileContents + // ? The idea is to get the file contents and return it if it exists and it should be up to date with the latest on DatoCMS, so we can reduce the amount of requests to DatoCMS + fileContents = parseFile(filePath) + // ? Due we are not updating the file contents frequently, we can return the file contents directly + // console.info('in', process.env.NODE_ENV) + if (process.env.NODE_ENV === 'production') { + return fileContents as BlogArticleData + } } catch (error) { - const englishVersion: BlogArticleData = parseFile( - `/dictionaries/en/blog/${category}/${slug}.json`, - ) - if (englishVersion) return englishVersion + try { + const englishVersion: BlogArticleData = parseFile( + `/dictionaries/en/blog/${category}/${slug}.json`, + ) + if (englishVersion) return englishVersion + } catch (error) { + console.error('❌ Failed to get cached file. Fetching new data', error) + } } // console.log('getBlogArticleData', { locale, category, slug }) @@ -342,8 +430,27 @@ export async function getBlogArticleData( // always create an english dictionary const result: BlogArticleData = { relatedBlogs, blogContent, topics } const fullPath = getFilePath(filePath) - fs.mkdirSync(path.dirname(fullPath), { recursive: true }) - fs.writeFileSync(fullPath, JSON.stringify(result, null, 2)) + + if (fileContents?.blogContent) { + // Check file article against new article. If no updated found on files, then we update the article + const fileArticle = fileContents + if ( + fileArticle.blogContent.title === blogContent.title && + fileArticle.blogContent._publishedAt === blogContent._publishedAt + ) { + return fileArticle + } + } + + // TODO: Fix cache file update on production build. + // ! It's not updating the file and we might choose to add cache to the user's browser instead. + // ? Or moving this to actions.ts + try { + fs.mkdirSync(getFilePath(dirPath), { recursive: true }) + fs.writeFileSync(getFilePath(filePath), JSON.stringify(result, null, 2)) + } catch (error) { + console.error('❌❌❌❌ Failed to update cache on file.', error) + } return result } diff --git a/apps/webapp/services/datocms/graphql/generated/cms/runtime/batcher.ts b/apps/webapp/services/datocms/graphql/generated/cms/runtime/batcher.ts index fe256ec92..622d6018e 100644 --- a/apps/webapp/services/datocms/graphql/generated/cms/runtime/batcher.ts +++ b/apps/webapp/services/datocms/graphql/generated/cms/runtime/batcher.ts @@ -1,5 +1,5 @@ -// @ts-nocheck import { GenqlError } from './error' +// @ts-nocheck import type { GraphqlOperation } from './generateGraphqlOperation' type Variables = Record @@ -46,28 +46,41 @@ function dispatchQueueBatch(client: QueryBatcher, queue: Queue): void { if (batchedQuery.length === 1) { batchedQuery = batchedQuery[0] } + ;(() => { + try { + return client.fetcher(batchedQuery) + } catch (e) { + return Promise.reject(e) + } + })() + .then((responses: any) => { + if (queue.length === 1 && !Array.isArray(responses)) { + if (responses.errors && responses.errors.length) { + queue[0].reject(new GenqlError(responses.errors, responses.data)) + return + } - client.fetcher(batchedQuery).then((responses: any) => { - if (queue.length === 1 && !Array.isArray(responses)) { - if (responses.errors && responses.errors.length) { - queue[0].reject(new GenqlError(responses.errors, responses.data)) + queue[0].resolve(responses) return + } else if (responses.length !== queue.length) { + throw new Error('response length did not match query length') } - queue[0].resolve(responses) - return - } else if (responses.length !== queue.length) { - throw new Error('response length did not match query length') - } - - for (let i = 0; i < queue.length; i++) { - if (responses[i].errors && responses[i].errors.length) { - queue[i].reject(new GenqlError(responses[i].errors, responses[i].data)) - } else { - queue[i].resolve(responses[i]) + for (let i = 0; i < queue.length; i++) { + if (responses[i].errors && responses[i].errors.length) { + queue[i].reject( + new GenqlError(responses[i].errors, responses[i].data), + ) + } else { + queue[i].resolve(responses[i]) + } } - } - }) + }) + .catch((e) => { + for (let i = 0; i < queue.length; i++) { + queue[i].reject(e) + } + }) } /** diff --git a/apps/webapp/services/datocms/graphql/generated/cms/runtime/fetcher.ts b/apps/webapp/services/datocms/graphql/generated/cms/runtime/fetcher.ts index d48b03f3e..d8cdd93cc 100644 --- a/apps/webapp/services/datocms/graphql/generated/cms/runtime/fetcher.ts +++ b/apps/webapp/services/datocms/graphql/generated/cms/runtime/fetcher.ts @@ -1,5 +1,6 @@ // @ts-nocheck import { QueryBatcher } from './batcher' + import type { ClientOptions } from './createClient' import { GenqlError } from './error' import type { GraphqlOperation } from './generateGraphqlOperation' diff --git a/apps/webapp/services/datocms/graphql/generated/cms/schema.graphql b/apps/webapp/services/datocms/graphql/generated/cms/schema.graphql index 28cafe4d9..8bca95d11 100644 --- a/apps/webapp/services/datocms/graphql/generated/cms/schema.graphql +++ b/apps/webapp/services/datocms/graphql/generated/cms/schema.graphql @@ -359,6 +359,129 @@ type BlogBitcoinRecord implements RecordInterface { topics: JsonField } +input BlogBitlauncherModelFilter { + _createdAt: CreatedAtFilter + id: ItemIdFilter + _firstPublishedAt: PublishedAtFilter + _publicationScheduledAt: PublishedAtFilter + _unpublishingScheduledAt: PublishedAtFilter + _publishedAt: PublishedAtFilter + _status: StatusFilter + _updatedAt: UpdatedAtFilter + _isValid: BooleanFilter + authorName: StringFilter + authorPicture: FileFilter + description: StringFilter + seo: SeoFilter + slug: SlugFilter + thumbnail: FileFilter + title: StringFilter + topics: JsonFilter + OR: [BlogBitlauncherModelFilter] + AND: [BlogBitlauncherModelFilter] +} + +enum BlogBitlauncherModelOrderBy { + _createdAt_ASC + _createdAt_DESC + id_ASC + id_DESC + _firstPublishedAt_ASC + _firstPublishedAt_DESC + _publicationScheduledAt_ASC + _publicationScheduledAt_DESC + _unpublishingScheduledAt_ASC + _unpublishingScheduledAt_DESC + _publishedAt_ASC + _publishedAt_DESC + _status_ASC + _status_DESC + _updatedAt_ASC + _updatedAt_DESC + _isValid_ASC + _isValid_DESC + authorName_ASC + authorName_DESC + description_ASC + description_DESC + title_ASC + title_DESC +} + +"""Record of type Bitlauncher Blog (blog_bitlauncher)""" +type BlogBitlauncherRecord implements RecordInterface { + _allDescriptionLocales( + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): [StringMultiLocaleField!] + _allSeoLocales( + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): [SeoFieldMultiLocaleField!] + _allTitleLocales( + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): [StringMultiLocaleField!] + _createdAt: DateTime! + + """Editing URL""" + _editingUrl: String + _firstPublishedAt: DateTime + _isValid: BooleanType! + _modelApiKey: String! + _publicationScheduledAt: DateTime + _publishedAt: DateTime + + """Generates SEO and Social card meta tags to be used in your frontend""" + _seoMetaTags( + """The locale to use to fetch the field's content""" + locale: SiteLocale + ): [Tag!]! + _status: ItemStatus! + _unpublishingScheduledAt: DateTime + _updatedAt: DateTime! + authorName: String + authorPicture: FileField + contentBlock: [ContentBlockRecord!]! + description( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): String + id: ItemId! + seo( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): SeoField + slug: String + thumbnail: FileField + title( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): String + topics: JsonField +} + input BlogCryptoModelFilter { _createdAt: CreatedAtFilter id: ItemIdFilter @@ -1218,15 +1341,51 @@ input ImgixParams { """ auto: [ImgixParamsAuto!] + """ + Background Removal Fallback + + Overrides default fallback behavior for bg-remove failures. + + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-remove) + """ + bgRemoveFallback: BooleanType + """ Background Removal Removes background from image. - [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background-removal/bg-remove) + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-remove) """ bgRemove: BooleanType + """ + Background Removal Fallback + + Overrides default fallback behavior for bg-replace failures. + + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-replace) + """ + bgReplaceFallback: BooleanType + + """ + Background Replacement Negative Prompt + + Provides a negative text suggestion for background replacement. + + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-replace-neg-prompt) + """ + bgReplaceNegPrompt: String + + """ + Background Replacement + + Replaces background from image using a string based prompt. + + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-replace) + """ + bgReplace: String + """ Background Color @@ -1655,6 +1814,149 @@ input ImgixParams { """ fillColor: String + """ + Fill Generative Fallback + + Sets the fallback behavior for generative fill. + + Depends on: `fit=fill`, `fill=gen` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-fallback) + """ + fillGenFallback: BooleanType + + """ + Fill Generative Negative Prompt + + Provides a negative text suggestion to the generative fill parameter. Used to reduce the probability of a subject, detail, or object appearing in generative output. + + Depends on: `fit=fill`, `fill=gen` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-neg-prompt) + """ + fillGenNegPrompt: String + + """ + Fill Generative Position + + Sets the position of the Origin Image in relation to the generative fill. + + Depends on: `fit=fill`, `fill=gen` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-pos) + """ + fillGenPos: [ImgixParamsFillGenPos!] + + """ + Fill Generative Prompt + + Provides a text suggestion to the generative fill parameter. + + Depends on: `fit=fill`, `fill=gen` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-prompt) + """ + fillGenPrompt: String + + """ + Fill Generative Seed + + Sets the generative seed value. Used to generate similar outputs from different prompts. + + Depends on: `fit=fill`, `fill=gen` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-seed) + """ + fillGenSeed: IntType + + """ + Fill Gradient Color Space + + Defines the color space as linear, sRGB, Oklab, HSL, or LCH for gradient color interpolation + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-cs) + """ + fillGradientCs: ImgixParamsFillGradientCs + + """ + Fill Gradient Linear Direction + + The fill-gradient-linear-direction specifies the gradient's direction, flowing towards the bottom, top, right, or left + + Depends on: `fit=fill`, `fill=gen` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-linear-direction) + """ + fillGradientLinearDirection: [ImgixParamsFillGradientLinearDirection!] + + """ + Fill Gradient Linear + + Blends a gradient between two colors, {color1} and {color2}, along a straight path + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-linear) + """ + fillGradientLinear: String + + """ + Fill Gradient Radial Radius + + Parameter defines the radial gradient's radius as pixels or a percentage (0.0-1.0) of the image's smallest dimension + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial-radius) + """ + fillGradientRadialRadius: String + + """ + Fill Gradient Radial X + + Specifies the location of the radial gradient's center along the x-axis, using either a pixel value or a floating point percentage (ranging from 0.0 to 1.0) of the image's width + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial-x) + """ + fillGradientRadialX: FloatType + + """ + Fill Gradient Radial Y + + Parameter sets the radial gradient's center on the y-axis, using pixels or a 0.0 to 1.0 percentage of the image's height + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial-y) + """ + fillGradientRadialY: FloatType + + """ + Fill Gradient Radial + + The fill-gradient-radial parameter creates a circular gradient transitioning from a central color (Color1) to an outer color (Color2) + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial) + """ + fillGradientRadial: String + + """ + Fill Gradient Type + + Specifies if a gradient is radial (circular) or linear (straight) + + Depends on: `fit=fill`, `fill=gradient` + + [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-type) + """ + fillGradientType: ImgixParamsFillGradientType + """ Fill Mode @@ -1763,6 +2065,8 @@ input ImgixParams { """ Animated Gif Quality + Specifies the quality of the animated gif. The higher the value, the better more compression is applied. + Depends on: `fm=gif` """ gifQ: IntType @@ -1844,6 +2148,13 @@ input ImgixParams { """ iptc: ImgixParamsIptc + """ + Jpg Progressive + + Specifies whether or not a jpg/jpeg uses progressive (true) or baseline (false) + """ + jpgProgressive: BooleanType + """ Animation Loop Count @@ -2272,6 +2583,13 @@ input ImgixParams { """ skip: IntType + """ + Sanitize Svg + + Specifies whether to sanitize an SVG. + """ + svgSanitize: BooleanType + """ Transparency @@ -2411,17 +2729,6 @@ input ImgixParams { """ txtLead: IntType - """ - Text Ligatures - - Controls the level of ligature substitution - - Depends on: `txt` - - [Open Imgix reference »](https://docs.imgix.com/apis/url/text/txt-lig) - """ - txtLig: IntType - """ Text Outline Color @@ -2530,6 +2837,24 @@ input ImgixParams { """ txt: String + """ + Super Resolution Fallback + + Overrides default fallback behavior for super resolution failures + + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/super-resolution/upscale-fallback) + """ + upscaleFallback: BooleanType + + """ + Super Resolution + + Uses generative AI fill to upscale low resolution images. + + [Open Imgix reference »](https://docs.imgix.com/apis/rendering/super-resolution/upscale) + """ + upscale: BooleanType + """ Unsharp Mask @@ -2567,6 +2892,13 @@ input ImgixParams { [Open Imgix reference »](https://docs.imgix.com/apis/url/size/w) """ w: FloatType + + """ + Bypasses any [DatoCMS Automatic Image Optimization](https://www.datocms.com/docs/cdn-settings/advanced-asset-settings) that might be set up for the project. + + Exercise caution when using this parameter, as it could significantly increase your bandwidth costs. + """ + skipDefaultOptimizations: BooleanType } enum ImgixParamsAuto { @@ -2651,6 +2983,38 @@ enum ImgixParamsCs { enum ImgixParamsFill { solid blur + gen + generative + gradient +} + +enum ImgixParamsFillGenPos { + top + bottom + middle + left + right + center +} + +enum ImgixParamsFillGradientCs { + linear + srgb + oklab + hsl + lch +} + +enum ImgixParamsFillGradientLinearDirection { + top + bottom + left + right +} + +enum ImgixParamsFillGradientType { + linear + radial } enum ImgixParamsFit { @@ -3393,6 +3757,13 @@ type Query { filter: BlogBitcoinModelFilter ): CollectionMetadata! + """Returns meta information regarding a record collection""" + _allBlogBitlaunchersMeta( + """The locale to use to fetch the field's content""" + locale: SiteLocale + filter: BlogBitlauncherModelFilter + ): CollectionMetadata! + """Returns meta information regarding a record collection""" _allBlogCryptosMeta( """The locale to use to fetch the field's content""" @@ -3510,6 +3881,25 @@ type Query { orderBy: [BlogBitcoinModelOrderBy] = [_updatedAt_DESC] ): [BlogBitcoinRecord!]! + """Returns a collection of records""" + allBlogBitlaunchers( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + + """Skip the first results""" + skip: IntType + + """Limit the number of results""" + first: IntType = 20 + filter: BlogBitlauncherModelFilter + orderBy: [BlogBitlauncherModelOrderBy] = [_updatedAt_DESC] + ): [BlogBitlauncherRecord!]! + """Returns a collection of records""" allBlogCryptos( """The locale to use to fetch the field's content""" @@ -3682,6 +4072,19 @@ type Query { orderBy: [BlogBitcoinModelOrderBy] = [_updatedAt_DESC] ): BlogBitcoinRecord + """Returns a specific record""" + blogBitlauncher( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + filter: BlogBitlauncherModelFilter + orderBy: [BlogBitlauncherModelOrderBy] = [_updatedAt_DESC] + ): BlogBitlauncherRecord + """Returns a specific record""" blogCrypto( """The locale to use to fetch the field's content""" @@ -4022,6 +4425,9 @@ enum SiteLocale { zh id vi + ko + pt + fr } """Specifies how to filter Slug fields""" @@ -4612,8 +5018,34 @@ input UploadUpdatedAtFilter { } type UploadVideoField { + alt( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): String + blurUpThumb( + """ + Controls the "punch" value (~contrast) of the blurhash decoding algorithm (defaults to 1.0) + """ + punch: Float! = 1 + + """Maximum image dimension (defaults to 24px)""" + size: Int! = 24 + + """Image quality (defaults to 70%)""" + quality: Int! = 70 + + """Imgix transformations to apply to the image""" + imgixParams: ImgixParams + ): String + blurhash: String duration: Int framerate: Int + height: IntType! mp4Url( """Pick highest resolution available up to the specified argument""" res: VideoMp4Res @@ -4624,12 +5056,23 @@ type UploadVideoField { muxAssetId: String! muxPlaybackId: String! streamingUrl: String! + thumbhash: String thumbnailUrl( """ The file extension of the requested image format. Either png, jpg or gif """ format: MuxThumbnailFormatType = jpg ): String! + title( + """The locale to use to fetch the field's content""" + locale: SiteLocale + + """ + If you want to fallback to a default translation when a translation has not been found + """ + fallbackLocales: [SiteLocale!] + ): String + width: IntType! } """Specifies how to filter by width""" diff --git a/apps/webapp/services/datocms/graphql/generated/cms/schema.ts b/apps/webapp/services/datocms/graphql/generated/cms/schema.ts index d45dd185d..c9a7ed4fd 100644 --- a/apps/webapp/services/datocms/graphql/generated/cms/schema.ts +++ b/apps/webapp/services/datocms/graphql/generated/cms/schema.ts @@ -190,6 +190,63 @@ export interface BlogBitcoinRecord { __typename: 'BlogBitcoinRecord' } +export type BlogBitlauncherModelOrderBy = + | '_createdAt_ASC' + | '_createdAt_DESC' + | 'id_ASC' + | 'id_DESC' + | '_firstPublishedAt_ASC' + | '_firstPublishedAt_DESC' + | '_publicationScheduledAt_ASC' + | '_publicationScheduledAt_DESC' + | '_unpublishingScheduledAt_ASC' + | '_unpublishingScheduledAt_DESC' + | '_publishedAt_ASC' + | '_publishedAt_DESC' + | '_status_ASC' + | '_status_DESC' + | '_updatedAt_ASC' + | '_updatedAt_DESC' + | '_isValid_ASC' + | '_isValid_DESC' + | 'authorName_ASC' + | 'authorName_DESC' + | 'description_ASC' + | 'description_DESC' + | 'title_ASC' + | 'title_DESC' + +/** Record of type Bitlauncher Blog (blog_bitlauncher) */ +export interface BlogBitlauncherRecord { + _allDescriptionLocales: StringMultiLocaleField[] | null + _allSeoLocales: SeoFieldMultiLocaleField[] | null + _allTitleLocales: StringMultiLocaleField[] | null + _createdAt: Scalars['DateTime'] + /** Editing URL */ + _editingUrl: Scalars['String'] | null + _firstPublishedAt: Scalars['DateTime'] | null + _isValid: Scalars['BooleanType'] + _modelApiKey: Scalars['String'] + _publicationScheduledAt: Scalars['DateTime'] | null + _publishedAt: Scalars['DateTime'] | null + /** Generates SEO and Social card meta tags to be used in your frontend */ + _seoMetaTags: Tag[] + _status: ItemStatus + _unpublishingScheduledAt: Scalars['DateTime'] | null + _updatedAt: Scalars['DateTime'] + authorName: Scalars['String'] | null + authorPicture: FileField | null + contentBlock: ContentBlockRecord[] + description: Scalars['String'] | null + id: Scalars['ItemId'] + seo: SeoField | null + slug: Scalars['String'] | null + thumbnail: FileField | null + title: Scalars['String'] | null + topics: Scalars['JsonField'] | null + __typename: 'BlogBitlauncherRecord' +} + export type BlogCryptoModelOrderBy = | '_createdAt_ASC' | '_createdAt_DESC' @@ -573,7 +630,35 @@ export type ImgixParamsCrop = export type ImgixParamsCs = 'srgb' | 'adobergb1998' | 'tinysrgb' | 'strip' -export type ImgixParamsFill = 'solid' | 'blur' +export type ImgixParamsFill = + | 'solid' + | 'blur' + | 'gen' + | 'generative' + | 'gradient' + +export type ImgixParamsFillGenPos = + | 'top' + | 'bottom' + | 'middle' + | 'left' + | 'right' + | 'center' + +export type ImgixParamsFillGradientCs = + | 'linear' + | 'srgb' + | 'oklab' + | 'hsl' + | 'lch' + +export type ImgixParamsFillGradientLinearDirection = + | 'top' + | 'bottom' + | 'left' + | 'right' + +export type ImgixParamsFillGradientType = 'linear' | 'radial' export type ImgixParamsFit = | 'clamp' @@ -806,6 +891,8 @@ export interface Query { /** Returns meta information regarding a record collection */ _allBlogBitcoinsMeta: CollectionMetadata /** Returns meta information regarding a record collection */ + _allBlogBitlaunchersMeta: CollectionMetadata + /** Returns meta information regarding a record collection */ _allBlogCryptosMeta: CollectionMetadata /** Returns meta information regarding a record collection */ _allBlogInvestingsMeta: CollectionMetadata @@ -828,6 +915,8 @@ export interface Query { /** Returns a collection of records */ allBlogBitcoins: BlogBitcoinRecord[] /** Returns a collection of records */ + allBlogBitlaunchers: BlogBitlauncherRecord[] + /** Returns a collection of records */ allBlogCryptos: BlogCryptoRecord[] /** Returns a collection of records */ allBlogInvestings: BlogInvestingRecord[] @@ -848,6 +937,8 @@ export interface Query { /** Returns a specific record */ blogBitcoin: BlogBitcoinRecord | null /** Returns a specific record */ + blogBitlauncher: BlogBitlauncherRecord | null + /** Returns a specific record */ blogCrypto: BlogCryptoRecord | null /** Returns a specific record */ blogInvesting: BlogInvestingRecord | null @@ -874,6 +965,7 @@ export type RecordInterface = ( | BlogAiRecord | BlogBitcashRecord | BlogBitcoinRecord + | BlogBitlauncherRecord | BlogCryptoRecord | BlogInvestingRecord | BlogNewsRecord @@ -1089,13 +1181,20 @@ export type UploadType = | 'archive' export interface UploadVideoField { + alt: Scalars['String'] | null + blurUpThumb: Scalars['String'] | null + blurhash: Scalars['String'] | null duration: Scalars['Int'] | null framerate: Scalars['Int'] | null + height: Scalars['IntType'] mp4Url: Scalars['String'] | null muxAssetId: Scalars['String'] muxPlaybackId: Scalars['String'] streamingUrl: Scalars['String'] + thumbhash: Scalars['String'] | null thumbnailUrl: Scalars['String'] + title: Scalars['String'] | null + width: Scalars['IntType'] __typename: 'UploadVideoField' } @@ -1400,6 +1499,107 @@ export interface BlogBitcoinRecordGenqlSelection { __scalar?: boolean | number } +export interface BlogBitlauncherModelFilter { + _createdAt?: CreatedAtFilter | null + id?: ItemIdFilter | null + _firstPublishedAt?: PublishedAtFilter | null + _publicationScheduledAt?: PublishedAtFilter | null + _unpublishingScheduledAt?: PublishedAtFilter | null + _publishedAt?: PublishedAtFilter | null + _status?: StatusFilter | null + _updatedAt?: UpdatedAtFilter | null + _isValid?: BooleanFilter | null + authorName?: StringFilter | null + authorPicture?: FileFilter | null + description?: StringFilter | null + seo?: SeoFilter | null + slug?: SlugFilter | null + thumbnail?: FileFilter | null + title?: StringFilter | null + topics?: JsonFilter | null + OR?: (BlogBitlauncherModelFilter | null)[] | null + AND?: (BlogBitlauncherModelFilter | null)[] | null +} + +/** Record of type Bitlauncher Blog (blog_bitlauncher) */ +export interface BlogBitlauncherRecordGenqlSelection { + _allDescriptionLocales?: StringMultiLocaleFieldGenqlSelection & { + __args?: { + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + _allSeoLocales?: SeoFieldMultiLocaleFieldGenqlSelection & { + __args?: { + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + _allTitleLocales?: StringMultiLocaleFieldGenqlSelection & { + __args?: { + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + _createdAt?: boolean | number + /** Editing URL */ + _editingUrl?: boolean | number + _firstPublishedAt?: boolean | number + _isValid?: boolean | number + _modelApiKey?: boolean | number + _publicationScheduledAt?: boolean | number + _publishedAt?: boolean | number + /** Generates SEO and Social card meta tags to be used in your frontend */ + _seoMetaTags?: TagGenqlSelection & { + __args?: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + } + } + _status?: boolean | number + _unpublishingScheduledAt?: boolean | number + _updatedAt?: boolean | number + authorName?: boolean | number + authorPicture?: FileFieldGenqlSelection + contentBlock?: ContentBlockRecordGenqlSelection + description?: + | { + __args: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + | boolean + | number + id?: boolean | number + seo?: SeoFieldGenqlSelection & { + __args?: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + slug?: boolean | number + thumbnail?: FileFieldGenqlSelection + title?: + | { + __args: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + | boolean + | number + topics?: boolean | number + __typename?: boolean | number + __scalar?: boolean | number +} + export interface BlogCryptoModelFilter { _createdAt?: CreatedAtFilter | null id?: ItemIdFilter | null @@ -2126,14 +2326,46 @@ export interface ImgixParams { * [Open Imgix reference »](https://docs.imgix.com/apis/url/auto) */ auto?: ImgixParamsAuto[] | null + /** + * Background Removal Fallback + * + * Overrides default fallback behavior for bg-remove failures. + * + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-remove) + */ + bgRemoveFallback?: Scalars['BooleanType'] | null /** * Background Removal * * Removes background from image. * - * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background-removal/bg-remove) + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-remove) */ bgRemove?: Scalars['BooleanType'] | null + /** + * Background Removal Fallback + * + * Overrides default fallback behavior for bg-replace failures. + * + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-replace) + */ + bgReplaceFallback?: Scalars['BooleanType'] | null + /** + * Background Replacement Negative Prompt + * + * Provides a negative text suggestion for background replacement. + * + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-replace-neg-prompt) + */ + bgReplaceNegPrompt?: Scalars['String'] | null + /** + * Background Replacement + * + * Replaces background from image using a string based prompt. + * + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/background/bg-replace) + */ + bgReplace?: Scalars['String'] | null /** * Background Color * @@ -2520,6 +2752,136 @@ export interface ImgixParams { * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-color) */ fillColor?: Scalars['String'] | null + /** + * Fill Generative Fallback + * + * Sets the fallback behavior for generative fill. + * + * Depends on: `fit=fill`, `fill=gen` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-fallback) + */ + fillGenFallback?: Scalars['BooleanType'] | null + /** + * Fill Generative Negative Prompt + * + * Provides a negative text suggestion to the generative fill parameter. Used to reduce the probability of a subject, detail, or object appearing in generative output. + * + * Depends on: `fit=fill`, `fill=gen` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-neg-prompt) + */ + fillGenNegPrompt?: Scalars['String'] | null + /** + * Fill Generative Position + * + * Sets the position of the Origin Image in relation to the generative fill. + * + * Depends on: `fit=fill`, `fill=gen` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-pos) + */ + fillGenPos?: ImgixParamsFillGenPos[] | null + /** + * Fill Generative Prompt + * + * Provides a text suggestion to the generative fill parameter. + * + * Depends on: `fit=fill`, `fill=gen` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-prompt) + */ + fillGenPrompt?: Scalars['String'] | null + /** + * Fill Generative Seed + * + * Sets the generative seed value. Used to generate similar outputs from different prompts. + * + * Depends on: `fit=fill`, `fill=gen` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gen-seed) + */ + fillGenSeed?: Scalars['IntType'] | null + /** + * Fill Gradient Color Space + * + * Defines the color space as linear, sRGB, Oklab, HSL, or LCH for gradient color interpolation + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-cs) + */ + fillGradientCs?: ImgixParamsFillGradientCs | null + /** + * Fill Gradient Linear Direction + * + * The fill-gradient-linear-direction specifies the gradient's direction, flowing towards the bottom, top, right, or left + * + * Depends on: `fit=fill`, `fill=gen` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-linear-direction) + */ + fillGradientLinearDirection?: ImgixParamsFillGradientLinearDirection[] | null + /** + * Fill Gradient Linear + * + * Blends a gradient between two colors, {color1} and {color2}, along a straight path + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-linear) + */ + fillGradientLinear?: Scalars['String'] | null + /** + * Fill Gradient Radial Radius + * + * Parameter defines the radial gradient's radius as pixels or a percentage (0.0-1.0) of the image's smallest dimension + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial-radius) + */ + fillGradientRadialRadius?: Scalars['String'] | null + /** + * Fill Gradient Radial X + * + * Specifies the location of the radial gradient's center along the x-axis, using either a pixel value or a floating point percentage (ranging from 0.0 to 1.0) of the image's width + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial-x) + */ + fillGradientRadialX?: Scalars['FloatType'] | null + /** + * Fill Gradient Radial Y + * + * Parameter sets the radial gradient's center on the y-axis, using pixels or a 0.0 to 1.0 percentage of the image's height + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial-y) + */ + fillGradientRadialY?: Scalars['FloatType'] | null + /** + * Fill Gradient Radial + * + * The fill-gradient-radial parameter creates a circular gradient transitioning from a central color (Color1) to an outer color (Color2) + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-radial) + */ + fillGradientRadial?: Scalars['String'] | null + /** + * Fill Gradient Type + * + * Specifies if a gradient is radial (circular) or linear (straight) + * + * Depends on: `fit=fill`, `fill=gradient` + * + * [Open Imgix reference »](https://docs.imgix.com/apis/url/fill/fill-gradient-type) + */ + fillGradientType?: ImgixParamsFillGradientType | null /** * Fill Mode * @@ -2617,6 +2979,8 @@ export interface ImgixParams { /** * Animated Gif Quality * + * Specifies the quality of the animated gif. The higher the value, the better more compression is applied. + * * Depends on: `fm=gif` */ gifQ?: Scalars['IntType'] | null @@ -2688,6 +3052,12 @@ export interface ImgixParams { * Determine if IPTC data should be passed for JPEG images. */ iptc?: ImgixParamsIptc | null + /** + * Jpg Progressive + * + * Specifies whether or not a jpg/jpeg uses progressive (true) or baseline (false) + */ + jpgProgressive?: Scalars['BooleanType'] | null /** * Animation Loop Count * @@ -3072,6 +3442,12 @@ export interface ImgixParams { * Skips every Nth frame starting with the first frame. */ skip?: Scalars['IntType'] | null + /** + * Sanitize Svg + * + * Specifies whether to sanitize an SVG. + */ + svgSanitize?: Scalars['BooleanType'] | null /** * Transparency * @@ -3198,16 +3574,6 @@ export interface ImgixParams { * [Open Imgix reference »](https://docs.imgix.com/apis/url/typesetting/txt-lead) */ txtLead?: Scalars['IntType'] | null - /** - * Text Ligatures - * - * Controls the level of ligature substitution - * - * Depends on: `txt` - * - * [Open Imgix reference »](https://docs.imgix.com/apis/url/text/txt-lig) - */ - txtLig?: Scalars['IntType'] | null /** * Text Outline Color * @@ -3306,6 +3672,22 @@ export interface ImgixParams { * [Open Imgix reference »](https://docs.imgix.com/apis/url/text/txt) */ txt?: Scalars['String'] | null + /** + * Super Resolution Fallback + * + * Overrides default fallback behavior for super resolution failures + * + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/super-resolution/upscale-fallback) + */ + upscaleFallback?: Scalars['BooleanType'] | null + /** + * Super Resolution + * + * Uses generative AI fill to upscale low resolution images. + * + * [Open Imgix reference »](https://docs.imgix.com/apis/rendering/super-resolution/upscale) + */ + upscale?: Scalars['BooleanType'] | null /** * Unsharp Mask * @@ -3340,6 +3722,12 @@ export interface ImgixParams { * [Open Imgix reference »](https://docs.imgix.com/apis/url/size/w) */ w?: Scalars['FloatType'] | null + /** + * Bypasses any [DatoCMS Automatic Image Optimization](https://www.datocms.com/docs/cdn-settings/advanced-asset-settings) that might be set up for the project. + * + * Exercise caution when using this parameter, as it could significantly increase your bandwidth costs. + */ + skipDefaultOptimizations?: Scalars['BooleanType'] | null } /** Specifies how to filter by usage */ @@ -3967,6 +4355,14 @@ export interface QueryGenqlSelection { } } /** Returns meta information regarding a record collection */ + _allBlogBitlaunchersMeta?: CollectionMetadataGenqlSelection & { + __args?: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + filter?: BlogBitlauncherModelFilter | null + } + } + /** Returns meta information regarding a record collection */ _allBlogCryptosMeta?: CollectionMetadataGenqlSelection & { __args?: { /** The locale to use to fetch the field's content */ @@ -4077,6 +4473,21 @@ export interface QueryGenqlSelection { } } /** Returns a collection of records */ + allBlogBitlaunchers?: BlogBitlauncherRecordGenqlSelection & { + __args?: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + /** Skip the first results */ + skip?: Scalars['IntType'] | null + /** Limit the number of results */ + first?: Scalars['IntType'] | null + filter?: BlogBitlauncherModelFilter | null + orderBy?: (BlogBitlauncherModelOrderBy | null)[] | null + } + } + /** Returns a collection of records */ allBlogCryptos?: BlogCryptoRecordGenqlSelection & { __args?: { /** The locale to use to fetch the field's content */ @@ -4215,6 +4626,17 @@ export interface QueryGenqlSelection { } } /** Returns a specific record */ + blogBitlauncher?: BlogBitlauncherRecordGenqlSelection & { + __args?: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + filter?: BlogBitlauncherModelFilter | null + orderBy?: (BlogBitlauncherModelOrderBy | null)[] | null + } + } + /** Returns a specific record */ blogCrypto?: BlogCryptoRecordGenqlSelection & { __args?: { /** The locale to use to fetch the field's content */ @@ -4345,6 +4767,7 @@ export interface RecordInterfaceGenqlSelection { on_BlogAiRecord?: BlogAiRecordGenqlSelection on_BlogBitcashRecord?: BlogBitcashRecordGenqlSelection on_BlogBitcoinRecord?: BlogBitcoinRecordGenqlSelection + on_BlogBitlauncherRecord?: BlogBitlauncherRecordGenqlSelection on_BlogCryptoRecord?: BlogCryptoRecordGenqlSelection on_BlogInvestingRecord?: BlogInvestingRecordGenqlSelection on_BlogNewsRecord?: BlogNewsRecordGenqlSelection @@ -4952,8 +5375,36 @@ export interface UploadUpdatedAtFilter { } export interface UploadVideoFieldGenqlSelection { + alt?: + | { + __args: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + | boolean + | number + blurUpThumb?: + | { + __args: { + /** Controls the "punch" value (~contrast) of the blurhash decoding algorithm (defaults to 1.0) */ + punch?: Scalars['Float'] + /** Maximum image dimension (defaults to 24px) */ + size?: Scalars['Int'] + /** Image quality (defaults to 70%) */ + quality?: Scalars['Int'] + /** Imgix transformations to apply to the image */ + imgixParams?: ImgixParams | null + } + } + | boolean + | number + blurhash?: boolean | number duration?: boolean | number framerate?: boolean | number + height?: boolean | number mp4Url?: | { __args: { @@ -4968,6 +5419,7 @@ export interface UploadVideoFieldGenqlSelection { muxAssetId?: boolean | number muxPlaybackId?: boolean | number streamingUrl?: boolean | number + thumbhash?: boolean | number thumbnailUrl?: | { __args: { @@ -4977,6 +5429,18 @@ export interface UploadVideoFieldGenqlSelection { } | boolean | number + title?: + | { + __args: { + /** The locale to use to fetch the field's content */ + locale?: SiteLocale | null + /** If you want to fallback to a default translation when a translation has not been found */ + fallbackLocales?: SiteLocale[] | null + } + } + | boolean + | number + width?: boolean | number __typename?: boolean | number __scalar?: boolean | number } @@ -5031,6 +5495,15 @@ export const isBlogBitcoinRecord = ( return BlogBitcoinRecord_possibleTypes.includes(obj.__typename) } +const BlogBitlauncherRecord_possibleTypes: string[] = ['BlogBitlauncherRecord'] +export const isBlogBitlauncherRecord = ( + obj?: { __typename?: any } | null, +): obj is BlogBitlauncherRecord => { + if (!obj?.__typename) + throw new Error('__typename is missing in "isBlogBitlauncherRecord"') + return BlogBitlauncherRecord_possibleTypes.includes(obj.__typename) +} + const BlogCryptoRecord_possibleTypes: string[] = ['BlogCryptoRecord'] export const isBlogCryptoRecord = ( obj?: { __typename?: any } | null, @@ -5213,6 +5686,7 @@ const RecordInterface_possibleTypes: string[] = [ 'BlogAiRecord', 'BlogBitcashRecord', 'BlogBitcoinRecord', + 'BlogBitlauncherRecord', 'BlogCryptoRecord', 'BlogInvestingRecord', 'BlogNewsRecord', @@ -5441,6 +5915,33 @@ export const enumBlogBitcoinModelOrderBy = { title_DESC: 'title_DESC' as const, } +export const enumBlogBitlauncherModelOrderBy = { + _createdAt_ASC: '_createdAt_ASC' as const, + _createdAt_DESC: '_createdAt_DESC' as const, + id_ASC: 'id_ASC' as const, + id_DESC: 'id_DESC' as const, + _firstPublishedAt_ASC: '_firstPublishedAt_ASC' as const, + _firstPublishedAt_DESC: '_firstPublishedAt_DESC' as const, + _publicationScheduledAt_ASC: '_publicationScheduledAt_ASC' as const, + _publicationScheduledAt_DESC: '_publicationScheduledAt_DESC' as const, + _unpublishingScheduledAt_ASC: '_unpublishingScheduledAt_ASC' as const, + _unpublishingScheduledAt_DESC: '_unpublishingScheduledAt_DESC' as const, + _publishedAt_ASC: '_publishedAt_ASC' as const, + _publishedAt_DESC: '_publishedAt_DESC' as const, + _status_ASC: '_status_ASC' as const, + _status_DESC: '_status_DESC' as const, + _updatedAt_ASC: '_updatedAt_ASC' as const, + _updatedAt_DESC: '_updatedAt_DESC' as const, + _isValid_ASC: '_isValid_ASC' as const, + _isValid_DESC: '_isValid_DESC' as const, + authorName_ASC: 'authorName_ASC' as const, + authorName_DESC: 'authorName_DESC' as const, + description_ASC: 'description_ASC' as const, + description_DESC: 'description_DESC' as const, + title_ASC: 'title_ASC' as const, + title_DESC: 'title_DESC' as const, +} + export const enumBlogCryptoModelOrderBy = { _createdAt_ASC: '_createdAt_ASC' as const, _createdAt_DESC: '_createdAt_DESC' as const, @@ -5652,6 +6153,38 @@ export const enumImgixParamsCs = { export const enumImgixParamsFill = { solid: 'solid' as const, blur: 'blur' as const, + gen: 'gen' as const, + generative: 'generative' as const, + gradient: 'gradient' as const, +} + +export const enumImgixParamsFillGenPos = { + top: 'top' as const, + bottom: 'bottom' as const, + middle: 'middle' as const, + left: 'left' as const, + right: 'right' as const, + center: 'center' as const, +} + +export const enumImgixParamsFillGradientCs = { + linear: 'linear' as const, + srgb: 'srgb' as const, + oklab: 'oklab' as const, + hsl: 'hsl' as const, + lch: 'lch' as const, +} + +export const enumImgixParamsFillGradientLinearDirection = { + top: 'top' as const, + bottom: 'bottom' as const, + left: 'left' as const, + right: 'right' as const, +} + +export const enumImgixParamsFillGradientType = { + linear: 'linear' as const, + radial: 'radial' as const, } export const enumImgixParamsFit = { @@ -5828,6 +6361,9 @@ export const enumSiteLocale = { zh: 'zh' as const, id: 'id' as const, vi: 'vi' as const, + ko: 'ko' as const, + pt: 'pt' as const, + fr: 'fr' as const, } export const enumUploadOrderBy = { diff --git a/apps/webapp/services/datocms/graphql/generated/cms/types.ts b/apps/webapp/services/datocms/graphql/generated/cms/types.ts index fdf01dcf4..9881ff555 100644 --- a/apps/webapp/services/datocms/graphql/generated/cms/types.ts +++ b/apps/webapp/services/datocms/graphql/generated/cms/types.ts @@ -1,990 +1,1100 @@ export default { scalars: [ - 1, 4, 7, 10, 13, 16, 19, 21, 23, 25, 30, 31, 32, 36, 37, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 64, - 65, 66, 68, 69, 74, 75, 78, 87, 90, 96, 99, 120, 125, 126, 130, 134, + 1, 4, 7, 10, 13, 16, 19, 22, 24, 26, 28, 33, 34, 35, 39, 40, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 71, 72, 73, 75, 76, 81, 82, 85, 94, 97, 103, 106, 127, 132, + 133, 137, 141, ], types: { BlogAiModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], OR: [0], AND: [0], - __typename: [99], + __typename: [106], }, BlogAiModelOrderBy: {}, BlogAiRecord: { _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], - description: [99], - id: [66], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], + description: [106], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, BlogBitcashModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], OR: [3], AND: [3], - __typename: [99], + __typename: [106], }, BlogBitcashModelOrderBy: {}, BlogBitcashRecord: { _allDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], description: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, BlogBitcoinModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], OR: [6], AND: [6], - __typename: [99], + __typename: [106], }, BlogBitcoinModelOrderBy: {}, BlogBitcoinRecord: { _allDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], description: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ + 106, + { + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + topics: [76], + __typename: [106], + }, + BlogBitlauncherModelFilter: { + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], + OR: [9], + AND: [9], + __typename: [106], + }, + BlogBitlauncherModelOrderBy: {}, + BlogBitlauncherRecord: { + _allDescriptionLocales: [ + 109, + { + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + _allSeoLocales: [ + 100, + { + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + _allTitleLocales: [ + 109, + { + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], + _seoMetaTags: [ + 110, + { + locale: [103], + }, + ], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], + description: [ + 106, + { + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + id: [73], + seo: [ 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + slug: [106], + thumbnail: [36], + title: [ + 106, + { + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + topics: [76], + __typename: [106], }, BlogCryptoModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], - OR: [9], - AND: [9], - __typename: [99], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], + OR: [12], + AND: [12], + __typename: [106], }, BlogCryptoModelOrderBy: {}, BlogCryptoRecord: { _allDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], description: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, BlogInvestingModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], - OR: [12], - AND: [12], - __typename: [99], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], + OR: [15], + AND: [15], + __typename: [106], }, BlogInvestingModelOrderBy: {}, BlogInvestingRecord: { _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], - description: [99], - id: [66], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], + description: [106], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, BlogNewsModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], - OR: [15], - AND: [15], - __typename: [99], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], + OR: [18], + AND: [18], + __typename: [106], }, BlogNewsModelOrderBy: {}, BlogNewsRecord: { _allDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], description: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, BlogStartupModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], - OR: [18], - AND: [18], - __typename: [99], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], + OR: [21], + AND: [21], + __typename: [106], }, BlogStartupModelOrderBy: {}, BlogStartupRecord: { _allDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], description: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, Boolean: {}, BooleanFilter: { - eq: [23], - __typename: [99], + eq: [26], + __typename: [106], }, BooleanType: {}, CollectionMetadata: { - count: [65], - __typename: [99], + count: [72], + __typename: [106], }, ColorBucketType: {}, ColorField: { - alpha: [65], - blue: [65], - cssRgb: [99], - green: [65], - hex: [99], - red: [65], - __typename: [99], + alpha: [72], + blue: [72], + cssRgb: [106], + green: [72], + hex: [106], + red: [72], + __typename: [106], }, ContentBlockModelMainContentField: { - blocks: [99], - links: [99], - value: [69], - __typename: [99], + blocks: [106], + links: [106], + value: [76], + __typename: [106], }, ContentBlockRecord: { - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - id: [66], - mainContent: [27], - topImages: [33], - __typename: [99], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + id: [73], + mainContent: [30], + topImages: [36], + __typename: [106], }, CreatedAtFilter: { - gt: [31], - lt: [31], - gte: [31], - lte: [31], - eq: [31], - neq: [31], - exists: [23], - __typename: [99], + gt: [34], + lt: [34], + gte: [34], + lte: [34], + eq: [34], + neq: [34], + exists: [26], + __typename: [106], }, CustomData: {}, DateTime: {}, FaviconType: {}, FileField: { - _createdAt: [31], - _editingUrl: [99], - _updatedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _updatedAt: [34], alt: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - author: [99], - basename: [99], + author: [106], + basename: [106], blurUpThumb: [ - 99, + 106, { - punch: [36, 'Float!'], - size: [64, 'Int!'], - quality: [64, 'Int!'], - imgixParams: [39], + punch: [39, 'Float!'], + size: [71, 'Int!'], + quality: [71, 'Int!'], + imgixParams: [42], }, ], - blurhash: [99], - colors: [26], - copyright: [99], + blurhash: [106], + colors: [29], + copyright: [106], customData: [ - 30, + 33, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - exifInfo: [30], - filename: [99], + exifInfo: [33], + filename: [106], focalPoint: [ - 135, + 142, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - format: [99], - height: [65], - id: [120], - md5: [99], - mimeType: [99], - notes: [99], + format: [106], + height: [72], + id: [127], + md5: [106], + mimeType: [106], + notes: [106], responsiveImage: [ - 91, + 98, { - imgixParams: [39], - sizes: [99], - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + imgixParams: [42], + sizes: [106], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - size: [65], - smartTags: [99], - tags: [99], - thumbhash: [99], + size: [72], + smartTags: [106], + tags: [106], + thumbhash: [106], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], url: [ - 99, + 106, { - imgixParams: [39], + imgixParams: [42], }, ], - video: [132], - width: [65], - __typename: [99], + video: [139], + width: [72], + __typename: [106], }, FileFieldInterface: { - _createdAt: [31], - _editingUrl: [99], - _updatedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _updatedAt: [34], alt: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - author: [99], - basename: [99], + author: [106], + basename: [106], blurUpThumb: [ - 99, + 106, { - punch: [36, 'Float!'], - size: [64, 'Int!'], - quality: [64, 'Int!'], - imgixParams: [39], + punch: [39, 'Float!'], + size: [71, 'Int!'], + quality: [71, 'Int!'], + imgixParams: [42], }, ], - blurhash: [99], - colors: [26], - copyright: [99], + blurhash: [106], + colors: [29], + copyright: [106], customData: [ - 30, + 33, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - exifInfo: [30], - filename: [99], + exifInfo: [33], + filename: [106], focalPoint: [ - 135, + 142, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - format: [99], - height: [65], - id: [120], - md5: [99], - mimeType: [99], - notes: [99], + format: [106], + height: [72], + id: [127], + md5: [106], + mimeType: [106], + notes: [106], responsiveImage: [ - 91, + 98, { - imgixParams: [39], - sizes: [99], - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + imgixParams: [42], + sizes: [106], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - size: [65], - smartTags: [99], - tags: [99], - thumbhash: [99], + size: [72], + smartTags: [106], + tags: [106], + thumbhash: [106], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], url: [ - 99, + 106, { - imgixParams: [39], + imgixParams: [42], }, ], - video: [132], - width: [65], - on_FileField: [33], - __typename: [99], + video: [139], + width: [72], + on_FileField: [36], + __typename: [106], }, FileFilter: { - eq: [120], - neq: [120], - in: [120], - notIn: [120], - exists: [23], - __typename: [99], + eq: [127], + neq: [127], + in: [127], + notIn: [127], + exists: [26], + __typename: [106], }, Float: {}, FloatType: {}, GlobalSeoField: { - facebookPageUrl: [99], - fallbackSeo: [92], - siteName: [99], - titleSuffix: [99], - twitterAccount: [99], - __typename: [99], + facebookPageUrl: [106], + fallbackSeo: [99], + siteName: [106], + titleSuffix: [106], + twitterAccount: [106], + __typename: [106], }, ImgixParams: { - ar: [99], - auto: [40], - bgRemove: [23], - bg: [99], - blendAlign: [41], - blendAlpha: [65], - blendColor: [99], - blendCrop: [42], - blendFit: [43], - blendH: [37], - blendMode: [44], - blendPad: [65], - blendSize: [45], - blendW: [37], - blendX: [65], - blendY: [65], - blend: [99], - blur: [65], - borderBottom: [65], - borderLeft: [65], - borderRadiusInner: [99], - borderRadius: [99], - borderRight: [65], - borderTop: [65], - border: [99], - bri: [65], - ch: [46], - chromasub: [65], - colorquant: [65], - colors: [65], - con: [65], - cornerRadius: [99], - crop: [47], - cs: [48], - dl: [99], - dpi: [65], - dpr: [37], - duotoneAlpha: [65], - duotone: [99], - exp: [65], - expires: [65], - faceindex: [65], - facepad: [37], - faces: [65], - fillColor: [99], - fill: [49], - fit: [50], - flip: [51], - fm: [52], - fpDebug: [23], - fpX: [37], - fpY: [37], - fpZ: [37], - fps: [65], - frame: [99], - gam: [65], - gifQ: [65], - gridColors: [99], - gridSize: [65], - h: [37], - high: [65], - htn: [65], - hue: [65], - interval: [65], - invert: [23], - iptc: [53], - loop: [65], - lossless: [23], - markAlign: [54], - markAlpha: [65], - markBase: [99], - markFit: [55], - markH: [37], - markPad: [65], - markRot: [37], - markScale: [65], - markTile: [56], - markW: [37], - markX: [65], - markY: [65], - mark: [99], - maskBg: [99], - mask: [99], - maxH: [65], - maxW: [65], - minH: [65], - minW: [65], - monochrome: [99], - nr: [65], - nrs: [65], - orient: [65], - padBottom: [65], - padLeft: [65], - padRight: [65], - padTop: [65], - pad: [65], - page: [65], - palette: [57], - pdfAnnotation: [23], - prefix: [99], - px: [65], - q: [65], - rect: [99], - reverse: [23], - rot: [37], - sat: [65], - sepia: [65], - shad: [37], - sharp: [37], - skip: [65], - transparency: [58], - trimColor: [99], - trimMd: [37], - trimPad: [65], - trimSd: [37], - trimTol: [37], - trim: [59], - txtAlign: [60], - txtClip: [61], - txtColor: [99], - txtFit: [62], - txtFont: [99], - txtLead: [65], - txtLig: [65], - txtLineColor: [99], - txtLine: [65], - txtPad: [65], - txtShad: [37], - txtSize: [65], - txtTrack: [65], - txtWidth: [65], - txtX: [65], - txtY: [65], - txt: [99], - usm: [65], - usmrad: [37], - vib: [65], - w: [37], - __typename: [99], + ar: [106], + auto: [43], + bgRemoveFallback: [26], + bgRemove: [26], + bgReplaceFallback: [26], + bgReplaceNegPrompt: [106], + bgReplace: [106], + bg: [106], + blendAlign: [44], + blendAlpha: [72], + blendColor: [106], + blendCrop: [45], + blendFit: [46], + blendH: [40], + blendMode: [47], + blendPad: [72], + blendSize: [48], + blendW: [40], + blendX: [72], + blendY: [72], + blend: [106], + blur: [72], + borderBottom: [72], + borderLeft: [72], + borderRadiusInner: [106], + borderRadius: [106], + borderRight: [72], + borderTop: [72], + border: [106], + bri: [72], + ch: [49], + chromasub: [72], + colorquant: [72], + colors: [72], + con: [72], + cornerRadius: [106], + crop: [50], + cs: [51], + dl: [106], + dpi: [72], + dpr: [40], + duotoneAlpha: [72], + duotone: [106], + exp: [72], + expires: [72], + faceindex: [72], + facepad: [40], + faces: [72], + fillColor: [106], + fillGenFallback: [26], + fillGenNegPrompt: [106], + fillGenPos: [53], + fillGenPrompt: [106], + fillGenSeed: [72], + fillGradientCs: [54], + fillGradientLinearDirection: [55], + fillGradientLinear: [106], + fillGradientRadialRadius: [106], + fillGradientRadialX: [40], + fillGradientRadialY: [40], + fillGradientRadial: [106], + fillGradientType: [56], + fill: [52], + fit: [57], + flip: [58], + fm: [59], + fpDebug: [26], + fpX: [40], + fpY: [40], + fpZ: [40], + fps: [72], + frame: [106], + gam: [72], + gifQ: [72], + gridColors: [106], + gridSize: [72], + h: [40], + high: [72], + htn: [72], + hue: [72], + interval: [72], + invert: [26], + iptc: [60], + jpgProgressive: [26], + loop: [72], + lossless: [26], + markAlign: [61], + markAlpha: [72], + markBase: [106], + markFit: [62], + markH: [40], + markPad: [72], + markRot: [40], + markScale: [72], + markTile: [63], + markW: [40], + markX: [72], + markY: [72], + mark: [106], + maskBg: [106], + mask: [106], + maxH: [72], + maxW: [72], + minH: [72], + minW: [72], + monochrome: [106], + nr: [72], + nrs: [72], + orient: [72], + padBottom: [72], + padLeft: [72], + padRight: [72], + padTop: [72], + pad: [72], + page: [72], + palette: [64], + pdfAnnotation: [26], + prefix: [106], + px: [72], + q: [72], + rect: [106], + reverse: [26], + rot: [40], + sat: [72], + sepia: [72], + shad: [40], + sharp: [40], + skip: [72], + svgSanitize: [26], + transparency: [65], + trimColor: [106], + trimMd: [40], + trimPad: [72], + trimSd: [40], + trimTol: [40], + trim: [66], + txtAlign: [67], + txtClip: [68], + txtColor: [106], + txtFit: [69], + txtFont: [106], + txtLead: [72], + txtLineColor: [106], + txtLine: [72], + txtPad: [72], + txtShad: [40], + txtSize: [72], + txtTrack: [72], + txtWidth: [72], + txtX: [72], + txtY: [72], + txt: [106], + upscaleFallback: [26], + upscale: [26], + usm: [72], + usmrad: [40], + vib: [72], + w: [40], + skipDefaultOptimizations: [26], + __typename: [106], }, ImgixParamsAuto: {}, ImgixParamsBlendAlign: {}, @@ -996,6 +1106,10 @@ export default { ImgixParamsCrop: {}, ImgixParamsCs: {}, ImgixParamsFill: {}, + ImgixParamsFillGenPos: {}, + ImgixParamsFillGradientCs: {}, + ImgixParamsFillGradientLinearDirection: {}, + ImgixParamsFillGradientType: {}, ImgixParamsFit: {}, ImgixParamsFlip: {}, ImgixParamsFm: {}, @@ -1010,557 +1124,564 @@ export default { ImgixParamsTxtClip: {}, ImgixParamsTxtFit: {}, InUseFilter: { - eq: [23], - __typename: [99], + eq: [26], + __typename: [106], }, Int: {}, IntType: {}, ItemId: {}, ItemIdFilter: { - eq: [66], - neq: [66], - in: [66], - notIn: [66], - __typename: [99], + eq: [73], + neq: [73], + in: [73], + notIn: [73], + __typename: [106], }, ItemStatus: {}, JsonField: {}, JsonFieldMultiLocaleField: { - locale: [96], - value: [69], - __typename: [99], + locale: [103], + value: [76], + __typename: [106], }, JsonFilter: { - exists: [23], - __typename: [99], + exists: [26], + __typename: [106], }, LayoutRecord: { _allAiFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allAiResearchFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allBackBitcashLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allBackHomeLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allBitcashNewsFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allBitcoinFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allCookieConsentCtaLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allCookieConsentDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allCryptoFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allEli5FollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allHomeFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allInvestingFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allNavigationCategoriesLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allNavigationPoliciesTermsLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allNavigationTopicLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSearchInputPlaceholderLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allStartUpsFollowLinksLocales: [ - 70, + 77, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSubscriptionCtaLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSubscriptionInputPlaceholderLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSubscriptionSubtitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allSubscriptionTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], aiFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], aiResearchFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], backBitcash: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], backHome: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], bitcashNewsFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], bitcoinFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], cookieConsentCta: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], cookieConsentDescription: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], cryptoFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], eli5FollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], homeFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], investingFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], navigationCategories: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], navigationPoliciesTerms: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], navigationTopic: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], searchInputPlaceholder: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], startUpsFollowLinks: [ - 69, + 76, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], subscriptionCta: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], subscriptionInputPlaceholder: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], subscriptionSubtitle: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], subscriptionTitle: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - __typename: [99], + __typename: [106], }, LocalesFilter: { - allIn: [96], - anyIn: [96], - notIn: [96], - __typename: [99], + allIn: [103], + anyIn: [103], + notIn: [103], + __typename: [106], }, MetaTagAttributes: {}, MuxThumbnailFormatType: {}, OrientationFilter: { - eq: [126], - neq: [126], - __typename: [99], + eq: [133], + neq: [133], + __typename: [106], }, PageSeoModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - description: [100], - pageSeo: [94], - seoType: [100], - title: [100], - OR: [77], - AND: [77], - __typename: [99], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + description: [107], + pageSeo: [101], + seoType: [107], + title: [107], + OR: [84], + AND: [84], + __typename: [106], }, PageSeoModelOrderBy: {}, PageSeoRecord: { _allDescriptionLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allPageSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], description: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - id: [66], + id: [73], pageSeo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - seoType: [99], + seoType: [106], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - __typename: [99], + __typename: [106], }, PrivacyPolicyModelMainContentField: { - blocks: [99], - links: [99], - value: [69], - __typename: [99], + blocks: [106], + links: [106], + value: [76], + __typename: [106], }, PrivacyPolicyModelMainContentFieldMultiLocaleField: { - locale: [96], - value: [80], - __typename: [99], + locale: [103], + value: [87], + __typename: [106], }, PrivacyPolicyRecord: { _allMainContentLocales: [ - 81, + 88, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - id: [66], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + id: [73], mainContent: [ - 80, + 87, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - __typename: [99], + __typename: [106], }, PublishedAtFilter: { - gt: [31], - lt: [31], - gte: [31], - lte: [31], - eq: [31], - neq: [31], - exists: [23], - __typename: [99], + gt: [34], + lt: [34], + gte: [34], + lte: [34], + eq: [34], + neq: [34], + exists: [26], + __typename: [106], }, Query: { _allBlogAisMeta: [ - 24, + 27, { - locale: [96], + locale: [103], filter: [0], }, ], _allBlogBitcashesMeta: [ - 24, + 27, { - locale: [96], + locale: [103], filter: [3], }, ], _allBlogBitcoinsMeta: [ - 24, + 27, { - locale: [96], + locale: [103], filter: [6], }, ], - _allBlogCryptosMeta: [ - 24, + _allBlogBitlaunchersMeta: [ + 27, { - locale: [96], + locale: [103], filter: [9], }, ], - _allBlogInvestingsMeta: [ - 24, + _allBlogCryptosMeta: [ + 27, { - locale: [96], + locale: [103], filter: [12], }, ], - _allBlogNewsMeta: [ - 24, + _allBlogInvestingsMeta: [ + 27, { - locale: [96], + locale: [103], filter: [15], }, ], - _allBlogStartupsMeta: [ - 24, + _allBlogNewsMeta: [ + 27, { - locale: [96], + locale: [103], filter: [18], }, ], + _allBlogStartupsMeta: [ + 27, + { + locale: [103], + filter: [21], + }, + ], _allPageSeosMeta: [ - 24, + 27, { - locale: [96], - filter: [77], + locale: [103], + filter: [84], }, ], _allResearchAisMeta: [ - 24, + 27, { - locale: [96], - filter: [86], + locale: [103], + filter: [93], }, ], _allUploadsMeta: [ - 24, + 27, { - locale: [96], - filter: [117], + locale: [103], + filter: [124], }, ], _site: [ - 95, + 102, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], allBlogAis: [ 2, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [0], orderBy: [1, '[BlogAiModelOrderBy]'], }, @@ -1568,10 +1689,10 @@ export default { allBlogBitcashes: [ 5, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [3], orderBy: [4, '[BlogBitcashModelOrderBy]'], }, @@ -1579,96 +1700,107 @@ export default { allBlogBitcoins: [ 8, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [6], orderBy: [7, '[BlogBitcoinModelOrderBy]'], }, ], - allBlogCryptos: [ + allBlogBitlaunchers: [ 11, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [9], - orderBy: [10, '[BlogCryptoModelOrderBy]'], + orderBy: [10, '[BlogBitlauncherModelOrderBy]'], }, ], - allBlogInvestings: [ + allBlogCryptos: [ 14, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [12], - orderBy: [13, '[BlogInvestingModelOrderBy]'], + orderBy: [13, '[BlogCryptoModelOrderBy]'], }, ], - allBlogNews: [ + allBlogInvestings: [ 17, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [15], - orderBy: [16, '[BlogNewsModelOrderBy]'], + orderBy: [16, '[BlogInvestingModelOrderBy]'], }, ], - allBlogStartups: [ + allBlogNews: [ 20, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], filter: [18], - orderBy: [19, '[BlogStartupModelOrderBy]'], + orderBy: [19, '[BlogNewsModelOrderBy]'], + }, + ], + allBlogStartups: [ + 23, + { + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], + filter: [21], + orderBy: [22, '[BlogStartupModelOrderBy]'], }, ], allPageSeos: [ - 79, + 86, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], - filter: [77], - orderBy: [78, '[PageSeoModelOrderBy]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], + filter: [84], + orderBy: [85, '[PageSeoModelOrderBy]'], }, ], allResearchAis: [ - 88, + 95, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], - filter: [86], - orderBy: [87, '[ResearchAiModelOrderBy]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], + filter: [93], + orderBy: [94, '[ResearchAiModelOrderBy]'], }, ], allUploads: [ - 33, + 36, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - skip: [65], - first: [65], - filter: [117], - orderBy: [125, '[UploadOrderBy]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + skip: [72], + first: [72], + filter: [124], + orderBy: [132, '[UploadOrderBy]'], }, ], blogAi: [ 2, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [0], orderBy: [1, '[BlogAiModelOrderBy]'], }, @@ -1676,8 +1808,8 @@ export default { blogBitcash: [ 5, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [3], orderBy: [4, '[BlogBitcashModelOrderBy]'], }, @@ -1685,592 +1817,629 @@ export default { blogBitcoin: [ 8, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [6], orderBy: [7, '[BlogBitcoinModelOrderBy]'], }, ], - blogCrypto: [ + blogBitlauncher: [ 11, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [9], - orderBy: [10, '[BlogCryptoModelOrderBy]'], + orderBy: [10, '[BlogBitlauncherModelOrderBy]'], }, ], - blogInvesting: [ + blogCrypto: [ 14, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [12], - orderBy: [13, '[BlogInvestingModelOrderBy]'], + orderBy: [13, '[BlogCryptoModelOrderBy]'], }, ], - blogNews: [ + blogInvesting: [ 17, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [15], - orderBy: [16, '[BlogNewsModelOrderBy]'], + orderBy: [16, '[BlogInvestingModelOrderBy]'], }, ], - blogStartup: [ + blogNews: [ 20, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], filter: [18], - orderBy: [19, '[BlogStartupModelOrderBy]'], + orderBy: [19, '[BlogNewsModelOrderBy]'], + }, + ], + blogStartup: [ + 23, + { + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + filter: [21], + orderBy: [22, '[BlogStartupModelOrderBy]'], }, ], layout: [ - 72, + 79, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], pageSeo: [ - 79, + 86, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - filter: [77], - orderBy: [78, '[PageSeoModelOrderBy]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + filter: [84], + orderBy: [85, '[PageSeoModelOrderBy]'], }, ], privacyPolicy: [ - 82, + 89, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], researchAi: [ - 88, + 95, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - filter: [86], - orderBy: [87, '[ResearchAiModelOrderBy]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + filter: [93], + orderBy: [94, '[ResearchAiModelOrderBy]'], }, ], termsAndCondition: [ - 106, + 113, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], upload: [ - 33, + 36, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], - filter: [117], - orderBy: [125, '[UploadOrderBy]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + filter: [124], + orderBy: [132, '[UploadOrderBy]'], }, ], - __typename: [99], + __typename: [106], }, RecordInterface: { - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - id: [66], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + id: [73], on_BlogAiRecord: [2], on_BlogBitcashRecord: [5], on_BlogBitcoinRecord: [8], - on_BlogCryptoRecord: [11], - on_BlogInvestingRecord: [14], - on_BlogNewsRecord: [17], - on_BlogStartupRecord: [20], - on_ContentBlockRecord: [28], - on_LayoutRecord: [72], - on_PageSeoRecord: [79], - on_PrivacyPolicyRecord: [82], - on_ResearchAiRecord: [88], - on_TermsAndConditionRecord: [106], - on_TopicRecord: [107], - __typename: [99], + on_BlogBitlauncherRecord: [11], + on_BlogCryptoRecord: [14], + on_BlogInvestingRecord: [17], + on_BlogNewsRecord: [20], + on_BlogStartupRecord: [23], + on_ContentBlockRecord: [31], + on_LayoutRecord: [79], + on_PageSeoRecord: [86], + on_PrivacyPolicyRecord: [89], + on_ResearchAiRecord: [95], + on_TermsAndConditionRecord: [113], + on_TopicRecord: [114], + __typename: [106], }, ResearchAiModelFilter: { - _createdAt: [29], - id: [67], - _firstPublishedAt: [83], - _publicationScheduledAt: [83], - _unpublishingScheduledAt: [83], - _publishedAt: [83], - _status: [98], - _updatedAt: [109], - _isValid: [22], - _locales: [73], - authorName: [100], - authorPicture: [35], - description: [100], - seo: [94], - slug: [97], - thumbnail: [35], - title: [100], - topics: [71], - OR: [86], - AND: [86], - __typename: [99], + _createdAt: [32], + id: [74], + _firstPublishedAt: [90], + _publicationScheduledAt: [90], + _unpublishingScheduledAt: [90], + _publishedAt: [90], + _status: [105], + _updatedAt: [116], + _isValid: [25], + _locales: [80], + authorName: [107], + authorPicture: [38], + description: [107], + seo: [101], + slug: [104], + thumbnail: [38], + title: [107], + topics: [78], + OR: [93], + AND: [93], + __typename: [106], }, ResearchAiModelOrderBy: {}, ResearchAiRecord: { _allSeoLocales: [ - 93, + 100, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], _allTitleLocales: [ - 102, + 109, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - authorName: [99], - authorPicture: [33], - contentBlock: [28], - description: [99], - id: [66], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + authorName: [106], + authorPicture: [36], + contentBlock: [31], + description: [106], + id: [73], seo: [ - 92, + 99, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - slug: [99], - thumbnail: [33], + slug: [106], + thumbnail: [36], title: [ - 99, + 106, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - topics: [69], - __typename: [99], + topics: [76], + __typename: [106], }, ResolutionFilter: { - eq: [90], - neq: [90], - in: [90], - notIn: [90], - __typename: [99], + eq: [97], + neq: [97], + in: [97], + notIn: [97], + __typename: [106], }, ResolutionType: {}, ResponsiveImage: { - alt: [99], - aspectRatio: [37], - base64: [99], - bgColor: [99], - height: [65], - sizes: [99], - src: [99], - srcSet: [99], - title: [99], - webpSrcSet: [99], - width: [65], - __typename: [99], + alt: [106], + aspectRatio: [40], + base64: [106], + bgColor: [106], + height: [72], + sizes: [106], + src: [106], + srcSet: [106], + title: [106], + webpSrcSet: [106], + width: [72], + __typename: [106], }, SeoField: { - description: [99], - image: [33], - noIndex: [23], - title: [99], - twitterCard: [99], - __typename: [99], + description: [106], + image: [36], + noIndex: [26], + title: [106], + twitterCard: [106], + __typename: [106], }, SeoFieldMultiLocaleField: { - locale: [96], - value: [92], - __typename: [99], + locale: [103], + value: [99], + __typename: [106], }, SeoFilter: { - exists: [23], - __typename: [99], + exists: [26], + __typename: [106], }, Site: { - favicon: [33], + favicon: [36], faviconMetaTags: [ - 103, + 110, { - variants: [32, '[FaviconType]'], + variants: [35, '[FaviconType]'], }, ], globalSeo: [ - 38, + 41, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - locales: [96], - noIndex: [23], - __typename: [99], + locales: [103], + noIndex: [26], + __typename: [106], }, SiteLocale: {}, SlugFilter: { - eq: [99], - neq: [99], - in: [99], - notIn: [99], - __typename: [99], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + __typename: [106], }, StatusFilter: { - eq: [68], - neq: [68], - in: [68], - notIn: [68], - __typename: [99], + eq: [75], + neq: [75], + in: [75], + notIn: [75], + __typename: [106], }, String: {}, StringFilter: { - matches: [101], - notMatches: [101], - isBlank: [23], - isPresent: [23], - eq: [99], - neq: [99], - in: [99], - notIn: [99], - exists: [23], - __typename: [99], + matches: [108], + notMatches: [108], + isBlank: [26], + isPresent: [26], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + exists: [26], + __typename: [106], }, StringMatchesFilter: { - pattern: [99], - caseSensitive: [23], - regexp: [23], - __typename: [99], + pattern: [106], + caseSensitive: [26], + regexp: [26], + __typename: [106], }, StringMultiLocaleField: { - locale: [96], - value: [99], - __typename: [99], + locale: [103], + value: [106], + __typename: [106], }, Tag: { - attributes: [74], - content: [99], - tag: [99], - __typename: [99], + attributes: [81], + content: [106], + tag: [106], + __typename: [106], }, TermsAndConditionModelMainContentField: { - blocks: [99], - links: [99], - value: [69], - __typename: [99], + blocks: [106], + links: [106], + value: [76], + __typename: [106], }, TermsAndConditionModelMainContentFieldMultiLocaleField: { - locale: [96], - value: [104], - __typename: [99], + locale: [103], + value: [111], + __typename: [106], }, TermsAndConditionRecord: { _allMainContentLocales: [ - 105, + 112, { - fallbackLocales: [96, '[SiteLocale!]'], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _locales: [96], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _locales: [103], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - id: [66], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + id: [73], mainContent: [ - 104, + 111, { - locale: [96], - fallbackLocales: [96, '[SiteLocale!]'], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - __typename: [99], + __typename: [106], }, TopicRecord: { - _createdAt: [31], - _editingUrl: [99], - _firstPublishedAt: [31], - _isValid: [23], - _modelApiKey: [99], - _publicationScheduledAt: [31], - _publishedAt: [31], + _createdAt: [34], + _editingUrl: [106], + _firstPublishedAt: [34], + _isValid: [26], + _modelApiKey: [106], + _publicationScheduledAt: [34], + _publishedAt: [34], _seoMetaTags: [ - 103, + 110, { - locale: [96], + locale: [103], }, ], - _status: [68], - _unpublishingScheduledAt: [31], - _updatedAt: [31], - id: [66], - __typename: [99], + _status: [75], + _unpublishingScheduledAt: [34], + _updatedAt: [34], + id: [73], + __typename: [106], }, TypeFilter: { - eq: [130], - neq: [130], - in: [130], - notIn: [130], - __typename: [99], + eq: [137], + neq: [137], + in: [137], + notIn: [137], + __typename: [106], }, UpdatedAtFilter: { - gt: [31], - lt: [31], - gte: [31], - lte: [31], - eq: [31], - neq: [31], - exists: [23], - __typename: [99], + gt: [34], + lt: [34], + gte: [34], + lte: [34], + eq: [34], + neq: [34], + exists: [26], + __typename: [106], }, UploadAltFilter: { - matches: [101], - notMatches: [101], - eq: [99], - neq: [99], - in: [99], - notIn: [99], - exists: [23], - __typename: [99], + matches: [108], + notMatches: [108], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + exists: [26], + __typename: [106], }, UploadAuthorFilter: { - matches: [101], - notMatches: [101], - exists: [23], - __typename: [99], + matches: [108], + notMatches: [108], + exists: [26], + __typename: [106], }, UploadBasenameFilter: { - matches: [101], - notMatches: [101], - __typename: [99], + matches: [108], + notMatches: [108], + __typename: [106], }, UploadColorsFilter: { - contains: [25], - allIn: [25], - anyIn: [25], - notIn: [25], - eq: [25], - __typename: [99], + contains: [28], + allIn: [28], + anyIn: [28], + notIn: [28], + eq: [28], + __typename: [106], }, UploadCopyrightFilter: { - matches: [101], - notMatches: [101], - exists: [23], - __typename: [99], + matches: [108], + notMatches: [108], + exists: [26], + __typename: [106], }, UploadCreatedAtFilter: { - eq: [31], - neq: [31], - lt: [31], - lte: [31], - gt: [31], - gte: [31], - __typename: [99], + eq: [34], + neq: [34], + lt: [34], + lte: [34], + gt: [34], + gte: [34], + __typename: [106], }, UploadFilenameFilter: { - matches: [101], - notMatches: [101], - __typename: [99], + matches: [108], + notMatches: [108], + __typename: [106], }, UploadFilter: { - type: [108], - inUse: [63], - resolution: [89], - size: [127], - tags: [128], - smartTags: [128], - colors: [113], - orientation: [76], - id: [121], - mimeType: [123], - format: [118], - height: [119], - width: [133], - alt: [110], - title: [129], - notes: [124], - md5: [122], - author: [111], - copyright: [114], - basename: [112], - filename: [116], - _createdAt: [115], - _updatedAt: [131], - OR: [117], - AND: [117], - __typename: [99], + type: [115], + inUse: [70], + resolution: [96], + size: [134], + tags: [135], + smartTags: [135], + colors: [120], + orientation: [83], + id: [128], + mimeType: [130], + format: [125], + height: [126], + width: [140], + alt: [117], + title: [136], + notes: [131], + md5: [129], + author: [118], + copyright: [121], + basename: [119], + filename: [123], + _createdAt: [122], + _updatedAt: [138], + OR: [124], + AND: [124], + __typename: [106], }, UploadFormatFilter: { - eq: [99], - neq: [99], - in: [99], - notIn: [99], - __typename: [99], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + __typename: [106], }, UploadHeightFilter: { - gt: [65], - lt: [65], - gte: [65], - lte: [65], - eq: [65], - neq: [65], - __typename: [99], + gt: [72], + lt: [72], + gte: [72], + lte: [72], + eq: [72], + neq: [72], + __typename: [106], }, UploadId: {}, UploadIdFilter: { - eq: [120], - neq: [120], - in: [120], - notIn: [120], - __typename: [99], + eq: [127], + neq: [127], + in: [127], + notIn: [127], + __typename: [106], }, UploadMd5Filter: { - eq: [99], - neq: [99], - in: [99], - notIn: [99], - __typename: [99], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + __typename: [106], }, UploadMimeTypeFilter: { - matches: [101], - notMatches: [101], - eq: [99], - neq: [99], - in: [99], - notIn: [99], - __typename: [99], + matches: [108], + notMatches: [108], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + __typename: [106], }, UploadNotesFilter: { - matches: [101], - notMatches: [101], - exists: [23], - __typename: [99], + matches: [108], + notMatches: [108], + exists: [26], + __typename: [106], }, UploadOrderBy: {}, UploadOrientation: {}, UploadSizeFilter: { - gt: [65], - lt: [65], - gte: [65], - lte: [65], - eq: [65], - neq: [65], - __typename: [99], + gt: [72], + lt: [72], + gte: [72], + lte: [72], + eq: [72], + neq: [72], + __typename: [106], }, UploadTagsFilter: { - contains: [99], - allIn: [99], - anyIn: [99], - notIn: [99], - eq: [99], - __typename: [99], + contains: [106], + allIn: [106], + anyIn: [106], + notIn: [106], + eq: [106], + __typename: [106], }, UploadTitleFilter: { - matches: [101], - notMatches: [101], - eq: [99], - neq: [99], - in: [99], - notIn: [99], - exists: [23], - __typename: [99], + matches: [108], + notMatches: [108], + eq: [106], + neq: [106], + in: [106], + notIn: [106], + exists: [26], + __typename: [106], }, UploadType: {}, UploadUpdatedAtFilter: { - eq: [31], - neq: [31], - lt: [31], - lte: [31], - gt: [31], - gte: [31], - __typename: [99], + eq: [34], + neq: [34], + lt: [34], + lte: [34], + gt: [34], + gte: [34], + __typename: [106], }, UploadVideoField: { - duration: [64], - framerate: [64], + alt: [ + 106, + { + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], + }, + ], + blurUpThumb: [ + 106, + { + punch: [39, 'Float!'], + size: [71, 'Int!'], + quality: [71, 'Int!'], + imgixParams: [42], + }, + ], + blurhash: [106], + duration: [71], + framerate: [71], + height: [72], mp4Url: [ - 99, + 106, { - res: [134], - exactRes: [134], + res: [141], + exactRes: [141], }, ], - muxAssetId: [99], - muxPlaybackId: [99], - streamingUrl: [99], + muxAssetId: [106], + muxPlaybackId: [106], + streamingUrl: [106], + thumbhash: [106], thumbnailUrl: [ - 99, + 106, + { + format: [82], + }, + ], + title: [ + 106, { - format: [75], + locale: [103], + fallbackLocales: [103, '[SiteLocale!]'], }, ], - __typename: [99], + width: [72], + __typename: [106], }, UploadWidthFilter: { - gt: [65], - lt: [65], - gte: [65], - lte: [65], - eq: [65], - neq: [65], - __typename: [99], + gt: [72], + lt: [72], + gte: [72], + lte: [72], + eq: [72], + neq: [72], + __typename: [106], }, VideoMp4Res: {}, focalPoint: { - x: [37], - y: [37], - __typename: [99], + x: [40], + y: [40], + __typename: [106], }, }, } diff --git a/apps/webapp/services/supabase/middleware.ts b/apps/webapp/services/supabase/middleware.ts index 3d6f710f1..1c2985928 100644 --- a/apps/webapp/services/supabase/middleware.ts +++ b/apps/webapp/services/supabase/middleware.ts @@ -2,8 +2,6 @@ import { type CookieOptions, createServerClient } from '@supabase/ssr' import { type NextRequest, NextResponse } from 'next/server' export const updateSession = async (request: NextRequest) => { - // This `try/catch` block is only here for the interactive tutorial. - // Feel free to remove once you have Supabase connected. try { // Create an unmodified response let response = NextResponse.next({ diff --git a/apps/webapp/services/supabase/service.ts b/apps/webapp/services/supabase/service.ts new file mode 100644 index 000000000..dc8864431 --- /dev/null +++ b/apps/webapp/services/supabase/service.ts @@ -0,0 +1,55 @@ +import type { SupabaseClient } from '@supabase/supabase-js' + +/** + * Fetches presale data for a specific project from Supabase + * @param {ProjectDataParams} params - Object containing projectId and supabase client + * @returns {Promise} Presale data for the specified project + * @throws {Error} If there's an error fetching the data + */ +export async function getPresaleData({ + projectId, + supabase, +}: ProjectDataParams) { + const { data, error } = await supabase + .from('presale') + .select('*') + .eq('id', projectId) + .single() + + if (error) { + console.error('Error fetching presale data:', error) + throw error + } + + return data +} + +/** + * Fetches project data for a specific project from Supabase + * @param {ProjectDataParams} params - Object containing projectId and supabase client + * @returns {Promise} Project data for the specified project + * @throws {Error} If there's an error fetching the data + */ +export async function getProjectData({ + projectId, + supabase, +}: ProjectDataParams) { + const { data, error } = await supabase + .from('project') + .select('*') + .eq('id', projectId) + .single() + + if (error) { + console.error('Error fetching project data:', error) + throw error + } + + return data +} + +// Interface for function parameters +interface ProjectDataParams { + projectId: number + supabase: SupabaseClient +} diff --git a/apps/webapp/tailwind.config.js b/apps/webapp/tailwind.config.js index ac9f027d3..34680e6f0 100644 --- a/apps/webapp/tailwind.config.js +++ b/apps/webapp/tailwind.config.js @@ -31,6 +31,7 @@ module.exports = { ring: 'hsla(var(--ring))', background: 'hsla(var(--background))', foreground: 'hsla(var(--foreground))', + infoForeground: '#9395AF', cornflowerblue: { 100: 'rgba(125, 129, 217, 0.2)', 200: 'rgba(125, 129, 217, 0.2)', @@ -177,7 +178,7 @@ module.exports = { 'sub-1-lg': ['36px', { lineHeight: '40px' }], 'sub-1-md': ['28px', { lineHeight: '40px' }], 'sub-2-lg': [ - '24px', + '22px', { lineHeight: '28px' }, { fontFamily: 'futura-pt-bold' }, ], diff --git a/bun.lockb b/bun.lockb index 04eeaf04d..6c5f40ec0 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 54e6c2453..3104f922b 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "bitlauncher monorepo", "author": "bitcash.org", "license": "MIT", + "type": "module", "private": true, "scripts": { "build": "turbo build --no-daemon", diff --git a/packages/alchemy/.gitignore b/packages/alchemy/.gitignore new file mode 100644 index 000000000..9b1ee42e8 --- /dev/null +++ b/packages/alchemy/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/packages/alchemy/README.md b/packages/alchemy/README.md new file mode 100644 index 000000000..a6afb1292 --- /dev/null +++ b/packages/alchemy/README.md @@ -0,0 +1,38 @@ +# Alchemy Hooks + +This project sets up Alchemy webhooks to listen for blockchain events. +These hooks invoke Trigger.dev jobs that process the events using Viem. + +## Getting Started + +This project follows the [Alchemy SDK Developer Challenge Guide](https://docs.alchemy.com/docs/sdk-developer-challenge-guide-7) to set up and configure Alchemy webhooks. The guide provides step-by-step instructions. For detailed implementation steps and best practices, refer to the guide above. + + +## Dependencies + + [Alchemy SDK](https://www.npmjs.com/package/alchemy-sdk): Used for interacting with Alchemy's API and setting up webhooks. + [Trigger.dev](https://www.npmjs.com/package/@trigger.dev/sdk): Used for creating and managing serverless functions and workflows. + [Viem](https://www.npmjs.com/package/viem): Ethereum JavaScript library for interacting with the Ethereum blockchain. + +## Documentation + +For more information on how to use Alchemy's services and set up webhooks, refer to the [Alchemy Documentation](https://docs.alchemy.com/). + +## Related Projects + +For details on how these webhooks are processed and used in our Trigger.dev jobs, please see the [Trigger App README](../trigger/README.md). + + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run src/index.ts +``` + +This project was created using `bun init` in bun v1.1.24. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/packages/alchemy/package.json b/packages/alchemy/package.json new file mode 100644 index 000000000..3fafada28 --- /dev/null +++ b/packages/alchemy/package.json @@ -0,0 +1,20 @@ +{ + "name": "@repo/alchemy", + "module": "src/index.ts", + "types": "src/index.d.ts", + "scripts": { + "create": "bun src/create.ts" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@repo/tokens": "workspace:*", + "alchemy-sdk": "^3.4.1", + "viem": "^2.20.0", + "zod": "^3.23.8" + } +} diff --git a/packages/alchemy/src/config.ts b/packages/alchemy/src/config.ts new file mode 100644 index 000000000..d0806a706 --- /dev/null +++ b/packages/alchemy/src/config.ts @@ -0,0 +1,22 @@ +import { isAddress } from 'viem' +import { z } from 'zod' + +const envSchema = z.object({ + ALCHEMY_NOTIFY_TOKEN: z.string().min(1, 'Alchemy notify token is required'), + ALCHEMY_ACTIVITY_WEBHOOK_URL: z.string().url('Invalid webhook URL'), + PRESALE_ADDRESS: z.string().refine(isAddress, 'Invalid Presale address'), +}) + +const parsedEnv = envSchema.safeParse(process.env) +if (!parsedEnv.success) { + console.error( + `Environment validation failed: ${JSON.stringify(parsedEnv.error.format())}`, + ) + process.exit(1) +} + +export const appConfig = { + alchemyNotifyToken: parsedEnv.data.ALCHEMY_NOTIFY_TOKEN, + alchemyActivityWebhookUrl: parsedEnv.data.ALCHEMY_ACTIVITY_WEBHOOK_URL, + presaleAddress: parsedEnv.data.PRESALE_ADDRESS, +} diff --git a/packages/alchemy/src/create.ts b/packages/alchemy/src/create.ts new file mode 100644 index 000000000..9527522be --- /dev/null +++ b/packages/alchemy/src/create.ts @@ -0,0 +1,30 @@ +import { Alchemy, Network, WebhookType } from 'alchemy-sdk' +import { appConfig } from './config' + +async function createAddressActivityNotification() { + try { + const settings = { + authToken: appConfig.alchemyNotifyToken, + network: Network.MATIC_MAINNET, // Replace with your network. + } + + const alchemy = new Alchemy(settings) + const addressActivityWebhook = await alchemy.notify.createWebhook( + appConfig.alchemyActivityWebhookUrl, + WebhookType.ADDRESS_ACTIVITY, + { + addresses: [appConfig.presaleAddress], + network: Network.MATIC_MAINNET, + }, + ) + console.log('Address Activity Webhook Details:') + console.log(JSON.stringify(addressActivityWebhook, null, 2)) + console.log( + 'Alchemy Notify address activity notification created, go to https://dashboard.alchemy.com/notify to see details of your custom hook.', + ) + } catch (error) { + console.error('Failed to create address activity notification:', error) + } +} + +createAddressActivityNotification() diff --git a/packages/alchemy/src/index.ts b/packages/alchemy/src/index.ts new file mode 100644 index 000000000..c9f6f047d --- /dev/null +++ b/packages/alchemy/src/index.ts @@ -0,0 +1 @@ +export * from './types' diff --git a/packages/alchemy/src/types.ts b/packages/alchemy/src/types.ts new file mode 100644 index 000000000..457b6c6b0 --- /dev/null +++ b/packages/alchemy/src/types.ts @@ -0,0 +1,46 @@ +import type { Network } from 'alchemy-sdk' +export interface AlchemyWebhookEvent { + webhookId: string + id: string + createdAt: Date + type: AlchemyWebhookType + event: Record +} + +export type AlchemyWebhookType = + | 'MINED_TRANSACTION' + | 'DROPPED_TRANSACTION' + | 'ADDRESS_ACTIVITY' + +export interface AlchemyActivity { + fromAddress: string + toAddress: string + blockNum: string + hash: string + value: number + asset: string + category: string + rawContract: { + rawValue: string + address: string + decimals: number + } + log?: { + address: string + topics: string[] + data: string + blockNumber: string + transactionHash: string + transactionIndex: string + blockHash: string + logIndex: string + removed: boolean + } +} + +export interface AlchemyActivityEvent { + network: AlchemyNetwork + activity: AlchemyActivity[] +} + +export type AlchemyNetwork = keyof typeof Network diff --git a/packages/alchemy/tsconfig.json b/packages/alchemy/tsconfig.json new file mode 100644 index 000000000..6432ecae3 --- /dev/null +++ b/packages/alchemy/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../packages/tsconfig/node16.json", + "include": ["./src/**/*", "src/lib/utils.ts"], + "exclude": ["node_modules"], + "compilerOptions": { + "sourceMap": true, + "inlineSources": true, + "sourceRoot": "/", + "outDir": "dist", + "baseUrl": "./src", + "paths": { + "~/*": ["./*"], + "@/*": ["/*"] + } + } +} diff --git a/packages/app-env/package.json b/packages/app-env/package.json index 984df8e0f..2da59a013 100644 --- a/packages/app-env/package.json +++ b/packages/app-env/package.json @@ -9,10 +9,10 @@ "types": "./src/index.ts", "dependencies": { "viem": "latest", - "app-contracts": "workspace:*" + "@repo/contracts": "workspace:*" }, "devDependencies": { - "@repo/typescript-config": "workspace:*", + "@repo/tsconfig": "workspace:*", "typescript": "^5.3.3" } } diff --git a/packages/app-env/src/chains.ts b/packages/app-env/src/chains.ts index ee618c150..f5f9653fb 100644 --- a/packages/app-env/src/chains.ts +++ b/packages/app-env/src/chains.ts @@ -1,23 +1,13 @@ import type { Chain } from 'viem' import { arbitrum, - aurora, avalanche, base, bsc, - celo, - cronos, - fantom, - gnosis, - harmonyOne, - kava, mainnet, - metis, - moonbeam, optimism, polygon, sepolia, - zkSync, } from 'viem/chains' export const eosEvmTestnet: Chain = { @@ -41,26 +31,19 @@ export const eosEvmTestnet: Chain = { testnet: true, } -const prodChains: Chain[] = [ - arbitrum, - avalanche, +export const prodChains: Chain[] = [ base, - celo, - mainnet, + arbitrum, optimism, polygon, - zkSync, - bsc, - fantom, - moonbeam, - cronos, - kava, - metis, - gnosis, - aurora, - harmonyOne, + mainnet, // Ethereum + avalanche, + bsc, // BNB Chain ] -const devChains: Chain[] = [eosEvmTestnet, sepolia] + +// Note: Solana is not included as it's not an EVM-compatible chain and not supported by viem + +export const devChains: Chain[] = [eosEvmTestnet, sepolia] // note: use .entries() to get an array export const appChains = { diff --git a/packages/app-env/src/env.ts b/packages/app-env/src/env.ts index e61719b80..705229046 100644 --- a/packages/app-env/src/env.ts +++ b/packages/app-env/src/env.ts @@ -7,7 +7,7 @@ import { type TokenContractData, usdcContracts, usdtContracts, -} from 'app-contracts' +} from '@repo/contracts' import type { Address, Chain } from 'viem' import { appChains } from './chains' diff --git a/packages/contracts/README.md b/packages/contracts/README.md new file mode 100644 index 000000000..823b520cd --- /dev/null +++ b/packages/contracts/README.md @@ -0,0 +1,15 @@ +# @repo/contracts + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run ./src/index.ts +``` + +This project was created using `bun init` in bun v1.1.24. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/packages/app-contracts/package.json b/packages/contracts/package.json similarity index 70% rename from packages/app-contracts/package.json rename to packages/contracts/package.json index 11c93a877..072dde042 100644 --- a/packages/app-contracts/package.json +++ b/packages/contracts/package.json @@ -1,5 +1,5 @@ { - "name": "app-contracts", + "name": "@repo/contracts", "version": "0.0.1", "private": true, "description": "Smartsale Smart Contracts Data", @@ -12,7 +12,8 @@ "viem": "latest" }, "devDependencies": { - "@repo/typescript-config": "workspace:*", - "typescript": "^5.3.3" + "@repo/tsconfig": "workspace:*", + "typescript": "^5.3.3", + "@types/bun": "latest" } } diff --git a/packages/app-contracts/src/dev/auction/testnet-allow-list.ts b/packages/contracts/src/dev/auction/testnet-allow-list.ts similarity index 100% rename from packages/app-contracts/src/dev/auction/testnet-allow-list.ts rename to packages/contracts/src/dev/auction/testnet-allow-list.ts diff --git a/packages/app-contracts/src/dev/auction/testnet-deposit-order.ts b/packages/contracts/src/dev/auction/testnet-deposit-order.ts similarity index 100% rename from packages/app-contracts/src/dev/auction/testnet-deposit-order.ts rename to packages/contracts/src/dev/auction/testnet-deposit-order.ts diff --git a/packages/app-contracts/src/dev/auction/testnet-easy-auction.ts b/packages/contracts/src/dev/auction/testnet-easy-auction.ts similarity index 100% rename from packages/app-contracts/src/dev/auction/testnet-easy-auction.ts rename to packages/contracts/src/dev/auction/testnet-easy-auction.ts diff --git a/packages/app-contracts/src/dev/index.ts b/packages/contracts/src/dev/index.ts similarity index 100% rename from packages/app-contracts/src/dev/index.ts rename to packages/contracts/src/dev/index.ts diff --git a/packages/app-contracts/src/dev/tokens/eos-fake-bitusd.ts b/packages/contracts/src/dev/tokens/eos-fake-bitusd.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/eos-fake-bitusd.ts rename to packages/contracts/src/dev/tokens/eos-fake-bitusd.ts diff --git a/packages/app-contracts/src/dev/tokens/eos-fake-usdt.ts b/packages/contracts/src/dev/tokens/eos-fake-usdt.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/eos-fake-usdt.ts rename to packages/contracts/src/dev/tokens/eos-fake-usdt.ts diff --git a/packages/app-contracts/src/dev/tokens/sepolia-usdt.ts b/packages/contracts/src/dev/tokens/sepolia-usdt.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/sepolia-usdt.ts rename to packages/contracts/src/dev/tokens/sepolia-usdt.ts diff --git a/packages/app-contracts/src/dev/tokens/testnet-blpl.ts b/packages/contracts/src/dev/tokens/testnet-blpl.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/testnet-blpl.ts rename to packages/contracts/src/dev/tokens/testnet-blpl.ts diff --git a/packages/app-contracts/src/dev/tokens/testnet-mbots-prelaunch.ts b/packages/contracts/src/dev/tokens/testnet-mbots-prelaunch.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/testnet-mbots-prelaunch.ts rename to packages/contracts/src/dev/tokens/testnet-mbots-prelaunch.ts diff --git a/packages/app-contracts/src/dev/tokens/testnet-usd-cred.ts b/packages/contracts/src/dev/tokens/testnet-usd-cred.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/testnet-usd-cred.ts rename to packages/contracts/src/dev/tokens/testnet-usd-cred.ts diff --git a/packages/app-contracts/src/dev/tokens/testnet-usdt.ts b/packages/contracts/src/dev/tokens/testnet-usdt.ts similarity index 100% rename from packages/app-contracts/src/dev/tokens/testnet-usdt.ts rename to packages/contracts/src/dev/tokens/testnet-usdt.ts diff --git a/packages/app-contracts/src/index.ts b/packages/contracts/src/index.ts similarity index 100% rename from packages/app-contracts/src/index.ts rename to packages/contracts/src/index.ts diff --git a/packages/app-contracts/src/prod/index.ts b/packages/contracts/src/prod/index.ts similarity index 100% rename from packages/app-contracts/src/prod/index.ts rename to packages/contracts/src/prod/index.ts diff --git a/packages/app-contracts/src/prod/tokens/eos-bitusd.ts b/packages/contracts/src/prod/tokens/eos-bitusd.ts similarity index 100% rename from packages/app-contracts/src/prod/tokens/eos-bitusd.ts rename to packages/contracts/src/prod/tokens/eos-bitusd.ts diff --git a/packages/app-contracts/src/prod/tokens/eos-usdt.ts b/packages/contracts/src/prod/tokens/eos-usdt.ts similarity index 100% rename from packages/app-contracts/src/prod/tokens/eos-usdt.ts rename to packages/contracts/src/prod/tokens/eos-usdt.ts diff --git a/packages/app-contracts/src/prod/tokens/usdc.ts b/packages/contracts/src/prod/tokens/usdc.ts similarity index 100% rename from packages/app-contracts/src/prod/tokens/usdc.ts rename to packages/contracts/src/prod/tokens/usdc.ts diff --git a/packages/app-contracts/src/prod/tokens/usdt.ts b/packages/contracts/src/prod/tokens/usdt.ts similarity index 100% rename from packages/app-contracts/src/prod/tokens/usdt.ts rename to packages/contracts/src/prod/tokens/usdt.ts diff --git a/packages/app-contracts/src/types.ts b/packages/contracts/src/types.ts similarity index 99% rename from packages/app-contracts/src/types.ts rename to packages/contracts/src/types.ts index 21be7a77a..85f86698e 100644 --- a/packages/app-contracts/src/types.ts +++ b/packages/contracts/src/types.ts @@ -1,5 +1,6 @@ import type { Abi, Address } from 'abitype' import type { Chain } from 'viem' + export interface ContractData { abi: Abi address: Address | string @@ -8,6 +9,7 @@ export interface ContractData { chainName: string indexFromBlock: number } + export interface TokenContractData extends ContractData { name: string symbol: string diff --git a/packages/app-contracts/tsconfig.json b/packages/contracts/tsconfig.json similarity index 100% rename from packages/app-contracts/tsconfig.json rename to packages/contracts/tsconfig.json diff --git a/packages/jobs/.env-sample b/packages/jobs/.env-sample new file mode 100644 index 000000000..5ffc4485d --- /dev/null +++ b/packages/jobs/.env-sample @@ -0,0 +1,5 @@ +DATABASE_URL="your_supabase_postgres_url" +SEPOLIA_RPC=https://eth-sepolia.g.alchemy.com/v2/xxx +ISSUER_KEY=xxx +ISSUER_ADDRESS=0x +PRESALE_ADDRESS=0x \ No newline at end of file diff --git a/packages/jobs/.gitignore b/packages/jobs/.gitignore new file mode 100644 index 000000000..6524f048d --- /dev/null +++ b/packages/jobs/.gitignore @@ -0,0 +1 @@ +.trigger \ No newline at end of file diff --git a/packages/jobs/README.md b/packages/jobs/README.md new file mode 100644 index 000000000..826636969 --- /dev/null +++ b/packages/jobs/README.md @@ -0,0 +1,23 @@ +# Trigger.dev Background Jobs + +This directory contains the configuration and implementation of background jobs using Trigger.dev for the Basilica project. + +## Overview + +Trigger.dev is an open-source job scheduling and execution platform that allows us to create, manage, and monitor background jobs efficiently. We use it for various issuance-related tasks and to handle webhook events from services like Moralis and Alchemy. + +## Key Features + +- **Webhook Integration**: Trigger.dev provides URLs that can be called from external webhooks, allowing us to process events from Moralis and Alchemy Web3 hooks. +- **Job Scheduling**: Easily schedule and manage recurring or one-time jobs. +- **Open Source**: Trigger.dev is open-source, providing flexibility and the option for self-hosting in the future if needed. +- **Cost-Effective**: Offers a robust feature set at a competitive price point. + +## Usage + +For detailed instructions on setting up and using Trigger.dev jobs, please refer to the official Trigger.dev documentation: + +[Trigger.dev Documentation](https://trigger.dev/docs) + +This comprehensive guide covers everything from creating your first job to advanced usage and best practices. + diff --git a/packages/jobs/package.json b/packages/jobs/package.json new file mode 100644 index 000000000..7eaf5fb89 --- /dev/null +++ b/packages/jobs/package.json @@ -0,0 +1,17 @@ +{ + "name": "@repo/jobs", + "version": "0.0.1", + "private": true, + "main": "src/index.ts", + "scripts": { + "dev": "bunx trigger.dev@beta dev", + "deploy:staging": "bunx trigger.dev@beta deploy --env staging", + "deploy:prod": "bunx trigger.dev@beta deploy --env prod" + }, + "dependencies": { + "@repo/alchemy": "workspace:*", + "@trigger.dev/sdk": "3.0.0-beta.55", + "alchemy-sdk": "^3.4.1", + "viem": "latest" + } +} diff --git a/packages/jobs/src/config.ts b/packages/jobs/src/config.ts new file mode 100644 index 000000000..44a043319 --- /dev/null +++ b/packages/jobs/src/config.ts @@ -0,0 +1,33 @@ +import type { Address } from 'viem' +import { isAddress } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { z } from 'zod' + +const envSchema = z.object({ + ISSUER_KEY: z + .string() + .min(1) + .length(64) + .regex(/^[a-f0-9]+$/i, 'Invalid issuer key format'), + ISSUER_ADDRESS: z + .string() + .refine( + (value): value is Address => isAddress(value), + 'Invalid issuer address', + ), +}) + +const parsedEnv = envSchema.safeParse(process.env) +if (!parsedEnv.success) { + console.error( + `Environment validation failed: ${JSON.stringify(parsedEnv.error.format())}`, + ) + process.exit(1) +} + +export const appConfig = { + eosEvmApi: 'https://api.testnet.evm.eosnetwork.com', + issuerKey: parsedEnv.data.ISSUER_KEY, + issuerAddress: parsedEnv.data.ISSUER_ADDRESS, + issuerAccount: privateKeyToAccount(`0x${parsedEnv.data.ISSUER_KEY}`), +} diff --git a/packages/jobs/src/index.ts b/packages/jobs/src/index.ts new file mode 100644 index 000000000..813c48b07 --- /dev/null +++ b/packages/jobs/src/index.ts @@ -0,0 +1 @@ +export * from './trigger/activity' diff --git a/packages/jobs/src/lib/presale-issuer.ts b/packages/jobs/src/lib/presale-issuer.ts new file mode 100644 index 000000000..c98642e3e --- /dev/null +++ b/packages/jobs/src/lib/presale-issuer.ts @@ -0,0 +1,44 @@ +// import { TestnetBLPL } from '@repo/contracts' +import { createWalletClient, erc20Abi, formatUnits } from 'viem' +import { http, type Address } from 'viem' +import { appConfig } from '../config' +import { eosEvmTestnet } from '../tmp' + +/** + * Issues presale tokens to a specified address. + * @param to The address to receive the presale tokens + * @param amount The amount of presale tokens to issue + */ +export async function issuePresaleTokens(to: Address, amount: bigint) { + try { + const walletClient = createWalletClient({ + chain: eosEvmTestnet, + transport: http(), + key: appConfig.issuerKey, + account: appConfig.issuerAccount, + }) + const trxHash = await walletClient.writeContract({ + address: TestnetBLPL.address, + abi: TestnetBLPL.abi, + functionName: 'transfer', + args: [to, amount], + }) + return `Issued ${formatUnits(amount, 6)} tokens to ${to} on transaction ${trxHash}` + } catch (error) { + console.log((error as Error).message) + return null + } +} + +export const TestnetBLPL = { + address: '0x2BF8feebD09B2520E69f27294768774544c98985', + name: 'Bitlauncher Prelaunch Token', + symbol: 'BLPL', + decimals: 18, + indexFromBlock: 30051449, + chainId: 15557, // eos_evm + chainType: 'evm', + chainName: 'EOS EVM Tesnet', + chain: eosEvmTestnet, + abi: erc20Abi, +} as const diff --git a/packages/jobs/src/tmp/chains.ts b/packages/jobs/src/tmp/chains.ts new file mode 100644 index 000000000..f5f9653fb --- /dev/null +++ b/packages/jobs/src/tmp/chains.ts @@ -0,0 +1,60 @@ +import type { Chain } from 'viem' +import { + arbitrum, + avalanche, + base, + bsc, + mainnet, + optimism, + polygon, + sepolia, +} from 'viem/chains' + +export const eosEvmTestnet: Chain = { + nativeCurrency: { + name: 'EOS', + symbol: 'EOS', + decimals: 18, + }, + id: 15557, + name: 'EOS EVM Testnet', + rpcUrls: { + default: { http: ['https://api.testnet.evm.eosnetwork.com/'] }, + public: { http: ['https://api.testnet.evm.eosnetwork.com/'] }, + }, + blockExplorers: { + default: { + name: 'EOS EVM Testnet Explorer', + url: 'https://explorer.testnet.evm.eosnetwork.com/', + }, + }, + testnet: true, +} + +export const prodChains: Chain[] = [ + base, + arbitrum, + optimism, + polygon, + mainnet, // Ethereum + avalanche, + bsc, // BNB Chain +] + +// Note: Solana is not included as it's not an EVM-compatible chain and not supported by viem + +export const devChains: Chain[] = [eosEvmTestnet, sepolia] + +// note: use .entries() to get an array +export const appChains = { + dev: createMapFromId(devChains), + prod: createMapFromId(prodChains), +} as const + +function createMapFromId(items: Chain[]): Map { + const mapFromId = new Map() + + items.forEach((item) => mapFromId.set(item.id, item)) + + return mapFromId +} diff --git a/packages/jobs/src/tmp/index.ts b/packages/jobs/src/tmp/index.ts new file mode 100644 index 000000000..8bf871d98 --- /dev/null +++ b/packages/jobs/src/tmp/index.ts @@ -0,0 +1,2 @@ +export * from './chains' +// export * from './env' diff --git a/packages/jobs/src/trigger/activity.ts b/packages/jobs/src/trigger/activity.ts new file mode 100644 index 000000000..4e92d4482 --- /dev/null +++ b/packages/jobs/src/trigger/activity.ts @@ -0,0 +1,35 @@ +import type { AlchemyActivity, AlchemyWebhookEvent } from '@repo/alchemy' +import { logger, task } from '@trigger.dev/sdk/v3' +import { isAddress, parseUnits } from 'viem' +import { issuePresaleTokens } from '../lib/presale-issuer' + +const STABLECOIN_DECIMALS = 6 + +export const addressActivityTask = task({ + id: 'address-activity', + run: async (payload: AlchemyWebhookEvent) => { + try { + const activity: AlchemyActivity = payload.event.activity[0] + console.log(activity) + + if (!isAddress(activity.toAddress)) + throw new Error(`Invalid to address: ${activity.toAddress}`) + + const valueInTokenUnits = parseUnits( + activity.value.toString(), + STABLECOIN_DECIMALS, + ) + + const result = await issuePresaleTokens( + activity.toAddress, + valueInTokenUnits, + ) + console.log(result) + } catch (error) { + logger.error('Error processing address activity', { + error: error instanceof Error ? error.message : String(error), + }) + throw error + } + }, +}) diff --git a/packages/jobs/src/trigger/example.ts b/packages/jobs/src/trigger/example.ts new file mode 100644 index 000000000..0529c873f --- /dev/null +++ b/packages/jobs/src/trigger/example.ts @@ -0,0 +1,14 @@ +import { logger, task, wait } from '@trigger.dev/sdk/v3' + +export const helloWorldTask = task({ + id: 'hello-world', + run: async (payload: any, { ctx }) => { + logger.log('Hello, world!', { payload, ctx }) + + await wait.for({ seconds: 5 }) + + return { + message: 'Hello, world!', + } + }, +}) diff --git a/packages/jobs/trigger.config.ts b/packages/jobs/trigger.config.ts new file mode 100644 index 000000000..191907b0b --- /dev/null +++ b/packages/jobs/trigger.config.ts @@ -0,0 +1,16 @@ +import type { TriggerConfig } from '@trigger.dev/sdk/v3' + +export const config: TriggerConfig = { + project: 'proj_uefmifhkitjdldujpocd', + logLevel: 'log', + retries: { + enabledInDev: true, + default: { + maxAttempts: 3, + minTimeoutInMs: 1000, + maxTimeoutInMs: 10000, + factor: 2, + randomize: true, + }, + }, +} diff --git a/packages/jobs/tsconfig.json b/packages/jobs/tsconfig.json new file mode 100644 index 000000000..3cc54f7e5 --- /dev/null +++ b/packages/jobs/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../packages/tsconfig/node16.json", + "include": ["./src/**/*", "src/lib/utils.ts", "trigger.config.ts"], + "exclude": ["node_modules"], + "compilerOptions": { + "sourceMap": true, + "inlineSources": true, + "sourceRoot": "/", + "outDir": "dist", + "baseUrl": "./src", + "paths": { + "~/*": ["./*"], + "@/*": ["./*"] + } + } +} diff --git a/apps/supabase/.gitignore b/packages/supabase/.gitignore similarity index 100% rename from apps/supabase/.gitignore rename to packages/supabase/.gitignore diff --git a/apps/supabase/README.md b/packages/supabase/README.md similarity index 100% rename from apps/supabase/README.md rename to packages/supabase/README.md diff --git a/apps/supabase/config.toml b/packages/supabase/config.toml similarity index 100% rename from apps/supabase/config.toml rename to packages/supabase/config.toml diff --git a/apps/supabase/migrations/20240414235435_remote_schema.sql b/packages/supabase/migrations/20240414235435_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240414235435_remote_schema.sql rename to packages/supabase/migrations/20240414235435_remote_schema.sql diff --git a/apps/supabase/migrations/20240417041423_remote_schema.sql b/packages/supabase/migrations/20240417041423_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240417041423_remote_schema.sql rename to packages/supabase/migrations/20240417041423_remote_schema.sql diff --git a/apps/supabase/migrations/20240417153529_remote_schema.sql b/packages/supabase/migrations/20240417153529_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240417153529_remote_schema.sql rename to packages/supabase/migrations/20240417153529_remote_schema.sql diff --git a/apps/supabase/migrations/20240418165957_remote_schema.sql b/packages/supabase/migrations/20240418165957_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240418165957_remote_schema.sql rename to packages/supabase/migrations/20240418165957_remote_schema.sql diff --git a/apps/supabase/migrations/20240418231216_remote_schema.sql b/packages/supabase/migrations/20240418231216_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240418231216_remote_schema.sql rename to packages/supabase/migrations/20240418231216_remote_schema.sql diff --git a/apps/supabase/migrations/20240419001509_remote_schema.sql b/packages/supabase/migrations/20240419001509_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240419001509_remote_schema.sql rename to packages/supabase/migrations/20240419001509_remote_schema.sql diff --git a/apps/supabase/migrations/20240419003028_remote_schema.sql b/packages/supabase/migrations/20240419003028_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240419003028_remote_schema.sql rename to packages/supabase/migrations/20240419003028_remote_schema.sql diff --git a/apps/supabase/migrations/20240419010728_remote_schema.sql b/packages/supabase/migrations/20240419010728_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240419010728_remote_schema.sql rename to packages/supabase/migrations/20240419010728_remote_schema.sql diff --git a/apps/supabase/migrations/20240719192750_remote_schema.sql b/packages/supabase/migrations/20240719192750_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240719192750_remote_schema.sql rename to packages/supabase/migrations/20240719192750_remote_schema.sql diff --git a/apps/supabase/migrations/20240720155732_remote_schema.sql b/packages/supabase/migrations/20240720155732_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240720155732_remote_schema.sql rename to packages/supabase/migrations/20240720155732_remote_schema.sql diff --git a/apps/supabase/migrations/20240805231931_remote_schema.sql b/packages/supabase/migrations/20240805231931_remote_schema.sql similarity index 100% rename from apps/supabase/migrations/20240805231931_remote_schema.sql rename to packages/supabase/migrations/20240805231931_remote_schema.sql diff --git a/packages/supabase/migrations/20240824213342_remote_schema.sql b/packages/supabase/migrations/20240824213342_remote_schema.sql new file mode 100644 index 000000000..6a80e1d23 --- /dev/null +++ b/packages/supabase/migrations/20240824213342_remote_schema.sql @@ -0,0 +1,274 @@ +create type "public"."chain_type" as enum ('evm', 'eos', 'solana', 'cosmos'); + +create type "public"."trx_type" as enum ('presale_deposit', 'usdcred_deposit', 'usdcred_withdrawal'); + +revoke delete on table "public"."user" from "anon"; + +revoke insert on table "public"."user" from "anon"; + +revoke references on table "public"."user" from "anon"; + +revoke select on table "public"."user" from "anon"; + +revoke trigger on table "public"."user" from "anon"; + +revoke truncate on table "public"."user" from "anon"; + +revoke update on table "public"."user" from "anon"; + +revoke delete on table "public"."user" from "authenticated"; + +revoke insert on table "public"."user" from "authenticated"; + +revoke references on table "public"."user" from "authenticated"; + +revoke select on table "public"."user" from "authenticated"; + +revoke trigger on table "public"."user" from "authenticated"; + +revoke truncate on table "public"."user" from "authenticated"; + +revoke update on table "public"."user" from "authenticated"; + +revoke delete on table "public"."user" from "service_role"; + +revoke insert on table "public"."user" from "service_role"; + +revoke references on table "public"."user" from "service_role"; + +revoke select on table "public"."user" from "service_role"; + +revoke trigger on table "public"."user" from "service_role"; + +revoke truncate on table "public"."user" from "service_role"; + +revoke update on table "public"."user" from "service_role"; + +alter table "public"."user" drop constraint "users_pkey"; + +drop index if exists "public"."users_pkey"; + +drop table "public"."user"; + +create table "public"."account" ( + "created_at" timestamp(6) with time zone not null default CURRENT_TIMESTAMP, + "short_link" text, + "account" text not null +); + + +create table "public"."presale_deposit" ( + "id" uuid not null default gen_random_uuid(), + "created_at" timestamp with time zone not null default now(), + "presale_id" bigint, + "deposit_hash" text, + "issuance_hash" text, + "amount" bigint +); + + +create table "public"."transaction" ( + "hash" text not null, + "created_at" timestamp with time zone not null default now(), + "chain_type" chain_type, + "chain_id" bigint, + "trx_type" trx_type, + "final" boolean default false +); + + +alter table "public"."auction" add column "project_id" bigint; + +alter table "public"."presale" drop column "signature"; + +alter table "public"."presale" add column "end_timestamptz" timestamp with time zone; + +alter table "public"."presale" add column "fundraising_goal" bigint; + +alter table "public"."presale" add column "max_allocation" bigint; + +alter table "public"."presale" add column "start_timestamptz" timestamp with time zone; + +alter table "public"."project" disable row level security; + +alter table "public"."transfer" drop column "chain_id"; + +alter table "public"."transfer" drop column "created_at"; + +alter table "public"."whitelist" add column "signed_message" text; + +CREATE UNIQUE INDEX presale_deposits_pkey ON public.presale_deposit USING btree (id); + +CREATE UNIQUE INDEX transactions_pkey ON public.transaction USING btree (hash); + +CREATE UNIQUE INDEX user_account_key ON public.account USING btree (account); + +CREATE UNIQUE INDEX user_pkey ON public.account USING btree (account); + +CREATE UNIQUE INDEX "user_shortLinks_key" ON public.account USING btree (short_link); + +alter table "public"."account" add constraint "user_pkey" PRIMARY KEY using index "user_pkey"; + +alter table "public"."presale_deposit" add constraint "presale_deposits_pkey" PRIMARY KEY using index "presale_deposits_pkey"; + +alter table "public"."transaction" add constraint "transactions_pkey" PRIMARY KEY using index "transactions_pkey"; + +alter table "public"."account" add constraint "user_account_key" UNIQUE using index "user_account_key"; + +alter table "public"."account" add constraint "user_shortLinks_key" UNIQUE using index "user_shortLinks_key"; + +alter table "public"."auction" add constraint "auction_project_id_fkey" FOREIGN KEY (project_id) REFERENCES project(id) not valid; + +alter table "public"."auction" validate constraint "auction_project_id_fkey"; + +alter table "public"."presale" add constraint "presale_project_id_fkey" FOREIGN KEY (project_id) REFERENCES project(id) not valid; + +alter table "public"."presale" validate constraint "presale_project_id_fkey"; + +alter table "public"."presale_deposit" add constraint "presale_deposit_deposit_hash_fkey" FOREIGN KEY (deposit_hash) REFERENCES transaction(hash) not valid; + +alter table "public"."presale_deposit" validate constraint "presale_deposit_deposit_hash_fkey"; + +alter table "public"."presale_deposit" add constraint "presale_deposit_issuance_hash_fkey" FOREIGN KEY (issuance_hash) REFERENCES transaction(hash) not valid; + +alter table "public"."presale_deposit" validate constraint "presale_deposit_issuance_hash_fkey"; + +alter table "public"."presale_deposit" add constraint "presale_deposit_presale_id_fkey" FOREIGN KEY (presale_id) REFERENCES presale(id) not valid; + +alter table "public"."presale_deposit" validate constraint "presale_deposit_presale_id_fkey"; + +alter table "public"."presale_deposit" add constraint "presale_deposits_presale_id_fkey" FOREIGN KEY (presale_id) REFERENCES presale(id) not valid; + +alter table "public"."presale_deposit" validate constraint "presale_deposits_presale_id_fkey"; + +alter table "public"."whitelist" add constraint "whitelist_project_id_fkey" FOREIGN KEY (project_id) REFERENCES project(id) not valid; + +alter table "public"."whitelist" validate constraint "whitelist_project_id_fkey"; + +grant delete on table "public"."account" to "anon"; + +grant insert on table "public"."account" to "anon"; + +grant references on table "public"."account" to "anon"; + +grant select on table "public"."account" to "anon"; + +grant trigger on table "public"."account" to "anon"; + +grant truncate on table "public"."account" to "anon"; + +grant update on table "public"."account" to "anon"; + +grant delete on table "public"."account" to "authenticated"; + +grant insert on table "public"."account" to "authenticated"; + +grant references on table "public"."account" to "authenticated"; + +grant select on table "public"."account" to "authenticated"; + +grant trigger on table "public"."account" to "authenticated"; + +grant truncate on table "public"."account" to "authenticated"; + +grant update on table "public"."account" to "authenticated"; + +grant delete on table "public"."account" to "service_role"; + +grant insert on table "public"."account" to "service_role"; + +grant references on table "public"."account" to "service_role"; + +grant select on table "public"."account" to "service_role"; + +grant trigger on table "public"."account" to "service_role"; + +grant truncate on table "public"."account" to "service_role"; + +grant update on table "public"."account" to "service_role"; + +grant delete on table "public"."presale_deposit" to "anon"; + +grant insert on table "public"."presale_deposit" to "anon"; + +grant references on table "public"."presale_deposit" to "anon"; + +grant select on table "public"."presale_deposit" to "anon"; + +grant trigger on table "public"."presale_deposit" to "anon"; + +grant truncate on table "public"."presale_deposit" to "anon"; + +grant update on table "public"."presale_deposit" to "anon"; + +grant delete on table "public"."presale_deposit" to "authenticated"; + +grant insert on table "public"."presale_deposit" to "authenticated"; + +grant references on table "public"."presale_deposit" to "authenticated"; + +grant select on table "public"."presale_deposit" to "authenticated"; + +grant trigger on table "public"."presale_deposit" to "authenticated"; + +grant truncate on table "public"."presale_deposit" to "authenticated"; + +grant update on table "public"."presale_deposit" to "authenticated"; + +grant delete on table "public"."presale_deposit" to "service_role"; + +grant insert on table "public"."presale_deposit" to "service_role"; + +grant references on table "public"."presale_deposit" to "service_role"; + +grant select on table "public"."presale_deposit" to "service_role"; + +grant trigger on table "public"."presale_deposit" to "service_role"; + +grant truncate on table "public"."presale_deposit" to "service_role"; + +grant update on table "public"."presale_deposit" to "service_role"; + +grant delete on table "public"."transaction" to "anon"; + +grant insert on table "public"."transaction" to "anon"; + +grant references on table "public"."transaction" to "anon"; + +grant select on table "public"."transaction" to "anon"; + +grant trigger on table "public"."transaction" to "anon"; + +grant truncate on table "public"."transaction" to "anon"; + +grant update on table "public"."transaction" to "anon"; + +grant delete on table "public"."transaction" to "authenticated"; + +grant insert on table "public"."transaction" to "authenticated"; + +grant references on table "public"."transaction" to "authenticated"; + +grant select on table "public"."transaction" to "authenticated"; + +grant trigger on table "public"."transaction" to "authenticated"; + +grant truncate on table "public"."transaction" to "authenticated"; + +grant update on table "public"."transaction" to "authenticated"; + +grant delete on table "public"."transaction" to "service_role"; + +grant insert on table "public"."transaction" to "service_role"; + +grant references on table "public"."transaction" to "service_role"; + +grant select on table "public"."transaction" to "service_role"; + +grant trigger on table "public"."transaction" to "service_role"; + +grant truncate on table "public"."transaction" to "service_role"; + +grant update on table "public"."transaction" to "service_role"; + + diff --git a/packages/supabase/migrations/20240825040214_remote_schema.sql b/packages/supabase/migrations/20240825040214_remote_schema.sql new file mode 100644 index 000000000..9dbf0296a --- /dev/null +++ b/packages/supabase/migrations/20240825040214_remote_schema.sql @@ -0,0 +1,33 @@ +alter table "public"."esr" alter column "account" set not null; + +alter table "public"."esr" alter column "code" set not null; + +alter table "public"."esr" alter column "trx_id" set not null; + +alter table "public"."presale" alter column "account" set not null; + +alter table "public"."presale" alter column "address" set not null; + +alter table "public"."presale" alter column "end_timestamptz" set not null; + +alter table "public"."presale" alter column "fundraising_goal" set not null; + +alter table "public"."presale" alter column "max_allocation" set not null; + +alter table "public"."presale" alter column "project_id" set not null; + +alter table "public"."presale" alter column "start_timestamptz" set not null; + +alter table "public"."presale_deposit" alter column "amount" set not null; + +alter table "public"."presale_deposit" alter column "deposit_hash" set not null; + +alter table "public"."presale_deposit" alter column "presale_id" set not null; + +alter table "public"."project" alter column "name" set not null; + +alter table "public"."project" alter column "pitch" set not null; + +alter table "public"."whitelist" alter column "signed_message" set not null; + + diff --git a/packages/supabase/migrations/20240825181232_remote_schema.sql b/packages/supabase/migrations/20240825181232_remote_schema.sql new file mode 100644 index 000000000..d3b95817a --- /dev/null +++ b/packages/supabase/migrations/20240825181232_remote_schema.sql @@ -0,0 +1,5 @@ +alter table "public"."presale" add column "close_timestampz" timestamp with time zone; + +alter table "public"."presale" add column "total_raised" bigint not null default '0'::bigint; + + diff --git a/apps/supabase/package.json b/packages/supabase/package.json similarity index 92% rename from apps/supabase/package.json rename to packages/supabase/package.json index dcbee76d4..c991b1fc5 100644 --- a/apps/supabase/package.json +++ b/packages/supabase/package.json @@ -2,6 +2,7 @@ "name": "@repo/supabase", "version": "0.0.1", "private": true, + "type": "module", "description": "supabase module for smartevm", "main": "./src/index.ts", "types": "./src/index.ts", @@ -15,7 +16,7 @@ "license": "ISC", "dependencies": {}, "devDependencies": { - "@repo/typescript-config": "workspace:*", + "@repo/tsconfig": "workspace:*", "supabase-to-zod": "^1.0.7", "@faker-js/faker": "^8.4.1", "supabase": "^1.187.3" diff --git a/apps/supabase/scripts/fake-orders.ts b/packages/supabase/scripts/fake-orders.ts similarity index 100% rename from apps/supabase/scripts/fake-orders.ts rename to packages/supabase/scripts/fake-orders.ts diff --git a/apps/supabase/seed.sql b/packages/supabase/seed.sql similarity index 100% rename from apps/supabase/seed.sql rename to packages/supabase/seed.sql diff --git a/apps/supabase/src/index.ts b/packages/supabase/src/index.ts similarity index 100% rename from apps/supabase/src/index.ts rename to packages/supabase/src/index.ts diff --git a/apps/supabase/src/supa.schemas.ts b/packages/supabase/src/supa.schemas.ts similarity index 61% rename from apps/supabase/src/supa.schemas.ts rename to packages/supabase/src/supa.schemas.ts index ec3ed42d4..342c3856f 100644 --- a/apps/supabase/src/supa.schemas.ts +++ b/packages/supabase/src/supa.schemas.ts @@ -1,6 +1,6 @@ // Generated by ts-to-zod -import { z } from 'zod' -import type { Json } from './supa.types' +import { z } from "zod"; +import { Json } from "./supa.types"; export const jsonSchema: z.ZodSchema = z.lazy(() => z @@ -12,7 +12,27 @@ export const jsonSchema: z.ZodSchema = z.lazy(() => z.array(jsonSchema), ]) .nullable(), -) +); + +export const accountRowSchema = z.object({ + account: z.string(), + created_at: z.string(), + short_link: z.string().nullable(), +}); + +export const accountInsertSchema = z.object({ + account: z.string(), + created_at: z.string().optional(), + short_link: z.string().optional().nullable(), +}); + +export const accountUpdateSchema = z.object({ + account: z.string().optional(), + created_at: z.string().optional(), + short_link: z.string().optional().nullable(), +}); + +export const accountRelationshipsSchema = z.tuple([]); export const auctionRowSchema = z.object({ address_auctioning_token: z.string().nullable(), @@ -36,11 +56,12 @@ export const auctionRowSchema = z.object({ min_funding_threshold: z.number().nullable(), minimum_bidding_amount_per_order: z.number().nullable(), order_cancellation_end_date: z.string().nullable(), + project_id: z.number().nullable(), starting_time_stamp: z.string().nullable(), symbol_auctioning_token: z.string().nullable(), symbol_bidding_token: z.string().nullable(), usd_amount_traded: z.number().nullable(), -}) +}); export const auctionInsertSchema = z.object({ address_auctioning_token: z.string().optional().nullable(), @@ -64,11 +85,12 @@ export const auctionInsertSchema = z.object({ min_funding_threshold: z.number().optional().nullable(), minimum_bidding_amount_per_order: z.number().optional().nullable(), order_cancellation_end_date: z.string().optional().nullable(), + project_id: z.number().optional().nullable(), starting_time_stamp: z.string().optional().nullable(), symbol_auctioning_token: z.string().optional().nullable(), symbol_bidding_token: z.string().optional().nullable(), usd_amount_traded: z.number().optional().nullable(), -}) +}); export const auctionUpdateSchema = z.object({ address_auctioning_token: z.string().optional().nullable(), @@ -92,56 +114,65 @@ export const auctionUpdateSchema = z.object({ min_funding_threshold: z.number().optional().nullable(), minimum_bidding_amount_per_order: z.number().optional().nullable(), order_cancellation_end_date: z.string().optional().nullable(), + project_id: z.number().optional().nullable(), starting_time_stamp: z.string().optional().nullable(), symbol_auctioning_token: z.string().optional().nullable(), symbol_bidding_token: z.string().optional().nullable(), usd_amount_traded: z.number().optional().nullable(), -}) - -export const auctionRelationshipsSchema = z.tuple([]) +}); + +export const auctionRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("auction_project_id_fkey"), + columns: z.tuple([z.literal("project_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("project"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); export const esrRowSchema = z.object({ - account: z.string().nullable(), - code: z.string().nullable(), + account: z.string(), + code: z.string(), created_at: z.string(), id: z.string(), - trx_id: z.string().nullable(), -}) + trx_id: z.string(), +}); export const esrInsertSchema = z.object({ - account: z.string().optional().nullable(), - code: z.string().optional().nullable(), + account: z.string(), + code: z.string(), created_at: z.string().optional(), id: z.string().optional(), - trx_id: z.string().optional().nullable(), -}) + trx_id: z.string(), +}); export const esrUpdateSchema = z.object({ - account: z.string().optional().nullable(), - code: z.string().optional().nullable(), + account: z.string().optional(), + code: z.string().optional(), created_at: z.string().optional(), id: z.string().optional(), - trx_id: z.string().optional().nullable(), -}) + trx_id: z.string().optional(), +}); -export const esrRelationshipsSchema = z.tuple([]) +export const esrRelationshipsSchema = z.tuple([]); export const indexerRowSchema = z.object({ id: z.number(), last_indexed_block: z.string(), -}) +}); export const indexerInsertSchema = z.object({ id: z.number().optional(), last_indexed_block: z.string(), -}) +}); export const indexerUpdateSchema = z.object({ id: z.number().optional(), last_indexed_block: z.string().optional(), -}) +}); -export const indexerRelationshipsSchema = z.tuple([]) +export const indexerRelationshipsSchema = z.tuple([]); export const orderRowSchema = z.object({ auction_id: z.number(), @@ -153,7 +184,7 @@ export const orderRowSchema = z.object({ transactionHash: z.string(), user_id: z.number(), volume: z.number().nullable(), -}) +}); export const orderInsertSchema = z.object({ auction_id: z.number(), @@ -165,7 +196,7 @@ export const orderInsertSchema = z.object({ transactionHash: z.string(), user_id: z.number(), volume: z.number().optional().nullable(), -}) +}); export const orderUpdateSchema = z.object({ auction_id: z.number().optional(), @@ -177,61 +208,142 @@ export const orderUpdateSchema = z.object({ transactionHash: z.string().optional(), user_id: z.number().optional(), volume: z.number().optional().nullable(), -}) +}); -export const orderRelationshipsSchema = z.tuple([]) +export const orderRelationshipsSchema = z.tuple([]); export const presaleRowSchema = z.object({ - account: z.string().nullable(), - address: z.string().nullable(), + account: z.string(), + address: z.string(), + close_timestampz: z.string().nullable(), created_at: z.string(), + end_timestamptz: z.string(), + fundraising_goal: z.number(), id: z.number(), - project_id: z.number().nullable(), - signature: z.string().nullable(), -}) + max_allocation: z.number(), + project_id: z.number(), + start_timestamptz: z.string(), + total_raised: z.number(), +}); export const presaleInsertSchema = z.object({ - account: z.string().optional().nullable(), - address: z.string().optional().nullable(), + account: z.string(), + address: z.string(), + close_timestampz: z.string().optional().nullable(), created_at: z.string().optional(), + end_timestamptz: z.string(), + fundraising_goal: z.number(), id: z.number().optional(), - project_id: z.number().optional().nullable(), - signature: z.string().optional().nullable(), -}) + max_allocation: z.number(), + project_id: z.number(), + start_timestamptz: z.string(), + total_raised: z.number().optional(), +}); export const presaleUpdateSchema = z.object({ - account: z.string().optional().nullable(), - address: z.string().optional().nullable(), + account: z.string().optional(), + address: z.string().optional(), + close_timestampz: z.string().optional().nullable(), created_at: z.string().optional(), + end_timestamptz: z.string().optional(), + fundraising_goal: z.number().optional(), id: z.number().optional(), - project_id: z.number().optional().nullable(), - signature: z.string().optional().nullable(), -}) + max_allocation: z.number().optional(), + project_id: z.number().optional(), + start_timestamptz: z.string().optional(), + total_raised: z.number().optional(), +}); + +export const presaleRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("presale_project_id_fkey"), + columns: z.tuple([z.literal("project_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("project"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const presaleDepositRowSchema = z.object({ + amount: z.number(), + created_at: z.string(), + deposit_hash: z.string(), + id: z.string(), + issuance_hash: z.string().nullable(), + presale_id: z.number(), +}); -export const presaleRelationshipsSchema = z.tuple([]) +export const presaleDepositInsertSchema = z.object({ + amount: z.number(), + created_at: z.string().optional(), + deposit_hash: z.string(), + id: z.string().optional(), + issuance_hash: z.string().optional().nullable(), + presale_id: z.number(), +}); + +export const presaleDepositUpdateSchema = z.object({ + amount: z.number().optional(), + created_at: z.string().optional(), + deposit_hash: z.string().optional(), + id: z.string().optional(), + issuance_hash: z.string().optional().nullable(), + presale_id: z.number().optional(), +}); + +export const presaleDepositRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("presale_deposit_deposit_hash_fkey"), + columns: z.tuple([z.literal("deposit_hash")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("transaction"), + referencedColumns: z.tuple([z.literal("hash")]), + }), + z.object({ + foreignKeyName: z.literal("presale_deposit_issuance_hash_fkey"), + columns: z.tuple([z.literal("issuance_hash")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("transaction"), + referencedColumns: z.tuple([z.literal("hash")]), + }), + z.object({ + foreignKeyName: z.literal("presale_deposit_presale_id_fkey"), + columns: z.tuple([z.literal("presale_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("presale"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("presale_deposits_presale_id_fkey"), + columns: z.tuple([z.literal("presale_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("presale"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); export const projectRowSchema = z.object({ created_at: z.string(), id: z.number(), - name: z.string().nullable(), - pitch: z.string().nullable(), -}) + name: z.string(), + pitch: z.string(), +}); export const projectInsertSchema = z.object({ created_at: z.string().optional(), id: z.number().optional(), - name: z.string().optional().nullable(), - pitch: z.string().optional().nullable(), -}) + name: z.string(), + pitch: z.string(), +}); export const projectUpdateSchema = z.object({ created_at: z.string().optional(), id: z.number().optional(), - name: z.string().optional().nullable(), - pitch: z.string().optional().nullable(), -}) + name: z.string().optional(), + pitch: z.string().optional(), +}); -export const projectRelationshipsSchema = z.tuple([]) +export const projectRelationshipsSchema = z.tuple([]); export const sessionRowSchema = z.object({ account: z.string(), @@ -239,7 +351,7 @@ export const sessionRowSchema = z.object({ esr_code: z.string().nullable(), id: z.string(), tx: z.string(), -}) +}); export const sessionInsertSchema = z.object({ account: z.string(), @@ -247,7 +359,7 @@ export const sessionInsertSchema = z.object({ esr_code: z.string().optional().nullable(), id: z.string().optional(), tx: z.string(), -}) +}); export const sessionUpdateSchema = z.object({ account: z.string().optional(), @@ -255,96 +367,117 @@ export const sessionUpdateSchema = z.object({ esr_code: z.string().optional().nullable(), id: z.string().optional(), tx: z.string().optional(), -}) +}); + +export const sessionRelationshipsSchema = z.tuple([]); + +export const chainTypeSchema = z.union([ + z.literal("evm"), + z.literal("eos"), + z.literal("solana"), + z.literal("cosmos"), +]); + +export const trxTypeSchema = z.union([ + z.literal("presale_deposit"), + z.literal("usdcred_deposit"), + z.literal("usdcred_withdrawal"), +]); + +export const transactionInsertSchema = z.object({ + chain_id: z.number().optional().nullable(), + chain_type: chainTypeSchema.optional().nullable(), + created_at: z.string().optional(), + final: z.boolean().optional().nullable(), + hash: z.string(), + trx_type: trxTypeSchema.optional().nullable(), +}); + +export const transactionUpdateSchema = z.object({ + chain_id: z.number().optional().nullable(), + chain_type: chainTypeSchema.optional().nullable(), + created_at: z.string().optional(), + final: z.boolean().optional().nullable(), + hash: z.string().optional(), + trx_type: trxTypeSchema.optional().nullable(), +}); -export const sessionRelationshipsSchema = z.tuple([]) +export const transactionRelationshipsSchema = z.tuple([]); export const transferRowSchema = z.object({ amount: z.number().nullable(), bl_presale_trx: z.string().nullable(), - chain_id: z.number().nullable(), - created_at: z.string(), from: z.string().nullable(), to: z.string().nullable(), token: z.string().nullable(), trx_hash: z.string(), type: z.string().nullable(), usdcred_trx: z.string().nullable(), -}) +}); export const transferInsertSchema = z.object({ amount: z.number().optional().nullable(), bl_presale_trx: z.string().optional().nullable(), - chain_id: z.number().optional().nullable(), - created_at: z.string().optional(), from: z.string().optional().nullable(), to: z.string().optional().nullable(), token: z.string().optional().nullable(), trx_hash: z.string(), type: z.string().optional().nullable(), usdcred_trx: z.string().optional().nullable(), -}) +}); export const transferUpdateSchema = z.object({ amount: z.number().optional().nullable(), bl_presale_trx: z.string().optional().nullable(), - chain_id: z.number().optional().nullable(), - created_at: z.string().optional(), from: z.string().optional().nullable(), to: z.string().optional().nullable(), token: z.string().optional().nullable(), trx_hash: z.string().optional(), type: z.string().optional().nullable(), usdcred_trx: z.string().optional().nullable(), -}) - -export const transferRelationshipsSchema = z.tuple([]) +}); -export const userRowSchema = z.object({ - account: z.string(), - address: z.array(z.string()), - created_at: z.string(), - id: z.number(), - short_link: z.string().nullable(), -}) - -export const userInsertSchema = z.object({ - account: z.string(), - address: z.array(z.string()), - created_at: z.string().optional(), - id: z.number().optional(), - short_link: z.string().optional().nullable(), -}) - -export const userUpdateSchema = z.object({ - account: z.string().optional(), - address: z.array(z.string()).optional(), - created_at: z.string().optional(), - id: z.number().optional(), - short_link: z.string().optional().nullable(), -}) - -export const userRelationshipsSchema = z.tuple([]) +export const transferRelationshipsSchema = z.tuple([]); export const whitelistRowSchema = z.object({ account: z.string(), address: z.string(), created_at: z.string(), project_id: z.number(), -}) + signed_message: z.string(), +}); export const whitelistInsertSchema = z.object({ account: z.string(), address: z.string(), created_at: z.string().optional(), project_id: z.number(), -}) + signed_message: z.string(), +}); export const whitelistUpdateSchema = z.object({ account: z.string().optional(), address: z.string().optional(), created_at: z.string().optional(), project_id: z.number().optional(), -}) - -export const whitelistRelationshipsSchema = z.tuple([]) + signed_message: z.string().optional(), +}); + +export const whitelistRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("whitelist_project_id_fkey"), + columns: z.tuple([z.literal("project_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("project"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const transactionRowSchema = z.object({ + chain_id: z.number().nullable(), + chain_type: chainTypeSchema.nullable(), + created_at: z.string(), + final: z.boolean().nullable(), + hash: z.string(), + trx_type: trxTypeSchema.nullable(), +}); diff --git a/apps/supabase/src/supa.types.ts b/packages/supabase/src/supa.types.ts similarity index 62% rename from apps/supabase/src/supa.types.ts rename to packages/supabase/src/supa.types.ts index e5ed15432..406e0cb9d 100644 --- a/apps/supabase/src/supa.types.ts +++ b/packages/supabase/src/supa.types.ts @@ -9,6 +9,24 @@ export type Json = export type Database = { public: { Tables: { + account: { + Row: { + account: string + created_at: string + short_link: string | null + } + Insert: { + account: string + created_at?: string + short_link?: string | null + } + Update: { + account?: string + created_at?: string + short_link?: string | null + } + Relationships: [] + } auction: { Row: { address_auctioning_token: string | null @@ -32,6 +50,7 @@ export type Database = { min_funding_threshold: number | null minimum_bidding_amount_per_order: number | null order_cancellation_end_date: string | null + project_id: number | null starting_time_stamp: string | null symbol_auctioning_token: string | null symbol_bidding_token: string | null @@ -59,6 +78,7 @@ export type Database = { min_funding_threshold?: number | null minimum_bidding_amount_per_order?: number | null order_cancellation_end_date?: string | null + project_id?: number | null starting_time_stamp?: string | null symbol_auctioning_token?: string | null symbol_bidding_token?: string | null @@ -86,34 +106,43 @@ export type Database = { min_funding_threshold?: number | null minimum_bidding_amount_per_order?: number | null order_cancellation_end_date?: string | null + project_id?: number | null starting_time_stamp?: string | null symbol_auctioning_token?: string | null symbol_bidding_token?: string | null usd_amount_traded?: number | null } - Relationships: [] + Relationships: [ + { + foreignKeyName: "auction_project_id_fkey" + columns: ["project_id"] + isOneToOne: false + referencedRelation: "project" + referencedColumns: ["id"] + }, + ] } esr: { Row: { - account: string | null - code: string | null + account: string + code: string created_at: string id: string - trx_id: string | null + trx_id: string } Insert: { - account?: string | null - code?: string | null + account: string + code: string created_at?: string id?: string - trx_id?: string | null + trx_id: string } Update: { - account?: string | null - code?: string | null + account?: string + code?: string created_at?: string id?: string - trx_id?: string | null + trx_id?: string } Relationships: [] } @@ -170,49 +199,128 @@ export type Database = { } presale: { Row: { - account: string | null - address: string | null + account: string + address: string + close_timestampz: string | null created_at: string + end_timestamptz: string + fundraising_goal: number id: number - project_id: number | null - signature: string | null + max_allocation: number + project_id: number + start_timestamptz: string + total_raised: number } Insert: { - account?: string | null - address?: string | null + account: string + address: string + close_timestampz?: string | null created_at?: string + end_timestamptz: string + fundraising_goal: number id?: number - project_id?: number | null - signature?: string | null + max_allocation: number + project_id: number + start_timestamptz: string + total_raised?: number } Update: { - account?: string | null - address?: string | null + account?: string + address?: string + close_timestampz?: string | null created_at?: string + end_timestamptz?: string + fundraising_goal?: number id?: number - project_id?: number | null - signature?: string | null + max_allocation?: number + project_id?: number + start_timestamptz?: string + total_raised?: number } - Relationships: [] + Relationships: [ + { + foreignKeyName: "presale_project_id_fkey" + columns: ["project_id"] + isOneToOne: false + referencedRelation: "project" + referencedColumns: ["id"] + }, + ] + } + presale_deposit: { + Row: { + amount: number + created_at: string + deposit_hash: string + id: string + issuance_hash: string | null + presale_id: number + } + Insert: { + amount: number + created_at?: string + deposit_hash: string + id?: string + issuance_hash?: string | null + presale_id: number + } + Update: { + amount?: number + created_at?: string + deposit_hash?: string + id?: string + issuance_hash?: string | null + presale_id?: number + } + Relationships: [ + { + foreignKeyName: "presale_deposit_deposit_hash_fkey" + columns: ["deposit_hash"] + isOneToOne: false + referencedRelation: "transaction" + referencedColumns: ["hash"] + }, + { + foreignKeyName: "presale_deposit_issuance_hash_fkey" + columns: ["issuance_hash"] + isOneToOne: false + referencedRelation: "transaction" + referencedColumns: ["hash"] + }, + { + foreignKeyName: "presale_deposit_presale_id_fkey" + columns: ["presale_id"] + isOneToOne: false + referencedRelation: "presale" + referencedColumns: ["id"] + }, + { + foreignKeyName: "presale_deposits_presale_id_fkey" + columns: ["presale_id"] + isOneToOne: false + referencedRelation: "presale" + referencedColumns: ["id"] + }, + ] } project: { Row: { created_at: string id: number - name: string | null - pitch: string | null + name: string + pitch: string } Insert: { created_at?: string id?: number - name?: string | null - pitch?: string | null + name: string + pitch: string } Update: { created_at?: string id?: number - name?: string | null - pitch?: string | null + name?: string + pitch?: string } Relationships: [] } @@ -240,12 +348,37 @@ export type Database = { } Relationships: [] } + transaction: { + Row: { + chain_id: number | null + chain_type: Database["public"]["Enums"]["chain_type"] | null + created_at: string + final: boolean | null + hash: string + trx_type: Database["public"]["Enums"]["trx_type"] | null + } + Insert: { + chain_id?: number | null + chain_type?: Database["public"]["Enums"]["chain_type"] | null + created_at?: string + final?: boolean | null + hash: string + trx_type?: Database["public"]["Enums"]["trx_type"] | null + } + Update: { + chain_id?: number | null + chain_type?: Database["public"]["Enums"]["chain_type"] | null + created_at?: string + final?: boolean | null + hash?: string + trx_type?: Database["public"]["Enums"]["trx_type"] | null + } + Relationships: [] + } transfer: { Row: { amount: number | null bl_presale_trx: string | null - chain_id: number | null - created_at: string from: string | null to: string | null token: string | null @@ -256,8 +389,6 @@ export type Database = { Insert: { amount?: number | null bl_presale_trx?: string | null - chain_id?: number | null - created_at?: string from?: string | null to?: string | null token?: string | null @@ -268,8 +399,6 @@ export type Database = { Update: { amount?: number | null bl_presale_trx?: string | null - chain_id?: number | null - created_at?: string from?: string | null to?: string | null token?: string | null @@ -279,50 +408,37 @@ export type Database = { } Relationships: [] } - user: { - Row: { - account: string - address: string[] - created_at: string - id: number - short_link: string | null - } - Insert: { - account: string - address: string[] - created_at?: string - id?: number - short_link?: string | null - } - Update: { - account?: string - address?: string[] - created_at?: string - id?: number - short_link?: string | null - } - Relationships: [] - } whitelist: { Row: { account: string address: string created_at: string project_id: number + signed_message: string } Insert: { account: string address: string created_at?: string project_id: number + signed_message: string } Update: { account?: string address?: string created_at?: string project_id?: number + signed_message?: string } - Relationships: [] + Relationships: [ + { + foreignKeyName: "whitelist_project_id_fkey" + columns: ["project_id"] + isOneToOne: false + referencedRelation: "project" + referencedColumns: ["id"] + }, + ] } } Views: { @@ -332,7 +448,8 @@ export type Database = { [_ in never]: never } Enums: { - [_ in never]: never + chain_type: "evm" | "eos" | "solana" | "cosmos" + trx_type: "presale_deposit" | "usdcred_deposit" | "usdcred_withdrawal" } CompositeTypes: { [_ in never]: never @@ -340,27 +457,27 @@ export type Database = { } } -type PublicSchema = Database[Extract] +type PublicSchema = Database[Extract] export type Tables< PublicTableNameOrOptions extends - | keyof (PublicSchema['Tables'] & PublicSchema['Views']) + | keyof (PublicSchema["Tables"] & PublicSchema["Views"]) | { schema: keyof Database }, TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views']) + ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] & + Database[PublicTableNameOrOptions["schema"]]["Views"]) : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } - ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { + ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & + Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { Row: infer R } ? R : never - : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & - PublicSchema['Views']) - ? (PublicSchema['Tables'] & - PublicSchema['Views'])[PublicTableNameOrOptions] extends { + : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & + PublicSchema["Views"]) + ? (PublicSchema["Tables"] & + PublicSchema["Views"])[PublicTableNameOrOptions] extends { Row: infer R } ? R @@ -369,19 +486,19 @@ export type Tables< export type TablesInsert< PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] + | keyof PublicSchema["Tables"] | { schema: keyof Database }, TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { Insert: infer I } ? I : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { Insert: infer I } ? I @@ -390,19 +507,19 @@ export type TablesInsert< export type TablesUpdate< PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] + | keyof PublicSchema["Tables"] | { schema: keyof Database }, TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] : never = never, > = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { Update: infer U } ? U : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] + ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { Update: infer U } ? U @@ -411,13 +528,13 @@ export type TablesUpdate< export type Enums< PublicEnumNameOrOptions extends - | keyof PublicSchema['Enums'] + | keyof PublicSchema["Enums"] | { schema: keyof Database }, EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"] : never = never, > = PublicEnumNameOrOptions extends { schema: keyof Database } - ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] - : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] - ? PublicSchema['Enums'][PublicEnumNameOrOptions] + ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] + : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] + ? PublicSchema["Enums"][PublicEnumNameOrOptions] : never diff --git a/packages/tokens/README.md b/packages/tokens/README.md new file mode 100644 index 000000000..bf7bdce79 --- /dev/null +++ b/packages/tokens/README.md @@ -0,0 +1,15 @@ +# @repo/tokens + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run src/index.ts +``` + +This project was created using `bun init` in bun v1.1.24. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/packages/tokens/package.json b/packages/tokens/package.json new file mode 100644 index 000000000..0c01c51c7 --- /dev/null +++ b/packages/tokens/package.json @@ -0,0 +1,10 @@ +{ + "name": "@repo/tokens", + "main": "src/index.ts", + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/packages/tokens/src/eos.ts b/packages/tokens/src/eos.ts new file mode 100644 index 000000000..6ece8fe8a --- /dev/null +++ b/packages/tokens/src/eos.ts @@ -0,0 +1,22 @@ +import type { AntelopeToken } from './types' + +export const antelopeTokens: AntelopeToken[] = [ + { + address: 'bkbtokentest', + chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', + symbol: 'BITUSD', + chainType: 'antelope', + chainName: 'EOS', + decimals: 4, + isStable: true, + }, + { + address: 'tethertether', + chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', + symbol: 'USDT', + chainType: 'antelope', + chainName: 'EOS', + decimals: 4, + isStable: true, + }, +] diff --git a/packages/tokens/src/evm.ts b/packages/tokens/src/evm.ts new file mode 100644 index 000000000..538789c9b --- /dev/null +++ b/packages/tokens/src/evm.ts @@ -0,0 +1,96 @@ +import type { EVMToken } from './types' + +const baseTokens = [ + { + address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + chainId: 1, + symbol: 'USDT', + chainName: 'Ethereum', + }, + { + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + chainId: 1, + symbol: 'USDC', + chainName: 'Ethereum', + }, + { + address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + chainId: 137, + symbol: 'USDT', + chainName: 'Polygon', + }, + { + address: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', + chainId: 137, + symbol: 'USDC', + chainName: 'Polygon', + }, + { + address: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + chainId: 42161, + symbol: 'USDT', + chainName: 'Arbitrum', + }, + { + address: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8', + chainId: 42161, + symbol: 'USDC', + chainName: 'Arbitrum', + }, + { + address: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58', + chainId: 10, + symbol: 'USDT', + chainName: 'Optimism', + }, + { + address: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607', + chainId: 10, + symbol: 'USDC', + chainName: 'Optimism', + }, + { + address: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', + chainId: 8453, + symbol: 'USDT', + chainName: 'Base', + }, + { + address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + chainId: 8453, + symbol: 'USDC', + chainName: 'Base', + }, + { + address: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7', + chainId: 43114, + symbol: 'USDT', + chainName: 'Avalanche', + }, + { + address: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', + chainId: 43114, + symbol: 'USDC', + chainName: 'Avalanche', + }, + { + address: '0x55d398326f99059fF775485246999027B3197955', + chainId: 56, + symbol: 'USDT', + chainName: 'BNB Chain', + }, + { + address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', + chainId: 56, + symbol: 'USDC', + chainName: 'BNB Chain', + }, +] + +export const evmTokens: EVMToken[] = baseTokens.map((token) => ({ + ...token, + chainType: 'evm', + // On BNB Chain (chainId 56), both USDT and USDC are implemented with 18 decimal places instead of the usual 6. + decimals: token.chainId === 56 ? 18 : 6, + isStable: true, +})) diff --git a/packages/tokens/src/index.ts b/packages/tokens/src/index.ts new file mode 100644 index 000000000..1fa929aed --- /dev/null +++ b/packages/tokens/src/index.ts @@ -0,0 +1,15 @@ +import type { Token } from './types' +export * from './types' +export * from './eos' +export * from './evm' +export * from './solana' + +import { antelopeTokens } from './eos' +import { evmTokens } from './evm' +import { solanaTokens } from './solana' + +export const tokens: Token[] = [ + ...antelopeTokens, + ...evmTokens, + ...solanaTokens, +] diff --git a/packages/tokens/src/solana.ts b/packages/tokens/src/solana.ts new file mode 100644 index 000000000..60bf49991 --- /dev/null +++ b/packages/tokens/src/solana.ts @@ -0,0 +1,21 @@ +import type { SolanaToken } from './types' + +const baseTokens = [ + { + symbol: 'USDC', + address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', + }, + { + symbol: 'USDT', + address: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB', + }, +] + +export const solanaTokens: SolanaToken[] = baseTokens.map((token) => ({ + ...token, + decimals: 6, + image: `https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/${token.address}/logo.png`, + chainName: 'Solana', + isStable: true, + chainType: 'solana' as const, +})) diff --git a/packages/tokens/src/types.ts b/packages/tokens/src/types.ts new file mode 100644 index 000000000..392663d61 --- /dev/null +++ b/packages/tokens/src/types.ts @@ -0,0 +1,34 @@ +export interface BaseToken { + symbol: string + chainName: string + image?: string + decimals: number + isStable: boolean +} + +export interface EVMToken extends BaseToken { + address: string + chainId: number + chainType: 'evm' +} + +export interface AntelopeToken extends BaseToken { + address: string + chainId: string + chainType: 'antelope' +} + +export interface SolanaToken extends BaseToken { + address: string // Solana uses public key as address + chainType: 'solana' +} + +export interface CosmosToken extends BaseToken { + denom: string // Cosmos uses denom instead of address + chainId: string + chainType: 'cosmos' +} + +export type Token = EVMToken | AntelopeToken | SolanaToken | CosmosToken + +export type ChainType = 'evm' | 'antelope' | 'solana' | 'cosmos' diff --git a/packages/tokens/tsconfig.json b/packages/tokens/tsconfig.json new file mode 100644 index 000000000..7ce5ae9d8 --- /dev/null +++ b/packages/tokens/tsconfig.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Default", + "compilerOptions": { + "composite": false, + "declaration": true, + "declarationMap": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "inlineSources": false, + "isolatedModules": true, + "moduleResolution": "node", + "noUnusedLocals": false, + "noUnusedParameters": false, + "preserveWatchOutput": true, + "skipLibCheck": true, + "strict": true + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/packages/config-typescript/base.json b/packages/tsconfig/base.json similarity index 100% rename from packages/config-typescript/base.json rename to packages/tsconfig/base.json diff --git a/packages/config-typescript/nextjs-14.json b/packages/tsconfig/nextjs-14.json similarity index 100% rename from packages/config-typescript/nextjs-14.json rename to packages/tsconfig/nextjs-14.json diff --git a/packages/config-typescript/nextjs.json b/packages/tsconfig/nextjs.json similarity index 100% rename from packages/config-typescript/nextjs.json rename to packages/tsconfig/nextjs.json diff --git a/packages/config-typescript/node16.json b/packages/tsconfig/node16.json similarity index 100% rename from packages/config-typescript/node16.json rename to packages/tsconfig/node16.json diff --git a/packages/config-typescript/package.json b/packages/tsconfig/package.json similarity index 75% rename from packages/config-typescript/package.json rename to packages/tsconfig/package.json index 27c0e6043..58907bf2f 100644 --- a/packages/config-typescript/package.json +++ b/packages/tsconfig/package.json @@ -1,5 +1,5 @@ { - "name": "@repo/typescript-config", + "name": "@repo/tsconfig", "version": "0.0.0", "private": true, "license": "MIT", diff --git a/packages/config-typescript/react-library.json b/packages/tsconfig/react-library.json similarity index 100% rename from packages/config-typescript/react-library.json rename to packages/tsconfig/react-library.json diff --git a/packages/config-typescript/vite.json b/packages/tsconfig/vite.json similarity index 93% rename from packages/config-typescript/vite.json rename to packages/tsconfig/vite.json index 7c67aeed4..d616cc738 100644 --- a/packages/config-typescript/vite.json +++ b/packages/tsconfig/vite.json @@ -35,7 +35,7 @@ ], "references": [ { - "path": "./@repo/typescript-config.node.json" + "path": "./@repo/tsconfig.node.json" } ] } \ No newline at end of file diff --git a/packages/config-typescript/vite.node.json b/packages/tsconfig/vite.node.json similarity index 100% rename from packages/config-typescript/vite.node.json rename to packages/tsconfig/vite.node.json diff --git a/packages/app-lib/package.json b/packages/utils/package.json similarity index 85% rename from packages/app-lib/package.json rename to packages/utils/package.json index 3a86138fe..d2a970e23 100644 --- a/packages/app-lib/package.json +++ b/packages/utils/package.json @@ -1,5 +1,5 @@ { - "name": "app-lib", + "name": "@repo/utils", "private": true, "version": "0.0.0", "main": "./src/index.ts", @@ -15,7 +15,7 @@ "devDependencies": { "@types/jsonwebtoken": "^9.0.5", "@types/lodash": "^4.14.195", - "@repo/typescript-config": "workspace:*", + "@repo/tsconfig": "workspace:*", "typescript": "^5.3.3" } } diff --git a/packages/app-lib/src/crypto/crypto.lib.ts b/packages/utils/src/crypto/crypto.lib.ts similarity index 100% rename from packages/app-lib/src/crypto/crypto.lib.ts rename to packages/utils/src/crypto/crypto.lib.ts diff --git a/packages/app-lib/src/crypto/index.ts b/packages/utils/src/crypto/index.ts similarity index 100% rename from packages/app-lib/src/crypto/index.ts rename to packages/utils/src/crypto/index.ts diff --git a/packages/app-lib/src/date/date.lib.ts b/packages/utils/src/date/date.lib.ts similarity index 100% rename from packages/app-lib/src/date/date.lib.ts rename to packages/utils/src/date/date.lib.ts diff --git a/packages/app-lib/src/date/index.ts b/packages/utils/src/date/index.ts similarity index 100% rename from packages/app-lib/src/date/index.ts rename to packages/utils/src/date/index.ts diff --git a/packages/app-lib/src/error/error.lib.ts b/packages/utils/src/error/error.lib.ts similarity index 100% rename from packages/app-lib/src/error/error.lib.ts rename to packages/utils/src/error/error.lib.ts diff --git a/packages/app-lib/src/error/index.ts b/packages/utils/src/error/index.ts similarity index 100% rename from packages/app-lib/src/error/index.ts rename to packages/utils/src/error/index.ts diff --git a/packages/app-lib/src/evm/evm.lib.ts b/packages/utils/src/evm/evm.lib.ts similarity index 100% rename from packages/app-lib/src/evm/evm.lib.ts rename to packages/utils/src/evm/evm.lib.ts diff --git a/packages/app-lib/src/evm/index.ts b/packages/utils/src/evm/index.ts similarity index 100% rename from packages/app-lib/src/evm/index.ts rename to packages/utils/src/evm/index.ts diff --git a/packages/app-lib/src/index.ts b/packages/utils/src/index.ts similarity index 100% rename from packages/app-lib/src/index.ts rename to packages/utils/src/index.ts diff --git a/packages/app-lib/src/number/index.ts b/packages/utils/src/number/index.ts similarity index 100% rename from packages/app-lib/src/number/index.ts rename to packages/utils/src/number/index.ts diff --git a/packages/app-lib/src/number/number.lib.ts b/packages/utils/src/number/number.lib.ts similarity index 100% rename from packages/app-lib/src/number/number.lib.ts rename to packages/utils/src/number/number.lib.ts diff --git a/packages/app-lib/src/object/index.ts b/packages/utils/src/object/index.ts similarity index 100% rename from packages/app-lib/src/object/index.ts rename to packages/utils/src/object/index.ts diff --git a/packages/app-lib/src/object/object.lib.ts b/packages/utils/src/object/object.lib.ts similarity index 100% rename from packages/app-lib/src/object/object.lib.ts rename to packages/utils/src/object/object.lib.ts diff --git a/packages/app-lib/src/runtime/index.ts b/packages/utils/src/runtime/index.ts similarity index 100% rename from packages/app-lib/src/runtime/index.ts rename to packages/utils/src/runtime/index.ts diff --git a/packages/app-lib/src/runtime/runtime.lib.ts b/packages/utils/src/runtime/runtime.lib.ts similarity index 100% rename from packages/app-lib/src/runtime/runtime.lib.ts rename to packages/utils/src/runtime/runtime.lib.ts diff --git a/packages/app-lib/src/string/index.ts b/packages/utils/src/string/index.ts similarity index 100% rename from packages/app-lib/src/string/index.ts rename to packages/utils/src/string/index.ts diff --git a/packages/app-lib/src/string/string.lib.ts b/packages/utils/src/string/string.lib.ts similarity index 100% rename from packages/app-lib/src/string/string.lib.ts rename to packages/utils/src/string/string.lib.ts diff --git a/packages/app-lib/src/url/index.ts b/packages/utils/src/url/index.ts similarity index 100% rename from packages/app-lib/src/url/index.ts rename to packages/utils/src/url/index.ts diff --git a/packages/app-lib/src/url/url.lib.ts b/packages/utils/src/url/url.lib.ts similarity index 100% rename from packages/app-lib/src/url/url.lib.ts rename to packages/utils/src/url/url.lib.ts diff --git a/packages/app-lib/tsconfig.json b/packages/utils/tsconfig.json similarity index 61% rename from packages/app-lib/tsconfig.json rename to packages/utils/tsconfig.json index d78879cf6..467a965e8 100644 --- a/packages/app-lib/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@repo/typescript-config/react-library.json", + "extends": "../../packages/tsconfig/react-library.json", "include": ["src", "../../apps/indexer/src/lib/logger.ts"], "exclude": ["node_modules"] }