velirapay 0.1.0 → 0.2.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +699 -51
  3. package/dist/cjs/client.d.ts +1 -1
  4. package/dist/cjs/enums.d.ts +159 -27
  5. package/dist/cjs/enums.js +150 -25
  6. package/dist/cjs/errors.d.ts +10 -1
  7. package/dist/cjs/errors.js +12 -1
  8. package/dist/cjs/http/transport.js +18 -3
  9. package/dist/cjs/index.d.ts +4 -4
  10. package/dist/cjs/index.js +12 -2
  11. package/dist/cjs/page.d.ts +14 -2
  12. package/dist/cjs/page.js +19 -2
  13. package/dist/cjs/params.d.ts +17 -10
  14. package/dist/cjs/resources/account.d.ts +13 -13
  15. package/dist/cjs/resources/account.js +7 -7
  16. package/dist/cjs/resources/activity.d.ts +4 -3
  17. package/dist/cjs/resources/activity.js +1 -1
  18. package/dist/cjs/resources/api-key.d.ts +3 -2
  19. package/dist/cjs/resources/api-resource.d.ts +2 -0
  20. package/dist/cjs/resources/api-resource.js +5 -0
  21. package/dist/cjs/resources/charge.d.ts +10 -2
  22. package/dist/cjs/resources/charge.js +6 -0
  23. package/dist/cjs/resources/coupon.d.ts +2 -1
  24. package/dist/cjs/resources/event.d.ts +3 -3
  25. package/dist/cjs/resources/event.js +1 -1
  26. package/dist/cjs/resources/invoice.d.ts +4 -4
  27. package/dist/cjs/resources/member.d.ts +5 -4
  28. package/dist/cjs/resources/member.js +2 -2
  29. package/dist/cjs/resources/overview.d.ts +116 -4
  30. package/dist/cjs/resources/overview.js +76 -3
  31. package/dist/cjs/resources/payment-link.d.ts +3 -3
  32. package/dist/cjs/resources/payout.d.ts +5 -5
  33. package/dist/cjs/resources/payout.js +1 -1
  34. package/dist/cjs/resources/pro-payment.d.ts +3 -2
  35. package/dist/cjs/resources/supported-asset.d.ts +2 -2
  36. package/dist/cjs/resources/webhook-endpoint.d.ts +5 -4
  37. package/dist/cjs/resources/webhook-endpoint.js +3 -2
  38. package/dist/cjs/services/account.js +1 -1
  39. package/dist/cjs/services/api-keys.d.ts +7 -1
  40. package/dist/cjs/services/api-keys.js +7 -1
  41. package/dist/cjs/services/assets.d.ts +3 -4
  42. package/dist/cjs/services/assets.js +3 -2
  43. package/dist/cjs/services/charges.d.ts +10 -10
  44. package/dist/cjs/services/charges.js +12 -8
  45. package/dist/cjs/services/coupons.js +1 -1
  46. package/dist/cjs/services/invoices.js +5 -1
  47. package/dist/cjs/services/members.d.ts +2 -2
  48. package/dist/cjs/services/members.js +2 -2
  49. package/dist/cjs/services/overview.d.ts +1 -1
  50. package/dist/cjs/services/overview.js +3 -2
  51. package/dist/cjs/services/payment-links.js +4 -2
  52. package/dist/cjs/services/payout-addresses.d.ts +9 -4
  53. package/dist/cjs/services/payout-addresses.js +6 -2
  54. package/dist/cjs/services/service.d.ts +8 -3
  55. package/dist/cjs/services/service.js +45 -10
  56. package/dist/cjs/services/webhook-endpoints.d.ts +15 -2
  57. package/dist/cjs/services/webhook-endpoints.js +15 -2
  58. package/dist/cjs/version.d.ts +1 -1
  59. package/dist/cjs/version.js +1 -1
  60. package/dist/esm/client.d.ts +1 -1
  61. package/dist/esm/enums.d.ts +159 -27
  62. package/dist/esm/enums.js +149 -24
  63. package/dist/esm/errors.d.ts +10 -1
  64. package/dist/esm/errors.js +12 -1
  65. package/dist/esm/http/transport.js +18 -3
  66. package/dist/esm/index.d.ts +4 -4
  67. package/dist/esm/index.js +3 -3
  68. package/dist/esm/page.d.ts +14 -2
  69. package/dist/esm/page.js +17 -1
  70. package/dist/esm/params.d.ts +17 -10
  71. package/dist/esm/resources/account.d.ts +13 -13
  72. package/dist/esm/resources/account.js +8 -8
  73. package/dist/esm/resources/activity.d.ts +4 -3
  74. package/dist/esm/resources/activity.js +1 -1
  75. package/dist/esm/resources/api-key.d.ts +3 -2
  76. package/dist/esm/resources/api-resource.d.ts +2 -0
  77. package/dist/esm/resources/api-resource.js +4 -0
  78. package/dist/esm/resources/charge.d.ts +10 -2
  79. package/dist/esm/resources/charge.js +6 -0
  80. package/dist/esm/resources/coupon.d.ts +2 -1
  81. package/dist/esm/resources/event.d.ts +3 -3
  82. package/dist/esm/resources/event.js +1 -1
  83. package/dist/esm/resources/invoice.d.ts +4 -4
  84. package/dist/esm/resources/member.d.ts +5 -4
  85. package/dist/esm/resources/member.js +2 -2
  86. package/dist/esm/resources/overview.d.ts +116 -4
  87. package/dist/esm/resources/overview.js +77 -4
  88. package/dist/esm/resources/payment-link.d.ts +3 -3
  89. package/dist/esm/resources/payout.d.ts +5 -5
  90. package/dist/esm/resources/payout.js +1 -1
  91. package/dist/esm/resources/pro-payment.d.ts +3 -2
  92. package/dist/esm/resources/supported-asset.d.ts +2 -2
  93. package/dist/esm/resources/webhook-endpoint.d.ts +5 -4
  94. package/dist/esm/resources/webhook-endpoint.js +3 -2
  95. package/dist/esm/services/account.js +2 -2
  96. package/dist/esm/services/api-keys.d.ts +7 -1
  97. package/dist/esm/services/api-keys.js +7 -1
  98. package/dist/esm/services/assets.d.ts +3 -4
  99. package/dist/esm/services/assets.js +3 -2
  100. package/dist/esm/services/charges.d.ts +10 -10
  101. package/dist/esm/services/charges.js +13 -9
  102. package/dist/esm/services/coupons.js +2 -2
  103. package/dist/esm/services/invoices.js +6 -2
  104. package/dist/esm/services/members.d.ts +2 -2
  105. package/dist/esm/services/members.js +2 -2
  106. package/dist/esm/services/overview.d.ts +1 -1
  107. package/dist/esm/services/overview.js +4 -3
  108. package/dist/esm/services/payment-links.js +5 -3
  109. package/dist/esm/services/payout-addresses.d.ts +9 -4
  110. package/dist/esm/services/payout-addresses.js +6 -2
  111. package/dist/esm/services/service.d.ts +8 -3
  112. package/dist/esm/services/service.js +44 -10
  113. package/dist/esm/services/webhook-endpoints.d.ts +15 -2
  114. package/dist/esm/services/webhook-endpoints.js +15 -2
  115. package/dist/esm/version.d.ts +1 -1
  116. package/dist/esm/version.js +1 -1
  117. package/package.json +12 -2
@@ -1,5 +1,5 @@
1
1
  import { Account } from '../resources/account.js';
2
- import { data, meta, Service } from './service.js';
2
+ import { data, meta, Service, withDecimalAmounts } from './service.js';
3
3
  /** The /v1/account and /v1/payment-settings endpoints. */
4
4
  export class AccountService extends Service {
5
5
  /** Retrieve the account the API key belongs to, with the coins it accepts in the key's mode. */
@@ -12,7 +12,7 @@ export class AccountService extends Service {
12
12
  }
13
13
  /** Change the default currency, the payment tolerances, the checkout language or invoice reminders. Needs payment_settings:write. */
14
14
  async updatePaymentSettings(params, options) {
15
- return account(await this.respond('PATCH', '/v1/payment-settings', params, options));
15
+ return account(await this.respond('PATCH', '/v1/payment-settings', withDecimalAmounts(params, 'underpayment_tolerance', 'overpayment_threshold'), options));
16
16
  }
17
17
  }
18
18
  /** Read the account and its meta from an answer. */
@@ -8,7 +8,13 @@ export declare class ApiKeyService extends Service {
8
8
  list(params?: PageParams): Promise<Page<ApiKey>>;
9
9
  /** Iterate over every active key, newest first, fetching pages as they are reached. */
10
10
  iterator(params?: Omit<PageParams, 'page'>): AsyncGenerator<ApiKey, void, undefined>;
11
- /** Create a key in the API key's mode. Its key property holds the key itself, shown this once; leaving permissions out gives full access. */
11
+ /**
12
+ * Create a key in the API key's mode. Its key property holds the key itself, shown this once; leaving permissions out gives full access.
13
+ *
14
+ * The answer is never kept for the idempotency key, so when it is lost, the library's retry or a repeat throws a ConflictError whose
15
+ * wasReplayed() is true: the key was made, but cannot be shown again. Find it with list() by its name and createdAt, revoke() it,
16
+ * and create another with a fresh idempotency key.
17
+ */
12
18
  create(params: ApiKeyCreateParams, options?: RequestOptions): Promise<ApiKey>;
13
19
  /** Change a key's name, permissions or allowed_ips, only those given; null permissions gives full access and null allowed_ips anywhere. */
14
20
  update(id: string, params: ApiKeyUpdateParams, options?: RequestOptions): Promise<ApiKey>;
@@ -10,7 +10,13 @@ export class ApiKeyService extends Service {
10
10
  async *iterator(params = {}) {
11
11
  yield* (await this.list(params)).autoPagingIterator();
12
12
  }
13
- /** Create a key in the API key's mode. Its key property holds the key itself, shown this once; leaving permissions out gives full access. */
13
+ /**
14
+ * Create a key in the API key's mode. Its key property holds the key itself, shown this once; leaving permissions out gives full access.
15
+ *
16
+ * The answer is never kept for the idempotency key, so when it is lost, the library's retry or a repeat throws a ConflictError whose
17
+ * wasReplayed() is true: the key was made, but cannot be shown again. Find it with list() by its name and createdAt, revoke() it,
18
+ * and create another with a fresh idempotency key.
19
+ */
14
20
  async create(params, options) {
15
21
  return new ApiKey(await this.request('POST', '/v1/api-keys', params, options));
16
22
  }
@@ -1,9 +1,8 @@
1
- import type { Page } from '../page.ts';
1
+ import { AssetPage } from '../page.ts';
2
2
  import type { AssetListParams } from '../params.ts';
3
- import { SupportedAsset } from '../resources/supported-asset.ts';
4
3
  import { Service } from './service.ts';
5
4
  /** The /v1/assets endpoint. */
6
5
  export declare class AssetService extends Service {
7
- /** List the coins that can be paid in the API key's mode, with the lowest price each can be charged at, in one page. */
8
- list(params?: AssetListParams): Promise<Page<SupportedAsset>>;
6
+ /** List the coins that can be paid in the API key's mode, with the lowest price each can be charged at, in one page that also gives the currencies prices can be asked in. */
7
+ list(params?: AssetListParams): Promise<AssetPage>;
9
8
  }
@@ -1,9 +1,10 @@
1
+ import { AssetPage } from '../page.js';
1
2
  import { SupportedAsset } from '../resources/supported-asset.js';
2
3
  import { Service } from './service.js';
3
4
  /** The /v1/assets endpoint. */
4
5
  export class AssetService extends Service {
5
- /** List the coins that can be paid in the API key's mode, with the lowest price each can be charged at, in one page. */
6
+ /** List the coins that can be paid in the API key's mode, with the lowest price each can be charged at, in one page that also gives the currencies prices can be asked in. */
6
7
  async list(params = {}) {
7
- return this.page('/v1/assets', params, (asset) => new SupportedAsset(asset));
8
+ return this.page('/v1/assets', params, (asset) => new SupportedAsset(asset), AssetPage);
8
9
  }
9
10
  }
@@ -1,25 +1,25 @@
1
1
  import type { Page } from '../page.ts';
2
2
  import type { ChargeCreateParams, ChargeListParams, RefundParams, RequestOptions, SimulateParams } from '../params.ts';
3
- import { Charge } from '../resources/charge.ts';
3
+ import { type ApiCharge } from '../resources/charge.ts';
4
4
  import { Service } from './service.ts';
5
5
  /** The /v1/charges endpoints. */
6
6
  export declare class ChargeService extends Service {
7
7
  /** Charge a customer: create a charge with what you already know about them, and send them to its checkoutUrl. */
8
- create(params: ChargeCreateParams, options?: RequestOptions): Promise<Charge>;
8
+ create(params: ChargeCreateParams, options?: RequestOptions): Promise<ApiCharge>;
9
9
  /** Retrieve a charge by its id. */
10
- retrieve(id: string): Promise<Charge>;
10
+ retrieve(id: string): Promise<ApiCharge>;
11
11
  /** List charges, newest first. */
12
- list(params?: ChargeListParams): Promise<Page<Charge>>;
12
+ list(params?: ChargeListParams): Promise<Page<ApiCharge>>;
13
13
  /** Iterate over every charge, newest first, fetching pages as they are reached. */
14
- iterator(params?: Omit<ChargeListParams, 'page'>): AsyncGenerator<Charge, void, undefined>;
14
+ iterator(params?: Omit<ChargeListParams, 'page'>): AsyncGenerator<ApiCharge, void, undefined>;
15
15
  /** Cancel a pending charge that no transfer has been seen for, so it can no longer be paid. */
16
- cancel(id: string, options?: RequestOptions): Promise<Charge>;
16
+ cancel(id: string, options?: RequestOptions): Promise<ApiCharge>;
17
17
  /** Record a refund you sent the customer from your own wallet. An underpaid charge or a late payment is accepted first, and the network surcharge is never refundable. */
18
- recordRefund(id: string, params: RefundParams, options?: RequestOptions): Promise<Charge>;
18
+ recordRefund(id: string, params: RefundParams, options?: RequestOptions): Promise<ApiCharge>;
19
19
  /** Email the customer the payment page of a pending charge. */
20
- send(id: string, options?: RequestOptions): Promise<Charge>;
20
+ send(id: string, options?: RequestOptions): Promise<ApiCharge>;
21
21
  /** Accept an underpaid charge, or a late payment on an expired or canceled one, as paid for what arrived and confirmed. */
22
- accept(id: string, options?: RequestOptions): Promise<Charge>;
22
+ accept(id: string, options?: RequestOptions): Promise<ApiCharge>;
23
23
  /** Pay a test-mode charge without coins, in full or by a chosen amount in the charge's coin. */
24
- simulate(id: string, params?: SimulateParams, options?: RequestOptions): Promise<Charge>;
24
+ simulate(id: string, params?: SimulateParams, options?: RequestOptions): Promise<ApiCharge>;
25
25
  }
@@ -1,18 +1,18 @@
1
1
  import { Charge } from '../resources/charge.js';
2
- import { path, Service } from './service.js';
2
+ import { path, Service, withDecimalAmounts } from './service.js';
3
3
  /** The /v1/charges endpoints. */
4
4
  export class ChargeService extends Service {
5
5
  /** Charge a customer: create a charge with what you already know about them, and send them to its checkoutUrl. */
6
6
  async create(params, options) {
7
- return new Charge(await this.request('POST', '/v1/charges', params, options));
7
+ return apiCharge(await this.request('POST', '/v1/charges', withDecimalAmounts(params, 'amount'), options));
8
8
  }
9
9
  /** Retrieve a charge by its id. */
10
10
  async retrieve(id) {
11
- return new Charge(await this.request('GET', path('/v1/charges/%s', id)));
11
+ return apiCharge(await this.request('GET', path('/v1/charges/%s', id)));
12
12
  }
13
13
  /** List charges, newest first. */
14
14
  async list(params = {}) {
15
- return this.page('/v1/charges', params, (charge) => new Charge(charge));
15
+ return this.page('/v1/charges', params, apiCharge);
16
16
  }
17
17
  /** Iterate over every charge, newest first, fetching pages as they are reached. */
18
18
  async *iterator(params = {}) {
@@ -20,22 +20,26 @@ export class ChargeService extends Service {
20
20
  }
21
21
  /** Cancel a pending charge that no transfer has been seen for, so it can no longer be paid. */
22
22
  async cancel(id, options) {
23
- return new Charge(await this.request('POST', path('/v1/charges/%s/cancel', id), undefined, options));
23
+ return apiCharge(await this.request('POST', path('/v1/charges/%s/cancel', id), undefined, options));
24
24
  }
25
25
  /** Record a refund you sent the customer from your own wallet. An underpaid charge or a late payment is accepted first, and the network surcharge is never refundable. */
26
26
  async recordRefund(id, params, options) {
27
- return new Charge(await this.request('POST', path('/v1/charges/%s/refunds', id), params, options));
27
+ return apiCharge(await this.request('POST', path('/v1/charges/%s/refunds', id), withDecimalAmounts(params, 'amount'), options));
28
28
  }
29
29
  /** Email the customer the payment page of a pending charge. */
30
30
  async send(id, options) {
31
- return new Charge(await this.request('POST', path('/v1/charges/%s/send', id), undefined, options));
31
+ return apiCharge(await this.request('POST', path('/v1/charges/%s/send', id), undefined, options));
32
32
  }
33
33
  /** Accept an underpaid charge, or a late payment on an expired or canceled one, as paid for what arrived and confirmed. */
34
34
  async accept(id, options) {
35
- return new Charge(await this.request('POST', path('/v1/charges/%s/accept', id), undefined, options));
35
+ return apiCharge(await this.request('POST', path('/v1/charges/%s/accept', id), undefined, options));
36
36
  }
37
37
  /** Pay a test-mode charge without coins, in full or by a chosen amount in the charge's coin. */
38
38
  async simulate(id, params = {}, options) {
39
- return new Charge(await this.request('POST', path('/v1/charges/%s/simulate', id), Object.keys(params).length === 0 ? undefined : params, options));
39
+ return apiCharge(await this.request('POST', path('/v1/charges/%s/simulate', id), Object.keys(params).length === 0 ? undefined : withDecimalAmounts(params, 'amount'), options));
40
40
  }
41
41
  }
42
+ /** Read a charge the API answered with, which always carries its checkout page. */
43
+ function apiCharge(attributes) {
44
+ return new Charge(attributes);
45
+ }
@@ -1,10 +1,10 @@
1
1
  import { Coupon } from '../resources/coupon.js';
2
- import { path, Service } from './service.js';
2
+ import { path, Service, withDecimalAmounts } from './service.js';
3
3
  /** The /v1/coupons endpoints, where a coupon's id is its code. */
4
4
  export class CouponService extends Service {
5
5
  /** Create a coupon taking either percent_off or amount_off; currency is required with amount_off or min_amount. */
6
6
  async create(params, options) {
7
- return new Coupon(await this.request('POST', '/v1/coupons', params, options));
7
+ return new Coupon(await this.request('POST', '/v1/coupons', withDecimalAmounts(params, 'percent_off', 'amount_off', 'min_amount'), options));
8
8
  }
9
9
  /** Retrieve a coupon by its code, in any case. */
10
10
  async retrieve(id) {
@@ -1,10 +1,14 @@
1
1
  import { Invoice } from '../resources/invoice.js';
2
- import { path, Service } from './service.js';
2
+ import { path, Service, withDecimalAmounts } from './service.js';
3
3
  /** The /v1/invoices endpoints. */
4
4
  export class InvoiceService extends Service {
5
5
  /** Create an invoice, for a total or a list of items, and optionally email it to the customer. */
6
6
  async create(params, options) {
7
- return new Invoice(await this.request('POST', '/v1/invoices', params, options));
7
+ const body = withDecimalAmounts(params, 'amount');
8
+ if (Array.isArray(params.items)) {
9
+ body.items = params.items.map((item) => withDecimalAmounts(item, 'quantity', 'unit_amount'));
10
+ }
11
+ return new Invoice(await this.request('POST', '/v1/invoices', body, options));
8
12
  }
9
13
  /** Retrieve an invoice by its id. */
10
14
  async retrieve(id) {
@@ -8,7 +8,7 @@ export declare class MemberService extends Service {
8
8
  list(params?: PageParams): Promise<Page<Member>>;
9
9
  /** Iterate over every member, oldest first, fetching pages as they are reached. */
10
10
  iterator(params?: Omit<PageParams, 'page'>): AsyncGenerator<Member, void, undefined>;
11
- /** Give a member another role: "admin", "finance", "support" or "viewer". An owner is never changed this way. */
11
+ /** Give a member another role: admin, finance, support or viewer, as the MemberRole values name them. An owner is never changed this way. */
12
12
  update(id: string, params: MemberUpdateParams, options?: RequestOptions): Promise<Member>;
13
13
  /** Remove a member, which also revokes the API keys they made. An owner is never removed this way. */
14
14
  remove(id: string, options?: RequestOptions): Promise<void>;
@@ -19,7 +19,7 @@ export declare class InvitationService extends Service {
19
19
  list(params?: PageParams): Promise<Page<Invitation>>;
20
20
  /** Iterate over every waiting invitation, newest first, fetching pages as they are reached. */
21
21
  iterator(params?: Omit<PageParams, 'page'>): AsyncGenerator<Invitation, void, undefined>;
22
- /** Email someone an invitation to join as an "admin", "finance", "support" or "viewer", in the name of whoever made the API key. */
22
+ /** Email someone an invitation to join as an admin, finance, support or viewer, in the name of whoever made the API key. */
23
23
  create(params: InvitationCreateParams, options?: RequestOptions): Promise<Invitation>;
24
24
  /** Withdraw an invitation, so its link stops working. */
25
25
  cancel(id: string, options?: RequestOptions): Promise<void>;
@@ -10,7 +10,7 @@ export class MemberService extends Service {
10
10
  async *iterator(params = {}) {
11
11
  yield* (await this.list(params)).autoPagingIterator();
12
12
  }
13
- /** Give a member another role: "admin", "finance", "support" or "viewer". An owner is never changed this way. */
13
+ /** Give a member another role: admin, finance, support or viewer, as the MemberRole values name them. An owner is never changed this way. */
14
14
  async update(id, params, options) {
15
15
  return new Member(await this.request('PATCH', path('/v1/members/%s', id), params, options));
16
16
  }
@@ -29,7 +29,7 @@ export class InvitationService extends Service {
29
29
  async *iterator(params = {}) {
30
30
  yield* (await this.list(params)).autoPagingIterator();
31
31
  }
32
- /** Email someone an invitation to join as an "admin", "finance", "support" or "viewer", in the name of whoever made the API key. */
32
+ /** Email someone an invitation to join as an admin, finance, support or viewer, in the name of whoever made the API key. */
33
33
  async create(params, options) {
34
34
  return new Invitation(await this.request('POST', '/v1/invitations', params, options));
35
35
  }
@@ -2,6 +2,6 @@ import { Overview } from '../resources/overview.ts';
2
2
  import { Service } from './service.ts';
3
3
  /** The /v1/overview endpoint. Needs overview:read. */
4
4
  export declare class OverviewService extends Service {
5
- /** Retrieve the dashboard's figures for the last 30 days, in the API key's mode. */
5
+ /** Retrieve the dashboard's figures for the last 30 days, in the API key's mode, and what needs attention now. */
6
6
  retrieve(): Promise<Overview>;
7
7
  }
@@ -1,9 +1,10 @@
1
1
  import { Overview } from '../resources/overview.js';
2
- import { Service } from './service.js';
2
+ import { data, meta, Service } from './service.js';
3
3
  /** The /v1/overview endpoint. Needs overview:read. */
4
4
  export class OverviewService extends Service {
5
- /** Retrieve the dashboard's figures for the last 30 days, in the API key's mode. */
5
+ /** Retrieve the dashboard's figures for the last 30 days, in the API key's mode, and what needs attention now. */
6
6
  async retrieve() {
7
- return new Overview(await this.request('GET', '/v1/overview'));
7
+ const response = await this.respond('GET', '/v1/overview');
8
+ return new Overview(data(response), meta(response));
8
9
  }
9
10
  }
@@ -1,10 +1,12 @@
1
1
  import { PaymentLink } from '../resources/payment-link.js';
2
- import { path, Service } from './service.js';
2
+ import { path, Service, withDecimalAmounts } from './service.js';
3
+ /** The amounts a payment link takes, which go out as decimal strings. */
4
+ const AMOUNTS = ['amount', 'suggested_amounts', 'min_amount', 'max_amount'];
3
5
  /** The /v1/payment-links endpoints. */
4
6
  export class PaymentLinkService extends Service {
5
7
  /** Create a payment link: one reusable public page, never one per customer. */
6
8
  async create(params, options) {
7
- return new PaymentLink(await this.request('POST', '/v1/payment-links', params, options));
9
+ return new PaymentLink(await this.request('POST', '/v1/payment-links', withDecimalAmounts(params, ...AMOUNTS), options));
8
10
  }
9
11
  /** Retrieve a payment link by its id. */
10
12
  async retrieve(id) {
@@ -12,7 +14,7 @@ export class PaymentLinkService extends Service {
12
14
  }
13
15
  /** Change any of a payment link's fields. */
14
16
  async update(id, params, options) {
15
- return new PaymentLink(await this.request('PATCH', path('/v1/payment-links/%s', id), params, options));
17
+ return new PaymentLink(await this.request('PATCH', path('/v1/payment-links/%s', id), withDecimalAmounts(params, ...AMOUNTS), options));
16
18
  }
17
19
  /** List payment links, newest first. */
18
20
  async list(params = {}) {
@@ -1,12 +1,17 @@
1
+ import type { AddressNetwork, OrString } from '../enums.ts';
1
2
  import type { PayoutAddressUpdateParams, RequestOptions } from '../params.ts';
2
3
  import { PayoutAddress } from '../resources/payout.ts';
3
4
  import { Service } from './service.ts';
4
- /** The /v1/payout-addresses endpoints. Reading needs payout_addresses:read; changing needs payout_addresses:write and an owner's switch under Payment settings. */
5
+ /**
6
+ * The /v1/payout-addresses endpoints, one address per network family: bitcoin, litecoin, dogecoin, bitcoincash, evm (Ethereum),
7
+ * bsc (BNB Chain), base, arbitrum, polygon, tron, monero, solana or lightning, as the AddressNetwork values name them.
8
+ * Reading needs payout_addresses:read; changing needs payout_addresses:write and an owner's switch under Payment settings.
9
+ */
5
10
  export declare class PayoutAddressService extends Service {
6
11
  /** List where payouts go in the API key's mode: one entry per network with coins on offer, its address null while there is none. */
7
12
  list(): Promise<PayoutAddress[]>;
8
- /** Point the payouts of one network, such as "bitcoin" or "evm", at an address. */
9
- update(network: string, params: PayoutAddressUpdateParams, options?: RequestOptions): Promise<PayoutAddress>;
13
+ /** Point the payouts of one network, such as AddressNetwork.Bitcoin or "evm", at an address. */
14
+ update(network: OrString<AddressNetwork>, params: PayoutAddressUpdateParams, options?: RequestOptions): Promise<PayoutAddress>;
10
15
  /** Remove the address of one network, so its payouts wait for a new one. */
11
- delete(network: string, options?: RequestOptions): Promise<PayoutAddress>;
16
+ delete(network: OrString<AddressNetwork>, options?: RequestOptions): Promise<PayoutAddress>;
12
17
  }
@@ -1,12 +1,16 @@
1
1
  import { PayoutAddress } from '../resources/payout.js';
2
2
  import { list, path, Service } from './service.js';
3
- /** The /v1/payout-addresses endpoints. Reading needs payout_addresses:read; changing needs payout_addresses:write and an owner's switch under Payment settings. */
3
+ /**
4
+ * The /v1/payout-addresses endpoints, one address per network family: bitcoin, litecoin, dogecoin, bitcoincash, evm (Ethereum),
5
+ * bsc (BNB Chain), base, arbitrum, polygon, tron, monero, solana or lightning, as the AddressNetwork values name them.
6
+ * Reading needs payout_addresses:read; changing needs payout_addresses:write and an owner's switch under Payment settings.
7
+ */
4
8
  export class PayoutAddressService extends Service {
5
9
  /** List where payouts go in the API key's mode: one entry per network with coins on offer, its address null while there is none. */
6
10
  async list() {
7
11
  return list(await this.respond('GET', '/v1/payout-addresses')).map((address) => new PayoutAddress(address));
8
12
  }
9
- /** Point the payouts of one network, such as "bitcoin" or "evm", at an address. */
13
+ /** Point the payouts of one network, such as AddressNetwork.Bitcoin or "evm", at an address. */
10
14
  async update(network, params, options) {
11
15
  return new PayoutAddress(await this.request('PUT', path('/v1/payout-addresses/%s', network), params, options));
12
16
  }
@@ -1,8 +1,10 @@
1
1
  import type { ApiResponse } from '../http/api-response.ts';
2
2
  import type { HttpTransport } from '../http/transport.ts';
3
- import { Page } from '../page.ts';
3
+ import { Page, type PagePosition } from '../page.ts';
4
4
  import type { RequestOptions } from '../params.ts';
5
5
  import { type ApiResource, type Attributes } from '../resources/api-resource.ts';
6
+ /** A class of page, such as Page itself or one that reads more of the list's meta. */
7
+ type PageKind<T extends ApiResource, P extends Page<T>> = new (data: T[], position: PagePosition, fetch: (page: number) => Promise<P>, meta: Attributes) => P;
6
8
  /** The requests shared by every group of endpoints. */
7
9
  export declare abstract class Service {
8
10
  protected readonly transport: HttpTransport;
@@ -11,8 +13,8 @@ export declare abstract class Service {
11
13
  protected request(method: string, path: string, body?: object, options?: RequestOptions): Promise<Attributes>;
12
14
  /** Send a request and return the whole response, for answers whose meta matters too. */
13
15
  protected respond(method: string, path: string, body?: object, options?: RequestOptions): Promise<ApiResponse>;
14
- /** Fetch one page of a list. */
15
- protected page<T extends ApiResource>(path: string, params: object, hydrate: (attributes: Attributes) => T): Promise<Page<T>>;
16
+ /** Fetch one page of a list, as a Page unless another kind is given. */
17
+ protected page<T extends ApiResource, P extends Page<T> = Page<T>>(path: string, params: object, hydrate: (attributes: Attributes) => T, kind?: PageKind<T, P>): Promise<P>;
16
18
  }
17
19
  /** Read the object under a response's "data" key. */
18
20
  export declare function data(response: ApiResponse): Attributes;
@@ -20,5 +22,8 @@ export declare function data(response: ApiResponse): Attributes;
20
22
  export declare function meta(response: ApiResponse): Attributes;
21
23
  /** Read the objects of the list under a response's "data" key. */
22
24
  export declare function list(response: ApiResponse): Attributes[];
25
+ /** A copy of the params with the amounts under the given keys, alone or in a list, written as the API reads them. */
26
+ export declare function withDecimalAmounts<T extends object>(params: T, ...keys: string[]): T;
23
27
  /** Build a path with the given ids escaped into its %s placeholders. */
24
28
  export declare function path(format: string, ...ids: string[]): string;
29
+ export {};
@@ -15,19 +15,18 @@ export class Service {
15
15
  respond(method, path, body, options) {
16
16
  return this.transport.request(method, path, {}, body, options?.idempotencyKey);
17
17
  }
18
- /** Fetch one page of a list. */
19
- async page(path, params, hydrate) {
18
+ /** Fetch one page of a list, as a Page unless another kind is given. */
19
+ async page(path, params, hydrate, kind = Page) {
20
20
  const response = await this.transport.request('GET', path, params);
21
21
  const data = list(response).map(hydrate);
22
- const json = response.json();
23
- const meta = isRecord(json['meta']) ? json['meta'] : {};
24
- const currentPage = integer(meta['current_page'], 1);
25
- return new Page(data, {
22
+ const metadata = meta(response);
23
+ const currentPage = integer(metadata['current_page'], 1);
24
+ return new kind(data, {
26
25
  currentPage,
27
- lastPage: integer(meta['last_page'], currentPage),
28
- perPage: integer(meta['per_page'], data.length),
29
- total: integer(meta['total'], data.length),
30
- }, (page) => this.page(path, { ...params, page }, hydrate));
26
+ lastPage: integer(metadata['last_page'], currentPage),
27
+ perPage: integer(metadata['per_page'], data.length),
28
+ total: integer(metadata['total'], data.length),
29
+ }, (page) => this.page(path, { ...params, page }, hydrate, kind), metadata);
31
30
  }
32
31
  }
33
32
  /** Read the object under a response's "data" key. */
@@ -51,6 +50,41 @@ export function list(response) {
51
50
  }
52
51
  return value.filter(isRecord);
53
52
  }
53
+ /** A copy of the params with the amounts under the given keys, alone or in a list, written as the API reads them. */
54
+ export function withDecimalAmounts(params, ...keys) {
55
+ const copy = { ...params };
56
+ for (const key of keys) {
57
+ if (Object.hasOwn(copy, key)) {
58
+ const value = copy[key];
59
+ copy[key] = Array.isArray(value) ? value.map((item) => decimalAmount(item, key)) : decimalAmount(value, key);
60
+ }
61
+ }
62
+ return copy;
63
+ }
64
+ /** An amount as the API reads it: a string as it is, and a number rounded to 14 significant digits, as the API read JSON numbers, and written without an exponent, which the API refuses. */
65
+ function decimalAmount(value, key) {
66
+ if (typeof value !== 'number') {
67
+ return value;
68
+ }
69
+ if (!Number.isFinite(value)) {
70
+ throw new InvalidArgumentError(`The ${key} must be a finite number, or a string such as "49.90", not ${value}.`);
71
+ }
72
+ if (!Number.isInteger(value) && Math.abs(value) >= 1e14) {
73
+ throw new InvalidArgumentError(`The ${key} ${value} has too many digits to be sent as a number: pass it as a string.`);
74
+ }
75
+ // Rounding drops the binary noise of a float, so 0.1 + 0.2 goes out as 0.3.
76
+ const rounded = Number.isInteger(value) ? value : Number(value.toPrecision(14));
77
+ const [, sign = '', whole = '', fraction = '', exponent] = /^(-?)(\d+)(?:\.(\d+))?e([+-]\d+)$/.exec(String(rounded)) ?? [];
78
+ if (exponent === undefined) {
79
+ return String(rounded);
80
+ }
81
+ const digits = whole + fraction;
82
+ const point = whole.length + Number(exponent);
83
+ if (point <= 0) {
84
+ return `${sign}0.${'0'.repeat(-point)}${digits}`;
85
+ }
86
+ return point >= digits.length ? `${sign}${digits}${'0'.repeat(point - digits.length)}` : `${sign}${digits.slice(0, point)}.${digits.slice(point)}`;
87
+ }
54
88
  /** Build a path with the given ids escaped into its %s placeholders. */
55
89
  export function path(format, ...ids) {
56
90
  let index = 0;
@@ -10,7 +10,13 @@ export declare class WebhookEndpointService extends Service {
10
10
  iterator(params?: Omit<PageParams, 'page'>): AsyncGenerator<WebhookEndpoint, void, undefined>;
11
11
  /** Retrieve one webhook endpoint. */
12
12
  retrieve(id: string): Promise<WebhookEndpoint>;
13
- /** Add an endpoint and send it its verification challenge. The answer carries its signing secret, shown this once, and verificationError while it has not answered. */
13
+ /**
14
+ * Add an endpoint and send it its verification challenge. The answer carries its signing secret, shown this once, and verificationError while it has not answered.
15
+ *
16
+ * The answer is never kept for the idempotency key, so when it is lost, the library's retry or a repeat throws a ConflictError whose
17
+ * wasReplayed() is true: the endpoint was added, but its secret cannot be shown again. Find it with list() and call rotateSecret(),
18
+ * since nothing relies on its first secret yet, or delete() it and add it again.
19
+ */
14
20
  create(params: WebhookEndpointCreateParams, options?: RequestOptions): Promise<WebhookEndpoint>;
15
21
  /** Change an endpoint's url, events, description or active, only those given. A new url is verified again. */
16
22
  update(id: string, params: WebhookEndpointUpdateParams, options?: RequestOptions): Promise<WebhookEndpoint>;
@@ -20,7 +26,14 @@ export declare class WebhookEndpointService extends Service {
20
26
  verify(id: string, options?: RequestOptions): Promise<WebhookEndpoint>;
21
27
  /** Queue a sample charge.paid event, marked as a test, to a verified endpoint. */
22
28
  test(id: string, options?: RequestOptions): Promise<WebhookDelivery>;
23
- /** Replace the endpoint's signing secret. The answer carries the new one, shown this once; the old one keeps signing for a day, until previousSecretExpiresAt. */
29
+ /**
30
+ * Replace the endpoint's signing secret. The answer carries the new one, shown this once; the old one keeps signing for a day, until previousSecretExpiresAt.
31
+ *
32
+ * The answer is never kept for the idempotency key, so when it is lost, the library's retry or a repeat throws a ConflictError whose
33
+ * wasReplayed() is true: the secret was rotated, but the new one cannot be shown again. The secret your receiver holds keeps
34
+ * verifying for a day as the previous one. Rotating again makes the lost secret the previous one and drops the one you hold at once,
35
+ * so only rotate again, with a fresh idempotency key, when you can deploy the new secret straight away; deliveries that fail meanwhile are retried.
36
+ */
24
37
  rotateSecret(id: string, options?: RequestOptions): Promise<WebhookEndpoint>;
25
38
  /** List what the endpoint was sent, newest first, kept for 30 days. */
26
39
  deliveries(id: string, params?: WebhookDeliveryListParams): Promise<Page<WebhookDelivery>>;
@@ -14,7 +14,13 @@ export class WebhookEndpointService extends Service {
14
14
  async retrieve(id) {
15
15
  return new WebhookEndpoint(await this.request('GET', path('/v1/webhook-endpoints/%s', id)));
16
16
  }
17
- /** Add an endpoint and send it its verification challenge. The answer carries its signing secret, shown this once, and verificationError while it has not answered. */
17
+ /**
18
+ * Add an endpoint and send it its verification challenge. The answer carries its signing secret, shown this once, and verificationError while it has not answered.
19
+ *
20
+ * The answer is never kept for the idempotency key, so when it is lost, the library's retry or a repeat throws a ConflictError whose
21
+ * wasReplayed() is true: the endpoint was added, but its secret cannot be shown again. Find it with list() and call rotateSecret(),
22
+ * since nothing relies on its first secret yet, or delete() it and add it again.
23
+ */
18
24
  async create(params, options) {
19
25
  return endpoint(await this.respond('POST', '/v1/webhook-endpoints', params, options));
20
26
  }
@@ -34,7 +40,14 @@ export class WebhookEndpointService extends Service {
34
40
  async test(id, options) {
35
41
  return new WebhookDelivery(await this.request('POST', path('/v1/webhook-endpoints/%s/test', id), undefined, options));
36
42
  }
37
- /** Replace the endpoint's signing secret. The answer carries the new one, shown this once; the old one keeps signing for a day, until previousSecretExpiresAt. */
43
+ /**
44
+ * Replace the endpoint's signing secret. The answer carries the new one, shown this once; the old one keeps signing for a day, until previousSecretExpiresAt.
45
+ *
46
+ * The answer is never kept for the idempotency key, so when it is lost, the library's retry or a repeat throws a ConflictError whose
47
+ * wasReplayed() is true: the secret was rotated, but the new one cannot be shown again. The secret your receiver holds keeps
48
+ * verifying for a day as the previous one. Rotating again makes the lost secret the previous one and drops the one you hold at once,
49
+ * so only rotate again, with a fresh idempotency key, when you can deploy the new secret straight away; deliveries that fail meanwhile are retried.
50
+ */
38
51
  async rotateSecret(id, options) {
39
52
  return endpoint(await this.respond('POST', path('/v1/webhook-endpoints/%s/secret', id), undefined, options));
40
53
  }
@@ -1,2 +1,2 @@
1
1
  /** The version of this library. */
2
- export declare const VERSION = "0.1.0";
2
+ export declare const VERSION = "0.2.0";
@@ -1,2 +1,2 @@
1
1
  /** The version of this library. */
2
- export const VERSION = '0.1.0';
2
+ export const VERSION = '0.2.0';
package/package.json CHANGED
@@ -1,19 +1,29 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package.json",
3
3
  "name": "velirapay",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "description": "The official Node.js library for VeliraPay crypto payments: charges, payment links, invoices, payouts, events and webhook verification.",
6
6
  "keywords": [
7
7
  "velirapay",
8
8
  "crypto",
9
+ "cryptocurrency",
10
+ "crypto-payments",
9
11
  "payments",
10
12
  "payment-gateway",
13
+ "payment-processing",
11
14
  "bitcoin",
12
15
  "ethereum",
16
+ "litecoin",
13
17
  "solana",
18
+ "usdt",
19
+ "usdc",
14
20
  "webhooks",
15
21
  "sdk",
16
- "api"
22
+ "api",
23
+ "api-client",
24
+ "typescript",
25
+ "javascript",
26
+ "nodejs"
17
27
  ],
18
28
  "homepage": "https://velirapay.com",
19
29
  "bugs": {