@rebasepro/firebase 0.0.1-canary.2 → 0.0.1-canary.eb08332
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 +97 -3
- package/dist/components/FirebaseLoginView.d.ts +3 -3
- package/dist/components/RebaseFirebaseApp.d.ts +2 -1
- package/dist/components/RebaseFirebaseAppProps.d.ts +9 -13
- package/dist/components/social_icons.d.ts +6 -6
- package/dist/hooks/index.d.ts +3 -1
- package/dist/hooks/useAppCheck.d.ts +2 -2
- package/dist/hooks/useBuildUserManagement.d.ts +78 -0
- package/dist/hooks/useFirebaseAccessGate.d.ts +44 -0
- package/dist/hooks/useFirebaseAuthController.d.ts +2 -2
- package/dist/hooks/useFirebaseRealTimeDBDelegate.d.ts +2 -2
- package/dist/hooks/useFirebaseStorageSource.d.ts +1 -1
- package/dist/hooks/{useFirestoreDataSource.d.ts → useFirestoreDriver.d.ts} +9 -9
- package/dist/index.es.js +2598 -2663
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +2704 -2702
- package/dist/index.umd.js.map +1 -1
- package/dist/types/auth.d.ts +2 -2
- package/dist/types/text_search.d.ts +3 -3
- package/dist/utils/algolia.d.ts +7 -6
- package/dist/utils/collections_firestore.d.ts +4 -4
- package/package.json +75 -65
- package/src/components/FirebaseLoginView.tsx +53 -50
- package/src/components/RebaseFirebaseApp.tsx +82 -56
- package/src/components/RebaseFirebaseAppProps.tsx +10 -24
- package/src/components/social_icons.tsx +8 -8
- package/src/hooks/index.ts +3 -1
- package/src/hooks/useAppCheck.ts +5 -5
- package/src/hooks/useBuildUserManagement.tsx +366 -0
- package/src/hooks/useFirebaseAccessGate.tsx +145 -0
- package/src/hooks/useFirebaseAuthController.ts +6 -8
- package/src/hooks/useFirebaseRealTimeDBDelegate.ts +70 -79
- package/src/hooks/useFirebaseStorageSource.ts +23 -25
- package/src/hooks/useFirestoreDriver.ts +812 -0
- package/src/hooks/useInitialiseFirebase.ts +2 -2
- package/src/types/auth.tsx +2 -2
- package/src/types/text_search.ts +3 -3
- package/src/utils/algolia.ts +6 -9
- package/src/utils/collections_firestore.ts +25 -29
- package/src/utils/database.ts +2 -2
- package/src/utils/local_text_search_controller.ts +12 -12
- package/src/utils/pinecone.ts +3 -3
- package/src/utils/rebase_search_controller.ts +23 -22
- package/src/utils/text_search_controller.ts +2 -2
- package/dist/social_icons.d.ts +0 -6
- package/src/hooks/useFirestoreDataSource.ts +0 -796
- package/src/social_icons.tsx +0 -135
|
@@ -15,18 +15,9 @@ import {
|
|
|
15
15
|
startAt
|
|
16
16
|
} from "@firebase/database";
|
|
17
17
|
import { useCallback } from "react";
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Entity,
|
|
22
|
-
FetchCollectionProps,
|
|
23
|
-
FetchEntityProps,
|
|
24
|
-
ListenCollectionProps,
|
|
25
|
-
ListenEntityProps,
|
|
26
|
-
SaveEntityProps
|
|
27
|
-
} from "@rebasepro/core";
|
|
28
|
-
|
|
29
|
-
export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: FirebaseApp }): DataSource {
|
|
18
|
+
import { DataDriver, DeleteProps, FetchCollectionProps, FetchOneProps, FilterValues, ListenCollectionProps, ListenOneProps, SaveProps } from "@rebasepro/types";
|
|
19
|
+
|
|
20
|
+
export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: FirebaseApp }): DataDriver {
|
|
30
21
|
|
|
31
22
|
const fetchCollection = useCallback(async <M extends Record<string, any>>({
|
|
32
23
|
path,
|
|
@@ -36,7 +27,7 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
36
27
|
orderBy,
|
|
37
28
|
order,
|
|
38
29
|
searchString
|
|
39
|
-
}: FetchCollectionProps<M>): Promise<
|
|
30
|
+
}: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> => {
|
|
40
31
|
if (!firebaseApp) {
|
|
41
32
|
throw new Error("Firebase app not provided");
|
|
42
33
|
}
|
|
@@ -46,18 +37,17 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
46
37
|
|
|
47
38
|
// Example to apply "limit" and "startAfter"
|
|
48
39
|
if (startAfter !== undefined) {
|
|
49
|
-
dbQuery = query(dbQuery, orderByKey(), startAt(startAfter
|
|
40
|
+
dbQuery = query(dbQuery, orderByKey(), startAt(String(startAfter)));
|
|
50
41
|
}
|
|
51
42
|
if (limit !== undefined) {
|
|
52
43
|
dbQuery = query(dbQuery, limitToFirst(limit));
|
|
53
44
|
}
|
|
54
45
|
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
return Object.entries(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
values: delegateToCMSModel(values) as M,
|
|
46
|
+
const entity = await get(dbQuery);
|
|
47
|
+
if (entity.exists()) {
|
|
48
|
+
return Object.entries(entity.val()).map(([id, values]) => ({
|
|
49
|
+
...(delegateToCMSModel(values) as Record<string, unknown>),
|
|
50
|
+
id
|
|
61
51
|
}));
|
|
62
52
|
}
|
|
63
53
|
return [];
|
|
@@ -65,7 +55,7 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
65
55
|
|
|
66
56
|
const listenCollection = useCallback(<M extends Record<string, any>>({
|
|
67
57
|
path,
|
|
68
|
-
onUpdate
|
|
58
|
+
onUpdate
|
|
69
59
|
// Realtime Database does not directly support onError in onValue
|
|
70
60
|
}: ListenCollectionProps<M>): () => void => {
|
|
71
61
|
if (!firebaseApp) {
|
|
@@ -74,12 +64,11 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
74
64
|
const database = getDatabase(firebaseApp);
|
|
75
65
|
|
|
76
66
|
const dbRef = ref(database, path);
|
|
77
|
-
const unsubscribe = onValue(dbRef, (
|
|
78
|
-
if (
|
|
79
|
-
const result:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
values: delegateToCMSModel(values) as M,
|
|
67
|
+
const unsubscribe = onValue(dbRef, (entity) => {
|
|
68
|
+
if (entity.exists()) {
|
|
69
|
+
const result: Record<string, unknown>[] = Object.entries(entity.val()).map(([id, values]) => ({
|
|
70
|
+
...(delegateToCMSModel(values) as Record<string, unknown>),
|
|
71
|
+
id
|
|
83
72
|
}));
|
|
84
73
|
onUpdate(result);
|
|
85
74
|
} else {
|
|
@@ -90,44 +79,42 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
90
79
|
return () => unsubscribe();
|
|
91
80
|
}, [firebaseApp]);
|
|
92
81
|
|
|
93
|
-
const
|
|
82
|
+
const fetchOne = useCallback(async <M extends Record<string, any>>({
|
|
94
83
|
path,
|
|
95
|
-
|
|
96
|
-
}:
|
|
84
|
+
id
|
|
85
|
+
}: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> => {
|
|
97
86
|
if (!firebaseApp) {
|
|
98
87
|
throw new Error("Firebase app not provided");
|
|
99
88
|
}
|
|
100
89
|
const database = getDatabase(firebaseApp);
|
|
101
90
|
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
91
|
+
const entity = await get(ref(database, `${path}/${id}`));
|
|
92
|
+
if (entity.exists()) {
|
|
104
93
|
return {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
values: delegateToCMSModel(snapshot.val()) as M
|
|
94
|
+
...(delegateToCMSModel(entity.val()) as Record<string, unknown>),
|
|
95
|
+
id: id
|
|
108
96
|
};
|
|
109
97
|
}
|
|
110
98
|
return undefined;
|
|
111
99
|
}, [firebaseApp]);
|
|
112
100
|
|
|
113
|
-
const
|
|
101
|
+
const listenOne = useCallback(<M extends Record<string, any>>({
|
|
114
102
|
path,
|
|
115
|
-
|
|
103
|
+
id,
|
|
116
104
|
onUpdate,
|
|
117
105
|
onError
|
|
118
|
-
}:
|
|
106
|
+
}: ListenOneProps<M>): () => void => {
|
|
119
107
|
if (!firebaseApp) {
|
|
120
108
|
throw new Error("Firebase app not provided");
|
|
121
109
|
}
|
|
122
110
|
const database = getDatabase(firebaseApp);
|
|
123
111
|
|
|
124
|
-
const dbRef = ref(database, `${path}/${
|
|
125
|
-
const unsubscribe = onValue(dbRef, (
|
|
126
|
-
if (
|
|
112
|
+
const dbRef = ref(database, `${path}/${id}`);
|
|
113
|
+
const unsubscribe = onValue(dbRef, (entity) => {
|
|
114
|
+
if (entity.exists()) {
|
|
127
115
|
onUpdate({
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
values: delegateToCMSModel(snapshot.val()) as M
|
|
116
|
+
...(delegateToCMSModel(entity.val()) as Record<string, unknown>),
|
|
117
|
+
id: id
|
|
131
118
|
});
|
|
132
119
|
} else {
|
|
133
120
|
onError?.(new Error("Entity does not exist"));
|
|
@@ -137,18 +124,18 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
137
124
|
return () => unsubscribe();
|
|
138
125
|
}, [firebaseApp]);
|
|
139
126
|
|
|
140
|
-
const
|
|
127
|
+
const save = useCallback(async <M extends Record<string, any>>({
|
|
141
128
|
path,
|
|
142
|
-
|
|
143
|
-
values
|
|
144
|
-
}:
|
|
129
|
+
id,
|
|
130
|
+
values
|
|
131
|
+
}: SaveProps<M>): Promise<Record<string, unknown>> => {
|
|
145
132
|
if (!firebaseApp) {
|
|
146
133
|
throw new Error("Firebase app not provided");
|
|
147
134
|
}
|
|
148
135
|
const database = getDatabase(firebaseApp);
|
|
149
136
|
|
|
150
|
-
// If
|
|
151
|
-
const finalId =
|
|
137
|
+
// If id is not provided, a new entity will be created
|
|
138
|
+
const finalId = id ?? push(ref(database, path)).key;
|
|
152
139
|
if (!finalId) {
|
|
153
140
|
throw new Error("Could not generate a new id");
|
|
154
141
|
}
|
|
@@ -158,41 +145,40 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
158
145
|
await set(ref(database, `${path}/${finalId}`), transformedValues);
|
|
159
146
|
|
|
160
147
|
return {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
values: values as M
|
|
148
|
+
...values,
|
|
149
|
+
id: finalId
|
|
164
150
|
};
|
|
165
151
|
}, [firebaseApp]);
|
|
166
152
|
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
}:
|
|
153
|
+
const deleteOne = useCallback(async <M extends Record<string, any>>({
|
|
154
|
+
row
|
|
155
|
+
}: DeleteProps<M>): Promise<void> => {
|
|
170
156
|
if (!firebaseApp) {
|
|
171
157
|
throw new Error("Firebase app not provided");
|
|
172
158
|
}
|
|
173
159
|
const database = getDatabase(firebaseApp);
|
|
174
160
|
|
|
175
|
-
await remove(ref(database, `${
|
|
161
|
+
await remove(ref(database, `${row.path}/${row.id}`));
|
|
176
162
|
}, [firebaseApp]);
|
|
177
163
|
|
|
178
|
-
// Implementing additional methods required by
|
|
179
|
-
const checkUniqueField = useCallback(async (slug: string, name: string, value:
|
|
164
|
+
// Implementing additional methods required by DataDriver
|
|
165
|
+
const checkUniqueField = useCallback(async (slug: string, name: string, value: unknown, id?: string | number): Promise<boolean> => {
|
|
180
166
|
if (!firebaseApp) {
|
|
181
167
|
throw new Error("Firebase app not provided");
|
|
182
168
|
}
|
|
183
169
|
const database = getDatabase(firebaseApp);
|
|
184
170
|
|
|
185
171
|
// Simplified example; the Realtime Database does not support querying with "not equal" conditions
|
|
186
|
-
const dbRef = query(ref(database, slug), orderByChild(name), startAt(value), limitToFirst(1));
|
|
187
|
-
const
|
|
172
|
+
const dbRef = query(ref(database, slug), orderByChild(name), startAt(value as string | number | boolean | null), limitToFirst(1));
|
|
173
|
+
const entity = await get(dbRef);
|
|
188
174
|
|
|
189
|
-
if (!
|
|
175
|
+
if (!entity.exists()) {
|
|
190
176
|
return true;
|
|
191
177
|
}
|
|
192
178
|
|
|
193
179
|
// Check if the found entity is the same as the one being checked
|
|
194
|
-
const [key, entityValue] = Object.entries(
|
|
195
|
-
if (entityValue && typeof entityValue === "object" && (entityValue as
|
|
180
|
+
const [key, entityValue] = Object.entries(entity.val())[0];
|
|
181
|
+
if (entityValue && typeof entityValue === "object" && (entityValue as Record<string, unknown>)[name] === value && key === id) {
|
|
196
182
|
return true;
|
|
197
183
|
}
|
|
198
184
|
|
|
@@ -203,7 +189,11 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
203
189
|
path,
|
|
204
190
|
filter,
|
|
205
191
|
sortBy
|
|
206
|
-
}:
|
|
192
|
+
}: {
|
|
193
|
+
path: string;
|
|
194
|
+
filter?: FilterValues<string>;
|
|
195
|
+
sortBy?: [string, "asc" | "desc"];
|
|
196
|
+
}): boolean => {
|
|
207
197
|
return false;
|
|
208
198
|
}, []);
|
|
209
199
|
|
|
@@ -211,10 +201,10 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
211
201
|
key: "firebase_rtdb",
|
|
212
202
|
fetchCollection,
|
|
213
203
|
listenCollection,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
204
|
+
fetchOne,
|
|
205
|
+
listenOne,
|
|
206
|
+
save,
|
|
207
|
+
delete: deleteOne,
|
|
218
208
|
checkUniqueField,
|
|
219
209
|
isFilterCombinationValid,
|
|
220
210
|
currentTime: () => new Date()
|
|
@@ -222,12 +212,11 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
222
212
|
}
|
|
223
213
|
|
|
224
214
|
|
|
225
|
-
|
|
226
215
|
/**
|
|
227
216
|
* Transform data from RTDB format back to CMS format
|
|
228
217
|
* This is used internally when fetching/listening to data
|
|
229
218
|
*/
|
|
230
|
-
function delegateToCMSModel(data:
|
|
219
|
+
function delegateToCMSModel(data: unknown): unknown {
|
|
231
220
|
if (data === null || data === undefined) return null;
|
|
232
221
|
|
|
233
222
|
if (Array.isArray(data)) {
|
|
@@ -235,9 +224,9 @@ function delegateToCMSModel(data: any): any {
|
|
|
235
224
|
}
|
|
236
225
|
|
|
237
226
|
if (typeof data === "object") {
|
|
238
|
-
const result: Record<string,
|
|
239
|
-
for (const key of Object.keys(data)) {
|
|
240
|
-
const childValue = delegateToCMSModel(data[key]);
|
|
227
|
+
const result: Record<string, unknown> = {};
|
|
228
|
+
for (const key of Object.keys(data as Record<string, unknown>)) {
|
|
229
|
+
const childValue = delegateToCMSModel((data as Record<string, unknown>)[key]);
|
|
241
230
|
if (childValue !== undefined)
|
|
242
231
|
result[key] = childValue;
|
|
243
232
|
}
|
|
@@ -251,20 +240,21 @@ function delegateToCMSModel(data: any): any {
|
|
|
251
240
|
* Transform data from CMS format to RTDB format
|
|
252
241
|
* This is used internally when saving data
|
|
253
242
|
*/
|
|
254
|
-
function cmsToRTDBModel(data:
|
|
243
|
+
function cmsToRTDBModel(data: unknown, database: Database): unknown {
|
|
255
244
|
if (data === undefined) {
|
|
256
245
|
return null;
|
|
257
246
|
} else if (data === null) {
|
|
258
247
|
return null;
|
|
259
248
|
} else if (Array.isArray(data)) {
|
|
260
249
|
return data.filter(v => v !== undefined).map(v => cmsToRTDBModel(v, database));
|
|
261
|
-
} else if (data.isEntityReference && data.isEntityReference()) {
|
|
262
|
-
|
|
250
|
+
} else if (typeof data === "object" && data !== null && "isEntityReference" in data && typeof (data as Record<string, unknown>).isEntityReference === "function" && (data as { isEntityReference: () => boolean }).isEntityReference()) {
|
|
251
|
+
const entityRef = data as unknown as { slug: string; id: string };
|
|
252
|
+
return ref(database, `${entityRef.slug}/${entityRef.id}`);
|
|
263
253
|
} else if (data instanceof Date) {
|
|
264
254
|
// For dates, convert to ISO string or timestamp.
|
|
265
255
|
return data.toISOString();
|
|
266
256
|
} else if (data && typeof data === "object") {
|
|
267
|
-
return Object.entries(data)
|
|
257
|
+
return Object.entries(data as Record<string, unknown>)
|
|
268
258
|
.map(([key, v]) => {
|
|
269
259
|
const rtdbModel = cmsToRTDBModel(v, database);
|
|
270
260
|
if (rtdbModel !== undefined)
|
|
@@ -272,7 +262,8 @@ function cmsToRTDBModel(data: any, database: Database): any {
|
|
|
272
262
|
else
|
|
273
263
|
return {};
|
|
274
264
|
})
|
|
275
|
-
.reduce((a, b) => ({ ...a,
|
|
265
|
+
.reduce((a, b) => ({ ...a,
|
|
266
|
+
...b }), {});
|
|
276
267
|
}
|
|
277
268
|
return data;
|
|
278
269
|
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ref,
|
|
9
9
|
uploadBytesResumable
|
|
10
10
|
} from "@firebase/storage";
|
|
11
|
-
import { DownloadConfig, DownloadMetadata, StorageListResult, StorageSource, UploadFileProps } from "@rebasepro/
|
|
11
|
+
import { DownloadConfig, DownloadMetadata, StorageListResult, StorageSource, UploadFileProps } from "@rebasepro/types";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @group Firebase
|
|
@@ -29,10 +29,9 @@ export function useFirebaseStorageSource({
|
|
|
29
29
|
const projectId = firebaseApp?.options?.projectId;
|
|
30
30
|
const urlsCache: Record<string, DownloadConfig> = {};
|
|
31
31
|
return {
|
|
32
|
-
|
|
32
|
+
putObject({
|
|
33
33
|
file,
|
|
34
|
-
|
|
35
|
-
path,
|
|
34
|
+
key,
|
|
36
35
|
metadata,
|
|
37
36
|
bucket
|
|
38
37
|
}: UploadFileProps)
|
|
@@ -42,9 +41,8 @@ export function useFirebaseStorageSource({
|
|
|
42
41
|
const storageBucketUrl = bucket ?? bucketUrl;
|
|
43
42
|
const storage = getStorage(firebaseApp, storageBucketUrl);
|
|
44
43
|
if (!storage) throw Error("useFirebaseStorageSource Firebase not initialised");
|
|
45
|
-
const usedFilename = fileName ?? file.name;
|
|
46
44
|
|
|
47
|
-
const storageRef = ref(storage,
|
|
45
|
+
const storageRef = ref(storage, key);
|
|
48
46
|
const uploadTask = uploadBytesResumable(storageRef, file, metadata);
|
|
49
47
|
|
|
50
48
|
return new Promise((resolve, reject) => {
|
|
@@ -71,8 +69,8 @@ export function useFirebaseStorageSource({
|
|
|
71
69
|
setProgressTimeout();
|
|
72
70
|
|
|
73
71
|
uploadTask.on("state_changed",
|
|
74
|
-
(
|
|
75
|
-
const progress = (
|
|
72
|
+
(entity) => {
|
|
73
|
+
const progress = (entity.bytesTransferred / entity.totalBytes) * 100;
|
|
76
74
|
|
|
77
75
|
if (progress > lastProgress) {
|
|
78
76
|
lastProgress = progress;
|
|
@@ -102,8 +100,7 @@ export function useFirebaseStorageSource({
|
|
|
102
100
|
} else if (errorMessage.toLowerCase().includes("network")) {
|
|
103
101
|
reject(new Error("Network error: Check your internet connection"));
|
|
104
102
|
} else {
|
|
105
|
-
const newError = new Error(errorMessage);
|
|
106
|
-
(newError as any).code = error?.code;
|
|
103
|
+
const newError = Object.assign(new Error(errorMessage), { code: error?.code });
|
|
107
104
|
reject(newError);
|
|
108
105
|
}
|
|
109
106
|
},
|
|
@@ -112,9 +109,9 @@ export function useFirebaseStorageSource({
|
|
|
112
109
|
const fullPath = uploadTask.snapshot.ref.fullPath;
|
|
113
110
|
const bucketName = uploadTask.snapshot.ref.bucket;
|
|
114
111
|
resolve({
|
|
115
|
-
|
|
112
|
+
key: fullPath,
|
|
116
113
|
bucket: bucketName,
|
|
117
|
-
storageUrl: `
|
|
114
|
+
storageUrl: `s3://${bucketName}/${fullPath}`
|
|
118
115
|
});
|
|
119
116
|
}
|
|
120
117
|
);
|
|
@@ -124,7 +121,7 @@ export function useFirebaseStorageSource({
|
|
|
124
121
|
}
|
|
125
122
|
},
|
|
126
123
|
|
|
127
|
-
async
|
|
124
|
+
async getObject(path: string, bucket?: string): Promise<File | null> {
|
|
128
125
|
try {
|
|
129
126
|
if (!firebaseApp) throw Error("useFirebaseStorageSource Firebase not initialised");
|
|
130
127
|
const storageBucketUrl = bucket ?? bucketUrl;
|
|
@@ -135,21 +132,22 @@ export function useFirebaseStorageSource({
|
|
|
135
132
|
const response = await fetch(url);
|
|
136
133
|
const blob = await response.blob();
|
|
137
134
|
return new File([blob], path);
|
|
138
|
-
} catch (e:
|
|
139
|
-
if (e
|
|
135
|
+
} catch (e: unknown) {
|
|
136
|
+
if (typeof e === "object" && e !== null && "code" in e && (e as { code: string }).code === "storage/object-not-found") return null;
|
|
140
137
|
throw e;
|
|
141
138
|
}
|
|
142
139
|
},
|
|
143
140
|
|
|
144
|
-
async
|
|
141
|
+
async getSignedUrl(storagePathOrUrl: string, bucket?: string): Promise<DownloadConfig> {
|
|
145
142
|
if (!firebaseApp) throw Error("useFirebaseStorageSource Firebase not initialised");
|
|
146
143
|
|
|
147
|
-
// Support fully-qualified gs:// URLs
|
|
144
|
+
// Support fully-qualified s3:// and gs:// URLs for backward compatibility
|
|
148
145
|
let resolvedPathOrUrl = storagePathOrUrl;
|
|
149
146
|
let resolvedBucket = bucket;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
147
|
+
const match = storagePathOrUrl.match(/^(s3|gs):\/\//);
|
|
148
|
+
if (match) {
|
|
149
|
+
const protocolLength = match[0].length;
|
|
150
|
+
const withoutProtocol = storagePathOrUrl.substring(protocolLength);
|
|
153
151
|
const firstSlash = withoutProtocol.indexOf("/");
|
|
154
152
|
if (firstSlash > 0) {
|
|
155
153
|
resolvedBucket = withoutProtocol.substring(0, firstSlash);
|
|
@@ -172,8 +170,8 @@ export function useFirebaseStorageSource({
|
|
|
172
170
|
}
|
|
173
171
|
urlsCache[storagePathOrUrl] = result;
|
|
174
172
|
return result;
|
|
175
|
-
} catch (e:
|
|
176
|
-
if (e
|
|
173
|
+
} catch (e: unknown) {
|
|
174
|
+
if (typeof e === "object" && e !== null && "code" in e && (e as { code: string }).code === "storage/object-not-found") return {
|
|
177
175
|
url: null,
|
|
178
176
|
fileNotFound: true
|
|
179
177
|
};
|
|
@@ -181,7 +179,7 @@ export function useFirebaseStorageSource({
|
|
|
181
179
|
}
|
|
182
180
|
},
|
|
183
181
|
|
|
184
|
-
async
|
|
182
|
+
async listObjects(prefix: string, options?: {
|
|
185
183
|
bucket?: string,
|
|
186
184
|
maxResults?: number,
|
|
187
185
|
pageToken?: string
|
|
@@ -190,14 +188,14 @@ export function useFirebaseStorageSource({
|
|
|
190
188
|
const storageBucketUrl = options?.bucket ?? bucketUrl;
|
|
191
189
|
const storage = getStorage(firebaseApp, storageBucketUrl);
|
|
192
190
|
if (!storage) throw Error("useFirebaseStorageSource Firebase not initialised");
|
|
193
|
-
const folderRef = ref(storage,
|
|
191
|
+
const folderRef = ref(storage, prefix);
|
|
194
192
|
return await list(folderRef, {
|
|
195
193
|
maxResults: options?.maxResults,
|
|
196
194
|
pageToken: options?.pageToken
|
|
197
195
|
});
|
|
198
196
|
},
|
|
199
197
|
|
|
200
|
-
async
|
|
198
|
+
async deleteObject(path: string, bucket?: string): Promise<void> {
|
|
201
199
|
if (!firebaseApp) throw Error("useFirebaseStorageSource Firebase not initialised");
|
|
202
200
|
const storageBucketUrl = bucket ?? bucketUrl;
|
|
203
201
|
const storage = getStorage(firebaseApp, storageBucketUrl);
|