1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
import { z } from "zod";
// Every kind of data source the dashboard knows how to show.
// "todos" is local data (no fetcher) — the others pull from the network/disk.
export const SOURCE_KINDS = [
"weather",
"news",
"briefs",
"feeds",
"onthisday",
"sports",
"calendar",
"mastodon",
"bluesky",
"github",
"vercel",
"aqi",
"markets",
"hackernews",
"uptime",
"obsidian",
"todos",
"links",
"cider",
] as const;
export const SourceKind = z.enum(SOURCE_KINDS);
export type SourceKind = z.infer<typeof SourceKind>;
// Bento tile sizes → grid spans (see lib/layout.ts).
export const SOURCE_SIZES = ["sm", "md", "wide", "tall", "lg"] as const;
export const SourceSize = z.enum(SOURCE_SIZES);
export type SourceSize = z.infer<typeof SourceSize>;
// Per-source config is free-form JSON validated by each source module's own
// configSchema. At the table level it's an opaque object.
export const SourceConfig = z.record(z.string(), z.unknown());
export type SourceConfig = z.infer<typeof SourceConfig>;
export const Source = z.object({
id: z.string(),
kind: SourceKind,
label: z.string().min(1).max(80),
enabled: z.boolean().default(true),
config: SourceConfig.default({}),
refreshSeconds: z.number().int().min(30).max(86_400).default(900),
position: z.number().int().default(0),
size: SourceSize.default("md"), // vestigial; layout now uses cols/rows
cols: z.number().int().min(1).max(6).default(1), // grid column span
rows: z.number().int().min(1).max(8).default(2), // grid row span
});
export type Source = z.infer<typeof Source>;
export const UpdateSource = Source.partial().omit({ id: true, kind: true });
export type UpdateSource = z.infer<typeof UpdateSource>;
|