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

@yaotoshi/n8n-sdk

v1.4.0

Published

SDK TypeScript untuk otomasi n8n yaotoshi. Tipe & klien di-generate dari openapi.json (openapi-fetch) — endpoint baru = regenerate, tanpa nulis method tangan.

Readme

@yaotoshi/n8n-sdk

SDK TypeScript untuk otomasi n8n yaotoshi — kirim notifikasi WhatsApp, terjemahkan invoice/packing list China dari Google Drive, cek input pembelian importir, dan ambil hasilnya lewat view layer (URL capability tanpa x-api-key). Tipe & klien di-generate dari openapi.json (via openapi-fetch; satu-satunya dependensi runtime, sangat kecil), dual ESM/CJS. Endpoint baru di openapi.json otomatis tersedia sebagai api.POST('/path') — tanpa menulis request helper tangan.

Kontrak v1 (major): POST /webhook/translate-invoice dan /webhook/cek-importir-pembelian selalu membalas 202 (ViewResult dengan status: 'processing') — tidak ada lagi respons HTML sinkron. Hasil diambil via view layer GET /view/<type>/<id> (HTML) / .json (data) — tanpa x-api-key; id capability-nya sendiri adalah secret-nya. wait: true di SDK = polling klien ke view .json (tidak ada parameter wait di wire).

Instalasi

npm install @yaotoshi/n8n-sdk

Penggunaan singkat

import { createN8nClient } from '@yaotoshi/n8n-sdk';

const n8n = createN8nClient({
  apiKey: process.env.N8N_WEBHOOK_SECRET, // nilai header x-api-key (webhook saja)
  // baseUrl opsional; default https://n8n.yaotoshi.xyz
});

Kirim notifikasi WhatsApp

const res = await n8n.sendWa({ to: 'me', message: 'Halo dari SDK' });
// res: { ok: true, messageId: '...', toJid: '[email protected]' }

// dengan media (URL publik yang bisa di-download gateway):
await n8n.sendWa({ to: 'me', message: 'Foto 🌄', mediaUrl: 'https://picsum.photos/300' });

to diisi nama penerima (alias/display_name dari direktori penerima), bukan nomor/JID — nomor mentah ditolak.

Terjemahkan invoice dari Google Drive (selalu 202)

const res = await n8n.translateInvoice({
  link: 'https://drive.google.com/file/d/<id>/view',
  // sheetIndex opsional (0-based, default 0) — untuk spreadsheet;
  // di luar jangkauan -> error 400
});
// res: ViewResult
// { ok: true, result_id: '<id capability>', view_type: 'translate',
//   status: 'processing', view: 'https://n8n.yaotoshi.xyz/view/translate/<id>' }

Hasil diambil lewat view layer — segera (polling manual) atau otomatis dengan wait: true (polling klien 3 detik, timeout 5 menit, sampai status: 'done'):

// polling klien: POST 202 -> loop GET view .json sampai done (maks 5 menit)
const done = await n8n.translateInvoice({ link: 'https://drive.google.com/file/d/<id>/view' }, { wait: true });
console.log(done.status, done.verdict, done.markdown); // done, 'TIDAK BERMASALAH', '## ...'

Cek input pembelian importir (selalu 202)

const res = await n8n.checkImportirPembelian({
  id: '5', // nota pembelian importir di cahub
  link: 'https://docs.google.com/spreadsheets/d/<id>/edit', // invoice/packing list
  // sheetIndex opsional (0-based, default 0)
});
// res: ViewResult { ok: true, result_id, view_type: 'cek-importir', status: 'processing', view }

const done = await n8n.checkImportirPembelian({ id: '5', link: '...' }, { wait: true });

Lihat hasil tersimpan (view layer)

URL view dari respons 202 bisa dibuka langsung di browser (HTML, tanpa x-api-key) atau diambil datanya:

// data row hasil (status processing|done + markdown/verdict/issues/model/dst.)
const row = await n8n.getViewData({ type: 'translate', id: res.result_id });
console.log(row.status, row.verdict, row.issues);

// proses ulang in-place (id & URL tetap; 404/409/429 -> N8nApiError)
const queued = await n8n.resetViewData({ type: 'translate', id: res.result_id });
// queued: { ok: true, status: 'processing', view: <URL sama> }

Biaya: reset memicu ulang pemrosesan (LLM) — rate limit 1x/60 detik per row.

getTranslateResult({ rid }) adalah alias deprecated (jawaban ViewResult, bukan HTML lama) yang memanggil getViewData. rid numerik ditolak di sisi klien — bukan lagi 404 samar dari server:

/** @deprecated pakai n8n.getViewData({ type: 'translate', id: rid }) */
const row = await n8n.getTranslateResult({ rid: '18aJlfjIddkjDvRTrsEolirT' });

// rid numerik -> N8nApiError 400: "...tidak dilayani view layer..."

Endpoint GET /webhook/translate-result sudah dibongkar (beserta method getLegacyTranslateResultHtml). View layer hanya melayani id capability random non-numerik (/gen-key); hasil ViewResult.done memuat data — objek terstruktur hasil model (responseSchema), plus markdown yang dibangun workflow darinya.

Contoh lengkap (dengan error handling)

import { createN8nClient, N8nApiError } from '@yaotoshi/n8n-sdk';

const n8n = createN8nClient({
  apiKey: process.env.N8N_WEBHOOK_SECRET, // nilai header x-api-key
});

try {
  const res = await n8n.checkImportirPembelian(
    { id: '268', link: 'https://docs.google.com/spreadsheets/d/<id>/edit' },
    { wait: true }, // polling klien sampai done (atau timeout 5 menit -> status terakhir)
  );
  if (res.status === 'done') {
    console.log(res.verdict); // 'BERMASALAH (1 masalah)' | 'TIDAK BERMASALAH' | 'GAGAL'
    console.log(res.issues, res.model, res.markdown);
  } else {
    console.log('masih diproses', res.view); // timeout 5 menit
  }
} catch (err) {
  if (err instanceof N8nApiError) {
    console.error('status', err.status, '| pesan:', err.message);
    // status 400 | pesan: Nota pembelian 99999999 tidak ditemukan di cahub
    // (pesan sudah dibersihkan dari sufiks internal n8n, siap dipakai mesin)
  } else {
    throw err;
  }
}

Catatan waktu: wait: true memakai polling klien (3 detik, timeout 5 menit — batas lama proses n8n). Cek yang rute reusenya aktif (hasil terjemahan sudah tersimpan) selesai ~10–30 detik; yang belum pernah diterjemahkan menjalankan terjemahan penuh ~1–2 menit (memakai workflow Terjemahkan secara internal). Gunakan fetch dengan timeout longgar (AbortSignal.timeout(180_000)) bila kamu meneruskan fetch kustom.

Wire selalu 202. wait adalah opsi polling di sisi klien — tidak ada parameter wait di body request.

Error

Semua kegagalan dilempar sebagai N8nApiError:

import { N8nApiError } from '@yaotoshi/n8n-sdk';

try {
  await n8n.sendWa({ to: 'tidak-ada', message: 'x' });
} catch (err) {
  if (err instanceof N8nApiError) {
    console.log(err.status, err.message); // status 400, message berisi daftar alias valid
  }
}

| Skenario | status | message (contoh) | |---|---|---| | x-api-key salah / tidak ada | 401 / 403 | x-api-key tidak valid atau tidak diizinkan | | Alias tak dikenal | 400 | Alias tidak dikenal… + daftar alias valid | | Alias ambigu (cocok >1 penerima) | 400 | Daftar kandidat | | mediaUrl gagal di-fetch gateway | 400 | Failed to fetch media… | | Link bukan Google Drive | 400 | Host tidak diizinkan… | | sheetIndex di luar jangkauan | 400 | sheetIndex … di luar jangkauan… | | Tipe file tidak didukung | 400 | Tipe file tidak didukung… | | Cek: id/link kosong | 400 | Field id wajib diisi… | | Cek: nota tidak ditemukan | 400 | Nota pembelian <id> tidak ditemukan di cahub | | View: id/type tidak dikenal | 404 | not found | | View: reset saat masih diproses | 409 | processing (body server: {ok:false, error:'processing'}) | | View: rate limit (reset per-row 60s / 30 req/menit per IP) | 429 | rate limited (body server: {ok:false, error:'rate limited'}) | | getTranslateResult dengan rid numerik | 400 (klien) | rid numerik legacy tidak dilayani view layer - endpoint /webhook/translate-result sudah dibongkar… | | Koneksi/network | — | TypeError: fetch failed (dari fetch) |

Catatan: view layer (getViewData/resetViewData) dipanggil tanpa x-api-key — id capability adalah secret-nya. apiKey tetap wajib di createN8nClient untuk jalur webhook.

Kontribusi / sinkron tipe

Tipe di-generate dari openapi.json:

npm run generate:sdk
npm run build
npm test

Aturan menambah endpoint publik: baca .claude/rules/api-sdk-sync.md di repo n8n-selfhosted — update openapi.json, naikkan version, regenerate, commit satu paket. Setelah regenerate, panggilan typed untuk endpoint baru tersedia otomatis (api.POST('/webhook/...')); wrapper ergonomis (sendWa, translateInvoice) tinggal 3 baris di src/index.ts. CI (publish-n8n-sdk.yml) menolak bila tipe tidak sinkron atau README tidak menyebut method, dan menerbitkan npm otomatis bila versi berbeda.

Dokumentasi API (Scalar)

Live: https://n8n.yaotoshi.xyz/docs/ — kontrak dari openapi.json disajikan server statis kecil (scripts/view-server.mjs di root repo, pm2 n8n-web), di-routing tunnel path /docs* di depan rule n8n biasa. Versi tanpa server juga tersedia: buka docs.html di browser (kontrak di-embed). Regenerasi bila openapi.json berubah:

bash scripts/gen-docs.sh

Lisensi

MIT