−25%

على الدفع السنوي لـ Windows حتى 31 أكتوبر. عرض الخطط

EQVPS
ابدأ الآن

حزمة TypeScript لصناديق الرمل في 5 دقائق: من npm i @eqvps/sdk إلى أول تشغيل

ثبّت ‎@eqvps/sdk، وشغّل صندوق رمل Firecracker من Node.js أو Deno أو Bun، ونفّذ فيه شيفرة Python وNode وshell، وانقل الملفات، وتابع مهمة طويلة مباشرة. ست خطوات بكل سطر من الشيفرة.

يشغّل هذا الدليل صندوق رمل من JavaScript أو TypeScript. ستبدأ آلة microVM معزولة من Firecracker، وتنفّذ الشيفرة بثلاث لغات، وتنقل الملفات، وتتابع مخرجات مهمة طويلة. كل خطوة مقطع شيفرة قصير.

تحتاج إلى Node.js 18+‎ (أو Deno أو Bun) وحساب في EQVPS.

1. احصل على رمز وصول

تصادق الحزمة برمز وصول حساب عادي. تشرح صفحة ربط الحساب كيفية الحصول عليه من لوحة التحكم أو الـ API أو خادم MCP.

export EQVPS_API_KEY="your-token"

يحصل الحساب الجديد الذي لا رصيد له على 1 دولار لصناديق الرمل عند إنشاء أول صندوق رمل. هذا يكفي لهذا الدليل مرات كثيرة.

2. ثبّت الحزمة

npm i @eqvps/sdk

تستخدم الأمثلة وحدات ES وawait على المستوى الأعلى. احفظها كملفات .mjs، أو كملفات .ts وشغّلها بـ npx tsx.

3. شغّل صندوق رمل ونفّذ الشيفرة

import { Sandbox } from "@eqvps/sdk";

await Sandbox.with({ tariff: "small" }, async (sb) => {
  console.log(sb.id);
  const r = await sb.run("import platform; print(platform.python_version())");
  console.log(r.exit_code, r.stdout);
});

المخرج هو معرّف صندوق الرمل (sb_ يليه 24 حرفًا)، ثم 0 3.12.x. تحذف Sandbox.with صندوق الرمل عند انتهاء الدالة الممرّرة، حتى لو رمت خطأً.

اللغة الافتراضية Python، واللغتان الأخريان على بُعد خيار واحد:

await Sandbox.with({}, async (sb) => {
  const js = await sb.run("console.log(process.version)", { language: "node" });
  const sh = await sb.run("uname -r && nproc", { language: "bash" });
  console.log(js.stdout, sh.stdout);
});

السكربت الفاشل لا يرمي شيئًا. تحقق من r.ok، وهي صحيحة عندما يكون exit_code صفرًا ولم يبلغ الأمر مهلته.

4. أوامر shell والحزم

يقبل exec نص shell أو مصفوفة argv. لصندوق الرمل اتصال بالإنترنت، لذا تعمل عمليات التثبيت عبر npm وpip:

await Sandbox.with({ tariff: "small" }, async (sb) => {
  await sb.exec("mkdir -p /root/app && cd /root/app && npm init -y && npm i lodash", { timeout: 55 });
  const r = await sb.exec(["node", "-e", "console.log(require('/root/app/node_modules/lodash').VERSION)"]);
  console.log(r.stdout);
});

يدوم الاستدعاء المتزامن 55 ثانية على الأكثر. ما هو أطول يذهب إلى مهمة في الخلفية (الخطوة 6).

5. الملفات

await Sandbox.with({}, async (sb) => {
  await sb.upload("/root/input.json", JSON.stringify({ values: [3, 5, 8] }));
  await sb.run("import json; d = json.load(open('/root/input.json')); open('/root/out.txt', 'w').write(str(sum(d['values'])))");
  console.log(await sb.downloadText("/root/out.txt"));   // 16
});

تقبل upload نصًا أو Uint8Array. تُرجع download قيمة Uint8Array، وdownloadText نصًا. النقل الواحد محدود بـ 5 MB.

6. مهام طويلة بمخرجات مباشرة

await Sandbox.with({ tariff: "standard" }, async (sb) => {
  const task = await sb.exec("for i in 1 2 3 4 5; do echo step $i; sleep 20; done", { background: true });
  const res = await task.wait({ onOutput: (out) => process.stdout.write(out) });
  console.log(res.state, res.exit_code);   // done 0
});

تعود المهمة فورًا وليس لها حد الـ 55 ثانية. تتحقق wait افتراضيًا كل ثانيتين (ويغيّر ذلك pollIntervalMs). توقفها task.kill()، وتعيد sb.task(id) الاتصال بها من عملية أخرى.

الأخطاء

import { Sandbox, InsufficientBalanceError, RateLimitError } from "@eqvps/sdk";

try {
  await Sandbox.with({}, async (sb) => console.log((await sb.run("print(1)")).stdout));
} catch (e) {
  if (e instanceof InsufficientBalanceError) console.log("Top up the balance");
  else if (e instanceof RateLimitError) console.log("Busy, retry in", e.retryAfter);
  else throw e;
}

تعيد الحزمة بنفسها محاولة 429 و503 حتى ثلاث مرات عندما يرسل الخادم Retry-After. أكثر حالات 429 شيوعًا سببها تشغيل أكثر من أمرين في الوقت نفسه على حساب واحد. كل الفئات موجودة في مرجع الحزمة.

تكلفة هذا الدليل

عاش كل مثال بضع ثوانٍ وحُسب بالحد الأدنى البالغ 60 ثانية: 0.00055 دولار على small، و0.0011 دولار على standard. عملت مهمة الخطوة 6 نحو 100 ثانية على standard، أي نحو 0.002 دولار. المجموع أقل بكثير من سنت واحد. القائمة الكاملة للأسعار في حدود صناديق الرمل وفوترتها.

الخطوات التالية

الأسئلة الشائعة

ما بيئات التشغيل التي تدعمها ‎@eqvps/sdk؟

Node.js 18 وأحدث، وDeno، وBun. لا اعتماديات لها وتستخدم fetch المدمجة، لذا تعمل في المتصفح أيضًا، لكن لا تضع رمز وصول حسابك في شيفرة الواجهة الأمامية.

هل يستطيع صندوق الرمل تشغيل Python إذا كان تطبيقي بلغة TypeScript؟

نعم. لغة تطبيقك ولغة الشيفرة داخل صندوق الرمل مستقلتان. تقبل run قيمة language بين python وnode وbash، وينفّذ exec أي أمر shell.

كيف أضمن حذف صندوق الرمل؟

استخدم Sandbox.with(options, fn)، فهي تحذف صندوق الرمل عندما تنتهي fn أو ترمي خطأً. ومع TypeScript 5.2 أو أحدث يمكنك أيضًا كتابة await using sb = await Sandbox.create().

ماذا تُرجع run عندما تفشل الشيفرة؟

تُرجع ExecResult برمز exit_code غير صفري والخطأ في stderr، ولا ترمي شيئًا. الاستثناءات للأخطاء الخاصة بالـ API فقط، مثل رمز وصول غير صالح أو رصيد فارغ.

التعليقات

لا تعليقات بعد. كن الأول.

اترك تعليقًا

تُراجَع التعليقات قبل ظهورها.