Skip to content

Commit dbb7b53

Browse files
Merge pull request #9 from hamdymohamedak/feat/ky-parity-features
Feat/parity features
2 parents ccdfd43 + 2f85226 commit dbb7b53

14 files changed

Lines changed: 426 additions & 40 deletions

‎.vitepress/config.mts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type NavLabels = {
3838
pluginsFluent: string;
3939
interceptors: string;
4040
architecture: string;
41+
featuresPipeline: string;
4142
retryCache: string;
4243
errorsSecurity: string;
4344
};
@@ -52,6 +53,7 @@ const LABELS: Record<Lang, NavLabels> = {
5253
pluginsFluent: "الإضافات والواجهة السلسة",
5354
interceptors: "المعترضات والوسيط",
5455
architecture: "البنية والداخلية",
56+
featuresPipeline: "الميزات ومسار الطلب",
5557
retryCache: "إعادة المحاولة والتخزين المؤقت",
5658
errorsSecurity: "الأخطاء والأمان",
5759
},
@@ -64,6 +66,7 @@ const LABELS: Record<Lang, NavLabels> = {
6466
pluginsFluent: "Plugins y API fluida",
6567
interceptors: "Interceptores y middleware",
6668
architecture: "Arquitectura",
69+
featuresPipeline: "Funciones y pipeline",
6770
retryCache: "Reintentos y caché",
6871
errorsSecurity: "Errores y seguridad",
6972
},
@@ -76,6 +79,7 @@ const LABELS: Record<Lang, NavLabels> = {
7679
pluginsFluent: "افزونه‌ها و API روان",
7780
interceptors: "قطع‌کننده‌ها و میان‌افزار",
7881
architecture: "معماری",
82+
featuresPipeline: "ویژگی‌ها و خط لوله",
7983
retryCache: "تلاش مجدد و حافظهٔ نهان",
8084
errorsSecurity: "خطا و امنیت",
8185
},
@@ -88,6 +92,7 @@ const LABELS: Record<Lang, NavLabels> = {
8892
pluginsFluent: "Plugins et API fluent",
8993
interceptors: "Intercepteurs et middleware",
9094
architecture: "Architecture",
95+
featuresPipeline: "Fonctionnalités et pipeline",
9196
retryCache: "Nouvelles tentatives et cache",
9297
errorsSecurity: "Erreurs et sécurité",
9398
},
@@ -100,6 +105,7 @@ const LABELS: Record<Lang, NavLabels> = {
100105
pluginsFluent: "प्लगइन और फ्लुएंट API",
101106
interceptors: "इंटरसेप्टर और मिडलवेयर",
102107
architecture: "Architecture",
108+
featuresPipeline: "Features और pipeline",
103109
retryCache: "रीट्राई और कैश",
104110
errorsSecurity: "त्रुटियाँ और सुरक्षा",
105111
},
@@ -112,6 +118,7 @@ const LABELS: Record<Lang, NavLabels> = {
112118
pluginsFluent: "Plugin e API fluent",
113119
interceptors: "Intercettori e middleware",
114120
architecture: "Architettura",
121+
featuresPipeline: "Funzionalità e pipeline",
115122
retryCache: "Retry e cache",
116123
errorsSecurity: "Errori e sicurezza",
117124
},
@@ -124,6 +131,7 @@ const LABELS: Record<Lang, NavLabels> = {
124131
pluginsFluent: "プラグインと Fluent API",
125132
interceptors: "インターセプターとミドルウェア",
126133
architecture: "アーキテクチャ",
134+
featuresPipeline: "機能とパイプライン",
127135
retryCache: "リトライとキャッシュ",
128136
errorsSecurity: "エラーとセキュリティ",
129137
},
@@ -136,6 +144,7 @@ const LABELS: Record<Lang, NavLabels> = {
136144
pluginsFluent: "플러그인과 Fluent API",
137145
interceptors: "인터셉터와 미들웨어",
138146
architecture: "아키텍처",
147+
featuresPipeline: "기능과 파이프라인",
139148
retryCache: "재시도와 캐시",
140149
errorsSecurity: "오류와 보안",
141150
},
@@ -148,6 +157,7 @@ const LABELS: Record<Lang, NavLabels> = {
148157
pluginsFluent: "Plugin û Fluent API",
149158
interceptors: "Interceptors û middleware",
150159
architecture: "Mîmarî",
160+
featuresPipeline: "Taybetmendî û pipeline",
151161
retryCache: "Retry û cache",
152162
errorsSecurity: "Çewtî û ewlehî",
153163
},
@@ -162,6 +172,7 @@ const ROOT_LABELS: NavLabels = {
162172
pluginsFluent: "Plugins & fluent API",
163173
interceptors: "Interceptors & middleware",
164174
architecture: "Architecture & internals",
175+
featuresPipeline: "Features & pipeline",
165176
retryCache: "Retry & cache",
166177
errorsSecurity: "Errors & security",
167178
};
@@ -193,6 +204,7 @@ function sidebarRoot() {
193204
{ text: L.pluginsFluent, link: "/plugins-fluent" },
194205
{ text: L.interceptors, link: "/interceptors-middleware" },
195206
{ text: L.architecture, link: "/architecture" },
207+
{ text: L.featuresPipeline, link: "/features-pipeline" },
196208
{ text: L.retryCache, link: "/retry-cache" },
197209
{ text: L.errorsSecurity, link: "/errors-security" },
198210
{ text: "AI assistants & skills", link: "/skills" },
@@ -224,6 +236,10 @@ function sidebarFor(lang: Lang) {
224236
{ text: L.pluginsFluent, link: pluginsFluentLink },
225237
{ text: L.interceptors, link: `${p}/interceptors-middleware` },
226238
{ text: L.architecture, link: architectureLink },
239+
{
240+
text: L.featuresPipeline,
241+
link: lang === "ar" ? `${p}/features-pipeline` : "/features-pipeline",
242+
},
227243
{ text: L.retryCache, link: `${p}/retry-cache` },
228244
{ text: L.errorsSecurity, link: `${p}/errors-security` },
229245
);

‎.vitepress/llms.template.txt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
- **This file (machine-oriented summary):** https://openfetch-js.github.io/openfetch-docs/llms.txt
1111
- VitePress `base` is `/openfetch-docs/` — prefix relative doc paths below with that base when resolving URLs (e.g. `/skills` → `https://openfetch-js.github.io/openfetch-docs/skills`).
1212
- Path map: English at `/` (default), locale hubs at `/ar/`, `/es/`, …, hub at `/languages/`.
13-
- Monorepo package layout & request lifecycle: `openFetch/docs/PROJECT_FLOW.md` in the GitHub repo.
13+
- Package layout & request lifecycle: [docs/PROJECT_FLOW.md](https://github.com/openfetch-js/OpenFetch/blob/main/docs/PROJECT_FLOW.md) in the library repo.
1414

1515
## Install & import
1616

@@ -105,7 +105,7 @@ import { createFluentClient } from "@hamdymohamedak/openfetch/sugar";
105105

106106
## Agent skills (Cursor, Claude Code, compatible tools)
107107

108-
The repo includes **`openfetchskill/`** — a **`SKILL.md`** skill aligned with the [Agent Skills specification](https://agentskills.io/specification) (YAML frontmatter + Markdown). Ecosystem hub: [skills.sh](https://skills.sh). Human docs page: `/skills` on the site above.
108+
Published plugin: **[openfetch-js/openFetchSkill](https://github.com/openfetch-js/openFetchSkill)** (`SKILL.md` + `references/`). The same folder exists as **`openfetchskill/`** in **[openfetch-js/OpenFetch](https://github.com/openfetch-js/OpenFetch)**. Spec: [Agent Skills](https://agentskills.io/specification). Hub: [skills.sh](https://skills.sh). Human overview: [openfetch-docs `/skills`](https://openfetch-js.github.io/openfetch-docs/skills).
109109

110110
## Human readers
111111

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,4 @@ Translated locales live under **`ar/`**, **`es/`**, etc. (same filenames where t
9696

9797
### Package version
9898

99-
The docs site reads the displayed version from **`.vitepress/openfetch-version.ts`** (single source of truth for pages, hero “Ask ChatGPT / Claude” links, and generated `public/llms.txt`). Bump that file when you cut a release. For runtime behavior details and file-level architecture, see `openFetch/docs/PROJECT_FLOW.md`.
99+
The docs site reads the displayed version from **`.vitepress/openfetch-version.ts`** (single source of truth for pages, hero “Ask ChatGPT / Claude” links, and generated `public/llms.txt`). Bump that file when you cut a release. For runtime behavior details and file-level architecture, see [**`docs/PROJECT_FLOW.md`**](https://github.com/openfetch-js/OpenFetch/blob/main/docs/PROJECT_FLOW.md) in the library repository.

‎ar/configuration.md‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# الإعدادات
22

3-
يُدمج الإعداد من **افتراضيات العميل** و**خيارات كل استدعاء** عبر `mergeConfig` (انظر قواعد الدمج أدناه).
3+
يُدمج الإعداد من **افتراضيات العميل** و**خيارات كل استدعاء** عبر `mergeConfig` (انظر قواعد الدمج أدناه). للصورة الكاملة للمسار والميزات الجديدة راجع [الميزات ومسار الطلب](./features-pipeline.md).
44

55
## `OpenFetchConfig` (الطلب)
66

@@ -24,14 +24,21 @@
2424

2525
### المهلات والإلغاء
2626

27-
- **`timeout`** — بالمللي ثانية؛ يستخدم `AbortController` داخلياً يُدمج مع **`signal`** عبر `mergeAbortSignals`.
27+
- **`timeout`** — بالمللي ثانية؛ يُدمج مع **`signal`**. إن انتهت **المهلة الداخلية** أولاً → **`ERR_TIMEOUT`**؛ إلغاء المستخدم على **`signal`** → **`ERR_CANCELED`**.
2828
- **`signal`** — `AbortSignal` خارجي؛ يُدمج مع مهلة الإلغاء.
2929

3030
### معالجة الاستجابة
3131

3232
- **`responseType`** — `"json"` | `"text"` | `"arraybuffer"` | `"blob"` | `"stream"`.
3333
إن وُجد، يستنتج JSON من `Content-Type: application/json`، وإلا يُقرأ كنص.
3434
- **`validateStatus`** — `(status: number) => boolean`. الافتراضي: 200–299. إن رجع `false`، يُرمى **`OpenFetchError`** برمز `ERR_BAD_RESPONSE` مع إرفاق الاستجابة.
35+
- **`throwHttpErrors`** — يُستخدم **فقط عند عدم** تعيين **`validateStatus`**: مثل Ky (`false` لا يرمي على حالة HTTP؛ دالة ترجع `true` تعني «ارمِ لهذه الحالة»). إن وُجد **`validateStatus`** يُتجاهل **`throwHttpErrors`**.
36+
- **`jsonSchema`** — [Standard Schema](https://github.com/standard-schema/standard-schema) اختياري على JSON المحلّل بعد نجاح الحالة؛ الفشل → **`SchemaValidationError`** (قبل **`transformResponse`**).
37+
- **`init`** — مصفوفة `(config) => void` **متزامنة** على الإعداد المدمج **قبل** معترضات الطلب.
38+
39+
### مدخل `Request`
40+
41+
- **`client.request(Request, تجاوزات?)`** — يدمج عنوان الطلب والطريقة والرؤوس والجسم والإشارة مع الافتراضيات ثم التجاوزات.
3542

3643
### التحويلات
3744

@@ -69,10 +76,11 @@ type OpenFetchResponse<T = unknown> = {
6976

7077
- المفاتيح على المستوى الأعلى: الإعداد الأحدث يغلب.
7178
- **`headers`**: دمج سطحي؛ رؤوس الاستدعاء تغلب الافتراضيات.
72-
- **`middlewares`**، **`transformRequest`**، **`transformResponse`**: **تُلحق** (الافتراضيات أولاً ثم الخاصة بالاستدعاء).
73-
- **`retry`**، **`memoryCache`**: دمج سطحي للكائنات.
79+
- **`middlewares`**، **`transformRequest`**، **`transformResponse`**، **`init`**: **تُلحق** (الافتراضيات أولاً ثم الخاصة بالاستدعاء).
80+
- **`retry`**، **`memoryCache`**: دمج سطحي لحقول الكائن؛ **`retry.onBeforeRetry`** و **`retry.onAfterResponse`** يُركّبان (الافتراضيات ثم لكل استدعاء).
7481
- تُزال مفاتيح تلوث النموذج الأولي (`__proto__`، `constructor`، `prototype`) من الكائنات المدمجة والرؤوس / `retry` / `memoryCache` المتداخلة.
7582

7683
## التالي
7784

85+
- [الميزات ومسار الطلب](./features-pipeline.md)
7886
- [المعترضات والوسيط](./interceptors-middleware.md)

‎ar/features-pipeline.md‎

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# الميزات ومسار الطلب الكامل
2+
3+
صفحة مرجعية: **ما يوفّره openFetch** و**ترتيب التنفيذ** من دمج الإعداد حتى إرجاع الاستجابة (بعد آخر التعديلات على الحزمة).
4+
5+
للمقارنات المعمّقة راجع [البنية والداخلية](./architecture.md). لجدول الخيارات راجع [الإعدادات](./configuration.md). النسخة الإنجليزية الكاملة: [Features & pipeline](../features-pipeline.md).
6+
7+
## نظرة على الحزمة
8+
9+
| الموضوع | التفاصيل |
10+
|---------|----------|
11+
| **npm** | `@hamdymohamedak/openfetch` |
12+
| **التنسيق** | ESM فقط |
13+
| **اعتماديات التشغيل** | صفر |
14+
| **المحركات** | Node 18+ والمتصفحات وBun وDeno وWorkers |
15+
| **نقاط الدخول** | الحزمة الرئيسية؛ `/plugins`؛ `/sugar` |
16+
| **النقل** | `fetch` الأصلي فقط |
17+
18+
---
19+
20+
## قائمة الميزات
21+
22+
### العميل والإعداد
23+
24+
- **`createClient` / `create`** — افتراضيات، أوامر HTTP، `request`، `use`.
25+
- **`mergeConfig`** — دمج افتراضيات + استدعاء؛ دمج رؤوس؛ **سلسلة** للـ `middlewares` و`transformRequest` و`transformResponse` و**`init`**؛ دمج مركّب لـ **`retry.onBeforeRetry` / `onAfterResponse`**؛ دمج سطحي لـ `retry` و`memoryCache`.
26+
- **`init`** — مصفوفة دوال **متزامنة** على الإعداد المدمج **قبل** المعترضات (تعديل رؤوس، إلخ).
27+
- **`Request` كمدخل** — `client.request(request, تجاوزات?)` يدمج عنوان الطلب والطريقة والرؤوس والجسم والإشارة مع الافتراضيات.
28+
- **`throwHttpErrors`** — سلوك قريب من Ky عند عدم وجود **`validateStatus`**: `false` لا يرمي على حالة HTTP؛ دالة ترجع `true` تعني «ارمِ خطأ HTTP لهذه الحالة». إن وُجد **`validateStatus`** فهو **يغلب** `throwHttpErrors`.
29+
30+
### المعترضات والوسيط
31+
32+
- **معترضات الطلب** — تسلسل غير متزامن (LIFO).
33+
- **معترضات الاستجابة** — تسلسل غير متزامن (FIFO).
34+
- **الوسيط** — حول `next()` حتى يصل الطلب إلى **`dispatch`** (استدعاء `fetch` الفعلي).
35+
36+
### `dispatch` (النقل)
37+
38+
- بناء URL، **`assertSafeUrl`** اختياري، رؤوس، **`Accept`** مقترح عند **`responseType`**، مصادقة Basic، **`transformRequest`**، ثم **`fetch`**.
39+
- **`timeout`** — مع تمييز **`ERR_TIMEOUT`** عن إلغاء المستخدم **`ERR_CANCELED`** عندما يكون الإلغاء من المهلة الداخلية فقط.
40+
- **`rawResponse`** — تخطي التحليل و`transformResponse`؛ `data` هي `Response` الأصلية.
41+
42+
### بعد `fetch` (المسار العادي)
43+
44+
1. **تحليل الجسم**
45+
2. **`validateStatus`** — فشل → `ERR_BAD_RESPONSE` (مع الجسم المحلّل إن وُجد)
46+
3. **`jsonSchema`** — تحقق Standard Schema اختياري؛ فشل → **`SchemaValidationError`**
47+
4. **`transformResponse`**
48+
49+
### إعادة المحاولة
50+
51+
- backoff، حالات HTTP، الشبكة، مفتاح **Idempotency** لـ POST عند التفعيل، ميزانية زمنية أحادية **`timeoutTotalMs`**.
52+
- **`onAfterResponse`** — بعد نجاح المحاولة؛ رمي **`OpenFetchForceRetry`** يعيد المحاولة.
53+
- **`onBeforeRetry`** — بعد فشل محاولة وقبل الانتظار (عند وجود محاولة لاحقة).
54+
- **`hooks()`** — يدمج `onBeforeRetry` / `onAfterResponse` في `ctx.request.retry`.
55+
56+
### التخزين المؤقت والـ fluent
57+
58+
- وسيط ذاكرة للـ GET/HEAD مع TTL وSWR (انظر [إعادة المحاولة والتخزين المؤقت](./retry-cache.md)).
59+
- الإضافات: `timeout`، `hooks`، `debug`، **`strictFetch`**.
60+
- **Fluent**: `createFluentClient`، سلاسل مثل `.json()` و**`.json(schema)`**، **`.memo()`**.
61+
62+
### الأخطاء والمساعدات
63+
64+
- **`OpenFetchError`** + **`toShape()`** للسجلات الآمنة نسبياً.
65+
- **`isOpenFetchError`**, **`isHTTPError`**, **`isTimeoutError`**, **`isSchemaValidationError`**.
66+
- **`assertSafeHttpUrl`**, **`maskHeaderValues`**, **`redactSensitiveUrlQuery`**, مفاتيح idempotency، **`cloneResponse`**.
67+
68+
---
69+
70+
## الصورة الكاملة للـ pipeline (مخطط)
71+
72+
```mermaid
73+
flowchart TD
74+
M[mergeConfig] --> I[init hooks متزامنة]
75+
I --> RI[معترضات الطلب]
76+
RI --> MW[كومة الوسيط]
77+
MW --> RO[معترضات الاستجابة]
78+
RO --> OUT[إرجاع OpenFetchResponse أو unwrap]
79+
```
80+
81+
**داخل الوسيط (مثال `createRetryMiddleware`):** كل محاولة تنفّذ `await next()` فيمرّ الوسيط الداخلي ثم **`dispatch`**. عند النجاح يُستدعى **`onAfterResponse`**؛ إذا أُلقِي **`OpenFetchForceRetry`** تُعاد المحاولة. عند الفشل يُستدعى **`onBeforeRetry`** (إن وُجد) ثم الانتظار ثم المحاولة التالية إن سمحت السياسة.
82+
83+
### داخل `dispatch` (بعد `fetch` — ليس `rawResponse`)
84+
85+
```mermaid
86+
flowchart TD
87+
A[URL + رؤوس + transformRequest + fetch] --> E{rawResponse?}
88+
E -->|نعم| VS1[validateStatus على الحالة فقط] --> Z[إرجاع Response كـ data]
89+
E -->|لا| P[parseBody]
90+
P --> VS2[validateStatus]
91+
VS2 --> JV{jsonSchema?}
92+
JV -->|نعم| SCHEMA[Standard Schema]
93+
JV -->|لا| TR
94+
SCHEMA --> TR[transformResponse]
95+
TR --> Z2[إرجاع OpenFetchResponse]
96+
```
97+
98+
### مخطط نصي (نسخ سريع)
99+
100+
```
101+
mergeConfig
102+
↓
103+
init hooks (sync)
104+
↓
105+
request interceptors
106+
↓
107+
middleware stack
108+
↓
109+
┌─ retry: لكل محاولة → next → … → dispatch
110+
│ dispatch: URL/headers → transformRequest → fetch
111+
│ [raw?] validateStatus → return Response
112+
│ OR parse → validateStatus → jsonSchema? → transformResponse
113+
│ ↓
114+
│ onAfterResponse — رمي OpenFetchForceRetry؟ → حلقة المحاولة
115+
│ ↓
116+
└─ عند الفشل: onBeforeRetry → backoff → حلقة
117+
↓
118+
response interceptors
119+
↓
120+
return
121+
```
122+
123+
**ملاحظات**
124+
125+
- **`onAfterResponse`** يعمل **بعد** اكتمال `dispatch` (بما فيه **`transformResponse`**)، فيرى `data` النهائية إلا في حالة **`rawResponse`**.
126+
- الوسيط **فوق** retry يعمل **مرة واحدة** لكل استدعاء عميل؛ الوسيط **تحت** retry يعمل **مرة لكل محاولة**.
127+
128+
---
129+
130+
## روابط
131+
132+
- [الإعدادات](./configuration.md)
133+
- [المعترضات والوسيط](./interceptors-middleware.md)
134+
- [إعادة المحاولة والتخزين المؤقت](./retry-cache.md)
135+
- [الأخطاء والأمان](./errors-security.md)
136+
- [الإضافات والـ fluent](../plugins-fluent.md) (إنجليزي)

0 commit comments

Comments
 (0)