Barazo AppView backend barazo.forum
at main 116 lines 3.7 kB view raw
1import { z } from 'zod/v4' 2 3// --------------------------------------------------------------------------- 4// Plugin source enum 5// --------------------------------------------------------------------------- 6 7const pluginSourceSchema = z.enum(['core', 'official', 'community', 'experimental']) 8 9export type PluginSource = z.infer<typeof pluginSourceSchema> 10 11// --------------------------------------------------------------------------- 12// Plugin setting schemas (discriminated union on `type`) 13// --------------------------------------------------------------------------- 14 15const booleanSettingSchema = z.object({ 16 type: z.literal('boolean'), 17 label: z.string().min(1), 18 description: z.string().optional(), 19 default: z.boolean(), 20}) 21 22const stringSettingSchema = z.object({ 23 type: z.literal('string'), 24 label: z.string().min(1), 25 description: z.string().optional(), 26 default: z.string(), 27 placeholder: z.string().optional(), 28}) 29 30const numberSettingSchema = z.object({ 31 type: z.literal('number'), 32 label: z.string().min(1), 33 description: z.string().optional(), 34 default: z.number(), 35 min: z.number().optional(), 36 max: z.number().optional(), 37}) 38 39const selectSettingSchema = z.object({ 40 type: z.literal('select'), 41 label: z.string().min(1), 42 description: z.string().optional(), 43 default: z.string(), 44 options: z.array(z.string()).min(1), 45}) 46 47const pluginSettingSchema = z.discriminatedUnion('type', [ 48 booleanSettingSchema, 49 stringSettingSchema, 50 numberSettingSchema, 51 selectSettingSchema, 52]) 53 54export type PluginSettingSchema = z.infer<typeof pluginSettingSchema> 55 56// --------------------------------------------------------------------------- 57// Plugin manifest schema 58// --------------------------------------------------------------------------- 59 60/** Name must be scoped @barazo/plugin-* or unscoped barazo-plugin-*. */ 61const pluginNamePattern = /^(@barazo\/plugin-[\w-]+|barazo-plugin-[\w-]+)$/ 62 63/** Strict semver: major.minor.patch with optional pre-release and build metadata. */ 64const semverPattern = /^\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/ 65 66/** Semver range expression (^, ~, >=, <, ||, *, x, etc.). */ 67const semverRangePattern = /^[\^~>=<|*\s\d.x-]+$/ 68 69export const pluginManifestSchema = z.object({ 70 // Required fields 71 name: z 72 .string() 73 .regex(pluginNamePattern, 'Plugin name must match @barazo/plugin-* or barazo-plugin-*'), 74 displayName: z.string().min(1).max(100), 75 version: z.string().regex(semverPattern, 'Version must be valid semver (e.g. 1.0.0)'), 76 description: z.string().min(1).max(500), 77 barazoVersion: z.string().regex(semverRangePattern, 'barazoVersion must be a valid semver range'), 78 source: pluginSourceSchema, 79 category: z.string().min(1).max(50), 80 author: z.object({ 81 name: z.string().min(1), 82 url: z.string().optional(), 83 }), 84 license: z.string().min(1), 85 permissions: z.object({ 86 backend: z.array(z.string()), 87 frontend: z.array(z.string()), 88 }), 89 90 // Optional fields 91 lexicons: z.array(z.string()).optional(), 92 dependencies: z.array(z.string()).optional(), 93 settings: z.record(z.string(), pluginSettingSchema).optional(), 94 hooks: z 95 .object({ 96 onInstall: z.string().optional(), 97 onUninstall: z.string().optional(), 98 onEnable: z.string().optional(), 99 onDisable: z.string().optional(), 100 onProfileSync: z.string().optional(), 101 }) 102 .optional(), 103 backend: z 104 .object({ 105 routes: z.string().optional(), 106 migrations: z.string().optional(), 107 }) 108 .optional(), 109 frontend: z 110 .object({ 111 register: z.string().optional(), 112 }) 113 .optional(), 114}) 115 116export type PluginManifest = z.infer<typeof pluginManifestSchema>