SDK تایپاسکریپت
همهٔ API در یک کلاینت تایپشده. SDK از روی توصیف API ایجاد میشود، پس هر مسیر، پارامتر و پاسخ همان است که در مرجع API میبینید، و فقط از APIهای استاندارد وب استفاده میکند تا در Node، مرورگر و فانکشنهای cloudhost یکسان کار کند.
نصب#
npm install @cloudhost/sdkNode 18 یا جدیدتر، هر مرورگر امروزی، و فانکشنهای cloudhost. وابستگی ندارد.
شروع#
یک کلید API در داشبورد (تنظیمات، کلیدهای API) یا با cloudhost keys create ایجاد کنید. کلاینت کلید را از CLOUDHOST_API_KEY میخواند، یا آن را به سازنده بدهید.
import { Cloudhost } from "@cloudhost/sdk";
// the key from CLOUDHOST_API_KEY, or: new Cloudhost({ apiKey: "chk_live_..." })
const client = new Cloudhost();
const me = await client.account.whoami();
console.log(me.team, me.role);| گزینه | پیشفرض | کار |
|---|---|---|
apiKey | CLOUDHOST_API_KEY | کلید API |
baseUrl | CLOUDHOST_API_URL · https://api.ibel.ai | آدرس API |
env | process.env | در فانکشن، env خود فانکشن را بدهید |
maxRetries | 3 | تلاش دوباره پس از ۴۲۹ و ۵۰۳ |
maxRetryDelay | 60000 | بیشترین صبر پیش از تلاش دوباره (میلیثانیه)؛ Retry-After بلندتر فوراً خطا میدهد |
timeout | 60000 | میلیثانیه برای هر تلاش |
fetch | fetch سراسری | fetch خودتان (آزمون، پراکسی) |
شکل متدها#
برای هر بخش API یک فضای نام هست: functions، apps، databases، caches، storage، queues، flags، domains، billing، teams، account و بقیه. اول پارامترهای مسیر میآیند، بعد بدنهٔ JSON، بعد پارامترهای کوئری و در آخر گزینههای درخواست (signal، timeout، maxRetries، headers). نام فیلدها همان نامهای API است (snake_case)، پس مرجع API همانطور خوانده میشود.
import { Cloudhost } from "@cloudhost/sdk";
const client = new Cloudhost();
await client.functions.get("my-api"); // GET /v1/functions/my-api
await client.functions.deploy("my-api", { version: 12 }); // a JSON body
await client.functions.getLogs("my-api", { since: "1h", level: "error" }); // query parameters
await client.flags.functions.list("my-api"); // a product's part of another namespaceخطاها#
هر پاسخ خطا یک زیرکلاس ApiError است که از روی وضعیت HTTP انتخاب میشود، با code پایدار API (مثلاً not_found)، message و details (فیلدهای اضافهٔ آن کد). code تایپ دارد: همهٔ کدهایی که API مستند کرده.
import { Cloudhost, ApiError, ConflictError, RateLimitError } from "@cloudhost/sdk";
const client = new Cloudhost();
try {
await client.databases.create({ name: "shop" });
} catch (err) {
if (err instanceof ConflictError && err.is("name_taken")) console.log("the name is taken");
else if (err instanceof RateLimitError) console.log("try again in", err.retryAfter, "s");
else if (err instanceof ApiError) console.log(err.status, err.code, err.message);
else throw err;
}| کلاس | وضعیت |
|---|---|
BadRequestError | 400 |
AuthenticationError | 401 |
PaymentRequiredError | 402 |
PermissionDeniedError | 403 |
NotFoundError | 404 |
ConflictError | 409 |
PayloadTooLargeError | 413 |
RateLimitError | 429 |
InternalServerError · BadGatewayError · ServiceUnavailableError | 500 · 502 · 503 |
ConnectionError · TimeoutError | پاسخی نیامد |
ConfigurationError | کلید API نیست، پیش از هر درخواست |
تلاش دوباره#
پاسخ ۴۲۹ (محدودیت درخواست) یا ۵۰۳ (موقتاً در دسترس نیست) تا maxRetries بار دوباره فرستاده میشود. صبر همان Retry-After پاسخ است، وگرنه ۰٫۵، ۱، ۲ ... تا ۸ ثانیه با کمی تصادف. قطع اتصال فقط در خواندنها دوباره امتحان میشود، چون نوشتن شاید انجام شده باشد؛ درخواستی که بدنهاش stream است هرگز دوباره فرستاده نمیشود.
import { Cloudhost } from "@cloudhost/sdk";
const client = new Cloudhost({ maxRetries: 5, timeout: 30_000 });
client.transport.onRetry = ({ attempt, delayMs, error }) => console.warn("retry", attempt, "in", delayMs, "ms:", error.message);
// per call: a signal, a timeout, retries, headers
const ctl = new AbortController();
await client.functions.list({ signal: ctl.signal, maxRetries: 0 });صفحهبندی#
فهرستی که صفحه دارد یک همزاد ...All() دارد: با for await روی همهٔ آیتمها بچرخید، با .pages() روی صفحهها، یا با .toArray({ max }) زودتر بایستید. لاگها، گزارش تغییرها، اعلانها، تحویلهای webhook، ردها، پیامهای صف، پروندههای پشتیبانی و تاریخچهٔ فلگها.
import { Cloudhost } from "@cloudhost/sdk";
const client = new Cloudhost();
for await (const event of client.account.listAuditAll({ type: "deploy" })) {
console.log(event.at, event.action);
}
const errors = await client.functions.getLogsAll("my-api", { since: "24h", level: "error" }).toArray({ max: 500 });
for await (const page of client.support.listAll({ status: "active" }).pages()) console.log(page.total);هر محصول#
import { Cloudhost } from "@cloudhost/sdk";
const client = new Cloudhost();
await client.functions.create({ name: "my-api" });
const v = await client.functions.uploadVersion("my-api", {
main_module: "index.js",
modules: { "index.js": `export default { fetch: () => new Response("hello") }` },
});
const live = await client.functions.deploy("my-api", { version: v.version });
await client.functions.putSecret("my-api", "PAYMENT_KEY", { value: "..." });
const tail = await client.functions.tail("my-api"); // the live log
for await (const entry of tail) {
console.log(entry.level, entry.msg);
if (entry.level === "error") break;
}دامنهها، بیلدها، پیشنمایشها، هشدارها، webhookها، تیم و صورتحساب هم همین شکل را دارند؛ README بسته نمونهٔ هر کدام را دارد.
داخل فانکشن#
کلید را متغیر محیطی حساس فانکشن کنید و env فانکشن را به کلاینت بدهید.
import { Cloudhost } from "@cloudhost/sdk";
export default {
async fetch(request: Request, env: Record<string, string>) {
const client = new Cloudhost({ env }); // reads CLOUDHOST_API_KEY from the function's env
const { functions } = await client.functions.list();
return Response.json(functions.map((f) => f.name));
},
};در مرورگر#
بسته کد مخصوص Node ندارد و با هر bundler کار میکند.
viewer) و انقضای کوتاه بدهید. API فعلاً فقط روی مسیرهای عمومیاش به درخواستهای origin دیگر پاسخ میدهد، پس صفحهای روی origin دیگر از راه سرور خودتان صدا میزند.نسخهها#
هر نسخهٔ SDK برای یک نسخهٔ API ایجاد شده و آن را در هدر cloudhost-version میفرستد. مسیرهای جدید API در نسخهٔ بعدی SDK میآیند؛ تا آن موقع client.transport.request() هر مسیری را صدا میزند.