-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathplugin-validator.zod.ts
More file actions
185 lines (160 loc) · 5.52 KB
/
Copy pathplugin-validator.zod.ts
File metadata and controls
185 lines (160 loc) · 5.52 KB
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
import { z } from 'zod';
/**
* Plugin Validator Protocol
*
* Zod schemas for plugin validation data structures.
* These schemas align with the IPluginValidator contract interface.
*
* Following ObjectStack "Zod First" principle - all data structures
* must have Zod schemas for runtime validation and JSON Schema generation.
*/
// ============================================================================
// Validation Result Schemas
// ============================================================================
/**
* Validation Error Schema
* Represents a single validation error
*
* @example
* {
* "field": "version",
* "message": "Invalid semver format",
* "code": "INVALID_VERSION"
* }
*/
import { lazySchema } from '../shared/lazy-schema';
export const ValidationErrorSchema = lazySchema(() => z.object({
/**
* Field that failed validation
*/
field: z.string().describe('Field name that failed validation'),
/**
* Human-readable error message
*/
message: z.string().describe('Human-readable error message'),
/**
* Machine-readable error code (optional)
*/
code: z.string().optional().describe('Machine-readable error code'),
}));
export type ValidationError = z.input<typeof ValidationErrorSchema>;
/**
* Validation Warning Schema
* Represents a non-fatal validation warning
*
* @example
* {
* "field": "description",
* "message": "Description is empty",
* "code": "MISSING_DESCRIPTION"
* }
*/
export const ValidationWarningSchema = lazySchema(() => z.object({
/**
* Field with warning
*/
field: z.string().describe('Field name with warning'),
/**
* Human-readable warning message
*/
message: z.string().describe('Human-readable warning message'),
/**
* Machine-readable warning code (optional)
*/
code: z.string().optional().describe('Machine-readable warning code'),
}));
export type ValidationWarning = z.input<typeof ValidationWarningSchema>;
/**
* Validation Result Schema
* Result of plugin validation operation
*
* @example
* {
* "valid": false,
* "errors": [{
* "field": "name",
* "message": "Plugin name is required",
* "code": "REQUIRED_FIELD"
* }],
* "warnings": [{
* "field": "description",
* "message": "Description is recommended",
* "code": "MISSING_DESCRIPTION"
* }]
* }
*/
export const ValidationResultSchema = lazySchema(() => z.object({
/**
* Whether validation passed
*/
valid: z.boolean().describe('Whether the plugin passed validation'),
/**
* Validation errors (if any)
*/
errors: z.array(ValidationErrorSchema).optional().describe('Validation errors'),
/**
* Validation warnings (non-fatal issues)
*/
warnings: z.array(ValidationWarningSchema).optional().describe('Validation warnings'),
}));
export type ValidationResult = z.input<typeof ValidationResultSchema>;
// ============================================================================
// Plugin Metadata Schema
// ============================================================================
/**
* Plugin Schema
* Metadata structure for a plugin
*
* This aligns with and extends the existing PluginSchema from plugin.zod.ts
*
* @example
* {
* "name": "crm-plugin",
* "version": "1.0.0",
* "dependencies": ["core-plugin"]
* }
*/
export const PluginMetadataSchema = lazySchema(() => z.object({
/**
* Unique plugin identifier (snake_case)
*/
name: z.string().min(1).describe('Unique plugin identifier'),
/**
* Plugin version (semver)
*/
version: z.string().regex(/^\d+\.\d+\.\d+$/).optional().describe('Semantic version (e.g., 1.0.0)'),
/**
* Plugin dependencies (array of plugin names)
*/
dependencies: z.array(z.string()).optional().describe('Array of plugin names this plugin depends on (hard — a missing name fails the boot)'),
/**
* Soft dependencies — order-if-present (ADR-0116, #4131). The kernel
* hoists composed names ahead exactly like `dependencies`, and silently
* skips absent names instead of failing the boot. For plugins that
* degrade gracefully without the dependency but must never initialize
* before it when both are composed.
*/
optionalDependencies: z.array(z.string()).optional().describe('Plugin names hoisted ahead when composed, skipped when absent (order-if-present, ADR-0116)'),
/**
* Services the plugin resolves synchronously during init() (ADR-0116).
* The kernel validates the resolved order before Phase 1 — a required
* service whose only declared provider initializes later is a named boot
* error — and re-checks immediately before this plugin's init runs.
*/
requiresServices: z.array(z.string()).optional().describe('Service names the plugin resolves synchronously during init(); validated by the kernel before Phase 1 (ADR-0116)'),
/**
* Services the plugin's init() UNCONDITIONALLY registers (ADR-0116).
* Never declare a conditionally-registered service: the kernel would
* blame orderings this plugin cannot satisfy.
*/
providesServices: z.array(z.string()).optional().describe('Service names the plugin\'s init() unconditionally registers (ADR-0116)'),
/**
* Plugin signature for cryptographic verification (optional)
*/
signature: z.string().optional().describe('Cryptographic signature for plugin verification'),
/**
* Additional plugin metadata
*/
}).passthrough().describe('Plugin metadata for validation'));
export type PluginMetadata = z.input<typeof PluginMetadataSchema>;