squarefi-bff-api-module 1.24.35 → 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 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).
@@ -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;
@@ -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.35",
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",
@@ -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
+ };
@@ -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();