@dependabit/manifest 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,293 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ DependencyManifestSchema,
4
+ DependencyEntrySchema,
5
+ DependabitConfigSchema,
6
+ AccessMethodSchema,
7
+ DependencyTypeSchema,
8
+ DetectionMethodSchema,
9
+ SeveritySchema
10
+ } from '../src/schema.js';
11
+
12
+ describe('Schema Tests', () => {
13
+ describe('AccessMethodSchema', () => {
14
+ it('should accept valid access methods', () => {
15
+ expect(AccessMethodSchema.parse('context7')).toBe('context7');
16
+ expect(AccessMethodSchema.parse('arxiv')).toBe('arxiv');
17
+ expect(AccessMethodSchema.parse('openapi')).toBe('openapi');
18
+ expect(AccessMethodSchema.parse('github-api')).toBe('github-api');
19
+ expect(AccessMethodSchema.parse('http')).toBe('http');
20
+ });
21
+
22
+ it('should reject invalid access methods', () => {
23
+ expect(() => AccessMethodSchema.parse('invalid')).toThrow();
24
+ });
25
+ });
26
+
27
+ describe('DependencyTypeSchema', () => {
28
+ it('should accept valid dependency types', () => {
29
+ expect(DependencyTypeSchema.parse('reference-implementation')).toBe(
30
+ 'reference-implementation'
31
+ );
32
+ expect(DependencyTypeSchema.parse('schema')).toBe('schema');
33
+ expect(DependencyTypeSchema.parse('documentation')).toBe('documentation');
34
+ });
35
+
36
+ it('should reject invalid dependency types', () => {
37
+ expect(() => DependencyTypeSchema.parse('invalid')).toThrow();
38
+ });
39
+ });
40
+
41
+ describe('DetectionMethodSchema', () => {
42
+ it('should accept valid detection methods', () => {
43
+ expect(DetectionMethodSchema.parse('llm-analysis')).toBe('llm-analysis');
44
+ expect(DetectionMethodSchema.parse('manual')).toBe('manual');
45
+ expect(DetectionMethodSchema.parse('package-json')).toBe('package-json');
46
+ });
47
+ });
48
+
49
+ describe('SeveritySchema', () => {
50
+ it('should accept valid severity levels', () => {
51
+ expect(SeveritySchema.parse('breaking')).toBe('breaking');
52
+ expect(SeveritySchema.parse('major')).toBe('major');
53
+ expect(SeveritySchema.parse('minor')).toBe('minor');
54
+ });
55
+ });
56
+
57
+ describe('DependencyEntrySchema', () => {
58
+ it('should validate a complete dependency entry', () => {
59
+ const entry = {
60
+ id: '550e8400-e29b-41d4-a716-446655440000',
61
+ url: 'https://github.com/microsoft/TypeScript',
62
+ type: 'reference-implementation',
63
+ accessMethod: 'github-api',
64
+ name: 'TypeScript',
65
+ description: 'TypeScript compiler',
66
+ currentVersion: '5.9.3',
67
+ currentStateHash: 'sha256:abc123',
68
+ detectionMethod: 'package-json',
69
+ detectionConfidence: 1.0,
70
+ detectedAt: '2026-01-29T10:30:00Z',
71
+ lastChecked: '2026-01-29T10:30:00Z',
72
+ auth: undefined,
73
+ referencedIn: [
74
+ {
75
+ file: 'package.json',
76
+ line: 15,
77
+ context: '"typescript": "^5.9.3"'
78
+ }
79
+ ],
80
+ changeHistory: []
81
+ };
82
+
83
+ const result = DependencyEntrySchema.parse(entry);
84
+ expect(result.id).toBe(entry.id);
85
+ expect(result.name).toBe('TypeScript');
86
+ });
87
+
88
+ it('should require all mandatory fields', () => {
89
+ expect(() =>
90
+ DependencyEntrySchema.parse({
91
+ url: 'https://example.com'
92
+ })
93
+ ).toThrow();
94
+ });
95
+
96
+ it('should validate UUID format', () => {
97
+ const entry = {
98
+ id: 'not-a-uuid',
99
+ url: 'https://github.com/microsoft/TypeScript',
100
+ type: 'reference-implementation',
101
+ accessMethod: 'github-api',
102
+ name: 'TypeScript',
103
+ currentStateHash: 'sha256:abc123',
104
+ detectionMethod: 'manual',
105
+ detectionConfidence: 1.0,
106
+ detectedAt: '2026-01-29T10:30:00Z',
107
+ lastChecked: '2026-01-29T10:30:00Z',
108
+ referencedIn: []
109
+ };
110
+
111
+ expect(() => DependencyEntrySchema.parse(entry)).toThrow();
112
+ });
113
+
114
+ it('should validate URL format', () => {
115
+ const entry = {
116
+ id: '550e8400-e29b-41d4-a716-446655440000',
117
+ url: 'not-a-url',
118
+ type: 'reference-implementation',
119
+ accessMethod: 'github-api',
120
+ name: 'TypeScript',
121
+ currentStateHash: 'sha256:abc123',
122
+ detectionMethod: 'manual',
123
+ detectionConfidence: 1.0,
124
+ detectedAt: '2026-01-29T10:30:00Z',
125
+ lastChecked: '2026-01-29T10:30:00Z',
126
+ referencedIn: []
127
+ };
128
+
129
+ expect(() => DependencyEntrySchema.parse(entry)).toThrow();
130
+ });
131
+
132
+ it('should validate confidence range', () => {
133
+ const entry = {
134
+ id: '550e8400-e29b-41d4-a716-446655440000',
135
+ url: 'https://github.com/microsoft/TypeScript',
136
+ type: 'reference-implementation',
137
+ accessMethod: 'github-api',
138
+ name: 'TypeScript',
139
+ currentStateHash: 'sha256:abc123',
140
+ detectionMethod: 'manual',
141
+ detectionConfidence: 1.5,
142
+ detectedAt: '2026-01-29T10:30:00Z',
143
+ lastChecked: '2026-01-29T10:30:00Z',
144
+ referencedIn: []
145
+ };
146
+
147
+ expect(() => DependencyEntrySchema.parse(entry)).toThrow();
148
+ });
149
+ });
150
+
151
+ describe('DependencyManifestSchema', () => {
152
+ it('should validate a complete manifest', () => {
153
+ const manifest = {
154
+ version: '1.0.0',
155
+ generatedAt: '2026-01-29T10:30:00Z',
156
+ generatedBy: {
157
+ action: 'dependabit',
158
+ version: '1.0.0',
159
+ llmProvider: 'github-copilot',
160
+ llmModel: 'gpt-4'
161
+ },
162
+ repository: {
163
+ owner: 'pradeepmouli',
164
+ name: 'dependabit',
165
+ branch: 'main',
166
+ commit: 'abc123def456'
167
+ },
168
+ dependencies: [
169
+ {
170
+ id: '550e8400-e29b-41d4-a716-446655440000',
171
+ url: 'https://github.com/microsoft/TypeScript',
172
+ type: 'reference-implementation',
173
+ accessMethod: 'github-api',
174
+ name: 'TypeScript',
175
+ currentStateHash: 'sha256:abc123',
176
+ detectionMethod: 'package-json',
177
+ detectionConfidence: 1.0,
178
+ detectedAt: '2026-01-29T10:30:00Z',
179
+ lastChecked: '2026-01-29T10:30:00Z',
180
+ referencedIn: []
181
+ }
182
+ ],
183
+ statistics: {
184
+ totalDependencies: 1,
185
+ byType: { 'reference-implementation': 1 },
186
+ byAccessMethod: { 'github-api': 1 },
187
+ byDetectionMethod: { 'package-json': 1 },
188
+ averageConfidence: 1.0
189
+ }
190
+ };
191
+
192
+ const result = DependencyManifestSchema.parse(manifest);
193
+ expect(result.version).toBe('1.0.0');
194
+ expect(result.dependencies).toHaveLength(1);
195
+ });
196
+
197
+ it('should require correct version', () => {
198
+ const manifest = {
199
+ version: '2.0.0',
200
+ generatedAt: '2026-01-29T10:30:00Z',
201
+ generatedBy: {
202
+ action: 'dependabit',
203
+ version: '1.0.0',
204
+ llmProvider: 'github-copilot'
205
+ },
206
+ repository: {
207
+ owner: 'pradeepmouli',
208
+ name: 'dependabit',
209
+ branch: 'main',
210
+ commit: 'abc123'
211
+ },
212
+ dependencies: [],
213
+ statistics: {
214
+ totalDependencies: 0,
215
+ byType: {},
216
+ byAccessMethod: {},
217
+ byDetectionMethod: {},
218
+ averageConfidence: 0
219
+ }
220
+ };
221
+
222
+ expect(() => DependencyManifestSchema.parse(manifest)).toThrow();
223
+ });
224
+ });
225
+
226
+ describe('DependabitConfigSchema', () => {
227
+ it('should validate a complete config', () => {
228
+ const config = {
229
+ version: '1',
230
+ llm: {
231
+ provider: 'github-copilot',
232
+ model: 'gpt-4',
233
+ maxTokens: 4000,
234
+ temperature: 0.3
235
+ },
236
+ schedule: {
237
+ interval: 'daily',
238
+ time: '02:00',
239
+ timezone: 'UTC'
240
+ },
241
+ issues: {
242
+ labels: ['dependabit', 'dependency-update'],
243
+ assignees: ['pradeepmouli'],
244
+ titleTemplate: '[dependabit] {name}: {change}'
245
+ },
246
+ monitoring: {
247
+ enabled: true,
248
+ autoUpdate: true,
249
+ falsePositiveThreshold: 0.1
250
+ }
251
+ };
252
+
253
+ const result = DependabitConfigSchema.parse(config);
254
+ expect(result.version).toBe('1');
255
+ expect(result.llm?.provider).toBe('github-copilot');
256
+ });
257
+
258
+ it('should apply defaults', () => {
259
+ const config = {
260
+ version: '1'
261
+ };
262
+
263
+ const result = DependabitConfigSchema.parse(config);
264
+ expect(result.schedule.interval).toBe('daily');
265
+ expect(result.schedule.timezone).toBe('UTC');
266
+ });
267
+
268
+ it('should validate schedule time format', () => {
269
+ const config = {
270
+ version: '1',
271
+ schedule: {
272
+ interval: 'daily',
273
+ time: '25:00',
274
+ timezone: 'UTC'
275
+ }
276
+ };
277
+
278
+ expect(() => DependabitConfigSchema.parse(config)).toThrow();
279
+ });
280
+
281
+ it('should validate LLM temperature range', () => {
282
+ const config = {
283
+ version: '1',
284
+ llm: {
285
+ provider: 'github-copilot',
286
+ temperature: 3.0
287
+ }
288
+ };
289
+
290
+ expect(() => DependabitConfigSchema.parse(config)).toThrow();
291
+ });
292
+ });
293
+ });
package/src/schema.ts ADDED
@@ -0,0 +1,265 @@
1
+ import { z } from 'zod';
2
+
3
+ // Version tracking
4
+ export const ManifestVersionSchema = z.literal('1.0.0');
5
+
6
+ // Access methods (HOW to retrieve/check dependency)
7
+ export const AccessMethodSchema = z.enum(['context7', 'arxiv', 'openapi', 'github-api', 'http']);
8
+
9
+ // Dependency types (WHAT the dependency represents)
10
+ export const DependencyTypeSchema = z.enum([
11
+ 'reference-implementation',
12
+ 'schema',
13
+ 'documentation',
14
+ 'research-paper',
15
+ 'api-example',
16
+ 'other'
17
+ ]);
18
+
19
+ // Detection methods
20
+ export const DetectionMethodSchema = z.enum([
21
+ 'llm-analysis',
22
+ 'manual',
23
+ 'package-json',
24
+ 'requirements-txt',
25
+ 'code-comment'
26
+ ]);
27
+
28
+ // Severity levels
29
+ export const SeveritySchema = z.enum(['breaking', 'major', 'minor']);
30
+
31
+ // Authentication configuration
32
+ export const AuthConfigSchema = z
33
+ .object({
34
+ type: z.enum(['token', 'basic', 'oauth', 'none']),
35
+ // Reference to an environment variable or secret identifier.
36
+ // Do NOT store raw secret values directly in the manifest.
37
+ secretEnvVar: z.string().optional()
38
+ })
39
+ .optional();
40
+
41
+ // Monitoring rules
42
+ export const MonitoringRulesSchema = z.object({
43
+ enabled: z.boolean().default(true),
44
+ checkFrequency: z.enum(['hourly', 'daily', 'weekly', 'monthly']).default('daily'),
45
+ ignoreChanges: z.boolean().default(false),
46
+ severityOverride: SeveritySchema.optional()
47
+ });
48
+
49
+ // Individual dependency entry
50
+ export const DependencyEntrySchema = z.object({
51
+ id: z.string().uuid(),
52
+ url: z.string().url(),
53
+ type: DependencyTypeSchema,
54
+ accessMethod: AccessMethodSchema,
55
+ name: z.string(),
56
+ description: z.string().optional(),
57
+
58
+ // Version/state tracking
59
+ currentVersion: z.string().optional(),
60
+ currentStateHash: z.string(),
61
+
62
+ // Metadata
63
+ detectionMethod: DetectionMethodSchema,
64
+ detectionConfidence: z.number().min(0).max(1),
65
+ detectedAt: z.string().datetime(),
66
+ lastChecked: z.string().datetime(),
67
+ lastChanged: z.string().datetime().optional(),
68
+
69
+ // Configuration
70
+ auth: AuthConfigSchema,
71
+ monitoring: MonitoringRulesSchema.optional(),
72
+
73
+ // Relationships
74
+ referencedIn: z.array(
75
+ z.object({
76
+ file: z.string(),
77
+ line: z.number().optional(),
78
+ context: z.string().optional()
79
+ })
80
+ ),
81
+
82
+ // Change history
83
+ changeHistory: z
84
+ .array(
85
+ z.object({
86
+ detectedAt: z.string().datetime(),
87
+ oldVersion: z.string().optional(),
88
+ newVersion: z.string().optional(),
89
+ severity: SeveritySchema,
90
+ issueNumber: z.number().optional(),
91
+ falsePositive: z.boolean().default(false)
92
+ })
93
+ )
94
+ .default([])
95
+ });
96
+
97
+ // Complete manifest
98
+ export const DependencyManifestSchema = z.object({
99
+ version: ManifestVersionSchema,
100
+ generatedAt: z.string().datetime(),
101
+ generatedBy: z.object({
102
+ action: z.string(),
103
+ version: z.string(),
104
+ llmProvider: z.string(),
105
+ llmModel: z.string().optional()
106
+ }),
107
+
108
+ repository: z.object({
109
+ owner: z.string(),
110
+ name: z.string(),
111
+ branch: z.string(),
112
+ commit: z.string()
113
+ }),
114
+
115
+ dependencies: z.array(DependencyEntrySchema),
116
+
117
+ statistics: z.object({
118
+ totalDependencies: z.number(),
119
+ byType: z.record(z.string(), z.number()),
120
+ byAccessMethod: z.record(z.string(), z.number()),
121
+ byDetectionMethod: z.record(z.string(), z.number()),
122
+ averageConfidence: z.number(),
123
+ falsePositiveRate: z.number().min(0).max(1).optional()
124
+ })
125
+ });
126
+
127
+ // Schedule configuration (dependabot-compatible)
128
+ export const ScheduleSchema = z.object({
129
+ interval: z.enum(['hourly', 'daily', 'weekly', 'monthly']),
130
+ day: z
131
+ .enum(['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'])
132
+ .optional(),
133
+ time: z
134
+ .string()
135
+ .regex(/^([01]\d|2[0-3]):([0-5]\d)$/)
136
+ .optional(),
137
+ timezone: z.string().default('UTC')
138
+ });
139
+
140
+ // LLM provider configuration
141
+ export const LLMConfigSchema = z.object({
142
+ provider: z
143
+ .enum(['github-copilot', 'claude', 'openai', 'azure-openai'])
144
+ .default('github-copilot'),
145
+ model: z.string().optional(),
146
+ maxTokens: z.number().int().positive().default(4000),
147
+ temperature: z.number().min(0).max(2).default(0.3)
148
+ });
149
+
150
+ // Issue configuration
151
+ export const IssueConfigSchema = z.object({
152
+ labels: z.array(z.string()).default(['dependabit', 'dependency-update']),
153
+ assignees: z.array(z.string()).default([]),
154
+ aiAgentAssignment: z
155
+ .object({
156
+ enabled: z.boolean().default(false),
157
+ breaking: z.string().optional(),
158
+ major: z.string().optional(),
159
+ minor: z.string().optional()
160
+ })
161
+ .optional(),
162
+ titleTemplate: z.string().default('[dependabit] {name}: {change}'),
163
+ bodyTemplate: z.string().optional()
164
+ });
165
+
166
+ // Per-dependency override
167
+ export const DependencyOverrideSchema = z.object({
168
+ url: z.string().url(),
169
+ schedule: ScheduleSchema.optional(),
170
+ monitoring: MonitoringRulesSchema.optional(),
171
+ issues: IssueConfigSchema.optional()
172
+ });
173
+
174
+ // Complete configuration
175
+ export const DependabitConfigSchema = z.object({
176
+ version: z.literal('1'),
177
+
178
+ // Global settings
179
+ llm: LLMConfigSchema.optional(),
180
+ schedule: ScheduleSchema.default({ interval: 'daily', timezone: 'UTC' }),
181
+ issues: IssueConfigSchema.optional(),
182
+
183
+ // Monitoring behavior
184
+ monitoring: z
185
+ .object({
186
+ enabled: z.boolean().default(true),
187
+ autoUpdate: z.boolean().default(true),
188
+ falsePositiveThreshold: z.number().min(0).max(1).default(0.1)
189
+ })
190
+ .optional(),
191
+
192
+ // Dependency-specific overrides
193
+ dependencies: z.array(DependencyOverrideSchema).optional(),
194
+
195
+ // Exclusions
196
+ ignore: z
197
+ .object({
198
+ urls: z.array(z.string()).optional(),
199
+ types: z.array(DependencyTypeSchema).optional(),
200
+ patterns: z.array(z.string()).optional()
201
+ })
202
+ .optional()
203
+ });
204
+
205
+ // Change detection schemas
206
+ export const ChangeTypeSchema = z.enum([
207
+ 'version-bump',
208
+ 'content-changed',
209
+ 'released',
210
+ 'deprecated',
211
+ 'unavailable',
212
+ 'unknown'
213
+ ]);
214
+
215
+ export const ChangeDetectionRecordSchema = z.object({
216
+ id: z.string().uuid(),
217
+ timestamp: z.string().datetime(),
218
+
219
+ // Dependency reference
220
+ dependencyId: z.string().uuid(),
221
+ dependencyUrl: z.string().url(),
222
+ dependencyName: z.string(),
223
+
224
+ // Change details
225
+ changeType: ChangeTypeSchema,
226
+ severity: SeveritySchema,
227
+
228
+ // State comparison
229
+ oldState: z.object({
230
+ version: z.string().optional(),
231
+ hash: z.string(),
232
+ checkedAt: z.string().datetime()
233
+ }),
234
+ newState: z.object({
235
+ version: z.string().optional(),
236
+ hash: z.string(),
237
+ checkedAt: z.string().datetime()
238
+ }),
239
+
240
+ // Change description
241
+ summary: z.string(),
242
+ details: z.string().optional(),
243
+ breakingChanges: z.array(z.string()).optional(),
244
+
245
+ // Action taken
246
+ issueCreated: z.boolean().default(false),
247
+ issueNumber: z.number().optional(),
248
+ issueUrl: z.string().url().optional()
249
+ });
250
+
251
+ // TypeScript types
252
+ export type DependencyManifest = z.infer<typeof DependencyManifestSchema>;
253
+ export type DependencyEntry = z.infer<typeof DependencyEntrySchema>;
254
+ export type DependencyType = z.infer<typeof DependencyTypeSchema>;
255
+ export type AccessMethod = z.infer<typeof AccessMethodSchema>;
256
+ export type DetectionMethod = z.infer<typeof DetectionMethodSchema>;
257
+ export type Severity = z.infer<typeof SeveritySchema>;
258
+ export type MonitoringRules = z.infer<typeof MonitoringRulesSchema>;
259
+ export type DependabitConfig = z.infer<typeof DependabitConfigSchema>;
260
+ export type Schedule = z.infer<typeof ScheduleSchema>;
261
+ export type LLMConfig = z.infer<typeof LLMConfigSchema>;
262
+ export type IssueConfig = z.infer<typeof IssueConfigSchema>;
263
+ export type DependencyOverride = z.infer<typeof DependencyOverrideSchema>;
264
+ export type ChangeType = z.infer<typeof ChangeTypeSchema>;
265
+ export type ChangeDetectionRecord = z.infer<typeof ChangeDetectionRecordSchema>;