@devnovaa-id/sambung-kata
v2.0.0
Published
Library universal untuk bermain game Sambung Kata (word chain) menggunakan API dari devnova.icu. Mendukung Node.js, browser, React, dan serverless.
Maintainers
Readme
🎮 @devnovaa-id/sambung-kata
Library untuk bermain Sambung Kata menggunakan API dari devnova.icu
Dapat digunakan di Node.js, React, browser, dan serverless (Vercel, Netlify, Cloudflare Workers, dll).
📖 Dokumentasi • 🚀 Quick Start • 💻 Contoh • 📚 API • 🤝 Kontribusi
✨ Fitur
- 🚀 Zero dependencies – Menggunakan native
fetch, ringan dan cepat - 📦 Universal – Bekerja di Node.js 18+, browser modern, dan lingkungan serverless
- 🔷 TypeScript first – Mendukung type definitions secara penuh
- 🔄 ESM & CommonJS – Support kedua format module
- 🛡️ Error handling – Exception yang jelas dan mudah ditangani
- 🎯 Sederhana – API yang intuitif dan mudah digunakan
- 🌍 Dukungan bahasa – Pilih bahasa Indonesia (id) atau Inggris (en)
🚀 Quick Start
Instalasi
npm install @devnovaa-id/sambung-kataAtau dengan yarn:
yarn add @devnovaa-id/sambung-kataPenggunaan Dasar
import { SambungKataClient } from '@devnovaa-id/sambung-kata';
const client = new SambungKataClient();
// Mulai game (default bahasa Indonesia)
const game = await client.startGame();
console.log(game.data.currentWord); // "kilat"
// Mulai game dalam bahasa Inggris
const englishGame = await client.startGame({ lang: 'en' });
console.log(englishGame.data.currentWord); // "nature"
// Jawab kata
const answer = await client.submitAnswer(game.data.gameId, 'atap');
console.log(answer.data.totalMoves); // 1
// Akhiri game
await client.endGame(game.data.gameId);💻 Contoh Lengkap
Node.js (ESM)
import { SambungKataClient } from '@devnovaa-id/sambung-kata';
async function playGame() {
const client = new SambungKataClient();
try {
// 1. Start game dalam bahasa Inggris
const start = await client.startGame({ lang: 'en' });
console.log('Game ID:', start.data.gameId);
console.log('Kata pertama:', start.data.currentWord);
console.log('Petunjuk:', start.data.message);
let gameId = start.data.gameId;
// 2. Jawab dengan kata yang valid
const jawaban = 'retry';
const answer = await client.submitAnswer(gameId, jawaban);
console.log('Jawaban diterima! Total langkah:', answer.data.totalMoves);
console.log('Kata saat ini:', answer.data.currentWord);
// 3. Lanjutkan game (refresh state)
const continueGame = await client.continueGame(gameId);
console.log('State terbaru:', continueGame.data.currentWord);
// 4. Akhiri game
const end = await client.endGame(gameId);
console.log(end.message);
} catch (error) {
console.error('Error:', error.message);
}
}
playGame();React Component
import { useEffect, useState } from 'react';
import { SambungKataClient } from '@devnovaa-id/sambung-kata';
function SambungKataGame() {
const [game, setGame] = useState(null);
const [answer, setAnswer] = useState('');
const [loading, setLoading] = useState(false);
const [lang, setLang] = useState('id');
const client = new SambungKataClient();
useEffect(() => {
startNewGame();
}, [lang]);
const startNewGame = async () => {
setLoading(true);
try {
const res = await client.startGame({ lang });
setGame(res.data);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
};
const submitAnswer = async () => {
if (!answer.trim()) return;
setLoading(true);
try {
const res = await client.submitAnswer(game.gameId, answer);
setGame(res.data);
setAnswer('');
} catch (err) {
alert(err.message);
} finally {
setLoading(false);
}
};
const endGame = async () => {
setLoading(true);
try {
await client.endGame(game.gameId);
setGame(null);
} catch (err) {
alert(err.message);
} finally {
setLoading(false);
}
};
if (!game) {
return (
<div>
<select value={lang} onChange={(e) => setLang(e.target.value)}>
<option value="id">Bahasa Indonesia</option>
<option value="en">English</option>
</select>
<button onClick={startNewGame}>Mulai Game</button>
</div>
);
}
return (
<div style={{ padding: '20px' }}>
<h2>🎯 Sambung Kata</h2>
<p>Kata saat ini: <strong>{game.currentWord}</strong></p>
<p>Total langkah: {game.totalMoves}</p>
<p>{game.message}</p>
<input
type="text"
value={answer}
onChange={(e) => setAnswer(e.target.value)}
placeholder="Masukkan kata..."
disabled={loading}
/>
<button onClick={submitAnswer} disabled={loading}>
Kirim
</button>
<button onClick={endGame} disabled={loading}>
Akhiri Game
</button>
</div>
);
}Browser (HTML + ESM)
<!DOCTYPE html>
<html>
<head>
<title>Sambung Kata Demo</title>
</head>
<body>
<select id="langSelect">
<option value="id">Bahasa Indonesia</option>
<option value="en">English</option>
</select>
<div id="game"></div>
<script type="module">
import { SambungKataClient } from 'https://unpkg.com/@devnovaa-id/[email protected]/dist/index.js';
const client = new SambungKataClient();
const gameDiv = document.getElementById('game');
const langSelect = document.getElementById('langSelect');
async function start() {
const lang = langSelect.value;
const game = await client.startGame({ lang });
gameDiv.innerHTML = `
<h2>Game Dimulai! (Bahasa: ${game.data.language})</h2>
<p>Kata: ${game.data.currentWord}</p>
<p>${game.data.message}</p>
<input id="answer" placeholder="Jawaban..." />
<button id="submit">Kirim</button>
<button id="end">Akhiri</button>
`;
document.getElementById('submit').onclick = async () => {
const answer = document.getElementById('answer').value;
const res = await client.submitAnswer(game.data.gameId, answer);
alert(res.data.message);
};
document.getElementById('end').onclick = async () => {
await client.endGame(game.data.gameId);
gameDiv.innerHTML = '<p>Game selesai.</p>';
};
}
start();
langSelect.addEventListener('change', start);
</script>
</body>
</html>Serverless (Vercel)
// api/sambung-kata.js
import { SambungKataClient } from '@devnovaa-id/sambung-kata';
export default async function handler(req, res) {
const client = new SambungKataClient();
const lang = req.query.lang || 'id';
const game = await client.startGame({ lang });
res.status(200).json(game.data);
}📚 API
| Method | Deskripsi | Parameters | Returns |
|--------|-----------|------------|---------|
| startGame(options) | Memulai game baru | options?: { lang?: 'id' | 'en' } | Promise<GameResponse> |
| submitAnswer(gameId, answer) | Mengirim jawaban | gameId: string, answer: string | Promise<GameResponse> |
| continueGame(gameId) | Mendapatkan state game | gameId: string | Promise<GameResponse> |
| endGame(gameId) | Mengakhiri game | gameId: string | Promise<GameResponse> |
Tipe GameResponse
interface GameResponse {
success: boolean;
data?: {
gameId: string;
currentWord: string;
usedWords: string[];
totalMoves: number;
language: string; // 'id' atau 'en'
message: string;
};
error?: string;
message?: string;
gameId?: string;
}🛠️ Error Handling
Semua error dilempar sebagai ApiError yang mewarisi SambungKataError.
import { SambungKataClient, ApiError } from '@devnovaa-id/sambung-kata';
try {
await client.submitAnswer('invalid-id', 'kata');
} catch (error) {
if (error instanceof ApiError) {
console.error(`Status: ${error.statusCode}, Pesan: ${error.message}`);
}
}🤝 Kontribusi
Kami sangat menerima kontribusi! Silakan buka issue atau pull request di GitHub.
Development
git clone https://github.com/devnovaa-id/sambung-kata.git
cd sambung-kata
npm install
npm run build
npm run type-checkMenjalankan Contoh
# Node.js
cd examples/node
npm start
# Browser (jalankan server statis)
npx serve .
# Buka http://localhost:3000/examples/browser📄 Lisensi
MIT © 2026 devnovaa-id
