refactor: split api into api, api-cli & api-plugin

This commit is contained in:
2023-06-02 16:41:25 +02:00
parent 495a63977c
commit b21833de40
205 changed files with 1981 additions and 1492 deletions

View File

@@ -90,7 +90,7 @@
"sinon-express-mock": "2.2.1",
"supertest": "6.3.3",
"tsup": "6.7.0",
"typescript": "4.8.4"
"typescript": "4.9.5"
},
"tsup": {
"entry": [

View File

@@ -167,12 +167,12 @@ export async function configureApp(app: Express, databases: {[name: string]: Dat
const database = new databases[backendConfig.internal.database.name](
backendConfig,
// mailQueue
typeof mailer !== 'undefined' && backendConfig.internal.monitoring ? new MailQueue(mailer) : undefined,
mailer !== undefined && backendConfig.internal.monitoring ? new MailQueue(mailer) : undefined,
);
await database.init();
if (typeof database === 'undefined') {
if (database === undefined) {
throw new TypeError('No implementation for configured database found. Please check your configuration.');
}

View File

@@ -8,7 +8,6 @@ const configPath = 'config';
/**
* Creates a config loader
*
* @param moduleName the name of the config file (module)
*/
function configLoader(moduleName: string): PublicExplorer {

View File

@@ -23,7 +23,6 @@ import path from 'path';
* This function tries to configure the new instance with JSON read from
* `./conf/prometheus.json`. When this fails an instance configured with
* default options is returned.
*
* @returns express.Express
*/
export function getPrometheusMiddleware(): express_prom_bundle.Middleware {

View File

@@ -17,7 +17,6 @@ import {Logger, SMTP, Transport, VerifiableTransport} from '@openstapps/logger';
/**
* Provides information if a transport is a verifiable transport
*
* @param instance A transport that needs to be checked
*/
export function isTransportWithVerification(instance: Transport): instance is VerifiableTransport {
@@ -56,7 +55,7 @@ export class BackendTransport {
* Provides instance of a backend transport
*/
public static getInstance(): BackendTransport {
if (typeof BackendTransport._instance !== 'undefined') {
if (BackendTransport._instance !== undefined) {
return BackendTransport._instance;
}
@@ -86,7 +85,7 @@ export class BackendTransport {
}
}
if (typeof this.transport !== 'undefined' && isTransportWithVerification(this.transport)) {
if (this.transport !== undefined && isTransportWithVerification(this.transport)) {
void this.verifyTransport(this.transport);
}
}

View File

@@ -50,7 +50,6 @@ export class MailQueue {
/**
* Creates a mail queue
*
* @param transport Transport which is used for sending mails
*/
constructor(private readonly transport: SMTP) {
@@ -67,7 +66,6 @@ export class MailQueue {
/**
* Adds a mail into the queue so it gets send when the queue is ready
*
* @param mail Information required for sending a mail
*/
private async addToQueue(mail: MailOptions) {
@@ -99,7 +97,6 @@ export class MailQueue {
/**
* Push a mail into the queue so it gets send when the queue is ready
*
* @param mail Information required for sending a mail
*/
public async push(mail: MailOptions) {

View File

@@ -33,7 +33,7 @@ export const bulkAddRouter = createRoute<SCBulkAddRequest, SCBulkAddResponse>(
const bulkMemory: BulkStorage = app.get('bulk');
const bulk = bulkMemory.read(parameters.UID);
if (typeof bulk === 'undefined') {
if (bulk === undefined) {
Logger.warn(`Bulk with ${parameters.UID} not found.`);
throw new SCNotFoundErrorResponse(isTestEnvironment);
}

View File

@@ -38,7 +38,7 @@ export const bulkDoneRouter = createRoute<SCBulkDoneRequest, SCBulkDoneResponse>
const bulkMemory: BulkStorage = app.get('bulk');
const bulk = bulkMemory.read(parameters.UID);
if (typeof bulk === 'undefined') {
if (bulk === undefined) {
Logger.warn(`Bulk with ${parameters.UID} not found.`);
throw new SCNotFoundErrorResponse(isTestEnvironment);
}

View File

@@ -46,7 +46,6 @@ export type HTTPVerb = (typeof httpVerbs)[number];
/**
* Provides information if a text (representing a method) is an HTTP verb
*
* @param method A text (representing a method) to check
*/
export function isHttpMethod(method: string): method is HTTPVerb {

View File

@@ -39,7 +39,6 @@ export const pluginRegisterRouter = createRoute(pluginRegisterRouteModel, plugin
/**
* Handles requests on route for registering plugins
*
* @param request Request received for registering or unregistering a plugin
* @param _app Express application
*/
@@ -59,7 +58,6 @@ export async function pluginRegisterHandler(
/**
* Adds a plugin to the list (map) of registered plugins
*
* @param plugin Meta data of the plugin
*/
function addPlugin(plugin: SCPluginMetaData): SCPluginRegisterResponse {
@@ -81,7 +79,7 @@ function addPlugin(plugin: SCPluginMetaData): SCPluginRegisterResponse {
// it's a new plugin so it can be added to the map of plugins
plugins.set(plugin.route, plugin);
// add plugin info to app config
if (typeof backendConfig.app.features.plugins === 'undefined') {
if (backendConfig.app.features.plugins === undefined) {
backendConfig.app.features.plugins = {};
}
backendConfig.app.features.plugins[plugin.name] = {urlPath: plugin.route};
@@ -94,7 +92,6 @@ function addPlugin(plugin: SCPluginMetaData): SCPluginRegisterResponse {
/**
* Removes a plugin from the list (map) of registered plugins using the provided route
*
* @param route Route of the plugin which needs to be unregistered
*/
function removePlugin(route: string): SCPluginRegisterResponse {

View File

@@ -31,7 +31,6 @@ import {isHttpMethod} from './http-types.js';
*
* The given router performs a request and response validation, sets status codes and checks if the given handler
* only returns errors that are allowed for the client to see
*
* @param routeClass Model of a route
* @param handler Implements the logic of the route
*/

View File

@@ -22,7 +22,6 @@ import {backendConfig} from '../config.js';
/**
* Generic route function used to proxy actual requests to plugins
*
* @param request The request for a plugin resource
* @param plugin Meta data of the plugin
* @throws {SCInternalServerErrorResponse} On request/response validation or response from the plugin errors
@@ -35,7 +34,7 @@ export async function virtualPluginRoute(request: Request, plugin: SCPluginMetaD
throw new SCValidationErrorResponse(requestValidation.errors, isTestEnvironment);
}
// send the request to the plugin (forward the body) and save the response
const response = await got.post(plugin.route.replace(/^\//gi, ''), {
const response = await got.post(plugin.route.replaceAll(/^\//gi, ''), {
prefixUrl: plugin.address,
json: request.body,
timeout: {

View File

@@ -69,7 +69,6 @@ export class Bulk implements SCBulkRequest {
/**
* Creates a new bulk process
*
* @param request Data needed for requesting a bulk
*/
constructor(request: SCBulkRequest) {
@@ -97,7 +96,6 @@ export class BulkStorage {
/**
* Creates a new BulkStorage
*
* @param database the database that is controlled by this bulk storage
*/
constructor(public database: Database) {
@@ -116,7 +114,6 @@ export class BulkStorage {
/**
* Saves a bulk process and assigns to it a user-defined ttl (time-to-live)
*
* @param bulk the bulk process to save
* @returns the bulk process that was saved
*/
@@ -132,7 +129,6 @@ export class BulkStorage {
/**
* Create and save a new bulk process
*
* @param bulkRequest a request for a new bulk process
* @returns a promise that contains the new bulk process
*/
@@ -151,14 +147,13 @@ export class BulkStorage {
/**
* Delete a bulk process
*
* @param uid uid of the bulk process
* @returns a promise that contains the deleted bulk process
*/
public async delete(uid: string): Promise<Bulk> {
const bulk = this.read(uid);
if (typeof bulk === 'undefined') {
if (bulk === undefined) {
throw new TypeError(`Bulk that should be deleted was not found. UID was "${uid}"`);
}
@@ -173,7 +168,6 @@ export class BulkStorage {
/**
* Update an old bulk process (replace it with the new one)
*
* @param bulk new bulk process
* @returns an empty promise
*/
@@ -189,7 +183,6 @@ export class BulkStorage {
/**
* Read an existing bulk process
*
* @param uid uid of the bulk process
* @returns a promise that contains a bulk
*/

View File

@@ -30,7 +30,6 @@ export interface Database {
* Gets called if a bulk was created
*
* The database should
*
* @param bulk A bulk to be created
*/
bulkCreated(bulk: Bulk): Promise<void>;
@@ -39,7 +38,6 @@ export interface Database {
* Gets called if a bulk expires
*
* The database should delete all data that is associtated with this bulk
*
* @param bulk A bulk which data needs to be removed
*/
bulkExpired(bulk: Bulk): Promise<void>;
@@ -49,14 +47,12 @@ export interface Database {
*
* If the database holds a bulk with the same type and source as the given
* bulk it should be replaced by the given one
*
* @param bulk A new bulk whose data should be saved instead of the data of the old bulk
*/
bulkUpdated(bulk: Bulk): Promise<void>;
/**
* Get a single document
*
* @param uid Unique identifier of the document
*/
get(uid: SCUuid): Promise<SCThings>;
@@ -68,7 +64,6 @@ export interface Database {
/**
* Add a thing to an existing bulk
*
* @param thing A StAppsCore thing to be added
* @param bulk A bulk to which the thing should be added
*/
@@ -78,14 +73,12 @@ export interface Database {
* Replace an existing thing in any Bulk
*
* Currently it is not possible to put an non-existing object
*
* @param thing A StAppsCore thing to be added to a bulk
*/
put(thing: SCThings): Promise<void>;
/**
* Search for things
*
* @param params Parameters which form a search query to search the backend data
*/
search(parameters: SCSearchQuery): Promise<SCSearchResponse>;

View File

@@ -23,7 +23,6 @@ import {SCFacet, SCThingType} from '@openstapps/core';
/**
* Parses elasticsearch aggregations (response from es) to facets for the app
*
* @param aggregationResponse - aggregations response from elasticsearch
*/
export function parseAggregations(

View File

@@ -81,15 +81,11 @@ export class Elasticsearch implements Database {
/**
* Create a new interface for elasticsearch
*
* @param config an assembled config file
* @param mailQueue a mail queue for monitoring
*/
constructor(private readonly config: SCConfigFile, mailQueue?: MailQueue) {
if (
typeof config.internal.database === 'undefined' ||
typeof config.internal.database.version !== 'string'
) {
if (config.internal.database === undefined || typeof config.internal.database.version !== 'string') {
throw new TypeError('Database version is undefined. Check your config file');
}
@@ -144,7 +140,6 @@ export class Elasticsearch implements Database {
/**
* Provides an elasticsearch object using containing thing's UID
*
* @param uid an UID to use for the search
* @returns an elasticsearch object containing the thing
*/
@@ -188,7 +183,6 @@ export class Elasticsearch implements Database {
/**
* Should be called when a new bulk was created. Creates a new index and applies the mapping to the index
*
* @param bulk the bulk process that was created
*/
public async bulkCreated(bulk: Bulk): Promise<void> {
@@ -208,7 +202,6 @@ export class Elasticsearch implements Database {
/**
* Should be called when a bulk process is expired. The index that was created with this bulk gets deleted
*
* @param bulk the bulk process that is expired
*/
public async bulkExpired(bulk: Bulk): Promise<void> {
@@ -227,7 +220,6 @@ export class Elasticsearch implements Database {
/**
* Should be called when a bulk process is updated (replaced by a newer bulk). This will replace the old
* index and publish all data that was indexed in the new instead
*
* @param bulk the new bulk process that should replace the old one with the same type and source
*/
public async bulkUpdated(bulk: Bulk): Promise<void> {
@@ -262,13 +254,12 @@ export class Elasticsearch implements Database {
/**
* Gets an SCThing from all indexed data
*
* @param uid uid of an SCThing
*/
public async get(uid: SCUuid): Promise<SCThings> {
const object = await this.getObject(uid);
if (typeof object?._source === 'undefined') {
if (object?._source === undefined) {
throw new TypeError('Item not found.');
}
@@ -281,8 +272,8 @@ export class Elasticsearch implements Database {
public async init(retryOptions: Partial<RetryOptions<IndicesGetAliasResponse>> = {}): Promise<void> {
const monitoringConfiguration = this.config.internal.monitoring;
if (typeof monitoringConfiguration !== 'undefined') {
if (typeof this.mailQueue === 'undefined') {
if (monitoringConfiguration !== undefined) {
if (this.mailQueue === undefined) {
throw new TypeError(
'Monitoring is defined, but MailQueue is undefined. A MailQueue is obligatory for monitoring.',
);
@@ -296,7 +287,6 @@ export class Elasticsearch implements Database {
/**
* Add an item to an index
*
* @param object the SCThing to add to the index
* @param bulk the bulk process which item belongs to
*/
@@ -341,13 +331,12 @@ export class Elasticsearch implements Database {
/**
* Put (update) an existing item
*
* @param object SCThing to put
*/
public async put(object: SCThings): Promise<void> {
const item = await this.getObject(object.uid);
if (typeof item !== 'undefined') {
if (item !== undefined) {
await this.client.update({
body: {
doc: object,
@@ -364,11 +353,10 @@ export class Elasticsearch implements Database {
/**
* Search all indexed data
*
* @param parameters search query
*/
public async search(parameters: SCSearchQuery): Promise<SCSearchResponse> {
if (typeof this.config.internal.database === 'undefined') {
if (this.config.internal.database === undefined) {
throw new TypeError('Database is undefined. You have to configure the query build');
}
@@ -388,7 +376,7 @@ export class Elasticsearch implements Database {
index: ACTIVE_INDICES_ALIAS,
allow_no_indices: true,
size: parameters.size,
sort: typeof parameters.sort === 'undefined' ? undefined : buildSort(parameters.sort),
sort: parameters.sort === undefined ? undefined : buildSort(parameters.sort),
});
return {
@@ -400,7 +388,7 @@ export class Elasticsearch implements Database {
})
.filter(noUndefined),
facets:
typeof response.aggregations === 'undefined'
response.aggregations === undefined
? []
: parseAggregations(response.aggregations as Record<AggregateName, AggregationsMultiTermsBucket>),
pagination: {

View File

@@ -29,7 +29,6 @@ import {MailQueue} from '../../notification/mail-queue.js';
/**
* Check if the given condition fails on the given number of results and the condition
*
* @param condition condition
* @param total number of results
*/
@@ -46,7 +45,6 @@ function conditionFails(
/**
* Check if the min condition fails
*
* @param minimumLength Minimal length allowed
* @param total Number of results
*/
@@ -56,7 +54,6 @@ function minConditionFails(minimumLength: number, total: number) {
/**
* Check if the max condition fails
*
* @param maximumLength Maximal length allowed
* @param total Number of results
*/
@@ -66,7 +63,6 @@ function maxConditionFails(maximumLength: number, total: number) {
/**
* Run all the given actions
*
* @param actions actions to perform
* @param watcherName name of watcher that wants to perform them
* @param triggerName name of trigger that triggered the watcher
@@ -99,7 +95,6 @@ function runActions(
/**
* Set up the triggers for the configured watchers
*
* @param monitoringConfig configuration of the monitoring
* @param esClient elasticsearch client
* @param mailQueue mailQueue for mail actions

View File

@@ -18,7 +18,6 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Creates boost functions for all type boost configurations
*
* @param boostingTypes Array of type boosting configurations
*/
export function buildFunctionsForBoostingTypes(
@@ -38,7 +37,7 @@ export function buildFunctionsForBoostingTypes(
weight: boostingForOneSCType.factor,
});
if (typeof boostingForOneSCType.fields !== 'undefined') {
if (boostingForOneSCType.fields !== undefined) {
const fields = boostingForOneSCType.fields;
for (const fieldName in boostingForOneSCType.fields) {

View File

@@ -18,7 +18,6 @@ import {buildFunctionsForBoostingTypes} from './boost-functions.js';
/**
* Builds scoring functions from boosting config
*
* @param boostings Backend boosting configuration for contexts and types
* @param context The context of the app from where the search was initiated
*/
@@ -29,7 +28,7 @@ export function buildScoringFunctions(
// default context
let functions = buildFunctionsForBoostingTypes(boostings['default' as SCSearchContext]);
if (typeof context !== 'undefined' && context !== 'default') {
if (context !== undefined && context !== 'default') {
// specific context provided, extend default context with additional boosts
functions = [...functions, ...buildFunctionsForBoostingTypes(boostings[context])];
}

View File

@@ -24,7 +24,6 @@ import {buildValueFilter} from './filters/value.js';
/**
* Converts Array of Filters to elasticsearch query-syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildFilter(filter: SCSearchFilter): QueryDslQueryContainer {

View File

@@ -17,14 +17,13 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Converts an availability filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildAvailabilityFilter(
filter: SCSearchAvailabilityFilter,
): QueryDslSpecificQueryContainer<'range'> {
const scope = filter.arguments.scope?.charAt(0) ?? 's';
const time = typeof filter.arguments.time === 'undefined' ? 'now' : `${filter.arguments.time}||`;
const time = filter.arguments.time === undefined ? 'now' : `${filter.arguments.time}||`;
return {
range: {

View File

@@ -19,7 +19,6 @@ import {buildFilter} from '../filter.js';
/**
* Converts a boolean filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildBooleanFilter(filter: SCSearchBooleanFilter): QueryDslSpecificQueryContainer<'bool'> {

View File

@@ -18,7 +18,6 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Converts a date range filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildDateRangeFilter(

View File

@@ -18,7 +18,6 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Converts a distance filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildDistanceFilter(

View File

@@ -17,7 +17,6 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Converts a geo filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildGeoFilter(filter: SCGeoFilter): QueryDslSpecificQueryContainer<'geo_shape'> {

View File

@@ -18,7 +18,6 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Converts a numeric range filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildNumericRangeFilter(

View File

@@ -17,7 +17,6 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
/**
* Converts a value filter to elasticsearch syntax
*
* @param filter A search filter for the retrieval of the data
*/
export function buildValueFilter(

View File

@@ -20,7 +20,6 @@ import {buildScoringFunctions} from './boost/scoring-functions.js';
/**
* Builds body for Elasticsearch requests
*
* @param parameters Parameters for querying the backend
* @param defaultConfig Default configuration of the backend
* @param elasticsearchConfig Elasticsearch configuration
@@ -33,7 +32,7 @@ export const buildQuery = function buildQuery(
): QueryDslQueryContainer {
// if config provides a minMatch parameter, we use query_string instead of a match query
let query;
if (typeof elasticsearchConfig.query === 'undefined') {
if (elasticsearchConfig.query === undefined) {
query = {
query_string: {
analyzer: 'search_german',
@@ -101,11 +100,11 @@ export const buildQuery = function buildQuery(
const mustMatch = functionScoreQuery.function_score?.query?.bool?.must;
if (Array.isArray(mustMatch)) {
if (typeof query !== 'undefined') {
if (query !== undefined) {
mustMatch.push(query);
}
if (typeof parameters.filter !== 'undefined') {
if (parameters.filter !== undefined) {
mustMatch.push(buildFilter(parameters.filter));
}
}

View File

@@ -21,7 +21,6 @@ import {buildPriceSort} from './sort/price.js';
/**
* converts query to
*
* @param sorts Sorting rules to apply to the data that is being queried
* @returns an array of sort queries
*/

View File

@@ -17,7 +17,6 @@ import {SCDistanceSort} from '@openstapps/core';
/**
* Converts a distance sort to elasticsearch syntax
*
* @param sort A sorting definition
*/
export function buildDistanceSort(sort: SCDistanceSort): SortOptions {

View File

@@ -17,7 +17,6 @@ import {SCDucetSort} from '@openstapps/core';
/**
* Converts a ducet sort to elasticsearch syntax
*
* @param sort A sorting definition
*/
export function buildDucetSort(sort: SCDucetSort): SortOptions {

View File

@@ -17,7 +17,6 @@ import {SCGenericSort} from '@openstapps/core';
/**
* Converts a generic sort to elasticsearch syntax
*
* @param sort A sorting definition
*/
export function buildGenericSort(sort: SCGenericSort): SortOptions {

View File

@@ -17,7 +17,6 @@ import {SCPriceSort, SCSportCoursePriceGroup, SCThingsField} from '@openstapps/c
/**
* Converts a price sort to elasticsearch syntax
*
* @param sort A sorting definition
*/
export function buildPriceSort(sort: SCPriceSort): SortOptions {
@@ -32,7 +31,6 @@ export function buildPriceSort(sort: SCPriceSort): SortOptions {
/**
* Provides a script for sorting search results by prices
*
* @param universityRole User group which consumes university services
* @param field Field in which wanted offers with prices are located
*/

View File

@@ -33,12 +33,11 @@ export const aggregations = JSON.parse(
* Prepares all indices
*
* This includes applying the mapping, settings
*
* @param client An elasticsearch client to use
* @param type the SCThingType of which the template should be set
*/
export async function putTemplate(client: Client, type: SCThingType) {
const sanitizedType = `template_${type.replace(/\s/g, '_')}`;
const sanitizedType = `template_${type.replaceAll(/\s/g, '_')}`;
return client.indices.putTemplate({
body: mappings[sanitizedType],

View File

@@ -27,35 +27,30 @@ export interface ElasticsearchQueryDisMaxConfig {
/**
* The maximum allowed Levenshtein Edit Distance (or number of edits)
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/common-options.html#fuzziness
*/
fuzziness: number | string;
/**
* Increase the importance (relevance score) of a field
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-boost.html
*/
matchBoosting: number;
/**
* Minimal number (or percentage) of words that should match in a query
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-minimum-should-match.html
*/
minMatch: string;
/**
* Type of the query - in this case 'dis_max' which is a union of its subqueries
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-dis-max-query.html
*/
queryType: 'dis_max';
/**
* Changes behavior of default calculation of the score when multiple results match
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-multi-match-query.html#tie-breaker
*/
tieBreaker: number;
@@ -70,14 +65,12 @@ export interface ElasticsearchQueryDisMaxConfig {
export interface ElasticsearchQueryQueryStringConfig {
/**
* Minimal number (or percentage) of words that should match in a query
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-minimum-should-match.html
*/
minMatch: string;
/**
* Type of the query - in this case 'query_string' which uses a query parser in order to parse content
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-query-string-query.html
*/
queryType: 'query_string';

View File

@@ -16,7 +16,6 @@ import {Logger} from '@openstapps/logger';
/**
* Checks for invalid character in alias names and removes them
*
* @param alias The alias name
* @param uid The UID of the current bulk (for debugging purposes)
*/

View File

@@ -44,25 +44,23 @@ export function parseIndexName(index: string): ParsedIndexName {
/**
* Gets the index name in elasticsearch for one SCThingType
*
* @param type SCThingType of data in the index
* @param source source of data in the index
* @param bulk bulk process which created this index
*/
export function getThingIndexName(type: SCThingType, source: string, bulk: SCBulkResponse) {
return `stapps_${type.replace(/\s+/g, '_')}_${source}_${getIndexUID(bulk.uid)}`;
return `stapps_${type.replaceAll(/\s+/g, '_')}_${source}_${getIndexUID(bulk.uid)}`;
}
/**
* Returns an index that matches all indices with the specified type
*/
export function matchIndexByType(type: SCThingType, source: string) {
return `stapps_${type.replace(/\s+/g, '_')}_${source}_*`;
return `stapps_${type.replaceAll(/\s+/g, '_')}_${source}_*`;
}
/**
* Provides the index UID (for its name) from the bulk UID
*
* @param uid Bulk UID
*/
export function getIndexUID(uid: SCUuid) {

View File

@@ -17,5 +17,5 @@
* Type guard for filter functions
*/
export function noUndefined<T>(item: T | undefined): item is T {
return typeof item !== 'undefined';
return item !== undefined;
}