| 
					
				 | 
			
			
				@@ -1,5 +1,6 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { reactive, ref } from "vue"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { useWebsocketStore } from "../websocket"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import utils from "@/utils"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const { runJob, subscribe, unsubscribe } = useWebsocketStore(); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -7,7 +8,13 @@ export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const models = ref([]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const permissions = ref(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const modelPermissions = ref({}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	const subscriptions = ref({}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const createdSubcription = ref(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const subscriptions = ref({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		models: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		created: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		updated: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		deleted: {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const fetchUserModelPermissions = async (_id?: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const data = await runJob("api.getUserModelPermissions", { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -41,15 +48,67 @@ export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return !!data[permission]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	const onUpdated = async ({ doc }) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const onCreatedCallback = async data => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Object.values(subscriptions.value.created).map( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				async subscription => subscription(data) // TODO: Error handling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const onCreated = async (callback: (data?: any) => any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!createdSubcription.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			createdSubcription.value = await subscribe( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				`model.${modelName}.created`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				onCreatedCallback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const uuid = utils.guid(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		subscriptions.value.created[uuid] = callback; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return uuid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const onUpdated = async (callback: (data?: any) => any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const uuid = utils.guid(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		subscriptions.value.updated[uuid] = callback; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return uuid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const onUpdatedCallback = async ({ doc }) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const index = models.value.findIndex(model => model._id === doc._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (index > -1) Object.assign(models.value[index], doc); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (modelPermissions.value[doc._id]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			await fetchUserModelPermissions(doc._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Object.values(subscriptions.value.updated).map( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				async subscription => subscription(data) // TODO: Error handling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	const onDeleted = async ({ oldDoc }) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const onDeleted = async (callback: (data?: any) => any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const uuid = utils.guid(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		subscriptions.value.deleted[uuid] = callback; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return uuid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const onDeletedCallback = async data => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const { oldDoc } = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Object.values(subscriptions.value.deleted).map( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				async subscription => subscription(data) // TODO: Error handling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		const index = models.value.findIndex(model => model._id === oldDoc._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if (index > -1) await unregisterModels(oldDoc._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -57,6 +116,27 @@ export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			delete modelPermissions.value[oldDoc._id]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const removeCallback = async ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		type: "created" | "updated" | "deleted", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		uuid: string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!subscriptions.value[type][uuid]) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		delete subscriptions.value[type][uuid]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			type === "created" && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Object.keys(subscriptions.value.created).length === 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			await unsubscribe( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				`model.${modelName}.created`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				createdSubcription.value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			createdSubcription.value = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const registerModels = async docs => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			(Array.isArray(docs) ? docs : [docs]).map(async _doc => { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -70,25 +150,31 @@ export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					models.value.push(docRef); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (subscriptions.value[_doc._id]) return docRef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (subscriptions.value.models[_doc._id]) return docRef; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				const updatedChannel = `model.${modelName}.updated.${_doc._id}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				const updatedUuid = await subscribe(updatedChannel, onUpdated); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				const updatedUuid = await subscribe( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					updatedChannel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					onUpdatedCallback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				const updated = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					channel: updatedChannel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					callback: onUpdated, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					callback: onUpdatedCallback, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					uuid: updatedUuid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				const deletedChannel = `model.${modelName}.deleted.${_doc._id}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				const deletedUuid = await subscribe(deletedChannel, onDeleted); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				const deletedUuid = await subscribe( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					deletedChannel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					onDeletedCallback 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				const deleted = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					channel: deletedChannel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					callback: onDeleted, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					callback: onDeletedCallback, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					uuid: deletedUuid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				subscriptions.value[_doc._id] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				subscriptions.value.models[_doc._id] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					updated, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					deleted 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				}; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -108,12 +194,15 @@ export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					const { updated, deleted } = subscriptions.value[modelId]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					const { updated, deleted } = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						subscriptions.value.models[modelId]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					await unsubscribe(updated.channel, updated.uuid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					await unsubscribe(deleted.channel, deleted.uuid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					delete subscriptions.value.models[modelId]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					models.value.splice( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						models.value.findIndex(model => model._id === modelId), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						1 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -150,6 +239,10 @@ export const createModelStore = modelName => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		permissions, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		modelPermissions, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		subscriptions, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		onCreated, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		onUpdated, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		onDeleted, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		removeCallback, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		registerModels, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		unregisterModels, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		fetchUserModelPermissions, 
			 |