@portal-hq/web 3.17.0-alpha.0 → 3.18.0-alpha.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 +2 -2
  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
@@ -69,11 +69,15 @@ describe('Noah', () => {
69
69
  const spy = jest.spyOn(mpc, 'initiatePayin').mockResolvedValue({
70
70
  data: {
71
71
  payinId: 'p1',
72
+ cryptoCurrency: 'USDC_TEST',
73
+ fee: { fiatCurrencyCode: 'USD', totalFeePct: '0', totalFeeBase: '0', totalFeeMin: '0' },
72
74
  bankDetails: {
73
75
  paymentMethodId: 'pm-123',
74
- paymentMethodType: 'bank_account',
76
+ paymentMethodType: 'BankLocal',
75
77
  accountNumber: '1234567890',
78
+ cryptoCurrency: 'USDC_TEST',
76
79
  network: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',
80
+ fee: { fiatCurrencyCode: 'USD', totalFeePct: '0', totalFeeBase: '0', totalFeeMin: '0' },
77
81
  },
78
82
  },
79
83
  });
@@ -135,6 +139,7 @@ describe('Noah', () => {
135
139
  payoutId: 'out-1',
136
140
  formSessionId: 'fs-1',
137
141
  cryptoAmountEstimate: '10',
142
+ cryptoAuthorizedAmount: '10',
138
143
  totalFee: '0.01',
139
144
  },
140
145
  });
@@ -163,7 +168,11 @@ describe('Noah', () => {
163
168
  const spy = jest.spyOn(mpc, 'getPaymentMethods').mockResolvedValue({
164
169
  data: { paymentMethods: [] },
165
170
  });
166
- yield noah.getPaymentMethods();
171
+ yield noah.getPaymentMethods({
172
+ pageSize: 50,
173
+ pageToken: 'token-123',
174
+ capability: 'PayoutFrom',
175
+ });
167
176
  expect(spy).toHaveBeenCalled();
168
177
  }));
169
178
  });
@@ -14,7 +14,7 @@ const errors_1 = require("./errors");
14
14
  const logger_1 = require("../logger");
15
15
  const index_1 = require("../index");
16
16
  const trace_1 = require("../shared/trace");
17
- const WEB_SDK_VERSION = '3.17.0-alpha.0';
17
+ const WEB_SDK_VERSION = '3.18.0-alpha.0';
18
18
  class Mpc {
19
19
  get ready() {
20
20
  return this._ready;
@@ -220,7 +220,10 @@ class Mpc {
220
220
  });
221
221
  }
222
222
  rawSign(curve, param, options) {
223
+ var _a;
223
224
  return __awaiter(this, void 0, void 0, function* () {
225
+ const traceId = (_a = options === null || options === void 0 ? void 0 : options.traceId) !== null && _a !== void 0 ? _a : (0, trace_1.generateTraceId)();
226
+ logger_1.sdkLogger.debug(`[Portal MPC] rawSign started | traceId=${traceId}`);
224
227
  return this.handleRequestToIframeAndPost({
225
228
  methodMessage: 'portal:mpc:rawSign',
226
229
  errorMessage: 'portal:mpc:rawSignError',
@@ -229,7 +232,7 @@ class Mpc {
229
232
  param }, ((options === null || options === void 0 ? void 0 : options.signatureApprovalMemo) !== undefined && {
230
233
  signatureApprovalMemo: options.signatureApprovalMemo,
231
234
  })),
232
- traceId: options === null || options === void 0 ? void 0 : options.traceId,
235
+ traceId,
233
236
  });
234
237
  });
235
238
  }
@@ -708,16 +711,176 @@ class Mpc {
708
711
  });
709
712
  });
710
713
  }
711
- getPaymentMethods() {
714
+ getPaymentMethods(data) {
712
715
  return __awaiter(this, void 0, void 0, function* () {
713
716
  return this.handleRequestToIframeAndPost({
714
717
  methodMessage: 'portal:noah:getPaymentMethods',
715
718
  errorMessage: 'portal:noah:getPaymentMethodsError',
716
719
  resultMessage: 'portal:noah:getPaymentMethodsResult',
720
+ data,
721
+ });
722
+ });
723
+ }
724
+ meldCreateCustomer(data) {
725
+ return __awaiter(this, void 0, void 0, function* () {
726
+ return this.handleRequestToIframeAndPost({
727
+ methodMessage: 'portal:meld:createCustomer',
728
+ errorMessage: 'portal:meld:createCustomerError',
729
+ resultMessage: 'portal:meld:createCustomerResult',
730
+ data,
731
+ });
732
+ });
733
+ }
734
+ meldSearchCustomer() {
735
+ return __awaiter(this, void 0, void 0, function* () {
736
+ return this.handleRequestToIframeAndPost({
737
+ methodMessage: 'portal:meld:searchCustomer',
738
+ errorMessage: 'portal:meld:searchCustomerError',
739
+ resultMessage: 'portal:meld:searchCustomerResult',
717
740
  data: {},
718
741
  });
719
742
  });
720
743
  }
744
+ meldGetRetailQuote(data) {
745
+ return __awaiter(this, void 0, void 0, function* () {
746
+ return this.handleRequestToIframeAndPost({
747
+ methodMessage: 'portal:meld:getRetailQuote',
748
+ errorMessage: 'portal:meld:getRetailQuoteError',
749
+ resultMessage: 'portal:meld:getRetailQuoteResult',
750
+ data,
751
+ });
752
+ });
753
+ }
754
+ meldCreateRetailWidget(data) {
755
+ return __awaiter(this, void 0, void 0, function* () {
756
+ return this.handleRequestToIframeAndPost({
757
+ methodMessage: 'portal:meld:createRetailWidget',
758
+ errorMessage: 'portal:meld:createRetailWidgetError',
759
+ resultMessage: 'portal:meld:createRetailWidgetResult',
760
+ data,
761
+ });
762
+ });
763
+ }
764
+ meldSearchRetailTransactions(data) {
765
+ return __awaiter(this, void 0, void 0, function* () {
766
+ return this.handleRequestToIframeAndPost({
767
+ methodMessage: 'portal:meld:searchRetailTransactions',
768
+ errorMessage: 'portal:meld:searchRetailTransactionsError',
769
+ resultMessage: 'portal:meld:searchRetailTransactionsResult',
770
+ data,
771
+ });
772
+ });
773
+ }
774
+ meldGetRetailTransactionBySession(sessionId) {
775
+ return __awaiter(this, void 0, void 0, function* () {
776
+ return this.handleRequestToIframeAndPost({
777
+ methodMessage: 'portal:meld:getRetailTransactionBySession',
778
+ errorMessage: 'portal:meld:getRetailTransactionBySessionError',
779
+ resultMessage: 'portal:meld:getRetailTransactionBySessionResult',
780
+ data: sessionId,
781
+ });
782
+ });
783
+ }
784
+ meldGetRetailTransaction(id) {
785
+ return __awaiter(this, void 0, void 0, function* () {
786
+ return this.handleRequestToIframeAndPost({
787
+ methodMessage: 'portal:meld:getRetailTransaction',
788
+ errorMessage: 'portal:meld:getRetailTransactionError',
789
+ resultMessage: 'portal:meld:getRetailTransactionResult',
790
+ data: id,
791
+ });
792
+ });
793
+ }
794
+ meldGetServiceProviders(data) {
795
+ return __awaiter(this, void 0, void 0, function* () {
796
+ return this.handleRequestToIframeAndPost({
797
+ methodMessage: 'portal:meld:getServiceProviders',
798
+ errorMessage: 'portal:meld:getServiceProvidersError',
799
+ resultMessage: 'portal:meld:getServiceProvidersResult',
800
+ data: data !== null && data !== void 0 ? data : {},
801
+ });
802
+ });
803
+ }
804
+ meldGetCountries(data) {
805
+ return __awaiter(this, void 0, void 0, function* () {
806
+ return this.handleRequestToIframeAndPost({
807
+ methodMessage: 'portal:meld:getCountries',
808
+ errorMessage: 'portal:meld:getCountriesError',
809
+ resultMessage: 'portal:meld:getCountriesResult',
810
+ data: data !== null && data !== void 0 ? data : {},
811
+ });
812
+ });
813
+ }
814
+ meldGetFiatCurrencies(data) {
815
+ return __awaiter(this, void 0, void 0, function* () {
816
+ return this.handleRequestToIframeAndPost({
817
+ methodMessage: 'portal:meld:getFiatCurrencies',
818
+ errorMessage: 'portal:meld:getFiatCurrenciesError',
819
+ resultMessage: 'portal:meld:getFiatCurrenciesResult',
820
+ data: data !== null && data !== void 0 ? data : {},
821
+ });
822
+ });
823
+ }
824
+ meldGetCryptoCurrencies(data) {
825
+ return __awaiter(this, void 0, void 0, function* () {
826
+ return this.handleRequestToIframeAndPost({
827
+ methodMessage: 'portal:meld:getCryptoCurrencies',
828
+ errorMessage: 'portal:meld:getCryptoCurrenciesError',
829
+ resultMessage: 'portal:meld:getCryptoCurrenciesResult',
830
+ data: data !== null && data !== void 0 ? data : {},
831
+ });
832
+ });
833
+ }
834
+ meldGetPaymentMethods(data) {
835
+ return __awaiter(this, void 0, void 0, function* () {
836
+ return this.handleRequestToIframeAndPost({
837
+ methodMessage: 'portal:meld:getPaymentMethods',
838
+ errorMessage: 'portal:meld:getPaymentMethodsError',
839
+ resultMessage: 'portal:meld:getPaymentMethodsResult',
840
+ data: data !== null && data !== void 0 ? data : {},
841
+ });
842
+ });
843
+ }
844
+ meldGetDefaults(data) {
845
+ return __awaiter(this, void 0, void 0, function* () {
846
+ return this.handleRequestToIframeAndPost({
847
+ methodMessage: 'portal:meld:getDefaults',
848
+ errorMessage: 'portal:meld:getDefaultsError',
849
+ resultMessage: 'portal:meld:getDefaultsResult',
850
+ data: data !== null && data !== void 0 ? data : {},
851
+ });
852
+ });
853
+ }
854
+ meldGetBuyLimits(data) {
855
+ return __awaiter(this, void 0, void 0, function* () {
856
+ return this.handleRequestToIframeAndPost({
857
+ methodMessage: 'portal:meld:getBuyLimits',
858
+ errorMessage: 'portal:meld:getBuyLimitsError',
859
+ resultMessage: 'portal:meld:getBuyLimitsResult',
860
+ data: data !== null && data !== void 0 ? data : {},
861
+ });
862
+ });
863
+ }
864
+ meldGetSellLimits(data) {
865
+ return __awaiter(this, void 0, void 0, function* () {
866
+ return this.handleRequestToIframeAndPost({
867
+ methodMessage: 'portal:meld:getSellLimits',
868
+ errorMessage: 'portal:meld:getSellLimitsError',
869
+ resultMessage: 'portal:meld:getSellLimitsResult',
870
+ data: data !== null && data !== void 0 ? data : {},
871
+ });
872
+ });
873
+ }
874
+ meldGetKycLimits(data) {
875
+ return __awaiter(this, void 0, void 0, function* () {
876
+ return this.handleRequestToIframeAndPost({
877
+ methodMessage: 'portal:meld:getKycLimits',
878
+ errorMessage: 'portal:meld:getKycLimitsError',
879
+ resultMessage: 'portal:meld:getKycLimitsResult',
880
+ data: data !== null && data !== void 0 ? data : {},
881
+ });
882
+ });
883
+ }
721
884
  getSwapsQuoteV2(data, options) {
722
885
  return __awaiter(this, void 0, void 0, function* () {
723
886
  return this.handleRequestToIframeAndPost({
@@ -962,6 +1125,12 @@ class Mpc {
962
1125
  handleRequestToIframeAndPost({ methodMessage, errorMessage, resultMessage, data, progressMessage, progressCallback, mapReturnValue, traceId: providedTraceId, }) {
963
1126
  return __awaiter(this, void 0, void 0, function* () {
964
1127
  // Single traceId per operation: use provided or generate. Propagates to iframe and all internal REST/MPC calls.
1128
+ if (!providedTraceId &&
1129
+ (methodMessage.startsWith('portal:wasm:') ||
1130
+ methodMessage.startsWith('portal:mpc:') ||
1131
+ methodMessage.startsWith('portal:accountAbstraction:'))) {
1132
+ logger_1.sdkLogger.debug(`[Portal] No traceId propagated to handleRequestToIframeAndPost for method=${methodMessage}; generating a new one.`);
1133
+ }
965
1134
  const traceId = providedTraceId !== null && providedTraceId !== void 0 ? providedTraceId : (0, trace_1.generateTraceId)();
966
1135
  logger_1.sdkLogger.debug('[Portal] request traceId:', traceId, 'method:', methodMessage);
967
1136
  return new Promise((resolve, reject) => {
@@ -1178,6 +1347,33 @@ class Mpc {
1178
1347
  // Update the address
1179
1348
  const address = yield this.getAddress();
1180
1349
  this.portal.address = address;
1350
+ // Detect if wallet shares were cleared from storage (e.g., Safari ITP).
1351
+ // Must be awaited before triggerReady so the event fires before app callbacks run.
1352
+ try {
1353
+ const [client, shares] = yield Promise.all([
1354
+ this.getClient(),
1355
+ this.checkSharesOnDevice(),
1356
+ ]);
1357
+ const completedWallets = client.wallets.filter((w) => w.signingSharePairs.some((sp) => sp.status === 'completed'));
1358
+ const requiredCurves = completedWallets.map((w) => w.curve);
1359
+ const walletOnDevice = requiredCurves.length > 0 &&
1360
+ requiredCurves.every((curve) => !!shares[curve]);
1361
+ // No completed wallets means the user is in initial setup — no prior
1362
+ // device state to have been lost.
1363
+ const isInitialSetup = completedWallets.length === 0;
1364
+ const shouldEmitWalletNotOnDevice = !isInitialSetup && !walletOnDevice && !client.ejectedAt;
1365
+ if (shouldEmitWalletNotOnDevice) {
1366
+ const isBackedUp = client.wallets.some((w) => w.backupSharePairs.some((bp) => bp.status === 'completed'));
1367
+ this.portal.triggerWalletNotOnDevice({
1368
+ clientId: client.id,
1369
+ isBackedUp,
1370
+ reason: 'storage_cleared',
1371
+ });
1372
+ }
1373
+ }
1374
+ catch (detectionError) {
1375
+ logger_1.sdkLogger.warn('[Portal] walletNotOnDevice detection failed (initialization continues):', detectionError);
1376
+ }
1181
1377
  // Trigger the ready callback
1182
1378
  this.portal.triggerReady();
1183
1379
  }