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

api-core-runtime

v1.1.0

Published

A lightweight, type-safe API client runtime for modern web applications.

Readme

🚀 Api Core Runtime

مكتبة متكاملة وخفيفة الوزن لإدارة الاتصال بالـ API في تطبيقات الويب الحديثة، مصممة خصيصاً لتوفير تجربة تطوير آمنة (Type-Safe) وسلسة مع دعم كامل لـ React Hooks، إدارة الحالة (State Management)، والتعامل المتقدم مع المصادقة (Authentication).

✨ المميزات الرئيسية

  • Type-Safety First: دعم كامل لـ TypeScript لضمان تطابق أنواع المدخلات والمخرجات.
  • Modular Architecture: تنظيم الـ API endpoints داخل وحدات (Modules) مستقلة وسهلة الصيانة.
  • React Hooks Integration: خطافات جاهزة (useQuery, useMutation, useInfiniteQuery) تشبه مكتبة React Query ولكن مدمجة مباشرة مع هيكل الـ API الخاص بك.
  • Advanced Auth Handling: نظام مدمج لإدارة الـ Tokens، التجديد التلقائي للجلسة (Refresh Token)، والتعامل مع حالات عدم المصادقة.
  • SSR & Server Support: إمكانية استخدام نفس تعريفات الـ API في بيئة الخادم (Server-Side) بسهولة.
  • Smart Caching: نظام تخزين مؤقت (Caching) ذكي وإلغاء تكرار الطلبات (Request Deduplication).
  • Infinite Scrolling: دعم مدمج للقوائم اللانهائية (Infinite Queries).

� التثبيت

npm install api-core-runtime axios uuid
# أو
yarn add api-core-runtime axios uuid

🛠️ الإعداد الأولي (Setup)

أولاً، قم بإنشاء ملف لإعداد الـ ApiCore (مثلاً src/api/client.ts). هذا هو المكان الذي تضبط فيه الإعدادات العامة مثل الرابط الأساسي والمصادقة.

// src/api/client.ts
import { ApiCore } from 'api-core-runtime';

export const apiCore = new ApiCore({
  baseURL: 'https://api.example.com/v1',
  
  // إعدادات المصادقة (اختياري)
  auth: {
    // دالة لجلب التوكن الحالي (من LocalStorage أو Cookies)
    getToken: () => localStorage.getItem('accessToken'),
    
    // مفتاح الهيدر (الافتراضي Authorization)
    authHeaderKey: 'Authorization',
    
    // نوع التوكن (الافتراضي Bearer)
    authTokenType: 'Bearer',

    // دالة تنفذ عند انتهاء صلاحية التوكن (401)
    refreshSession: async (error) => {
      try {
        const response = await fetch('/api/refresh-token'); // مثال
        const data = await response.json();
        localStorage.setItem('accessToken', data.token);
        return true; // تم التجديد بنجاح
      } catch (e) {
        return false; // فشل التجديد
      }
    },

    // دالة تنفذ عند فشل المصادقة تماماً
    onUnauthenticated: () => {
      window.location.href = '/login';
    }
  },

  // إعدادات Axios الإضافية
  timeout: 30000,
});

🏗️ تعريف الوحدات (Modules Definition)

بدلاً من كتابة الروابط بشكل نصي في كل مكان، نستخدم ModuleBuilder لتعريف وحدات مترابطة.

// src/api/modules/users.ts
import { ModuleBuilder, action } from 'api-core-runtime';
import { apiCore } from '../client';

// تعريف أنواع البيانات (Types)
interface UserProfile {
  id: string;
  name: string;
  email: string;
}

interface UpdateUserRequest {
  name?: string;
  email?: string;
}

// تعريف الوحدة
export const users = new ModuleBuilder(apiCore, {
  
  // 1. تعريف Query (جلب بيانات)
  getProfile: {
    method: 'GET',
    path: '/users/me',
  },

  // 2. تعريف Mutation (تعديل بيانات)
  updateProfile: {
    method: 'PUT',
    path: '/users/me',
    // نحدد الأنواع هنا لضمان الـ Type-Safety
  } as import('api-core-runtime').ApiActionConfig<UpdateUserRequest, UserProfile>,

  // 3. مثال لـ Infinite Query
  getPosts: {
    method: 'GET',
    path: '/users/posts',
    isPublic: true, // لا يرسل التوكن
  }
});

🚀 الاستخدام (Usage)

1. جلب البيانات (useQuery)

استخدم الدالة المعرفة في الوحدة مباشرة كـ Hook.

import { users } from './api/modules/users';

function UserProfile() {
  const { data, isLoading, error } = users.useQuery('getProfile');

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error loading profile</div>;

  return (
    <div>
      <h1>{data?.data.name}</h1>
      <p>{data?.data.email}</p>
    </div>
  );
}

2. تعديل البيانات (useMutation)

import { users } from './api/modules/users';

function EditProfile() {
  const { mutate, isLoading } = users.useMutation('updateProfile', {
    onSuccess: (response) => {
      console.log('Updated successfully', response);
    },
    onError: (err) => {
      console.error('Update failed', err);
    }
  });

  const handleSave = () => {
    mutate({ name: 'New Name' }); // TypeScript سيتحقق من أن المدخلات صحيحة هنا
  };

  return (
    <button onClick={handleSave} disabled={isLoading}>
      Save Changes
    </button>
  );
}

3. القوائم اللانهائية (useInfiniteQuery)

import { users } from './api/modules/users';

function UserPosts() {
  const { 
    data, 
    fetchNextPage, 
    hasNextPage, 
    isFetchingNextPage 
  } = users.useInfiniteQuery('getPosts', {
    getNextPageParam: (lastPage) => lastPage.meta.nextPageCursor, // استخراج مؤشر الصفحة التالية
    input: { limit: 10 } // المدخلات الأولية
  });

  return (
    <div>
      {data?.pages.map((page, i) => (
        <div key={i}>
          {page.data.items.map(post => <div key={post.id}>{post.title}</div>)}
        </div>
      ))}
      
      <button 
        onClick={() => fetchNextPage()} 
        disabled={!hasNextPage || isFetchingNextPage}
      >
        {isFetchingNextPage ? 'Loading more...' : 'Load More'}
      </button>
    </div>
  );
}

4. الاستخدام في الخادم (Server-Side / SSR)

يمكنك استخدام نفس الوحدات لجلب البيانات مباشرة في بيئة الخادم (مثلاً في Next.js getServerSideProps أو Server Components).

import { users } from './api/modules/users';

// دالة Server Component أو API Route
export async function GET() {
  try {
    const response = await users.server.fetch('getProfile');
    return Response.json(response.data);
  } catch (error) {
    return Response.error();
  }
}

🔧 إدارة الـ Cache (QueryClient Helpers)

المكتبة توفر مجموعة من الدوال المساعدة لإدارة الـ cache بسهولة مع type-safety كاملة.

Invalidate Queries

// إبطال query محددة وإعادة تحميلها
await users.invalidate('getProfile');

// إبطال مع input محدد
await users.invalidate('getUserPosts', { userId: '123' });

// خيارات متقدمة
await users.invalidate('getProfile', undefined, {
  exact: true,           // فقط الـ query المطابق بالضبط
  refetchType: 'active'  // فقط الـ queries النشطة
});

Set/Get Query Data

// تحديث يدوي للـ cache
users.setData('getProfile', {
  id: '1',
  name: 'Updated Name',
  email: '[email protected]'
});

// تحديث باستخدام updater function
users.setData('getProfile', (old) => ({
  ...old,
  name: 'New Name'
}));

// قراءة البيانات من الـ cache
const cachedProfile = users.getData('getProfile');
if (cachedProfile) {
  console.log(cachedProfile.name);
}

إدارة متقدمة

// إلغاء queries قيد التنفيذ (لمنع race conditions)
await users.cancel('getProfile');

// إعادة تعيين query لحالتها الأولية
await users.reset('getProfile');

// حذف query من الـ cache
users.remove('getProfile');

// التحقق من عدد الـ queries قيد التنفيذ
const fetchingCount = users.isFetching('getProfile');

🚨 معالجة الأخطاء المحسنة (Enhanced Error Handling)

المكتبة توفر ApiError class موحد لمعالجة الأخطاء بشكل احترافي.

استخدام ApiError

import { isApiError } from 'api-core-runtime';

function UserProfile() {
  const { data, error } = users.useQuery('getProfile');

  if (error) {
    if (isApiError(error)) {
      // الوصول لجميع تفاصيل الخطأ
      console.log('Status:', error.status);           // 404
      console.log('Code:', error.code);               // 'ERR_NOT_FOUND'
      console.log('Messages:', error.getMessages());  // ['User not found']
      
      // التحقق من status محدد
      if (error.isStatus(404)) {
        return <NotFoundPage />;
      }
      
      // التحقق من multiple statuses
      if (error.isStatusIn([401, 403])) {
        return <UnauthorizedPage />;
      }
      
      // أخطاء validation
      const validationErrors = error.getValidationErrors();
      if (validationErrors) {
        console.log('Field errors:', validationErrors);
        // { email: ['Invalid format'], name: ['Required'] }
      }
    }
  }

  return <div>{data?.name}</div>;
}

معالجة Errors في Mutations

const mutation = users.useMutation('updateProfile', {
  onError: (error) => {
    if (isApiError(error)) {
      if (error.isStatus(422)) {
        // عرض أخطاء الـ validation
        const validationErrors = error.getValidationErrors();
        Object.entries(validationErrors || {}).forEach(([field, messages]) => {
          toast.error(`${field}: ${messages.join(', ')}`);
        });
      } else {
        // أخطاء عامة
        error.getMessages().forEach(msg => toast.error(msg));
      }
    }
  }
});

🛠️ أدوات التطوير (React Query Devtools)

استخدم أدوات التطوير من TanStack Query لمراقبة وتصحيح الـ cache.

التثبيت والتكامل

npm install @tanstack/react-query-devtools
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { apiCore } from './api/client';

function App() {
  return (
    <QueryClientProvider client={apiCore.queryClient}>
      <YourApp />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

للمزيد من التفاصيل، راجع:


⚙️ التكوين المتقدم (Configuration)

ApiCoreConfig

| الخاصية | النوع | الوصف | | :--- | :--- | :--- | | baseURL | string | الرابط الأساسي للـ API. | | auth | AuthConfig | كائن إعدادات المصادقة (التوكن، التجديد، إلخ). | | headers | object | function | هيدرز إضافية ترسل مع كل طلب. | | timeout | number | مهلة الطلب (بالمللي ثانية). | | axiosConfig | AxiosRequestConfig | أي إعدادات إضافية خاصة بمكتبة Axios. | | responseAdapter | function | دالة لتحويل شكل استجابة الباك اند إلى الشكل القياسي StandardApiResponse. |

ApiActionConfig

عند تعريف أي Endpoint، يمكنك تحديد الخصائص التالية:

| الخاصية | النوع | الوصف | | :--- | :--- | :--- | | method | 'GET' \| 'POST' ... | نوع الطلب HTTP. | | path | string | مسار الـ Endpoint. | | isPublic | boolean | إذا كانت true، لن يتم إرسال توكن المصادقة مع الطلب. | | contentType | 'json' \| 'formData' | نوع المحتوى المرسل (تلقائياً json). |


📄 الترخيص

هذه المكتبة مرخصة تحت [MIT License].