alestadb
v2.0.1
Published
Official AlestaDB driver: pooled, pipelining, with change streams
Maintainers
Readme
alestadb
AlestaDB için resmi Node.js driver'ı. Havuzlu bağlantı, pipelining, change stream ve yönetim API'si. Sıfır bağımlılık.
npm i alestadbPaket public, erişim değil. Paketi herkes indirebilir; sunucuya bağlanmak için global IP allowlist'te olmanız, geçerli bir credential'ınız olması ve proje bazlı IP allowlist'ten geçmeniz gerekir. Paket yalnızca protokolü bilir.
Hızlı başlangıç
const { AlestaClient } = require('alestadb');
// tlsFingerprint zorunlu: sunucu kendi imzaladığı bir sertifika sunuyor, onu
// tanıyan tek şey bu özet. Sunucu başlarken ekrana yazar.
const client = await new AlestaClient(
'alesta://panel:[email protected]:5445/proje' +
'?tlsFingerprint=3f9a…'
).connect();
const users = client.collection('users');
await users.insertOne({ email: '[email protected]', role: 'owner' });
const admins = await users.find({ role: 'admin' })
.sort({ createdAt: -1 })
.limit(20)
.toArray();
await client.close();ESM de çalışır:
import { AlestaClient } from 'alestadb';Connection string
alesta://credential:parola@host:port/proje?seçenek=değer| Seçenek | Varsayılan | Anlamı |
|---|---|---|
| poolSize | 10 | Havuzdaki soket sayısı |
| connectTimeoutMS | 10000 | |
| socketTimeoutMS | 30000 | |
| appName | — | Sunucunun audit log'unda ve metriklerinde görünür |
| tlsFingerprint | — | Sunucu sertifikasının SHA-256'sı — zorunlu, aşağıya bakın |
| tlsInsecure | false | Sunucuyu doğrulamadan bağlan; bilinçli bir vazgeçiş |
Parolayı URL-encode edin. Driver connection string'i hiçbir zaman olduğu
gibi yazdırmaz; client.toString() ve hata mesajları maskelenmiş hâli döner.
tlsFingerprint neden zorunlu
AlestaDB kendi imzaladığı bir sertifika sunar. Böyle bir sertifikada sertifika zinciri hiçbir şey kanıtlamaz, dolayısıyla sunucunun gerçekten o sunucu olduğunu söyleyen tek şey parmak izidir. Verilmezse bağlantı şifrelidir ama kimliği doğrulanmamıştır: ağ yolundaki biri araya girip trafiği okuyabilir ve değiştirebilir.
Bu yüzden driver, parmak izi olmayan bir bağlantıyı açmak yerine
ERR_TLS_UNPINNED ile durur. İki istisna var:
- Loopback (
127.0.0.1,localhost) parmak izi istemez. Araya girilecek bir ağ yolu yoktur; oraya erişebilen zaten makinenin içindedir. tlsInsecure=trueyazarsanız uyarısız bağlanır. Bunu yalnız ne yaptığınızı bilerek kullanın.
Parmak izini sunucu açılışta ekrana yazar.
Sorgular
// Operatörler
await users.find({ age: { $gte: 18, $lt: 65 } }).toArray();
await users.find({ role: { $in: ['admin', 'owner'] } }).toArray();
await users.find({ $or: [{ role: 'owner' }, { age: { $lt: 20 } }] }).toArray();
await users.find({ 'profile.city': 'Ankara' }).toArray();
await users.find({ email: { $regex: '^vaco', $options: 'i' } }).toArray();
await users.find({ deletedAt: { $exists: false } }).toArray();
// Şekillendirme
await users.find().sort({ age: -1 }).skip(10).limit(5).project({ email: 1, _id: 0 }).toArray();
// Akış — büyük sonuçlar belleğe sığmak zorunda değil
for await (const user of users.find({ role: 'user' })) {
console.log(user.email);
}for await döngüsünden break ile çıkarsanız cursor sunucuda kapatılır.
Sunucu cursor'ları bir snapshot tuttuğu için bu önemli: terk edilen bir cursor
zaman aşımına kadar disk alanı tutar.
Neden sayfalama doğru
Cursor açıldığında sunucu bir depolama snapshot'ı sabitler. Siz sayfaları gezerken araya giren yazmalar sonucu kaydırmaz — hiçbir doküman atlanmaz, hiçbiri iki kez gelmez.
Yazma
await users.insertOne({ email: '[email protected]' });
await users.insertMany([{ n: 1 }, { n: 2 }], { ordered: false });
await users.updateOne({ email: '[email protected]' }, { $set: { role: 'admin' }, $inc: { logins: 1 } });
await users.updateMany({ role: 'user' }, { $set: { active: true } });
await users.updateOne({ email: '[email protected]' }, { $set: { role: 'user' } }, { upsert: true });
await users.deleteOne({ email: '[email protected]' });
await users.deleteMany({ active: false });Operatörler: $set $unset $inc $push $pull $addToSet. Noktalı yol
desteklenir ($set: { 'profile.city': 'Ankara' }).
matchedCount ile modifiedCount ayrıdır: zaten o değerde olan bir doküman
eşleşir ama değişmez.
Index'ler
await users.createIndex({ email: 1 }, { unique: true });
await users.createIndex({ guild: 1, createdAt: -1 }); // bileşik
await users.listIndexes();
await users.dropIndex('email_1');
// Planlayıcının ne yapacağını görün
console.log(await users.explain({ email: '[email protected]' }));
// { plan: 'IXSCAN', index: 'email_1', sortSatisfiedByPlan: true, inMemorySort: false }plan: 'COLLSCAN' görüyorsanız sorgunuz koleksiyonu baştan sona tarıyor demektir.
Change stream
Panelin "veriler anlık düşsün" ihtiyacını karşılayan mekanizma. Polling yok.
const stream = users.watch({ filter: { role: 'admin' } });
for await (const change of stream) {
console.log(change.operationType, change.fullDocument);
saveResumeToken(change.resumeToken);
}Bağlantı koparsa kaldığınız yerden devam edin:
const stream = users.watch({ resumeToken: loadResumeToken() });Yavaş abone. Sunucu, yazmaları bir aboneyi beklemek için asla durdurmaz.
Çok geride kalırsanız en eski olaylar düşürülür ve stream ERR_STREAM_LAG ile
hata verir — sessizce eksik veri almazsınız. Son token'dan devam edip aradaki
olayları oplog'dan alabilirsiniz.
Yönetim
admin scope'lu bir credential gerektirir.
await client.admin.createProject('nesyatest', { ipRules: ['203.0.113.0/24'] });
await client.admin.createCredential('discord_bot', 'nesyatest', 'readWrite', 'uzun-parola');
await client.admin.setIpRules('nesyatest', ['203.0.113.0/24', 'localhost']);
// Erişimi kaldırmak anında etkili — oturumlar da kapanır
await client.admin.revokeCredential('discord_bot');
console.log(await client.admin.metrics());
await client.admin.backup('/var/backups/alestadb/manual');Mongoose benzeri kullanım
Önceki pakete göre yazılmış kod çalışmaya devam eder:
const { connectDefault, Schema, model } = require('alestadb');
await connectDefault('alesta://panel:parola@host:5445/proje?tlsFingerprint=3f9a…');
const userSchema = new Schema({
email: { type: String, required: true, unique: true },
role: { type: String, default: 'user' },
createdAt: { type: Date, default: () => new Date() },
});
const User = model('users', userSchema);
await User.createIndexes();
await User.create({ email: '[email protected]' });
const owner = await User.findOne({ role: 'owner' });Hata yönetimi
const { AlestaError } = require('alestadb');
try {
await users.insertOne({ email: '[email protected]' });
} catch (error) {
if (error.isDuplicateKey) { /* ... */ }
if (error.isAuthError) { /* ... */ }
if (error.retryable) await new Promise(r => setTimeout(r, error.retryAfterMs ?? 100));
console.log(error.code); // "ERR_DUPLICATE_KEY" gibi kararlı bir kod
}Mesaj metnine değil error.code'a bakın; kodlar protokolün parçası ve
sürümler arasında değişmez.
Bilmeye değer üç şey
Snowflake'ler korunur. 2^53'ten büyük tamsayılar BigInt olarak döner.
Discord snowflake'leri tam bu aralıkta; Number olarak dönselerdi son
haneleri yuvarlanır ve iki farklı kullanıcı eşit görünürdü.
await stats.insertOne({ user: 1234567890123456789n });
const row = await stats.findOne({ user: 1234567890123456789n });
typeof row.user; // 'bigint'İlk bağlantı yavaştır, sonrakiler değil. Kimlik doğrulama SCRAM ile yapılır ve parola KDF'i Argon2id'dir — kasıtlı olarak pahalı. Node'da yerleşik Argon2 olmadığı için paket kendi saf JS implementasyonunu taşır (bu yüzden hiçbir bağımlılığı yok). Türetme süreç başına bir kez yapılır; havuzdaki diğer soketler ve reconnect'ler sunucudan alınan session token'ı kullanır.
İstekler pipeline'lanır. await etmeden birden çok çağrı başlatabilirsiniz;
hepsi aynı anda uçar ve yanıtlar requestId ile eşleşir.
await Promise.all(ids.map(id => users.findById(id)));Test
npm run test:unit # sunucu gerekmez
ALESTADB_TEST_URI='alesta://owner:[email protected]:5444/' npm testKripto katmanı OpenSSL'e karşı doğrulanır: BLAKE2b 1200'den fazla girdi
uzunluğunda ve RFC 7693 vektöründe, Argon2id ise OpenSSL'in ARGON2ID KDF'ine
karşı birden çok parametre setinde. Entegrasyon testleri gerçek sunucuya
karşı koşar — iki bağımsız implementasyonun aynı protokolde anlaşması.
Lisans
MIT
