@edgedev/firebase 1.1.6 → 1.2.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/README.md +62 -5
- package/edgeFirebase.ts +485 -0
- package/index.ts +6 -446
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -16,23 +16,80 @@ pnpm install @edgedev/firebase
|
|
|
16
16
|
```bash
|
|
17
17
|
pnpm install @edgedev/firebase
|
|
18
18
|
```
|
|
19
|
-
|
|
19
|
+
### Installing with Nuxt 3 global composables
|
|
20
|
+
|
|
21
|
+
Add a file (whatever.ts) to your "composables" folder with this code:
|
|
20
22
|
|
|
21
23
|
```typescript
|
|
22
|
-
import
|
|
24
|
+
import { EdgeFirebase } from "@edgedev/firebase";
|
|
25
|
+
const config = {
|
|
26
|
+
apiKey: "your-apiKey",
|
|
27
|
+
authDomain: "your-authDomain",
|
|
28
|
+
projectId: "your-projectId",
|
|
29
|
+
storageBucket: "your-storageBucket",
|
|
30
|
+
messagingSenderId: "your-messagingSenderId",
|
|
31
|
+
appId: "your-appId"
|
|
32
|
+
};
|
|
33
|
+
const edgeFirebase = new EdgeFirebase(config);
|
|
23
34
|
export { edgeFirebase };
|
|
24
35
|
```
|
|
25
36
|
|
|
26
|
-
|
|
37
|
+
##### *Nuxt must be configured with SSR disabled, update the nuxt.config.ts file (if other parts of your project SSR, see Nuxt 3 plugin instuctions):
|
|
38
|
+
```javascript
|
|
39
|
+
export default defineNuxtConfig({ ssr: false });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Installing as a plugin
|
|
43
|
+
|
|
44
|
+
#### Vue 3 plugin, main.js example:
|
|
45
|
+
```javascript
|
|
46
|
+
import { createApp } from "vue";
|
|
47
|
+
import App from "./App.vue";
|
|
48
|
+
|
|
49
|
+
//edgeFirebase Plugin
|
|
50
|
+
import eFb from "@edgedev/firebase";
|
|
51
|
+
app.use(eFb, {
|
|
52
|
+
apiKey: "your-apiKey",
|
|
53
|
+
authDomain: "your-authDomain",
|
|
54
|
+
projectId: "your-projectId",
|
|
55
|
+
storageBucket: "your-storageBucket",
|
|
56
|
+
messagingSenderId: "your-messagingSenderId",
|
|
57
|
+
appId: "your-appId"
|
|
58
|
+
})
|
|
59
|
+
//end edgeFirebase
|
|
60
|
+
|
|
61
|
+
app.mount("#app");
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Nuxt 3 example using the plugins folder:
|
|
65
|
+
Add a file (whatever**.client**.ts) to your "plugins" folder with the following code:
|
|
66
|
+
|
|
67
|
+
***-Note the ".client" in the file name. If the file doesn't have that in the name you must disabled SSR in the nuxt config.***
|
|
68
|
+
```javascript
|
|
69
|
+
import eFb from "@edgedev/firebase";
|
|
70
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
71
|
+
nuxtApp.vueApp.use(eFb, {
|
|
72
|
+
apiKey: "your-apiKey",
|
|
73
|
+
authDomain: "your-authDomain",
|
|
74
|
+
projectId: "your-projectId",
|
|
75
|
+
storageBucket: "your-storageBucket",
|
|
76
|
+
messagingSenderId: "your-messagingSenderId",
|
|
77
|
+
appId: "your-appId"
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
***-Alternatively you can disable SSR for your entire Nuxt project instead of naming the plugin with ".client", update the nuxt.config.ts file:***
|
|
82
|
+
|
|
27
83
|
```javascript
|
|
28
84
|
export default defineNuxtConfig({ ssr: false });
|
|
29
85
|
```
|
|
30
86
|
|
|
31
|
-
If not in Nuxt 3 or there is no need for it to be global, put this in your components <script setup>
|
|
32
87
|
|
|
88
|
+
#### After installing as a plugin you will need to include this in <script setup> in any component you want to use EdgeFirebase in:
|
|
33
89
|
```javascript
|
|
34
90
|
<script setup>
|
|
35
|
-
import
|
|
91
|
+
import { inject } from "vue";
|
|
92
|
+
const edgeFirebase = inject("edgeFirebase");
|
|
36
93
|
</script>
|
|
37
94
|
```
|
|
38
95
|
# Firebase Authentication
|
package/edgeFirebase.ts
ADDED
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import { initializeApp } from "firebase/app";
|
|
2
|
+
import { reactive } from "vue";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getFirestore,
|
|
6
|
+
collection,
|
|
7
|
+
addDoc,
|
|
8
|
+
doc,
|
|
9
|
+
query,
|
|
10
|
+
onSnapshot,
|
|
11
|
+
WhereFilterOp,
|
|
12
|
+
QueryConstraint,
|
|
13
|
+
Unsubscribe,
|
|
14
|
+
where,
|
|
15
|
+
deleteDoc,
|
|
16
|
+
getDocs,
|
|
17
|
+
getDoc,
|
|
18
|
+
orderBy,
|
|
19
|
+
limit,
|
|
20
|
+
Query,
|
|
21
|
+
startAfter,
|
|
22
|
+
DocumentData,
|
|
23
|
+
setDoc
|
|
24
|
+
} from "firebase/firestore";
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
getAuth,
|
|
28
|
+
setPersistence,
|
|
29
|
+
browserSessionPersistence,
|
|
30
|
+
browserLocalPersistence,
|
|
31
|
+
Persistence,
|
|
32
|
+
signInWithEmailAndPassword,
|
|
33
|
+
onAuthStateChanged,
|
|
34
|
+
signOut
|
|
35
|
+
} from "firebase/auth";
|
|
36
|
+
|
|
37
|
+
interface FirestoreQuery {
|
|
38
|
+
field: string;
|
|
39
|
+
operator: WhereFilterOp; // '==' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'array-contains-any';
|
|
40
|
+
value: unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface FirestoreOrderBy {
|
|
44
|
+
field: string;
|
|
45
|
+
direction: "asc" | "desc";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface FirestoreLimit {
|
|
49
|
+
limit: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface CollectionUnsubscribeObject {
|
|
53
|
+
[key: string]: Unsubscribe;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface CollectionDataObject {
|
|
57
|
+
[key: string]: object;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface UserDataObject {
|
|
61
|
+
uid: string | null;
|
|
62
|
+
email: string;
|
|
63
|
+
loggedIn: boolean;
|
|
64
|
+
logInError: boolean;
|
|
65
|
+
logInErrorMessage: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface Credentials {
|
|
69
|
+
email: string;
|
|
70
|
+
password: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface StaticDataResult {
|
|
74
|
+
data: object;
|
|
75
|
+
next: DocumentData | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface firebaseConfig {
|
|
79
|
+
apiKey: string;
|
|
80
|
+
authDomain: string;
|
|
81
|
+
projectId: string;
|
|
82
|
+
storageBucket: string;
|
|
83
|
+
messagingSenderId: string;
|
|
84
|
+
appId: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const EdgeFirebase = class {
|
|
88
|
+
constructor(
|
|
89
|
+
firebaseConfig: firebaseConfig = {
|
|
90
|
+
apiKey: "",
|
|
91
|
+
authDomain: "",
|
|
92
|
+
projectId: "",
|
|
93
|
+
storageBucket: "",
|
|
94
|
+
messagingSenderId: "",
|
|
95
|
+
appId: ""
|
|
96
|
+
}
|
|
97
|
+
) {
|
|
98
|
+
this.firebaseConfig = firebaseConfig;
|
|
99
|
+
this.app = initializeApp(this.firebaseConfig);
|
|
100
|
+
this.auth = getAuth(this.app);
|
|
101
|
+
this.db = getFirestore(this.app);
|
|
102
|
+
this.setOnAuthStateChanged();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private firebaseConfig = null;
|
|
106
|
+
|
|
107
|
+
// Initialize Firebase
|
|
108
|
+
public app = null;
|
|
109
|
+
public auth = null;
|
|
110
|
+
public db = null;
|
|
111
|
+
|
|
112
|
+
// Composable to logout
|
|
113
|
+
public logOut = (): void => {
|
|
114
|
+
signOut(this.auth)
|
|
115
|
+
.then(() => {
|
|
116
|
+
Object.keys(this.unsubscibe).forEach((key) => {
|
|
117
|
+
if (this.unsubscibe[key] instanceof Function) {
|
|
118
|
+
this.unsubscibe[key]();
|
|
119
|
+
this.unsubscibe[key] = null;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
})
|
|
123
|
+
.catch(() => {
|
|
124
|
+
// Do nothing
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
private setOnAuthStateChanged = (): void => {
|
|
129
|
+
onAuthStateChanged(this.auth, (userAuth) => {
|
|
130
|
+
if (userAuth) {
|
|
131
|
+
this.user.email = userAuth.email;
|
|
132
|
+
this.user.uid = userAuth.uid;
|
|
133
|
+
this.user.loggedIn = true;
|
|
134
|
+
this.user.logInError = false;
|
|
135
|
+
this.user.logInErrorMessage = "";
|
|
136
|
+
} else {
|
|
137
|
+
this.user.email = "";
|
|
138
|
+
this.user.uid = null;
|
|
139
|
+
this.user.loggedIn = false;
|
|
140
|
+
this.user.logInError = false;
|
|
141
|
+
this.user.logInErrorMessage = "";
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Composable to login and set persistence
|
|
147
|
+
public logIn = (credentials: Credentials, isPersistant = false): void => {
|
|
148
|
+
this.logOut();
|
|
149
|
+
let persistence: Persistence = browserSessionPersistence;
|
|
150
|
+
if (isPersistant) {
|
|
151
|
+
persistence = browserLocalPersistence;
|
|
152
|
+
}
|
|
153
|
+
setPersistence(this.auth, persistence)
|
|
154
|
+
.then(() => {
|
|
155
|
+
signInWithEmailAndPassword(
|
|
156
|
+
this.auth,
|
|
157
|
+
credentials.email,
|
|
158
|
+
credentials.password
|
|
159
|
+
)
|
|
160
|
+
.then(() => {
|
|
161
|
+
// do nothing
|
|
162
|
+
})
|
|
163
|
+
.catch((error) => {
|
|
164
|
+
this.user.email = "";
|
|
165
|
+
this.user.uid = null;
|
|
166
|
+
|
|
167
|
+
this.user.loggedIn = false;
|
|
168
|
+
this.user.logInError = true;
|
|
169
|
+
this.user.logInErrorMessage = error.code + ": " + error.message;
|
|
170
|
+
});
|
|
171
|
+
})
|
|
172
|
+
.catch((error) => {
|
|
173
|
+
this.user.email = "";
|
|
174
|
+
this.user.uid = null;
|
|
175
|
+
|
|
176
|
+
this.user.loggedIn = false;
|
|
177
|
+
this.user.logInError = true;
|
|
178
|
+
this.user.logInErrorMessage = error.code + ": " + error.message;
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Keeping this for reference on how to Type a Ref.
|
|
183
|
+
// const user = ref<UserDataObject>({
|
|
184
|
+
// uid: null,
|
|
185
|
+
// email: "",
|
|
186
|
+
// loggedIn: false,
|
|
187
|
+
// logInError: false,
|
|
188
|
+
// logInErrorMessage: ""
|
|
189
|
+
// });
|
|
190
|
+
|
|
191
|
+
// Simple Store Items (add matching key per firebase collection)
|
|
192
|
+
public data: CollectionDataObject = reactive({});
|
|
193
|
+
public unsubscibe: CollectionUnsubscribeObject = reactive({});
|
|
194
|
+
public user: UserDataObject = reactive({
|
|
195
|
+
uid: null,
|
|
196
|
+
email: "",
|
|
197
|
+
loggedIn: false,
|
|
198
|
+
logInError: false,
|
|
199
|
+
logInErrorMessage: ""
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
public getDocData = async (
|
|
203
|
+
collectionPath: string,
|
|
204
|
+
docId: string
|
|
205
|
+
): Promise<{ [key: string]: unknown }> => {
|
|
206
|
+
const docRef = doc(this.db, collectionPath, docId);
|
|
207
|
+
const docSnap = await getDoc(docRef);
|
|
208
|
+
const docData = docSnap.data();
|
|
209
|
+
docData.docId = docSnap.id;
|
|
210
|
+
return docData;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
private getStaticData = async (
|
|
214
|
+
collectionPath: string,
|
|
215
|
+
queryList: FirestoreQuery[] = [],
|
|
216
|
+
orderList: FirestoreOrderBy[] = [],
|
|
217
|
+
max = 0,
|
|
218
|
+
last: DocumentData | null = null
|
|
219
|
+
): Promise<StaticDataResult> => {
|
|
220
|
+
const data: object = {};
|
|
221
|
+
|
|
222
|
+
const q = this.getQuery(collectionPath, queryList, orderList, max, last);
|
|
223
|
+
|
|
224
|
+
const docs = await getDocs(q);
|
|
225
|
+
const nextLast: DocumentData = docs.docs[docs.docs.length - 1];
|
|
226
|
+
|
|
227
|
+
docs.forEach((doc) => {
|
|
228
|
+
const item = doc.data();
|
|
229
|
+
item.docId = doc.id;
|
|
230
|
+
data[doc.id] = item;
|
|
231
|
+
});
|
|
232
|
+
return { data, next: nextLast };
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Class for wrapping a getSaticData to handle pagination
|
|
236
|
+
get SearchStaticData() {
|
|
237
|
+
const getStaticData = this.getStaticData;
|
|
238
|
+
return class {
|
|
239
|
+
private collectionPath = "";
|
|
240
|
+
private queryList: FirestoreQuery[] = [];
|
|
241
|
+
private orderList: FirestoreOrderBy[] = [];
|
|
242
|
+
private max = 0;
|
|
243
|
+
|
|
244
|
+
public results = reactive({
|
|
245
|
+
data: {},
|
|
246
|
+
pagination: [],
|
|
247
|
+
staticIsLastPage: true,
|
|
248
|
+
staticIsFirstPage: true,
|
|
249
|
+
staticCurrentPage: ""
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
public prev = async (): Promise<void> => {
|
|
253
|
+
const findIndex = this.results.pagination.findIndex(
|
|
254
|
+
(x) => x.key === this.results.staticCurrentPage
|
|
255
|
+
);
|
|
256
|
+
let last = null;
|
|
257
|
+
if (findIndex === 1) {
|
|
258
|
+
this.results.staticCurrentPage = "";
|
|
259
|
+
this.results.staticIsLastPage = false;
|
|
260
|
+
this.results.staticIsFirstPage = true;
|
|
261
|
+
} else {
|
|
262
|
+
last = this.results.pagination[findIndex - 2].next;
|
|
263
|
+
this.results.staticCurrentPage =
|
|
264
|
+
this.results.pagination[findIndex - 2].key;
|
|
265
|
+
}
|
|
266
|
+
await this.afterNextPrev(last);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
public next = async (): Promise<void> => {
|
|
270
|
+
const findIndex = this.results.pagination.findIndex(
|
|
271
|
+
(x) => x.key === this.results.staticCurrentPage
|
|
272
|
+
);
|
|
273
|
+
const last = this.results.pagination[findIndex].next;
|
|
274
|
+
if (this.results.pagination.length === 1) {
|
|
275
|
+
this.results.staticIsFirstPage = true;
|
|
276
|
+
} else {
|
|
277
|
+
this.results.staticIsFirstPage = false;
|
|
278
|
+
}
|
|
279
|
+
await this.afterNextPrev(last);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
private afterNextPrev = async (last): Promise<void> => {
|
|
283
|
+
let results = await getStaticData(
|
|
284
|
+
"users",
|
|
285
|
+
this.queryList,
|
|
286
|
+
this.orderList,
|
|
287
|
+
this.max,
|
|
288
|
+
last
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
if (last && Object.keys(results.data).length === 0) {
|
|
292
|
+
this.results.staticIsLastPage = true;
|
|
293
|
+
if (this.results.pagination.length === 1) {
|
|
294
|
+
last = null;
|
|
295
|
+
this.results.staticCurrentPage = "";
|
|
296
|
+
this.results.staticIsFirstPage = true;
|
|
297
|
+
} else {
|
|
298
|
+
last =
|
|
299
|
+
this.results.pagination[this.results.pagination.length - 2].next;
|
|
300
|
+
this.results.staticCurrentPage =
|
|
301
|
+
this.results.pagination[this.results.pagination.length - 2].key;
|
|
302
|
+
}
|
|
303
|
+
results = await getStaticData(
|
|
304
|
+
"users",
|
|
305
|
+
this.queryList,
|
|
306
|
+
this.orderList,
|
|
307
|
+
this.max,
|
|
308
|
+
last
|
|
309
|
+
);
|
|
310
|
+
} else {
|
|
311
|
+
this.results.staticIsLastPage = false;
|
|
312
|
+
if (this.results.pagination.length === 1) {
|
|
313
|
+
this.results.staticIsFirstPage = false;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
this.results.data = results.data;
|
|
317
|
+
this.results.staticCurrentPage = results.next.id;
|
|
318
|
+
if (!this.results.staticIsLastPage) {
|
|
319
|
+
if (results.next) {
|
|
320
|
+
const findItem = this.results.pagination.find(
|
|
321
|
+
(x) => x.key === results.next.id
|
|
322
|
+
);
|
|
323
|
+
if (!findItem) {
|
|
324
|
+
this.results.pagination.push({
|
|
325
|
+
key: results.next.id,
|
|
326
|
+
next: results.next
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
public getData = async (
|
|
334
|
+
collectionPath: string,
|
|
335
|
+
queryList: FirestoreQuery[] = [],
|
|
336
|
+
orderList: FirestoreOrderBy[] = [],
|
|
337
|
+
max = 0
|
|
338
|
+
): Promise<void> => {
|
|
339
|
+
this.collectionPath = collectionPath;
|
|
340
|
+
this.queryList = queryList;
|
|
341
|
+
this.orderList = orderList;
|
|
342
|
+
this.max = max;
|
|
343
|
+
this.results.staticIsLastPage = true;
|
|
344
|
+
this.results.staticIsFirstPage = true;
|
|
345
|
+
this.results.staticCurrentPage = "";
|
|
346
|
+
this.results.pagination = [];
|
|
347
|
+
this.results.pagination = [];
|
|
348
|
+
this.results.data = {};
|
|
349
|
+
const results = await getStaticData(
|
|
350
|
+
collectionPath,
|
|
351
|
+
queryList,
|
|
352
|
+
orderList,
|
|
353
|
+
max
|
|
354
|
+
);
|
|
355
|
+
if (Object.keys(results.data).length > 0) {
|
|
356
|
+
this.results.staticIsLastPage = false;
|
|
357
|
+
this.results.data = results.data;
|
|
358
|
+
this.results.staticCurrentPage = results.next.id;
|
|
359
|
+
this.results.pagination.push({
|
|
360
|
+
key: results.next.id,
|
|
361
|
+
next: results.next
|
|
362
|
+
});
|
|
363
|
+
} else {
|
|
364
|
+
this.results.staticIsLastPage = true;
|
|
365
|
+
this.results.staticIsFirstPage = true;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Class for wrapping a getSaticData to handle pagination
|
|
372
|
+
public SearchStaticDatas = new (class {})();
|
|
373
|
+
|
|
374
|
+
// Composable to start snapshot listener and set unsubscribe function
|
|
375
|
+
public startSnapshot = (
|
|
376
|
+
collectionPath: string,
|
|
377
|
+
queryList: FirestoreQuery[] = [],
|
|
378
|
+
orderList: FirestoreOrderBy[] = [],
|
|
379
|
+
max = 0
|
|
380
|
+
): void => {
|
|
381
|
+
this.data[collectionPath] = {};
|
|
382
|
+
const q = this.getQuery(collectionPath, queryList, orderList, max);
|
|
383
|
+
const unsubscribe = onSnapshot(q, (querySnapshot) => {
|
|
384
|
+
const items = {};
|
|
385
|
+
querySnapshot.forEach((doc) => {
|
|
386
|
+
const item = doc.data();
|
|
387
|
+
item.docId = doc.id;
|
|
388
|
+
items[doc.id] = item;
|
|
389
|
+
});
|
|
390
|
+
this.data[collectionPath] = items;
|
|
391
|
+
});
|
|
392
|
+
this.unsubscibe[collectionPath] = unsubscribe;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
private getQuery = (
|
|
396
|
+
collectionPath: string,
|
|
397
|
+
queryList: FirestoreQuery[] = [],
|
|
398
|
+
orderList: FirestoreOrderBy[] = [],
|
|
399
|
+
max = 0,
|
|
400
|
+
after: DocumentData | null = null
|
|
401
|
+
): Query => {
|
|
402
|
+
const queryConditions: QueryConstraint[] = queryList.map((condition) =>
|
|
403
|
+
where(condition.field, condition.operator, condition.value)
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
const orderConditions: QueryConstraint[] = orderList.map((condition) =>
|
|
407
|
+
orderBy(condition.field, condition.direction)
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
let limitList: FirestoreLimit[] = [];
|
|
411
|
+
if (max > 0) {
|
|
412
|
+
limitList = [{ limit: max }];
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const limitConditions: QueryConstraint[] = limitList.map((condition) =>
|
|
416
|
+
limit(condition.limit)
|
|
417
|
+
);
|
|
418
|
+
if (after) {
|
|
419
|
+
return query(
|
|
420
|
+
collection(this.db, collectionPath),
|
|
421
|
+
...queryConditions,
|
|
422
|
+
...orderConditions,
|
|
423
|
+
...limitConditions,
|
|
424
|
+
startAfter(after)
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
return query(
|
|
428
|
+
collection(this.db, collectionPath),
|
|
429
|
+
...queryConditions,
|
|
430
|
+
...orderConditions,
|
|
431
|
+
...limitConditions
|
|
432
|
+
);
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// Composable to update/add a document
|
|
436
|
+
public storeDoc = async (
|
|
437
|
+
collectionPath: string,
|
|
438
|
+
item: object
|
|
439
|
+
): Promise<void> => {
|
|
440
|
+
const cloneItem = JSON.parse(JSON.stringify(item));
|
|
441
|
+
const currentTime = new Date().getTime();
|
|
442
|
+
cloneItem.last_updated = currentTime;
|
|
443
|
+
cloneItem.uid = this.user.uid;
|
|
444
|
+
if (!Object.prototype.hasOwnProperty.call(cloneItem, "doc_created_at")) {
|
|
445
|
+
cloneItem.doc_created_at = currentTime;
|
|
446
|
+
}
|
|
447
|
+
if (Object.prototype.hasOwnProperty.call(cloneItem, "docId")) {
|
|
448
|
+
const docId = cloneItem.docId;
|
|
449
|
+
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
450
|
+
this.data[collectionPath][docId] = cloneItem;
|
|
451
|
+
}
|
|
452
|
+
setDoc(doc(this.db, collectionPath, docId), cloneItem);
|
|
453
|
+
} else {
|
|
454
|
+
const docRef = await addDoc(
|
|
455
|
+
collection(this.db, collectionPath),
|
|
456
|
+
cloneItem
|
|
457
|
+
);
|
|
458
|
+
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
459
|
+
this.data[collectionPath][docRef.id] = cloneItem;
|
|
460
|
+
}
|
|
461
|
+
this.storeDoc(collectionPath, { ...cloneItem, docId: docRef.id });
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
// Composable to delete a document
|
|
466
|
+
public removeDoc = (collectionPath: string, docId: string): void => {
|
|
467
|
+
// Just in case getting collection back from firebase is slow:
|
|
468
|
+
if (Object.prototype.hasOwnProperty.call(this.data, collectionPath)) {
|
|
469
|
+
if (
|
|
470
|
+
Object.prototype.hasOwnProperty.call(this.data[collectionPath], docId)
|
|
471
|
+
) {
|
|
472
|
+
delete this.data[collectionPath][docId];
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
deleteDoc(doc(this.db, collectionPath, docId));
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
// Composable to stop snapshot listener
|
|
479
|
+
public stopSnapshot = (collectionPath: string): void => {
|
|
480
|
+
if (this.unsubscibe[collectionPath] instanceof Function) {
|
|
481
|
+
this.unsubscibe[collectionPath]();
|
|
482
|
+
this.unsubscibe[collectionPath] = null;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
};
|
package/index.ts
CHANGED
|
@@ -1,448 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
collection,
|
|
7
|
-
addDoc,
|
|
8
|
-
updateDoc,
|
|
9
|
-
doc,
|
|
10
|
-
query,
|
|
11
|
-
onSnapshot,
|
|
12
|
-
WhereFilterOp,
|
|
13
|
-
QueryConstraint,
|
|
14
|
-
Unsubscribe,
|
|
15
|
-
where,
|
|
16
|
-
deleteDoc,
|
|
17
|
-
getDocs,
|
|
18
|
-
getDoc,
|
|
19
|
-
orderBy,
|
|
20
|
-
limit,
|
|
21
|
-
Query,
|
|
22
|
-
startAfter,
|
|
23
|
-
DocumentData,
|
|
24
|
-
setDoc
|
|
25
|
-
} from "firebase/firestore";
|
|
26
|
-
|
|
27
|
-
import {
|
|
28
|
-
getAuth,
|
|
29
|
-
setPersistence,
|
|
30
|
-
browserSessionPersistence,
|
|
31
|
-
browserLocalPersistence,
|
|
32
|
-
Persistence,
|
|
33
|
-
signInWithEmailAndPassword,
|
|
34
|
-
onAuthStateChanged,
|
|
35
|
-
signOut
|
|
36
|
-
} from "firebase/auth";
|
|
37
|
-
|
|
38
|
-
interface FirestoreQuery {
|
|
39
|
-
field: string;
|
|
40
|
-
operator: WhereFilterOp; // '==' | '<' | '<=' | '>' | '>=' | 'array-contains' | 'in' | 'array-contains-any';
|
|
41
|
-
value: unknown;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface FirestoreOrderBy {
|
|
45
|
-
field: string;
|
|
46
|
-
direction: "asc" | "desc";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface FirestoreLimit {
|
|
50
|
-
limit: number;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface CollectionUnsubscribeObject {
|
|
54
|
-
[key: string]: Unsubscribe;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
interface CollectionDataObject {
|
|
58
|
-
[key: string]: object;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
interface UserDataObject {
|
|
62
|
-
uid: string | null;
|
|
63
|
-
email: string;
|
|
64
|
-
loggedIn: boolean;
|
|
65
|
-
logInError: boolean;
|
|
66
|
-
logInErrorMessage: string;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
interface Credentials {
|
|
70
|
-
email: string;
|
|
71
|
-
password: string;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
interface StaticDataResult {
|
|
75
|
-
data: object;
|
|
76
|
-
next: DocumentData | null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const firebaseConfig = {
|
|
80
|
-
apiKey: import.meta.env.VITE_FIREBASE_API_KEY as string,
|
|
81
|
-
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN as string,
|
|
82
|
-
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID as string,
|
|
83
|
-
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET as string,
|
|
84
|
-
messagingSenderId: import.meta.env
|
|
85
|
-
.VITE_FIREBASE_MESSAGING_SENDER_ID as string,
|
|
86
|
-
appId: import.meta.env.VITE_FIREBASE_APP_ID as string
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// Initialize Firebase
|
|
90
|
-
export const app = initializeApp(firebaseConfig);
|
|
91
|
-
export const auth = getAuth(app);
|
|
92
|
-
export const db = getFirestore(app);
|
|
93
|
-
|
|
94
|
-
onAuthStateChanged(auth, (userAuth) => {
|
|
95
|
-
if (userAuth) {
|
|
96
|
-
user.email = userAuth.email;
|
|
97
|
-
user.uid = userAuth.uid;
|
|
98
|
-
user.loggedIn = true;
|
|
99
|
-
user.logInError = false;
|
|
100
|
-
user.logInErrorMessage = "";
|
|
101
|
-
} else {
|
|
102
|
-
user.email = "";
|
|
103
|
-
user.uid = null;
|
|
104
|
-
user.loggedIn = false;
|
|
105
|
-
user.logInError = false;
|
|
106
|
-
user.logInErrorMessage = "";
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// Composable to logout
|
|
111
|
-
export const logOut = (): void => {
|
|
112
|
-
signOut(auth)
|
|
113
|
-
.then(() => {
|
|
114
|
-
Object.keys(unsubscibe).forEach((key) => {
|
|
115
|
-
if (unsubscibe[key] instanceof Function) {
|
|
116
|
-
unsubscibe[key]();
|
|
117
|
-
unsubscibe[key] = null;
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
})
|
|
121
|
-
.catch(() => {
|
|
122
|
-
// Do nothing
|
|
123
|
-
});
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// Composable to login and set persistence
|
|
127
|
-
export const logIn = (credentials: Credentials, isPersistant = false): void => {
|
|
128
|
-
logOut();
|
|
129
|
-
let persistence: Persistence = browserSessionPersistence;
|
|
130
|
-
if (isPersistant) {
|
|
131
|
-
persistence = browserLocalPersistence;
|
|
132
|
-
}
|
|
133
|
-
setPersistence(auth, persistence)
|
|
134
|
-
.then(() => {
|
|
135
|
-
signInWithEmailAndPassword(auth, credentials.email, credentials.password)
|
|
136
|
-
.then(() => {
|
|
137
|
-
// do nothing
|
|
138
|
-
})
|
|
139
|
-
.catch((error) => {
|
|
140
|
-
user.email = "";
|
|
141
|
-
user.uid = null;
|
|
142
|
-
|
|
143
|
-
user.loggedIn = false;
|
|
144
|
-
user.logInError = true;
|
|
145
|
-
user.logInErrorMessage = error.code + ": " + error.message;
|
|
146
|
-
});
|
|
147
|
-
})
|
|
148
|
-
.catch((error) => {
|
|
149
|
-
user.email = "";
|
|
150
|
-
user.uid = null;
|
|
151
|
-
|
|
152
|
-
user.loggedIn = false;
|
|
153
|
-
user.logInError = true;
|
|
154
|
-
user.logInErrorMessage = error.code + ": " + error.message;
|
|
155
|
-
});
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// Keeping this for reference on how to Type a Ref.
|
|
159
|
-
// export const user = ref<UserDataObject>({
|
|
160
|
-
// uid: null,
|
|
161
|
-
// email: "",
|
|
162
|
-
// loggedIn: false,
|
|
163
|
-
// logInError: false,
|
|
164
|
-
// logInErrorMessage: ""
|
|
165
|
-
// });
|
|
166
|
-
|
|
167
|
-
// Simple Store Items (add matching key per firebase collection)
|
|
168
|
-
export const data: CollectionDataObject = reactive({});
|
|
169
|
-
export const unsubscibe: CollectionUnsubscribeObject = reactive({});
|
|
170
|
-
export const user: UserDataObject = reactive({
|
|
171
|
-
uid: null,
|
|
172
|
-
email: "",
|
|
173
|
-
loggedIn: false,
|
|
174
|
-
logInError: false,
|
|
175
|
-
logInErrorMessage: ""
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
export const getDocData = async (
|
|
179
|
-
collectionPath: string,
|
|
180
|
-
docId: string
|
|
181
|
-
): Promise<{ [key: string]: unknown }> => {
|
|
182
|
-
const docRef = doc(db, collectionPath, docId);
|
|
183
|
-
const docSnap = await getDoc(docRef);
|
|
184
|
-
const docData = docSnap.data();
|
|
185
|
-
docData.docId = docSnap.id;
|
|
186
|
-
return docData;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
export const getStaticData = async (
|
|
190
|
-
collectionPath: string,
|
|
191
|
-
queryList: FirestoreQuery[] = [],
|
|
192
|
-
orderList: FirestoreOrderBy[] = [],
|
|
193
|
-
max = 0,
|
|
194
|
-
last: DocumentData | null = null
|
|
195
|
-
): Promise<StaticDataResult> => {
|
|
196
|
-
const data: object = {};
|
|
197
|
-
|
|
198
|
-
const q = getQuery(collectionPath, queryList, orderList, max, last);
|
|
199
|
-
|
|
200
|
-
const docs = await getDocs(q);
|
|
201
|
-
const nextLast: DocumentData = docs.docs[docs.docs.length - 1];
|
|
202
|
-
|
|
203
|
-
docs.forEach((doc) => {
|
|
204
|
-
const item = doc.data();
|
|
205
|
-
item.docId = doc.id;
|
|
206
|
-
data[doc.id] = item;
|
|
207
|
-
});
|
|
208
|
-
return { data, next: nextLast };
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
// Class for wrapping a getSaticData to handle pagination
|
|
212
|
-
export class SearchStaticData {
|
|
213
|
-
collectionPath = "";
|
|
214
|
-
queryList: FirestoreQuery[] = [];
|
|
215
|
-
orderList: FirestoreOrderBy[] = [];
|
|
216
|
-
max = 0;
|
|
217
|
-
|
|
218
|
-
results = reactive({
|
|
219
|
-
data: {},
|
|
220
|
-
pagination: [],
|
|
221
|
-
staticIsLastPage: true,
|
|
222
|
-
staticIsFirstPage: true,
|
|
223
|
-
staticCurrentPage: ""
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
prev = async (): Promise<void> => {
|
|
227
|
-
const findIndex = this.results.pagination.findIndex(
|
|
228
|
-
(x) => x.key === this.results.staticCurrentPage
|
|
229
|
-
);
|
|
230
|
-
let last = null;
|
|
231
|
-
if (findIndex === 1) {
|
|
232
|
-
this.results.staticCurrentPage = "";
|
|
233
|
-
this.results.staticIsLastPage = false;
|
|
234
|
-
this.results.staticIsFirstPage = true;
|
|
235
|
-
} else {
|
|
236
|
-
last = this.results.pagination[findIndex - 2].next;
|
|
237
|
-
this.results.staticCurrentPage =
|
|
238
|
-
this.results.pagination[findIndex - 2].key;
|
|
239
|
-
}
|
|
240
|
-
await this.afterNextPrev(last);
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
next = async (): Promise<void> => {
|
|
244
|
-
const findIndex = this.results.pagination.findIndex(
|
|
245
|
-
(x) => x.key === this.results.staticCurrentPage
|
|
246
|
-
);
|
|
247
|
-
const last = this.results.pagination[findIndex].next;
|
|
248
|
-
if (this.results.pagination.length === 1) {
|
|
249
|
-
this.results.staticIsFirstPage = true;
|
|
250
|
-
} else {
|
|
251
|
-
this.results.staticIsFirstPage = false;
|
|
252
|
-
}
|
|
253
|
-
await this.afterNextPrev(last);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
afterNextPrev = async (last): Promise<void> => {
|
|
257
|
-
let results = await getStaticData(
|
|
258
|
-
"users",
|
|
259
|
-
this.queryList,
|
|
260
|
-
this.orderList,
|
|
261
|
-
this.max,
|
|
262
|
-
last
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
if (last && Object.keys(results.data).length === 0) {
|
|
266
|
-
this.results.staticIsLastPage = true;
|
|
267
|
-
if (this.results.pagination.length === 1) {
|
|
268
|
-
last = null;
|
|
269
|
-
this.results.staticCurrentPage = "";
|
|
270
|
-
this.results.staticIsFirstPage = true;
|
|
271
|
-
} else {
|
|
272
|
-
last = this.results.pagination[this.results.pagination.length - 2].next;
|
|
273
|
-
this.results.staticCurrentPage =
|
|
274
|
-
this.results.pagination[this.results.pagination.length - 2].key;
|
|
275
|
-
}
|
|
276
|
-
results = await getStaticData(
|
|
277
|
-
"users",
|
|
278
|
-
this.queryList,
|
|
279
|
-
this.orderList,
|
|
280
|
-
this.max,
|
|
281
|
-
last
|
|
282
|
-
);
|
|
283
|
-
} else {
|
|
284
|
-
this.results.staticIsLastPage = false;
|
|
285
|
-
if (this.results.pagination.length === 1) {
|
|
286
|
-
this.results.staticIsFirstPage = false;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
this.results.data = results.data;
|
|
290
|
-
this.results.staticCurrentPage = results.next.id;
|
|
291
|
-
if (!this.results.staticIsLastPage) {
|
|
292
|
-
if (results.next) {
|
|
293
|
-
const findItem = this.results.pagination.find(
|
|
294
|
-
(x) => x.key === results.next.id
|
|
295
|
-
);
|
|
296
|
-
if (!findItem) {
|
|
297
|
-
this.results.pagination.push({
|
|
298
|
-
key: results.next.id,
|
|
299
|
-
next: results.next
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
getData = async (
|
|
307
|
-
collectionPath: string,
|
|
308
|
-
queryList: FirestoreQuery[] = [],
|
|
309
|
-
orderList: FirestoreOrderBy[] = [],
|
|
310
|
-
max = 0
|
|
311
|
-
): Promise<void> => {
|
|
312
|
-
this.collectionPath = collectionPath;
|
|
313
|
-
this.queryList = queryList;
|
|
314
|
-
this.orderList = orderList;
|
|
315
|
-
this.max = max;
|
|
316
|
-
this.results.staticIsLastPage = true;
|
|
317
|
-
this.results.staticIsFirstPage = true;
|
|
318
|
-
this.results.staticCurrentPage = "";
|
|
319
|
-
this.results.pagination = [];
|
|
320
|
-
this.results.pagination = [];
|
|
321
|
-
this.results.data = {};
|
|
322
|
-
const results = await getStaticData(
|
|
323
|
-
collectionPath,
|
|
324
|
-
queryList,
|
|
325
|
-
orderList,
|
|
326
|
-
max
|
|
327
|
-
);
|
|
328
|
-
if (Object.keys(results.data).length > 0) {
|
|
329
|
-
this.results.staticIsLastPage = false;
|
|
330
|
-
this.results.data = results.data;
|
|
331
|
-
this.results.staticCurrentPage = results.next.id;
|
|
332
|
-
this.results.pagination.push({
|
|
333
|
-
key: results.next.id,
|
|
334
|
-
next: results.next
|
|
335
|
-
});
|
|
336
|
-
} else {
|
|
337
|
-
this.results.staticIsLastPage = true;
|
|
338
|
-
this.results.staticIsFirstPage = true;
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Composable to start snapshot listener and set unsubscribe function
|
|
344
|
-
export const startSnapshot = (
|
|
345
|
-
collectionPath: string,
|
|
346
|
-
queryList: FirestoreQuery[] = [],
|
|
347
|
-
orderList: FirestoreOrderBy[] = [],
|
|
348
|
-
max = 0
|
|
349
|
-
): void => {
|
|
350
|
-
data[collectionPath] = {};
|
|
351
|
-
const q = getQuery(collectionPath, queryList, orderList, max);
|
|
352
|
-
const unsubscribe = onSnapshot(q, (querySnapshot) => {
|
|
353
|
-
const items = {};
|
|
354
|
-
querySnapshot.forEach((doc) => {
|
|
355
|
-
const item = doc.data();
|
|
356
|
-
item.docId = doc.id;
|
|
357
|
-
items[doc.id] = item;
|
|
358
|
-
});
|
|
359
|
-
data[collectionPath] = items;
|
|
360
|
-
});
|
|
361
|
-
unsubscibe[collectionPath] = unsubscribe;
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
const getQuery = (
|
|
365
|
-
collectionPath: string,
|
|
366
|
-
queryList: FirestoreQuery[] = [],
|
|
367
|
-
orderList: FirestoreOrderBy[] = [],
|
|
368
|
-
max = 0,
|
|
369
|
-
after: DocumentData | null = null
|
|
370
|
-
): Query => {
|
|
371
|
-
const queryConditions: QueryConstraint[] = queryList.map((condition) =>
|
|
372
|
-
where(condition.field, condition.operator, condition.value)
|
|
373
|
-
);
|
|
374
|
-
|
|
375
|
-
const orderConditions: QueryConstraint[] = orderList.map((condition) =>
|
|
376
|
-
orderBy(condition.field, condition.direction)
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
let limitList: FirestoreLimit[] = [];
|
|
380
|
-
if (max > 0) {
|
|
381
|
-
limitList = [{ limit: max }];
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const limitConditions: QueryConstraint[] = limitList.map((condition) =>
|
|
385
|
-
limit(condition.limit)
|
|
386
|
-
);
|
|
387
|
-
if (after) {
|
|
388
|
-
return query(
|
|
389
|
-
collection(db, collectionPath),
|
|
390
|
-
...queryConditions,
|
|
391
|
-
...orderConditions,
|
|
392
|
-
...limitConditions,
|
|
393
|
-
startAfter(after)
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
return query(
|
|
397
|
-
collection(db, collectionPath),
|
|
398
|
-
...queryConditions,
|
|
399
|
-
...orderConditions,
|
|
400
|
-
...limitConditions
|
|
401
|
-
);
|
|
402
|
-
};
|
|
403
|
-
|
|
404
|
-
// Composable to update/add a document
|
|
405
|
-
export const storeDoc = async (
|
|
406
|
-
collectionPath: string,
|
|
407
|
-
item: object
|
|
408
|
-
): Promise<void> => {
|
|
409
|
-
const cloneItem = JSON.parse(JSON.stringify(item));
|
|
410
|
-
const currentTime = new Date().getTime();
|
|
411
|
-
cloneItem.last_updated = currentTime;
|
|
412
|
-
cloneItem.uid = user.uid;
|
|
413
|
-
if (!Object.prototype.hasOwnProperty.call(cloneItem, "doc_created_at")) {
|
|
414
|
-
cloneItem.doc_created_at = currentTime;
|
|
415
|
-
}
|
|
416
|
-
if (Object.prototype.hasOwnProperty.call(cloneItem, "docId")) {
|
|
417
|
-
const docId = cloneItem.docId;
|
|
418
|
-
if (Object.prototype.hasOwnProperty.call(data, collectionPath)) {
|
|
419
|
-
data[collectionPath][docId] = cloneItem;
|
|
420
|
-
}
|
|
421
|
-
setDoc(doc(db, collectionPath, docId), cloneItem);
|
|
422
|
-
} else {
|
|
423
|
-
const docRef = await addDoc(collection(db, collectionPath), cloneItem);
|
|
424
|
-
if (Object.prototype.hasOwnProperty.call(data, collectionPath)) {
|
|
425
|
-
data[collectionPath][docRef.id] = cloneItem;
|
|
426
|
-
}
|
|
427
|
-
storeDoc(collectionPath, { ...cloneItem, docId: docRef.id });
|
|
428
|
-
}
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
// Composable to delete a document
|
|
432
|
-
export const removeDoc = (collectionPath: string, docId: string): void => {
|
|
433
|
-
// Just in case getting collection back from firebase is slow:
|
|
434
|
-
if (Object.prototype.hasOwnProperty.call(data, collectionPath)) {
|
|
435
|
-
if (Object.prototype.hasOwnProperty.call(data[collectionPath], docId)) {
|
|
436
|
-
delete data[collectionPath][docId];
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
deleteDoc(doc(db, collectionPath, docId));
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
// Composable to stop snapshot listener
|
|
443
|
-
export const stopSnapshot = (collectionPath: string): void => {
|
|
444
|
-
if (unsubscibe[collectionPath] instanceof Function) {
|
|
445
|
-
unsubscibe[collectionPath]();
|
|
446
|
-
unsubscibe[collectionPath] = null;
|
|
1
|
+
import { EdgeFirebase } from "./edgeFirebase";
|
|
2
|
+
export default {
|
|
3
|
+
install: (app, options) => {
|
|
4
|
+
const eFb = new EdgeFirebase(options);
|
|
5
|
+
app.provide("edgeFirebase", eFb);
|
|
447
6
|
}
|
|
448
7
|
};
|
|
8
|
+
export { EdgeFirebase };
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgedev/firebase",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.2",
|
|
4
|
+
"description": "Vue 3 / Nuxt 3 Plugin or Nuxt 3 global composable for firebase authenication and firestore",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"author": "Seth Fischer",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"firebase",
|
|
9
|
+
"nuxt 3",
|
|
10
|
+
"vue 3"
|
|
11
|
+
],
|
|
7
12
|
"license": "ISC",
|
|
8
13
|
"publishConfig": {
|
|
9
14
|
"access": "public"
|
|
@@ -14,17 +19,14 @@
|
|
|
14
19
|
"@typescript-eslint/parser": "^5.40.0",
|
|
15
20
|
"eslint": "^8.25.0",
|
|
16
21
|
"eslint-config-prettier": "^8.5.0",
|
|
22
|
+
"firebase": "^9.12.1",
|
|
17
23
|
"prettier": "^2.7.1",
|
|
18
24
|
"typescript": "^4.8.4",
|
|
19
|
-
"
|
|
20
|
-
"vue": "^3.2.41",
|
|
21
|
-
"firebase": "^9.12.1"
|
|
25
|
+
"vue": "^3.2.41"
|
|
22
26
|
},
|
|
23
|
-
"dependencies": {},
|
|
24
27
|
"peerDependencies": {
|
|
25
28
|
"firebase": "^9.12.1",
|
|
26
|
-
"vue": "^3.0.0"
|
|
27
|
-
"vite": "^3.1.8"
|
|
29
|
+
"vue": "^3.0.0"
|
|
28
30
|
},
|
|
29
31
|
"scripts": {
|
|
30
32
|
"test": "echo \"Error: no test specified\" && exit 1"
|