squarefi-bff-api-module 1.24.34 → 1.25.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 (32) hide show
  1. package/README.md +60 -10
  2. package/dist/api/types/autogen/apiV2.types.d.ts +4 -3
  3. package/dist/api/types/types.d.ts +10 -131
  4. package/dist/api/wallets.d.ts +1 -1
  5. package/dist/api/wallets.js +4 -1
  6. package/dist/hooks/index.d.ts +1 -0
  7. package/dist/hooks/index.js +1 -0
  8. package/dist/hooks/useSupabaseSubscription/config.d.ts +2 -0
  9. package/dist/hooks/useSupabaseSubscription/config.js +9 -0
  10. package/dist/hooks/useSupabaseSubscription/index.d.ts +3 -0
  11. package/dist/hooks/useSupabaseSubscription/index.js +7 -0
  12. package/dist/hooks/useSupabaseSubscription/specialized.d.ts +5 -0
  13. package/dist/hooks/useSupabaseSubscription/specialized.js +11 -0
  14. package/dist/hooks/useSupabaseSubscription/types.d.ts +17 -0
  15. package/dist/hooks/useSupabaseSubscription/types.js +2 -0
  16. package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.d.ts +5 -0
  17. package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.js +38 -0
  18. package/dist/utils/encrypt.js +48 -2
  19. package/dist/utils/supabase.d.ts +1 -0
  20. package/dist/utils/supabase.js +14 -0
  21. package/package.json +2 -1
  22. package/src/api/types/autogen/apiV2.types.ts +4 -3
  23. package/src/api/types/types.ts +149 -139
  24. package/src/api/wallets.ts +9 -3
  25. package/src/hooks/index.ts +1 -0
  26. package/src/hooks/useSupabaseSubscription/config.ts +7 -0
  27. package/src/hooks/useSupabaseSubscription/index.ts +3 -0
  28. package/src/hooks/useSupabaseSubscription/specialized.ts +14 -0
  29. package/src/hooks/useSupabaseSubscription/types.ts +19 -0
  30. package/src/hooks/useSupabaseSubscription/useSupabaseSubscription.ts +55 -0
  31. package/src/utils/encrypt.ts +52 -2
  32. package/src/utils/supabase.ts +15 -0
package/README.md CHANGED
@@ -49,9 +49,19 @@ const cards = await api.issuing.cards.byWalletUuid.getAll({
49
49
 
50
50
  // 3) Exchange rates helper
51
51
  await api.exchange.byOrderType[OrderType.DEPOSIT_FIAT_SEPA].getByFromCurrency(firstWalletUuid);
52
- ```
53
52
 
54
- See the [Examples](#examples) section below for more real-life snippets.
53
+ // 4) Real-time subscriptions (React only)
54
+ import { useSupabaseSubscription } from 'squarefi-bff-api-module';
55
+
56
+ const { isConnected } = useSupabaseSubscription({
57
+ config: {
58
+ channelName: 'my-channel',
59
+ table: 'transactions',
60
+ event: '*',
61
+ },
62
+ callback: (payload) => console.log('Real-time update:', payload),
63
+ });
64
+ ```
55
65
 
56
66
  ---
57
67
 
@@ -59,19 +69,59 @@ See the [Examples](#examples) section below for more real-life snippets.
59
69
 
60
70
  The SDK reads connection details from process-level variables. When bundling for the browser, tools like **Vite**, **Webpack DefinePlugin**, or **Next.js** can safely inline those values at build time.
61
71
 
62
- | Name | Description | Required | Example |
63
- | -------------------------- | -------------------------------------------------------------------- | ----------------------------- | ----------------------------- |
64
- | `API_URL` | Base URL of the BFF **v1** service | ✅ | `https://api-v1.squarefi.com` |
65
- | `API_V2_URL` | Base URL of the BFF **v2** service | ✅ | `https://api-v2.squarefi.com` |
66
- | `API_TOTP_URL` | Base URL of the **TOTP / OTP** micro-service | ⚠️ _If you use TOTP features_ | `https://totp.squarefi.com` |
67
- | `TENANT_ID` | Your tenant / organisation identifier | ✅ | `tenant_12345` |
68
- | `LOGOUT_URL` | Frontend route where the user is redirected when refresh token fails | ❌ | `/auth/logout` |
69
- | `SERVER_PUBLIC_KEY_BASE64` | PEM encoded key (base64) used for request signing | ✅ | `MIIBIjANBgkqh…` |
72
+ | Name | Description | Required | Example |
73
+ | -------------------------- | -------------------------------------------------------------------- | ------------------------------ | ----------------------------- |
74
+ | `API_URL` | Base URL of the BFF **v1** service | ✅ | `https://api-v1.squarefi.com` |
75
+ | `API_V2_URL` | Base URL of the BFF **v2** service | ✅ | `https://api-v2.squarefi.com` |
76
+ | `API_TOTP_URL` | Base URL of the **TOTP / OTP** micro-service | ⚠️ _If you use TOTP features_ | `https://totp.squarefi.com` |
77
+ | `TENANT_ID` | Your tenant / organisation identifier | ✅ | `tenant_12345` |
78
+ | `LOGOUT_URL` | Frontend route where the user is redirected when refresh token fails | ❌ | `/auth/logout` |
79
+ | `SERVER_PUBLIC_KEY_BASE64` | PEM encoded key (base64) used for request signing | ✅ | `MIIBIjANBgkqh…` |
80
+ | `SUPABASE_URL` | Supabase project URL for real-time subscriptions | ⚠️ _If you use Supabase hooks_ | `https://xyz.supabase.co` |
81
+ | `SUPABASE_PUBLIC_KEY` | Supabase public anon key for client authentication | ⚠️ _If you use Supabase hooks_ | `eyJhbGciOiJIUzI1NiIs…` |
70
82
 
71
83
  > ℹ️ When running in Node.js you can place these variables in a `.env` file and load them with [dotenv](https://npmjs.com/package/dotenv).
72
84
 
73
85
  ---
74
86
 
87
+ ## 🔄 React Hooks
88
+
89
+ The SDK includes React hooks for real-time functionality powered by Supabase:
90
+
91
+ ### useSupabaseSubscription
92
+
93
+ A hook for subscribing to real-time database changes via Supabase.
94
+
95
+ ```tsx
96
+ import { useSupabaseSubscription } from 'squarefi-bff-api-module';
97
+
98
+ function MyComponent() {
99
+ const { isConnected, isClientAvailable } = useSupabaseSubscription({
100
+ config: {
101
+ channelName: 'wallet-transactions',
102
+ table: 'transactions',
103
+ schema: 'public',
104
+ event: 'INSERT', // 'INSERT' | 'UPDATE' | 'DELETE' | '*'
105
+ filter: 'wallet_id=eq.123',
106
+ },
107
+ callback: (payload) => {
108
+ console.log('New transaction:', payload);
109
+ },
110
+ enabled: true,
111
+ });
112
+
113
+ if (!isClientAvailable) {
114
+ return <div>Supabase not configured</div>;
115
+ }
116
+
117
+ return <div>Status: {isConnected ? 'Connected' : 'Disconnected'}</div>;
118
+ }
119
+ ```
120
+
121
+ > ⚠️ **Important**: The hook will throw an error if Supabase environment variables are missing and you attempt to use it. Make sure to set `SUPABASE_URL` and `SUPABASE_PUBLIC_KEY` environment variables.
122
+
123
+ ---
124
+
75
125
  ## 🗺️ API surface
76
126
 
77
127
  `squarefi_bff_api_client` is a plain object where every property is a namespaced group of operations. The list below reflects the current SDK version (v1.18.13).
@@ -1237,8 +1237,6 @@ export interface components {
1237
1237
  TransactionsFilter: {
1238
1238
  created_at?: string;
1239
1239
  /** @enum {string} */
1240
- status?: "complete" | "pending" | "canceled" | "failed" | "processing" | "new";
1241
- /** @enum {string} */
1242
1240
  type?: "deposit_crypto" | "withdrawal_crypto" | "deposit_fiat" | "withdrawal_fiat" | "deposit_vcard" | "withdrawal_vcard" | "deposit" | "withdrawal";
1243
1241
  /** @enum {string|null} */
1244
1242
  method?: "p2p" | "crypto" | "bank_transfer" | "exchange" | "sbp" | "internal_fiat" | null;
@@ -1255,6 +1253,7 @@ export interface components {
1255
1253
  to_created_at?: string;
1256
1254
  /** @default false */
1257
1255
  show_low_balance: boolean;
1256
+ status?: ("complete" | "pending" | "canceled" | "failed" | "processing" | "new")[];
1258
1257
  };
1259
1258
  ChainDto: {
1260
1259
  id: number;
@@ -2984,7 +2983,9 @@ export interface operations {
2984
2983
  };
2985
2984
  WalletsTransactionsController_export: {
2986
2985
  parameters: {
2987
- query?: never;
2986
+ query?: {
2987
+ status?: ("complete" | "pending" | "canceled" | "failed" | "processing" | "new")[];
2988
+ };
2988
2989
  header?: never;
2989
2990
  path: {
2990
2991
  wallet_id: string;
@@ -668,136 +668,6 @@ export declare namespace API {
668
668
  }
669
669
  }
670
670
  }
671
- namespace SubAccountsV2 {
672
- type SubAccountDetails = {
673
- iban: string;
674
- bank_name: string;
675
- swift_code: string;
676
- bank_address: string;
677
- receiver_name: string;
678
- payment_details: string;
679
- reference_number: string;
680
- registration_number: string;
681
- };
682
- interface SubAccount {
683
- balance: number;
684
- cards_count: number;
685
- created_at: string;
686
- currency: API.Currencies.FiatCurrency;
687
- fiat_balance: number;
688
- id: string;
689
- issuing_program: API.Cards.Config.Program;
690
- nick_name: string;
691
- program_id: string;
692
- realtimeauth_balance: number;
693
- status: string;
694
- total_balance: number;
695
- wallet_id: string;
696
- }
697
- namespace ExtendedSubAccount {
698
- interface ExtendedSubAccount extends SubAccount {
699
- account_details?: SubAccountDetails;
700
- payment_types: Array<{
701
- order_type: OrderType;
702
- }>;
703
- realtime_auth: [
704
- {
705
- crypto_token: string;
706
- fiat_account: string;
707
- id: string;
708
- priority: number;
709
- }
710
- ];
711
- }
712
- interface Request {
713
- wallet_uuid: string;
714
- fiat_account_id: string;
715
- }
716
- type Response = ExtendedSubAccount;
717
- }
718
- interface SubAccountWithCards extends SubAccount {
719
- cards: API.Cards.IssuingCardListItem[];
720
- }
721
- interface SubAccountsList<T extends SubAccount | SubAccountWithCards> {
722
- count: number;
723
- data: T[];
724
- }
725
- type SubAccountsListWithCards = SubAccountsList<SubAccountWithCards>;
726
- type SubAccountsListWithoutCards = SubAccountsList<SubAccount>;
727
- namespace CreateSubAccount {
728
- interface Request {
729
- wallet_id: string;
730
- program_id: string;
731
- }
732
- type Response = {
733
- id: string;
734
- balance: number;
735
- nick_name: string;
736
- wallet_id: string;
737
- created_at: string;
738
- account_currency: string;
739
- type: SubAccountType | string;
740
- program_id: string;
741
- status: 'ACTIVE';
742
- fiat: {
743
- code: string;
744
- uuid: string;
745
- symbol: string;
746
- enabled: boolean;
747
- coingecko: string;
748
- };
749
- issuing_program: {
750
- id: string;
751
- form_factor: CardFormFactor | string;
752
- brand: string;
753
- tokenizable: boolean;
754
- type: CardType | string;
755
- };
756
- };
757
- }
758
- namespace Transactions {
759
- type Transaction = {
760
- vendor_transaction_id: string;
761
- created_at: string;
762
- cleared_at: string;
763
- merchant: {
764
- name: string;
765
- category_code: string;
766
- city: string;
767
- country: string;
768
- };
769
- last4: string;
770
- title: string;
771
- billing_amount: number;
772
- billing_currency: string;
773
- transaction_amount: number;
774
- transaction_currency: string;
775
- vendor_sub_account_id: string;
776
- failure_reason: string;
777
- status: string;
778
- transaction_type: string;
779
- is_credit: boolean;
780
- has_receipt: boolean;
781
- adjustment_type: string;
782
- review_status: string;
783
- group: string;
784
- total_amount: number;
785
- };
786
- namespace TransactionList {
787
- interface Request {
788
- fiat_account_id: string;
789
- wallet_uuid: string;
790
- limit?: number;
791
- offset?: number;
792
- }
793
- interface Response {
794
- count: number;
795
- data: Transaction[];
796
- has_more: boolean;
797
- }
798
- }
799
- }
800
- }
801
671
  namespace Issuing {
802
672
  namespace Programs {
803
673
  type Request = {
@@ -2419,7 +2289,7 @@ export declare namespace API {
2419
2289
  offset: number;
2420
2290
  filter?: {
2421
2291
  created_at?: string;
2422
- status?: WalletTransactionStatus;
2292
+ status?: WalletTransactionStatus[];
2423
2293
  type?: WalletTransactionType;
2424
2294
  method?: WalletTransactionMethod;
2425
2295
  record_type?: WalletTransactionRecordType;
@@ -2435,6 +2305,15 @@ export declare namespace API {
2435
2305
  total: number;
2436
2306
  data: Transaction[];
2437
2307
  };
2308
+ namespace ExportCsv {
2309
+ type Request = {
2310
+ wallet_uuid: string;
2311
+ status?: WalletTransactionStatus[];
2312
+ from_created_at?: string;
2313
+ to_created_at?: string;
2314
+ };
2315
+ type Response = string;
2316
+ }
2438
2317
  }
2439
2318
  }
2440
2319
  }
@@ -18,7 +18,7 @@ export declare const wallets: {
18
18
  getByUuid: ({ wallet_uuid, uuid, }: API.Wallets.WalletTransactions.GetByUuid.Request) => Promise<API.Wallets.WalletTransactions.DetailedTransaction>;
19
19
  };
20
20
  csv: {
21
- getByWalletUuid: (wallet_uuid: string) => Promise<string>;
21
+ getByWalletUuid: ({ wallet_uuid, ...params }: API.Wallets.WalletTransactions.TransactionList.ExportCsv.Request) => Promise<API.Wallets.WalletTransactions.TransactionList.ExportCsv.Response>;
22
22
  };
23
23
  };
24
24
  };
@@ -47,7 +47,10 @@ exports.wallets = {
47
47
  getByUuid: ({ wallet_uuid, uuid, }) => apiClientFactory_1.apiClientV2.getRequest(`/wallets/${wallet_uuid}/transactions/${uuid}`),
48
48
  },
49
49
  csv: {
50
- getByWalletUuid: (wallet_uuid) => apiClientFactory_1.apiClientV1.getRequest(`/wallets/transactions/${wallet_uuid}/csv`),
50
+ getByWalletUuid: (_a) => {
51
+ var { wallet_uuid } = _a, params = __rest(_a, ["wallet_uuid"]);
52
+ return apiClientFactory_1.apiClientV2.getRequest(`/wallets/${wallet_uuid}/transactions/export/csv`, { params });
53
+ },
51
54
  },
52
55
  },
53
56
  };
@@ -1 +1,2 @@
1
1
  export * from './useCalc';
2
+ export * from './useSupabaseSubscription';
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./useCalc"), exports);
18
+ __exportStar(require("./useSupabaseSubscription"), exports);
@@ -0,0 +1,2 @@
1
+ import { SubscriptionConfig } from './types';
2
+ export declare const createWalletTransactionsConfig: (walletId: string) => SubscriptionConfig;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWalletTransactionsConfig = void 0;
4
+ const createWalletTransactionsConfig = (walletId) => ({
5
+ channelName: `wallet-transactions-${walletId}`,
6
+ table: 'transactions',
7
+ filter: `wallet_id=eq.${walletId}`,
8
+ });
9
+ exports.createWalletTransactionsConfig = createWalletTransactionsConfig;
@@ -0,0 +1,3 @@
1
+ export { useSupabaseSubscription } from './useSupabaseSubscription';
2
+ export { useWalletTransactionsSubscription } from './specialized';
3
+ export type { SubscriptionConfig, UseSupabaseSubscriptionProps, UseWalletTransactionsSubscriptionProps } from './types';
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useWalletTransactionsSubscription = exports.useSupabaseSubscription = void 0;
4
+ var useSupabaseSubscription_1 = require("./useSupabaseSubscription");
5
+ Object.defineProperty(exports, "useSupabaseSubscription", { enumerable: true, get: function () { return useSupabaseSubscription_1.useSupabaseSubscription; } });
6
+ var specialized_1 = require("./specialized");
7
+ Object.defineProperty(exports, "useWalletTransactionsSubscription", { enumerable: true, get: function () { return specialized_1.useWalletTransactionsSubscription; } });
@@ -0,0 +1,5 @@
1
+ import { UseWalletTransactionsSubscriptionProps } from './types';
2
+ export declare const useWalletTransactionsSubscription: ({ walletId, callback, enabled, }: UseWalletTransactionsSubscriptionProps) => {
3
+ isConnected: boolean;
4
+ isClientAvailable: boolean;
5
+ };
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useWalletTransactionsSubscription = void 0;
4
+ const config_1 = require("./config");
5
+ const useSupabaseSubscription_1 = require("./useSupabaseSubscription");
6
+ const useWalletTransactionsSubscription = ({ walletId, callback, enabled = true, }) => (0, useSupabaseSubscription_1.useSupabaseSubscription)({
7
+ config: (0, config_1.createWalletTransactionsConfig)(walletId || ''),
8
+ callback,
9
+ enabled: enabled && !!walletId,
10
+ });
11
+ exports.useWalletTransactionsSubscription = useWalletTransactionsSubscription;
@@ -0,0 +1,17 @@
1
+ export interface SubscriptionConfig {
2
+ channelName: string;
3
+ table: string;
4
+ schema?: string;
5
+ event?: 'INSERT' | 'UPDATE' | 'DELETE' | '*';
6
+ filter?: string;
7
+ }
8
+ export interface UseSupabaseSubscriptionProps {
9
+ config: SubscriptionConfig;
10
+ callback: (payload?: unknown) => void;
11
+ enabled?: boolean;
12
+ }
13
+ export interface UseWalletTransactionsSubscriptionProps {
14
+ walletId: string | undefined;
15
+ callback: () => void;
16
+ enabled?: boolean;
17
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import { UseSupabaseSubscriptionProps } from './types';
2
+ export declare const useSupabaseSubscription: ({ config, callback, enabled }: UseSupabaseSubscriptionProps) => {
3
+ isConnected: boolean;
4
+ isClientAvailable: boolean;
5
+ };
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSupabaseSubscription = void 0;
4
+ const react_1 = require("react");
5
+ const supabase_1 = require("../../utils/supabase");
6
+ const useSupabaseSubscription = ({ config, callback, enabled = true }) => {
7
+ const subscriptionRef = (0, react_1.useRef)(null);
8
+ const callbackRef = (0, react_1.useRef)(callback);
9
+ callbackRef.current = callback;
10
+ (0, react_1.useEffect)(() => {
11
+ if (!enabled) {
12
+ return;
13
+ }
14
+ if (!supabase_1.supabaseClient) {
15
+ throw new Error('Supabase client is not available');
16
+ }
17
+ if (subscriptionRef.current) {
18
+ supabase_1.supabaseClient.removeChannel(subscriptionRef.current);
19
+ subscriptionRef.current = null;
20
+ }
21
+ const subscription = supabase_1.supabaseClient
22
+ .channel(config.channelName)
23
+ .on('postgres_changes', Object.assign({ event: config.event || '*', schema: config.schema || 'public', table: config.table }, (config.filter && { filter: config.filter })), (payload) => callbackRef.current(payload))
24
+ .subscribe();
25
+ subscriptionRef.current = subscription;
26
+ return () => {
27
+ if (subscriptionRef.current && supabase_1.supabaseClient) {
28
+ supabase_1.supabaseClient.removeChannel(subscriptionRef.current);
29
+ subscriptionRef.current = null;
30
+ }
31
+ };
32
+ }, [enabled, config.channelName, config.table, config.schema, config.event, config.filter]);
33
+ return {
34
+ isConnected: !!subscriptionRef.current,
35
+ isClientAvailable: !!supabase_1.supabaseClient,
36
+ };
37
+ };
38
+ exports.useSupabaseSubscription = useSupabaseSubscription;
@@ -27,10 +27,56 @@ const decryptAESData = (encryptedData, iv, secretKey) => __awaiter(void 0, void
27
27
  return JSON.parse(decrypted);
28
28
  });
29
29
  exports.decryptAESData = decryptAESData;
30
+ /**
31
+ * Очищает и валидирует публичный RSA ключ
32
+ * Исправляет ошибку InvalidAsn1Error: encoding too long
33
+ * путем удаления лишних символов и нормализации переносов строк
34
+ */
35
+ const cleanAndValidatePublicKey = (publicKey) => {
36
+ try {
37
+ // Декодируем base64 ключ
38
+ const publicKeyBase64 = Buffer.from(publicKey, 'base64').toString('utf8');
39
+ // Удаляем лишние символы (переносы строк, пробелы в начале и конце)
40
+ // Нормализуем переносы строк для корректной обработки ASN.1
41
+ const cleanedKey = publicKeyBase64.trim().replace(/\r?\n|\r/g, '\n');
42
+ // Проверяем, что ключ содержит необходимые маркеры
43
+ if (!cleanedKey.includes('BEGIN') || !cleanedKey.includes('END')) {
44
+ throw new Error('Invalid public key format: missing BEGIN/END markers');
45
+ }
46
+ return cleanedKey;
47
+ }
48
+ catch (error) {
49
+ throw new Error(`Invalid public key format: ${error instanceof Error ? error.message : 'Unknown error'}`);
50
+ }
51
+ };
52
+ /**
53
+ * Автоматически определяет формат RSA ключа по заголовку
54
+ * Помогает избежать ошибок импорта при неправильном указании формата
55
+ */
56
+ const detectKeyFormat = (key) => {
57
+ if (key.includes('BEGIN RSA PUBLIC KEY')) {
58
+ return 'pkcs1';
59
+ }
60
+ else if (key.includes('BEGIN PUBLIC KEY')) {
61
+ return 'pkcs8';
62
+ }
63
+ // По умолчанию возвращаем pkcs8, как было ранее
64
+ return 'pkcs8';
65
+ };
30
66
  const makeSecureRequest = (_a) => __awaiter(void 0, [_a], void 0, function* ({ callback, publicKey }) {
31
67
  const clientRsa = new node_rsa_1.default();
32
- const publicKeyBase64 = Buffer.from(publicKey, 'base64').toString('utf8');
33
- clientRsa.importKey(publicKeyBase64, 'pkcs8-public-pem');
68
+ try {
69
+ // Очищаем и валидируем публичный ключ
70
+ const cleanedPublicKey = cleanAndValidatePublicKey(publicKey);
71
+ // Определяем формат ключа автоматически
72
+ const keyFormat = detectKeyFormat(cleanedPublicKey);
73
+ // Импортируем ключ с правильным форматом
74
+ clientRsa.importKey(cleanedPublicKey, `${keyFormat}-public-pem`);
75
+ }
76
+ catch (error) {
77
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
78
+ throw new Error(`Failed to import RSA public key: ${errorMessage}`);
79
+ }
34
80
  const clientSecretKey = (0, exports.generateSecretKey)();
35
81
  const clientPayload = {
36
82
  key: clientSecretKey.toString('base64'),
@@ -0,0 +1 @@
1
+ export declare const supabaseClient: import("@supabase/supabase-js").SupabaseClient<any, "public", any> | null;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.supabaseClient = void 0;
4
+ const supabase_js_1 = require("@supabase/supabase-js");
5
+ const createSupabaseClient = () => {
6
+ const supabaseUrl = process.env.SUPABASE_URL;
7
+ const supabasePublicKey = process.env.SUPABASE_PUBLIC_KEY;
8
+ if (!supabaseUrl || !supabasePublicKey) {
9
+ console.warn('Supabase environment variables are missing. Client will not be created.');
10
+ return null;
11
+ }
12
+ return (0, supabase_js_1.createClient)(supabaseUrl, supabasePublicKey);
13
+ };
14
+ exports.supabaseClient = createSupabaseClient();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squarefi-bff-api-module",
3
- "version": "1.24.34",
3
+ "version": "1.25.0",
4
4
  "description": "Squarefi BFF API client module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "author": "Your Name",
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
+ "@supabase/supabase-js": "^2.55.0",
26
27
  "@telegram-apps/sdk-react": "^3.1.2",
27
28
  "axios": "^1.6.7",
28
29
  "lodash.debounce": "^4.0.8",
@@ -1238,8 +1238,6 @@ export interface components {
1238
1238
  TransactionsFilter: {
1239
1239
  created_at?: string;
1240
1240
  /** @enum {string} */
1241
- status?: "complete" | "pending" | "canceled" | "failed" | "processing" | "new";
1242
- /** @enum {string} */
1243
1241
  type?: "deposit_crypto" | "withdrawal_crypto" | "deposit_fiat" | "withdrawal_fiat" | "deposit_vcard" | "withdrawal_vcard" | "deposit" | "withdrawal";
1244
1242
  /** @enum {string|null} */
1245
1243
  method?: "p2p" | "crypto" | "bank_transfer" | "exchange" | "sbp" | "internal_fiat" | null;
@@ -1256,6 +1254,7 @@ export interface components {
1256
1254
  to_created_at?: string;
1257
1255
  /** @default false */
1258
1256
  show_low_balance: boolean;
1257
+ status?: ("complete" | "pending" | "canceled" | "failed" | "processing" | "new")[];
1259
1258
  };
1260
1259
  ChainDto: {
1261
1260
  id: number;
@@ -2985,7 +2984,9 @@ export interface operations {
2985
2984
  };
2986
2985
  WalletsTransactionsController_export: {
2987
2986
  parameters: {
2988
- query?: never;
2987
+ query?: {
2988
+ status?: ("complete" | "pending" | "canceled" | "failed" | "processing" | "new")[];
2989
+ };
2989
2990
  header?: never;
2990
2991
  path: {
2991
2992
  wallet_id: string;
@@ -819,144 +819,144 @@ export namespace API {
819
819
  }
820
820
  }
821
821
 
822
- export namespace SubAccountsV2 {
823
- export type SubAccountDetails = {
824
- iban: string;
825
- bank_name: string;
826
- swift_code: string;
827
- bank_address: string;
828
- receiver_name: string;
829
- payment_details: string;
830
- reference_number: string;
831
- registration_number: string;
832
- };
833
-
834
- export interface SubAccount {
835
- balance: number;
836
- cards_count: number;
837
- created_at: string;
838
- currency: API.Currencies.FiatCurrency;
839
- fiat_balance: number;
840
- id: string;
841
- issuing_program: API.Cards.Config.Program;
842
- nick_name: string;
843
- program_id: string;
844
- realtimeauth_balance: number;
845
- status: string;
846
- total_balance: number;
847
- wallet_id: string;
848
- }
849
-
850
- export namespace ExtendedSubAccount {
851
- export interface ExtendedSubAccount extends SubAccount {
852
- account_details?: SubAccountDetails;
853
- payment_types: Array<{ order_type: OrderType }>;
854
- realtime_auth: [
855
- {
856
- crypto_token: string;
857
- fiat_account: string;
858
- id: string;
859
- priority: number;
860
- }
861
- ];
862
- }
863
- export interface Request {
864
- wallet_uuid: string;
865
- fiat_account_id: string;
866
- }
867
-
868
- export type Response = ExtendedSubAccount;
869
- }
870
-
871
- export interface SubAccountWithCards extends SubAccount {
872
- cards: API.Cards.IssuingCardListItem[];
873
- }
874
-
875
- export interface SubAccountsList<T extends SubAccount | SubAccountWithCards> {
876
- count: number;
877
- data: T[];
878
- }
879
-
880
- export type SubAccountsListWithCards = SubAccountsList<SubAccountWithCards>;
881
- export type SubAccountsListWithoutCards = SubAccountsList<SubAccount>;
882
-
883
- export namespace CreateSubAccount {
884
- export interface Request {
885
- wallet_id: string;
886
- program_id: string;
887
- }
888
- export type Response = {
889
- id: string;
890
- balance: number;
891
- nick_name: string;
892
- wallet_id: string;
893
- created_at: string;
894
- account_currency: string;
895
- type: SubAccountType | string;
896
- program_id: string;
897
- status: 'ACTIVE';
898
- fiat: {
899
- code: string;
900
- uuid: string;
901
- symbol: string;
902
- enabled: boolean;
903
- coingecko: string;
904
- };
905
- issuing_program: {
906
- id: string;
907
- form_factor: CardFormFactor | string;
908
- brand: string;
909
- tokenizable: boolean;
910
- type: CardType | string;
911
- };
912
- };
913
- }
914
-
915
- export namespace Transactions {
916
- // export type Transaction = API.Cards.TransactionItem;
917
- export type Transaction = {
918
- vendor_transaction_id: string;
919
- created_at: string;
920
- cleared_at: string;
921
- merchant: {
922
- name: string;
923
- category_code: string;
924
- city: string;
925
- country: string;
926
- };
927
- last4: string;
928
- title: string;
929
- billing_amount: number;
930
- billing_currency: string;
931
- transaction_amount: number;
932
- transaction_currency: string;
933
- vendor_sub_account_id: string;
934
- failure_reason: string;
935
- status: string;
936
- transaction_type: string;
937
- is_credit: boolean;
938
- has_receipt: boolean;
939
- adjustment_type: string;
940
- review_status: string;
941
- group: string;
942
- total_amount: number;
943
- };
944
-
945
- export namespace TransactionList {
946
- export interface Request {
947
- fiat_account_id: string;
948
- wallet_uuid: string;
949
- limit?: number;
950
- offset?: number;
951
- }
952
- export interface Response {
953
- count: number;
954
- data: Transaction[];
955
- has_more: boolean;
956
- }
957
- }
958
- }
959
- }
822
+ // export namespace SubAccountsV2 {
823
+ // export type SubAccountDetails = {
824
+ // iban: string;
825
+ // bank_name: string;
826
+ // swift_code: string;
827
+ // bank_address: string;
828
+ // receiver_name: string;
829
+ // payment_details: string;
830
+ // reference_number: string;
831
+ // registration_number: string;
832
+ // };
833
+
834
+ // export interface SubAccount {
835
+ // balance: number;
836
+ // cards_count: number;
837
+ // created_at: string;
838
+ // currency: API.Currencies.FiatCurrency;
839
+ // fiat_balance: number;
840
+ // id: string;
841
+ // issuing_program: API.Cards.Config.Program;
842
+ // nick_name: string;
843
+ // program_id: string;
844
+ // realtimeauth_balance: number;
845
+ // status: string;
846
+ // total_balance: number;
847
+ // wallet_id: string;
848
+ // }
849
+
850
+ // export namespace ExtendedSubAccount {
851
+ // export interface ExtendedSubAccount extends SubAccount {
852
+ // account_details?: SubAccountDetails;
853
+ // payment_types: Array<{ order_type: OrderType }>;
854
+ // realtime_auth: [
855
+ // {
856
+ // crypto_token: string;
857
+ // fiat_account: string;
858
+ // id: string;
859
+ // priority: number;
860
+ // }
861
+ // ];
862
+ // }
863
+ // export interface Request {
864
+ // wallet_uuid: string;
865
+ // fiat_account_id: string;
866
+ // }
867
+
868
+ // export type Response = ExtendedSubAccount;
869
+ // }
870
+
871
+ // export interface SubAccountWithCards extends SubAccount {
872
+ // cards: API.Cards.IssuingCardListItem[];
873
+ // }
874
+
875
+ // export interface SubAccountsList<T extends SubAccount | SubAccountWithCards> {
876
+ // count: number;
877
+ // data: T[];
878
+ // }
879
+
880
+ // export type SubAccountsListWithCards = SubAccountsList<SubAccountWithCards>;
881
+ // export type SubAccountsListWithoutCards = SubAccountsList<SubAccount>;
882
+
883
+ // export namespace CreateSubAccount {
884
+ // export interface Request {
885
+ // wallet_id: string;
886
+ // program_id: string;
887
+ // }
888
+ // export type Response = {
889
+ // id: string;
890
+ // balance: number;
891
+ // nick_name: string;
892
+ // wallet_id: string;
893
+ // created_at: string;
894
+ // account_currency: string;
895
+ // type: SubAccountType | string;
896
+ // program_id: string;
897
+ // status: 'ACTIVE';
898
+ // fiat: {
899
+ // code: string;
900
+ // uuid: string;
901
+ // symbol: string;
902
+ // enabled: boolean;
903
+ // coingecko: string;
904
+ // };
905
+ // issuing_program: {
906
+ // id: string;
907
+ // form_factor: CardFormFactor | string;
908
+ // brand: string;
909
+ // tokenizable: boolean;
910
+ // type: CardType | string;
911
+ // };
912
+ // };
913
+ // }
914
+
915
+ // export namespace Transactions {
916
+ // // export type Transaction = API.Cards.TransactionItem;
917
+ // export type Transaction = {
918
+ // vendor_transaction_id: string;
919
+ // created_at: string;
920
+ // cleared_at: string;
921
+ // merchant: {
922
+ // name: string;
923
+ // category_code: string;
924
+ // city: string;
925
+ // country: string;
926
+ // };
927
+ // last4: string;
928
+ // title: string;
929
+ // billing_amount: number;
930
+ // billing_currency: string;
931
+ // transaction_amount: number;
932
+ // transaction_currency: string;
933
+ // vendor_sub_account_id: string;
934
+ // failure_reason: string;
935
+ // status: string;
936
+ // transaction_type: string;
937
+ // is_credit: boolean;
938
+ // has_receipt: boolean;
939
+ // adjustment_type: string;
940
+ // review_status: string;
941
+ // group: string;
942
+ // total_amount: number;
943
+ // };
944
+
945
+ // export namespace TransactionList {
946
+ // export interface Request {
947
+ // fiat_account_id: string;
948
+ // wallet_uuid: string;
949
+ // limit?: number;
950
+ // offset?: number;
951
+ // }
952
+ // export interface Response {
953
+ // count: number;
954
+ // data: Transaction[];
955
+ // has_more: boolean;
956
+ // }
957
+ // }
958
+ // }
959
+ // }
960
960
 
961
961
  export namespace Issuing {
962
962
  export namespace Programs {
@@ -2824,7 +2824,7 @@ export namespace API {
2824
2824
  offset: number;
2825
2825
  filter?: {
2826
2826
  created_at?: string;
2827
- status?: WalletTransactionStatus;
2827
+ status?: WalletTransactionStatus[];
2828
2828
  type?: WalletTransactionType;
2829
2829
  method?: WalletTransactionMethod;
2830
2830
  record_type?: WalletTransactionRecordType;
@@ -2840,6 +2840,16 @@ export namespace API {
2840
2840
  total: number;
2841
2841
  data: Transaction[];
2842
2842
  };
2843
+
2844
+ export namespace ExportCsv {
2845
+ export type Request = {
2846
+ wallet_uuid: string;
2847
+ status?: WalletTransactionStatus[];
2848
+ from_created_at?: string;
2849
+ to_created_at?: string;
2850
+ };
2851
+ export type Response = string;
2852
+ }
2843
2853
  }
2844
2854
  }
2845
2855
  }
@@ -1,6 +1,6 @@
1
1
  import { API } from './types/types';
2
2
 
3
- import { apiClientV1, apiClientV2 } from '../utils/apiClientFactory';
3
+ import { apiClientV2 } from '../utils/apiClientFactory';
4
4
 
5
5
  import { defaultPaginationParams, WalletTypeValues } from '../constants';
6
6
 
@@ -52,8 +52,14 @@ export const wallets = {
52
52
  ),
53
53
  },
54
54
  csv: {
55
- getByWalletUuid: (wallet_uuid: string): Promise<string> =>
56
- apiClientV1.getRequest<string>(`/wallets/transactions/${wallet_uuid}/csv`),
55
+ getByWalletUuid: ({
56
+ wallet_uuid,
57
+ ...params
58
+ }: API.Wallets.WalletTransactions.TransactionList.ExportCsv.Request): Promise<API.Wallets.WalletTransactions.TransactionList.ExportCsv.Response> =>
59
+ apiClientV2.getRequest<API.Wallets.WalletTransactions.TransactionList.ExportCsv.Response>(
60
+ `/wallets/${wallet_uuid}/transactions/export/csv`,
61
+ { params }
62
+ ),
57
63
  },
58
64
  },
59
65
  };
@@ -1 +1,2 @@
1
1
  export * from './useCalc';
2
+ export * from './useSupabaseSubscription';
@@ -0,0 +1,7 @@
1
+ import { SubscriptionConfig } from './types';
2
+
3
+ export const createWalletTransactionsConfig = (walletId: string): SubscriptionConfig => ({
4
+ channelName: `wallet-transactions-${walletId}`,
5
+ table: 'transactions',
6
+ filter: `wallet_id=eq.${walletId}`,
7
+ });
@@ -0,0 +1,3 @@
1
+ export { useSupabaseSubscription } from './useSupabaseSubscription';
2
+ export { useWalletTransactionsSubscription } from './specialized';
3
+ export type { SubscriptionConfig, UseSupabaseSubscriptionProps, UseWalletTransactionsSubscriptionProps } from './types';
@@ -0,0 +1,14 @@
1
+ import { createWalletTransactionsConfig } from './config';
2
+ import { UseWalletTransactionsSubscriptionProps } from './types';
3
+ import { useSupabaseSubscription } from './useSupabaseSubscription';
4
+
5
+ export const useWalletTransactionsSubscription = ({
6
+ walletId,
7
+ callback,
8
+ enabled = true,
9
+ }: UseWalletTransactionsSubscriptionProps) =>
10
+ useSupabaseSubscription({
11
+ config: createWalletTransactionsConfig(walletId || ''),
12
+ callback,
13
+ enabled: enabled && !!walletId,
14
+ });
@@ -0,0 +1,19 @@
1
+ export interface SubscriptionConfig {
2
+ channelName: string;
3
+ table: string;
4
+ schema?: string;
5
+ event?: 'INSERT' | 'UPDATE' | 'DELETE' | '*';
6
+ filter?: string;
7
+ }
8
+
9
+ export interface UseSupabaseSubscriptionProps {
10
+ config: SubscriptionConfig;
11
+ callback: (payload?: unknown) => void;
12
+ enabled?: boolean;
13
+ }
14
+
15
+ export interface UseWalletTransactionsSubscriptionProps {
16
+ walletId: string | undefined;
17
+ callback: () => void;
18
+ enabled?: boolean;
19
+ }
@@ -0,0 +1,55 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ import { UseSupabaseSubscriptionProps } from './types';
4
+
5
+ import { supabaseClient } from '../../utils/supabase';
6
+
7
+ export const useSupabaseSubscription = ({ config, callback, enabled = true }: UseSupabaseSubscriptionProps) => {
8
+ const subscriptionRef = useRef<any>(null);
9
+ const callbackRef = useRef(callback);
10
+
11
+ callbackRef.current = callback;
12
+
13
+ useEffect(() => {
14
+ if (!enabled) {
15
+ return;
16
+ }
17
+
18
+ if (!supabaseClient) {
19
+ throw new Error('Supabase client is not available');
20
+ }
21
+
22
+ if (subscriptionRef.current) {
23
+ supabaseClient.removeChannel(subscriptionRef.current);
24
+ subscriptionRef.current = null;
25
+ }
26
+
27
+ const subscription = supabaseClient
28
+ .channel(config.channelName)
29
+ .on(
30
+ 'postgres_changes' as any,
31
+ {
32
+ event: config.event || '*',
33
+ schema: config.schema || 'public',
34
+ table: config.table,
35
+ ...(config.filter && { filter: config.filter }),
36
+ },
37
+ (payload) => callbackRef.current(payload)
38
+ )
39
+ .subscribe();
40
+
41
+ subscriptionRef.current = subscription;
42
+
43
+ return () => {
44
+ if (subscriptionRef.current && supabaseClient) {
45
+ supabaseClient.removeChannel(subscriptionRef.current);
46
+ subscriptionRef.current = null;
47
+ }
48
+ };
49
+ }, [enabled, config.channelName, config.table, config.schema, config.event, config.filter]);
50
+
51
+ return {
52
+ isConnected: !!subscriptionRef.current,
53
+ isClientAvailable: !!supabaseClient,
54
+ };
55
+ };
@@ -20,11 +20,61 @@ export const decryptAESData = async (encryptedData: string, iv: string, secretKe
20
20
  return JSON.parse(decrypted);
21
21
  };
22
22
 
23
+ /**
24
+ * Очищает и валидирует публичный RSA ключ
25
+ * Исправляет ошибку InvalidAsn1Error: encoding too long
26
+ * путем удаления лишних символов и нормализации переносов строк
27
+ */
28
+ const cleanAndValidatePublicKey = (publicKey: string): string => {
29
+ try {
30
+ // Декодируем base64 ключ
31
+ const publicKeyBase64 = Buffer.from(publicKey, 'base64').toString('utf8');
32
+
33
+ // Удаляем лишние символы (переносы строк, пробелы в начале и конце)
34
+ // Нормализуем переносы строк для корректной обработки ASN.1
35
+ const cleanedKey = publicKeyBase64.trim().replace(/\r?\n|\r/g, '\n');
36
+
37
+ // Проверяем, что ключ содержит необходимые маркеры
38
+ if (!cleanedKey.includes('BEGIN') || !cleanedKey.includes('END')) {
39
+ throw new Error('Invalid public key format: missing BEGIN/END markers');
40
+ }
41
+
42
+ return cleanedKey;
43
+ } catch (error) {
44
+ throw new Error(`Invalid public key format: ${error instanceof Error ? error.message : 'Unknown error'}`);
45
+ }
46
+ };
47
+
48
+ /**
49
+ * Автоматически определяет формат RSA ключа по заголовку
50
+ * Помогает избежать ошибок импорта при неправильном указании формата
51
+ */
52
+ const detectKeyFormat = (key: string): 'pkcs1' | 'pkcs8' => {
53
+ if (key.includes('BEGIN RSA PUBLIC KEY')) {
54
+ return 'pkcs1';
55
+ } else if (key.includes('BEGIN PUBLIC KEY')) {
56
+ return 'pkcs8';
57
+ }
58
+ // По умолчанию возвращаем pkcs8, как было ранее
59
+ return 'pkcs8';
60
+ };
61
+
23
62
  export const makeSecureRequest = async <T>({ callback, publicKey }: MakeSecureRequestParams): Promise<T> => {
24
63
  const clientRsa = new NodeRSA();
25
64
 
26
- const publicKeyBase64 = Buffer.from(publicKey, 'base64').toString('utf8');
27
- clientRsa.importKey(publicKeyBase64, 'pkcs8-public-pem');
65
+ try {
66
+ // Очищаем и валидируем публичный ключ
67
+ const cleanedPublicKey = cleanAndValidatePublicKey(publicKey);
68
+
69
+ // Определяем формат ключа автоматически
70
+ const keyFormat = detectKeyFormat(cleanedPublicKey);
71
+
72
+ // Импортируем ключ с правильным форматом
73
+ clientRsa.importKey(cleanedPublicKey, `${keyFormat}-public-pem`);
74
+ } catch (error) {
75
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
76
+ throw new Error(`Failed to import RSA public key: ${errorMessage}`);
77
+ }
28
78
 
29
79
  const clientSecretKey = generateSecretKey();
30
80
  const clientPayload = {
@@ -0,0 +1,15 @@
1
+ import { createClient } from '@supabase/supabase-js';
2
+
3
+ const createSupabaseClient = () => {
4
+ const supabaseUrl = process.env.SUPABASE_URL;
5
+ const supabasePublicKey = process.env.SUPABASE_PUBLIC_KEY;
6
+
7
+ if (!supabaseUrl || !supabasePublicKey) {
8
+ console.warn('Supabase environment variables are missing. Client will not be created.');
9
+ return null;
10
+ }
11
+
12
+ return createClient(supabaseUrl, supabasePublicKey);
13
+ };
14
+
15
+ export const supabaseClient = createSupabaseClient();