@saishnarvekar/plugin-elastic-devtool-backend 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2026 Saish Narvekar
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ developing the plugin backend itself.
2
+
3
+ # Elastic Dev Tool Plugin for Backstage (Backend)
4
+
5
+ ![Backstage Logo](https://backstage.io/img/logo.svg)
6
+
7
+ > [!TIP]
8
+ > Backend API for Elasticsearch management and query in Backstage.
9
+
10
+ ---
11
+
12
+ ## Overview
13
+
14
+ `@saishnarvekar/plugin-elastic-devtool-backend` provides the backend API and service layer for the Elastic Dev Tool plugin, enabling secure, robust Elasticsearch operations from your Backstage instance.
15
+
16
+ ---
17
+
18
+ ## Features
19
+
20
+ - REST API for Elasticsearch query and index management
21
+ - Secure proxy to your Elasticsearch cluster
22
+ - Cluster health and stats endpoints
23
+ - Built with Backstage backend best practices
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ Add the backend plugin to your Backstage backend:
30
+
31
+ ```bash
32
+ yarn --cwd packages/backend add @saishnarvekar/plugin-elastic-devtool-backend
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Usage
38
+
39
+ Register the plugin in your backend (e.g. in `packages/backend/src/index.ts`):
40
+
41
+ ```ts
42
+ import { elasticDevToolPlugin } from '@saishnarvekar/plugin-elastic-devtool-backend';
43
+
44
+ const backend = createBackend();
45
+ // ...existing code...
46
+ backend.add(elasticDevToolPlugin());
47
+ ```
48
+
49
+ Configure your Elasticsearch connection in `app-config.yaml`:
50
+
51
+ ```yaml
52
+ elastic:
53
+ baseUrl: 'http://localhost:9200'
54
+ username: 'elastic' # optional
55
+ password: 'password' # optional
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Development
61
+
62
+ To run the backend plugin in isolation for development:
63
+
64
+ ```bash
65
+ yarn start
66
+ ```
67
+
68
+ This will launch a local backend server for rapid development and testing.
69
+
70
+ ---
71
+
72
+ ## Resources
73
+
74
+ - [Backstage Backend Plugins](https://backstage.io/docs/backend-system/)
75
+ - [Elasticsearch Node.js Client](https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/)
76
+ - [Backstage Plugin Authoring](https://backstage.io/docs/plugins/)
77
+
78
+ ---
79
+
80
+ > [!IMPORTANT]
81
+ > Use together with [`@saishnarvekar/plugin-elastic-devtool`](../elastic-devtool/) for a complete frontend + backend solution.
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var plugin = require('./plugin.cjs.js');
6
+
7
+
8
+
9
+ exports.default = plugin.elasticDevtoolPlugin;
10
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -0,0 +1,10 @@
1
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
+
3
+ /**
4
+ * elasticDevtoolPlugin backend plugin
5
+ *
6
+ * @public
7
+ */
8
+ declare const elasticDevtoolPlugin: _backstage_backend_plugin_api.BackendFeature;
9
+
10
+ export { elasticDevtoolPlugin as default };
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var backendPluginApi = require('@backstage/backend-plugin-api');
4
+ var router = require('./router.cjs.js');
5
+
6
+ const elasticDevtoolPlugin = backendPluginApi.createBackendPlugin({
7
+ pluginId: "elastic-devtool",
8
+ register(env) {
9
+ env.registerInit({
10
+ deps: {
11
+ httpRouter: backendPluginApi.coreServices.httpRouter,
12
+ config: backendPluginApi.coreServices.rootConfig
13
+ },
14
+ async init({ httpRouter, config }) {
15
+ httpRouter.use(
16
+ await router.createRouter({ config })
17
+ );
18
+ httpRouter.addAuthPolicy({
19
+ path: "/health",
20
+ allow: "unauthenticated"
21
+ });
22
+ }
23
+ });
24
+ }
25
+ });
26
+
27
+ exports.elasticDevtoolPlugin = elasticDevtoolPlugin;
28
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './router';\n\n/**\n * elasticDevtoolPlugin backend plugin\n *\n * @public\n */\nexport const elasticDevtoolPlugin = createBackendPlugin({\n pluginId: 'elastic-devtool',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n config: coreServices.rootConfig,\n },\n async init({ httpRouter, config }) {\n httpRouter.use(\n await createRouter({ config }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","createRouter"],"mappings":";;;;;AAWO,MAAM,uBAAuBA,oCAAA,CAAoB;AAAA,EACtD,QAAA,EAAU,iBAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,YAAYC,6BAAA,CAAa,UAAA;AAAA,QACzB,QAAQA,6BAAA,CAAa;AAAA,OACvB;AAAA,MACA,MAAM,IAAA,CAAK,EAAE,UAAA,EAAY,QAAO,EAAG;AACjC,QAAA,UAAA,CAAW,GAAA;AAAA,UACT,MAAMC,mBAAA,CAAa,EAAE,MAAA,EAAQ;AAAA,SAC/B;AACA,QAAA,UAAA,CAAW,aAAA,CAAc;AAAA,UACvB,IAAA,EAAM,SAAA;AAAA,UACN,KAAA,EAAO;AAAA,SACR,CAAA;AAAA,MACH;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ var express = require('express');
4
+ var Router = require('express-promise-router');
5
+ var elasticsearch = require('@elastic/elasticsearch');
6
+
7
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
8
+
9
+ var express__default = /*#__PURE__*/_interopDefaultCompat(express);
10
+ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
11
+
12
+ async function createRouter(options) {
13
+ const router = Router__default.default();
14
+ router.use(express__default.default.json());
15
+ const esNode = options.config.getString("elastic-devtool.elasticsearch.node");
16
+ const esUsername = options.config.getString("elastic-devtool.elasticsearch.username");
17
+ const esPassword = options.config.getString("elastic-devtool.elasticsearch.password");
18
+ const esClient = new elasticsearch.Client({
19
+ node: esNode,
20
+ auth: {
21
+ username: esUsername,
22
+ password: esPassword
23
+ },
24
+ tls: {
25
+ rejectUnauthorized: false
26
+ }
27
+ });
28
+ router.get("/health", async (_, res) => {
29
+ res.json({ status: "ok" });
30
+ });
31
+ router.get("/indices", async (_, res) => {
32
+ try {
33
+ const result = await esClient.cat.indices({ format: "json" });
34
+ const names = result.map((r) => r.index);
35
+ res.json(names);
36
+ } catch (error) {
37
+ res.status(500).json({ error: String(error) });
38
+ }
39
+ });
40
+ router.post("/search", async (req, res) => {
41
+ const body = req.body;
42
+ console.info("Received ES query", { body });
43
+ try {
44
+ const result = await esClient.search(body);
45
+ res.json(result);
46
+ } catch (error) {
47
+ console.error("ES query failed", { error });
48
+ res.status(500).json({ error: String(error) });
49
+ }
50
+ });
51
+ return router;
52
+ }
53
+
54
+ exports.createRouter = createRouter;
55
+ //# sourceMappingURL=router.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.cjs.js","sources":["../src/router.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport { Client } from '@elastic/elasticsearch';\n\nexport async function createRouter(options: {config: any}): Promise<express.Router> {\n const router = Router();\n router.use(express.json());\n\n const esNode = options.config.getString(\"elastic-devtool.elasticsearch.node\");\n const esUsername = options.config.getString(\"elastic-devtool.elasticsearch.username\");\n const esPassword = options.config.getString(\"elastic-devtool.elasticsearch.password\");\n \n const esClient = new Client({\n node: esNode,\n auth: {\n username: esUsername,\n password: esPassword,\n },\n tls: {\n rejectUnauthorized: false,\n },\n });\n\n router.get('/health', async (_, res) => {\n res.json({ status: 'ok' });\n });\n\n router.get('/indices', async (_, res) => {\n try {\n const result = await esClient.cat.indices({ format: 'json' });\n const names = result.map(r => r.index);\n res.json(names);\n } catch (error) {\n res.status(500).json({ error: String(error) });\n }\n });\n\n router.post('/search', async (req, res) => {\n const body = req.body;\n console.info('Received ES query', { body });\n try {\n const result = await esClient.search(body);\n res.json(result);\n } catch (error) {\n console.error('ES query failed', { error });\n res.status(500).json({ error: String(error) });\n }\n });\n return router;\n}\n"],"names":["Router","express","Client"],"mappings":";;;;;;;;;;;AAIA,eAAsB,aAAa,OAAA,EAAiD;AAClF,EAAA,MAAM,SAASA,uBAAA,EAAO;AACtB,EAAA,MAAA,CAAO,GAAA,CAAIC,wBAAA,CAAQ,IAAA,EAAM,CAAA;AAEzB,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,oCAAoC,CAAA;AAC5E,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,wCAAwC,CAAA;AACpF,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,wCAAwC,CAAA;AAEpF,EAAA,MAAM,QAAA,GAAW,IAAIC,oBAAA,CAAO;AAAA,IAC1B,IAAA,EAAM,MAAA;AAAA,IACN,IAAA,EAAM;AAAA,MACJ,QAAA,EAAU,UAAA;AAAA,MACV,QAAA,EAAU;AAAA,KACZ;AAAA,IACA,GAAA,EAAK;AAAA,MACH,kBAAA,EAAoB;AAAA;AACtB,GACD,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,OAAO,CAAA,EAAG,GAAA,KAAQ;AACtC,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,CAAA;AAAA,EAC3B,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,OAAO,CAAA,EAAG,GAAA,KAAQ;AACvC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,GAAA,CAAI,QAAQ,EAAE,MAAA,EAAQ,QAAQ,CAAA;AAC5D,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,KAAK,CAAA;AACrC,MAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IAChB,SAAS,KAAA,EAAO;AACd,MAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,CAAA;AAAA,IAC/C;AAAA,EACF,CAAC,CAAA;AAED,EAAA,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,OAAO,GAAA,EAAK,GAAA,KAAQ;AACzC,IAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,IAAA,OAAA,CAAQ,IAAA,CAAK,mBAAA,EAAqB,EAAE,IAAA,EAAM,CAAA;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA;AACzC,MAAA,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,IACjB,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,iBAAA,EAAmB,EAAE,KAAA,EAAO,CAAA;AAC1C,MAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,EAAG,CAAA;AAAA,IAC/C;AAAA,EACF,CAAC,CAAA;AACD,EAAA,OAAO,MAAA;AACT;;;;"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@saishnarvekar/plugin-elastic-devtool-backend",
3
+ "version": "0.1.0",
4
+ "license": "Apache-2.0",
5
+ "main": "dist/index.cjs.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.cjs.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "backstage": {
13
+ "role": "backend-plugin",
14
+ "pluginId": "elastic-devtool",
15
+ "pluginPackages": [
16
+ "@saishnarvekar/plugin-elastic-devtool",
17
+ "@saishnarvekar/plugin-elastic-devtool-backend"
18
+ ],
19
+ "features": {
20
+ ".": "@backstage/BackendFeature"
21
+ }
22
+ },
23
+ "scripts": {
24
+ "start": "backstage-cli package start",
25
+ "build": "backstage-cli package build",
26
+ "lint": "backstage-cli package lint",
27
+ "test": "backstage-cli package test",
28
+ "clean": "backstage-cli package clean",
29
+ "prepack": "backstage-cli package prepack",
30
+ "postpack": "backstage-cli package postpack"
31
+ },
32
+ "dependencies": {
33
+ "@backstage/backend-defaults": "^0.13.0",
34
+ "@backstage/backend-plugin-api": "^1.4.4",
35
+ "@backstage/catalog-client": "^1.12.0",
36
+ "@backstage/errors": "^1.2.7",
37
+ "@backstage/plugin-catalog-node": "^1.19.1",
38
+ "@backstage/types": "^1.2.2",
39
+ "@elastic/elasticsearch": "^9.2.0",
40
+ "express": "^4.17.1",
41
+ "express-promise-router": "^4.1.0",
42
+ "zod": "^3.22.4"
43
+ },
44
+ "devDependencies": {
45
+ "@backstage/backend-test-utils": "^1.9.1",
46
+ "@backstage/cli": "^0.34.4",
47
+ "@types/express": "^4.17.6",
48
+ "@types/supertest": "^2.0.12",
49
+ "supertest": "^6.2.4"
50
+ },
51
+ "files": [
52
+ "dist"
53
+ ],
54
+ "typesVersions": {
55
+ "*": {
56
+ "package.json": [
57
+ "package.json"
58
+ ]
59
+ }
60
+ }
61
+ }