diff --git a/.changeset/rude-radios-grab.md b/.changeset/rude-radios-grab.md new file mode 100644 index 000000000..cc247a3cd --- /dev/null +++ b/.changeset/rude-radios-grab.md @@ -0,0 +1,5 @@ +--- +'@lit-protocol/e2e': patch +--- + +Add standalone Naga health checks (EOA + single PKP) covering handshake, pkpSign, signSessionKey, executeJs, and encrypt/decrypt, with status logging via @lit-protocol/lit-status-sdk (no breaking changes). diff --git a/.github/workflows/naga-health-check.yml b/.github/workflows/naga-health-check.yml new file mode 100644 index 000000000..7c4138cbb --- /dev/null +++ b/.github/workflows/naga-health-check.yml @@ -0,0 +1,114 @@ +name: Naga Health Checks + +on: + push: + branches: + - feature/jss-29-feature-add-naga-uptime-bot + schedule: + - cron: '*/5 * * * *' + workflow_dispatch: + inputs: + naga_branch: + description: 'Branch to run health checks from (optional)' + required: true + default: 'naga' + network: + description: 'Specific network to test (leave empty for all)' + required: false + type: choice + options: + - naga-dev + - naga-test + +env: + LIT_STATUS_WRITE_KEY: ${{ secrets.LIT_STATUS_WRITE_KEY }} + LIT_STATUS_BACKEND_URL: ${{ vars.LIT_STATUS_BACKEND_URL }} + +jobs: + naga-health-check: + runs-on: ubuntu-latest + environment: Health Check + strategy: + fail-fast: false + matrix: + network: [naga-dev, naga-test] + env: + NETWORK: ${{ matrix.network }} + LIVE_MASTER_ACCOUNT: ${{ matrix.network == 'naga-dev' && secrets.LIVE_MASTER_ACCOUNT_NAGA_DEV || secrets.LIVE_MASTER_ACCOUNT_NAGA_TEST }} + LIT_YELLOWSTONE_PRIVATE_RPC_URL: ${{ vars.LIT_YELLOWSTONE_PRIVATE_RPC_URL }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.naga_branch || github.ref }} + fetch-depth: 1 + + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rust-std + + - name: Install wasm-pack + uses: jetli/wasm-pack-action@v0.4.0 + with: + version: latest + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22.18.0' + registry-url: 'https://registry.npmjs.org' + + - name: Enable corepack and setup pnpm + run: | + corepack enable + corepack prepare pnpm@9.15.0 --activate + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project + run: pnpm build + + - name: Verify required environment variables + run: | + echo "Checking environment variables for ${{ matrix.network }}..." + if [ -z "${LIVE_MASTER_ACCOUNT}" ]; then + echo "❌ LIVE_MASTER_ACCOUNT is not set for ${{ matrix.network }}" + exit 1 + fi + if [ -z "${LIT_STATUS_WRITE_KEY}" ]; then + echo "❌ LIT_STATUS_WRITE_KEY is not set" + exit 1 + fi + if [ -z "${LIT_STATUS_BACKEND_URL}" ]; then + echo "❌ LIT_STATUS_BACKEND_URL is not set" + exit 1 + fi + echo "✅ All required environment variables are set" + + - name: Run health check for ${{ matrix.network }} + if: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.network == '' || github.event.inputs.network == matrix.network }} + run: pnpm run ci:health + timeout-minutes: 10 + env: + NETWORK: ${{ matrix.network }} + LIVE_MASTER_ACCOUNT: ${{ matrix.network == 'naga-dev' && secrets.LIVE_MASTER_ACCOUNT_NAGA_DEV || secrets.LIVE_MASTER_ACCOUNT_NAGA_TEST }} + LIT_STATUS_WRITE_KEY: ${{ secrets.LIT_STATUS_WRITE_KEY }} + LIT_STATUS_BACKEND_URL: ${{ vars.LIT_STATUS_BACKEND_URL }} + LIT_YELLOWSTONE_PRIVATE_RPC_URL: ${{ vars.LIT_YELLOWSTONE_PRIVATE_RPC_URL }} + LOG_LEVEL: info + + - name: Health check summary + if: always() + run: | + if [[ "${{ job.status }}" == "success" ]]; then + echo "✅ Health check passed for ${{ matrix.network }}" + echo "Time: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" + else + echo "❌ Health check failed for ${{ matrix.network }}" + echo "Time: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" + echo "Please check the logs above for details" + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a55d15793..b4bfae112 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,7 +45,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - ref: ${{ github.event.workflow_run.head_sha }} + ref: ${{ github.event.workflow_run.head_branch }} - name: Setup PNPM uses: pnpm/action-setup@v4 @@ -91,7 +91,7 @@ jobs: id: changesets uses: changesets/action@v1 with: - branch: naga + branch: ${{ github.event.workflow_run.head_branch || 'naga' }} version: pnpm changeset version publish: pnpm changeset publish --access public commit: 'chore(release): version packages' diff --git a/package.json b/package.json index 7813a7dcf..26a3ee1bf 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "format:check": "npx nx format:check --all", "test:e2e": "npx jest --clearCache --config ./jest.e2e.config.ts && LOG_LEVEL=${LOG_LEVEL:-silent} dotenvx run --env-file=.env -- jest --runInBand --detectOpenHandles --forceExit --config ./jest.e2e.config.ts --testTimeout=50000000 -t", "test:custom": "npx jest --clearCache --config ./jest.e2e.config.ts && LOG_LEVEL=${LOG_LEVEL:-silent} dotenvx run --env-file=.env -- jest --runInBand --detectOpenHandles --forceExit --config ./jest.e2e.config.ts --testTimeout=50000000", - "test:e2e:ci": "npx jest --clearCache --config ./jest.e2e.config.ts && LOG_LEVEL=${LOG_LEVEL:-silent} npx jest --runInBand --detectOpenHandles --forceExit --config ./jest.e2e.config.ts --testTimeout=50000000 --runTestsByPath" + "test:e2e:ci": "npx jest --clearCache --config ./jest.e2e.config.ts && LOG_LEVEL=${LOG_LEVEL:-silent} npx jest --runInBand --detectOpenHandles --forceExit --config ./jest.e2e.config.ts --testTimeout=50000000 --runTestsByPath", + "test:health": "LOG_LEVEL=${LOG_LEVEL:-silent} dotenvx run --env-file=.env -- tsx packages/e2e/src/health/index.ts", + "ci:health": "LOG_LEVEL=${LOG_LEVEL:-silent} tsx packages/e2e/src/health/index.ts" }, "private": true, "dependencies": { @@ -21,6 +23,7 @@ "@babel/preset-env": "^7.28.3", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.6.4", + "@lit-protocol/lit-status-sdk": "^0.1.8", "@lit-protocol/nacl": "7.1.1", "@lit-protocol/uint8arrays": "7.1.1", "@metamask/eth-sig-util": "5.0.2", diff --git a/packages/e2e/src/health/NagaHealthManager.ts b/packages/e2e/src/health/NagaHealthManager.ts new file mode 100644 index 000000000..122c58a26 --- /dev/null +++ b/packages/e2e/src/health/NagaHealthManager.ts @@ -0,0 +1,247 @@ +/** + * Naga Health Manager + * + * This module implements health checks for Naga network endpoints. + * It tests the core functionality of the Lit Protocol network by executing + * a series of endpoint tests using a single test account. + * + * Tested Endpoints: + * 1. Handshake - Verifies basic node connectivity + * 2. PKP Sign - Tests PKP signing functionality + * 3. Sign Session Key - Tests session key signing (via PKP auth context creation) + * 4. Execute JS - Tests Lit Actions execution + * 5. Decrypt - Tests encryption and decryption flow + * + * Usage: + * const manager = new NagaHealthManager(ctx); + * await manager.handshakeTest(); + * await manager.pkpSignTest(); + * // ... other tests + */ + +import { initHealthCheck } from './health-init'; +import { createAccBuilder } from '@lit-protocol/access-control-conditions'; + +type HealthCheckContext = Awaited>; + +export class NagaHealthManager { + private ctx: HealthCheckContext; + + constructor(ctx: HealthCheckContext) { + this.ctx = ctx; + } + + /** + * Test 1: Handshake Test + * + * Verifies basic connectivity to Lit nodes by checking if the client + * is properly initialized and connected. + * + * This is the most basic health check - if this fails, the network is down. + */ + handshakeTest = async (): Promise => { + try { + // Fetch current context which includes the latest handshake result + const ctx = await this.ctx.litClient.getContext(); + + if (!ctx?.handshakeResult) { + throw new Error('Handshake result missing from client context'); + } + + const { serverKeys, connectedNodes, threshold } = ctx.handshakeResult; + + const numServers = serverKeys ? Object.keys(serverKeys).length : 0; + const numConnected = connectedNodes ? connectedNodes.size : 0; + + if (numServers === 0) { + throw new Error('No server keys received during handshake'); + } + + if (typeof threshold === 'number' && numConnected < threshold) { + throw new Error( + `Connected nodes (${numConnected}) below threshold (${threshold})` + ); + } + + console.log('✅ Handshake test passed'); + } catch (e) { + console.error('❌ Handshake test failed:', e); + throw e; + } + }; + + /** + * Test 2: PKP Sign Test + * + * Tests the PKP signing endpoint by signing a simple message. + * This verifies that: + * - The PKP is accessible + * - The auth context is valid + * - The signing endpoint is operational + */ + pkpSignTest = async (): Promise => { + try { + const testMessage = 'Hello from Naga health check!'; + + const result = await this.ctx.litClient.chain.ethereum.pkpSign({ + authContext: this.ctx.aliceEoaAuthContext, + pubKey: this.ctx.aliceViemAccountPkp.pubkey, + toSign: testMessage, + }); + + if (!result.signature) { + throw new Error('No signature returned from pkpSign'); + } + + console.log('✅ PKP Sign test passed'); + } catch (e) { + console.error('❌ PKP Sign test failed:', e); + throw e; + } + }; + + /** + * Test 3: Sign Session Key Test + * + * Tests the session key signing endpoint by creating a PKP auth context. + * This involves the signSessionKey endpoint which is critical for + * establishing authenticated sessions with PKPs. + */ + signSessionKeyTest = async (): Promise => { + try { + // Creating a PKP auth context involves calling the signSessionKey endpoint + const pkpAuthContext = await this.ctx.authManager.createPkpAuthContext({ + authData: this.ctx.aliceViemAccountAuthData, + pkpPublicKey: this.ctx.aliceViemAccountPkp.pubkey, + authConfig: { + resources: [ + ['pkp-signing', '*'], + ['lit-action-execution', '*'], + ], + expiration: new Date(Date.now() + 1000 * 60 * 15).toISOString(), // 15 minutes + }, + litClient: this.ctx.litClient, + }); + + if (!pkpAuthContext) { + throw new Error('Failed to create PKP auth context'); + } + + console.log('✅ Sign Session Key test passed'); + } catch (e) { + console.error('❌ Sign Session Key test failed:', e); + throw e; + } + }; + + /** + * Test 4: Execute JS Test + * + * Tests Lit Actions execution by running a simple JavaScript code + * that performs an ECDSA signature. + * + * This verifies: + * - Lit Actions runtime is operational + * - Code execution environment is working + * - Signing within actions works + */ + executeJsTest = async (): Promise => { + try { + const litActionCode = ` +(async () => { + const { sigName, toSign, publicKey } = jsParams; + const { keccak256, arrayify } = ethers.utils; + + const toSignBytes = new TextEncoder().encode(toSign); + const toSignBytes32 = keccak256(toSignBytes); + const toSignBytes32Array = arrayify(toSignBytes32); + + const sigShare = await Lit.Actions.signEcdsa({ + toSign: toSignBytes32Array, + publicKey, + sigName, + }); +})();`; + + const result = await this.ctx.litClient.executeJs({ + code: litActionCode, + authContext: this.ctx.aliceEoaAuthContext, + jsParams: { + sigName: 'health-check-sig', + toSign: 'Health check message', + publicKey: this.ctx.aliceViemAccountPkp.pubkey, + }, + }); + + if (!result || !result.signatures) { + throw new Error('No signatures returned from executeJs'); + } + + console.log('✅ Execute JS test passed'); + } catch (e) { + console.error('❌ Execute JS test failed:', e); + throw e; + } + }; + + /** + * Test 5: Decrypt Test + * + * Tests the encryption and decryption flow: + * 1. Encrypts data with access control conditions + * 2. Decrypts the data using the same account + * + * This verifies: + * - Encryption endpoint works + * - Access control condition evaluation works + * - Decryption endpoint works + * - End-to-end encryption flow is operational + */ + decryptTest = async (): Promise => { + try { + const testData = 'Secret health check data'; + + // Create access control conditions for Alice's wallet + const builder = createAccBuilder(); + const accs = builder + .requireWalletOwnership(this.ctx.aliceViemAccount.address) + .on('ethereum') + .build(); + + // Encrypt the data + const encryptedData = await this.ctx.litClient.encrypt({ + dataToEncrypt: testData, + unifiedAccessControlConditions: accs, + chain: 'ethereum', + }); + + if (!encryptedData.ciphertext || !encryptedData.dataToEncryptHash) { + throw new Error('Encryption failed - missing ciphertext or hash'); + } + + // Decrypt the data + const decryptedData = await this.ctx.litClient.decrypt({ + data: encryptedData, + unifiedAccessControlConditions: accs, + chain: 'ethereum', + authContext: this.ctx.aliceEoaAuthContext, + }); + + if (!decryptedData.convertedData) { + throw new Error('Decryption failed - no converted data'); + } + + // Verify the decrypted data matches + if (decryptedData.convertedData !== testData) { + throw new Error( + `Decryption mismatch: expected "${testData}", got "${decryptedData.convertedData}"` + ); + } + + console.log('✅ Decrypt test passed'); + } catch (e) { + console.error('❌ Decrypt test failed:', e); + throw e; + } + }; +} diff --git a/packages/e2e/src/health/README.md b/packages/e2e/src/health/README.md new file mode 100644 index 000000000..dd9723184 --- /dev/null +++ b/packages/e2e/src/health/README.md @@ -0,0 +1,270 @@ +# Naga Health Checks + +This directory contains the health check system for Naga networks. Health checks run automatically every 5 minutes to monitor the status of critical Lit Protocol endpoints. + +## 🎯 Purpose + +The health check system verifies that core Lit Protocol functionality is operational by testing key endpoints: + +1. **Handshake** - Basic node connectivity +2. **PKP Sign** - PKP signing functionality +3. **Sign Session Key** - Session key signing for PKP authentication +4. **Execute JS** - Lit Actions execution +5. **Decrypt** - Encryption and decryption flow + +Results are automatically logged to the Lit Status backend for monitoring and alerting. + +## 📁 File Structure + +``` +health/ +├── README.md # This file +├── health-init.ts # Lightweight initialization with minimal chain interactions +├── NagaHealthManager.ts # Health check test implementations +└── index.ts # Main runner with lit-status-sdk integration +``` + +## 🏗️ Architecture + +### Design Philosophy + +The health check system is designed to be: + +- **Lightweight**: Minimal chain interactions to reduce overhead +- **Fast**: Quick execution for frequent monitoring (every 5 minutes) +- **Reliable**: Single person setup reduces points of failure +- **Standalone**: Separate from e2e tests to avoid interference + +### How It Works + +1. **Initialization** (`health-init.ts`): + + - Creates a single test account (Alice) + - Funds it with minimal amount + - Creates one PKP + - Sets up EOA auth context + - No Bob, Eve, or complex multi-account setup + +2. **Test Execution** (`NagaHealthManager.ts`): + + - Reuses the same Alice account and auth context + - Tests each endpoint sequentially + - Throws errors on failures for proper error tracking + +3. **Logging** (`index.ts`): + - Integrates with `@lit-protocol/lit-status-sdk` + - Logs test results to status backend + - Provides detailed console output + +## 🚀 Usage + +### Local Testing + +Test health checks locally before deploying: + +```bash +# Set up environment variables in .env +NETWORK=naga-dev +LIVE_MASTER_ACCOUNT=0x... +LIT_STATUS_BACKEND_URL=https://status.litprotocol.com +LIT_STATUS_WRITE_KEY=your-api-key + +# Run health check +pnpm run test:health +``` + +### CI/CD Testing + +Health checks run automatically via GitHub Actions: + +```bash +# Runs without .env file (uses GitHub secrets) +pnpm run ci:health +``` + +### Manual GitHub Workflow Trigger + +You can manually trigger health checks from GitHub: + +1. Go to Actions → Naga Health Checks +2. Click "Run workflow" +3. Select branch (default: `naga`) +4. (Optional) Select specific network or leave empty for all +5. Click "Run workflow" + +## 🔧 Configuration + +### Environment Variables + +**Required:** + +- `NETWORK` - Network to test (`naga-dev` or `naga-test`) +- `LIVE_MASTER_ACCOUNT` - Private key for funding test accounts +- `LIT_STATUS_BACKEND_URL` - URL of the status monitoring backend +- `LIT_STATUS_WRITE_KEY` - API key for writing status updates + +**Optional:** + +- `LOG_LEVEL` - Logging verbosity (`silent`, `info`, `debug`) - default: `silent` +- `LIT_YELLOWSTONE_PRIVATE_RPC_URL` - Override RPC URL if needed + +### GitHub Secrets + +Configure these in your repository settings under `Settings → Secrets and variables → Actions`: + +**Secrets:** + +- `LIT_STATUS_WRITE_KEY` - API key for status backend +- `LIVE_MASTER_ACCOUNT_NAGA_DEV` - Funding account for naga-dev +- `LIVE_MASTER_ACCOUNT_NAGA_TEST` - Funding account for naga-test + +**Variables:** + +- `LIT_STATUS_BACKEND_URL` - Status backend URL +- `LIT_YELLOWSTONE_PRIVATE_RPC_URL` - (Optional) Custom RPC URL + +Environment: `Health Check` (create this environment in repository settings) + +## 📊 Monitoring + +### Status Dashboard + +View health check results at the Lit Status dashboard: + +- URL: Configured via `LIT_STATUS_BACKEND_URL` +- Shows success/failure rates +- Tracks response times +- Provides historical data + +### GitHub Actions + +Monitor workflow runs: + +- Go to `Actions → Naga Health Checks` +- View recent runs and their status +- Check logs for detailed error messages + +## 🔍 Troubleshooting + +### Health Check Failures + +If health checks fail: + +1. **Check the logs** - GitHub Actions logs show which test failed +2. **Verify network status** - Is the network operational? +3. **Check balances** - Does the master account have sufficient funds? +4. **Validate secrets** - Are GitHub secrets configured correctly? + +### Common Issues + +**Error: "NETWORK environment variable is not set"** + +- Solution: Ensure `NETWORK` is set in the workflow or .env file + +**Error: "LIVE_MASTER_ACCOUNT is not set"** + +- Solution: Check that the appropriate secret is configured in GitHub + +**Error: "Failed to get network information"** + +- Solution: Network may be down or unreachable. Check node status. + +**Error: "Insufficient funds"** + +- Solution: Fund the master account with more tokens + +## 🧪 Testing Locally + +To test the health check system locally: + +```bash +# 1. Build the project +pnpm build + +# 2. Set up .env file with required variables +cat > .env << EOF +NETWORK=naga-dev +LIVE_MASTER_ACCOUNT=0x...your-key... +LIT_STATUS_BACKEND_URL=https://status.litprotocol.com +LIT_STATUS_WRITE_KEY=your-api-key +LOG_LEVEL=info +EOF + +# 3. Run health check +pnpm run test:health + +# 4. Check output for success/failure +``` + +## 📝 Adding New Tests + +To add a new health check test: + +1. **Add test method to `NagaHealthManager.ts`**: + +```typescript +myNewTest = async (): Promise => { + try { + // Your test logic here + console.log('✅ My new test passed'); + } catch (e) { + console.error('❌ My new test failed:', e); + throw e; + } +}; +``` + +2. **Register function in `index.ts`**: + +```typescript +const txs = await statusClient.getOrRegisterFunctions({ + network: NETWORK!, + product: PRODUCT, + functions: [ + 'handshake', + 'pkpSign', + 'signSessionKey', + 'executeJs', + 'decrypt', + 'myNewTest', // Add here + ] as const, +}); +``` + +3. **Execute test in `index.ts`**: + +```typescript +console.log('6️⃣ Testing: My New Test'); +await statusClient.executeAndLog(txs.myNewTest.id, healthManager.myNewTest); +``` + +## 🔐 Security Considerations + +- **Private Keys**: Never commit private keys. Use GitHub secrets. +- **API Keys**: Status write keys should be kept secret. +- **Funding Accounts**: Monitor balance and limit exposure. +- **RPC URLs**: Private RPC URLs should not be logged or exposed. + +## 📚 Related Documentation + +- [E2E Testing Guide](../README.md) +- [Lit Status SDK](https://www.npmjs.com/package/@lit-protocol/lit-status-sdk) +- [GitHub Actions Workflows](../../../../.github/workflows/) + +## 🤝 Contributing + +When modifying health checks: + +1. Test locally first +2. Ensure all tests pass +3. Update this README if adding features +4. Document any new environment variables +5. Update GitHub secrets/variables if needed + +## 📧 Support + +For issues or questions: + +- Create an issue in the repository +- Contact the Lit Protocol team +- Check the status dashboard for network-wide issues diff --git a/packages/e2e/src/health/health-init.ts b/packages/e2e/src/health/health-init.ts new file mode 100644 index 000000000..9b404a52e --- /dev/null +++ b/packages/e2e/src/health/health-init.ts @@ -0,0 +1,250 @@ +/** + * Health Check Initialization Module + * + * This module provides a lightweight initialization for health checks that minimizes + * chain interactions. Unlike the full e2e init, this only creates a single test person + * using EOA authentication and reuses it across all endpoint tests. + * + * Design Philosophy: + * - Minimal chain interactions (only what's necessary for testing endpoints) + * - Single person setup to reduce overhead + * - Fast execution for frequent health monitoring + * - Reusable auth context across all tests + */ + +import { + createAuthManager, + storagePlugins, + ViemAccountAuthenticator, +} from '@lit-protocol/auth'; +import { createLitClient } from '@lit-protocol/lit-client'; +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; +import { z } from 'zod'; +import { fundAccount } from '../helper/fundAccount'; +import { getOrCreatePkp } from '../helper/pkp-utils'; +import { PKPData, AuthData } from '@lit-protocol/schemas'; +import { + AuthContext, + AuthManagerInstance, + LitClientInstance, + ViemAccount, +} from '../types'; + +const SupportedNetworkSchema = z.enum(['naga-dev', 'naga-test']); + +type SupportedNetwork = z.infer; + +const LogLevelSchema = z.enum(['silent', 'info', 'debug']); +type LogLevel = z.infer; + +// Configuration constants +const LIVE_NETWORK_FUNDING_AMOUNT = '0.01'; +const LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT = '2'; + +/** + * Initialize the health check environment with minimal setup + * + * This function: + * 1. Creates a single test account (Alice) + * 2. Funds it minimally + * 3. Creates one PKP for testing + * 4. Sets up auth context for endpoint testing + * + * @param network - The network to run health checks on (naga-dev or naga-test) + * @param logLevel - Logging level for the health check run + * @returns Initialized components needed for health checks + */ +export const initHealthCheck = async ( + network?: SupportedNetwork, + logLevel?: LogLevel +): Promise<{ + litClient: LitClientInstance; + authManager: AuthManagerInstance; + aliceViemAccount: ViemAccount; + aliceViemAccountAuthData: AuthData; + aliceViemAccountPkp: PKPData; + aliceEoaAuthContext: AuthContext; + networkName: string; +}> => { + /** + * ==================================== + * Environment Configuration + * ==================================== + */ + const _network = network || process.env['NETWORK']; + const _logLevel = logLevel || process.env['LOG_LEVEL'] || 'silent'; + process.env['LOG_LEVEL'] = _logLevel; + + if (!_network) { + throw new Error( + `❌ Network not specified. Please set the NETWORK environment variable or pass a network parameter. Available networks: ${SupportedNetworkSchema.options.join( + ', ' + )}` + ); + } + + // Validate network + const parsedNetwork = SupportedNetworkSchema.safeParse(_network); + if (!parsedNetwork.success) { + throw new Error( + `❌ Invalid network: ${_network}. Must be one of: ${SupportedNetworkSchema.options.join( + ', ' + )}` + ); + } + + console.log('🔍 Health Check Configuration:'); + console.log(' Network:', _network); + console.log(' Log Level:', _logLevel); + + /** + * ==================================== + * Account Setup (Minimal) + * ==================================== + */ + const masterAccount = privateKeyToAccount( + process.env['LIVE_MASTER_ACCOUNT'] as `0x${string}` + ); + + // Create a single test account + const aliceViemAccount = privateKeyToAccount(generatePrivateKey()); + const aliceViemAccountAuthData = await ViemAccountAuthenticator.authenticate( + aliceViemAccount + ); + + /** + * ==================================== + * Network Module Setup + * ==================================== + */ + const networkConfig = { + 'naga-dev': { importName: 'nagaDev' }, + 'naga-test': { importName: 'nagaTest' }, + } as const; + + const config = networkConfig[_network as keyof typeof networkConfig]; + if (!config) { + throw new Error(`❌ Invalid network configuration for: ${_network}`); + } + + // Dynamic import of network module + const networksModule = await import('@lit-protocol/networks'); + const _baseNetworkModule = networksModule[config.importName]; + + // Optional RPC override + const rpcOverride = process.env['LIT_YELLOWSTONE_PRIVATE_RPC_URL']; + const _networkModule = + rpcOverride && typeof _baseNetworkModule.withOverrides === 'function' + ? _baseNetworkModule.withOverrides({ rpcUrl: rpcOverride }) + : _baseNetworkModule; + + if (rpcOverride) { + console.log(' RPC Override:', rpcOverride); + } + + /** + * ==================================== + * Fund Account (Minimal) + * ==================================== + */ + await fundAccount(aliceViemAccount, masterAccount, _networkModule, { + ifLessThan: LIVE_NETWORK_FUNDING_AMOUNT, + thenFundWith: LIVE_NETWORK_FUNDING_AMOUNT, + }); + + /** + * ==================================== + * Initialize Lit Client + * ==================================== + */ + const litClient = await createLitClient({ network: _networkModule }); + console.log('✅ Lit Client initialized'); + + /** + * ==================================== + * Payment Manager Setup + * ==================================== + */ + const masterPaymentManager = await litClient.getPaymentManager({ + account: masterAccount, + }); + + const masterPaymentBalance = await masterPaymentManager.getBalance({ + userAddress: masterAccount.address, + }); + console.log('✅ Master Payment Balance:', masterPaymentBalance); + + // Deposit for Alice + await masterPaymentManager.depositForUser({ + userAddress: aliceViemAccount.address, + amountInEth: LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT, + }); + + /** + * ==================================== + * Auth Manager Setup + * ==================================== + */ + const authManager = createAuthManager({ + storage: storagePlugins.localStorageNode({ + appName: 'lit-health-check', + networkName: _network, + storagePath: './.health-check/lit-auth-local', + }), + }); + + /** + * ==================================== + * Create PKP for Alice (Minimal) + * ==================================== + */ + const aliceViemAccountPkp = await getOrCreatePkp( + litClient, + aliceViemAccountAuthData, + aliceViemAccount + ); + + // Deposit for Alice's PKP + await masterPaymentManager.depositForUser({ + userAddress: aliceViemAccountPkp.ethAddress, + amountInEth: LIVE_NETWORK_LEDGER_DEPOSIT_AMOUNT, + }); + + console.log('✅ PKP created and funded'); + + /** + * ==================================== + * Create EOA Auth Context + * ==================================== + */ + const aliceEoaAuthContext = await authManager.createEoaAuthContext({ + config: { + account: aliceViemAccount, + }, + authConfig: { + statement: 'Health check authorization for Lit Protocol endpoints.', + domain: 'health-check.lit', + resources: [ + ['lit-action-execution', '*'], + ['pkp-signing', '*'], + ['access-control-condition-decryption', '*'], + ], + capabilityAuthSigs: [], + expiration: new Date(Date.now() + 1000 * 60 * 30).toISOString(), // 30 minutes + }, + litClient: litClient, + }); + + console.log('✅ Auth context created'); + console.log('✅ Health check initialization complete\n'); + + return { + litClient, + authManager, + aliceViemAccount, + aliceViemAccountAuthData, + aliceViemAccountPkp, + aliceEoaAuthContext, + networkName: _network, + }; +}; diff --git a/packages/e2e/src/health/index.ts b/packages/e2e/src/health/index.ts new file mode 100644 index 000000000..3764c615f --- /dev/null +++ b/packages/e2e/src/health/index.ts @@ -0,0 +1,183 @@ +/** + * Naga Health Check Runner + * + * This is the main entry point for running health checks on Naga networks. + * It initializes the environment, runs all endpoint tests, and logs results + * to the Lit Status backend for monitoring. + * + * Environment Variables Required: + * - NETWORK: The network to test (naga-dev or naga-test) + * - LIVE_MASTER_ACCOUNT: Private key of the master funding account + * - LIT_STATUS_BACKEND_URL: URL of the status backend + * - LIT_STATUS_WRITE_KEY: API key for writing to status backend + * + * Optional: + * - LOG_LEVEL: Logging verbosity (silent, info, debug) + * - LIT_YELLOWSTONE_PRIVATE_RPC_URL: Override RPC URL + * + * Usage: + * NETWORK=naga-dev pnpm run ci:health + * NETWORK=naga-test pnpm run test:health + */ + +import { initHealthCheck } from './health-init'; +import { NagaHealthManager } from './NagaHealthManager'; + +// Configuration from environment +const NETWORK = process.env['NETWORK']; +const PRODUCT = 'js-sdk/naga'; + +/** + * Validate required environment variables + */ +function validateEnvironment(): void { + console.log('🔍 Environment Variables:'); + console.log(' NETWORK:', process.env['NETWORK']); + console.log( + ' LIT_STATUS_BACKEND_URL:', + process.env['LIT_STATUS_BACKEND_URL'] + ); + console.log( + ' LIT_STATUS_WRITE_KEY:', + process.env['LIT_STATUS_WRITE_KEY'] ? '[SET]' : '[NOT SET]' + ); + console.log( + ' LIVE_MASTER_ACCOUNT:', + process.env['LIVE_MASTER_ACCOUNT'] ? '[SET]' : '[NOT SET]' + ); + + if (!NETWORK) { + throw new Error('❌ NETWORK environment variable is not set'); + } + + if (!process.env['LIT_STATUS_BACKEND_URL']) { + throw new Error( + '❌ LIT_STATUS_BACKEND_URL environment variable is not set' + ); + } + + if (!process.env['LIT_STATUS_WRITE_KEY']) { + throw new Error('❌ LIT_STATUS_WRITE_KEY environment variable is not set'); + } + + if (!process.env['LIVE_MASTER_ACCOUNT']) { + throw new Error('❌ LIVE_MASTER_ACCOUNT environment variable is not set'); + } + + console.log('✅ All required environment variables are set\n'); +} + +/** + * Main health check execution + */ +async function runHealthCheck(): Promise { + // Validate environment + validateEnvironment(); + + console.log('═══════════════════════════════════════'); + console.log('🏥 Naga Health Check Starting'); + console.log('═══════════════════════════════════════'); + console.log(`Network: ${NETWORK}`); + console.log(`Product: ${PRODUCT}`); + console.log(`Time: ${new Date().toISOString()}\n`); + + // Initialize Lit Status Client (dynamic import for ESM compatibility) + const { createLitStatusClient } = await import( + '@lit-protocol/lit-status-sdk' + ); + const statusClient = createLitStatusClient({ + url: process.env['LIT_STATUS_BACKEND_URL']!, + apiKey: process.env['LIT_STATUS_WRITE_KEY']!, + }); + + console.log('✅ Lit Status Client initialized\n'); + + // Register or get function IDs for tracking + console.log('📝 Registering health check functions...'); + const txs = await statusClient.getOrRegisterFunctions({ + network: NETWORK!, + product: PRODUCT, + functions: [ + 'handshake', + 'pkpSign', + 'signSessionKey', + 'executeJs', + 'decrypt', + ] as const, + }); + + console.log('✅ Functions registered\n'); + + // Initialize health check environment + console.log('🚀 Initializing health check environment...'); + console.log('───────────────────────────────────────'); + const ctx = await initHealthCheck(); + console.log('───────────────────────────────────────\n'); + + // Create health manager + const healthManager = new NagaHealthManager(ctx); + + // Run tests and log results + console.log('🧪 Running Health Check Tests'); + console.log('═══════════════════════════════════════\n'); + + // Test 1: Handshake + console.log('1️⃣ Testing: Handshake'); + await statusClient.executeAndLog( + txs.handshake.id, + healthManager.handshakeTest + ); + console.log(''); + + // Test 2: PKP Sign + console.log('2️⃣ Testing: PKP Sign'); + await statusClient.executeAndLog(txs.pkpSign.id, healthManager.pkpSignTest); + console.log(''); + + // Test 3: Sign Session Key + console.log('3️⃣ Testing: Sign Session Key'); + await statusClient.executeAndLog( + txs.signSessionKey.id, + healthManager.signSessionKeyTest + ); + console.log(''); + + // Test 4: Execute JS + console.log('4️⃣ Testing: Execute JS (Lit Actions)'); + await statusClient.executeAndLog( + txs.executeJs.id, + healthManager.executeJsTest + ); + console.log(''); + + // Test 5: Decrypt + console.log('5️⃣ Testing: Encrypt/Decrypt'); + await statusClient.executeAndLog(txs.decrypt.id, healthManager.decryptTest); + console.log(''); + + console.log('═══════════════════════════════════════'); + console.log('✅ Health Check Completed Successfully'); + console.log('═══════════════════════════════════════'); + console.log(`Network: ${NETWORK}`); + console.log(`Time: ${new Date().toISOString()}`); + console.log('All 5 endpoint tests passed ✨\n'); +} + +/** + * Entry point with error handling + */ +(async () => { + try { + await runHealthCheck(); + process.exit(0); + } catch (error) { + console.error('\n═══════════════════════════════════════'); + console.error('❌ Health Check Failed'); + console.error('═══════════════════════════════════════'); + console.error('Error:', error); + console.error('Network:', NETWORK); + console.error('Time:', new Date().toISOString()); + console.error('═══════════════════════════════════════\n'); + process.exit(1); + } +})(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f082211c..f3ce1f53e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,6 +22,9 @@ importers: '@ethersproject/contracts': specifier: 5.8.0 version: 5.8.0 + '@lit-protocol/lit-status-sdk': + specifier: ^0.1.8 + version: 0.1.8(typescript@5.8.3) '@lit-protocol/nacl': specifier: 7.1.1 version: 7.1.1 @@ -3024,6 +3027,13 @@ packages: integrity: sha512-HKZPmO8OSSAAo20H2B3xgJdxZaLTwtlMwxg0967scnrDlPwe6j5+ULGHyIqwgTbFCn9yv/ff8CmfWZLE9YKBzA==, } + '@google-cloud/monitoring@5.3.0': + resolution: + { + integrity: sha512-jAx0ASRcRqr+TZIgMTS3gFQR/FqkYzd4usCD0Y/QOkWt4vTT0SgYMaXn62gtuuEmY66VNBVROhpzOMeasgHuKw==, + } + engines: { node: '>=18' } + '@grpc/grpc-js@1.13.4': resolution: { @@ -3039,6 +3049,14 @@ packages: engines: { node: '>=6' } hasBin: true + '@grpc/proto-loader@0.8.0': + resolution: + { + integrity: sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==, + } + engines: { node: '>=6' } + hasBin: true + '@hapi/hoek@9.3.0': resolution: { @@ -3497,6 +3515,14 @@ packages: peerDependencies: typescript: ^5.0.0 + '@lit-protocol/lit-status-sdk@0.1.8': + resolution: + { + integrity: sha512-Rq/1dvF1R3CExxHIbZNjZehidmam5hxGCbsXWiWQqHSJXnZNuhVdFMLfGUIWS+NVRRnmhg1jF8PJD768iP0MUg==, + } + peerDependencies: + typescript: ^5 + '@lit-protocol/nacl@7.1.1': resolution: { @@ -4075,6 +4101,13 @@ packages: integrity: sha512-+V7QuD6v5sMWez7cu+5DXoXMim+iQssOcspoNgbWDW8sEyC54Mdo5VuIkcIjqhPmQYOzBWo5qlbzNGEpD6PzMA==, } + '@opentelemetry/api-logs@0.203.0': + resolution: + { + integrity: sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ==, + } + engines: { node: '>=8.0.0' } + '@opentelemetry/api-logs@0.41.2': resolution: { @@ -7546,6 +7579,13 @@ packages: integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, } + data-uri-to-buffer@4.0.1: + resolution: + { + integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==, + } + engines: { node: '>= 12' } + data-urls@3.0.2: resolution: { @@ -8902,6 +8942,13 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: + { + integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==, + } + engines: { node: ^12.20 || >= 14.13 } + fflate@0.8.1: resolution: { @@ -9076,6 +9123,13 @@ packages: } engines: { node: '>= 6' } + formdata-polyfill@4.0.10: + resolution: + { + integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==, + } + engines: { node: '>=12.20.0' } + forwarded@0.2.0: resolution: { @@ -9171,6 +9225,13 @@ packages: } engines: { node: '>=14' } + gaxios@7.1.2: + resolution: + { + integrity: sha512-/Szrn8nr+2TsQT1Gp8iIe/BEytJmbyfrbFh419DfGQSkEgNEhbPi7JRJuughjkTzPWgU9gBQf5AVu3DbHt0OXA==, + } + engines: { node: '>=18' } + gcp-metadata@6.1.1: resolution: { @@ -9178,6 +9239,13 @@ packages: } engines: { node: '>=14' } + gcp-metadata@7.0.1: + resolution: + { + integrity: sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==, + } + engines: { node: '>=18' } + generic-pool@3.9.0: resolution: { @@ -9352,6 +9420,13 @@ packages: engines: { node: '>=0.6.0' } hasBin: true + google-auth-library@10.4.0: + resolution: + { + integrity: sha512-CmIrSy1bqMQUsPmA9+hcSbAXL80cFhu40cGMUjCaLpNKVzzvi+0uAHq8GNZxkoGYIsTX4ZQ7e4aInAqWxgn4fg==, + } + engines: { node: '>=18' } + google-auth-library@9.15.1: resolution: { @@ -9359,6 +9434,13 @@ packages: } engines: { node: '>=14' } + google-gax@5.0.4: + resolution: + { + integrity: sha512-HmQ6zIYBs2EikTk+kjeHmtHprNTEpsnVaKONw9cwZZwUNCkUb+D5RYrJpCxyjdvIDvJp3wLbVReolJLRZRms1g==, + } + engines: { node: '>=18' } + google-logging-utils@0.0.2: resolution: { @@ -9366,6 +9448,13 @@ packages: } engines: { node: '>=14' } + google-logging-utils@1.1.1: + resolution: + { + integrity: sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==, + } + engines: { node: '>=14' } + gopd@1.2.0: resolution: { @@ -9399,6 +9488,13 @@ packages: } engines: { node: '>=14.0.0' } + gtoken@8.0.0: + resolution: + { + integrity: sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==, + } + engines: { node: '>=18' } + h3@1.15.4: resolution: { @@ -11529,6 +11625,14 @@ packages: integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==, } + node-domexception@1.0.0: + resolution: + { + integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==, + } + engines: { node: '>=10.5.0' } + deprecated: Use your platform's native DOMException instead + node-fetch-native@1.6.7: resolution: { @@ -11547,6 +11651,13 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: + { + integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + node-gyp-build-optional-packages@5.2.2: resolution: { @@ -11674,6 +11785,13 @@ packages: } engines: { node: '>=0.10.0' } + object-hash@3.0.0: + resolution: + { + integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, + } + engines: { node: '>= 6' } + object-inspect@1.13.4: resolution: { @@ -12342,6 +12460,13 @@ packages: } engines: { node: '>=10' } + prom-client@15.1.3: + resolution: + { + integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==, + } + engines: { node: ^16 || ^18 || >=20 } + prompts@2.4.2: resolution: { @@ -12349,6 +12474,13 @@ packages: } engines: { node: '>= 6' } + proto3-json-serializer@3.0.2: + resolution: + { + integrity: sha512-AnMIfnoK2Ml3F/ZVl5PxcwIoefMxj4U/lomJ5/B2eIGdxw4UkbV1YamtsMQsEkZATdMCKMbnI1iG9RQaJbxBGw==, + } + engines: { node: '>=18' } + protobufjs@7.5.4: resolution: { @@ -12827,6 +12959,13 @@ packages: } engines: { node: '>=8' } + retry-request@8.0.2: + resolution: + { + integrity: sha512-JzFPAfklk1kjR1w76f0QOIhoDkNkSqW8wYKT08n9yysTmZfB+RQ2QoXoTAeOi1HD9ZipTyTAZg3c4pM/jeqgSw==, + } + engines: { node: '>=18' } + reusify@1.1.0: resolution: { @@ -13322,6 +13461,12 @@ packages: integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==, } + stream-events@1.0.5: + resolution: + { + integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==, + } + stream-http@3.2.0: resolution: { @@ -13504,6 +13649,12 @@ packages: } engines: { node: '>=18' } + stubs@3.0.0: + resolution: + { + integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==, + } + stylus-lookup@5.0.1: resolution: { @@ -13600,6 +13751,13 @@ packages: integrity: sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==, } + teeny-request@10.1.0: + resolution: + { + integrity: sha512-3ZnLvgWF29jikg1sAQ1g0o+lr5JX6sVgYvfUJazn7ZjJroDBUTWp44/+cFVX0bULjv4vci+rBD+oGVAkWqhUbw==, + } + engines: { node: '>=18' } + temp@0.9.4: resolution: { @@ -14420,6 +14578,13 @@ packages: integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==, } + web-streams-polyfill@3.3.3: + resolution: + { + integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==, + } + engines: { node: '>= 8' } + webextension-polyfill@0.10.0: resolution: { @@ -17258,6 +17423,12 @@ snapshots: '@shikijs/types': 3.12.2 '@shikijs/vscode-textmate': 10.0.2 + '@google-cloud/monitoring@5.3.0': + dependencies: + google-gax: 5.0.4 + transitivePeerDependencies: + - supports-color + '@grpc/grpc-js@1.13.4': dependencies: '@grpc/proto-loader': 0.7.15 @@ -17270,6 +17441,13 @@ snapshots: protobufjs: 7.5.4 yargs: 17.7.2 + '@grpc/proto-loader@0.8.0': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.5.4 + yargs: 17.7.2 + '@hapi/hoek@9.3.0': {} '@hapi/topo@5.1.0': @@ -17663,6 +17841,19 @@ snapshots: dependencies: typescript: 5.8.3 + '@lit-protocol/lit-status-sdk@0.1.8(typescript@5.8.3)': + dependencies: + '@google-cloud/monitoring': 5.3.0 + cors: 2.8.5 + express: 5.1.0 + prom-client: 15.1.3 + typescript: 5.8.3 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.203.0 + transitivePeerDependencies: + - supports-color + '@lit-protocol/nacl@7.1.1': dependencies: tslib: 1.14.1 @@ -18282,6 +18473,11 @@ snapshots: inherits: 2.0.4 sprintf-js: 1.1.3 + '@opentelemetry/api-logs@0.203.0': + dependencies: + '@opentelemetry/api': 1.9.0 + optional: true + '@opentelemetry/api-logs@0.41.2': dependencies: '@opentelemetry/api': 1.9.0 @@ -21546,6 +21742,8 @@ snapshots: damerau-levenshtein@1.0.8: {} + data-uri-to-buffer@4.0.1: {} + data-urls@3.0.2: dependencies: abab: 2.0.6 @@ -22638,6 +22836,11 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + fflate@0.8.1: {} fflate@0.8.2: {} @@ -22760,6 +22963,10 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + forwarded@0.2.0: {} fresh@2.0.0: {} @@ -22820,6 +23027,14 @@ snapshots: - encoding - supports-color + gaxios@7.1.2: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + gcp-metadata@6.1.1(encoding@0.1.13): dependencies: gaxios: 6.7.1(encoding@0.1.13) @@ -22829,6 +23044,14 @@ snapshots: - encoding - supports-color + gcp-metadata@7.0.1: + dependencies: + gaxios: 7.1.2 + google-logging-utils: 1.1.1 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + generic-pool@3.9.0: {} gensync@1.0.0-beta.2: {} @@ -22951,6 +23174,18 @@ snapshots: dependencies: minimist: 1.2.8 + google-auth-library@10.4.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.2 + gcp-metadata: 7.0.1 + google-logging-utils: 1.1.1 + gtoken: 8.0.0 + jws: 4.0.0 + transitivePeerDependencies: + - supports-color + google-auth-library@9.15.1(encoding@0.1.13): dependencies: base64-js: 1.5.1 @@ -22963,8 +23198,25 @@ snapshots: - encoding - supports-color + google-gax@5.0.4: + dependencies: + '@grpc/grpc-js': 1.13.4 + '@grpc/proto-loader': 0.8.0 + duplexify: 4.1.3 + google-auth-library: 10.4.0 + google-logging-utils: 1.1.1 + node-fetch: 3.3.2 + object-hash: 3.0.0 + proto3-json-serializer: 3.0.2 + protobufjs: 7.5.4 + retry-request: 8.0.2 + transitivePeerDependencies: + - supports-color + google-logging-utils@0.0.2: {} + google-logging-utils@1.1.1: {} + gopd@1.2.0: {} got@11.8.6: @@ -22993,6 +23245,13 @@ snapshots: - encoding - supports-color + gtoken@8.0.0: + dependencies: + gaxios: 7.1.2 + jws: 4.0.0 + transitivePeerDependencies: + - supports-color + h3@1.15.4: dependencies: cookie-es: 1.2.2 @@ -24431,6 +24690,8 @@ snapshots: node-addon-api@2.0.2: {} + node-domexception@1.0.0: {} + node-fetch-native@1.6.7: {} node-fetch@2.7.0(encoding@0.1.13): @@ -24439,6 +24700,12 @@ snapshots: optionalDependencies: encoding: 0.1.13 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.0.4 @@ -24544,6 +24811,8 @@ snapshots: object-assign@4.1.1: {} + object-hash@3.0.0: {} + object-inspect@1.13.4: {} object-is@1.1.6: @@ -24999,11 +25268,20 @@ snapshots: dependencies: tdigest: 0.1.2 + prom-client@15.1.3: + dependencies: + '@opentelemetry/api': 1.9.0 + tdigest: 0.1.2 + prompts@2.4.2: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 + proto3-json-serializer@3.0.2: + dependencies: + protobufjs: 7.5.4 + protobufjs@7.5.4: dependencies: '@protobufjs/aspromise': 1.1.2 @@ -25289,6 +25567,13 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + retry-request@8.0.2: + dependencies: + extend: 3.0.2 + teeny-request: 10.1.0 + transitivePeerDependencies: + - supports-color + reusify@1.1.0: {} rimraf@2.6.3: @@ -25607,6 +25892,10 @@ snapshots: stream-chain@2.2.5: {} + stream-events@1.0.5: + dependencies: + stubs: 3.0.0 + stream-http@3.2.0: dependencies: builtin-status-codes: 3.0.0 @@ -25716,6 +26005,8 @@ snapshots: dependencies: '@tokenizer/token': 0.3.0 + stubs@3.0.0: {} + stylus-lookup@5.0.1: dependencies: commander: 10.0.1 @@ -25773,6 +26064,15 @@ snapshots: dependencies: bintrees: 1.0.2 + teeny-request@10.1.0: + dependencies: + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + node-fetch: 3.3.2 + stream-events: 1.0.5 + transitivePeerDependencies: + - supports-color + temp@0.9.4: dependencies: mkdirp: 0.5.6 @@ -26314,6 +26614,8 @@ snapshots: dependencies: defaults: 1.0.4 + web-streams-polyfill@3.3.3: {} + webextension-polyfill@0.10.0: {} webidl-conversions@3.0.1: {}