sourcedb-client (0.3.0)
Installation
registry=https://gits.hibna.com.tr/api/packages/hibna/npm/npm install sourcedb-client@0.3.0"sourcedb-client": "0.3.0"About this package
sourcedb-client
SourceDB'nin HTTP/JSON API'si için tipli, bağımlılıksız JavaScript/TypeScript
istemcisi. Node 18+ (global fetch) ve modern tarayıcılarda çalışır; derleme
adımı yok.
Sunucuyu çalıştırın:
sourcedb --serve-http 127.0.0.1:7878 --db ./db
Kurulum
npm install sourcedb-client
Not: paket adı kayıt defterinde doluysa kendi kapsamınızla yayınlayın (
@kullanici/sourcedb) ya da Gitea npm registry'sini kullanın.
Kullanım
import { SourceDB } from "sourcedb-client";
const db = new SourceDB("http://127.0.0.1:7878", { token: "gizli" }); // token isteğe bağlı
// Sunucu / gözlem
await db.health(); // { status: "ok" }
await db.metrics(); // sorgu/gecikme sayaçları
await db.resources(); // { cpu_percent, rss_bytes, disk_bytes, ... }
await db.tables(); // [{ name, engine }]
await db.createTable("users", "Collection");
await db.tableStats("users"); // "engine=Collection records=…"
// KeyValue (değerler string olarak saklanır)
const kv = db.kv("oturumlar");
await kv.put("sess:1", "token-abc");
await kv.get("sess:1"); // "token-abc" | null
await kv.mget(["sess:1", "yok"]); // { "sess:1": "token-abc", "yok": null }
// Değerler JSON ise sunucu tarafı alan projeksiyonu (yük küçülür):
await kv.mget(["8rypRidm"], { root: "_source", fields: ["home", "away"] });
await kv.keys({ limit: 100 }); // ["sess:1", ...]
await kv.delete("sess:1");
// Collection (tipli alanlar + ikincil/tam-metin indeks)
const c = db.collection("users");
await c.createIndex("email", { unique: true });
await c.createTextIndex("bio");
await c.put("user:1", { ad: "Ali Veli", email: "ali@x.com", yas: 30, aktif: true, bio: "rust sever" });
await c.get("user:1"); // { ad, email, yas, aktif, bio } | null
await c.find({ email: "ali@x.com" }); // ["user:1"]
await c.search("bio", "rust", "and"); // ["user:1"]
await c.records({ limit: 50 }); // [{ pk, fields }]
await c.delete("user:1");
// Log (kullanıcı başına akış)
const log = db.log("bildirimler");
await log.append(7, "merhaba");
await log.recent(7, 20); // ["merhaba", ...] en yeni → eski
// Odds (oran eşleştirme)
const odds = db.odds("maclar");
await odds.add(1, [{ source: 0, market: "1X2", outcome: 0, value: 1.85 }]);
await odds.match([{ source: 0, market: "1X2", outcome: 0, value: 1.85 }], { tolerance: 0 });
await odds.stats();
// Sözlükler: lokal .dict kopyası ve import sırasına bağlı id'ler gerekmez.
await db.dicts(); // [{ name, bytes }]
await db.dictResolve("football_bookmakers", ["bookmaker_bet365"]); // { bookmaker_bet365: 4 }
await db.dictNames("football_matchids", [12, 34]); // { "12": "8rypRidm", "34": ... }
// En pratiği: match'te çözümü doğrudan istemek — source bahisçi ADI olur,
// sonuç ES matchId'leriyle döner (matchKeys):
const { matches, matchKeys } = await db.odds("football_odds").match(
[{ source: "bookmaker_bet365", market: "MATCH_AH_-0.25", value: 3.45 }],
{ sourceDict: "football_bookmakers", matchDict: "football_matchids" },
);
Elasticsearch drop-in adaptörü (es-adapter)
ES'e bulk/update/search ile yazan mevcut feed scriptlerini (ör. canlı
oran çekme döngüleri) kod değişikliği olmadan SourceDB'ye taşımak için:
import { SourceDBEsAdapter } from "sourcedb-client/es-adapter";
const esClient = new SourceDBEsAdapter({ node: "http://127.0.0.1:7878", token: null });
// esClient.info() / .bulk() / .update() / .search() / .scroll() / .close()
// @elastic/elasticsearch v8 yüzeyinin scriptlerce kullanılan alt kümesiyle uyumlu.
Ne yapar:
update+doc_as_upsert→ KV'de kısmi birleştirme (ES partial update gibi: kapanış güncellemesi opening alanlarına dokunmaz). Ham dokümanlares_<index>KV tablolarında{_index,_id,_source}olarak tutulur (CLI--pull-esile aynı düzen).bookmaker_*/basket_bookmaker_*dokümanı yazılınca maçın TÜM bürolarının oranları KV'den yeniden kurulupfootball_odds/basket_oddstablosuna tam-değiştirme ile yazılır → tek büronün kapanışı güncellenirken diğer bürolar korunur, eski değerler sorgudan düşer; yazılan ANINDA sorgulanabilir.- Kimlikler string gider (
match_key+ bahisçi adı); sunucu sözlüğe intern eder — istemci sayısal id bilmez, id'ler import sırasından bağımsız. searchyalnızcaquery.termsdestekler (varlık kontrolü);scrolltek sayfa döner.
Tek-yazar kuralı: adaptör çalışırken aynı sözlüklere yazan CLI
--pull-esaynı anda çalıştırılmamalıdır (iki yazar id çakıştırır).
Canlı duman testi: SDB_URL=... node test/es-adapter-smoke.mjs.
Hata yönetimi
Başarısız istekler SourceDBError fırlatır (.status = HTTP kodu):
import { SourceDBError } from "sourcedb-client";
try {
await db.collection("users").put("user:9", { email: "ali@x.com" }); // benzersiz ihlali
} catch (e) {
if (e instanceof SourceDBError && e.status === 409) console.log("çakışma:", e.message);
}
TypeScript
Tipler pakette gömülü (index.d.ts); ek @types gerekmez.
import { SourceDB, type CollectionRecord } from "sourcedb-client";
const db = new SourceDB();
const recs: CollectionRecord[] = await db.collection("users").records();