curl and Terminal Clients

curl, Wget, HTTPie and xh get a page's first frame as truecolor ANSI text. Configure its size or turn it off.

تحصل عملاء HTTP في الطرفية على الإطار الأول للصفحة كنص ANSI بألوان حقيقية بدلًا من مستند HTML. لا تحتاج إلى ضبط أي إعدادات.

curl https://my-app.example.com/about

الطلبات التي تحصل على إطار

يحصل الطلب على إطار عند تحقق كل الشروط التالية:

  • الطريقة هي GET أو HEAD؛
  • يبدأ User-Agent بإحدى القيم curl/ أو Wget/ أو wget2/ أو HTTPie/ أو xh/؛
  • ترويسة Accept غائبة أو لا تتضمن text/html.

تحصل المتصفحات وبرامج الزحف ومعاينات الروابط على صفحة HTML. للحصول على HTML من curl، اطلبه:

curl -H 'Accept: text/html' https://my-app.example.com/about

يُختار الإطار عند النقطة التي ستُقدّم فيها الصفحة: بعد middleware و rewrites ومعالجات المسارات، ولا يُختار أبدًا للملفات أو المسارات التي يحتوي مقطعها الأخير على نقطة. تنطبق عمليات إعادة التوجيه واستجابات 401 والترويسات وإعادة كتابة المسارات في middleware على curl كما تنطبق على المتصفحات. يظل /api/health يشغّل معالجه ويظل /robots.txt يقدّم الملف.

محتويات الإطار

الإطار هو العرض الأول للصفحة، كما في هيكل معروض مسبقًا: يعرض كل حد من حدود <Suspense> التي لا تزال تنتظر محتواه البديل. لا تعمل مكوّنات الخادم غير المتزامنة، ولا يكتمل fetch() أبدًا، لذا تبقى البيانات المحمّلة في التأثيرات في حالة التحميل.

  • الحجم: ⁦80 × 24⁩ خلية. يستخدم التطبيق ذو مساحة العرض الثابتة (viewport.responsive: false) القيمة viewport.width × viewport.height بدلًا من ذلك.
  • الألوان: رموز هروب SGR بعمق 24 بت وفق viewport.theme في التطبيق. ينتهي كل صف بإعادة ضبط، وينتهي الإطار بسطر جديد.
  • الحالة: 200، أو 404 مع صفحة عدم العثور الخاصة بالتطبيق عندما لا تتطابق أي صفحة أو تستدعي الصفحة notFound(). تقدّم الصفحة التي تستدعي redirect() أثناء العرض محتوى HTML.

تأتي الاستجابات بالنوع text/plain; charset=utf-8 مع Vary: User-Agent, Accept و Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate، لذا لا تخزّن ذاكرات التخزين المؤقت المشتركة إطارًا لتقدّمه إلى متصفح. تحمل صفحة HTML في المسار الذي يحصل فيه curl على إطار ترويسة Vary نفسها.

بيئات التشغيل المدعومة

المضيفالصفحات الثابتةالصفحات الديناميكية، المسارات غير المعروفة
text devتُعرض عند الطلبتُعرض عند الطلب
text start، bunيعرضها text build مسبقًاتُعرض عند الطلب
vercel، cloudflareيعرضها text build مسبقًاصفحة HTML
staticصفحة HTMLصفحة HTML

تحتاج الصفحات المعروضة على الخادم إلى text start أو bun (انظر النشر).

لا تستطيع المضيفات الثابتة الاستجابة لعميل بصورة مختلفة عن آخر، لذا لا يدعم المحوّل static الإطارات. على Vercel و Cloudflare، تُرفق إطارات الصفحات الثابتة بناتج البناء. تقدّم الصفحات الديناميكية ([id]، force-dynamic) محتوى HTML هناك، لأن المحوّلين vercel و cloudflare لا ينشران عارضًا.

يعرض text start و bun dist/server.js الصفحات المتبقية عند الطلب باستخدام .text/server/live.mjs، ويحتفظان بآخر 128 إطارًا لمدة 10 ثوانٍ. يعرض كل خادم 20 صفحة غير مخزّنة مؤقتًا كحد أقصى كل 10 ثوانٍ. بعد ذلك، يحصل curl على صفحة HTML حتى تتجدد الحصة. إذا تعذّر تحميل live.mjs على الخادم، مثلًا لأن وحدة صفحة تقرأ window في المستوى الأعلى، فإن تلك الصفحات تقدّم محتوى HTML.

يعرض text build تقريرًا بالإطارات المعروضة مسبقًا:

 ✓ Prerendering curl frames (5/5)

الإعدادات

غيّر الحجم للتطبيق بأكمله، أو عطّل الإطارات:

text.config.tsts
import { defineConfig } from "@textjs/app";export default defineConfig({  ansi: { cols: 100, rows: 30 },  // ansi: false,});

يمكن للصفحة تغيير حجمها الخاص، أو تقديم HTML إلى الطرفيات أيضًا:

app/dashboard/page.tsxtsx
export const ansi = { cols: 120, rows: 40 };// export const ansi = false;

تُحصر الأحجام ضمن ⁦1–500⁩ خلية. عند ضبط ansi: false في text.config.ts، تُتجاهل صادرات الصفحات.

⁦HTTP⁩ غير المشفّر

لا يتبع curl عمليات إعادة التوجيه إلا عند تمرير -L. يعيد Vercel توجيه طلبات http:// إلى https://، وكذلك Cloudflare عند تفعيل استخدام HTTPS دائمًا، لذا يطبع curl http://… إعادة التوجيه بدلًا من الإطار. شارك عناوين URL التي تستخدم https://.

الخوادم المخصصة

تصدّر الحزمة @textjs/app/ansi دوال الكشف والاستجابة المساعدة، للخوادم والدوال التي لا تشغّل text start أو محوّلًا:

import { ansiResponse, wantsAnsi } from "@textjs/app/ansi";import { frameToAnsi } from "@textjs/react";if (wantsAnsi(request)) return ansiResponse(frameToAnsi(buffer, { theme: "geistDark" }), request.method);

تقبل wantsAnsi(request) أيضًا الوسيطين (method, headers) مع Headers من واجهة Web أو IncomingHttpHeaders من Node. ترمّز frameToAnsi(buffer, { theme }) كائن CellBuffer معروضًا بالطريقة نفسها التي يستخدمها إطار العمل.

تحرير هذه الصفحة على GitHub