Client SDK (@storagedb/client)

Rasmiy JavaScript/TypeScript SDK storagedb-ga ulanish, ma'lumotlar bazasi operatsiyalari, autentifikatsiya, storage, va realtime funksiyalari uchun.

O'rnatish va Boshlang'ich sozlama

StorageDB client SDK @storagedb/client npm paketidagi barcha zarorat qiladigan funksiyalarni taqdim etadi. Loyihangizga qo'shing:

npm i @storagedb/client

Client yaratish uchun createClient() funksiyasini ishlating. U Supabase-js ga o'xshaydi. Api URL va API kalit (anon yoki service) zarur:

TypeScript/JavaScript: const { createClient } = require('@storagedb/client'); const db = createClient('https://storage.identify.uz/v1/<REF>', '<ANON_KEY>');

Barcha amallar promise-based. Natija { data, error, ... } qaytaradi. Tizimsiz xatolarni boshqarish uchun har doim error ni tekshiring.

Asosiy setup
import { createClient } from '@storagedb/client';

const db = createClient(
  'https://storage.identify.uz/v1/my-project-ref',
  'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' // anon_key
);

// Endi siz db.from(), db.auth, db.storage ishlatishingiz mumkin.
curl bilan service API-ga ulanish
curl -X GET 'https://storage.identify.uz/v1/my-ref/rest/v1/todos?select=*' \
  -H 'apikey: service_key_value' \
  -H 'authorization: Bearer service_key_value'

Jadval so'rovlari (Database Queries)

StorageDB barcha jadvallar bilan PostgREST uslubida ishlashni qo'llab-quvvatlaydi. db.from('table_name') orqali QueryBuilder olasiz. U select, insert, update, delete amallarini qo'llab-quvvatlaydi.

SELECT: .select('*|col1,col2,...', { count: 'exact'|'estimated' })

INSERT: .insert(data) — bir yoki ko'p qatorlarni qo'shadi.

UPDATE: .update(changes) — WHERE shartiga mos qatorlarni o'zgartiradi.

DELETE: .delete() — qatorlarni o'chiradi.

UPSERT: .upsert(data) — mavjud bo'lsa yangilaydi, yo'q bo'lsa qo'shadi.

Filtrlar: .eq(), .neq(), .gt(), .gte(), .lt(), .lte(), .like(), .ilike(), .in(), .is(), .not(), .or(), .textSearch()

Tartib va sahifalash: .order('col', { ascending: false }), .limit(n), .range(from, to), .single()

SELECT — ro'yxat olish
const { data: todos, error, count } = await db
  .from('todos')
  .select('*, author(*)', { count: 'exact' })
  .eq('done', false)
  .order('id', { ascending: false })
  .limit(20);

if (error) console.error('Xato:', error.message);
else console.log(`${count} adaslash topildi:`, todos);
SELECT — curl bilan
curl -X GET 'https://storage.identify.uz/v1/my-ref/rest/v1/todos?select=*%2Cauthor(*)&done=eq.false&order=id.desc&limit=20&count=exact' \
  -H 'apikey: <ANON_KEY>' \
  -H 'authorization: Bearer <ANON_KEY>'
INSERT — yangi qator qo'shish
const { data: newTodo, error } = await db
  .from('todos')
  .insert({
    title: 'Dars yozish',
    done: false,
    user_id: 'usr_123'
  })
  .single(); // bitta qator qaytaradi

if (error) console.error('Qo\'shish xatosi:', error.message);
else console.log('Qo\'shildi:', newTodo);
INSERT — curl bilan
curl -X POST 'https://storage.identify.uz/v1/my-ref/rest/v1/todos' \
  -H 'apikey: <ANON_KEY>' \
  -H 'content-type: application/json' \
  -H 'prefer: return=representation' \
  -d '{"title":"Dars yozish","done":false,"user_id":"usr_123"}'
UPDATE — mavjud qatorni o'zgartirish
const { data: updated, error } = await db
  .from('todos')
  .update({ done: true, updated_at: new Date() })
  .eq('id', 42)
  .single();

if (error) console.error('Update xatosi:', error.message);
else console.log('O\'zgartirildi:', updated);
UPSERT — qo'shish yoki yangilash
const { data: result, error } = await db
  .from('users')
  .upsert({
    id: 'usr_123',
    email: 'user@example.com',
    name: 'Ali'
  })
  .single();

if (error) console.error('Upsert xatosi:', error.message);
else console.log('Natija:', result);
Murakkab filtrlar
// Bir nechta shartlar bilan qidiruv
const { data, error } = await db
  .from('posts')
  .select('*')
  .gte('created_at', '2024-01-01')
  .lt('created_at', '2025-01-01')
  .ilike('title', '%O\'zbek%') // katalog-siz
  .in('status', ['draft', 'published'])
  .eq('author_id', 'usr_42')
  .order('created_at', { ascending: false });

console.log(`${data?.length} post topildi`);
Full-text search
// Postgres full-text search
const { data: results, error } = await db
  .from('articles')
  .select('id, title, body')
  .textSearch('body', 'database search query', { type: 'websearch' })
  .limit(10);

if (error) console.error('Qidiruv xatosi:', error.message);
else console.log('Natijalar:', results);

Autentifikatsiya (Auth)

StorageDB o'z authentication xizmati bilan birga keladi. db.auth orqali sign up, sign in, sign out, parol tiklash va admin amallarini bajarishingiz mumkin.

signUp: yangi foydalanuvchi ro'yxatdan o'tkazadi. Session yo'q bo'lishi mumkin (email tasdiqlash shart bo'lsa).

signInWithPassword: emailu va parol bilan kirish.

refreshSession: refresh token orqali access token yangilash.

signOut: chiqish va sessiyani tozalash.

getUser: joriy foydalanuvchining ma'lumotlarini olish (access token kerak).

resetPasswordForEmail: parol tiklovchi link yuborish.

admin.* — service_key bilan faqat admin amallar (foydalanuvchilar bo'yicha).

Sign Up — ro'yxatdan o'tish
const { data, error } = await db.auth.signUp({
  email: 'newuser@example.com',
  password: 'SecurePassword123',
  data: {
    full_name: 'Ali Karimov',
    avatar_url: 'https://example.com/avatar.jpg'
  }
});

if (error) {
  console.error('Ro\'yxatdan o\'tish xatosi:', error.message);
} else {
  console.log('Yangi foydalanuvchi:', data.user);
  console.log('Sessiya:', data.session); // null bo'lishi mumkin
}
Sign Up — curl bilan
curl -X POST 'https://storage.identify.uz/v1/my-ref/auth/v1/signup' \
  -H 'apikey: <ANON_KEY>' \
  -H 'content-type: application/json' \
  -d '{
    "email": "newuser@example.com",
    "password": "SecurePassword123",
    "data": {"full_name": "Ali Karimov"}
  }'
Sign In — kirish
const { data: session, error } = await db.auth.signInWithPassword({
  email: 'user@example.com',
  password: 'UserPassword123'
});

if (error) {
  console.error('Kirish xatosi:', error.message);
} else {
  console.log('Access token:', session.access_token);
  console.log('Foydalanuvchi:', session.user);
  // Sessiya avtomatik saqlanadi
}
Sign In — curl bilan
curl -X POST 'https://storage.identify.uz/v1/my-ref/auth/v1/token?grant_type=password' \
  -H 'apikey: <ANON_KEY>' \
  -H 'content-type: application/json' \
  -d '{
    "email": "user@example.com",
    "password": "UserPassword123"
  }'
Get User — joriy foydalanuvchi
const { data: user, error } = await db.auth.getUser();

if (error) {
  console.error('Foydalanuvchini olishda xato:', error.message);
} else if (user) {
  console.log('Foydalanuvchi ID:', user.id);
  console.log('Email:', user.email);
  console.log('Metadata:', user.user_metadata);
}
Refresh Session — tokeni yangilash
const { data: newSession, error } = await db.auth.refreshSession();

if (error) {
  console.error('Yangilash xatosi:', error.message);
} else {
  console.log('Yangi access token:', newSession.access_token);
  // Avtomatik saqlandi
}
Sign Out — chiqish
const { error } = await db.auth.signOut();

if (error) {
  console.error('Chiqish xatosi:', error.message);
} else {
  console.log('Sessiya to\'g\'ri tuhtatildi');
  // Foydalanuvchi bilan bog'langan barcha tokenlar bekor qilindi
}
Reset Password — parolni tiklash
const { error } = await db.auth.resetPasswordForEmail('user@example.com');

if (error) {
  console.error('Reset link yuborishda xato:', error.message);
} else {
  console.log('Reset link foydalanuvchi emailiga yuborildi');
}
Admin: foydalanuvchilar ro'yxati (service_key orqali)
// Service key bilan yaratilgan client kerak
const adminDb = createClient('https://...', 'service_key_value');

const { data: users, error } = await adminDb.auth.admin.listUsers();

if (error) {
  console.error('Admin xatosi:', error.message);
} else {
  console.log('Jami foydalanuvchilar:', users.length);
  users.forEach(u => console.log(`- ${u.email}`));
}

Storage (Fayllar)

StorageDB storage xizmati S3-ga o'xshash API taqdim etadi. Bucket yaratish, fayllarni yuklash/yuklab olish, public URL olish, va signed URL yaratish mumkin.

db.storage.from(bucket_name) — bucket API olish.

bucket.upload(path, data, opts) — faylni yuklash.

bucket.download(path) — faylni yuklab olish.

bucket.remove(path) — faylni o'chirish.

bucket.getPublicUrl(path) — public bucket uchun to'g'ridan-to'g'ri URL.

bucket.createSignedUrl(path, expiresIn) — vaqtli ro'yxatdan o'tgan URL (private bucket uchun).

db.storage.createBucket(id, opts) — yangi bucket yaratish (admin).

Faylni yuklash
const fileData = new Blob(['Fayl mazmuni'], { type: 'text/plain' });

const { data, error } = await db.storage
  .from('my-bucket')
  .upload('users/user123/avatar.jpg', fileData, {
    contentType: 'image/jpeg'
  });

if (error) {
  console.error('Upload xatosi:', error.message);
} else {
  console.log('Yuklandi:', data.Key); // 'users/user123/avatar.jpg'
}
Faylni yuklash — curl bilan
curl -X POST 'https://storage.identify.uz/v1/my-ref/storage/v1/object/my-bucket/users/avatar.jpg' \
  -H 'apikey: <ANON_KEY>' \
  -H 'content-type: image/jpeg' \
  --data-binary @/path/to/avatar.jpg
Faylni yuklab olish
const { data: blob, error } = await db.storage
  .from('my-bucket')
  .download('users/user123/avatar.jpg');

if (error) {
  console.error('Download xatosi:', error.message);
} else {
  // blob `Blob` tipida
  const url = URL.createObjectURL(blob);
  console.log('Fayl hazirlandi:', url);
}
Public bucket URL
const { publicUrl } = db.storage
  .from('public-files')
  .getPublicUrl('documents/report.pdf');

console.log('Ochiq URL:', publicUrl);
// https://storage.identify.uz/v1/my-ref/storage/v1/public/public-files/documents/report.pdf
Signed URL yaratish (private bucket)
const { data, error } = await db.storage
  .from('private-bucket')
  .createSignedUrl('secure-docs/contract.pdf', 3600); // 1 soat

if (error) {
  console.error('Signed URL xatosi:', error.message);
} else {
  console.log('Imzolangan URL:', data.signedUrl);
  // Bu URL 1 soat davomida yaroqli
}
Signed URL yaratish — curl bilan
curl -X POST 'https://storage.identify.uz/v1/my-ref/storage/v1/object/sign/private-bucket/secure-docs/contract.pdf' \
  -H 'apikey: <SERVICE_KEY>' \
  -H 'content-type: application/json' \
  -d '{"expiresIn": 3600}'
Faylni o'chirish
const { error } = await db.storage
  .from('my-bucket')
  .remove('users/user123/old-avatar.jpg');

if (error) {
  console.error('O\'chirish xatosi:', error.message);
} else {
  console.log('Fayl o\'chirildi');
}
Yangi bucket yaratish (admin)
const adminDb = createClient('https://...', 'service_key_value');

const { data, error } = await adminDb.storage.createBucket('new-bucket', {
  public: false // Private bucket
});

if (error) {
  console.error('Bucket yaratish xatosi:', error.message);
} else {
  console.log('Bucket yaratildi:', data.id);
}

RPC (Postgres funksiyalari)

StorageDB bazasida yaratilgan Postgres funksiyalari (stored procedures, functions) RPC orqali chaqiriladi.

db.rpc(function_name, args) — funksiyani chaqirish.

args — funksiya parametrlari (object).

Natija { data, error } qaytaradi. data ning tipi funksiya qaytaradigan qiymati bilan bog'liq.

RPC funksiyasini chaqirish
const { data: result, error } = await db.rpc('calculate_total', {
  user_id: 'usr_123',
  month: 'January'
});

if (error) {
  console.error('RPC xatosi:', error.message);
} else {
  console.log('Natija:', result); // server tomondan qaytarilgan qiymat
}
RPC — curl bilan
curl -X POST 'https://storage.identify.uz/v1/my-ref/rest/v1/rpc/calculate_total' \
  -H 'apikey: <ANON_KEY>' \
  -H 'content-type: application/json' \
  -d '{"user_id": "usr_123", "month": "January"}'
RPC qatorlarni qaytarsa
interface UserStats {
  count: number;
  average_age: number;
  last_login: string;
}

const { data: stats, error } = await db.rpc<UserStats>('get_user_stats', {
  department: 'sales'
});

if (error) {
  console.error('Stats xatosi:', error.message);
} else {
  console.log(`${stats?.count} foydalanuvchi, O'rta yosh: ${stats?.average_age}`);
}

Realtime (Websocket subscription)

StorageDB realtime xizmati PostgreSQL o'zgarishlari, broadcast xabarlari, va presence (kimlar onlayn ekanini) qo'llab-quvvatlaydi.

db.channel(name) — kanal yaratish.

on(event, callback) — Postgres change events: INSERT, UPDATE, DELETE, yoki '*'.

onBroadcast(event, callback) — custom broadcast xabarlari.

onPresenceSync(cb) — presence state yangilanishi.

onPresenceJoin(cb) — foydalanuvchi online bo'lsa.

onPresenceLeave(cb) — foydalanuvchi offline bo'lsa.

subscribe(onStatus?) — WebSocket ulanishni boshlash.

send(event, payload) — topic'ga broadcast yuborish.

track(state) — o'z presence holatini belgilash.

unsubscribe() — disconnectni to'xtatish.

Postgres o'zgarishlari kuzatish
const channel = db.channel('todos')
  .on('INSERT', (payload) => {
    console.log('Yangi todo qo\'shildi:', payload.record);
  })
  .on('UPDATE', (payload) => {
    console.log('Todo o\'zgartirildi:', payload.record);
    console.log('Eski qiymat:', payload.old_record);
  })
  .on('DELETE', (payload) => {
    console.log('Todo o\'chirildi, ID:', payload.record?.id);
  })
  .subscribe((status) => {
    console.log('Kanal holati:', status); // 'SUBSCRIBED' yoki 'ERROR'
  });

// Chiqish uchun:
// channel.unsubscribe();
Broadcast xabarlari (mijoz ↔ mijoz)
const room = db.channel('collaboration-room')
  .onBroadcast('cursor', (message) => {
    console.log(`Foydalanuvchi kursorin pozitsiyasi:`, message.payload);
  })
  .subscribe();

// Xabar yuborish
room.send('cursor', { x: 150, y: 200, user_id: 'usr_42' });
Presence — kimlar onlayn
const chat = db.channel('chat-room')
  .onPresenceSync(() => {
    const state = chat.presenceState();
    console.log('Onlayn foydalanuvchilar:', state);
  })
  .onPresenceJoin((event) => {
    console.log(`${event.key} online bo'ldi`, event.state);
  })
  .onPresenceLeave((event) => {
    console.log(`${event.key} offline bo'ldi`);
  })
  .subscribe();

// O'z holatini belgilash
chat.track({
  user_id: 'usr_123',
  name: 'Ali',
  status: 'typing'
});

// O'z holatini yangilash
chat.track({ user_id: 'usr_123', name: 'Ali', status: 'away' });

// Chiqish
chat.untrack();

Xatolar boshqarish va TypeScript

Barcha SDK operatsiyalari { data, error } formatda qaytaradi. Xatolarni har doim tekshiring.

error null bo'lsa, operatsiya muvaffaqiyatli. Aks holda error.message xatoning tafsilotini o'z ichiga oladi.

QueryResult<T> turini import qilib, select, insert, update, delete amallarining turini belgilashingiz mumkin.

TypeScript barcha callback va parameter turlarni avtomatik bilan tekshiradi.

Service key maxfiy — server tomonda yoki environment variable sifatida saqlang. Anon key brauzer qatlamida foydalanishga xavfsiz.

Xatoni to'g'ri boshqarish
const { data, error, count } = await db
  .from('posts')
  .select('*', { count: 'exact' })
  .eq('status', 'published');

if (error) {
  console.error('Query xatosi:', error.message);
  console.error('Kod:', error.code); // 'PGRST...' yoki boshqa
} else if (data) {
  console.log(`${count || 0} published post topildi`);
  data.forEach(post => console.log(`- ${post.title}`));
} else {
  console.log('Ma\'lumot yo\'q');
}
TypeScript turlar
interface Todo {
  id: number;
  title: string;
  done: boolean;
  created_at: string;
  user_id: string;
}

// Strongly typed query
const { data: todos, error } = await db
  .from<Todo>('todos')
  .select('*')
  .eq('user_id', 'usr_123');

if (!error && todos) {
  // TypeScript biladi todos Todo[] ekanini
  todos.forEach(todo => {
    console.log(`✓ ${todo.title}`);
  });
}
Environment variables (Next.js misoli)
// .env.local
// NEXT_PUBLIC_API_URL=https://storage.identify.uz/v1/my-ref
// NEXT_PUBLIC_ANON_KEY=eyJ...
// SERVICE_KEY=eyJ... (server tomonda faqat)

// lib/db.ts
import { createClient } from '@storagedb/client';

const apiUrl = process.env.NEXT_PUBLIC_API_URL || '';
const key = typeof window === 'undefined'
  ? process.env.SERVICE_KEY || process.env.NEXT_PUBLIC_ANON_KEY || ''
  : process.env.NEXT_PUBLIC_ANON_KEY || '';

export const db = createClient(apiUrl, key);