Skip to content

Commit

Permalink
chore: no proxy, PluginCallbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyrxng committed Nov 8, 2024
1 parent bec5cde commit 5115477
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 110 deletions.
5 changes: 3 additions & 2 deletions src/sdk/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { customOctokit } from "./octokit";
import { sanitizeMetadata } from "./util";
import { verifySignature } from "./signature";
import { KERNEL_PUBLIC_KEY } from "./constants";
import { CallbackBuilder, handlePluginCallbacks } from "./plugin-callbacks";

config();

Expand All @@ -32,7 +33,7 @@ const inputSchema = T.Object({
});

export async function createActionsPlugin<TConfig = unknown, TEnv = unknown, TSupportedEvents extends WebhookEventName = WebhookEventName>(
handler: (context: Context<TConfig, TEnv, TSupportedEvents>) => Promise<Record<string, unknown> | undefined>,
callbackBuilder: CallbackBuilder,
options?: Options
) {
const pluginOptions = {
Expand Down Expand Up @@ -90,7 +91,7 @@ export async function createActionsPlugin<TConfig = unknown, TEnv = unknown, TSu
};

try {
const result = await handler(context);
const result = await handlePluginCallbacks(context, callbackBuilder);
core.setOutput("result", result);
await returnDataToKernel(pluginGithubToken, inputs.stateId, result);
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export { createPlugin } from "./server";
export { createActionsPlugin } from "./actions";
export { CallbackBuilder } from "./proxy-callbacks";
export { CallbackBuilder } from "./plugin-callbacks";
export { postComment } from "./comment";
export type { Context } from "./context";
export * from "./constants";
Expand Down
101 changes: 101 additions & 0 deletions src/sdk/plugin-callbacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { Context, SupportedEventsU } from "./context";
import { CallbackFunction, PluginCallbacks } from "../types/helpers";
import { postWorkerErrorComment } from "./errors";

/**
* Build your callbacks first and pass `CallbackBuilder` directly to `createPlugin`.
*
* @example
```ts
const builder = new CallbackBuilder()
.addCallback("issue_comment.created", <CallbackFunction<"issue_comment.created">>helloWorld)
.addCallback("issue_comment.deleted", <CallbackFunction<"issue_comment.deleted">>goodbyeCruelWorld);
```
*/
export class CallbackBuilder {
private _callbacks: PluginCallbacks = {} as PluginCallbacks;

/**
* Add a callback for the given event.
*
* @param event The event to add a callback for.
* @param callback The callback to add.
*/
addCallback<TEvent extends SupportedEventsU>(event: TEvent, callback: CallbackFunction<TEvent>) {
this._callbacks[event] ??= [];
this._callbacks[event].push(callback);
return this;
}

/**
* Add multiple callbacks for the given event.
*
* @param event The event to add callbacks for.
* @param callbacks The callbacks to add.
*/
addCallbacks<TEvent extends SupportedEventsU>(event: TEvent, callbacks: CallbackFunction<TEvent>[]) {
this._callbacks[event] ??= [];
this._callbacks[event].push(...callbacks);
return this;
}

/**
* This simply returns the callbacks object.
*/
build() {
return this._callbacks;
}
}

export async function handlePluginCallbacks(context: Context, callbackBuilder: CallbackBuilder) {
const { eventName } = context;
const callbacks = callbackBuilder.build()[eventName];

if (!callbacks || !callbacks.length) {
context.logger.info(`No callbacks found for event ${eventName}`);
return { status: 204, reason: "skipped" };
}

try {
const res = await Promise.all(callbacks.map((callback) => handleCallback(callback, context)));
context.logger.info(`${eventName} callbacks completed`, { res });
let hasFailed = false;
for (const r of res) {
if (r.status === 500) {
await postWorkerErrorComment(context, context.logger.error(r.reason, { content: r.content }));
hasFailed = true;
} else if (r.status === 404) {
context.logger.error(r.reason, { content: r.content });
} else if (r.status === 204) {
context.logger.info(r.reason, { content: r.content });
} else {
context.logger.ok(r.reason, { content: r.content });
}
}

if (hasFailed) {
return { status: 500, reason: `One or more callbacks failed for event ${eventName}` };
}
return { status: 200, reason: "success" };
} catch (er) {
await postWorkerErrorComment(context, context.logger.fatal("Error in handlePluginCallbacks", { er }));
return { status: 500, reason: "error", content: String(er) };
}
}

/**
* Why do we need this wrapper function?
*
* By using a generic `Function` type for the callback parameter, we bypass strict type
* checking temporarily. This allows us to pass a standard `Context` object, which we know
* contains the correct event and payload types, to the callback safely.
*
* We can trust that the `ProxyCallbacks` type has already ensured that each callback function
* matches the expected event and payload types, so this function provides a safe and
* flexible way to handle callbacks without introducing type or logic errors.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
function handleCallback(callback: Function, context: Context) {
return callback(context);
}
104 changes: 0 additions & 104 deletions src/sdk/proxy-callbacks.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/sdk/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { verifySignature } from "./signature";
import { env as honoEnv } from "hono/adapter";
import { postComment } from "./comment";
import { Type as T } from "@sinclair/typebox";
import { CallbackBuilder, handleProxyCallbacks, proxyCallbacks } from "./proxy-callbacks";
import { CallbackBuilder, handlePluginCallbacks } from "./plugin-callbacks";
import { postWorkerErrorComment } from "./errors";

interface Options {
Expand Down Expand Up @@ -106,7 +106,7 @@ export function createPlugin<TConfig = unknown, TEnv = unknown, TSupportedEvents
};

try {
const result = await handleProxyCallbacks(proxyCallbacks(context, callbackBuilder), context);
const result = await handlePluginCallbacks(context, callbackBuilder);
return ctx.json({ stateId: inputs.stateId, output: result });
} catch (error) {
console.error(error);
Expand Down
2 changes: 1 addition & 1 deletion src/types/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ export type CallbackFunction<TEvent extends SupportedEventsU, TConfig = Record<s
* ```
*/

export type ProxyCallbacks = {
export type PluginCallbacks = {
[K in SupportedEventsU]: Array<CallbackFunction<K>>;
};

0 comments on commit 5115477

Please sign in to comment.