@caspay/sdk 1.0.4 → 1.1.1

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.
@@ -1,14 +1,10 @@
1
1
  import type { CasPayConfig } from '../types';
2
- /**
3
- * HTTP Client for CasPay API
4
- * Handles all API requests with authentication and error handling
5
- */
6
2
  export declare class HttpClient {
7
3
  private readonly baseUrl;
8
4
  private apiKey;
9
5
  private merchantId;
10
- private readonly SDK_VERSION;
11
6
  constructor(config: CasPayConfig);
12
7
  request<T>(method: string, path: string, body?: Record<string, any>): Promise<T>;
13
8
  getMerchantId(): string;
9
+ getBaseUrl(): string;
14
10
  }
@@ -0,0 +1,8 @@
1
+ import type { Wallet } from '../resources/wallet';
2
+ import type { TransferParams, TransferResult } from '../types';
3
+ export declare class Transfer {
4
+ private wallet;
5
+ private apiBaseUrl;
6
+ constructor(wallet: Wallet, apiBaseUrl: string);
7
+ execute(params: TransferParams): Promise<TransferResult>;
8
+ }
package/dist/index.d.ts CHANGED
@@ -1,38 +1,17 @@
1
1
  import { Payments } from './resources/payments';
2
+ import { Subscriptions } from './resources/subscriptions';
3
+ import { Wallet } from './resources/wallet';
2
4
  import type { CasPayConfig } from './types';
3
- /**
4
- * CasPay SDK
5
- * Official JavaScript/TypeScript SDK for CasPay payment gateway
6
- *
7
- * @example
8
- * ```typescript
9
- * import CasPay from '@caspay/sdk';
10
- *
11
- * const caspay = new CasPay({
12
- * apiKey: 'cp_live_...',
13
- * merchantId: 'MERCH_...'
14
- * });
15
- *
16
- * const payment = await caspay.payments.create({
17
- * senderAddress: '0x123...',
18
- * productId: 'prod_abc',
19
- * amount: 100
20
- * });
21
- * ```
22
- */
23
5
  export default class CasPay {
24
- /** Payments resource for creating and managing payments */
25
6
  payments: Payments;
7
+ subscriptions: Subscriptions;
8
+ wallet: Wallet;
26
9
  private client;
27
- /**
28
- * Create a new CasPay SDK instance
29
- * @param config - SDK configuration
30
- */
10
+ private transfer;
11
+ private config;
31
12
  constructor(config: CasPayConfig);
32
- /**
33
- * Get SDK version
34
- */
35
13
  static get version(): string;
14
+ getConfig(): CasPayConfig;
36
15
  }
37
16
  export { CasPay };
38
17
  export * from './types';
package/dist/index.esm.js CHANGED
@@ -1,14 +1,12 @@
1
- /**
2
- * HTTP Client for CasPay API
3
- * Handles all API requests with authentication and error handling
4
- */
1
+ import { PublicKey, ExecutableDeployItem, TransferDeployItem, DeployHeader, Deploy } from 'casper-js-sdk';
2
+
3
+ const SDK_VERSION = '1.1.1';
4
+
5
5
  class HttpClient {
6
6
  constructor(config) {
7
- this.baseUrl = 'https://caspay.link/api';
8
- this.SDK_VERSION = '1.0.4';
9
7
  this.apiKey = config.apiKey;
10
8
  this.merchantId = config.merchantId;
11
- // Validate required config
9
+ this.baseUrl = config.baseUrl || 'https://caspay.link/api';
12
10
  if (!this.apiKey) {
13
11
  throw new Error('CasPay SDK: apiKey is required');
14
12
  }
@@ -24,8 +22,8 @@ class HttpClient {
24
22
  headers: {
25
23
  'Content-Type': 'application/json',
26
24
  'X-CasPay-Key': this.apiKey,
27
- 'X-CasPay-SDK-Version': this.SDK_VERSION,
28
- 'User-Agent': `CasPay-SDK-JS/${this.SDK_VERSION}`,
25
+ 'X-CasPay-SDK-Version': SDK_VERSION,
26
+ 'User-Agent': `CasPay-SDK-JS/${SDK_VERSION}`,
29
27
  },
30
28
  body: body ? JSON.stringify(body) : undefined,
31
29
  });
@@ -41,11 +39,9 @@ class HttpClient {
41
39
  return data;
42
40
  }
43
41
  catch (error) {
44
- // Re-throw CasPay errors
45
42
  if (error.error && error.code) {
46
43
  throw error;
47
44
  }
48
- // Wrap network errors
49
45
  throw {
50
46
  error: error.message || 'Network error',
51
47
  code: 'NETWORK_ERROR',
@@ -56,35 +52,126 @@ class HttpClient {
56
52
  getMerchantId() {
57
53
  return this.merchantId;
58
54
  }
55
+ getBaseUrl() {
56
+ return this.baseUrl;
57
+ }
58
+ }
59
+
60
+ const CSPR_TO_MOTES = 1000000000;
61
+ const DEFAULT_PAYMENT_AMOUNT = '100000000';
62
+ class Transfer {
63
+ constructor(wallet, apiBaseUrl) {
64
+ this.wallet = wallet;
65
+ this.apiBaseUrl = apiBaseUrl;
66
+ }
67
+ async execute(params) {
68
+ const senderAddress = await this.wallet.getAddress();
69
+ if (!senderAddress) {
70
+ const error = {
71
+ code: 'WALLET_NOT_FOUND',
72
+ message: 'Please connect your wallet first.',
73
+ };
74
+ throw error;
75
+ }
76
+ const provider = this.wallet.getProvider();
77
+ if (!provider) {
78
+ const error = {
79
+ code: 'WALLET_NOT_FOUND',
80
+ message: 'Wallet provider not available.',
81
+ };
82
+ throw error;
83
+ }
84
+ const amountInMotes = Math.floor(params.amount * CSPR_TO_MOTES).toString();
85
+ const network = this.wallet.getNetwork();
86
+ const transferId = Date.now();
87
+ try {
88
+ const senderPublicKey = PublicKey.fromHex(senderAddress);
89
+ const recipientPublicKey = PublicKey.fromHex(params.recipientAddress);
90
+ const session = new ExecutableDeployItem();
91
+ session.transfer = TransferDeployItem.newTransfer(amountInMotes, recipientPublicKey, undefined, transferId);
92
+ const payment = ExecutableDeployItem.standardPayment(DEFAULT_PAYMENT_AMOUNT);
93
+ const deployHeader = DeployHeader.default();
94
+ deployHeader.account = senderPublicKey;
95
+ deployHeader.chainName = network;
96
+ const deploy = Deploy.makeDeploy(deployHeader, payment, session);
97
+ const deployJson = Deploy.toJSON(deploy);
98
+ const signResult = await provider.sign(JSON.stringify(deployJson), senderAddress);
99
+ if (signResult.cancelled) {
100
+ const error = {
101
+ code: 'TRANSFER_REJECTED',
102
+ message: 'Transfer was cancelled by the user.',
103
+ };
104
+ throw error;
105
+ }
106
+ const algorithmTag = senderAddress.substring(0, 2);
107
+ const signatureHex = typeof signResult.signature === 'string'
108
+ ? signResult.signature
109
+ : Array.from(signResult.signature)
110
+ .map((b) => b.toString(16).padStart(2, '0'))
111
+ .join('');
112
+ const signatureWithTag = algorithmTag + signatureHex;
113
+ const signedDeployJson = Deploy.toJSON(deploy);
114
+ signedDeployJson.approvals = [
115
+ {
116
+ signer: senderAddress,
117
+ signature: signatureWithTag,
118
+ },
119
+ ];
120
+ const isMainnet = network === 'casper';
121
+ const rpcProxyUrl = `${this.apiBaseUrl}/rpc`;
122
+ const response = await fetch(rpcProxyUrl, {
123
+ method: 'POST',
124
+ headers: {
125
+ 'Content-Type': 'application/json',
126
+ },
127
+ body: JSON.stringify({
128
+ deploy: signedDeployJson,
129
+ network: isMainnet ? 'mainnet' : 'testnet',
130
+ }),
131
+ });
132
+ const result = await response.json();
133
+ if (!response.ok || result.error) {
134
+ throw new Error(result.error || 'RPC request failed');
135
+ }
136
+ const deployHash = result.deploy_hash;
137
+ return {
138
+ deployHash,
139
+ senderAddress,
140
+ recipientAddress: params.recipientAddress,
141
+ amount: params.amount,
142
+ };
143
+ }
144
+ catch (error) {
145
+ if (error.code === 'TRANSFER_REJECTED') {
146
+ throw error;
147
+ }
148
+ if (error.cancelled || error.code === 2 || error.message?.includes('rejected') || error.message?.includes('cancel')) {
149
+ const walletError = {
150
+ code: 'TRANSFER_REJECTED',
151
+ message: 'Transfer was cancelled by the user.',
152
+ };
153
+ throw walletError;
154
+ }
155
+ const walletError = {
156
+ code: 'NETWORK_ERROR',
157
+ message: error.message || 'Failed to execute transfer.',
158
+ };
159
+ throw walletError;
160
+ }
161
+ }
59
162
  }
60
163
 
61
- /**
62
- * Payments Resource
63
- * Handle payment creation and verification
64
- */
65
164
  class Payments {
66
165
  constructor(client) {
166
+ this.wallet = null;
167
+ this.transfer = null;
67
168
  this.client = client;
68
169
  }
69
- /**
70
- * Create a new payment record
71
- *
72
- * @param params - Payment parameters
73
- * @returns Payment response with transaction details
74
- * @throws {CasPayError} If payment creation fails
75
- *
76
- * @example
77
- * ```typescript
78
- * const payment = await caspay.payments.create({
79
- * senderAddress: '0x123...',
80
- * productId: 'prod_abc123',
81
- * amount: 100,
82
- * currency: 'USD'
83
- * });
84
- * ```
85
- */
86
- async create(params) {
87
- // Validate required fields
170
+ setWallet(wallet, transfer) {
171
+ this.wallet = wallet;
172
+ this.transfer = transfer;
173
+ }
174
+ async recordPayment(params) {
88
175
  if (!params.senderAddress) {
89
176
  throw {
90
177
  error: 'senderAddress is required',
@@ -117,42 +204,353 @@ class Payments {
117
204
  };
118
205
  return this.client.request('POST', '/v1/payments/record', payload);
119
206
  }
207
+ async recordSubscription(params) {
208
+ if (!params.subscriptionPlanId) {
209
+ throw {
210
+ error: 'subscriptionPlanId is required for subscription recording',
211
+ code: 'INVALID_PARAMS',
212
+ status: 400,
213
+ };
214
+ }
215
+ return this.recordPayment(params);
216
+ }
217
+ async makePayment(params) {
218
+ if (!this.wallet || !this.transfer) {
219
+ throw {
220
+ error: 'Wallet not initialized. Make sure to use the SDK in browser environment.',
221
+ code: 'WALLET_NOT_INITIALIZED',
222
+ status: 500,
223
+ };
224
+ }
225
+ if (!params.amount || params.amount <= 0) {
226
+ throw {
227
+ error: 'amount must be greater than 0',
228
+ code: 'INVALID_PARAMS',
229
+ status: 400,
230
+ };
231
+ }
232
+ if (!params.productId && !params.subscriptionPlanId) {
233
+ throw {
234
+ error: 'Either productId or subscriptionPlanId is required',
235
+ code: 'INVALID_PARAMS',
236
+ status: 400,
237
+ };
238
+ }
239
+ try {
240
+ const isConnected = await this.wallet.isConnected();
241
+ if (!isConnected) {
242
+ await this.wallet.connect();
243
+ }
244
+ const senderAddress = await this.wallet.getAddress();
245
+ if (!senderAddress) {
246
+ throw {
247
+ error: 'Failed to get wallet address',
248
+ code: 'WALLET_ERROR',
249
+ status: 500,
250
+ };
251
+ }
252
+ const merchantWalletAddress = this.wallet.getMerchantWalletAddress();
253
+ const transferResult = await this.transfer.execute({
254
+ recipientAddress: merchantWalletAddress,
255
+ amount: params.amount
256
+ });
257
+ try {
258
+ const paymentRecord = await this.recordPayment({
259
+ senderAddress: senderAddress,
260
+ transactionHash: transferResult.deployHash,
261
+ productId: params.productId,
262
+ subscriptionPlanId: params.subscriptionPlanId,
263
+ amount: params.amount,
264
+ currency: params.currency || 'CSPR',
265
+ });
266
+ return {
267
+ success: true,
268
+ transactionHash: transferResult.deployHash,
269
+ payment: paymentRecord,
270
+ };
271
+ }
272
+ catch (recordError) {
273
+ return {
274
+ success: true,
275
+ transactionHash: transferResult.deployHash,
276
+ error: `Payment transferred but recording failed: ${recordError.error || recordError.message}`,
277
+ };
278
+ }
279
+ }
280
+ catch (error) {
281
+ return {
282
+ success: false,
283
+ transactionHash: '',
284
+ error: error.message || error.error || 'Payment failed',
285
+ };
286
+ }
287
+ }
288
+ }
289
+
290
+ class Subscriptions {
291
+ constructor(client) {
292
+ this.client = client;
293
+ }
294
+ async checkStatus(params) {
295
+ if (!params.subscriberAddress) {
296
+ throw {
297
+ error: 'subscriberAddress is required',
298
+ code: 'INVALID_PARAMS',
299
+ status: 400,
300
+ };
301
+ }
302
+ const merchantId = this.client.getMerchantId();
303
+ let url = `/v1/subscriptions/check/?merchant_id=${merchantId}&subscriber=${params.subscriberAddress}`;
304
+ if (params.planId) {
305
+ url += `&plan_id=${params.planId}`;
306
+ }
307
+ return this.client.request('GET', url);
308
+ }
309
+ }
310
+
311
+ const CASPER_WALLET_INSTALL_URL = 'https://www.casperwallet.io/';
312
+ class Wallet {
313
+ constructor(config) {
314
+ this.provider = null;
315
+ this.connected = false;
316
+ this.activeAddress = null;
317
+ this.config = config;
318
+ this.initProvider();
319
+ }
320
+ initProvider() {
321
+ if (typeof window === 'undefined')
322
+ return;
323
+ const CasperWalletProvider = window.CasperWalletProvider;
324
+ if (CasperWalletProvider) {
325
+ this.provider = CasperWalletProvider({ timeout: 30 * 60 * 1000 });
326
+ this.setupEventListeners();
327
+ }
328
+ }
329
+ setupEventListeners() {
330
+ if (typeof window === 'undefined')
331
+ return;
332
+ window.addEventListener('casper-wallet:connected', (event) => {
333
+ try {
334
+ const state = JSON.parse(event.detail);
335
+ this.connected = true;
336
+ this.activeAddress = state.activeKey || null;
337
+ }
338
+ catch (e) {
339
+ }
340
+ });
341
+ window.addEventListener('casper-wallet:disconnected', () => {
342
+ this.connected = false;
343
+ this.activeAddress = null;
344
+ });
345
+ window.addEventListener('casper-wallet:activeKeyChanged', (event) => {
346
+ try {
347
+ const state = JSON.parse(event.detail);
348
+ this.activeAddress = state.activeKey || null;
349
+ }
350
+ catch (e) {
351
+ }
352
+ });
353
+ window.addEventListener('casper-wallet:locked', () => {
354
+ this.connected = false;
355
+ });
356
+ window.addEventListener('casper-wallet:unlocked', async () => {
357
+ if (this.provider) {
358
+ try {
359
+ const isConnected = await this.provider.isConnected();
360
+ this.connected = isConnected;
361
+ if (isConnected) {
362
+ this.activeAddress = await this.provider.getActivePublicKey();
363
+ }
364
+ }
365
+ catch (e) {
366
+ }
367
+ }
368
+ });
369
+ }
370
+ isAvailable() {
371
+ return typeof window !== 'undefined' && !!window.CasperWalletProvider;
372
+ }
373
+ async isConnected() {
374
+ if (!this.provider) {
375
+ this.connected = false;
376
+ return false;
377
+ }
378
+ try {
379
+ const connected = await this.provider.isConnected();
380
+ this.connected = connected;
381
+ return connected;
382
+ }
383
+ catch (error) {
384
+ this.connected = false;
385
+ if (error.code === 1) {
386
+ return false;
387
+ }
388
+ return false;
389
+ }
390
+ }
391
+ async connect() {
392
+ if (!this.isAvailable()) {
393
+ const error = {
394
+ code: 'WALLET_NOT_FOUND',
395
+ message: 'Casper Wallet extension not found. Please install it first.',
396
+ installUrl: CASPER_WALLET_INSTALL_URL,
397
+ };
398
+ throw error;
399
+ }
400
+ if (!this.provider) {
401
+ this.initProvider();
402
+ }
403
+ if (!this.provider) {
404
+ const error = {
405
+ code: 'WALLET_NOT_FOUND',
406
+ message: 'Failed to initialize Casper Wallet provider.',
407
+ installUrl: CASPER_WALLET_INSTALL_URL,
408
+ };
409
+ throw error;
410
+ }
411
+ try {
412
+ const connected = await this.provider.requestConnection();
413
+ if (!connected) {
414
+ const error = {
415
+ code: 'CONNECTION_REJECTED',
416
+ message: 'Wallet connection was rejected by the user.',
417
+ };
418
+ throw error;
419
+ }
420
+ this.connected = true;
421
+ this.activeAddress = await this.provider.getActivePublicKey();
422
+ if (!this.activeAddress) {
423
+ const error = {
424
+ code: 'UNKNOWN_ERROR',
425
+ message: 'Failed to get wallet address after connection.',
426
+ };
427
+ throw error;
428
+ }
429
+ return this.activeAddress;
430
+ }
431
+ catch (error) {
432
+ if (error.code === 'CONNECTION_REJECTED') {
433
+ throw error;
434
+ }
435
+ if (error.code === 1) {
436
+ const walletError = {
437
+ code: 'WALLET_LOCKED',
438
+ message: 'Wallet is locked. Please unlock your Casper Wallet and try again.',
439
+ };
440
+ throw walletError;
441
+ }
442
+ const walletError = {
443
+ code: 'UNKNOWN_ERROR',
444
+ message: error.message || 'Failed to connect to wallet.',
445
+ };
446
+ throw walletError;
447
+ }
448
+ }
449
+ async disconnect() {
450
+ if (this.provider) {
451
+ try {
452
+ await this.provider.disconnectFromSite();
453
+ }
454
+ catch (e) {
455
+ }
456
+ }
457
+ this.connected = false;
458
+ this.activeAddress = null;
459
+ }
460
+ async getAddress() {
461
+ if (!this.provider) {
462
+ return null;
463
+ }
464
+ try {
465
+ const isConnected = await this.isConnected();
466
+ if (!isConnected) {
467
+ return null;
468
+ }
469
+ this.activeAddress = await this.provider.getActivePublicKey();
470
+ return this.activeAddress;
471
+ }
472
+ catch (error) {
473
+ return null;
474
+ }
475
+ }
476
+ getInfo() {
477
+ return {
478
+ isConnected: this.connected,
479
+ address: this.activeAddress,
480
+ };
481
+ }
482
+ async getState() {
483
+ const connected = await this.isConnected();
484
+ const address = connected ? await this.getAddress() : null;
485
+ return {
486
+ connected,
487
+ address,
488
+ locked: !connected && this.isAvailable(),
489
+ };
490
+ }
491
+ getProvider() {
492
+ return this.provider;
493
+ }
494
+ getMerchantWalletAddress() {
495
+ return this.config.walletAddress;
496
+ }
497
+ getNetwork() {
498
+ return this.config.network === 'mainnet' ? 'casper' : 'casper-test';
499
+ }
500
+ async signDeploy(deploy) {
501
+ if (!this.provider) {
502
+ const error = {
503
+ code: 'WALLET_NOT_FOUND',
504
+ message: 'Casper Wallet not available.',
505
+ installUrl: CASPER_WALLET_INSTALL_URL,
506
+ };
507
+ throw error;
508
+ }
509
+ const isConnected = await this.isConnected();
510
+ if (!isConnected) {
511
+ await this.connect();
512
+ }
513
+ try {
514
+ const deployJson = JSON.stringify(deploy);
515
+ const signature = await this.provider.sign(deployJson, this.activeAddress);
516
+ return signature;
517
+ }
518
+ catch (error) {
519
+ if (error.code === 2 || error.message?.includes('rejected') || error.message?.includes('cancelled')) {
520
+ const walletError = {
521
+ code: 'TRANSFER_REJECTED',
522
+ message: 'Transaction was rejected by the user.',
523
+ };
524
+ throw walletError;
525
+ }
526
+ const walletError = {
527
+ code: 'UNKNOWN_ERROR',
528
+ message: error.message || 'Failed to sign deploy.',
529
+ };
530
+ throw walletError;
531
+ }
532
+ }
120
533
  }
121
534
 
122
- /**
123
- * CasPay SDK
124
- * Official JavaScript/TypeScript SDK for CasPay payment gateway
125
- *
126
- * @example
127
- * ```typescript
128
- * import CasPay from '@caspay/sdk';
129
- *
130
- * const caspay = new CasPay({
131
- * apiKey: 'cp_live_...',
132
- * merchantId: 'MERCH_...'
133
- * });
134
- *
135
- * const payment = await caspay.payments.create({
136
- * senderAddress: '0x123...',
137
- * productId: 'prod_abc',
138
- * amount: 100
139
- * });
140
- * ```
141
- */
142
535
  class CasPay {
143
- /**
144
- * Create a new CasPay SDK instance
145
- * @param config - SDK configuration
146
- */
147
536
  constructor(config) {
537
+ if (!config.walletAddress) {
538
+ throw new Error('CasPay SDK: walletAddress is required');
539
+ }
540
+ this.config = config;
148
541
  this.client = new HttpClient(config);
542
+ this.wallet = new Wallet(config);
543
+ const apiBaseUrl = this.client.getBaseUrl();
544
+ this.transfer = new Transfer(this.wallet, apiBaseUrl);
149
545
  this.payments = new Payments(this.client);
546
+ this.payments.setWallet(this.wallet, this.transfer);
547
+ this.subscriptions = new Subscriptions(this.client);
150
548
  }
151
- /**
152
- * Get SDK version
153
- */
154
549
  static get version() {
155
- return '1.0.4';
550
+ return SDK_VERSION;
551
+ }
552
+ getConfig() {
553
+ return { ...this.config };
156
554
  }
157
555
  }
158
556