fix: improve plugins functionality with server management
This commit is contained in:
@@ -11,7 +11,6 @@ export interface IssuedToken {
|
||||
}
|
||||
|
||||
const TOKEN_TTL_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
const tokens = new Map<string, IssuedToken>();
|
||||
|
||||
export function issueToken(params: {
|
||||
|
||||
@@ -59,6 +59,17 @@ export function getDocsHtml(specUrl: string): string {
|
||||
disabled: true
|
||||
}
|
||||
};
|
||||
const contentSecurityPolicy = [
|
||||
"default-src 'none'",
|
||||
"script-src 'self' 'nonce-metoyou-local-api-docs'",
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
"img-src 'self' data: blob:",
|
||||
"font-src 'self' data:",
|
||||
"connect-src 'self'",
|
||||
"base-uri 'none'",
|
||||
"form-action 'none'",
|
||||
"frame-ancestors 'none'"
|
||||
].join('; ');
|
||||
|
||||
return `<!doctype html>
|
||||
<html lang="en">
|
||||
@@ -67,7 +78,7 @@ export function getDocsHtml(specUrl: string): string {
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'none'; script-src 'self' 'nonce-metoyou-local-api-docs'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'"
|
||||
content="${contentSecurityPolicy}"
|
||||
/>
|
||||
<title>MetoYou Local API</title>
|
||||
<style>
|
||||
|
||||
@@ -72,7 +72,11 @@ export async function resolveDocusaurusRoute(pathname: string): Promise<{ filePa
|
||||
const root = await getDocusaurusBuildRoot();
|
||||
|
||||
if (!root) {
|
||||
throw new HttpError(503, 'Docusaurus build is not available. Run npm run build:docs before opening the docs endpoint.', 'DOCUSAURUS_BUILD_MISSING');
|
||||
throw new HttpError(
|
||||
503,
|
||||
'Docusaurus build is not available. Run npm run build:docs before opening the docs endpoint.',
|
||||
'DOCUSAURUS_BUILD_MISSING'
|
||||
);
|
||||
}
|
||||
|
||||
let filePath = resolveAssetPath(root, pathname);
|
||||
|
||||
@@ -37,6 +37,7 @@ export async function readJsonBody<T>(req: IncomingMessage): Promise<T> {
|
||||
}
|
||||
|
||||
const chunks: Buffer[] = [];
|
||||
|
||||
let received = 0;
|
||||
|
||||
for await (const chunk of req) {
|
||||
|
||||
@@ -196,9 +196,9 @@ export async function startLocalApiServer(settings: LocalApiSettings): Promise<S
|
||||
currentError = null;
|
||||
currentBindHost = pickBindHost(settings);
|
||||
currentBindPort = settings.port;
|
||||
|
||||
const requestSettings = activeSettings;
|
||||
const httpServer = createServer((req, res) => {
|
||||
void handleRequest(req, res, activeSettings!).catch((error) => {
|
||||
void handleRequest(req, res, requestSettings).catch((error) => {
|
||||
console.error('[LocalApi] Unhandled request error:', error);
|
||||
|
||||
try {
|
||||
|
||||
@@ -36,7 +36,11 @@ export function buildOpenApiDocument(options: OpenApiBuildOptions): unknown {
|
||||
},
|
||||
LoginRequest: {
|
||||
type: 'object',
|
||||
required: ['username', 'password', 'serverUrl'],
|
||||
required: [
|
||||
'username',
|
||||
'password',
|
||||
'serverUrl'
|
||||
],
|
||||
properties: {
|
||||
username: { type: 'string' },
|
||||
password: { type: 'string' },
|
||||
@@ -49,7 +53,11 @@ export function buildOpenApiDocument(options: OpenApiBuildOptions): unknown {
|
||||
},
|
||||
LoginResponse: {
|
||||
type: 'object',
|
||||
required: ['token', 'expiresAt', 'user'],
|
||||
required: [
|
||||
'token',
|
||||
'expiresAt',
|
||||
'user'
|
||||
],
|
||||
properties: {
|
||||
token: { type: 'string' },
|
||||
expiresAt: { type: 'integer', format: 'int64' },
|
||||
@@ -58,7 +66,11 @@ export function buildOpenApiDocument(options: OpenApiBuildOptions): unknown {
|
||||
},
|
||||
AuthUser: {
|
||||
type: 'object',
|
||||
required: ['id', 'username', 'displayName'],
|
||||
required: [
|
||||
'id',
|
||||
'username',
|
||||
'displayName'
|
||||
],
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
username: { type: 'string' },
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
import { app, net } from 'electron';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { buildQueryHandlers } from '../cqrs/queries';
|
||||
import { QueryType, QueryTypeKey, Query } from '../cqrs/types';
|
||||
import { issueToken, consumeToken, revokeToken, IssuedToken } from './auth-store';
|
||||
import {
|
||||
QueryType,
|
||||
QueryTypeKey,
|
||||
Query
|
||||
} from '../cqrs/types';
|
||||
import {
|
||||
issueToken,
|
||||
consumeToken,
|
||||
revokeToken,
|
||||
IssuedToken
|
||||
} from './auth-store';
|
||||
import { buildOpenApiDocument } from './openapi';
|
||||
import { HttpError, RequestContext, readJsonBody } from './http-helpers';
|
||||
import { HttpError, RequestContext } from './http-helpers';
|
||||
import { getDocsHtml, getScalarApiReferenceBundlePath } from './docs-html';
|
||||
import { resolveDocusaurusRoute } from './docusaurus-static';
|
||||
import { LocalApiSettings } from '../desktop-settings';
|
||||
@@ -48,12 +57,14 @@ function compilePattern(template: string): { pattern: RegExp; paramKeys: string[
|
||||
const escaped = template.replace(/[.*+?^${}()|[\]\\]/g, (match) => {
|
||||
if (match === '*' || match === '+' || match === '?')
|
||||
return `\\${match}`;
|
||||
|
||||
return `\\${match}`;
|
||||
});
|
||||
const source = template.replace(/\{([^}]+)\}/g, (_full, key: string) => {
|
||||
paramKeys.push(key);
|
||||
return '([^/]+)';
|
||||
});
|
||||
|
||||
void escaped;
|
||||
|
||||
return { pattern: new RegExp(`^${source}$`), paramKeys };
|
||||
@@ -273,7 +284,6 @@ const ROUTES: RouteDefinition[] = [
|
||||
|
||||
const limit = clampInt(ctx.request.url.searchParams.get('limit'), 1, 500, 100);
|
||||
const offset = clampInt(ctx.request.url.searchParams.get('offset'), 0, Number.MAX_SAFE_INTEGER, 0);
|
||||
|
||||
const messages = await runQuery<unknown[]>(requireDataSource(ctx.dataSource), {
|
||||
type: QueryType.GetMessages,
|
||||
payload: { roomId: decodeURIComponent(roomId), limit, offset }
|
||||
|
||||
Reference in New Issue
Block a user