@edgedev/firebase 1.8.6 → 1.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -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,95 @@ staticSearch.getData("myItems", query, sort, limit);
863
768
  </script>
864
769
  ```
865
770
 
771
+ # Run a Cloud Function
866
772
 
867
- # Responses
773
+ 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.
868
774
 
869
- Most functions will return a response that can be used.
775
+ #### Parameters
870
776
 
871
- ```javascript
872
- const response = edgeFirebase.startSnapshot("things");
873
- const response = await edgeFirebase.storeDoc("myItems", {name: "John Doe"});
874
- ```
777
+ - `functionName`: A string representing the name of the cloud function to be invoked.
778
+ - `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.
875
779
 
876
- reponse:
780
+ #### Returns
877
781
 
878
- ```typescript
879
- interface actionResponse {
880
- success: boolean;
881
- message: string;
882
- meta: {}
883
- }
884
- ```
782
+ A Promise that resolves to the result of the invoked cloud function.
885
783
 
886
- # Firestore Rules
784
+ #### Example
785
+
786
+ Suppose you have a cloud function named `sendNotification` that takes two arguments: `message` and `recipientId`.
787
+
788
+ 1. First, you need to define the `sendNotification` function in your Firebase `index.js`:
887
789
 
888
790
  ```javascript
889
- rules_version = '2';
890
- service cloud.firestore {
791
+ const functions = require('firebase-functions');
891
792
 
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;
793
+ exports.sendNotification = functions.https.onCall(async (data, context) => {
794
+ if (data.uid !== context.auth.uid) {
795
+ throw new functions.https.HttpsError('permission-denied', 'Unauthorized access');
904
796
  }
905
797
 
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
- }
798
+ const message = data.message;
799
+ const recipientId = data.recipientId;
800
+ const uid = data.uid; // The user's UID is automatically included in the data object
920
801
 
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
- }
802
+ // Your notification sending logic here
951
803
 
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
- }
804
+ return { success: true, message: 'Notification sent successfully' };
805
+ });
806
+ ```
974
807
 
808
+ 1. To call this function using the `runFunction` method, you would do the following:
975
809
 
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
- );
810
+ ```javascript
811
+ <script setup>
812
+ const edgeFirebase = ...; // Reference to the object containing the runFunction method
813
+ const sendNotification = async () => {
814
+ try {
815
+ const message = "Hello, User!";
816
+ const recipientId = "someUserId";
817
+ const result = await edgeFirebase.runFunction("sendNotification", { message, recipientId });
818
+ console.log("Notification sent successfully:", result);
819
+ } catch (error) {
820
+ console.error("Error sending notification:", error);
1011
821
  }
822
+ };
823
+ </script>
1012
824
 
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
- }
825
+ <template>
826
+ <button @click="sendNotification">Send Notification</button>
827
+ </template>
828
+ ```
1030
829
 
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
- )
830
+ 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
831
 
1058
- }
832
+ # Responses
1059
833
 
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
- }
834
+ Most functions will return a response that can be used.
1065
835
 
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
- }
836
+ ```javascript
837
+ const response = edgeFirebase.startSnapshot("things");
838
+ const response = await edgeFirebase.storeDoc("myItems", {name: "John Doe"});
839
+ ```
1071
840
 
1072
- function noPermissionData() {
1073
- return request.resource.data.roles.size() == 0 && request.resource.data.specialPermissions.size() == 0;
1074
- }
841
+ reponse:
1075
842
 
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
- }
843
+ ```typescript
844
+ interface actionResponse {
845
+ success: boolean;
846
+ message: string;
847
+ meta: {}
848
+ }
849
+ ```
1082
850
 
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
- }
851
+ # Firestore Rules
1095
852
 
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
- }
853
+ 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"
854
+
855
+ ```javascript
856
+ rules_version = '2';
857
+ // #EDGE FIREBASE RULES START
858
+
859
+ // #EDGE FIREBASE RULES END
1174
860
  ```
1175
861
 
1176
862
 
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;
@@ -1633,6 +1648,7 @@ export const EdgeFirebase = class {
1633
1648
  docId?: string,
1634
1649
  ): Promise<actionResponse> => {
1635
1650
  const cloneItem = JSON.parse(JSON.stringify(item));
1651
+ cloneItem.uid = this.user.uid;
1636
1652
  if (docId !== undefined) {
1637
1653
  await setDoc( doc(this.db, collectionPath, docId), cloneItem);
1638
1654
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgedev/firebase",
3
- "version": "1.8.6",
3
+ "version": "1.8.9",
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": {
@@ -241,39 +241,39 @@ service cloud.firestore {
241
241
  match /{seg2} {
242
242
  allow get: if checkPermission(seg1 + "-" + seg2, "read");
243
243
  allow list: if checkPermission(seg1, "read");
244
- allow create: if checkPermission(seg1, "write");
245
- allow update: if checkPermission(seg1 + "-" + seg2, "write");
244
+ allow create: if request.auth.uid == request.resource.data.uid && checkPermission(seg1, "write");
245
+ allow update: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2, "write");
246
246
  allow delete: if checkPermission(seg1, "delete");
247
247
  match /{seg3} {
248
248
  allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
249
249
  allow list: if checkPermission(seg1 + "-" + seg2, "read");
250
- allow create: if checkPermission(seg1 + "-" + seg2, "write");
251
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
250
+ allow create: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2, "write");
251
+ allow update: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
252
252
  allow delete: if checkPermission(seg1 + "-" + seg2, "delete");
253
253
  match /{seg4} {
254
254
  allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
255
255
  allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "read");
256
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
257
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
256
+ allow create: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3, "write");
257
+ allow update: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
258
258
  allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3, "delete");
259
259
 
260
260
  match /{seg5} {
261
261
  allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
262
262
  allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "read");
263
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
264
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
263
+ allow create: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "write");
264
+ allow update: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
265
265
  allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4, "delete");
266
266
  match /{seg6} {
267
267
  allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
268
268
  allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "read");
269
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
270
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
269
+ allow create: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "write");
270
+ allow update: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
271
271
  allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5, "delete");
272
272
  match /{seg7} {
273
273
  allow get: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "read");
274
274
  allow list: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "read");
275
- allow create: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
276
- allow update: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "write");
275
+ allow create: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "write");
276
+ allow update: if request.auth.uid == request.resource.data.uid && checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6 + "-" + seg7, "write");
277
277
  allow delete: if checkPermission(seg1 + "-" + seg2 + "-" + seg3 + "-" + seg4 + "-" + seg5 + "-" + seg6, "delete");
278
278
  }
279
279
  }