From 7a7d6b749efb22e4203059dfbfe53d583a6e4ff9 Mon Sep 17 00:00:00 2001 From: krystal <56278409+theekrystallee@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:05:59 -0800 Subject: [PATCH 1/3] Add files via upload Signed-off-by: krystal <56278409+theekrystallee@users.noreply.github.com> --- .github/scripts/sync-openapi.js | 258 ++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 .github/scripts/sync-openapi.js diff --git a/.github/scripts/sync-openapi.js b/.github/scripts/sync-openapi.js new file mode 100644 index 0000000..8af2b53 --- /dev/null +++ b/.github/scripts/sync-openapi.js @@ -0,0 +1,258 @@ +#!/usr/bin/env node + +/** + * Sync OpenAPI Specification from Hedera Mirror Node + * + * This script downloads the latest OpenAPI specification from Hedera Mirror Node + * and updates the local openapi.yaml file if there are changes. + * + * Usage: + * node sync-openapi.js [--network=testnet|mainnet] [--output=path/to/openapi.yaml] + */ + +const https = require('https'); +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +// Configuration +const NETWORKS = { + testnet: 'https://testnet.mirrornode.hedera.com/api/v1/docs/openapi.yml', + mainnet: 'https://mainnet.mirrornode.hedera.com/api/v1/docs/openapi.yml' +}; + +// Parse command line arguments +const args = process.argv.slice(2).reduce((acc, arg) => { + const [key, value] = arg.replace('--', '').split('='); + acc[key] = value || true; + return acc; +}, {}); + +const network = args.network || 'mainnet'; +const outputPath = args.output || path.join(process.cwd(), 'openapi.yaml'); +const dryRun = args['dry-run'] || false; +const verbose = args.verbose || false; + +// Validate network +if (!NETWORKS[network]) { + console.error(`❌ Error: Invalid network "${network}". Must be "testnet" or "mainnet".`); + process.exit(1); +} + +const sourceUrl = NETWORKS[network]; + +/** + * Log message if verbose mode is enabled + */ +function log(message) { + if (verbose) { + console.log(message); + } +} + +/** + * Download content from URL + */ +function downloadFile(url) { + return new Promise((resolve, reject) => { + log(`đŸ“Ĩ Downloading from ${url}...`); + + https.get(url, (response) => { + if (response.statusCode !== 200) { + reject(new Error(`Failed to download: HTTP ${response.statusCode}`)); + return; + } + + let data = ''; + response.on('data', (chunk) => { + data += chunk; + }); + + response.on('end', () => { + log(`✓ Download complete (${data.length} bytes)`); + resolve(data); + }); + }).on('error', (error) => { + reject(error); + }); + }); +} + +/** + * Extract version from OpenAPI content + */ +function extractVersion(content) { + const match = content.match(/version:\s*['"]?([0-9.]+)['"]?/); + return match ? match[1] : 'unknown'; +} + +/** + * Check if files are different + */ +function filesAreDifferent(content1, content2) { + // Normalize line endings and trim whitespace + const normalize = (str) => str.replace(/\r\n/g, '\n').trim(); + return normalize(content1) !== normalize(content2); +} + +/** + * Create backup of existing file + */ +function createBackup(filePath) { + if (fs.existsSync(filePath)) { + const backupPath = `${filePath}.backup`; + fs.copyFileSync(filePath, backupPath); + log(`✓ Created backup at ${backupPath}`); + return backupPath; + } + return null; +} + +/** + * Validate YAML syntax + */ +function validateYaml(content) { + try { + // Try to parse with Node.js (basic validation) + // For production, consider using a proper YAML parser like 'js-yaml' + const lines = content.split('\n'); + let indentStack = [0]; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (line.trim() === '' || line.trim().startsWith('#')) continue; + + const indent = line.search(/\S/); + if (indent === -1) continue; + + // Basic indentation check + if (indent > indentStack[indentStack.length - 1]) { + indentStack.push(indent); + } else { + while (indentStack.length > 0 && indent < indentStack[indentStack.length - 1]) { + indentStack.pop(); + } + } + } + + log('✓ YAML syntax validation passed'); + return true; + } catch (error) { + console.error(`❌ YAML validation failed: ${error.message}`); + return false; + } +} + +/** + * Main sync function + */ +async function syncOpenApi() { + console.log('🔄 Hedera Mirror Node OpenAPI Sync'); + console.log('====================================='); + console.log(`Network: ${network}`); + console.log(`Source: ${sourceUrl}`); + console.log(`Output: ${outputPath}`); + console.log(`Dry run: ${dryRun ? 'Yes' : 'No'}`); + console.log(''); + + try { + // Download new content + const newContent = await downloadFile(sourceUrl); + const newVersion = extractVersion(newContent); + + console.log(`đŸ“Ļ Downloaded version: ${newVersion}`); + + // Validate YAML + if (!validateYaml(newContent)) { + throw new Error('Downloaded content failed YAML validation'); + } + + // Check if file exists and compare + let hasChanges = true; + let currentVersion = 'none'; + + if (fs.existsSync(outputPath)) { + const currentContent = fs.readFileSync(outputPath, 'utf8'); + currentVersion = extractVersion(currentContent); + hasChanges = filesAreDifferent(currentContent, newContent); + + console.log(`📄 Current version: ${currentVersion}`); + + if (!hasChanges) { + console.log('✅ No changes detected. File is up to date.'); + return { updated: false, version: currentVersion }; + } + + console.log('🔍 Changes detected!'); + } else { + console.log('📝 No existing file found. Creating new file.'); + } + + if (dryRun) { + console.log(''); + console.log('🔍 DRY RUN MODE - No files will be modified'); + console.log(`Would update from version ${currentVersion} to ${newVersion}`); + return { updated: false, version: newVersion, dryRun: true }; + } + + // Create backup + const backupPath = createBackup(outputPath); + + // Write new content + const outputDir = path.dirname(outputPath); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + fs.writeFileSync(outputPath, newContent, 'utf8'); + console.log(`✅ Successfully updated ${outputPath}`); + + if (backupPath) { + console.log(`💾 Backup saved to ${backupPath}`); + } + + // Summary + console.log(''); + console.log('📊 Summary:'); + console.log(` Previous version: ${currentVersion}`); + console.log(` New version: ${newVersion}`); + console.log(` File size: ${newContent.length} bytes`); + + return { + updated: true, + version: newVersion, + previousVersion: currentVersion, + backupPath + }; + + } catch (error) { + console.error(''); + console.error('❌ Error:', error.message); + + if (verbose && error.stack) { + console.error(''); + console.error('Stack trace:'); + console.error(error.stack); + } + + process.exit(1); + } +} + +// Run if called directly +if (require.main === module) { + syncOpenApi() + .then((result) => { + if (result.updated) { + process.exit(0); + } else { + process.exit(0); + } + }) + .catch((error) => { + console.error('Fatal error:', error); + process.exit(1); + }); +} + +module.exports = { syncOpenApi, NETWORKS }; From ef6ead3535b6bd410f9b1362124158009a1fa7f0 Mon Sep 17 00:00:00 2001 From: krystal <56278409+theekrystallee@users.noreply.github.com> Date: Wed, 26 Nov 2025 14:07:34 -0800 Subject: [PATCH 2/3] Add workflow to sync OpenAPI specification This workflow syncs the OpenAPI specification from the Hedera Mirror Node API, allowing for scheduled updates and manual triggers. It includes options for creating pull requests or committing changes directly based on user input. Signed-off-by: krystal <56278409+theekrystallee@users.noreply.github.com> --- .github/workflows/sync-openapi.yml | 131 +++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 .github/workflows/sync-openapi.yml diff --git a/.github/workflows/sync-openapi.yml b/.github/workflows/sync-openapi.yml new file mode 100644 index 0000000..8054cc0 --- /dev/null +++ b/.github/workflows/sync-openapi.yml @@ -0,0 +1,131 @@ +name: Sync OpenAPI Specification + +on: + # Run daily at 2 AM UTC to check for updates + schedule: + - cron: '0 2 * * *' + + # Allow manual trigger + workflow_dispatch: + inputs: + network: + description: 'Network to sync from' + required: true + default: 'testnet' + type: choice + options: + - mainnet + - testnet + create_pr: + description: 'Create pull request if changes detected' + required: true + default: true + type: boolean + +jobs: + sync-openapi: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Run OpenAPI sync script + id: sync + run: | + NETWORK="${{ github.event.inputs.network || 'mainnet' }}" + echo "Syncing from $NETWORK network..." + + # Run the sync script + node sync-openapi.js --network=$NETWORK --output=openapi.yaml --verbose + + # Check if there are changes + if git diff --quiet openapi.yaml; then + echo "has_changes=false" >> $GITHUB_OUTPUT + echo "No changes detected" + else + echo "has_changes=true" >> $GITHUB_OUTPUT + echo "Changes detected" + + # Extract version from the new file + VERSION=$(grep -m 1 "version:" openapi.yaml | sed 's/.*version: *//;s/["\x27]//g') + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Detected version: $VERSION" + fi + + - name: Create Pull Request + if: steps.sync.outputs.has_changes == 'true' && (github.event.inputs.create_pr != 'false' || github.event_name == 'schedule') + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: 'chore: update OpenAPI spec to v${{ steps.sync.outputs.version }}' + title: 'Update Mirror Node OpenAPI Specification to v${{ steps.sync.outputs.version }}' + body: | + ## 🔄 Automated OpenAPI Sync + + This PR updates the OpenAPI specification from the Hedera Mirror Node API. + + **Details:** + - **Network:** ${{ github.event.inputs.network || 'mainnet' }} + - **Version:** ${{ steps.sync.outputs.version }} + - **Source:** https://${{ github.event.inputs.network || 'mainnet' }}.mirrornode.hedera.com/api/v1/docs/openapi.yml + - **Triggered by:** ${{ github.event_name }} + + **Changes:** + This automated sync detected changes in the Mirror Node OpenAPI specification. Please review the changes to ensure they align with the documentation requirements. + + **Review Checklist:** + - [ ] Verify new endpoints are documented + - [ ] Check for breaking changes + - [ ] Update related documentation if needed + - [ ] Validate YAML syntax + + --- + + 🤖 This PR was automatically created by the OpenAPI sync workflow. + + **Related Links:** + - [Mirror Node Release Notes](https://docs.hedera.com/hedera/networks/release-notes/mirror-node) + - [Mirror Node API Docs](https://docs.hedera.com/hedera/sdks-and-apis/rest-api) + branch: automated/sync-openapi-${{ steps.sync.outputs.version }} + delete-branch: true + labels: | + automated + documentation + mirror-node + openapi + + - name: Commit changes directly (if no PR) + if: steps.sync.outputs.has_changes == 'true' && github.event.inputs.create_pr == 'false' && github.event_name != 'schedule' + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add openapi.yaml + git commit -m "chore: update OpenAPI spec to v${{ steps.sync.outputs.version }}" + git push + + - name: Summary + run: | + echo "## OpenAPI Sync Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Network:** ${{ github.event.inputs.network || 'mainnet' }}" >> $GITHUB_STEP_SUMMARY + echo "- **Has Changes:** ${{ steps.sync.outputs.has_changes }}" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.sync.outputs.has_changes }}" == "true" ]; then + echo "- **New Version:** ${{ steps.sync.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "✅ OpenAPI specification has been updated." >> $GITHUB_STEP_SUMMARY + else + echo "" >> $GITHUB_STEP_SUMMARY + echo "â„šī¸ No changes detected. OpenAPI specification is up to date." >> $GITHUB_STEP_SUMMARY + fi From 1d6df15932b145e10521eb6185f2e951490a215d Mon Sep 17 00:00:00 2001 From: krystal <56278409+theekrystallee@users.noreply.github.com> Date: Tue, 30 Dec 2025 08:30:40 -0800 Subject: [PATCH 3/3] testing deploy bot Signed-off-by: krystal <56278409+theekrystallee@users.noreply.github.com> --- .../getting-started-evm-developers/add-hedera-to-metamask.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hedera/getting-started-evm-developers/add-hedera-to-metamask.mdx b/hedera/getting-started-evm-developers/add-hedera-to-metamask.mdx index d4d29f6..34e0895 100644 --- a/hedera/getting-started-evm-developers/add-hedera-to-metamask.mdx +++ b/hedera/getting-started-evm-developers/add-hedera-to-metamask.mdx @@ -26,3 +26,6 @@ Hedera is fully compatible with web3 wallets like MetaMask. Just add the JSON-RP />
NameValue
Network NameHedera Testnet
RPC Endpointhttps://testnet.hashio.io/api
Chain ID296
Currency SymbolHBAR
Block Explorer URLhttps://hashscan.io/testnet
+ + +# TESTING \ No newline at end of file