@portal-hq/web 3.17.0 → 3.18.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 (55) hide show
  1. package/lib/commonjs/index.js +62 -20
  2. package/lib/commonjs/index.test.js +51 -10
  3. package/lib/commonjs/integrations/ramps/index.js +2 -0
  4. package/lib/commonjs/integrations/ramps/meld/index.js +121 -0
  5. package/lib/commonjs/integrations/ramps/meld/index.test.js +162 -0
  6. package/lib/commonjs/integrations/ramps/noah/index.js +2 -2
  7. package/lib/commonjs/integrations/ramps/noah/index.test.js +11 -2
  8. package/lib/commonjs/mpc/index.js +199 -3
  9. package/lib/commonjs/mpc/index.test.js +634 -0
  10. package/lib/commonjs/provider/index.js +44 -2
  11. package/lib/commonjs/provider/index.test.js +186 -0
  12. package/lib/commonjs/rpc.test.js +162 -0
  13. package/lib/commonjs/shared/rpc/auth.js +29 -0
  14. package/lib/commonjs/shared/rpc/defaults.js +40 -0
  15. package/lib/commonjs/shared/types/index.js +1 -0
  16. package/lib/commonjs/shared/types/meld.js +2 -0
  17. package/lib/esm/index.js +59 -19
  18. package/lib/esm/index.test.js +51 -10
  19. package/lib/esm/integrations/ramps/index.js +2 -0
  20. package/lib/esm/integrations/ramps/meld/index.js +118 -0
  21. package/lib/esm/integrations/ramps/meld/index.test.js +157 -0
  22. package/lib/esm/integrations/ramps/noah/index.js +2 -2
  23. package/lib/esm/integrations/ramps/noah/index.test.js +11 -2
  24. package/lib/esm/mpc/index.js +199 -3
  25. package/lib/esm/mpc/index.test.js +635 -1
  26. package/lib/esm/provider/index.js +44 -2
  27. package/lib/esm/provider/index.test.js +186 -0
  28. package/lib/esm/rpc.test.js +157 -0
  29. package/lib/esm/shared/rpc/auth.js +25 -0
  30. package/lib/esm/shared/rpc/defaults.js +36 -0
  31. package/lib/esm/shared/types/index.js +1 -0
  32. package/lib/esm/shared/types/meld.js +1 -0
  33. package/noah-types.d.ts +17 -1
  34. package/package.json +1 -1
  35. package/src/__mocks/constants.ts +68 -0
  36. package/src/__mocks/portal/portal.ts +0 -1
  37. package/src/index.test.ts +90 -0
  38. package/src/index.ts +159 -7
  39. package/src/integrations/ramps/index.ts +3 -0
  40. package/src/integrations/ramps/meld/index.test.ts +189 -0
  41. package/src/integrations/ramps/meld/index.ts +149 -0
  42. package/src/integrations/ramps/noah/index.test.ts +11 -2
  43. package/src/integrations/ramps/noah/index.ts +5 -2
  44. package/src/mpc/index.test.ts +804 -7
  45. package/src/mpc/index.ts +247 -3
  46. package/src/provider/index.test.ts +233 -0
  47. package/src/provider/index.ts +64 -1
  48. package/src/rpc.test.ts +190 -0
  49. package/src/shared/rpc/auth.ts +27 -0
  50. package/src/shared/rpc/defaults.ts +41 -0
  51. package/src/shared/types/common.ts +24 -0
  52. package/src/shared/types/index.ts +1 -0
  53. package/src/shared/types/meld.ts +302 -0
  54. package/src/shared/types/noah.ts +191 -29
  55. package/types.d.ts +65 -3
@@ -0,0 +1,189 @@
1
+ import Meld from '.'
2
+ import Mpc from '../../../mpc'
3
+
4
+ const mockMeldCreateCustomerResponse = {
5
+ data: { id: 'cust-1', accountId: 'acc-1', externalId: 'ext-1' },
6
+ }
7
+ const mockMeldSearchCustomerResponse = {
8
+ data: { customers: [], count: 0, remaining: 0 },
9
+ }
10
+ const mockMeldGetRetailQuoteResponse = {
11
+ data: { quotes: [] },
12
+ }
13
+ const mockMeldCreateRetailWidgetResponse = {
14
+ data: { id: 'sess-1', token: 'tok-1', customerId: 'cust-1', externalCustomerId: 'ext-1', externalSessionId: 'ses-1', widgetUrl: 'https://widget.meld.io' },
15
+ }
16
+ const mockMeldSearchRetailTransactionsResponse = {
17
+ data: { transactions: [], count: 0, remaining: 0, totalCount: 0 },
18
+ }
19
+ const mockMeldGetRetailTransactionResponse = {
20
+ data: { transaction: { id: 'tx-1', sessionId: 'ses-1', status: 'COMPLETED', transactionType: 'BUY', serviceProvider: 'STRIPE', createdAt: '2024-01-01', updatedAt: '2024-01-01' } },
21
+ }
22
+ const mockMeldDiscoveryResponse = { data: [] }
23
+
24
+ const buildMpcMock = () =>
25
+ ({
26
+ meldCreateCustomer: jest.fn().mockResolvedValue(mockMeldCreateCustomerResponse),
27
+ meldSearchCustomer: jest.fn().mockResolvedValue(mockMeldSearchCustomerResponse),
28
+ meldGetRetailQuote: jest.fn().mockResolvedValue(mockMeldGetRetailQuoteResponse),
29
+ meldCreateRetailWidget: jest.fn().mockResolvedValue(mockMeldCreateRetailWidgetResponse),
30
+ meldSearchRetailTransactions: jest.fn().mockResolvedValue(mockMeldSearchRetailTransactionsResponse),
31
+ meldGetRetailTransactionBySession: jest.fn().mockResolvedValue(mockMeldGetRetailTransactionResponse),
32
+ meldGetRetailTransaction: jest.fn().mockResolvedValue(mockMeldGetRetailTransactionResponse),
33
+ meldGetServiceProviders: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
34
+ meldGetCountries: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
35
+ meldGetFiatCurrencies: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
36
+ meldGetCryptoCurrencies: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
37
+ meldGetPaymentMethods: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
38
+ meldGetDefaults: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
39
+ meldGetBuyLimits: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
40
+ meldGetSellLimits: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
41
+ meldGetKycLimits: jest.fn().mockResolvedValue(mockMeldDiscoveryResponse),
42
+ }) as unknown as Mpc
43
+
44
+ describe('Meld', () => {
45
+ let mpcMock: Mpc
46
+ let meld: Meld
47
+
48
+ beforeEach(() => {
49
+ mpcMock = buildMpcMock()
50
+ meld = new Meld({ mpc: mpcMock })
51
+ })
52
+
53
+ it('createCustomer delegates to mpc.meldCreateCustomer', async () => {
54
+ const req = { email: 'user@example.com', type: 'INDIVIDUAL' as const }
55
+ const result = await meld.createCustomer(req)
56
+
57
+ expect(mpcMock.meldCreateCustomer).toHaveBeenCalledWith(req)
58
+ expect(result).toEqual(mockMeldCreateCustomerResponse)
59
+ })
60
+
61
+ it('searchCustomer delegates to mpc.meldSearchCustomer', async () => {
62
+ const result = await meld.searchCustomer()
63
+
64
+ expect(mpcMock.meldSearchCustomer).toHaveBeenCalled()
65
+ expect(result).toEqual(mockMeldSearchCustomerResponse)
66
+ })
67
+
68
+ it('getRetailQuote delegates to mpc.meldGetRetailQuote', async () => {
69
+ const req = { countryCode: 'US', sourceCurrencyCode: 'USD', destinationCurrencyCode: 'ETH', sourceAmount: 100 }
70
+ const result = await meld.getRetailQuote(req)
71
+
72
+ expect(mpcMock.meldGetRetailQuote).toHaveBeenCalledWith(req)
73
+ expect(result).toEqual(mockMeldGetRetailQuoteResponse)
74
+ })
75
+
76
+ it('createRetailWidget delegates to mpc.meldCreateRetailWidget', async () => {
77
+ const req = {
78
+ sessionType: 'BUY' as const,
79
+ sessionData: {
80
+ countryCode: 'US',
81
+ serviceProvider: 'STRIPE',
82
+ sourceCurrencyCode: 'USD',
83
+ sourceAmount: '100',
84
+ destinationCurrencyCode: 'ETH',
85
+ },
86
+ }
87
+ const result = await meld.createRetailWidget(req)
88
+
89
+ expect(mpcMock.meldCreateRetailWidget).toHaveBeenCalledWith(req)
90
+ expect(result).toEqual(mockMeldCreateRetailWidgetResponse)
91
+ })
92
+
93
+ it('searchRetailTransactions delegates to mpc.meldSearchRetailTransactions without params', async () => {
94
+ const result = await meld.searchRetailTransactions()
95
+
96
+ expect(mpcMock.meldSearchRetailTransactions).toHaveBeenCalledWith(undefined)
97
+ expect(result).toEqual(mockMeldSearchRetailTransactionsResponse)
98
+ })
99
+
100
+ it('searchRetailTransactions delegates with params when provided', async () => {
101
+ const params = { status: 'COMPLETED' }
102
+ await meld.searchRetailTransactions(params)
103
+
104
+ expect(mpcMock.meldSearchRetailTransactions).toHaveBeenCalledWith(params)
105
+ })
106
+
107
+ it('getRetailTransactionBySession delegates to mpc.meldGetRetailTransactionBySession', async () => {
108
+ const result = await meld.getRetailTransactionBySession('ses-1')
109
+
110
+ expect(mpcMock.meldGetRetailTransactionBySession).toHaveBeenCalledWith('ses-1')
111
+ expect(result).toEqual(mockMeldGetRetailTransactionResponse)
112
+ })
113
+
114
+ it('getRetailTransaction delegates to mpc.meldGetRetailTransaction', async () => {
115
+ const result = await meld.getRetailTransaction('tx-1')
116
+
117
+ expect(mpcMock.meldGetRetailTransaction).toHaveBeenCalledWith('tx-1')
118
+ expect(result).toEqual(mockMeldGetRetailTransactionResponse)
119
+ })
120
+
121
+ it('getServiceProviders delegates to mpc.meldGetServiceProviders', async () => {
122
+ const params = { countries: 'US' }
123
+ const result = await meld.getServiceProviders(params)
124
+
125
+ expect(mpcMock.meldGetServiceProviders).toHaveBeenCalledWith(params)
126
+ expect(result).toEqual(mockMeldDiscoveryResponse)
127
+ })
128
+
129
+ it('getServiceProviders without params delegates undefined', async () => {
130
+ await meld.getServiceProviders()
131
+ expect(mpcMock.meldGetServiceProviders).toHaveBeenCalledWith(undefined)
132
+ })
133
+
134
+ it('getCountries delegates to mpc.meldGetCountries', async () => {
135
+ const result = await meld.getCountries()
136
+
137
+ expect(mpcMock.meldGetCountries).toHaveBeenCalledWith(undefined)
138
+ expect(result).toEqual(mockMeldDiscoveryResponse)
139
+ })
140
+
141
+ it('getFiatCurrencies delegates to mpc.meldGetFiatCurrencies', async () => {
142
+ const result = await meld.getFiatCurrencies()
143
+
144
+ expect(mpcMock.meldGetFiatCurrencies).toHaveBeenCalledWith(undefined)
145
+ expect(result).toEqual(mockMeldDiscoveryResponse)
146
+ })
147
+
148
+ it('getCryptoCurrencies delegates to mpc.meldGetCryptoCurrencies', async () => {
149
+ const result = await meld.getCryptoCurrencies()
150
+
151
+ expect(mpcMock.meldGetCryptoCurrencies).toHaveBeenCalledWith(undefined)
152
+ expect(result).toEqual(mockMeldDiscoveryResponse)
153
+ })
154
+
155
+ it('getPaymentMethods delegates to mpc.meldGetPaymentMethods', async () => {
156
+ const result = await meld.getPaymentMethods()
157
+
158
+ expect(mpcMock.meldGetPaymentMethods).toHaveBeenCalledWith(undefined)
159
+ expect(result).toEqual(mockMeldDiscoveryResponse)
160
+ })
161
+
162
+ it('getDefaults delegates to mpc.meldGetDefaults', async () => {
163
+ const result = await meld.getDefaults()
164
+
165
+ expect(mpcMock.meldGetDefaults).toHaveBeenCalledWith(undefined)
166
+ expect(result).toEqual(mockMeldDiscoveryResponse)
167
+ })
168
+
169
+ it('getBuyLimits delegates to mpc.meldGetBuyLimits', async () => {
170
+ const result = await meld.getBuyLimits()
171
+
172
+ expect(mpcMock.meldGetBuyLimits).toHaveBeenCalledWith(undefined)
173
+ expect(result).toEqual(mockMeldDiscoveryResponse)
174
+ })
175
+
176
+ it('getSellLimits delegates to mpc.meldGetSellLimits', async () => {
177
+ const result = await meld.getSellLimits()
178
+
179
+ expect(mpcMock.meldGetSellLimits).toHaveBeenCalledWith(undefined)
180
+ expect(result).toEqual(mockMeldDiscoveryResponse)
181
+ })
182
+
183
+ it('getKycLimits delegates to mpc.meldGetKycLimits', async () => {
184
+ const result = await meld.getKycLimits()
185
+
186
+ expect(mpcMock.meldGetKycLimits).toHaveBeenCalledWith(undefined)
187
+ expect(result).toEqual(mockMeldDiscoveryResponse)
188
+ })
189
+ })
@@ -0,0 +1,149 @@
1
+ import Mpc from '../../../mpc'
2
+ import type {
3
+ MeldCreateCustomerRequest,
4
+ MeldCreateCustomerResponse,
5
+ MeldSearchCustomerResponse,
6
+ MeldGetRetailQuoteRequest,
7
+ MeldGetRetailQuoteResponse,
8
+ MeldCreateRetailWidgetRequest,
9
+ MeldCreateRetailWidgetResponse,
10
+ MeldSearchRetailTransactionsParams,
11
+ MeldSearchRetailTransactionsResponse,
12
+ MeldGetRetailTransactionResponse,
13
+ MeldDiscoveryParams,
14
+ MeldGetServiceProvidersResponse,
15
+ MeldGetCountriesResponse,
16
+ MeldGetFiatCurrenciesResponse,
17
+ MeldGetCryptoCurrenciesResponse,
18
+ MeldGetPaymentMethodsResponse,
19
+ MeldGetDefaultsResponse,
20
+ MeldGetBuyLimitsResponse,
21
+ MeldGetSellLimitsResponse,
22
+ MeldGetKycLimitsResponse,
23
+ } from '../../../shared/types'
24
+
25
+ /**
26
+ * Meld fiat on-ramp API on `portal.ramps.meld`.
27
+ * Each method forwards to the embedded Portal iframe, which calls connect-api.
28
+ */
29
+ export default class Meld {
30
+ private mpc: Mpc
31
+
32
+ constructor({ mpc }: { mpc: Mpc }) {
33
+ this.mpc = mpc
34
+ }
35
+
36
+ /** Register a new Meld customer for the authenticated client. */
37
+ public async createCustomer(
38
+ data: MeldCreateCustomerRequest,
39
+ ): Promise<MeldCreateCustomerResponse> {
40
+ return this.mpc.meldCreateCustomer(data)
41
+ }
42
+
43
+ /** Retrieve the Meld customer record for the authenticated client. */
44
+ public async searchCustomer(): Promise<MeldSearchCustomerResponse> {
45
+ return this.mpc.meldSearchCustomer()
46
+ }
47
+
48
+ /** Get fiat-to-crypto purchase quotes from Meld service providers. */
49
+ public async getRetailQuote(
50
+ data: MeldGetRetailQuoteRequest,
51
+ ): Promise<MeldGetRetailQuoteResponse> {
52
+ return this.mpc.meldGetRetailQuote(data)
53
+ }
54
+
55
+ /**
56
+ * Create a Meld-hosted retail widget session.
57
+ * The response contains `data.widgetUrl` — open this URL in a new browser tab
58
+ * to let the user complete the purchase or KYC flow on the Meld-hosted page.
59
+ */
60
+ public async createRetailWidget(
61
+ data: MeldCreateRetailWidgetRequest,
62
+ ): Promise<MeldCreateRetailWidgetResponse> {
63
+ return this.mpc.meldCreateRetailWidget(data)
64
+ }
65
+
66
+ /** Search retail transactions for the authenticated client. */
67
+ public async searchRetailTransactions(
68
+ data?: MeldSearchRetailTransactionsParams,
69
+ ): Promise<MeldSearchRetailTransactionsResponse> {
70
+ return this.mpc.meldSearchRetailTransactions(data)
71
+ }
72
+
73
+ /** Get a single retail transaction by session ID. */
74
+ public async getRetailTransactionBySession(
75
+ sessionId: string,
76
+ ): Promise<MeldGetRetailTransactionResponse> {
77
+ return this.mpc.meldGetRetailTransactionBySession(sessionId)
78
+ }
79
+
80
+ /** Get a single retail transaction by transaction ID. */
81
+ public async getRetailTransaction(
82
+ id: string,
83
+ ): Promise<MeldGetRetailTransactionResponse> {
84
+ return this.mpc.meldGetRetailTransaction(id)
85
+ }
86
+
87
+ /** Discover available Meld service providers. */
88
+ public async getServiceProviders(
89
+ params?: MeldDiscoveryParams,
90
+ ): Promise<MeldGetServiceProvidersResponse> {
91
+ return this.mpc.meldGetServiceProviders(params)
92
+ }
93
+
94
+ /** Discover supported countries. */
95
+ public async getCountries(
96
+ params?: MeldDiscoveryParams,
97
+ ): Promise<MeldGetCountriesResponse> {
98
+ return this.mpc.meldGetCountries(params)
99
+ }
100
+
101
+ /** Discover supported fiat currencies. */
102
+ public async getFiatCurrencies(
103
+ params?: MeldDiscoveryParams,
104
+ ): Promise<MeldGetFiatCurrenciesResponse> {
105
+ return this.mpc.meldGetFiatCurrencies(params)
106
+ }
107
+
108
+ /** Discover supported crypto currencies. */
109
+ public async getCryptoCurrencies(
110
+ params?: MeldDiscoveryParams,
111
+ ): Promise<MeldGetCryptoCurrenciesResponse> {
112
+ return this.mpc.meldGetCryptoCurrencies(params)
113
+ }
114
+
115
+ /** Discover supported payment methods. */
116
+ public async getPaymentMethods(
117
+ params?: MeldDiscoveryParams,
118
+ ): Promise<MeldGetPaymentMethodsResponse> {
119
+ return this.mpc.meldGetPaymentMethods(params)
120
+ }
121
+
122
+ /** Discover default currency and payment method settings by country. */
123
+ public async getDefaults(
124
+ params?: MeldDiscoveryParams,
125
+ ): Promise<MeldGetDefaultsResponse> {
126
+ return this.mpc.meldGetDefaults(params)
127
+ }
128
+
129
+ /** Discover fiat currency purchase limits. */
130
+ public async getBuyLimits(
131
+ params?: MeldDiscoveryParams,
132
+ ): Promise<MeldGetBuyLimitsResponse> {
133
+ return this.mpc.meldGetBuyLimits(params)
134
+ }
135
+
136
+ /** Discover crypto currency sell limits. */
137
+ public async getSellLimits(
138
+ params?: MeldDiscoveryParams,
139
+ ): Promise<MeldGetSellLimitsResponse> {
140
+ return this.mpc.meldGetSellLimits(params)
141
+ }
142
+
143
+ /** Discover KYC fiat level limits. */
144
+ public async getKycLimits(
145
+ params?: MeldDiscoveryParams,
146
+ ): Promise<MeldGetKycLimitsResponse> {
147
+ return this.mpc.meldGetKycLimits(params)
148
+ }
149
+ }
@@ -65,11 +65,15 @@ describe('Noah', () => {
65
65
  const spy = jest.spyOn(mpc, 'initiatePayin').mockResolvedValue({
66
66
  data: {
67
67
  payinId: 'p1',
68
+ cryptoCurrency: 'USDC_TEST',
69
+ fee: { fiatCurrencyCode: 'USD', totalFeePct: '0', totalFeeBase: '0', totalFeeMin: '0' },
68
70
  bankDetails: {
69
71
  paymentMethodId: 'pm-123',
70
- paymentMethodType: 'bank_account',
72
+ paymentMethodType: 'BankLocal',
71
73
  accountNumber: '1234567890',
74
+ cryptoCurrency: 'USDC_TEST',
72
75
  network: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
76
+ fee: { fiatCurrencyCode: 'USD', totalFeePct: '0', totalFeeBase: '0', totalFeeMin: '0' },
73
77
  },
74
78
  },
75
79
  })
@@ -136,6 +140,7 @@ describe('Noah', () => {
136
140
  payoutId: 'out-1',
137
141
  formSessionId: 'fs-1',
138
142
  cryptoAmountEstimate: '10',
143
+ cryptoAuthorizedAmount: '10',
139
144
  totalFee: '0.01',
140
145
  },
141
146
  })
@@ -166,7 +171,11 @@ describe('Noah', () => {
166
171
  const spy = jest.spyOn(mpc, 'getPaymentMethods').mockResolvedValue({
167
172
  data: { paymentMethods: [] },
168
173
  })
169
- await noah.getPaymentMethods()
174
+ await noah.getPaymentMethods({
175
+ pageSize: 50,
176
+ pageToken: 'token-123',
177
+ capability: 'PayoutFrom',
178
+ })
170
179
  expect(spy).toHaveBeenCalled()
171
180
  })
172
181
  })
@@ -15,6 +15,7 @@ import type {
15
15
  NoahInitiatePayoutResponse,
16
16
  NoahSimulatePayinRequest,
17
17
  NoahSimulatePayinResponse,
18
+ NoahGetPaymentMethodsRequest,
18
19
  } from '../../../shared/types'
19
20
 
20
21
  /**
@@ -83,7 +84,9 @@ export default class Noah {
83
84
  }
84
85
 
85
86
  /** Pay-in payment methods available to the customer. */
86
- public async getPaymentMethods(): Promise<NoahGetPaymentMethodsResponse> {
87
- return this.mpc.getPaymentMethods()
87
+ public async getPaymentMethods(
88
+ data?: NoahGetPaymentMethodsRequest,
89
+ ): Promise<NoahGetPaymentMethodsResponse> {
90
+ return this.mpc.getPaymentMethods(data)
88
91
  }
89
92
  }