85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
import type { ClawdbotConfig } from "../config/config.js";
|
|
import type { SlackChannelConfig } from "../config/types.slack.js";
|
|
import { normalizeAccountId } from "../routing/session-key.js";
|
|
|
|
type SlackChannels = Record<string, SlackChannelConfig>;
|
|
|
|
type MigrationScope = "account" | "global";
|
|
|
|
export type SlackChannelMigrationResult = {
|
|
migrated: boolean;
|
|
skippedExisting: boolean;
|
|
scopes: MigrationScope[];
|
|
};
|
|
|
|
function resolveAccountChannels(
|
|
cfg: ClawdbotConfig,
|
|
accountId?: string | null,
|
|
): { channels?: SlackChannels } {
|
|
if (!accountId) return {};
|
|
const normalized = normalizeAccountId(accountId);
|
|
const accounts = cfg.channels?.slack?.accounts;
|
|
if (!accounts || typeof accounts !== "object") return {};
|
|
const exact = accounts[normalized];
|
|
if (exact?.channels) return { channels: exact.channels };
|
|
const matchKey = Object.keys(accounts).find(
|
|
(key) => key.toLowerCase() === normalized.toLowerCase(),
|
|
);
|
|
return { channels: matchKey ? accounts[matchKey]?.channels : undefined };
|
|
}
|
|
|
|
export function migrateSlackChannelsInPlace(
|
|
channels: SlackChannels | undefined,
|
|
oldChannelId: string,
|
|
newChannelId: string,
|
|
): { migrated: boolean; skippedExisting: boolean } {
|
|
if (!channels) return { migrated: false, skippedExisting: false };
|
|
if (oldChannelId === newChannelId) return { migrated: false, skippedExisting: false };
|
|
if (!Object.hasOwn(channels, oldChannelId)) return { migrated: false, skippedExisting: false };
|
|
if (Object.hasOwn(channels, newChannelId)) return { migrated: false, skippedExisting: true };
|
|
channels[newChannelId] = channels[oldChannelId];
|
|
delete channels[oldChannelId];
|
|
return { migrated: true, skippedExisting: false };
|
|
}
|
|
|
|
export function migrateSlackChannelConfig(params: {
|
|
cfg: ClawdbotConfig;
|
|
accountId?: string | null;
|
|
oldChannelId: string;
|
|
newChannelId: string;
|
|
}): SlackChannelMigrationResult {
|
|
const scopes: MigrationScope[] = [];
|
|
let migrated = false;
|
|
let skippedExisting = false;
|
|
|
|
const accountChannels = resolveAccountChannels(params.cfg, params.accountId).channels;
|
|
if (accountChannels) {
|
|
const result = migrateSlackChannelsInPlace(
|
|
accountChannels,
|
|
params.oldChannelId,
|
|
params.newChannelId,
|
|
);
|
|
if (result.migrated) {
|
|
migrated = true;
|
|
scopes.push("account");
|
|
}
|
|
if (result.skippedExisting) skippedExisting = true;
|
|
}
|
|
|
|
const globalChannels = params.cfg.channels?.slack?.channels;
|
|
if (globalChannels) {
|
|
const result = migrateSlackChannelsInPlace(
|
|
globalChannels,
|
|
params.oldChannelId,
|
|
params.newChannelId,
|
|
);
|
|
if (result.migrated) {
|
|
migrated = true;
|
|
scopes.push("global");
|
|
}
|
|
if (result.skippedExisting) skippedExisting = true;
|
|
}
|
|
|
|
return { migrated, skippedExisting, scopes };
|
|
}
|