@profullstack/coinpay 0.6.11 → 0.9.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@profullstack/coinpay",
3
- "version": "0.6.11",
4
- "description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
3
+ "version": "0.9.0",
4
+ "description": "CoinPay SDK & CLI \u2014 Accept cryptocurrency and card payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet, swap and a live finances dashboard",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./src/index.d.ts",
@@ -17,6 +17,10 @@
17
17
  "import": "./src/payments.js",
18
18
  "types": "./src/payments.d.ts"
19
19
  },
20
+ "./tokens": {
21
+ "import": "./src/tokens.js",
22
+ "types": "./src/tokens.d.ts"
23
+ },
20
24
  "./card-payments": {
21
25
  "import": "./src/card-payments.js",
22
26
  "types": "./src/card-payments.d.ts"
@@ -32,6 +36,28 @@
32
36
  "./swap": {
33
37
  "import": "./src/swap.js",
34
38
  "types": "./src/swap.d.ts"
39
+ },
40
+ "./x402": {
41
+ "import": "./src/x402.js"
42
+ },
43
+ "./x402-v2": {
44
+ "import": "./src/x402-v2.js"
45
+ },
46
+ "./x402-browser": {
47
+ "import": "./src/x402-browser.js"
48
+ },
49
+ "./x402-pay-server": {
50
+ "import": "./src/x402-pay-server.js"
51
+ },
52
+ "./taskmarket": {
53
+ "import": "./src/taskmarket.js"
54
+ },
55
+ "./finances": {
56
+ "import": "./src/finances.js",
57
+ "types": "./src/finances.d.ts"
58
+ },
59
+ "./finances-tui": {
60
+ "import": "./src/finances-tui.js"
35
61
  }
36
62
  },
37
63
  "files": [
@@ -70,7 +96,12 @@
70
96
  "payment-gateway",
71
97
  "merchant",
72
98
  "bip39",
73
- "mnemonic"
99
+ "mnemonic",
100
+ "finances",
101
+ "tui",
102
+ "dashboard",
103
+ "plaid",
104
+ "simplefin"
74
105
  ],
75
106
  "author": "Profullstack, Inc.",
76
107
  "license": "MIT",
@@ -87,15 +118,16 @@
87
118
  "node": ">=20.0.0"
88
119
  },
89
120
  "devDependencies": {
90
- "vitest": "^2.1.8",
91
121
  "eslint": "^8.57.0",
92
- "prettier": "^3.4.1"
122
+ "prettier": "^3.4.1",
123
+ "vitest": "^4.1.0"
93
124
  },
94
- "peerDependencies": {},
95
125
  "dependencies": {
96
- "@scure/bip39": "^1.4.0",
97
- "@scure/bip32": "^1.5.0",
126
+ "@inquirer/prompts": "^8.3.0",
98
127
  "@noble/curves": "^1.6.0",
99
- "@noble/hashes": "^1.5.0"
128
+ "@noble/hashes": "^1.5.0",
129
+ "@profullstack/hqtui": "^0.1.11",
130
+ "@scure/bip32": "^1.5.0",
131
+ "@scure/bip39": "^1.4.0"
100
132
  }
101
133
  }
package/src/auth.js CHANGED
@@ -58,7 +58,8 @@ export async function loginMerchant(client, { email, password }) {
58
58
  * @returns {Promise<Object>} Merchant information
59
59
  */
60
60
  export async function getMe(client) {
61
+ // GET — the /auth/me endpoint is GET-only (a POST returns 405).
61
62
  return client.request('/auth/me', {
62
- method: 'POST',
63
+ method: 'GET',
63
64
  });
64
65
  }
@@ -309,13 +309,21 @@ export async function createCardEscrow(client, businessId, amountUSD, descriptio
309
309
  // Convert USD to cents
310
310
  const amountCents = Math.round(amountUSD * 100);
311
311
 
312
- return client.request('POST', '/api/stripe/payments/create', {
313
- businessId,
314
- amount: amountCents,
315
- currency: 'usd',
316
- description,
317
- metadata,
318
- escrowMode: true,
312
+ // `CoinPayClient.request(endpoint, options)` takes TWO arguments. Every call
313
+ // in this file passed three, in the shape `request(method, path, body)` — so
314
+ // `endpoint` received 'POST', the URL became `baseUrl + 'POST'`, and `options`
315
+ // received the path as a string. These calls failed 100% of the time, which
316
+ // made releasing or refunding a card escrow unreachable through the SDK.
317
+ return client.request('/api/stripe/payments/create', {
318
+ method: 'POST',
319
+ body: JSON.stringify({
320
+ businessId,
321
+ amount: amountCents,
322
+ currency: 'usd',
323
+ description,
324
+ metadata,
325
+ escrowMode: true,
326
+ }),
319
327
  });
320
328
  }
321
329
 
@@ -346,7 +354,7 @@ export async function listCardEscrows(client, options = {}) {
346
354
  const queryString = queryParams.toString();
347
355
  const url = `/api/stripe/escrows${queryString ? `?${queryString}` : ''}`;
348
356
 
349
- return client.request('GET', url);
357
+ return client.request(url, { method: 'GET' });
350
358
  }
351
359
 
352
360
  /**
@@ -360,8 +368,9 @@ export async function listCardEscrows(client, options = {}) {
360
368
  * const result = await releaseCardEscrow(client, 'escrow-123');
361
369
  */
362
370
  export async function releaseCardEscrow(client, escrowId) {
363
- return client.request('POST', '/api/stripe/escrow/release', {
364
- escrowId,
371
+ return client.request('/api/stripe/escrow/release', {
372
+ method: 'POST',
373
+ body: JSON.stringify({ escrowId }),
365
374
  });
366
375
  }
367
376
 
@@ -386,9 +395,9 @@ export async function releaseCardEscrow(client, escrowId) {
386
395
  * });
387
396
  */
388
397
  export async function refundCardEscrow(client, escrowId, options = {}) {
389
- return client.request('POST', '/api/stripe/escrow/refund', {
390
- escrowId,
391
- ...options,
398
+ return client.request('/api/stripe/escrow/refund', {
399
+ method: 'POST',
400
+ body: JSON.stringify({ escrowId, ...options }),
392
401
  });
393
402
  }
394
403
 
@@ -404,7 +413,7 @@ export async function refundCardEscrow(client, escrowId, options = {}) {
404
413
  * console.log(status.escrow_status); // 'pending', 'released', 'refunded'
405
414
  */
406
415
  export async function getCardEscrowStatus(client, escrowId) {
407
- return client.request('GET', `/api/stripe/transactions/${escrowId}`);
416
+ return client.request(`/api/stripe/transactions/${escrowId}`, { method: 'GET' });
408
417
  }
409
418
 
410
419
  /**
package/src/client.d.ts CHANGED
@@ -41,6 +41,14 @@ export interface ListPaymentsParams {
41
41
  offset?: number;
42
42
  }
43
43
 
44
+ /** Parameters for supported coin/token discovery */
45
+ export interface SupportedCoinsParams {
46
+ /** Business ID. Required for merchant JWTs; optional with business API keys if it matches key scope. */
47
+ businessId?: string;
48
+ /** If true, only active wallets are returned. */
49
+ activeOnly?: boolean;
50
+ }
51
+
44
52
  /** Options for the `waitForPayment` polling method */
45
53
  export interface WaitForPaymentOptions {
46
54
  /** Polling interval in milliseconds (default: `5000`) */
@@ -109,6 +117,36 @@ export interface ListPaymentsResponse {
109
117
  payments: Payment[];
110
118
  }
111
119
 
120
+ /** Supported payment coin record */
121
+ export interface SupportedCoin {
122
+ symbol: string;
123
+ name: string;
124
+ is_active: boolean;
125
+ has_wallet: boolean;
126
+ wallet_source: 'business' | 'merchant_global';
127
+ }
128
+
129
+ /** Checkout token record with lower-case code accepted by createPayment currency */
130
+ export interface SupportedToken extends SupportedCoin {
131
+ code: string;
132
+ ticker: string;
133
+ chain?: string;
134
+ }
135
+
136
+ /** Response from supported coin discovery */
137
+ export interface SupportedCoinsResponse {
138
+ success: boolean;
139
+ coins: SupportedCoin[];
140
+ business_id: string;
141
+ merchant_id?: string;
142
+ total: number;
143
+ }
144
+
145
+ /** Response from token discovery */
146
+ export interface TokensResponse extends SupportedCoinsResponse {
147
+ tokens: SupportedToken[];
148
+ }
149
+
112
150
  /**
113
151
  * CoinPay API Client
114
152
  *
@@ -186,6 +224,20 @@ export class CoinPayClient {
186
224
  */
187
225
  listPayments(params: ListPaymentsParams): Promise<ListPaymentsResponse>;
188
226
 
227
+ /**
228
+ * List supported payment coins for a business.
229
+ *
230
+ * Business wallets win; merchant global wallets are used as fallback.
231
+ */
232
+ getSupportedCoins(params?: SupportedCoinsParams): Promise<SupportedCoinsResponse>;
233
+
234
+ /**
235
+ * List checkout-friendly tokens for a business.
236
+ *
237
+ * Returns lower-case `code` values accepted by `createPayment({ currency })`.
238
+ */
239
+ getTokens(params?: SupportedCoinsParams): Promise<TokensResponse>;
240
+
189
241
  /**
190
242
  * Get a URL pointing to the QR code image for a payment.
191
243
  *
package/src/client.js CHANGED
@@ -279,6 +279,45 @@ export class CoinPayClient {
279
279
  return this.request(`/payments?${params.toString()}`);
280
280
  }
281
281
 
282
+ /**
283
+ * Get supported payment coins for a business.
284
+ *
285
+ * Business API keys derive the business from the key. Passing businessId is
286
+ * still allowed and must match the key scope. Merchant JWTs require
287
+ * businessId.
288
+ *
289
+ * @param {Object} [params]
290
+ * @param {string} [params.businessId] - Business ID
291
+ * @param {boolean} [params.activeOnly] - Only return active wallets
292
+ * @returns {Promise<Object>} Supported coins response
293
+ */
294
+ async getSupportedCoins({ businessId, activeOnly } = {}) {
295
+ const params = new URLSearchParams();
296
+ if (businessId) params.set('business_id', businessId);
297
+ if (activeOnly) params.set('active_only', 'true');
298
+ const query = params.toString();
299
+ return this.request(`/supported-coins${query ? `?${query}` : ''}`);
300
+ }
301
+
302
+ /**
303
+ * Get payment-option tokens for a business.
304
+ *
305
+ * Returns lower-case `code` values accepted by /payments/create, plus
306
+ * display fields for checkout coin pickers.
307
+ *
308
+ * @param {Object} [params]
309
+ * @param {string} [params.businessId] - Business ID
310
+ * @param {boolean} [params.activeOnly] - Only return active wallets
311
+ * @returns {Promise<Object>} Tokens response
312
+ */
313
+ async getTokens({ businessId, activeOnly } = {}) {
314
+ const params = new URLSearchParams();
315
+ if (businessId) params.set('business_id', businessId);
316
+ if (activeOnly) params.set('active_only', 'true');
317
+ const query = params.toString();
318
+ return this.request(`/tokens${query ? `?${query}` : ''}`);
319
+ }
320
+
282
321
  /**
283
322
  * Get payment QR code URL
284
323
  *
@@ -415,23 +454,61 @@ export class CoinPayClient {
415
454
 
416
455
  /**
417
456
  * Create a new business
457
+ *
458
+ * Field names are snake_case because that is what the API reads. This used to
459
+ * send `webhookUrl`, which POST /api/businesses does not look at -- it reads
460
+ * `input.webhook_url` -- so every business created through the SDK came back
461
+ * with a null webhook_url and no webhook secret, silently. The value was
462
+ * accepted, echoed nowhere, and dropped.
463
+ *
464
+ * `category` is required by the API and was not sent at all, so
465
+ * `coinpay business create` failed outright with "Select a valid business
466
+ * category" and there was no flag to supply one. Valid slugs live in
467
+ * src/lib/business/taxonomy.ts.
468
+ *
418
469
  * @param {Object} params - Business parameters
419
470
  * @param {string} params.name - Business name
471
+ * @param {string} params.category - Taxonomy slug; required by the API
472
+ * @param {string} [params.description]
420
473
  * @param {string} [params.webhookUrl] - Webhook URL
474
+ * @param {string} [params.webhookSecret] - Supply one, or the API generates it
421
475
  * @param {Object} [params.walletAddresses] - Wallet addresses by chain
422
476
  * @returns {Promise<Object>} Created business
423
477
  */
424
- async createBusiness({ name, webhookUrl, walletAddresses }) {
478
+ async createBusiness({
479
+ name,
480
+ category,
481
+ description,
482
+ webhookUrl,
483
+ webhookSecret,
484
+ walletAddresses,
485
+ }) {
425
486
  return this.request('/businesses', {
426
487
  method: 'POST',
427
488
  body: JSON.stringify({
428
489
  name,
429
- webhookUrl,
490
+ category,
491
+ description,
492
+ webhook_url: webhookUrl,
493
+ webhook_secret: webhookSecret,
430
494
  walletAddresses,
431
495
  }),
432
496
  });
433
497
  }
434
498
 
499
+ /**
500
+ * The taxonomy a business may be created with.
501
+ *
502
+ * Fetched rather than bundled: a copy inside the SDK goes stale the moment a
503
+ * category is added, and a stale copy is how "Select a valid business category"
504
+ * happens a second time.
505
+ *
506
+ * @returns {Promise<Object>} { success, categories: [{ slug, label, group, baseRisk }] }
507
+ */
508
+ async listBusinessCategories() {
509
+ return this.request('/businesses/categories', { method: 'GET' });
510
+ }
511
+
435
512
  /**
436
513
  * Update business
437
514
  * @param {string} businessId - Business ID
@@ -685,22 +762,29 @@ export class CoinPayClient {
685
762
 
686
763
  /**
687
764
  * Create Stripe Connect onboarding link
688
- *
765
+ *
689
766
  * Generates a Stripe Express onboarding link for a merchant.
690
767
  * The merchant must complete this onboarding before they can accept card payments.
691
- *
768
+ *
769
+ * Country is required on the first onboarding call and is locked at Stripe
770
+ * account creation — it cannot be changed afterward. Subsequent calls (e.g.
771
+ * to finish remaining requirements) may omit it; the server reuses the
772
+ * country stored on the business. All Stripe Connect supported countries are
773
+ * accepted (US, CA, GB, AU, DE, FR, JP, SG, ...). See
774
+ * https://stripe.com/global for the full list.
775
+ *
692
776
  * @param {string} businessId - Business ID
693
777
  * @param {Object} [params] - Optional parameters
694
778
  * @param {string} [params.email] - Merchant email (pre-fills onboarding form)
695
- * @param {string} [params.country='US'] - Country code (US, CA, GB, etc.)
779
+ * @param {string} [params.country] - ISO-3166-1 alpha-2 country code (e.g. 'US', 'CA', 'GB'). Required on first onboarding.
696
780
  * @returns {Promise<Object>} Onboarding link and account ID
697
- *
781
+ *
698
782
  * @example
699
783
  * const onboarding = await client.createStripeOnboardingLink('business-id', {
700
784
  * email: 'merchant@example.com',
701
- * country: 'US'
785
+ * country: 'CA'
702
786
  * });
703
- *
787
+ *
704
788
  * // Redirect merchant to onboarding.onboarding_url
705
789
  */
706
790
  async createStripeOnboardingLink(businessId, params = {}) {
@@ -913,4 +997,4 @@ export class CoinPayClient {
913
997
  }
914
998
  }
915
999
 
916
- export default CoinPayClient;
1000
+ export default CoinPayClient;