Makelore 2.0 initial clean snapshot
This commit is contained in:
268
shared/user-sync.ts
Normal file
268
shared/user-sync.ts
Normal file
@@ -0,0 +1,268 @@
|
||||
export type UserSyncTheme = 'light' | 'dark' | 'system';
|
||||
|
||||
export type UserSyncPreferences = {
|
||||
theme?: UserSyncTheme;
|
||||
language?: string;
|
||||
defaultModel?: string;
|
||||
defaultProviderAccountId?: string;
|
||||
sidebarCollapsed?: boolean;
|
||||
devModeUnlocked?: boolean;
|
||||
selectedBundles?: string[];
|
||||
enabledSkills?: string[];
|
||||
disabledSkills?: string[];
|
||||
};
|
||||
|
||||
export type UserSyncProviderAccount = {
|
||||
id: string;
|
||||
vendorId: string;
|
||||
label: string;
|
||||
authMode: string;
|
||||
baseUrl?: string;
|
||||
apiProtocol?: string;
|
||||
model?: string;
|
||||
fallbackModels?: string[];
|
||||
fallbackAccountIds?: string[];
|
||||
enabled: boolean;
|
||||
isDefault: boolean;
|
||||
metadata: Record<string, unknown>;
|
||||
updatedAt?: string;
|
||||
};
|
||||
|
||||
export type UserSyncPartner = {
|
||||
id: string;
|
||||
displayName: string;
|
||||
templateRoleId: string;
|
||||
description?: string;
|
||||
avatarTone?: string;
|
||||
avatarDataUrl?: string;
|
||||
prompt?: string;
|
||||
skillIds?: string[];
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
};
|
||||
|
||||
export type UserSyncUsageAggregate = {
|
||||
date: string;
|
||||
model?: string;
|
||||
providerAccountId?: string;
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
cacheReadTokens: number;
|
||||
cacheWriteTokens: number;
|
||||
estimatedCostUsd: number;
|
||||
requestCount: number;
|
||||
};
|
||||
|
||||
export type UserSyncBootstrap = {
|
||||
preferences: UserSyncPreferences;
|
||||
providerAccounts: UserSyncProviderAccount[];
|
||||
partners: UserSyncPartner[];
|
||||
usageAggregates: UserSyncUsageAggregate[];
|
||||
};
|
||||
|
||||
type UnknownRecord = Record<string, unknown>;
|
||||
|
||||
function isRecord(value: unknown): value is UnknownRecord {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function text(value: unknown): string | undefined {
|
||||
if (typeof value !== 'string') return undefined;
|
||||
const trimmed = value.trim();
|
||||
return trimmed || undefined;
|
||||
}
|
||||
|
||||
function bool(value: unknown): boolean | undefined {
|
||||
return typeof value === 'boolean' ? value : undefined;
|
||||
}
|
||||
|
||||
function stringArray(value: unknown): string[] | undefined {
|
||||
if (!Array.isArray(value)) return undefined;
|
||||
const seen = new Set<string>();
|
||||
const result: string[] = [];
|
||||
for (const item of value) {
|
||||
const clean = text(item);
|
||||
if (clean && !seen.has(clean)) {
|
||||
seen.add(clean);
|
||||
result.push(clean);
|
||||
}
|
||||
}
|
||||
return result.length ? result : undefined;
|
||||
}
|
||||
|
||||
function plainMetadata(value: unknown): Record<string, unknown> {
|
||||
if (!isRecord(value)) return {};
|
||||
const result: Record<string, unknown> = {};
|
||||
for (const [key, entry] of Object.entries(value)) {
|
||||
if (entry === undefined || typeof entry === 'function') continue;
|
||||
result[key] = entry;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function compact<T extends Record<string, unknown>>(value: T): Partial<T> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).filter(([, entry]) => entry !== undefined),
|
||||
) as Partial<T>;
|
||||
}
|
||||
|
||||
function oneOfTheme(value: unknown): UserSyncTheme | undefined {
|
||||
return value === 'light' || value === 'dark' || value === 'system' ? value : undefined;
|
||||
}
|
||||
|
||||
function numberValue(value: unknown): number | undefined {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
||||
}
|
||||
|
||||
export function toUserSyncPreferences(
|
||||
input: unknown,
|
||||
defaultProviderAccountId?: string | null,
|
||||
): UserSyncPreferences {
|
||||
const record = isRecord(input) ? input : {};
|
||||
return compact({
|
||||
theme: oneOfTheme(record.theme),
|
||||
language: text(record.language),
|
||||
defaultModel: text(record.defaultModel ?? record.default_model),
|
||||
defaultProviderAccountId: text(defaultProviderAccountId) ?? text(record.defaultProviderAccountId ?? record.default_provider_account_id),
|
||||
sidebarCollapsed: bool(record.sidebarCollapsed ?? record.sidebar_collapsed),
|
||||
devModeUnlocked: bool(record.devModeUnlocked ?? record.dev_mode_unlocked),
|
||||
selectedBundles: stringArray(record.selectedBundles ?? record.selected_bundles),
|
||||
enabledSkills: stringArray(record.enabledSkills ?? record.enabled_skills),
|
||||
disabledSkills: stringArray(record.disabledSkills ?? record.disabled_skills),
|
||||
});
|
||||
}
|
||||
|
||||
export function toUserSyncProviderAccount(input: unknown): UserSyncProviderAccount {
|
||||
const record = isRecord(input) ? input : {};
|
||||
return compact({
|
||||
id: text(record.id),
|
||||
vendorId: text(record.vendorId ?? record.vendor_id),
|
||||
label: text(record.label),
|
||||
authMode: text(record.authMode ?? record.auth_mode),
|
||||
baseUrl: text(record.baseUrl ?? record.base_url),
|
||||
apiProtocol: text(record.apiProtocol ?? record.api_protocol),
|
||||
model: text(record.model),
|
||||
fallbackModels: stringArray(record.fallbackModels ?? record.fallback_models),
|
||||
fallbackAccountIds: stringArray(record.fallbackAccountIds ?? record.fallback_account_ids),
|
||||
enabled: bool(record.enabled) ?? true,
|
||||
isDefault: bool(record.isDefault ?? record.is_default) ?? false,
|
||||
metadata: plainMetadata(record.metadata),
|
||||
updatedAt: text(record.updatedAt ?? record.updated_at),
|
||||
}) as UserSyncProviderAccount;
|
||||
}
|
||||
|
||||
export function toUserSyncPartner(input: unknown): UserSyncPartner {
|
||||
const record = isRecord(input) ? input : {};
|
||||
return compact({
|
||||
id: text(record.id),
|
||||
displayName: text(record.displayName ?? record.display_name),
|
||||
templateRoleId: text(record.templateRoleId ?? record.template_role_id),
|
||||
description: text(record.description),
|
||||
avatarTone: text(record.avatarTone ?? record.avatar_tone),
|
||||
avatarDataUrl: text(record.avatarDataUrl ?? record.avatar_data_url),
|
||||
prompt: text(record.prompt),
|
||||
skillIds: stringArray(record.skillIds ?? record.skill_ids),
|
||||
createdAt: text(record.createdAt ?? record.created_at),
|
||||
updatedAt: text(record.updatedAt ?? record.updated_at),
|
||||
}) as UserSyncPartner;
|
||||
}
|
||||
|
||||
export function toServerUserSyncPreferences(input: unknown): UnknownRecord {
|
||||
const preferences = toUserSyncPreferences(input);
|
||||
return compact({
|
||||
theme: preferences.theme,
|
||||
language: preferences.language,
|
||||
default_model: preferences.defaultModel,
|
||||
default_provider_account_id: preferences.defaultProviderAccountId,
|
||||
sidebar_collapsed: preferences.sidebarCollapsed,
|
||||
dev_mode_unlocked: preferences.devModeUnlocked,
|
||||
selected_bundles: preferences.selectedBundles,
|
||||
enabled_skills: preferences.enabledSkills,
|
||||
disabled_skills: preferences.disabledSkills,
|
||||
});
|
||||
}
|
||||
|
||||
export function toServerUserSyncProviderAccount(input: unknown): UnknownRecord {
|
||||
const account = toUserSyncProviderAccount(input);
|
||||
return compact({
|
||||
id: account.id,
|
||||
vendor_id: account.vendorId,
|
||||
label: account.label,
|
||||
auth_mode: account.authMode,
|
||||
base_url: account.baseUrl,
|
||||
api_protocol: account.apiProtocol,
|
||||
model: account.model,
|
||||
fallback_models: account.fallbackModels,
|
||||
fallback_account_ids: account.fallbackAccountIds,
|
||||
enabled: account.enabled,
|
||||
is_default: account.isDefault,
|
||||
metadata: account.metadata,
|
||||
updated_at: account.updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
export function toServerUserSyncPartner(input: unknown): UnknownRecord {
|
||||
const partner = toUserSyncPartner(input);
|
||||
return compact({
|
||||
id: partner.id,
|
||||
display_name: partner.displayName,
|
||||
template_role_id: partner.templateRoleId,
|
||||
description: partner.description,
|
||||
avatar_tone: partner.avatarTone,
|
||||
avatar_data_url: partner.avatarDataUrl,
|
||||
prompt: partner.prompt,
|
||||
skill_ids: partner.skillIds,
|
||||
created_at: partner.createdAt,
|
||||
updated_at: partner.updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
export function normalizeUserSyncBootstrap(input: unknown): UserSyncBootstrap {
|
||||
const record = isRecord(input) ? input : {};
|
||||
const rawProviderAccounts = record.providerAccounts ?? record.provider_accounts;
|
||||
const rawPartners = record.partners;
|
||||
const rawUsageAggregates = record.usageAggregates ?? record.usage_aggregates;
|
||||
const providerAccounts = Array.isArray(rawProviderAccounts)
|
||||
? rawProviderAccounts.map(toUserSyncProviderAccount).filter(hasProviderIdentity)
|
||||
: [];
|
||||
const partners = Array.isArray(rawPartners)
|
||||
? rawPartners.map(toUserSyncPartner).filter(hasPartnerIdentity)
|
||||
: [];
|
||||
const usageAggregates = Array.isArray(rawUsageAggregates)
|
||||
? rawUsageAggregates.map(toUserSyncUsageAggregate).filter(hasUsageDate)
|
||||
: [];
|
||||
|
||||
return {
|
||||
preferences: toUserSyncPreferences(record.preferences),
|
||||
providerAccounts,
|
||||
partners,
|
||||
usageAggregates,
|
||||
};
|
||||
}
|
||||
|
||||
function hasProviderIdentity(account: UserSyncProviderAccount): boolean {
|
||||
return Boolean(account.id && account.vendorId && account.label && account.authMode);
|
||||
}
|
||||
|
||||
function hasPartnerIdentity(partner: UserSyncPartner): boolean {
|
||||
return Boolean(partner.id && partner.displayName && partner.templateRoleId);
|
||||
}
|
||||
|
||||
function hasUsageDate(aggregate: UserSyncUsageAggregate): boolean {
|
||||
return Boolean(aggregate.date);
|
||||
}
|
||||
|
||||
function toUserSyncUsageAggregate(input: unknown): UserSyncUsageAggregate {
|
||||
const record = isRecord(input) ? input : {};
|
||||
return compact({
|
||||
date: text(record.date),
|
||||
model: text(record.model),
|
||||
providerAccountId: text(record.providerAccountId ?? record.provider_account_id),
|
||||
inputTokens: numberValue(record.inputTokens ?? record.input_tokens) ?? 0,
|
||||
outputTokens: numberValue(record.outputTokens ?? record.output_tokens) ?? 0,
|
||||
cacheReadTokens: numberValue(record.cacheReadTokens ?? record.cache_read_tokens) ?? 0,
|
||||
cacheWriteTokens: numberValue(record.cacheWriteTokens ?? record.cache_write_tokens) ?? 0,
|
||||
estimatedCostUsd: numberValue(record.estimatedCostUsd ?? record.estimated_cost_usd) ?? 0,
|
||||
requestCount: numberValue(record.requestCount ?? record.request_count) ?? 0,
|
||||
}) as UserSyncUsageAggregate;
|
||||
}
|
||||
Reference in New Issue
Block a user