| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * \file | 
					
						
							|  |  |  |  * \defgroup tfcore Tilde Friends Core JS | 
					
						
							|  |  |  |  * Tilde Friends process management, in JavaScript. | 
					
						
							|  |  |  |  * @{ | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  | /** \cond */ | 
					
						
							| 
									
										
										
										
											2022-06-18 17:39:08 +00:00
										 |  |  | import * as app from './app.js'; | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  | export {invoke, getProcessBlob}; | 
					
						
							|  |  |  | /** \endcond */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** All running processes. */ | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | let gProcesses = {}; | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** Whether stats are currently being sent. */ | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | let gStatsTimer = false; | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** Effectively a process ID. */ | 
					
						
							| 
									
										
										
										
											2025-02-27 15:00:02 -05:00
										 |  |  | let g_handler_index = 0; | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** Time between pings, in milliseconds. */ | 
					
						
							| 
									
										
										
										
											2025-02-27 15:00:02 -05:00
										 |  |  | const k_ping_interval = 60 * 1000; | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Print an error. | 
					
						
							|  |  |  |  * @param error The error. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | function printError(error) { | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 	if (error.stackTrace) { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 		print(error.fileName + ':' + error.lineNumber + ': ' + error.message); | 
					
						
							|  |  |  | 		print(error.stackTrace); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-05-27 16:51:56 +00:00
										 |  |  | 		for (let [k, v] of Object.entries(error)) { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 			print(k, v); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 		print(error.toString()); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Invoke a handler. | 
					
						
							|  |  |  |  * @param handlers The handlers on which to invoke the callback. | 
					
						
							|  |  |  |  * @param argv Arguments to pass to the handlers. | 
					
						
							|  |  |  |  * @return A promise. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | function invoke(handlers, argv) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 	let promises = []; | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 	if (handlers) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 		for (let i = 0; i < handlers.length; ++i) { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			try { | 
					
						
							|  |  |  | 				promises.push(handlers[i](...argv)); | 
					
						
							|  |  |  | 			} catch (error) { | 
					
						
							|  |  |  | 				handlers.splice(i, 1); | 
					
						
							|  |  |  | 				i--; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				promises.push( | 
					
						
							|  |  |  | 					new Promise(function (resolve, reject) { | 
					
						
							|  |  |  | 						reject(error); | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Promise.all(promises); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Broadcast a named event to all registered apps. | 
					
						
							|  |  |  |  * @param eventName the name of the event. | 
					
						
							|  |  |  |  * @param argv Arguments to pass to the handlers. | 
					
						
							|  |  |  |  * @return A promise. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | function broadcastEvent(eventName, argv) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 	let promises = []; | 
					
						
							| 
									
										
										
										
											2024-01-11 02:11:24 +00:00
										 |  |  | 	for (let process of Object.values(gProcesses)) { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 		if (process.eventHandlers[eventName]) { | 
					
						
							|  |  |  | 			promises.push(invoke(process.eventHandlers[eventName], argv)); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return Promise.all(promises); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-04-13 19:52:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Send a message to all other instances of the same app. | 
					
						
							|  |  |  |  * @param message The message. | 
					
						
							|  |  |  |  * @return A promise. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | function broadcast(message) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 	let sender = this; | 
					
						
							|  |  |  | 	let promises = []; | 
					
						
							| 
									
										
										
										
											2024-01-11 02:11:24 +00:00
										 |  |  | 	for (let process of Object.values(gProcesses)) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		if ( | 
					
						
							|  |  |  | 			process != sender && | 
					
						
							|  |  |  | 			process.packageOwner == sender.packageOwner && | 
					
						
							|  |  |  | 			process.packageName == sender.packageName | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 			let from = getUser(process, sender); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 			promises.push(postMessageInternal(from, process, message)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Promise.all(promises); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Send a message to all instances of the same app running as the same user. | 
					
						
							|  |  |  |  * @param user The user. | 
					
						
							|  |  |  |  * @param packageOwner The owner of the app. | 
					
						
							|  |  |  |  * @param packageName The name of the app. | 
					
						
							|  |  |  |  * @param eventName The name of the event. | 
					
						
							|  |  |  |  * @param argv The arguments to pass. | 
					
						
							|  |  |  |  * @return A promise. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | function broadcastAppEventToUser( | 
					
						
							|  |  |  | 	user, | 
					
						
							|  |  |  | 	packageOwner, | 
					
						
							|  |  |  | 	packageName, | 
					
						
							|  |  |  | 	eventName, | 
					
						
							|  |  |  | 	argv | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2024-04-13 19:52:40 -04:00
										 |  |  | 	let promises = []; | 
					
						
							|  |  |  | 	for (let process of Object.values(gProcesses)) { | 
					
						
							|  |  |  | 		if ( | 
					
						
							|  |  |  | 			process.credentials?.session?.name === user && | 
					
						
							|  |  |  | 			process.packageOwner == packageOwner && | 
					
						
							|  |  |  | 			process.packageName == packageName | 
					
						
							|  |  |  | 		) { | 
					
						
							|  |  |  | 			if (process.eventHandlers[eventName]) { | 
					
						
							|  |  |  | 				promises.push(invoke(process.eventHandlers[eventName], argv)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Promise.all(promises); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Get user context information for a call. | 
					
						
							|  |  |  |  * @param caller The calling process. | 
					
						
							|  |  |  |  * @param process The receiving process. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | function getUser(caller, process) { | 
					
						
							|  |  |  | 	return { | 
					
						
							| 
									
										
										
										
											2016-03-12 18:55:55 +00:00
										 |  |  | 		key: process.key, | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 		packageOwner: process.packageOwner, | 
					
						
							|  |  |  | 		packageName: process.packageName, | 
					
						
							|  |  |  | 		credentials: process.credentials, | 
					
						
							|  |  |  | 		postMessage: postMessageInternal.bind(caller, caller, process), | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Send a message. | 
					
						
							|  |  |  |  * @param from The calling process. | 
					
						
							|  |  |  |  * @param to The receiving process. | 
					
						
							|  |  |  |  * @param message The message. | 
					
						
							|  |  |  |  * @return A promise. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | function postMessageInternal(from, to, message) { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 	if (to.eventHandlers['message']) { | 
					
						
							|  |  |  | 		return invoke(to.eventHandlers['message'], [getUser(from, from), message]); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Get or create a process for an app blob. | 
					
						
							|  |  |  |  * @param blobId The blob identifier. | 
					
						
							|  |  |  |  * @param key A unique key for the invocation. | 
					
						
							|  |  |  |  * @param options Other options. | 
					
						
							|  |  |  |  * @return The process. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | async function getProcessBlob(blobId, key, options) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 	let process = gProcesses[key]; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	if (!process && !(options && 'create' in options && !options.create)) { | 
					
						
							| 
									
										
										
										
											2023-02-17 01:42:56 +00:00
										 |  |  | 		let resolveReady; | 
					
						
							|  |  |  | 		let rejectReady; | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 		try { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			print('Creating task for ' + blobId + ' ' + key); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 			process = {}; | 
					
						
							|  |  |  | 			process.key = key; | 
					
						
							|  |  |  | 			process.credentials = options.credentials || {}; | 
					
						
							|  |  |  | 			process.task = new Task(); | 
					
						
							| 
									
										
										
										
											2024-04-13 19:52:40 -04:00
										 |  |  | 			process.packageOwner = options.packageOwner; | 
					
						
							|  |  |  | 			process.packageName = options.packageName; | 
					
						
							| 
									
										
										
										
											2025-10-06 06:53:41 -04:00
										 |  |  | 			process.url = options?.url; | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 			process.eventHandlers = {}; | 
					
						
							| 
									
										
										
										
											2023-05-19 19:57:40 +00:00
										 |  |  | 			if (!options?.script || options?.script === 'app.js') { | 
					
						
							|  |  |  | 				process.app = new app.App(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 			process.lastActive = Date.now(); | 
					
						
							|  |  |  | 			process.lastPing = null; | 
					
						
							| 
									
										
										
										
											2025-02-27 15:00:02 -05:00
										 |  |  | 			process.timeout = k_ping_interval; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			process.ready = new Promise(function (resolve, reject) { | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 				resolveReady = resolve; | 
					
						
							|  |  |  | 				rejectReady = reject; | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			gProcesses[key] = process; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			process.task.onExit = function (exitCode, terminationSignal) { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 				process.task = null; | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 				delete gProcesses[key]; | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 			let imports = { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				core: { | 
					
						
							|  |  |  | 					broadcast: broadcast.bind(process), | 
					
						
							|  |  |  | 					user: getUser(process, process), | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 					allPermissionsGranted: async function () { | 
					
						
							| 
									
										
										
										
											2022-08-14 01:46:11 +00:00
										 |  |  | 						let user = process?.credentials?.session?.name; | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 						let settings = await loadSettings(); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 						if ( | 
					
						
							|  |  |  | 							user && | 
					
						
							| 
									
										
										
										
											2022-08-14 01:46:11 +00:00
										 |  |  | 							options?.packageOwner && | 
					
						
							|  |  |  | 							options?.packageName && | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 							settings.userPermissions && | 
					
						
							|  |  |  | 							settings.userPermissions[user] | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 						) { | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 							return settings.userPermissions[user]; | 
					
						
							| 
									
										
										
										
											2022-08-14 01:46:11 +00:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 					permissionTest: async function (permission) { | 
					
						
							| 
									
										
										
										
											2022-07-27 00:27:10 +00:00
										 |  |  | 						let user = process?.credentials?.session?.name; | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 						let settings = await loadSettings(); | 
					
						
							| 
									
										
										
										
											2022-07-27 00:27:10 +00:00
										 |  |  | 						if (!user || !options?.packageOwner || !options?.packageName) { | 
					
						
							| 
									
										
										
										
											2022-08-14 01:46:11 +00:00
										 |  |  | 							return; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 						} else if ( | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 							settings.userPermissions && | 
					
						
							|  |  |  | 							settings.userPermissions[user] && | 
					
						
							|  |  |  | 							settings.userPermissions[user][options.packageOwner] && | 
					
						
							|  |  |  | 							settings.userPermissions[user][options.packageOwner][ | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 								options.packageName | 
					
						
							|  |  |  | 							] && | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 							settings.userPermissions[user][options.packageOwner][ | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 								options.packageName | 
					
						
							|  |  |  | 							][permission] !== undefined | 
					
						
							|  |  |  | 						) { | 
					
						
							|  |  |  | 							if ( | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 								settings.userPermissions[user][options.packageOwner][ | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 									options.packageName | 
					
						
							|  |  |  | 								][permission] | 
					
						
							|  |  |  | 							) { | 
					
						
							| 
									
										
										
										
											2022-08-14 01:46:11 +00:00
										 |  |  | 								return true; | 
					
						
							| 
									
										
										
										
											2022-07-27 00:27:10 +00:00
										 |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2022-08-14 17:34:27 +00:00
										 |  |  | 								throw Error(`Permission denied: ${permission}.`); | 
					
						
							| 
									
										
										
										
											2022-07-27 00:27:10 +00:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2023-05-19 19:57:40 +00:00
										 |  |  | 						} else if (process.app) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 							return process.app | 
					
						
							|  |  |  | 								.makeFunction(['requestPermission'])(permission) | 
					
						
							| 
									
										
										
										
											2024-10-16 20:36:53 -04:00
										 |  |  | 								.then(async function (value) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 									if (value == 'allow') { | 
					
						
							| 
									
										
										
										
											2024-10-16 20:36:53 -04:00
										 |  |  | 										await ssb.setUserPermission( | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 											user, | 
					
						
							|  |  |  | 											options.packageOwner, | 
					
						
							|  |  |  | 											options.packageName, | 
					
						
							|  |  |  | 											permission, | 
					
						
							|  |  |  | 											true | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 										process.sendPermissions(); | 
					
						
							|  |  |  | 										return true; | 
					
						
							|  |  |  | 									} else if (value == 'allow once') { | 
					
						
							|  |  |  | 										return true; | 
					
						
							|  |  |  | 									} else if (value == 'deny') { | 
					
						
							| 
									
										
										
										
											2024-10-16 20:36:53 -04:00
										 |  |  | 										await ssb.setUserPermission( | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 											user, | 
					
						
							|  |  |  | 											options.packageOwner, | 
					
						
							|  |  |  | 											options.packageName, | 
					
						
							|  |  |  | 											permission, | 
					
						
							|  |  |  | 											false | 
					
						
							|  |  |  | 										); | 
					
						
							|  |  |  | 										process.sendPermissions(); | 
					
						
							|  |  |  | 										throw Error(`Permission denied: ${permission}.`); | 
					
						
							|  |  |  | 									} else if (value == 'deny once') { | 
					
						
							|  |  |  | 										throw Error(`Permission denied: ${permission}.`); | 
					
						
							|  |  |  | 									} | 
					
						
							| 
									
										
										
										
											2022-08-14 17:34:27 +00:00
										 |  |  | 									throw Error(`Permission denied: ${permission}.`); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 								}); | 
					
						
							| 
									
										
										
										
											2023-05-19 19:57:40 +00:00
										 |  |  | 						} else { | 
					
						
							|  |  |  | 							throw Error(`Permission denied: ${permission}.`); | 
					
						
							| 
									
										
										
										
											2022-07-27 00:27:10 +00:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | 			process.sendIdentities = async function () { | 
					
						
							| 
									
										
										
										
											2024-04-17 20:56:33 -04:00
										 |  |  | 				process.app.send( | 
					
						
							|  |  |  | 					Object.assign( | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							action: 'identities', | 
					
						
							|  |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2025-09-28 17:19:58 -04:00
										 |  |  | 						await ssb_internal.getIdentityInfo( | 
					
						
							| 
									
										
										
										
											2024-04-17 20:56:33 -04:00
										 |  |  | 							process?.credentials?.session?.name, | 
					
						
							|  |  |  | 							options?.packageOwner, | 
					
						
							|  |  |  | 							options?.packageName | 
					
						
							|  |  |  | 						) | 
					
						
							|  |  |  | 					) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | 			process.setActiveIdentity = async function (identity) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process?.credentials?.session?.name && | 
					
						
							|  |  |  | 					options.packageOwner && | 
					
						
							|  |  |  | 					options.packageName | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					await new Database(process?.credentials?.session?.name).set( | 
					
						
							|  |  |  | 						`id:${options.packageOwner}:${options.packageName}`, | 
					
						
							|  |  |  | 						identity | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				process.sendIdentities(); | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | 				broadcastAppEventToUser( | 
					
						
							|  |  |  | 					process?.credentials?.session?.name, | 
					
						
							|  |  |  | 					options.packageOwner, | 
					
						
							|  |  |  | 					options.packageName, | 
					
						
							|  |  |  | 					'setActiveIdentity', | 
					
						
							|  |  |  | 					[identity] | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | 			process.createIdentity = async function () { | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							|  |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-05-14 12:41:17 -04:00
										 |  |  | 					process.credentials.session.name && | 
					
						
							|  |  |  | 					process.credentials.session.name !== 'guest' | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 				) { | 
					
						
							| 
									
										
										
										
											2024-06-12 20:47:48 -04:00
										 |  |  | 					let id = await ssb.createIdentity(process.credentials.session.name); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 					await process.sendIdentities(); | 
					
						
							| 
									
										
										
										
											2024-04-13 20:32:17 -04:00
										 |  |  | 					broadcastAppEventToUser( | 
					
						
							|  |  |  | 						process?.credentials?.session?.name, | 
					
						
							|  |  |  | 						options.packageOwner, | 
					
						
							|  |  |  | 						options.packageName, | 
					
						
							|  |  |  | 						'setActiveIdentity', | 
					
						
							|  |  |  | 						[ | 
					
						
							| 
									
										
										
										
											2025-10-08 18:30:38 -04:00
										 |  |  | 							await imports.ssb.getActiveIdentity( | 
					
						
							| 
									
										
										
										
											2024-04-13 20:32:17 -04:00
										 |  |  | 								process.credentials?.session?.name, | 
					
						
							|  |  |  | 								options.packageOwner, | 
					
						
							|  |  |  | 								options.packageName | 
					
						
							| 
									
										
										
										
											2024-04-17 20:56:33 -04:00
										 |  |  | 							), | 
					
						
							| 
									
										
										
										
											2024-04-13 20:32:17 -04:00
										 |  |  | 						] | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 					return id; | 
					
						
							| 
									
										
										
										
											2024-05-14 12:41:17 -04:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					throw new Error('Must be signed-in to create an account.'); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | 			if (process.credentials?.permissions?.administration) { | 
					
						
							| 
									
										
										
										
											2024-08-28 19:39:05 -04:00
										 |  |  | 				imports.core.globalSettingsSet = async function (key, value) { | 
					
						
							| 
									
										
										
										
											2024-11-30 16:58:48 -05:00
										 |  |  | 					await imports.core.permissionTest('set_global_setting'); | 
					
						
							| 
									
										
										
										
											2022-08-17 00:29:57 +00:00
										 |  |  | 					print('Setting', key, value); | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 					let settings = await loadSettings(); | 
					
						
							|  |  |  | 					settings[key] = value; | 
					
						
							| 
									
										
										
										
											2024-10-16 21:02:48 -04:00
										 |  |  | 					await new Database('core').set('settings', JSON.stringify(settings)); | 
					
						
							| 
									
										
										
										
											2022-08-17 00:29:57 +00:00
										 |  |  | 					print('Done.'); | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2024-06-10 15:30:14 -04:00
										 |  |  | 				imports.core.deleteUser = async function (user) { | 
					
						
							| 
									
										
										
										
											2024-06-20 12:36:21 -04:00
										 |  |  | 					await imports.core.permissionTest('delete_user'); | 
					
						
							| 
									
										
										
										
											2024-06-10 15:30:14 -04:00
										 |  |  | 					let db = new Database('auth'); | 
					
						
							|  |  |  | 					db.remove('user:' + user); | 
					
						
							|  |  |  | 					let users = new Set(); | 
					
						
							|  |  |  | 					let users_original = await db.get('users'); | 
					
						
							|  |  |  | 					try { | 
					
						
							|  |  |  | 						users = new Set(JSON.parse(users_original)); | 
					
						
							|  |  |  | 					} catch {} | 
					
						
							|  |  |  | 					users.delete(user); | 
					
						
							|  |  |  | 					users = JSON.stringify([...users].sort()); | 
					
						
							|  |  |  | 					if (users !== users_original) { | 
					
						
							|  |  |  | 						await db.set('users', users); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2022-08-17 00:29:57 +00:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2022-08-04 00:57:56 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			if (options.api) { | 
					
						
							|  |  |  | 				imports.app = {}; | 
					
						
							|  |  |  | 				for (let i in options.api) { | 
					
						
							|  |  |  | 					let api = options.api[i]; | 
					
						
							|  |  |  | 					imports.app[api[0]] = process.app.makeFunction(api); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-05-17 20:22:13 +00:00
										 |  |  | 			for (let [name, f] of Object.entries(options?.imports || {})) { | 
					
						
							|  |  |  | 				imports[name] = f; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			process.task.onPrint = function (args) { | 
					
						
							| 
									
										
										
										
											2023-05-17 20:22:13 +00:00
										 |  |  | 				if (imports.app) { | 
					
						
							|  |  |  | 					imports.app.print(...args); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2022-02-13 22:39:22 +00:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			process.task.onError = function (error) { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 				try { | 
					
						
							| 
									
										
										
										
											2023-05-19 19:57:40 +00:00
										 |  |  | 					if (process.app) { | 
					
						
							|  |  |  | 						process.app.makeFunction(['error'])(error); | 
					
						
							|  |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 						printError(error); | 
					
						
							| 
									
										
										
										
											2023-05-19 19:57:40 +00:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} catch (e) { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 					printError(error); | 
					
						
							| 
									
										
										
										
											2016-04-16 21:30:52 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb = Object.fromEntries( | 
					
						
							|  |  |  | 				Object.keys(ssb).map((key) => [key, ssb[key].bind(ssb)]) | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2024-04-13 13:22:59 -04:00
										 |  |  | 			imports.ssb.createIdentity = () => process.createIdentity(); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb.addIdentity = function (id) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							| 
									
										
										
										
											2024-01-04 01:17:30 +00:00
										 |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return Promise.resolve( | 
					
						
							|  |  |  | 						imports.core.permissionTest('ssb_id_add') | 
					
						
							|  |  |  | 					).then(function () { | 
					
						
							| 
									
										
										
										
											2024-01-04 01:17:30 +00:00
										 |  |  | 						return ssb.addIdentity(process.credentials.session.name, id); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb.deleteIdentity = function (id) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							| 
									
										
										
										
											2024-01-06 19:22:49 +00:00
										 |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return Promise.resolve( | 
					
						
							|  |  |  | 						imports.core.permissionTest('ssb_id_delete') | 
					
						
							|  |  |  | 					).then(function () { | 
					
						
							| 
									
										
										
										
											2024-01-06 19:22:49 +00:00
										 |  |  | 						return ssb.deleteIdentity(process.credentials.session.name, id); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-04-13 20:07:39 -04:00
										 |  |  | 			imports.ssb.setActiveIdentity = (id) => process.setActiveIdentity(id); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb.getPrivateKey = function (id) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							| 
									
										
										
										
											2024-01-04 00:21:15 +00:00
										 |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return Promise.resolve( | 
					
						
							|  |  |  | 						imports.core.permissionTest('ssb_id_export') | 
					
						
							|  |  |  | 					).then(function () { | 
					
						
							| 
									
										
										
										
											2024-01-04 00:21:15 +00:00
										 |  |  | 						return ssb.getPrivateKey(process.credentials.session.name, id); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb.appendMessageWithIdentity = function (id, message) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							| 
									
										
										
										
											2022-07-31 19:01:08 +00:00
										 |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return Promise.resolve( | 
					
						
							|  |  |  | 						imports.core.permissionTest('ssb_append') | 
					
						
							|  |  |  | 					).then(function () { | 
					
						
							|  |  |  | 						return ssb.appendMessageWithIdentity( | 
					
						
							|  |  |  | 							process.credentials.session.name, | 
					
						
							|  |  |  | 							id, | 
					
						
							|  |  |  | 							message | 
					
						
							|  |  |  | 						); | 
					
						
							| 
									
										
										
										
											2022-08-14 01:46:11 +00:00
										 |  |  | 					}); | 
					
						
							| 
									
										
										
										
											2022-07-31 19:01:08 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb.privateMessageEncrypt = function (id, recipients, message) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							| 
									
										
										
										
											2023-02-26 19:51:54 +00:00
										 |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return ssb.privateMessageEncrypt( | 
					
						
							|  |  |  | 						process.credentials.session.name, | 
					
						
							|  |  |  | 						id, | 
					
						
							|  |  |  | 						recipients, | 
					
						
							|  |  |  | 						message | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2023-02-26 19:51:54 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			imports.ssb.privateMessageDecrypt = function (id, message) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							| 
									
										
										
										
											2023-02-26 19:51:54 +00:00
										 |  |  | 					process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return ssb.privateMessageDecrypt( | 
					
						
							|  |  |  | 						process.credentials.session.name, | 
					
						
							|  |  |  | 						id, | 
					
						
							|  |  |  | 						message | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2023-02-26 19:51:54 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-10-13 14:40:14 -04:00
										 |  |  | 			imports.ssb.swapWithServerIdentity = function (id) { | 
					
						
							|  |  |  | 				if ( | 
					
						
							|  |  |  | 					process.credentials && | 
					
						
							|  |  |  | 					process.credentials.session && | 
					
						
							|  |  |  | 					process.credentials.session.name | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					return ssb.swapWithServerIdentity( | 
					
						
							|  |  |  | 						process.credentials.session.name, | 
					
						
							|  |  |  | 						id | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2022-07-31 19:45:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			if ( | 
					
						
							|  |  |  | 				process.credentials && | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 				process.credentials.session && | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				process.credentials.session.name | 
					
						
							|  |  |  | 			) { | 
					
						
							|  |  |  | 				imports.database = function (key) { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 					let db = new Database(process.credentials.session.name + ':' + key); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					return Object.fromEntries( | 
					
						
							|  |  |  | 						Object.keys(db).map((x) => [x, db[x].bind(db)]) | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				imports.my_shared_database = function (packageName, key) { | 
					
						
							|  |  |  | 					let db = new Database( | 
					
						
							|  |  |  | 						':shared:' + | 
					
						
							|  |  |  | 							process.credentials.session.name + | 
					
						
							|  |  |  | 							':' + | 
					
						
							|  |  |  | 							packageName + | 
					
						
							|  |  |  | 							':' + | 
					
						
							|  |  |  | 							key | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					return Object.fromEntries( | 
					
						
							|  |  |  | 						Object.keys(db).map((x) => [x, db[x].bind(db)]) | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2022-05-25 23:45:52 +00:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2024-10-29 20:19:50 -04:00
										 |  |  | 				imports.databases = async function () { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					return [].concat( | 
					
						
							| 
									
										
										
										
											2024-10-29 20:19:50 -04:00
										 |  |  | 						await databases.list( | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 							':shared:' + process.credentials.session.name + ':%' | 
					
						
							|  |  |  | 						), | 
					
						
							| 
									
										
										
										
											2024-10-29 20:19:50 -04:00
										 |  |  | 						await databases.list(process.credentials.session.name + ':%') | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					); | 
					
						
							| 
									
										
										
										
											2022-05-25 23:45:52 +00:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2016-04-09 15:24:48 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-03-16 00:23:14 +00:00
										 |  |  | 			if (options.packageOwner && options.packageName) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				imports.shared_database = function (key) { | 
					
						
							|  |  |  | 					let db = new Database( | 
					
						
							|  |  |  | 						':shared:' + | 
					
						
							|  |  |  | 							options.packageOwner + | 
					
						
							|  |  |  | 							':' + | 
					
						
							|  |  |  | 							options.packageName + | 
					
						
							|  |  |  | 							':' + | 
					
						
							|  |  |  | 							key | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					return Object.fromEntries( | 
					
						
							|  |  |  | 						Object.keys(db).map((x) => [x, db[x].bind(db)]) | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2022-03-16 00:23:14 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 			process.sendPermissions = async function sendPermissions() { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				process.app.send({ | 
					
						
							|  |  |  | 					action: 'permissions', | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 					permissions: await imports.core.permissionsGranted(), | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				}); | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2025-02-27 14:28:07 -05:00
										 |  |  | 			process.client_api = { | 
					
						
							| 
									
										
										
										
											2025-02-27 15:00:37 -05:00
										 |  |  | 				createIdentity: function () { | 
					
						
							| 
									
										
										
										
											2025-02-27 14:28:07 -05:00
										 |  |  | 					return process.createIdentity(); | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				resetPermission: async function resetPermission(message) { | 
					
						
							|  |  |  | 					let user = process?.credentials?.session?.name; | 
					
						
							|  |  |  | 					await ssb.setUserPermission( | 
					
						
							|  |  |  | 						user, | 
					
						
							|  |  |  | 						options?.packageOwner, | 
					
						
							|  |  |  | 						options?.packageName, | 
					
						
							|  |  |  | 						message.permission, | 
					
						
							|  |  |  | 						undefined | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					return process.sendPermissions(); | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				setActiveIdentity: function setActiveIdentity(message) { | 
					
						
							|  |  |  | 					return process.setActiveIdentity(message.identity); | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2025-02-27 09:58:15 -05:00
										 |  |  | 			ssb.registerImports(imports, process); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 			process.task.setImports(imports); | 
					
						
							|  |  |  | 			process.task.activate(); | 
					
						
							| 
									
										
										
										
											2024-06-16 16:02:39 -04:00
										 |  |  | 			let source = await ssb.blobGet(blobId); | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 			let appSourceName = blobId; | 
					
						
							|  |  |  | 			let appSource = utf8Decode(source); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			try { | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 				let appObject = JSON.parse(appSource); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				if (appObject.type == 'tildefriends-app') { | 
					
						
							| 
									
										
										
										
											2023-05-17 20:22:13 +00:00
										 |  |  | 					appSourceName = options?.script ?? 'app.js'; | 
					
						
							| 
									
										
										
										
											2023-01-28 22:44:45 +00:00
										 |  |  | 					let id = appObject.files[appSourceName]; | 
					
						
							| 
									
										
										
										
											2024-06-16 16:02:39 -04:00
										 |  |  | 					let blob = await ssb.blobGet(id); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 					appSource = utf8Decode(blob); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					await process.task.loadFile([ | 
					
						
							|  |  |  | 						'/tfrpc.js', | 
					
						
							|  |  |  | 						await File.readFile('core/tfrpc.js'), | 
					
						
							|  |  |  | 					]); | 
					
						
							|  |  |  | 					await Promise.all( | 
					
						
							|  |  |  | 						Object.keys(appObject.files).map(async function (f) { | 
					
						
							|  |  |  | 							await process.task.loadFile([ | 
					
						
							|  |  |  | 								f, | 
					
						
							| 
									
										
										
										
											2024-06-16 16:02:39 -04:00
										 |  |  | 								await ssb.blobGet(appObject.files[f]), | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 							]); | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} catch (e) { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 				printError(e); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if (process.app) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				process.app.send({action: 'ready', version: version()}); | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 				await process.sendPermissions(); | 
					
						
							| 
									
										
										
										
											2017-05-23 17:47:48 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2022-01-30 21:09:32 +00:00
										 |  |  | 			await process.task.execute({name: appSourceName, source: appSource}); | 
					
						
							| 
									
										
										
										
											2023-05-27 16:51:56 +00:00
										 |  |  | 			resolveReady(process); | 
					
						
							| 
									
										
										
										
											2024-07-24 12:15:05 -04:00
										 |  |  | 			if (!gStatsTimer) { | 
					
						
							|  |  |  | 				gStatsTimer = true; | 
					
						
							|  |  |  | 				sendStats(); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 		} catch (error) { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 			if (process?.app && process?.task?.onError) { | 
					
						
							|  |  |  | 				process.task.onError(error); | 
					
						
							| 
									
										
										
										
											2022-01-03 02:25:11 +00:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2025-02-27 10:01:59 -05:00
										 |  |  | 				printError(error); | 
					
						
							| 
									
										
										
										
											2022-01-03 02:25:11 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-05-27 16:51:56 +00:00
										 |  |  | 			rejectReady(error); | 
					
						
							| 
									
										
										
										
											2016-03-12 18:50:43 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return process; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-03 18:47:34 -04:00
										 |  |  | /** | 
					
						
							|  |  |  |  * SSB message added callback. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-09-28 17:19:58 -04:00
										 |  |  | ssb_internal.addEventListener('message', function () { | 
					
						
							| 
									
										
										
										
											2024-05-22 18:51:21 -04:00
										 |  |  | 	broadcastEvent('onMessage', [...arguments]); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-28 17:19:58 -04:00
										 |  |  | ssb_internal.addEventListener('blob', function () { | 
					
						
							| 
									
										
										
										
											2025-09-24 11:34:34 -04:00
										 |  |  | 	broadcastEvent('onBlob', [...arguments]); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-28 17:19:58 -04:00
										 |  |  | ssb_internal.addEventListener('broadcasts', function () { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 	broadcastEvent('onBroadcastsChanged', []); | 
					
						
							| 
									
										
										
										
											2021-11-07 22:28:58 +00:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-28 17:19:58 -04:00
										 |  |  | ssb_internal.addEventListener('connections', function () { | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 	broadcastEvent('onConnectionsChanged', []); | 
					
						
							| 
									
										
										
										
											2021-11-07 22:28:58 +00:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-01-02 18:10:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Load settings from the database. | 
					
						
							|  |  |  |  * @return The settings as a key value pairs object. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-10-06 01:25:33 +00:00
										 |  |  | async function loadSettings() { | 
					
						
							| 
									
										
										
										
											2023-02-01 23:40:21 +00:00
										 |  |  | 	let data = {}; | 
					
						
							| 
									
										
										
										
											2021-10-06 01:25:33 +00:00
										 |  |  | 	try { | 
					
						
							| 
									
										
										
										
											2024-06-10 15:30:14 -04:00
										 |  |  | 		let settings = await new Database('core').get('settings'); | 
					
						
							| 
									
										
										
										
											2022-01-18 02:50:46 +00:00
										 |  |  | 		if (settings) { | 
					
						
							|  |  |  | 			data = JSON.parse(settings); | 
					
						
							| 
									
										
										
										
											2017-01-29 12:30:02 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-06 01:25:33 +00:00
										 |  |  | 	} catch (error) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		print('Settings not found in database:', error); | 
					
						
							| 
									
										
										
										
											2022-01-18 02:50:46 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-06 20:29:48 -05:00
										 |  |  | 	for (let [key, value] of Object.entries(defaultGlobalSettings())) { | 
					
						
							| 
									
										
										
										
											2023-03-11 02:37:27 +00:00
										 |  |  | 		if (data[key] === undefined) { | 
					
						
							|  |  |  | 			data[key] = value.default_value; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-10-16 18:11:08 -04:00
										 |  |  | 	return data; | 
					
						
							| 
									
										
										
										
											2021-10-06 01:25:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Send periodic stats to all clients. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-01-21 02:53:15 +00:00
										 |  |  | function sendStats() { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	let apps = Object.values(gProcesses) | 
					
						
							| 
									
										
										
										
											2024-07-24 12:15:05 -04:00
										 |  |  | 		.filter((process) => process.app) | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		.map((process) => process.app); | 
					
						
							| 
									
										
										
										
											2023-01-28 00:14:56 +00:00
										 |  |  | 	if (apps.length) { | 
					
						
							|  |  |  | 		let stats = getStats(); | 
					
						
							|  |  |  | 		for (let app of apps) { | 
					
						
							|  |  |  | 			app.send({action: 'stats', stats: stats}); | 
					
						
							| 
									
										
										
										
											2022-01-21 02:53:15 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-02-26 21:17:15 +00:00
										 |  |  | 		setTimeout(sendStats, 1000); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		gStatsTimer = false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-21 02:53:15 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-27 21:48:18 -04:00
										 |  |  |  * Invoke an app's handler.js. | 
					
						
							|  |  |  |  * @param response The response object. | 
					
						
							|  |  |  |  * @param app_blob_id The app's blob identifier. | 
					
						
							|  |  |  |  * @param path The request path. | 
					
						
							|  |  |  |  * @param query The request query string. | 
					
						
							|  |  |  |  * @param headers The request headers. | 
					
						
							|  |  |  |  * @param package_owner The app's owner. | 
					
						
							|  |  |  |  * @param package_name The app's name. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2024-11-03 21:09:57 -05:00
										 |  |  | exports.callAppHandler = async function callAppHandler( | 
					
						
							|  |  |  | 	response, | 
					
						
							|  |  |  | 	app_blob_id, | 
					
						
							|  |  |  | 	path, | 
					
						
							|  |  |  | 	query, | 
					
						
							|  |  |  | 	headers, | 
					
						
							|  |  |  | 	package_owner, | 
					
						
							|  |  |  | 	package_name | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	let answer; | 
					
						
							|  |  |  | 	try { | 
					
						
							|  |  |  | 		let do_resolve; | 
					
						
							|  |  |  | 		let promise = new Promise(async function (resolve, reject) { | 
					
						
							|  |  |  | 			do_resolve = resolve; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		let process; | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			process = await getProcessBlob( | 
					
						
							|  |  |  | 				app_blob_id, | 
					
						
							|  |  |  | 				'handler_' + g_handler_index++, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					script: 'handler.js', | 
					
						
							|  |  |  | 					imports: { | 
					
						
							|  |  |  | 						request: { | 
					
						
							|  |  |  | 							path: path, | 
					
						
							|  |  |  | 							query: query, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						respond: do_resolve, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					credentials: await httpd.auth_query(headers), | 
					
						
							|  |  |  | 					packageOwner: package_owner, | 
					
						
							|  |  |  | 					packageName: package_name, | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			await process.ready; | 
					
						
							|  |  |  | 			answer = await promise; | 
					
						
							|  |  |  | 		} finally { | 
					
						
							|  |  |  | 			if (process?.task) { | 
					
						
							|  |  |  | 				await process.task.kill(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} catch (error) { | 
					
						
							|  |  |  | 		let data = utf8Encode( | 
					
						
							|  |  |  | 			`Internal Server Error\n\n${error?.message}\n${error?.stack}` | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 		response.writeHead(500, { | 
					
						
							|  |  |  | 			'Content-Type': 'text/plain; charset=utf-8', | 
					
						
							|  |  |  | 			'Content-Length': data.length, | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 		response.end(data); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (typeof answer?.data == 'string') { | 
					
						
							|  |  |  | 		answer.data = utf8Encode(answer.data); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	response.writeHead(answer?.status_code, { | 
					
						
							|  |  |  | 		'Content-Type': answer?.content_type, | 
					
						
							|  |  |  | 		'Content-Length': answer?.data?.length, | 
					
						
							|  |  |  | 		'Access-Control-Allow-Origin': '*', | 
					
						
							|  |  |  | 		'Content-Security-Policy': | 
					
						
							|  |  |  | 			'sandbox allow-downloads allow-top-navigation-by-user-activation', | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 	response.end(answer?.data); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-27 15:04:17 -04:00
										 |  |  | /** @} */ |