Skip to content

Instantly share code, notes, and snippets.

@usrbowe
Last active January 10, 2023 16:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save usrbowe/f45c93384e57ea35054b0e7d41ee2557 to your computer and use it in GitHub Desktop.
Save usrbowe/f45c93384e57ea35054b0e7d41ee2557 to your computer and use it in GitHub Desktop.
Flipper Marketplace - server

Flipper Marketplace

Used by the marketplace feature of Flipper: facebook/flipper#3491

This code needs a few changes to make it work, depending on the NPM server used. npmAdapter is written for verdaccio.co.

Usage

  1. Start server yarn && yarn start
  2. Enable marketplace in Flipper settings & set Martkeplace URL to http://localhost:4004/flipper-plugins
import express from 'express';
import cache from 'route-cache';
import { getAllPlugins } from './npmAdapter.js';
const indexServer = express();
const port = process.env['PORT'] || 4004;
const pluginsRouteCache = 600; // 10 minutes
/**
* List plugins
*
* Cache: Allow cache to lower the ammount of requests sent to npmAdapter.
* Each Flipper app will periodically request for plugins, so the more clients we need to serve
* the more requests need to be processed and handled by the npm server.
* This will also speed up the response, since it will be served mostly from cache.
*
*/
indexServer.get('/flipper-plugins', cache.cacheSeconds(pluginsRouteCache), async (req, res) => {
const plugins = await getAllPlugins();
res.format({
'application/json': () => {
res.send(plugins)
}
})
})
indexServer.listen(port, () => {
console.log(`Flipper index server listening on port ${port}`)
})
import fetch from 'node-fetch';
// FIXME: Can be replaced by API search query, but verdaccio does not provide stable full-text search.
import internalPlugins from './pluginsList.js';
// NPM server URL
const NPM_PACKAGE_DETAIL_URL = 'https://npm.verdaccio.io';
export async function getAllPlugins() {
try {
const plugins = await Promise.all(internalPlugins.map(async pluginName => {
const response = await fetch(`${NPM_PACKAGE_DETAIL_URL}/${pluginName}`);
const pluginDetail = await response.json();
return pluginDetail;
}));
// Some unpublished plugins will return error message (maybe can log those for debug)
const filterErrorPlugins = plugins.filter(plugin => !plugin.error);
// Remap the verdaccio package structure to flipper
const flipperPlugins = filterErrorPlugins.map(plugin => ({
...plugin,
// spread the package.json of latest package
...plugin.versions[plugin['dist-tags']?.latest],
downloadUrl: plugin.versions[plugin['dist-tags']?.latest].dist.tarball,
availableVersions: Object.values(plugin.versions).map(plugin => ({
...plugin,
downloadUrl: plugin.dist.tarball,
})),
// Provide defaults
isActivatable: false,
isBundled: false,
isEnabledByDefault: false,
}))
return flipperPlugins;
} catch(e) {
console.error('Retrieving packages failed', e);
return [];
}
}
{
"name": "flipper-marketplace",
"version": "1.0.0",
"description": "Flipper plugins index server to make internal plugins discoverable",
"main": "index.js",
"scripts": {
"start": "node src/index.js"
},
"dependencies": {
"express": "^4.17.3",
"node-fetch": "^3.2.0",
"route-cache": "^0.4.7"
},
"type": "module"
}
/**
* List of all internal plugins published on: npm.verdaccio.io
*
* The motivation behind static config is that verdaccio search API does not index
* all plugins reliably, so we don't have 100% guarantee all plugins will be returned.
*/
const list = [
'flipper-plugin-xxx',
'flipper-plugin-xxx-2'
]
export default list;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment