@dependabit/manifest 0.1.13 → 0.1.15
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.
- package/CHANGELOG.md +12 -0
- package/dist/config.d.ts +66 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +66 -6
- package/dist/config.js.map +1 -1
- package/dist/manifest.d.ts +131 -8
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +131 -8
- package/dist/manifest.js.map +1 -1
- package/dist/schema.d.ts +129 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +42 -0
- package/dist/schema.js.map +1 -1
- package/dist/size-check.js.map +1 -1
- package/dist/validator.d.ts +7 -1
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +7 -1
- package/dist/validator.js.map +1 -1
- package/package.json +25 -8
- package/src/config.test.ts +0 -266
- package/src/config.ts +0 -96
- package/src/index.ts +0 -16
- package/src/manifest.test.ts +0 -400
- package/src/manifest.ts +0 -278
- package/src/schema.test.ts +0 -293
- package/src/schema.ts +0 -266
- package/src/size-check.test.ts +0 -246
- package/src/size-check.ts +0 -124
- package/src/validator.test.ts +0 -161
- package/src/validator.ts +0 -131
- package/tsconfig.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
package/src/schema.ts
DELETED
|
@@ -1,266 +0,0 @@
|
|
|
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
|
-
useGitExcludes: z.boolean().default(true)
|
|
202
|
-
})
|
|
203
|
-
.optional()
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// Change detection schemas
|
|
207
|
-
export const ChangeTypeSchema = z.enum([
|
|
208
|
-
'version-bump',
|
|
209
|
-
'content-changed',
|
|
210
|
-
'released',
|
|
211
|
-
'deprecated',
|
|
212
|
-
'unavailable',
|
|
213
|
-
'unknown'
|
|
214
|
-
]);
|
|
215
|
-
|
|
216
|
-
export const ChangeDetectionRecordSchema = z.object({
|
|
217
|
-
id: z.string().uuid(),
|
|
218
|
-
timestamp: z.string().datetime(),
|
|
219
|
-
|
|
220
|
-
// Dependency reference
|
|
221
|
-
dependencyId: z.string().uuid(),
|
|
222
|
-
dependencyUrl: z.string().url(),
|
|
223
|
-
dependencyName: z.string(),
|
|
224
|
-
|
|
225
|
-
// Change details
|
|
226
|
-
changeType: ChangeTypeSchema,
|
|
227
|
-
severity: SeveritySchema,
|
|
228
|
-
|
|
229
|
-
// State comparison
|
|
230
|
-
oldState: z.object({
|
|
231
|
-
version: z.string().optional(),
|
|
232
|
-
hash: z.string(),
|
|
233
|
-
checkedAt: z.string().datetime()
|
|
234
|
-
}),
|
|
235
|
-
newState: z.object({
|
|
236
|
-
version: z.string().optional(),
|
|
237
|
-
hash: z.string(),
|
|
238
|
-
checkedAt: z.string().datetime()
|
|
239
|
-
}),
|
|
240
|
-
|
|
241
|
-
// Change description
|
|
242
|
-
summary: z.string(),
|
|
243
|
-
details: z.string().optional(),
|
|
244
|
-
breakingChanges: z.array(z.string()).optional(),
|
|
245
|
-
|
|
246
|
-
// Action taken
|
|
247
|
-
issueCreated: z.boolean().default(false),
|
|
248
|
-
issueNumber: z.number().optional(),
|
|
249
|
-
issueUrl: z.string().url().optional()
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
// TypeScript types
|
|
253
|
-
export type DependencyManifest = z.infer<typeof DependencyManifestSchema>;
|
|
254
|
-
export type DependencyEntry = z.infer<typeof DependencyEntrySchema>;
|
|
255
|
-
export type DependencyType = z.infer<typeof DependencyTypeSchema>;
|
|
256
|
-
export type AccessMethod = z.infer<typeof AccessMethodSchema>;
|
|
257
|
-
export type DetectionMethod = z.infer<typeof DetectionMethodSchema>;
|
|
258
|
-
export type Severity = z.infer<typeof SeveritySchema>;
|
|
259
|
-
export type MonitoringRules = z.infer<typeof MonitoringRulesSchema>;
|
|
260
|
-
export type DependabitConfig = z.infer<typeof DependabitConfigSchema>;
|
|
261
|
-
export type Schedule = z.infer<typeof ScheduleSchema>;
|
|
262
|
-
export type LLMConfig = z.infer<typeof LLMConfigSchema>;
|
|
263
|
-
export type IssueConfig = z.infer<typeof IssueConfigSchema>;
|
|
264
|
-
export type DependencyOverride = z.infer<typeof DependencyOverrideSchema>;
|
|
265
|
-
export type ChangeType = z.infer<typeof ChangeTypeSchema>;
|
|
266
|
-
export type ChangeDetectionRecord = z.infer<typeof ChangeDetectionRecordSchema>;
|
package/src/size-check.test.ts
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
checkManifestSize,
|
|
4
|
-
formatSize,
|
|
5
|
-
validateManifestObject,
|
|
6
|
-
estimateEntrySize,
|
|
7
|
-
canAddEntry
|
|
8
|
-
} from './size-check.js';
|
|
9
|
-
|
|
10
|
-
describe('checkManifestSize', () => {
|
|
11
|
-
it('should return ok status for small content', () => {
|
|
12
|
-
const content = 'small content';
|
|
13
|
-
const result = checkManifestSize(content);
|
|
14
|
-
|
|
15
|
-
expect(result.status).toBe('ok');
|
|
16
|
-
expect(result.message).toBeUndefined();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should return warning status when exceeding warn threshold', () => {
|
|
20
|
-
const content = Buffer.alloc(1.5 * 1024 * 1024); // 1.5 MB
|
|
21
|
-
const result = checkManifestSize(content);
|
|
22
|
-
|
|
23
|
-
expect(result.status).toBe('warning');
|
|
24
|
-
expect(result.message).toContain('approaching limit');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should return error status when exceeding error threshold', () => {
|
|
28
|
-
const content = Buffer.alloc(11 * 1024 * 1024); // 11 MB
|
|
29
|
-
const result = checkManifestSize(content);
|
|
30
|
-
|
|
31
|
-
expect(result.status).toBe('error');
|
|
32
|
-
expect(result.message).toContain('exceeds maximum limit');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should handle exact threshold values', () => {
|
|
36
|
-
const exactWarnSize = 1 * 1024 * 1024; // Exactly 1 MB
|
|
37
|
-
const result = checkManifestSize(Buffer.alloc(exactWarnSize));
|
|
38
|
-
|
|
39
|
-
expect(result.status).toBe('warning');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should support custom thresholds', () => {
|
|
43
|
-
const content = Buffer.alloc(2.5 * 1024 * 1024); // 2.5 MB
|
|
44
|
-
const result = checkManifestSize(content, {
|
|
45
|
-
warnThreshold: 2,
|
|
46
|
-
errorThreshold: 5
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
expect(result.status).toBe('warning');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should handle empty content', () => {
|
|
53
|
-
const result = checkManifestSize('');
|
|
54
|
-
|
|
55
|
-
expect(result.status).toBe('ok');
|
|
56
|
-
expect(result.sizeBytes).toBe(0);
|
|
57
|
-
expect(result.sizeMB).toBe(0);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should handle Buffer input', () => {
|
|
61
|
-
const buffer = Buffer.from('test content');
|
|
62
|
-
const result = checkManifestSize(buffer);
|
|
63
|
-
|
|
64
|
-
expect(result.sizeBytes).toBe(buffer.length);
|
|
65
|
-
expect(result.status).toBe('ok');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should handle string input with multi-byte characters', () => {
|
|
69
|
-
const content = '你好世界🌍'; // Multi-byte UTF-8 characters
|
|
70
|
-
const result = checkManifestSize(content);
|
|
71
|
-
|
|
72
|
-
expect(result.sizeBytes).toBe(Buffer.byteLength(content, 'utf8'));
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe('formatSize', () => {
|
|
77
|
-
it('should format bytes correctly', () => {
|
|
78
|
-
expect(formatSize(512)).toBe('512 B');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should format kilobytes correctly', () => {
|
|
82
|
-
expect(formatSize(1024)).toBe('1.00 KB');
|
|
83
|
-
expect(formatSize(5 * 1024)).toBe('5.00 KB');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should format megabytes correctly', () => {
|
|
87
|
-
expect(formatSize(1024 * 1024)).toBe('1.00 MB');
|
|
88
|
-
expect(formatSize(2.5 * 1024 * 1024)).toBe('2.50 MB');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle zero', () => {
|
|
92
|
-
expect(formatSize(0)).toBe('0 B');
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should handle large values', () => {
|
|
96
|
-
expect(formatSize(100 * 1024 * 1024)).toBe('100.00 MB');
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe('validateManifestObject', () => {
|
|
101
|
-
it('should validate small manifest objects', () => {
|
|
102
|
-
const manifest = { dependencies: [{ id: '1', name: 'test' }] };
|
|
103
|
-
const result = validateManifestObject(manifest);
|
|
104
|
-
|
|
105
|
-
expect(result.status).toBe('ok');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should detect large manifest objects', () => {
|
|
109
|
-
const largeDeps = Array.from({ length: 10000 }, (_, i) => ({
|
|
110
|
-
id: `dep-${i}`,
|
|
111
|
-
name: `dependency-${i}`,
|
|
112
|
-
url: `https://github.com/org/repo-${i}`,
|
|
113
|
-
description: 'A'.repeat(100)
|
|
114
|
-
}));
|
|
115
|
-
|
|
116
|
-
const manifest = { dependencies: largeDeps };
|
|
117
|
-
const result = validateManifestObject(manifest);
|
|
118
|
-
|
|
119
|
-
expect(result.status).not.toBe('ok');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should handle empty objects', () => {
|
|
123
|
-
const result = validateManifestObject({});
|
|
124
|
-
|
|
125
|
-
expect(result.status).toBe('ok');
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should support custom thresholds', () => {
|
|
129
|
-
const manifest = { data: 'x'.repeat(500 * 1024) }; // ~500 KB
|
|
130
|
-
const result = validateManifestObject(manifest, {
|
|
131
|
-
warnThreshold: 0.4,
|
|
132
|
-
errorThreshold: 1
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
expect(result.status).toBe('warning');
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
describe('estimateEntrySize', () => {
|
|
140
|
-
it('should estimate size of simple entries', () => {
|
|
141
|
-
const entry = { id: '1', name: 'test' };
|
|
142
|
-
const size = estimateEntrySize(entry);
|
|
143
|
-
|
|
144
|
-
expect(size).toBeGreaterThan(0);
|
|
145
|
-
expect(size).toBe(JSON.stringify(entry).length);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('should estimate size of complex entries', () => {
|
|
149
|
-
const entry = {
|
|
150
|
-
id: '1',
|
|
151
|
-
name: 'complex-dependency',
|
|
152
|
-
metadata: {
|
|
153
|
-
version: '1.0.0',
|
|
154
|
-
tags: ['tag1', 'tag2', 'tag3'],
|
|
155
|
-
description: 'A long description with multiple words'
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const size = estimateEntrySize(entry);
|
|
160
|
-
expect(size).toBeGreaterThan(50);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should handle null', () => {
|
|
164
|
-
expect(estimateEntrySize(null)).toBe(4); // "null"
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('should handle arrays', () => {
|
|
168
|
-
const entry = [1, 2, 3];
|
|
169
|
-
const size = estimateEntrySize(entry);
|
|
170
|
-
expect(size).toBe(JSON.stringify(entry).length);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
describe('canAddEntry', () => {
|
|
175
|
-
it('should allow adding small entries to small manifests', () => {
|
|
176
|
-
const manifest = { dependencies: [] };
|
|
177
|
-
const entry = { id: '1', name: 'test' };
|
|
178
|
-
|
|
179
|
-
const result = canAddEntry(manifest, entry);
|
|
180
|
-
|
|
181
|
-
expect(result.canAdd).toBe(true);
|
|
182
|
-
expect(result.currentSize.status).toBe('ok');
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it('should prevent adding entries when it would exceed limit', () => {
|
|
186
|
-
// Create a manifest that's already close to the limit
|
|
187
|
-
const largeDeps = Array.from({ length: 10000 }, (_, i) => ({
|
|
188
|
-
id: `dep-${i}`,
|
|
189
|
-
url: `https://example.com/${i}`,
|
|
190
|
-
description: 'A'.repeat(800) // ~800 bytes each, total ~8MB
|
|
191
|
-
}));
|
|
192
|
-
|
|
193
|
-
const manifest = { dependencies: largeDeps };
|
|
194
|
-
const newEntry = {
|
|
195
|
-
id: 'new-dep',
|
|
196
|
-
url: 'https://example.com/new',
|
|
197
|
-
description: 'B'.repeat(3000000) // Very large entry ~3MB
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const result = canAddEntry(manifest, newEntry, {
|
|
201
|
-
errorThreshold: 10
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
expect(result.canAdd).toBe(false);
|
|
205
|
-
expect(result.estimatedSize.message).toContain('exceed size limit');
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('should show warning status when approaching limit', () => {
|
|
209
|
-
const deps = Array.from({ length: 1000 }, (_, i) => ({
|
|
210
|
-
id: `dep-${i}`,
|
|
211
|
-
data: 'x'.repeat(900) // Each ~900 bytes
|
|
212
|
-
}));
|
|
213
|
-
|
|
214
|
-
const manifest = { dependencies: deps };
|
|
215
|
-
const entry = { id: 'new', data: 'y'.repeat(100) };
|
|
216
|
-
|
|
217
|
-
const result = canAddEntry(manifest, entry, {
|
|
218
|
-
warnThreshold: 0.8,
|
|
219
|
-
errorThreshold: 10
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
expect(result.canAdd).toBe(true);
|
|
223
|
-
expect(result.estimatedSize.status).toBe('warning');
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
it('should handle adding entry to empty manifest', () => {
|
|
227
|
-
const manifest = {};
|
|
228
|
-
const entry = { id: '1', name: 'first' };
|
|
229
|
-
|
|
230
|
-
const result = canAddEntry(manifest, entry);
|
|
231
|
-
|
|
232
|
-
expect(result.canAdd).toBe(true);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
it('should account for JSON formatting overhead', () => {
|
|
236
|
-
const manifest = { dependencies: [{ id: '1' }] };
|
|
237
|
-
const entry = { id: '2' };
|
|
238
|
-
|
|
239
|
-
const result = canAddEntry(manifest, entry);
|
|
240
|
-
|
|
241
|
-
// Estimated size should be larger than current + entry due to formatting buffer
|
|
242
|
-
expect(result.estimatedSize.sizeBytes).toBeGreaterThan(
|
|
243
|
-
result.currentSize.sizeBytes + estimateEntrySize(entry)
|
|
244
|
-
);
|
|
245
|
-
});
|
|
246
|
-
});
|
package/src/size-check.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Manifest size validation and warnings
|
|
3
|
-
* Checks manifest size and warns when approaching limits
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface SizeCheckResult {
|
|
7
|
-
sizeBytes: number;
|
|
8
|
-
sizeMB: number;
|
|
9
|
-
status: 'ok' | 'warning' | 'error';
|
|
10
|
-
message?: string | undefined;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface SizeCheckOptions {
|
|
14
|
-
warnThreshold?: number; // MB (default: 1)
|
|
15
|
-
errorThreshold?: number; // MB (default: 10)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Check manifest size and return status
|
|
20
|
-
*/
|
|
21
|
-
export function checkManifestSize(
|
|
22
|
-
content: string | Buffer,
|
|
23
|
-
options?: SizeCheckOptions
|
|
24
|
-
): SizeCheckResult {
|
|
25
|
-
const warnThreshold = (options?.warnThreshold ?? 1) * 1024 * 1024; // Convert MB to bytes
|
|
26
|
-
const errorThreshold = (options?.errorThreshold ?? 10) * 1024 * 1024;
|
|
27
|
-
|
|
28
|
-
const sizeBytes =
|
|
29
|
-
typeof content === 'string' ? Buffer.byteLength(content, 'utf8') : content.length;
|
|
30
|
-
|
|
31
|
-
const sizeMB = sizeBytes / (1024 * 1024);
|
|
32
|
-
|
|
33
|
-
if (sizeBytes >= errorThreshold) {
|
|
34
|
-
return {
|
|
35
|
-
sizeBytes,
|
|
36
|
-
sizeMB,
|
|
37
|
-
status: 'error',
|
|
38
|
-
message: `Manifest size (${sizeMB.toFixed(2)}MB) exceeds maximum limit of ${(errorThreshold / 1024 / 1024).toFixed(0)}MB. Consider splitting or pruning data.`
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (sizeBytes >= warnThreshold) {
|
|
43
|
-
return {
|
|
44
|
-
sizeBytes,
|
|
45
|
-
sizeMB,
|
|
46
|
-
status: 'warning',
|
|
47
|
-
message: `Manifest size (${sizeMB.toFixed(2)}MB) is approaching limit. Warning threshold: ${(warnThreshold / 1024 / 1024).toFixed(0)}MB, Max: ${(errorThreshold / 1024 / 1024).toFixed(0)}MB.`
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return {
|
|
52
|
-
sizeBytes,
|
|
53
|
-
sizeMB,
|
|
54
|
-
status: 'ok'
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Get formatted size string
|
|
60
|
-
*/
|
|
61
|
-
export function formatSize(bytes: number): string {
|
|
62
|
-
if (bytes < 1024) {
|
|
63
|
-
return `${bytes} B`;
|
|
64
|
-
}
|
|
65
|
-
if (bytes < 1024 * 1024) {
|
|
66
|
-
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
67
|
-
}
|
|
68
|
-
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Validate manifest object size before serialization
|
|
73
|
-
*/
|
|
74
|
-
export function validateManifestObject(
|
|
75
|
-
manifest: unknown,
|
|
76
|
-
options?: SizeCheckOptions
|
|
77
|
-
): SizeCheckResult {
|
|
78
|
-
const serialized = JSON.stringify(manifest, null, 2);
|
|
79
|
-
return checkManifestSize(serialized, options);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Estimate manifest size impact of adding an entry
|
|
84
|
-
*/
|
|
85
|
-
export function estimateEntrySize(entry: unknown): number {
|
|
86
|
-
const serialized = JSON.stringify(entry);
|
|
87
|
-
return Buffer.byteLength(serialized, 'utf8');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Check if adding an entry would exceed limits
|
|
92
|
-
*/
|
|
93
|
-
export function canAddEntry(
|
|
94
|
-
currentManifest: unknown,
|
|
95
|
-
newEntry: unknown,
|
|
96
|
-
options?: SizeCheckOptions
|
|
97
|
-
): {
|
|
98
|
-
canAdd: boolean;
|
|
99
|
-
currentSize: SizeCheckResult;
|
|
100
|
-
estimatedSize: SizeCheckResult;
|
|
101
|
-
} {
|
|
102
|
-
const currentSize = validateManifestObject(currentManifest, options);
|
|
103
|
-
const entrySize = estimateEntrySize(newEntry);
|
|
104
|
-
|
|
105
|
-
// Estimate new size (accounting for JSON formatting)
|
|
106
|
-
const estimatedBytes = currentSize.sizeBytes + entrySize + 100; // Add buffer for formatting
|
|
107
|
-
const estimatedSizeMB = estimatedBytes / (1024 * 1024);
|
|
108
|
-
|
|
109
|
-
const errorThreshold = (options?.errorThreshold ?? 10) * 1024 * 1024;
|
|
110
|
-
const canAdd = estimatedBytes < errorThreshold;
|
|
111
|
-
|
|
112
|
-
const estimatedResult = checkManifestSize(Buffer.alloc(estimatedBytes), options);
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
canAdd,
|
|
116
|
-
currentSize,
|
|
117
|
-
estimatedSize: {
|
|
118
|
-
...estimatedResult,
|
|
119
|
-
message: canAdd
|
|
120
|
-
? estimatedResult.message
|
|
121
|
-
: `Adding entry would exceed size limit (estimated: ${estimatedSizeMB.toFixed(2)}MB)`
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
}
|