Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@backstage/plugin-search-backend-node

Package Overview
Dependencies
Maintainers
4
Versions
1079
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@backstage/plugin-search-backend-node - npm Package Compare versions

Comparing version 0.1.4 to 0.2.0

85

CHANGELOG.md
# @backstage/plugin-search-backend-node
## 0.2.0
### Minor Changes
- 5aff84759: This release represents a move out of a pre-alpha phase of the Backstage Search
plugin, into an alpha phase. With this release, you gain more control over the
layout of your search page on the frontend, as well as the ability to extend
search on the backend to encompass everything Backstage users may want to find.
If you are updating to version `v0.4.0` of `@backstage/plugin-search` from a
prior release, you will need to make modifications to your app backend.
First, navigate to your backend package and install the two related search
backend packages:
```sh
cd packages/backend
yarn add @backstage/plugin-search-backend @backstage/plugin-search-backend-node
```
Wire up these new packages into your app backend by first creating a new
`search.ts` file at `src/plugins/search.ts` with contents like the following:
```typescript
import { useHotCleanup } from '@backstage/backend-common';
import { createRouter } from '@backstage/plugin-search-backend';
import {
IndexBuilder,
LunrSearchEngine,
} from '@backstage/plugin-search-backend-node';
import { PluginEnvironment } from '../types';
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
export default async function createPlugin({
logger,
discovery,
}: PluginEnvironment) {
// Initialize a connection to a search engine.
const searchEngine = new LunrSearchEngine({ logger });
const indexBuilder = new IndexBuilder({ logger, searchEngine });
// Collators are responsible for gathering documents known to plugins. This
// particular collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: new DefaultCatalogCollator({ discovery }),
});
// The scheduler controls when documents are gathered from collators and sent
// to the search engine for indexing.
const { scheduler } = await indexBuilder.build();
// A 3 second delay gives the backend server a chance to initialize before
// any collators are executed, which may attempt requests against the API.
setTimeout(() => scheduler.start(), 3000);
useHotCleanup(module, () => scheduler.stop());
return await createRouter({
engine: indexBuilder.getSearchEngine(),
logger,
});
}
```
Then, ensure the search plugin you configured above is initialized by modifying
your backend's `index.ts` file in the following ways:
```diff
+import search from './plugins/search';
// ...
+const searchEnv = useHotMemoize(module, () => createEnv('search'));
// ...
+apiRouter.use('/search', await search(searchEnv));
// ...
```
### Patch Changes
- db1c8f93b: The `<Search...Next /> set of components exported by the Search Plugin are now updated to use the Search Backend API. These will be made available as the default non-"next" versions in a follow-up release.
The interfaces for decorators and collators in the Search Backend have also seen minor, breaking revisions ahead of a general release. If you happen to be building on top of these interfaces, check and update your implementations accordingly. The APIs will be considered more stable in a follow-up release.
- Updated dependencies [db1c8f93b]
- @backstage/search-common@0.1.2
## 0.1.4

@@ -4,0 +89,0 @@

58

dist/index.cjs.js

@@ -22,8 +22,7 @@ 'use strict';

addCollator({
type,
collator,
defaultRefreshIntervalSeconds
}) {
this.logger.info(`Added ${collator.constructor.name} collator for type ${type}`);
this.collators[type] = {
this.logger.info(`Added ${collator.constructor.name} collator for type ${collator.type}`);
this.collators[collator.type] = {
refreshInterval: defaultRefreshIntervalSeconds,

@@ -33,6 +32,4 @@ collate: collator

}
addDecorator({
types = ["*"],
decorator
}) {
addDecorator({decorator}) {
const types = decorator.types || ["*"];
this.logger.info(`Added decorator ${decorator.constructor.name} to types ${types.join(", ")}`);

@@ -86,2 +83,3 @@ types.forEach((type) => {

this.schedule.forEach(({task, interval}) => {
task();
this.intervalTimeouts.push(setInterval(() => {

@@ -110,7 +108,20 @@ task();

let lunrQueryFilters;
const lunrTerm = term ? `+${term}` : "";
if (filters) {
lunrQueryFilters = Object.entries(filters).map(([key, value]) => ` +${key}:${value}`).join("");
lunrQueryFilters = Object.entries(filters).map(([field, value]) => {
if (["string", "number", "boolean"].includes(typeof value)) {
return ` +${field}:${value}`;
}
if (Array.isArray(value)) {
this.logger.warn(`Non-scalar filter value used for field ${field}. Consider using a different Search Engine for better results.`);
return ` ${value.map((v) => {
return `${field}:${v}`;
})}`;
}
this.logger.warn(`Unknown filter type used on field ${field}`);
return "";
}).join("");
}
return {
lunrQueryString: `${term}${lunrQueryFilters || ""}`,
lunrQueryString: `${lunrTerm}${lunrQueryFilters || ""}`,
documentTypes: types || ["*"]

@@ -122,2 +133,5 @@ };

}
setTranslator(translator) {
this.translator = translator;
}
index(type, documents) {

@@ -139,5 +153,10 @@ const lunrBuilder = new lunr__default['default'].Builder();

if (documentTypes.length === 1 && documentTypes[0] === "*") {
Object.values(this.lunrIndices).forEach((i) => {
Object.keys(this.lunrIndices).forEach((type) => {
try {
results.push(...i.search(lunrQueryString));
results.push(...this.lunrIndices[type].search(lunrQueryString).map((result) => {
return {
result,
type
};
}));
} catch (err) {

@@ -149,5 +168,10 @@ if (err instanceof lunr__default['default'].QueryParseError && err.message.startsWith("unrecognised field"))

} else {
Object.keys(this.lunrIndices).filter((d) => documentTypes.includes(d)).forEach((d) => {
Object.keys(this.lunrIndices).filter((type) => documentTypes.includes(type)).forEach((type) => {
try {
results.push(...this.lunrIndices[d].search(lunrQueryString));
results.push(...this.lunrIndices[type].search(lunrQueryString).map((result) => {
return {
result,
type
};
}));
} catch (err) {

@@ -160,10 +184,10 @@ if (err instanceof lunr__default['default'].QueryParseError && err.message.startsWith("unrecognised field"))

results.sort((doc1, doc2) => {
return doc2.score - doc1.score;
return doc2.result.score - doc1.result.score;
});
const resultSet = {
const realResultSet = {
results: results.map((d) => {
return {document: this.docStore[d.ref]};
return {type: d.type, document: this.docStore[d.result.ref]};
})
};
return Promise.resolve(resultSet);
return Promise.resolve(realResultSet);
}

@@ -170,0 +194,0 @@ }

@@ -10,6 +10,2 @@ import { Logger } from 'winston';

/**
* The type of document to be indexed (used to name indices, to configure refresh loop, etc).
*/
type: string;
/**
* The default interval (in seconds) that the provided collator will be called (can be overridden in config).

@@ -31,7 +27,2 @@ */

decorator: DocumentDecorator;
/**
* (Optional) An array of document types that the given decorator should apply to. If none are provided,
* the decorator will be applied to all types.
*/
types?: string[];
}

@@ -49,4 +40,13 @@ /**

interface SearchEngine {
translator: QueryTranslator;
/**
* Override the default translator provided by the SearchEngine.
*/
setTranslator(translator: QueryTranslator): void;
/**
* Add the given documents to the SearchEngine index of the given type.
*/
index(type: string, documents: IndexableDocument[]): void;
/**
* Perform a search query against the SearchEngine.
*/
query(query: SearchQuery): Promise<SearchResultSet>;

@@ -70,9 +70,9 @@ }

*/
addCollator({ type, collator, defaultRefreshIntervalSeconds, }: RegisterCollatorParameters): void;
addCollator({ collator, defaultRefreshIntervalSeconds, }: RegisterCollatorParameters): void;
/**
* Makes the index builder aware of a decorator. If no types are provided, it
* will be applied to documents from all known collators, otherwise it will
* only be applied to documents of the given types.
* Makes the index builder aware of a decorator. If no types are provided on
* the decorator, it will be applied to documents from all known collators,
* otherwise it will only be applied to documents of the given types.
*/
addDecorator({ types, decorator, }: RegisterDecoratorParameters): void;
addDecorator({ decorator }: RegisterDecoratorParameters): void;
/**

@@ -112,2 +112,7 @@ * Compiles collators and decorators into tasks, which are added to a

declare type ConcreteLunrQuery = {
lunrQueryString: string;
documentTypes: string[];
};
declare type LunrQueryTranslator = (query: SearchQuery) => ConcreteLunrQuery;
declare class LunrSearchEngine implements SearchEngine {

@@ -120,3 +125,4 @@ protected lunrIndices: Record<string, lunr.Index>;

});
translator: QueryTranslator;
protected translator: QueryTranslator;
setTranslator(translator: LunrQueryTranslator): void;
index(type: string, documents: IndexableDocument[]): void;

@@ -123,0 +129,0 @@ query(query: SearchQuery): Promise<SearchResultSet>;

{
"name": "@backstage/plugin-search-backend-node",
"version": "0.1.4",
"version": "0.2.0",
"main": "dist/index.cjs.js",

@@ -22,3 +22,3 @@ "types": "dist/index.d.ts",

"dependencies": {
"@backstage/search-common": "^0.1.1",
"@backstage/search-common": "^0.1.2",
"@types/lunr": "^2.3.3",

@@ -29,4 +29,4 @@ "lunr": "^2.3.9",

"devDependencies": {
"@backstage/backend-common": "^0.6.3",
"@backstage/cli": "^0.6.9"
"@backstage/backend-common": "^0.8.2",
"@backstage/cli": "^0.7.0"
},

@@ -36,3 +36,3 @@ "files": [

],
"gitHead": "88f56a51f68928f8da122843045d529b01832674"
"gitHead": "2147ab9c1bd37e93e9e332c5ee14daa08be031e6"
}
# search-backend-node
This plugin is part of a suite of plugins that comprise the Backstage search
platform, which is still very much under development. This plugin specifically
is responsible for:
platform. This particular plugin is responsible for all aspects of the search
indexing process, including:
- Allowing other backend plugins to register the fact that they have documents
that they'd like to be indexed by a search engine (known as `collators`)
- Allowing other backend plugins to register the fact that they have metadata
that they'd like to augment existing documents in the search index with
(known as `decorators`)
- Providing connections to search engines where actual document indices live
and queries can be made.
- Defining a mechanism for plugins to expose documents that they'd like to be
indexed (called `collators`).
- Defining a mechanism for plugins to add extra metadata to documents that the
source plugin may not be aware of (known as `decorators`).
- A scheduler that, at configurable intervals, compiles documents to be indexed
and passes them to a search engine for indexing
- Types for all of the above
and passes them to a search engine for indexing.
- A builder class to wire up all of the above.
- Naturally, types for all of the above.

@@ -16,0 +18,0 @@ Documentation on how to develop and improve the search platform is currently

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc