UNPKG

@scott-the-programmer/backstage-plugin-spacelift-backend

Version:

[![Maintainability](https://api.codeclimate.com/v1/badges/65206b49b30dfc4e2312/maintainability)](https://codeclimate.com/github/scott-the-programmer/backstage-plugin-spacelift/maintainability)

202 lines (193 loc) 5.61 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var express = require('express'); var fetch = require('node-fetch'); var graphqlRequest = require('graphql-request'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); class SpaceliftApiClient { constructor(org, clientId, clientSecret) { this.apiUrl = `https://${org}.app.spacelift.io`; this.clientId = clientId; this.clientSecret = clientSecret; } async getSpaceliftToken() { const getSpaceliftTokenMutation = graphqlRequest.gql` mutation GetSpaceliftToken($keyId: ID!, $keySecret: String!) { apiKeyUser(id: $keyId, secret: $keySecret) { id jwt } } `; const variables = { keyId: this.clientId, keySecret: this.clientSecret }; try { const response = await graphqlRequest.request( `${this.apiUrl}/graphql`, getSpaceliftTokenMutation, variables ); return response.apiKeyUser.jwt; } catch (error) { console.error("Error fetching JWT:", error); throw error; } } async getApiToken() { if (!this.apiToken || this.isTokenExpired(this.apiToken)) { this.apiToken = await this.getSpaceliftToken(); } return this.apiToken; } async setApiToken(token) { this.apiToken = token; } isTokenExpired(token) { try { const decoded = this.decodeSpaceliftToken(token); if (decoded) { const currentTimestamp = Math.floor(Date.now() / 1e3); return currentTimestamp >= decoded.exp; } return false; } catch (error) { console.error("Error decoding JWT:", error); throw error; } } // Spacelift signs their token against a self-signed certificate, // so we can't verify the integrity. Instead, let's just decode the payload // and check the expiration date ourselves. decodeSpaceliftToken(token) { try { const payloadBase64Url = token.split(".")[1]; const payloadBase64 = payloadBase64Url.replace(/-/g, "+").replace(/_/g, "/"); const payloadJson = Buffer.from(payloadBase64, "base64").toString("utf8"); const claims = JSON.parse(payloadJson); return claims; } catch (error) { console.error("Error decoding JWT payload:", error); return null; } } async fetchRuns(stackId) { const apiToken = await this.getApiToken(); const response = await fetch__default["default"](`${this.apiUrl}/graphql`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiToken}` }, body: JSON.stringify({ query: ` { stack(id: "${stackId}") { id runs { id, branch, state, createdAt, commit { url, authorName, timestamp, hash } } } } ` }) }); const { data } = await response.json(); return data.stack.runs; } async fetchStacks() { const apiToken = await this.getApiToken(); const response = await fetch__default["default"](`${this.apiUrl}/graphql`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiToken}` }, body: JSON.stringify({ query: ` { stacks { id name, description, apiHost, branch, repository, projectRoot, namespace, space, state, } } ` }) }); const { data } = await response.json(); return data.stacks; } getSpaceliftUrl() { const url = { url: this.apiUrl }; return url; } } function createSpaceliftRouter(config) { const router = express.Router(); const spaceliftClient = new SpaceliftApiClient( config.getOptionalString("spacelift.org") || process.env.SPACELIFT_ORG, config.getOptionalString("spacelift.id") || process.env.SPACELIFT_ID, config.getOptionalString("spacelift.secret") || process.env.SPACELIFT_SECRET ); router.get("/projects", async (_, res) => { try { const projects = await spaceliftClient.fetchStacks(); res.send(projects); } catch (error) { console.log(error); res.status(500).send({ error: "Error fetching projects" }); } }); router.get("/url", (_, res) => { try { const projects = spaceliftClient.getSpaceliftUrl(); res.send(projects); } catch (error) { console.log(error); res.status(500).send({ error: "Error retrieving spacelift url" }); } }); router.get("/runs/:stackId", async (req, res) => { const { stackId } = req.params; try { const projects = await spaceliftClient.fetchRuns(stackId); res.send(projects); } catch (error) { console.log(error); res.status(500).send({ error: "Error retrieving spacelift url" }); } }); return router; } async function createRouter(env) { const router = express.Router(); const spaceliftRouter = await createSpaceliftRouter(env.config); router.use("/", spaceliftRouter); return router; } exports.createRouter = createRouter; //# sourceMappingURL=index.cjs.js.map