
Research
/Security News
Weaponizing Discord for Command and Control Across npm, PyPI, and RubyGems.org
Socket researchers uncover how threat actors weaponize Discord across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.
@openfin/search-api
Advanced tools
The OpenFin Search Extention is a framework for searching, fetching, aggregating and actioning data through application interopability.
There are two options for using this package.
Import functions from NPM package and bundle:
import { create, subscribe } from '@openfin/search-api';
Or import the script fron our CDN and use the fin.Search
global namespace.
<script src="https://home.openfin.co/search-api/index.js" />
<script>
const create = fin.Search.create;
const subscribe = fin.Search.subscribe;
</script>
More in depth API documentation can be found here.
// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { subscribe } from '@openfin/search-api';
// Subscribe to a search topic.
const searchTopic = await subscribe({ topic: 'foo' });
/* Search for data with query `bar`.
This will return a generator which can be called multiple times
while there are pending responses from search data providers. */
const generator = searchTopic.search({ query: 'bar' });
while (true) {
const { value, done } = await generator.next();
// Implementation specifc rendering logic.
render(results);
// If done is true, all search providers have responded with their data.
if (done) {
break;
}
}
// When done with search request, call close.
generator.close();
// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { subscribe } from '@openfin/search-api';
const openWindowAction = 'Open Window';
// Example search handler that returns results from a backend query.
async function getSearchResults({ query }) {
const res = await fetch('/search?q=' + encodeURIComponent(query));
if (!res.ok) {
throw new Error('uh oh something went wrong');
}
const json = await res.json();
/* Return initial search results.
All results must have the `name` and `description`
field at the very least for rendering purposes. */
return json.map((myResult) => ({
name: myResult.nameAttribute,
shortDescription: myResult.shortDescriptionAttribute,
description: myResult.descriptionAttribute,
actions: [openWindowAction], // Dispatchable actions for this search result.
data: myResult.customMetadata
}));
}
// Example function for actioning a result from `getSearchResults`.
function openWindowForSearchResult(result) {
const dispatchedAction = result.action; // `result.action` is set to the action that was dispatched.
if (dispatchedAction !== openWindowAction) return;
window.open(result.data.url);
}
// Subscribe to a search topic.
const searchTopic = await subscribe({ topic: 'foo' });
/* The `name` and `onSearch` attributes are required for a data provider.
The `onSearch` function will be called back when the topic is searched
on. (ex. `searchTopic.search("my query")`)
The `onResultDispatch` function will be called back when a search result
is dispatched. (ex. `searchTopic.dispatch("Provider Name", searchResult, "Open Window")`) */
const provider = {
name: 'bar',
onSearch: getSearchResults,
onResultDispatch: openWindowForSearchResult
};
// Register the search data provider.
await searchTopic.register(provider);
// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { subscribe } from '@openfin/search-api';
// Subscribe to a search topic.
const searchTopic = await subscribe({ topic: 'foo' });
// Get search results.
const generator = searchTopic.search({ query: 'bar' });
const { value } = await generator.next();
/* Dispatches the first search result in the first response back to the
respective provider, such that the provider can action the result. */
const firstSearchProviderResponse = value[0];
const firstSearchProviderName = firstSearchProviderResponse.provider.name;
const firstSearchResult = firstSearchProviderResponse.results[0];
const firstSearchAction = firstSearchResult.actions[0];
await searchTopic.dispatch(firstSearchProviderName, firstSearchResult, firstSearchAction); // Omitting will default to first action in `result.actions`.
// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { create } from "@openfin/search-api";
const searchTopic = await create({ topic: "foo" });
// Only hosts in the list can subscribe to the search topic.
const allowedHosts = ["www.vendor.com"];
searchTopic.onSubscription(identity => {
// Get the URL of the subscribing identity.
const info = await fin.View.wrapSync(identity).getInfo();
const url = new URL(info.url);
return allowedHosts.includes(url.host);
});
// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { create } from '@openfin/search-api';
// Subscribe or create a search topic.
const searchTopic = await create({ topic: 'foo' });
// Returns a list of provider info objects.
const info = await searchTopic.getAllProviderInfo();
for (let provider of info) {
console.log(`Provider Name: ${provider.name}, Openfin Identity: ${provider.identity}`);
}
// It is recommended to bundle and import search API functions.
// However, the global `fin.Search` namespace can be used as an alternative.
import { create } from '@openfin/search-api';
// Subscribe or create a search topic.
const searchTopic = await create({ topic: 'foo' });
// Only searches against providers in the provider name list.
searchTopic.searchProviders(['Provider Name 1', 'Provider Name 2'], 'bar');
For simple use cases, the Search Extension allows search providers to register an async handler function that returns a set of search results. Internally the Search Extension uses a pull architecture, allowing the search requester to pull in an initial set of results from all search providers listening in on a search topic.
// A simple search handler that returns an initial set of search results.
async function getSearchResults({ query }) {
const res = await fetch('/search?q=' + encodeURIComponent(query));
if (!res.ok) {
throw new Error('uh oh something went wrong');
}
const json = await res.json();
// These results will be pulled in by the search requester.
return json.map((myResult) => ({
name: myResult.nameAttribute,
shortDescription: myResult.shortDescriptionAttribute,
description: myResult.descriptionAttribute,
actions: [openWindowAction],
data: myResult.customMetadata
}));
}
For a more complex use case, like a long running query, it might be desired to push new or updated search results to the search requester after a long period of time. For said use case, you can use the search listener response object as highlighted in the example below.
/* An advanced search handler that pushes new or updated search results
as long as the search request has not been closed. */
async function getSearchResults(request, response) {
/* ID of the search request.
Can be used to tie related search providers together. */
const id = request.id;
// The search query.
const query = request.query;
/* ▼ PUSH ARCHITECTURE ▼ */
/* Open the response stream, notifying the search requester that
there are new or updated search results that have yet to be pushed
by the current provider. */
response.open();
const myLongRunningQuery = makeMyLongRunningQuery(query);
// On new or updated search results push them to the search requester.
const onNewResults = (myResults) => {
// Map the new results.
const newResults = myResults.map((myResult) => ({
key: myResult.keyAttribute,
name: myResult.nameAttribute,
shortDescription: myResult.shortDescriptionAttribute,
description: myResult.descriptionAttribute,
actions: [openWindowAction],
data: myResult.customMetadata
}));
/* Push the new results to the search requester.
If the `key` attribute matches a previously pushed search result,
the old result will be updated with the new result's content. */
response.respond(newResults);
};
myLongRunningQuery.onNewResults(onNewResults);
/* Remove the listener and close the long running query if
the request has been closed by the search requester. */
request.onClose(() => {
myLongRunningQuery.close();
});
/**
* Upon query completion, close the response. This notifies
* the requester that the current search provider is done sending results.
*/
myLongRunningQuery.onQueryDone(() => {
response.close();
});
}
FAQs
A search API framework for OpenFin.
The npm package @openfin/search-api receives a total of 1,299 weekly downloads. As such, @openfin/search-api popularity was classified as popular.
We found that @openfin/search-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 60 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Socket researchers uncover how threat actors weaponize Discord across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.
Security News
Socket now integrates with Bun 1.3’s Security Scanner API to block risky packages at install time and enforce your organization’s policies in local dev and CI.
Research
The Socket Threat Research Team is tracking weekly intrusions into the npm registry that follow a repeatable adversarial playbook used by North Korean state-sponsored actors.