Finish webhooks management POC
This commit is contained in:
parent
7efa970079
commit
bd757776f2
6 changed files with 293 additions and 0 deletions
|
@ -8,6 +8,7 @@ import { hideBin } from "yargs/helpers";
|
||||||
import { installAppCommand } from "./commands/install-app-command";
|
import { installAppCommand } from "./commands/install-app-command";
|
||||||
import { uninstallAppCommand } from "./commands/uninstall-app-command";
|
import { uninstallAppCommand } from "./commands/uninstall-app-command";
|
||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
|
import { webhooksCommand } from "./commands/webhooks-command";
|
||||||
|
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
const pkg = require("../package.json");
|
const pkg = require("../package.json");
|
||||||
|
@ -117,6 +118,35 @@ const parser = yargs(hideBin(process.argv))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.command(
|
||||||
|
"webhooks",
|
||||||
|
"Print webhook details of installed app.",
|
||||||
|
(yargs) => {
|
||||||
|
return yargs
|
||||||
|
.option("instanceUrl", {
|
||||||
|
type: "string",
|
||||||
|
desc: "URL to the Saleor GraphQL API. Example: https://example.com/graphql/",
|
||||||
|
demandOption: true,
|
||||||
|
})
|
||||||
|
.option("userEmail", {
|
||||||
|
type: "string",
|
||||||
|
desc: "Dashboard user email",
|
||||||
|
demandOption: true,
|
||||||
|
})
|
||||||
|
.option("userPassword", {
|
||||||
|
type: "string",
|
||||||
|
desc: "Dashboard user password",
|
||||||
|
demandOption: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(argv) => {
|
||||||
|
webhooksCommand({
|
||||||
|
instanceUrl: argv.instanceUrl,
|
||||||
|
userEmail: argv.userEmail,
|
||||||
|
userPassword: argv.userPassword,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
.demandCommand(1, "You need at least one command before moving on")
|
.demandCommand(1, "You need at least one command before moving on")
|
||||||
.alias("h", "help")
|
.alias("h", "help")
|
||||||
.wrap(null);
|
.wrap(null);
|
||||||
|
|
|
@ -50,6 +50,11 @@ export const uninstallAppCommand = async ({
|
||||||
|
|
||||||
appListSpinner.succeed();
|
appListSpinner.succeed();
|
||||||
|
|
||||||
|
if (!installedApps.length) {
|
||||||
|
console.log("No apps installed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Display CLI interface with multiselect if none of the filters were provided
|
// Display CLI interface with multiselect if none of the filters were provided
|
||||||
if (appId || appName || manifestUrl) {
|
if (appId || appName || manifestUrl) {
|
||||||
const filteredApps = filterApps({
|
const filteredApps = filterApps({
|
||||||
|
|
120
apps/apps-cli/src/commands/webhooks-command.ts
Normal file
120
apps/apps-cli/src/commands/webhooks-command.ts
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import ora from "ora";
|
||||||
|
import { getAccessTokenMutation } from "../saleor-api/operations/get-access-token-mutation";
|
||||||
|
import { getAppsListQuery } from "../saleor-api/operations/get-apps-list-query";
|
||||||
|
import { select } from "@inquirer/prompts";
|
||||||
|
import { getAppWebhooksQuery } from "../saleor-api/operations/get-app-webhooks-query";
|
||||||
|
import { removeWebhookMutation } from "../saleor-api/operations/remove-webhook-mutation";
|
||||||
|
|
||||||
|
interface DumpMetadataCommandArgs {
|
||||||
|
instanceUrl: string;
|
||||||
|
userEmail: string;
|
||||||
|
userPassword: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const webhooksCommand = async ({
|
||||||
|
instanceUrl,
|
||||||
|
userEmail,
|
||||||
|
userPassword,
|
||||||
|
}: DumpMetadataCommandArgs) => {
|
||||||
|
const loginSpinner = ora("Logging into Saleor instance").start();
|
||||||
|
|
||||||
|
const token = await getAccessTokenMutation({
|
||||||
|
email: userEmail,
|
||||||
|
password: userPassword,
|
||||||
|
saleorApiUrl: instanceUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
loginSpinner.succeed();
|
||||||
|
|
||||||
|
const appListSpinner = ora("Fetching installed apps").start();
|
||||||
|
|
||||||
|
const installedApps = await getAppsListQuery({
|
||||||
|
saleorApiUrl: instanceUrl,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
|
||||||
|
appListSpinner.succeed();
|
||||||
|
|
||||||
|
if (!installedApps.length) {
|
||||||
|
console.log("No apps installed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const appId = await select({
|
||||||
|
message: "Select app",
|
||||||
|
choices: installedApps.map((app) => ({
|
||||||
|
name: app.name ? `${app.name} (${app.id})` : app.id,
|
||||||
|
value: app.id,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
const webhooksData = await getAppWebhooksQuery({
|
||||||
|
appId,
|
||||||
|
saleorApiUrl: instanceUrl,
|
||||||
|
token,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!webhooksData.length) {
|
||||||
|
console.log("Application has no webhooks configured");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const webhook = await select({
|
||||||
|
message: "Select webhook to investigate",
|
||||||
|
choices: webhooksData.map((webhook) => ({
|
||||||
|
name: `${webhook.name} (${[...webhook.syncEvents, ...webhook.asyncEvents]
|
||||||
|
.map((e) => e.name)
|
||||||
|
.join(", ")})`,
|
||||||
|
value: webhook,
|
||||||
|
description: `
|
||||||
|
Target url: ${webhook.targetUrl}
|
||||||
|
Active: ${webhook.isActive}
|
||||||
|
Captured event deliveries count: ${webhook.eventDeliveries?.edges.length}
|
||||||
|
`,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
const operation = await select({
|
||||||
|
message: "Operation",
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: "List event deliveries",
|
||||||
|
value: "list",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Remove webhook",
|
||||||
|
value: "remove",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (operation === "list") {
|
||||||
|
console.log("Number of entries: ", webhook.eventDeliveries?.edges.length);
|
||||||
|
for (const deliveryEdge of webhook.eventDeliveries?.edges ?? []) {
|
||||||
|
const delivery = deliveryEdge.node;
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
Event type: ${delivery.eventType}
|
||||||
|
Created at: ${delivery.createdAt}
|
||||||
|
Status: ${delivery.status}`);
|
||||||
|
const attempts = delivery.attempts?.edges ?? [];
|
||||||
|
const lastAttempt = attempts[attempts.length - 1]?.node;
|
||||||
|
|
||||||
|
if (lastAttempt) {
|
||||||
|
console.log(`
|
||||||
|
Date of the last attempt: ${lastAttempt.createdAt}
|
||||||
|
Status: ${lastAttempt.status}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (operation === "remove") {
|
||||||
|
const removeSpinner = ora("Removing webhook...").start();
|
||||||
|
|
||||||
|
await removeWebhookMutation({
|
||||||
|
saleorApiUrl: instanceUrl,
|
||||||
|
token,
|
||||||
|
webhookId: webhook.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
removeSpinner.succeed();
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,31 @@
|
||||||
|
import request from "graphql-request";
|
||||||
|
|
||||||
|
import { graphql } from "../generated/gql";
|
||||||
|
|
||||||
|
const getAppMetadataQueryDocument = graphql(/* GraphQL */ `
|
||||||
|
query GetAppMetadata {
|
||||||
|
app(id: "QXBwOjE=") {
|
||||||
|
metadata {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
export const getAppMetadataQuery = async ({
|
||||||
|
saleorApiUrl,
|
||||||
|
token,
|
||||||
|
}: {
|
||||||
|
saleorApiUrl: string;
|
||||||
|
token: string;
|
||||||
|
}) => {
|
||||||
|
const { app } = await request(
|
||||||
|
saleorApiUrl,
|
||||||
|
getAppMetadataQueryDocument,
|
||||||
|
{},
|
||||||
|
{ "Authorization-Bearer": token }
|
||||||
|
);
|
||||||
|
|
||||||
|
return app?.metadata ?? [];
|
||||||
|
};
|
|
@ -0,0 +1,67 @@
|
||||||
|
import request from "graphql-request";
|
||||||
|
|
||||||
|
import { graphql } from "../generated/gql";
|
||||||
|
|
||||||
|
const getAppWebhooksQueryDocument = graphql(/* GraphQL */ `
|
||||||
|
query GetAppWebhooks($id: ID!) {
|
||||||
|
app(id: $id) {
|
||||||
|
webhooks {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
isActive
|
||||||
|
syncEvents {
|
||||||
|
name
|
||||||
|
eventType
|
||||||
|
}
|
||||||
|
asyncEvents {
|
||||||
|
name
|
||||||
|
eventType
|
||||||
|
}
|
||||||
|
targetUrl
|
||||||
|
eventDeliveries(first: 10) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
status
|
||||||
|
eventType
|
||||||
|
attempts(first: 10) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
taskId
|
||||||
|
duration
|
||||||
|
response
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
export const getAppWebhooksQuery = async ({
|
||||||
|
saleorApiUrl,
|
||||||
|
token,
|
||||||
|
appId,
|
||||||
|
}: {
|
||||||
|
saleorApiUrl: string;
|
||||||
|
token: string;
|
||||||
|
appId: string;
|
||||||
|
}) => {
|
||||||
|
const { app } = await request(
|
||||||
|
saleorApiUrl,
|
||||||
|
getAppWebhooksQueryDocument,
|
||||||
|
{
|
||||||
|
id: appId,
|
||||||
|
},
|
||||||
|
{ "Authorization-Bearer": token }
|
||||||
|
);
|
||||||
|
|
||||||
|
return app?.webhooks ?? [];
|
||||||
|
};
|
|
@ -0,0 +1,40 @@
|
||||||
|
import request from "graphql-request";
|
||||||
|
|
||||||
|
import { graphql } from "../generated/gql";
|
||||||
|
|
||||||
|
const removeWebhookMutationDocument = graphql(/* GraphQL */ `
|
||||||
|
mutation RemoveWebhook($webhookId: ID!) {
|
||||||
|
webhookDelete(id: $webhookId) {
|
||||||
|
errors {
|
||||||
|
field
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
export const removeWebhookMutation = async ({
|
||||||
|
saleorApiUrl,
|
||||||
|
token,
|
||||||
|
webhookId,
|
||||||
|
}: {
|
||||||
|
saleorApiUrl: string;
|
||||||
|
token: string;
|
||||||
|
webhookId: string;
|
||||||
|
}) => {
|
||||||
|
const { webhookDelete } = await request(
|
||||||
|
saleorApiUrl,
|
||||||
|
removeWebhookMutationDocument,
|
||||||
|
{
|
||||||
|
webhookId,
|
||||||
|
},
|
||||||
|
{ "Authorization-Bearer": token }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (webhookDelete?.errors.length) {
|
||||||
|
console.log("Sth went wrong", webhookDelete.errors);
|
||||||
|
throw new Error(`Remove webhook mutation failed`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
};
|
Loading…
Reference in a new issue