Skip to content

Commit

Permalink
added ts services
Browse files Browse the repository at this point in the history
  • Loading branch information
golsch committed Dec 13, 2024
1 parent cd93dbf commit 3efd262
Show file tree
Hide file tree
Showing 14 changed files with 854 additions and 0 deletions.
56 changes: 56 additions & 0 deletions src/auth/fetch-jwt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*!
* This file is part of *** M y C o R e ***
* See https://www.mycore.de/ for details.
*
* MyCoRe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
*/

import { createUrl } from '../common/url';
import { handleError } from '../common/error';

interface MCRJWTResponse {
login_success: boolean;
access_token: string;
}

/**
* Fetches a JSON Web Token (JWT) from a remote server.
*
* @param baseUrl - The base URL of the server from which the JWT will be fetched
* @param params - Optional query parameters to be included in the request
*
* @returns A promise that resolves to a string containing the JWT access token if the login is successful
*
* @throws Will throw an error if the fetch operation fails, if the server response is invalid or unexpected,
* or if the login attempt fails.
*/
const fetchJWT = async(baseUrl: string, params?: Record<string, string>): Promise<string> => {
const url = createUrl(baseUrl, 'rsc/jwt', params);
let response: Response;
try {
response = await fetch(url);
} catch (error) {
return handleError('Error while fetching JWT', error);
}
if (!response.ok) {
throw new Error('Failed to fetch JWT for current user.');
}
const result: MCRJWTResponse = await response.json() as MCRJWTResponse;
if (!result.login_success) {
throw new Error('Login failed.');
}
return result.access_token;
};

export { fetchJWT };
1 change: 1 addition & 0 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './fetch-jwt';
71 changes: 71 additions & 0 deletions src/common/cache/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* This file is part of *** M y C o R e ***
* See https://www.mycore.de/ for details.
*
* MyCoRe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
*/

/**
* A generic interface representing a cache with basic CRUD operations and TTL support.
*
* @typeParam T - The type of the cached values. This can be any type, such as `string`, `number`, or more complex objects
*/
interface MCRCache<T> {

/**
* Sets a value in the cache with an optional time-to-live (TTL) in seconds.
*
* @param key - The key to associate with the value
* @param value - The value to store in the cache
* @param ttl - Optional time-to-live for the cache entry in seconds
*/
set(key: string, value: T, ttl?: number): void;

/**
* Retrieves a value from the cache by its key.
*
* @param key - The key of the cached value to retrieve
* @returns The cached value if it exists, or `undefined` if the key does not exist in the cache
*/
get(key: string): T | undefined;

/**
* Checks if a key exists in the cache.
*
* @param key - The key to check in the cache
* @returns `true` if the key exists in the cache, `false` otherwise
*/
has(key: string): boolean;

/**
* Deletes a value from the cache by its key.
*
* @param key - The key of the cached value to delete
*/
delete(key: string): void;

/**
* Clears all values from the cache.
*/
clear(): void;

/**
* Gets the number of items currently in the cache.
*
* @returns The number of cached items
*/
size(): number;
}

export { MCRCache };
2 changes: 2 additions & 0 deletions src/common/cache/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './cache';
export * from './memory-cache';
89 changes: 89 additions & 0 deletions src/common/cache/memory-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* This file is part of *** M y C o R e ***
* See https://www.mycore.de/ for details.
*
* MyCoRe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
*/

import { MCRCache } from './cache';

/**
* A memory-based cache implementation that stores values in memory using a `Map` with optional TTL (Time-to-Live).
*
* @typeParam T - The type of the cached values. This can be any type, such as `string`, `number`, or more complex objects.
*/
class MCRMemoryCache<T> implements MCRCache<T> {
private cache: Map<string, { value: T; expiry: number | null }>;

constructor() {
this.cache = new Map();
}

/**
* @override
*/
public set(key: string, value: T, ttl = 0): void {
const expiry = ttl === 0 ? null : Date.now() + ttl * 1000;
this.cache.set(key, { value, expiry });
}

/**
* @override
*/
public get(key: string): T | undefined {
const cached = this.cache.get(key);
if (!cached) return undefined;
if (cached.expiry !== null && cached.expiry < Date.now()) {
this.cache.delete(key);
return undefined;
}
return cached.value;
}

/**
* @override
*/
public has(key: string): boolean {
const cached = this.cache.get(key);
if (!cached) return false;
if (cached.expiry !== null && cached.expiry < Date.now()) {
this.cache.delete(key);
return false;
}
return true;
}

/**
* @override
*/
public delete(key: string): void {
this.cache.delete(key);
}

/**
* @override
*/
public clear(): void {
this.cache.clear();
}

/**
* @override
*/
public size(): number {
return this.cache.size;
}
}

export { MCRMemoryCache };
31 changes: 31 additions & 0 deletions src/common/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* This file is part of *** M y C o R e ***
* See https://www.mycore.de/ for details.
*
* MyCoRe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
*/

/**
* Handles an error by creating a new error message and throwing an error.
*
* @param message - A custom error message to prepend to the error
* @param error - The error object to handle. If the provided `error` is not an instance of `Error`, a generic message ('Unknown error') will be used
*
* @throws Always throws an `Error` with a detailed message, including the provided message and the error's message.
*/
const handleError = (message: string, error: unknown): never => {
throw new Error(`${message}: ${error instanceof Error ? error.message : 'Unknown error'}`);
};

export { handleError };
56 changes: 56 additions & 0 deletions src/common/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This file is part of *** M y C o R e ***
* See https://www.mycore.de/ for details.
*
* MyCoRe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
*/

import { handleError } from './error';

/**
* Creates a `URL` object by combining a base URL, a path, query parameters and a fragment.
*
* @param baseUrl - The base URL, either as a `URL` object or a string
* @param path - An optional path to append to the base URL. Defaults to an empty string
* @param queryParams - An optional object containing key-value pairs for query parameters
* @param fragment - An optional fragment identifier (the part after `#`) to append to the URL
*
* @returns A `URL` object representing the constructed URL.
*
* @throws Will throw an error if the `baseUrl` or `path` is invalid.
*/
const createUrl = (
baseUrl: URL | string,
path?: string,
queryParams?: Record<string, string | number>,
fragment?: string
): URL => {
let url;
try {
url = (path) ? new URL(path, baseUrl) : new URL (baseUrl);
} catch (error) {
return handleError('Invalid URL input', error);
}
if (queryParams) {
Object.entries(queryParams).forEach(([key, value]) => {
url.searchParams.set(key, value.toString());
});
}
if (fragment) {
url.hash = `#${fragment}`;
}
return url;
};

export { createUrl };
3 changes: 3 additions & 0 deletions src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './lang-service';
export * from './lang-service-impl';

Loading

0 comments on commit 3efd262

Please sign in to comment.