Skip to content

Commit

Permalink
feat: validation config
Browse files Browse the repository at this point in the history
  • Loading branch information
hywax committed Jan 5, 2024
1 parent 6094ba0 commit 349b546
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 10 deletions.
2 changes: 1 addition & 1 deletion composables/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface ServiceDataOptions {
}

export function useServiceData<T extends BaseService, R>(service: T, options?: ServiceDataOptions) {
const immediate = options?.immediate || true
const immediate = options?.immediate || false
const updateInterval = (options?.updateInterval || 60) * 1000
const type = service.type || 'base'

Expand Down
71 changes: 63 additions & 8 deletions server/utils/config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import crypto from 'node:crypto'
import yaml from 'yaml'
import defu from 'defu'
import { ZodError, z } from 'zod'
import type { BaseService, CompleteConfig } from '~/types'

type draftService = Omit<BaseService, 'id'>
type DraftService = Omit<BaseService, 'id'>

function determineServiceId(items: draftService[]): BaseService[] {
function determineServiceId(items: DraftService[]): BaseService[] {
return items.map((item) => ({
id: crypto.randomUUID(),
...item,
Expand All @@ -17,30 +18,72 @@ export function getDefaultConfig(): CompleteConfig {
title: 'Mafl Home Page',
lang: 'en',
theme: 'system',
services: [],
checkUpdates: true,
services: [],
}
}

export function validateConfigSchema(config: any) {
const status = z.object({
enabled: z.boolean().optional(),
interval: z.number().optional(),
})

const icon = z.object({
url: z.string().optional(),
name: z.string().optional(),
wrap: z.boolean().optional(),
background: z.string().optional(),
color: z.string().optional(),
})

const service = z.object({
title: z.string(),
description: z.string().optional(),
link: z.string(),
icon: icon.optional(),
status: status.optional(),
type: z.string().optional(),
options: z.record(z.string()).optional(),
secrets: z.record(z.string()).optional(),
})

const schema = z.object({
title: z.string().optional(),
lang: z.string().optional(),
theme: z.string().optional(),
checkUpdates: z.boolean().optional(),
services: z.union([
z.array(service),
z.record(z.array(service)),
]),
})

return schema.parse(config)
}

export async function loadLocalConfig(): Promise<CompleteConfig> {
const defaultConfig = getDefaultConfig()
const storage = useStorage('data')
const file = 'config.yml'

try {
if (!await storage.hasItem(file)) {
return getDefaultConfig()
throw new Error('Config not found')
}

const raw = await storage.getItem<string>(file)
const config = yaml.parse(raw || '') || {}
const services: CompleteConfig['services'] = []

validateConfigSchema(config)

if (Array.isArray(config.services)) {
services.push({
items: determineServiceId(config.services),
})
} else {
const entries = Object.entries<draftService[]>(config.services || [])
const entries = Object.entries<DraftService[]>(config.services || [])

for (const [title, items] of entries) {
services.push({
Expand All @@ -50,12 +93,24 @@ export async function loadLocalConfig(): Promise<CompleteConfig> {
}
}

return defu({ ...config, services }, getDefaultConfig())
return defu({ ...config, services }, defaultConfig)
} catch (e) {
// ...
logger.error(e)

if (e instanceof Error) {
defaultConfig.error = e.message
}

if (e instanceof ZodError) {
defaultConfig.error = JSON.stringify(
e.format(),
(key, val) => (key === '_errors' && !val.length) ? undefined : val,
' ',
)
}
}

return getDefaultConfig()
return defaultConfig
}

export async function getLocalConfig(): Promise<CompleteConfig | null> {
Expand Down
4 changes: 3 additions & 1 deletion types/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ export interface Config {
checkUpdates: boolean
}

export type CompleteConfig = Required<Config>
export type CompleteConfig = Required<Config> & {
error?: string
}

0 comments on commit 349b546

Please sign in to comment.