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.
- package/README.md +60 -10
- package/dist/api/types/autogen/apiV2.types.d.ts +4 -3
- package/dist/api/types/types.d.ts +10 -131
- package/dist/api/wallets.d.ts +1 -1
- package/dist/api/wallets.js +4 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useSupabaseSubscription/config.d.ts +2 -0
- package/dist/hooks/useSupabaseSubscription/config.js +9 -0
- package/dist/hooks/useSupabaseSubscription/index.d.ts +3 -0
- package/dist/hooks/useSupabaseSubscription/index.js +7 -0
- package/dist/hooks/useSupabaseSubscription/specialized.d.ts +5 -0
- package/dist/hooks/useSupabaseSubscription/specialized.js +11 -0
- package/dist/hooks/useSupabaseSubscription/types.d.ts +17 -0
- package/dist/hooks/useSupabaseSubscription/types.js +2 -0
- package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.d.ts +5 -0
- package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.js +38 -0
- package/dist/utils/encrypt.js +48 -2
- package/dist/utils/supabase.d.ts +1 -0
- package/dist/utils/supabase.js +14 -0
- package/package.json +2 -1
- package/src/api/types/autogen/apiV2.types.ts +4 -3
- package/src/api/types/types.ts +149 -139
- package/src/api/wallets.ts +9 -3
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useSupabaseSubscription/config.ts +7 -0
- package/src/hooks/useSupabaseSubscription/index.ts +3 -0
- package/src/hooks/useSupabaseSubscription/specialized.ts +14 -0
- package/src/hooks/useSupabaseSubscription/types.ts +19 -0
- package/src/hooks/useSupabaseSubscription/useSupabaseSubscription.ts +55 -0
- package/src/utils/encrypt.ts +52 -2
- 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
|
-
|
|
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
|
|
63
|
-
| -------------------------- | -------------------------------------------------------------------- |
|
|
64
|
-
| `API_URL` | Base URL of the BFF **v1** service | ✅
|
|
65
|
-
| `API_V2_URL` | Base URL of the BFF **v2** service | ✅
|
|
66
|
-
| `API_TOTP_URL` | Base URL of the **TOTP / OTP** micro-service | ⚠️ _If you use TOTP features_
|
|
67
|
-
| `TENANT_ID` | Your tenant / organisation identifier | ✅
|
|
68
|
-
| `LOGOUT_URL` | Frontend route where the user is redirected when refresh token fails | ❌
|
|
69
|
-
| `SERVER_PUBLIC_KEY_BASE64` | PEM encoded key (base64) used for request signing | ✅
|
|
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?:
|
|
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
|
}
|
package/dist/api/wallets.d.ts
CHANGED
|
@@ -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:
|
|
21
|
+
getByWalletUuid: ({ wallet_uuid, ...params }: API.Wallets.WalletTransactions.TransactionList.ExportCsv.Request) => Promise<API.Wallets.WalletTransactions.TransactionList.ExportCsv.Response>;
|
|
22
22
|
};
|
|
23
23
|
};
|
|
24
24
|
};
|
package/dist/api/wallets.js
CHANGED
|
@@ -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: (
|
|
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
|
};
|
package/dist/hooks/index.d.ts
CHANGED
package/dist/hooks/index.js
CHANGED
|
@@ -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,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,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,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;
|
package/dist/utils/encrypt.js
CHANGED
|
@@ -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
|
-
|
|
33
|
-
|
|
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.
|
|
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?:
|
|
2987
|
+
query?: {
|
|
2988
|
+
status?: ("complete" | "pending" | "canceled" | "failed" | "processing" | "new")[];
|
|
2989
|
+
};
|
|
2989
2990
|
header?: never;
|
|
2990
2991
|
path: {
|
|
2991
2992
|
wallet_id: string;
|
package/src/api/types/types.ts
CHANGED
|
@@ -819,144 +819,144 @@ export namespace API {
|
|
|
819
819
|
}
|
|
820
820
|
}
|
|
821
821
|
|
|
822
|
-
export namespace SubAccountsV2 {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
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
|
}
|
package/src/api/wallets.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { API } from './types/types';
|
|
2
2
|
|
|
3
|
-
import {
|
|
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: (
|
|
56
|
-
|
|
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
|
};
|
package/src/hooks/index.ts
CHANGED
|
@@ -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
|
+
};
|
package/src/utils/encrypt.ts
CHANGED
|
@@ -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
|
-
|
|
27
|
-
|
|
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();
|