# Zibal SDK for Node.js

SDK درگاه پرداخت زیبال برای Node.js 18 و بالاتر. این نسخه از `fetch` داخلی Node استفاده می‌کند و وابستگی runtime ندارد.

این نسخه flow اصلی `request` و `verify` را پوشش می‌دهد. سرویس‌های `inquiry` و Lazy فعلاً جزو API عمومی این پکیج نیستند. [مستندات رسمی IPG زیبال](https://help.zibal.ir/ipg/)

## نصب

```bash
npm install zibal
```

## ایجاد تراکنش

```js
const Zibal = require("zibal");

const merchant = process.env.ZIBAL_MERCHANT;
if (!merchant) throw new Error("ZIBAL_MERCHANT is required");

const zibal = new Zibal({
  merchant,
  callbackUrl: "https://example.com/payment/callback",
  timeout: 10000,
});

(async () => {
  try {
    const payment = await zibal.request({
      amount: 200000,
      orderId: "ORDER-1",
    });

    console.log(payment.paymentUrl);
  } catch (error) {
    console.error(error.code, error.message);
  }
})();
```

برای sandbox نیز merchant را صریحاً برابر `"zibal"` قرار دهید. پکیج عمداً merchant پیش‌فرض ندارد تا نبودن متغیر محیطی، برنامه را بی‌صدا وارد محیط آزمایشی نکند.

در هدایت مرورگر به `paymentUrl`، زیبال اکنون هدر `Referer` معتبر می‌خواهد. مرورگر در navigation معمولی آن را ارسال می‌کند؛ در اپلیکیشن موبایل، بات یا درخواست برنامه‌ای باید `Referer` را دستی و مطابق دامنه ثبت‌شده درگاه تنظیم کنید.

## تایید امن تراکنش

`trackId`، مبلغ و شناسه سفارش را قبل از redirect در دیتابیس ذخیره کنید. در callback فقط به query string اعتماد نکنید:

```js
const payment = await zibal.verify({
  trackId: order.zibalTrackId,
  expectedAmount: order.amount,
  expectedOrderId: order.id,
});

// نهایی‌سازی سفارش باید idempotent و داخل transaction دیتابیس باشد.
await markOrderAsPaidOnce(order.id, payment);
```

## خطاها

- `ZibalValidationError`: ورودی نامعتبر
- `ZibalApiError`: خطای تجاری برگشتی از زیبال
- `ZibalNetworkError`: خطای اتصال
- `ZibalTimeoutError`: پایان timeout
- `ZibalAbortError`: لغو درخواست با AbortSignal
- `ZibalHttpError`: HTTP status ناموفق
- `ZibalResponseError`: JSON یا ساختار پاسخ نامعتبر
- `ZibalIntegrityError`: عدم تطابق مبلغ یا شناسه سفارش

تمام خطاها reject می‌شوند. خطای اصلی transport در `error.cause` حفظ می‌شود و SDK چیزی را در console چاپ نمی‌کند.

## لغو درخواست

```js
const controller = new AbortController();

const promise = zibal.verify({
  trackId,
  expectedAmount: order.amount,
  signal: controller.signal,
});

controller.abort();
await promise;
```

## مهاجرت از نسخه 1

نسخه 2 یک breaking release است:

- Node.js 18 یا جدیدتر لازم است.
- تعیین صریح `merchant` در constructor و `expectedAmount` در `verify` الزامی است.
- خطاهای API و شبکه همگی reject می‌شوند.
- برای مدیریت خطا از `try/catch` استفاده کنید.
- Axios حذف شده است.
- timeout پیش‌فرض ۱۰ ثانیه است.
- متدهای قدیمی `init` و `setMerchant` برای سازگاری باقی مانده‌اند، اما `update` روش پیشنهادی است.
