| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  | const {spawn} = require("child_process"); | 
					
						
							|  |  |  | const kill  = require('tree-kill'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | let etapiAuthToken; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const getEtapiAuthorizationHeader = () => "Basic " + Buffer.from(`etapi:${etapiAuthToken}`).toString('base64'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const PORT = '9999'; | 
					
						
							|  |  |  | const HOST = 'http://localhost:' + PORT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function describeEtapi(description, specDefinitions) { | 
					
						
							|  |  |  |     describe(description, () => { | 
					
						
							|  |  |  |         let appProcess; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         beforeAll(async () => { | 
					
						
							|  |  |  |             appProcess = spawn('npm', ['run', 'start-test-server']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             await new Promise(res => { | 
					
						
							|  |  |  |                 appProcess.stdout.on('data', data => { | 
					
						
							|  |  |  |                     console.log("Trilium: " + data.toString().trim()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (data.toString().includes('Listening on port')) { | 
					
						
							|  |  |  |                         res(); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             await fetch(HOST + '/api/setup/new-document', { method: 'POST' }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const formData = new URLSearchParams(); | 
					
						
							|  |  |  |             formData.append('password1', '1234'); | 
					
						
							|  |  |  |             formData.append('password2', '1234'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             await fetch(HOST + '/set-password', { method: 'POST', body: formData }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             etapiAuthToken = (await (await fetch(HOST + '/etapi/auth/login', { | 
					
						
							|  |  |  |                 method: 'POST', | 
					
						
							|  |  |  |                 headers: { | 
					
						
							|  |  |  |                     "Content-Type": "application/json", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 body: JSON.stringify({ password: '1234' }) | 
					
						
							|  |  |  |             })).json()).authToken; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         afterAll(() => { | 
					
						
							|  |  |  |             console.log("Attempting to kill the Trilium process as part of the cleanup..."); | 
					
						
							|  |  |  |             kill(appProcess.pid, 'SIGKILL', () => { console.log("Trilium process killed.") }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         specDefinitions(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  | async function getEtapiResponse(url) { | 
					
						
							|  |  |  |     return await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  |         method: 'GET', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function getEtapi(url) { | 
					
						
							|  |  |  |     const response = await getEtapiResponse(url); | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  |     return await processEtapiResponse(response); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function getEtapiContent(url) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'GET', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     checkStatus(response); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return response; | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function postEtapi(url, data = {}) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'POST', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             "Content-Type": "application/json", | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         body: JSON.stringify(data) | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return await processEtapiResponse(response); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 00:41:35 +01:00
										 |  |  | async function postEtapiContent(url, data) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'POST', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             "Content-Type": "application/octet-stream", | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         body: data | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     checkStatus(response); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return response; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  | async function putEtapi(url, data = {}) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'PUT', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             "Content-Type": "application/json", | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         body: JSON.stringify(data) | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return await processEtapiResponse(response); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  | async function putEtapiContent(url, data) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'PUT', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             "Content-Type": "application/octet-stream", | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         body: data | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     checkStatus(response); | 
					
						
							| 
									
										
										
										
											2023-11-01 00:41:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return response; | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function patchEtapi(url, data = {}) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'PATCH', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             "Content-Type": "application/json", | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         body: JSON.stringify(data) | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return await processEtapiResponse(response); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  | async function deleteEtapi(url) { | 
					
						
							|  |  |  |     const response = await fetch(`${HOST}/etapi/${url}`, { | 
					
						
							|  |  |  |         method: 'DELETE', | 
					
						
							|  |  |  |         headers: { | 
					
						
							|  |  |  |             Authorization: getEtapiAuthorizationHeader() | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return await processEtapiResponse(response); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function processEtapiResponse(response) { | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  |     const text = await response.text(); | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (response.status < 200 || response.status >= 300) { | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  |         throw new Error(`ETAPI error ${response.status}: ` + text); | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  |     return text?.trim() ? JSON.parse(text) : null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function checkStatus(response) { | 
					
						
							|  |  |  |     if (response.status < 200 || response.status >= 300) { | 
					
						
							|  |  |  |         throw new Error(`ETAPI error ${response.status}`); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = { | 
					
						
							|  |  |  |     describeEtapi, | 
					
						
							|  |  |  |     getEtapi, | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  |     getEtapiResponse, | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  |     getEtapiContent, | 
					
						
							|  |  |  |     postEtapi, | 
					
						
							| 
									
										
										
										
											2023-11-01 00:41:35 +01:00
										 |  |  |     postEtapiContent, | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  |     putEtapi, | 
					
						
							| 
									
										
										
										
											2023-10-30 23:51:53 +01:00
										 |  |  |     putEtapiContent, | 
					
						
							|  |  |  |     patchEtapi, | 
					
						
							| 
									
										
										
										
											2023-10-29 23:24:11 +01:00
										 |  |  |     deleteEtapi | 
					
						
							|  |  |  | }; |