squarefi-bff-api-module 1.32.1 → 1.32.2
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/dist/api/auth.d.ts +29 -0
- package/dist/api/auth.js +59 -0
- package/dist/api/bank-data.d.ts +4 -0
- package/dist/api/bank-data.js +6 -0
- package/dist/api/counterparties.d.ts +14 -0
- package/dist/api/counterparties.js +16 -0
- package/dist/api/developer.d.ts +12 -0
- package/dist/api/developer.js +12 -0
- package/dist/api/exchange.d.ts +14 -0
- package/dist/api/exchange.js +20 -0
- package/dist/api/frontend.d.ts +11 -0
- package/dist/api/frontend.js +11 -0
- package/dist/api/index.d.ts +38 -0
- package/dist/api/index.js +36 -0
- package/dist/api/issuing.d.ts +64 -0
- package/dist/api/issuing.js +140 -0
- package/dist/api/kyc.d.ts +21 -0
- package/dist/api/kyc.js +21 -0
- package/dist/api/list.d.ts +16 -0
- package/dist/api/list.js +16 -0
- package/dist/api/orders.d.ts +49 -0
- package/dist/api/orders.js +84 -0
- package/dist/api/persona.d.ts +7 -0
- package/dist/api/persona.js +7 -0
- package/dist/api/storage.d.ts +8 -0
- package/dist/api/storage.js +16 -0
- package/dist/api/tenants.d.ts +6 -0
- package/dist/api/tenants.js +6 -0
- package/dist/api/totp.d.ts +17 -0
- package/dist/api/totp.js +45 -0
- package/{src/api/types/autogen/apiV2.types.ts → dist/api/types/autogen/apiV2.types.d.ts} +0 -1
- package/dist/api/types/autogen/apiV2.types.js +5 -0
- package/dist/api/types/types.d.ts +2258 -0
- package/dist/api/types/types.js +1 -0
- package/dist/api/user.d.ts +18 -0
- package/dist/api/user.js +18 -0
- package/dist/api/virtual-accounts.d.ts +9 -0
- package/dist/api/virtual-accounts.js +9 -0
- package/dist/api/wallets.d.ts +24 -0
- package/dist/api/wallets.js +30 -0
- package/dist/constants.d.ts +303 -0
- package/dist/constants.js +332 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useCalc.d.ts +25 -0
- package/dist/hooks/useCalc.js +115 -0
- package/dist/hooks/useFileUpload.d.ts +49 -0
- package/dist/hooks/useFileUpload.js +100 -0
- package/dist/hooks/useSupabaseSubscription/config.d.ts +2 -0
- package/dist/hooks/useSupabaseSubscription/config.js +5 -0
- package/dist/hooks/useSupabaseSubscription/index.js +2 -0
- package/dist/hooks/useSupabaseSubscription/specialized.d.ts +5 -0
- package/{src/hooks/useSupabaseSubscription/specialized.ts → dist/hooks/useSupabaseSubscription/specialized.js} +2 -5
- package/dist/hooks/useSupabaseSubscription/types.d.ts +16 -0
- package/dist/hooks/useSupabaseSubscription/types.js +1 -0
- package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.d.ts +5 -0
- package/dist/hooks/useSupabaseSubscription/useSupabaseSubscription.js +37 -0
- package/dist/index.d.ts +7 -0
- package/dist/utils/apiClientFactory.d.ts +31 -0
- package/dist/utils/apiClientFactory.js +138 -0
- package/dist/utils/converters.d.ts +1 -0
- package/dist/utils/converters.js +1 -0
- package/dist/utils/encrypt.d.ts +10 -0
- package/dist/utils/encrypt.js +77 -0
- package/dist/utils/fileStorage.d.ts +120 -0
- package/dist/utils/fileStorage.js +292 -0
- package/dist/utils/storage.d.ts +3 -0
- package/dist/utils/storage.js +24 -0
- package/dist/utils/supabase.d.ts +1 -0
- package/dist/utils/supabase.js +12 -0
- package/dist/utils/tokensFactory.d.ts +12 -0
- package/dist/utils/tokensFactory.js +42 -0
- package/package.json +4 -1
- package/.env.example +0 -1
- package/.husky/pre-commit +0 -2
- package/.prettierignore +0 -6
- package/.prettierrc +0 -7
- package/CHANGELOG.md +0 -1415
- package/FIXED_RLS_ERROR.md +0 -146
- package/QUICK_TEST.md +0 -127
- package/STORAGE_MODULE_SUMMARY.md +0 -228
- package/TEST_INSTRUCTIONS.md +0 -122
- package/docs/AUTH_TOKEN_USAGE.md +0 -290
- package/docs/BACKEND_SERVICE_URL.md +0 -334
- package/docs/FRONTEND_STORAGE_GUIDE.md +0 -529
- package/docs/STORAGE_MODULE.md +0 -490
- package/docs/STORAGE_QUICK_START.md +0 -76
- package/scripts/generate-openapi-types.ts +0 -41
- package/scripts/supabase-storage-setup.sql +0 -223
- package/src/api/auth.ts +0 -78
- package/src/api/bank-data.ts +0 -11
- package/src/api/counterparties.ts +0 -73
- package/src/api/developer.ts +0 -20
- package/src/api/exchange.ts +0 -44
- package/src/api/frontend.ts +0 -20
- package/src/api/index.ts +0 -57
- package/src/api/issuing.ts +0 -214
- package/src/api/kyc.ts +0 -41
- package/src/api/list.ts +0 -26
- package/src/api/orders.ts +0 -255
- package/src/api/persona.ts +0 -16
- package/src/api/storage.ts +0 -24
- package/src/api/tenants.ts +0 -8
- package/src/api/totp.ts +0 -51
- package/src/api/types/types.ts +0 -2820
- package/src/api/user.ts +0 -27
- package/src/api/virtual-accounts.ts +0 -15
- package/src/api/wallets.ts +0 -65
- package/src/constants.ts +0 -343
- package/src/hooks/useCalc.ts +0 -181
- package/src/hooks/useFileUpload.ts +0 -129
- package/src/hooks/useSupabaseSubscription/config.ts +0 -7
- package/src/hooks/useSupabaseSubscription/types.ts +0 -18
- package/src/hooks/useSupabaseSubscription/useSupabaseSubscription.ts +0 -53
- package/src/utils/apiClientFactory.ts +0 -194
- package/src/utils/converters.ts +0 -1
- package/src/utils/encrypt.ts +0 -96
- package/src/utils/fileStorage.ts +0 -353
- package/src/utils/storage.ts +0 -29
- package/src/utils/supabase.ts +0 -16
- package/src/utils/tokensFactory.ts +0 -59
- package/tsconfig.json +0 -15
- package/types.d.ts +0 -11
- /package/{src/hooks/index.ts → dist/hooks/index.d.ts} +0 -0
- /package/{src/hooks/useSupabaseSubscription/index.ts → dist/hooks/useSupabaseSubscription/index.d.ts} +0 -0
- /package/{src/index.ts → dist/index.js} +0 -0
package/docs/STORAGE_MODULE.md
DELETED
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
# Supabase Storage Module
|
|
2
|
-
|
|
3
|
-
The module provides functions for working with Supabase file storage with automatic user-level access protection.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- ✅ Upload files to protected storage
|
|
8
|
-
- ✅ Get signed URLs for secure access
|
|
9
|
-
- ✅ Automatic file organization by user
|
|
10
|
-
- ✅ Security policies: access only for owner or superadmin
|
|
11
|
-
- ✅ Support for multiple buckets (user-files, documents, images)
|
|
12
|
-
- ✅ File and folder deletion
|
|
13
|
-
- ✅ File download
|
|
14
|
-
|
|
15
|
-
## Installation and Setup
|
|
16
|
-
|
|
17
|
-
### 1. Environment Variables Setup
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# Copy env.example to .env and fill in your values
|
|
21
|
-
# See env.example in repository root for all available variables
|
|
22
|
-
|
|
23
|
-
SUPABASE_URL=your-supabase-url
|
|
24
|
-
SUPABASE_PUBLIC_KEY=your-supabase-anon-key
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### 2. Supabase Storage Setup
|
|
28
|
-
|
|
29
|
-
Execute the SQL script `scripts/supabase-storage-setup.sql` in your Supabase database via SQL Editor:
|
|
30
|
-
|
|
31
|
-
1. Open Supabase Dashboard
|
|
32
|
-
2. Go to SQL Editor
|
|
33
|
-
3. Copy the content of `supabase-storage-setup.sql`
|
|
34
|
-
4. Execute the script
|
|
35
|
-
|
|
36
|
-
**Important:** Modify the `is_super_admin()` function in the script according to your user and role schema.
|
|
37
|
-
|
|
38
|
-
## Usage
|
|
39
|
-
|
|
40
|
-
### Import
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
import {
|
|
44
|
-
uploadFile,
|
|
45
|
-
getSignedUrl,
|
|
46
|
-
getPublicUrl,
|
|
47
|
-
deleteFile,
|
|
48
|
-
deleteFiles,
|
|
49
|
-
listUserFiles,
|
|
50
|
-
downloadFile,
|
|
51
|
-
DEFAULT_BUCKET,
|
|
52
|
-
DOCUMENTS_BUCKET,
|
|
53
|
-
IMAGES_BUCKET,
|
|
54
|
-
} from '@your-package/bff-api-module';
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Upload File
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
const handleFileUpload = async (file: File, userId: string) => {
|
|
61
|
-
const result = await uploadFile({
|
|
62
|
-
file: file,
|
|
63
|
-
fileName: file.name,
|
|
64
|
-
userId: userId,
|
|
65
|
-
bucket: DEFAULT_BUCKET, // or DOCUMENTS_BUCKET, IMAGES_BUCKET
|
|
66
|
-
contentType: file.type,
|
|
67
|
-
upsert: false, // if true, will overwrite existing file
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (result.success) {
|
|
71
|
-
console.log('File uploaded:', result.path);
|
|
72
|
-
console.log('Public URL:', result.publicUrl);
|
|
73
|
-
console.log('Signed URL:', result.signedUrl);
|
|
74
|
-
|
|
75
|
-
// Save result.path in your database for future access
|
|
76
|
-
return result.path;
|
|
77
|
-
} else {
|
|
78
|
-
console.error('Upload error:', result.error);
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Get Signed URL
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
// Signed URL for secure file access (temporary, expires)
|
|
88
|
-
const getFileUrl = async (filePath: string) => {
|
|
89
|
-
const signedUrl = await getSignedUrl({
|
|
90
|
-
path: filePath,
|
|
91
|
-
bucket: DEFAULT_BUCKET,
|
|
92
|
-
expiresIn: 3600, // URL valid for 1 hour (in seconds)
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
if (signedUrl) {
|
|
96
|
-
// Use URL to access the file
|
|
97
|
-
window.open(signedUrl, '_blank');
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Get Public URL (for Superadmin Backend Access)
|
|
103
|
-
|
|
104
|
-
For **private buckets**, `getPublicUrl()` returns a permanent URL that requires authentication:
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
import { getPublicUrl, DEFAULT_BUCKET } from '@your-package/bff-api-module';
|
|
108
|
-
|
|
109
|
-
// Get permanent URL (works on frontend or backend)
|
|
110
|
-
const publicUrl = getPublicUrl(filePath, DEFAULT_BUCKET);
|
|
111
|
-
|
|
112
|
-
console.log('Public URL:', publicUrl);
|
|
113
|
-
// Example: https://xxx.supabase.co/storage/v1/object/public/user-files/userId/file.pdf
|
|
114
|
-
|
|
115
|
-
// On BACKEND, access with service role key:
|
|
116
|
-
fetch(publicUrl, {
|
|
117
|
-
headers: {
|
|
118
|
-
'Authorization': `Bearer ${process.env.SUPABASE_SERVICE_ROLE_KEY}`
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
**Important**:
|
|
124
|
-
- For private buckets, this URL requires service role key in Authorization header
|
|
125
|
-
- Never expose service role key on frontend
|
|
126
|
-
- For regular users, use `getSignedUrl()` instead
|
|
127
|
-
|
|
128
|
-
### Download File
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
const downloadUserFile = async (filePath: string) => {
|
|
132
|
-
const blob = await downloadFile(filePath, DEFAULT_BUCKET);
|
|
133
|
-
|
|
134
|
-
if (blob) {
|
|
135
|
-
// Create download link
|
|
136
|
-
const url = URL.createObjectURL(blob);
|
|
137
|
-
const a = document.createElement('a');
|
|
138
|
-
a.href = url;
|
|
139
|
-
a.download = filePath.split('/').pop() || 'download';
|
|
140
|
-
a.click();
|
|
141
|
-
URL.revokeObjectURL(url);
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### List User Files
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
const getUserFiles = async (userId: string) => {
|
|
150
|
-
const files = await listUserFiles(userId, DEFAULT_BUCKET);
|
|
151
|
-
|
|
152
|
-
console.log('User files:', files);
|
|
153
|
-
|
|
154
|
-
// Each file contains:
|
|
155
|
-
// - name: file name
|
|
156
|
-
// - id: file ID
|
|
157
|
-
// - updated_at: update date
|
|
158
|
-
// - created_at: creation date
|
|
159
|
-
// - last_accessed_at: last access date
|
|
160
|
-
// - metadata: file metadata
|
|
161
|
-
|
|
162
|
-
return files;
|
|
163
|
-
};
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Delete File
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
const removeFile = async (filePath: string) => {
|
|
170
|
-
const success = await deleteFile(filePath, DEFAULT_BUCKET);
|
|
171
|
-
|
|
172
|
-
if (success) {
|
|
173
|
-
console.log('File deleted');
|
|
174
|
-
} else {
|
|
175
|
-
console.error('Error deleting file');
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Delete Multiple Files
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
const removeMultipleFiles = async (filePaths: string[]) => {
|
|
184
|
-
const success = await deleteFiles(filePaths, DEFAULT_BUCKET);
|
|
185
|
-
|
|
186
|
-
if (success) {
|
|
187
|
-
console.log('Files deleted');
|
|
188
|
-
} else {
|
|
189
|
-
console.error('Error deleting files');
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## React Usage Examples
|
|
195
|
-
|
|
196
|
-
### File Upload Component
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
import React, { useState } from 'react';
|
|
200
|
-
import { uploadFile, DEFAULT_BUCKET } from '@your-package/bff-api-module';
|
|
201
|
-
|
|
202
|
-
interface FileUploaderProps {
|
|
203
|
-
userId: string;
|
|
204
|
-
onUploadSuccess: (path: string) => void;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export const FileUploader: React.FC<FileUploaderProps> = ({ userId, onUploadSuccess }) => {
|
|
208
|
-
const [uploading, setUploading] = useState(false);
|
|
209
|
-
const [error, setError] = useState<string | null>(null);
|
|
210
|
-
|
|
211
|
-
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
212
|
-
const file = e.target.files?.[0];
|
|
213
|
-
if (!file) return;
|
|
214
|
-
|
|
215
|
-
setUploading(true);
|
|
216
|
-
setError(null);
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
const result = await uploadFile({
|
|
220
|
-
file,
|
|
221
|
-
fileName: `${Date.now()}-${file.name}`,
|
|
222
|
-
userId,
|
|
223
|
-
bucket: DEFAULT_BUCKET,
|
|
224
|
-
contentType: file.type,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
if (result.success && result.path) {
|
|
228
|
-
onUploadSuccess(result.path);
|
|
229
|
-
} else {
|
|
230
|
-
setError(result.error || 'Upload error');
|
|
231
|
-
}
|
|
232
|
-
} catch (err) {
|
|
233
|
-
setError('Unexpected error');
|
|
234
|
-
} finally {
|
|
235
|
-
setUploading(false);
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
return (
|
|
240
|
-
<div>
|
|
241
|
-
<input
|
|
242
|
-
type="file"
|
|
243
|
-
onChange={handleFileChange}
|
|
244
|
-
disabled={uploading}
|
|
245
|
-
/>
|
|
246
|
-
{uploading && <p>Uploading...</p>}
|
|
247
|
-
{error && <p style={{ color: 'red' }}>{error}</p>}
|
|
248
|
-
</div>
|
|
249
|
-
);
|
|
250
|
-
};
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### File List Component
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
256
|
-
import React, { useEffect, useState } from 'react';
|
|
257
|
-
import {
|
|
258
|
-
listUserFiles,
|
|
259
|
-
getSignedUrl,
|
|
260
|
-
deleteFile,
|
|
261
|
-
DEFAULT_BUCKET,
|
|
262
|
-
} from '@your-package/bff-api-module';
|
|
263
|
-
|
|
264
|
-
interface FileListProps {
|
|
265
|
-
userId: string;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
export const FileList: React.FC<FileListProps> = ({ userId }) => {
|
|
269
|
-
const [files, setFiles] = useState<any[]>([]);
|
|
270
|
-
const [loading, setLoading] = useState(true);
|
|
271
|
-
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
loadFiles();
|
|
274
|
-
}, [userId]);
|
|
275
|
-
|
|
276
|
-
const loadFiles = async () => {
|
|
277
|
-
setLoading(true);
|
|
278
|
-
const userFiles = await listUserFiles(userId, DEFAULT_BUCKET);
|
|
279
|
-
setFiles(userFiles);
|
|
280
|
-
setLoading(false);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
const handleDownload = async (fileName: string) => {
|
|
284
|
-
const filePath = `${userId}/${fileName}`;
|
|
285
|
-
const signedUrl = await getSignedUrl({
|
|
286
|
-
path: filePath,
|
|
287
|
-
bucket: DEFAULT_BUCKET,
|
|
288
|
-
expiresIn: 3600,
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
if (signedUrl) {
|
|
292
|
-
window.open(signedUrl, '_blank');
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
const handleDelete = async (fileName: string) => {
|
|
297
|
-
const filePath = `${userId}/${fileName}`;
|
|
298
|
-
const success = await deleteFile(filePath, DEFAULT_BUCKET);
|
|
299
|
-
|
|
300
|
-
if (success) {
|
|
301
|
-
loadFiles(); // Reload list
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
if (loading) return <div>Loading...</div>;
|
|
306
|
-
|
|
307
|
-
return (
|
|
308
|
-
<div>
|
|
309
|
-
<h3>My Files</h3>
|
|
310
|
-
<ul>
|
|
311
|
-
{files.map((file) => (
|
|
312
|
-
<li key={file.id}>
|
|
313
|
-
<span>{file.name}</span>
|
|
314
|
-
<button onClick={() => handleDownload(file.name)}>Download</button>
|
|
315
|
-
<button onClick={() => handleDelete(file.name)}>Delete</button>
|
|
316
|
-
</li>
|
|
317
|
-
))}
|
|
318
|
-
</ul>
|
|
319
|
-
</div>
|
|
320
|
-
);
|
|
321
|
-
};
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
## Storage Structure
|
|
325
|
-
|
|
326
|
-
Files are organized by the following structure:
|
|
327
|
-
|
|
328
|
-
```
|
|
329
|
-
bucket/
|
|
330
|
-
└── {userId}/
|
|
331
|
-
├── file1.pdf
|
|
332
|
-
├── file2.jpg
|
|
333
|
-
└── file3.docx
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
Where `{userId}` is the UUID of the authenticated user from Supabase Auth.
|
|
337
|
-
|
|
338
|
-
## Security
|
|
339
|
-
|
|
340
|
-
### Row Level Security (RLS)
|
|
341
|
-
|
|
342
|
-
All files are protected by RLS policies at Supabase level:
|
|
343
|
-
|
|
344
|
-
1. **Upload**: Users can only upload files to their own folder (`{userId}/`)
|
|
345
|
-
2. **View**: Users can only view their own files (or all if superadmin)
|
|
346
|
-
3. **Update**: Users can only update their own files (or all if superadmin)
|
|
347
|
-
4. **Delete**: Users can only delete their own files (or all if superadmin)
|
|
348
|
-
|
|
349
|
-
### URL Types
|
|
350
|
-
|
|
351
|
-
**1. Signed URLs** (for regular users):
|
|
352
|
-
- ✅ Temporary access with expiration time (default 1 hour)
|
|
353
|
-
- ✅ Work independently of RLS policies
|
|
354
|
-
- ✅ Safe to share with end users
|
|
355
|
-
- ✅ No authentication required
|
|
356
|
-
|
|
357
|
-
**2. Public URLs** (for superadmin backend, private buckets):
|
|
358
|
-
- ✅ Permanent URL, never expires
|
|
359
|
-
- ✅ Requires Supabase service role key in Authorization header
|
|
360
|
-
- ✅ Bypasses RLS policies (service role has admin access)
|
|
361
|
-
- ⚠️ **NEVER expose service role key on frontend**
|
|
362
|
-
- ✅ Use only on secure backend
|
|
363
|
-
|
|
364
|
-
**Example public URL usage on backend:**
|
|
365
|
-
```javascript
|
|
366
|
-
// Get URL (can be done anywhere)
|
|
367
|
-
const publicUrl = getPublicUrl(filePath, bucket);
|
|
368
|
-
|
|
369
|
-
// Backend only - access with service key!
|
|
370
|
-
const response = await fetch(publicUrl, {
|
|
371
|
-
headers: {
|
|
372
|
-
'Authorization': `Bearer ${process.env.SUPABASE_SERVICE_ROLE_KEY}`
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
## Buckets
|
|
378
|
-
|
|
379
|
-
Three pre-configured buckets are available:
|
|
380
|
-
|
|
381
|
-
- `user-files` (DEFAULT_BUCKET) - for general user files
|
|
382
|
-
- `documents` (DOCUMENTS_BUCKET) - for documents
|
|
383
|
-
- `images` (IMAGES_BUCKET) - for images
|
|
384
|
-
|
|
385
|
-
All buckets are configured as private (`public: false`) with identical security policies.
|
|
386
|
-
|
|
387
|
-
## Limitations
|
|
388
|
-
|
|
389
|
-
By default, Supabase has the following limitations:
|
|
390
|
-
|
|
391
|
-
- Maximum file size: **50 MB** (can be increased in project settings)
|
|
392
|
-
- Total storage limit depends on your pricing plan
|
|
393
|
-
|
|
394
|
-
## Error Handling
|
|
395
|
-
|
|
396
|
-
All functions return results with error handling:
|
|
397
|
-
|
|
398
|
-
```typescript
|
|
399
|
-
const result = await uploadFile({...});
|
|
400
|
-
|
|
401
|
-
if (result.success) {
|
|
402
|
-
// Successful upload
|
|
403
|
-
console.log(result.path, result.signedUrl);
|
|
404
|
-
} else {
|
|
405
|
-
// Handle error
|
|
406
|
-
console.error(result.error);
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
## Data Types
|
|
411
|
-
|
|
412
|
-
### UploadFileOptions
|
|
413
|
-
|
|
414
|
-
```typescript
|
|
415
|
-
interface UploadFileOptions {
|
|
416
|
-
file: File | Blob; // File to upload
|
|
417
|
-
fileName: string; // File name
|
|
418
|
-
bucket?: string; // Bucket (default DEFAULT_BUCKET)
|
|
419
|
-
userId: string; // User ID (required)
|
|
420
|
-
contentType?: string; // File MIME type
|
|
421
|
-
cacheControl?: string; // Cache-Control header (default '3600')
|
|
422
|
-
upsert?: boolean; // Overwrite existing file (default false)
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### UploadFileResult
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
interface UploadFileResult {
|
|
430
|
-
success: boolean; // Operation status
|
|
431
|
-
publicUrl?: string; // Public URL (use with caution)
|
|
432
|
-
signedUrl?: string; // Signed URL (recommended)
|
|
433
|
-
path?: string; // File path in storage
|
|
434
|
-
error?: string; // Error message
|
|
435
|
-
}
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### GetFileUrlOptions
|
|
439
|
-
|
|
440
|
-
```typescript
|
|
441
|
-
interface GetFileUrlOptions {
|
|
442
|
-
path: string; // File path
|
|
443
|
-
bucket?: string; // Bucket (default DEFAULT_BUCKET)
|
|
444
|
-
expiresIn?: number; // URL expiration in seconds (default 3600)
|
|
445
|
-
}
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
## FAQ
|
|
449
|
-
|
|
450
|
-
### How to modify superadmin check logic?
|
|
451
|
-
|
|
452
|
-
Edit the `is_super_admin()` function in `supabase-storage-setup.sql` before execution:
|
|
453
|
-
|
|
454
|
-
```sql
|
|
455
|
-
CREATE OR REPLACE FUNCTION public.is_super_admin(user_id uuid)
|
|
456
|
-
RETURNS boolean AS $$
|
|
457
|
-
BEGIN
|
|
458
|
-
-- Your check logic
|
|
459
|
-
RETURN EXISTS (
|
|
460
|
-
SELECT 1
|
|
461
|
-
FROM public.your_users_table
|
|
462
|
-
WHERE id = user_id
|
|
463
|
-
AND your_role_field = 'admin'
|
|
464
|
-
);
|
|
465
|
-
END;
|
|
466
|
-
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### How to create a public bucket?
|
|
470
|
-
|
|
471
|
-
If you need a public bucket (without RLS), create it with `public: true`:
|
|
472
|
-
|
|
473
|
-
```sql
|
|
474
|
-
INSERT INTO storage.buckets (id, name, public)
|
|
475
|
-
VALUES ('public-images', 'public-images', true);
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
### How to increase maximum file size?
|
|
479
|
-
|
|
480
|
-
1. Open Supabase Dashboard
|
|
481
|
-
2. Go to Settings → Storage
|
|
482
|
-
3. Change `File Size Limit`
|
|
483
|
-
|
|
484
|
-
### Should I save file paths in the database?
|
|
485
|
-
|
|
486
|
-
Yes, it's recommended to save the `path` from upload result in your database for future file access.
|
|
487
|
-
|
|
488
|
-
## Support
|
|
489
|
-
|
|
490
|
-
If you have questions or issues, please create an issue in the project repository.
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
# Storage Module - Quick Start 🚀
|
|
2
|
-
|
|
3
|
-
## 1️⃣ Setup (one time)
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
# Copy env.example to .env and fill in your values
|
|
7
|
-
# See env.example in repository root for all available variables
|
|
8
|
-
|
|
9
|
-
# .env
|
|
10
|
-
SUPABASE_URL=https://xxx.supabase.co
|
|
11
|
-
SUPABASE_PUBLIC_KEY=eyJxxx...
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Execute SQL in Supabase Dashboard:
|
|
15
|
-
```bash
|
|
16
|
-
scripts/supabase-storage-setup.sql
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## 2️⃣ Import
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
import {
|
|
23
|
-
useFileUpload,
|
|
24
|
-
useUserFiles
|
|
25
|
-
} from 'squarefi-bff-api-module';
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## 3️⃣ Usage
|
|
29
|
-
|
|
30
|
-
### Upload File
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
function MyComponent({ userId }) {
|
|
34
|
-
const { upload, uploading } = useFileUpload({ userId });
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<input
|
|
38
|
-
type="file"
|
|
39
|
-
onChange={(e) => upload(e.target.files[0])}
|
|
40
|
-
disabled={uploading}
|
|
41
|
-
/>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### File List
|
|
47
|
-
|
|
48
|
-
```tsx
|
|
49
|
-
function FileList({ userId }) {
|
|
50
|
-
const { files, deleteOne } = useUserFiles({
|
|
51
|
-
userId,
|
|
52
|
-
autoLoad: true,
|
|
53
|
-
autoGenerateUrls: true
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<ul>
|
|
58
|
-
{files.map(file => (
|
|
59
|
-
<li key={file.id}>
|
|
60
|
-
<a href={file.signedUrl}>{file.name}</a>
|
|
61
|
-
<button onClick={() => deleteOne(file.name)}>🗑️</button>
|
|
62
|
-
</li>
|
|
63
|
-
))}
|
|
64
|
-
</ul>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## 4️⃣ Done! ✅
|
|
70
|
-
|
|
71
|
-
All files automatically:
|
|
72
|
-
- ✅ Organized by `{userId}/filename`
|
|
73
|
-
- ✅ Protected by RLS policies
|
|
74
|
-
- ✅ Accessible only to owner
|
|
75
|
-
|
|
76
|
-
📚 **More details**: [FRONTEND_STORAGE_GUIDE.md](./FRONTEND_STORAGE_GUIDE.md)
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
import { exec } from 'child_process';
|
|
3
|
-
import { mkdirSync, writeFileSync } from 'fs';
|
|
4
|
-
import { dirname, resolve } from 'path';
|
|
5
|
-
|
|
6
|
-
type ApiDocsData = {
|
|
7
|
-
url: string | undefined;
|
|
8
|
-
name: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const apiDocsData: ApiDocsData[] = [
|
|
12
|
-
{
|
|
13
|
-
url: process.env.API_DOCS_V2_URL,
|
|
14
|
-
name: 'apiV2',
|
|
15
|
-
},
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
const generateDocs = async (apiDoc: ApiDocsData) => {
|
|
19
|
-
if (!apiDoc.url) {
|
|
20
|
-
console.error(`${apiDoc.name} URL is not set`);
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
const outputPath = resolve(`src/api/types/autogen/${apiDoc.name}.types.ts`);
|
|
24
|
-
const outputDir = dirname(outputPath);
|
|
25
|
-
|
|
26
|
-
mkdirSync(outputDir, { recursive: true });
|
|
27
|
-
|
|
28
|
-
exec(`npx openapi-typescript "${apiDoc.url}"`, (error, stdout, stderr) => {
|
|
29
|
-
if (error) {
|
|
30
|
-
console.error(`Error: ${error.message}`);
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
if (stderr) {
|
|
34
|
-
console.error(`stderr: ${stderr}`);
|
|
35
|
-
}
|
|
36
|
-
writeFileSync(outputPath, stdout);
|
|
37
|
-
console.log(`Types generated at ${outputPath}`);
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
apiDocsData.forEach(generateDocs);
|