@scott-the-programmer/backstage-plugin-spacelift-backend
Version:
[](https://codeclimate.com/github/scott-the-programmer/backstage-plugin-spacelift/maintainability)
202 lines (193 loc) • 5.61 kB
JavaScript
;
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