From c6e7af5586581f10409bc48610ad9b91624cbea8 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 18:29:36 +0100 Subject: [PATCH 01/21] chore: test --- .github/workflows/create-chat.yml | 60 ++++++++++++++++++++++++++ package.json | 6 +-- src/types/env.ts | 2 + src/utils/logger.ts | 39 ----------------- src/workflows/README.md | 6 +++ src/workflows/bot.ts | 68 ++++++++++++++++++++++++++++++ src/workflows/create-chat/index.ts | 19 +++++++++ 7 files changed, 157 insertions(+), 43 deletions(-) create mode 100644 .github/workflows/create-chat.yml delete mode 100644 src/utils/logger.ts create mode 100644 src/workflows/README.md create mode 100644 src/workflows/bot.ts create mode 100644 src/workflows/create-chat/index.ts diff --git a/.github/workflows/create-chat.yml b/.github/workflows/create-chat.yml new file mode 100644 index 0000000..2508b7a --- /dev/null +++ b/.github/workflows/create-chat.yml @@ -0,0 +1,60 @@ +name: "create-telegram-chat" + +on: + repository_dispatch: + types: [create-telegram-chat] + +jobs: + create-telegram-chat: + name: "Create Telegram Chat" + runs-on: ubuntu-latest + permissions: write-all + env: + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + BOT_MODE: ${{ secrets.BOT_MODE }} + BOT_ADMINS: ${{ secrets.BOT_ADMINS }} + BOT_WEBHOOK: ${{ secrets.BOT_WEBHOOK }} + BOT_WEBHOOK_SECRET: ${{ secrets.BOT_WEBHOOK_SECRET }} + + TELEGRAM_APP_ID: ${{ secrets.TELEGRAM_APP_ID }} + TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} + + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + + LOG_LEVEL: ${{ secrets.LOG_LEVEL }} + DEBUG: ${{ secrets.DEBUG }} + SERVER_HOST: ${{ secrets.SERVER_HOST }} + SERVER_PORT: ${{ secrets.SERVER_PORT }} + + steps: + - uses: actions/checkout@v4 + + - name: setup node + uses: actions/setup-node@v4 + with: + node-version: "20.10.0" + + - name: install dependencies + run: yarn + + - name: execute directive + run: npx tsx ./src/workflows/create-chat/index.ts + id: create-telegram-chat + env: + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + BOT_MODE: ${{ secrets.BOT_MODE }} + BOT_ADMINS: ${{ secrets.BOT_ADMINS }} + BOT_WEBHOOK: ${{ secrets.BOT_WEBHOOK }} + BOT_WEBHOOK_SECRET: ${{ secrets.BOT_WEBHOOK_SECRET }} + + TELEGRAM_APP_ID: ${{ secrets.TELEGRAM_APP_ID }} + TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} + + SUPABASE_URL: ${{ secrets.SUPABASE_URL }} + SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + + LOG_LEVEL: ${{ secrets.LOG_LEVEL }} + DEBUG: ${{ secrets.DEBUG }} + SERVER_HOST: ${{ secrets.SERVER_HOST }} + SERVER_PORT: ${{ secrets.SERVER_PORT }} \ No newline at end of file diff --git a/package.json b/package.json index 347beff..ad8d89b 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,7 @@ "worker": "wrangler dev --env dev --port 3000", "dev": "tsc-watch --onSuccess \"tsx ./src/main.ts\"", "start": "tsx ./src/main.ts", - "deploy": "wrangler deploy --minify src/main.ts", - "build": "npx tsx build/esbuild-build.ts", - "serve": "npx tsx build/esbuild-server.ts" + "deploy": "wrangler deploy --minify src/main.ts" }, "keywords": [ "typescript", @@ -111,4 +109,4 @@ ] }, "packageManager": "yarn@1.22.22" -} +} \ No newline at end of file diff --git a/src/types/env.ts b/src/types/env.ts index 1f86fdf..d6164eb 100644 --- a/src/types/env.ts +++ b/src/types/env.ts @@ -29,6 +29,8 @@ export const env = T.Object({ ALLOWED_UPDATES: T.Optional(T.Array(T.KeyOf(allowedUpdates))), SUPABASE_URL: T.String(), SUPABASE_KEY: T.String(), + TELEGRAM_APP_ID: T.Transform(T.Unknown()).Decode((str) => Number(str)).Encode((num) => num.toString()), + TELEGRAM_API_HASH: T.String(), }); /** diff --git a/src/utils/logger.ts b/src/utils/logger.ts deleted file mode 100644 index 8a25fd1..0000000 --- a/src/utils/logger.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { LogReturn, Logs, Metadata } from "@ubiquity-dao/ubiquibot-logger"; - -export class Logger extends Logs { - updateId: number | string; - - constructor(updateId: number | string) { - super("verbose"); - this.updateId = updateId; - } - - storeUpdateId(updateId: number | string): Logger { - this.updateId = updateId; - return this; - } - - debug(log: string, metadata?: Metadata): LogReturn { - return super.debug(`[update_id: ${this.updateId}] ${log}`, metadata); - } - - error(log: string, metadata?: Metadata): LogReturn { - return super.error(`[update_id: ${this.updateId}] ${log}`, metadata); - } - - fatal(log: string, metadata?: Metadata): LogReturn { - return super.fatal(`[update_id: ${this.updateId}] ${log}`, metadata); - } - - info(log: string, metadata?: Metadata): LogReturn { - return super.info(`[update_id: ${this.updateId}] ${log}`, metadata); - } - - ok(log: string, metadata?: Metadata): LogReturn { - return super.ok(`[update_id: ${this.updateId}] ${log}`, metadata); - } - - verbose(log: string, metadata?: Metadata): LogReturn { - return super.verbose(`[update_id: ${this.updateId}] ${log}`, metadata); - } -} \ No newline at end of file diff --git a/src/workflows/README.md b/src/workflows/README.md new file mode 100644 index 0000000..4d5c116 --- /dev/null +++ b/src/workflows/README.md @@ -0,0 +1,6 @@ +These are intended to be an extension of the worker's functionalities due to the restrictions of Cloudflare workers. They are not meant to be a replacement for the worker itself. They are meant to be used in conjunction with the worker. + +The worker should `repository_dispatch` to the workflow to trigger it. The workflow will then run it's logic and return the result to the worker if necessary. + + +... \ No newline at end of file diff --git a/src/workflows/bot.ts b/src/workflows/bot.ts new file mode 100644 index 0000000..ed4daac --- /dev/null +++ b/src/workflows/bot.ts @@ -0,0 +1,68 @@ +import { Context } from '#root/types/context.js'; +import { TelegramClient } from 'telegram'; +import { Api } from 'telegram/tl'; +import { MemorySession } from 'telegram/sessions'; +import { TelegramClientParams } from 'telegram/client/telegramBaseClient'; + +export class MtProtoSingleton { + private static instance: MtProtoSingleton; + private static client: TelegramClient; + private static api: typeof Api; + + private constructor() { } + + static async initialize(env: Context["env"]) { + if (!MtProtoSingleton.instance) { + MtProtoSingleton.instance = new MtProtoSingleton(); + MtProtoSingleton.api = Api; + MtProtoSingleton.client = await mtProtoInit(env, MtProtoSingleton.api); + } + return MtProtoSingleton.instance; + } + + static getInstance(env: Context["env"]) { + if (!MtProtoSingleton.instance) { + return this.initialize(env) + } + return MtProtoSingleton.instance; + } + + getClient() { + return MtProtoSingleton.client; + } + + getApi() { + return MtProtoSingleton.api; + } +} + +async function mtProtoInit(env: Context["env"], api: typeof Api) { + const { TELEGRAM_API_HASH, TELEGRAM_APP_ID, BOT_TOKEN } = env + + if (!TELEGRAM_API_HASH || !TELEGRAM_APP_ID || !BOT_TOKEN) { + throw new Error("Missing required environment variables for Telegram API") + } + + const session = new MemorySession(); + session.save(); + + const clientParams: TelegramClientParams = { + connectionRetries: 5, + } + + const client = new TelegramClient( + session, + TELEGRAM_APP_ID, + TELEGRAM_API_HASH, + clientParams + ); + client.invoke(new api.auth.ImportBotAuthorization({ + apiId: TELEGRAM_APP_ID, + apiHash: TELEGRAM_API_HASH, + botAuthToken: BOT_TOKEN, + })); + + await client.connect(); + + return client; +} \ No newline at end of file diff --git a/src/workflows/create-chat/index.ts b/src/workflows/create-chat/index.ts new file mode 100644 index 0000000..266fffb --- /dev/null +++ b/src/workflows/create-chat/index.ts @@ -0,0 +1,19 @@ +import { Context } from "#root/types/context"; +import { MtProtoSingleton } from "../bot"; + +export async function createChat(env: Context["env"], chatName: string) { + const mtProto = await MtProtoSingleton.getInstance(env); + const client = mtProto.getClient(); + const api = mtProto.getApi(); + console.log("Creating chat with name: ", chatName); + const chat = await client.invoke( + new api.channels.CreateChannel({ + title: chatName, + broadcast: false, + }) + ); + + console.log("Chat created: ", chat); + + return chat; +} From a94a2e33ae53a61ae48d69ae459ca318900fb7ea Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:33:44 +0100 Subject: [PATCH 02/21] chore: workflow functions --- .../README.md | 0 src/{workflows => workflow-functions}/bot.ts | 5 ++++ src/workflow-functions/create-chat.ts | 29 +++++++++++++++++++ src/workflow-functions/index.ts | 5 ++++ src/workflows/create-chat/index.ts | 19 ------------ 5 files changed, 39 insertions(+), 19 deletions(-) rename src/{workflows => workflow-functions}/README.md (100%) rename src/{workflows => workflow-functions}/bot.ts (89%) create mode 100644 src/workflow-functions/create-chat.ts create mode 100644 src/workflow-functions/index.ts delete mode 100644 src/workflows/create-chat/index.ts diff --git a/src/workflows/README.md b/src/workflow-functions/README.md similarity index 100% rename from src/workflows/README.md rename to src/workflow-functions/README.md diff --git a/src/workflows/bot.ts b/src/workflow-functions/bot.ts similarity index 89% rename from src/workflows/bot.ts rename to src/workflow-functions/bot.ts index ed4daac..1ef4593 100644 --- a/src/workflows/bot.ts +++ b/src/workflow-functions/bot.ts @@ -4,6 +4,11 @@ import { Api } from 'telegram/tl'; import { MemorySession } from 'telegram/sessions'; import { TelegramClientParams } from 'telegram/client/telegramBaseClient'; +/** + * This is a different client from the worker instance. This requires a Node + * environment to run and is used to interact with the Telegram API as + * opposed to just the Bot API that the worker instance uses. + */ export class MtProtoSingleton { private static instance: MtProtoSingleton; private static client: TelegramClient; diff --git a/src/workflow-functions/create-chat.ts b/src/workflow-functions/create-chat.ts new file mode 100644 index 0000000..fd25d82 --- /dev/null +++ b/src/workflow-functions/create-chat.ts @@ -0,0 +1,29 @@ +import { Context, SupportedEvents } from "#root/types/context"; +import { CallbackResult } from "#root/types/proxy.js"; +import { MtProtoSingleton } from "./bot"; + +export async function createChat(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise { + try { + const { payload, env } = context; + const chatName = payload.issue.title; + + const mtProto = await MtProtoSingleton.getInstance(env); + const client = mtProto.getClient(); + const api = mtProto.getApi(); + console.log("Creating chat with name: ", chatName); + const chat = await client.invoke( + new api.channels.CreateChannel({ + title: chatName, + broadcast: false, + }) + ); + + console.log("Chat created: ", chat); + + return { status: 200, reason: "chat_created" }; + } catch (er) { + context.logger.error("Failed to create chat", { er }); + return { status: 500, reason: "chat_creation_failed", content: { error: er } }; + } + +} diff --git a/src/workflow-functions/index.ts b/src/workflow-functions/index.ts new file mode 100644 index 0000000..6e8973d --- /dev/null +++ b/src/workflow-functions/index.ts @@ -0,0 +1,5 @@ +export const WORKFLOW_FUNCTIONS = { + CREATE_CHAT: "create-telegram-chat", +} as const; + +export type WorkflowFunction = typeof WORKFLOW_FUNCTIONS[keyof typeof WORKFLOW_FUNCTIONS]; \ No newline at end of file diff --git a/src/workflows/create-chat/index.ts b/src/workflows/create-chat/index.ts deleted file mode 100644 index 266fffb..0000000 --- a/src/workflows/create-chat/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Context } from "#root/types/context"; -import { MtProtoSingleton } from "../bot"; - -export async function createChat(env: Context["env"], chatName: string) { - const mtProto = await MtProtoSingleton.getInstance(env); - const client = mtProto.getClient(); - const api = mtProto.getApi(); - console.log("Creating chat with name: ", chatName); - const chat = await client.invoke( - new api.channels.CreateChannel({ - title: chatName, - broadcast: false, - }) - ); - - console.log("Chat created: ", chat); - - return chat; -} From 36124fa774a4aefe1b1bf63c90f73c262bb2b0b5 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:35:37 +0100 Subject: [PATCH 03/21] chore: typeguards and error helpers --- src/plugin.ts | 22 +++------------------- src/types/typeguards.ts | 10 ++++++++++ src/utils/errors.ts | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/plugin.ts b/src/plugin.ts index 7f84716..e858f2d 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -2,32 +2,16 @@ import { Env, PluginInputs } from "./types"; import { Context } from "./types"; import { PluginContext } from "./utils/plugin-context-single"; import { proxyCallbacks } from "./handlers/callbacks-proxy"; -import { LogReturn } from "@ubiquity-dao/ubiquibot-logger"; -import { addCommentToIssue } from "./handlers/github/utils/add-comment-to-issues"; +import { bubbleUpErrorComment, sanitizeMetadata } from "./utils/errors"; export async function runPlugin(context: Context) { - const { logger, eventName } = context; + const { eventName } = context; try { return proxyCallbacks(context)[eventName] } catch (err) { - let errorMessage; - if (err instanceof LogReturn) { - errorMessage = err; - } else if (err instanceof Error) { - errorMessage = context.logger.error(err.message, { error: err }); - } else { - errorMessage = context.logger.error("An error occurred", { err }); - } - await addCommentToIssue(context, `${errorMessage?.logMessage.diff}\n`); + return bubbleUpErrorComment(context, err) } - - logger.error(`Unsupported event: ${eventName}`); -} - - -function sanitizeMetadata(obj: LogReturn["metadata"]): string { - return JSON.stringify(obj, null, 2).replace(//g, ">").replace(/--/g, "--"); } /** diff --git a/src/types/typeguards.ts b/src/types/typeguards.ts index d25d056..84c1a9d 100644 --- a/src/types/typeguards.ts +++ b/src/types/typeguards.ts @@ -1,6 +1,7 @@ import { Update } from "@grammyjs/types"; import { Context } from "./context"; import { PluginInputs } from "./plugin-inputs"; +import { WORKFLOW_FUNCTIONS } from "../workflow-functions"; export function isIssueOpenedEvent(context: Context): context is Context<"issues.opened"> { return context.eventName === "issues.opened"; @@ -21,3 +22,12 @@ export function isGithubPayload(inputs: any): inputs is PluginInputs { return false; } } + + +export function isIssueLabeledEvent(context: Context): context is Context<"issues.labeled"> { + return context.eventName === "issues.labeled"; +} + +export function isWorkflowFunction(event: string): event is keyof typeof WORKFLOW_FUNCTIONS { + return Object.keys(WORKFLOW_FUNCTIONS).includes(event); +} \ No newline at end of file diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 921330e..530f9de 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,6 +1,24 @@ +import { LogReturn } from "@ubiquity-dao/ubiquibot-logger"; +import { Context } from "../types"; +import { addCommentToIssue } from "#root/handlers/github/utils/add-comment-to-issues.js"; export function handleUncaughtError(error: unknown) { console.error(error); const status = 500; return new Response(JSON.stringify({ error }), { status: status, headers: { "content-type": "application/json" } }); +} +export function sanitizeMetadata(obj: LogReturn["metadata"]): string { + return JSON.stringify(obj, null, 2).replace(//g, ">").replace(/--/g, "--"); +} + +export async function bubbleUpErrorComment(context: Context, err: unknown) { + let errorMessage; + if (err instanceof LogReturn) { + errorMessage = err; + } else if (err instanceof Error) { + errorMessage = context.logger.error(err.message, { error: err }); + } else { + errorMessage = context.logger.error("An error occurred", { err }); + } + await addCommentToIssue(context, `${errorMessage?.logMessage.diff}\n`); } \ No newline at end of file From 43e13ab640502d1e5f71df301a62939c78a0d306 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:36:34 +0100 Subject: [PATCH 04/21] chore: proxy types and new env vars --- src/types/env.ts | 2 ++ src/types/proxy.ts | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/types/proxy.ts diff --git a/src/types/env.ts b/src/types/env.ts index d6164eb..669baee 100644 --- a/src/types/env.ts +++ b/src/types/env.ts @@ -31,6 +31,8 @@ export const env = T.Object({ SUPABASE_KEY: T.String(), TELEGRAM_APP_ID: T.Transform(T.Unknown()).Decode((str) => Number(str)).Encode((num) => num.toString()), TELEGRAM_API_HASH: T.String(), + APP_ID: T.Transform(T.Unknown()).Decode((str) => Number(str)).Encode((num) => num.toString()), + APP_PRIVATE_KEY: T.String(), }); /** diff --git a/src/types/proxy.ts b/src/types/proxy.ts new file mode 100644 index 0000000..c477765 --- /dev/null +++ b/src/types/proxy.ts @@ -0,0 +1,52 @@ +import { WorkflowFunction } from "../workflow-functions"; +import { Context, SupportedEvents, SupportedEventsU } from "./context"; + +export type CallbackResult = { status: 200 | 201 | 204 | 404 | 500, reason: string; content?: string | Record }; + +/** + * The `Context` type is a generic type defined as `Context`, + * where `TEvent` is a string representing the event name (e.g., "issues.labeled") + * and `TPayload` is the webhook payload type for that event, derived from + * the `SupportedEvents` type map. + * + * The `ProxyCallbacks` object is cast to allow optional callbacks + * for each event type. This is useful because not all events may have associated callbacks. + * As opposed to Partial which could mean an undefined object. + * + * The expected function signature for callbacks looks like this: + * + * ```typescript + * fn(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise + * ``` + */ + +type ProxyTypeHelper = { + [K in SupportedEventsU]: Array<(context: Context) => Promise>; +}; +export type ProxyCallbacks = ProxyTypeHelper; + +/** + * Was unable to figure a way to make this work elegantly to avoid having to use + * typeguards in the workflow functions like we have in `ProxyCallbacks`. + * + * Something in the lines of: + * Each callback would define a generic type `T` that would be just that event type as to + * restrict inference in Context to only that webhook although it infers all payloads in + * all of my attempts. + * + * Would be handy as we could avoid having to use typeguards in the workflow functions. + */ +type WorkflowTypeHelper = { + [K in SupportedEventsU]: { + [P in WorkflowFunction]: Array<(context: Context) => Promise>; + } +}; + +/** + * * The expected function signature for callbacks looks like this: + * + * ```typescript + * fn(context: Context): Promise + * ``` + */ +export type WorkflowCallbacks = WorkflowTypeHelper; \ No newline at end of file From d266dfd531040a7ed6ef4be57168157490b7e98a Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:42:55 +0100 Subject: [PATCH 05/21] chore: repo dispatch approach --- src/handlers/callbacks-proxy.ts | 76 ++++++++++++++++++---------- src/handlers/github/workrooms.ts | 31 ++---------- src/handlers/repository-dispatch.ts | 44 ++++++++++++++++ src/helpers/authenticated-octokit.ts | 15 ++++++ src/utils/plugin-context-single.ts | 4 ++ src/workflow-entry.ts | 44 +++++++++------- 6 files changed, 143 insertions(+), 71 deletions(-) create mode 100644 src/handlers/repository-dispatch.ts create mode 100644 src/helpers/authenticated-octokit.ts diff --git a/src/handlers/callbacks-proxy.ts b/src/handlers/callbacks-proxy.ts index 055eb65..c1646c5 100644 --- a/src/handlers/callbacks-proxy.ts +++ b/src/handlers/callbacks-proxy.ts @@ -1,29 +1,8 @@ -import { Context, SupportedEvents, SupportedEventsU } from "../types"; +import { ProxyCallbacks, WorkflowCallbacks } from "#root/types/proxy.js"; +import { Context, SupportedEventsU } from "../types"; +import { createChat } from "../workflow-functions/create-chat"; import { closeWorkroom, createWorkroom, reOpenWorkroom } from "./github/workrooms"; - -export type CallbackResult = { status: 200 | 201 | 204 | 404 | 500, reason: string; content?: string | Record }; - -/** - * The `Context` type is a generic type defined as `Context`, - * where `TEvent` is a string representing the event name (e.g., "issues.labeled") - * and `TPayload` is the webhook payload type for that event, derived from - * the `SupportedEvents` type map. - * - * The `ProxyCallbacks` type is defined using `Partial` to allow - * optional callbacks for each event type. This is useful because not all events - * may have associated callbacks. - * - * The expected function signature for callbacks looks like this: - * - * ```typescript - * fn(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise - * ``` - */ - -type ProxyCallbacks = ProxyTypeHelper; -type ProxyTypeHelper = { - [K in SupportedEventsU]: Array<(context: Context) => Promise>; -}; +import { WorkflowFunction } from "../workflow-functions"; /** * Why do we need this wrapper function? @@ -39,7 +18,6 @@ type ProxyTypeHelper = { function handleCallback(callback: Function, context: Context) { return callback(context); } - /** * The `callbacks` object defines an array of callback functions for each supported event type. * @@ -93,3 +71,49 @@ export function proxyCallbacks(context: Context): ProxyCallbacks { }, }); } + +/** + * These are function which get dispatched by this worker to fire off workflows + * in the repository. We enter through the main `compute.yml` just like a typical + * action plugin would, we forward the same payload that the worker received to + * the workflow the same way that the kernel does. + * + * - First event fires, `issues.labeled` and the worker catches it. + * - The worker then dispatches a workflow to `compute.yml` with the event name as the input. + * - The workflow receives a `issues.labeled` payload but eventName is now WorkflowFunction (`create-telegram-chat`). + * - The workflow then runs the `createChat` function which needs a node env to run. + * + * I.e we're essentially running the first dual action/worker plugin which is + * ideal for telegram-bot as it's a bot that needs to be able to be super flexible. + * + * TODO: Might not need to do specify the workflow function and instead just pass the payload? + */ +const workflowCallbacks = { + "issues.labeled": { + "create-telegram-chat": [ + createChat + ] + } +} as WorkflowCallbacks; + +export function proxyWorkflowCallbacks(context: Context): WorkflowCallbacks { + return new Proxy(workflowCallbacks, { + get(target, prop: WorkflowFunction) { + return (async () => { + try { + return await Promise.all(Object.keys(target).map((event) => { + const eventCallbacks = target[event as SupportedEventsU][prop]; + if (!eventCallbacks) { + context.logger.info(`No callbacks found for event ${event}`); + return { status: 204, reason: "skipped" }; + } + return Promise.all(eventCallbacks.map((callback) => handleCallback(callback, context))); + })); + } catch (er) { + context.logger.error(`Failed to handle event ${prop}`, { er }); + return { status: 500, reason: "failed" }; + } + })(); + }, + }); +} diff --git a/src/handlers/github/workrooms.ts b/src/handlers/github/workrooms.ts index d934e6c..9fff909 100644 --- a/src/handlers/github/workrooms.ts +++ b/src/handlers/github/workrooms.ts @@ -1,7 +1,8 @@ import { Chat } from "#root/adapters/supabase/helpers/chats.js"; +import { CallbackResult } from "#root/types/proxy.js"; import { TelegramBotSingleton } from "#root/utils/telegram-bot-single.js"; import { Context, SupportedEvents } from "../../types"; -import { CallbackResult } from "../callbacks-proxy"; +import { repositoryDispatch } from "../repository-dispatch"; import { addCommentToIssue } from "./utils/add-comment-to-issues"; /** @@ -20,32 +21,8 @@ import { addCommentToIssue } from "./utils/add-comment-to-issues"; */ export async function createWorkroom(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise { - const { logger, config, adapters: { supabase: { chats } } } = context; - const bot = TelegramBotSingleton.getInstance().getBot(); - const title = context.payload.issue.title - const { issue, repository } = context.payload; - const { full_name } = repository; - const [owner, repo] = full_name.split("/"); - - const workroom = await chats.getChatByTaskNodeId(issue.node_id); - - if (workroom) { - logger.debug("Workroom already exists for issue", { title }); - return { status: 404, reason: "workroom_already_exists" }; - } - - logger.info(`Creating workroom for issue ${title}`); - - try { - const forum = await bot.api?.createForumTopic(config.supergroupChatId, title); - await addCommentToIssue(context, `Workroom created: https://t.me/${config.supergroupChatName}/${forum?.message_thread_id}`, owner, repo, issue.number); - await chats.saveChat(forum?.message_thread_id, title, issue.node_id); - return { status: 201, reason: "workroom_created" }; - } catch (er) { - await addCommentToIssue(context, logger.error(`Failed to create workroom for issue ${title}`, { er }).logMessage.diff, owner, repo, issue.number); - return { status: 500, reason: "workroom_creation_failed" }; - } - + repositoryDispatch(context, "create-telegram-chat").catch(console.error); + return { status: 200, reason: "workflow_dispatched" }; } export async function closeWorkroom(context: Context<"issues.closed", SupportedEvents["issues.closed"]>): Promise { diff --git a/src/handlers/repository-dispatch.ts b/src/handlers/repository-dispatch.ts new file mode 100644 index 0000000..4fdd894 --- /dev/null +++ b/src/handlers/repository-dispatch.ts @@ -0,0 +1,44 @@ +import { getAppOctokit } from "#root/helpers/authenticated-octokit.js"; +import { PluginContext } from "#root/utils/plugin-context-single.js"; +import { Context } from "../types"; +import { WorkflowFunction } from "../workflow-functions"; + +/** + * Used by the worker instance to kick off workflows within it's own repository. + * + * These workflows are extensions of the worker allowing for more complex operations + * to be performed outside of Cloudflare Workers' limitations. + * + * @param env The environment variables for the worker instance. These + * will be taken from the repository's secrets. + * @param args The arguments passed to the workflow. + * + */ + + +export async function repositoryDispatch(context: Context, workflow: WorkflowFunction) { + const inputs = PluginContext.getInstance().getInputs(); + const { logger } = context; + const repository = "telegram--bot"; + const owner = "ubq-testing"; + const branch = "workflows"; + const octokit = await getAppOctokit(context); + + logger.info(`Dispatching workflow function: ${workflow}`); + + /** + * We'll hit the main workflow entry and pass in the same inputs so + * that it essentially runs on the same context as the worker. + */ + return await octokit.rest.actions.createWorkflowDispatch({ + owner, + repo: repository, + workflow_id: "compute.yml", + ref: branch, + inputs: { + ...inputs, + workflowFunction: workflow + } + }); +} + diff --git a/src/helpers/authenticated-octokit.ts b/src/helpers/authenticated-octokit.ts new file mode 100644 index 0000000..51cb49a --- /dev/null +++ b/src/helpers/authenticated-octokit.ts @@ -0,0 +1,15 @@ +import { Octokit } from "@octokit/rest"; +import { Context } from "../types"; + +export async function getAppOctokit(context: Context) { + const { env } = context; + const { APP_ID, APP_PRIVATE_KEY } = env; + const appOctokit = new Octokit({ + auth: { + appId: APP_ID, + privateKey: APP_PRIVATE_KEY, + }, + }); + + return appOctokit; +} \ No newline at end of file diff --git a/src/utils/plugin-context-single.ts b/src/utils/plugin-context-single.ts index 879b683..d210a75 100644 --- a/src/utils/plugin-context-single.ts +++ b/src/utils/plugin-context-single.ts @@ -34,6 +34,10 @@ export class PluginContext { return PluginContext.instance; } + getInputs(): PluginInputs { + return this.inputs; + } + getContext(): Context { const octokit = new Octokit({ auth: this.inputs.authToken }); const ctx: Context = { diff --git a/src/workflow-entry.ts b/src/workflow-entry.ts index b46765e..fc5e774 100644 --- a/src/workflow-entry.ts +++ b/src/workflow-entry.ts @@ -1,9 +1,10 @@ import * as core from "@actions/core"; import * as github from "@actions/github"; -import { Octokit } from "@octokit/rest"; import { Value } from "@sinclair/typebox/value"; -import { envSchema, pluginSettingsSchema, PluginInputs, pluginSettingsValidator } from "./types"; -import { plugin } from "./plugin"; +import { envValidator, pluginSettingsSchema, PluginInputs, pluginSettingsValidator } from "./types"; +import { PluginContext } from "./utils/plugin-context-single"; +import { proxyWorkflowCallbacks } from "./handlers/callbacks-proxy"; +import { bubbleUpErrorComment, sanitizeMetadata } from "./utils/errors"; /** * How a GitHub action executes the plugin. @@ -11,7 +12,7 @@ import { plugin } from "./plugin"; export async function run() { const payload = github.context.payload.inputs; - const env = Value.Decode(envSchema, payload.env); + const env = Value.Decode(envValidator.schema, payload.env); const settings = Value.Decode(pluginSettingsSchema, Value.Default(pluginSettingsSchema, JSON.parse(payload.settings))); if (!pluginSettingsValidator.test(settings)) { @@ -27,24 +28,31 @@ export async function run() { ref: payload.ref, }; - await plugin(inputs, env); + PluginContext.initialize(inputs, env); - return returnDataToKernel(inputs.authToken, inputs.stateId, {}); -} + const context = PluginContext.getInstance().getContext(); -async function returnDataToKernel(repoToken: string, stateId: string, output: object) { - const octokit = new Octokit({ auth: repoToken }); - await octokit.repos.createDispatchEvent({ - owner: github.context.repo.owner, - repo: github.context.repo.repo, - event_type: "return_data_to_ubiquibot_kernel", - client_payload: { - state_id: stateId, - output: JSON.stringify(output), - }, - }); + try { + return proxyWorkflowCallbacks(context)[inputs.eventName]; + } catch (err) { + return bubbleUpErrorComment(context, err) + } } +// Might use this later to receive data back from it's own workflows +// async function returnDataToKernel(repoToken: string, stateId: string, output: object) { +// const octokit = new Octokit({ auth: repoToken }); +// await octokit.repos.createDispatchEvent({ +// owner: github.context.repo.owner, +// repo: github.context.repo.repo, +// event_type: "return_data_to_ubiquibot_kernel", +// client_payload: { +// state_id: stateId, +// output: JSON.stringify(output), +// }, +// }); +// } + run() .then((result) => { core.setOutput("result", result); From 1c2398096115a0d8148319d0af7c08df6f87a432 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:47:26 +0100 Subject: [PATCH 06/21] chore: remove need to specify workflow function --- src/handlers/callbacks-proxy.ts | 35 +++++++++++---------------- src/handlers/github/workrooms.ts | 2 +- src/handlers/repository-dispatch.ts | 3 +-- src/types/proxy.ts | 8 +----- src/workflow-functions/create-chat.ts | 1 + 5 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/handlers/callbacks-proxy.ts b/src/handlers/callbacks-proxy.ts index c1646c5..8138c0b 100644 --- a/src/handlers/callbacks-proxy.ts +++ b/src/handlers/callbacks-proxy.ts @@ -1,8 +1,7 @@ -import { ProxyCallbacks, WorkflowCallbacks } from "#root/types/proxy.js"; +import { ProxyCallbacks } from "#root/types/proxy.js"; import { Context, SupportedEventsU } from "../types"; import { createChat } from "../workflow-functions/create-chat"; import { closeWorkroom, createWorkroom, reOpenWorkroom } from "./github/workrooms"; -import { WorkflowFunction } from "../workflow-functions"; /** * Why do we need this wrapper function? @@ -85,30 +84,24 @@ export function proxyCallbacks(context: Context): ProxyCallbacks { * * I.e we're essentially running the first dual action/worker plugin which is * ideal for telegram-bot as it's a bot that needs to be able to be super flexible. - * - * TODO: Might not need to do specify the workflow function and instead just pass the payload? */ const workflowCallbacks = { - "issues.labeled": { - "create-telegram-chat": [ - createChat - ] - } -} as WorkflowCallbacks; + "issues.labeled": [ + createChat + ] +} as ProxyCallbacks; + -export function proxyWorkflowCallbacks(context: Context): WorkflowCallbacks { +export function proxyWorkflowCallbacks(context: Context): ProxyCallbacks { return new Proxy(workflowCallbacks, { - get(target, prop: WorkflowFunction) { + get(target, prop: SupportedEventsU) { + if (!target[prop]) { + context.logger.info(`No callbacks found for event ${prop}`); + return { status: 204, reason: "skipped" }; + } return (async () => { try { - return await Promise.all(Object.keys(target).map((event) => { - const eventCallbacks = target[event as SupportedEventsU][prop]; - if (!eventCallbacks) { - context.logger.info(`No callbacks found for event ${event}`); - return { status: 204, reason: "skipped" }; - } - return Promise.all(eventCallbacks.map((callback) => handleCallback(callback, context))); - })); + return await Promise.all(target[prop].map((callback) => handleCallback(callback, context))); } catch (er) { context.logger.error(`Failed to handle event ${prop}`, { er }); return { status: 500, reason: "failed" }; @@ -116,4 +109,4 @@ export function proxyWorkflowCallbacks(context: Context): WorkflowCallbacks { })(); }, }); -} +} \ No newline at end of file diff --git a/src/handlers/github/workrooms.ts b/src/handlers/github/workrooms.ts index 9fff909..e5a9833 100644 --- a/src/handlers/github/workrooms.ts +++ b/src/handlers/github/workrooms.ts @@ -21,7 +21,7 @@ import { addCommentToIssue } from "./utils/add-comment-to-issues"; */ export async function createWorkroom(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise { - repositoryDispatch(context, "create-telegram-chat").catch(console.error); + await repositoryDispatch(context, "create-telegram-chat").catch(console.error); return { status: 200, reason: "workflow_dispatched" }; } diff --git a/src/handlers/repository-dispatch.ts b/src/handlers/repository-dispatch.ts index 4fdd894..d1c1146 100644 --- a/src/handlers/repository-dispatch.ts +++ b/src/handlers/repository-dispatch.ts @@ -15,7 +15,6 @@ import { WorkflowFunction } from "../workflow-functions"; * */ - export async function repositoryDispatch(context: Context, workflow: WorkflowFunction) { const inputs = PluginContext.getInstance().getInputs(); const { logger } = context; @@ -37,7 +36,7 @@ export async function repositoryDispatch(context: Context, workflow: WorkflowFun ref: branch, inputs: { ...inputs, - workflowFunction: workflow + workflowFunction: workflow // here for the workflow logs, not used in the workflow } }); } diff --git a/src/types/proxy.ts b/src/types/proxy.ts index c477765..2c61c1d 100644 --- a/src/types/proxy.ts +++ b/src/types/proxy.ts @@ -36,11 +36,6 @@ export type ProxyCallbacks = ProxyTypeHelper; * * Would be handy as we could avoid having to use typeguards in the workflow functions. */ -type WorkflowTypeHelper = { - [K in SupportedEventsU]: { - [P in WorkflowFunction]: Array<(context: Context) => Promise>; - } -}; /** * * The expected function signature for callbacks looks like this: @@ -48,5 +43,4 @@ type WorkflowTypeHelper = { * ```typescript * fn(context: Context): Promise * ``` - */ -export type WorkflowCallbacks = WorkflowTypeHelper; \ No newline at end of file + */ \ No newline at end of file diff --git a/src/workflow-functions/create-chat.ts b/src/workflow-functions/create-chat.ts index fd25d82..ca7ef6a 100644 --- a/src/workflow-functions/create-chat.ts +++ b/src/workflow-functions/create-chat.ts @@ -3,6 +3,7 @@ import { CallbackResult } from "#root/types/proxy.js"; import { MtProtoSingleton } from "./bot"; export async function createChat(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise { + console.log("Creating chat"); try { const { payload, env } = context; const chatName = payload.issue.title; From fdb01f27611dca48793e97342521981ad469a9ff Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:50:27 +0100 Subject: [PATCH 07/21] chore: deleting files --- .github/workflows/create-chat.yml | 60 ------------------------------- src/types/proxy.ts | 23 +----------- src/types/typeguards.ts | 5 --- src/workflow-functions/index.ts | 5 --- 4 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 .github/workflows/create-chat.yml delete mode 100644 src/workflow-functions/index.ts diff --git a/.github/workflows/create-chat.yml b/.github/workflows/create-chat.yml deleted file mode 100644 index 2508b7a..0000000 --- a/.github/workflows/create-chat.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: "create-telegram-chat" - -on: - repository_dispatch: - types: [create-telegram-chat] - -jobs: - create-telegram-chat: - name: "Create Telegram Chat" - runs-on: ubuntu-latest - permissions: write-all - env: - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - BOT_MODE: ${{ secrets.BOT_MODE }} - BOT_ADMINS: ${{ secrets.BOT_ADMINS }} - BOT_WEBHOOK: ${{ secrets.BOT_WEBHOOK }} - BOT_WEBHOOK_SECRET: ${{ secrets.BOT_WEBHOOK_SECRET }} - - TELEGRAM_APP_ID: ${{ secrets.TELEGRAM_APP_ID }} - TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} - - SUPABASE_URL: ${{ secrets.SUPABASE_URL }} - SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} - - LOG_LEVEL: ${{ secrets.LOG_LEVEL }} - DEBUG: ${{ secrets.DEBUG }} - SERVER_HOST: ${{ secrets.SERVER_HOST }} - SERVER_PORT: ${{ secrets.SERVER_PORT }} - - steps: - - uses: actions/checkout@v4 - - - name: setup node - uses: actions/setup-node@v4 - with: - node-version: "20.10.0" - - - name: install dependencies - run: yarn - - - name: execute directive - run: npx tsx ./src/workflows/create-chat/index.ts - id: create-telegram-chat - env: - BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - BOT_MODE: ${{ secrets.BOT_MODE }} - BOT_ADMINS: ${{ secrets.BOT_ADMINS }} - BOT_WEBHOOK: ${{ secrets.BOT_WEBHOOK }} - BOT_WEBHOOK_SECRET: ${{ secrets.BOT_WEBHOOK_SECRET }} - - TELEGRAM_APP_ID: ${{ secrets.TELEGRAM_APP_ID }} - TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} - - SUPABASE_URL: ${{ secrets.SUPABASE_URL }} - SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} - - LOG_LEVEL: ${{ secrets.LOG_LEVEL }} - DEBUG: ${{ secrets.DEBUG }} - SERVER_HOST: ${{ secrets.SERVER_HOST }} - SERVER_PORT: ${{ secrets.SERVER_PORT }} \ No newline at end of file diff --git a/src/types/proxy.ts b/src/types/proxy.ts index 2c61c1d..e021116 100644 --- a/src/types/proxy.ts +++ b/src/types/proxy.ts @@ -1,4 +1,3 @@ -import { WorkflowFunction } from "../workflow-functions"; import { Context, SupportedEvents, SupportedEventsU } from "./context"; export type CallbackResult = { status: 200 | 201 | 204 | 404 | 500, reason: string; content?: string | Record }; @@ -23,24 +22,4 @@ export type CallbackResult = { status: 200 | 201 | 204 | 404 | 500, reason: stri type ProxyTypeHelper = { [K in SupportedEventsU]: Array<(context: Context) => Promise>; }; -export type ProxyCallbacks = ProxyTypeHelper; - -/** - * Was unable to figure a way to make this work elegantly to avoid having to use - * typeguards in the workflow functions like we have in `ProxyCallbacks`. - * - * Something in the lines of: - * Each callback would define a generic type `T` that would be just that event type as to - * restrict inference in Context to only that webhook although it infers all payloads in - * all of my attempts. - * - * Would be handy as we could avoid having to use typeguards in the workflow functions. - */ - -/** - * * The expected function signature for callbacks looks like this: - * - * ```typescript - * fn(context: Context): Promise - * ``` - */ \ No newline at end of file +export type ProxyCallbacks = ProxyTypeHelper; \ No newline at end of file diff --git a/src/types/typeguards.ts b/src/types/typeguards.ts index 84c1a9d..5e21818 100644 --- a/src/types/typeguards.ts +++ b/src/types/typeguards.ts @@ -1,7 +1,6 @@ import { Update } from "@grammyjs/types"; import { Context } from "./context"; import { PluginInputs } from "./plugin-inputs"; -import { WORKFLOW_FUNCTIONS } from "../workflow-functions"; export function isIssueOpenedEvent(context: Context): context is Context<"issues.opened"> { return context.eventName === "issues.opened"; @@ -26,8 +25,4 @@ export function isGithubPayload(inputs: any): inputs is PluginInputs { export function isIssueLabeledEvent(context: Context): context is Context<"issues.labeled"> { return context.eventName === "issues.labeled"; -} - -export function isWorkflowFunction(event: string): event is keyof typeof WORKFLOW_FUNCTIONS { - return Object.keys(WORKFLOW_FUNCTIONS).includes(event); } \ No newline at end of file diff --git a/src/workflow-functions/index.ts b/src/workflow-functions/index.ts deleted file mode 100644 index 6e8973d..0000000 --- a/src/workflow-functions/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const WORKFLOW_FUNCTIONS = { - CREATE_CHAT: "create-telegram-chat", -} as const; - -export type WorkflowFunction = typeof WORKFLOW_FUNCTIONS[keyof typeof WORKFLOW_FUNCTIONS]; \ No newline at end of file From 96990a5e28f277c7116f765297b965d8f2a12e4b Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Tue, 3 Sep 2024 21:11:08 +0100 Subject: [PATCH 08/21] chore: remove server post and host env --- .github/workflows/compute.yml | 24 ++++++++++++++++++++++++ src/types/env.ts | 2 -- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compute.yml b/.github/workflows/compute.yml index 3d204b1..9070237 100644 --- a/.github/workflows/compute.yml +++ b/.github/workflows/compute.yml @@ -24,6 +24,18 @@ jobs: env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + BOT_MODE: ${{ secrets.BOT_MODE }} + BOT_ADMINS: ${{ secrets.BOT_ADMINS }} + BOT_WEBHOOK: ${{ secrets.BOT_WEBHOOK }} + BOT_WEBHOOK_SECRET: ${{ secrets.BOT_WEBHOOK_SECRET }} + + TELEGRAM_APP_ID: ${{ secrets.TELEGRAM_APP_ID }} + TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} + + LOG_LEVEL: ${{ secrets.LOG_LEVEL }} + DEBUG: ${{ secrets.DEBUG }} steps: - uses: actions/checkout@v4 @@ -42,3 +54,15 @@ jobs: env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} + + BOT_TOKEN: ${{ secrets.BOT_TOKEN }} + BOT_MODE: ${{ secrets.BOT_MODE }} + BOT_ADMINS: ${{ secrets.BOT_ADMINS }} + BOT_WEBHOOK: ${{ secrets.BOT_WEBHOOK }} + BOT_WEBHOOK_SECRET: ${{ secrets.BOT_WEBHOOK_SECRET }} + + TELEGRAM_APP_ID: ${{ secrets.TELEGRAM_APP_ID }} + TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} + + LOG_LEVEL: ${{ secrets.LOG_LEVEL }} + DEBUG: ${{ secrets.DEBUG }} \ No newline at end of file diff --git a/src/types/env.ts b/src/types/env.ts index 669baee..3593ffb 100644 --- a/src/types/env.ts +++ b/src/types/env.ts @@ -23,8 +23,6 @@ export const env = T.Object({ DEBUG: T.Transform(T.Union([T.String(), T.Boolean()])).Decode((str) => str === "true" || str === "false" ? str === "true" : str).Encode((bool) => bool.toString()), BOT_WEBHOOK: T.String(), BOT_WEBHOOK_SECRET: T.String(), - SERVER_HOST: T.String(), - SERVER_PORT: T.Transform(T.Unknown()).Decode((str) => Number(str)).Encode((num) => num.toString()), BOT_ADMINS: T.Transform(T.Unknown()).Decode((str) => Array.isArray(str) ? str.map(Number) : [Number(str)]).Encode((arr) => arr.toString()), ALLOWED_UPDATES: T.Optional(T.Array(T.KeyOf(allowedUpdates))), SUPABASE_URL: T.String(), From ec8dca5bc38fb71a7895ce2639621682a1290030 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:06:13 +0100 Subject: [PATCH 09/21] chore: add octokit for app auth --- package.json | 3 +- src/handlers/repository-dispatch.ts | 3 +- src/helpers/authenticated-octokit.ts | 14 +-- yarn.lock | 164 ++++++++++++++++++++++++++- 4 files changed, 168 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index ad8d89b..eeb2289 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "grammy-guard": "0.5.0", "hono": "^4.5.9", "iso-639-1": "3.1.2", + "octokit": "^4.0.2", "pino": "9.3.2", "pino-pretty": "11.2.2", "telegram": "^2.24.11", @@ -109,4 +110,4 @@ ] }, "packageManager": "yarn@1.22.22" -} \ No newline at end of file +} diff --git a/src/handlers/repository-dispatch.ts b/src/handlers/repository-dispatch.ts index d1c1146..0260ab7 100644 --- a/src/handlers/repository-dispatch.ts +++ b/src/handlers/repository-dispatch.ts @@ -1,7 +1,6 @@ import { getAppOctokit } from "#root/helpers/authenticated-octokit.js"; import { PluginContext } from "#root/utils/plugin-context-single.js"; import { Context } from "../types"; -import { WorkflowFunction } from "../workflow-functions"; /** * Used by the worker instance to kick off workflows within it's own repository. @@ -15,7 +14,7 @@ import { WorkflowFunction } from "../workflow-functions"; * */ -export async function repositoryDispatch(context: Context, workflow: WorkflowFunction) { +export async function repositoryDispatch(context: Context, workflow: string) { const inputs = PluginContext.getInstance().getInputs(); const { logger } = context; const repository = "telegram--bot"; diff --git a/src/helpers/authenticated-octokit.ts b/src/helpers/authenticated-octokit.ts index 51cb49a..b79c01e 100644 --- a/src/helpers/authenticated-octokit.ts +++ b/src/helpers/authenticated-octokit.ts @@ -1,15 +1,13 @@ -import { Octokit } from "@octokit/rest"; +import { App } from "octokit"; import { Context } from "../types"; export async function getAppOctokit(context: Context) { const { env } = context; const { APP_ID, APP_PRIVATE_KEY } = env; - const appOctokit = new Octokit({ - auth: { - appId: APP_ID, - privateKey: APP_PRIVATE_KEY, - }, - }); + const app = new App({ + appId: APP_ID, + privateKey: APP_PRIVATE_KEY, + }) - return appOctokit; + return app.octokit; } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f5eb332..180e8f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2406,6 +2406,65 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@octokit/app@^15.0.0": + version "15.1.0" + resolved "https://registry.yarnpkg.com/@octokit/app/-/app-15.1.0.tgz#b330d8826be088ec8d1d43a59dc27ef57d1232b2" + integrity sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg== + dependencies: + "@octokit/auth-app" "^7.0.0" + "@octokit/auth-unauthenticated" "^6.0.0" + "@octokit/core" "^6.1.2" + "@octokit/oauth-app" "^7.0.0" + "@octokit/plugin-paginate-rest" "^11.0.0" + "@octokit/types" "^13.0.0" + "@octokit/webhooks" "^13.0.0" + +"@octokit/auth-app@^7.0.0": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-app/-/auth-app-7.1.1.tgz#d8916ad01e6ffb0a0a50507aa613e91fe7a49b93" + integrity sha512-kRAd6yelV9OgvlEJE88H0VLlQdZcag9UlLr7dV0YYP37X8PPDvhgiTy66QVhDXdyoT0AleFN2w/qXkPdrSzINg== + dependencies: + "@octokit/auth-oauth-app" "^8.1.0" + "@octokit/auth-oauth-user" "^5.1.0" + "@octokit/request" "^9.1.1" + "@octokit/request-error" "^6.1.1" + "@octokit/types" "^13.4.1" + lru-cache "^10.0.0" + universal-github-app-jwt "^2.2.0" + universal-user-agent "^7.0.0" + +"@octokit/auth-oauth-app@^8.0.0", "@octokit/auth-oauth-app@^8.1.0": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz#6204affa6e86f535016799cadf2af9befe5e893c" + integrity sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg== + dependencies: + "@octokit/auth-oauth-device" "^7.0.0" + "@octokit/auth-oauth-user" "^5.0.1" + "@octokit/request" "^9.0.0" + "@octokit/types" "^13.0.0" + universal-user-agent "^7.0.0" + +"@octokit/auth-oauth-device@^7.0.0", "@octokit/auth-oauth-device@^7.0.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz#7b4f8f97cbcadbe9894d48cde4406dbdef39875a" + integrity sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg== + dependencies: + "@octokit/oauth-methods" "^5.0.0" + "@octokit/request" "^9.0.0" + "@octokit/types" "^13.0.0" + universal-user-agent "^7.0.0" + +"@octokit/auth-oauth-user@^5.0.1", "@octokit/auth-oauth-user@^5.1.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz#4f1570c6ee15bb9ddc3dcca83308dcaa159e3848" + integrity sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw== + dependencies: + "@octokit/auth-oauth-device" "^7.0.1" + "@octokit/oauth-methods" "^5.0.0" + "@octokit/request" "^9.0.1" + "@octokit/types" "^13.0.0" + universal-user-agent "^7.0.0" + "@octokit/auth-token@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-4.0.0.tgz#40d203ea827b9f17f42a29c6afb93b7745ef80c7" @@ -2416,6 +2475,14 @@ resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.1.tgz#3bbfe905111332a17f72d80bd0b51a3e2fa2cf07" integrity sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA== +"@octokit/auth-unauthenticated@^6.0.0", "@octokit/auth-unauthenticated@^6.0.0-beta.1": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-unauthenticated/-/auth-unauthenticated-6.1.0.tgz#de0fe923bb06ed93aea526ab99972a98c546d0bf" + integrity sha512-zPSmfrUAcspZH/lOFQnVnvjQZsIvmfApQH6GzJrkIunDooU1Su2qt2FfMTSVPRp7WLTQyC20Kd55lF+mIYaohQ== + dependencies: + "@octokit/request-error" "^6.0.1" + "@octokit/types" "^13.0.0" + "@octokit/core@^5.0.1": version "5.2.0" resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.2.0.tgz#ddbeaefc6b44a39834e1bb2e58a49a117672a7ea" @@ -2429,7 +2496,7 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/core@^6.1.2": +"@octokit/core@^6.0.0", "@octokit/core@^6.1.2": version "6.1.2" resolved "https://registry.yarnpkg.com/@octokit/core/-/core-6.1.2.tgz#20442d0a97c411612da206411e356014d1d1bd17" integrity sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg== @@ -2476,6 +2543,35 @@ "@octokit/types" "^13.0.0" universal-user-agent "^7.0.0" +"@octokit/oauth-app@^7.0.0": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@octokit/oauth-app/-/oauth-app-7.1.3.tgz#a0f256dd185e7c00bfbc3e6bc3c5aad66e42c609" + integrity sha512-EHXbOpBkSGVVGF1W+NLMmsnSsJRkcrnVmDKt0TQYRBb6xWfWzoi9sBD4DIqZ8jGhOWO/V8t4fqFyJ4vDQDn9bg== + dependencies: + "@octokit/auth-oauth-app" "^8.0.0" + "@octokit/auth-oauth-user" "^5.0.1" + "@octokit/auth-unauthenticated" "^6.0.0-beta.1" + "@octokit/core" "^6.0.0" + "@octokit/oauth-authorization-url" "^7.0.0" + "@octokit/oauth-methods" "^5.0.0" + "@types/aws-lambda" "^8.10.83" + universal-user-agent "^7.0.0" + +"@octokit/oauth-authorization-url@^7.0.0": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz#0e17c2225eb66b58ec902d02b6f1315ffe9ff04b" + integrity sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA== + +"@octokit/oauth-methods@^5.0.0": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz#fd31d2a69f4c91d1abc1ed1814dda5252c697e02" + integrity sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g== + dependencies: + "@octokit/oauth-authorization-url" "^7.0.0" + "@octokit/request" "^9.1.0" + "@octokit/request-error" "^6.1.0" + "@octokit/types" "^13.0.0" + "@octokit/openapi-types@^20.0.0": version "20.0.0" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-20.0.0.tgz#9ec2daa0090eeb865ee147636e0c00f73790c6e5" @@ -2491,6 +2587,11 @@ resolved "https://registry.yarnpkg.com/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-8.3.0.tgz#a7a4da00c0f27f7f5708eb3fcebefa08f8d51125" integrity sha512-vKLsoR4xQxg4Z+6rU/F65ItTUz/EXbD+j/d4mlq2GW8TsA4Tc8Kdma2JTAAJ5hrKWUQzkR/Esn2fjsqiVRYaQg== +"@octokit/plugin-paginate-graphql@^5.0.0": + version "5.2.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-5.2.2.tgz#54e2afef55bb204eb945a891b85a169b9ddad1f8" + integrity sha512-7znSVvlNAOJisCqAnjN1FtEziweOHSjPGAuc5W58NeGNAr/ZB57yCsjQbXDlWsVryA7hHQaEQPcBbJYFawlkyg== + "@octokit/plugin-paginate-rest@^11.0.0": version "11.3.3" resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.3.tgz#efc97ba66aae6797e2807a082f99b9cfc0e05aba" @@ -2524,6 +2625,23 @@ dependencies: "@octokit/types" "^13.5.0" +"@octokit/plugin-retry@^7.0.0": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-retry/-/plugin-retry-7.1.1.tgz#a84483e4afdd068dd71da81abe206a9e442c1288" + integrity sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw== + dependencies: + "@octokit/request-error" "^6.0.0" + "@octokit/types" "^13.0.0" + bottleneck "^2.15.3" + +"@octokit/plugin-throttling@^9.0.0": + version "9.3.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-throttling/-/plugin-throttling-9.3.1.tgz#5648165e1e70e861625f3a16af6c55cafe861061" + integrity sha512-Qd91H4liUBhwLB2h6jZ99bsxoQdhgPk6TdwnClPyTBSDAdviGPceViEgUwj+pcQDmB/rfAXAXK7MTochpHM3yQ== + dependencies: + "@octokit/types" "^13.0.0" + bottleneck "^2.15.3" + "@octokit/request-error@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.1.0.tgz#ee4138538d08c81a60be3f320cd71063064a3b30" @@ -2533,7 +2651,7 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request-error@^6.0.1": +"@octokit/request-error@^6.0.0", "@octokit/request-error@^6.0.1", "@octokit/request-error@^6.1.0", "@octokit/request-error@^6.1.1": version "6.1.4" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.4.tgz#ad96e29148d19edc2ba8009fc2b5a24a36c90f16" integrity sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg== @@ -2550,7 +2668,7 @@ "@octokit/types" "^13.1.0" universal-user-agent "^6.0.0" -"@octokit/request@^9.0.0": +"@octokit/request@^9.0.0", "@octokit/request@^9.0.1", "@octokit/request@^9.1.0", "@octokit/request@^9.1.1": version "9.1.3" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.1.3.tgz#42b693bc06238f43af3c037ebfd35621c6457838" integrity sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA== @@ -2577,7 +2695,7 @@ dependencies: "@octokit/openapi-types" "^20.0.0" -"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.5.0": +"@octokit/types@^13.0.0", "@octokit/types@^13.1.0", "@octokit/types@^13.4.1", "@octokit/types@^13.5.0": version "13.5.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.5.0.tgz#4796e56b7b267ebc7c921dcec262b3d5bfb18883" integrity sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ== @@ -2589,7 +2707,7 @@ resolved "https://registry.yarnpkg.com/@octokit/webhooks-methods/-/webhooks-methods-5.1.0.tgz#13b6c08f89902c1ab0ddf31c6eeeec9c2772cfe6" integrity sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ== -"@octokit/webhooks@13.3.0": +"@octokit/webhooks@13.3.0", "@octokit/webhooks@^13.0.0": version "13.3.0" resolved "https://registry.yarnpkg.com/@octokit/webhooks/-/webhooks-13.3.0.tgz#fd5d54d47c789c75d60a00eb04e982152d7c654a" integrity sha512-TUkJLtI163Bz5+JK0O+zDkQpn4gKwN+BovclUvCj6pI/6RXrFqQvUMRS2M+Rt8Rv0qR3wjoMoOPmpJKeOh0nBg== @@ -2711,6 +2829,11 @@ "@supabase/realtime-js" "2.10.2" "@supabase/storage-js" "2.7.0" +"@types/aws-lambda@^8.10.83": + version "8.10.145" + resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.145.tgz#b2d31a987f4888e5553ff1819f57cafa475594d9" + integrity sha512-dtByW6WiFk5W5Jfgz1VM+YPA21xMXTuSFoLYIDY0L44jDLLflVPtZkYuu3/YxpGcvjzKFBZLU+GyKjR0HOYtyw== + "@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" @@ -3518,6 +3641,11 @@ blake3-wasm@^2.1.5: resolved "https://registry.yarnpkg.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz#b22dbb84bc9419ed0159caa76af4b1b132e6ba52" integrity sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g== +bottleneck@^2.15.3: + version "2.19.5" + resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" + integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -6625,6 +6753,11 @@ loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +lru-cache@^10.0.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -7014,6 +7147,22 @@ object.values@^1.1.6, object.values@^1.1.7, object.values@^1.2.0: define-properties "^1.2.1" es-object-atoms "^1.0.0" +octokit@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/octokit/-/octokit-4.0.2.tgz#775d68d363cdaec69d7b73d3dc82ae909d30f59b" + integrity sha512-wbqF4uc1YbcldtiBFfkSnquHtECEIpYD78YUXI6ri1Im5OO2NLo6ZVpRdbJpdnpZ05zMrVPssNiEo6JQtea+Qg== + dependencies: + "@octokit/app" "^15.0.0" + "@octokit/core" "^6.0.0" + "@octokit/oauth-app" "^7.0.0" + "@octokit/plugin-paginate-graphql" "^5.0.0" + "@octokit/plugin-paginate-rest" "^11.0.0" + "@octokit/plugin-rest-endpoint-methods" "^13.0.0" + "@octokit/plugin-retry" "^7.0.0" + "@octokit/plugin-throttling" "^9.0.0" + "@octokit/request-error" "^6.0.0" + "@octokit/types" "^13.0.0" + on-exit-leak-free@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" @@ -8565,6 +8714,11 @@ unicorn-magic@^0.1.0: resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== +universal-github-app-jwt@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz#dc6c8929e76f1996a766ba2a08fb420f73365d77" + integrity sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ== + universal-user-agent@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" From db9dcb000563b0077603e7f38a8279534f9b854d Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:51:08 +0100 Subject: [PATCH 10/21] chore: test --- .github/workflows/compute.yml | 2 +- src/handlers/repository-dispatch.ts | 14 ++++++++++++-- src/helpers/authenticated-octokit.ts | 10 ++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/workflows/compute.yml b/.github/workflows/compute.yml index 9070237..7d778b5 100644 --- a/.github/workflows/compute.yml +++ b/.github/workflows/compute.yml @@ -49,7 +49,7 @@ jobs: run: yarn - name: execute directive - run: npx tsx ./src/main.ts + run: npx tsx ./src/workflow-entry.ts id: plugin-name env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} diff --git a/src/handlers/repository-dispatch.ts b/src/handlers/repository-dispatch.ts index 0260ab7..f9d7e3e 100644 --- a/src/handlers/repository-dispatch.ts +++ b/src/handlers/repository-dispatch.ts @@ -20,14 +20,23 @@ export async function repositoryDispatch(context: Context, workflow: string) { const repository = "telegram--bot"; const owner = "ubq-testing"; const branch = "workflows"; - const octokit = await getAppOctokit(context); + const app = await getAppOctokit(context); + const installation = await app.octokit.rest.apps.getRepoInstallation({ owner, repo: repository }); + + // Set the installation id for the octokit instance + + const octokit = await app.getInstallationOctokit(installation.data.id); logger.info(`Dispatching workflow function: ${workflow}`); + /** * We'll hit the main workflow entry and pass in the same inputs so * that it essentially runs on the same context as the worker. */ + + Reflect.deleteProperty(inputs, "signature"); + return await octokit.rest.actions.createWorkflowDispatch({ owner, repo: repository, @@ -35,7 +44,8 @@ export async function repositoryDispatch(context: Context, workflow: string) { ref: branch, inputs: { ...inputs, - workflowFunction: workflow // here for the workflow logs, not used in the workflow + eventPayload: JSON.stringify(context.payload), + settings: JSON.stringify(context.config), } }); } diff --git a/src/helpers/authenticated-octokit.ts b/src/helpers/authenticated-octokit.ts index b79c01e..7df5d36 100644 --- a/src/helpers/authenticated-octokit.ts +++ b/src/helpers/authenticated-octokit.ts @@ -2,12 +2,6 @@ import { App } from "octokit"; import { Context } from "../types"; export async function getAppOctokit(context: Context) { - const { env } = context; - const { APP_ID, APP_PRIVATE_KEY } = env; - const app = new App({ - appId: APP_ID, - privateKey: APP_PRIVATE_KEY, - }) - - return app.octokit; + const { env: { APP_ID, APP_PRIVATE_KEY } } = context; + return new App({ appId: APP_ID, privateKey: APP_PRIVATE_KEY }); } \ No newline at end of file From 8986d67089816ad56ba5d64c08283adf1dcd35d1 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:04:10 +0100 Subject: [PATCH 11/21] chore: typebox debug --- src/workflow-entry.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/workflow-entry.ts b/src/workflow-entry.ts index fc5e774..62ac050 100644 --- a/src/workflow-entry.ts +++ b/src/workflow-entry.ts @@ -11,9 +11,22 @@ import { bubbleUpErrorComment, sanitizeMetadata } from "./utils/errors"; */ export async function run() { const payload = github.context.payload.inputs; + let env, settings; + try { + env = Value.Decode(envValidator.schema, payload.env); + } catch (err) { + console.log("Error decoding env: ", err); + } + + try { + settings = Value.Decode(pluginSettingsSchema, Value.Default(pluginSettingsSchema, JSON.parse(payload.settings))); + } catch (err) { + console.log("Error decoding settings: ", err); + } - const env = Value.Decode(envValidator.schema, payload.env); - const settings = Value.Decode(pluginSettingsSchema, Value.Default(pluginSettingsSchema, JSON.parse(payload.settings))); + if (!(settings && env)) { + throw new Error("Invalid settings or env provided"); + } if (!pluginSettingsValidator.test(settings)) { throw new Error("Invalid settings provided"); From 3293d36353e6a598823ee7f51e663b5c2d64daa7 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:11:15 +0100 Subject: [PATCH 12/21] chore: use process.env for workflow --- src/workflow-entry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workflow-entry.ts b/src/workflow-entry.ts index 62ac050..f77b5f2 100644 --- a/src/workflow-entry.ts +++ b/src/workflow-entry.ts @@ -13,7 +13,7 @@ export async function run() { const payload = github.context.payload.inputs; let env, settings; try { - env = Value.Decode(envValidator.schema, payload.env); + env = Value.Decode(envValidator.schema, process.env); } catch (err) { console.log("Error decoding env: ", err); } From 3f8c1da5daac2fdcff93c10e9236dc51fbf6657b Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:14:42 +0100 Subject: [PATCH 13/21] chore: use dotenv --- src/workflow-entry.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/workflow-entry.ts b/src/workflow-entry.ts index f77b5f2..aa810e0 100644 --- a/src/workflow-entry.ts +++ b/src/workflow-entry.ts @@ -5,6 +5,9 @@ import { envValidator, pluginSettingsSchema, PluginInputs, pluginSettingsValidat import { PluginContext } from "./utils/plugin-context-single"; import { proxyWorkflowCallbacks } from "./handlers/callbacks-proxy"; import { bubbleUpErrorComment, sanitizeMetadata } from "./utils/errors"; +import dotenv from "dotenv"; +dotenv.config(); + /** * How a GitHub action executes the plugin. From 1368fe14a2ba4d9abd6799f4ea6b195f31ed1c2f Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:20:04 +0100 Subject: [PATCH 14/21] chore: build separate env --- src/workflow-entry.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/workflow-entry.ts b/src/workflow-entry.ts index aa810e0..f606254 100644 --- a/src/workflow-entry.ts +++ b/src/workflow-entry.ts @@ -6,6 +6,7 @@ import { PluginContext } from "./utils/plugin-context-single"; import { proxyWorkflowCallbacks } from "./handlers/callbacks-proxy"; import { bubbleUpErrorComment, sanitizeMetadata } from "./utils/errors"; import dotenv from "dotenv"; +import { LOG_LEVEL } from "@ubiquity-dao/ubiquibot-logger"; dotenv.config(); @@ -14,9 +15,27 @@ dotenv.config(); */ export async function run() { const payload = github.context.payload.inputs; + let env, settings; + + const payloadEnv = { + BOT_TOKEN: process.env.BOT_TOKEN, + BOT_MODE: process.env.BOT_MODE, + LOG_LEVEL: process.env.LOG_LEVEL, + DEBUG: process.env.DEBUG, + BOT_WEBHOOK: process.env.BOT_WEBHOOK, + BOT_WEBHOOK_SECRET: process.env.BOT_WEBHOOK_SECRET, + BOT_ADMINS: process.env.BOT_ADMINS, + TELEGRAM_APP_ID: process.env.TELEGRAM_APP_ID, + TELEGRAM_API_HASH: process.env.TELEGRAM_API_HASH, + SUPABASE_URL: process.env.SUPABASE_URL, + SUPABASE_KEY: process.env.SUPABASE_KEY, + APP_PRIVATE_KEY: process.env.APP_PRIVATE_KEY, + APP_ID: process.env.APP_ID, + } + try { - env = Value.Decode(envValidator.schema, process.env); + env = Value.Decode(envValidator.schema, payloadEnv); } catch (err) { console.log("Error decoding env: ", err); } From 75de906c7956ced4fe195a444cb9c1750d4efecb Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:34:32 +0100 Subject: [PATCH 15/21] chore: test --- src/types/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/env.ts b/src/types/env.ts index 3593ffb..9cee110 100644 --- a/src/types/env.ts +++ b/src/types/env.ts @@ -30,7 +30,7 @@ export const env = T.Object({ TELEGRAM_APP_ID: T.Transform(T.Unknown()).Decode((str) => Number(str)).Encode((num) => num.toString()), TELEGRAM_API_HASH: T.String(), APP_ID: T.Transform(T.Unknown()).Decode((str) => Number(str)).Encode((num) => num.toString()), - APP_PRIVATE_KEY: T.String(), + APP_PRIVATE_KEY: T.Transform(T.Unknown()).Decode((str) => String(str)).Encode((str) => str), }); /** From a2decc83815eae2b271637374cae8fffde6bdf6d Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:36:51 +0100 Subject: [PATCH 16/21] chore: reduce to 10 env items --- src/types/env.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/types/env.ts b/src/types/env.ts index 9cee110..a950a2e 100644 --- a/src/types/env.ts +++ b/src/types/env.ts @@ -18,9 +18,6 @@ const allowedUpdates = T.Object({ export const env = T.Object({ BOT_TOKEN: T.String(), - BOT_MODE: T.String(), - LOG_LEVEL: T.String(), - DEBUG: T.Transform(T.Union([T.String(), T.Boolean()])).Decode((str) => str === "true" || str === "false" ? str === "true" : str).Encode((bool) => bool.toString()), BOT_WEBHOOK: T.String(), BOT_WEBHOOK_SECRET: T.String(), BOT_ADMINS: T.Transform(T.Unknown()).Decode((str) => Array.isArray(str) ? str.map(Number) : [Number(str)]).Encode((arr) => arr.toString()), From 98d3b8d5d4edb491019a22f6f0c1a3f0472e9475 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:40:02 +0100 Subject: [PATCH 17/21] chore:add connect event --- src/workflow-functions/bot.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/workflow-functions/bot.ts b/src/workflow-functions/bot.ts index 1ef4593..102df49 100644 --- a/src/workflow-functions/bot.ts +++ b/src/workflow-functions/bot.ts @@ -21,6 +21,7 @@ export class MtProtoSingleton { MtProtoSingleton.instance = new MtProtoSingleton(); MtProtoSingleton.api = Api; MtProtoSingleton.client = await mtProtoInit(env, MtProtoSingleton.api); + await MtProtoSingleton.client.connect(); } return MtProtoSingleton.instance; } From 0eef0d13e0ef112796d04a56676274690fcd3623 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:43:48 +0100 Subject: [PATCH 18/21] chore: move connect to before api invoke --- src/workflow-functions/bot.ts | 1 - src/workflow-functions/create-chat.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/workflow-functions/bot.ts b/src/workflow-functions/bot.ts index 102df49..1ef4593 100644 --- a/src/workflow-functions/bot.ts +++ b/src/workflow-functions/bot.ts @@ -21,7 +21,6 @@ export class MtProtoSingleton { MtProtoSingleton.instance = new MtProtoSingleton(); MtProtoSingleton.api = Api; MtProtoSingleton.client = await mtProtoInit(env, MtProtoSingleton.api); - await MtProtoSingleton.client.connect(); } return MtProtoSingleton.instance; } diff --git a/src/workflow-functions/create-chat.ts b/src/workflow-functions/create-chat.ts index ca7ef6a..ade01e9 100644 --- a/src/workflow-functions/create-chat.ts +++ b/src/workflow-functions/create-chat.ts @@ -10,6 +10,7 @@ export async function createChat(context: Context<"issues.labeled", SupportedEve const mtProto = await MtProtoSingleton.getInstance(env); const client = mtProto.getClient(); + await client.connect(); const api = mtProto.getApi(); console.log("Creating chat with name: ", chatName); const chat = await client.invoke( From 97b8cffde67eb4d85bebff2cd1722cd245cb7d08 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:46:43 +0100 Subject: [PATCH 19/21] chore: correct connect in init fn --- src/workflow-functions/bot.ts | 3 ++- src/workflow-functions/create-chat.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workflow-functions/bot.ts b/src/workflow-functions/bot.ts index 1ef4593..81befae 100644 --- a/src/workflow-functions/bot.ts +++ b/src/workflow-functions/bot.ts @@ -61,13 +61,14 @@ async function mtProtoInit(env: Context["env"], api: typeof Api) { TELEGRAM_API_HASH, clientParams ); + await client.connect(); + client.invoke(new api.auth.ImportBotAuthorization({ apiId: TELEGRAM_APP_ID, apiHash: TELEGRAM_API_HASH, botAuthToken: BOT_TOKEN, })); - await client.connect(); return client; } \ No newline at end of file diff --git a/src/workflow-functions/create-chat.ts b/src/workflow-functions/create-chat.ts index ade01e9..ca7ef6a 100644 --- a/src/workflow-functions/create-chat.ts +++ b/src/workflow-functions/create-chat.ts @@ -10,7 +10,6 @@ export async function createChat(context: Context<"issues.labeled", SupportedEve const mtProto = await MtProtoSingleton.getInstance(env); const client = mtProto.getClient(); - await client.connect(); const api = mtProto.getApi(); console.log("Creating chat with name: ", chatName); const chat = await client.invoke( From 995bddac78c3fb29a5b27fc80fbcbde64bd6312a Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:50:48 +0100 Subject: [PATCH 20/21] chore: use messages.createChat --- .github/workflows/compute.yml | 6 +++--- src/workflow-functions/create-chat.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/compute.yml b/.github/workflows/compute.yml index 7d778b5..85e12f3 100644 --- a/.github/workflows/compute.yml +++ b/.github/workflows/compute.yml @@ -1,4 +1,4 @@ -name: "the name of the plugin" +name: "Workflow Functions" on: workflow_dispatch: @@ -18,7 +18,7 @@ on: jobs: compute: - name: "plugin name" + name: "Telegram-Bot" runs-on: ubuntu-latest permissions: write-all env: @@ -50,7 +50,7 @@ jobs: - name: execute directive run: npx tsx ./src/workflow-entry.ts - id: plugin-name + id: telegram-bot env: SUPABASE_URL: ${{ secrets.SUPABASE_URL }} SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }} diff --git a/src/workflow-functions/create-chat.ts b/src/workflow-functions/create-chat.ts index ca7ef6a..73b8b39 100644 --- a/src/workflow-functions/create-chat.ts +++ b/src/workflow-functions/create-chat.ts @@ -13,9 +13,9 @@ export async function createChat(context: Context<"issues.labeled", SupportedEve const api = mtProto.getApi(); console.log("Creating chat with name: ", chatName); const chat = await client.invoke( - new api.channels.CreateChannel({ + new api.messages.CreateChat({ title: chatName, - broadcast: false, + users: [], }) ); From 3e0bc58392f0a36cdb873c6179ebb080cd3afa06 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:04:26 +0100 Subject: [PATCH 21/21] chore: revert to channels.createChannell --- src/workflow-functions/create-chat.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/workflow-functions/create-chat.ts b/src/workflow-functions/create-chat.ts index 73b8b39..7269fea 100644 --- a/src/workflow-functions/create-chat.ts +++ b/src/workflow-functions/create-chat.ts @@ -13,9 +13,10 @@ export async function createChat(context: Context<"issues.labeled", SupportedEve const api = mtProto.getApi(); console.log("Creating chat with name: ", chatName); const chat = await client.invoke( - new api.messages.CreateChat({ + new api.channels.CreateChannel({ title: chatName, - users: [], + broadcast: true, + about: payload.issue.body || "No description provided", }) );