SPB Git forge

spb/websensor

Public
33commits 1branches 0releases
3.4 MBsize
maindefault branch
10 days agolast push
TypeScript 55.4% Python 43.2% SQL 1.2%
3.3 KB · 70 lines typescript
Raw Blame History
1import { z } from "zod";2import { SENSOR_TYPES, TIERS } from "./taxonomy";34/**5 * Source-registry seed schema (shared by the engine's seed loader, the validator CLI and the6 * API's bulk-import endpoint). Dependency-free apart from zod; no filesystem access here.7 */8export const sensorSchema = z.object({9  id: z.string().optional(),10  name: z.string(),11  url: z.string().url(),12  type: z.enum(SENSOR_TYPES),13  connector: z.string().default("http"),14  tier: z.enum(TIERS).optional(),15  interval: z.number().int().positive().optional(),16  weight: z.number().positive().optional(),17  config: z.record(z.string(), z.unknown()).default({}),18});19export type SensorSeed = z.infer<typeof sensorSchema>;2021export const productSchema = z.object({ id: z.string().optional(), name: z.string(), type: z.string().default("product"), aliases: z.array(z.string()).default([]) });2223export const sourceSchema = z.object({24  id: z.string().regex(/^[a-z0-9][a-z0-9-]*$/, "id must be kebab-case"),25  name: z.string(),26  domain: z.string(),27  homepage: z.string().url().optional(),28  description: z.string().optional(),29  categories: z.array(z.string()).default([]),30  tier: z.enum(TIERS).default("B"),31  weight: z.number().positive().default(1),32  entity_type: z.string().default("organization"),33  aliases: z.array(z.string()).default([]),34  products: z.array(productSchema).default([]),35  discover: z.object({ rss: z.boolean().optional(), sitemap: z.boolean().optional(), status: z.boolean().optional(), pages: z.boolean().optional() }).default({}),36  fallback: z.object({ firecrawl: z.boolean().optional(), scrapfly: z.boolean().optional() }).default({}),37  sensors: z.array(sensorSchema).default([]),38  notes: z.string().optional(),39  enabled: z.boolean().default(true),40  /** false = heuristics only (high-volume feeds such as news wires) */41  llm: z.boolean().default(true),42  /** ISO 3166-1 alpha-2 (upper-case) when the organization is national/regional; "EU" for EU bodies; "INT" for global bodies */43  country: z.string().regex(/^[A-Z]{2,3}$/).optional(),44  /** primary language of the published content (ISO 639-1); defaults to "en" downstream */45  language: z.string().regex(/^[a-z]{2}$/).optional(),46  /** false for media/aggregators reporting about others (news wires, tech press); true for the organization's own channels */47  first_party: z.boolean().optional(),48  /** fragment-only: merge into an already declared source instead of redefining it */49  extend: z.boolean().default(false),50});51export type SourceSeed = z.infer<typeof sourceSchema>;5253/** Partial schema for `extend: true` entries — only `id` is required. */54export const extendSchema = z.object({55  id: z.string(),56  extend: z.literal(true),57  aliases: z.array(z.string()).default([]),58  products: z.array(productSchema).default([]),59  sensors: z.array(sensorSchema).default([]),60  categories: z.array(z.string()).default([]),61  fallback: z.object({ firecrawl: z.boolean().optional(), scrapfly: z.boolean().optional() }).optional(),62  notes: z.string().optional(),63  country: z.string().regex(/^[A-Z]{2,3}$/).optional(),64  language: z.string().regex(/^[a-z]{2}$/).optional(),65  first_party: z.boolean().optional(),66});6768/** Bulk import document (JSON / YAML already parsed): `{ sources: [...] }`. */69export const importDocumentSchema = z.object({ sources: z.array(z.unknown()).min(1).max(2000) });70