@edgedev/firebase 1.8.7 → 1.8.10

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.
Files changed (3) hide show
  1. package/README.md +73 -385
  2. package/edgeFirebase.ts +17 -2
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,8 @@ A Vue 3 / Nuxt 3 Plugin or Nuxt 3 global composable for firebase authentication
8
8
  **[Firebase Authentication](#firebase-authentication)**
9
9
  **[Firestore Basic Document Interactions](#firestore-Basic-document-interactions)**
10
10
  **[Firestore Snapshot Listeners](#firestore-snapshot-listeners)**
11
- **[Firestore Static Collection Data](#firestore-static-collection-data)**
11
+ **[Firestore Static Collection Data](#firestore-static-collection-data)**
12
+ **[Run a Cloud Function](#run-a-cloud-function)**
12
13
  **[Await and response](#responses)**
13
14
  **[Firestore Rules](#firestore-rules)**
14
15
 
@@ -38,6 +39,7 @@ const config = {
38
39
  appId: "your-appId",
39
40
  emulatorAuth: "", // local emlulator port populated app will be started with auth emulator
40
41
  emulatorFirestore: "", // local emlulator port populated app will be started with firestore emulator
42
+ emulatorFunctions: "", // local emulator port populated app will be started with functions emulator, used to test Cloud Functions locally.
41
43
  };
42
44
  const isPersistant = true // If "persistence" is true, login will be saved locally, they can close their browser and when they open they will be logged in automatically. If "persistence" is false login saved only for the session.
43
45
  const edgeFirebase = new EdgeFirebase(config, isPersistant);
@@ -68,6 +70,7 @@ app.use(eFb, {
68
70
  appId: "your-appId",
69
71
  emulatorAuth: "", // local emlulator port populated app will be started with auth emulator
70
72
  emulatorFirestore: "", // local emlulator port populated app will be started with firestore emulator
73
+ emulatorFunctions: "", // local emulator port populated app will be started with functions emulator, used to test Cloud Functions locally.
71
74
  }, isPersistant)
72
75
  //end edgeFirebase
73
76
 
@@ -117,7 +120,7 @@ The trigger considers various scenarios such as the presence of a `userId` field
117
120
 
118
121
  In essence, the `updateUser` trigger streamlines user data management by automatically synchronizing updates between the `staged-users` and `users` collections in your Firebase project and adds another layer of security.
119
122
 
120
- User mangement requires setting up in this firestore trigger function and helper functions in your firebase functions:
123
+ User mangement requires setting up a firestore trigger function and helper functions in your firebase functions, these functions are automatically added to functions/index.js in your project, wrapped in "// START @edge/firebase functions" and "// END @edge/firebase functions".
121
124
 
122
125
  ```javascript
123
126
  const functions = require('firebase-functions')
@@ -126,105 +129,7 @@ admin.initializeApp()
126
129
  const db = admin.firestore()
127
130
 
128
131
  // START @edge/firebase functions
129
- exports.updateUser = functions.firestore.document('staged-users/{docId}').onUpdate((change, context) => {
130
- const eventId = context.eventId
131
- const eventRef = db.collection('events').doc(eventId)
132
- const stagedDocId = context.params.docId
133
- let newData = change.after.data()
134
- const oldData = change.before.data()
135
- return shouldProcess(eventRef).then((process) => {
136
- if (process) {
137
- // Note: we can trust on newData.uid because we are checking in rules that it matches the auth.uid
138
- if (newData.userId) {
139
- const userRef = db.collection('users').doc(newData.userId)
140
- setUser(userRef, newData, oldData, stagedDocId).then(() => {
141
- return markProcessed(eventRef)
142
- })
143
- }
144
- else {
145
- if (newData.templateUserId !== oldData.templateUserId) {
146
- newData.isTemplate = false
147
- const templateUserId = newData.templateUserId
148
- newData.meta = newData.templateMeta
149
- delete newData.templateMeta
150
- delete newData.templateUserId
151
- if (Object.prototype.hasOwnProperty.call(newData, 'subCreate') && Object.values(newData.subCreate).length > 0) {
152
- const subCreate = newData.subCreate
153
- delete newData.subCreate
154
- db.collection(subCreate.rootPath).add({ [subCreate.dynamicDocumentField]: newData.dynamicDocumentFieldValue }).then((addedDoc) => {
155
- db.collection(subCreate.rootPath).doc(addedDoc.id).update({ docId: addedDoc.id }).then(() => {
156
- delete newData.dynamicDocumentFieldValue
157
- const newRole = { [`${subCreate.rootPath}-${addedDoc.id}`]: { collectionPath: `${subCreate.rootPath}-${addedDoc.id}`, role: subCreate.role } }
158
- if (Object.prototype.hasOwnProperty.call(newData, 'collectionPaths')) {
159
- newData.collectionPaths.push(`${subCreate.rootPath}-${addedDoc.id}`)
160
- }
161
- else {
162
- newData.collectionPaths = [`${subCreate.rootPath}-${addedDoc.id}`]
163
- }
164
- const newRoles = { ...newData.roles, ...newRole }
165
- newData = { ...newData, roles: newRoles }
166
- const stagedUserRef = db.collection('staged-users').doc(templateUserId)
167
- return stagedUserRef.set({ ...newData, userId: templateUserId }).then(() => {
168
- const userRef = db.collection('users').doc(templateUserId)
169
- setUser(userRef, newData, oldData, templateUserId).then(() => {
170
- return markProcessed(eventRef)
171
- })
172
- })
173
- })
174
- })
175
- }
176
- else {
177
- const stagedUserRef = db.collection('staged-users').doc(templateUserId)
178
- return stagedUserRef.set({ ...newData, userId: templateUserId }).then(() => {
179
- const userRef = db.collection('users').doc(templateUserId)
180
- setUser(userRef, newData, oldData, templateUserId).then(() => {
181
- return markProcessed(eventRef)
182
- })
183
- })
184
- }
185
- }
186
- }
187
- return markProcessed(eventRef)
188
- }
189
- })
190
- })
191
-
192
- function setUser(userRef, newData, oldData, stagedDocId) {
193
- return userRef.get().then((user) => {
194
- let userUpdate = { meta: newData.meta, stagedDocId }
195
-
196
- if (Object.prototype.hasOwnProperty.call(newData, 'roles')) {
197
- userUpdate = { ...userUpdate, roles: newData.roles }
198
- }
199
- if (Object.prototype.hasOwnProperty.call(newData, 'specialPermissions')) {
200
- userUpdate = { ...userUpdate, specialPermissions: newData.specialPermissions }
201
- }
202
-
203
- if (!oldData.userId) {
204
- userUpdate = { ...userUpdate, userId: newData.uid }
205
- }
206
- console.log(userUpdate)
207
- if (!user.exists) {
208
- return userRef.set(userUpdate)
209
- }
210
- else {
211
- return userRef.update(userUpdate)
212
- }
213
- })
214
- }
215
-
216
- function shouldProcess(eventRef) {
217
- return eventRef.get().then((eventDoc) => {
218
- return !eventDoc.exists || !eventDoc.data().processed
219
- })
220
- }
221
-
222
- function markProcessed(eventRef) {
223
- return eventRef.set({ processed: true }).then(() => {
224
- return null
225
- })
226
- }
227
-
132
+ .......
228
133
  // END @edge/firebase functions
229
134
  ```
230
135
 
@@ -259,7 +164,7 @@ edgeFirebase.addUser({
259
164
  }
260
165
  ],
261
166
  meta: { firstName: "John", lastName: "Doe", age: 28 } // This is just an example of meta, it can contain any fields and any number of fields.
262
- template: true, // Optional - Only true if setting up template for self registation
167
+ isTemplate: true, // Optional - Only true if setting up template for self registation
263
168
  subCreate: {
264
169
  rootPath: 'myItems',
265
170
  role: 'admin',
@@ -863,314 +768,97 @@ staticSearch.getData("myItems", query, sort, limit);
863
768
  </script>
864
769
  ```
865
770
 
771
+ # Run a Cloud Function
866
772
 
867
- # Responses
773
+ ### edgeFirebase.runFunction('cloudFunction', {data});
868
774
 
869
- Most functions will return a response that can be used.
775
+ This function allows you to invoke a specified cloud function by providing its name and an optional data object. The user's UID is automatically added to the data object before the cloud function is called.
870
776
 
871
- ```javascript
872
- const response = edgeFirebase.startSnapshot("things");
873
- const response = await edgeFirebase.storeDoc("myItems", {name: "John Doe"});
874
- ```
777
+ #### Parameters
875
778
 
876
- reponse:
779
+ - `functionName`: A string representing the name of the cloud function to be invoked.
780
+ - `data`: An optional object containing key-value pairs that will be passed to the cloud function as arguments. The user's UID is automatically included in the data object.
877
781
 
878
- ```typescript
879
- interface actionResponse {
880
- success: boolean;
881
- message: string;
882
- meta: {}
883
- }
884
- ```
782
+ #### Returns
885
783
 
886
- # Firestore Rules
784
+ A Promise that resolves to the result of the invoked cloud function.
785
+
786
+ #### Example
787
+
788
+ Suppose you have a cloud function named `sendNotification` that takes two arguments: `message` and `recipientId`.
789
+
790
+ 1. First, you need to define the `sendNotification` function in your Firebase `index.js`:
887
791
 
888
792
  ```javascript
889
- rules_version = '2';
890
- service cloud.firestore {
793
+ const functions = require('firebase-functions');
891
794
 
892
- match /databases/{database}/documents/events/{event} {
893
- allow read: if false;
894
- allow create: if false;
895
- allow update: if false;
896
- allow delete: if false;
897
- }
898
-
899
- match /databases/{database}/documents/rule-helpers/{helper} {
900
- allow read: if false;
901
- allow create: if request.auth.uid == request.resource.data.uid;
902
- allow update: if request.auth.uid == request.resource.data.uid;
903
- allow delete: if false;
795
+ exports.sendNotification = functions.https.onCall(async (data, context) => {
796
+ if (data.uid !== context.auth.uid) {
797
+ throw new functions.https.HttpsError('permission-denied', 'Unauthorized access');
904
798
  }
905
799
 
906
- match /databases/{database}/documents/users/{user} {
907
- function readSelf() {
908
- return resource == null ||
909
- (
910
- "userId" in resource.data &&
911
- resource.data.userId == request.auth.uid
912
- );
913
- }
914
-
915
- allow read: if readSelf();
916
- allow create: if false;
917
- allow update: if false;
918
- allow delete: if readSelf();
919
- }
800
+ const message = data.message;
801
+ const recipientId = data.recipientId;
802
+ const uid = data.uid; // The user's UID is automatically included in the data object
920
803
 
921
- match /databases/{database}/documents/collection-data/{collectionPath} {
922
- // TODO: these rules need tested.
923
- function getRolePermission(role, collection, permissionCheck) {
924
- let pathCollectionPermissions = get(/databases/$(database)/documents/collection-data/$(collection)).data;
925
- let defaultPermissions = get(/databases/$(database)/documents/collection-data/-default-).data;
926
- return (role in pathCollectionPermissions && pathCollectionPermissions[role][permissionCheck]) ||
927
- (role in defaultPermissions && defaultPermissions[role][permissionCheck]);
928
- }
929
- function canAssign() {
930
- let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
931
- let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data['edge-assignment-helper'];
932
- return collectionPath.matches("^" + ruleHelper[collectionPath].permissionCheckPath + ".*$") &&
933
- (
934
- "specialPermissions" in user &&
935
- ruleHelper[collectionPath].permissionCheckPath in user.specialPermissions &&
936
- "assign" in user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath] &&
937
- user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath]["assign"]
938
- ) ||
939
- (
940
- "roles" in user &&
941
- ruleHelper[collectionPath].permissionCheckPath in user.roles &&
942
- "role" in user.roles[ruleHelper[collectionPath].permissionCheckPath] &&
943
- getRolePermission(user.roles[ruleHelper[collectionPath].permissionCheckPath].role, collectionPath, "assign")
944
- );
945
- }
946
- allow read: if request.auth != null; // All signed in users can read collection-data
947
- allow create: if canAssign();
948
- allow update: if canAssign();
949
- allow delete: if canAssign();
950
- }
804
+ // Your notification sending logic here
951
805
 
952
- match /databases/{database}/documents/staged-users/{user} {
953
-
954
- function canUpdate() {
955
- let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
956
- let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
957
-
958
- return (
959
- resource == null ||
960
- request.resource.data.userId == resource.data.userId ||
961
- (
962
- resource.data.userId == "" &&
963
- (
964
- request.resource.data.userId == request.auth.uid ||
965
- request.resource.data.templateUserId == request.auth.uid
966
- )
967
- )
968
- ) &&
969
- "edge-assignment-helper" in ruleHelper &&
970
- permissionUpdatesCheck(user, ruleHelper, "roles") &&
971
- permissionUpdatesCheck(user, ruleHelper, "specialPermssions") &&
972
- request.auth.uid == request.resource.data.uid;
973
- }
806
+ return { success: true, message: 'Notification sent successfully' };
807
+ });
808
+ ```
974
809
 
810
+ 1. To call this function using the `runFunction` method, you would do the following:
975
811
 
976
- function permissionUpdatesCheck(user, ruleHelper, permissionType) {
977
- return !(permissionType in request.resource.data) ||
978
- (
979
- resource.data.userId == request.auth.uid &&
980
- request.resource.data[permissionType].keys().hasOnly(resource.data[permissionType].keys())
981
- ) ||
982
- (
983
- resource.data.userId != request.auth.uid &&
984
- permissionCheck(permissionType, user, ruleHelper)
985
- );
986
- }
987
- function permissionCheck(permissionType, user, ruleHelper) {
988
- let lastPathUpdated = ruleHelper["edge-assignment-helper"].fullPath;
989
- let permissionCheckPath = ruleHelper["edge-assignment-helper"].permissionCheckPath;
990
- return request.resource.data[permissionType].diff(resource.data[permissionType]).affectedKeys().size() == 0 ||
991
- (
992
- request.resource.data[permissionType].diff(resource.data[permissionType]).affectedKeys().size() == 1 &&
993
- request.resource.data[permissionType].diff(resource.data[permissionType]).affectedKeys() == [lastPathUpdated].toSet() &&
994
- (
995
- permissionCheckPath == "-" ||
996
- lastPathUpdated.matches("^" + permissionCheckPath + ".*$")
997
- ) &&
998
- (
999
- (
1000
- "roles" in user &&
1001
- getRolePermission(user.roles[permissionCheckPath].role, permissionCheckPath, "assign")
1002
- ) ||
1003
- (
1004
- "specialPermissions" in user &&
1005
- permissionCheckPath in user.specialPermissions &&
1006
- "assign" in user.specialPermissions[permissionCheckPath] &&
1007
- user.specialPermissions[permissionCheckPath]["assign"]
1008
- )
1009
- )
1010
- );
812
+ ```javascript
813
+ <script setup>
814
+ const edgeFirebase = ...; // Reference to the object containing the runFunction method
815
+ const sendNotification = async () => {
816
+ try {
817
+ const message = "Hello, User!";
818
+ const recipientId = "someUserId";
819
+ const result = await edgeFirebase.runFunction("sendNotification", { message, recipientId });
820
+ console.log("Notification sent successfully:", result);
821
+ } catch (error) {
822
+ console.error("Error sending notification:", error);
1011
823
  }
824
+ };
825
+ </script>
1012
826
 
1013
- function canAssign(user, ruleHelper) {
1014
- return request.auth != null &&
1015
- "edge-assignment-helper" in ruleHelper &&
1016
- (
1017
- (
1018
- "roles" in user &&
1019
- ruleHelper["edge-assignment-helper"].permissionCheckPath in user.roles &&
1020
- getRolePermission(user.roles[ruleHelper["edge-assignment-helper"].permissionCheckPath].role, ruleHelper["edge-assignment-helper"].permissionCheckPath, 'assign')
1021
- ) ||
1022
- (
1023
- "specialPermissions" in user &&
1024
- ruleHelper["edge-assignment-helper"].permissionCheckPath in user.specialPermissions &&
1025
- "assign" in user.specialPermissions[ruleHelper["edge-assignment-helper"].permissionCheckPath] &&
1026
- user.specialPermissions[ruleHelper["edge-assignment-helper"].permissionCheckPath]["assign"]
1027
- )
1028
- )
1029
- }
827
+ <template>
828
+ <button @click="sendNotification">Send Notification</button>
829
+ </template>
830
+ ```
1030
831
 
1031
- function canAssignSubCreatePath(user, ruleHelper) {
1032
- let permissionCheckPath = ruleHelper["edge-assignment-helper"].permissionCheckPath;
1033
- return (
1034
- !("subCreate" in request.resource.data) ||
1035
- (
1036
- "subCreate" in request.resource.data &&
1037
- request.resource.data.subCreate.keys().size() == 0
1038
- )
1039
- )||
1040
- (
1041
- permissionCheckPath == "-" ||
1042
- request.resource.data.subCreate.rootPath.matches("^" + permissionCheckPath + ".*$")
1043
- ) &&
1044
- (
1045
- (
1046
- "roles" in user &&
1047
- permissionCheckPath in user.roles &&
1048
- getRolePermission(user.roles[permissionCheckPath].role, permissionCheckPath, "assign")
1049
- ) ||
1050
- (
1051
- "specialPermissions" in user &&
1052
- permissionCheckPath in user.specialPermissions &&
1053
- "assign" in user.specialPermissions[permissionCheckPath] &&
1054
- user.specialPermissions[permissionCheckPath]["assign"]
1055
- )
1056
- )
832
+ In this example, clicking the "Send Notification" button will invoke the `sendNotification` cloud function with the specified `message` and `recipientId`. The result of the function will be logged to the console. The cloud function checks if the provided `data.uid` matches the authenticated user's UID (`context.auth.uid`) for security purposes.
1057
833
 
1058
- }
834
+ # Responses
1059
835
 
1060
- function canList() {
1061
- let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
1062
- let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
1063
- return canAssign(user, ruleHelper);
1064
- }
836
+ Most functions will return a response that can be used.
1065
837
 
1066
- function canCreate() {
1067
- let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
1068
- let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
1069
- return noPermissionData() && canAssign(user, ruleHelper) && canAssignSubCreatePath(user, ruleHelper);
1070
- }
838
+ ```javascript
839
+ const response = edgeFirebase.startSnapshot("things");
840
+ const response = await edgeFirebase.storeDoc("myItems", {name: "John Doe"});
841
+ ```
1071
842
 
1072
- function noPermissionData() {
1073
- return request.resource.data.roles.size() == 0 && request.resource.data.specialPermissions.size() == 0;
1074
- }
843
+ reponse:
1075
844
 
1076
- function getRolePermission(role, collection, permissionCheck) {
1077
- let pathCollectionPermissions = get(/databases/$(database)/documents/collection-data/$(collection)).data;
1078
- let defaultPermissions = get(/databases/$(database)/documents/collection-data/-default-).data;
1079
- return (role in pathCollectionPermissions && pathCollectionPermissions[role][permissionCheck]) ||
1080
- (role in defaultPermissions && defaultPermissions[role][permissionCheck]);
1081
- }
845
+ ```typescript
846
+ interface actionResponse {
847
+ success: boolean;
848
+ message: string;
849
+ meta: {}
850
+ }
851
+ ```
1082
852
 
1083
- function canGet () {
1084
- return resource == null ||
1085
- ("userId" in resource.data && resource.data.userId == "") ||
1086
- ("userId" in resource.data && resource.data.userId == request.auth.uid) ||
1087
- canAssign(get(/databases/$(database)/documents/users/$(request.auth.uid)).data, get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data);
1088
- }
1089
- allow get: if canGet();
1090
- allow list: if canList();
1091
- allow create: if canCreate();
1092
- allow update: if canUpdate();
1093
- allow delete: if request.auth.uid == resource.data.userId // TODO: if isTemplate is true... can delete... if assign permission
1094
- }
853
+ # Firestore Rules
1095
854
 
1096
- match /databases/{database}/documents/{seg1} {
1097
- function getRolePermission(role, collection, permissionCheck) {
1098
- let pathCollectionPermissions = get(/databases/$(database)/documents/collection-data/$(collection)).data;
1099
- let defaultPermissions = get(/databases/$(database)/documents/collection-data/-default-).data;
1100
- return (role in pathCollectionPermissions && pathCollectionPermissions[role][permissionCheck]) ||
1101
- (role in defaultPermissions && defaultPermissions[role][permissionCheck]);
1102
- }
1103
- function checkPermission(collectionPath, permissionCheck) {
1104
- let user = get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
1105
- let skipPaths = ["collection-data", "users", "staged-users", "events", "rule-helpers"];
1106
- let ruleHelper = get(/databases/$(database)/documents/rule-helpers/$(request.auth.uid)).data;
1107
- return !(collectionPath in skipPaths) &&
1108
- request.auth != null &&
1109
- collectionPath in ruleHelper &&
1110
- "permissionCheckPath" in ruleHelper[collectionPath] &&
1111
- (
1112
- ruleHelper[collectionPath].permissionCheckPath == "-" ||
1113
- collectionPath.matches("^" + ruleHelper[collectionPath].permissionCheckPath + ".*$")
1114
- ) &&
1115
- (
1116
- (
1117
- "roles" in user &&
1118
- ruleHelper[collectionPath].permissionCheckPath in user.roles &&
1119
- getRolePermission(user.roles[ruleHelper[collectionPath].permissionCheckPath].role, ruleHelper[collectionPath].permissionCheckPath, permissionCheck)
1120
- ) ||
1121
- (
1122
- "specialPermissions" in user &&
1123
- ruleHelper[collectionPath].permissionCheckPath in user.specialPermissions &&
1124
- permissionCheck in user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath] &&
1125
- user.specialPermissions[ruleHelper[collectionPath].permissionCheckPath][permissionCheck]
1126
- )
1127
- );
1128
- }
1129
- match /{seg2} {
1130
- allow get: if checkPermission(seg1 + "-" + seg2, "read");
1131
- allow list: if checkPermission(seg1, "read");
1132
- allow create: if checkPermission(seg1, "write");
1133
- allow update: if checkPermission(seg1 + "-" + seg2, "write");
1134
- allow delete: if checkPermission(seg1, "delete");
1135
- match /{seg3} {
1136
- allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
1137
- allow list: if checkPermission(seg1 + "-" + seg2, "read");
1138
- allow create: if checkPermission(seg1 + "-" + seg2, "write");
1139
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
1140
- allow delete: if checkPermission(seg1 + "-" + seg2, "delete");
1141
- match /{seg4} {
1142
- allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
1143
- allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
1144
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
1145
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
1146
- allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "delete");
1147
-
1148
- match /{seg5} {
1149
- allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
1150
- allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
1151
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
1152
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
1153
- allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "delete");
1154
- match /{seg6} {
1155
- allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
1156
- allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
1157
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
1158
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
1159
- allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "delete");
1160
- match /{seg7} {
1161
- allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "read");
1162
- allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
1163
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
1164
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "write");
1165
- allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "delete");
1166
- }
1167
- }
1168
- }
1169
- }
1170
- }
1171
- }
1172
- }
1173
- }
855
+ Firestore rules are automatically written to your project in the firestore.rules file the are wrapped in: "// #EDGE FIREBASE RULES START" and "// #EDGE FIREBASE RULES END"
856
+
857
+ ```javascript
858
+ rules_version = '2';
859
+ // #EDGE FIREBASE RULES START
860
+
861
+ // #EDGE FIREBASE RULES END
1174
862
  ```
1175
863
 
1176
864
 
package/edgeFirebase.ts CHANGED
@@ -48,6 +48,7 @@ import {
48
48
  signInWithPopup,
49
49
  } from "firebase/auth";
50
50
 
51
+ import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
51
52
 
52
53
  import { getAnalytics, logEvent } from "firebase/analytics";
53
54
 
@@ -163,6 +164,7 @@ interface firebaseConfig {
163
164
  emulatorAuth?: string;
164
165
  measurementId?: string;
165
166
  emulatorFirestore?: string;
167
+ emulatorFunctions?: string;
166
168
  }
167
169
 
168
170
  interface actionResponse {
@@ -187,7 +189,8 @@ export const EdgeFirebase = class {
187
189
  appId: "",
188
190
  measurementId: "",
189
191
  emulatorAuth: "",
190
- emulatorFirestore: ""
192
+ emulatorFirestore: "",
193
+ emulatorFunctions: ""
191
194
  },
192
195
  isPersistant: false
193
196
  ) {
@@ -212,6 +215,10 @@ export const EdgeFirebase = class {
212
215
  this.anaytics = getAnalytics(this.app);
213
216
  }
214
217
 
218
+ this.functions = getFunctions(this.app);
219
+ if (this.firebaseConfig.emulatorFunctions) {
220
+ connectFunctionsEmulator(this.functions, "localhost", this.firebaseConfig.emulatorFunctions)
221
+ }
215
222
  this.setOnAuthStateChanged();
216
223
  }
217
224
 
@@ -223,6 +230,14 @@ export const EdgeFirebase = class {
223
230
 
224
231
  private anaytics = null;
225
232
 
233
+ private functions = null;
234
+
235
+ public runFunction = async (functionName: string, data: { [key: string]: unknown }) => {
236
+ data.uid = this.user.uid;
237
+ const callable = httpsCallable(this.functions, functionName);
238
+ return await callable(data);
239
+ };
240
+
226
241
  public logAnalyticsEvent = (eventName: string, eventParams: object = {}) => {
227
242
  if (this.anaytics) {
228
243
  logEvent(this.anaytics, eventName, eventParams);
@@ -399,7 +414,7 @@ export const EdgeFirebase = class {
399
414
  return;
400
415
  }
401
416
  console.log(result.user.uid);
402
- const userRef = doc(this.db, "users", result.user.uid);
417
+ const userRef = doc(this.db, "staged-users", result.user.uid);
403
418
  const userSnap = await getDoc(userRef);
404
419
  if (!userSnap.exists()) {
405
420
  this.user.logInError = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgedev/firebase",
3
- "version": "1.8.7",
3
+ "version": "1.8.10",
4
4
  "description": "Vue 3 / Nuxt 3 Plugin or Nuxt 3 plugin for firebase authentication and firestore.",
5
5
  "main": "index.ts",
6
6
  "scripts": {