@vobs/payment 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vobsjs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,34 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * Alipay official driver (Open Platform API) — face-to-face (PC scan) / PC web / mobile web (H5).
7
+ *
8
+ * Covered scenes (web):
9
+ * - `pc` → alipay.trade.precreate (face-to-face) → `{kind:'qr', qrUrl: qr_code}`
10
+ * - `h5` → alipay.trade.wap.pay (mobile web) → `{kind:'redirect', payUrl}`
11
+ * - `miniapp` → same as h5 (Alipay miniapp webview uses H5 payment; native my.tradePay out of scope)
12
+ *
13
+ * Security:
14
+ * - Request signing: app private key RSA2 (SHA256withRSA), params joined in lexicographic order
15
+ * - Async notify: verify with Alipay public key (excluding sign/sign_type) + notify_id anti-replay + state-machine idempotency
16
+ * - Channel self-verification: callbacks bypass the framework's generic HMAC protocol; this driver verifies itself
17
+ *
18
+ * Dependencies: node:crypto (Node built-in, zero third-party). Sandbox: set baseUrl to openapi-sandbox.dl.alipaydev.com.
19
+ */
20
+ import type { PaymentDriver } from './types.js';
21
+ import type { PaymentStore } from './store.js';
22
+ export interface AlipayOfficialOptions {
23
+ readonly appId: string;
24
+ /** App private key (PEM, used for request signing). */
25
+ readonly privateKeyPem: string;
26
+ /** Alipay public key (PEM, used to verify async-notify/response signatures). */
27
+ readonly alipayPublicKeyPem: string;
28
+ /** Gateway URL. Production defaults to openapi.alipay.com, sandbox to openapi-sandbox.dl.alipaydev.com. */
29
+ readonly baseUrl?: string;
30
+ /** Page-jump gateway (GET redirects for PC web / mobile web). Defaults to baseUrl. */
31
+ readonly pageBaseUrl?: string;
32
+ readonly fetchImpl?: typeof fetch;
33
+ }
34
+ export declare function createAlipayOfficialDriver(store: PaymentStore, options: AlipayOfficialOptions): PaymentDriver;
@@ -0,0 +1,195 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * Alipay official driver (Open Platform API) — face-to-face (PC scan) / PC web / mobile web (H5).
7
+ *
8
+ * Covered scenes (web):
9
+ * - `pc` → alipay.trade.precreate (face-to-face) → `{kind:'qr', qrUrl: qr_code}`
10
+ * - `h5` → alipay.trade.wap.pay (mobile web) → `{kind:'redirect', payUrl}`
11
+ * - `miniapp` → same as h5 (Alipay miniapp webview uses H5 payment; native my.tradePay out of scope)
12
+ *
13
+ * Security:
14
+ * - Request signing: app private key RSA2 (SHA256withRSA), params joined in lexicographic order
15
+ * - Async notify: verify with Alipay public key (excluding sign/sign_type) + notify_id anti-replay + state-machine idempotency
16
+ * - Channel self-verification: callbacks bypass the framework's generic HMAC protocol; this driver verifies itself
17
+ *
18
+ * Dependencies: node:crypto (Node built-in, zero third-party). Sandbox: set baseUrl to openapi-sandbox.dl.alipaydev.com.
19
+ */
20
+ import { createPrivateKey, createPublicKey, sign, verify } from 'node:crypto';
21
+ const DEFAULT_GATEWAY = 'https://openapi.alipay.com/gateway.do';
22
+ /** Yuan (string) → fen (integer): '99.90' → 9990. */
23
+ function yuanToFen(v) {
24
+ return Math.round(Number(v) * 100);
25
+ }
26
+ /** Fen → yuan string (2 decimals): 9990 → '99.90'. */
27
+ function fenToYuan(amount) {
28
+ return (amount / 100).toFixed(2);
29
+ }
30
+ function nowTimestamp() {
31
+ const d = new Date();
32
+ const pad = (n) => String(n).padStart(2, '0');
33
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
34
+ }
35
+ export function createAlipayOfficialDriver(store, options) {
36
+ const baseUrl = options.baseUrl ?? DEFAULT_GATEWAY;
37
+ const pageBaseUrl = options.pageBaseUrl ?? options.baseUrl ?? DEFAULT_GATEWAY;
38
+ const fetchImpl = options.fetchImpl ?? ((...args) => fetch(...args));
39
+ const privateKey = createPrivateKey(options.privateKeyPem);
40
+ const alipayPublicKey = createPublicKey(options.alipayPublicKeyPem);
41
+ /** RSA2 signature (SHA256withRSA), base64-encoded. */
42
+ function rsaSign(data) {
43
+ return sign('RSA-SHA256', Buffer.from(data), privateKey).toString('base64');
44
+ }
45
+ /** RSA2 verify (Alipay public key). */
46
+ function rsaVerify(data, signature) {
47
+ try {
48
+ return verify('RSA-SHA256', Buffer.from(data), alipayPublicKey, Buffer.from(signature, 'base64'));
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
54
+ /** Join params (excluding sign/sign_type) in lexicographic order → k=v&k=v. */
55
+ function sortParams(params) {
56
+ return Object.keys(params)
57
+ .filter((k) => k !== 'sign' && k !== 'sign_type')
58
+ .sort()
59
+ .map((k) => `${k}=${params[k]}`)
60
+ .join('&');
61
+ }
62
+ async function gateway(method, bizContent) {
63
+ const params = {
64
+ app_id: options.appId,
65
+ method,
66
+ charset: 'utf-8',
67
+ sign_type: 'RSA2',
68
+ timestamp: nowTimestamp(),
69
+ version: '1.0',
70
+ biz_content: JSON.stringify(bizContent),
71
+ };
72
+ params['sign'] = rsaSign(sortParams(params));
73
+ const res = await fetchImpl(baseUrl, {
74
+ method: 'POST',
75
+ headers: { 'Content-Type': 'application/json' },
76
+ body: JSON.stringify(params),
77
+ });
78
+ const body = (await res.json());
79
+ if (!res.ok) {
80
+ throw new Error(`alipay_api_error:${res.status}`);
81
+ }
82
+ return body;
83
+ }
84
+ function buildPageUrl(method, bizContent) {
85
+ const params = {
86
+ app_id: options.appId,
87
+ method,
88
+ charset: 'utf-8',
89
+ sign_type: 'RSA2',
90
+ timestamp: nowTimestamp(),
91
+ version: '1.0',
92
+ biz_content: JSON.stringify(bizContent),
93
+ return_url: '',
94
+ notify_url: '',
95
+ };
96
+ params['sign'] = rsaSign(sortParams(params));
97
+ const qs = Object.keys(params)
98
+ .sort()
99
+ .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(params[k] ?? '')}`)
100
+ .join('&');
101
+ return `${pageBaseUrl}?${qs}`;
102
+ }
103
+ async function createOrder(input) {
104
+ const biz = {
105
+ out_trade_no: input.orderId,
106
+ total_amount: fenToYuan(input.amount),
107
+ subject: input.subject,
108
+ };
109
+ if (input.scene === 'pc') {
110
+ // Face-to-face (scan) payment
111
+ const body = await gateway('alipay.trade.precreate', biz);
112
+ const resp = body.alipay_trade_precreate_response;
113
+ if (resp?.code !== '10000' || !resp.qr_code) {
114
+ throw new Error(`alipay_precreate_failed:${resp?.sub_code ?? resp?.msg ?? 'unknown'}`);
115
+ }
116
+ return {
117
+ kind: 'qr',
118
+ qrUrl: resp.qr_code,
119
+ expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
120
+ };
121
+ }
122
+ // h5 / miniapp: mobile web payment (redirect to cashier)
123
+ return { kind: 'redirect', payUrl: buildPageUrl('alipay.trade.wap.pay', biz) };
124
+ }
125
+ function verifyCallback(payload, _headers) {
126
+ // Async notify is a form-encoded string: a=1&b=2&sign=... (URL-decoded)
127
+ let params;
128
+ if (typeof payload === 'string') {
129
+ params = {};
130
+ for (const pair of payload.split('&')) {
131
+ const eq = pair.indexOf('=');
132
+ if (eq > 0) {
133
+ const k = decodeURIComponent(pair.slice(0, eq));
134
+ const v = decodeURIComponent(pair.slice(eq + 1));
135
+ params[k] = v;
136
+ }
137
+ }
138
+ }
139
+ else {
140
+ const obj = payload;
141
+ params = Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, String(v)]));
142
+ }
143
+ const signature = params['sign'] ?? '';
144
+ if (!rsaVerify(sortParams(params), signature)) {
145
+ return { ok: false, reason: 'bad_alipay_signature' };
146
+ }
147
+ // notify_id anti-replay (channel self-verification path)
148
+ const notifyId = params['notify_id'] ?? '';
149
+ if (!store.addNonce(`ali:${notifyId}`)) {
150
+ return { ok: false, reason: 'nonce_reused' };
151
+ }
152
+ // Only successful states are booked (TRADE_SUCCESS / TRADE_FINISHED)
153
+ const tradeStatus = params['trade_status'] ?? '';
154
+ if (tradeStatus !== 'TRADE_SUCCESS' && tradeStatus !== 'TRADE_FINISHED') {
155
+ return { ok: false, reason: `trade_status:${tradeStatus}` };
156
+ }
157
+ const orderId = params['out_trade_no'];
158
+ if (!orderId || params['total_amount'] === undefined) {
159
+ return { ok: false, reason: 'bad_payload' };
160
+ }
161
+ return {
162
+ ok: true,
163
+ orderId,
164
+ paidAmount: yuanToFen(params['total_amount']),
165
+ ...(params['trade_no'] ? { channelTxnId: params['trade_no'] } : {}),
166
+ };
167
+ }
168
+ async function queryOrder(orderId) {
169
+ try {
170
+ const body = await gateway('alipay.trade.query', {
171
+ out_trade_no: orderId,
172
+ });
173
+ const resp = body.alipay_trade_query_response;
174
+ const status = resp?.trade_status;
175
+ if (status === 'TRADE_SUCCESS' || status === 'TRADE_FINISHED') {
176
+ return { state: 'paid', ...(resp.send_pay_date ? { paidAt: resp.send_pay_date } : {}) };
177
+ }
178
+ if (status === 'TRADE_CLOSED') {
179
+ return { state: 'closed' };
180
+ }
181
+ return { state: 'created' };
182
+ }
183
+ catch {
184
+ return { state: 'unknown', raw: { error: 'query_failed' } };
185
+ }
186
+ }
187
+ return {
188
+ name: 'alipay_official',
189
+ scenes: ['pc', 'h5', 'miniapp'],
190
+ createOrder,
191
+ verifyCallback,
192
+ queryOrder,
193
+ successResponseText: 'success',
194
+ };
195
+ }
@@ -0,0 +1,33 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * Framework-agnostic HTTP handler layer — `paymentHttpDispatch` returns standard responses that
7
+ * the business wraps in one line inside its own server (Hono/Express/Fastify). This package does
8
+ * not bind to any server.
9
+ *
10
+ * Route conventions (per design doc §3.3/§3.5):
11
+ * GET /payment/available-methods available payment methods
12
+ * POST /api/payment/orders create order (server-side pricing + limit + idempotency + duplicate guard)
13
+ * GET /api/payment/orders/:id/status query status (frontend polling)
14
+ * POST /api/payment/orders/:id/close close on timeout/cancel (example helper)
15
+ * POST /api/payment/orders/:id/confirm manual release for large-amount review (admin; business-side auth required)
16
+ * POST /payment/callback/:driver channel callback (verify + anti-replay + state machine)
17
+ */
18
+ import type { PaymentManager } from './manager.js';
19
+ export interface HttpResponse {
20
+ readonly status: number;
21
+ readonly body: unknown;
22
+ }
23
+ export interface HttpRequestContext {
24
+ readonly method: string;
25
+ /** Relative path (e.g. `/api/payment/orders` or `/payment/callback/mock`). */
26
+ readonly path: string;
27
+ readonly headers?: Readonly<Record<string, string | undefined>>;
28
+ readonly body?: string;
29
+ }
30
+ type RouteResult = HttpResponse;
31
+ /** Create a dispatch function (pure logic, no framework dependency). */
32
+ export declare function paymentHttpDispatch(manager: PaymentManager): (ctx: HttpRequestContext) => Promise<RouteResult>;
33
+ export {};
@@ -0,0 +1,95 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * Framework-agnostic HTTP handler layer — `paymentHttpDispatch` returns standard responses that
7
+ * the business wraps in one line inside its own server (Hono/Express/Fastify). This package does
8
+ * not bind to any server.
9
+ *
10
+ * Route conventions (per design doc §3.3/§3.5):
11
+ * GET /payment/available-methods available payment methods
12
+ * POST /api/payment/orders create order (server-side pricing + limit + idempotency + duplicate guard)
13
+ * GET /api/payment/orders/:id/status query status (frontend polling)
14
+ * POST /api/payment/orders/:id/close close on timeout/cancel (example helper)
15
+ * POST /api/payment/orders/:id/confirm manual release for large-amount review (admin; business-side auth required)
16
+ * POST /payment/callback/:driver channel callback (verify + anti-replay + state machine)
17
+ */
18
+ const json = (status, body) => ({ status, body });
19
+ function errorStatus(err) {
20
+ switch (err.error) {
21
+ case 'order_not_found':
22
+ return 404;
23
+ case 'amount_exceeds_limit':
24
+ case 'amount_mismatch':
25
+ case 'bad_request':
26
+ return 400;
27
+ case 'order_conflict':
28
+ return 409;
29
+ case 'channel_unavailable':
30
+ return 503;
31
+ default:
32
+ return 500;
33
+ }
34
+ }
35
+ /** Create a dispatch function (pure logic, no framework dependency). */
36
+ export function paymentHttpDispatch(manager) {
37
+ return async function dispatch(ctx) {
38
+ const { method, path } = ctx;
39
+ if (method === 'GET' && path === '/payment/available-methods') {
40
+ return json(200, { methods: manager.available() });
41
+ }
42
+ if (method === 'POST' && path === '/api/payment/orders') {
43
+ let req;
44
+ try {
45
+ req = JSON.parse(ctx.body ?? '');
46
+ }
47
+ catch {
48
+ return json(400, { error: 'bad_json' });
49
+ }
50
+ const outcome = await manager.createOrder(req);
51
+ if ('error' in outcome) {
52
+ return json(errorStatus(outcome), outcome);
53
+ }
54
+ return json(200, outcome);
55
+ }
56
+ const statusMatch = path.match(/^\/api\/payment\/orders\/([^/]+)\/status$/);
57
+ if (statusMatch && method === 'GET') {
58
+ const orderId = statusMatch[1];
59
+ const status = manager.getStatus(orderId);
60
+ if (!status)
61
+ return json(404, { error: 'order_not_found' });
62
+ return json(200, { orderId, ...status });
63
+ }
64
+ const closeMatch = path.match(/^\/api\/payment\/orders\/([^/]+)\/close$/);
65
+ if (closeMatch && method === 'POST') {
66
+ const orderId = closeMatch[1];
67
+ const status = manager.close(orderId);
68
+ if (!status)
69
+ return json(404, { error: 'order_not_found' });
70
+ return json(200, { orderId, ...status });
71
+ }
72
+ const confirmMatch = path.match(/^\/api\/payment\/orders\/([^/]+)\/confirm$/);
73
+ if (confirmMatch && method === 'POST') {
74
+ const orderId = confirmMatch[1];
75
+ const status = manager.confirm(orderId);
76
+ if (!status)
77
+ return json(404, { error: 'order_not_found' });
78
+ return json(200, { orderId, ...status });
79
+ }
80
+ const callbackMatch = path.match(/^\/payment\/callback\/([^/]+)$/);
81
+ if (callbackMatch && method === 'POST') {
82
+ const driver = callbackMatch[1];
83
+ const result = await manager.handleCallback(driver, {
84
+ headers: ctx.headers ?? {},
85
+ body: ctx.body ?? '',
86
+ });
87
+ // Channel-agreed response protocol: if text exists → plain text (WeChat/Jeepay SUCCESS, Alipay success), else JSON
88
+ if (result.text !== undefined) {
89
+ return { status: result.status, body: result.text };
90
+ }
91
+ return json(result.status, result.body);
92
+ }
93
+ return json(404, { error: 'not_found' });
94
+ };
95
+ }
@@ -0,0 +1,35 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * @vobs/payment — payment-factory backend SDK (Experimental).
7
+ *
8
+ * Positioning: an official vobs extension package embedded in the business backend (not a standalone service).
9
+ * Responsibility: the forward payment pipeline (order → verify → book → reconcile); **no refunds**.
10
+ *
11
+ * Usage (business backend, 3 touch points):
12
+ * ```ts
13
+ * import { createPaymentManager, createMockDriver, paymentHttpDispatch } from '@vobs/payment'
14
+ *
15
+ * const manager = createPaymentManager({
16
+ * apiKey: process.env.PAYMENT_API_KEY!,
17
+ * getOrderAmount: (orderId) => orderDao.find(orderId)?.amount, // server-side pricing (red line)
18
+ * onVerified: ({ orderId }) => orderDao.markPaid(orderId), // idempotent
19
+ * })
20
+ * manager.registerDriver(createMockDriver(store)) // swap in a real channel driver for P1
21
+ * const dispatch = paymentHttpDispatch(manager)
22
+ * // in your server: app.post('/api/payment/orders', async (req) => dispatch({ method:'POST', path:'/api/payment/orders', body: await req.text() }))
23
+ * ```
24
+ */
25
+ export * from './types.js';
26
+ export * from './verify.js';
27
+ export * from './state-machine.js';
28
+ export * from './store.js';
29
+ export * from './mock-driver.js';
30
+ export * from './wechat-official.js';
31
+ export * from './alipay-official.js';
32
+ export * from './jeepay.js';
33
+ export * from './lakala.js';
34
+ export * from './manager.js';
35
+ export * from './handlers.js';
package/dist/index.js ADDED
@@ -0,0 +1,35 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * @vobs/payment — payment-factory backend SDK (Experimental).
7
+ *
8
+ * Positioning: an official vobs extension package embedded in the business backend (not a standalone service).
9
+ * Responsibility: the forward payment pipeline (order → verify → book → reconcile); **no refunds**.
10
+ *
11
+ * Usage (business backend, 3 touch points):
12
+ * ```ts
13
+ * import { createPaymentManager, createMockDriver, paymentHttpDispatch } from '@vobs/payment'
14
+ *
15
+ * const manager = createPaymentManager({
16
+ * apiKey: process.env.PAYMENT_API_KEY!,
17
+ * getOrderAmount: (orderId) => orderDao.find(orderId)?.amount, // server-side pricing (red line)
18
+ * onVerified: ({ orderId }) => orderDao.markPaid(orderId), // idempotent
19
+ * })
20
+ * manager.registerDriver(createMockDriver(store)) // swap in a real channel driver for P1
21
+ * const dispatch = paymentHttpDispatch(manager)
22
+ * // in your server: app.post('/api/payment/orders', async (req) => dispatch({ method:'POST', path:'/api/payment/orders', body: await req.text() }))
23
+ * ```
24
+ */
25
+ export * from './types.js';
26
+ export * from './verify.js';
27
+ export * from './state-machine.js';
28
+ export * from './store.js';
29
+ export * from './mock-driver.js';
30
+ export * from './wechat-official.js';
31
+ export * from './alipay-official.js';
32
+ export * from './jeepay.js';
33
+ export * from './lakala.js';
34
+ export * from './manager.js';
35
+ export * from './handlers.js';
@@ -0,0 +1,39 @@
1
+ /** @license MIT
2
+ * Copyright (c) 2026 vobsjs
3
+ * @vobs/payment
4
+ */
5
+ /**
6
+ * Jeepay (Jiquan Payment) aggregator driver — open-source aggregator payment system (LGPL-3.0).
7
+ *
8
+ * Integration shape: merchant business system → Jeepay payment gateway (self-hosted or official cloud pay.jeepay.vip).
9
+ * Docs: docs.jeequan.com/docs/jeepay/payment_api (refer to the latest official docs for field details).
10
+ *
11
+ * Scene mapping (wayCode → OrderInit):
12
+ * - `pc` (no openid) → `WX_NATIVE` / `ALI_QR` → payDataType=codeUrl → `{kind:'qr'}`
13
+ * - `h5` + openid (official account) → `WX_JSAPI` → payDataType=wxpay → `{kind:'jsapi'}`
14
+ * - `h5` (no openid) → `ALI_WAP` / `WX_H5` → payDataType=payUrl → `{kind:'redirect'}`
15
+ * - `miniapp` (webview) → `WX_LITE` → payDataType=wxpay → `{kind:'jsapi'}`
16
+ * - extras.wayCode can be set explicitly (the business decides WeChat/Alipay channel)
17
+ *
18
+ * Security:
19
+ * - Request/callback signing: MD5 (non-empty params in ASCII lexicographic order + &key=appSecret → uppercase MD5)
20
+ * - Callbacks use the channel self-verification path; Jeepay notifications have no unique ID,
21
+ * so anti-replay relies on signature verification + HTTPS + state-machine idempotency
22
+ * (duplicate notifications for an already-paid order return success without re-booking)
23
+ *
24
+ * Dependencies: node:crypto (MD5). Zero third-party.
25
+ */
26
+ import type { PaymentDriver } from './types.js';
27
+ import type { PaymentStore } from './store.js';
28
+ export interface JeepayOptions {
29
+ /** Merchant number (issued by the Jeepay ops platform). */
30
+ readonly mchNo: string;
31
+ /** Application ID (merchant app). */
32
+ readonly appId: string;
33
+ /** Signing secret (configured on the merchant app, used for MD5). */
34
+ readonly appSecret: string;
35
+ /** Payment gateway URL (self-hosted, e.g. https://pay.example.com; or official cloud https://pay.jeepay.vip). */
36
+ readonly baseUrl: string;
37
+ readonly fetchImpl?: typeof fetch;
38
+ }
39
+ export declare function createJeepayDriver(_store: PaymentStore, options: JeepayOptions): PaymentDriver;