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

swiftfetch-elsolya

v0.1.0

Published

Framework-agnostic HTTP client with caching, dedupe, retry, abort - TypeScript first

Readme

SwiftFetch-elsolya (swiftfetch-elsolya)

مكتبة Framework-agnostic لجلب الداتا (HTTP client) بتشتغل مع أي Framework:
React / Next.js / Vue / Nuxt / Angular / Node … إلخ.

تركّز على:

  • API بسيطة: get / post / put / patch / delete
  • TypeScript first (Generics)
  • Query params
  • Headers و auth
  • Abort / cancel
  • Retry (اختياري)
  • Caching + Deduplication (اختياريين)

ملاحظة مهمة: اسم حزمة npm لازم يكون lowercase، لذلك النشر يكون باسم: swiftfetch-elsolya


التثبيت

npm i swiftfetch-elsolya
# أو
yarn add swiftfetch-elsolya
# أو
pnpm add swiftfetch-elsolya

لو بتستخدم Node أقل من 18، لازم توفر fetch (مثلاً عبر undici).
Node 18+ و أغلب المتصفحات فيها fetch جاهز.


Quick Start (Vanilla) — ينفع في أي مكان

1) إنشاء Client

import { createClient } from "swiftfetch-elsolya";

export const api = createClient({
  baseURL: "https://api.example.com",
  defaultHeaders: {
    "Content-Type": "application/json",
  },

  // Retry (اختياري)
  retry: {
    retries: 2,
    retryDelay: (attempt) => attempt * 500, // ms
    retryOn: (err) => err.status >= 500,     // جرّب تاني بس في أخطاء السيرفر
  },

  // Cache + Deduplication (اختياري)
  cache: {
    enabled: true,
    staleTime: 30_000,   // الداتا تعتبر fresh لمدة 30 ثانية
    cacheTime: 300_000,  // تفضل مخزنة 5 دقايق
  },
});

استخدام الـ HTTP Methods

كل الميثودز بتقبل Generics للـ TypeScript: api.get<User[]>("/users")

GET

type User = { id: number; name: string };

const users = await api.get<User[]>("/users");

GET مع Query Params

const users = await api.get<User[]>("/users", {
  query: { page: 1, limit: 20, search: "ali" },
});

POST

type CreateUserDto = { name: string };

const created = await api.post<User>("/users", {
  body: { name: "Ali" } satisfies CreateUserDto,
});

PUT

const updated = await api.put<User>("/users/1", {
  body: { name: "Ali Updated" },
});

PATCH

const patched = await api.patch<User>("/users/1", {
  body: { name: "Ali Patched" },
});

DELETE

await api.delete<void>("/users/1");

Request عام (لو عايز method بأي قيمة)

const data = await api.request<User>({
  method: "GET",
  url: "/users/1",
});

Headers و Auth

إضافة Authorization لكل الطلبات

export const api = createClient({
  baseURL: "https://api.example.com",
  defaultHeaders: () => ({
    Authorization: `Bearer ${localStorage.getItem("token") ?? ""}`,
    "Content-Type": "application/json",
  }),
});

أو إضافة Headers لطلب واحد

const users = await api.get<User[]>("/users", {
  headers: { "X-Trace-Id": "abc-123" },
});

Abort / Cancel Request (مهم جدًا في UI)

الطريقة القياسية (AbortController)

const ac = new AbortController();

const p = api.get<User[]>("/users", { signal: ac.signal });

// بعدين لو احتجت:
ac.abort();

await p;

في React/Vue تقدر تعمل abort داخل cleanup لما الـ component يتشال.


أخطاء الطلبات (Errors)

المكتبة بترمي Error موحّد (Normalized) بالشكل ده تقريبًا:

try {
  await api.get("/boom");
} catch (err) {
  // err.message
  // err.status
  // err.data (لو السيرفر رجّع body للخطأ)
}

استخدام SwiftFetch-elsolya في كل Framework

✅ React (CRA/Vite/React 18)

مثال GET + Abort + State

import { useEffect, useState } from "react";
import { api } from "./api";

type User = { id: number; name: string };

export function Users() {
  const [users, setUsers] = useState<User[] | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const ac = new AbortController();

    api.get<User[]>("/users", { signal: ac.signal })
      .then(setUsers)
      .catch((e) => {
        if (e?.name !== "AbortError") setError(e.message ?? "Unknown error");
      });

    return () => ac.abort();
  }, []);

  if (error) return <div>Error: {error}</div>;
  if (!users) return <div>Loading...</div>;

  return (
    <ul>
      {users.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
    </ul>
  );
}

مثال POST

await api.post("/users", { body: { name: "New User" } });

✅ Next.js (App Router / Pages Router)

1) Server Component (App Router) — GET على السيرفر

// app/users/page.tsx
import { createClient } from "swiftfetch-elsolya";

type User = { id: number; name: string };

const api = createClient({
  baseURL: process.env.API_URL!,
  // في السيرفر غالبًا مفيش localStorage، خلي auth من cookies أو env
});

export default async function Page() {
  // لو عايز تمنع كاش Next.js للطلب:
  const users = await api.get<User[]>("/users", { next: { revalidate: 0 } });

  return (
    <div>
      <h1>Users</h1>
      <pre>{JSON.stringify(users, null, 2)}</pre>
    </div>
  );
}

next هنا خيار اختياري لو أنت في Next.js وعايز تمرر تلميحات للكاش (زي revalidate).
لو مش محتاجه، تجاهله.

2) Client Component (زي React عادي)

"use client";
import { useEffect, useState } from "react";
import { api } from "@/lib/api";

export default function UsersClient() {
  const [data, setData] = useState<any>(null);

  useEffect(() => {
    api.get("/users").then(setData);
  }, []);

  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

3) Route Handler (API) — POST/GET على السيرفر

// app/api/users/route.ts
import { NextResponse } from "next/server";
import { createClient } from "swiftfetch-elsolya";

const api = createClient({ baseURL: process.env.API_URL! });

export async function GET() {
  const users = await api.get("/users");
  return NextResponse.json(users);
}

export async function POST(req: Request) {
  const body = await req.json();
  const created = await api.post("/users", { body });
  return NextResponse.json(created);
}

✅ Vue 3 (Vite) — Composable بسيط

// composables/useUsers.ts
import { ref, onMounted, onBeforeUnmount } from "vue";
import { api } from "../api";

type User = { id: number; name: string };

export function useUsers() {
  const data = ref<User[] | null>(null);
  const error = ref<string | null>(null);
  const loading = ref(false);
  const ac = new AbortController();

  onMounted(async () => {
    loading.value = true;
    try {
      data.value = await api.get<User[]>("/users", { signal: ac.signal });
    } catch (e: any) {
      if (e?.name !== "AbortError") error.value = e?.message ?? "Unknown error";
    } finally {
      loading.value = false;
    }
  });

  onBeforeUnmount(() => ac.abort());

  return { data, error, loading };
}

✅ Nuxt 3 — Plugin + Injection

1) Plugin

// plugins/swiftfetch.ts
import { createClient } from "swiftfetch-elsolya";

export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig();

  const api = createClient({
    baseURL: config.public.apiBase,
    defaultHeaders: () => ({
      "Content-Type": "application/json",
      // مثال: Authorization من cookie/ pinia / أي مصدر
    }),
  });

  return {
    provide: { api },
  };
});

في nuxt.config.ts:

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      apiBase: "https://api.example.com",
    },
  },
});

2) استخدامه داخل أي Component/Composable

const { $api } = useNuxtApp();
const users = await $api.get("/users");

POST/PUT/PATCH/DELETE

await $api.post("/users", { body: { name: "Ali" } });
await $api.put("/users/1", { body: { name: "Ali Updated" } });
await $api.patch("/users/1", { body: { name: "Ali Patched" } });
await $api.delete("/users/1");

✅ Angular — Service (مع Observables)

1) Service

// api.service.ts
import { Injectable } from "@angular/core";
import { createClient } from "swiftfetch-elsolya";
import { from, Observable } from "rxjs";
import { environment } from "../environments/environment";

type User = { id: number; name: string };

@Injectable({ providedIn: "root" })
export class ApiService {
  private api = createClient({ baseURL: environment.apiBase });

  getUsers(): Observable<User[]> {
    return from(this.api.get<User[]>("/users"));
  }

  createUser(dto: { name: string }): Observable<User> {
    return from(this.api.post<User>("/users", { body: dto }));
  }

  deleteUser(id: number): Observable<void> {
    return from(this.api.delete<void>(`/users/${id}`));
  }
}

2) استخدامه في Component

constructor(private api: ApiService) {}

ngOnInit() {
  this.api.getUsers().subscribe(users => console.log(users));
}

خيارات متقدمة

Timeout (لو حابب)

await api.get("/users", { timeoutMs: 10_000 });

Cache per request (لو عايز تتحكم لطلب واحد)

await api.get("/users", {
  cache: { enabled: true, staleTime: 5_000 },
});

Force refetch (تجاهل الكاش)

await api.get("/users", { cache: { enabled: false } });

API Reference (مختصر)

createClient(config)

client.get<T>(url, options?)
client.post<T>(url, options?)
client.put<T>(url, options?)
client.patch<T>(url, options?)
client.delete<T>(url, options?)
client.request<T>({ method, url, ...options })

options غالبًا تشمل:

  • query?: Record<string, any>
  • body?: any
  • headers?: Record<string, string>
  • signal?: AbortSignal
  • timeoutMs?: number
  • retry?: { retries?: number; retryDelay?: (n:number)=>number; retryOn?: (err)=>boolean }
  • cache?: { enabled?: boolean; staleTime?: number; cacheTime?: number }
  • (Next.js فقط اختياري) next?: { revalidate?: number }

License

Ahmed Alsolya