mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 10:02:59 +08:00
client-ts: Port services/server
This commit is contained in:
parent
ba7035a346
commit
5875aa3bef
@ -1,13 +1,35 @@
|
|||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import ValidationError from "./validation_error.js";
|
import ValidationError from "./validation_error.js";
|
||||||
|
|
||||||
async function getHeaders(headers) {
|
type Headers = Record<string, string | null | undefined>;
|
||||||
|
|
||||||
|
type Method = string;
|
||||||
|
|
||||||
|
interface Response {
|
||||||
|
headers: Headers;
|
||||||
|
body: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Arg extends Response {
|
||||||
|
statusCode: number;
|
||||||
|
method: Method;
|
||||||
|
url: string;
|
||||||
|
requestId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RequestData {
|
||||||
|
resolve: (value: unknown) => any;
|
||||||
|
reject: (reason: unknown) => any;
|
||||||
|
silentNotFound: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getHeaders(headers?: Headers) {
|
||||||
const appContext = (await import('../components/app_context.js')).default;
|
const appContext = (await import('../components/app_context.js')).default;
|
||||||
const activeNoteContext = appContext.tabManager ? appContext.tabManager.getActiveContext() : null;
|
const activeNoteContext = appContext.tabManager ? appContext.tabManager.getActiveContext() : null;
|
||||||
|
|
||||||
// headers need to be lowercase because node.js automatically converts them to lower case
|
// headers need to be lowercase because node.js automatically converts them to lower case
|
||||||
// also avoiding using underscores instead of dashes since nginx filters them out by default
|
// also avoiding using underscores instead of dashes since nginx filters them out by default
|
||||||
const allHeaders = {
|
const allHeaders: Headers = {
|
||||||
'trilium-component-id': glob.componentId,
|
'trilium-component-id': glob.componentId,
|
||||||
'trilium-local-now-datetime': utils.localNowDateTime(),
|
'trilium-local-now-datetime': utils.localNowDateTime(),
|
||||||
'trilium-hoisted-note-id': activeNoteContext ? activeNoteContext.hoistedNoteId : null,
|
'trilium-hoisted-note-id': activeNoteContext ? activeNoteContext.hoistedNoteId : null,
|
||||||
@ -28,31 +50,31 @@ async function getHeaders(headers) {
|
|||||||
return allHeaders;
|
return allHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getWithSilentNotFound(url, componentId) {
|
async function getWithSilentNotFound<T>(url: string, componentId?: string) {
|
||||||
return await call('GET', url, componentId, { silentNotFound: true });
|
return await call<T>('GET', url, componentId, { silentNotFound: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get(url, componentId) {
|
async function get<T>(url: string, componentId?: string) {
|
||||||
return await call('GET', url, componentId);
|
return await call<T>('GET', url, componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function post(url, data, componentId) {
|
async function post<T>(url: string, data: unknown, componentId?: string) {
|
||||||
return await call('POST', url, componentId, { data });
|
return await call<T>('POST', url, componentId, { data });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function put(url, data, componentId) {
|
async function put<T>(url: string, data: unknown, componentId?: string) {
|
||||||
return await call('PUT', url, componentId, { data });
|
return await call<T>('PUT', url, componentId, { data });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function patch(url, data, componentId) {
|
async function patch<T>(url: string, data: unknown, componentId?: string) {
|
||||||
return await call('PATCH', url, componentId, { data });
|
return await call<T>('PATCH', url, componentId, { data });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remove(url, componentId) {
|
async function remove<T>(url: string, componentId?: string) {
|
||||||
return await call('DELETE', url, componentId);
|
return await call<T>('DELETE', url, componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function upload(url, fileToUpload) {
|
async function upload(url: string, fileToUpload: File) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('upload', fileToUpload);
|
formData.append('upload', fileToUpload);
|
||||||
|
|
||||||
@ -68,11 +90,17 @@ async function upload(url, fileToUpload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let idCounter = 1;
|
let idCounter = 1;
|
||||||
const idToRequestMap = {};
|
|
||||||
|
const idToRequestMap: Record<string, RequestData> = {};
|
||||||
|
|
||||||
let maxKnownEntityChangeId = 0;
|
let maxKnownEntityChangeId = 0;
|
||||||
|
|
||||||
async function call(method, url, componentId, options = {}) {
|
interface CallOptions {
|
||||||
|
data?: unknown;
|
||||||
|
silentNotFound?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function call<T>(method: string, url: string, componentId?: string, options: CallOptions = {}) {
|
||||||
let resp;
|
let resp;
|
||||||
|
|
||||||
const headers = await getHeaders({
|
const headers = await getHeaders({
|
||||||
@ -98,7 +126,7 @@ async function call(method, url, componentId, options = {}) {
|
|||||||
url: `/${window.glob.baseApiUrl}${url}`,
|
url: `/${window.glob.baseApiUrl}${url}`,
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
});
|
}) as any;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resp = await ajax(url, method, data, headers, !!options.silentNotFound);
|
resp = await ajax(url, method, data, headers, !!options.silentNotFound);
|
||||||
@ -110,23 +138,25 @@ async function call(method, url, componentId, options = {}) {
|
|||||||
maxKnownEntityChangeId = Math.max(maxKnownEntityChangeId, parseInt(maxEntityChangeIdStr));
|
maxKnownEntityChangeId = Math.max(maxKnownEntityChangeId, parseInt(maxEntityChangeIdStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.body;
|
return resp.body as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ajax(url, method, data, headers, silentNotFound) {
|
function ajax(url: string, method: string, data: unknown, headers: Headers, silentNotFound: boolean): Promise<Response> {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
const options = {
|
const options: JQueryAjaxSettings = {
|
||||||
url: window.glob.baseApiUrl + url,
|
url: window.glob.baseApiUrl + url,
|
||||||
type: method,
|
type: method,
|
||||||
headers: headers,
|
headers: headers,
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
success: (body, textStatus, jqXhr) => {
|
success: (body, textStatus, jqXhr) => {
|
||||||
const respHeaders = {};
|
const respHeaders: Headers = {};
|
||||||
|
|
||||||
jqXhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(line => {
|
jqXhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach(line => {
|
||||||
const parts = line.split(': ');
|
const parts = line.split(': ');
|
||||||
const header = parts.shift();
|
const header = parts.shift();
|
||||||
respHeaders[header] = parts.join(': ');
|
if (header) {
|
||||||
|
respHeaders[header] = parts.join(': ');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
res({
|
res({
|
||||||
@ -161,7 +191,7 @@ function ajax(url, method, data, headers, silentNotFound) {
|
|||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
const ipc = utils.dynamicRequire('electron').ipcRenderer;
|
const ipc = utils.dynamicRequire('electron').ipcRenderer;
|
||||||
|
|
||||||
ipc.on('server-response', async (event, arg) => {
|
ipc.on('server-response', async (event: string, arg: Arg) => {
|
||||||
if (arg.statusCode >= 200 && arg.statusCode < 300) {
|
if (arg.statusCode >= 200 && arg.statusCode < 300) {
|
||||||
handleSuccessfulResponse(arg);
|
handleSuccessfulResponse(arg);
|
||||||
}
|
}
|
||||||
@ -178,8 +208,8 @@ if (utils.isElectron()) {
|
|||||||
delete idToRequestMap[arg.requestId];
|
delete idToRequestMap[arg.requestId];
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleSuccessfulResponse(arg) {
|
function handleSuccessfulResponse(arg: Arg) {
|
||||||
if (arg.headers['Content-Type'] === 'application/json') {
|
if (arg.headers['Content-Type'] === 'application/json' && typeof arg.body === "string") {
|
||||||
arg.body = JSON.parse(arg.body);
|
arg.body = JSON.parse(arg.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,13 +225,13 @@ if (utils.isElectron()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reportError(method, url, statusCode, response) {
|
async function reportError(method: string, url: string, statusCode: number, response: unknown) {
|
||||||
let message = response;
|
let message = response;
|
||||||
|
|
||||||
if (typeof response === 'string') {
|
if (typeof response === 'string') {
|
||||||
try {
|
try {
|
||||||
response = JSON.parse(response);
|
response = JSON.parse(response);
|
||||||
message = response.message;
|
message = (response as any).message;
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
}
|
}
|
3
src/public/app/types.d.ts
vendored
3
src/public/app/types.d.ts
vendored
@ -21,6 +21,9 @@ interface CustomGlobals {
|
|||||||
importMarkdownInline: () => Promise<unknown>;
|
importMarkdownInline: () => Promise<unknown>;
|
||||||
SEARCH_HELP_TEXT: string;
|
SEARCH_HELP_TEXT: string;
|
||||||
activeDialog: JQuery<HTMLElement> | null;
|
activeDialog: JQuery<HTMLElement> | null;
|
||||||
|
componentId: string;
|
||||||
|
csrfToken: string;
|
||||||
|
baseApiUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequireMethod = (moduleName: string) => any;
|
type RequireMethod = (moduleName: string) => any;
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
"lib": ["ES2022"],
|
"lib": ["ES2022"],
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true,
|
||||||
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.js",
|
"./src/**/*.js",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user