@bitalcer/partner-api 1.0.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/index.d.ts +156 -0
- package/index.js +292 -0
- package/package.json +17 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitalcer Partner API — TypeScript type definitions v1.0.0
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
declare module '@bitalcer/partner-api' {
|
|
6
|
+
export interface ClientConfig {
|
|
7
|
+
apiKey: string;
|
|
8
|
+
hmacSecret: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PingResponse {
|
|
13
|
+
status: string;
|
|
14
|
+
partner_id: number;
|
|
15
|
+
environment: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UserResponse {
|
|
19
|
+
id: number;
|
|
20
|
+
partner_id: number;
|
|
21
|
+
external_user_id: string;
|
|
22
|
+
internal_user_id: number | null;
|
|
23
|
+
status: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface WalletResponse {
|
|
27
|
+
external_user_id: string;
|
|
28
|
+
address: string;
|
|
29
|
+
chain: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface BalanceResponse {
|
|
33
|
+
external_user_id: string;
|
|
34
|
+
token: string;
|
|
35
|
+
chain: string;
|
|
36
|
+
balance: string;
|
|
37
|
+
address: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface WithdrawParams {
|
|
41
|
+
externalUserId: string;
|
|
42
|
+
toAddress: string;
|
|
43
|
+
amount: string;
|
|
44
|
+
token?: string;
|
|
45
|
+
chain?: 'bsc' | 'polygon';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface WithdrawResponse {
|
|
49
|
+
withdraw_id: string;
|
|
50
|
+
tx_hash: string;
|
|
51
|
+
status: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TransferParams {
|
|
55
|
+
senderExternalUserId: string;
|
|
56
|
+
receiverExternalUserId: string;
|
|
57
|
+
amount: string;
|
|
58
|
+
token?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface TransferResponse {
|
|
62
|
+
transfer_id: string;
|
|
63
|
+
status: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface QuoteParams {
|
|
67
|
+
externalUserId: string;
|
|
68
|
+
baseAsset: 'GTQ' | 'USDT';
|
|
69
|
+
quoteAsset: 'GTQ' | 'USDT';
|
|
70
|
+
amount: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface QuoteResponse {
|
|
74
|
+
pair: string;
|
|
75
|
+
estimated_amount_out: number;
|
|
76
|
+
price_applied: number;
|
|
77
|
+
fee_amount: number;
|
|
78
|
+
fee_bps: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CreateOrderParams {
|
|
82
|
+
externalUserId: string;
|
|
83
|
+
baseAsset: 'GTQ' | 'USDT';
|
|
84
|
+
quoteAsset: 'GTQ' | 'USDT';
|
|
85
|
+
requestedAmount: number;
|
|
86
|
+
side: 'buy' | 'sell';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface OrderResponse {
|
|
90
|
+
order_id: string;
|
|
91
|
+
status: string;
|
|
92
|
+
quote_expires_at: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ExecuteResponse {
|
|
96
|
+
order_id: string;
|
|
97
|
+
status: string;
|
|
98
|
+
executed_at: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface OrderStatusResponse {
|
|
102
|
+
order_id: string;
|
|
103
|
+
status: string;
|
|
104
|
+
executed_amount: number;
|
|
105
|
+
price_applied: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface TreasuryBalanceResponse {
|
|
109
|
+
partner_id: number;
|
|
110
|
+
available_balance_usd: number;
|
|
111
|
+
reserved_balance_usd: number;
|
|
112
|
+
tier: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ApiError extends Error {
|
|
116
|
+
status: number;
|
|
117
|
+
code: string;
|
|
118
|
+
body: any;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export class UsersClient {
|
|
122
|
+
create(externalUserId: string): Promise<UserResponse>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class WalletsClient {
|
|
126
|
+
create(externalUserId: string, chain?: 'bsc' | 'polygon' | 'btc'): Promise<WalletResponse>;
|
|
127
|
+
getBalance(externalUserId: string, opts?: { token?: string; chain?: string }): Promise<BalanceResponse>;
|
|
128
|
+
getAddress(externalUserId: string, opts?: { chain?: string }): Promise<WalletResponse>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export class TransactionsClient {
|
|
132
|
+
withdraw(params: WithdrawParams): Promise<WithdrawResponse>;
|
|
133
|
+
transfer(params: TransferParams): Promise<TransferResponse>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export class ConversionClient {
|
|
137
|
+
quote(params: QuoteParams): Promise<QuoteResponse>;
|
|
138
|
+
createOrder(params: CreateOrderParams): Promise<OrderResponse>;
|
|
139
|
+
execute(externalUserId: string, orderId: string): Promise<ExecuteResponse>;
|
|
140
|
+
getStatus(externalUserId: string, orderId: string): Promise<OrderStatusResponse>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class TreasuryClient {
|
|
144
|
+
getBalance(): Promise<TreasuryBalanceResponse>;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export class Client {
|
|
148
|
+
constructor(config: ClientConfig);
|
|
149
|
+
ping(): Promise<PingResponse>;
|
|
150
|
+
users: UsersClient;
|
|
151
|
+
wallets: WalletsClient;
|
|
152
|
+
transactions: TransactionsClient;
|
|
153
|
+
conversion: ConversionClient;
|
|
154
|
+
treasury: TreasuryClient;
|
|
155
|
+
}
|
|
156
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitalcer Partner API — JavaScript SDK v1.0.0
|
|
3
|
+
*
|
|
4
|
+
* Cliente oficial para la Bitalcer Custody-as-a-Service Partner API.
|
|
5
|
+
* Firma HMAC-SHA256 automática. Sin dependencias externas.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const { Client } = require('@bitalcer/partner-api');
|
|
9
|
+
* const bitalcer = new Client({ apiKey: 'bak_...', hmacSecret: '...' });
|
|
10
|
+
* await bitalcer.ping();
|
|
11
|
+
* const user = await bitalcer.users.create('cust-00001');
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const crypto = require('crypto');
|
|
17
|
+
|
|
18
|
+
// ── Helpers ───────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Calcula la firma HMAC-SHA256 para un request.
|
|
22
|
+
* @param {string} secret - HMAC secret en hex
|
|
23
|
+
* @param {string} timestamp - Epoch en ms como string
|
|
24
|
+
* @param {string} body - Body crudo (string vacío para GET)
|
|
25
|
+
* @returns {string} Firma en hexadecimal
|
|
26
|
+
*/
|
|
27
|
+
function sign(secret, timestamp, body) {
|
|
28
|
+
return crypto
|
|
29
|
+
.createHmac('sha256', secret)
|
|
30
|
+
.update(timestamp + ':' + body)
|
|
31
|
+
.digest('hex');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Realiza un request firmado a la Partner API.
|
|
36
|
+
* @param {object} opts
|
|
37
|
+
* @param {string} opts.baseUrl
|
|
38
|
+
* @param {string} opts.apiKey
|
|
39
|
+
* @param {string} opts.hmacSecret
|
|
40
|
+
* @param {string} opts.method
|
|
41
|
+
* @param {string} opts.path
|
|
42
|
+
* @param {object} [opts.body]
|
|
43
|
+
* @returns {Promise<object>} Respuesta parseada como JSON
|
|
44
|
+
*/
|
|
45
|
+
async function request(opts) {
|
|
46
|
+
const { baseUrl, apiKey, hmacSecret, method, path, body } = opts;
|
|
47
|
+
const rawBody = body ? JSON.stringify(body) : '';
|
|
48
|
+
const timestamp = String(Date.now());
|
|
49
|
+
const signature = sign(hmacSecret, timestamp, rawBody);
|
|
50
|
+
|
|
51
|
+
const headers = {
|
|
52
|
+
'x-api-key': apiKey,
|
|
53
|
+
'x-timestamp': timestamp,
|
|
54
|
+
'x-signature': signature,
|
|
55
|
+
};
|
|
56
|
+
if (body) {
|
|
57
|
+
headers['Content-Type'] = 'application/json';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const url = baseUrl.replace(/\/+$/, '') + '/' + path.replace(/^\/+/, '');
|
|
61
|
+
const res = await fetch(url, {
|
|
62
|
+
method,
|
|
63
|
+
headers,
|
|
64
|
+
body: rawBody || undefined,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const data = await res.json();
|
|
68
|
+
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
const err = new Error(data.error || data.message || `HTTP ${res.status}`);
|
|
71
|
+
err.status = res.status;
|
|
72
|
+
err.code = data.error;
|
|
73
|
+
err.body = data;
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return data;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Client ────────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
class Client {
|
|
83
|
+
/**
|
|
84
|
+
* @param {object} config
|
|
85
|
+
* @param {string} config.apiKey - API key de sandbox o production
|
|
86
|
+
* @param {string} config.hmacSecret - HMAC secret correspondiente
|
|
87
|
+
* @param {string} [config.baseUrl='https://api.bitalcer.com']
|
|
88
|
+
*/
|
|
89
|
+
constructor({ apiKey, hmacSecret, baseUrl = 'https://api.bitalcer.com' }) {
|
|
90
|
+
if (!apiKey || !hmacSecret) {
|
|
91
|
+
throw new Error('apiKey y hmacSecret son obligatorios.');
|
|
92
|
+
}
|
|
93
|
+
/** @private */ this._baseUrl = baseUrl;
|
|
94
|
+
/** @private */ this._apiKey = apiKey;
|
|
95
|
+
/** @private */ this._hmacSecret = hmacSecret;
|
|
96
|
+
|
|
97
|
+
this.users = new UsersClient(this);
|
|
98
|
+
this.wallets = new WalletsClient(this);
|
|
99
|
+
this.transactions = new TransactionsClient(this);
|
|
100
|
+
this.conversion = new ConversionClient(this);
|
|
101
|
+
this.treasury = new TreasuryClient(this);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Verifica conectividad y credenciales.
|
|
106
|
+
* @returns {Promise<{status: string, partner_id: number, environment: string}>}
|
|
107
|
+
*/
|
|
108
|
+
async ping() {
|
|
109
|
+
return this._req('GET', '/partner/v1/ping');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** @private */
|
|
113
|
+
_req(method, path, body) {
|
|
114
|
+
return request({
|
|
115
|
+
baseUrl: this._baseUrl,
|
|
116
|
+
apiKey: this._apiKey,
|
|
117
|
+
hmacSecret: this._hmacSecret,
|
|
118
|
+
method,
|
|
119
|
+
path,
|
|
120
|
+
body,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── Sub-clientes ──────────────────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
class UsersClient {
|
|
128
|
+
/** @private */ constructor(client) { this._c = client; }
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Registra (u obtiene) un usuario del partner.
|
|
132
|
+
* Idempotente: si el external_user_id ya existe, devuelve el registro existente.
|
|
133
|
+
* @param {string} externalUserId - Identificador del usuario en tu sistema
|
|
134
|
+
* @returns {Promise<{id: number, partner_id: number, external_user_id: string, internal_user_id: number|null, status: string}>}
|
|
135
|
+
*/
|
|
136
|
+
async create(externalUserId) {
|
|
137
|
+
return this._c._req('POST', '/partner/v1/users', { external_user_id: externalUserId });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
class WalletsClient {
|
|
142
|
+
/** @private */ constructor(client) { this._c = client; }
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Crea una wallet on-chain para un usuario.
|
|
146
|
+
* @param {string} externalUserId
|
|
147
|
+
* @param {'bsc'|'polygon'|'btc'} [chain='bsc']
|
|
148
|
+
* @returns {Promise<{external_user_id: string, address: string, chain: string}>}
|
|
149
|
+
*/
|
|
150
|
+
async create(externalUserId, chain = 'bsc') {
|
|
151
|
+
return this._c._req('POST', '/partner/v1/wallets', { external_user_id: externalUserId, chain });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Consulta el saldo de un token en la wallet de un usuario.
|
|
156
|
+
* @param {string} externalUserId
|
|
157
|
+
* @param {{token?: string, chain?: string}} [opts]
|
|
158
|
+
* @returns {Promise<{external_user_id: string, token: string, chain: string, balance: string, address: string}>}
|
|
159
|
+
*/
|
|
160
|
+
async getBalance(externalUserId, { token = 'USDT', chain = 'bsc' } = {}) {
|
|
161
|
+
const qs = `token=${token}&chain=${chain}`;
|
|
162
|
+
return this._c._req('GET', `/partner/v1/wallets/${externalUserId}/balance?${qs}`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Obtiene la dirección de depósito. Si no existe wallet, la crea automáticamente.
|
|
167
|
+
* @param {string} externalUserId
|
|
168
|
+
* @param {{chain?: string}} [opts]
|
|
169
|
+
* @returns {Promise<{external_user_id: string, address: string, chain: string}>}
|
|
170
|
+
*/
|
|
171
|
+
async getAddress(externalUserId, { chain = 'bsc' } = {}) {
|
|
172
|
+
return this._c._req('GET', `/partner/v1/wallets/${externalUserId}/address?chain=${chain}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
class TransactionsClient {
|
|
177
|
+
/** @private */ constructor(client) { this._c = client; }
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Retira fondos hacia una dirección externa. Descuenta del Partner Treasury.
|
|
181
|
+
* @param {object} params
|
|
182
|
+
* @param {string} params.externalUserId
|
|
183
|
+
* @param {string} params.toAddress - Dirección de destino
|
|
184
|
+
* @param {string} params.amount - Monto (ej. "100.00")
|
|
185
|
+
* @param {string} [params.token='USDT']
|
|
186
|
+
* @param {'bsc'|'polygon'} [params.chain='bsc']
|
|
187
|
+
* @returns {Promise<{withdraw_id: string, tx_hash: string, status: string}>}
|
|
188
|
+
*/
|
|
189
|
+
async withdraw({ externalUserId, toAddress, amount, token = 'USDT', chain = 'bsc' }) {
|
|
190
|
+
return this._c._req('POST', '/partner/v1/transactions/withdraw', {
|
|
191
|
+
external_user_id: externalUserId,
|
|
192
|
+
to_address: toAddress,
|
|
193
|
+
amount,
|
|
194
|
+
token,
|
|
195
|
+
chain,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Transferencia interna instantánea entre dos usuarios del partner.
|
|
201
|
+
* @param {object} params
|
|
202
|
+
* @param {string} params.senderExternalUserId
|
|
203
|
+
* @param {string} params.receiverExternalUserId
|
|
204
|
+
* @param {string} params.amount
|
|
205
|
+
* @param {string} [params.token='USDT']
|
|
206
|
+
* @returns {Promise<{transfer_id: string, status: string}>}
|
|
207
|
+
*/
|
|
208
|
+
async transfer({ senderExternalUserId, receiverExternalUserId, amount, token = 'USDT' }) {
|
|
209
|
+
return this._c._req('POST', '/partner/v1/transactions/transfer', {
|
|
210
|
+
sender_external_user_id: senderExternalUserId,
|
|
211
|
+
receiver_external_user_id: receiverExternalUserId,
|
|
212
|
+
amount,
|
|
213
|
+
token,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
class ConversionClient {
|
|
219
|
+
/** @private */ constructor(client) { this._c = client; }
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Paso 1/4: Cotiza conversión GTQ↔USDT sin crear orden.
|
|
223
|
+
* @param {object} params
|
|
224
|
+
* @param {string} params.externalUserId
|
|
225
|
+
* @param {'GTQ'|'USDT'} params.baseAsset
|
|
226
|
+
* @param {'GTQ'|'USDT'} params.quoteAsset
|
|
227
|
+
* @param {number} params.amount
|
|
228
|
+
* @returns {Promise<{pair: string, estimated_amount_out: number, price_applied: number}>}
|
|
229
|
+
*/
|
|
230
|
+
async quote({ externalUserId, baseAsset, quoteAsset, amount }) {
|
|
231
|
+
const qs = `external_user_id=${externalUserId}&base_asset=${baseAsset}"e_asset=${quoteAsset}&amount=${amount}`;
|
|
232
|
+
return this._c._req('GET', `/partner/v1/conversion/quote?${qs}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Paso 2/4: Crea una orden de conversión en estado quoted.
|
|
237
|
+
* @param {object} params
|
|
238
|
+
* @param {string} params.externalUserId
|
|
239
|
+
* @param {'GTQ'|'USDT'} params.baseAsset
|
|
240
|
+
* @param {'GTQ'|'USDT'} params.quoteAsset
|
|
241
|
+
* @param {number} params.requestedAmount
|
|
242
|
+
* @param {'buy'|'sell'} params.side
|
|
243
|
+
* @returns {Promise<{order_id: string, status: string, quote_expires_at: string}>}
|
|
244
|
+
*/
|
|
245
|
+
async createOrder({ externalUserId, baseAsset, quoteAsset, requestedAmount, side }) {
|
|
246
|
+
return this._c._req('POST', '/partner/v1/conversion/orders', {
|
|
247
|
+
external_user_id: externalUserId,
|
|
248
|
+
base_asset: baseAsset,
|
|
249
|
+
quote_asset: quoteAsset,
|
|
250
|
+
requested_amount: requestedAmount,
|
|
251
|
+
side,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Paso 3/4: Ejecuta una orden de conversión.
|
|
257
|
+
* @param {string} externalUserId
|
|
258
|
+
* @param {string} orderId
|
|
259
|
+
* @returns {Promise<{order_id: string, status: string, executed_at: string}>}
|
|
260
|
+
*/
|
|
261
|
+
async execute(externalUserId, orderId) {
|
|
262
|
+
return this._c._req('POST', '/partner/v1/conversion/execute', {
|
|
263
|
+
external_user_id: externalUserId,
|
|
264
|
+
order_id: orderId,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Paso 4/4: Consulta el estado de una orden.
|
|
270
|
+
* @param {string} externalUserId
|
|
271
|
+
* @param {string} orderId
|
|
272
|
+
* @returns {Promise<{order_id: string, status: string, executed_amount: number}>}
|
|
273
|
+
*/
|
|
274
|
+
async getStatus(externalUserId, orderId) {
|
|
275
|
+
const qs = `external_user_id=${externalUserId}&order_id=${orderId}`;
|
|
276
|
+
return this._c._req('GET', `/partner/v1/conversion/status?${qs}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
class TreasuryClient {
|
|
281
|
+
/** @private */ constructor(client) { this._c = client; }
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Consulta el saldo del Partner Treasury (tu saldo prepagado en USD).
|
|
285
|
+
* @returns {Promise<{partner_id: number, available_balance_usd: number, reserved_balance_usd: number, tier: string}>}
|
|
286
|
+
*/
|
|
287
|
+
async getBalance() {
|
|
288
|
+
return this._c._req('GET', '/partner/v1/treasury/balance');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = { Client };
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bitalcer/partner-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Bitalcer Custody-as-a-Service Partner API — SDK oficial para JavaScript/TypeScript. Firma HMAC-SHA256 automática, tipado completo.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"files": ["index.js", "index.d.ts", "README.md"],
|
|
8
|
+
"keywords": ["bitalcer", "crypto", "custody", "wallet", "api", "partner", "hmac", "usdt", "remesas"],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/bitalcer/partner-api-js"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=16"
|
|
16
|
+
}
|
|
17
|
+
}
|