npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@felixneo/uploadergithub

v1.0.1

Published

Smart GitHub file uploader with auto-update and skip unchanged files

Readme

Catatan penting: await harus berada di dalam async function, kecuali project memakai ES Module + top-level await. Supaya aman untuk pengguna CommonJS (require()), semua contoh aku bungkus dengan async function main().

🚀 @felixneo/uploadergithub

Smart GitHub Uploader dengan Auto-Skip, Auto-Update, ZIP Extraction, Retry, Batch Processing, dan Compare Mode.


✨ Tentang

@felixneo/uploadergithub adalah library Node.js untuk mengupload file, folder, atau ZIP langsung ke GitHub.

Library ini dirancang untuk membuat proses upload lebih cepat dan efisien dengan mendeteksi file yang sudah ada, melewati file yang tidak berubah, dan hanya mengupload file yang memang diperlukan.

🔥 Fitur Utama

| Fitur | Deskripsi | | ------------------------ | ------------------------------------------- | | 🧠 Auto-Skip | Skip file yang tidak mengalami perubahan | | 🔄 Auto-Update | Update file yang berubah secara otomatis | | 📦 Auto-Unzip | Upload ZIP lalu extract ke repository | | ⚡ Force Mode | Upload ulang semua file tanpa pengecekan | | 📊 Upload Statistics | Statistik new, updated, skipped, dan failed | | 🔍 Compare Mode | Bandingkan file lokal dengan GitHub | | 📁 Folder Support | Upload folder beserta struktur direktorinya | | 💾 Storage Saver | Mengurangi upload file yang sama | | 🚀 Batch Processing | Memproses banyak file secara paralel | | 🔁 Auto Retry | Retry otomatis ketika upload gagal | | 🌿 Branch Support | Upload ke branch tertentu | | 🛡️ Error Handling | Menangani error GitHub dan filesystem |


📦 Instalasi

npm install @felixneo/uploadergithub

Node.js: 18 atau lebih baru direkomendasikan.


🚀 Quick Start

Contoh paling sederhana:

const { smartUploadToGitHub } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await smartUploadToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './dist'
    });

    console.log(result);
  } catch (error) {
    console.error('❌ Upload failed:', error);
  }
}

main();

💡 Semua contoh menggunakan async function main() agar await tidak menyebabkan error "await is only valid in async functions".


📤 Usage

1️⃣ Smart Upload

Upload file atau folder menggunakan sistem Auto-Skip + Auto-Update.

File yang sama akan dilewati, sedangkan file baru atau berubah akan di-upload.

📋 Salin Code

const { smartUploadToGitHub } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await smartUploadToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './baileys',
      autoUnzip: false
    });

    if (result.success) {
      console.log('✅ Upload successful!');
      console.log(result);
    } else {
      console.error('❌ Upload failed:', result.error);
    }
  } catch (error) {
    if (error.code === 'ENOENT') {
      console.error('❌ File/folder tidak ditemukan!');
    } else if (error.status === 401) {
      console.error('🔐 GitHub token tidak valid!');
    } else if (error.status === 404) {
      console.error('📁 Repository tidak ditemukan!');
    } else {
      console.error('❌ Unexpected error:', error);
    }
  }
}

main();

⚙️ Cara Kerja

Local Files
    │
    ▼
Compare with GitHub
    │
    ├── Same ────────► ⏭️ Skip
    │
    ├── New ─────────► ➕ Upload
    │
    └── Changed ─────► 🔄 Update

⚡ 2️⃣ Force Upload

Gunakan forceUploadToGitHub() jika ingin mengupload semua file tanpa melakukan pengecekan perubahan.

📋 Salin Code

const { forceUploadToGitHub } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await forceUploadToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './dist',
      targetPath: 'build',
      branch: 'main',
      message: 'Force upload all files'
    });

    if (result.success) {
      console.log('✅ Force upload successful!');
    } else {
      console.error('❌ Upload failed:', result.error);
    }
  } catch (error) {
    console.error('❌ Upload error:', error);
  }
}

main();

⚠️ Force mode dapat menggunakan lebih banyak GitHub API requests karena tidak melakukan optimasi skip.


🔄 3️⃣ Sync Folder

Sinkronisasi folder dengan GitHub.

Hanya file yang baru atau berubah yang akan di-upload.

📋 Salin Code

const { syncFolderToGitHub } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await syncFolderToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './public',
      targetPath: 'static',
      branch: 'main',
      message: 'Sync public folder'
    });

    console.log('🔄 SYNC COMPLETE');

    console.log(`➕ New: ${result.new || 0}`);
    console.log(`🔄 Updated: ${result.updated || 0}`);
    console.log(`⏭️ Skipped: ${result.skipped || 0}`);
    console.log(`❌ Failed: ${result.failed || 0}`);
  } catch (error) {
    console.error('❌ Sync failed:', error);
  }
}

main();

Contoh Output

🔄 SYNC COMPLETE

➕ New: 3
🔄 Updated: 5
⏭️ Skipped: 12
❌ Failed: 0

💾 Storage saved: 2.50 MB

➕ 4️⃣ Upload New Files Only

Upload hanya file baru.

File yang sudah ada di GitHub akan dilewati meskipun isinya berubah.

📋 Salin Code

const { uploadNewOnly } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await uploadNewOnly({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './new-assets',
      targetPath: 'assets',
      branch: 'main'
    });

    console.log('✅ New files uploaded!');
    console.log(result);
  } catch (error) {
    console.error('❌ Upload failed:', error);
  }
}

main();

📦 5️⃣ Upload ZIP + Auto Extract

Upload file .zip kemudian extract isinya langsung ke repository.

📋 Salin Code

const { smartUploadToGitHub } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await smartUploadToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './build.zip',
      targetPath: 'build',
      autoUnzip: true
    });

    if (result.success) {
      console.log('📦 ZIP uploaded and extracted!');
    } else {
      console.error('❌ ZIP upload failed:', result.error);
    }
  } catch (error) {
    console.error('❌ Error:', error);
  }
}

main();

📁 Contoh Struktur

build.zip
│
├── index.html
├── style.css
└── assets/
    ├── logo.png
    └── app.js

Setelah upload:

GitHub Repository
│
└── build/
    ├── index.html
    ├── style.css
    └── assets/
        ├── logo.png
        └── app.js

🔍 6️⃣ Compare Local vs GitHub

Sebelum upload, kamu bisa mengecek file mana yang:

  • sudah ada
  • baru
  • berubah
  • sama

📋 Salin Code

const { compareWithGitHub } = require('@felixneo/uploadergithub');

async function main() {
  try {
    const comparison = await compareWithGitHub('./dist', {
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      branch: 'main',
      targetPath: 'build'
    });

    console.log('\n📊 COMPARISON RESULT');
    console.log('────────────────────');
    console.log(`📁 Total:       ${comparison.total}`);
    console.log(`📌 Existing:    ${comparison.existing}`);
    console.log(`➕ New:         ${comparison.new}`);
    console.log(`🔄 Need Update: ${comparison.needUpdate}`);
    console.log(`⏭️ Same:        ${comparison.same}`);
  } catch (error) {
    console.error('❌ Comparison failed:', error);
  }
}

main();

📊 7️⃣ Get Upload Statistics

Gunakan getUploadStats() untuk mendapatkan ringkasan hasil upload.

📋 Salin Code

const {
  syncFolderToGitHub,
  getUploadStats
} = require('@felixneo/uploadergithub');

async function main() {
  try {
    const result = await syncFolderToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './dist',
      branch: 'main'
    });

    console.log('\n📊 Upload Statistics');
    console.log(getUploadStats(result));
  } catch (error) {
    console.error('❌ Upload failed:', error);
  }
}

main();

Contoh:

➕ New: 5 | 🔄 Updated: 3 | ⏭️ Skipped: 12

🔧 Parameter

| Parameter | Type | Required | Default | Description | | ------------ | --------- | -------: | -------- | ---------------------------- | | token | string | ✅ | - | GitHub Personal Access Token | | owner | string | ✅ | - | Username atau organization | | repo | string | ✅ | - | Nama repository | | filePath | string | ✅ | - | Path file, folder, atau ZIP | | targetPath | string | ❌ | "" | Path tujuan di repository | | branch | string | ❌ | "main" | Branch tujuan | | message | string | ❌ | Auto | Commit message | | autoUnzip | boolean | ❌ | true | Extract ZIP otomatis | | batchSize | number | ❌ | 3 | Jumlah upload paralel | | force | boolean | ❌ | false | Force upload semua file |


🌐 Deployment Example

Deploy Website ke GitHub Pages

deploy.js

const {
  syncFolderToGitHub,
  getUploadStats
} = require('@felixneo/uploadergithub');

async function deploy() {
  console.log('🚀 Starting deployment...\n');

  try {
    const result = await syncFolderToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'myusername',
      repo: 'mywebsite',
      filePath: './dist',
      branch: 'gh-pages',
      message: `Deploy ${new Date().toISOString()}`
    });

    if (!result.success) {
      throw new Error(result.error || 'Deployment failed');
    }

    console.log('✅ Deployment successful!');
    console.log(`📊 ${getUploadStats(result)}`);
  } catch (error) {
    console.error('❌ Deployment failed:', error.message);
    process.exitCode = 1;
  }
}

deploy();

🤖 GitHub Actions

Contoh workflow:

.github/workflows/deploy.yml

name: Deploy to GitHub

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: 📥 Checkout
        uses: actions/checkout@v4

      - name: 🟢 Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18

      - name: 📦 Install dependencies
        run: npm install

      - name: 🔨 Build project
        run: npm run build

      - name: 🚀 Upload to GitHub
        run: node deploy.js
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

💾 Backup Example

Untuk melakukan backup dengan mode force:

📋 Salin Code

const { forceUploadToGitHub } = require('@felixneo/uploadergithub');

async function backup() {
  try {
    const result = await forceUploadToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'myorg',
      repo: 'backups',
      filePath: './database-dump',
      targetPath: `backup-${Date.now()}`,
      branch: 'main',
      message: 'Full backup'
    });

    if (result.success) {
      console.log('✅ Backup completed!');
    } else {
      console.error('❌ Backup failed:', result.error);
    }
  } catch (error) {
    console.error('❌ Backup error:', error);
  }
}

backup();

🔐 GitHub Token

Untuk menggunakan package ini, kamu membutuhkan GitHub Personal Access Token.

Cara Membuat Token

  1. Buka GitHub Settings
  2. Masuk ke Developer settings
  3. Pilih Personal access tokens
  4. Generate token
  5. Berikan permission yang diperlukan
  6. Simpan token dengan aman

🔒 Jangan pernah hard-code token ke source code atau upload token ke repository.


🔑 Recommended: Environment Variable

.env

GITHUB_TOKEN=github_pat_xxxxxxxxxxxxxxxxx

Kemudian gunakan:

const token = process.env.GITHUB_TOKEN;

❌ Jangan

token: 'github_pat_123456789'

✅ Gunakan

token: process.env.GITHUB_TOKEN

🛡️ Error Handling

Gunakan try/catch untuk menangani error filesystem maupun GitHub API.

📋 Salin Code

const { smartUploadToGitHub } = require('@felixneo/uploadergithub');

async function upload() {
  try {
    const result = await smartUploadToGitHub({
      token: process.env.GITHUB_TOKEN,
      owner: 'username',
      repo: 'repo-name',
      filePath: './dist'
    });

    if (result.success) {
      console.log('✅ Upload successful!');
    } else {
      console.error('❌ Upload failed:', result.error);
    }
  } catch (error) {
    switch (error.code) {
      case 'ENOENT':
        console.error('❌ File/folder tidak ditemukan!');
        break;

      default:
        if (error.status === 401) {
          console.error('🔐 GitHub token tidak valid!');
        } else if (error.status === 404) {
          console.error('📁 Repository tidak ditemukan!');
        } else {
          console.error('❌ Unexpected error:', error.message);
        }
    }
  }
}

upload();

⚡ Performance Tips

1. Gunakan Sync Mode

Untuk deployment, gunakan:

await syncFolderToGitHub({
  // ...
});

Dengan begitu file yang tidak berubah dapat dilewati.


2. Atur Batch Size

Untuk jumlah file yang besar:

await syncFolderToGitHub({
  // ...
  batchSize: 10
});

Contoh:

batchSize: 3
→ 3 file diproses bersamaan

batchSize: 10
→ 10 file diproses bersamaan

⚠️ Jangan menggunakan batch size terlalu besar karena GitHub API memiliki rate limit.


3. Gunakan Force Mode Hanya Jika Diperlukan

await forceUploadToGitHub({
  // ...
});

Gunakan force mode ketika memang ingin mengabaikan proses comparison.


🧠 Kapan Menggunakan Function?

| Function | Cocok Untuk | | ----------------------- | -------------------------------- | | smartUploadToGitHub() | Upload pintar dengan auto-skip | | syncFolderToGitHub() | Deployment / sinkronisasi folder | | forceUploadToGitHub() | Upload ulang semua file | | uploadNewOnly() | Hanya file baru | | compareWithGitHub() | Cek perubahan sebelum upload | | getUploadStats() | Membaca statistik upload |


❓ FAQ

Apakah support file besar?

Package ditujukan untuk upload file ke GitHub, tetapi batas ukuran aktual mengikuti batasan GitHub API dan implementasi package.

Apakah bisa upload ke branch lain?

Bisa.

branch: 'development'

Kenapa file saya di-skip?

Karena package mendeteksi file tersebut tidak mengalami perubahan.

Jika ingin memaksa upload:

force: true

atau gunakan:

forceUploadToGitHub()

Bagaimana mengatasi SHA mismatch?

Gunakan force upload atau lakukan sinkronisasi ulang repository.

const result = await forceUploadToGitHub({
  // ...
});

Kenapa await saya error?

Pastikan await berada di dalam async function.

❌ Salah:

const result = await syncFolderToGitHub({
  // ...
});

✅ Benar:

async function main() {
  const result = await syncFolderToGitHub({
    // ...
  });
}

main();

🧩 CommonJS vs ES Module

Package dapat digunakan dengan CommonJS:

const {
  smartUploadToGitHub
} = require('@felixneo/uploadergithub');

Kemudian:

async function main() {
  await smartUploadToGitHub({
    // ...
  });
}

main();

Jika project menggunakan ES Module:

import {
  smartUploadToGitHub
} from '@felixneo/uploadergithub';

async function main() {
  await smartUploadToGitHub({
    // ...
  });
}

main();

💡 Menggunakan async function main() tetap direkomendasikan karena kompatibel dengan lebih banyak konfigurasi Node.js.


🧪 Complete Example

Contoh penggunaan lengkap yang siap dijadikan deploy.js:

const {
  syncFolderToGitHub,
  getUploadStats
} = require('@felixneo/uploadergithub');

async function main() {
  const config = {
    token: process.env.GITHUB_TOKEN,
    owner: 'username',
    repo: 'my-project',
    filePath: './dist',
    targetPath: '',
    branch: 'main',
    message: '🚀 Deploy project',
    autoUnzip: true,
    batchSize: 5
  };

  if (!config.token) {
    throw new Error('GITHUB_TOKEN environment variable is required');
  }

  console.log('🚀 Starting GitHub upload...\n');

  try {
    const result = await syncFolderToGitHub(config);

    if (!result.success) {
      throw new Error(result.error || 'Upload failed');
    }

    console.log('\n╭─────────────────────────────╮');
    console.log('│     🚀 UPLOAD COMPLETE      │');
    console.log('╰─────────────────────────────╯');

    console.log(`\n📊 ${getUploadStats(result)}`);
    console.log('✅ Done!');
  } catch (error) {
    console.error('\n╭─────────────────────────────╮');
    console.error('│       ❌ UPLOAD FAILED      │');
    console.error('╰─────────────────────────────╯');

    console.error(`\n${error.message}`);

    process.exitCode = 1;
  }
}

main();

📊 Upload Flow

                 ┌──────────────────┐
                 │   Local Files    │
                 └────────┬─────────┘
                          │
                          ▼
                 ┌──────────────────┐
                 │ Scan Files       │
                 └────────┬─────────┘
                          │
                          ▼
                 ┌──────────────────┐
                 │ Compare GitHub   │
                 └────────┬─────────┘
                          │
              ┌───────────┼───────────┐
              ▼           ▼           ▼
           New File    Changed      Same
              │           │           │
              ▼           ▼           ▼
           ➕ Upload    🔄 Update   ⏭️ Skip
              │           │           │
              └───────────┼───────────┘
                          ▼
                 ┌──────────────────┐
                 │ Upload Summary   │
                 └──────────────────┘

📈 Result Statistics

Contoh hasil:

╭──────────────────────────────────╮
│       🚀 UPLOAD SUMMARY          │
├──────────────────────────────────┤
│ ➕ New       : 12                 │
│ 🔄 Updated  : 7                  │
│ ⏭️ Skipped   : 31                 │
│ ❌ Failed   : 0                  │
├──────────────────────────────────┤
│ 📁 Total     : 50                 │
│ 💾 Saved     : 4.82 MB            │
╰──────────────────────────────────╯

📝 License

MIT © felixneo


🤝 Contributing

Pull Request sangat diterima! ❤️

Jika ingin melakukan perubahan besar, silakan buat Issue terlebih dahulu agar perubahan dapat didiskusikan.


⭐ Support

Jika package ini membantu project kamu, jangan lupa:

  • ⭐ Star repository
  • 📦 Gunakan package di project kamu
  • 🐛 Laporkan bug
  • 💡 Kirim feature request
  • 🤝 Submit Pull Request

Made with ❤️ by felixneo

Smart Upload. Less API Calls. Faster Deployment. 🚀