forked from EduCraft/curriculum-project-hub
feat: archive bindings on Feishu lifecycle events
This commit is contained in:
@@ -106,6 +106,13 @@ export interface CardActionEvent {
|
||||
readonly token?: string;
|
||||
}
|
||||
|
||||
/** A binding-ending Feishu event delivered to this application's bot. */
|
||||
export interface FeishuBindingLifecycleEvent {
|
||||
readonly eventId: string;
|
||||
readonly chatId: string;
|
||||
readonly reason: "chat_dissolved" | "bot_removed";
|
||||
}
|
||||
|
||||
interface ContactBasicUser {
|
||||
readonly name?: string | undefined;
|
||||
readonly i18n_name?: {
|
||||
@@ -922,6 +929,7 @@ export async function startFeishuListenerWithClient(
|
||||
onMessage: (event: MessageReceiveEvent, rt: FeishuRuntime) => Promise<void>,
|
||||
onCardAction?: (event: CardActionEvent, rt: FeishuRuntime) => Promise<void>,
|
||||
onTerminalError?: (error: Error) => void,
|
||||
onBindingLifecycle?: (event: FeishuBindingLifecycleEvent) => Promise<void>,
|
||||
): Promise<FeishuRuntime> {
|
||||
let state: "STARTING" | "READY" | "FAILED" = "STARTING";
|
||||
let resolveReady!: () => void;
|
||||
@@ -963,6 +971,14 @@ export async function startFeishuListenerWithClient(
|
||||
.catch((e) => { logger.error({ err: e }, "feishu card action handler threw"); });
|
||||
};
|
||||
}
|
||||
if (onBindingLifecycle !== undefined) {
|
||||
handlers["im.chat.disbanded_v1"] = async (data) => {
|
||||
await dispatchBindingLifecycleEvent(data, "chat_dissolved", onBindingLifecycle, logger);
|
||||
};
|
||||
handlers["im.chat.member.bot.deleted_v1"] = async (data) => {
|
||||
await dispatchBindingLifecycleEvent(data, "bot_removed", onBindingLifecycle, logger);
|
||||
};
|
||||
}
|
||||
await wsClient.start({ eventDispatcher: new lark.EventDispatcher({}).register(handlers) });
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
const startupTimeout = new Promise<never>((_resolve, reject) => {
|
||||
@@ -977,6 +993,36 @@ export async function startFeishuListenerWithClient(
|
||||
return rt;
|
||||
}
|
||||
|
||||
async function dispatchBindingLifecycleEvent(
|
||||
data: unknown,
|
||||
reason: FeishuBindingLifecycleEvent["reason"],
|
||||
onBindingLifecycle: (event: FeishuBindingLifecycleEvent) => Promise<void>,
|
||||
logger: FastifyBaseLogger,
|
||||
): Promise<void> {
|
||||
const event = bindingLifecycleEventFrom(data, reason);
|
||||
if (event === null) {
|
||||
logger.warn({ reason }, "feishu binding lifecycle event missing chat id");
|
||||
return;
|
||||
}
|
||||
await onBindingLifecycle(event);
|
||||
}
|
||||
|
||||
function bindingLifecycleEventFrom(
|
||||
data: unknown,
|
||||
reason: FeishuBindingLifecycleEvent["reason"],
|
||||
): FeishuBindingLifecycleEvent | null {
|
||||
if (typeof data !== "object" || data === null) return null;
|
||||
const event = data as { readonly chat_id?: unknown; readonly event_id?: unknown; readonly header?: { readonly event_id?: unknown } };
|
||||
if (typeof event.chat_id !== "string" || event.chat_id.trim() === "") return null;
|
||||
const eventId = typeof event.event_id === "string" && event.event_id !== ""
|
||||
? event.event_id
|
||||
: typeof event.header?.event_id === "string" && event.header.event_id !== ""
|
||||
? event.header.event_id
|
||||
: undefined;
|
||||
if (eventId === undefined) return null;
|
||||
return { chatId: event.chat_id, reason, eventId };
|
||||
}
|
||||
|
||||
export async function startFeishuListener(
|
||||
config: FeishuConfig,
|
||||
logger: FastifyBaseLogger,
|
||||
|
||||
Reference in New Issue
Block a user