Adds two more packages and moves files into the packages (#100375)

## Summary

* Adds package `kbn-securitysolution-list-api`
* Adds package `kbn-securitysolution-list-hooks`
* Moves files into the packages
* Moves a few additional types into the other packages such as the `kbn-securitysolution-io-ts-types` package to remove more things from the shard_export/shared_import between lists and security solution
* Removes more duplicated code

### Checklist

- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
Frank Hassanabad 2021-05-20 12:36:07 -06:00 committed by GitHub
parent 3523a937f6
commit 192c8ba743
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
128 changed files with 1669 additions and 517 deletions

View file

@ -0,0 +1,88 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm")
PKG_BASE_NAME = "kbn-securitysolution-list-api"
PKG_REQUIRE_NAME = "@kbn/securitysolution-list-api"
SOURCE_FILES = glob(
[
"src/**/*.ts",
],
exclude = [
"**/*.test.*",
"**/*.mock.*",
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
"README.md",
]
SRC_DEPS = [
"//packages/kbn-securitysolution-io-ts-utils",
"//packages/kbn-securitysolution-io-ts-list-types",
"@npm//fp-ts",
"@npm//io-ts",
"@npm//tslib",
]
TYPES_DEPS = [
"@npm//@types/jest",
"@npm//@types/node",
]
DEPS = SRC_DEPS + TYPES_DEPS
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
],
)
ts_project(
name = "tsc",
srcs = SRCS,
args = ["--pretty"],
declaration = True,
declaration_map = True,
incremental = True,
out_dir = "target",
root_dir = "src",
source_map = True,
tsconfig = ":tsconfig",
deps = DEPS,
)
js_library(
name = PKG_BASE_NAME,
package_name = PKG_REQUIRE_NAME,
srcs = NPM_MODULE_EXTRA_FILES,
visibility = ["//visibility:public"],
deps = [":tsc"] + DEPS,
)
pkg_npm(
name = "npm_module",
deps = [
":%s" % PKG_BASE_NAME,
],
)
filegroup(
name = "build",
srcs = [
":npm_module",
],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,4 @@
# kbn-securitysolution-list-api
This is where the REST API for the list plugin lives

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-securitysolution-list-api'],
};

View file

@ -0,0 +1,9 @@
{
"name": "@kbn/securitysolution-list-api",
"version": "1.0.0",
"description": "security solution list REST API",
"license": "SSPL-1.0 OR Elastic License 2.0",
"main": "./target/index.js",
"types": "./target/index.d.ts",
"private": true
}

View file

@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
describe('Exceptions Lists API', () => {
test('we should port these tests', () => {
// See the file outside of this at: x-pack/plugins/lists/public/exceptions/api.test.ts
// for the tests. We cannot port the tests over until we move the mocks into their own package
// and possibly core mocks end up within packages.
expect(true).toBe(true);
});
});

View file

@ -0,0 +1,564 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { chain, fromEither, tryCatch } from 'fp-ts/lib/TaskEither';
import { flow } from 'fp-ts/lib/function';
import { validateEither } from '@kbn/securitysolution-io-ts-utils';
import {
CreateEndpointListSchema,
ExceptionListItemSchema,
ExceptionListSchema,
FoundExceptionListItemSchema,
FoundExceptionListSchema,
createEndpointListSchema,
exceptionListItemSchema,
exceptionListSchema,
foundExceptionListItemSchema,
foundExceptionListSchema,
AddEndpointExceptionListProps,
AddExceptionListItemProps,
AddExceptionListProps,
ApiCallByIdProps,
ApiCallByListIdProps,
ApiCallFetchExceptionListsProps,
ExportExceptionListProps,
UpdateExceptionListItemProps,
UpdateExceptionListProps,
} from '@kbn/securitysolution-io-ts-list-types';
import { toError, toPromise } from '../fp_utils';
import {
ENDPOINT_LIST_URL,
EXCEPTION_LIST_ITEM_URL,
EXCEPTION_LIST_NAMESPACE,
EXCEPTION_LIST_NAMESPACE_AGNOSTIC,
EXCEPTION_LIST_URL,
} from '../constants';
/**
* Add new ExceptionList
*
* @param http Kibana http service
* @param list exception list to add
* @param signal to cancel request
*
* @throws An error if response is not OK
*
*/
const addExceptionList = async ({
http,
list,
signal,
}: AddExceptionListProps): Promise<ExceptionListSchema> =>
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
body: JSON.stringify(list),
method: 'POST',
signal,
});
const addExceptionListWithValidation = async ({
http,
list,
signal,
}: AddExceptionListProps): Promise<ExceptionListSchema> =>
flow(
() =>
tryCatch(
() =>
addExceptionList({
http,
list,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
flow(toPromise)
)();
export { addExceptionListWithValidation as addExceptionList };
/**
* Add new ExceptionListItem
*
* @param http Kibana http service
* @param listItem exception list item to add
* @param signal to cancel request
*
* @throws An error if response is not OK
*
*/
const addExceptionListItem = async ({
http,
listItem,
signal,
}: AddExceptionListItemProps): Promise<ExceptionListItemSchema> =>
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
body: JSON.stringify(listItem),
method: 'POST',
signal,
});
const addExceptionListItemWithValidation = async ({
http,
listItem,
signal,
}: AddExceptionListItemProps): Promise<ExceptionListItemSchema> =>
flow(
() =>
tryCatch(
() =>
addExceptionListItem({
http,
listItem,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
flow(toPromise)
)();
export { addExceptionListItemWithValidation as addExceptionListItem };
/**
* Update existing ExceptionList
*
* @param http Kibana http service
* @param list exception list to add
* @param signal to cancel request
*
* @throws An error if response is not OK
*
*/
const updateExceptionList = async ({
http,
list,
signal,
}: UpdateExceptionListProps): Promise<ExceptionListSchema> =>
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
body: JSON.stringify(list),
method: 'PUT',
signal,
});
const updateExceptionListWithValidation = async ({
http,
list,
signal,
}: UpdateExceptionListProps): Promise<ExceptionListSchema> =>
flow(
() =>
tryCatch(
() =>
updateExceptionList({
http,
list,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
flow(toPromise)
)();
export { updateExceptionListWithValidation as updateExceptionList };
/**
* Update existing ExceptionListItem
*
* @param http Kibana http service
* @param listItem exception list item to add
* @param signal to cancel request
*
* @throws An error if response is not OK
*
*/
const updateExceptionListItem = async ({
http,
listItem,
signal,
}: UpdateExceptionListItemProps): Promise<ExceptionListItemSchema> =>
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
body: JSON.stringify(listItem),
method: 'PUT',
signal,
});
const updateExceptionListItemWithValidation = async ({
http,
listItem,
signal,
}: UpdateExceptionListItemProps): Promise<ExceptionListItemSchema> =>
flow(
() =>
tryCatch(
() =>
updateExceptionListItem({
http,
listItem,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
flow(toPromise)
)();
export { updateExceptionListItemWithValidation as updateExceptionListItem };
/**
* Fetch all ExceptionLists (optionally by namespaceType)
*
* @param http Kibana http service
* @param namespaceTypes ExceptionList namespace_types of lists to find
* @param filters search bar filters
* @param pagination optional
* @param signal to cancel request
*
* @throws An error if request params or response is not OK
*/
const fetchExceptionLists = async ({
http,
filters,
namespaceTypes,
pagination,
signal,
}: ApiCallFetchExceptionListsProps): Promise<FoundExceptionListSchema> => {
const query = {
filter: filters,
namespace_type: namespaceTypes,
page: pagination.page ? `${pagination.page}` : '1',
per_page: pagination.perPage ? `${pagination.perPage}` : '20',
sort_field: 'exception-list.created_at',
sort_order: 'desc',
};
return http.fetch<FoundExceptionListSchema>(`${EXCEPTION_LIST_URL}/_find`, {
method: 'GET',
query,
signal,
});
};
const fetchExceptionListsWithValidation = async ({
filters,
http,
namespaceTypes,
pagination,
signal,
}: ApiCallFetchExceptionListsProps): Promise<FoundExceptionListSchema> =>
flow(
() =>
tryCatch(
() =>
fetchExceptionLists({
filters,
http,
namespaceTypes,
pagination,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(foundExceptionListSchema, response))),
flow(toPromise)
)();
export { fetchExceptionListsWithValidation as fetchExceptionLists };
/**
* Fetch an ExceptionList by providing a ExceptionList ID
*
* @param http Kibana http service
* @param id ExceptionList ID (not list_id)
* @param namespaceType ExceptionList namespace_type
* @param signal to cancel request
*
* @throws An error if response is not OK
*/
const fetchExceptionListById = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
method: 'GET',
query: { id, namespace_type: namespaceType },
signal,
});
const fetchExceptionListByIdWithValidation = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
flow(
() =>
tryCatch(
() =>
fetchExceptionListById({
http,
id,
namespaceType,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
flow(toPromise)
)();
export { fetchExceptionListByIdWithValidation as fetchExceptionListById };
/**
* Fetch an ExceptionList's ExceptionItems by providing a ExceptionList list_id
*
* @param http Kibana http service
* @param listIds ExceptionList list_ids (not ID)
* @param namespaceTypes ExceptionList namespace_types
* @param filterOptions optional - filter by field or tags
* @param pagination optional
* @param signal to cancel request
*
* @throws An error if response is not OK
*/
const fetchExceptionListsItemsByListIds = async ({
http,
listIds,
namespaceTypes,
filterOptions,
pagination,
signal,
}: ApiCallByListIdProps): Promise<FoundExceptionListItemSchema> => {
const filters: string = filterOptions
.map<string>((filter, index) => {
const namespace = namespaceTypes[index];
const filterNamespace =
namespace === 'agnostic' ? EXCEPTION_LIST_NAMESPACE_AGNOSTIC : EXCEPTION_LIST_NAMESPACE;
const formattedFilters = [
...(filter.filter.length
? [`${filterNamespace}.attributes.entries.field:${filter.filter}*`]
: []),
...(filter.tags.length
? filter.tags.map((t) => `${filterNamespace}.attributes.tags:${t}`)
: []),
];
return formattedFilters.join(' AND ');
})
.join(',');
const query = {
list_id: listIds.join(','),
namespace_type: namespaceTypes.join(','),
page: pagination.page ? `${pagination.page}` : '1',
per_page: pagination.perPage ? `${pagination.perPage}` : '20',
sort_field: 'exception-list.created_at',
sort_order: 'desc',
...(filters.trim() !== '' ? { filter: filters } : {}),
};
return http.fetch<FoundExceptionListItemSchema>(`${EXCEPTION_LIST_ITEM_URL}/_find`, {
method: 'GET',
query,
signal,
});
};
const fetchExceptionListsItemsByListIdsWithValidation = async ({
filterOptions,
http,
listIds,
namespaceTypes,
pagination,
signal,
}: ApiCallByListIdProps): Promise<FoundExceptionListItemSchema> =>
flow(
() =>
tryCatch(
() =>
fetchExceptionListsItemsByListIds({
filterOptions,
http,
listIds,
namespaceTypes,
pagination,
signal,
}),
toError
),
chain((response) => fromEither(validateEither(foundExceptionListItemSchema, response))),
flow(toPromise)
)();
export { fetchExceptionListsItemsByListIdsWithValidation as fetchExceptionListsItemsByListIds };
/**
* Fetch an ExceptionListItem by providing a ExceptionListItem ID
*
* @param http Kibana http service
* @param id ExceptionListItem ID (not item_id)
* @param namespaceType ExceptionList namespace_type
* @param signal to cancel request
*
* @throws An error if response is not OK
*/
const fetchExceptionListItemById = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
method: 'GET',
query: { id, namespace_type: namespaceType },
signal,
});
const fetchExceptionListItemByIdWithValidation = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
flow(
() => tryCatch(() => fetchExceptionListItemById({ http, id, namespaceType, signal }), toError),
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
flow(toPromise)
)();
export { fetchExceptionListItemByIdWithValidation as fetchExceptionListItemById };
/**
* Delete an ExceptionList by providing a ExceptionList ID
*
* @param http Kibana http service
* @param id ExceptionList ID (not list_id)
* @param namespaceType ExceptionList namespace_type
* @param signal to cancel request
*
* @throws An error if response is not OK
*/
const deleteExceptionListById = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
http.fetch<ExceptionListSchema>(EXCEPTION_LIST_URL, {
method: 'DELETE',
query: { id, namespace_type: namespaceType },
signal,
});
const deleteExceptionListByIdWithValidation = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListSchema> =>
flow(
() => tryCatch(() => deleteExceptionListById({ http, id, namespaceType, signal }), toError),
chain((response) => fromEither(validateEither(exceptionListSchema, response))),
flow(toPromise)
)();
export { deleteExceptionListByIdWithValidation as deleteExceptionListById };
/**
* Delete an ExceptionListItem by providing a ExceptionListItem ID
*
* @param http Kibana http service
* @param id ExceptionListItem ID (not item_id)
* @param namespaceType ExceptionList namespace_type
* @param signal to cancel request
*
* @throws An error if response is not OK
*/
const deleteExceptionListItemById = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
http.fetch<ExceptionListItemSchema>(EXCEPTION_LIST_ITEM_URL, {
method: 'DELETE',
query: { id, namespace_type: namespaceType },
signal,
});
const deleteExceptionListItemByIdWithValidation = async ({
http,
id,
namespaceType,
signal,
}: ApiCallByIdProps): Promise<ExceptionListItemSchema> =>
flow(
() => tryCatch(() => deleteExceptionListItemById({ http, id, namespaceType, signal }), toError),
chain((response) => fromEither(validateEither(exceptionListItemSchema, response))),
flow(toPromise)
)();
export { deleteExceptionListItemByIdWithValidation as deleteExceptionListItemById };
/**
* Add new Endpoint ExceptionList
*
* @param http Kibana http service
* @param signal to cancel request
*
* @throws An error if response is not OK
*
*/
const addEndpointExceptionList = async ({
http,
signal,
}: AddEndpointExceptionListProps): Promise<CreateEndpointListSchema> =>
http.fetch<ExceptionListItemSchema>(ENDPOINT_LIST_URL, {
method: 'POST',
signal,
});
const addEndpointExceptionListWithValidation = async ({
http,
signal,
}: AddEndpointExceptionListProps): Promise<CreateEndpointListSchema> =>
flow(
() => tryCatch(() => addEndpointExceptionList({ http, signal }), toError),
chain((response) => fromEither(validateEither(createEndpointListSchema, response))),
flow(toPromise)
)();
export { addEndpointExceptionListWithValidation as addEndpointExceptionList };
/**
* Fetch an ExceptionList by providing a ExceptionList ID
*
* @param http Kibana http service
* @param id ExceptionList ID (not list_id)
* @param listId ExceptionList LIST_ID (not id)
* @param namespaceType ExceptionList namespace_type
* @param signal to cancel request
*
* @throws An error if response is not OK
*/
export const exportExceptionList = async ({
http,
id,
listId,
namespaceType,
signal,
}: ExportExceptionListProps): Promise<Blob> =>
http.fetch<Blob>(`${EXCEPTION_LIST_URL}/_export`, {
method: 'GET',
query: { id, list_id: listId, namespace_type: namespaceType },
signal,
});

View file

@ -0,0 +1,39 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
// TODO: These should be all replaced with constants from a shared kbn constants package
export const LIST_URL = '/api/lists';
export const LIST_INDEX = `${LIST_URL}/index`;
export const LIST_ITEM_URL = `${LIST_URL}/items`;
export const LIST_PRIVILEGES_URL = `${LIST_URL}/privileges`;
/**
* Exception list routes
*/
export const EXCEPTION_LIST_URL = '/api/exception_lists';
export const EXCEPTION_LIST_ITEM_URL = '/api/exception_lists/items';
/**
* Exception list spaces
*/
export const EXCEPTION_LIST_NAMESPACE_AGNOSTIC = 'exception-list-agnostic';
export const EXCEPTION_LIST_NAMESPACE = 'exception-list';
/**
* Specific routes for the single global space agnostic endpoint list
*/
export const ENDPOINT_LIST_URL = '/api/endpoint_list';
/**
* Specific routes for the single global space agnostic endpoint list. These are convenience
* routes where they are going to try and create the global space agnostic endpoint list if it
* does not exist yet or if it was deleted at some point and re-create it before adding items to
* the list
*/
export const ENDPOINT_LIST_ITEM_URL = '/api/endpoint_list/items';

View file

@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { tryCatch } from 'fp-ts/lib/TaskEither';
import { toPromise } from '.';
describe('toPromise', () => {
it('rejects with left if TaskEither is left', async () => {
const task = tryCatch(() => Promise.reject(new Error('whoops')), String);
await expect(toPromise(task)).rejects.toEqual('Error: whoops');
});
it('resolves with right if TaskEither is right', async () => {
const task = tryCatch(() => Promise.resolve('success'), String);
await expect(toPromise(task)).resolves.toEqual('success');
});
});

View file

@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { pipe } from 'fp-ts/lib/pipeable';
import { TaskEither } from 'fp-ts/lib/TaskEither';
import { fold } from 'fp-ts/lib/Either';
// TODO: This is copied in a few other spots and probably should live within its own kbn package
// rather than living here. A package such as kbn-security-solution-fp-utils
export const toPromise = async <E, A>(taskEither: TaskEither<E, A>): Promise<A> =>
pipe(
await taskEither(),
fold(
(e) => Promise.reject(e),
(a) => Promise.resolve(a)
)
);
export const toError = (e: unknown): Error => (e instanceof Error ? e : new Error(String(e)));

View file

@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export * from './api';
export * from './fp_utils';
export * from './list_api';

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
describe('Value Lists API', () => {
test('Tests should be ported', () => {
// TODO: Port all the tests from: x-pack/plugins/lists/public/lists/api.test.ts here once mocks are figured out and kbn package mocks are figured out
expect(true).toBe(true);
});
});

View file

@ -0,0 +1,230 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { chain, fromEither, map, tryCatch } from 'fp-ts/lib/TaskEither';
import { flow } from 'fp-ts/lib/function';
import { pipe } from 'fp-ts/lib/pipeable';
import { validateEither } from '@kbn/securitysolution-io-ts-utils';
import {
AcknowledgeSchema,
DeleteListSchemaEncoded,
ExportListItemQuerySchemaEncoded,
FindListSchemaEncoded,
FoundListSchema,
ImportListItemQuerySchemaEncoded,
ImportListItemSchemaEncoded,
ListItemIndexExistSchema,
ListSchema,
acknowledgeSchema,
deleteListSchema,
exportListItemQuerySchema,
findListSchema,
foundListSchema,
importListItemQuerySchema,
importListItemSchema,
listItemIndexExistSchema,
listSchema,
} from '@kbn/securitysolution-io-ts-list-types';
import { toError, toPromise } from '../fp_utils';
import { LIST_INDEX, LIST_ITEM_URL, LIST_PRIVILEGES_URL, LIST_URL } from '../constants';
import {
ApiParams,
DeleteListParams,
ExportListParams,
FindListsParams,
ImportListParams,
} from './types';
const findLists = async ({
http,
cursor,
page,
// eslint-disable-next-line @typescript-eslint/naming-convention
per_page,
signal,
}: ApiParams & FindListSchemaEncoded): Promise<FoundListSchema> => {
return http.fetch(`${LIST_URL}/_find`, {
method: 'GET',
query: {
cursor,
page,
per_page,
},
signal,
});
};
const findListsWithValidation = async ({
cursor,
http,
pageIndex,
pageSize,
signal,
}: FindListsParams): Promise<FoundListSchema> =>
pipe(
{
cursor: cursor != null ? cursor.toString() : undefined,
page: pageIndex != null ? pageIndex.toString() : undefined,
per_page: pageSize != null ? pageSize.toString() : undefined,
},
(payload) => fromEither(validateEither(findListSchema, payload)),
chain((payload) => tryCatch(() => findLists({ http, signal, ...payload }), toError)),
chain((response) => fromEither(validateEither(foundListSchema, response))),
flow(toPromise)
);
export { findListsWithValidation as findLists };
const importList = async ({
file,
http,
// eslint-disable-next-line @typescript-eslint/naming-convention
list_id,
type,
signal,
}: ApiParams &
ImportListItemSchemaEncoded &
ImportListItemQuerySchemaEncoded): Promise<ListSchema> => {
const formData = new FormData();
formData.append('file', file as Blob);
return http.fetch<ListSchema>(`${LIST_ITEM_URL}/_import`, {
body: formData,
headers: { 'Content-Type': undefined },
method: 'POST',
query: { list_id, type },
signal,
});
};
const importListWithValidation = async ({
file,
http,
listId,
type,
signal,
}: ImportListParams): Promise<ListSchema> =>
pipe(
{
list_id: listId,
type,
},
(query) => fromEither(validateEither(importListItemQuerySchema, query)),
chain((query) =>
pipe(
fromEither(validateEither(importListItemSchema, { file })),
map((body) => ({ ...body, ...query }))
)
),
chain((payload) => tryCatch(() => importList({ http, signal, ...payload }), toError)),
chain((response) => fromEither(validateEither(listSchema, response))),
toPromise
);
export { importListWithValidation as importList };
const deleteList = async ({
deleteReferences = false,
http,
id,
ignoreReferences = false,
signal,
}: ApiParams & DeleteListSchemaEncoded): Promise<ListSchema> =>
http.fetch<ListSchema>(LIST_URL, {
method: 'DELETE',
query: { deleteReferences, id, ignoreReferences },
signal,
});
const deleteListWithValidation = async ({
deleteReferences,
http,
id,
ignoreReferences,
signal,
}: DeleteListParams): Promise<ListSchema> =>
pipe(
{ deleteReferences, id, ignoreReferences },
(payload) => fromEither(validateEither(deleteListSchema, payload)),
chain((payload) => tryCatch(() => deleteList({ http, signal, ...payload }), toError)),
chain((response) => fromEither(validateEither(listSchema, response))),
flow(toPromise)
);
export { deleteListWithValidation as deleteList };
const exportList = async ({
http,
// eslint-disable-next-line @typescript-eslint/naming-convention
list_id,
signal,
}: ApiParams & ExportListItemQuerySchemaEncoded): Promise<Blob> =>
http.fetch<Blob>(`${LIST_ITEM_URL}/_export`, {
method: 'POST',
query: { list_id },
signal,
});
const exportListWithValidation = async ({
http,
listId,
signal,
}: ExportListParams): Promise<Blob> =>
pipe(
{ list_id: listId },
(payload) => fromEither(validateEither(exportListItemQuerySchema, payload)),
chain((payload) => tryCatch(() => exportList({ http, signal, ...payload }), toError)),
flow(toPromise)
);
export { exportListWithValidation as exportList };
const readListIndex = async ({ http, signal }: ApiParams): Promise<ListItemIndexExistSchema> =>
http.fetch<ListItemIndexExistSchema>(LIST_INDEX, {
method: 'GET',
signal,
});
const readListIndexWithValidation = async ({
http,
signal,
}: ApiParams): Promise<ListItemIndexExistSchema> =>
flow(
() => tryCatch(() => readListIndex({ http, signal }), toError),
chain((response) => fromEither(validateEither(listItemIndexExistSchema, response))),
flow(toPromise)
)();
export { readListIndexWithValidation as readListIndex };
// TODO add types and validation
export const readListPrivileges = async ({ http, signal }: ApiParams): Promise<unknown> =>
http.fetch<unknown>(LIST_PRIVILEGES_URL, {
method: 'GET',
signal,
});
const createListIndex = async ({ http, signal }: ApiParams): Promise<AcknowledgeSchema> =>
http.fetch<AcknowledgeSchema>(LIST_INDEX, {
method: 'POST',
signal,
});
const createListIndexWithValidation = async ({
http,
signal,
}: ApiParams): Promise<AcknowledgeSchema> =>
flow(
() => tryCatch(() => createListIndex({ http, signal }), toError),
chain((response) => fromEither(validateEither(acknowledgeSchema, response))),
flow(toPromise)
)();
export { createListIndexWithValidation as createListIndex };

View file

@ -0,0 +1,44 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import type { Type } from '@kbn/securitysolution-io-ts-list-types';
// TODO: Replace these with kbn packaged versions once we have those available to us
// These originally came from this location below before moving them to this hacked "any" types:
// import { HttpStart, NotificationsStart } from '../../../../../src/core/public';
interface HttpStart {
fetch: <T>(...args: any) => any;
}
export interface ApiParams {
http: HttpStart;
signal: AbortSignal;
}
export type ApiPayload<T extends ApiParams> = Omit<T, 'http' | 'signal'>;
export interface FindListsParams extends ApiParams {
cursor?: string | undefined;
pageSize: number | undefined;
pageIndex: number | undefined;
}
export interface ImportListParams extends ApiParams {
file: File;
listId: string | undefined;
type: Type | undefined;
}
export interface DeleteListParams extends ApiParams {
deleteReferences?: boolean;
id: string;
ignoreReferences?: boolean;
}
export interface ExportListParams extends ApiParams {
listId: string;
}

View file

@ -0,0 +1,19 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"incremental": true,
"outDir": "target",
"rootDir": "src",
"sourceMap": true,
"sourceRoot": "../../../../packages/kbn-securitysolution-list-api/src",
"types": [
"jest",
"node"
]
},
"include": [
"src/**/*"
]
}